src/main.c
512dcd98
 /*
53c7e0f1
  * Copyright (C) 2001-2003 FhG Fokus
7dd0b342
  *
6a0f4382
  * This file is part of Kamailio, a free SIP server.
7dd0b342
  *
6a0f4382
  * Kamailio is free software; you can redistribute it and/or modify
7dd0b342
  * 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
  *
6a0f4382
  * Kamailio is distributed in the hope that it will be useful,
7dd0b342
  * 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.
  *
b017f49c
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
9e1ff448
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
2d4b798e
  *
512dcd98
  */
 
4af91169
 /** Kamailio core :: main file (init, daemonize, startup)
1ef55a09
  * @file main.c
  * @ingroup core
  * Module: core
1d0661db
  */
 
6a0f4382
 /*! @defgroup core Kamailio core
1d0661db
  *
1ef55a09
  * sip router core part.
1d0661db
  */
 
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>
a7380699
 #include <sys/types.h>
1b1b19d8
 #include <sys/socket.h>
a7380699
 #if defined(HAVE_NETINET_IN_SYSTM)
 #include <netinet/in_systm.h>
 #endif
1b1b19d8
 #include <netinet/in.h>
fe09f315
 #include <netinet/ip.h>
1b1b19d8
 #include <arpa/inet.h>
 #include <sys/utsname.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
 
cf83221d
 #include "core/config.h"
 #include "core/dprint.h"
 #include "core/daemonize.h"
 #include "core/route.h"
 #include "core/udp_server.h"
 #include "core/globals.h"
 #include "core/mem/mem.h"
 #include "core/mem/shm_mem.h"
 #include "core/shm_init.h"
 #include "core/sr_module.h"
 #include "core/timer.h"
 #include "core/parser/msg_parser.h"
 #include "core/ip_addr.h"
 #include "core/resolve.h"
 #include "core/parser/parse_hname2.h"
 #include "core/parser/digest/digest_parser.h"
 #include "core/name_alias.h"
 #include "core/hash_func.h"
 #include "core/pt.h"
 #include "core/script_cb.h"
 #include "core/nonsip_hooks.h"
 #include "core/ut.h"
 #include "core/events.h"
 #include "core/signals.h"
22e7e32e
 #ifdef USE_RAW_SOCKS
cf83221d
 #include "core/raw_sock.h"
22e7e32e
 #endif /* USE_RAW_SOCKS */
f2f969dd
 #ifdef USE_TCP
cf83221d
 #include "core/poll_types.h"
 #include "core/tcp_init.h"
 #include "core/tcp_options.h"
6c53d41a
 #ifdef CORE_TLS
cf83221d
 #include "core/tls/tls_init.h"
6c53d41a
 #define tls_has_init_si() 1
 #define tls_loaded() 1
 #else
cf83221d
 #include "core/tls_hooks_init.h"
6c53d41a
 #endif /* CORE_TLS */
 #endif /* USE_TCP */
c3611173
 #ifdef USE_SCTP
cf83221d
 #include "core/sctp_core.h"
c3611173
 #endif
cf83221d
 #include "core/usr_avp.h"
 #include "core/rpc_lookup.h"
 #include "core/core_cmd.h"
 #include "core/flags.h"
 #include "core/lock_ops_init.h"
 #include "core/atomic_ops_init.h"
dcb59e67
 #ifdef USE_DNS_CACHE
cf83221d
 #include "core/dns_cache.h"
dcb59e67
 #endif
 #ifdef USE_DST_BLACKLIST
cf83221d
 #include "core/dst_blacklist.h"
dcb59e67
 #endif
cf83221d
 #include "core/rand/fastrand.h" /* seed */
 #include "core/rand/kam_rand.h"
0a974a1d
 
cf83221d
 #include "core/stats.h"
 #include "core/counters.h"
 #include "core/cfg/cfg.h"
 #include "core/cfg/cfg_struct.h"
 #include "core/cfg_core.h"
 #include "core/endianness.h" /* init */
 #include "core/basex.h" /* init */
 #include "core/pvapi.h" /* init PV api */
 #include "core/pv_core.h" /* register core pvars */
 #include "core/ppcfg.h"
 #include "core/sock_ut.h"
 #include "core/async_task.h"
 #include "core/dset.h"
 #include "core/timer_proc.h"
 #include "core/srapi.h"
af3f94dd
 #include "core/receive.h"
726efa25
 
03150098
 #ifdef DEBUG_DMALLOC
 #include <dmalloc.h>
 #endif
cf83221d
 #include "core/ver.h"
03150098
 
96d09107
 /* define SIG_DEBUG by default */
 #ifdef NO_SIG_DEBUG
 #undef SIG_DEBUG
 #else
 #define SIG_DEBUG
 #endif
 
dd0e65a8
 
726efa25
 
1b1b19d8
 static char help_msg[]= "\
f4194f69
 Usage: " NAME " [options]\n\
1b1b19d8
 Options:\n\
f4194f69
     -f file      Configuration file (default: " CFG_FILE ")\n\
c82fe029
     -L path      Modules search path (default: " MODS_DIR ")\n\
dda578ba
     -c           Check configuration file for errors\n\
5dcfb23d
     -l address   Listen on the specified address/interface (multiple -l\n\
16d4e079
                   mean listening on more addresses).  The address format is\n\
72bba9e3
                   [proto:]addr_lst[:port], where proto=udp|tcp|tls|sctp, \n\
                   addr_lst= addr|(addr, addr_lst) and \n\
                   addr= host|ip_address|interface_name. \n\
324f3f23
                   E.g: -l localhost, -l udp:127.0.0.1:5080, -l eth0:5062,\n\
72bba9e3
                   -l \"sctp:(eth0)\", -l \"(eth0, eth1, 127.0.0.1):5065\".\n\
                   The default behaviour is to listen on all the interfaces.\n\
1b1b19d8
     -n processes Number of child processes to fork per interface\n\
16d4e079
                   (default: 8)\n\
1b1b19d8
     -r           Use dns to check if is necessary to add a \"received=\"\n\
16d4e079
                   field to a via\n\
c6016a4c
     -R           Same as `-r` but use reverse dns;\n\
16d4e079
                   (to use both use `-rR`)\n\
70d6cae2
     -K           Turn on \"via:\" host checking when forwarding replies\n\
1b1b19d8
     -d           Debugging mode (multiple -d increase the level)\n\
2b337687
     -D           Control how daemonize is done:\n\
                   -D..do not fork (almost) anyway;\n\
                   -DD..do not daemonize creator;\n\
                   -DDD..daemonize (default)\n\
6bda9c0b
     -E           Log to stderr\n\
     -e           Log messages printed in terminal colors (requires -E)\n"
