/[hydra]/hydra/src/boa.c
ViewVC logotype

Annotation of /hydra/src/boa.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.23 - (hide annotations)
Mon Oct 21 18:46:26 2002 UTC (21 years, 5 months ago) by nmav
Branch: MAIN
CVS Tags: hydra_0_0_8
Changes since 1.22: +33 -23 lines
File MIME type: text/plain
Added several stuff from Boa 0.94.14rc1

1 nmav 1.1 /*
2 nmav 1.12 * Hydra, an http server (based on Boa 0.94.13)
3 nmav 1.1 * Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
4     * Some changes Copyright (C) 1996 Charles F. Randall <crandall@goldsys.com>
5     * Some changes Copyright (C) 1996 Larry Doolittle <ldoolitt@boa.org>
6     * Some changes Copyright (C) 1996-2002 Jon Nelson <jnelson@boa.org>
7     * Portions Copyright (C) 2002 Nikos Mavroyanopoulos <nmav@gnutls.org>
8     *
9     * This program is free software; you can redistribute it and/or modify
10     * it under the terms of the GNU General Public License as published by
11     * the Free Software Foundation; either version 1, or (at your option)
12     * any later version.
13     *
14     * This program is distributed in the hope that it will be useful,
15     * but WITHOUT ANY WARRANTY; without even the implied warranty of
16     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17     * GNU General Public License for more details.
18     *
19     * You should have received a copy of the GNU General Public License
20     * along with this program; if not, write to the Free Software
21     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22     *
23     */
24    
25 nmav 1.23 /* $Id: boa.c,v 1.22 2002/10/05 16:42:52 nmav Exp $*/
26 nmav 1.1
27     #include "boa.h"
28     #include "ssl.h"
29     #include <sys/resource.h>
30     #ifdef ENABLE_SMP
31     pthread_t father_id;
32     #endif
33    
34     extern int ssl_params_refresh;
35    
36     /* globals */
37     int backlog = SO_MAXCONN;
38     time_t start_time;
39    
40     time_t current_time;
41    
42    
43     /* static to boa.c */
44     static void fixup_server_root(void);
45 nmav 1.15 static socket_type create_server_socket(int port, int);
46     void hic_init(void);
47 nmav 1.17 static void initialize_rlimits();
48 nmav 1.1 static void drop_privs(void);
49     static server_params *smp_init(socket_type server_s[2]);
50 nmav 1.15 static void create_server_names( void);
51    
52 nmav 1.1 static int sock_opt = 1;
53     static int do_fork = 1;
54    
55     int main(int argc, char **argv)
56     {
57 nmav 1.15 int c; /* command line arg */
58     socket_type server_s[2] = { {-1, 0, 0, 0}, {-1, -1, 0, 0} }; /* boa socket */
59     server_params *params;
60 nmav 1.23 pid_t pid;
61 nmav 1.15
62     /* set umask to u+rw, u-x, go-rwx */
63 nmav 1.23 c = umask(077);
64 nmav 1.15 if (c == -1) {
65     perror("umask");
66     exit(1);
67     }
68    
69 nmav 1.23 { int devnullfd = -1;
70     devnullfd = open("/dev/null", 0);
71 nmav 1.15
72 nmav 1.23 /* make STDIN and STDOUT point to /dev/null */
73     if (devnullfd == -1) {
74     DIE("can't open /dev/null");
75     }
76    
77     if (dup2(devnullfd, STDIN_FILENO) == -1) {
78     DIE("can't dup2 /dev/null to STDIN_FILENO");
79     }
80 nmav 1.15
81 nmav 1.23 close(devnullfd);
82 nmav 1.15 }
83    
84     /* but first, update timestamp, because log_error_time uses it */
85     (void) time(&current_time);
86    
87     while ((c = getopt(argc, argv, "c:r:d")) != -1) {
88     switch (c) {
89     case 'c':
90     if (server_root)
91     free(server_root);
92     server_root = strdup(optarg);
93     if (!server_root) {
94     perror("strdup (for server_root)");
95     exit(1);
96     }
97     break;
98     case 'r':
99     if (chdir(optarg) == -1) {
100     log_error_time();
101     perror("chdir (to chroot)");
102     exit(1);
103     }
104     if (chroot(optarg) == -1) {
105     log_error_time();
106     perror("chroot");
107     exit(1);
108     }
109     if (chdir("/") == -1) {
110     log_error_time();
111     perror("chdir (after chroot)");
112     exit(1);
113     }
114     break;
115     case 'd':
116     do_fork = 0;
117     break;
118     default:
119     fprintf(stderr, "Usage: %s [-c serverroot] [-r chroot] [-d]\n",
120     argv[0]);
121     exit(1);
122     }
123     }
124    
125     create_server_names();
126     fixup_server_root();
127     read_config_files();
128     open_logs();
129    
130     if ((boa_ssl >= 2 || boa_ssl == 0) && server_port > 0) {
131     server_s[0] = create_server_socket(server_port, 0);
132     }
133    
134     if (boa_ssl != 0 && ssl_port > 0) {
135     server_s[1] = create_server_socket(ssl_port, 1);
136     }
137    
138     if (server_s[1].socket == -1 && server_s[0].socket == -1) {
139     log_error_time();
140     fprintf(stderr, "Could not initialize sockets\n");
141     exit(1);
142     }
143    
144     init_signals();
145 nmav 1.21 initialize_rlimits();
146    
147 nmav 1.15 create_common_env();
148     build_needs_escape();
149 nmav 1.1
150 nmav 1.15 if (boa_ssl) {
151     initialize_ssl();
152     }
153    
154     initialize_mmap();
155    
156     /* background ourself */
157     if (do_fork) {
158 nmav 1.23 pid = fork();
159     } else {
160     pid = getpid();
161     }
162    
163     switch (pid) {
164 nmav 1.15 case -1:
165     /* error */
166     perror("fork");
167     exit(1);
168     break;
169     case 0:
170     /* child, success */
171     break;
172     default:
173     /* parent, success */
174 nmav 1.23 if(pid_file != NULL) {
175     FILE *PID_FILE = fopen(pid_file, "w");
176     if(PID_FILE != NULL) {
177     fprintf(PID_FILE, "%d", pid);
178     fclose(PID_FILE);
179     } else {
180     perror("fopen pid file");
181     }
182     }
183     if (do_fork)
184     exit(0);
185 nmav 1.15 break;
186     }
187    
188 nmav 1.23 drop_privs();
189    
190 nmav 1.15 /* main loop */
191     timestamp();
192    
193     start_time = current_time;
194    
195     /* Blocks signals that are not supposed to be catched
196     * by the children.
197     */
198     block_main_signals();
199    
200 nmav 1.14 #ifdef ENABLE_HIC
201 nmav 1.15 hic_init();
202 nmav 1.14 #endif
203 nmav 1.1
204 nmav 1.15 /* spawn the children pool
205     */
206     params = smp_init(server_s);
207    
208     /* unblock signals for daddy
209     */
210     unblock_main_signals();
211 nmav 1.1
212 nmav 1.15 /* regenerate parameters in that time interval
213     */
214 nmav 1.11 #ifdef ENABLE_SSL
215 nmav 1.15 if (boa_ssl) {
216     if (ssl_params_refresh < DEFAULT_SSL_PARAMS_REFRESH) {
217     log_error_time();
218     fprintf(stderr,
219     "SSL parameters will be refreshed every %d minutes\n",
220     DEFAULT_SSL_PARAMS_REFRESH / 60);
221     ssl_params_refresh = DEFAULT_SSL_PARAMS_REFRESH;
222     }
223     alarm(ssl_params_refresh);
224     }
225 nmav 1.11 #endif
226 nmav 1.1
227 nmav 1.15 select_loop(params);
228 nmav 1.1
229 nmav 1.15 return 0;
230 nmav 1.1 }
231    
232     server_params *global_server_params;
233 nmav 1.15 int global_server_params_size = 0;
234 nmav 1.1
235 nmav 1.15 #ifdef ENABLE_HIC
236     hic_params *global_hic_params = NULL;
237     int global_hic_params_size = 0;
238     #endif
239 nmav 1.1
240     /* This function will return a server_params pointer. This
241     * pointer is to be used as a pointer to the select loop.
242     */
243 nmav 1.15 static server_params *smp_init(socket_type server_s[2])
244 nmav 1.1 {
245 nmav 1.15 int i;
246     server_params *params;
247 nmav 1.1
248     #ifdef ENABLE_SMP
249 nmav 1.15 pthread_t tid;
250     int max_threads = max_server_threads;
251 nmav 1.1
252 nmav 1.15 father_id = pthread_self();
253 nmav 1.1 #else
254 nmav 1.15 const int max_threads = 1;
255 nmav 1.1 #endif
256    
257 nmav 1.15 params = malloc(sizeof(server_params) * max_threads);
258     if (params == NULL) {
259 nmav 1.1 log_error_time();
260 nmav 1.15 fprintf(stderr, "Could not allocate memory.\n");
261 nmav 1.1 exit(1);
262 nmav 1.15 }
263    
264     for (i = 0; i < max_threads; i++) {
265     params[i].server_s[0] = server_s[0];
266     params[i].server_s[1] = server_s[1];
267     params[i].request_ready = NULL;
268     params[i].request_block = NULL;
269     params[i].request_free = NULL;
270    
271     /* for signal handling */
272     params[i].sighup_flag = 0;
273     params[i].sigchld_flag = 0;
274     params[i].sigalrm_flag = 0;
275     params[i].sigusr1_flag = 0;
276     params[i].sigterm_flag = 0;
277    
278     params[i].sockbufsize = SOCKETBUF_SIZE;
279    
280     params[i].status.requests = 0;
281     params[i].status.errors = 0;
282    
283     params[i].total_connections = 0;
284     params[i].max_fd = 0;
285    
286     params[i].handle_sigbus = 0;
287     }
288 nmav 1.1
289     #ifdef ENABLE_SMP
290 nmav 1.15 params[0].tid = father_id;
291 nmav 1.1
292 nmav 1.15 for (i = 1; i < max_threads; i++) {
293     if (pthread_create(&tid, NULL, &select_loop, &params[i]) != 0) {
294     log_error_time();
295     fprintf(stderr, "Could not dispatch threads.\n");
296     exit(1);
297 nmav 1.1 }
298     params[i].tid = tid;
299 nmav 1.15 }
300 nmav 1.1 #endif
301    
302 nmav 1.15 if (max_threads > 1) {
303 nmav 1.1 log_error_time();
304 nmav 1.15 fprintf(stderr,
305     "%s: Dispatched %d HTTP server threads.\n", SERVER_NAME,
306     max_threads);
307     }
308 nmav 1.1
309 nmav 1.15 global_server_params_size = max_threads;
310     global_server_params = params;
311 nmav 1.1
312 nmav 1.15 return &params[0];
313 nmav 1.1 }
314    
315     void smp_reinit()
316     {
317     #ifdef ENABLE_SMP
318 nmav 1.2 int i;
319     server_params *params = global_server_params;
320 nmav 1.15 int max_threads = max_server_threads;
321 nmav 1.1 #else
322 nmav 1.2 int max_threads = 1;
323 nmav 1.1 #endif
324    
325 nmav 1.2 if (global_server_params_size < max_threads) {
326 nmav 1.15 log_error_time();
327     fprintf(stderr, "Cannot increase threads on runtime.\n");
328     max_threads = global_server_params_size;
329 nmav 1.2 }
330 nmav 1.1 #ifdef ENABLE_SMP
331 nmav 1.15 for (i = 1; i < max_threads; i++) {
332 nmav 1.1 pthread_t tid;
333 nmav 1.15 if (pthread_create(&tid, NULL, &select_loop, &params[i]) != 0) {
334     log_error_time();
335     fprintf(stderr, "Could not dispatch threads.\n");
336     exit(1);
337 nmav 1.1 }
338     params[i].tid = tid;
339 nmav 1.2 }
340 nmav 1.1 #endif
341    
342 nmav 1.2 if (max_threads > 0) {
343 nmav 1.1 log_error_time();
344 nmav 1.15 fprintf(stderr, "Regenerated a pool of %d threads.\n", max_threads);
345     }
346 nmav 1.1
347 nmav 1.2 return;
348 nmav 1.1 }
349    
350 nmav 1.8 #ifdef ENABLE_HIC
351 nmav 1.10
352     pthread_t hic_tid;
353 nmav 1.8
354     /* This function will return a server_params pointer. This
355     * pointer is to be used as a pointer to the select loop.
356     */
357 nmav 1.15 void hic_init()
358 nmav 1.8 {
359 nmav 1.15 hic_params *params = global_hic_params;
360     int i;
361     #ifdef ENABLE_SMP
362     pthread_t tid;
363     #endif
364    
365     if (max_hic_threads == 0)
366     return;
367 nmav 1.8
368     #ifdef ENABLE_SMP
369    
370 nmav 1.15 if (global_hic_params_size > 0
371     && global_hic_params_size != max_hic_threads) {
372     log_error_time();
373     fprintf(stderr,
374     "Cannot change the HIC threads number on runtime.\n");
375     max_hic_threads = global_hic_params_size;
376     } else {
377     /* first time.. Allocate memory */
378     params = calloc(1, sizeof(hic_params) * max_hic_threads);
379     if (params == NULL) {
380     log_error_time();
381     fprintf(stderr,
382     "Could not allocate memory for HIC parameters.\n");
383     exit(1);
384     }
385    
386     for (i = 0; i < max_hic_threads; i++) { /* initialize mutexes */
387     pthread_mutex_init(&params[i].lock, NULL);
388 nmav 1.8 }
389    
390 nmav 1.15 global_hic_params = params;
391     global_hic_params_size = max_hic_threads;
392    
393     }
394    
395     for (i = 0; i < max_hic_threads; i++) {
396     if (pthread_create(&tid, NULL, &hic_main_loop, &params[i]) != 0) {
397     log_error_time();
398     fprintf(stderr, "Could not dispatch hic thread.\n");
399     exit(1);
400     }
401     params[i].tid = tid;
402     }
403    
404     log_error_time();
405     fprintf(stderr,
406     "%s: Dispatched %d HIC threads.\n", SERVER_NAME,
407     max_hic_threads);
408 nmav 1.8
409     #endif
410    
411 nmav 1.15 return;
412 nmav 1.8 }
413    
414 nmav 1.15 #endif /* ENABLE_HIC */
415 nmav 1.1
416 nmav 1.15 static socket_type create_server_socket(int port, int secure)
417 nmav 1.1 {
418 nmav 1.15 socket_type server_s;
419 nmav 1.1
420 nmav 1.15 server_s.secure = secure;
421     server_s.port = port;
422    
423     server_s.socket = socket(SERVER_AF, SOCK_STREAM, IPPROTO_TCP);
424     if (server_s.socket == -1) {
425     DIE("unable to create socket");
426     }
427    
428     /* server socket is nonblocking */
429     if (set_nonblock_fd(server_s.socket) == -1) {
430     DIE("fcntl: unable to set server socket to nonblocking");
431     }
432    
433     /* close server socket on exec so cgi's can't write to it */
434     if (fcntl(server_s.socket, F_SETFD, 1) == -1) {
435     DIE("can't set close-on-exec on server socket!");
436     }
437 nmav 1.1
438 nmav 1.15 /* reuse socket addr */
439     if ((setsockopt
440     (server_s.socket, SOL_SOCKET, SO_REUSEADDR, (void *) &sock_opt,
441     sizeof(sock_opt))) == -1) {
442     DIE("setsockopt");
443     }
444    
445     /* internet family-specific code encapsulated in bind_server() */
446     if (bind_server(server_s.socket, server_ip, port) == -1) {
447     DIE("unable to bind");
448     }
449    
450     /* listen: large number just in case your kernel is nicely tweaked */
451     if (listen(server_s.socket, backlog) == -1) {
452     DIE("unable to listen");
453     }
454     return server_s;
455 nmav 1.1 }
456    
457     static void drop_privs(void)
458     {
459 nmav 1.15 /* give away our privs if we can */
460     if (getuid() == 0) {
461     struct passwd *passwdbuf;
462     passwdbuf = getpwuid(server_uid);
463     if (passwdbuf == NULL) {
464     DIE("getpwuid");
465     }
466     if (initgroups(passwdbuf->pw_name, passwdbuf->pw_gid) == -1) {
467     DIE("initgroups");
468     }
469     if (setgid(server_gid) == -1) {
470     DIE("setgid");
471     }
472     if (setuid(server_uid) == -1) {
473     DIE("setuid");
474     }
475     /* test for failed-but-return-was-successful setuid
476     * http://www.securityportal.com/list-archive/bugtraq/2000/Jun/0101.html
477     */
478     if (setuid(0) != -1) {
479     DIE("icky Linux kernel bug!");
480     }
481     } else {
482     if (server_gid || server_uid) {
483     log_error_time();
484     fprintf(stderr, "Warning: "
485     "Not running as root: no attempt to change"
486     " to uid %d gid %d\n", server_uid, server_gid);
487     }
488     server_gid = getgid();
489     server_uid = getuid();
490     }
491 nmav 1.1 }
492    
493     /*
494     * Name: fixup_server_root
495     *
496     * Description: Makes sure the server root is valid.
497     *
498     */
499    
500     static void fixup_server_root()
501     {
502 nmav 1.15 if (!server_root) {
503 nmav 1.1 #ifdef SERVER_ROOT
504 nmav 1.15 server_root = strdup(SERVER_ROOT);
505     if (!server_root) {
506     perror("strdup (SERVER_ROOT)");
507     exit(1);
508     }
509 nmav 1.1 #else
510 nmav 1.15 fputs(SERVER_NAME
511     ": don't know where server root is. Please #define "
512     "SERVER_ROOT in defines.h\n"
513     "and recompile, or use the -c command line option to "
514     "specify it.\n", stderr);
515     exit(1);
516     #endif
517     }
518    
519     if (chdir(server_root) == -1) {
520     fprintf(stderr, "Could not chdir to \"%s\": aborting\n",
521     server_root);
522     exit(1);
523     }
524    
525 nmav 1.1 }
526    
527 nmav 1.15 char boa_tls_version[64] = "\0";
528 nmav 1.16 char boa_version[] = "Server: "SERVER_NAME"/"SERVER_VERSION"\r\n";
529 nmav 1.15
530     static void create_server_names()
531     {
532 nmav 1.19 #ifdef ENABLE_SSL
533 nmav 1.15 if ( boa_tls_version[0] == 0) {
534     strcpy( boa_tls_version, "Server: "SERVER_NAME"/"SERVER_VERSION" GnuTLS/");
535     strcat( boa_tls_version, gnutls_check_version(NULL));
536 nmav 1.16 strcat( boa_tls_version, "\r\n");
537 nmav 1.15 }
538 nmav 1.19 #endif
539 nmav 1.15 }
540 nmav 1.17
541     #ifdef HAVE_GETRLIMIT
542    
543     #ifndef RLIMIT_NOFILE
544     # define RLIMIT_NOFILE RLIMIT_OFILE
545     #endif
546    
547     #define SET_MAX_CON( lim) \
548     if (lim == RLIM_INFINITY) { \
549 nmav 1.21 max_connections = INT_MAX; \
550 nmav 1.17 } else { \
551     max_connections = lim; \
552     }
553    
554     static void initialize_rlimits( )
555     {
556     int c;
557     struct rlimit rl;
558    
559 nmav 1.20 if (max_connections < 1) {
560 nmav 1.17 /* has not been set explicitly */
561     c = getrlimit(RLIMIT_NOFILE, &rl);
562     if (c < 0) {
563     perror("getrlimit");
564     exit(1);
565     }
566     SET_MAX_CON( rl.rlim_cur);
567     #ifdef HAVE_SETRLIMIT
568     if (rl.rlim_max > rl.rlim_cur) {
569     rl.rlim_cur = rl.rlim_max;
570     c = setrlimit(RLIMIT_NOFILE, &rl);
571     if (c < 0) {
572     perror("setrlimit:");
573 nmav 1.18 } else {
574     SET_MAX_CON( rl.rlim_max);
575     fprintf(stderr, "%s: Increasing max open files from %ld to %ld.\n",
576     SERVER_NAME, (long int)rl.rlim_cur, max_connections);
577 nmav 1.17 }
578     }
579     #endif
580     }
581     }
582    
583     #else /* rlimits are not present */
584     static void initialize_rlimits( )
585     {
586 nmav 1.21 if (max_connections < 1)
587     max_connections = INT_MAX;
588 nmav 1.17 return;
589     }
590     #endif

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26