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

📄 child.c

📁 apache的软件linux版本
💻 C
📖 第 1 页 / 共 3 页
字号:
	}	do {            clen = sizeof(sa_client);            csd = accept(nsd, (struct sockaddr *) &sa_client, &clen);        } while (csd < 0 && APR_STATUS_IS_EINTR(apr_get_netos_error()));	if (csd < 0) {            if (APR_STATUS_IS_ECONNABORTED(apr_get_netos_error())) {		ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_netos_error(), ap_server_conf,			    "accept: (client socket)");            }	}	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;    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 = sizeof(struct sockaddr);        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 = sizeof(struct sockaddr);        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  = APR_INET;        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 250static 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;    apr_os_sock_get(&nlsd, lr->sd);    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 (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;            }        }        /* 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;                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: Unknown. "                                 "Try using the Win32DisableAcceptEx directive.", my_pid);                    err_count = 0;                }                continue;            }            /* 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  = APR_INET;        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;    DWORD CompKey;    LPOVERLAPPED pol;    mpm_recycle_completion_context(context);    apr_atomic_inc(&g_blocked_threads);    while (1) {        if (workers_may_exit) {            apr_atomic_dec(&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_dec(&g_blocked_threads);            return NULL;        default:            apr_atomic_dec(&g_blocked_threads);            return NULL;        }        break;    }    apr_atomic_dec(&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;    ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, ap_server_conf,                 "Child %d: Worker thread %ld starting.", my_pid, thread_num);    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);    ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, ap_server_conf,                 "Child %d: Worker thread %ld exiting.", my_pid, thread_num);    return 0;}static void cleanup_thread(HANDLE *handles, int *thread_cnt, int thread_to_clean){    int i;    CloseHandle(handles[thread_to_clean]);    for (i = thread_to_clean; i < ((*thread_cnt) - 1); i++)	handles[i] = handles[i + 1];    (*thread_cnt)--;}/* * child_main()  * Entry point for the main control thread for the child process.  * This thread creates the accept thread, worker threads and * monitors the child process for maintenance and shutdown

⌨️ 快捷键说明

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