5dcfb23d
 #ifdef USE_TCP
 "    -T           Disable tcp\n\
f4194f69
     -N           Number of tcp child processes (default: equal to `-n')\n\
84597b7b
     -W type      poll method (depending on support in OS, it can be: poll,\n\
                   epoll_lt, epoll_et, sigio_rt, select, kqueue, /dev/poll)\n"
5dcfb23d
 #endif
c3611173
 #ifdef USE_SCTP
c8e95587
 "    -S           disable sctp\n\
5219ecb7
     -Q            Number of sctp child processes (default: equal to `-n')\n"
c3611173
 #endif /* USE_SCTP */
9834ed6e
 "    -v (-V)      Version number\n\
1b1b19d8
     -h           This help message\n\
9834ed6e
     -I           Print more internal compile flags and options\n\
c3ce2841
     -b nr        Maximum receive buffer size which will not be exceeded by\n\
16d4e079
                   auto-probing procedure even if  OS allows\n\
4e2fdd79
     -m nr        Size of shared memory allocated in Megabytes\n\
7b3a6eca
     -M nr        Size of private memory allocated, in Megabytes\n\
f4194f69
     -w dir       Change the working directory to \"dir\" (default: \"/\")\n\
0762e9d5
     -t dir       Chroot to \"dir\"\n\
31e21ff2
     -u uid       Change uid (user id)\n\
     -g gid       Change gid (group id)\n\
5dcfb23d
     -P file      Create a pid file\n\
5219ecb7
     -G file      Create a pgid file\n\
31e21ff2
     -Y dir       Runtime dir path\n\
b01dc20a
     -O nr        Script optimization level (debugging option)\n\
     -a mode      Auto aliases mode: enable with yes or on,\n\
95dec431
                   disable with no or off\n\
f3992928
     -A define    Add config pre-processor define (e.g., -A WITH_AUTH)\n\
     -x name      Specify internal manager for shared memory (shm)\n\
                   - can be: fm, qm or tlsf\n\
     -X name      Specify internal manager for private memory (pkg)\n\
                   - if omitted, the one for shm is used\n"
f571aa35
 #ifdef STATS
31e21ff2
 "    -s file     File where to write internal statistics on SIGUSR1\n"
f571aa35
 #endif
 ;
512dcd98
 
9167c186
 
af6fb476
 /* print compile-time constants */
abb01fb4
 void print_ct_constants(void)
af6fb476
 {
30f1f956
 #ifdef ADAPTIVE_WAIT
4f655313
 	printf("ADAPTIVE_WAIT_LOOPS %d, ", ADAPTIVE_WAIT_LOOPS);
30f1f956
 #endif
40a8d9dd
 /*
4f655313
 	printf("SHM_MEM_SIZE %dMB, ", SHM_MEM_SIZE);
40a8d9dd
 */
4f655313
 	printf("MAX_RECV_BUFFER_SIZE %d,"
7b3a6eca
 			" MAX_URI_SIZE %d, BUF_SIZE %d, DEFAULT PKG_SIZE %uMB\n",
79aa7201
 		MAX_RECV_BUFFER_SIZE, MAX_URI_SIZE,
bdc85a8c
 		BUF_SIZE, PKG_MEM_SIZE);
0ba367ec
 #ifdef USE_TCP
 	printf("poll method support: %s.\n", poll_support);
 #endif
af6fb476
 }
512dcd98
 
f5803916
 /* print compile-time constants */
abb01fb4
 void print_internals(void)
f5803916
 {
 	printf("Print out of %s internals\n", NAME);
 	printf("  Version: %s\n", full_version);
 	printf("  Default config: %s\n", CFG_FILE);
 	printf("  Default paths to modules: %s\n", MODS_DIR);
 	printf("  Compile flags: %s\n", ver_flags );
 	printf("  MAX_RECV_BUFFER_SIZE=%d\n", MAX_RECV_BUFFER_SIZE);
 	printf("  MAX_URI_SIZE=%d\n", MAX_URI_SIZE);
 	printf("  BUF_SIZE=%d\n", BUF_SIZE);
 	printf("  DEFAULT PKG_SIZE=%uMB\n", PKG_MEM_SIZE);
 	printf("  DEFAULT SHM_SIZE=%uMB\n", SHM_MEM_SIZE);
 #ifdef ADAPTIVE_WAIT
 	printf("  ADAPTIVE_WAIT_LOOPS=%d\n", ADAPTIVE_WAIT_LOOPS);
 #endif
 #ifdef USE_TCP
 	printf("  TCP poll methods: %s\n", poll_support);
 #endif
 	printf("  Source code revision ID: %s\n", ver_id);
 	printf("  Compiled with: %s\n", ver_compiler);
 	printf("  Compiled on: %s\n", ver_compiled_time);
 	printf("Thank you for flying %s!\n", NAME);
 }
 
53c7e0f1
 /* debugging function */
e60a9728
 /*
abb01fb4
 void receive_stdin_loop(void)
888ca09d
 {
 	#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 */
 
b484b774
 int own_pgid = 0; /* whether or not we have our own pgid (and it's ok
 					 to use kill(0, sig) */
f4194f69
 
c82fe029
 char* mods_dir = MODS_DIR;  /* search path for dyn. loadable modules */
e1e40d3a
 int   mods_dir_cmd = 0; /* mods dir path set in command lin e*/
f4194f69
 
1b1b19d8
 char* cfg_file = 0;
4e2fdd79
 unsigned int maxbuffer = MAX_RECV_BUFFER_SIZE; /* maximum buffer size we do
53c7e0f1
 												  not want to exceed during the
b017f49c
 												  auto-probing procedure; may
4e2fdd79
 												  be re-configured */
5cd87175
 unsigned int sql_buffer_size = 65535; /* Size for the SQL buffer. Defaults to 64k. 
                                          This may be re-configured */
edf5e385
 int socket_workers = 0;		/* number of workers processing requests for a socket
 							   - it's reset everytime with a new listen socket */
 int children_no = 0;		/* number of children processing requests */
5b532c7f
 #ifdef USE_TCP
edf5e385
 int tcp_cfg_children_no = 0; /* set via config or command line option */
 int tcp_children_no = 0; /* based on socket_workers and tcp_cfg_children_no */
5dcfb23d
 int tcp_disable = 0; /* 1 if tcp is disabled */
5b532c7f
 #endif
f22b996b
 #ifdef USE_TLS
6c53d41a
 #ifdef	CORE_TLS
 int tls_disable = 0;  /* tls enabled by default */
 #else
 int tls_disable = 1;  /* tls disabled by default */
 #endif /* CORE_TLS */
 #endif /* USE_TLS */
c3611173
 #ifdef USE_SCTP
 int sctp_children_no = 0;
c8e95587
 int sctp_disable = 2; /* 1 if sctp is disabled, 2 if auto mode, 0 enabled */
c3611173
 #endif /* USE_SCTP */
37209e14
 
53c7e0f1
 struct process_table *pt=0;		/*array with children pids, 0= main proc,
4e2fdd79
 									alloc'ed in shared mem if possible*/
021e7e0e
 int *process_count = 0;			/* Total number of SER processes currently
37209e14
 								   running */
 gen_lock_t* process_lock;		/* lock on the process table */
 int process_no = 0;				/* index of process in the pt */
 
78a65d14
 time_t up_since;
6e94f57f
 int sig_flag = 0;              /* last signal received */
1b1b19d8
 int dont_fork = 0;
bc404f2b
 int dont_daemonize = 0;
1b1b19d8
 int log_stderr = 0;
6bda9c0b
 int log_color = 0;
95bf8645
 /* set custom app name for syslog printing */
 char *log_name = 0;
35e94c97
 char *log_prefix_fmt = 0;
02f62296
 pid_t creator_pid = (pid_t) -1;
dda578ba
 int config_check = 0;
caf80ae6
 /* check if reply first via host==us */
b017f49c
 int check_via =  0;
face488e
 /* translate user=phone URIs to TEL URIs */
 int phone2tel = 1;
af93cbdf
 /* debugging level for timer debugging */
 int timerlog = L_WARN;
258b58e2
 /* should replies include extensive warnings? by default no,
caf80ae6
    good for trouble-shooting
 */
258b58e2
 int sip_warning = 0;
caf80ae6
 /* should localy-generated messages include server's signature?
    be default yes, good for trouble-shooting
 */
 int server_signature=1;
c745469f
 str server_hdr = {SERVER_HDR, SERVER_HDR_LEN};
 str user_agent_hdr = {USER_AGENT, USER_AGENT_LEN};
8fb8b261
 str version_table = {VERSION_TABLE, VERSION_TABLE_LEN};
2d4b798e
 /* should ser try to locate outbound interface on multihomed
  * host? by default not -- too expensive
  */
 int mhomed=0;
b017f49c
 /* use dns and/or rdns or to see if we need to add
caf80ae6
    a ;received=x.x.x.x to via: */
b017f49c
 int received_dns = 0;
bb4cd6b0
 /* add or not the rev dns names to aliases list */
 int sr_auto_aliases=1;
c9ca45b3
 char* working_dir = 0;
 char* chroot_dir = 0;
ca1358f2
 char* runtime_dir = "" RUN_DIR;
054cb6cf
 char* user=0;
 char* group=0;
c9ca45b3
 int uid = 0;
 int gid = 0;
71fd3ebd
 char* sock_user=0;
 char* sock_group=0;
 int sock_uid= -1;
 int sock_gid= -1;
 int sock_mode= S_IRUSR| S_IWUSR| S_IRGRP| S_IWGRP; /* rw-rw---- */
 
89fde575
 int server_id = 0; /* Configurable unique ID of the server */
 
e008edb9
 /* maximum number of branches for transaction */
 unsigned int sr_dst_max_branches = MAX_BRANCHES_DEFAULT;
 
d4ed4771
 /* set timeval for each received sip message */
 int sr_msg_time = 1;
 
214b161e
 /* onsend_route is executed for replies*/
 int onsend_route_reply = 0;
 
385c63eb
 /* more config stuff */
 int disable_core_dump=0; /* by default enabled */
 int open_files_limit=-1; /* don't touch it by default */
8390f722
 
 /* memory options */
 int shm_force_alloc=0; /* force immediate (on startup) page allocation
 						  (by writting 0 in the pages), useful if
 						  mlock_pages is also 1 */
 int mlock_pages=0; /* default off, try to disable swapping */
 
 /* real time options */
 int real_time=0; /* default off, flags: 1 on only timer, 2  slow timer,
16d4e079
 										4 all procs (7=all) */
021e7e0e
 int rt_prio=0;
8390f722
 int rt_policy=0; /* SCHED_OTHER */
 int rt_timer1_prio=0;  /* "fast" timer */
 int rt_timer2_prio=0;  /* "slow" timer */
 int rt_timer1_policy=0; /* "fast" timer, SCHED_OTHER */
 int rt_timer2_policy=0; /* "slow" timer, SCHED_OTHER */
 
 
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
 
2ba73117
 #ifdef USE_MCAST
 int mcast_loopback = 0;
956d111a
 int mcast_ttl = -1; /* if -1, don't touch it, use the default (usually 1) */
8b39cb6a
 char* mcast = 0;
2ba73117
 #endif /* USE_MCAST */
 
fe09f315
 int tos = IPTOS_LOWDELAY;
f3a26797
 int pmtu_discovery = 0;
fe09f315
 
3e154160
 int auto_bind_ipv6 = 0;
 
9f4c52ce
 struct socket_info* udp_listen=0;
5b532c7f
 #ifdef USE_TCP
f2e1aa50
 int tcp_main_pid=0; /* set after the tcp main process is started */
9f4c52ce
 struct socket_info* tcp_listen=0;
5b532c7f
 #endif
f22b996b
 #ifdef USE_TLS
9f4c52ce
 struct socket_info* tls_listen=0;
f22b996b
 #endif
c3611173
 #ifdef USE_SCTP
 struct socket_info* sctp_listen=0;
 #endif
1baa06b5
 struct socket_info* bind_address=0; /* pointer to the crt. proc.
e3fc93f4
 									 listening address*/
36ef0329
 struct socket_info* sendipv4; /* ipv4 socket to use when msg. comes from ipv6*/
 struct socket_info* sendipv6; /* same as above for ipv6 */
22e7e32e
 #ifdef USE_RAW_SOCKS
 int raw_udp4_send_sock = -1; /* raw socket used for sending udp4 packets */
 #endif /* USE_RAW_SOCKS */
f2f969dd
 #ifdef USE_TCP
b017f49c
 struct socket_info* sendipv4_tcp;
 struct socket_info* sendipv6_tcp;
f2f969dd
 #endif
f22b996b
 #ifdef USE_TLS
 struct socket_info* sendipv4_tls;
 struct socket_info* sendipv6_tls;
 #endif
c3611173
 #ifdef USE_SCTP
 struct socket_info* sendipv4_sctp;
 struct socket_info* sendipv6_sctp;
 #endif
36ef0329
 
 unsigned short port_no=0; /* default port*/
f22b996b
 #ifdef USE_TLS
 unsigned short tls_port_no=0; /* default port */
 #endif
1b1b19d8
 
e278821b
 struct host_alias* aliases=0; /* name aliases list */
 
3167c744
 /* Parameter to child_init */
 int child_rank = 0;
 
96d09107
 /* how much to wait for children to terminate, before taking extreme measures*/
 int ser_kill_timeout=DEFAULT_SER_KILL_TIMEOUT;
 
751c181f
 int ksr_verbose_startup = 0;
 
63fa628f
 /* cfg parsing */
 int cfg_errors=0;
dcb59e67
 int cfg_warnings=0;
 
888ca09d
 
40a8d9dd
 /* shared memory (in MB) */
647cc983
 unsigned long shm_mem_size=0;
7b3a6eca
 /* private (pkg) memory (in MB) */
 unsigned long pkg_mem_size=0;
40a8d9dd
 
049f64c2
 /* export command-line to anywhere else */
 int my_argc;
 char **my_argv;
 
29e63735
 /* set to 1 when the cfg framework and core cfg is initialized/registered */
 static int cfg_ok=0;
 
cc2199a9
 #define MAX_FD 32 /* maximum number of inherited open file descriptors,
 		    (normally it shouldn't  be bigger  than 3) */
 
3e429f5c
 
 extern FILE* yyin;
abb01fb4
 extern int yyparse(void);
3e429f5c
 
 
428e3b83
 int is_main=1; /* flag = is this the  "main" process? */
b0123c36
 int fixup_complete=0; /* flag = is the fixup complete ? */
3e429f5c
 
a7cbdb26
 char* pid_file = 0; /* filename as asked by use */
9a428799
 char* pgid_file = 0;
8aeb47e2
 
 
4c2ef7f3
 /* memory manager */
0859d223
 #define SR_MEMMNG_DEFAULT	"qm"
4c2ef7f3
 
 char *sr_memmng_pkg = NULL;
 char *sr_memmng_shm = NULL;
 
4c57d02e
 static int *_sr_instance_started = NULL;
 
97af78a5
 /**
  * return 1 if all child processes were forked
  * - note: they might still be in init phase (i.e., child init)
  * - note: see also sr_insance_ready()
  */
 int sr_instance_started(void)
4c57d02e
 {
 	if(_sr_instance_started!=NULL && *_sr_instance_started==1) {
 		return 1;
 	}
 	return 0;
 }
 
53c7e0f1
 /* call it before exiting; if show_status==1, mem status is displayed */
ad2f899c
 void cleanup(int show_status)
8aeb47e2
 {
e4f42ce1
 	int memlog;
ad2f899c
 
8aeb47e2
 	/*clean-up*/
fbe11914
 #ifndef SHM_SAFE_MALLOC
1ec69642
 	if(shm_initialized()) {
 		/* force-unlock the shared memory lock in case some process crashed
 		 * and let it locked; this will allow an almost gracious shutdown */
 		shm_global_unlock();
 	}
fbe11914
 #endif
56131033
 	destroy_rpcs();
8aeb47e2
 	destroy_modules();
dcb59e67
 #ifdef USE_DNS_CACHE
 	destroy_dns_cache();
 #endif
 #ifdef USE_DST_BLACKLIST
 	destroy_dst_blacklist();
 #endif
5174bbf3
 	/* restore the original core configuration before the
 	 * config block is freed, otherwise even logging is unusable,
 	 * it can case segfault */
29e63735
 	if (cfg_ok){
 		cfg_update();
 		/* copy current config into default_core_cfg */
 		if (core_cfg)
 			default_core_cfg=*((struct cfg_group_core*)core_cfg);
 	}
5174bbf3
 	core_cfg = &default_core_cfg;
9188021a
 	cfg_destroy();
8aeb47e2
 #ifdef USE_TCP
 	destroy_tcp();
f22b996b
 #ifdef USE_TLS
 	destroy_tls();
7ad18de8
 #endif /* USE_TLS */
 #endif /* USE_TCP */
c3611173
 #ifdef USE_SCTP
7f8e7a85
 	sctp_core_destroy();
c3611173
 #endif
8aeb47e2
 	destroy_timer();
7e7d9399
 	pv_destroy_api();
af3f94dd
 	ksr_route_locks_set_destroy();
3c8bd369
 	destroy_script_cb();
ac34f9f4
 	destroy_nonsip_hooks();
93349b4e
 	destroy_routes();
d307929c
 	destroy_atomic_ops();
4208dc00
 	destroy_counters();
e4f42ce1
 	memlog=cfg_get(core, core_cfg, memlog);
8aeb47e2
 #ifdef PKG_MALLOC
d740c34e
 	if (show_status && memlog <= cfg_get(core, core_cfg, debug)){
 		if (cfg_get(core, core_cfg, mem_summary) & 1) {
 			LOG(memlog, "Memory status (pkg):\n");
 			pkg_status();
 		}
a31cd01b
 		if (cfg_get(core, core_cfg, mem_summary) & 4) {
d740c34e
 			LOG(memlog, "Memory still-in-use summary (pkg):\n");
 			pkg_sums();
 		}
8aeb47e2
 	}
 #endif
b137a4b8
 	if (pt) shm_free(pt);
8aeb47e2
 	pt=0;
d740c34e
 	if (show_status && memlog <= cfg_get(core, core_cfg, debug)){
a31cd01b
 		if (cfg_get(core, core_cfg, mem_summary) & 2) {
8aeb47e2
 			LOG(memlog, "Memory status (shm):\n");
 			shm_status();
d740c34e
 		}
a31cd01b
 		if (cfg_get(core, core_cfg, mem_summary) & 8) {
ed20ee1d
 			LOG(memlog, "Memory still-in-use summary (shm):\n");
 			shm_sums();
d740c34e
 		}
8aeb47e2
 	}
 	/* zero all shmem alloc vars that we still use */
4c2ef7f3
 	shm_destroy_manager();
8b8fc486
 	destroy_lock_ops();
8aeb47e2
 	if (pid_file) unlink(pid_file);
9a428799
 	if (pgid_file) unlink(pgid_file);
4c2ef7f3
 	pkg_destroy_manager();
8aeb47e2
 }
 
 
b484b774
 /* tries to send a signal to all our processes
  * if daemonized  is ok to send the signal to all the process group,
  * however if not daemonized we might end up sending the signal also
b017f49c
  * to the shell which launched us => most signals will kill it if
  * it's not in interactive mode and we don't want this. The non-daemonized
  * case can occur when an error is encountered before daemonize is called
b484b774
  * (e.g. when parsing the config file) or when ser is started in "dont-fork"
  *  mode. Sending the signal to all the processes in pt[] will not work
b017f49c
  *  for processes forked from modules (which have no correspondent entry in
b484b774
  *  pt), but this can happen only in dont_fork mode (which is only for
  *  debugging). So in the worst case + "dont-fork" we might leave some
  *  zombies. -- andrei */
 static void kill_all_children(int signum)
 {
 	int r;
02dae965
 
b484b774
 	if (own_pgid) kill(0, signum);
37209e14
 	else if (pt){
d4fb00dc
 		 /* lock processes table only if this is a child process
 		  * (only main can add processes, so from main is safe not to lock
 		  *  and moreover it avoids the lock-holding suicidal children problem)
 		  */
021e7e0e
 		if (!is_main) lock_get(process_lock);
37209e14
 		for (r=1; r<*process_count; r++){
d4fb00dc
 			if (r==process_no) continue; /* try not to be suicidal */
37209e14
 			if (pt[r].pid) {
 				kill(pt[r].pid, signum);
 			}
a2a91d7d
 			else LM_CRIT("killing: %s > %d no pid!!!\n",
37209e14
 							pt[r].desc, pt[r].pid);
 		}
d4fb00dc
 		if (!is_main) lock_release(process_lock);
37209e14
 	}
b484b774
 }
 
 
 
f2e1aa50
 /* if this handler is called, a critical timeout has occurred while
7fb8a246
  * waiting for the children to finish => we should kill everything and exit */
 static void sig_alarm_kill(int signo)
 {
 	kill_all_children(SIGKILL); /* this will kill the whole group
 								  including "this" process;
 								  for debugging replace with SIGABRT
 								  (but warning: it might generate lots
 								   of cores) */
 }
 
 
f2e1aa50
 /* like sig_alarm_kill, but the timeout has occurred when cleaning up
7fb8a246
  * => try to leave a core for future diagnostics */
 static void sig_alarm_abort(int signo)
 {
 	/* LOG is not signal safe, but who cares, we are abort-ing anyway :-) */
a2a91d7d
 	LM_CRIT("shutdown timeout triggered, dying...");
7fb8a246
 	abort();
 }
 
 
 
d4fb00dc
 static void shutdown_children(int sig, int show_status)
 {
 	kill_all_children(sig);
 	if (set_sig_h(SIGALRM, sig_alarm_kill) == SIG_ERR ) {
a2a91d7d
 		LM_ERR("could not install SIGALARM handler\n");
d4fb00dc
 		/* continue, the process will die anyway if no
 		 * alarm is installed which is exactly what we want */
 	}
 	alarm(ser_kill_timeout);
021e7e0e
 	while((wait(0) > 0) || (errno==EINTR)); /* wait for all the
d4fb00dc
 											   children to terminate*/
 	set_sig_h(SIGALRM, sig_alarm_abort);
 	cleanup(show_status); /* cleanup & show status*/
 	alarm(0);
 	set_sig_h(SIGALRM, SIG_IGN);
 }
 
 
 
abb01fb4
 void handle_sigs(void)
6e94f57f
 {
 	pid_t	chld;
 	int	chld_status;
1c5e1660
 	int	any_chld_stopped;
e4f42ce1
 	int memlog;
6e94f57f
 
 	switch(sig_flag){
 		case 0: break; /* do nothing*/
 		case SIGPIPE:
c082a437
 				/* SIGPIPE might be rarely received on use of
 				   exec module; simply ignore it
 				 */
a2a91d7d
 				LM_WARN("SIGPIPE received and ignored\n");
c082a437
 				break;
 		case SIGINT:
6e94f57f
 		case SIGTERM:
 			/* we end the program in all these cases */
 			if (sig_flag==SIGINT)
002879f8
 				LM_DBG("INT received, program terminates\n");
6e94f57f
 			else
002879f8
 				LM_DBG("SIGTERM received, program terminates\n");
a2a91d7d
 			LM_NOTICE("Thank you for flying " NAME "!!!\n");
d4fb00dc
 			/* shutdown/kill all the children */
 			shutdown_children(SIGTERM, 1);
6e94f57f
 			exit(0);
 			break;
b017f49c
 
6e94f57f
 		case SIGUSR1:
 #ifdef STATS
 			dump_all_statistic();
 #endif
e4f42ce1
 		memlog=cfg_get(core, core_cfg, memlog);
6e94f57f
 #ifdef PKG_MALLOC
d740c34e
 		if (memlog <= cfg_get(core, core_cfg, debug)){
 			if (cfg_get(core, core_cfg, mem_summary) & 1) {
 				LOG(memlog, "Memory status (pkg):\n");
 				pkg_status();
 			}
b8750364
 			if (cfg_get(core, core_cfg, mem_summary) & 4) {
d740c34e
 				LOG(memlog, "Memory still-in-use summary (pkg):\n");
 				pkg_sums();
 			}
 		}
6e94f57f
 #endif
d740c34e
 		if (memlog <= cfg_get(core, core_cfg, debug)){
b8750364
 			if (cfg_get(core, core_cfg, mem_summary) & 2) {
d740c34e
 				LOG(memlog, "Memory status (shm):\n");
 				shm_status();
 			}
b8750364
 			if (cfg_get(core, core_cfg, mem_summary) & 8) {
d740c34e
 				LOG(memlog, "Memory still-in-use summary (shm):\n");
 				shm_sums();
 			}
 		}
6e94f57f
 			break;
b017f49c
 
6e94f57f
 		case SIGCHLD:
1c5e1660
 			any_chld_stopped=0;
6e94f57f
 			while ((chld=waitpid( -1, &chld_status, WNOHANG ))>0) {
1c5e1660
 				any_chld_stopped=1;
b017f49c
 				if (WIFEXITED(chld_status))
a2a91d7d
 					LM_ALERT("child process %ld exited normally,"
ca351abe
 							" status=%d\n", (long)chld,
6e94f57f
 							WEXITSTATUS(chld_status));
 				else if (WIFSIGNALED(chld_status)) {
a2a91d7d
 					LM_ALERT("child process %ld exited by a signal"
ca351abe
 							" %d\n", (long)chld, WTERMSIG(chld_status));
6e94f57f
 #ifdef WCOREDUMP
a2a91d7d
 					LM_ALERT("core was %sgenerated\n",
a0196887
 							 WCOREDUMP(chld_status) ?  "" : "not " );
6e94f57f
 #endif
b017f49c
 				}else if (WIFSTOPPED(chld_status))
a2a91d7d
 					LM_ALERT("child process %ld stopped by a"
ca351abe
 								" signal %d\n", (long)chld,
6e94f57f
 								 WSTOPSIG(chld_status));
 			}
1c5e1660
 
 			/* If it appears that no child process has stopped, then do not terminate on SIGCHLD.
 			   Certain modules like app_python can run external scripts which cause child processes to be started and
 			   stopped. That can result in SIGCHLD being received here even though there is no real problem. Therefore,
 			   we do not terminate Kamailio unless we can find the child process which has stopped. */
 			if (!any_chld_stopped) {
 				LM_INFO("SIGCHLD received, but no child has stopped, ignoring it\n");
 				break;
 			}
 
49041f7b
 #ifndef STOP_JIRIS_CHANGES
 			if (dont_fork) {
a2a91d7d
 				LM_INFO("dont_fork turned on, living on\n");
49041f7b
 				break;
b017f49c
 			}
a2a91d7d
 			LM_INFO("terminating due to SIGCHLD\n");
49041f7b
 #endif
5a142f7c
 			LM_DBG("terminating due to SIGCHLD\n");
6e94f57f
 			/* exit */
d4fb00dc
 			shutdown_children(SIGTERM, 1);
dd7854ea
 			if (WIFSIGNALED(chld_status)) {
 				exit(1);
 			} else {
 				exit(0);
 			}
6e94f57f
 			break;
b017f49c
 
6e94f57f
 		case SIGHUP: /* ignoring it*/
002879f8
 					LM_DBG("SIGHUP received, ignoring it\n");
6e94f57f
 					break;
 		default:
a2a91d7d
 			LM_CRIT("unhandled signal %d\n", sig_flag);
6e94f57f
 	}
 	sig_flag=0;
 }
 
 
 
428e3b83
 /* 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
b017f49c
     - modified by andrei: moved most of the stuff to handle_sigs,
428e3b83
        made it safer for the "fork" case
 */
17cde665
 void sig_usr(int signo)
428e3b83
 {
 
e4f42ce1
 #ifdef PKG_MALLOC
 	int memlog;
 #endif
428e3b83
 
 	if (is_main){
 		if (sig_flag==0) sig_flag=signo;
 		else /*  previous sig. not processed yet, ignoring? */
 			return; ;
b017f49c
 		if (dont_fork)
428e3b83
 				/* only one proc, doing everything from the sig handler,
 				unsafe, but this is only for debugging mode*/
 			handle_sigs();
 	}else{
 		/* process the important signals */
 		switch(signo){
 			case SIGPIPE:
96d09107
 #ifdef SIG_DEBUG /* signal unsafe stuff follows */
a2a91d7d
 					LM_INFO("signal %d received\n", signo);
96d09107
 #endif
428e3b83
 				break;
 			case SIGINT:
 			case SIGTERM:
96d09107
 #ifdef SIG_DEBUG /* signal unsafe stuff follows */
a2a91d7d
 					LM_INFO("signal %d received\n", signo);
428e3b83
 					/* print memory stats for non-main too */
 					#ifdef PKG_MALLOC
5c323052
 					/* make sure we have current cfg values, but update only
 					  the safe part (values not requiring callbacks), to
 					  account for processes that might not have registered
 					  config support */
 					cfg_update_no_cbs();
e4f42ce1
 					memlog=cfg_get(core, core_cfg, memlog);
d740c34e
 					if (memlog <= cfg_get(core, core_cfg, debug)){
 						if (cfg_get(core, core_cfg, mem_summary) & 1) {
 							LOG(memlog, "Memory status (pkg):\n");
 							pkg_status();
 						}
b8750364
 						if (cfg_get(core, core_cfg, mem_summary) & 4) {
d740c34e
 							LOG(memlog, "Memory still-in-use summary (pkg):"
 									"\n");
 							pkg_sums();
 						}
 					}
428e3b83
 					#endif
96d09107
 #endif
5b84defd
 					_exit(0);
428e3b83
 					break;
 			case SIGUSR1:
cf085a87
 #ifdef PKG_MALLOC
 					cfg_update_no_cbs();
 					memlog=cfg_get(core, core_cfg, memlog);
 					if (memlog <= cfg_get(core, core_cfg, debug)){
 						if (cfg_get(core, core_cfg, mem_summary) & 1) {
 							LOG(memlog, "Memory status (pkg):\n");
 							pkg_status();
 						}
b8750364
 						if (cfg_get(core, core_cfg, mem_summary) & 4) {
cf085a87
 							LOG(memlog, "Memory still-in-use summary (pkg):\n");
 							pkg_sums();
 						}
 					}
 #endif
428e3b83
 					break;
 				/* ignored*/
 			case SIGUSR2:
 			case SIGHUP:
 					break;
 			case SIGCHLD:
 #ifndef 			STOP_JIRIS_CHANGES
96d09107
 #ifdef SIG_DEBUG /* signal unsafe stuff follows */
002879f8
 					LM_DBG("SIGCHLD received: "
428e3b83
 						"we do not worry about grand-children\n");
96d09107
 #endif
428e3b83
 #else
5b84defd
 					_exit(0); /* terminate if one child died */
428e3b83
 #endif
96d09107
 					break;
428e3b83
 		}
 	}
 }
 
 
 
 /* install the signal handlers, returns 0 on success, -1 on error */
abb01fb4
 int install_sigs(void)
428e3b83
 {
 	/* added by jku: add exit handler */
02dae965
 	if (set_sig_h(SIGINT, sig_usr) == SIG_ERR ) {
bf79b581
 		ERR("no SIGINT signal handler can be installed\n");
428e3b83
 		goto error;
 	}
 	/* if we debug and write to a pipe, we want to exit nicely too */
02dae965
 	if (set_sig_h(SIGPIPE, sig_usr) == SIG_ERR ) {
bf79b581
 		ERR("no SIGINT signal handler can be installed\n");
428e3b83
 		goto error;
 	}
02dae965
 	if (set_sig_h(SIGUSR1, sig_usr)  == SIG_ERR ) {
bf79b581
 		ERR("no SIGUSR1 signal handler can be installed\n");
428e3b83
 		goto error;
 	}
02dae965
 	if (set_sig_h(SIGCHLD , sig_usr)  == SIG_ERR ) {
bf79b581
 		ERR("no SIGCHLD signal handler can be installed\n");
428e3b83
 		goto error;
 	}
02dae965
 	if (set_sig_h(SIGTERM , sig_usr)  == SIG_ERR ) {
bf79b581
 		ERR("no SIGTERM signal handler can be installed\n");
428e3b83
 		goto error;
 	}
02dae965
 	if (set_sig_h(SIGHUP , sig_usr)  == SIG_ERR ) {
bf79b581
 		ERR("no SIGHUP signal handler can be installed\n");
428e3b83
 		goto error;
 	}
02dae965
 	if (set_sig_h(SIGUSR2 , sig_usr)  == SIG_ERR ) {
bf79b581
 		ERR("no SIGUSR2 signal handler can be installed\n");
428e3b83
 		goto error;
 	}
 	return 0;
 error:
 	return -1;
 }
 
943a9d00
 /* returns -1 on error, 0 on success
  * sets proto */
6335d07c
 int parse_proto(unsigned char* s, long len, int* proto)
943a9d00
 {
c3611173
 #define PROTO2UINT3(a, b, c) ((	(((unsigned int)(a))<<16)+ \
943a9d00
 								(((unsigned int)(b))<<8)+  \
 								((unsigned int)(c)) ) | 0x20202020)
c3611173
 #define PROTO2UINT4(a, b ,c ,d) ((	(((unsigned int)(a))<<24)+ \
 									(((unsigned int)(b))<<16)+ \
 									(((unsigned int)(c))<< 8)+ \
 									(((unsigned int)(d))) \
 								  )| 0x20202020 )
