main.c
512dcd98
 /*
  * $Id$
  */
 
 #include <stdio.h>
3e429f5c
 #include <stdlib.h>
512dcd98
 #include <errno.h>
3e429f5c
 #include <ctype.h>
512dcd98
 #include <string.h>
e60a9728
 #include <netdb.h>
1b1b19d8
 #include <unistd.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <sys/utsname.h>
f571aa35
 #include <sys/types.h>
 #include <sys/mman.h>
 #include <sys/fcntl.h>
 #include <sys/time.h>
e9d701db
 #include <sys/wait.h>
512dcd98
 
e60a9728
 #include "config.h"
512dcd98
 #include "dprint.h"
 #include "route.h"
e60a9728
 #include "udp_server.h"
1b1b19d8
 #include "globals.h"
dda9dab1
 #include "mem/mem.h"
628e3a5a
 #ifdef SHM_MEM
dda9dab1
 #include "mem/shm_mem.h"
628e3a5a
 #endif
bf08223a
 #include "sr_module.h"
cd57180a
 #include "timer.h"
22d4aa5d
 
1b1b19d8
 
726efa25
 #include <signal.h>
0a974a1d
 
5b253cc6
 #include "stats.h"
726efa25
 
03150098
 #ifdef DEBUG_DMALLOC
 #include <dmalloc.h>
 #endif
 
1b1b19d8
 static char id[]="@(#) $Id$";
b2dec9c6
 static char version[]=  NAME " " VERSION " (" ARCH "/" OS ")" ;
247c2b65
 static char compiled[]= __TIME__ __DATE__ ;
7db4ee8d
 static char flags[]=
 "STATS:"
af6fb476
 #ifdef STATS
 "On"
 #else
 "Off"
 #endif
f8d46776
 #ifdef NO_DEBUG
 ", NO_DEBUG"
 #endif
 #ifdef NO_LOG
 ", NO_LOG"
 #endif
25b49bb4
 #ifdef EXTRA_DEBUG
 ", EXTRA_DEBUG"
f8d46776
 #endif
104316b6
 #ifdef DNS_IP_HACK
 ", DNS_IP_HACK"
 #endif
25b49bb4
 #ifdef SHM_MEM
 ", SHM_MEM"
 #endif
dcb5f364
 #ifdef SHM_MMAP
 ", SHM_MMAP"
 #endif
25b49bb4
 #ifdef PKG_MALLOC
 ", PKG_MALLOC"
 #endif
dda9dab1
 #ifdef VQ_MALLOC
 ", VQ_MALLOC"
 #endif
b2dec9c6
 #ifdef F_MALLOC
 ", F_MALLOC"
 #endif
25b49bb4
 #ifdef USE_SHM_MEM
 ", USE_SHM_MEM"
 #endif
 #ifdef DBG_QM_MALLOC
 ", DBG_QM_MALLOC"
 #endif
 #ifdef DEBUG_DMALLOC
 ", DEBUG_DMALLOC"
 #endif
b2dec9c6
 #ifdef FAST_LOCK
 ", FAST_LOCK"
 #endif
726efa25
 ;
 
1b1b19d8
 static char help_msg[]= "\
247c2b65
 Usage: " NAME " -l address [-l address] [options]\n\
1b1b19d8
 Options:\n\
0eb1315e
     -c           Perform loop checks and compute branches\n\
1b1b19d8
     -f file      Configuration file (default " CFG_FILE ")\n\
     -p port      Listen on the specified port (default: 5060)\n\
     -l address   Listen on the specified address (multiple -l mean\n\
                  listening on more addresses). The default behaviour\n\
                  is to listen on the addresses returned by uname(2)\n\
 \n\
     -n processes Number of child processes to fork per interface\n\
                  (default: 8)\n\
 \n\
     -r           Use dns to check if is necessary to add a \"received=\"\n\
                  field to a via\n\
     -R           Same as `-r� but use reverse dns;\n\
                  (to use both use `-rR�)\n\
 \n\
     -v           Turn on \"via:\" host checking when forwarding replies\n\
     -d           Debugging mode (multiple -d increase the level)\n\
     -D           Do not fork into daemon mode\n\
     -E           Log to stderr\n\
     -V           Version number\n\
     -h           This help message\n\
c3ce2841
     -b nr        Maximum receive buffer size which will not be exceeded by\n\
