Example #1
0
/**
 * 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;

}
Example #2
0
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;
}
Example #3
0
/*! \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;
}
Example #4
0
/*!
 * \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;
}
Example #5
0
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;
}