943a9d00
 	unsigned int i;
c3611173
 	if (likely(len==3)){
 		i=PROTO2UINT3(s[0], s[1], s[2]);
 		switch(i){
 			case PROTO2UINT3('u', 'd', 'p'):
 				*proto=PROTO_UDP;
 				break;
943a9d00
 #ifdef USE_TCP
c3611173
 			case PROTO2UINT3('t', 'c', 'p'):
 				*proto=PROTO_TCP;
 				break;
943a9d00
 #ifdef USE_TLS
c3611173
 			case PROTO2UINT3('t', 'l', 's'):
 				*proto=PROTO_TLS;
 				break;
943a9d00
 #endif
 #endif
c3611173
 			default:
 				return -1;
 		}
 	}
 #ifdef USE_SCTP
 	else if (likely(len==4)){
 		i=PROTO2UINT4(s[0], s[1], s[2], s[3]);
 		if (i==PROTO2UINT4('s', 'c', 't', 'p'))
 			*proto=PROTO_SCTP;
 		else
943a9d00
 			return -1;
 	}
c3611173
 #endif /* USE_SCTP */
 	else
3d4a77d8
 	/* Deliberately leaving out PROTO_WS and PROTO_WSS as these are just
 	   upgraded TCP/TLS connections. */
c3611173
 		return -1;