c9ca45b3
                  auto-probing procedure even if  OS allows\n\
     -w  dir      change the working directory to \"dir\" (default \"/\")\n\
     -t  dir      chroot to \"dir\"\n\
     -u uid       change uid \n\
     -g gid       change gid \n"
f571aa35
 #ifdef STATS
 "    -s file	 File to which statistics is dumped (disabled otherwise)\n"
 #endif
 ;
512dcd98
 
af6fb476
 /* print compile-time constants */
 void print_ct_constants()
 {
4bd1673d
 	printf("MAX_RECV_BUFFER_SIZE %d, MAX_LISTEN %d, MAX_URI_SIZE %d, MAX_PROCESSES %d\n",
 		MAX_RECV_BUFFER_SIZE, MAX_LISTEN, MAX_URI_SIZE, MAX_PROCESSES );
af6fb476
 }
512dcd98
 
888ca09d
 /* debuging function */
e60a9728
 /*
888ca09d
 void receive_stdin_loop()
 {
 	#define BSIZE 1024
 	char buf[BSIZE+1];
 	int len;
5655ca6f
 
888ca09d
 	while(1){
 		len=fread(buf,1,BSIZE,stdin);
 		buf[len+1]=0;
 		receive_msg(buf, len);
 		printf("-------------------------\n");
 	}
 }
e60a9728
 */
888ca09d
 
1b1b19d8
 /* global vars */
 
 char* cfg_file = 0;
 unsigned short port_no = 0; /* port on which we listen */
b2e71d5b
 char port_no_str[MAX_PORT_LEN];
 int port_no_str_len=0;
f571aa35
 unsigned int maxbuffer = MAX_RECV_BUFFER_SIZE; /* maximum buffer size we do not want to exceed
 				      		durig the auto-probing procedure; may be
 				      		re-configured */
cc2199a9
 int children_no = 0;           /* number of children processing requests */
404073d3
 int *pids=0;		       /*array with childrens pids, 0= main proc,
cbd9fc8b
 				alloc'ed in shared mem if possible*/
1b1b19d8
 int debug = 0;
 int dont_fork = 0;
 int log_stderr = 0;
 int check_via =  0;        /* check if reply first via host==us */
676eb608
 int loop_checks = 0;	/* calculate branches and check for loops/spirals */
1b1b19d8
 int received_dns = 0;      /* use dns and/or rdns or to see if we need to 
                               add a ;received=x.x.x.x to via: */
c9ca45b3
 char* working_dir = 0;
 char* chroot_dir = 0;
 int uid = 0;
 int gid = 0;
1b1b19d8
 
 char* names[MAX_LISTEN];               /* our names */
b2e71d5b
 int names_len[MAX_LISTEN];    /* lengths of the names*/
1b1b19d8
 unsigned long addresses[MAX_LISTEN];   /* our ips */
 int addresses_no=0;                    /* number of names/ips */
 
cc2199a9
 /* ipc related globals */
 int process_no = 0;
4bd1673d
 process_bm_t process_bit = 0;
cc2199a9
 #ifdef ROUTE_SRV
 #endif
888ca09d
 
63fa628f
 /* cfg parsing */
 int cfg_errors=0;
888ca09d
 
