main.c
512dcd98
 /*
  * $Id$
7dd0b342
  *
  * Copyright (C) 2001-2003 Fhg Fokus
  *
  * This file is part of ser, a free SIP server.
  *
  * ser is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version
  *
  * For a license to use the ser software under conditions
  * other than those described here, or to purchase support for this
  * software, please contact iptel.org by e-mail at the following addresses:
  *    info@iptel.org
  *
  * ser is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License 
  * along with this program; if not, write to the Free Software 
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
2d4b798e
  *
  * History:
  * -------
e3dccdc9
  * 2002-01-29  argc/argv globalized via my_{argc|argv} (jiri)
  * 2003-01-23  mhomed added (jiri)
  * 2003-03-19  replaced all malloc/frees w/ pkg_malloc/pkg_free (andrei)
3c8bd369
  * 2003-03-29  pkg cleaners for fifo and script callbacks introduced (jiri)
2d4b798e
  *
512dcd98
  */
 
7dd0b342
 
512dcd98
 #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>
85f1f3ee
 #include <sys/stat.h>
f571aa35
 #include <sys/mman.h>
85f1f3ee
 #include <fcntl.h>
f571aa35
 #include <sys/time.h>
e9d701db
 #include <sys/wait.h>
054cb6cf
 #include <pwd.h>
 #include <grp.h>
4e2fdd79
 #include <signal.h>
512dcd98
 
57e2cd15
 #include <sys/ioctl.h>
 #include <net/if.h>
087d0976
 #ifdef HAVE_SYS_SOCKIO_H
57e2cd15
 #include <sys/sockio.h>
 #endif
 
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"
3881f12c
 #include "parser/msg_parser.h"
4e2fdd79
 #include "ip_addr.h"
 #include "resolve.h"
2bb60634
 #include "parser/parse_hname2.h"
335d097b
 #include "parser/digest/digest_parser.h"
caf80ae6
 #include "fifo_server.h"
e278821b
 #include "name_alias.h"
9df1213c
 #include "hash_func.h"
f51155cf
 #include "pt.h"
3c8bd369
 #include "script_cb.h"
f2f969dd
 #ifdef USE_TCP
 #include "tcp_init.h"
 #endif
1b1b19d8
 
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 ")" ;
aee4712e
 static char compiled[]= __TIME__ " " __DATE__ ;
7db4ee8d
 static char flags[]=
 "STATS:"
af6fb476
 #ifdef STATS
 "On"
 #else
 "Off"
 #endif
4e2fdd79
 #ifdef USE_IPV6
 ", USE_IPV6"
 #endif
5b532c7f
 #ifdef USE_TCP
 ", USE_TCP"
 #endif
b33736bc
 #ifdef DISABLE_NAGLE
 ", DISABLE_NAGLE"
 #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"
30f1f956
 #ifdef BUSY_WAIT
 "-BUSY_WAIT"
b2dec9c6
 #endif
e0135488
 #ifdef USE_PTHREAD_MUTEX
 ", USE_PTHREAD_MUTEX"
 #endif
 #ifdef USE_POSIX_SEM
 ", USE_POSIX_SEM"
 #endif
 #ifdef USE_SYSV_SEM
 ", USE_SYSV_SEM"
 #endif
30f1f956
 #ifdef ADAPTIVE_WAIT
 "-ADAPTIVE_WAIT"
 #endif
 #ifdef NOSMP
 "-NOSMP"
 #endif
 #endif /*FAST_LOCK*/
726efa25
 ;
 
1b1b19d8
 static char help_msg[]= "\
36ef0329
 Usage: " NAME " -l address [-p port] [-l address [-p port]...] [options]\n\
1b1b19d8
 Options:\n\
     -f file      Configuration file (default " CFG_FILE ")\n\
     -p port      Listen on the specified port (default: 5060)\n\
36ef0329
                  applies to the last address in -l and to all \n\
                  following that do not have a corespponding -p\n\
1b1b19d8
     -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\
c6016a4c
     -R           Same as `-r` but use reverse dns;\n\
                  (to use both use `-rR`)\n\
1b1b19d8
 \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\
4e2fdd79
     -m nr        Size of shared memory allocated in Megabytes\n\
c9ca45b3
     -w  dir      change the working directory to \"dir\" (default \"/\")\n\
     -t  dir      chroot to \"dir\"\n\
     -u uid       change uid \n\
b2934963
     -g gid       change gid \n\
97f17e60
     -P file      create a pid file\n\
     -i fifo_path create a fifo (usefull for monitoring " NAME ") \n"
f571aa35
 #ifdef STATS
97f17e60
 "    -s file     File to which statistics is dumped (disabled otherwise)\n"
f571aa35
 #endif
 ;
512dcd98
 