943a9d00
 	return 0;
 }
 
 
 
72bba9e3
 static struct name_lst* mk_name_lst_elem(char* name, int name_len, int flags)
 {
 	struct name_lst* l;
 	
 	l=pkg_malloc(sizeof(struct name_lst)+name_len+1/* 0 */);
 	if (l){
 		l->name=((char*)l)+sizeof(struct name_lst);
 		memcpy(l->name, name, name_len);
 		l->name[name_len]=0;
 		l->flags=flags;
 		l->next=0;
5667377c
 		return l;
 	} else {
 		PKG_MEM_ERROR;
 		return 0;
72bba9e3
 	}
 }
 
 
 
 /* free a name_lst list with elements allocated with mk_name_lst_elem
  * (single block both for the structure and for the name) */
 static void free_name_lst(struct name_lst* lst)
 {
 	struct name_lst* l;
 	
 	while(lst){
 		l=lst;
 		lst=lst->next;
 		pkg_free(l);
 	}
 }
 
 
 
 /* parse h and returns a name lst (flags are set to SI_IS_MHOMED if
  * h contains more then one name or contains a name surrounded by '(' ')' )
  * valid formats:    "hostname"
  *                   "(hostname, hostname1, hostname2)"
  *                   "(hostname hostname1 hostname2)"
  *                   "(hostname)"
  */
 static struct name_lst* parse_name_lst(char* h, int h_len)
 {
 	char* last;
 	char* p;
 	struct name_lst* n_lst;
 	struct name_lst* l;
 	struct name_lst** tail;
 	int flags;
 	
 	n_lst=0;
 	tail=&n_lst;
 	last=h+h_len-1;
 	flags=0;
 	/* eat whitespace */
 	for(; h<=last && ((*h==' ') || (*h=='\t')); h++);
 	for(; last>h && ((*last==' ') || (*last=='\t')); last--);
 	/* catch empty strings and invalid lens */
 	if (h>last) goto error;
 	
 	if (*h=='('){
 		/* list mode */
 		if (*last!=')' || ((h+1)>(last-1)))
 			goto error;
 		h++;
 		last--;
 		flags=SI_IS_MHOMED;
 		for(p=h; p<=last; p++)
 			switch (*p){
 				case ',':
 				case ';':
 				case ' ':
 				case '\t':
 					if ((int)(p-h)>0){
 						l=mk_name_lst_elem(h, (int)(p-h), flags);
 						if (l==0) 
 							goto error;
 						*tail=l;
 						tail=&l->next;
 					}
 					h=p+1;
 					break;
 			}
 	}else{
 		/* single addr. mode */
 		flags=0;
 		p=last+1;
 	}
 	if ((int)(p-h)>0){
 		l=mk_name_lst_elem(h, (int)(p-h), flags);
 		if (l==0) 
 			goto error;
 		*tail=l;
 		tail=&l->next;
 	}
 	return n_lst;
 error:
 	if (n_lst) free_name_lst(n_lst);
 	return 0;
 }
 
 
 
943a9d00
 /*
72bba9e3
  * parses [proto:]host[:port]  or
  *  [proto:](host_1, host_2, ... host_n)[:port]
943a9d00
  * where proto= udp|tcp|tls
72bba9e3
  * returns  fills proto, port, host and returns list of addresses on success
  * (pkg malloc'ed) and 0 on failure
943a9d00
  */
df088fb8
 /** get protocol host and port from a string representation.
  * parses [proto:]host[:port]  or
  *  [proto:](host_1, host_2, ... host_n)[:port]
  * where proto= udp|tcp|tls|sctp
  * @param s  - string (like above)
  * @param host - will be filled with the host part
  *               Note: for multi-homing it wil contain all the addresses
  *               (e.g.: "sctp:(1.2.3.4, 5.6.7.8)" => host="(1.2.3.4, 5.6.7.8)")
  * @param hlen - will be filled with the length of the host part.
  * @param port - will be filled with the port if present or 0 if it's not.
  * @param proto - will be filled with the protocol if present or PROTO_NONE
  *                if it's not.
  * @return  fills proto, port, host and returns 0 on success and -1 on failure.
  */
 int parse_phostport(char* s, char** host, int* hlen,
537ce843
 								 int* port, int* proto)
943a9d00
 {
 	char* first; /* first ':' occurrence */
 	char* second; /* second ':' occurrence */
 	char* p;
 	int bracket;
 	char* tmp;
b017f49c
 
943a9d00
 	first=second=0;
 	bracket=0;
b017f49c
 
943a9d00
 	/* find the first 2 ':', ignoring possible ipv6 addresses
 	 * (substrings between [])
 	 */
 	for(p=s; *p; p++){
 		switch(*p){
 			case '[':
 				bracket++;
 				if (bracket>1) goto error_brackets;
 				break;
 			case ']':
 				bracket--;
 				if (bracket<0) goto error_brackets;
 				break;
 			case ':':
 				if (bracket==0){
 					if (first==0) first=p;
 					else if( second==0) second=p;
 					else goto error_colons;
 				}
 				break;
 		}
 	}
df088fb8
 	if (p==s) return -1;
943a9d00
 	if (*(p-1)==':') goto error_colons;
b017f49c
 
943a9d00
 	if (first==0){ /* no ':' => only host */
 		*host=s;
 		*hlen=(int)(p-s);
 		*port=0;
 		*proto=0;
72bba9e3
 		goto end;
943a9d00
 	}
 	if (second){ /* 2 ':' found => check if valid */
d7a3fdea
 		if (parse_proto((unsigned char*)s, first-s, proto)<0) goto error_proto;
943a9d00
 		*port=strtol(second+1, &tmp, 10);
 		if ((tmp==0)||(*tmp)||(tmp==second+1)) goto error_port;
 		*host=first+1;
 		*hlen=(int)(second-*host);
72bba9e3
 		goto end;
943a9d00
 	}
 	/* only 1 ':' found => it's either proto:host or host:port */
 	*port=strtol(first+1, &tmp, 10);
 	if ((tmp==0)||(*tmp)||(tmp==first+1)){
 		/* invalid port => it's proto:host */
d7a3fdea
 		if (parse_proto((unsigned char*)s, first-s, proto)<0) goto error_proto;
943a9d00
 		*port=0;
 		*host=first+1;
 		*hlen=(int)(p-*host);
 	}else{
 		/* valid port => its host:port */
 		*proto=0;
 		*host=s;
 		*hlen=(int)(first-*host);
 	}
72bba9e3
 end:
df088fb8
 	return 0;
943a9d00
 error_brackets:
a2a91d7d
 	LM_ERR("too many brackets in %s\n", s);
df088fb8
 	return -1;
943a9d00
 error_colons:
a2a91d7d
 	LM_ERR("too many colons in %s\n", s);
df088fb8
 	return -1;
943a9d00
 error_proto:
a2a91d7d
 	LM_ERR("bad protocol in %s\n", s);
df088fb8
 	return -1;
943a9d00
 error_port:
a2a91d7d
 	LM_ERR("bad port number in %s\n", s);
df088fb8
 	return -1;
 }
 
 
 
 /** get protocol host, port and MH addresses list from a string representation.
  * parses [proto:]host[:port]  or
  *  [proto:](host_1, host_2, ... host_n)[:port]
  * where proto= udp|tcp|tls|sctp
  * @param s  - string (like above)
  * @param host - will be filled with the host part
  *               Note: for multi-homing it wil contain all the addresses
  *               (e.g.: "sctp:(1.2.3.4, 5.6.7.8)" => host="(1.2.3.4, 5.6.7.8)")
  * @param hlen - will be filled with the length of the host part.
  * @param port - will be filled with the port if present or 0 if it's not.
  * @param proto - will be filled with the protocol if present or PROTO_NONE
  *                if it's not.
  * @return  fills proto, port, host and returns list of addresses on success
  * (pkg malloc'ed) and 0 on failure
  */
 static struct name_lst* parse_phostport_mh(char* s, char** host, int* hlen,
 								 int* port, int* proto)
 {
 	if (parse_phostport(s, host, hlen, port, proto)==0)
 		return parse_name_lst(*host, *hlen);
72bba9e3
 	return 0;
943a9d00
 }
 
 
df088fb8
 
b2471cfc
 /** Update \c cfg_file variable to contain full pathname. The function updates
  * the value of \c cfg_file global variable to contain full absolute pathname
  * to the main configuration file of SER. The function uses CFG_FILE macro to
  * determine the default path to the configuration file if the user did not
  * specify one using the command line option. If \c cfg_file contains an
  * absolute pathname then it is used unmodified, if it contains a relative
  * pathanme than the value returned by \c getcwd function will be added at the
  * beginning. This function must be run before SER changes its current working
  * directory to / (in daemon mode).
  * @return Zero on success, negative number
  * on error.
  */
 int fix_cfg_file(void)
 {
 	char* res = NULL;
 	size_t max_len, cwd_len, cfg_len;
 	
 	if (cfg_file == NULL) cfg_file = CFG_FILE;
 	if (cfg_file[0] == '/') return 0;
6f96f4fb
 	if (cfg_file[0] == '-' && strlen(cfg_file)==1) return 0;
b2471cfc
 	
 	/* cfg_file contains a relative pathname, get the current
 	 * working directory and add it at the beginning
 	 */
 	cfg_len = strlen(cfg_file);
 	
 	max_len = pathmax();
 	if ((res = malloc(max_len)) == NULL) goto error;
 	
 	if (getcwd(res, max_len) == NULL) goto error;
 	cwd_len = strlen(res);
 	
 	/* Make sure that the buffer is big enough */
 	if (cwd_len + 1 + cfg_len >= max_len) goto error;
 	
 	res[cwd_len] = '/';
 	memcpy(res + cwd_len + 1, cfg_file, cfg_len);
 	
 	res[cwd_len + 1 + cfg_len] = '\0'; /* Add terminating zero */
 	cfg_file = res;
 	return 0;
 	
  error:
 	fprintf(stderr, "ERROR: Unable to fix cfg_file to contain full pathname\n");
 	if (res) free(res);
 	return -1;
 }
 
943a9d00
 
cc2199a9
 /* main loop */
abb01fb4
 int main_loop(void)
