]> granicus.if.org Git - apache/blob - server/mpm/winnt/mpm_winnt.c
Get rid of dependency on os/win32/getopt.c & .h
[apache] / server / mpm / winnt / mpm_winnt.c
1 /* ====================================================================
2  * Copyright (c) 1995-1999 The Apache Group.  All rights reserved.
3  * 
4  * Redistribution and use in source and binary forms, with or without 
5  * modification, are permitted provided that the following conditions 
6  * are met: 
7  * 
8  * 1. Redistributions of source code must retain the above copyright 
9  *    notice, this list of conditions and the following disclaimer.  
10  * 
11  * 2. Redistributions in binary form must reproduce the above copyright 
12  *    notice, this list of conditions and the following disclaimer in 
13  *    the documentation and/or other materials provided with the 
14  *    distribution. 
15  * 
16  * 3. All advertising materials mentioning features or use of this 
17  *    software must display the following acknowledgment: 
18  *    "This product includes software developed by the Apache Group 
19  *    for use in the Apache HTTP server project (http://www.apache.org/)." 
20  * 
21  * 4. The names "Apache Server" and "Apache Group" must not be used to 
22  *    endorse or promote products derived from this software without 
23  *    prior written permission. For written permission, please contact 
24  *    apache@apache.org. 
25  * 
26  * 5. Products derived from this software may not be called "Apache" 
27  *    nor may "Apache" appear in their names without prior written 
28  *    permission of the Apache Group. 
29  * 
30  * 6. Redistributions of any form whatsoever must retain the following 
31  *    acknowledgment: 
32  *    "This product includes software developed by the Apache Group 
33  *    for use in the Apache HTTP server project (http://www.apache.org/)." 
34  * 
35  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY 
36  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
37  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
38  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR 
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
41  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
42  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
43  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
44  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
45  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
46  * OF THE POSSIBILITY OF SUCH DAMAGE. 
47  * ==================================================================== 
48  * 
49  * This software consists of voluntary contributions made by many 
50  * individuals on behalf of the Apache Group and was originally based 
51  * on public domain software written at the National Center for 
52  * Supercomputing Applications, University of Illinois, Urbana-Champaign. 
53  * For more information on the Apache Group and the Apache HTTP server 
54  * project, please see <http://www.apache.org/>. 
55  * 
56  */ 
57  
58 #define CORE_PRIVATE 
59 #include "apr_portable.h"
60 #include "httpd.h" 
61 #include "http_main.h" 
62 #include "http_log.h" 
63 #include "http_config.h"        /* for read_config */ 
64 #include "http_core.h"          /* for get_remote_host */ 
65 #include "http_connection.h"
66 #include "ap_mpm.h"
67 #include "ap_config.h"
68 #include "ap_listen.h"
69 #include "mpm_default.h"
70 #include "../os/win32/iol_socket.h"
71 #include "winnt.h"
72
73
74 /*
75  * Definitions of WINNT MPM specific config globals
76  */
77
78 static char *mpm_pid_fname=NULL;
79 static int ap_threads_per_child = 0;
80 static int workers_may_exit = 0;
81 static int max_requests_per_child = 0;
82
83 static struct fd_set listenfds;
84 static int num_listenfds = 0;
85 static SOCKET listenmaxfd = INVALID_SOCKET;
86
87 static ap_context_t *pconf;             /* Pool for config stuff */
88
89 static char ap_coredump_dir[MAX_STRING_LEN];
90
91 static server_rec *server_conf;
92 HANDLE AcceptExCompPort = NULL;
93
94 static int one_process = 0;
95
96 static OSVERSIONINFO osver; /* VER_PLATFORM_WIN32_NT */
97
98 int ap_max_requests_per_child=0;
99 int ap_daemons_to_start=0;
100
101 event *exit_event;
102 ap_lock_t *start_mutex;
103 int my_pid;
104 int parent_pid;
105
106
107 /* A bunch or routines from os/win32/multithread.c that need to be merged into APR
108  * or thrown out entirely...
109  */
110
111 static int
112 map_rv(int rv)
113 {
114     switch(rv)
115     {
116     case WAIT_OBJECT_0:
117     case WAIT_ABANDONED:
118         return(MULTI_OK);
119     case WAIT_TIMEOUT:
120         return(MULTI_TIMEOUT);
121     case WAIT_FAILED:
122         return(MULTI_ERR);
123     default:
124         ap_assert(0);
125     }
126
127     ap_assert(0);
128     return(0);
129 }
130
131 typedef void semaphore;
132 typedef void event;
133
134 static semaphore *
135 create_semaphore(int initial)
136 {
137     return(CreateSemaphore(NULL, initial, 1000000, NULL));
138 }
139
140 static int acquire_semaphore(semaphore *semaphore_id)
141 {
142     int rv;
143     
144     rv = WaitForSingleObject(semaphore_id, INFINITE);
145     
146     return(map_rv(rv));
147 }
148
149 static int release_semaphore(semaphore *semaphore_id)
150 {
151     return(ReleaseSemaphore(semaphore_id, 1, NULL));
152 }
153
154 static void destroy_semaphore(semaphore *semaphore_id)
155 {
156     CloseHandle(semaphore_id);
157 }
158
159
160 static event *
161 create_event(int manual, int initial, char *name)
162 {
163     return(CreateEvent(NULL, manual, initial, name));
164 }
165
166 static event *
167 open_event(char *name)
168 {
169     return(OpenEvent(EVENT_ALL_ACCESS, FALSE, name));
170 }
171
172
173 static int acquire_event(event *event_id)
174 {
175     int rv;
176     
177     rv = WaitForSingleObject(event_id, INFINITE);
178     
179     return(map_rv(rv));
180 }
181
182 static int set_event(event *event_id)
183 {
184     return(SetEvent(event_id));
185 }
186
187 static int reset_event(event *event_id)
188 {
189     return(ResetEvent(event_id));
190 }
191
192
193 static void destroy_event(event *event_id)
194 {
195     CloseHandle(event_id);
196 }
197
198 /*
199  * The Win32 call WaitForMultipleObjects will only allow you to wait for 
200  * a maximum of MAXIMUM_WAIT_OBJECTS (current 64).  Since the threading 
201  * model in the multithreaded version of apache wants to use this call, 
202  * we are restricted to a maximum of 64 threads.  This is a simplistic 
203  * routine that will increase this size.
204  */
205 static DWORD wait_for_many_objects(DWORD nCount, CONST HANDLE *lpHandles, 
206                             DWORD dwSeconds)
207 {
208     time_t tStopTime;
209     DWORD dwRet = WAIT_TIMEOUT;
210     DWORD dwIndex=0;
211     BOOL bFirst = TRUE;
212   
213     tStopTime = time(NULL) + dwSeconds;
214   
215     do {
216         if (!bFirst)
217             Sleep(1000);
218         else
219             bFirst = FALSE;
220           
221         for (dwIndex = 0; dwIndex * MAXIMUM_WAIT_OBJECTS < nCount; dwIndex++) {
222             dwRet = WaitForMultipleObjects(
223                         min(MAXIMUM_WAIT_OBJECTS, 
224                             nCount - (dwIndex * MAXIMUM_WAIT_OBJECTS)),
225                         lpHandles + (dwIndex * MAXIMUM_WAIT_OBJECTS), 
226                         0, 0);
227                                            
228             if (dwRet != WAIT_TIMEOUT) {                                          
229               break;
230             }
231         }
232     } while((time(NULL) < tStopTime) && (dwRet == WAIT_TIMEOUT));
233     
234     return dwRet;
235 }
236
237 /*
238  * Signalling Apache on NT.
239  *
240  * Under Unix, Apache can be told to shutdown or restart by sending various
241  * signals (HUP, USR, TERM). On NT we don't have easy access to signals, so
242  * we use "events" instead. The parent apache process goes into a loop
243  * where it waits forever for a set of events. Two of those events are
244  * called
245  *
246  *    apPID_shutdown
247  *    apPID_restart
248  *
249  * (where PID is the PID of the apache parent process). When one of these
250  * is signalled, the Apache parent performs the appropriate action. The events
251  * can become signalled through internal Apache methods (e.g. if the child
252  * finds a fatal error and needs to kill its parent), via the service
253  * control manager (the control thread will signal the shutdown event when
254  * requested to stop the Apache service), from the -k Apache command line,
255  * or from any external program which finds the Apache PID from the
256  * httpd.pid file.
257  *
258  * The signal_parent() function, below, is used to signal one of these events.
259  * It can be called by any child or parent process, since it does not
260  * rely on global variables.
261  *
262  * On entry, type gives the event to signal. 0 means shutdown, 1 means 
263  * graceful restart.
264  */
265
266 static void signal_parent(int type)
267 {
268     HANDLE e;
269     char *signal_name;
270     extern char signal_shutdown_name[];
271     extern char signal_restart_name[];
272
273     /* after updating the shutdown_pending or restart flags, we need
274      * to wake up the parent process so it can see the changes. The
275      * parent will normally be waiting for either a child process
276      * to die, or for a signal on the "spache-signal" event. So set the
277      * "apache-signal" event here.
278      */
279     if (one_process) {
280         return;
281     }
282
283     switch(type) {
284     case 0: signal_name = signal_shutdown_name; break;
285     case 1: signal_name = signal_restart_name; break;
286     default: return;
287     }
288
289     e = OpenEvent(EVENT_ALL_ACCESS, FALSE, signal_name);
290     if (!e) {
291         /* Um, problem, can't signal the parent, which means we can't
292          * signal ourselves to die. Ignore for now...
293          */
294         ap_log_error(APLOG_MARK, APLOG_EMERG, GetLastError(), server_conf,
295             "OpenEvent on %s event", signal_name);
296         return;
297     }
298     if (SetEvent(e) == 0) {
299         /* Same problem as above */
300         ap_log_error(APLOG_MARK, APLOG_EMERG, GetLastError(), server_conf,
301             "SetEvent on %s event", signal_name);
302         CloseHandle(e);
303         return;
304     }
305     CloseHandle(e);
306 }
307 void ap_start_shutdown(void)
308 {
309     signal_parent(0);
310 }
311 void ap_start_restart(int graceful)
312 {
313     signal_parent(1);
314 }
315
316 static int volatile is_graceful = 0;
317 API_EXPORT(int) ap_graceful_stop_signalled(void)
318 {
319     return is_graceful;
320 }
321
322 /*
323  * Routines that deal with sockets, some are WIN32 specific...
324  */
325 static int s_iInitCount = 0;
326 static int AMCSocketInitialize(void)
327 {
328     int iVersionRequested;
329     WSADATA wsaData;
330     int err;
331
332     if (s_iInitCount > 0) {
333         s_iInitCount++;
334         return (0);
335     }
336     else if (s_iInitCount < 0)
337         return (s_iInitCount);
338
339     /* s_iInitCount == 0. Do the initailization */
340     iVersionRequested = MAKEWORD(2, 0);
341     err = WSAStartup((WORD) iVersionRequested, &wsaData);
342     if (err) {
343         s_iInitCount = -1;
344         return (s_iInitCount);
345     }
346     if (LOBYTE(wsaData.wVersion) != 1 ||
347         HIBYTE(wsaData.wVersion) != 1) {
348         s_iInitCount = -2;
349         WSACleanup();
350         return (s_iInitCount);
351     }
352
353     s_iInitCount++;
354     return (s_iInitCount);
355
356 }
357 static void AMCSocketCleanup(void)
358 {
359     if (--s_iInitCount == 0)
360         WSACleanup();
361     return;
362 }
363
364 static void sock_disable_nagle(int s) /* ZZZ abstract */
365 {
366     /* The Nagle algorithm says that we should delay sending partial
367      * packets in hopes of getting more data.  We don't want to do
368      * this; we are not telnet.  There are bad interactions between
369      * persistent connections and Nagle's algorithm that have very severe
370      * performance penalties.  (Failing to disable Nagle is not much of a
371      * problem with simple HTTP.)
372      *
373      * In spite of these problems, failure here is not a shooting offense.
374      */
375     int just_say_no = 1;
376
377     if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *) &just_say_no,
378                    sizeof(int)) < 0) {
379         ap_log_error(APLOG_MARK, APLOG_WARNING, APR_SUCCESS, server_conf,
380                     "setsockopt: (TCP_NODELAY)");
381     }
382 }
383
384 /*
385  * Routines to deal with managing the list of listening sockets.
386  */
387 static ap_listen_rec *head_listener;
388 static ap_inline ap_listen_rec *find_ready_listener(fd_set * main_fds)
389 {
390     ap_listen_rec *lr;
391     SOCKET nsd;
392
393     for (lr = head_listener; lr ; lr = lr->next) {
394         ap_get_os_sock(&nsd, lr->sd);
395         if (FD_ISSET(nsd, main_fds)) {
396             head_listener = lr->next;
397             if (head_listener == NULL)
398                 head_listener = ap_listeners;
399
400             return (lr);
401         }
402     }
403     return NULL;
404 }
405 static int setup_listeners(server_rec *s)
406 {
407     ap_listen_rec *lr;
408     int num_listeners = 0;
409     SOCKET nsd;
410
411     /* Setup the listeners */
412     FD_ZERO(&listenfds);
413
414     if (ap_listen_open(s->process, s->port)) {
415        return 0;
416     }
417     for (lr = ap_listeners; lr; lr = lr->next) {
418         num_listeners++;
419         if (lr->sd != NULL) {
420             ap_get_os_sock(&nsd, lr->sd);
421             FD_SET(nsd, &listenfds);
422             if (listenmaxfd == INVALID_SOCKET || nsd > listenmaxfd) {
423                 listenmaxfd = nsd;
424             }
425         }
426         lr->count = 0;
427     }
428
429     head_listener = ap_listeners;
430
431     return num_listeners;
432 }
433
434 static int setup_inherited_listeners(server_rec *s)
435 {
436     WSAPROTOCOL_INFO WSAProtocolInfo;
437     HANDLE pipe;
438     ap_listen_rec *lr;
439     DWORD BytesRead;
440     int num_listeners = 0;
441     SOCKET nsd;
442
443     /* Setup the listeners */
444     FD_ZERO(&listenfds);
445
446     /* Set up a default listener if necessary */
447
448     if (ap_listeners == NULL) {
449         ap_listen_rec *lr;
450         lr = ap_palloc(s->process->pool, sizeof(ap_listen_rec));
451         if (!lr)
452             return 0;
453         lr->sd = NULL;
454         lr->next = ap_listeners;
455         ap_listeners = lr;
456     }
457
458     /* Open the pipe to the parent process to receive the inherited socket
459      * data. The sockets have been set to listening in the parent process.
460      */
461     pipe = GetStdHandle(STD_INPUT_HANDLE);
462     for (lr = ap_listeners; lr; lr = lr->next) {
463         if (!ReadFile(pipe, &WSAProtocolInfo, sizeof(WSAPROTOCOL_INFO), 
464                       &BytesRead, (LPOVERLAPPED) NULL)) {
465             ap_log_error(APLOG_MARK, APLOG_CRIT, GetLastError(), server_conf,
466                          "setup_inherited_listeners: Unable to read socket data from parent");
467             signal_parent(0);   /* tell parent to die */
468             exit(1);
469         }
470         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, APR_SUCCESS, server_conf,
471                      "BytesRead = %d WSAProtocolInfo = %x20", BytesRead, WSAProtocolInfo);
472         nsd = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,
473                         &WSAProtocolInfo, 0, 0);
474         if (nsd == INVALID_SOCKET) {
475             ap_log_error(APLOG_MARK, APLOG_CRIT, WSAGetLastError(), server_conf,
476                          "setup_inherited_listeners: WSASocket failed to open the inherited socket.");
477             signal_parent(0);   /* tell parent to die */
478             exit(1);
479         }
480         if (nsd >= 0) {
481             FD_SET(nsd, &listenfds);
482             if (listenmaxfd == INVALID_SOCKET || nsd > listenmaxfd) {
483                 listenmaxfd = nsd;
484             }
485         }
486 //        ap_register_cleanup(p, (void *)lr->sd, socket_cleanup, ap_null_cleanup);
487         ap_put_os_sock(&lr->sd, &nsd, pconf);
488         lr->count = 0;
489     }
490     CloseHandle(pipe);
491
492
493     for (lr = ap_listeners; lr; lr = lr->next) {
494         num_listeners++;
495     }
496
497     head_listener = ap_listeners;
498
499     return num_listeners;
500 }
501
502
503 /**********************************************************************
504  * Multithreaded implementation
505  *
506  * This code is fairly specific to Win32.
507  *
508  * The model used to handle requests is a set of threads. One "main"
509  * thread listens for new requests. When something becomes
510  * available, it does a select and places the newly available socket
511  * onto a list of "jobs" (add_job()). Then any one of a fixed number
512  * of "worker" threads takes the top job off the job list with
513  * remove_job() and handles that connection to completion. After
514  * the connection has finished the thread is free to take another
515  * job from the job list.
516  *
517  * In the code, the "main" thread is running within the worker_main()
518  * function. The first thing this function does is create the
519  * worker threads, which operate in the child_sub_main() function. The
520  * main thread then goes into a loop within worker_main() where they
521  * do a select() on the listening sockets. The select times out once
522  * per second so that the thread can check for an "exit" signal
523  * from the parent process (see below). If this signal is set, the 
524  * thread can exit, but only after it has accepted all incoming
525  * connections already in the listen queue (since Win32 appears
526  * to through away listened but unaccepted connections when a 
527  * process dies).
528  *
529  * Because the main and worker threads exist within a single process
530  * they are vulnerable to crashes or memory leaks (crashes can also
531  * be caused within modules, of course). There also needs to be a 
532  * mechanism to perform restarts and shutdowns. This is done by
533  * creating the main & worker threads within a subprocess. A
534  * main process (the "parent process") creates one (or more) 
535  * processes to do the work, then the parent sits around waiting
536  * for the working process to die, in which case it starts a new
537  * one. The parent process also handles restarts (by creating
538  * a new working process then signalling the previous working process 
539  * exit ) and shutdowns (by signalling the working process to exit).
540  * The parent process operates within the master_main() function. This
541  * process also handles requests from the service manager (NT only).
542  *
543  * Signalling between the parent and working process uses a Win32
544  * event. Each child has a unique name for the event, which is
545  * passed to it with the -Z argument when the child is spawned. The
546  * parent sets (signals) this event to tell the child to die.
547  * At present all children do a graceful die - they finish all
548  * current jobs _and_ empty the listen queue before they exit.
549  * A non-graceful die would need a second event. The -Z argument in
550  * the child is also used to create the shutdown and restart events,
551  * since the prefix (apPID) contains the parent process PID.
552  *
553  * The code below starts with functions at the lowest level -
554  * worker threads, and works up to the top level - the main()
555  * function of the parent process.
556  *
557  * The scoreboard (in process memory) contains details of the worker
558  * threads (within the active working process). There is no shared
559  * "scoreboard" between processes, since only one is ever active
560  * at once (or at most, two, when one has been told to shutdown but
561  * is processes outstanding requests, and a new one has been started).
562  * This is controlled by a "start_mutex" which ensures only one working
563  * process is active at once.
564  **********************************************************************/
565
566 int service_init()
567 {
568 /*
569     common_init();
570  
571     ap_cpystrn(ap_server_root, HTTPD_ROOT, sizeof(ap_server_root));
572     if (ap_registry_get_service_conf(pconf, ap_server_confname, sizeof(ap_server_confname),
573                                      ap_server_argv0))
574         return FALSE;
575
576     ap_setup_prelinked_modules();
577     server_conf = ap_read_config(pconf, ptrans, ap_server_confname);
578     ap_log_pid(pconf, ap_pid_fname);
579     post_parse_init();
580 */
581     return TRUE;
582 }
583
584 /*
585  * Definition of jobs, shared by main and worker threads.
586  */
587
588 typedef struct joblist_s {
589     struct joblist_s *next;
590     int sock;
591 } joblist;
592
593 /*
594  * Globals common to main and worker threads. This structure is not
595  * used by the parent process.
596  */
597
598 typedef struct globals_s {
599     semaphore *jobsemaphore;
600     joblist *jobhead;
601     joblist *jobtail;
602     ap_lock_t *jobmutex;
603     int jobcount;
604 } globals;
605
606 globals allowed_globals =
607 {NULL, NULL, NULL, NULL, 0};
608 #define MAX_SELECT_ERRORS 100
609 #define PADDED_ADDR_SIZE sizeof(SOCKADDR_IN)+16
610
611 /* Windows 9x specific code...
612  * Accept processing for on Windows 95/98 uses a producer/consumer queue 
613  * model. A single thread accepts connections and queues the accepted socket 
614  * to the accept queue for consumption by a pool of worker threads.
615  *
616  * win9x_get_connection()
617  *    Calls remove_job() to pull a job from the accept queue. All the worker 
618  *    threads block on remove_job.
619  * accept_and_queue_connections()
620  *    The accept threads runs this function, which accepts connections off 
621  *    the network and calls add_job() to queue jobs to the accept_queue.
622  * add_job()/remove_job()
623  *    Add or remove an accepted socket from the list of sockets 
624  *    connected to clients. allowed_globals.jobmutex protects
625  *    against multiple concurrent access to the linked list of jobs.
626  */
627 static void add_job(int sock)
628 {
629     joblist *new_job;
630
631     new_job = (joblist *) malloc(sizeof(joblist));
632     if (new_job == NULL) {
633         fprintf(stderr, "Ouch!  Out of memory in add_job()!\n");
634         return;
635     }
636     new_job->next = NULL;
637     new_job->sock = sock;
638
639     ap_lock(allowed_globals.jobmutex);
640
641     if (allowed_globals.jobtail != NULL)
642         allowed_globals.jobtail->next = new_job;
643     allowed_globals.jobtail = new_job;
644     if (!allowed_globals.jobhead)
645         allowed_globals.jobhead = new_job;
646     allowed_globals.jobcount++;
647     release_semaphore(allowed_globals.jobsemaphore);
648
649     ap_unlock(allowed_globals.jobmutex);
650 }
651
652 static int remove_job(void)
653 {
654     joblist *job;
655     int sock;
656
657     acquire_semaphore(allowed_globals.jobsemaphore);
658     ap_lock(allowed_globals.jobmutex);
659
660     if (workers_may_exit && !allowed_globals.jobhead) {
661         ap_unlock(allowed_globals.jobmutex);
662         return (-1);
663     }
664     job = allowed_globals.jobhead;
665     ap_assert(job);
666     allowed_globals.jobhead = job->next;
667     if (allowed_globals.jobhead == NULL)
668         allowed_globals.jobtail = NULL;
669     ap_unlock(allowed_globals.jobmutex);
670     sock = job->sock;
671     free(job);
672
673     return (sock);
674 }
675
676 static void accept_and_queue_connections(void * dummy)
677 {
678     int requests_this_child = 0;
679     struct timeval tv;
680     fd_set main_fds;
681     int wait_time = 1;
682     int csd;
683     int nsd = INVALID_SOCKET;
684     struct sockaddr_in sa_client;
685     int count_select_errors = 0;
686     int rc;
687     int clen;
688
689     while (!workers_may_exit) {
690         if (ap_max_requests_per_child && (requests_this_child > ap_max_requests_per_child)) {
691             break;
692         }
693
694         tv.tv_sec = wait_time;
695         tv.tv_usec = 0;
696         memcpy(&main_fds, &listenfds, sizeof(fd_set));
697
698 //      rc = ap_select(listenmaxfd + 1, &main_fds, NULL, NULL, &tv);
699         rc = select(listenmaxfd + 1, &main_fds, NULL, NULL, &tv);
700
701         if (rc == 0 || (rc == SOCKET_ERROR && h_errno == WSAEINTR)) {
702             count_select_errors = 0;    /* reset count of errors */            
703             continue;
704         }
705         else if (rc == SOCKET_ERROR) {
706             /* A "real" error occurred, log it and increment the count of
707              * select errors. This count is used to ensure we don't go into
708              * a busy loop of continuous errors.
709              */
710             ap_log_error(APLOG_MARK, APLOG_INFO, h_errno, server_conf, 
711                          "select failed with errno %d", h_errno);
712             count_select_errors++;
713             if (count_select_errors > MAX_SELECT_ERRORS) {
714                 workers_may_exit = 1;
715                 ap_log_error(APLOG_MARK, APLOG_ERR, h_errno, server_conf,
716                              "Too many errors in select loop. Child process exiting.");
717                 break;
718             }
719         } else {
720             ap_listen_rec *lr;
721
722             lr = find_ready_listener(&main_fds);
723             if (lr != NULL) {
724                 /* fetch the native socket descriptor */
725                 ap_get_os_sock(&nsd, lr->sd);
726             }
727         }
728
729         do {
730             clen = sizeof(sa_client);
731             csd = accept(nsd, (struct sockaddr *) &sa_client, &clen);
732             if (csd == INVALID_SOCKET) {
733                 csd = -1;
734             }
735         } while (csd < 0 && h_errno == WSAEINTR);
736
737         if (csd < 0) {
738             if (h_errno != WSAECONNABORTED) {
739                 ap_log_error(APLOG_MARK, APLOG_ERR, h_errno, server_conf,
740                             "accept: (client socket)");
741             }
742         }
743         else {
744             add_job(csd);
745             requests_this_child++;
746         }
747     }
748     SetEvent(exit_event);
749 }
750 static PCOMP_CONTEXT win9x_get_connection(PCOMP_CONTEXT context)
751 {
752     int len;
753
754     if (context == NULL) {
755         /* allocate the completion context and the transaction pool */
756         context = ap_pcalloc(pconf, sizeof(COMP_CONTEXT));
757         if (!context) {
758             ap_log_error(APLOG_MARK,APLOG_ERR, GetLastError(), server_conf,
759                          "win9x_get_connection: ap_pcalloc() failed. Process will exit.");
760             return NULL;
761         }
762         ap_create_context(&context->ptrans, pconf);
763     }
764     
765
766     while (1) {
767         ap_clear_pool(context->ptrans);        
768         context->accept_socket = remove_job();
769         if (context->accept_socket == -1) {
770             return NULL;
771         }
772         //ap_note_cleanups_for_socket(ptrans, csd);
773         len = sizeof(struct sockaddr);
774         context->sa_server = ap_palloc(context->ptrans, len);
775         if (getsockname(context->accept_socket, 
776                         context->sa_server, &len)== SOCKET_ERROR) {
777             ap_log_error(APLOG_MARK, APLOG_WARNING, WSAGetLastError(), server_conf, 
778                          "getsockname failed");
779             continue;
780         }
781         len = sizeof(struct sockaddr);
782         context->sa_client = ap_palloc(context->ptrans, len);
783         if ((getpeername(context->accept_socket,
784                          context->sa_client, &len)) == SOCKET_ERROR) {
785             ap_log_error(APLOG_MARK, APLOG_WARNING, h_errno, server_conf, 
786                          "getpeername failed with error %d\n", WSAGetLastError());
787             memset(&context->sa_client, '\0', sizeof(context->sa_client));
788         }
789
790         context->conn_io = ap_bcreate(context->ptrans, B_RDWR);
791
792         /* do we NEED_DUPPED_CSD ?? */
793         
794         return context;
795     }
796 }
797
798 /* 
799  * Windows 2000/NT specific code...
800  * create_and_queue_acceptex_context()
801  * requeue_acceptex_context()
802  * winnt_get_connection()
803  *
804  * TODO: Insert a discussion of 'completion contexts' and what these function do here...
805  */
806 static int create_and_queue_acceptex_context(ap_context_t *_pconf, ap_listen_rec *lr) 
807 {
808     PCOMP_CONTEXT context;
809     DWORD BytesRead;
810     SOCKET nsd;
811     int lasterror;
812     
813     /* allocate the completion context */
814     context = ap_pcalloc(_pconf, sizeof(COMP_CONTEXT));
815     if (!context) {
816         ap_log_error(APLOG_MARK,APLOG_ERR, GetLastError(), server_conf,
817                      "create_and_queue_acceptex_context: ap_pcalloc() failed. Process will exit.");
818         return -1;
819     }
820
821     /* initialize the completion context */
822     context->lr = lr;
823     context->Overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 
824     if (context->Overlapped.hEvent == NULL) {
825         ap_log_error(APLOG_MARK,APLOG_ERR, GetLastError(), server_conf,
826                      "create_and_queue_acceptex_context: CreateEvent() failed. Process will exit.");
827         return -1;
828     }
829     context->accept_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
830     if (context->accept_socket == INVALID_SOCKET) {
831         ap_log_error(APLOG_MARK,APLOG_ERR, WSAGetLastError(), server_conf,
832                      "create_and_queue_acceptex_context: socket() failed. Process will exit.");
833         return -1;
834     }
835     ap_create_context(&context->ptrans, _pconf);
836     context->conn_io = ap_bcreate(context->ptrans, B_RDWR);
837     context->recv_buf = context->conn_io->inbase;
838     context->recv_buf_size = context->conn_io->bufsiz - 2*PADDED_ADDR_SIZE;
839     ap_get_os_sock(&nsd, context->lr->sd);
840
841     /* AcceptEx on the completion context. The completion context will be signaled
842      * when a connection is accepted. */
843     if (!AcceptEx(nsd, context->accept_socket,
844                   context->recv_buf, context->recv_buf_size,
845                   PADDED_ADDR_SIZE, PADDED_ADDR_SIZE,
846                   &BytesRead,
847                   (LPOVERLAPPED) context)) {
848         lasterror = WSAGetLastError();
849         if (lasterror != ERROR_IO_PENDING) {
850             ap_log_error(APLOG_MARK,APLOG_ERR, WSAGetLastError(), server_conf,
851                          "create_and_queue_acceptex_context: AcceptEx failed. Process will exit.");
852             return -1;
853         }
854     }
855     lr->count++;
856
857     return 0;
858 }
859 static ap_inline int requeue_acceptex_context(PCOMP_CONTEXT context) 
860 {
861     DWORD BytesRead;
862     SOCKET nsd;
863     int lasterror;
864     context->lr->count++;
865
866     if (context->accept_socket == -1)
867         context->accept_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
868
869     if (context->accept_socket == INVALID_SOCKET) {
870         ap_log_error(APLOG_MARK,APLOG_ERR, WSAGetLastError(), server_conf,
871                      "requeue_acceptex_context: socket() failed. Process will exit.");
872         return -1;
873     }
874
875     ap_clear_pool(context->ptrans);
876     context->conn_io = ap_bcreate(context->ptrans, B_RDWR);
877     context->recv_buf = context->conn_io->inbase;
878     context->recv_buf_size = context->conn_io->bufsiz - 2*PADDED_ADDR_SIZE;
879     ap_get_os_sock(&nsd, context->lr->sd);
880
881     if (!AcceptEx(nsd, 
882                   context->accept_socket, 
883                   context->recv_buf, context->recv_buf_size,
884                   PADDED_ADDR_SIZE, PADDED_ADDR_SIZE,
885                   &BytesRead, (LPOVERLAPPED) context)) {
886         lasterror = WSAGetLastError();
887         if (lasterror != ERROR_IO_PENDING) {
888             ap_log_error(APLOG_MARK,APLOG_ERR, WSAGetLastError(), server_conf,
889                          "requeue_acceptex_context: AcceptEx failed. Leaving the process running.");
890             return -1;
891         }
892     }
893     return 0;
894 }
895 static PCOMP_CONTEXT winnt_get_connection(PCOMP_CONTEXT context)
896 {
897     int requests_this_child = 0;
898     int rc;
899
900     LPOVERLAPPED pol;
901     DWORD CompKey;
902     DWORD BytesRead;
903
904     if (context != NULL) {
905         context->accept_socket = -1; /* Don't reuse the socket */
906         if (requeue_acceptex_context(context) == -1) {
907             if (context->accept_socket != -1)
908                 closesocket(context->accept_socket);
909             CloseHandle(context->Overlapped.hEvent);
910             return NULL;
911         }
912     }
913
914     rc = GetQueuedCompletionStatus(AcceptExCompPort,
915                                    &BytesRead,
916                                    &CompKey,
917                                    &pol,
918                                    INFINITE);
919     context = (PCOMP_CONTEXT) pol;
920     if (CompKey == 999) {
921         if (context) {
922             closesocket(context->accept_socket);
923             CloseHandle(context->Overlapped.hEvent);
924             return NULL;
925         }
926     }
927
928     ap_lock(allowed_globals.jobmutex);
929
930     context->lr->count--;
931     if (context->lr->count < 2) {
932         if (create_and_queue_acceptex_context(pconf, context->lr) == -1) {
933             ap_log_error(APLOG_MARK,APLOG_ERR, GetLastError(), server_conf,
934                          "Unable to create an AcceptEx completion context -- process will exit");
935             closesocket(context->accept_socket);
936             CloseHandle(context->Overlapped.hEvent);
937             return NULL;
938         }
939     }
940     ap_unlock(allowed_globals.jobmutex);
941
942     context->conn_io->incnt = BytesRead;
943
944     GetAcceptExSockaddrs(context->recv_buf, 
945                          context->recv_buf_size,
946                          PADDED_ADDR_SIZE,
947                          PADDED_ADDR_SIZE,
948                          &context->sa_server,
949                          &context->sa_server_len,
950                          &context->sa_client,
951                          &context->sa_client_len);
952
953     return context;
954 /*
955     CloseHandle(context->Overlapped.hEvent);
956     SetEvent(exit_event);
957     return NULL;
958 */
959 }
960 /*
961  * child_main() - this is the main loop for the worker threads
962  *
963  * Each thread runs within this function. They wait within remove_job()
964  * for a job to become available, then handle all the requests on that
965  * connection until it is closed, then return to remove_job().
966  *
967  * The worker thread will exit when it removes a job which contains
968  * socket number -1. This provides a graceful thread exit, since
969  * it will never exit during a connection.
970  *
971  * This code in this function is basically equivalent to the child_main()
972  * from the multi-process (Unix) environment, except that we
973  *
974  *  - do not call child_init_modules (child init API phase)
975  *  - block in remove_job, and when unblocked we have an already
976  *    accepted socket, instead of blocking on a mutex or select().
977  */
978 static void child_main(int child_num)
979 {
980     PCOMP_CONTEXT context = NULL;
981
982     while (1) {
983         conn_rec *current_conn;
984         ap_iol *iol;
985
986         /* Grab a connection off the network */
987         if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
988             context = win9x_get_connection(context);
989         }
990         else {
991             context = winnt_get_connection(context);
992         }
993
994         if (!context)
995             break;
996
997         /* TODO: Register cleanups for our sockets.*/
998         /* ap_note_cleanups_for_socket(context->ptrans, context->accept_socket); */
999
1000         sock_disable_nagle(context->accept_socket);
1001
1002         iol = win32_attach_socket(context->ptrans, context->accept_socket);
1003         if (iol == NULL) {
1004             ap_log_error(APLOG_MARK, APLOG_ERR, APR_ENOMEM, server_conf,
1005                          "child_main: attach_socket() failed. Continuing...");
1006             closesocket(context->accept_socket);
1007             continue;
1008         }
1009         ap_bpush_iol(context->conn_io, iol);
1010         current_conn = ap_new_connection(context->ptrans, server_conf, context->conn_io,
1011                                          (struct sockaddr_in *) context->sa_client,
1012                                          (struct sockaddr_in *) context->sa_server,
1013                                          child_num);
1014
1015         ap_process_connection(current_conn);
1016     }
1017     SetEvent(exit_event);
1018     /* TODO: Add code to clean-up completion contexts here */
1019 }
1020
1021 static void cleanup_thread(thread **handles, int *thread_cnt, int thread_to_clean)
1022 {
1023     int i;
1024
1025     free_thread(handles[thread_to_clean]);
1026     for (i = thread_to_clean; i < ((*thread_cnt) - 1); i++)
1027         handles[i] = handles[i + 1];
1028     (*thread_cnt)--;
1029 }
1030
1031
1032
1033 /*
1034  * Initialise the signal names, in the global variables signal_name_prefix, 
1035  * signal_restart_name and signal_shutdown_name.
1036  */
1037
1038 #define MAX_SIGNAL_NAME 30  /* Long enough for apPID_shutdown, where PID is an int */
1039 char signal_name_prefix[MAX_SIGNAL_NAME];
1040 char signal_restart_name[MAX_SIGNAL_NAME]; 
1041 char signal_shutdown_name[MAX_SIGNAL_NAME];
1042 static void setup_signal_names(char *prefix)
1043 {
1044     ap_snprintf(signal_name_prefix, sizeof(signal_name_prefix), prefix);    
1045     ap_snprintf(signal_shutdown_name, sizeof(signal_shutdown_name), 
1046         "%s_shutdown", signal_name_prefix);    
1047     ap_snprintf(signal_restart_name, sizeof(signal_restart_name), 
1048         "%s_restart", signal_name_prefix);    
1049 }
1050
1051 /*
1052  * worker_main() is main loop for the child process. The loop in
1053  * this function becomes the controlling thread for the actually working
1054  * threads (which run in a loop in child_sub_main()).
1055  * Globals Used:
1056  *  exit_event, start_mutex, ap_threads_per_child, server_conf,
1057  *  h_errno defined to WSAGetLastError in winsock2.h,
1058  */
1059 static void worker_main()
1060 {
1061     int nthreads = ap_threads_per_child;
1062
1063     thread **child_handles;
1064     int rv;
1065     ap_status_t status;
1066     time_t end_time;
1067     int i;
1068     ap_context_t *pchild;
1069
1070     ap_create_context(&pchild, pconf);
1071
1072 //    ap_restart_time = time(NULL);
1073
1074     /*
1075      * Wait until we have permission to start accepting connections.
1076      * start_mutex is used to ensure that only one child ever
1077      * goes into the listen/accept loop at once.
1078      */
1079     status = ap_lock(start_mutex);
1080     if (status != APR_SUCCESS) {
1081         ap_log_error(APLOG_MARK,APLOG_ERR, status, server_conf,
1082                      "Waiting for start_mutex or exit_event -- process will exit");
1083
1084         ap_destroy_context(pchild);
1085         exit(0);
1086     }
1087
1088     /* Setup the listening sockets */
1089     if (one_process) {
1090         setup_listeners(server_conf);
1091     } else {
1092         /* Get listeners from the parent process */
1093         setup_inherited_listeners(server_conf);
1094     }
1095     if (listenmaxfd == INVALID_SOCKET) {
1096         /* Help, no sockets were made, better log something and exit */
1097         ap_log_error(APLOG_MARK, APLOG_CRIT, h_errno, NULL,
1098                     "No sockets were created for listening");
1099         signal_parent(0);       /* tell parent to die */
1100         ap_destroy_context(pchild);
1101         exit(0);
1102     }
1103
1104     allowed_globals.jobsemaphore = create_semaphore(0);
1105     ap_create_lock(&allowed_globals.jobmutex, APR_MUTEX, APR_INTRAPROCESS, NULL, pchild);
1106
1107     if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1108         /* Win9X (Windows 95/98)
1109          * Create the worker thread pool... */
1110         child_handles = (thread *) alloca(nthreads * sizeof(int));
1111         for (i = 0; i < nthreads; i++) {
1112             child_handles[i] = create_thread((void (*)(void *)) child_main, (void *) i);
1113         }
1114         /* Create the accept thread */
1115         create_thread((void (*)(void *)) accept_and_queue_connections, (void *) NULL);
1116     } /* Windows 95/98 */
1117     else {
1118         /* Windows NT/2000 
1119          * Windows NT/2000 have nifty network I/O routines not available in 
1120          * Windows 95/98 like AcceptEx, TransmitFile and CompletionPorts. If we want to use
1121          * them, we gotta do things differently. */
1122         ap_listen_rec *lr;
1123         SOCKET nsd;
1124
1125         /* Create the AcceptEx completion port 
1126          * All listeners are associated with the AcceptEx completion port. When a connection
1127          * is accepted, the AcceptEx completion port is signaled and one of the worker threads
1128          * blocked on it will be awakened (in LIFO order) to handle the connection. 
1129          * Note: Experiment with CONCURRENT_ACTIVE_THREADS. A setting of 0 is best for performance
1130          * (only one thread will be 'active', i.e., not blocked on I/O, at any time). This is bad
1131          * if your 'active' threads get caught in computationally intensive tasks... */
1132         AcceptExCompPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,
1133                                                   NULL,
1134                                                   0,
1135                                                   0); /* CONCURRENT ACTIVE THREADS */
1136         if (AcceptExCompPort == NULL) {
1137             ap_log_error(APLOG_MARK,APLOG_ERR, GetLastError(), server_conf,
1138                          "Unable to create the AcceptExCompletionPort -- process will exit");
1139             ap_destroy_context(pchild);
1140             exit(0);
1141         }
1142
1143         /* Associate each listener with the AcceptEx completion port */
1144         for (lr = ap_listeners; lr != NULL; lr = lr->next) {
1145             ap_get_os_sock(&nsd, lr->sd);
1146             if (!CreateIoCompletionPort((HANDLE) nsd, AcceptExCompPort, 0, 0)) {
1147                 ap_log_error(APLOG_MARK,APLOG_ERR, GetLastError(), server_conf,
1148                              "Unable to associate listener with the AcceptExCompletionPort -- process will exit");
1149                 ap_destroy_context(pchild);
1150                 exit(0);
1151             }
1152         }
1153
1154         /* Create the worker thread pool */
1155         child_handles = (thread *) alloca(nthreads * sizeof(int));
1156         for (i = 0; i < nthreads; i++) {
1157             child_handles[i] = create_thread((void (*)(void *)) child_main, (void *) i);
1158         }
1159
1160         /* Create 3 AcceptEx contexts for each listener then queue them to the 
1161          * AcceptEx completion port. */
1162         for (lr = ap_listeners; lr != NULL; lr = lr->next) {
1163             for(i=0; i<2; i++) {
1164                 if (create_and_queue_acceptex_context(pconf, lr) == -1) {
1165                     ap_log_error(APLOG_MARK,APLOG_ERR, GetLastError(), server_conf,
1166                                  "Unable to create an AcceptEx completion context -- process will exit");
1167                     ap_destroy_context(pchild);
1168                     exit(0);
1169                 }
1170             }
1171         }
1172     } /* Windows 2000/NT */
1173
1174     rv = WaitForSingleObject(exit_event, INFINITE);
1175     printf("exit event signalled \n");
1176     ap_log_error(APLOG_MARK,APLOG_INFO, APR_SUCCESS, server_conf,
1177                  "Exit event signaled. Child process is ending.");
1178     workers_may_exit = 1;      
1179
1180     /* Get ready to shutdown and exit */
1181     ap_unlock(start_mutex);
1182
1183     /* Tell the workers to stop */
1184     if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1185         /* Windows 95/98
1186          * Tell the workers to stop */
1187         for (i = 0; i < nthreads; i++) {
1188             add_job(-1);
1189         }
1190     }
1191     else {
1192         /* Windows NT/2000
1193          * Drain any completion contexts and threads waiting for them */
1194         for (i=0; i < nthreads; i++) {
1195             PostQueuedCompletionStatus(AcceptExCompPort, 0, 999, NULL);
1196         }
1197     }
1198
1199     /* Wait for all your children */
1200     end_time = time(NULL) + 180;
1201     while (nthreads) {
1202         rv = wait_for_many_objects(nthreads, child_handles, 
1203                                    end_time - time(NULL));
1204         if (rv != WAIT_TIMEOUT) {
1205             rv = rv - WAIT_OBJECT_0;
1206             ap_assert((rv >= 0) && (rv < nthreads));
1207             cleanup_thread(child_handles, &nthreads, rv);
1208             continue;
1209         }
1210         break;
1211     }
1212
1213     for (i = 0; i < nthreads; i++) {
1214         kill_thread(child_handles[i]);
1215         free_thread(child_handles[i]);
1216     }
1217
1218     destroy_semaphore(allowed_globals.jobsemaphore);
1219     ap_destroy_lock(allowed_globals.jobmutex);
1220
1221     ap_destroy_context(pchild);
1222
1223 }
1224 static HANDLE create_exit_event(const char* event_name)
1225 {
1226     return CreateEvent(NULL, TRUE, FALSE, event_name);
1227 }
1228 /*
1229  * Spawn a child Apache process. The child process has the command line arguments from
1230  * argc and argv[], plus a -Z argument giving the name of an event. The child should
1231  * open and poll or wait on this event. When it is signalled, the child should die.
1232  * prefix is a prefix string for the event name.
1233  * 
1234  * The child_num argument on entry contains a serial number for this child (used to create
1235  * a unique event name). On exit, this number will have been incremented by one, ready
1236  * for the next call. 
1237  *
1238  * On exit, the value pointed to be *ev will contain the event created
1239  * to signal the new child process.
1240  *
1241  * The return value is the handle to the child process if successful, else -1. If -1 is
1242  * returned the error will already have been logged by ap_log_error().
1243  */
1244
1245 /**********************************************************************
1246  * master_main - this is the parent (main) process. We create a
1247  * child process to do the work, then sit around waiting for either
1248  * the child to exit, or a restart or exit signal. If the child dies,
1249  * we just respawn a new one. If we have a shutdown or graceful restart,
1250  * tell the child to die when it is ready. If it is a non-graceful
1251  * restart, force the child to die immediately.
1252  **********************************************************************/
1253
1254 #define MAX_PROCESSES 50 /* must be < MAX_WAIT_OBJECTS-1 */
1255
1256 static void cleanup_process(HANDLE *handles, HANDLE *events, int position, int *processes)
1257 {
1258     int i;
1259     int handle = 0;
1260
1261     CloseHandle(handles[position]);
1262     CloseHandle(events[position]);
1263
1264     handle = (int)handles[position];
1265
1266     for (i = position; i < (*processes)-1; i++) {
1267         handles[i] = handles[i + 1];
1268         events[i] = events[i + 1];
1269     }
1270     (*processes)--;
1271 }
1272
1273 static int create_process(ap_context_t *p, HANDLE *handles, HANDLE *events, int *processes)
1274 {
1275     int rv;
1276     char buf[1024];
1277     char *pCommand;
1278
1279     STARTUPINFO si;           /* Filled in prior to call to CreateProcess */
1280     PROCESS_INFORMATION pi;   /* filled in on call to CreateProces */
1281
1282     ap_listen_rec *lr;
1283     DWORD BytesWritten;
1284     HANDLE hPipeRead = NULL;
1285     HANDLE hPipeWrite = NULL;
1286     SECURITY_ATTRIBUTES sa = {0};  
1287
1288     sa.nLength = sizeof(sa);
1289     sa.bInheritHandle = TRUE;
1290     sa.lpSecurityDescriptor = NULL;
1291
1292     /* Build the command line. Should look something like this:
1293      * C:/apache/bin/apache.exe -f ap_server_confname 
1294      * First, get the path to the executable...
1295      */
1296     rv = GetModuleFileName(NULL, buf, sizeof(buf));
1297     if (rv == sizeof(buf)) {
1298         ap_log_error(APLOG_MARK, APLOG_CRIT, ERROR_BAD_PATHNAME, server_conf,
1299                      "Parent: Path to Apache process too long");
1300         return -1;
1301     } else if (rv == 0) {
1302         ap_log_error(APLOG_MARK, APLOG_CRIT, GetLastError(), server_conf,
1303                      "Parent: GetModuleFileName() returned NULL for current process.");
1304         return -1;
1305     }
1306
1307     //    pCommand = ap_psprintf(p, "\"%s\" -f \"%s\"", buf, ap_server_confname);  
1308     pCommand = ap_psprintf(p, "\"%s\" -f \"%s\"", buf, SERVER_CONFIG_FILE);  
1309
1310     /* Create a pipe to send socket info to the child */
1311     if (!CreatePipe(&hPipeRead, &hPipeWrite, &sa, 0)) {
1312         ap_log_error(APLOG_MARK, APLOG_CRIT, GetLastError(), server_conf,
1313                      "Parent: Unable to create pipe to child process.\n");
1314         return -1;
1315     }
1316
1317     SetEnvironmentVariable("AP_PARENT_PID",ap_psprintf(p,"%d",parent_pid));
1318
1319     /* Give the read in of the pipe (hPipeRead) to the child as stdin. The 
1320      * parent will write the socket data to the child on this pipe.
1321      */
1322     memset(&si, 0, sizeof(si));
1323     memset(&pi, 0, sizeof(pi));
1324     si.cb = sizeof(si);
1325     si.dwFlags     = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
1326     si.wShowWindow = SW_HIDE;
1327     si.hStdInput   = hPipeRead;
1328
1329     if (!CreateProcess(NULL, pCommand, NULL, NULL, 
1330                        TRUE,               /* Inherit handles */
1331                        CREATE_SUSPENDED,   /* Creation flags */
1332                        NULL,               /* Environment block */
1333                        NULL,
1334                        &si, &pi)) {
1335         ap_log_error(APLOG_MARK, APLOG_CRIT, GetLastError(), server_conf,
1336                      "Parent: Not able to create the child process.");
1337         /*
1338          * We must close the handles to the new process and its main thread
1339          * to prevent handle and memory leaks.
1340          */ 
1341         CloseHandle(pi.hProcess);
1342         CloseHandle(pi.hThread);
1343         return -1;
1344     }
1345     else {
1346         HANDLE kill_event;
1347         LPWSAPROTOCOL_INFO  lpWSAProtocolInfo;
1348
1349         ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, server_conf,
1350                      "Parent: Created child process %d", pi.dwProcessId);
1351
1352         SetEnvironmentVariable("AP_PARENT_PID",NULL);
1353
1354         /* Create the exit_event, apCHILD_PID */
1355         kill_event = create_exit_event(ap_psprintf(pconf,"apC%d", pi.dwProcessId));
1356 //CreateEvent(NULL, TRUE, TRUE, ap_psprintf(pconf,"apC%d", pi.dwProcessId)); // exit_event_name...
1357         if (!kill_event) {
1358             ap_log_error(APLOG_MARK, APLOG_CRIT, GetLastError(), server_conf,
1359                          "Parent: Could not create exit event for child process");
1360             CloseHandle(pi.hProcess);
1361             CloseHandle(pi.hThread);
1362             return -1;
1363         }
1364         
1365         /* Assume the child process lives. Update the process and event tables */
1366         handles[*processes] = pi.hProcess;
1367         events[*processes] = kill_event;
1368         (*processes)++;
1369
1370         /* We never store the thread's handle, so close it now. */
1371         ResumeThread(pi.hThread);
1372         CloseHandle(pi.hThread);
1373
1374         /* Run the chain of open sockets. For each socket, duplicate it 
1375          * for the target process then send the WSAPROTOCOL_INFO 
1376          * (returned by dup socket) to the child */
1377         for (lr = ap_listeners; lr; lr = lr->next) {
1378             int nsd;
1379             lpWSAProtocolInfo = ap_pcalloc(p, sizeof(WSAPROTOCOL_INFO));
1380             ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_INFO, APR_SUCCESS, server_conf,
1381                          "Parent: Duplicating socket %d and sending it to child process %d", lr->sd, pi.dwProcessId);
1382             ap_get_os_sock(&nsd,lr->sd);
1383             if (WSADuplicateSocket(nsd, 
1384                                    pi.dwProcessId,
1385                                    lpWSAProtocolInfo) == SOCKET_ERROR) {
1386                 ap_log_error(APLOG_MARK, APLOG_CRIT, h_errno, server_conf,
1387                              "Parent: WSADuplicateSocket failed for socket %d.", lr->sd );
1388                 return -1;
1389             }
1390
1391             if (!WriteFile(hPipeWrite, lpWSAProtocolInfo, (DWORD) sizeof(WSAPROTOCOL_INFO),
1392                            &BytesWritten,
1393                            (LPOVERLAPPED) NULL)) {
1394                 ap_log_error(APLOG_MARK, APLOG_CRIT, GetLastError(), server_conf,
1395                              "Parent: Unable to write duplicated socket %d to the child.", lr->sd );
1396                 return -1;
1397             }
1398             ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, APR_SUCCESS, server_conf,
1399                          "BytesWritten = %d WSAProtocolInfo = %x20", BytesWritten, *lpWSAProtocolInfo);
1400         }
1401     }
1402     CloseHandle(hPipeRead);
1403     CloseHandle(hPipeWrite);        
1404
1405     return 0;
1406 }
1407
1408 /* To share the semaphores with other processes, we need a NULL ACL
1409  * Code from MS KB Q106387
1410  */
1411 static PSECURITY_ATTRIBUTES GetNullACL()
1412 {
1413     PSECURITY_DESCRIPTOR pSD;
1414     PSECURITY_ATTRIBUTES sa;
1415
1416     sa  = (PSECURITY_ATTRIBUTES) LocalAlloc(LPTR, sizeof(SECURITY_ATTRIBUTES));
1417     pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR,
1418                                             SECURITY_DESCRIPTOR_MIN_LENGTH);
1419     if (pSD == NULL || sa == NULL) {
1420         return NULL;
1421     }
1422     if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)
1423         || GetLastError()) {
1424         LocalFree( pSD );
1425         LocalFree( sa );
1426         return NULL;
1427     }
1428     if (!SetSecurityDescriptorDacl(pSD, TRUE, (PACL) NULL, FALSE)
1429         || GetLastError()) {
1430         LocalFree( pSD );
1431         LocalFree( sa );
1432         return NULL;
1433     }
1434     sa->nLength = sizeof(sa);
1435     sa->lpSecurityDescriptor = pSD;
1436     sa->bInheritHandle = TRUE;
1437     return sa;
1438 }
1439
1440 static void CleanNullACL( void *sa ) {
1441     if( sa ) {
1442         LocalFree( ((PSECURITY_ATTRIBUTES)sa)->lpSecurityDescriptor);
1443         LocalFree( sa );
1444     }
1445 }
1446
1447 static int master_main(server_rec *s, HANDLE shutdown_event, HANDLE restart_event)
1448 {
1449     int remaining_children_to_start = ap_daemons_to_start;
1450     int i;
1451     int rv, cld;
1452     int child_num = 0;
1453     int restart_pending = 0;
1454     int shutdown_pending = 0;
1455     int current_live_processes = 0; /* number of child process we know about */
1456
1457     HANDLE process_handles[MAX_PROCESSES];
1458     HANDLE process_kill_events[MAX_PROCESSES];
1459
1460     setup_listeners(s);
1461
1462     /* Create child process 
1463      * Should only be one in this version of Apache for WIN32 
1464      */
1465     while (remaining_children_to_start--) {
1466         if (create_process(pconf, process_handles, process_kill_events, 
1467                            &current_live_processes) < 0) {
1468             ap_log_error(APLOG_MARK, APLOG_CRIT, GetLastError(), server_conf,
1469                          "master_main: create child process failed. Exiting.");
1470             shutdown_pending = 1;
1471             goto die_now;
1472         }
1473     }
1474
1475     /* service_set_status(SERVICE_RUNNING);*/
1476     restart_pending = shutdown_pending = 0;
1477     
1478     /* Wait for shutdown or restart events or for child death */
1479     process_handles[current_live_processes] = shutdown_event;
1480     process_handles[current_live_processes+1] = restart_event;
1481     rv = WaitForMultipleObjects(current_live_processes+2, (HANDLE *)process_handles, 
1482                                 FALSE, INFINITE);
1483     cld = rv - WAIT_OBJECT_0;
1484     if (rv == WAIT_FAILED) {
1485         /* Something serious is wrong */
1486         ap_log_error(APLOG_MARK,APLOG_CRIT, GetLastError(), server_conf,
1487                      "master_main: : WaitForMultipeObjects on process handles and apache-signal -- doing shutdown");
1488         shutdown_pending = 1;
1489     }
1490     else if (rv == WAIT_TIMEOUT) {
1491         /* Hey, this cannot happen */
1492         ap_log_error(APLOG_MARK, APLOG_ERR, GetLastError(), s,
1493                      "master_main: WaitForMultipeObjects with INFINITE wait exited with WAIT_TIMEOUT");
1494         shutdown_pending = 1;
1495     }
1496     else if (cld == current_live_processes) {
1497         /* shutdown_event signalled */
1498         shutdown_pending = 1;
1499         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, APR_SUCCESS, s, 
1500                      "master_main: Shutdown event signaled. Shutting the server down.");
1501         if (ResetEvent(shutdown_event) == 0) {
1502             ap_log_error(APLOG_MARK, APLOG_ERR, GetLastError(), s,
1503                          "ResetEvent(shutdown_event)");
1504         }
1505
1506     }
1507     else if (cld == current_live_processes+1) {
1508         /* restart_event signalled */
1509         int children_to_kill = current_live_processes;
1510         restart_pending = 1;
1511         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, APR_SUCCESS, s, 
1512                      "master_main: Restart event signaled. Doing a graceful restart.");
1513         if (ResetEvent(restart_event) == 0) {
1514             ap_log_error(APLOG_MARK, APLOG_ERR, GetLastError(), s,
1515                          "master_main: ResetEvent(restart_event) failed.");
1516         }
1517         /* Signal each child process to die 
1518          * We are making a big assumption here that the child process, once signaled,
1519          * will REALLY go away. Since this is a restart, we do not want to hold the 
1520          * new child process up waiting for the old child to die. Remove the old 
1521          * child out of the process_handles ap_table_t and hope for the best...
1522          */
1523         for (i = 0; i < children_to_kill; i++) {
1524             /* APD3("master_main: signalling child #%d handle %d to die", i, process_handles[i]); */
1525             if (SetEvent(process_kill_events[i]) == 0)
1526                 ap_log_error(APLOG_MARK, APLOG_ERR, GetLastError(), s,
1527                              "master_main: SetEvent for child process in slot #%d failed", i);
1528             cleanup_process(process_handles, process_kill_events, i, &current_live_processes);
1529         }
1530     } 
1531     else {
1532         /* A child process must have exited because of MaxRequestPerChild being hit
1533          * or a fatal error condition (seg fault, etc.). Remove the dead process 
1534          * from the process_handles and process_kill_events ap_table_t and create a new
1535          * child process.
1536          * TODO: Consider restarting the child immediately without looping through http_main
1537          * and without rereading the configuration. Will need this if we ever support multiple 
1538          * children. One option, create a parent thread which waits on child death and restarts it.
1539          */
1540         restart_pending = 1;
1541         ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, APR_SUCCESS, server_conf, 
1542                      "master_main: Child processed exited (due to MaxRequestsPerChild?). Restarting the child process.");
1543         ap_assert(cld < current_live_processes);
1544         cleanup_process(process_handles, process_kill_events, cld, &current_live_processes);
1545         /* APD2("main_process: child in slot %d died", rv); */
1546         /* restart_child(process_hancles, process_kill_events, cld, &current_live_processes); */
1547     }
1548
1549 die_now:
1550     if (shutdown_pending) {
1551         int tmstart = time(NULL);
1552         /* Signal each child processes to die */
1553         for (i = 0; i < current_live_processes; i++) {
1554             if (SetEvent(process_kill_events[i]) == 0)
1555                 ap_log_error(APLOG_MARK,APLOG_ERR, GetLastError(), server_conf,
1556                              "master_main: SetEvent for child process in slot #%d failed", i);
1557         }
1558
1559         while (current_live_processes && ((tmstart+60) > time(NULL))) {
1560             rv = WaitForMultipleObjects(current_live_processes, (HANDLE *)process_handles, FALSE, 2000);
1561             if (rv == WAIT_TIMEOUT)
1562                 continue;
1563             ap_assert(rv != WAIT_FAILED);
1564             cld = rv - WAIT_OBJECT_0;
1565             ap_assert(rv < current_live_processes);
1566             cleanup_process(process_handles, process_kill_events, cld, &current_live_processes);
1567         }
1568         for (i = 0; i < current_live_processes; i++) {
1569             ap_log_error(APLOG_MARK,APLOG_ERR|APLOG_NOERRNO, APR_SUCCESS, server_conf,
1570                          "forcing termination of child #%d (handle %d)", i, process_handles[i]);
1571             TerminateProcess((HANDLE) process_handles[i], 1);
1572         }
1573         return (0); /* Tell the caller we are shutting down */
1574     }
1575
1576     return (1); /* Tell the caller we want a restart */
1577 }
1578
1579 /* 
1580  * winnt_pre_config() hook
1581  */
1582 static void winnt_pre_config(ap_context_t *pconf, ap_context_t *plog, ap_context_t *ptemp) 
1583 {
1584     char *pid;
1585 #if 0
1586     one_process=1;
1587 #else
1588     one_process = !!getenv("ONE_PROCESS");
1589 #endif
1590
1591     osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1592     GetVersionEx(&osver);
1593
1594     /* AP_PARENT_PID is only valid in the child */
1595     pid = getenv("AP_PARENT_PID");
1596     if (pid) {
1597         /* This is the child */
1598         parent_pid = atoi(pid);
1599         my_pid = getpid();
1600     }
1601     else {
1602         /* This is the parent */
1603         parent_pid = my_pid = getpid();
1604         ap_log_pid(pconf, mpm_pid_fname);
1605     }
1606
1607     ap_listen_pre_config();
1608     ap_daemons_to_start = DEFAULT_NUM_DAEMON;
1609     ap_threads_per_child = DEFAULT_START_THREAD;
1610     mpm_pid_fname = DEFAULT_PIDLOG;
1611     max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;
1612
1613     ap_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
1614
1615 }
1616
1617 static void winnt_post_config(ap_context_t *pconf, ap_context_t *plog, ap_context_t *ptemp, server_rec* server_conf)
1618 {
1619     server_conf = server_conf;
1620 }
1621
1622 API_EXPORT(int) ap_mpm_run(ap_context_t *_pconf, ap_context_t *plog, server_rec *s )
1623 {
1624
1625     char* exit_event_name;
1626
1627 //    time_t tmstart;
1628     HANDLE shutdown_event;      /* used to signal shutdown to parent */
1629     HANDLE restart_event;       /* used to signal a restart to parent */
1630
1631     pconf = _pconf;
1632     server_conf = s;
1633
1634     if ((parent_pid != my_pid) || one_process) {
1635         /* Child process */
1636         AMCSocketInitialize();
1637         exit_event_name = ap_psprintf(pconf, "apC%d", my_pid);
1638         setup_signal_names(ap_psprintf(pconf,"ap%d", parent_pid));
1639         if (one_process) {
1640             ap_create_lock(&start_mutex,APR_MUTEX, APR_CROSS_PROCESS,signal_name_prefix,pconf);
1641             exit_event = create_exit_event(exit_event_name);
1642         }
1643         else {
1644             ap_child_init_lock(&start_mutex, signal_name_prefix, pconf);
1645             exit_event = open_event(exit_event_name);
1646         }
1647         ap_assert(start_mutex);
1648         ap_assert(exit_event);
1649
1650         worker_main();
1651
1652         destroy_event(exit_event);
1653         AMCSocketCleanup();
1654     }
1655     else {
1656         /* Parent process */
1657         static int restart = 0;
1658         PSECURITY_ATTRIBUTES sa = GetNullACL();  /* returns NULL if invalid (Win95?) */
1659
1660         ap_clear_pool(plog);
1661         ap_open_logs(server_conf, plog);
1662
1663         if (!restart) {
1664             /* service_set_status(SERVICE_START_PENDING);*/
1665             AMCSocketInitialize();
1666             setup_signal_names(ap_psprintf(pconf,"ap%d", parent_pid));
1667         
1668             /* Create shutdown event, apPID_shutdown, where PID is the parent 
1669              * Apache process ID. Shutdown is signaled by 'apache -k shutdown'.
1670              */
1671             shutdown_event = CreateEvent(sa, TRUE, FALSE, signal_shutdown_name);
1672             if (!shutdown_event) {
1673                 ap_log_error(APLOG_MARK, APLOG_EMERG, GetLastError(), s,
1674                              "master_main: Cannot create shutdown event %s", signal_shutdown_name);
1675                 CleanNullACL((void *)sa);
1676                 exit(1);
1677             }
1678
1679             /* Create restart event, apPID_restart, where PID is the parent 
1680              * Apache process ID. Restart is signaled by 'apache -k restart'.
1681              */
1682             restart_event = CreateEvent(sa, TRUE, FALSE, signal_restart_name);
1683             if (!restart_event) {
1684                 CloseHandle(shutdown_event);
1685                 ap_log_error(APLOG_MARK, APLOG_EMERG, GetLastError(), s,
1686                              "master_main: Cannot create restart event %s", signal_restart_name);
1687                 CleanNullACL((void *)sa);
1688                 exit(1);
1689             }
1690             CleanNullACL((void *)sa);
1691             
1692             /* Create the start mutex, apPID, where PID is the parent Apache process ID.
1693              * Ths start mutex is used during a restart to prevent more than one 
1694              * child process from entering the accept loop at once.
1695              */
1696             ap_create_lock(&start_mutex,APR_MUTEX, APR_CROSS_PROCESS,signal_name_prefix,pconf);
1697             /* TODO: Add some code to detect failure */
1698         }
1699
1700         /* Go to work... */
1701         restart = master_main(server_conf, shutdown_event, restart_event);
1702
1703         if (!restart) {
1704             const char *pidfile = NULL;
1705             /* Shutting down. Clean up... */
1706             pidfile = ap_server_root_relative (pconf, mpm_pid_fname);
1707             if ( pidfile != NULL && unlink(pidfile) == 0)
1708                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO,APR_SUCCESS,
1709                              server_conf,
1710                              "removed PID file %s (pid=%ld)",
1711                              pidfile, (long)getpid());
1712             ap_destroy_lock(start_mutex);
1713
1714             CloseHandle(restart_event);
1715             CloseHandle(shutdown_event);
1716             AMCSocketCleanup();
1717             /* service_set_status(SERVICE_STOPPED); */
1718         }
1719         return !restart;
1720     }
1721     return (0);
1722 }
1723
1724 static void winnt_hooks(void)
1725 {
1726 //    INIT_SIGLIST()
1727     one_process = 0;
1728     /* Configuration hooks implemented by http_config.c ... */
1729     ap_hook_pre_config(winnt_pre_config, NULL, NULL, HOOK_MIDDLE);
1730 }
1731
1732 /* 
1733  * Command processors 
1734  */
1735 static const char *set_pidfile(cmd_parms *cmd, void *dummy, char *arg) 
1736 {
1737     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1738     if (err != NULL) {
1739         return err;
1740     }
1741
1742     if (cmd->server->is_virtual) {
1743         return "PidFile directive not allowed in <VirtualHost>";
1744     }
1745     mpm_pid_fname = arg;
1746     return NULL;
1747 }
1748
1749 static const char *set_threads_per_child (cmd_parms *cmd, void *dummy, char *arg) 
1750 {
1751     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1752     if (err != NULL) {
1753         return err;
1754     }
1755
1756     ap_threads_per_child = atoi(arg);
1757     if (ap_threads_per_child > HARD_THREAD_LIMIT) {
1758         fprintf(stderr, "WARNING: ThreadsPerChild of %d exceeds compile time"
1759                 " limit of %d threads,\n", ap_threads_per_child,
1760                 HARD_THREAD_LIMIT);
1761         fprintf(stderr, " lowering ThreadsPerChild to %d. To increase, please"
1762                 " see the\n", HARD_THREAD_LIMIT);
1763         fprintf(stderr, " HARD_THREAD_LIMIT define in src/include/httpd.h.\n");
1764     }
1765     else if (ap_threads_per_child < 1) {
1766         fprintf(stderr, "WARNING: Require ThreadsPerChild > 0, setting to 1\n");
1767         ap_threads_per_child = 1;
1768     }
1769     return NULL;
1770 }
1771
1772
1773 static const char *set_max_requests(cmd_parms *cmd, void *dummy, char *arg) 
1774 {
1775     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1776     if (err != NULL) {
1777         return err;
1778     }
1779
1780     max_requests_per_child = atoi(arg);
1781
1782     return NULL;
1783 }
1784
1785 static const char *set_coredumpdir (cmd_parms *cmd, void *dummy, char *arg) 
1786 {
1787     struct stat finfo;
1788     const char *fname;
1789     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1790     if (err != NULL) {
1791         return err;
1792     }
1793
1794     fname = ap_server_root_relative(cmd->pool, arg);
1795     /* ZZZ change this to the AP func FileInfo*/
1796     if ((stat(fname, &finfo) == -1) || !S_ISDIR(finfo.st_mode)) {
1797         return ap_pstrcat(cmd->pool, "CoreDumpDirectory ", fname, 
1798                           " does not exist or is not a directory", NULL);
1799     }
1800     ap_cpystrn(ap_coredump_dir, fname, sizeof(ap_coredump_dir));
1801     return NULL;
1802 }
1803
1804 /* Stub functions until this MPM supports the connection status API */
1805
1806 API_EXPORT(void) ap_update_connection_status(long conn_id, const char *key, \
1807                                              const char *value)
1808 {
1809     /* NOP */
1810 }
1811
1812 API_EXPORT(void) ap_reset_connection_status(long conn_id)
1813 {
1814     /* NOP */
1815 }
1816
1817 static const command_rec winnt_cmds[] = {
1818 LISTEN_COMMANDS
1819 { "PidFile", set_pidfile, NULL, RSRC_CONF, TAKE1,
1820     "A file for logging the server process ID"},
1821 { "ThreadsPerChild", set_threads_per_child, NULL, RSRC_CONF, TAKE1,
1822   "Number of threads each child creates" },
1823 { "MaxRequestsPerChild", set_max_requests, NULL, RSRC_CONF, TAKE1,
1824   "Maximum number of requests a particular child serves before dying." },
1825 { "CoreDumpDirectory", set_coredumpdir, NULL, RSRC_CONF, TAKE1,
1826   "The location of the directory Apache changes to before dumping core" },
1827 { NULL }
1828 };
1829
1830 module MODULE_VAR_EXPORT mpm_winnt_module = {
1831     STANDARD20_MODULE_STUFF,
1832     NULL,                       /* create per-directory config structure */
1833     NULL,                       /* merge per-directory config structures */
1834     NULL,                       /* create per-server config structure */
1835     NULL,                       /* merge per-server config structures */
1836     winnt_cmds,                 /* command ap_table_t */
1837     NULL,                       /* handlers */
1838     winnt_hooks                 /* register_hooks */
1839 };