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

Annotation of /hydra/src/boa.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.17 - (hide annotations)
Wed Oct 2 19:26:15 2002 UTC (21 years, 6 months ago) by nmav
Branch: MAIN
Changes since 1.16: +55 -12 lines
File MIME type: text/plain
Better use of limits. If getrlimit() returns a cur limit less than max limit, we increase the cur limit.

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.17 /* $Id: boa.c,v 1.16 2002/09/30 18:18: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     int devnullfd = -1;
55    
56     int main(int argc, char **argv)
57     {
58 nmav 1.15 int c; /* command line arg */
59     socket_type server_s[2] = { {-1, 0, 0, 0}, {-1, -1, 0, 0} }; /* boa socket */
60     server_params *params;
61    
62     /* set umask to u+rw, u-x, go-rwx */
63     c = umask(~0600);
64     if (c == -1) {
65     perror("umask");
66     exit(1);
67     }
68    
69     devnullfd = open("/dev/null", 0);
70    
71     /* make STDIN and STDOUT point to /dev/null */
72     if (devnullfd == -1) {
73     DIE("can't open /dev/null");
74     }
75    
76     if (dup2(devnullfd, STDIN_FILENO) == -1) {
77     DIE("can't dup2 /dev/null to STDIN_FILENO");
78     }
79    
80     if (dup2(devnullfd, STDOUT_FILENO) == -1) {
81     DIE("can't dup2 /dev/null to STDOUT_FILENO");
82     }
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     drop_privs();
146     create_common_env();
147     build_needs_escape();
148 nmav 1.1
149 nmav 1.11 #ifdef ENABLE_SSL
150 nmav 1.15 if (boa_ssl) {
151     initialize_ssl();
152     }
153     #endif
154    
155     initialize_mmap();
156    
157 nmav 1.17 initialize_rlimits();
158 nmav 1.15
159     /* background ourself */
160     if (do_fork) {
161     switch (fork()) {
162     case -1:
163     /* error */
164     perror("fork");
165     exit(1);
166     break;
167     case 0:
168     /* child, success */
169     break;
170     default:
171     /* parent, success */
172     exit(0);
173     break;
174     }
175     }
176    
177     /* main loop */
178     timestamp();
179    
180     start_time = current_time;
181    
182     /* Blocks signals that are not supposed to be catched
183     * by the children.
184     */
185     block_main_signals();
186    
187 nmav 1.14 #ifdef ENABLE_HIC
188 nmav 1.15 hic_init();
189 nmav 1.14 #endif
190 nmav 1.1
191 nmav 1.15 /* spawn the children pool
192     */
193     params = smp_init(server_s);
194    
195     /* unblock signals for daddy
196     */
197     unblock_main_signals();
198 nmav 1.1
199 nmav 1.15 /* regenerate parameters in that time interval
200     */
201 nmav 1.11 #ifdef ENABLE_SSL
202 nmav 1.15 if (boa_ssl) {
203     if (ssl_params_refresh < DEFAULT_SSL_PARAMS_REFRESH) {
204     log_error_time();
205     fprintf(stderr,
206     "SSL parameters will be refreshed every %d minutes\n",
207     DEFAULT_SSL_PARAMS_REFRESH / 60);
208     ssl_params_refresh = DEFAULT_SSL_PARAMS_REFRESH;
209     }
210     alarm(ssl_params_refresh);
211     }
212 nmav 1.11 #endif
213 nmav 1.1
214 nmav 1.15 select_loop(params);
215 nmav 1.1
216 nmav 1.15 return 0;
217 nmav 1.1 }
218    
219     server_params *global_server_params;
220 nmav 1.15 int global_server_params_size = 0;
221 nmav 1.1
222 nmav 1.15 #ifdef ENABLE_HIC
223     hic_params *global_hic_params = NULL;
224     int global_hic_params_size = 0;
225     #endif
226 nmav 1.1
227     /* This function will return a server_params pointer. This
228     * pointer is to be used as a pointer to the select loop.
229     */
230 nmav 1.15 static server_params *smp_init(socket_type server_s[2])
231 nmav 1.1 {
232 nmav 1.15 int i;
233     server_params *params;
234 nmav 1.1
235     #ifdef ENABLE_SMP
236 nmav 1.15 pthread_t tid;
237     int max_threads = max_server_threads;
238 nmav 1.1
239 nmav 1.15 father_id = pthread_self();
240 nmav 1.1 #else
241 nmav 1.15 const int max_threads = 1;
242 nmav 1.1 #endif
243    
244 nmav 1.15 params = malloc(sizeof(server_params) * max_threads);
245     if (params == NULL) {
246 nmav 1.1 log_error_time();
247 nmav 1.15 fprintf(stderr, "Could not allocate memory.\n");
248 nmav 1.1 exit(1);
249 nmav 1.15 }
250    
251     for (i = 0; i < max_threads; i++) {
252     params[i].server_s[0] = server_s[0];
253     params[i].server_s[1] = server_s[1];
254     params[i].request_ready = NULL;
255     params[i].request_block = NULL;
256     params[i].request_free = NULL;
257    
258     /* for signal handling */
259     params[i].sighup_flag = 0;
260     params[i].sigchld_flag = 0;
261     params[i].sigalrm_flag = 0;
262     params[i].sigusr1_flag = 0;
263     params[i].sigterm_flag = 0;
264    
265     params[i].sockbufsize = SOCKETBUF_SIZE;
266    
267     params[i].status.requests = 0;
268     params[i].status.errors = 0;
269    
270     params[i].total_connections = 0;
271     params[i].max_fd = 0;
272    
273     params[i].handle_sigbus = 0;
274     }
275 nmav 1.1
276     #ifdef ENABLE_SMP
277 nmav 1.15 params[0].tid = father_id;
278 nmav 1.1
279 nmav 1.15 for (i = 1; i < max_threads; i++) {
280     if (pthread_create(&tid, NULL, &select_loop, &params[i]) != 0) {
281     log_error_time();
282     fprintf(stderr, "Could not dispatch threads.\n");
283     exit(1);
284 nmav 1.1 }
285     params[i].tid = tid;
286 nmav 1.15 }
287 nmav 1.1 #endif
288    
289 nmav 1.15 if (max_threads > 1) {
290 nmav 1.1 log_error_time();
291 nmav 1.15 fprintf(stderr,
292     "%s: Dispatched %d HTTP server threads.\n", SERVER_NAME,
293     max_threads);
294     }
295 nmav 1.1
296 nmav 1.15 global_server_params_size = max_threads;
297     global_server_params = params;
298 nmav 1.1
299 nmav 1.15 return &params[0];
300 nmav 1.1 }
301    
302     void smp_reinit()
303     {
304     #ifdef ENABLE_SMP
305 nmav 1.2 int i;
306     server_params *params = global_server_params;
307 nmav 1.15 int max_threads = max_server_threads;
308 nmav 1.1 #else
309 nmav 1.2 int max_threads = 1;
310 nmav 1.1 #endif
311    
312 nmav 1.2 if (global_server_params_size < max_threads) {
313 nmav 1.15 log_error_time();
314     fprintf(stderr, "Cannot increase threads on runtime.\n");
315     max_threads = global_server_params_size;
316 nmav 1.2 }
317 nmav 1.1 #ifdef ENABLE_SMP
318 nmav 1.15 for (i = 1; i < max_threads; i++) {
319 nmav 1.1 pthread_t tid;
320 nmav 1.15 if (pthread_create(&tid, NULL, &select_loop, &params[i]) != 0) {
321     log_error_time();
322     fprintf(stderr, "Could not dispatch threads.\n");
323     exit(1);
324 nmav 1.1 }
325     params[i].tid = tid;
326 nmav 1.2 }
327 nmav 1.1 #endif
328    
329 nmav 1.2 if (max_threads > 0) {
330 nmav 1.1 log_error_time();
331 nmav 1.15 fprintf(stderr, "Regenerated a pool of %d threads.\n", max_threads);
332     }
333 nmav 1.1
334 nmav 1.2 return;
335 nmav 1.1 }
336    
337 nmav 1.8 #ifdef ENABLE_HIC
338 nmav 1.10
339     pthread_t hic_tid;
340 nmav 1.8
341     /* This function will return a server_params pointer. This
342     * pointer is to be used as a pointer to the select loop.
343     */
344 nmav 1.15 void hic_init()
345 nmav 1.8 {
346 nmav 1.15 hic_params *params = global_hic_params;
347     int i;
348     #ifdef ENABLE_SMP
349     pthread_t tid;
350     #endif
351    
352     if (max_hic_threads == 0)
353     return;
354 nmav 1.8
355     #ifdef ENABLE_SMP
356    
357 nmav 1.15 if (global_hic_params_size > 0
358     && global_hic_params_size != max_hic_threads) {
359     log_error_time();
360     fprintf(stderr,
361     "Cannot change the HIC threads number on runtime.\n");
362     max_hic_threads = global_hic_params_size;
363     } else {
364     /* first time.. Allocate memory */
365     params = calloc(1, sizeof(hic_params) * max_hic_threads);
366     if (params == NULL) {
367     log_error_time();
368     fprintf(stderr,
369     "Could not allocate memory for HIC parameters.\n");
370     exit(1);
371     }
372    
373     for (i = 0; i < max_hic_threads; i++) { /* initialize mutexes */
374     pthread_mutex_init(&params[i].lock, NULL);
375 nmav 1.8 }
376    
377 nmav 1.15 global_hic_params = params;
378     global_hic_params_size = max_hic_threads;
379    
380     }
381    
382     for (i = 0; i < max_hic_threads; i++) {
383     if (pthread_create(&tid, NULL, &hic_main_loop, &params[i]) != 0) {
384     log_error_time();
385     fprintf(stderr, "Could not dispatch hic thread.\n");
386     exit(1);
387     }
388     params[i].tid = tid;
389     }
390    
391     log_error_time();
392     fprintf(stderr,
393     "%s: Dispatched %d HIC threads.\n", SERVER_NAME,
394     max_hic_threads);
395 nmav 1.8
396     #endif
397    
398 nmav 1.15 return;
399 nmav 1.8 }
400    
401 nmav 1.15 #endif /* ENABLE_HIC */
402 nmav 1.1
403 nmav 1.15 static socket_type create_server_socket(int port, int secure)
404 nmav 1.1 {
405 nmav 1.15 socket_type server_s;
406 nmav 1.1
407 nmav 1.15 server_s.secure = secure;
408     server_s.port = port;
409    
410     server_s.socket = socket(SERVER_AF, SOCK_STREAM, IPPROTO_TCP);
411     if (server_s.socket == -1) {
412     DIE("unable to create socket");
413     }
414    
415     /* server socket is nonblocking */
416     if (set_nonblock_fd(server_s.socket) == -1) {
417     DIE("fcntl: unable to set server socket to nonblocking");
418     }
419    
420     /* close server socket on exec so cgi's can't write to it */
421     if (fcntl(server_s.socket, F_SETFD, 1) == -1) {
422     DIE("can't set close-on-exec on server socket!");
423     }
424 nmav 1.1
425 nmav 1.15 /* reuse socket addr */
426     if ((setsockopt
427     (server_s.socket, SOL_SOCKET, SO_REUSEADDR, (void *) &sock_opt,
428     sizeof(sock_opt))) == -1) {
429     DIE("setsockopt");
430     }
431    
432     /* internet family-specific code encapsulated in bind_server() */
433     if (bind_server(server_s.socket, server_ip, port) == -1) {
434     DIE("unable to bind");
435     }
436    
437     /* listen: large number just in case your kernel is nicely tweaked */
438     if (listen(server_s.socket, backlog) == -1) {
439     DIE("unable to listen");
440     }
441     return server_s;
442 nmav 1.1 }
443    
444     static void drop_privs(void)
445     {
446 nmav 1.15 /* give away our privs if we can */
447     if (getuid() == 0) {
448     struct passwd *passwdbuf;
449     passwdbuf = getpwuid(server_uid);
450     if (passwdbuf == NULL) {
451     DIE("getpwuid");
452     }
453     if (initgroups(passwdbuf->pw_name, passwdbuf->pw_gid) == -1) {
454     DIE("initgroups");
455     }
456     if (setgid(server_gid) == -1) {
457     DIE("setgid");
458     }
459     if (setuid(server_uid) == -1) {
460     DIE("setuid");
461     }
462     /* test for failed-but-return-was-successful setuid
463     * http://www.securityportal.com/list-archive/bugtraq/2000/Jun/0101.html
464     */
465     if (setuid(0) != -1) {
466     DIE("icky Linux kernel bug!");
467     }
468     } else {
469     if (server_gid || server_uid) {
470     log_error_time();
471     fprintf(stderr, "Warning: "
472     "Not running as root: no attempt to change"
473     " to uid %d gid %d\n", server_uid, server_gid);
474     }
475     server_gid = getgid();
476     server_uid = getuid();
477     }
478 nmav 1.1 }
479    
480     /*
481     * Name: fixup_server_root
482     *
483     * Description: Makes sure the server root is valid.
484     *
485     */
486    
487     static void fixup_server_root()
488     {
489 nmav 1.15 char *dirbuf;
490 nmav 1.1
491 nmav 1.15 if (!server_root) {
492 nmav 1.1 #ifdef SERVER_ROOT
493 nmav 1.15 server_root = strdup(SERVER_ROOT);
494     if (!server_root) {
495     perror("strdup (SERVER_ROOT)");
496     exit(1);
497     }
498 nmav 1.1 #else
499 nmav 1.15 fputs(SERVER_NAME
500     ": don't know where server root is. Please #define "
501     "SERVER_ROOT in defines.h\n"
502     "and recompile, or use the -c command line option to "
503     "specify it.\n", stderr);
504     exit(1);
505     #endif
506     }
507    
508     if (chdir(server_root) == -1) {
509     fprintf(stderr, "Could not chdir to \"%s\": aborting\n",
510     server_root);
511     exit(1);
512     }
513    
514     dirbuf = normalize_path(server_root);
515     free(server_root);
516     server_root = dirbuf;
517 nmav 1.1 }
518    
519 nmav 1.15 char boa_tls_version[64] = "\0";
520 nmav 1.16 char boa_version[] = "Server: "SERVER_NAME"/"SERVER_VERSION"\r\n";
521 nmav 1.15
522     static void create_server_names()
523     {
524     if ( boa_tls_version[0] == 0) {
525     strcpy( boa_tls_version, "Server: "SERVER_NAME"/"SERVER_VERSION" GnuTLS/");
526     strcat( boa_tls_version, gnutls_check_version(NULL));
527 nmav 1.16 strcat( boa_tls_version, "\r\n");
528 nmav 1.15 }
529     }
530 nmav 1.17
531     #ifdef HAVE_GETRLIMIT
532    
533     #ifndef RLIMIT_NOFILE
534     # define RLIMIT_NOFILE RLIMIT_OFILE
535     #endif
536    
537     #ifndef LONG_MAX
538     # define LONG_MAX 2147483647L
539     #endif
540    
541     #define SET_MAX_CON( lim) \
542     if (lim == RLIM_INFINITY) { \
543     max_connections = LONG_MAX; \
544     } else { \
545     max_connections = lim; \
546     }
547    
548     static void initialize_rlimits( )
549     {
550     int c;
551     struct rlimit rl;
552    
553     if (max_connections > 0 && max_connections < 1) {
554     /* has not been set explicitly */
555     c = getrlimit(RLIMIT_NOFILE, &rl);
556     if (c < 0) {
557     perror("getrlimit");
558     exit(1);
559     }
560     SET_MAX_CON( rl.rlim_cur);
561     #ifdef HAVE_SETRLIMIT
562     if (rl.rlim_max > rl.rlim_cur) {
563     rl.rlim_cur = rl.rlim_max;
564     c = setrlimit(RLIMIT_NOFILE, &rl);
565     if (c < 0) {
566     perror("setrlimit:");
567     }
568    
569     SET_MAX_CON( rl.rlim_max);
570    
571     }
572     #endif
573     }
574     }
575    
576     #else /* rlimits are not present */
577     static void initialize_rlimits( )
578     {
579     return;
580     }
581     #endif

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26