cc2199a9
 {
9f4c52ce
 	int  i;
cc2199a9
 	pid_t pid;
9f4c52ce
 	struct socket_info* si;
f238de3d
 	char si_desc[MAX_PT_DESC];
af93cbdf
 #ifdef EXTRA_DEBUG
5f8ad85f
 	int r;
 #endif
edf5e385
 	int nrprocs;
b3d38eac
 	int woneinit;
cc2199a9
 
4c57d02e
 	if(_sr_instance_started == NULL) {
 		_sr_instance_started = shm_malloc(sizeof(int));
 		if(_sr_instance_started == NULL) {
851fe7f7
 			SHM_MEM_ERROR;
4c57d02e
 			goto error;
 		}
 		*_sr_instance_started = 0;
 	}
cc2199a9
 	/* one "main" process and n children handling i/o */
 	if (dont_fork){
f571aa35
 #ifdef STATS
 		setstats( 0 );
 #endif
49de5d20
 		if (udp_listen==0){
a2a91d7d
 			LM_ERR("no fork mode requires at least one"
49de5d20
 					" udp listen address, exiting...\n");
 			goto error;
 		}
36ef0329
 		/* only one address, we ignore all the others */
9f4c52ce
 		if (udp_init(udp_listen)==-1) goto error;
 		bind_address=udp_listen;
22e7e32e
 		if (bind_address->address.af==AF_INET) {
61b60763
 			sendipv4=bind_address;
22e7e32e
 #ifdef USE_RAW_SOCKS
 		/* always try to have a raw socket opened if we are using ipv4 */
 		raw_udp4_send_sock = raw_socket(IPPROTO_RAW, 0, 0, 1);
 		if (raw_udp4_send_sock < 0) {
 			if ( default_core_cfg.udp4_raw > 0) {
 				/* force use raw socket failed */
 				ERR("could not initialize raw udp send socket (ipv4):"
 						" %s (%d)\n", strerror(errno), errno);
 				if (errno == EPERM)
 					ERR("could not initialize raw socket on startup"
 						" due to inadequate permissions, please"
 						" restart as root or with CAP_NET_RAW\n");
 				goto error;
 			}
 			default_core_cfg.udp4_raw = 0; /* disabled */
 		} else {
 			register_fds(1);
 			if (default_core_cfg.udp4_raw < 0) {
 				/* auto-detect => use it */
 				default_core_cfg.udp4_raw = 1; /* enabled */
002879f8
 				LM_DBG("raw socket possible => turning it on\n");
22e7e32e
 			}
9eb54078
 			if (default_core_cfg.udp4_raw_ttl < 0) {
 				/* auto-detect */
 				default_core_cfg.udp4_raw_ttl = sock_get_ttl(sendipv4->socket);
 				if (default_core_cfg.udp4_raw_ttl < 0)
 					/* error, use some default value */
 					default_core_cfg.udp4_raw_ttl = 63;
 			}
22e7e32e
 		}
 #else
94d2d2e6
 		default_core_cfg.udp4_raw = 0;
22e7e32e
 #endif /* USE_RAW_SOCKS */
 		} else
61b60763
 			sendipv6=bind_address;
9f4c52ce
 		if (udp_listen->next){
a2a91d7d
 			LM_WARN("using only the first listen address (no fork)\n");
36ef0329
 		}
5322385b
 
fbf0d2e0
 		/* delay cfg_shmize to the last moment (it must be called _before_
 		   forking). Changes to default cfgs after this point will be
 		   ignored.
 		*/
 		if (cfg_shmize() < 0) {
a2a91d7d
 			LM_CRIT("could not initialize shared configuration\n");
fbf0d2e0
 			goto error;
 		}
ec15b23f
 
5322385b
 		/* Register the children that will keep updating their
 		 * local configuration */
 		cfg_register_child(
 				1   /* main = udp listener */
 				+ 1 /* timer */
 #ifdef USE_SLOW_TIMER
 				+ 1 /* slow timer */
 #endif
 			);
53c7e0f1
 		if (do_suid()==-1) goto error; /* try to drop privileges */
db249450
 		/* process_no now initialized to zero -- increase from now on
b017f49c
 		   as new processes are forked (while skipping 0 reserved for main
db249450
 		*/
 
5d3449a0
 		/* Temporary set the local configuration of the main process
 		 * to make the group instances available in PROC_INIT.
 		 */
 		cfg_main_set_local();
 
35e94c97
 		/* init log prefix format */
 		log_prefix_init();
 
021e7e0e
 		/* init childs with rank==PROC_INIT before forking any process,
f828cb17
 		 * this is a place for delayed (after mod_init) initializations
 		 * (e.g. shared vars that depend on the total number of processes
 		 * that is known only after all mod_inits have been executed )
 		 * WARNING: the same init_child will be called latter, a second time
021e7e0e
 		 * for the "main" process with rank PROC_MAIN (make sure things are
f828cb17
 		 * not initialized twice)*/
 		if (init_child(PROC_INIT) < 0) {
a2a91d7d
 			LM_ERR("init_child(PROC_INT) -- exiting\n");
5d3449a0
 			cfg_main_reset_local();
f828cb17
 			goto error;
 		}
5d3449a0
 		cfg_main_reset_local();
4208dc00
 		if (counters_prefork_init(get_max_procs()) == -1) goto error;
f828cb17
 
af93cbdf
 #ifdef USE_SLOW_TIMER
 		/* we need another process to act as the "slow" timer*/
37209e14
 				pid = fork_process(PROC_TIMER, "slow timer", 0);
 				if (pid<0){
a2a91d7d
 					LM_CRIT("Cannot fork\n");
af93cbdf
 					goto error;
 				}
 				if (pid==0){
 					/* child */
 					/* timer!*/
8390f722
 					if (real_time&2)
 						set_rt_prio(rt_timer2_prio, rt_timer2_policy);
021e7e0e
 
af93cbdf
 					if (arm_slow_timer()<0) goto error;
 					slow_timer_main();
 				}else{
 					slow_timer_pid=pid;
 				}
5dc00db6
 #endif
af93cbdf
 				/* we need another process to act as the "main" timer*/
37209e14
 				pid = fork_process(PROC_TIMER, "timer", 0);
 				if (pid<0){
a2a91d7d
 					LM_CRIT("Cannot fork\n");
cd57180a
 					goto error;
 				}
 				if (pid==0){
 					/* child */
 					/* timer!*/
8390f722
 					if (real_time&1)
 						set_rt_prio(rt_timer1_prio, rt_timer1_policy);
af93cbdf
 					if (arm_timer()<0) goto error;
 					timer_main();
cbd9fc8b
 				}else{
cd57180a
 				}
1380e79e
 
a482c5de
 		if(sr_wtimer_start()<0) {
 			LM_CRIT("Cannot start wtimer\n");
 			goto error;
 		}
72b7f9a2
 		/* main process, receive loop */
 		process_no=0; /*main process number*/
f51155cf
 		pt[process_no].pid=getpid();
b017f49c
 		snprintf(pt[process_no].desc, MAX_PT_DESC,
 			"stand-alone receiver @ %s:%s",
f51155cf
 			 bind_address->name.s, bind_address->port_no_str.s );
021e7e0e
 
c3611173
 		/* call it also w/ PROC_MAIN to make sure modules that init things 
 		 * only in PROC_MAIN get a chance to run */
 		if (init_child(PROC_MAIN) < 0) {
a2a91d7d
 			LM_ERR("init_child(PROC_MAIN) -- exiting\n");
c3611173
 			goto error;
 		}
b017f49c
 
8390f722
 		/* 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
 		 */
eedd46b1
 
ece30366
 		if (init_child(PROC_SIPINIT) < 0) {
a2a91d7d
 			LM_ERR("init_child failed\n");
192ac55b
 			goto error;
 		}
4c57d02e
 		*_sr_instance_started = 1;
391fa285
 		return udp_rcv_loop();
8390f722
 	}else{ /* fork: */
9e7eed4d
 
5322385b
 		/* Register the children that will keep updating their
 		 * local configuration. (udp/tcp/sctp listeneres
 		 * will be added later.) */
 		cfg_register_child(
 				1   /* timer */
 #ifdef USE_SLOW_TIMER
 				+ 1 /* slow timer */
 #endif
 			);
 
9f4c52ce
 		for(si=udp_listen;si;si=si->next){
1fb7b1aa
 			/* create the listening socket (for each address)*/
f2f969dd
 			/* udp */
9f4c52ce
 			if (udp_init(si)==-1) goto error;
36ef0329
 			/* get first ipv4/ipv6 socket*/
9f4c52ce
 			if ((si->address.af==AF_INET)&&
8b17718a
 					((sendipv4==0)||(sendipv4->flags&(SI_IS_LO|SI_IS_MCAST))))
9f4c52ce
 				sendipv4=si;
61b60763
 			if ( ((sendipv6==0)||(sendipv6->flags&(SI_IS_LO|SI_IS_MCAST))) &&
 					(si->address.af==AF_INET6))
9f4c52ce
 				sendipv6=si;
5322385b
 			/* children_no per each socket */
edf5e385
 			cfg_register_child((si->workers>0)?si->workers:children_no);
9f4c52ce
 		}
22e7e32e
 #ifdef USE_RAW_SOCKS
 		/* always try to have a raw socket opened if we are using ipv4 */
 		if (sendipv4) {
 			raw_udp4_send_sock = raw_socket(IPPROTO_RAW, 0, 0, 1);
 			if (raw_udp4_send_sock < 0) {
 				if ( default_core_cfg.udp4_raw > 0) {
 						/* force use raw socket failed */
 						ERR("could not initialize raw udp send socket (ipv4):"
 								" %s (%d)\n", strerror(errno), errno);
 						if (errno == EPERM)
 							ERR("could not initialize raw socket on startup"
 								" due to inadequate permissions, please"
 								" restart as root or with CAP_NET_RAW\n");
 						goto error;
 					}
 					default_core_cfg.udp4_raw = 0; /* disabled */
 			} else {
 				register_fds(1);
 				if (default_core_cfg.udp4_raw < 0) {
 					/* auto-detect => use it */
 					default_core_cfg.udp4_raw = 1; /* enabled */
002879f8
 					LM_DBG("raw socket possible => turning it on\n");
22e7e32e
 				}
9eb54078
 				if (default_core_cfg.udp4_raw_ttl < 0) {
 					/* auto-detect */
 					default_core_cfg.udp4_raw_ttl =
 						sock_get_ttl(sendipv4->socket);
 					if (default_core_cfg.udp4_raw_ttl < 0)
 						/* error, use some default value */
 						default_core_cfg.udp4_raw_ttl = 63;
 				}
22e7e32e
 			}
 		}
 #else
 		default_core_cfg.udp4_raw = 0;
 #endif /* USE_RAW_SOCKS */
c3611173
 #ifdef USE_SCTP
 		if (!sctp_disable){
 			for(si=sctp_listen; si; si=si->next){
7f8e7a85
 				if (sctp_core_init_sock(si)==-1)  goto error;
c3611173
 				/* get first ipv4/ipv6 socket*/
61b60763
 				if ((si->address.af==AF_INET) &&
 						((sendipv4_sctp==0) ||
 							(sendipv4_sctp->flags&(SI_IS_LO|SI_IS_MCAST))))
c3611173
 					sendipv4_sctp=si;
61b60763
 				if( ((sendipv6_sctp==0) || 
 							(sendipv6_sctp->flags&(SI_IS_LO|SI_IS_MCAST))) &&
 						(si->address.af==AF_INET6))
c3611173
 					sendipv6_sctp=si;
5322385b
 				/* sctp_children_no per each socket */
edf5e385
 				cfg_register_child((si->workers>0)?si->workers:sctp_children_no);
c3611173
 			}
 		}
 #endif /* USE_SCTP */
f2f969dd
 #ifdef USE_TCP
9f4c52ce
 		if (!tcp_disable){
 			for(si=tcp_listen; si; si=si->next){
5dcfb23d
 				/* same thing for tcp */
9f4c52ce
 				if (tcp_init(si)==-1)  goto error;
5dcfb23d
 				/* get first ipv4/ipv6 socket*/
9f4c52ce
 				if ((si->address.af==AF_INET)&&
61b60763
 						((sendipv4_tcp==0) ||
 							(sendipv4_tcp->flags&(SI_IS_LO|SI_IS_MCAST))))
9f4c52ce
 					sendipv4_tcp=si;
61b60763
 				if( ((sendipv6_tcp==0) ||
 							(sendipv6_tcp->flags&(SI_IS_LO|SI_IS_MCAST))) &&
 						(si->address.af==AF_INET6))
9f4c52ce
 					sendipv6_tcp=si;
5dcfb23d
 			}
5322385b
 			/* the number of sockets does not matter */
 			cfg_register_child(tcp_children_no + 1 /* tcp main */);
9f4c52ce
 		}
f22b996b
 #ifdef USE_TLS
6c53d41a
 		if (!tls_disable && tls_has_init_si()){
9f4c52ce
 			for(si=tls_listen; si; si=si->next){
f22b996b
 				/* same as for tcp*/
9f4c52ce
 				if (tls_init(si)==-1)  goto error;
f22b996b
 				/* get first ipv4/ipv6 socket*/
9f4c52ce
 				if ((si->address.af==AF_INET)&&
61b60763
 						((sendipv4_tls==0) ||
 							(sendipv4_tls->flags&(SI_IS_LO|SI_IS_MCAST))))
9f4c52ce
 					sendipv4_tls=si;
61b60763
 				if( ((sendipv6_tls==0) ||
 							(sendipv6_tls->flags&(SI_IS_LO|SI_IS_MCAST))) &&
 						(si->address.af==AF_INET6))
9f4c52ce
 					sendipv6_tls=si;
f22b996b
 			}
9f4c52ce
 		}
f22b996b
 #endif /* USE_TLS */
 #endif /* USE_TCP */
b3fef92b
 
c3611173
 			/* all processes should have access to all the sockets (for 
 			 * sending) so we open all first*/
53c7e0f1
 		if (do_suid()==-1) goto error; /* try to drop privileges */
9e7eed4d
 
fbf0d2e0
 		/* delay cfg_shmize to the last moment (it must be called _before_
 		   forking). Changes to default cfgs after this point will be
 		   ignored (cfg_shmize() will copy the default cfgs into shmem).
 		*/
 		if (cfg_shmize() < 0) {
a2a91d7d
 			LM_CRIT("could not initialize shared configuration\n");
fbf0d2e0
 			goto error;
 		}
5d3449a0
 
 		/* Temporary set the local configuration of the main process
 		 * to make the group instances available in PROC_INIT.
 		 */
 		cfg_main_set_local();
 
35e94c97
 		/* init log prefix format */
 		log_prefix_init();
 
021e7e0e
 		/* init childs with rank==PROC_INIT before forking any process,
8390f722
 		 * this is a place for delayed (after mod_init) initializations
 		 * (e.g. shared vars that depend on the total number of processes
 		 * that is known only after all mod_inits have been executed )
 		 * WARNING: the same init_child will be called latter, a second time
021e7e0e
 		 * for the "main" process with rank PROC_MAIN (make sure things are
8390f722
 		 * not initialized twice)*/
 		if (init_child(PROC_INIT) < 0) {
a2a91d7d
 			LM_ERR("error in init_child(PROC_INT) -- exiting\n");
5d3449a0
 			cfg_main_reset_local();
8390f722
 			goto error;
 		}
5d3449a0
 		cfg_main_reset_local();
4208dc00
 		if (counters_prefork_init(get_max_procs()) == -1) goto error;
8390f722
 
 
b3d38eac
 		woneinit = 0;
9f4c52ce
 		/* udp processes */
 		for(si=udp_listen; si; si=si->next){
edf5e385
 			nrprocs = (si->workers>0)?si->workers:children_no;
 			for(i=0;i<nrprocs;i++){
5629f449
 				if(si->address.af==AF_INET6) {
574daa6d
 					if(si->useinfo.name.s)
 						snprintf(si_desc, MAX_PT_DESC, "udp receiver child=%d "
 							"sock=[%s]:%s (%s:%s)",
 							i, si->name.s, si->port_no_str.s,
 							si->useinfo.name.s, si->useinfo.port_no_str.s);
 					else
 						snprintf(si_desc, MAX_PT_DESC, "udp receiver child=%d "
 							"sock=[%s]:%s",
 							i, si->name.s, si->port_no_str.s);
5629f449
 				} else {
574daa6d
 					if(si->useinfo.name.s)
 						snprintf(si_desc, MAX_PT_DESC, "udp receiver child=%d "
 							"sock=%s:%s (%s:%s)",
 							i, si->name.s, si->port_no_str.s,
 							si->useinfo.name.s, si->useinfo.port_no_str.s);
 					else
 						snprintf(si_desc, MAX_PT_DESC, "udp receiver child=%d "
 							"sock=%s:%s",
 							i, si->name.s, si->port_no_str.s);
5629f449
 				}
3167c744
 				child_rank++;
f238de3d
 				pid = fork_process(child_rank, si_desc, 1);
37209e14
 				if (pid<0){
a2a91d7d
 					LM_CRIT("Cannot fork\n");
cc2199a9
 					goto error;
36ef0329
 				}else if (pid==0){
37209e14
 					/* child */
9f4c52ce
 					bind_address=si; /* shortcut */
f571aa35
 #ifdef STATS
0df81fe8
 					setstats( i+r*children_no );
f571aa35
 #endif
b3d38eac
 					if(woneinit==0) {
 						if(run_child_one_init_route()<0)
 							goto error;
 					}
cc2199a9
 					return udp_rcv_loop();
 				}
b3d38eac
 				woneinit = 1;
cc2199a9
 			}
bf0fab3f
 			/*parent*/
 			/*close(udp_sock)*/; /*if it's closed=>sendto invalid fd errors?*/
cc2199a9
 		}
c3611173
 #ifdef USE_SCTP
 		/* sctp processes */
 		if (!sctp_disable){
 			for(si=sctp_listen; si; si=si->next){
edf5e385
 				nrprocs = (si->workers>0)?si->workers:sctp_children_no;
 				for(i=0;i<nrprocs;i++){
5629f449
 					if(si->address.af==AF_INET6) {
 						snprintf(si_desc, MAX_PT_DESC, "sctp receiver child=%d "
 								"sock=[%s]:%s",
 								i, si->name.s, si->port_no_str.s);
 					} else {
 						snprintf(si_desc, MAX_PT_DESC, "sctp receiver child=%d "
c3611173
 								"sock=%s:%s",
 								i, si->name.s, si->port_no_str.s);
5629f449
 					}
c3611173
 					child_rank++;
 					pid = fork_process(child_rank, si_desc, 1);
 					if (pid<0){
a2a91d7d
 						LM_CRIT("Cannot fork\n");
c3611173
 						goto error;
 					}else if (pid==0){
 						/* child */
 						bind_address=si; /* shortcut */
 #ifdef STATS
 						setstats( i+r*children_no );
 #endif
7f8e7a85
 						return sctp_core_rcv_loop();
c3611173
 					}
 				}
 			/*parent*/
 			/*close(sctp_sock)*/; /*if closed=>sendto invalid fd errors?*/
 			}
 		}
 #endif /* USE_SCTP */
db249450
 
c3611173
 		/*this is the main process*/
 		bind_address=0;	/* main proc -> it shouldn't send anything, */
b017f49c
 
af93cbdf
 #ifdef USE_SLOW_TIMER
 		/* fork again for the "slow" timer process*/
37209e14
 		pid = fork_process(PROC_TIMER, "slow timer", 1);
 		if (pid<0){
a2a91d7d
 			LM_CRIT("cannot fork \"slow\" timer process\n");
af93cbdf
 			goto error;
 		}else if (pid==0){
 			/* child */
8390f722
 			if (real_time&2)
 				set_rt_prio(rt_timer2_prio, rt_timer2_policy);
af93cbdf
 			if (arm_slow_timer()<0) goto error;
 			slow_timer_main();
 		}else{
 			slow_timer_pid=pid;
 		}
 #endif /* USE_SLOW_TIMER */
b017f49c
 
af93cbdf
 		/* fork again for the "main" timer process*/
37209e14
 		pid = fork_process(PROC_TIMER, "timer", 1);
 		if (pid<0){
a2a91d7d
 			LM_CRIT("cannot fork timer process\n");
6e94f57f
 			goto error;
 		}else if (pid==0){
 			/* child */
8390f722
 			if (real_time&1)
 				set_rt_prio(rt_timer1_prio, rt_timer1_policy);
af93cbdf
 			if (arm_timer()<0) goto error;
 			timer_main();
cd57180a
 		}
a482c5de
 		if(sr_wtimer_start()<0) {
 			LM_CRIT("Cannot start wtimer\n");
 			goto error;
 		}
f2e1aa50
 
c3611173
 	/* init childs with rank==MAIN before starting tcp main (in case they want
 	 * to fork  a tcp capable process, the corresponding tcp. comm. fds in
 	 * pt[] must be set before calling tcp_main_loop()) */
 		if (init_child(PROC_MAIN) < 0) {
a2a91d7d
 			LM_ERR("error in init_child\n");
c3611173
 			goto error;
 		}
f2e1aa50
 
0c5da34b
 #ifdef USE_TCP
5dcfb23d
 		if (!tcp_disable){
f22b996b
 				/* start tcp  & tls receivers */
5dcfb23d
 			if (tcp_init_children()<0) goto error;
f22b996b
 				/* start tcp+tls master proc */
37209e14
 			pid = fork_process(PROC_TCP_MAIN, "tcp main process", 0);
 			if (pid<0){
a2a91d7d
 				LM_CRIT("cannot fork tcp main process: %s\n", strerror(errno));
cb87691a
 				goto error;
5dcfb23d
 			}else if (pid==0){
 				/* child */
 				tcp_main_loop();
 			}else{
f2e1aa50
 				tcp_main_pid=pid;
5dcfb23d
 				unix_tcp_sock=-1;
cb87691a
 			}
0c5da34b
 		}
 #endif
c3611173
 		/* main */
b727c99b
 		strncpy(pt[0].desc, "main process - attendant", MAX_PT_DESC );
0c5da34b
 #ifdef USE_TCP
c3611173
 		close_extra_socks(PROC_ATTENDANT, get_proc_no());
 		if(!tcp_disable){
 			/* main's tcp sockets are disabled by default from init_pt() */
 			unix_tcp_sock=-1;
 		}
0c5da34b
 #endif
7362f824
 		/* init cfg, but without per child callbacks support */
 		cfg_child_no_cb_init();
9d8e1c67
 		cfg_ok=1;
55a45269
 
4c57d02e
 		*_sr_instance_started = 1;
 
55a45269
 #ifdef EXTRA_DEBUG
c3611173
 		for (r=0; r<*process_count; r++){
 			fprintf(stderr, "% 3d   % 5d - %s\n", r, pt[r].pid, pt[r].desc);
 		}
55a45269
 #endif
002879f8
 		LM_DBG("Expect maximum %d  open fds\n", get_max_open_fds());
83e91df1
 		/* in daemonize mode send the exit code back to the parent process */
 		if (!dont_daemonize) {
 			if (daemon_status_send(0) < 0) {
 				ERR("error sending daemon status: %s [%d]\n",
 						strerror(errno), errno);
9167c186
 				goto error;
 			}
 		}
c3611173
 		for(;;){
6e94f57f
 			handle_sigs();
d4fb00dc
 			pause();
7362f824
 			cfg_update();
c3611173
 		}
 	
6e94f57f
 	}
b017f49c
 
51eadd0c
 	/*return 0; */
c3611173
 error:
f2e1aa50
 				 /* if we are here, we are the "main process",
dd0e65a8
 				  any forked children should exit with exit(-1) and not
 				  ever use return */
cc2199a9
 	return -1;
 
 }
