📄 mpm_winnt.c
字号:
if (head_listener == NULL) head_listener = ap_listeners; return (lr); } } return NULL;}/* * get_listeners_from_parent() * The listen sockets are opened in the parent. This function, which runs * exclusively in the child process, receives them from the parent and * makes them availeble in the child. */static int get_listeners_from_parent(server_rec *s){ WSAPROTOCOL_INFO WSAProtocolInfo; HANDLE pipe; ap_listen_rec *lr; DWORD BytesRead; int num_listeners = 0; SOCKET nsd; /* Set up a default listener if necessary */ if (ap_listeners == NULL) { ap_listen_rec *lr; lr = apr_palloc(s->process->pool, sizeof(ap_listen_rec)); if (!lr) return 0; lr->sd = NULL; lr->next = ap_listeners; ap_listeners = lr; } /* Open the pipe to the parent process to receive the inherited socket * data. The sockets have been set to listening in the parent process. */ pipe = GetStdHandle(STD_INPUT_HANDLE); for (lr = ap_listeners; lr; lr = lr->next) { if (!ReadFile(pipe, &WSAProtocolInfo, sizeof(WSAPROTOCOL_INFO), &BytesRead, (LPOVERLAPPED) NULL)) { ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_os_error(), server_conf, "setup_inherited_listeners: Unable to read socket data from parent"); signal_parent(0); /* tell parent to die */ exit(1); } ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, APR_SUCCESS, server_conf, "Child %d: setup_inherited_listener() read = %d bytes of WSAProtocolInfo.", my_pid); nsd = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, &WSAProtocolInfo, 0, 0); if (nsd == INVALID_SOCKET) { ap_log_error(APLOG_MARK, APLOG_CRIT, apr_get_netos_error(), server_conf, "Child %d: setup_inherited_listeners(), WSASocket failed to open the inherited socket.", my_pid); signal_parent(0); /* tell parent to die */ exit(1); } apr_os_sock_put(&lr->sd, &nsd, pconf); num_listeners++; } CloseHandle(pipe); return num_listeners;}/* Windows 9x specific code... * Accept processing for on Windows 95/98 uses a producer/consumer queue * model. A single thread accepts connections and queues the accepted socket * to the accept queue for consumption by a pool of worker threads. * * win9x_accept() * The accept threads runs this function, which accepts connections off * the network and calls add_job() to queue jobs to the accept_queue. * add_job()/remove_job() * Add or remove an accepted socket from the list of sockets * connected to clients. allowed_globals.jobmutex protects * against multiple concurrent access to the linked list of jobs. * win9x_get_connection() * Calls remove_job() to pull a job from the accept queue. All the worker * threads block on remove_job. */typedef struct joblist_s { struct joblist_s *next; int sock;} joblist;typedef struct globals_s { HANDLE jobsemaphore; joblist *jobhead; joblist *jobtail; apr_lock_t *jobmutex; int jobcount;} globals;globals allowed_globals = {NULL, NULL, NULL, NULL, 0};#define MAX_SELECT_ERRORS 100static void add_job(int sock){ joblist *new_job; new_job = (joblist *) malloc(sizeof(joblist)); if (new_job == NULL) { ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "Ouch! Out of memory in add_job()!"); return; } new_job->next = NULL; new_job->sock = sock; apr_lock_acquire(allowed_globals.jobmutex); if (allowed_globals.jobtail != NULL) allowed_globals.jobtail->next = new_job; allowed_globals.jobtail = new_job; if (!allowed_globals.jobhead) allowed_globals.jobhead = new_job; allowed_globals.jobcount++; ReleaseSemaphore(allowed_globals.jobsemaphore, 1, NULL); apr_lock_release(allowed_globals.jobmutex);}static int remove_job(void){ joblist *job; int sock; WaitForSingleObject(allowed_globals.jobsemaphore, INFINITE); apr_lock_acquire(allowed_globals.jobmutex); if (shutdown_in_progress && !allowed_globals.jobhead) { apr_lock_release(allowed_globals.jobmutex); return (-1); } job = allowed_globals.jobhead; ap_assert(job); allowed_globals.jobhead = job->next; if (allowed_globals.jobhead == NULL) allowed_globals.jobtail = NULL; apr_lock_release(allowed_globals.jobmutex); sock = job->sock; free(job); return (sock);}static void win9x_accept(void * dummy){ int requests_this_child = 0; struct timeval tv; fd_set main_fds; int wait_time = 1; int csd; SOCKET nsd = INVALID_SOCKET; struct sockaddr_in sa_client; int count_select_errors = 0; int rc; int clen; ap_listen_rec *lr; struct fd_set listenfds; SOCKET listenmaxfd = INVALID_SOCKET; /* Setup the listeners * ToDo: Use apr_poll() */ FD_ZERO(&listenfds); for (lr = ap_listeners; lr; lr = lr->next) { if (lr->sd != NULL) { apr_os_sock_get(&nsd, lr->sd); FD_SET(nsd, &listenfds); if (listenmaxfd == INVALID_SOCKET || nsd > listenmaxfd) { listenmaxfd = nsd; } } } head_listener = ap_listeners; while (!shutdown_in_progress) { if (ap_max_requests_per_child && (requests_this_child > ap_max_requests_per_child)) { break; } tv.tv_sec = wait_time; tv.tv_usec = 0; memcpy(&main_fds, &listenfds, sizeof(fd_set)); rc = select(listenmaxfd + 1, &main_fds, NULL, NULL, &tv); if (rc == 0 || (rc == SOCKET_ERROR && APR_STATUS_IS_EINTR(apr_get_netos_error()))) { count_select_errors = 0; /* reset count of errors */ continue; } else if (rc == SOCKET_ERROR) { /* A "real" error occurred, log it and increment the count of * select errors. This count is used to ensure we don't go into * a busy loop of continuous errors. */ ap_log_error(APLOG_MARK, APLOG_INFO, apr_get_netos_error(), server_conf, "select failed with error %d", apr_get_netos_error()); count_select_errors++; if (count_select_errors > MAX_SELECT_ERRORS) { shutdown_in_progress = 1; ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_netos_error(), server_conf, "Too many errors in select loop. Child process exiting."); break; } } else { ap_listen_rec *lr; lr = find_ready_listener(&main_fds); if (lr != NULL) { /* fetch the native socket descriptor */ apr_os_sock_get(&nsd, lr->sd); } } do { clen = sizeof(sa_client); csd = accept(nsd, (struct sockaddr *) &sa_client, &clen); if (csd == INVALID_SOCKET) { csd = -1; } } 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(), server_conf, "accept: (client socket)"); } } else { add_job(csd); requests_this_child++; } } SetEvent(exit_event);}static PCOMP_CONTEXT win9x_get_connection(PCOMP_CONTEXT context){ int len; if (context == NULL) { /* allocate the completion context and the transaction pool */ context = apr_pcalloc(pconf, sizeof(COMP_CONTEXT)); if (!context) { ap_log_error(APLOG_MARK,APLOG_ERR, apr_get_os_error(), server_conf, "win9x_get_connection: apr_pcalloc() failed. Process will exit."); return NULL; } apr_pool_create(&context->ptrans, pconf); } while (1) { apr_pool_clear(context->ptrans); context->accept_socket = remove_job(); if (context->accept_socket == -1) { 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(), 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(), server_conf, "getpeername failed"); memset(&context->sa_client, '\0', sizeof(context->sa_client)); } /* do we NEED_DUPPED_CSD ?? */ 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. */static void winnt_accept(void *listen_socket) { static int num_completion_contexts = 0; PCOMP_CONTEXT pCompContext; DWORD BytesRead; SOCKET nlsd; int lasterror; nlsd = (SOCKET) listen_socket; while (1) { pCompContext = NULL; /* Grab a context off the queue */ apr_lock_acquire(qlock); if (qhead) { pCompContext = qhead; qhead = qhead->next; if (!qhead) qtail = NULL; } apr_lock_release(qlock); /* If we failed to grab a context off the queue, alloc one out of * the child pool. There may be up to ap_threads_per_child contexts * in the system at once. */ if (!pCompContext) { if (num_completion_contexts >= ap_threads_per_child) { static int reported = 0; if (!reported) { ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, server_conf, "Server ran out of threads to serve requests. Consider " "raising the ThreadsPerChild setting"); reported = 1; } Sleep(500); continue; } pCompContext = (PCOMP_CONTEXT) apr_pcalloc(pchild, sizeof(COMP_CONTEXT)); pCompContext->Overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (pCompContext->Overlapped.hEvent == NULL) { ap_log_error(APLOG_MARK,APLOG_ERR, apr_get_os_error(), server_conf, "winnt_accept: CreateEvent failed. Process will exit."); // return -1; } pCompContext->accept_socket = INVALID_SOCKET; num_completion_contexts++; } again: /* Create and initialize the accept socket */ if (pCompContext->accept_socket == INVALID_SOCKET) { pCompContext->accept_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (pCompContext->accept_socket == INVALID_SOCKET) { ap_log_error(APLOG_MARK,APLOG_ERR, apr_get_netos_error(), server_conf, "winnt_accept: socket() failed. Process will exit."); // return -1; } /* SO_UPDATE_ACCEPT_CONTEXT is required for shutdown() to work */ if (setsockopt(pCompContext->accept_socket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char *)&nlsd, sizeof(nlsd))) { ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_netos_error(), server_conf, "setsockopt(SO_UPDATE_ACCEPT_CONTEXT) failed."); /* Not a failure condition. Keep running. */ } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -