/** * 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; pid_t pid; struct socket_info* si; int* startup_done = NULL; atomic_t *load_p; chd_rank=0; if (dont_fork){ 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; load_p = shm_malloc(sizeof(atomic_t)); if (!load_p) { /* highly improbable */ LM_ERR("no more shm\n"); goto error; } memset(load_p,0,sizeof(atomic_t)); pt[process_no].load = load_p; register_udp_load_stat(&udp_listen->sock_str,load_p); 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){ load_p = shm_malloc(sizeof(atomic_t)); if (!load_p) { /* highly improbable */ LM_ERR("no more shm\n"); goto error; } memset(load_p,0,sizeof(atomic_t)); register_udp_load_stat(&si->sock_str,load_p); 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"); exit(-1); } 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"); exit(-1); } 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"); exit(-1); } 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; } 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 */ return -1; }
/** * 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* startup_done = NULL; chd_rank=0; if (init_debug() != 0) { LM_ERR("failed to init logging levels\n"); goto error; } if (dont_fork) { if (create_status_pipe() < 0) { LM_ERR("failed to create status pipe\n"); goto error; } if (udp_init_nofork() < 0) { LM_ERR("failed to init UDP for no fork mode\n"); goto error; } /* 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; } is_main=1; udp_start_nofork(); /* udp_start_nofork() returns only if error */ /* in case of failed startup, behave as "attendant" to trigger * proper cleanup sequance (and proper signal handler !!!). * So, reset the dont_fork (as it will force inline signal handling)*/ dont_fork = 0; return -1; } else { /* don't fork */ if (trans_init_all_listeners()<0) { LM_ERR("failed to init all SIP listeners, aborting\n"); goto error; } /* 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; } if (fix_socket_list(&bin) != 0) { LM_ERR("failed to initialize binary interface socket list!\n"); goto error; } /* OpenSIPS <--> OpenSIPS communication interface */ if (bin && start_bin_receivers() != 0) { LM_CRIT("cannot start binary interface receiver processes!\n"); goto error; } /* fork for the timer process*/ if (start_timer_processes()!=0) { LM_CRIT("cannot start timer process(es)\n"); goto error; } /* fork all processes required by UDP network layer */ if (udp_start_processes( &chd_rank, startup_done)<0) { LM_CRIT("cannot start TCP processes\n"); goto error; } /* fork all processes required by TCP network layer */ if (tcp_start_processes( &chd_rank, startup_done)<0) { LM_CRIT("cannot start TCP processes\n"); goto error; } } /* this is the main process -> it shouldn't send anything */ bind_address=0; if (startup_done) { if (*startup_done==0) LM_CRIT("BUG: startup route defined, but not run :( \n"); shm_free(startup_done); } /* 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"); report_failure_status(); goto error; } report_conditional_status( (!no_daemon_mode), 0); 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 */ report_conditional_status( (!dont_fork), -1); return -1; }
/* main loop */ int main_loop() { int i; pid_t pid; struct socket_info* si; #ifdef USE_TCP int sockfd[2]; #endif /* one "main" process and n children handling i/o */ is_main=0; if (dont_fork){ #ifdef STATS setstats( 0 ); #endif if (udp_listen==0){ LOG(L_ERR, "ERROR: 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){ LOG(L_WARN, "WARNING: using only the first listen address" " (no fork)\n"); } /* initialize fifo server -- we need to open the fifo before * do_suid() and start the fifo server after all the socket * are initialized, to inherit them*/ if (init_fifo_server()<0) { LOG(L_ERR, "initializing fifo server failed\n"); goto error; } /* Initialize Unix domain socket server */ if (init_unixsock_socket()<0) { LOG(L_ERR, "Error while creating unix domain sockets\n"); goto error; } if (do_suid()==-1) goto error; /* try to drop privileges */ /* process_no now initialized to zero -- increase from now on as new processes are forked (while skipping 0 reserved for main */ /* we need another process to act as the timer*/ #ifdef USE_TCP /* if we are using tcp we always need a timer process, * we cannot count on select timeout to measure time * (it works only on linux) */ if ((!tcp_disable)||(timer_list)) #else if (timer_list) #endif { process_no++; if ((pid=fork())<0){ LOG(L_CRIT, "ERROR: main_loop: Cannot fork\n"); goto error; } if (pid==0){ /* child */ /* timer!*/ /* process_bit = 0; */ if (init_child(PROC_TIMER) < 0) { LOG(L_ERR, "timer: init_child failed\n"); goto error; } for(;;){ sleep(TIMER_TICK); timer_ticker(); } }else{ pt[process_no].pid=pid; /*should be shared mem anyway*/ strncpy(pt[process_no].desc, "timer", MAX_PT_DESC ); } } /* if configured, start a server for accepting FIFO commands, * we need to do it after all the sockets are initialized, to * inherit them*/ if (start_fifo_server()<0) { LOG(L_ERR, "starting fifo server failed\n"); goto error; } if (init_unixsock_children()<0) { LOG(L_ERR, "Error while initializing Unix domain socket server\n"); goto error; } /* main process, receive loop */ process_no=0; /*main process number*/ pt[process_no].pid=getpid(); snprintf(pt[process_no].desc, MAX_PT_DESC, "stand-alone receiver @ %s:%s", bind_address->name.s, bind_address->port_no_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) { LOG(L_ERR, "main_dontfork: init_child failed\n"); goto error; } is_main=1; /* hack 42: call init_child with is_main=0 in case some modules wants to fork a child */ return udp_rcv_loop(); }else{ /* process_no now initialized to zero -- increase from now on as new processes are forked (while skipping 0 reserved for main ) */ 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 */ /* initialize fifo server -- we need to open the fifo before * do_suid() and start the fifo server after all the socket * are initialized, to inherit them*/ if (init_fifo_server()<0) { LOG(L_ERR, "initializing fifo server failed\n"); goto error; } /* Initialize Unix domain socket server */ /* Create the unix domain sockets */ if (init_unixsock_socket()<0) { LOG(L_ERR, "ERROR: Could not create unix domain sockets\n"); goto error; } /* all processes should have access to all the sockets (for sending) * so we open all first*/ if (do_suid()==-1) goto error; /* try to drop privileges */ /* if configured, start a server for accepting FIFO commands, * we need to do it after all the sockets are initialized, to * inherit them*/ if (start_fifo_server()<0) { LOG(L_ERR, "starting fifo server failed\n"); goto error; } /* Spawn children listening on unix domain socket if and only if * the unix domain socket server has not been disabled (i == 0) */ if (init_unixsock_children()<0) { LOG(L_ERR, "ERROR: Could not initialize unix domain socket server\n"); goto error; } /* udp processes */ for(si=udp_listen; si; si=si->next){ for(i=0;i<children_no;i++){ process_no++; #ifdef USE_TCP if(!tcp_disable){ if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd)<0){ LOG(L_ERR, "ERROR: main_loop: socketpair failed: %s\n", strerror(errno)); goto error; } } #endif if ((pid=fork())<0){ LOG(L_CRIT, "main_loop: Cannot fork\n"); goto error; }else if (pid==0){ /* child */ #ifdef USE_TCP if (!tcp_disable){ close(sockfd[0]); unix_tcp_sock=sockfd[1]; } #endif bind_address=si; /* shortcut */ if (init_child(i + 1) < 0) { LOG(L_ERR, "init_child failed\n"); goto error; } #ifdef STATS setstats( i+r*children_no ); #endif return udp_rcv_loop(); }else{ pt[process_no].pid=pid; /*should be in shared mem.*/ snprintf(pt[process_no].desc, MAX_PT_DESC, "receiver child=%d sock= %s:%s", i, si->name.s, si->port_no_str.s ); #ifdef USE_TCP if (!tcp_disable){ close(sockfd[1]); pt[process_no].unix_sock=sockfd[0]; pt[process_no].idx=-1; /* this is not a "tcp" process*/ } #endif } } /*parent*/ /*close(udp_sock)*/; /*if it's closed=>sendto invalid fd errors?*/ } } /*this is the main process*/ bind_address=0; /* main proc -> it shouldn't send anything, */ #ifdef USE_TCP /* if we are using tcp we always need the timer */ if ((!tcp_disable)||(timer_list)) #else if (timer_list) #endif { #ifdef USE_TCP if (!tcp_disable){ if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd)<0){ LOG(L_ERR, "ERROR: main_loop: socketpair failed: %s\n", strerror(errno)); goto error; } } #endif /* fork again for the attendant process*/ process_no++; if ((pid=fork())<0){ LOG(L_CRIT, "main_loop: cannot fork timer process\n"); goto error; }else if (pid==0){ /* child */ /* is_main=0; */ #ifdef USE_TCP if (!tcp_disable){ close(sockfd[0]); unix_tcp_sock=sockfd[1]; } #endif if (init_child(PROC_TIMER) < 0) { LOG(L_ERR, "timer: init_child failed\n"); goto error; } for(;;){ /* debug: instead of doing something useful */ /* (placeholder for timers, etc.) */ sleep(TIMER_TICK); /* if we received a signal => TIMER_TICK may have not elapsed*/ timer_ticker(); } }else{ pt[process_no].pid=pid; strncpy(pt[process_no].desc, "timer", MAX_PT_DESC ); #ifdef USE_TCP if(!tcp_disable){ close(sockfd[1]); pt[process_no].unix_sock=sockfd[0]; pt[process_no].idx=-1; /* this is not a "tcp" process*/ } #endif } } #ifdef USE_TCP if (!tcp_disable){ /* start tcp & tls receivers */ if (tcp_init_children()<0) goto error; /* start tcp+tls master proc */ process_no++; if ((pid=fork())<0){ LOG(L_CRIT, "main_loop: cannot fork tcp main process\n"); goto error; }else if (pid==0){ /* child */ /* is_main=0; */ if (init_child(PROC_TCP_MAIN) < 0) { LOG(L_ERR, "tcp_main: error in init_child\n"); goto error; } tcp_main_loop(); }else{ pt[process_no].pid=pid; strncpy(pt[process_no].desc, "tcp main process", MAX_PT_DESC ); pt[process_no].unix_sock=-1; pt[process_no].idx=-1; /* this is not a "tcp" process*/ unix_tcp_sock=-1; } } #endif /* main */ pt[0].pid=getpid(); strncpy(pt[0].desc, "attendant", MAX_PT_DESC ); #ifdef USE_TCP if(!tcp_disable){ pt[process_no].unix_sock=-1; pt[process_no].idx=-1; /* this is not a "tcp" process*/ unix_tcp_sock=-1; } #endif /*DEBUG- remove it*/ #ifdef DEBUG fprintf(stderr, "\n% 3d processes (%3d), % 3d children * " "listening addresses + tcp listeners + tls listeners" "+ main + fifo %s\n", process_no+1, process_count(), children_no, (timer_list)?"+ timer":""); for (r=0; r<=process_no; r++){ fprintf(stderr, "% 3d % 5d - %s\n", r, pt[r].pid, pt[r].desc); } #endif process_no=0; /* process_bit = 0; */ is_main=1; if (init_child(PROC_MAIN) < 0) { LOG(L_ERR, "main: error in init_child\n"); goto error; } for(;;){ pause(); handle_sigs(); } /*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 */ return -1; }
/** * 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 (init_debug() != 0) { LM_ERR("failed to init logging levels\n"); goto error; } 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, 1)!=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; } if (fix_socket_list(&bin) != 0) { LM_ERR("failed to initialize binary interface socket list!\n"); goto error; } /* OpenSIPS <--> OpenSIPS communication interface */ if (bin && start_bin_receivers() != 0) { LM_CRIT("cannot start binary interface receiver processes!\n"); goto error; } /* udp processes */ for(si=udp_listen; si; si=si->next){ if(register_udp_load_stat(&si->sock_str,&load_p,si->children)!=0){ LM_ERR("failed to init load statistics\n"); goto error; } for(i=0;i<si->children;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(); if (chd_rank == 1 && startup_done) *startup_done = -1; exit(-1); } /* first UDP proc runs statup_route (if defined) */ if(chd_rank == 1 && startup_done!=NULL) { LM_DBG("runing startup for first UDP\n"); if(run_startup_route()< 0) { if (send_status_code(-1) < 0) LM_ERR("failed to send status code\n"); clean_write_pipeend(); *startup_done = -1; LM_ERR("Startup route processing failed\n"); exit(-1); } *startup_done = 1; } if (!no_daemon_mode && send_status_code(0) < 0) LM_ERR("failed to send status code\n"); clean_write_pipeend(); /* all UDP listeners on same interface * have same SHM load pointer */ pt[process_no].load = load_p; udp_rcv_loop(); exit(-1); } else { /* wait for first proc to finish the startup route */ if(chd_rank == 1 && startup_done!=NULL) while( !(*startup_done) ) {usleep(5);handle_sigs();} } } } /*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<si->children;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(); if( (si==sctp_listen && i==0) && startup_done) *startup_done = -1; exit(-1); } /* was startup route executed so far ? if not, run it only by the * first SCTP proc (first proc from first interface) */ if( (si==sctp_listen && i==0) && startup_done!=NULL && *startup_done==0) { LM_DBG("runing startup for first SCTP\n"); if(run_startup_route()< 0) { LM_ERR("Startup route processing failed\n"); if (send_status_code(-1) < 0) LM_ERR("failed to send status code\n"); clean_write_pipeend(); *startup_done = -1; exit(-1); } *startup_done = 1; } if (!no_daemon_mode && send_status_code(0) < 0) LM_ERR("failed to send status code\n"); clean_write_pipeend(); sctp_server_rcv_loop(); exit(-1); } else { /* wait for first proc to finish the startup route */ if( (si==sctp_listen && i==0) && startup_done!=NULL) while( !(*startup_done) ) {usleep(5);handle_sigs();} } } } } #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, startup_done)<0) goto error; /* wait for the startup route to be executed */ if( startup_done!=NULL) while( !(*startup_done) ) {usleep(5);handle_sigs();} /* 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 (!no_daemon_mode && send_status_code(0) < 0) LM_ERR("failed to send status code\n"); clean_write_pipeend(); tcp_main_loop(); exit(-1); } } #endif if (startup_done) { if (*startup_done==0) LM_CRIT("BUG: startup route defined, but not run :( \n"); shm_free(startup_done); } /* main process left */ is_main=1; set_proc_attrs("attendant"); if (init_child(PROC_MAIN) < 0) { if (send_status_code(-1) < 0) LM_ERR("failed to send status code\n"); clean_write_pipeend(); LM_ERR("error in init_child for PROC_MAIN\n"); goto error; } if (!no_daemon_mode && 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; }
/** * Main routine, start of the program execution. * \param argc the number of arguments * \param argv pointer to the arguments array * \return don't return on sucess, -1 on error * \see main_loop */ int main(int argc, char** argv) { /* configure by default logging to syslog */ int cfg_log_stderr = 1; FILE* cfg_stream; int c,r; char *tmp; int tmp_len; int port; int proto; char *options; int ret; unsigned int seed; int rfd; /*init*/ ret=-1; my_argc=argc; my_argv=argv; /* process pkg mem size from command line */ opterr=0; options="f:cCm:M:b:l:n:N:rRvdDFETSVhw:t:u:g:P:G:W:o:"; while((c=getopt(argc,argv,options))!=-1){ switch(c){ case 'M': pkg_mem_size=strtol(optarg, &tmp, 10) * 1024 * 1024; if (tmp &&(*tmp)){ LM_ERR("bad pkgmem size number: -m %s\n", optarg); goto error00; }; break; } } /*init pkg mallocs (before parsing cfg but after parsing cmd line !)*/ if (init_pkg_mallocs()==-1) goto error00; init_route_lists(); /* process command line (get port no, cfg. file path etc) */ /* first reset getopt */ optind = 1; while((c=getopt(argc,argv,options))!=-1){ switch(c){ case 'f': cfg_file=optarg; break; case 'C': config_check |= 2; case 'c': if (config_check==3) break; config_check |= 1; cfg_log_stderr=1; /* force stderr logging */ break; case 'm': shm_mem_size=strtol(optarg, &tmp, 10) * 1024 * 1024; if (tmp &&(*tmp)){ LM_ERR("bad shmem size number: -m %s\n", optarg); goto error00; }; break; case 'M': /* ignoring it, parsed previously */ break; case 'b': maxbuffer=strtol(optarg, &tmp, 10); if (tmp &&(*tmp)){ LM_ERR("bad max buffer size number: -b %s\n", optarg); goto error00; } break; case 'l': if (parse_phostport(optarg, strlen(optarg), &tmp, &tmp_len, &port, &proto)<0){ LM_ERR("bad -l address specifier: %s\n", optarg); goto error00; } tmp[tmp_len]=0; /* null terminate the host */ /* add a new addr. to our address list */ if (add_cmd_listener(tmp, port, proto)!=0){ LM_ERR("failed to add new listen address\n"); goto error00; } break; case 'n': children_no=strtol(optarg, &tmp, 10); if ((tmp==0) ||(*tmp)){ LM_ERR("bad process number: -n %s\n", optarg); goto error00; } break; case 'v': check_via=1; break; case 'r': received_dns|=DO_DNS; break; case 'R': received_dns|=DO_REV_DNS; break; case 'd': *log_level = debug_mode ? L_DBG : (*log_level)+1; break; case 'D': debug_mode=1; *log_level = L_DBG; break; case 'F': no_daemon_mode=1; break; case 'E': cfg_log_stderr=1; break; case 'N': tcp_children_no=strtol(optarg, &tmp, 10); if ((tmp==0) ||(*tmp)){ LM_ERR("bad process number: -N %s\n", optarg); goto error00; } break; case 'W': io_poll_method=get_poll_type(optarg); if (io_poll_method==POLL_NONE){ LM_ERR("bad poll method name: -W %s\ntry " "one of %s.\n", optarg, poll_support); goto error00; } break; case 'V': printf("version: %s\n", version); printf("flags: %s\n", flags ); print_ct_constants(); printf("%s compiled on %s with %s\n", __FILE__, compiled, COMPILER ); exit(0); break; case 'h': printf("version: %s\n", version); printf("%s",help_msg); exit(0); break; case 'w': working_dir=optarg; break; case 't': chroot_dir=optarg; break; case 'u': user=optarg; break; case 'g': group=optarg; break; case 'P': pid_file=optarg; break; case 'G': pgid_file=optarg; break; case 'o': if (add_arg_var(optarg) < 0) LM_ERR("cannot add option %s\n", optarg); break; case '?': if (isprint(optopt)) LM_ERR("Unknown option `-%c`.\n", optopt); else LM_ERR("Unknown option character `\\x%x`.\n", optopt); goto error00; case ':': LM_ERR("Option `-%c` requires an argument.\n", optopt); goto error00; default: abort(); } } log_stderr = cfg_log_stderr; /* fill missing arguments with the default values*/ if (cfg_file==0) cfg_file=CFG_FILE; /* load config file or die */ cfg_stream=fopen (cfg_file, "r"); if (cfg_stream==0){ LM_ERR("loading config file(%s): %s\n", cfg_file, strerror(errno)); goto error00; } /* seed the prng, try to use /dev/urandom if possible */ /* no debugging information is logged, because the standard log level prior the config file parsing is L_NOTICE */ seed=0; if ((rfd=open("/dev/urandom", O_RDONLY))!=-1){ try_again: if (read(rfd, (void*)&seed, sizeof(seed))==-1){ if (errno==EINTR) goto try_again; /* interrupted by signal */ LM_WARN("could not read from /dev/urandom (%d)\n", errno); } LM_DBG("initialize the pseudo random generator from " "/dev/urandom\n"); LM_DBG("read %u from /dev/urandom\n", seed); close(rfd); }else{ LM_WARN("could not open /dev/urandom (%d)\n", errno); LM_WARN("using a unsafe seed for the pseudo random number generator"); } seed+=getpid()+time(0); LM_DBG("seeding PRNG with %u\n", seed); srand(seed); LM_DBG("test random number %u\n", rand()); /*register builtin modules*/ register_builtin_modules(); /* init avps */ if (init_global_avps() != 0) { LM_ERR("error while initializing avps\n"); goto error; } /* used for parser debugging */ #ifdef DEBUG_PARSER yydebug = 1; #endif /* * initializes transport interfaces - we initialize them here because we * can have listening interfaces declared in the command line */ if (trans_init() < 0) { LM_ERR("cannot initialize transport interface\n"); goto error; } /* get uid/gid */ if (user){ if (user2uid(&uid, &gid, user)<0){ LM_ERR("bad user name/uid number: -u %s\n", user); goto error00; } } if (group){ if (group2gid(&gid, group)<0){ LM_ERR("bad group name/gid number: -u %s\n", group); goto error00; } } /*init shm mallocs * this must be here * -to allow setting shm mem size from the command line * -it must be also before init_timer and init_tcp * -it must be after we know uid (so that in the SYSV sems case, * the sems will have the correct euid) * --andrei */ if (init_shm_mallocs()==-1) goto error; if (init_stats_collector() < 0) { LM_ERR("failed to initialize statistics\n"); goto error; } /* parse the config file, prior to this only default values e.g. for debugging settings will be used */ yyin=cfg_stream; if ((yyparse()!=0)||(cfg_errors)){ LM_ERR("bad config file (%d errors)\n", cfg_errors); goto error00; } if (config_check>1 && check_rls()!=0) { LM_ERR("bad function call in config file\n"); return ret; } if (solve_module_dependencies(modules) != 0) { LM_ERR("failed to solve module dependencies\n"); return -1; } /* init the resolver, before fixing the config */ resolv_init(); fix_poll_method( &io_poll_method ); /* fix temporary listeners added in the cmd line */ if (fix_cmd_listeners() < 0) { LM_ERR("cannot add temproray listeners\n"); return ret; } /* load transport protocols */ if (trans_load() < 0) { LM_ERR("cannot load transport protocols\n"); goto error; } /* fix parameters */ if (working_dir==0) working_dir="/"; if (fix_all_socket_lists()!=0){ LM_ERR("failed to initialize list addresses\n"); goto error00; } /* print all the listen addresses */ printf("Listening on \n"); print_all_socket_lists(); printf("Aliases: \n"); /*print_aliases();*/ print_aliases(); printf("\n"); if (config_check){ LM_NOTICE("config file ok, exiting...\n"); return 0; } time(&startup_time); /* Init statistics */ init_shm_statistics(); /*init UDP networking layer*/ if (udp_init()<0){ LM_CRIT("could not initialize tcp\n"); goto error; } /*init TCP networking layer*/ if (tcp_init()<0){ LM_CRIT("could not initialize tcp\n"); goto error; } if (create_status_pipe() < 0) { LM_ERR("failed to create status pipe\n"); goto error; } if (debug_mode) { LM_NOTICE("DEBUG MODE activated\n"); if (no_daemon_mode==0) { LM_NOTICE("disabling daemon mode (found enabled)\n"); no_daemon_mode = 1; } if (log_stderr==0) { LM_NOTICE("enabling logging to standard error (found disabled)\n"); log_stderr = 1; } if (*log_level<L_DBG) { LM_NOTICE("setting logging to debug level (found on %d)\n", *log_level); *log_level = L_DBG; } if (disable_core_dump) { LM_NOTICE("enabling core dumping (found off)\n"); disable_core_dump = 0; } if (udp_count_processes()!=0) { if (children_no!=2) { LM_NOTICE("setting UDP children to 2 (found %d)\n", children_no); children_no = 2; } } if (tcp_count_processes()!=0) { if (tcp_children_no!=2) { LM_NOTICE("setting TCP children to 2 (found %d)\n", tcp_children_no); tcp_children_no = 2; } } } else { /* debug_mode */ /* init_daemon */ if ( daemonize((log_name==0)?argv[0]:log_name, &own_pgid) <0 ) goto error; } /* install signal handlers */ if (install_sigs() != 0){ LM_ERR("could not install the signal handlers\n"); goto error; } if (disable_core_dump) set_core_dump(0, 0); else set_core_dump(1, shm_mem_size+pkg_mem_size+4*1024*1024); if (open_files_limit>0) { if(set_open_fds_limit()<0){ LM_ERR("ERROR: error could not increase file limits\n"); goto error; } } /* print OpenSIPS version to log for history tracking */ LM_NOTICE("version: %s\n", version); /* print some data about the configuration */ LM_INFO("using %ld Mb shared memory\n", ((shm_mem_size/1024)/1024)); LM_INFO("using %ld Mb private memory per process\n", ((pkg_mem_size/1024)/1024)); /* init async reactor */ if (init_reactor_size()<0) { LM_CRIT("failed to init internal reactor, exiting...\n"); goto error; } /* init timer */ if (init_timer()<0){ LM_CRIT("could not initialize timer, exiting...\n"); goto error; } /* init serial forking engine */ if (init_serialization()!=0) { LM_ERR("failed to initialize serialization\n"); goto error; } /* Init MI */ if (init_mi_core()<0) { LM_ERR("failed to initialize MI core\n"); goto error; } /* Register core events */ if (evi_register_core() != 0) { LM_ERR("failed register core events\n"); goto error; } /* init black list engine */ if (init_black_lists()!=0) { LM_CRIT("failed to init blacklists\n"); goto error; } /* init resolver's blacklist */ if (resolv_blacklist_init()!=0) { LM_CRIT("failed to create DNS blacklist\n"); goto error; } /* init modules */ if (init_modules() != 0) { LM_ERR("error while initializing modules\n"); goto error; } /* register route timers */ if(register_route_timers() < 0) { LM_ERR("Failed to register timer\n"); goto error; } /* check pv context list */ if(pv_contextlist_check() != 0) { LM_ERR("used pv context that was not defined\n"); goto error; } /* init query list now in shm * so all processes that will be forked from now on * will have access to it * * if it fails, give it a try and carry on */ if (init_ql_support() != 0) { LM_ERR("failed to initialise buffering query list\n"); query_buffer_size = 0; *query_list = NULL; } /* init multi processes support */ if (init_multi_proc_support()!=0) { LM_ERR("failed to init multi-proc support\n"); goto error; } #ifdef PKG_MALLOC /* init stats support for pkg mem */ if (init_pkg_stats(counted_processes)!=0) { LM_ERR("failed to init stats for pkg\n"); goto error; } #endif /* init avps */ if (init_extra_avps() != 0) { LM_ERR("error while initializing avps\n"); goto error; } /* fix routing lists */ if ( (r=fix_rls())!=0){ LM_ERR("failed to fix configuration with err code %d\n", r); goto error; } if (init_log_level() != 0) { LM_ERR("failed to init logging levels\n"); goto error; } if (trans_init_all_listeners()<0) { LM_ERR("failed to init all SIP listeners, aborting\n"); goto error; } /* all processes should have access to all the sockets (for sending) * so we open all first*/ if (do_suid(uid, gid)==-1) goto error; ret = main_loop(); error: /*kill everything*/ kill_all_children(SIGTERM); /*clean-up*/ cleanup(0); error00: LM_NOTICE("Exiting....\n"); return ret; }