726efa25
 
55a45269
 /*
  * Calculate number of processes, this does not
  * include processes created by modules
  */
 static int calc_proc_no(void)
 {
 	int udp_listeners;
 	struct socket_info* si;
edf5e385
 #ifdef USE_TCP
 	int tcp_listeners;
 	int tcp_e_listeners;
 #endif
c3611173
 #ifdef USE_SCTP
 	int sctp_listeners;
 #endif
b017f49c
 
edf5e385
 	for (si=udp_listen, udp_listeners=0; si; si=si->next)
 		udp_listeners += (si->workers>0)?si->workers:children_no;
 #ifdef USE_TCP
 	for (si=tcp_listen, tcp_listeners=0, tcp_e_listeners=0; si; si=si->next) {
 		if(si->workers>0)
 			tcp_listeners += si->workers;
 		else
 			 tcp_e_listeners = tcp_cfg_children_no;
 	}
 	tcp_listeners += tcp_e_listeners;
eea7f9d0
 #ifdef USE_TLS
 	tcp_e_listeners = 0;
9b9d1587
 	for (si=tls_listen, tcp_e_listeners=0; si; si=si->next) {
eea7f9d0
 		if(si->workers>0)
 			tcp_listeners += si->workers;
 		else {
 			if(tcp_listeners==0)
 				tcp_e_listeners = tcp_cfg_children_no;
 		}
 	}
 	tcp_listeners += tcp_e_listeners;
 #endif
edf5e385
 	tcp_children_no = tcp_listeners;
 #endif
c3611173
 #ifdef USE_SCTP
edf5e385
 	for (si=sctp_listen, sctp_listeners=0; si; si=si->next)
 		sctp_listeners += (si->workers>0)?si->workers:sctp_children_no;
c3611173
 #endif
55a45269
 	return
 		     /* receivers and attendant */
edf5e385
 		(dont_fork ? 1 : udp_listeners + 1)
55a45269
 		     /* timer process */
 		+ 1 /* always, we need it in most cases, and we can't tell here
 		       & now if we don't need it */
 #ifdef USE_SLOW_TIMER
 		+ 1 /* slow timer process */
 #endif
 #ifdef USE_TCP
edf5e385
 		+((!tcp_disable)?( 1/* tcp main */ + tcp_listeners ):0)
55a45269
 #endif
c3611173
 #ifdef USE_SCTP
edf5e385
 		+((!sctp_disable)?sctp_listeners:0)
c3611173
 #endif
55a45269
 		;
 }
57e2cd15
 
512dcd98
 int main(int argc, char** argv)
 {
 
 	FILE* cfg_stream;
9f4c52ce
 	int c,r;
1b1b19d8
 	char *tmp;
943a9d00
 	int tmp_len;
 	int port;
 	int proto;
f571aa35
 	char *options;
3db079b5
 	int ret;
7d31b911
 	unsigned int seed;
 	int rfd;
dcb59e67
 	int debug_save, debug_flag;
 	int dont_fork_cnt;
72bba9e3
 	struct name_lst* n_lst;
95dec431
 	char *p;
b151e9d6
 	struct stat st = {0};
9167c186
 
3db079b5
 	/*init*/
78a65d14
 	time(&up_since);
02f62296
 	creator_pid = getpid();
3db079b5
 	ret=-1;
049f64c2
 	my_argc=argc; my_argv=argv;
dcb59e67
 	debug_flag=0;
 	dont_fork_cnt=0;
b017f49c
 
4af91169
 	sr_cfgenv_init();
83e91df1
 	daemon_status_init();
6bda9c0b
 
 	dprint_init_colors();
 
7b3a6eca
 	/* command line options */
9834ed6e
 	options=  ":f:cm:M:dVIhEeb:l:L:n:vKrRDTN:W:w:t:u:g:P:G:SQ:O:a:A:x:X:Y:"
7b3a6eca
 #ifdef STATS
 		"s:"
 #endif
 	;
 	/* Handle special command line arguments, that must be treated before
 	 * intializing the various subsystem or before parsing other arguments:
 	 *  - get the startup debug and log_stderr values
 	 *  - look if pkg mem size is overriden on the command line (-M) and get
 	 *    the new value here (before intializing pkg_mem).
 	 *  - look if there is a -h, e.g. -f -h construction won't be caught
 	 *    later
 	 */
 	opterr = 0;
 	while((c=getopt(argc,argv,options))!=-1) {
 		switch(c) {
 			case 'd':
 					debug_flag = 1;
 					default_core_cfg.debug++;
 					break;
 			case 'E':
 					log_stderr=1;
 					break;
6bda9c0b
 			case 'e':
 					log_color=1;
 					break;
7b3a6eca
 			case 'M':
7eb1eae6
 					if (optarg == NULL) {
 						fprintf(stderr, "bad private mem size\n");
 						goto error;
 					}
7b3a6eca
 					pkg_mem_size=strtol(optarg, &tmp, 10) * 1024 * 1024;
 					if (tmp &&(*tmp)){
 						fprintf(stderr, "bad private mem size number: -M %s\n",
 											optarg);
 						goto error;
 					};
 					break;
4c2ef7f3
 			case 'x':
 					sr_memmng_shm = optarg;
 					break;
 			case 'X':
 					sr_memmng_pkg = optarg;
 					break;
7b3a6eca
 			default:
 					if (c == 'h' || (optarg && strcmp(optarg, "-h") == 0)) {
 						printf("version: %s\n", full_version);
 						printf("%s",help_msg);
 						exit(0);
 					}
 					break;
 		}
 	}
4c2ef7f3
 
 	if(sr_memmng_pkg==NULL) {
 		if(sr_memmng_shm!=NULL) {
 			sr_memmng_pkg = sr_memmng_shm;
 		} else {
 			sr_memmng_pkg = SR_MEMMNG_DEFAULT;
 		}
 	}
 	if(sr_memmng_shm==NULL) {
 		sr_memmng_shm = SR_MEMMNG_DEFAULT;
 	}
 	shm_set_mname(sr_memmng_shm);
 	if (pkg_mem_size == 0) {
 		pkg_mem_size = PKG_MEM_POOL_SIZE;
 	}
 
7b3a6eca
 	/*init pkg mallocs (before parsing cfg or the rest of the cmd line !)*/
 	if (pkg_mem_size)
a2a91d7d
 		LM_INFO("private (per process) memory: %ld bytes\n", pkg_mem_size );
4c2ef7f3
 	if (pkg_init_manager(sr_memmng_pkg)<0)
d31fcdf0
 		goto error;
 
be125734
 #ifdef DBG_MSG_QA
 	fprintf(stderr, "WARNING: ser startup: "
 		"DBG_MSG_QA enabled, ser may exit abruptly\n");
 #endif
6e94f57f
 
4208dc00
 	/* init counters / stats */
 	if (init_counters() == -1)
 		goto error;
dc93916e
 #ifdef USE_TCP
 	init_tcp_options(); /* set the defaults before the config */
 #endif
a482c5de
 
95fc59a0
 	pp_define_core();
 
f4194f69
 	/* process command line (cfg. file path etc) */
b017f49c
 	optind = 1;  /* reset getopt */
 	/* switches required before script processing */
 	while((c=getopt(argc,argv,options))!=-1) {
 		switch(c) {
4c2ef7f3
 			case 'M':
 			case 'x':
 			case 'X':
 					/* ignore, they were parsed immediately after startup */
 					break;
1b1b19d8
 			case 'f':
 					cfg_file=optarg;
 					break;
dda578ba
 			case 'c':
 					config_check=1;
 					log_stderr=1; /* force stderr logging */
 					break;
f4194f69
 			case 'L':
 					mods_dir = optarg;
e1e40d3a
 					mods_dir_cmd = 1;
f4194f69
 					break;
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;
 					};
a2a91d7d
 					LM_INFO("shared memory: %ld bytes\n", shm_mem_size );
40a8d9dd
 					break;
b017f49c
 			case 'd':
7b3a6eca
 					/* ignore it, was parsed immediately after startup */
b017f49c
 					break;
70d6cae2
 			case 'v':
b017f49c
 			case 'V':
1ef55a09
 					printf("version: %s\n", full_version);
 					printf("flags: %s\n", ver_flags );
b017f49c
 					print_ct_constants();
1ef55a09
 					printf("id: %s\n", ver_id);
e03d1279
 					if(strlen(ver_compiled_time)>0)
 						printf("compiled on %s with %s\n",
1ef55a09
 							ver_compiled_time, ver_compiler );
e03d1279
 					else
 						printf("compiled with %s\n",
 							ver_compiler );
40a8d9dd
 
b017f49c
 					exit(0);
 					break;
f5803916
 			case 'I':
 					print_internals();
 					exit(0);
 					break;
b017f49c
 			case 'E':
7b3a6eca
 					/* ignore it, was parsed immediately after startup */
b017f49c
 					break;
6bda9c0b
 			case 'e':
 					/* ignore it, was parsed immediately after startup */
 					break;
5219ecb7
 			case 'O':
 					scr_opt_lev=strtol(optarg, &tmp, 10);
 					if (tmp &&(*tmp)){
 						fprintf(stderr, "bad optimization level: -O %s\n",
 										optarg);
 						goto error;
 					};
 					break;
2c4ae148
 			case 'u':
 					/* user needed for possible shm. pre-init */
 					user=optarg;
 					break;
95dec431
 			case 'A':
 					p = strchr(optarg, '=');
 					if(p) {
 						*p = '\0';
 					}
13de789c
 					pp_define_set_type(0);
95dec431
 					if(pp_define(strlen(optarg), optarg)<0) {
 						fprintf(stderr, "error at define param: -A %s\n",
 								optarg);
 						goto error;
 					}
 					if(p) {
 						*p = '=';
 						p++;
 						if(pp_define_set(strlen(p), p)<0) {
 							fprintf(stderr, "error at define value: -A %s\n",
 								optarg);
 							goto error;
 						}
 					}
 					break;
b017f49c
 			case 'b':
 			case 'l':
 			case 'n':
70d6cae2
 			case 'K':
b017f49c
 			case 'r':
 			case 'R':
 			case 'D':
 			case 'T':
 			case 'N':
 			case 'W':
 			case 'w':
 			case 't':
 			case 'g':
 			case 'P':
f4194f69
 			case 'G':
720f74cd
 			case 'S':
5219ecb7
 			case 'Q':
b01dc20a
 			case 'a':
b017f49c
 			case 's':
9834ed6e
 			case 'Y':
b017f49c
 					break;
 			case '?':
f4194f69
 					if (isprint(optopt)) {
16d4e079
 						fprintf(stderr, "Unknown option `-%c'."
 										" Use -h for help.\n", optopt);
f4194f69
 					} else {
16d4e079
 						fprintf(stderr, "Unknown option character `\\x%x'."
 										" Use -h for help.\n",
f4194f69
 							optopt);
 					}
b017f49c
 					goto error;
 			case ':':
16d4e079
 					fprintf(stderr, "Option `-%c' requires an argument."
 									" Use -h for help.\n",
f4194f69
 						optopt);
b017f49c
 					goto error;
 			default:
 					abort();
 		}
 	}