cc2199a9
 #define MAX_FD 32 /* maximum number of inherited open file descriptors,
 		    (normally it shouldn't  be bigger  than 3) */
 
3e429f5c
 
 extern FILE* yyin;
 extern int yyparse();
 
 
8e759838
 static int is_main=0; /* flag = is this the  "main" process? */
3e429f5c
 
cc2199a9
 /* daemon init, return 0 on success, -1 on error */
 int daemonize(char*  name)
 {
 	pid_t pid;
 	int r;
 	
 	if (log_stderr==0)
cbd9fc8b
 		openlog(name, LOG_PID|LOG_CONS, LOG_LOCAL1 /*LOG_DAEMON*/);
 		/* LOG_CONS, LOG_PERRROR ? */
cc2199a9
 
c9ca45b3
 
 	if (chroot_dir&&(chroot(chroot_dir)<0)){
 		LOG(L_CRIT, "Cannot chroot to %s: %s\n", chroot_dir, strerror(errno));
cc2199a9
 		goto error;
 	}
 	
c9ca45b3
 	if (chdir(working_dir)<0){
 		LOG(L_CRIT,"cannot chdir to %s: %s\n", working_dir, strerror(errno));
 		goto error;
 	}
 
 	if (gid&&(setgid(gid)<0)){
 		LOG(L_CRIT, "cannot change gid to %d: %s\n", gid, strerror(errno));
 		goto error;
 	}
 	
 	if(uid&&(setuid(uid)<0)){
 		LOG(L_CRIT, "cannot change uid to %d: %s\n", uid, strerror(errno));
 		goto error;
 	}
 
cc2199a9
 	/* fork to become!= group leader*/
 	if ((pid=fork())<0){
 		LOG(L_CRIT, "Cannot fork:%s\n", strerror(errno));
 		goto error;
 	}
 	if (pid!=0){
 		/* parent process => exit*/
 		exit(0);
 	}
 	/* become session leader to drop the ctrl. terminal */
 	if (setsid()<0){
 		LOG(L_WARN, "setsid failed: %s\n",strerror(errno));
 	}
 	/* fork again to drop group  leadership */
 	if ((pid=fork())<0){
 		LOG(L_CRIT, "Cannot  fork:%s\n", strerror(errno));
 		goto error;
 	}
 	if (pid!=0){
 		/*parent process => exit */
 		exit(0);
 	}
 	
 	/* close any open file descriptors */
676924fb
 	if (log_stderr==0)
 		for (r=0;r<MAX_FD; r++){
 			if ((r==3) && log_stderr)  continue;
 			close(r);
 		}
cc2199a9
 	return  0;
 
 error:
 	return -1;
 }
 
 
 
 /* main loop */
 int main_loop()
 {
 	int r, i;
 	pid_t pid;
 
 	/* one "main" process and n children handling i/o */
 
1fb7b1aa
 
cc2199a9
 	if (dont_fork){
f571aa35
 #ifdef STATS
 		setstats( 0 );
 #endif
cc2199a9
 		/* only one address */
 		if (udp_init(addresses[0],port_no)==-1) goto error;
cd57180a
 
 		/* we need another process to act as the timer*/
 		if (timer_list){
cbd9fc8b
 				process_no++;
cd57180a
 				if ((pid=fork())<0){
d4f2d8b0
 					LOG(L_CRIT,  "ERRROR: main_loop: Cannot fork\n");
cd57180a
 					goto error;
 				}
cbd9fc8b
 				
cd57180a
 				if (pid==0){
 					/* child */
 					/* timer!*/
4bd1673d
 					process_bit = 0;
cd57180a
 					for(;;){
 						sleep(TIMER_TICK);
 						timer_ticker();
 					}
cbd9fc8b
 				}else{
 						pids[process_no]=pid; /*should be shared mem anway*/
cd57180a
 				}
 		}
8e759838
 		/* main process, receive loop */
 		is_main=1;
cbd9fc8b
 		pids[0]=getpid();
4bd1673d
 		process_bit = 1;
cbd9fc8b
 		process_no=0; /*main process number*/
391fa285
 		return udp_rcv_loop();
cc2199a9
 	}else{
 		for(r=0;r<addresses_no;r++){
1fb7b1aa
 			/* create the listening socket (for each address)*/
 			if (udp_init(addresses[r], port_no)==-1) goto error;
cc2199a9
 			for(i=0;i<children_no;i++){
 				if ((pid=fork())<0){
 					LOG(L_CRIT,  "main_loop: Cannot fork\n");
 					goto error;
 				}
 				if (pid==0){
 					/* child */
cbd9fc8b
 					process_no=i+1; /*0=main*/
4bd1673d
 					process_bit = 1 << i;
f571aa35
 #ifdef STATS
 					setstats( i );
 #endif
cc2199a9
 					return udp_rcv_loop();
cbd9fc8b
 				}else{
 						pids[i+1]=pid; /*should be in shared mem.*/
cc2199a9
 				}
 			}
bf0fab3f
 			/*parent*/
 			/*close(udp_sock)*/; /*if it's closed=>sendto invalid fd errors?*/
cc2199a9
 		}
 	}
8e759838
 	/*this is the main process*/
cbd9fc8b
 	pids[process_no]=getpid();
4bd1673d
 	process_bit = 0;
8e759838
 	is_main=1;
cd57180a
 	if (timer_list){
 		for(;;){
 			/* debug:  instead of doing something usefull */
 			/* (placeholder for timers, etc.) */
 			sleep(TIMER_TICK);
 			/* if we received a signal => TIMER_TICK may have not elapsed*/
 			timer_ticker();
 		}
 	}else{
 		for(;;) sleep(LONG_SLEEP);
cc2199a9
 	}
 	
 	return 0;
  error:
 	return -1;
 
 }
726efa25
 
f571aa35
 
726efa25
 /* added by jku; allows for regular exit on a specific signal;
    good for profiling which only works if exited regularly and
    not by default signal handlers
 */	
 
 static void sig_usr(int signo)
 {
e9d701db
 	pid_t	chld;
 	int	chld_status;
 
dda9dab1
 	if (signo==SIGINT || signo==SIGPIPE) {	/* exit gracefuly */
e9d701db
 		DPrint("INT received, program terminates\n");
 #		ifdef STATS
f571aa35
 		/* print statistics on exit only for the first process */
 		if (stats->process_index==0 && stat_file )
 			if (dump_all_statistic()==0)
 				printf("statistic dumped to %s\n", stat_file );
 			else
 				printf("statistics dump to %s failed\n", stat_file );
e9d701db
 #		endif
bf08223a
 		/* WARNING: very dangerous, might be unsafe*/
8e759838
 		if (is_main)
 			destroy_modules();
02690ea6
 #ifdef PKG_MALLOC
9dfa5dc4
 		LOG(L_INFO, "Memory status (pkg):\n");
02690ea6
 		pkg_status();
e9d701db
 #		endif
628e3a5a
 #ifdef SHM_MEM
9dfa5dc4
 		if (is_main){
 			LOG(L_INFO, "Memory status (shm):\n");
8e759838
 			shm_status();
404073d3
 			/*zero all shmem  alloc vars, that will still use*/
 			pids=0;
8e759838
 			shm_mem_destroy();
404073d3
 		}
628e3a5a
 #endif
2c65bd8b
 		dprint("Thank you for flying " NAME "\n");
dcb5f364
 		exit(0);
f571aa35
 	} else if (signo==SIGUSR1) { /* statistic */
e4067ffb
 #ifdef STATS
f571aa35
 		dump_all_statistic();
e4067ffb
 #endif
02690ea6
 #ifdef PKG_MALLOC
9dfa5dc4
 		LOG(L_INFO, "Memory status (pkg):\n");
02690ea6
 		pkg_status();
 #endif
628e3a5a
 #ifdef SHM_MEM
9dfa5dc4
 		LOG(L_INFO, "Memory status (shm):\n");
21f03122
 		shm_status();
628e3a5a
 #endif
e9d701db
 	} else if (signo==SIGCHLD) {
 		while ((chld=waitpid( -1, &chld_status, WNOHANG ))>0) {
 			if (WIFEXITED(chld_status)) 
 				LOG(L_INFO, "child process %d exited normally, status=%d\n",
 					chld, WEXITSTATUS(chld_status));
 			else if (WIFSIGNALED(chld_status)) {
 				LOG(L_INFO, "child process %d exited by a signal %d\n",
 					chld, WTERMSIG(chld_status));
 #				ifdef WCOREDUMP
 				LOG(L_INFO, "core was %sgenerated\n", WCOREDUMP(chld_status) ?
 					"" : "not" );
 #				endif
 			} else if (WIFSTOPPED(chld_status)) 
 				LOG(L_INFO, "child process %d stopped by a signal %d\n",
 					chld, WSTOPSIG(chld_status));
 		}
f571aa35
 	}
726efa25
 }
cd57180a
 
 
dda9dab1
 void test();
cd57180a
 
512dcd98
 int main(int argc, char** argv)
 {
 
 	FILE* cfg_stream;
e60a9728
 	struct hostent* he;
1b1b19d8
 	int c,r;
 	char *tmp;
 	struct utsname myname;
f571aa35
 	char *options;
512dcd98
 
726efa25
 	/* added by jku: add exit handler */
628e3a5a
 	if (signal(SIGINT, sig_usr) == SIG_ERR ) {
 		DPrint("ERROR: no SIGINT signal handler can be installed\n");
 		goto error;
 	}
dda9dab1
 	/* if we debug and write to a pipe, we want to exit nicely too */
 	if (signal(SIGPIPE, sig_usr) == SIG_ERR ) {
 		DPrint("ERROR: no SIGINT signal handler can be installed\n");
 		goto error;
 	}
628e3a5a
 
f571aa35
 	if (signal(SIGUSR1, sig_usr)  == SIG_ERR ) {
628e3a5a
 		DPrint("ERROR: no SIGUSR1 signal handler can be installed\n");
 		goto error;
 	}
e9d701db
 	if (signal(SIGCHLD , sig_usr)  == SIG_ERR ) {
 		DPrint("ERROR: no SIGCHLD signal handler can be installed\n");
 		goto error;
 	}
726efa25
 
dda9dab1
 	//memtest();
 	//hashtest();
 
512dcd98
 	/* process command line (get port no, cfg. file path etc) */
1b1b19d8
 	opterr=0;
f571aa35
 	options=
 #ifdef STATS
 	"s:"
 #endif
c9ca45b3
 	"f:p:b:l:n:rRvcdDEVhw:t:u:g:";
f571aa35
 	
 	while((c=getopt(argc,argv,options))!=-1){
1b1b19d8
 		switch(c){
 			case 'f':
 					cfg_file=optarg;
 					break;
f571aa35
 			case 's':
e4067ffb
 				#ifdef STATS
f571aa35
 					stat_file=optarg;
e4067ffb
 				#endif
f571aa35
 					break;
1b1b19d8
 			case 'p':
 					port_no=strtol(optarg, &tmp, 10);
 					if (tmp &&(*tmp)){
 						fprintf(stderr, "bad port number: -p %s\n", optarg);
 						goto error;
 					}
 					break;
c3ce2841
 
 			case 'b':
 					maxbuffer=strtol(optarg, &tmp, 10);
 					if (tmp &&(*tmp)){
                                                 fprintf(stderr, "bad max buffer size number: -p %s\n", optarg);
                                                 goto error;
                                         }
                                         break;
1b1b19d8
 			case 'l':
e7671eb9
 					/* add a new addr. to our address list */
1b1b19d8
 					if (addresses_no < MAX_LISTEN){
 						names[addresses_no]=(char*)malloc(strlen(optarg)+1);
 						if (names[addresses_no]==0){
 							fprintf(stderr, "Out of memory.\n");
 							goto error;
 						}
 						strncpy(names[addresses_no], optarg, strlen(optarg)+1);
 						addresses_no++;
 					}else{
 						fprintf(stderr, 
 									"Too many addresses (max. %d).\n",
 									MAX_LISTEN);
 						goto error;
 					}
 					break;
 			case 'n':
3e429f5c
 					children_no=strtol(optarg, &tmp, 10);
 					if ((tmp==0) ||(*tmp)){
1b1b19d8
 						fprintf(stderr, "bad process number: -n %s\n", optarg);
 						goto error;
 					}
 					break;
 			case 'v':
 					check_via=1;
 					break;
676eb608
 			case 'c':
 					loop_checks=1;
 					break;
1b1b19d8
 			case 'r':
 					received_dns|=DO_DNS;
 					break;
 			case 'R':
 					received_dns|=DO_REV_DNS;
 			case 'd':
 					debug++;
 					break;
 			case 'D':
 					dont_fork=1;
 					break;
 			case 'E':
 					log_stderr=1;
 					break;
 			case 'V':
 					printf("version: %s\n", version);
726efa25
 					printf("flags: %s\n", flags );
af6fb476
 					print_ct_constants();
3e429f5c
 					printf("%s\n",id);
b2dec9c6
 					printf("%s compiled on %s at %s with %s\n", __FILE__,
 							__DATE__, __TIME__, COMPILER );
 					
1b1b19d8
 					exit(0);
 					break;
 			case 'h':
 					printf("version: %s\n", version);
 					printf("%s",help_msg);
 					exit(0);
 					break;
c9ca45b3
 			case 'w':
 					working_dir=optarg;
 					break;
 			case 't':
 					chroot_dir=optarg;
 					break;
 			case 'u':
 					uid=strtol(optarg, &tmp, 10);
 					if ((tmp==0) ||(*tmp)){
 						fprintf(stderr, "bad uid number: -u %s\n", optarg);
 						goto error;
 					}
 					/* test if string?*/
 					break;
 			case 'g':
 					gid=strtol(optarg, &tmp, 10);
 					if ((tmp==0) ||(*tmp)){
 						fprintf(stderr, "bad gid number: -g %s\n", optarg);
 						goto error;
 					}
 					break;
1b1b19d8
 			case '?':
 					if (isprint(optopt))
675b7412
 						fprintf(stderr, "Unknown option `-%c�.\n", optopt);
1b1b19d8
 					else
 						fprintf(stderr, 
 								"Unknown option character `\\x%x�.\n",
 								optopt);
 					goto error;
 			case ':':
 					fprintf(stderr, 
 								"Option `-%c� requires an argument.\n",
 								optopt);
 					goto error;
 			default:
 					abort();
 		}
 	}
 	
 	/* fill missing arguments with the default values*/
 	if (cfg_file==0) cfg_file=CFG_FILE;
7268726e
 
 	/* load config file or die */
 	cfg_stream=fopen (cfg_file, "r");
 	if (cfg_stream==0){
 		fprintf(stderr, "ERROR: loading config file(%s): %s\n", cfg_file,
 				strerror(errno));
 		goto error;
 	}
e8e9c7a9
 
 	/*init mallocs (before parsing cfg !)*/
dda9dab1
 	if (init_mallocs()==-1)
e8e9c7a9
 		goto error;
 
d4f2d8b0
 	/*init timer, before parsing the cfg!*/
 	if (init_timer()<0){
 		LOG(L_CRIT, "could not initialize timer, exiting...\n");
 		goto error;
 	}
e8e9c7a9
 
404073d3
 	/*init builtin  modules*/
 	init_builtin_modules();
 
7268726e
 	yyin=cfg_stream;
 	if ((yyparse()!=0)||(cfg_errors)){
 		fprintf(stderr, "ERROR: bad config file (%d errors)\n", cfg_errors);
 		goto error;
 	}
 	
 	
 	print_rl();
f20a56a2
 	/* fix routing lists */
 	if ( (r=fix_rls())!=0){
 		fprintf(stderr, "ERROR: error %x while trying to fix configuration\n",
 						r);
 		goto error;
 	};
7268726e
 
 	/* fix parameters */
cc2199a9
 	if (port_no<=0) port_no=SIP_PORT;
b2e71d5b
 	port_no_str_len=snprintf(port_no_str, MAX_PORT_LEN, ":%d", 
 				(unsigned short) port_no);
 	if (port_no_str_len<0){
 		fprintf(stderr, "ERROR: bad port number: %d\n", port_no);
 		goto error;
 	}
 	/* on some system snprintf return really strange things if it does not have
 	 * enough space */
 	port_no_str_len=
 				(port_no_str_len<MAX_PORT_LEN)?port_no_str_len:MAX_PORT_LEN;
 
 	
cc2199a9
 	if (children_no<=0) children_no=CHILD_NO;
4bd1673d
 	else if (children_no >= MAX_PROCESSES ) {
c4217e61
 		fprintf(stderr, "ERROR: too many children processes configured;"
 				" maximum is %d\n",
4bd1673d
 			MAX_PROCESSES-1 );
 		goto error;
 	}
c9ca45b3
 	
 	if (working_dir==0) working_dir="/";
cbd9fc8b
 	/*alloc pids*/
 #ifdef SHM_MEM
b2dec9c6
 	pids=shm_malloc(sizeof(int)*(children_no+1));
cbd9fc8b
 #else
b2dec9c6
 	pids=malloc(sizeof(int)*(children_no+1));
cbd9fc8b
 #endif
 	if (pids==0){
 		fprintf(stderr, "ERROR: out  of memory\n");
 		goto error;
 	}
b2dec9c6
 	memset(pids, 0, sizeof(int)*(children_no+1));
cbd9fc8b
 
1b1b19d8
 	if (addresses_no==0) {
 		/* get our address, only the first one */
 		if (uname (&myname) <0){
 			fprintf(stderr, "cannot determine hostname, try -l address\n");
 			goto error;
 		}
 		names[addresses_no]=(char*)malloc(strlen(myname.nodename)+1);
 		if (names[addresses_no]==0){
 			fprintf(stderr, "Out of memory.\n");
 			goto error;
 		}
 		strncpy(names[addresses_no], myname.nodename,
 				strlen(myname.nodename)+1);
 		addresses_no++;
 	}
5b253cc6
 
b2e71d5b
 	/*get name lens*/
 	for(r=0; r<addresses_no; r++){
 		names_len[r]=strlen(names[r]);
 	}
 
1b1b19d8
 	
 	/* get ips */
 	printf("Listening on ");
 	for (r=0; r<addresses_no;r++){
 		he=gethostbyname(names[r]);
 		if (he==0){
 			DPrint("ERROR: could not resolve %s\n", names[r]);
 			goto error;
 		}
 		addresses[r]=*((long*)he->h_addr_list[0]);
 		printf("%s [%s] : %d\n",names[r],
 				inet_ntoa(*(struct in_addr*)&addresses[r]),
 				(unsigned short)port_no);
e60a9728
 	}
512dcd98
 
f571aa35
 #ifdef STATS
 	if (init_stats(  dont_fork ? 1 : children_no  )==-1) goto error;
 #endif
 
22d4aa5d
 	
e60a9728
 	/* init_daemon? */
cc2199a9
 	if (!dont_fork){
 		if ( daemonize(argv[0]) <0 ) goto error;
 	}
22d4aa5d
 
cc2199a9
 	return main_loop();
888ca09d
 
512dcd98
 
 error:
 	return -1;
 
 }
dda9dab1