af6fb476
 /* print compile-time constants */
 void print_ct_constants()
 {
30f1f956
 #ifdef ADAPTIVE_WAIT
 	printf("ADAPTIVE_WAIT_LOOPS=%d, ", ADAPTIVE_WAIT_LOOPS);
 #endif
40a8d9dd
 /*
30f1f956
 #ifdef SHM_MEM
 	printf("SHM_MEM_SIZE=%d, ", SHM_MEM_SIZE);
 #endif
40a8d9dd
 */
30f1f956
 	printf("MAX_RECV_BUFFER_SIZE %d, MAX_LISTEN %d,"
caf80ae6
 			" MAX_URI_SIZE %d, BUF_SIZE %d\n",
 		MAX_RECV_BUFFER_SIZE, MAX_LISTEN, MAX_URI_SIZE, 
1f377e97
 		BUF_SIZE );
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;
4e2fdd79
 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 */
 int children_no = 0;			/* number of children processing requests */
5b532c7f
 #ifdef USE_TCP
 int tcp_children_no = 0;
 #endif
f51155cf
 struct process_table *pt=0;		/*array with childrens pids, 0= main proc,
4e2fdd79
 									alloc'ed in shared mem if possible*/
6e94f57f
 int sig_flag = 0;              /* last signal received */
1b1b19d8
 int debug = 0;
 int dont_fork = 0;
 int log_stderr = 0;
caf80ae6
 /* check if reply first via host==us */
 int check_via =  0;        
 /* shall use stateful synonym branches? faster but not reboot-safe */
855c2e68
 int syn_branch = 1;
609ada42
 /* debugging level for memory stats */
 int memlog = L_DBG;
caf80ae6
 /* should replies include extensive warnings? by default yes,
    good for trouble-shooting
 */
 int sip_warning = 1;
 /* should localy-generated messages include server's signature?
    be default yes, good for trouble-shooting
 */
 int server_signature=1;
2d4b798e
 /* should ser try to locate outbound interface on multihomed
  * host? by default not -- too expensive
  */
 int mhomed=0;
caf80ae6
 /* use dns and/or rdns or to see if we need to add 
    a ;received=x.x.x.x to via: */
 int received_dns = 0;      
c9ca45b3
 char* working_dir = 0;
 char* chroot_dir = 0;
054cb6cf
 char* user=0;
 char* group=0;
c9ca45b3
 int uid = 0;
 int gid = 0;
caf80ae6
 /* a hint to reply modules whether they should send reply
    to IP advertised in Via or IP from which a request came
 */
 int reply_to_via=0;
1b1b19d8
 
36ef0329
 #if 0
1d597ac3
 char* names[MAX_LISTEN];              /* our names */
 int names_len[MAX_LISTEN];            /* lengths of the names*/
4e2fdd79
 struct ip_addr addresses[MAX_LISTEN]; /* our ips */
1d597ac3
 int addresses_no=0;                   /* number of names/ips */
36ef0329
 #endif
e3fc93f4
 struct socket_info sock_info[MAX_LISTEN];/*all addresses we listen/send from*/
5b532c7f
 #ifdef USE_TCP
 struct socket_info tcp_info[MAX_LISTEN];/*all tcp addresses we listen on*/
 #endif
36ef0329
 int sock_no=0; /* number of addresses/open sockets*/
1baa06b5
 struct socket_info* bind_address=0; /* pointer to the crt. proc.
e3fc93f4
 									 listening address*/
36ef0329
 int bind_idx; /* same as above but index in the bound[] array */
 struct socket_info* sendipv4; /* ipv4 socket to use when msg. comes from ipv6*/
 struct socket_info* sendipv6; /* same as above for ipv6 */
f2f969dd
 #ifdef USE_TCP
 struct socket_info* sendipv4_tcp; 
 struct socket_info* sendipv6_tcp; 
 #endif
36ef0329
 
 unsigned short port_no=0; /* default port*/
1b1b19d8
 
e278821b
 struct host_alias* aliases=0; /* name aliases list */
 
cc2199a9
 /* ipc related globals */
 int process_no = 0;
a76545c8
 /* process_bm_t process_bit = 0; */
cc2199a9
 #ifdef ROUTE_SRV
 #endif
888ca09d
 
63fa628f
 /* cfg parsing */
 int cfg_errors=0;
888ca09d
 
40a8d9dd
 /* shared memory (in MB) */
 unsigned int shm_mem_size=SHM_MEM_SIZE * 1024 * 1024;
 
049f64c2
 /* export command-line to anywhere else */
 int my_argc;
 char **my_argv;
 
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();
 
 
71bb231e
 int is_main=0; /* flag = is this the  "main" process? */
3e429f5c
 
a7cbdb26
 char* pid_file = 0; /* filename as asked by use */
b2934963
 
8aeb47e2
 
 
 /* callit before exiting; if show_status==1, mem status is displayed */
 void cleanup(show_status)
 {
 	/*clean-up*/
 	destroy_modules();
 #ifdef USE_TCP
 	destroy_tcp();
 #endif
 	destroy_timer();
3c8bd369
 	destroy_fifo();
 	destroy_script_cb();
8aeb47e2
 #ifdef PKG_MALLOC
 	if (show_status){
 		LOG(memlog, "Memory status (pkg):\n");
 		pkg_status();
 	}
 #endif
 #ifdef SHM_MEM
 	shm_free(pt);
 	pt=0;
 	if (show_status){
 			LOG(memlog, "Memory status (shm):\n");
 			shm_status();
 	}
 	/* zero all shmem alloc vars that we still use */
 	shm_mem_destroy();
 #endif
 	if (pid_file) unlink(pid_file);
 }
 
 
 
cc2199a9
 /* daemon init, return 0 on success, -1 on error */
 int daemonize(char*  name)
 {
b2934963
 	FILE *pid_stream;
cc2199a9
 	pid_t pid;
b2934963
 	int r, p;
 
a7cbdb26
 
b2934963
 	p=-1;
 
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;
36ef0329
 	}else if (pid!=0){
cc2199a9
 		/* 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;
36ef0329
 	}else if (pid!=0){
cc2199a9
 		/*parent process => exit */
 		exit(0);
 	}
b2934963
 
 	/* added by noh: create a pid file for the main process */
 	if (pid_file!=0){
a7cbdb26
 		
36ef0329
 		if ((pid_stream=fopen(pid_file, "r"))!=NULL){
b2934963
 			fscanf(pid_stream, "%d", &p);
 			fclose(pid_stream);
 			if (p==-1){
 				LOG(L_CRIT, "pid file %s exists, but doesn't contain a valid"
36ef0329
 					" pid number\n", pid_file);
b2934963
 				goto error;
 			}
 			if (kill((pid_t)p, 0)==0 || errno==EPERM){
 				LOG(L_CRIT, "running process found in the pid file %s\n",
36ef0329
 					pid_file);
b2934963
 				goto error;
 			}else{
 				LOG(L_WARN, "pid file contains old pid, replacing pid\n");
 			}
 		}
 		pid=getpid();
36ef0329
 		if ((pid_stream=fopen(pid_file, "w"))==NULL){
a7cbdb26
 			LOG(L_WARN, "unable to create pid file %s: %s\n", 
36ef0329
 				pid_file, strerror(errno));
b2934963
 			goto error;
 		}else{
 			fprintf(pid_stream, "%i\n", (int)pid);
 			fclose(pid_stream);
 		}
 	}
cc2199a9
 	
e833d08a
 	/* try to replace stdin, stdout & stderr with /dev/null */
 	if (freopen("/dev/null", "r", stdin)==0){
 		LOG(L_ERR, "unable to replace stdin with /dev/null: %s\n",
 				strerror(errno));
 		/* continue, leave it open */
 	};
 	if (freopen("/dev/null", "w", stdout)==0){
 		LOG(L_ERR, "unable to replace stdout with /dev/null: %s\n",
 				strerror(errno));
 		/* continue, leave it open */
 	};
 	/* close stderr only if log_stderr=0 */
5dc00db6
 	if ((!log_stderr) &&(freopen("/dev/null", "w", stderr)==0)){
e833d08a
 		LOG(L_ERR, "unable to replace stderr with /dev/null: %s\n",
 				strerror(errno));
 		/* continue, leave it open */
 	};
 	
cc2199a9
 	/* close any open file descriptors */
e833d08a
 	for (r=3;r<MAX_FD; r++){
676924fb
 			close(r);
1c80cd8d
 	}
8b45313f
 	
 	if (log_stderr==0)
087d0976
 		openlog(name, LOG_PID|LOG_CONS, LOG_DAEMON);
8b45313f
 		/* LOG_CONS, LOG_PERRROR ? */
cc2199a9
 	return  0;
 
 error:
 	return -1;
 }
 
 
 