4c2ef7f3
 	if (shm_mem_size == 0) {
 		shm_mem_size = SHM_MEM_POOL_SIZE;
 	}
021e7e0e
 
22db42e4
 	if (endianness_sanity_check() != 0){
 		fprintf(stderr, "BUG: endianness sanity tests failed\n");
 		goto error;
 	}
93349b4e
 	if (init_routes()<0) goto error;
ac34f9f4
 	if (init_nonsip_hooks()<0) goto error;
0a99f1b3
 	if (init_script_cb()<0) goto error;
7e7d9399
 	if (pv_init_api()<0) goto error;
8c3a7158
 	if (pv_register_core_vars()!=0) goto error;
5099fd64
 	if (init_rpcs()<0) goto error;
 	if (register_core_rpcs()!=0) goto error;
b2471cfc
 
 	/* Fix the value of cfg_file variable.*/
 	if (fix_cfg_file() < 0) goto error;
b017f49c
 
 	/* load config file or die */
6f96f4fb
 	if (cfg_file[0] == '-' && strlen(cfg_file)==1) {
 		cfg_stream=stdin;
 	} else {
 		cfg_stream=fopen (cfg_file, "r");
 	}
b017f49c
 	if (cfg_stream==0){
 		fprintf(stderr, "ERROR: loading config file(%s): %s\n", cfg_file,
 				strerror(errno));
 		goto error;
 	}
 
 	/* seed the prng */
 	/* try to use /dev/urandom if possible */
 	seed=0;
 	if ((rfd=open("/dev/urandom", O_RDONLY))!=-1){
 try_again:
 		if (read(rfd, (void*)&seed, sizeof(seed))==-1){
 			if (errno==EINTR) goto try_again; /* interrupted by signal */
a2a91d7d
 			LM_WARN("could not read from /dev/urandom (%d)\n", errno);
b017f49c
 		}
002879f8
 		LM_DBG("read %u from /dev/urandom\n", seed);
b017f49c
 			close(rfd);
 	}else{
a2a91d7d
 		LM_WARN("could not open /dev/urandom (%d)\n", errno);
b017f49c
 	}
 	seed+=getpid()+time(0);
002879f8
 	LM_DBG("seeding PRNG with %u\n", seed);
db11faca
 	kam_srand(seed);
 	fastrand_seed(kam_rand());
 	srandom(kam_rand()+time(0));
 	LM_DBG("test random numbers %u %lu %u\n", kam_rand(), random(), fastrand());
b017f49c
 
 	/*register builtin  modules*/
 	register_builtin_modules();
 
65938e0e
 	/* init named flags */
 	init_named_flags();
 
b017f49c
 	yyin=cfg_stream;
7ac069af
 	debug_save = default_core_cfg.debug;
b017f49c
 	if ((yyparse()!=0)||(cfg_errors)){
 		fprintf(stderr, "ERROR: bad config file (%d errors)\n", cfg_errors);
713a0a1f
 		if (debug_flag) default_core_cfg.debug = debug_save;
 		pp_ifdef_level_check();
9167c186
 
b017f49c
 		goto error;
 	}
dcb59e67
 	if (cfg_warnings){
 		fprintf(stderr, "%d config warnings\n", cfg_warnings);
 	}
7ac069af
 	if (debug_flag) default_core_cfg.debug = debug_save;
713a0a1f
 	pp_ifdef_level_check();
93349b4e
 	print_rls();
b017f49c
 
e008edb9
 	if(init_dst_set()<0) {
 		LM_ERR("failed to initialize destination set structure\n");
 		goto error;
 	}
b017f49c
 	/* options with higher priority than cfg file */
 	optind = 1;  /* reset getopt */
 	while((c=getopt(argc,argv,options))!=-1) {
 		switch(c) {
 			case 'f':
 			case 'c':
 			case 'm':
7b3a6eca
 			case 'M':
b017f49c
 			case 'd':
70d6cae2
 			case 'v':
b017f49c
 			case 'V':
f5803916
 			case 'I':
b017f49c
 			case 'h':
5219ecb7
 			case 'O':
95dec431
 			case 'A':
b017f49c
 					break;
 			case 'E':
7b3a6eca
 					log_stderr=1;	/* use in both getopt switches,
 									   takes priority over config */
b017f49c
 					break;
6bda9c0b
 			case 'e':
 					log_color=1;	/* use in both getopt switches,
 									   takes priority over config */
 					break;
c3ce2841
 			case 'b':
 					maxbuffer=strtol(optarg, &tmp, 10);
 					if (tmp &&(*tmp)){
f4194f69
 						fprintf(stderr, "bad max buffer size number: -b %s\n",
36ef0329
 											optarg);
 						goto error;
 					}
 					break;
1b1b19d8
 			case 'l':
df088fb8
 					if ((n_lst=parse_phostport_mh(optarg, &tmp, &tmp_len,
72bba9e3
 											&port, &proto))==0){
943a9d00
 						fprintf(stderr, "bad -l address specifier: %s\n",
 										optarg);
 						goto error;
 					}
e7671eb9
 					/* add a new addr. to our address list */
72bba9e3
 					if (add_listen_iface(n_lst->name, n_lst->next,  port,
 											proto, n_lst->flags)!=0){
9f4c52ce
 						fprintf(stderr, "failed to add new listen address\n");
72bba9e3
 						free_name_lst(n_lst);
1b1b19d8
 						goto error;
 					}
72bba9e3
 					free_name_lst(n_lst);
1b1b19d8
 					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;
70d6cae2
 			case 'K':
1b1b19d8
 					check_via=1;
 					break;
 			case 'r':
 					received_dns|=DO_DNS;
 					break;
 			case 'R':
 					received_dns|=DO_REV_DNS;
 					break;
 			case 'D':
bc404f2b
 					dont_fork_cnt++;
1b1b19d8
 					break;
5dcfb23d
 			case 'T':
b017f49c
 				#ifdef USE_TCP
5dcfb23d
 					tcp_disable=1;
b017f49c
 				#else
5dcfb23d
 					fprintf(stderr,"WARNING: tcp support not compiled in\n");
b017f49c
 				#endif
5dcfb23d
 					break;
 			case 'N':
b017f49c
 				#ifdef USE_TCP
edf5e385
 					tcp_cfg_children_no=strtol(optarg, &tmp, 10);
5dcfb23d
 					if ((tmp==0) ||(*tmp)){
 						fprintf(stderr, "bad process number: -N %s\n",
 									optarg);
 						goto error;
 					}
b017f49c
 				#else
5dcfb23d
 					fprintf(stderr,"WARNING: tcp support not compiled in\n");
b017f49c
 				#endif
5dcfb23d
 					break;
0ba367ec
 			case 'W':
b017f49c
 				#ifdef USE_TCP
0ba367ec
 					tcp_poll_method=get_poll_type(optarg);
 					if (tcp_poll_method==POLL_NONE){
 						fprintf(stderr, "bad poll method name: -W %s\ntry "
 										"one of %s.\n", optarg, poll_support);
 						goto error;
 					}
b017f49c
 				#else
0ba367ec
 					fprintf(stderr,"WARNING: tcp support not compiled in\n");
b017f49c
 				#endif
1b1b19d8
 					break;
c3611173
 			case 'S':
 				#ifdef USE_SCTP
 					sctp_disable=1;
 				#else
 					fprintf(stderr,"WARNING: sctp support not compiled in\n");
 				#endif
 					break;
5219ecb7
 			case 'Q':
c3611173
 				#ifdef USE_SCTP
 					sctp_children_no=strtol(optarg, &tmp, 10);
 					if ((tmp==0) ||(*tmp)){
 						fprintf(stderr, "bad process number: -O %s\n",
 									optarg);
 						goto error;
 					}
 				#else
 					fprintf(stderr,"WARNING: sctp support not compiled in\n");
 				#endif
 					break;
c9ca45b3
 			case 'w':
 					working_dir=optarg;
 					break;
9834ed6e
 			case 'Y':
 					runtime_dir=optarg;
 					break;
c9ca45b3
 			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;
f4194f69
 			case 'G':
 					pgid_file=optarg;
 					break;
b01dc20a
 			case 'a':
 					if(strcmp(optarg, "on")==0 || strcmp(optarg, "yes")==0)
 						sr_auto_aliases = 1;
 					else if(strcmp(optarg, "off")==0 || strcmp(optarg, "no")==0)
 						sr_auto_aliases = 0;
 					else {
 						fprintf(stderr,
 							"bad auto aliases parameter: %s (valid on, off, yes, no)\n",
 							optarg);
 						goto error;
 					}
 					break;
b017f49c
 			case 's':
 				#ifdef STATS
 					stat_file=optarg;
 				#endif
 					break;
1b1b19d8
 			default:
b017f49c
 					break;
7d31b911
 		}
 	}
404073d3
 
8d666c30
 	/* reinit if pv buffer size has been set in config */
 	if (pv_reinit_buffer()<0)
 		goto error;
 
af3f94dd
 	if (ksr_route_locks_set_init()<0)
 		goto error;
 
2d826efb
 	/* init lookup for core event routes */
 	sr_core_ert_init();
 
bc404f2b
 	if (dont_fork_cnt)
 		dont_fork = dont_fork_cnt;	/* override by command line */
 
 	if (dont_fork > 0) {
 		dont_daemonize = dont_fork == 2;
 		dont_fork = dont_fork == 1;
 	}
8b8fc486
 	/* init locks first */
 	if (init_lock_ops()!=0)
 		goto error;
c3611173
 #ifdef USE_TCP
 #ifdef USE_TLS
 	if (tcp_disable)
 		tls_disable=1; /* if no tcp => no tls */
 #endif /* USE_TLS */
 #endif /* USE_TCP */
