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

Annotation of /hydra/src/boa.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.15 - (hide annotations)
Mon Sep 30 17:16:54 2002 UTC (21 years, 6 months ago) by nmav
Branch: MAIN
Changes since 1.14: +381 -333 lines
File MIME type: text/plain
Added support for multiple HIC threads.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26