6e94f57f
 void handle_sigs()
 {
 	pid_t	chld;
 	int	chld_status;
 
 	switch(sig_flag){
 		case 0: break; /* do nothing*/
 		case SIGPIPE:
c082a437
 				/* SIGPIPE might be rarely received on use of
 				   exec module; simply ignore it
 				 */
 				LOG(L_WARN, "WARNING: SIGPIPE received and ignored\n");
 				break;
 		case SIGINT:
6e94f57f
 		case SIGTERM:
 			/* we end the program in all these cases */
 			if (sig_flag==SIGINT)
 				DBG("INT received, program terminates\n");
c082a437
 #ifdef OBSOLETED
 			else if (sig_flag==SIGPIPE) 
3db079b5
 				DBG("SIGPIPE received, program terminates\n");
c082a437
 #endif
6e94f57f
 			else
 				DBG("SIGTERM received, program terminates\n");
 				
8e8c1478
 			/* first of all, kill the children also */
 			kill(0, SIGTERM);
55ce9059
 
 			     /* Wait for all the children to die */
 			while(wait(0) > 0);
8aeb47e2
 			
 			cleanup(1); /* cleanup & show status*/
6e94f57f
 			dprint("Thank you for flying " NAME "\n");
 			exit(0);
 			break;
 			
 		case SIGUSR1:
 #ifdef STATS
 			dump_all_statistic();
 #endif
 #ifdef PKG_MALLOC
f51155cf
 			LOG(memlog, "Memory status (pkg):\n");
6e94f57f
 			pkg_status();
 #endif
 #ifdef SHM_MEM
f51155cf
 			LOG(memlog, "Memory status (shm):\n");
6e94f57f
 			shm_status();
 #endif
 			break;
 			
 		case 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",
a0196887
 							 WCOREDUMP(chld_status) ?  "" : "not " );
6e94f57f
 #endif
 				}else if (WIFSTOPPED(chld_status)) 
 					LOG(L_INFO, "child process %d stopped by a"
 								" signal %d\n", chld,
 								 WSTOPSIG(chld_status));
 			}
49041f7b
 #ifndef STOP_JIRIS_CHANGES
 			if (dont_fork) {
 				LOG(L_INFO, "INFO: dont_fork turned on, living on\n");
 				break;
 			} 
 			LOG(L_INFO, "INFO: terminating due to SIGCHLD\n");
 #endif
6e94f57f
 			/* exit */
 			kill(0, SIGTERM);
8aeb47e2
 			while(wait(0) > 0); /* wait for all the children to terminate*/
 			cleanup(1); /* cleanup & show status*/
6e94f57f
 			DBG("terminating due to SIGCHLD\n");
 			exit(0);
 			break;
 		
 		case SIGHUP: /* ignoring it*/
 					DBG("SIGHUP received, ignoring it\n");
 					break;
 		default:
 			LOG(L_CRIT, "WARNING: unhandled signal %d\n", sig_flag);
 	}
 	sig_flag=0;
 }
 
 
 
cc2199a9
 /* main loop */
 int main_loop()
 {
 	int r, i;
 	pid_t pid;
0c5da34b
 #ifdef USE_TCP
 	int sockfd[2];
 #endif
2f781952
 #ifdef WITH_SNMP_MOD
 	int (*snmp_start)();
 
 	/* initialize snmp module */
 	snmp_start = (int(*)())find_export("snmp_start", 0);
 	if(snmp_start)
 		if(snmp_start() == -1)
 			LOG(L_ERR, "ERROR: Couldn't start snmp agent\n");
 #endif
 		
cc2199a9
 
 	/* one "main" process and n children handling i/o */
 
1fb7b1aa
 
cc2199a9
 	if (dont_fork){
f571aa35
 #ifdef STATS
 		setstats( 0 );
 #endif
36ef0329
 		/* only one address, we ignore all the others */
 		if (udp_init(&sock_info[0])==-1) goto error;
 		bind_address=&sock_info[0];
 		bind_idx=0;
 		if (sock_no>1){
e3fc93f4
 			LOG(L_WARN, "WARNING: using only the first listen address"
 						" (no fork)\n");
36ef0329
 		}
cd57180a
 
db249450
 		/* process_no now initialized to zero -- increase from now on
 		   as new processes are forked (while skipping 0 reserved for main 
 		*/
 
cd57180a
 		/* we need another process to act as the timer*/
5dc00db6
 #ifndef 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 (timer_list)
 #endif
 		{
cbd9fc8b
 				process_no++;
cd57180a
 				if ((pid=fork())<0){
36ef0329
 					LOG(L_CRIT,  "ERROR: main_loop: Cannot fork\n");
cd57180a
 					goto error;
 				}
cbd9fc8b
 				
cd57180a
 				if (pid==0){
 					/* child */
 					/* timer!*/
a76545c8
 					/* process_bit = 0; */
cd57180a
 					for(;;){
 						sleep(TIMER_TICK);
 						timer_ticker();
 					}
cbd9fc8b
 				}else{
f51155cf
 						pt[process_no].pid=pid; /*should be shared mem anway*/
 						strncpy(pt[process_no].desc, "timer", MAX_PT_DESC );
cd57180a
 				}
 		}
1380e79e
 
 		/* if configured to do so, start a server for accepting FIFO commands */
 		if (open_fifo_server()<0) {
 			LOG(L_ERR, "opening fifo server failed\n");
 			goto error;
 		}
72b7f9a2
 		/* main process, receive loop */
 		process_no=0; /*main process number*/
f51155cf
 		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 );
 		
192ac55b
 		
 		     /* We will call child_init even if we
 		      * do not fork
 		      */
eedd46b1
 
 		if (init_child(0) < 0) {
192ac55b
 			LOG(L_ERR, "init_child failed\n");
 			goto error;
 		}
caf80ae6
 
db1b5017
 		is_main=1; /* hack 42: call init_child with is_main=0 in case
 					 some modules wants to fork a child */
eedd46b1
 		
391fa285
 		return udp_rcv_loop();
cc2199a9
 	}else{
db249450
 		/* process_no now initialized to zero -- increase from now on
f51155cf
 		   as new processes are forked (while skipping 0 reserved for main )
db249450
 		*/
36ef0329
 		for(r=0;r<sock_no;r++){
1fb7b1aa
 			/* create the listening socket (for each address)*/
f2f969dd
 			/* udp */
36ef0329
 			if (udp_init(&sock_info[r])==-1) goto error;
 			/* get first ipv4/ipv6 socket*/
1baa06b5
 			if ((sock_info[r].address.af==AF_INET)&&
 					((sendipv4==0)||(sendipv4->is_lo)))
36ef0329
 				sendipv4=&sock_info[r];
 	#ifdef USE_IPV6
 			if((sendipv6==0)&&(sock_info[r].address.af==AF_INET6))
 				sendipv6=&sock_info[r];
 	#endif
f2f969dd
 #ifdef USE_TCP
 			tcp_info[r]=sock_info[r]; /* copy the sockets */
 			/* same thing for tcp */
 			if (tcp_init(&tcp_info[r])==-1)  goto error;
 			/* get first ipv4/ipv6 socket*/
 			if ((tcp_info[r].address.af==AF_INET)&&
 					((sendipv4_tcp==0)||(sendipv4_tcp->is_lo)))
 				sendipv4_tcp=&tcp_info[r];
 	#ifdef USE_IPV6
 			if((sendipv6_tcp==0)&&(tcp_info[r].address.af==AF_INET6))
 				sendipv6_tcp=&tcp_info[r];
 	#endif
 #endif
36ef0329
 			/* all procs should have access to all the sockets (for sending)
 			 * so we open all first*/
 		}
 		for(r=0; r<sock_no;r++){
cc2199a9
 			for(i=0;i<children_no;i++){
0df81fe8
 				process_no++;
0c5da34b
 #ifdef USE_TCP
b988daef
 		 		if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd)<0){
0c5da34b
 					LOG(L_ERR, "ERROR: main_loop: socketpair failed: %s\n",
 						strerror(errno));
 					goto error;
 				}
 #endif
cc2199a9
 				if ((pid=fork())<0){
 					LOG(L_CRIT,  "main_loop: Cannot fork\n");
 					goto error;
36ef0329
 				}else if (pid==0){
192ac55b
 					     /* child */
0c5da34b
 #ifdef USE_TCP
 					close(sockfd[0]);
 					unix_tcp_sock=sockfd[1];
 #endif
36ef0329
 					bind_address=&sock_info[r]; /* shortcut */
 					bind_idx=r;
192ac55b
 					if (init_child(i) < 0) {
 						LOG(L_ERR, "init_child failed\n");
 						goto error;
 					}
f571aa35
 #ifdef STATS
0df81fe8
 					setstats( i+r*children_no );
f571aa35
 #endif
cc2199a9
 					return udp_rcv_loop();
cbd9fc8b
 				}else{
f51155cf
 						pt[process_no].pid=pid; /*should be in shared mem.*/
 						snprintf(pt[process_no].desc, MAX_PT_DESC,
 							"receiver child=%d sock=%d @ %s:%s", i, r, 	
 							sock_info[r].name.s, sock_info[r].port_no_str.s );
0c5da34b
 #ifdef USE_TCP
 						close(sockfd[1]);
 						pt[process_no].unix_sock=sockfd[0];
 						pt[process_no].idx=-1; /* this is not "tcp" process*/
 #endif
cc2199a9
 				}
 			}
