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

Contents of /hydra/src/boa.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.9 - (show annotations)
Fri Sep 27 23:40:29 2002 UTC (21 years, 6 months ago) by nmav
Branch: MAIN
Changes since 1.8: +3 -3 lines
File MIME type: text/plain
Improvements on HIC support.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26