/** * Main loop, forks the children, bind to addresses, * handle signals. * \return don't return on sucess, -1 on error */ static int main_loop(void) { static int chd_rank; int i,rc; pid_t pid; struct socket_info* si; int* startup_done = NULL; stat_var *load_p = NULL; chd_rank=0; if (dont_fork) { if (create_status_pipe() < 0) { LM_ERR("failed to create status pipe"); goto error; } if (udp_listen==0) { LM_ERR("no fork mode requires at least one" " udp listen address, exiting...\n"); goto error; } /* only one address, we ignore all the others */ if (udp_init(udp_listen)==-1) goto error; bind_address=udp_listen; sendipv4=bind_address; sendipv6=bind_address; /*FIXME*/ if (udp_listen->next) { LM_WARN("using only the first listen address (no fork)\n"); } /* try to drop privileges */ if (do_suid(uid, gid)==-1) goto error; if (start_module_procs()!=0) { LM_ERR("failed to fork module processes\n"); goto error; } /* we need another process to act as the timer*/ if (start_timer_processes()!=0) { LM_CRIT("cannot start timer process(es)\n"); goto error; } /* main process, receive loop */ set_proc_attrs("stand-alone SIP receiver %.*s", bind_address->sock_str.len, bind_address->sock_str.s ); /* We will call child_init even if we * do not fork - and it will be called with rank 1 because * in fact we behave like a child, not like main process */ if (init_child(1) < 0) { LM_ERR("init_child failed in don't fork\n"); goto error; } if (startup_rlist.a) run_startup_route(); is_main=1; if (register_udp_load_stat(&udp_listen->sock_str, &pt[process_no].load)!=0) { LM_ERR("failed to init udp load statistics\n"); goto error; } clean_write_pipeend(); LM_DBG("waiting for status code from children\n"); rc = wait_for_all_children(); if (rc < 0) { LM_ERR("failed to succesfully init children\n"); return rc; } return udp_rcv_loop(); } else { /* don't fork */ for(si=udp_listen; si; si=si->next) { /* create the listening socket (for each address)*/ /* udp */ if (udp_init(si)==-1) goto error; /* get first ipv4/ipv6 socket*/ if ((si->address.af==AF_INET)&& ((sendipv4==0)||(sendipv4->flags&SI_IS_LO))) sendipv4=si; #ifdef USE_IPV6 if((sendipv6==0)&&(si->address.af==AF_INET6)) sendipv6=si; #endif } #ifdef USE_TCP if (!tcp_disable) { for(si=tcp_listen; si; si=si->next) { /* same thing for tcp */ if (tcp_init(si)==-1) goto error; /* get first ipv4/ipv6 socket*/ if ((si->address.af==AF_INET)& ((sendipv4_tcp==0)||(sendipv4_tcp->flags&SI_IS_LO))) sendipv4_tcp=si; #ifdef USE_IPV6 if((sendipv6_tcp==0)&&(si->address.af==AF_INET6)) sendipv6_tcp=si; #endif } } #ifdef USE_TLS if (!tls_disable) { for(si=tls_listen; si; si=si->next) { /* same as for tcp*/ if (tls_init(si)==-1) goto error; /* get first ipv4/ipv6 socket*/ if ((si->address.af==AF_INET)&& ((sendipv4_tls==0)||(sendipv4_tls->flags&SI_IS_LO))) sendipv4_tls=si; #ifdef USE_IPV6 if((sendipv6_tls==0)&&(si->address.af==AF_INET6)) sendipv6_tls=si; #endif } } #endif /* USE_TLS */ #endif /* USE_TCP */ #ifdef USE_SCTP if (!sctp_disable) { for(si=sctp_listen; si; si=si->next) { /* same thing for sctp */ if (sctp_server_init(si)==-1) goto error; /* get first ipv4/ipv6 socket*/ if ((si->address.af==AF_INET)&& ((sendipv4_sctp==0)||(sendipv4_sctp->flags&SI_IS_LO))) sendipv4_sctp=si; #ifdef USE_IPV6 if((sendipv6_sctp==0)&&(si->address.af==AF_INET6)) sendipv6_sctp=si; #endif } } #endif /* USE_SCTP */ /* all processes should have access to all the sockets (for sending) * so we open all first*/ if (do_suid(uid, gid)==-1) goto error; /* try to drop privileges */ if (start_module_procs()!=0) { LM_ERR("failed to fork module processes\n"); goto error; } if(startup_rlist.a) {/* if a startup route was defined */ startup_done = (int*)shm_malloc(sizeof(int)); if(startup_done == NULL) { LM_ERR("No more shared memory\n"); goto error; } *startup_done = 0; } /* udp processes */ for(si=udp_listen; si; si=si->next) { if (register_udp_load_stat(&si->sock_str, &load_p)!=0) { LM_ERR("failed to init load statistics\n"); goto error; } for(i=0; i<children_no; i++) { chd_rank++; if ( (pid=internal_fork( "UDP receiver"))<0 ) { LM_CRIT("cannot fork UDP process\n"); goto error; } else { if (pid==0) { /* new UDP process */ /* set a more detailed description */ set_proc_attrs("SIP receiver %.*s ", si->sock_str.len, si->sock_str.s); bind_address=si; /* shortcut */ if (init_child(chd_rank) < 0) { LM_ERR("init_child failed for UDP listener\n"); if (send_status_code(-1) < 0) LM_ERR("failed to send status code\n"); clean_write_pipeend(); exit(-1); } if (send_status_code(0) < 0) LM_ERR("failed to send status code\n"); clean_write_pipeend(); if(chd_rank == 1 && startup_rlist.a) { if(run_startup_route()< 0) { LM_ERR("Startup route processing failed\n"); exit(-1); } *startup_done = 1; } /* all UDP listeners on same interface * have same SHM load pointer */ pt[process_no].load = load_p; udp_rcv_loop(); exit(-1); } else { /* if the first process that runs startup_route*/ if(chd_rank == 1 && startup_rlist.a) { while(!startup_done) { usleep(5); } shm_free(startup_done); } } } } /*parent*/ /*close(udp_sock)*/; /*if it's closed=>sendto invalid fd errors?*/ } } #ifdef USE_SCTP if(!sctp_disable) { for(si=sctp_listen; si; si=si->next) { for(i=0; i<children_no; i++) { chd_rank++; if ( (pid=internal_fork( "SCTP receiver"))<0 ) { LM_CRIT("cannot fork SCTP process\n"); goto error; } else if (pid==0) { /* new SCTP process */ /* set a more detailed description */ set_proc_attrs("SIP receiver %.*s ", si->sock_str.len, si->sock_str.s); bind_address=si; /* shortcut */ if (init_child(chd_rank) < 0) { LM_ERR("init_child failed\n"); if (send_status_code(-1) < 0) LM_ERR("failed to send status code\n"); clean_write_pipeend(); exit(-1); } if (send_status_code(0) < 0) LM_ERR("failed to send status code\n"); clean_write_pipeend(); sctp_server_rcv_loop(); exit(-1); } } } } #endif /* USE_SCTP */ /* this is the main process -> it shouldn't send anything */ bind_address=0; /* fork for the timer process*/ if (start_timer_processes()!=0) { LM_CRIT("cannot start timer process(es)\n"); goto error; } #ifdef USE_TCP if (!tcp_disable) { /* start tcp & tls receivers */ if (tcp_init_children(&chd_rank)<0) goto error; /* start tcp+tls master proc */ if ( (pid=internal_fork( "TCP main"))<0 ) { LM_CRIT("cannot fork tcp main process\n"); goto error; } else if (pid==0) { /* child */ /* close the TCP inter-process sockets */ close(unix_tcp_sock); unix_tcp_sock = -1; close(pt[process_no].unix_sock); pt[process_no].unix_sock = -1; /* init modules */ if (init_child(PROC_TCP_MAIN) < 0) { LM_ERR("error in init_child for tcp main\n"); if (send_status_code(-1) < 0) LM_ERR("failed to send status code\n"); clean_write_pipeend(); exit(-1); } if (send_status_code(0) < 0) LM_ERR("failed to send status code\n"); clean_write_pipeend(); tcp_main_loop(); exit(-1); } } #endif /* main process left */ is_main=1; set_proc_attrs("attendant"); if (init_child(PROC_MAIN) < 0) { LM_ERR("error in init_child for PROC_MAIN\n"); goto error; } if (send_status_code(0) < 0) LM_ERR("failed to send status code\n"); clean_write_pipeend(); for(;;) { handle_sigs(); pause(); } /*return 0; */ error: is_main=1; /* if we are here, we are the "main process", any forked children should exit with exit(-1) and not ever use return */ if (!dont_fork && send_status_code(-1) < 0) LM_ERR("failed to send status code\n"); clean_write_pipeend(); return -1; }
int start_timer_processes(void) { struct sr_timer_process *tpl; pid_t pid; /* * A change of the way timers were run. In the pre-1.5 times, * all timer processes had their own jiffies and just the first * one was doing the global ones. Now, there's a separate process * that increases jiffies - run_timer_process_jif(), and the rest * just use that one. * * The main reason for this change was when a function that relied * on jiffies for its timeouts got called from the timer thread and * was unable to detect timeouts. */ if ( (pid=internal_fork("time_keeper"))<0 ) { LM_CRIT("cannot fork time keeper process\n"); goto error; } else if (pid==0) { /* new process */ clean_write_pipeend(); run_timer_process_jif(); exit(-1); } for( tpl=timer_proc_list ; tpl ; tpl=tpl->next ) { if (tpl->timer_list==NULL && tpl->utimer_list==NULL) continue; /* fork a new process */ if ( (pid=internal_fork("timer"))<0 ) { LM_CRIT("cannot fork timer process\n"); goto error; } else if (pid==0) { /* new process */ /* run init if required */ if ( tpl->flags&TIMER_PROC_INIT_FLAG ) { LM_DBG("initializing timer\n"); inc_init_timer(); if (init_child(PROC_TIMER)<0 ) { LM_ERR("init_child failed for timer proc\n"); if (send_status_code(-1) < 0) LM_ERR("failed to send status code\n"); clean_write_pipeend(); exit(-1); } if (!no_daemon_mode && send_status_code(0) < 0) LM_ERR("failed to send status code\n"); clean_write_pipeend(); } else clean_write_pipeend(); run_timer_process( tpl ); exit(-1); } } return 0; error: return -1; }
/*! \brief starts the tcp processes */ int tcp_init_children(int *chd_rank) { int r; //int sockfd[2]; int reader_fd[2]; /* for comm. with the tcp children read */ pid_t pid; struct socket_info *si; atomic_t *load_p; /* estimate max fd. no: * 1 tcp send unix socket/all_proc, * + 1 udp sock/udp proc + 1 tcp_child sock/tcp child* * + no_listen_tcp */ for(r=0, si=tcp_listen; si; si=si->next, r++); #ifdef USE_TLS if (! tls_disable) for (si=tls_listen; si; si=si->next, r++); #endif tcp_max_fd_no=counted_processes*2 +r-1 /* timer */ +3; /* stdin/out/err*/ tcp_max_fd_no+=tcp_max_connections; /* create the tcp sock_info structures */ /* copy the sockets --moved to main_loop*/ load_p = shm_malloc(sizeof(atomic_t)); if (!load_p) goto error; memset(load_p,0,sizeof(atomic_t)); if (register_tcp_load_stat(load_p)!=0) { LM_ERR("failed to init tcp load statistics\n"); goto error; } /* fork children & create the socket pairs*/ for(r=0; r<tcp_children_no; r++){ /*if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd)<0){ LM_ERR("socketpair failed: %s\n", strerror(errno)); goto error; }*/ if (socketpair(AF_UNIX, SOCK_STREAM, 0, reader_fd)<0){ LM_ERR("socketpair failed: %s\n", strerror(errno)); goto error; } (*chd_rank)++; pid=internal_fork("SIP receiver TCP"); if (pid<0){ LM_ERR("fork failed\n"); goto error; }else if (pid>0){ /* parent */ close(reader_fd[1]); tcp_children[r].pid=pid; tcp_children[r].proc_no=process_no; tcp_children[r].busy=0; tcp_children[r].n_reqs=0; tcp_children[r].unix_sock=reader_fd[0]; }else{ /* child */ set_proc_attrs("TCP receiver"); pt[process_no].idx=r; pt[process_no].load = load_p; bind_address=0; /* force a SEGFAULT if someone uses a non-init. bind address on tcp */ if (init_child(*chd_rank) < 0) { LM_ERR("init_children failed\n"); if (send_status_code(-1) < 0) LM_ERR("failed to send status code\n"); clean_write_pipeend(); exit(-1); } if (send_status_code(0) < 0) LM_ERR("failed to send status code\n"); clean_write_pipeend(); tcp_receive_loop(reader_fd[1]); exit(-1); } } return 0; error: return -1; }
/*! * \brief daemon init * \param name daemon name * \param own_pgid daemon process group * \return return 0 on success, -1 on error */ int daemonize(char* name, int * own_pgid) { FILE *pid_stream; pid_t pid; int r, p,rc; int pid_items; p=-1; /* flush std file descriptors to avoid flushes after fork * (same message appearing multiple times) * and switch to unbuffered */ setbuf(stdout, 0); setbuf(stderr, 0); if (chroot_dir&&(chroot(chroot_dir)<0)){ LM_CRIT("Cannot chroot to %s: %s\n", chroot_dir, strerror(errno)); goto error; } if (chdir(working_dir)<0){ LM_CRIT("Cannot chdir to %s: %s\n", working_dir, strerror(errno)); goto error; } if (create_status_pipe() < 0) { LM_ERR("failed to create status pipe"); goto error; } if (!no_daemon_mode) { /* fork to become!= group leader*/ if ((pid=fork())<0){ LM_CRIT("Cannot fork:%s\n", strerror(errno)); goto error; }else if (pid!=0){ /* parent process => wait for status codes from children*/ clean_write_pipeend(); LM_DBG("waiting for status code from children\n"); rc = wait_for_all_children(); LM_INFO("pre-daemon process exiting with %d\n",rc); exit(rc); } /* cleanup read end - nobody should * need to read from status pipe from this point on */ clean_read_pipeend(); /* become session leader to drop the ctrl. terminal */ if (setsid()<0){ LM_WARN("setsid failed: %s\n",strerror(errno)); }else{ *own_pgid=1;/* we have our own process group */ } /* fork again to drop group leadership */ if ((pid=fork())<0){ LM_CRIT("Cannot fork:%s\n", strerror(errno)); goto error; }else if (pid!=0){ /*parent process => exit */ exit(0); } } #ifdef __OS_linux /* setsid may disables core dumping on linux, reenable it */ if ( !disable_core_dump && prctl(PR_SET_DUMPABLE, 1)) { LM_ERR("Cannot enable core dumping after setuid\n"); } #endif /* added by noh: create a pid file for the main process */ if (pid_file!=0){ if ((pid_stream=fopen(pid_file, "r"))!=NULL){ pid_items=fscanf(pid_stream, "%d", &p); fclose(pid_stream); if (p==-1 || pid_items <= 0){ LM_WARN("pid file %s exists, but doesn't contain a valid" " pid number, replacing...\n", pid_file); } else if (kill((pid_t)p, 0)==0 || errno==EPERM){ LM_CRIT("running process found in the pid file %s\n", pid_file); goto error; }else{ LM_WARN("pid file contains old pid, replacing pid\n"); } } pid=getpid(); if ((pid_stream=fopen(pid_file, "w"))==NULL){ LM_ERR("unable to create pid file %s: %s\n", pid_file, strerror(errno)); goto error; }else{ r = fprintf(pid_stream, "%i\n", (int)pid); if (r<=0) { LM_ERR("unable to write pid to file %s: %s\n", pid_file, strerror(errno)); goto error; } fclose(pid_stream); } } if (pgid_file!=0){ if ((pid_stream=fopen(pgid_file, "r"))!=NULL){ pid_items=fscanf(pid_stream, "%d", &p); fclose(pid_stream); if (p==-1 || pid_items <= 0){ LM_WARN("pgid file %s exists, but doesn't contain a valid" " pgid number, replacing...\n", pgid_file); } } if (own_pgid){ pid=getpgid(0); if ((pid_stream=fopen(pgid_file, "w"))==NULL){ LM_ERR("unable to create pgid file %s: %s\n", pgid_file, strerror(errno)); goto error; }else{ r = fprintf(pid_stream, "%i\n", (int)pid); if (r<=0) { LM_ERR("unable to write pgid to file %s: %s\n", pid_file, strerror(errno)); goto error; } fclose(pid_stream); } }else{ LM_WARN("we don't have our own process so we won't save" " our pgid\n"); unlink(pgid_file); /* just to be sure nobody will miss-use the old value*/ } } /* try to replace stdin, stdout & stderr with /dev/null */ if (freopen("/dev/null", "r", stdin)==0){ LM_WARN("unable to replace stdin with /dev/null: %s\n", strerror(errno)); /* continue, leave it open */ }; if (freopen("/dev/null", "w", stdout)==0){ LM_WARN("unable to replace stdout with /dev/null: %s\n", strerror(errno)); /* continue, leave it open */ }; /* close stderr only if not to be used */ if ( (!log_stderr) && (freopen("/dev/null", "w", stderr)==0)){ LM_WARN("unable to replace stderr with /dev/null: %s\n", strerror(errno)); /* continue, leave it open */ }; /* close any open file descriptors */ closelog(); /* 32 is the maximum number of inherited open file descriptors */ for (r=3; r < 32; r++){ /* future children must still inherit * and write to this pipe end */ if (r != status_pipe[1]) close(r); } if (!log_stderr) openlog(name, LOG_PID|LOG_CONS, log_facility); /* LOG_CONS, LOG_PERRROR ? */ return 0; error: return -1; }
int start_module_procs(void) { struct sr_module *m; unsigned int n; unsigned int l; pid_t x; for( m=modules ; m ; m=m->next) { if (m->exports->procs==NULL) continue; for( n=0 ; m->exports->procs[n].name ; n++) { if ( !m->exports->procs[n].no || !m->exports->procs[n].function ) continue; /* run pre-fork function */ if (m->exports->procs[n].pre_fork_function) if (m->exports->procs[n].pre_fork_function()!=0) { LM_ERR("pre-fork function failed for process \"%s\" " "in module %s\n", m->exports->procs[n].name, m->exports->name); return -1; } /* fork the processes */ for ( l=0; l<m->exports->procs[n].no ; l++) { LM_DBG("forking process \"%s\"/%d for module %s\n", m->exports->procs[n].name, l, m->exports->name); x = internal_fork(m->exports->procs[n].name); if (x<0) { LM_ERR("failed to fork process \"%s\"/%d for module %s\n", m->exports->procs[n].name, l, m->exports->name); return -1; } else if (x==0) { /* new process */ /* initialize the process for the rest of the modules */ if ( m->exports->procs[n].flags&PROC_FLAG_INITCHILD ) { if (init_child(PROC_MODULE) < 0) { LM_ERR("error in init_child for PROC_MODULE\n"); if (send_status_code(-1) < 0) LM_ERR("failed to send status code\n"); clean_write_pipeend(); exit(-1); } if (send_status_code(0) < 0) LM_ERR("failed to send status code\n"); clean_write_pipeend(); } else clean_write_pipeend(); /* run the function */ m->exports->procs[n].function(l); /* we shouldn't get here */ exit(0); } } /* run post-fork function */ if (m->exports->procs[n].post_fork_function) if (m->exports->procs[n].post_fork_function()!=0) { LM_ERR("post-fork function failed for process \"%s\" " "in module %s\n", m->exports->procs[n].name, m->exports->name); return -1; } } } return 0; }