/**
 * 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;

}
Exemple #2
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;
}