bf0fab3f
 			/*parent*/
 			/*close(udp_sock)*/; /*if it's closed=>sendto invalid fd errors?*/
cc2199a9
 		}
 	}
db249450
 
a0196887
 	/*this is the main process*/
 	bind_address=&sock_info[0]; /* main proc -> it shoudln't send anything, */
 	bind_idx=0;					/* if it does it will use the first address */
0c5da34b
 	
caf80ae6
 	/* if configured to do so, start a server for accepting FIFO commands */
 	if (open_fifo_server()<0) {
 		LOG(L_ERR, "opening fifo server failed\n");
 		goto error;
 	}
36ef0329
 
6ee62314
 #ifndef USE_TCP
 	/* if we are using tcp we always need the timer */
 	if (timer_list)
 #endif
 	{
0c5da34b
 #ifdef USE_TCP
b988daef
  		if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd)<0){
0c5da34b
 			LOG(L_ERR, "ERROR: main_loop: socketpair failed: %s\n",
 				strerror(errno));
 			goto error;
 		}
 #endif
6e94f57f
 		/* fork again for the attendant process*/
db249450
 		process_no++;
6e94f57f
 		if ((pid=fork())<0){
 			LOG(L_CRIT, "main_loop: cannot fork timer process\n");
 			goto error;
 		}else if (pid==0){
 			/* child */
0df81fe8
 			/* is_main=0; */
0c5da34b
 #ifdef USE_TCP
 			close(sockfd[0]);
 			unix_tcp_sock=sockfd[1];
 #endif
6e94f57f
 			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();
 			}
0df81fe8
 		}else{
f51155cf
 			pt[process_no].pid=pid;
 			strncpy(pt[process_no].desc, "timer", MAX_PT_DESC );
0c5da34b
 #ifdef USE_TCP
 						close(sockfd[1]);
 						pt[process_no].unix_sock=sockfd[0];
 						pt[process_no].idx=-1; /* this is not a "tcp" process*/
 #endif
cd57180a
 		}
cc2199a9
 	}
0c5da34b
 #ifdef USE_TCP
 			/* start tcp receivers */
 		if (tcp_init_children()<0) goto error;
 			/* start tcp 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; */
 			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
0df81fe8
 	/* main */
f51155cf
 	pt[0].pid=getpid();
 	strncpy(pt[0].desc, "attendant", MAX_PT_DESC );
0c5da34b
 #ifdef USE_TCP
 	pt[process_no].unix_sock=-1;
 	pt[process_no].idx=-1; /* this is not a "tcp" process*/
 	unix_tcp_sock=-1;
 #endif
0df81fe8
 	/*DEBUG- remove it*/
f51155cf
 #ifdef DEBUG
e3fc93f4
 	printf("\n% 3d processes, % 3d children * % 3d listening addresses + main"
 			" + fifo %s\n", process_no+1, children_no, sock_no,
 			(timer_list)?"+ timer":"");
0df81fe8
 	for (r=0; r<=process_no; r++){
f51155cf
 		printf("% 3d   % 5d\n", r, pt[r].pid);
0df81fe8
 	}
f51155cf
 #endif
0df81fe8
 	process_no=0; 
a76545c8
 	/* process_bit = 0; */
db249450
 	is_main=1;
cc2199a9
 	
6e94f57f
 	for(;;){
 			pause();
 			handle_sigs();
 	}
 	
 	
51eadd0c
 	/*return 0; */
cc2199a9
  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
6e94f57f
     - modified by andrei: moved most of the stuff to handle_sigs, 
        made it safer for the "fork" case
36ef0329
 */
