⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 child.c

📁 linux网络服务器工具
💻 C
📖 第 1 页 / 共 3 页
字号:
        else {            add_job(csd);        }    }    SetEvent(exit_event);    return 0;}static PCOMP_CONTEXT win9x_get_connection(PCOMP_CONTEXT context){    apr_os_sock_info_t sockinfo;    int len, salen;#if APR_HAVE_IPV6    salen = sizeof(struct sockaddr_in6);#else    salen = sizeof(struct sockaddr_in);#endif    if (context == NULL) {        /* allocate the completion context and the transaction pool */        apr_allocator_t *allocator;        apr_thread_mutex_lock(child_lock);        context = apr_pcalloc(pchild, sizeof(COMP_CONTEXT));        apr_allocator_create(&allocator);        apr_allocator_max_free_set(allocator, ap_max_mem_free);        apr_pool_create_ex(&context->ptrans, pchild, NULL, allocator);        apr_allocator_owner_set(allocator, context->ptrans);        apr_pool_tag(context->ptrans, "transaction");        apr_thread_mutex_unlock(child_lock);    }    while (1) {        apr_pool_clear(context->ptrans);        context->ba = apr_bucket_alloc_create(context->ptrans);        context->accept_socket = remove_job();        if (context->accept_socket == INVALID_SOCKET) {            return NULL;        }        len = salen;        context->sa_server = apr_palloc(context->ptrans, len);        if (getsockname(context->accept_socket,                        context->sa_server, &len)== SOCKET_ERROR) {            ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_netos_error(), ap_server_conf,                         "getsockname failed");            continue;        }        len = salen;        context->sa_client = apr_palloc(context->ptrans, len);        if ((getpeername(context->accept_socket,                         context->sa_client, &len)) == SOCKET_ERROR) {            ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_netos_error(), ap_server_conf,                         "getpeername failed");            memset(&context->sa_client, '\0', sizeof(context->sa_client));        }        sockinfo.os_sock = &context->accept_socket;        sockinfo.local   = context->sa_server;        sockinfo.remote  = context->sa_client;        sockinfo.family  = context->sa_server->sa_family;        sockinfo.type    = SOCK_STREAM;        apr_os_sock_make(&context->sock, &sockinfo, context->ptrans);        return context;    }}/* Windows NT/2000 specific code... * Accept processing for on Windows NT uses a producer/consumer queue * model. An accept thread accepts connections off the network then issues * PostQueuedCompletionStatus() to awake a thread blocked on the ThreadDispatch * IOCompletionPort. * * winnt_accept() *    One or more accept threads run in this function, each of which accepts *    connections off the network and calls PostQueuedCompletionStatus() to *    queue an io completion packet to the ThreadDispatch IOCompletionPort. * winnt_get_connection() *    Worker threads block on the ThreadDispatch IOCompletionPort awaiting *    connections to service. */#define MAX_ACCEPTEX_ERR_COUNT 100static unsigned int __stdcall winnt_accept(void *lr_){    ap_listen_rec *lr = (ap_listen_rec *)lr_;    apr_os_sock_info_t sockinfo;    PCOMP_CONTEXT context = NULL;    DWORD BytesRead;    SOCKET nlsd;    int rv, err_count = 0;#if APR_HAVE_IPV6    SOCKADDR_STORAGE ss_listen;    int namelen = sizeof(ss_listen);#endif    apr_os_sock_get(&nlsd, lr->sd);#if APR_HAVE_IPV6    if (getsockname(nlsd, (struct sockaddr *)&ss_listen, &namelen) == SOCKET_ERROR) {        ap_log_error(APLOG_MARK,APLOG_ERR, apr_get_netos_error(), ap_server_conf,                    "winnt_accept: getsockname error on listening socket, is IPv6 available?");        return 1;   }#endif    ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,                 "Child %d: Starting thread to listen on port %d.", my_pid, lr->bind_addr->port);    while (!shutdown_in_progress) {        if (!context) {            context = mpm_get_completion_context();            if (!context) {                /* Temporary resource constraint? */                Sleep(0);                continue;            }        }        /* Create and initialize the accept socket */#if APR_HAVE_IPV6        if (context->accept_socket == INVALID_SOCKET) {            context->accept_socket = socket(ss_listen.ss_family, SOCK_STREAM, IPPROTO_TCP);            context->socket_family = ss_listen.ss_family;        }        else if (context->socket_family != ss_listen.ss_family) {            closesocket(context->accept_socket);            context->accept_socket = socket(ss_listen.ss_family, SOCK_STREAM, IPPROTO_TCP);            context->socket_family = ss_listen.ss_family;        }        if (context->accept_socket == INVALID_SOCKET) {            ap_log_error(APLOG_MARK,APLOG_WARNING, apr_get_netos_error(), ap_server_conf,                         "winnt_accept: Failed to allocate an accept socket. "                         "Temporary resource constraint? Try again.");            Sleep(100);            continue;        }#else        if (context->accept_socket == INVALID_SOCKET) {            context->accept_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);            if (context->accept_socket == INVALID_SOCKET) {                /* Another temporary condition? */                ap_log_error(APLOG_MARK,APLOG_WARNING, apr_get_netos_error(), ap_server_conf,                             "winnt_accept: Failed to allocate an accept socket. "                             "Temporary resource constraint? Try again.");                Sleep(100);                continue;            }        }#endif        /* AcceptEx on the completion context. The completion context will be         * signaled when a connection is accepted.         */        if (!AcceptEx(nlsd, context->accept_socket,                      context->buff,                      0,                      PADDED_ADDR_SIZE,                      PADDED_ADDR_SIZE,                      &BytesRead,                      &context->Overlapped)) {            rv = apr_get_netos_error();            if ((rv == APR_FROM_OS_ERROR(WSAEINVAL)) ||                (rv == APR_FROM_OS_ERROR(WSAENOTSOCK))) {                /* We can get here when:                 * 1) the client disconnects early                 * 2) TransmitFile does not properly recycle the accept socket (typically                 *    because the client disconnected)                 * 3) there is VPN or Firewall software installed with buggy AcceptEx implementation                 * 4) the webserver is using a dynamic address that has changed                 */                ++err_count;                closesocket(context->accept_socket);                context->accept_socket = INVALID_SOCKET;                if (err_count > MAX_ACCEPTEX_ERR_COUNT) {                    ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf,                                 "Child %d: Encountered too many errors accepting client connections. "                                 "Possible causes: dynamic address renewal, or incompatible VPN or firewall software. "                                 "Try using the Win32DisableAcceptEx directive.", my_pid);                    err_count = 0;                }                continue;            }            else if ((rv != APR_FROM_OS_ERROR(ERROR_IO_PENDING)) &&                     (rv != APR_FROM_OS_ERROR(WSA_IO_PENDING))) {                ++err_count;                if (err_count > MAX_ACCEPTEX_ERR_COUNT) {                    ap_log_error(APLOG_MARK,APLOG_ERR, rv, ap_server_conf,                                 "Child %d: Encountered too many errors accepting client connections. "                                 "Possible causes: Unknown. "                                 "Try using the Win32DisableAcceptEx directive.", my_pid);                    err_count = 0;                }                closesocket(context->accept_socket);                context->accept_socket = INVALID_SOCKET;                continue;            }            err_count = 0;            /* Wait for pending i/o.             * Wake up once per second to check for shutdown .             * XXX: We should be waiting on exit_event instead of polling             */            while (1) {                rv = WaitForSingleObject(context->Overlapped.hEvent, 1000);                if (rv == WAIT_OBJECT_0) {                    if (context->accept_socket == INVALID_SOCKET) {                        /* socket already closed */                        break;                    }                    if (!GetOverlappedResult((HANDLE)context->accept_socket,                                             &context->Overlapped,                                             &BytesRead, FALSE)) {                        ap_log_error(APLOG_MARK, APLOG_WARNING,                                     apr_get_os_error(), ap_server_conf,                             "winnt_accept: Asynchronous AcceptEx failed.");                        closesocket(context->accept_socket);                        context->accept_socket = INVALID_SOCKET;                    }                    break;                }                /* WAIT_TIMEOUT */                if (shutdown_in_progress) {                    closesocket(context->accept_socket);                    context->accept_socket = INVALID_SOCKET;                    break;                }            }            if (context->accept_socket == INVALID_SOCKET) {                continue;            }        }        err_count = 0;        /* Inherit the listen socket settings. Required for         * shutdown() to work         */        if (setsockopt(context->accept_socket, SOL_SOCKET,                       SO_UPDATE_ACCEPT_CONTEXT, (char *)&nlsd,                       sizeof(nlsd))) {            ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_netos_error(), ap_server_conf,                         "setsockopt(SO_UPDATE_ACCEPT_CONTEXT) failed.");            /* Not a failure condition. Keep running. */        }        /* Get the local & remote address */        GetAcceptExSockaddrs(context->buff,                             0,                             PADDED_ADDR_SIZE,                             PADDED_ADDR_SIZE,                             &context->sa_server,                             &context->sa_server_len,                             &context->sa_client,                             &context->sa_client_len);        sockinfo.os_sock = &context->accept_socket;        sockinfo.local   = context->sa_server;        sockinfo.remote  = context->sa_client;        sockinfo.family  = context->sa_server->sa_family;        sockinfo.type    = SOCK_STREAM;        apr_os_sock_make(&context->sock, &sockinfo, context->ptrans);        /* When a connection is received, send an io completion notification to         * the ThreadDispatchIOCP. This function could be replaced by         * mpm_post_completion_context(), but why do an extra function call...         */        PostQueuedCompletionStatus(ThreadDispatchIOCP, 0, IOCP_CONNECTION_ACCEPTED,                                   &context->Overlapped);        context = NULL;    }    if (!shutdown_in_progress) {        /* Yow, hit an irrecoverable error! Tell the child to die. */        SetEvent(exit_event);    }    ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, ap_server_conf,                 "Child %d: Accept thread exiting.", my_pid);    return 0;}static PCOMP_CONTEXT winnt_get_connection(PCOMP_CONTEXT context){    int rc;    DWORD BytesRead;    LPOVERLAPPED pol;#ifdef _WIN64    ULONG_PTR CompKey;#else    DWORD CompKey;#endif    mpm_recycle_completion_context(context);    apr_atomic_inc32(&g_blocked_threads);    while (1) {        if (workers_may_exit) {            apr_atomic_dec32(&g_blocked_threads);            return NULL;        }        rc = GetQueuedCompletionStatus(ThreadDispatchIOCP, &BytesRead, &CompKey,                                       &pol, INFINITE);        if (!rc) {            rc = apr_get_os_error();            ap_log_error(APLOG_MARK,APLOG_DEBUG, rc, ap_server_conf,                             "Child %d: GetQueuedComplationStatus returned %d", my_pid, rc);            continue;        }        switch (CompKey) {        case IOCP_CONNECTION_ACCEPTED:            context = CONTAINING_RECORD(pol, COMP_CONTEXT, Overlapped);            break;        case IOCP_SHUTDOWN:            apr_atomic_dec32(&g_blocked_threads);            return NULL;        default:            apr_atomic_dec32(&g_blocked_threads);            return NULL;        }        break;    }    apr_atomic_dec32(&g_blocked_threads);    return context;}/* * worker_main() * Main entry point for the worker threads. Worker threads block in * win*_get_connection() awaiting a connection to service. */static unsigned int __stdcall worker_main(void *thread_num_val){    static int requests_this_child = 0;    PCOMP_CONTEXT context = NULL;    int thread_num = (int)thread_num_val;    ap_sb_handle_t *sbh;    while (1) {        conn_rec *c;        apr_int32_t disconnected;        ap_update_child_status_from_indexes(0, thread_num, SERVER_READY, NULL);        /* Grab a connection off the network */        if (use_acceptex) {            context = winnt_get_connection(context);        }        else {            context = win9x_get_connection(context);        }        if (!context) {            /* Time for the thread to exit */            break;        }        /* Have we hit MaxRequestPerChild connections? */        if (ap_max_requests_per_child) {            requests_this_child++;            if (requests_this_child > ap_max_requests_per_child) {                SetEvent(max_requests_per_child_event);            }        }        ap_create_sb_handle(&sbh, context->ptrans, 0, thread_num);        c = ap_run_create_connection(context->ptrans, ap_server_conf,                                     context->sock, thread_num, sbh,                                     context->ba);        if (c) {            ap_process_connection(c, context->sock);            apr_socket_opt_get(context->sock, APR_SO_DISCONNECTED,                               &disconnected);            if (!disconnected) {                context->accept_socket = INVALID_SOCKET;                ap_lingering_close(c);            }            else if (!use_acceptex) {                /* If the socket is disconnected but we are not using acceptex,                 * we cannot reuse the socket. Disconnected sockets are removed                 * from the apr_socket_t struct by apr_sendfile() to prevent the                 * socket descriptor from being inadvertently closed by a call                 * to apr_socket_close(), so close it directly.                 */                closesocket(context->accept_socket);                context->accept_socket = INVALID_SOCKET;            }        }        else {            /* ap_run_create_connection closes the socket on failure */            context->accept_socket = INVALID_SOCKET;        }    }    ap_update_child_status_from_indexes(0, thread_num, SERVER_DEAD,                                        (request_rec *) NULL);    return 0;}static void cleanup_thread(HANDLE *handles, int *thread_cnt, int thread_to_clean){    int i;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -