00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00036 #include "pt.h"
00037 #include "tcp_init.h"
00038 #include "sr_module.h"
00039 #include "socket_info.h"
00040 #include "rand/fastrand.h"
00041 #ifdef PKG_MALLOC
00042 #include "mem/mem.h"
00043 #endif
00044 #ifdef SHM_MEM
00045 #include "mem/shm_mem.h"
00046 #endif
00047 #if defined PKG_MALLOC || defined SHM_MEM
00048 #include "cfg_core.h"
00049 #endif
00050 #include "daemonize.h"
00051
00052 #include <stdio.h>
00053 #include <time.h>
00054
00055 #define FORK_DONT_WAIT
00056
00057
00058
00059
00060 #ifdef PROFILING
00061 #include <sys/gmon.h>
00062
00063 extern void _start(void);
00064 extern void etext(void);
00065 #endif
00066
00067
00068 static int estimated_proc_no=0;
00069 static int estimated_fds_no=0;
00070
00071
00072 static unsigned int fork_delay = 0;
00073
00074 unsigned int set_fork_delay(unsigned int v)
00075 {
00076 unsigned int r;
00077 r = fork_delay;
00078 fork_delay = v;
00079 return r;
00080 }
00081
00082
00083 static int calc_common_open_fds_no(void)
00084 {
00085 int max_fds_no;
00086
00087
00088
00089
00090
00091
00092
00093
00094 max_fds_no=estimated_proc_no*4
00095
00096
00097 -1 + 3 +
00098 #ifdef USE_IPV6
00099 2*mhomed
00100 #else
00101 mhomed
00102 #endif
00103 ;
00104 return max_fds_no;
00105 }
00106
00107
00108
00109
00110 int init_pt(int proc_no)
00111 {
00112 #ifdef USE_TCP
00113 int r;
00114 #endif
00115
00116 estimated_proc_no+=proc_no;
00117 estimated_fds_no+=calc_common_open_fds_no();
00118
00119 #ifdef SHM_MEM
00120 pt=shm_malloc(sizeof(struct process_table)*estimated_proc_no);
00121 process_count = shm_malloc(sizeof(int));
00122 #else
00123 pt=pkg_malloc(sizeof(struct process_table)*estimated_proc_no);
00124 process_count = pkg_malloc(sizeof(int));
00125 #endif
00126 process_lock = lock_alloc();
00127 process_lock = lock_init(process_lock);
00128 if (pt==0||process_count==0||process_lock==0){
00129 LOG(L_ERR, "ERROR: out of memory\n");
00130 return -1;
00131 }
00132 memset(pt, 0, sizeof(struct process_table)*estimated_proc_no);
00133 #ifdef USE_TCP
00134 for (r=0; r<estimated_proc_no; r++){
00135 pt[r].unix_sock=-1;
00136 pt[r].idx=-1;
00137 }
00138 #endif
00139 process_no=0;
00140 pt[process_no].pid=getpid();
00141 memcpy(pt[process_no].desc,"main",5);
00142 *process_count=1;
00143 return 0;
00144 }
00145
00146
00147
00148
00149
00150
00151 int register_procs(int no)
00152 {
00153 if (pt){
00154 LOG(L_CRIT, "BUG: register_procs(%d) called at runtime\n", no);
00155 return -1;
00156 }
00157 estimated_proc_no+=no;
00158 return 0;
00159 }
00160
00161
00162
00163
00164 int get_max_procs()
00165 {
00166 if (pt==0){
00167 LOG(L_CRIT, "BUG: get_max_procs() called too early "
00168 "(it must _not_ be called from mod_init())\n");
00169 abort();
00170 }
00171 return estimated_proc_no;
00172 }
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183 int register_fds(int no)
00184 {
00185
00186 estimated_fds_no+=no;
00187 return 0;
00188 }
00189
00190
00191
00192
00193 int get_max_open_fds()
00194 {
00195 if (pt==0){
00196 LOG(L_CRIT, "BUG: get_max_open_fds() called too early "
00197 "(it must _not_ be called from mod_init())\n");
00198 abort();
00199 }
00200 return estimated_fds_no;
00201 }
00202
00203
00204
00205 int my_pid()
00206 {
00207 return pt ? pt[process_no].pid : getpid();
00208 }
00209
00210
00211
00212
00213 int close_extra_socks(int child_id, int proc_no)
00214 {
00215 #ifdef USE_TCP
00216 int r;
00217 struct socket_info* si;
00218
00219 if (child_id!=PROC_TCP_MAIN){
00220 for (r=0; r<proc_no; r++){
00221 if (pt[r].unix_sock>=0){
00222
00223
00224 close(pt[r].unix_sock);
00225 }
00226 }
00227
00228 if (!tcp_disable){
00229 for(si=tcp_listen; si; si=si->next){
00230 close(si->socket);
00231
00232 si->socket=-1;
00233 }
00234 #ifdef USE_TLS
00235 if (!tls_disable){
00236 for(si=tls_listen; si; si=si->next){
00237 close(si->socket);
00238
00239 si->socket=-1;
00240 }
00241 }
00242 #endif
00243 }
00244
00245
00246 }
00247 #endif
00248 return 0;
00249 }
00250
00251
00252
00261 int fork_process(int child_id, char *desc, int make_sock)
00262 {
00263 int pid, child_process_no;
00264 int ret;
00265 unsigned int new_seed1;
00266 unsigned int new_seed2;
00267 #ifdef USE_TCP
00268 int sockfd[2];
00269 #endif
00270
00271 if(unlikely(fork_delay>0))
00272 sleep_us(fork_delay);
00273
00274 ret=-1;
00275 #ifdef USE_TCP
00276 sockfd[0]=sockfd[1]=-1;
00277 if(make_sock && !tcp_disable){
00278 if (!is_main){
00279 LOG(L_CRIT, "BUG: fork_process(..., 1) called from a non "
00280 "\"main\" process! If forking from a module's "
00281 "child_init() fork only if rank==PROC_MAIN or"
00282 " give up tcp send support (use 0 for make_sock)\n");
00283 goto error;
00284 }
00285 if (tcp_main_pid){
00286 LOG(L_CRIT, "BUG: fork_process(..., 1) called, but tcp main "
00287 " is already started\n");
00288 goto error;
00289 }
00290 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd)<0){
00291 LOG(L_ERR, "ERROR: fork_process(): socketpair failed: %s\n",
00292 strerror(errno));
00293 goto error;
00294 }
00295 }
00296 #endif
00297 lock_get(process_lock);
00298 if (*process_count>=estimated_proc_no) {
00299 LOG(L_CRIT, "ERROR: fork_process(): Process limit of %d exceeded."
00300 " Will simulate fork fail.\n", estimated_proc_no);
00301 lock_release(process_lock);
00302 goto error;
00303 }
00304
00305
00306 child_process_no = *process_count;
00307 new_seed1=rand();
00308 new_seed2=random();
00309 pid = fork();
00310 if (pid<0) {
00311 lock_release(process_lock);
00312 ret=pid;
00313 goto error;
00314 }else if (pid==0){
00315
00316 is_main=0;
00317 process_no=child_process_no;
00318 daemon_status_on_fork_cleanup();
00319
00320 #ifdef USE_TCP
00321 close_extra_socks(child_id, process_no);
00322 #endif
00323 srand(new_seed1);
00324 fastrand_seed(rand());
00325 srandom(new_seed2+time(0));
00326 shm_malloc_on_fork();
00327 #ifdef PROFILING
00328 monstartup((u_long) &_start, (u_long) &etext);
00329 #endif
00330 #ifdef FORK_DONT_WAIT
00331
00332
00333 pt[process_no].pid=getpid();
00334 #else
00335
00336
00337
00338 lock_get(process_lock);
00339 lock_release(process_lock);
00340 #endif
00341 #ifdef USE_TCP
00342 if (make_sock && !tcp_disable){
00343 close(sockfd[0]);
00344 unix_tcp_sock=sockfd[1];
00345 }
00346 #endif
00347 if ((child_id!=PROC_NOCHLDINIT) && (init_child(child_id) < 0)) {
00348 LOG(L_ERR, "ERROR: fork_process(): init_child failed for "
00349 " process %d, pid %d, \"%s\"\n", process_no,
00350 pt[process_no].pid, pt[process_no].desc);
00351 return -1;
00352 }
00353 return pid;
00354 } else {
00355
00356 (*process_count)++;
00357 #ifdef FORK_DONT_WAIT
00358 lock_release(process_lock);
00359 #endif
00360
00361 pt[child_process_no].pid=pid;
00362 if (desc){
00363 strncpy(pt[child_process_no].desc, desc, MAX_PT_DESC);
00364 }
00365 #ifdef USE_TCP
00366 if (make_sock && !tcp_disable){
00367 close(sockfd[1]);
00368 pt[child_process_no].unix_sock=sockfd[0];
00369 pt[child_process_no].idx=-1;
00370 }
00371 #endif
00372 #ifdef FORK_DONT_WAIT
00373 #else
00374 lock_release(process_lock);
00375 #endif
00376 ret=pid;
00377 goto end;
00378 }
00379 error:
00380 #ifdef USE_TCP
00381 if (sockfd[0]!=-1) close(sockfd[0]);
00382 if (sockfd[1]!=-1) close(sockfd[1]);
00383 #endif
00384 end:
00385 return ret;
00386 }
00387
00395 #ifdef USE_TCP
00396 int fork_tcp_process(int child_id, char *desc, int r, int *reader_fd_1)
00397 {
00398 int pid, child_process_no;
00399 int sockfd[2];
00400 int reader_fd[2];
00401 int ret;
00402 int i;
00403 unsigned int new_seed1;
00404 unsigned int new_seed2;
00405
00406
00407 sockfd[0]=sockfd[1]=-1;
00408 reader_fd[0]=reader_fd[1]=-1;
00409 ret=-1;
00410
00411 if (!is_main){
00412 LOG(L_CRIT, "BUG: fork_tcp_process() called from a non \"main\" "
00413 "process\n");
00414 goto error;
00415 }
00416 if (tcp_main_pid){
00417 LOG(L_CRIT, "BUG: fork_tcp_process(..., 1) called _after_ starting"
00418 " tcp main\n");
00419 goto error;
00420 }
00421 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd)<0){
00422 LOG(L_ERR, "ERROR: fork_tcp_process(): socketpair failed: %s\n",
00423 strerror(errno));
00424 goto error;
00425 }
00426 if (socketpair(AF_UNIX, SOCK_STREAM, 0, reader_fd)<0){
00427 LOG(L_ERR, "ERROR: fork_tcp_process(): socketpair failed: %s\n",
00428 strerror(errno));
00429 goto error;
00430 }
00431 if (tcp_fix_child_sockets(reader_fd)<0){
00432 LOG(L_ERR, "ERROR: fork_tcp_process(): failed to set non blocking"
00433 "on child sockets\n");
00434
00435
00436 }
00437 lock_get(process_lock);
00438
00439 if (*process_count>=estimated_proc_no) {
00440 LOG(L_CRIT, "ERROR: fork_tcp_process(): Process limit of %d exceeded."
00441 " Simulating fork fail\n", estimated_proc_no);
00442 lock_release(process_lock);
00443 goto error;
00444 }
00445
00446
00447 child_process_no = *process_count;
00448 new_seed1=rand();
00449 new_seed2=random();
00450 pid = fork();
00451 if (pid<0) {
00452 lock_release(process_lock);
00453 ret=pid;
00454 goto end;
00455 }
00456 if (pid==0){
00457 is_main=0;
00458 process_no=child_process_no;
00459
00460 close_extra_socks(child_id, process_no);
00461
00462 for (i=0; i<r; i++){
00463 if (tcp_children[i].unix_sock>=0){
00464 close(tcp_children[i].unix_sock);
00465
00466
00467 tcp_children[i].unix_sock=-1;
00468 }
00469 }
00470 daemon_status_on_fork_cleanup();
00471 srand(new_seed1);
00472 fastrand_seed(rand());
00473 srandom(new_seed2+time(0));
00474 shm_malloc_on_fork();
00475 #ifdef PROFILING
00476 monstartup((u_long) &_start, (u_long) &etext);
00477 #endif
00478 #ifdef FORK_DONT_WAIT
00479
00480
00481 pt[process_no].pid=getpid();
00482 #else
00483
00484 lock_get(process_lock);
00485 lock_release(process_lock);
00486 #endif
00487 close(sockfd[0]);
00488 unix_tcp_sock=sockfd[1];
00489 close(reader_fd[0]);
00490 if (reader_fd_1) *reader_fd_1=reader_fd[1];
00491 if ((child_id!=PROC_NOCHLDINIT) && (init_child(child_id) < 0)) {
00492 LOG(L_ERR, "ERROR: fork_tcp_process(): init_child failed for "
00493 "process %d, pid %d, \"%s\"\n", process_no,
00494 pt[process_no].pid, pt[process_no].desc);
00495 return -1;
00496 }
00497 return pid;
00498 } else {
00499
00500 (*process_count)++;
00501 #ifdef FORK_DONT_WAIT
00502 lock_release(process_lock);
00503 #endif
00504
00505 pt[child_process_no].pid=pid;
00506 pt[child_process_no].unix_sock=sockfd[0];
00507 pt[child_process_no].idx=r;
00508 if (desc){
00509 snprintf(pt[child_process_no].desc, MAX_PT_DESC, "%s child=%d",
00510 desc, r);
00511 }
00512 #ifdef FORK_DONT_WAIT
00513 #else
00514 lock_release(process_lock);
00515 #endif
00516
00517 close(sockfd[1]);
00518 close(reader_fd[1]);
00519
00520 tcp_children[r].pid=pid;
00521 tcp_children[r].proc_no=child_process_no;
00522 tcp_children[r].busy=0;
00523 tcp_children[r].n_reqs=0;
00524 tcp_children[r].unix_sock=reader_fd[0];
00525
00526 ret=pid;
00527 goto end;
00528 }
00529 error:
00530 if (sockfd[0]!=-1) close(sockfd[0]);
00531 if (sockfd[1]!=-1) close(sockfd[1]);
00532 if (reader_fd[0]!=-1) close(reader_fd[0]);
00533 if (reader_fd[1]!=-1) close(reader_fd[1]);
00534 end:
00535 return ret;
00536 }
00537 #endif
00538
00539 #ifdef PKG_MALLOC
00540
00541
00542
00543
00544 void mem_dump_pkg_cb(str *gname, str *name)
00545 {
00546 int old_memlog;
00547 int memlog;
00548
00549 if (cfg_get(core, core_cfg, mem_dump_pkg) == my_pid()) {
00550
00551
00552 old_memlog = cfg_get(core, core_cfg, memlog);
00553 memlog = L_ALERT;
00554
00555
00556 ((struct cfg_group_core*)core_cfg)->memlog=memlog;
00557
00558 LOG(memlog, "Memory status (pkg) of process %d:\n", my_pid());
00559 pkg_status();
00560
00561 ((struct cfg_group_core*)core_cfg)->memlog=old_memlog;
00562 }
00563 }
00564 #endif
00565
00566 #ifdef SHM_MEM
00567
00568
00569
00570
00571 int mem_dump_shm_fixup(void *handle, str *gname, str *name, void **val)
00572 {
00573 int old_memlog;
00574 int memlog;
00575
00576 if ((long)(void*)(*val)) {
00577
00578
00579 old_memlog = cfg_get(core, core_cfg, memlog);
00580 memlog = L_ALERT;
00581
00582
00583 ((struct cfg_group_core*)core_cfg)->memlog=memlog;
00584
00585 LOG(memlog, "Memory status (shm)\n");
00586 shm_status();
00587
00588 ((struct cfg_group_core*)core_cfg)->memlog=old_memlog;
00589 *val = (void*)(long)0;
00590 }
00591 return 0;
00592 }
00593 #endif