726efa25
 static void sig_usr(int signo)
 {
e9d701db
 
caf80ae6
 
6e94f57f
 	if (is_main){
 		if (sig_flag==0) sig_flag=signo;
 		else /*  previous sig. not processed yet, ignoring? */
 			return; ;
 		if (dont_fork) 
db1b5017
 				/* only one proc, doing everything from the sig handler,
6e94f57f
 				unsafe, but this is only for debugging mode*/
 			handle_sigs();
 	}else{
 		/* process the important signals */
 		switch(signo){
 			case SIGPIPE:
ab130758
 					LOG(L_INFO, "INFO: signal %d received\n", signo);
 				break;
 			case SIGINT:
6e94f57f
 			case SIGTERM:
de38488e
 					LOG(L_INFO, "INFO: signal %d received\n", signo);
caf80ae6
 					/* print memory stats for non-main too */
 					#ifdef PKG_MALLOC
f51155cf
 					LOG(memlog, "Memory status (pkg):\n");
caf80ae6
 					pkg_status();
 					#endif
6e94f57f
 					exit(0);
 					break;
 			case SIGUSR1:
 				/* statistics, do nothing, printed only from the main proc */
 					break;
 				/* ignored*/
 			case SIGUSR2:
 			case SIGHUP:
 					break;
db1b5017
 			case SIGCHLD:
49041f7b
 #ifndef 			STOP_JIRIS_CHANGES
 					LOG(L_INFO, "INFO: SIGCHLD received: "
 						"we do not worry about grand-children\n");
 #else
db1b5017
 					exit(0); /* terminate if one child died */
49041f7b
 #endif
e9d701db
 		}
f571aa35
 	}
726efa25
 }
cd57180a
 
 
6e94f57f
 
57e2cd15
 /* add all family type addresses of interface if_name to the socket_info array
  * if if_name==0, adds all addresses on all interfaces
  * WARNING: it only works with ipv6 addresses on FreeBSD
  * return: -1 on error, 0 on success
  */
 int add_interfaces(char* if_name, int family, unsigned short port)
 {
 	struct ifconf ifc;
85f1f3ee
 	struct ifreq ifr;
57e2cd15
 	struct ifreq ifrcopy;
 	char*  last;
85f1f3ee
 	char* p;
57e2cd15
 	int size;
 	int lastlen;
 	int s;
 	char* tmp;
 	struct ip_addr addr;
 	int ret;
53531528
 
087d0976
 #ifdef HAVE_SOCKADDR_SA_LEN
aee4712e
 	#ifndef MAX
 		#define MAX(a,b) ( ((a)>(b))?(a):(b))
 	#endif
53531528
 #endif
57e2cd15
 	/* ipv4 or ipv6 only*/
 	s=socket(family, SOCK_DGRAM, 0);
 	ret=-1;
 	lastlen=0;
 	ifc.ifc_req=0;
 	for (size=10; ; size*=2){
 		ifc.ifc_len=size*sizeof(struct ifreq);
e3dccdc9
 		ifc.ifc_req=(struct ifreq*) pkg_malloc(size*sizeof(struct ifreq));
57e2cd15
 		if (ifc.ifc_req==0){
 			fprintf(stderr, "memory allocation failure\n");
 			goto error;
 		}
 		if (ioctl(s, SIOCGIFCONF, &ifc)==-1){
 			if(errno==EBADF) return 0; /* invalid descriptor => no such ifs*/
 			fprintf(stderr, "ioctl failed: %s\n", strerror(errno));
 			goto error;
 		}
 		if  ((lastlen) && (ifc.ifc_len==lastlen)) break; /*success,
 														   len not changed*/
 		lastlen=ifc.ifc_len;
 		/* try a bigger array*/
e3dccdc9
 		pkg_free(ifc.ifc_req);
57e2cd15
 	}
 	
 	last=(char*)ifc.ifc_req+ifc.ifc_len;
85f1f3ee
 	for(p=(char*)ifc.ifc_req; p<last;
 			p+=(sizeof(ifr.ifr_name)+
087d0976
 			#ifdef  HAVE_SOCKADDR_SA_LEN
85f1f3ee
 				MAX(ifr.ifr_addr.sa_len, sizeof(struct sockaddr))
57e2cd15
 			#else
85f1f3ee
 				( (ifr.ifr_addr.sa_family==AF_INET)?
57e2cd15
 					sizeof(struct sockaddr_in):
85f1f3ee
 					((ifr.ifr_addr.sa_family==AF_INET6)?
57e2cd15
 						sizeof(struct sockaddr_in6):sizeof(struct sockaddr)) )
 			#endif
 				)
 		)
 	{
85f1f3ee
 		/* copy contents into ifr structure
 		 * warning: it might be longer (e.g. ipv6 address) */
 		memcpy(&ifr, p, sizeof(ifr));
 		if (ifr.ifr_addr.sa_family!=family){
57e2cd15
 			/*printf("strange family %d skipping...\n",
 					ifr->ifr_addr.sa_family);*/
 			continue;
 		}
 		
1baa06b5
 		/*get flags*/
85f1f3ee
 		ifrcopy=ifr;
1baa06b5
 		if (ioctl(s, SIOCGIFFLAGS,  &ifrcopy)!=-1){ /* ignore errors */
 			/* ignore down ifs only if listening on all of them*/
 			if (if_name==0){ 
57e2cd15
 				/* if if not up, skip it*/
 				if (!(ifrcopy.ifr_flags & IFF_UP)) continue;
 			}
 		}
 		
 		
 		
 		if ((if_name==0)||
85f1f3ee
 			(strncmp(if_name, ifr.ifr_name, sizeof(ifr.ifr_name))==0)){
57e2cd15
 			
 				/*add address*/
 			if (sock_no<MAX_LISTEN){
85f1f3ee
 				sockaddr2ip_addr(&addr, 
 					(struct sockaddr*)(p+(long)&((struct ifreq*)0)->ifr_addr));
57e2cd15
 				if ((tmp=ip_addr2a(&addr))==0) goto error;
 				/* fill the strings*/
e3dccdc9
 				sock_info[sock_no].name.s=(char*)pkg_malloc(strlen(tmp)+1);
57e2cd15
 				if(sock_info[sock_no].name.s==0){
 					fprintf(stderr, "Out of memory.\n");
 					goto error;
 				}
 				/* fill in the new name and port */
 				sock_info[sock_no].name.len=strlen(tmp);
 				strncpy(sock_info[sock_no].name.s, tmp, 
 							sock_info[sock_no].name.len+1);
 				sock_info[sock_no].port_no=port;
1baa06b5
 				/* mark if loopback */
 				if (ifrcopy.ifr_flags & IFF_LOOPBACK) 
 					sock_info[sock_no].is_lo=1;
57e2cd15
 				sock_no++;
 				ret=0;
 			}else{
 				fprintf(stderr, "Too many addresses (max %d)\n", MAX_LISTEN);
 				goto error;
 			}
 		}
 			/*
 			printf("%s:\n", ifr->ifr_name);
 			printf("        ");
 			print_sockaddr(&(ifr->ifr_addr));
 			printf("        ");
 			ls_ifflags(ifr->ifr_name, family, options);
 			printf("\n");*/
 	}
e3dccdc9
 	pkg_free(ifc.ifc_req); /*clean up*/
57e2cd15
 	close(s);
 	return  ret;
 error:
e3dccdc9
 	if (ifc.ifc_req) pkg_free(ifc.ifc_req);
57e2cd15
 	close(s);
 	return -1;
 }
 
 
