static int child_init(int rank) { /* Note: We call init_fifo_server from mod_init, this * will call the function at an early init stage -- before * do_suid, thus the function would have sufficient permissions * to change the user and group for FIFO * * start_fifo_server gets called from PROC_MAIN child init, this * ensures that the function gets called at the end of the init * process, when all the sockets are properly initialized. */ if (rank == PROC_MAIN) { /* FIXME: nofork rank==1 */ if (start_fifo_server() < 0) return -1; } return 0; }
/* 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; }