1
/* Licensed to the Apache Software Foundation (ASF) under one or more
2
* contributor license agreements. See the NOTICE file distributed with
3
* this work for additional information regarding copyright ownership.
4
* The ASF licenses this file to You under the Apache License, Version 2.0
5
* (the "License"); you may not use this file except in compliance with
6
* the License. You may obtain a copy of the License at
8
* http://www.apache.org/licenses/LICENSE-2.0
10
* Unless required by applicable law or agreed to in writing, software
11
* distributed under the License is distributed on an "AS IS" BASIS,
12
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
* See the License for the specific language governing permissions and
14
* limitations under the License.
18
* httpd.c: simple http daemon for answering WWW file requests
21
* 03-21-93 Rob McCool wrote original code (up to NCSA HTTPd 1.3)
24
* changed server number for child-alone processes to 0 and changed name
28
* Added numerous speed hacks proposed by Robert S. Thau (rst@ai.mit.edu)
29
* including set group before fork, and call gettime before to fork
30
* to set up libraries.
33
* Brandon's code snarfed from NCSA 1.4, but tinkered to work with the
34
* Apache server, and also to have child processes do accept() directly.
37
* Extensive rework for Apache.
41
#include "apr_portable.h"
42
#include "apr_strings.h"
43
#include "apr_thread_proc.h"
44
#include "apr_signal.h"
45
#include "apr_tables.h"
46
#include "apr_getopt.h"
47
#include "apr_thread_mutex.h"
49
#define APR_WANT_STDIO
50
#define APR_WANT_STRFUNC
56
#if APR_HAVE_SYS_TYPES_H
57
#include <sys/types.h>
61
#include <sys/select.h>
66
#include "ap_config.h"
68
#include "mpm_default.h"
69
#include "http_main.h"
71
#include "http_config.h"
72
#include "http_core.h" /* for get_remote_host */
73
#include "http_connection.h"
74
#include "scoreboard.h"
76
#include "mpm_common.h"
77
#include "ap_listen.h"
87
#include <nks/netware.h>
91
/* Limit on the total --- clients will be locked out if more servers than
92
* this are needed. It is intended solely to keep the server from crashing
93
* when things get out of hand.
95
* We keep a hard maximum number of servers, for two reasons --- first off,
96
* in case something goes seriously wrong, we want to stop the fork bomb
97
* short of actually crashing the machine we're running on by filling some
98
* kernel table. Secondly, it keeps the size of the scoreboard file small
99
* enough that we can read the whole thing without worrying too much about
102
#ifndef HARD_SERVER_LIMIT
103
#define HARD_SERVER_LIMIT 1
106
#define WORKER_DEAD SERVER_DEAD
107
#define WORKER_STARTING SERVER_STARTING
108
#define WORKER_READY SERVER_READY
109
#define WORKER_IDLE_KILL SERVER_IDLE_KILL
113
int ap_threads_per_child=0; /* Worker threads per child */
114
static int ap_threads_to_start=0;
115
static int ap_threads_min_free=0;
116
static int ap_threads_max_free=0;
117
static int ap_threads_limit=0;
118
static int mpm_state = AP_MPMQ_STARTING;
121
* The max child slot ever assigned, preserved across restarts. Necessary
122
* to deal with MaxClients changes across SIGWINCH restarts. We use this
123
* value to optimize routines that have to scan the entire scoreboard.
125
int ap_max_workers_limit = -1;
126
server_rec *ap_server_conf;
128
/* *Non*-shared http_main globals... */
130
int hold_screen_on_exit = 0; /* Indicates whether the screen should be held open */
132
static fd_set listenfds;
133
static int listenmaxfd;
135
static apr_pool_t *pconf; /* Pool for config stuff */
136
static apr_pool_t *pmain; /* Pool for httpd child stuff */
138
static pid_t ap_my_pid; /* it seems silly to call getpid all the time */
139
static char *ap_my_addrspace = NULL;
141
static int die_now = 0;
143
/* Keep track of the number of worker threads currently active */
144
static unsigned long worker_thread_count;
145
static int request_count;
147
/* Structure used to register/deregister a console handler with the OS */
148
static int InstallConsoleHandler(void);
149
static void RemoveConsoleHandler(void);
150
static int CommandLineInterpreter(scr_t screenID, const char *commandLine);
151
static CommandParser_t ConsoleHandler = {0, NULL, 0};
152
#define HANDLEDCOMMAND 0
153
#define NOTMYCOMMAND 1
155
static int show_settings = 0;
160
#define DBPRINT0(s) printf(s)
161
#define DBPRINT1(s,v1) printf(s,v1)
162
#define DBPRINT2(s,v1,v2) printf(s,v1,v2)
165
#define DBPRINT1(s,v1)
166
#define DBPRINT2(s,v1,v2)
169
/* volatile just in case */
170
static int volatile shutdown_pending;
171
static int volatile restart_pending;
172
static int volatile is_graceful;
173
static int volatile wait_to_finish=1;
174
ap_generation_t volatile ap_my_generation=0;
176
/* a clean exit from a child with proper cleanup */
177
static void clean_child_exit(int code, int worker_num, apr_pool_t *ptrans,
178
apr_bucket_alloc_t *bucket_alloc) __attribute__ ((noreturn));
179
static void clean_child_exit(int code, int worker_num, apr_pool_t *ptrans,
180
apr_bucket_alloc_t *bucket_alloc)
182
apr_bucket_alloc_destroy(bucket_alloc);
183
if (!shutdown_pending) {
184
apr_pool_destroy(ptrans);
187
atomic_dec (&worker_thread_count);
189
ap_update_child_status_from_indexes(0, worker_num, WORKER_DEAD,
190
(request_rec *) NULL);
191
NXThreadExit((void*)&code);
194
AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result)
197
case AP_MPMQ_MAX_DAEMON_USED:
200
case AP_MPMQ_IS_THREADED:
201
*result = AP_MPMQ_DYNAMIC;
203
case AP_MPMQ_IS_FORKED:
204
*result = AP_MPMQ_NOT_SUPPORTED;
206
case AP_MPMQ_HARD_LIMIT_DAEMONS:
207
*result = HARD_SERVER_LIMIT;
209
case AP_MPMQ_HARD_LIMIT_THREADS:
210
*result = HARD_THREAD_LIMIT;
212
case AP_MPMQ_MAX_THREADS:
213
*result = ap_threads_limit;
215
case AP_MPMQ_MIN_SPARE_DAEMONS:
218
case AP_MPMQ_MIN_SPARE_THREADS:
219
*result = ap_threads_min_free;
221
case AP_MPMQ_MAX_SPARE_DAEMONS:
224
case AP_MPMQ_MAX_SPARE_THREADS:
225
*result = ap_threads_max_free;
227
case AP_MPMQ_MAX_REQUESTS_DAEMON:
228
*result = ap_max_requests_per_child;
230
case AP_MPMQ_MAX_DAEMONS:
233
case AP_MPMQ_MPM_STATE:
241
/*****************************************************************
242
* Connection structures and accounting...
245
static void mpm_term(void)
247
RemoveConsoleHandler();
252
static void sig_term(int sig)
254
if (shutdown_pending == 1) {
255
/* Um, is this _probably_ not an error, if the user has
256
* tried to do a shutdown twice quickly, so we won't
257
* worry about reporting it.
261
shutdown_pending = 1;
263
DBPRINT0 ("waiting for threads\n");
264
while (wait_to_finish) {
267
DBPRINT0 ("goodbye\n");
270
/* restart() is the signal handler for SIGHUP and SIGWINCH
271
* in the parent process, unless running in ONE_PROCESS mode
273
static void restart(void)
275
if (restart_pending == 1) {
276
/* Probably not an error - don't bother reporting it */
283
static void set_signals(void)
285
apr_signal(SIGTERM, sig_term);
286
apr_signal(SIGABRT, sig_term);
289
int nlmUnloadSignaled(int wait)
291
shutdown_pending = 1;
294
while (wait_to_finish) {
302
/*****************************************************************
303
* Child process main loop.
304
* The following vars are static to avoid getting clobbered by longjmp();
305
* they are really private to child_main.
309
int ap_graceful_stop_signalled(void)
311
/* not ever called anymore... */
315
#define MAX_WB_RETRIES 3
317
static int would_block = 0;
318
static int retry_success = 0;
319
static int retry_fail = 0;
320
static int avg_retries = 0;
324
void worker_main(void *arg)
326
ap_listen_rec *lr, *first_lr, *last_lr = NULL;
329
apr_allocator_t *allocator;
330
apr_bucket_alloc_t *bucket_alloc;
331
conn_rec *current_conn;
332
apr_status_t stat = APR_EINIT;
335
int my_worker_num = (int)arg;
336
apr_socket_t *csd = NULL;
337
int requests_this_child = 0;
338
apr_socket_t *sd = NULL;
344
int wouldblock_retry;
349
apr_allocator_create(&allocator);
350
apr_allocator_max_free_set(allocator, ap_max_mem_free);
352
apr_pool_create_ex(&ptrans, pmain, NULL, allocator);
353
apr_allocator_owner_set(allocator, ptrans);
354
apr_pool_tag(ptrans, "transaction");
356
bucket_alloc = apr_bucket_alloc_create_ex(allocator);
358
atomic_inc (&worker_thread_count);
362
* (Re)initialize this child to a pre-connection state.
365
apr_pool_clear(ptrans);
367
if ((ap_max_requests_per_child > 0
368
&& requests_this_child++ >= ap_max_requests_per_child)) {
369
DBPRINT1 ("\n**Thread slot %d is shutting down", my_worker_num);
370
clean_child_exit(0, my_worker_num, ptrans, bucket_alloc);
373
ap_update_child_status_from_indexes(0, my_worker_num, WORKER_READY,
374
(request_rec *) NULL);
377
* Wait for an acceptable connection to arrive.
381
if (shutdown_pending || restart_pending || (ap_scoreboard_image->servers[0][my_worker_num].status == WORKER_IDLE_KILL)) {
382
DBPRINT1 ("\nThread slot %d is shutting down\n", my_worker_num);
383
clean_child_exit(0, my_worker_num, ptrans, bucket_alloc);
386
/* Check the listen queue on all sockets for requests */
387
memcpy(&main_fds, &listenfds, sizeof(fd_set));
388
srv = select(listenmaxfd + 1, &main_fds, NULL, NULL, &tv);
392
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
393
"select() failed on listen socket");
399
/* remember the last_lr we searched last time around so that
400
we don't end up starving any particular listening socket */
401
if (last_lr == NULL) {
411
apr_os_sock_get(&sockdes, lr->sd);
412
if (FD_ISSET(sockdes, &main_fds))
417
} while (lr != first_lr);
418
/* if we get here, something unexpected happened. Go back
419
into the select state and try again.
426
wouldblock_retry = MAX_WB_RETRIES;
428
while (wouldblock_retry) {
429
if ((stat = apr_socket_accept(&csd, sd, ptrans)) == APR_SUCCESS) {
433
/* if the error is a wouldblock then maybe we were too
434
quick try to pull the next request from the listen
435
queue. Try a few more times then return to our idle
437
if (!APR_STATUS_IS_EAGAIN(stat)) {
441
if (wouldblock_retry--) {
447
/* If we got a new socket, set it to non-blocking mode and process
448
it. Otherwise handle the error. */
449
if (stat == APR_SUCCESS) {
450
apr_socket_opt_set(csd, APR_SO_NONBLOCK, 0);
452
if (wouldblock_retry < MAX_WB_RETRIES) {
454
avg_retries += (MAX_WB_RETRIES-wouldblock_retry);
457
break; /* We have a socket ready for reading */
461
if (APR_STATUS_IS_EAGAIN(stat)) {
467
if (APR_STATUS_IS_EAGAIN(stat) ||
469
APR_STATUS_IS_ECONNRESET(stat) ||
470
APR_STATUS_IS_ETIMEDOUT(stat) ||
471
APR_STATUS_IS_EHOSTUNREACH(stat) ||
472
APR_STATUS_IS_ENETUNREACH(stat)) {
476
else if (APR_STATUS_IS_ENETDOWN(stat)) {
478
* When the network layer has been shut down, there
479
* is not much use in simply exiting: the parent
480
* would simply re-create us (and we'd fail again).
481
* Use the CHILDFATAL code to tear the server down.
482
* @@@ Martin's idea for possible improvement:
483
* A different approach would be to define
484
* a new APEXIT_NETDOWN exit code, the reception
485
* of which would make the parent shutdown all
486
* children, then idle-loop until it detected that
487
* the network is up again, and restart the children.
488
* Ben Hyde noted that temporary ENETDOWN situations
489
* occur in mobile IP.
491
ap_log_error(APLOG_MARK, APLOG_EMERG, stat, ap_server_conf,
492
"apr_socket_accept: giving up.");
493
clean_child_exit(APEXIT_CHILDFATAL, my_worker_num, ptrans,
498
ap_log_error(APLOG_MARK, APLOG_ERR, stat, ap_server_conf,
499
"apr_socket_accept: (client socket)");
500
clean_child_exit(1, my_worker_num, ptrans, bucket_alloc);
505
ap_create_sb_handle(&sbh, ptrans, 0, my_worker_num);
507
* We now have a connection, so set it up with the appropriate
508
* socket options, file descriptors, and read/write buffers.
510
current_conn = ap_run_create_connection(ptrans, ap_server_conf, csd,
514
ap_process_connection(current_conn, csd);
515
ap_lingering_close(current_conn);
519
clean_child_exit(0, my_worker_num, ptrans, bucket_alloc);
523
static int make_child(server_rec *s, int slot)
529
if (slot + 1 > ap_max_workers_limit) {
530
ap_max_workers_limit = slot + 1;
533
ap_update_child_status_from_indexes(0, slot, WORKER_STARTING,
534
(request_rec *) NULL);
536
if (ctx = NXContextAlloc((void (*)(void *)) worker_main, (void*)slot, NX_PRIO_MED, ap_thread_stacksize, NX_CTX_NORMAL, &err)) {
539
sprintf (threadName, "Apache_Worker %d", slot);
540
NXContextSetName(ctx, threadName);
541
err = NXThreadCreate(ctx, NX_THR_BIND_CONTEXT, &tid);
548
/* create thread didn't succeed. Fix the scoreboard or else
549
* it will say SERVER_STARTING forever and ever
551
ap_update_child_status_from_indexes(0, slot, WORKER_DEAD,
552
(request_rec *) NULL);
554
/* In case system resources are maxxed out, we don't want
555
Apache running away with the CPU trying to fork over and
556
over and over again. */
562
ap_scoreboard_image->servers[0][slot].tid = tid;
568
/* start up a bunch of worker threads */
569
static void startup_workers(int number_to_start)
573
for (i = 0; number_to_start && i < ap_threads_limit; ++i) {
574
if (ap_scoreboard_image->servers[0][i].status != WORKER_DEAD) {
577
if (make_child(ap_server_conf, i) < 0) {
586
* idle_spawn_rate is the number of children that will be spawned on the
587
* next maintenance cycle if there aren't enough idle servers. It is
588
* doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by
589
* without the need to spawn.
591
static int idle_spawn_rate = 1;
592
#ifndef MAX_SPAWN_RATE
593
#define MAX_SPAWN_RATE (64)
595
static int hold_off_on_exponential_spawning;
597
static void perform_idle_server_maintenance(apr_pool_t *p)
604
int free_slots[MAX_SPAWN_RATE];
608
/* initialize the free_list */
616
for (i = 0; i < ap_threads_limit; ++i) {
619
if (i >= ap_max_workers_limit && free_length == idle_spawn_rate)
621
ws = &ap_scoreboard_image->servers[0][i];
623
if (status == WORKER_DEAD) {
624
/* try to keep children numbers as low as possible */
625
if (free_length < idle_spawn_rate) {
626
free_slots[free_length] = i;
630
else if (status == WORKER_IDLE_KILL) {
631
/* If it is already marked to die, skip it */
635
/* We consider a starting server as idle because we started it
636
* at least a cycle ago, and if it still hasn't finished starting
637
* then we're just going to swamp things worse by forking more.
638
* So we hopefully won't need to fork more if we count it.
639
* This depends on the ordering of SERVER_READY and SERVER_STARTING.
641
if (status <= WORKER_READY) {
643
/* always kill the highest numbered child if we have to...
644
* no really well thought out reason ... other than observing
645
* the server behaviour under linux where lower numbered children
646
* tend to service more hits (and hence are more likely to have
647
* their data in cpu caches).
656
DBPRINT2("Total: %d Idle Count: %d \r", total_non_dead, idle_count);
657
ap_max_workers_limit = last_non_dead + 1;
658
if (idle_count > ap_threads_max_free) {
659
/* kill off one child... we use the pod because that'll cause it to
660
* shut down gracefully, in case it happened to pick up a request
661
* while we were counting
664
ap_update_child_status_from_indexes(0, last_non_dead, WORKER_IDLE_KILL,
665
(request_rec *) NULL);
666
DBPRINT1("\nKilling idle thread: %d\n", last_non_dead);
668
else if (idle_count < ap_threads_min_free) {
669
/* terminate the free list */
670
if (free_length == 0) {
671
/* only report this condition once */
672
static int reported = 0;
675
ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf,
676
"server reached MaxClients setting, consider"
677
" raising the MaxClients setting");
683
if (idle_spawn_rate >= 8) {
684
ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf,
685
"server seems busy, (you may need "
686
"to increase StartServers, or Min/MaxSpareServers), "
687
"spawning %d children, there are %d idle, and "
688
"%d total children", idle_spawn_rate,
689
idle_count, total_non_dead);
692
for (i = 0; i < free_length; ++i) {
693
DBPRINT1("Spawning additional thread slot: %d\n", free_slots[i]);
694
make_child(ap_server_conf, free_slots[i]);
696
/* the next time around we want to spawn twice as many if this
697
* wasn't good enough, but not if we've just done a graceful
699
if (hold_off_on_exponential_spawning) {
700
--hold_off_on_exponential_spawning;
702
else if (idle_spawn_rate < MAX_SPAWN_RATE) {
703
idle_spawn_rate *= 2;
712
static void display_settings ()
714
int status_array[SERVER_NUM_STATUS];
715
int i, status, total=0;
716
int reqs = request_count;
718
int wblock = would_block;
725
ClearScreen (getscreenhandle());
726
printf("%s \n", ap_get_server_version());
728
for (i=0;i<SERVER_NUM_STATUS;i++) {
732
for (i = 0; i < ap_threads_limit; ++i) {
733
status = (ap_scoreboard_image->servers[0][i]).status;
734
status_array[status]++;
737
for (i=0;i<SERVER_NUM_STATUS;i++) {
741
printf ("Available:\t%d\n", status_array[i]);
743
case SERVER_STARTING:
744
printf ("Starting:\t%d\n", status_array[i]);
747
printf ("Ready:\t\t%d\n", status_array[i]);
749
case SERVER_BUSY_READ:
750
printf ("Busy:\t\t%d\n", status_array[i]);
752
case SERVER_BUSY_WRITE:
753
printf ("Busy Write:\t%d\n", status_array[i]);
755
case SERVER_BUSY_KEEPALIVE:
756
printf ("Busy Keepalive:\t%d\n", status_array[i]);
758
case SERVER_BUSY_LOG:
759
printf ("Busy Log:\t%d\n", status_array[i]);
761
case SERVER_BUSY_DNS:
762
printf ("Busy DNS:\t%d\n", status_array[i]);
765
printf ("Closing:\t%d\n", status_array[i]);
767
case SERVER_GRACEFUL:
768
printf ("Restart:\t%d\n", status_array[i]);
770
case SERVER_IDLE_KILL:
771
printf ("Idle Kill:\t%d\n", status_array[i]);
774
printf ("Unknown Status:\t%d\n", status_array[i]);
777
if (i != SERVER_DEAD)
778
total+=status_array[i];
780
printf ("Total Running:\t%d\tout of: \t%d\n", total, ap_threads_limit);
781
printf ("Requests per interval:\t%d\n", reqs);
784
printf ("Would blocks:\t%d\n", wblock);
785
printf ("Successful retries:\t%d\n", retry_success);
786
printf ("Failed retries:\t%d\n", retry_fail);
787
printf ("Avg retries:\t%d\n", retry_success == 0 ? 0 : avg_retries / retry_success);
791
static void show_server_data()
796
printf("%s\n", ap_get_server_version());
797
if (ap_my_addrspace && (ap_my_addrspace[0] != 'O') && (ap_my_addrspace[1] != 'S'))
798
printf(" Running in address space %s\n", ap_my_addrspace);
801
/* Display listening ports */
802
printf(" Listening on port(s):");
805
printf(" %d", lr->bind_addr->port);
807
} while(lr && lr != ap_listeners);
809
/* Display dynamic modules loaded */
811
for (m = ap_loaded_modules; *m != NULL; m++) {
812
if (((module*)*m)->dynamic_load_handle) {
813
printf(" Loaded dynamic module %s\n", ((module*)*m)->name);
819
static int setup_listeners(server_rec *s)
824
if (ap_setup_listeners(s) < 1 ) {
825
ap_log_error(APLOG_MARK, APLOG_ALERT, 0, s,
826
"no listening sockets available, shutting down");
832
for (lr = ap_listeners; lr; lr = lr->next) {
833
apr_os_sock_get(&sockdes, lr->sd);
834
FD_SET(sockdes, &listenfds);
835
if (sockdes > listenmaxfd) {
836
listenmaxfd = sockdes;
842
static int shutdown_listeners()
846
for (lr = ap_listeners; lr; lr = lr->next) {
847
apr_socket_close(lr->sd);
853
/*****************************************************************
854
* Executive routines.
857
int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
859
apr_status_t status=0;
864
if (setup_listeners(s)) {
865
ap_log_error(APLOG_MARK, APLOG_ALERT, status, s,
866
"no listening sockets available, shutting down");
870
restart_pending = shutdown_pending = 0;
871
worker_thread_count = 0;
874
if (ap_run_pre_mpm(s->process->pool, SB_NOT_SHARED) != OK) {
879
/* Only set slot 0 since that is all NetWare will ever have. */
880
ap_scoreboard_image->parent[0].pid = getpid();
884
apr_pool_create(&pmain, pconf);
885
ap_run_child_init(pmain, ap_server_conf);
887
if (ap_threads_max_free < ap_threads_min_free + 1) /* Don't thrash... */
888
ap_threads_max_free = ap_threads_min_free + 1;
891
startup_workers(ap_threads_to_start);
893
/* Allow the Apache screen to be closed normally on exit() only if it
894
has not been explicitly forced to close on exit(). (ie. the -E flag
895
was specified at startup) */
896
if (hold_screen_on_exit > 0) {
897
hold_screen_on_exit = 0;
900
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
901
"%s configured -- resuming normal operations",
902
ap_get_server_version());
903
ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf,
904
"Server built: %s", ap_get_server_built());
905
#ifdef AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
906
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
907
"AcceptMutex: %s (default: %s)",
908
apr_proc_mutex_name(accept_mutex),
909
apr_proc_mutex_defname());
913
mpm_state = AP_MPMQ_RUNNING;
914
while (!restart_pending && !shutdown_pending) {
915
perform_idle_server_maintenance(pconf);
919
apr_sleep(SCOREBOARD_MAINTENANCE_INTERVAL);
921
mpm_state = AP_MPMQ_STOPPING;
924
/* Shutdown the listen sockets so that we don't get stuck in a blocking call.
925
shutdown_listeners();*/
927
if (shutdown_pending) { /* Got an unload from the console */
928
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
929
"caught SIGTERM, shutting down");
931
while (worker_thread_count > 0) {
932
printf ("\rShutdown pending. Waiting for %d thread(s) to terminate...",
933
worker_thread_count);
939
else { /* the only other way out is a restart */
940
/* advance to the next generation */
941
/* XXX: we really need to make sure this new generation number isn't in
942
* use by any of the children.
945
ap_scoreboard_image->global->running_generation = ap_my_generation;
947
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
948
"Graceful restart requested, doing restart");
950
/* Wait for all of the threads to terminate before initiating the restart */
951
while (worker_thread_count > 0) {
952
printf ("\rRestart pending. Waiting for %d thread(s) to terminate...",
953
worker_thread_count);
956
printf ("\nRestarting...\n");
962
static int netware_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp)
965
char *addrname = NULL;
967
mpm_state = AP_MPMQ_STARTING;
969
debug = ap_exists_config_define("DEBUG");
972
ap_my_pid = getpid();
973
addrname = getaddressspacename (NULL, NULL);
975
ap_my_addrspace = apr_pstrdup (p, addrname);
980
/* The following call has been moved to the mod_nw_ssl pre-config handler */
981
ap_listen_pre_config();
984
ap_threads_to_start = DEFAULT_START_THREADS;
985
ap_threads_min_free = DEFAULT_MIN_FREE_THREADS;
986
ap_threads_max_free = DEFAULT_MAX_FREE_THREADS;
987
ap_threads_limit = HARD_THREAD_LIMIT;
988
ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;
989
ap_extended_status = 0;
990
ap_thread_stacksize = DEFAULT_THREAD_STACKSIZE;
991
#ifdef AP_MPM_WANT_SET_MAX_MEM_FREE
992
ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED;
998
static void netware_mpm_hooks(apr_pool_t *p)
1000
ap_hook_pre_config(netware_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
1003
void netware_rewrite_args(process_rec *process)
1005
char *def_server_root;
1007
const char *opt_arg;
1009
apr_array_header_t *mpm_new_argv;
1013
InstallConsoleHandler();
1015
/* Make sure to hold the Apache screen open if exit() is called */
1016
hold_screen_on_exit = 1;
1018
/* Rewrite process->argv[];
1020
* add default -d serverroot from the path of this executable
1022
* The end result will look like:
1023
* The -d serverroot default from the running executable
1025
if (process->argc > 0) {
1026
char *s = apr_pstrdup (process->pconf, process->argv[0]);
1028
int i, len = strlen(s);
1030
for (i=len; i; i--) {
1031
if (s[i] == '\\' || s[i] == '/') {
1033
apr_filepath_merge(&def_server_root, NULL, s,
1034
APR_FILEPATH_TRUENAME, process->pool);
1038
/* Use process->pool so that the rewritten argv
1039
* lasts for the lifetime of the server process,
1040
* because pconf will be destroyed after the
1041
* initial pre-flight of the config parser.
1043
mpm_new_argv = apr_array_make(process->pool, process->argc + 2,
1044
sizeof(const char *));
1045
*(const char **)apr_array_push(mpm_new_argv) = process->argv[0];
1046
*(const char **)apr_array_push(mpm_new_argv) = "-d";
1047
*(const char **)apr_array_push(mpm_new_argv) = def_server_root;
1051
apr_getopt_init(&opt, process->pool, process->argc, (char**) process->argv);
1052
while (apr_getopt(opt, AP_SERVER_BASEARGS"n:", optbuf + 1, &opt_arg) == APR_SUCCESS) {
1053
switch (optbuf[1]) {
1056
renamescreen(opt_arg);
1060
/* Don't need to hold the screen open if the output is going to a file */
1061
hold_screen_on_exit = -1;
1063
*(const char **)apr_array_push(mpm_new_argv) =
1064
apr_pstrdup(process->pool, optbuf);
1067
*(const char **)apr_array_push(mpm_new_argv) = opt_arg;
1072
process->argc = mpm_new_argv->nelts;
1073
process->argv = (const char * const *) mpm_new_argv->elts;
1078
static int CommandLineInterpreter(scr_t screenID, const char *commandLine)
1080
char *szCommand = "APACHE2 ";
1081
int iCommandLen = 8;
1082
char szcommandLine[256];
1084
screenID = screenID;
1087
if (commandLine == NULL)
1088
return NOTMYCOMMAND;
1089
if (strlen(commandLine) <= strlen(szCommand))
1090
return NOTMYCOMMAND;
1092
strncpy (szcommandLine, commandLine, sizeof(szcommandLine)-1);
1094
/* All added commands begin with "APACHE2 " */
1096
if (!strnicmp(szCommand, szcommandLine, iCommandLen)) {
1097
ActivateScreen (getscreenhandle());
1099
/* If an instance id was not given but the nlm is loaded in
1100
protected space, then the the command belongs to the
1101
OS address space instance to pass it on. */
1102
pID = strstr (szcommandLine, "-p");
1103
if ((pID == NULL) && nlmisloadedprotected())
1104
return NOTMYCOMMAND;
1106
/* If we got an instance id but it doesn't match this
1107
instance of the nlm, pass it on. */
1110
while (*pID && (*pID == ' '))
1113
if (pID && ap_my_addrspace && strnicmp(pID, ap_my_addrspace, strlen(ap_my_addrspace)))
1114
return NOTMYCOMMAND;
1116
/* If we have determined that this command belongs to this
1117
instance of the nlm, then handle it. */
1118
if (!strnicmp("RESTART",&szcommandLine[iCommandLen],3)) {
1119
printf("Restart Requested...\n");
1122
else if (!strnicmp("VERSION",&szcommandLine[iCommandLen],3)) {
1123
printf("Server version: %s\n", ap_get_server_version());
1124
printf("Server built: %s\n", ap_get_server_built());
1126
else if (!strnicmp("MODULES",&szcommandLine[iCommandLen],3)) {
1129
else if (!strnicmp("DIRECTIVES",&szcommandLine[iCommandLen],3)) {
1130
ap_show_directives();
1132
else if (!strnicmp("SHUTDOWN",&szcommandLine[iCommandLen],3)) {
1133
printf("Shutdown Requested...\n");
1134
shutdown_pending = 1;
1136
else if (!strnicmp("SETTINGS",&szcommandLine[iCommandLen],3)) {
1137
if (show_settings) {
1139
ClearScreen (getscreenhandle());
1149
if (strnicmp("HELP",&szcommandLine[iCommandLen],3))
1150
printf("Unknown APACHE2 command %s\n", &szcommandLine[iCommandLen]);
1151
printf("Usage: APACHE2 [command] [-p <instance ID>]\n");
1152
printf("Commands:\n");
1153
printf("\tDIRECTIVES - Show directives\n");
1154
printf("\tHELP - Display this help information\n");
1155
printf("\tMODULES - Show a list of the loaded modules\n");
1156
printf("\tRESTART - Reread the configuration file and restart Apache\n");
1157
printf("\tSETTINGS - Show current thread status\n");
1158
printf("\tSHUTDOWN - Shutdown Apache\n");
1159
printf("\tVERSION - Display the server version information\n");
1162
/* Tell NetWare we handled the command */
1163
return HANDLEDCOMMAND;
1166
/* Tell NetWare that the command isn't mine */
1167
return NOTMYCOMMAND;
1170
static int InstallConsoleHandler(void)
1172
/* Our command line handler interfaces the system operator
1175
NX_WRAP_INTERFACE(CommandLineInterpreter, 2, (void*)&(ConsoleHandler.parser));
1177
ConsoleHandler.rTag = AllocateResourceTag(getnlmhandle(), "Command Line Processor",
1178
ConsoleCommandSignature);
1179
if (!ConsoleHandler.rTag)
1181
printf("Error on allocate resource tag\n");
1185
RegisterConsoleCommand(&ConsoleHandler);
1187
/* The Remove procedure unregisters the console handler */
1192
static void RemoveConsoleHandler(void)
1194
UnRegisterConsoleCommand(&ConsoleHandler);
1195
NX_UNWRAP_INTERFACE(ConsoleHandler.parser);
1198
static const char *set_threads_to_start(cmd_parms *cmd, void *dummy, const char *arg)
1200
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1205
ap_threads_to_start = atoi(arg);
1209
static const char *set_min_free_threads(cmd_parms *cmd, void *dummy, const char *arg)
1211
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1216
ap_threads_min_free = atoi(arg);
1217
if (ap_threads_min_free <= 0) {
1218
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1219
"WARNING: detected MinSpareServers set to non-positive.");
1220
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1221
"Resetting to 1 to avoid almost certain Apache failure.");
1222
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1223
"Please read the documentation.");
1224
ap_threads_min_free = 1;
1230
static const char *set_max_free_threads(cmd_parms *cmd, void *dummy, const char *arg)
1232
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1237
ap_threads_max_free = atoi(arg);
1241
static const char *set_thread_limit (cmd_parms *cmd, void *dummy, const char *arg)
1243
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1248
ap_threads_limit = atoi(arg);
1249
if (ap_threads_limit > HARD_THREAD_LIMIT) {
1250
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1251
"WARNING: MaxThreads of %d exceeds compile time limit "
1252
"of %d threads,", ap_threads_limit, HARD_THREAD_LIMIT);
1253
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1254
" lowering MaxThreads to %d. To increase, please "
1255
"see the", HARD_THREAD_LIMIT);
1256
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1257
" HARD_THREAD_LIMIT define in %s.",
1258
AP_MPM_HARD_LIMITS_FILE);
1259
ap_threads_limit = HARD_THREAD_LIMIT;
1261
else if (ap_threads_limit < 1) {
1262
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
1263
"WARNING: Require MaxThreads > 0, setting to 1");
1264
ap_threads_limit = 1;
1269
static const command_rec netware_mpm_cmds[] = {
1271
AP_INIT_TAKE1("StartThreads", set_threads_to_start, NULL, RSRC_CONF,
1272
"Number of worker threads launched at server startup"),
1273
AP_INIT_TAKE1("MinSpareThreads", set_min_free_threads, NULL, RSRC_CONF,
1274
"Minimum number of idle threads, to handle request spikes"),
1275
AP_INIT_TAKE1("MaxSpareThreads", set_max_free_threads, NULL, RSRC_CONF,
1276
"Maximum number of idle threads"),
1277
AP_INIT_TAKE1("MaxThreads", set_thread_limit, NULL, RSRC_CONF,
1278
"Maximum number of worker threads alive at the same time"),
1282
module AP_MODULE_DECLARE_DATA mpm_netware_module = {
1284
netware_rewrite_args, /* hook to run before apache parses args */
1285
NULL, /* create per-directory config structure */
1286
NULL, /* merge per-directory config structures */
1287
NULL, /* create per-server config structure */
1288
NULL, /* merge per-server config structures */
1289
netware_mpm_cmds, /* command apr_table_t */
1290
netware_mpm_hooks, /* register hooks */