cd57180a
 
512dcd98
 int main(int argc, char** argv)
 {
 
 	FILE* cfg_stream;
e60a9728
 	struct hostent* he;
57e2cd15
 	int c,r,t;
1b1b19d8
 	char *tmp;
e278821b
 	char** h;
 	struct host_alias* a;
1b1b19d8
 	struct utsname myname;
f571aa35
 	char *options;
36ef0329
 	char port_no_str[MAX_PORT_LEN];
3db079b5
 	int port_no_str_len;
 	int ret;
054cb6cf
 	struct passwd *pw_entry;
 	struct group  *gr_entry;
7d31b911
 	unsigned int seed;
 	int rfd;
512dcd98
 
3db079b5
 	/*init*/
 	port_no_str_len=0;
 	ret=-1;
049f64c2
 	my_argc=argc; my_argv=argv;
3db079b5
 	
d31fcdf0
 	/*init mallocs (before parsing cfg or cmd line !)*/
 	if (init_mallocs()==-1)
 		goto error;
 
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;
 	}
b2934963
 	if (signal(SIGTERM , sig_usr)  == SIG_ERR ) {
 		DPrint("ERROR: no SIGTERM signal handler can be installed\n");
 		goto error;
 	}
6e94f57f
 	if (signal(SIGHUP , sig_usr)  == SIG_ERR ) {
 		DPrint("ERROR: no SIGHUP signal handler can be installed\n");
 		goto error;
 	}
 	if (signal(SIGUSR2 , sig_usr)  == SIG_ERR ) {
 		DPrint("ERROR: no SIGUSR2 signal handler can be installed\n");
 		goto error;
 	}
be125734
 #ifdef DBG_MSG_QA
 	fprintf(stderr, "WARNING: ser startup: "
 		"DBG_MSG_QA enabled, ser may exit abruptly\n");
 #endif
6e94f57f
 
 
726efa25
 
512dcd98
 	/* process command line (get port no, cfg. file path etc) */
1b1b19d8
 	opterr=0;
f571aa35
 	options=
 #ifdef STATS
 	"s:"
 #endif
97f17e60
 	"f:p:m:b:l:n:rRvdDEVhw:t:u:g:P:i:";
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;
 					}
36ef0329
 					if (sock_no>0) sock_info[sock_no-1].port_no=port_no;
1b1b19d8
 					break;
c3ce2841
 
40a8d9dd
 			case 'm':
 					shm_mem_size=strtol(optarg, &tmp, 10) * 1024 * 1024;
 					if (tmp &&(*tmp)){
36ef0329
 						fprintf(stderr, "bad shmem size number: -m %s\n",
 										optarg);
40a8d9dd
 						goto error;
 					};
36ef0329
 					LOG(L_INFO, "ser: shared memory allocated: %d MByte\n",
 									shm_mem_size );
40a8d9dd
 					break;
 
c3ce2841
 			case 'b':
 					maxbuffer=strtol(optarg, &tmp, 10);
 					if (tmp &&(*tmp)){
36ef0329
 						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 */
36ef0329
 					if (sock_no < MAX_LISTEN){
 						sock_info[sock_no].name.s=
e3dccdc9
 										(char*)pkg_malloc(strlen(optarg)+1);
36ef0329
 						if (sock_info[sock_no].name.s==0){
1b1b19d8
 							fprintf(stderr, "Out of memory.\n");
 							goto error;
 						}
36ef0329
 						strncpy(sock_info[sock_no].name.s, optarg,
 												strlen(optarg)+1);
 						sock_info[sock_no].name.len=strlen(optarg);
 						/* set default port */
 						sock_info[sock_no].port_no=port_no;
 						sock_no++;
1b1b19d8
 					}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)){
36ef0329
 						fprintf(stderr, "bad process number: -n %s\n",
 									optarg);
1b1b19d8
 						goto error;
 					}
 					break;
 			case 'v':
 					check_via=1;
 					break;
 			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);
e22bbdb8
 					printf("%s compiled on %s with %s\n", __FILE__,
 							compiled, COMPILER );
b2dec9c6
 					
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':
054cb6cf
 					user=optarg;
c9ca45b3
 					break;
 			case 'g':
054cb6cf
 					group=optarg;
c9ca45b3
 					break;
b2934963
 			case 'P':
 					pid_file=optarg;
 					break;
97f17e60
 			case 'i':
 					fifo=optarg;
 					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
 
7d31b911
 	/* seed the prng */
 	/* try to use /dev/random if possible */
 	seed=0;
 	if ((rfd=open("/dev/random", O_RDONLY))!=-1){
 try_again:
 		if (read(rfd, (void*)&seed, sizeof(seed))==-1){
 			if (errno==EINTR) goto try_again; /* interrupted by signal */
 			LOG(L_WARN, "WARNING: could not read from /dev/random (%d)\n",
 						errno);
 		}
 		DBG("read %u from /dev/random\n", seed);
 			close(rfd);
 	}else{
 		LOG(L_WARN, "WARNING: could not open /dev/random (%d)\n", errno);
 	}
 	seed+=getpid()+time(0);
 	DBG("seeding PRNG with %u\n", seed);
 	srand(seed);
 	DBG("test random number %u\n", rand());
 	
 	
9df1213c
 
e8e9c7a9
 
d4f2d8b0
 	/*init timer, before parsing the cfg!*/
 	if (init_timer()<0){
 		LOG(L_CRIT, "could not initialize timer, exiting...\n");
 		goto error;
 	}
0c5da34b
 #ifdef USE_TCP
 	/*init tcp*/
 	if (init_tcp()<0){
 		LOG(L_CRIT, "could not initialize tcp, exiting...\n");
 		goto error;
 	}
 #endif
 	
caf80ae6
 	/* register a diagnostic FIFO command */
90b0b10d
 	if (register_core_fifo()<0) {
 		LOG(L_CRIT, "unable to register core FIFO commands\n");
caf80ae6
 		goto error;
 	}
c0b1bfb5
 
ad79ca94
 	/*register builtin  modules*/
 	register_builtin_modules();
404073d3
 
7268726e
 	yyin=cfg_stream;
 	if ((yyparse()!=0)||(cfg_errors)){
 		fprintf(stderr, "ERROR: bad config file (%d errors)\n", cfg_errors);
 		goto error;
 	}
16181f18
 
2f781952
 
ad79ca94
 
7268726e
 	print_rl();
 
 	/* fix parameters */
cc2199a9
 	if (port_no<=0) port_no=SIP_PORT;
b2e71d5b
 
 	
cc2199a9
 	if (children_no<=0) children_no=CHILD_NO;
5b532c7f
 #ifdef USE_TCP
 	tcp_children_no=children_no;
 #endif
caf80ae6
 #ifdef _OBSOLETED
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;
 	}
caf80ae6
 #endif
c9ca45b3
 	
 	if (working_dir==0) working_dir="/";
054cb6cf
 	
 	/* get uid/gid */
 	if (user){
 		uid=strtol(user, &tmp, 10);
 		if ((tmp==0) ||(*tmp)){
 			/* maybe it's a string */
 			pw_entry=getpwnam(user);
 			if (pw_entry==0){
 				fprintf(stderr, "bad user name/uid number: -u %s\n", user);
 				goto error;
 			}
 			uid=pw_entry->pw_uid;
 			gid=pw_entry->pw_gid;
 		}
 	}
 	if (group){
 		gid=strtol(user, &tmp, 10);
 		if ((tmp==0) ||(*tmp)){
 			/* maybe it's a string */
 			gr_entry=getgrnam(group);
 			if (gr_entry==0){
 				fprintf(stderr, "bad group name/gid number: -u %s\n", group);
 				goto error;
 			}
 			gid=gr_entry->gr_gid;
 		}
 	}
cbd9fc8b
 
36ef0329
 	if (sock_no==0) {
57e2cd15
 		/* try to get all listening ipv4 interfaces */
 		if (add_interfaces(0, AF_INET, 0)==-1){
 			/* if error fall back to get hostname*/
 			/* get our address, only the first one */
 			if (uname (&myname) <0){
 				fprintf(stderr, "cannot determine hostname, try -l address\n");
 				goto error;
 			}
e3dccdc9
 			sock_info[sock_no].name.s=
 								(char*)pkg_malloc(strlen(myname.nodename)+1);
57e2cd15
 			if (sock_info[sock_no].name.s==0){
 				fprintf(stderr, "Out of memory.\n");
 				goto error;
 			}
 			sock_info[sock_no].name.len=strlen(myname.nodename);
 			strncpy(sock_info[sock_no].name.s, myname.nodename,
 					sock_info[sock_no].name.len+1);
 			sock_no++;
1b1b19d8
 		}
 	}
5b253cc6
 
57e2cd15
 	/* try to change all the interface names into addresses
 	 *  --ugly hack */
 	for (r=0; r<sock_no;){
 		if (add_interfaces(sock_info[r].name.s, AF_INET,
 					sock_info[r].port_no)!=-1){
 			/* success => remove current entry (shift the entire array)*/
e3dccdc9
 			pkg_free(sock_info[r].name.s);
57e2cd15
 			memmove(&sock_info[r], &sock_info[r+1], 
 						(sock_no-r)*sizeof(struct socket_info));
 			sock_no--;
 			continue;
 		}
 		r++;
 	}
36ef0329
 	/* get ips & fill the port numbers*/
0bafb279
 #ifdef EXTRA_DEBUG
57e2cd15
 	printf("Listening on \n");
0bafb279
 #endif