23ca6c06
 #ifdef USE_SCTP
 	if (sctp_disable!=1){
 		/* fix it */
7f8e7a85
 		if (sctp_core_check_support()==-1){
23ca6c06
 			/* check if sctp support is auto, if not warn about disabling it */
 			if (sctp_disable!=2){
 				fprintf(stderr, "ERROR: " "sctp enabled, but not supported by"
 								" the OS\n");
 				goto error;
 			}
 			sctp_disable=1;
 		}else{
 			/* sctp_disable!=1 and sctp supported => enable sctp */
 			sctp_disable=0;
 		}
 	}
 #endif /* USE_SCTP */
c3611173
 	/* initialize the configured proto list */
 	init_proto_order();
878fc194
 	/* init the resolver, before fixing the config */
 	resolv_init();
7268726e
 	/* fix parameters */
cc2199a9
 	if (port_no<=0) port_no=SIP_PORT;
f22b996b
 #ifdef USE_TLS
 	if (tls_port_no<=0) tls_port_no=SIPS_PORT;
 #endif
b017f49c
 
 
cc2199a9
 	if (children_no<=0) children_no=CHILD_NO;
5b532c7f
 #ifdef USE_TCP
5dcfb23d
 	if (!tcp_disable){
edf5e385
 		if (tcp_cfg_children_no<=0) tcp_cfg_children_no=children_no;
 		tcp_children_no = tcp_cfg_children_no;
4bd1673d
 	}
caf80ae6
 #endif
c3611173
 #ifdef USE_SCTP
 	if (!sctp_disable){
 		if (sctp_children_no<=0) sctp_children_no=children_no;
 	}
 #endif
b017f49c
 
c9ca45b3
 	if (working_dir==0) working_dir="/";
b017f49c
 
054cb6cf
 	/* get uid/gid */
 	if (user){
71fd3ebd
 		if (user2uid(&uid, &gid, user)<0){
 			fprintf(stderr, "bad user name/uid number: -u %s\n", user);
 			goto error;
054cb6cf
 		}
d7a10e6a
 		sock_uid = uid;
 		sock_gid = gid;
054cb6cf
 	}
 	if (group){
71fd3ebd
 		if (group2gid(&gid, group)<0){
054cb6cf
 				fprintf(stderr, "bad group name/gid number: -u %s\n", group);
71fd3ebd
 			goto error;
 		}
d7a10e6a
 		sock_gid = gid;
71fd3ebd
 	}
b151e9d6
 	/* create runtime dir if doesn't exist */
 	if (stat(runtime_dir, &st) == -1) {
 		if(mkdir(runtime_dir, 0700) == -1) {
5e9f144c
 			LM_ERR("failed to create runtime dir %s\n", runtime_dir);
 			fprintf(stderr,  "failed to create runtime dir %s\n", runtime_dir);
b151e9d6
 			goto error;
 		}
 		if(sock_uid!=-1 || sock_gid!=-1) {
 			if(chown(runtime_dir, sock_uid, sock_gid) == -1) {
5e9f144c
 				LM_ERR("failed to change owner of runtime dir %s\n", runtime_dir);
 				fprintf(stderr,  "failed to change owner of runtime dir %s\n", runtime_dir);
b151e9d6
 				goto error;
 			}
 		}
 	}
2cfcc6bb
 	if (fix_all_socket_lists()!=0){
53c7e0f1
 		fprintf(stderr,  "failed to initialize list addresses\n");
9f4c52ce
 		goto error;
e60a9728
 	}
2cfcc6bb
 	if (default_core_cfg.dns_try_ipv6 && !(socket_types & SOCKET_T_IPV6)){
dcb59e67
 		/* if we are not listening on any ipv6 address => no point
 		 * to try to resovle ipv6 addresses */
2cfcc6bb
 		default_core_cfg.dns_try_ipv6=0;
dcb59e67
 	}
57e2cd15
 	/* print all the listen addresses */
 	printf("Listening on \n");
9f4c52ce
 	print_all_socket_lists();
 	printf("Aliases: \n");
 	/*print_aliases();*/
 	print_aliases();
e278821b
 	printf("\n");
b017f49c
 
0df81fe8
 	if (dont_fork){
b017f49c
 		fprintf(stderr, "WARNING: no fork mode %s\n",
49de5d20
 				(udp_listen)?(
b017f49c
 				(udp_listen->next)?"and more than one listen address found "
64146b14
 				"(will use only the first one)":""
49de5d20
 				):"and no udp listen address found" );
0df81fe8
 	}
dda578ba
 	if (config_check){
 		fprintf(stderr, "config file ok, exiting...\n");
51e93de7
 		return 0;
dda578ba
 	}
dd0e65a8
 
 
 	/*init shm mallocs
b017f49c
 	 *  this must be here
dd0e65a8
 	 *     -to allow setting shm mem size from the command line
 	 *       => if shm_mem should be settable from the cfg file move
 	 *       everything after
 	 *     -it must be also before init_timer and init_tcp
 	 *     -it must be after we know uid (so that in the SYSV sems case,
 	 *        the sems will have the correct euid)
2c4ae148
 	 *  Note: shm can now be initialized when parsing the config script, that's
 	 *  why checking for a prior initialization is needed.
dd0e65a8
 	 * --andrei */
2c4ae148
 	if (!shm_initialized() && init_shm()<0)
dd0e65a8
 		goto error;
4c2ef7f3
 	pkg_print_manager();
 	shm_print_manager();
d307929c
 	if (init_atomic_ops()==-1)
 		goto error;
22db42e4
 	if (init_basex() != 0){
a2a91d7d
 		LM_CRIT("could not initialize base* framework\n");
22db42e4
 		goto error;
 	}
50ca02e5
 	if (sr_cfg_init() < 0) {
a2a91d7d
 		LM_CRIT("could not initialize configuration framework\n");
22db42e4
 		goto error;
 	}
 	/* declare the core cfg before the module configs */
 	if (cfg_declare("core", core_cfg_def, &default_core_cfg, cfg_sizeof(core),
 			&core_cfg)
 	) {
a2a91d7d
 		LM_CRIT("could not declare the core configuration\n");
22db42e4
 		goto error;
 	}
 #ifdef USE_TCP
 	if (tcp_register_cfg()){
a2a91d7d
 		LM_CRIT("could not register the tcp configuration\n");
22db42e4
 		goto error;
 	}
 #endif /* USE_TCP */
dd0e65a8
 	/*init timer, before parsing the cfg!*/
 	if (init_timer()<0){
a2a91d7d
 		LM_CRIT("could not initialize timer, exiting...\n");
dd0e65a8
 		goto error;
 	}
a482c5de
 	/* init wtimer */
 	if(sr_wtimer_init()<0) {
 		LM_CRIT("could not initialize wtimer, exiting...\n");
 		goto error;
 	}
 
dcb59e67
 #ifdef USE_DNS_CACHE
7905e2d6
 	if (init_dns_cache()<0){
a2a91d7d
 		LM_CRIT("could not initialize the dns cache, exiting...\n");
dcb59e67
 		goto error;
 	}
021e7e0e
 #ifdef USE_DNS_CACHE_STATS
 	/* preinitializing before the nubmer of processes is determined */
 	if (init_dns_cache_stats(1)<0){
a2a91d7d
 		LM_CRIT("could not initialize the dns cache measurement\n");
021e7e0e
 		goto error;
 	}
 #endif /* USE_DNS_CACHE_STATS */
dcb59e67
 #endif
 #ifdef USE_DST_BLACKLIST
 	if (init_dst_blacklist()<0){
a2a91d7d
 		LM_CRIT("could not initialize the dst blacklist, exiting...\n");
dcb59e67
 		goto error;
 	}
021e7e0e
 #ifdef USE_DST_BLACKLIST_STATS
4208dc00
 	/* preinitializing before the number of processes is determined */
021e7e0e
 	if (init_dst_blacklist_stats(1)<0){
a2a91d7d
 		LM_CRIT("could not initialize the dst blacklist measurement\n");
021e7e0e
 		goto error;
 	}
 #endif /* USE_DST_BLACKLIST_STATS */
dcb59e67
 #endif
74ce7043
 	if (init_avps()<0) goto error;
539283cd
 	if (rpc_init_time() < 0) goto error;
74ce7043
 
5dcfb23d
 #ifdef USE_TCP
 	if (!tcp_disable){
 		/*init tcp*/
 		if (init_tcp()<0){
a2a91d7d
 			LM_CRIT("could not initialize tcp, exiting...\n");
5dcfb23d
 			goto error;
 		}
 	}
f22b996b
 #endif /* USE_TCP */
31fd952b
 #ifdef USE_SCTP
 	if (!sctp_disable){
7f8e7a85
 		if (sctp_core_init()<0){
a2a91d7d
 			LM_CRIT("Could not initialize sctp, exiting...\n");
31fd952b
 			goto error;
 		}
 	}
 #endif /* USE_SCTP */
ed2b50d3
 	/* init_daemon? */
83e91df1
 	if( !dont_fork && daemonize((log_name==0)?argv[0]:log_name, 1) < 0)
 		goto error;
428e3b83
 	if (install_sigs() != 0){
 		fprintf(stderr, "ERROR: could not install the signal handlers\n");
 		goto error;
 	}
385c63eb
 
 	if (disable_core_dump) set_core_dump(0, 0);
7b3a6eca
 	else set_core_dump(1, shm_mem_size+pkg_mem_size+4*1024*1024);
385c63eb
 	if (open_files_limit>0){
b017f49c
 		if(increase_open_fds(open_files_limit)<0){
385c63eb
 			fprintf(stderr, "ERROR: error could not increase file limits\n");
 			goto error;
 		}
 	}
8390f722
 	if (mlock_pages)
 		mem_lock_pages();
021e7e0e
 
8390f722
 	if (real_time&4)
 			set_rt_prio(rt_prio, rt_policy);
021e7e0e
 
4700831f
 #ifdef USE_TCP
 #ifdef USE_TLS
 	if (!tls_disable){
 		if (!tls_loaded()){
 			LM_WARN("tls support enabled, but no tls engine "
 						" available (forgot to load the tls module?)\n");
 			LM_WARN("disabling tls...\n");
 			tls_disable=1;
 		} else {
 			if (pre_init_tls()<0){
 				LM_CRIT("could not pre-initialize tls, exiting...\n");
 				goto error;
 			}
 		}
 	}
 #endif /* USE_TLS */
 #endif /* USE_TCP */
9188021a
 	
385c63eb
 	if (init_modules() != 0) {
 		fprintf(stderr, "ERROR: error while initializing modules\n");
 		goto error;
 	}
9188021a
 	
021e7e0e
 	/* initialize process_table, add core process no. (calc_proc_no()) to the
37209e14
 	 * processes registered from the modules*/
 	if (init_pt(calc_proc_no())==-1)
55a45269
 		goto error;
8628de22
 #ifdef USE_TCP
 #ifdef USE_TLS
 	if (!tls_disable){
6c53d41a
 		if (!tls_loaded()){
a2a91d7d
 			LM_WARN("tls support enabled, but no tls engine "
6c53d41a
 						" available (forgot to load the tls module?)\n");
a2a91d7d
 			LM_WARN("disabling tls...\n");
6c53d41a
 			tls_disable=1;
 		}
8628de22
 		/* init tls*/
 		if (init_tls()<0){
a2a91d7d
 			LM_CRIT("could not initialize tls, exiting...\n");
8628de22
 			goto error;
 		}
 	}
 #endif /* USE_TLS */
 #endif /* USE_TCP */
021e7e0e
 
37209e14
 	/* The total number of processes is now known, note that no
 	 * function being called before this point may rely on the
 	 * number of processes !
 	 */
f057e844
 	LM_INFO("processes (at least): %d - shm size: %lu - pkg size: %lu\n",
 			get_max_procs(), shm_mem_size, pkg_mem_size);
55a45269
 
021e7e0e
 #if defined USE_DNS_CACHE && defined USE_DNS_CACHE_STATS
 	if (init_dns_cache_stats(get_max_procs())<0){
a2a91d7d
 		LM_CRIT("could not initialize the dns cache measurement\n");
021e7e0e
 		goto error;
 	}
 #endif
 #if defined USE_DST_BLACKLIST && defined USE_DST_BLACKLIST_STATS
 	if (init_dst_blacklist_stats(get_max_procs())<0){
a2a91d7d
 		LM_CRIT("could not initialize the dst blacklist measurement\n");
021e7e0e
 		goto error;
 	}
 #endif
 
6bb03a39
 	/* fix routing lists */
 	if ( (r=fix_rls())!=0){
54774017
 		fprintf(stderr, "error %d while trying to fix configuration\n", r);
6bb03a39
 		goto error;
 	};
b0123c36
 	fixup_complete=1;
22d4aa5d
 
2f781952
 #ifdef STATS
 	if (init_stats(  dont_fork ? 1 : children_no  )==-1) goto error;
 #endif
b017f49c
 
3db079b5
 	ret=main_loop();
83e91df1
 	if (ret < 0)
 		goto error;
3db079b5
 	/*kill everything*/
d4fb00dc
 	if (is_main) shutdown_children(SIGTERM, 0);
83e91df1
 	if (!dont_daemonize) {
 		if (daemon_status_send(0) < 0)
54774017
 			fprintf(stderr, "error sending exit status: %s [%d]\n",
83e91df1
 					strerror(errno), errno);
 	}
d4fb00dc
 	/* else terminate process */
3db079b5
 	return ret;
512dcd98
 
 error:
3db079b5
 	/*kill everything*/
d4fb00dc
 	if (is_main) shutdown_children(SIGTERM, 0);
83e91df1
 	if (!dont_daemonize) {
 		if (daemon_status_send((char)-1) < 0)
54774017
 			fprintf(stderr, "error sending exit status: %s [%d]\n",
83e91df1
 					strerror(errno), errno);
 	}
512dcd98
 	return -1;
 }