36ef0329
 	for (r=0; r<sock_no;r++){
1baa06b5
 		/* fix port number, port_no should be !=0 here */
 		if (sock_info[r].port_no==0) sock_info[r].port_no=port_no;
 		port_no_str_len=snprintf(port_no_str, MAX_PORT_LEN, ":%d", 
 									(unsigned short) sock_info[r].port_no);
0bf716b8
 		/* if buffer too small, snprintf may return per C99 estimated size
 		   of needed space; there is no guarantee how many characters 
 		   have been written to the buffer and we can be happy if
 		   the snprintf implementation zero-terminates whatever it wrote
 		   -jku
 		*/
 		if (port_no_str_len<0 || port_no_str_len>=MAX_PORT_LEN){
1baa06b5
 			fprintf(stderr, "ERROR: bad port number: %d\n", 
 						sock_info[r].port_no);
 			goto error;
 		}
 		/* on some systems snprintf returns 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;
e3dccdc9
 		sock_info[r].port_no_str.s=(char*)pkg_malloc(strlen(port_no_str)+1);
1baa06b5
 		if (sock_info[r].port_no_str.s==0){
 			fprintf(stderr, "Out of memory.\n");
 			goto error;
 		}
 		strncpy(sock_info[r].port_no_str.s, port_no_str,
 					strlen(port_no_str)+1);
 		sock_info[r].port_no_str.len=strlen(port_no_str);
 		
 		/* get "official hostnames", all the aliases etc. */
36ef0329
 		he=resolvehost(sock_info[r].name.s);
1b1b19d8
 		if (he==0){
36ef0329
 			DPrint("ERROR: could not resolve %s\n", sock_info[r].name.s);
1b1b19d8
 			goto error;
 		}
e278821b
 		/* check if we got the official name */
 		if (strcasecmp(he->h_name, sock_info[r].name.s)!=0){
1baa06b5
 			if (add_alias(sock_info[r].name.s, sock_info[r].name.len,
 							sock_info[r].port_no)<0){
e278821b
 				LOG(L_ERR, "ERROR: main: add_alias failed\n");
 			}
 			/* change the oficial name */
e3dccdc9
 			pkg_free(sock_info[r].name.s);
 			sock_info[r].name.s=(char*)pkg_malloc(strlen(he->h_name)+1);
e278821b
 			if (sock_info[r].name.s==0){
 				fprintf(stderr, "Out of memory.\n");
 				goto error;
 			}
 			sock_info[r].name.len=strlen(he->h_name);
 			strncpy(sock_info[r].name.s, he->h_name, sock_info[r].name.len+1);
 		}
 		/* add the aliases*/
 		for(h=he->h_aliases; h && *h; h++)
1baa06b5
 			if (add_alias(*h, strlen(*h), sock_info[r].port_no)<0){
e278821b
 				LOG(L_ERR, "ERROR: main: add_alias failed\n");
 			}
f41ab77e
 		hostent2ip_addr(&sock_info[r].address, he, 0); /*convert to ip_addr 
 														 format*/
57e2cd15
 		if ((tmp=ip_addr2a(&sock_info[r].address))==0) goto error;
e3dccdc9
 		sock_info[r].address_str.s=(char*)pkg_malloc(strlen(tmp)+1);
36ef0329
 		if (sock_info[r].address_str.s==0){
 			fprintf(stderr, "Out of memory.\n");
 			goto error;
 		}
 		strncpy(sock_info[r].address_str.s, tmp, strlen(tmp)+1);
855c2e68
 		/* set is_ip (1 if name is an ip address, 0 otherwise) */
36ef0329
 		sock_info[r].address_str.len=strlen(tmp);
855c2e68
 		if 	(	(sock_info[r].address_str.len==sock_info[r].name.len)&&
 				(strncasecmp(sock_info[r].address_str.s, sock_info[r].name.s,
 						 sock_info[r].address_str.len)==0)
d615a5cd
 			){
 				sock_info[r].is_ip=1;
 				/* do rev. dns on it (for aliases)*/
 				he=rev_resolvehost(&sock_info[r].address);
 				if (he==0){
 					DPrint("WARNING: could not rev. resolve %s\n",
 							sock_info[r].name.s);
 				}else{
 					/* add the aliases*/
1baa06b5
 					if (add_alias(he->h_name, strlen(he->h_name),
 									sock_info[r].port_no)<0){
d615a5cd
 						LOG(L_ERR, "ERROR: main: add_alias failed\n");
 					}
 					for(h=he->h_aliases; h && *h; h++)
1baa06b5
 						if (add_alias(*h,strlen(*h),sock_info[r].port_no)<0){
d615a5cd
 							LOG(L_ERR, "ERROR: main: add_alias failed\n");
 						}
 				}
 		}else{ sock_info[r].is_ip=0; };
855c2e68
 			
0bafb279
 #ifdef EXTRA_DEBUG
054cb6cf
 		printf("              %.*s [%s]:%s\n", sock_info[r].name.len, 
 				sock_info[r].name.s,
57e2cd15
 				sock_info[r].address_str.s, sock_info[r].port_no_str.s);
0bafb279
 #endif
57e2cd15
 	}
 	/* removing duplicate addresses*/
 	for (r=0; r<sock_no; r++){
 		for (t=r+1; t<sock_no;){
 			if ((sock_info[r].port_no==sock_info[t].port_no) &&
 				(sock_info[r].address.af==sock_info[t].address.af) &&
 				(memcmp(sock_info[r].address.u.addr, 
 						sock_info[t].address.u.addr,
 						sock_info[r].address.len)  == 0)
 				){
0bafb279
 #ifdef EXTRA_DEBUG
57e2cd15
 				printf("removing duplicate (%d) %s [%s] == (%d) %s [%s]\n",
 						r, sock_info[r].name.s, sock_info[r].address_str.s,
 						t, sock_info[t].name.s, sock_info[t].address_str.s);
0bafb279
 #endif
57e2cd15
 				/* add the name to the alias list*/
 				if ((!sock_info[t].is_ip) && (
 						(sock_info[t].name.len!=sock_info[r].name.len)||
 						(strncmp(sock_info[t].name.s, sock_info[r].name.s,
 								 sock_info[r].name.len)!=0))
 					)
1baa06b5
 					add_alias(sock_info[t].name.s, sock_info[t].name.len,
 								sock_info[t].port_no);
57e2cd15
 						
 				/* free space*/
e3dccdc9
 				pkg_free(sock_info[t].name.s);
 				pkg_free(sock_info[t].address_str.s);
 				pkg_free(sock_info[t].port_no_str.s);
57e2cd15
 				/* shift the array*/
 				memmove(&sock_info[t], &sock_info[t+1], 
 							(sock_no-t)*sizeof(struct socket_info));
 				sock_no--;
 				continue;
 			}
 			t++;
 		}
e60a9728
 	}
57e2cd15
 	/* print all the listen addresses */
 	printf("Listening on \n");
 	for (r=0; r<sock_no; r++)
 		printf("              %s [%s]:%s\n",sock_info[r].name.s,
 				sock_info[r].address_str.s, sock_info[r].port_no_str.s);
 
e278821b
 	printf("Aliases: ");
1baa06b5
 	for(a=aliases; a; a=a->next) 
 		if (a->port)
 			printf("%.*s:%d ", a->alias.len, a->alias.s, a->port);
 		else
 			printf("%.*s:* ", a->alias.len, a->alias.s);
e278821b
 	printf("\n");
0df81fe8
 	if (sock_no==0){
 		fprintf(stderr, "ERROR: no listening sockets");
 		goto error;
 	}
 	if (dont_fork){
 		fprintf(stderr, "WARNING: no fork mode %s\n", 
e3fc93f4
 				(sock_no>1)?" and more than one listen address found (will"
 							" use only the the first one)":"");
0df81fe8
 	}
 	
ed2b50d3
 	/* init_daemon? */
 	if (!dont_fork){
 		if ( daemonize(argv[0]) <0 ) goto error;
 	}
 	if (init_modules() != 0) {
 		fprintf(stderr, "ERROR: error while initializing modules\n");
 		goto error;
 	}
 	
0df81fe8
 	/*alloc pids*/
 #ifdef SHM_MEM
f51155cf
 	pt=shm_malloc(sizeof(struct process_table)*process_count());
0df81fe8
 #else
e3dccdc9
 	pt=pkg_malloc(sizeof(struct process_table)*process_count());
0df81fe8
 #endif
f51155cf
 	if (pt==0){
0df81fe8
 		fprintf(stderr, "ERROR: out  of memory\n");
 		goto error;
 	}
f51155cf
 	memset(pt, 0, sizeof(struct process_table)*process_count());
6bb03a39
 	/* fix routing lists */
 	if ( (r=fix_rls())!=0){
 		fprintf(stderr, "ERROR: error %x while trying to fix configuration\n",
 						r);
 		goto error;
 	};
22d4aa5d
 
2f781952
 #ifdef STATS
 	if (init_stats(  dont_fork ? 1 : children_no  )==-1) goto error;
 #endif
 	
3db079b5
 	ret=main_loop();
 	/*kill everything*/
 	kill(0, SIGTERM);
8aeb47e2
 	/*clean-up*/
 	cleanup(0);
3db079b5
 	return ret;
512dcd98
 
 error:
3db079b5
 	/*kill everything*/
 	kill(0, SIGTERM);
8aeb47e2
 	/*clean-up*/
 	cleanup(0);
512dcd98
 	return -1;
 
 }
dda9dab1