512dcd98 |
/*
* $Id$
|
7dd0b342 |
*
|
53c7e0f1 |
* Copyright (C) 2001-2003 FhG Fokus
|
7dd0b342 |
*
* 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.
*
|
b017f49c |
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
|
7dd0b342 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
2d4b798e |
*
* History:
* -------
|
7ec958f3 |
* 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)
* 2003-03-29 pkg cleaners for fifo and script callbacks introduced (jiri)
* 2003-03-31 removed snmp part (obsolete & no place in core) (andrei)
|
cb87691a |
* 2003-04-06 child_init called in all processes (janakj)
|
b017f49c |
* 2003-04-08 init_mallocs split into init_{pkg,shm}_mallocs and
|
90907c3f |
* init_shm_mallocs called after cmd. line parsing (andrei)
|
5dcfb23d |
* 2003-04-15 added tcp_disable support (andrei)
|
b017f49c |
* 2003-05-09 closelog() before openlog to force opening a new fd
|
02dae965 |
* (needed on solaris) (andrei)
|
428e3b83 |
* 2003-06-11 moved all signal handlers init. in install_sigs and moved it
* after daemonize (so that we won't catch anymore our own
* SIGCHLD generated when becoming session leader) (andrei)
* changed is_main default value to 1 (andrei)
|
b484b774 |
* 2003-06-28 kill_all_children is now used instead of kill(0, sig)
* see comment above it for explanations. (andrei)
* 2003-06-29 replaced port_no_str snprintf w/ int2str (andrei)
|
dda578ba |
* 2003-10-10 added switch for config check (-c) (andrei)
|
9f4c52ce |
* 2003-10-24 converted to the new socket_info lists (andrei)
|
385c63eb |
* 2004-03-30 core dump is enabled by default
* added support for increasing the open files limit (andrei)
|
71fd3ebd |
* 2004-04-28 sock_{user,group,uid,gid,mode} added
* user2uid() & user2gid() added (andrei)
|
7fb8a246 |
* 2004-09-11 added timeout on children shutdown and final cleanup
* (if it takes more than 60s => something is definitely wrong
* => kill all or abort) (andrei)
* force a shm_unlock before cleaning-up, in case we have a
* crashed childvwhich still holds the lock (andrei)
|
943a9d00 |
* 2004-12-02 removed -p, extended -l to support [proto:]address[:port],
* added parse_phostport, parse_proto (andrei)
|
0ba367ec |
* 2005-06-16 always record the pid in pt[process_no].pid twice: once in the
* parent & once in the child to avoid a short window when one
* of them might use it "unset" (andrei)
|
02dae965 |
* 2005-07-25 use sigaction for setting the signal handlers (andrei)
|
dcb59e67 |
* 2006-07-13 added dns cache/failover init. (andrei)
|
96227c65 |
* 2006-10-13 added global variables stun_refresh_interval, stun_allow_stun
|
96d09107 |
* and stun_allow_fp (vlada)
|
f2e1aa50 |
* 2006-10-25 don't log messages from signal handlers if NO_SIG_DEBUG is
|
96d09107 |
* defined; improved exit kill timeout (andrei)
|
f2e1aa50 |
* init_childs(PROC_MAIN) before starting tcp_main, to allow
* tcp usage for module started processes (andrei)
|
d4fb00dc |
* 2007-01-18 children shutdown procedure moved into shutdown_children;
|
6c53d41a |
* safer shutdown on start-up error (andrei)
|
021e7e0e |
* 2007-02-09 TLS support split into tls-in-core (CORE_TLS) and generic TLS
|
6c53d41a |
* (USE_TLS) (andrei)
|
8390f722 |
* 2007-06-07 added support for locking pages in mem. and using real time
* scheduling policies (andrei)
|
021e7e0e |
* 2007-07-30 dst blacklist and DNS cache measurements added (Gergo)
|
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>
|
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
|
e60a9728 |
#include "config.h"
|
512dcd98 |
#include "dprint.h"
|
c03cc017 |
#include "daemonize.h"
|
512dcd98 |
#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"
|
e278821b |
#include "name_alias.h"
|
9df1213c |
#include "hash_func.h"
|
f51155cf |
#include "pt.h"
|
3c8bd369 |
#include "script_cb.h"
|
ac34f9f4 |
#include "nonsip_hooks.h"
|
f22b996b |
#include "ut.h"
|
af93cbdf |
#include "signals.h"
|
f2f969dd |
#ifdef USE_TCP
|
0ba367ec |
#include "poll_types.h"
|
f2f969dd |
#include "tcp_init.h"
|
6c53d41a |
#ifdef CORE_TLS
|
e8f8146e |
#include "tls/tls_init.h"
|
6c53d41a |
#define tls_has_init_si() 1
#define tls_loaded() 1
#else
#include "tls_hooks_init.h"
#endif /* CORE_TLS */
#endif /* USE_TCP */
|
74ce7043 |
#include "usr_avp.h"
|
539283cd |
#include "core_cmd.h"
|
65938e0e |
#include "flags.h"
|
8b8fc486 |
#include "lock_ops_init.h"
|
d307929c |
#include "atomic_ops_init.h"
|
dcb59e67 |
#ifdef USE_DNS_CACHE
#include "dns_cache.h"
#endif
#ifdef USE_DST_BLACKLIST
#include "dst_blacklist.h"
#endif
|
2c07f591 |
#include "rand/fastrand.h" /* seed */
|
0a974a1d |
|
5b253cc6 |
#include "stats.h"
|
726efa25 |
|
03150098 |
#ifdef DEBUG_DMALLOC
#include <dmalloc.h>
#endif
|
dd0e65a8 |
#include "version.h"
|
03150098 |
|
96d09107 |
/* define SIG_DEBUG by default */
#ifdef NO_SIG_DEBUG
#undef SIG_DEBUG
#else
#define SIG_DEBUG
#endif
|
1b1b19d8 |
static char id[]="@(#) $Id$";
|
dd0e65a8 |
static char* version=SER_FULL_VERSION;
static char* flags=SER_COMPILE_FLAGS;
char compiled[]= __TIME__ " " __DATE__ ;
|
726efa25 |
|
1b1b19d8 |
static char help_msg[]= "\
|
f4194f69 |
Usage: " NAME " [options]\n\
|
1b1b19d8 |
Options:\n\
|
f4194f69 |
-f file Configuration file (default: " CFG_FILE ")\n\
-L dir Modules directory (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\
[proto:]addr[:port], where proto=udp|tcp and \n\
addr= host|ip_address|interface_name. E.g: -l locahost, \n\
-l udp:127.0.0.1:5080, -l eth0:5062 The default behavior\n\
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\
|
1b1b19d8 |
-v Turn on \"via:\" host checking when forwarding replies\n\
-d Debugging mode (multiple -d increase the level)\n\
|
16d4e079 |
-D no 1..do not fork (almost) anyway, 2..do not daemonize creator\n\
3..daemonize (default)\n\
|
5dcfb23d |
-E Log to stderr\n"
#ifdef USE_TCP
" -T Disable tcp\n\
|
f4194f69 |
-N Number of tcp child processes (default: equal to `-n')\n\
|
0ba367ec |
-W poll method\n"
|
5dcfb23d |
#endif
" -V Version number\n\
|
1b1b19d8 |
-h This help message\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\
|
f4194f69 |
-w dir Change the working directory to \"dir\" (default: \"/\")\n\
|
0762e9d5 |
-t dir Chroot to \"dir\"\n\
|
5dcfb23d |
-u uid Change uid \n\
-g gid Change gid \n\
-P file Create a pid file\n\
|
539283cd |
-G file Create a pgid file\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",
|
b017f49c |
MAX_RECV_BUFFER_SIZE, MAX_LISTEN, MAX_URI_SIZE,
|
1f377e97 |
BUF_SIZE );
|
0ba367ec |
#ifdef USE_TCP
printf("poll method support: %s.\n", poll_support);
#endif
|
af6fb476 |
}
|
512dcd98 |
|
53c7e0f1 |
/* debugging 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 */
|
b484b774 |
int own_pgid = 0; /* whether or not we have our own pgid (and it's ok
to use kill(0, sig) */
|
f4194f69 |
char* mods_dir = MODS_DIR; /* directory with dyn. loadable modules */
|
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 */
int children_no = 0; /* number of children processing requests */
|
5b532c7f |
#ifdef USE_TCP
int tcp_children_no = 0;
|
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 */
|
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 */
|
6e94f57f |
int sig_flag = 0; /* last signal received */
|
58d0d1b5 |
int debug = L_DEFAULT; /* print only msg. < L_WARN */
|
1b1b19d8 |
int dont_fork = 0;
|
bc404f2b |
int dont_daemonize = 0;
|
1b1b19d8 |
int log_stderr = 0;
|
02f62296 |
pid_t creator_pid = (pid_t) -1;
|
26456ace |
/* log facility (see syslog(3)) */
int log_facility = LOG_DAEMON;
|
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;
|
caf80ae6 |
/* shall use stateful synonym branches? faster but not reboot-safe */
|
855c2e68 |
int syn_branch = 1;
|
609ada42 |
/* debugging level for memory stats */
|
2dbd0868 |
int memlog = L_DBG;
|
58d0d1b5 |
/* debugging level for the malloc debug messages */
int memdbg = L_DBG;
|
af93cbdf |
/* debugging level for timer debugging */
int timerlog = L_WARN;
|
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;
|
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;
|
c9ca45b3 |
char* working_dir = 0;
char* chroot_dir = 0;
|
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---- */
|
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) */
|
2ba73117 |
#endif /* USE_MCAST */
|
dcb59e67 |
#ifdef USE_DNS_CACHE
int use_dns_cache=1; /* 1 if the cache is enabled, 0 otherwise */
int use_dns_failover=0; /* 1 if failover is enabled, 0 otherwise */
#endif
#ifdef USE_DST_BLACKLIST
int use_dst_blacklist=0; /* 1 if the blacklist is enabled */
#endif
|
2ba73117 |
|
fe09f315 |
int tos = IPTOS_LOWDELAY;
|
f3a26797 |
int pmtu_discovery = 0;
|
fe09f315 |
|
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
|
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
|
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 */
|
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
|
36ef0329 |
unsigned short port_no=0; /* default port*/
|
f22b996b |
#ifdef USE_TLS
unsigned short tls_port_no=0; /* default port */
#endif
|
1b1b19d8 |
|
96227c65 |
#ifdef USE_STUN
/* refresh interval in miliseconds */
unsigned int stun_refresh_interval=0;
/* stun can be switch off even if it is compiled */
int stun_allow_stun=1;
/* use or don't use fingerprint */
int stun_allow_fp=1;
#endif
|
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;
|
a76545c8 |
/* process_bm_t process_bit = 0; */
|
cc2199a9 |
#ifdef ROUTE_SRV
#endif
|
888ca09d |
|
63fa628f |
/* cfg parsing */
int cfg_errors=0;
|
dcb59e67 |
int cfg_warnings=0;
|
888ca09d |
|
40a8d9dd |
/* shared memory (in MB) */
|
c082177a |
unsigned long shm_mem_size=SHM_MEM_SIZE * 1024 * 1024;
|
40a8d9dd |
|
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();
|
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 |
|
53c7e0f1 |
/* call it before exiting; if show_status==1, mem status is displayed */
|
8aeb47e2 |
void cleanup(show_status)
{
/*clean-up*/
|
fbe11914 |
#ifndef SHM_SAFE_MALLOC
|
b017f49c |
if (mem_lock)
|
dd0e65a8 |
shm_unlock(); /* hack: force-unlock the shared memory lock in case
|
b017f49c |
some process crashed and let it locked; this will
|
7fb8a246 |
allow an almost gracious shutdown */
|
fbe11914 |
#endif
|
8aeb47e2 |
destroy_modules();
|
dcb59e67 |
#ifdef USE_DNS_CACHE
destroy_dns_cache();
#endif
#ifdef USE_DST_BLACKLIST
destroy_dst_blacklist();
#endif
|
8aeb47e2 |
#ifdef USE_TCP
destroy_tcp();
|
f22b996b |
#endif
#ifdef USE_TLS
destroy_tls();
|
8aeb47e2 |
#endif
destroy_timer();
|
3c8bd369 |
destroy_script_cb();
|
ac34f9f4 |
destroy_nonsip_hooks();
|
93349b4e |
destroy_routes();
|
d307929c |
destroy_atomic_ops();
|
8aeb47e2 |
#ifdef PKG_MALLOC
if (show_status){
LOG(memlog, "Memory status (pkg):\n");
pkg_status();
}
#endif
#ifdef SHM_MEM
|
b137a4b8 |
if (pt) shm_free(pt);
|
8aeb47e2 |
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
|
8b8fc486 |
destroy_lock_ops();
|
8aeb47e2 |
if (pid_file) unlink(pid_file);
|
9a428799 |
if (pgid_file) unlink(pgid_file);
|
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);
}
else LOG(L_CRIT, "BUG: killing: %s > %d no pid!!!\n",
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 :-) */
LOG(L_CRIT, "BUG: shutdown timeout triggered, dying...");
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 ) {
LOG(L_ERR, "ERROR: shutdown: could not install SIGALARM handler\n");
/* 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);
}
|
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");
else
DBG("SIGTERM received, program terminates\n");
|
d4fb00dc |
/* shutdown/kill all the children */
shutdown_children(SIGTERM, 1);
|
6e94f57f |
dprint("Thank you for flying " NAME "\n");
exit(0);
break;
|
b017f49c |
|
6e94f57f |
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;
|
b017f49c |
|
6e94f57f |
case SIGCHLD:
while ((chld=waitpid( -1, &chld_status, WNOHANG ))>0) {
|
b017f49c |
if (WIFEXITED(chld_status))
|
6e94f57f |
LOG(L_INFO, "child process %d exited normally,"
|
b017f49c |
" status=%d\n", chld,
|
6e94f57f |
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
|
b017f49c |
}else if (WIFSTOPPED(chld_status))
|
6e94f57f |
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;
|
b017f49c |
}
|
49041f7b |
LOG(L_INFO, "INFO: terminating due to SIGCHLD\n");
#endif
|
6e94f57f |
/* exit */
|
d4fb00dc |
shutdown_children(SIGTERM, 1);
|
6e94f57f |
DBG("terminating due to SIGCHLD\n");
exit(0);
break;
|
b017f49c |
|
6e94f57f |
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;
}
|
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 |
{
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 */
|
428e3b83 |
LOG(L_INFO, "INFO: signal %d received\n", signo);
|
96d09107 |
#endif
|
428e3b83 |
break;
case SIGINT:
case SIGTERM:
|
96d09107 |
#ifdef SIG_DEBUG /* signal unsafe stuff follows */
|
428e3b83 |
LOG(L_INFO, "INFO: signal %d received\n", signo);
/* print memory stats for non-main too */
#ifdef PKG_MALLOC
LOG(memlog, "Memory status (pkg):\n");
pkg_status();
#endif
|
96d09107 |
#endif
|
5b84defd |
_exit(0);
|
428e3b83 |
break;
case SIGUSR1:
/* statistics, do nothing, printed only from the main proc */
break;
/* ignored*/
case SIGUSR2:
case SIGHUP:
break;
case SIGCHLD:
#ifndef STOP_JIRIS_CHANGES
|
96d09107 |
#ifdef SIG_DEBUG /* signal unsafe stuff follows */
|
3eabab21 |
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 */
int install_sigs()
{
/* added by jku: add exit handler */
|
02dae965 |
if (set_sig_h(SIGINT, sig_usr) == SIG_ERR ) {
|
428e3b83 |
DPrint("ERROR: no SIGINT signal handler can be installed\n");
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 ) {
|
428e3b83 |
DPrint("ERROR: no SIGINT signal handler can be installed\n");
goto error;
}
|
02dae965 |
if (set_sig_h(SIGUSR1, sig_usr) == SIG_ERR ) {
|
428e3b83 |
DPrint("ERROR: no SIGUSR1 signal handler can be installed\n");
goto error;
}
|
02dae965 |
if (set_sig_h(SIGCHLD , sig_usr) == SIG_ERR ) {
|
428e3b83 |
DPrint("ERROR: no SIGCHLD signal handler can be installed\n");
goto error;
}
|
02dae965 |
if (set_sig_h(SIGTERM , sig_usr) == SIG_ERR ) {
|
428e3b83 |
DPrint("ERROR: no SIGTERM signal handler can be installed\n");
goto error;
}
|
02dae965 |
if (set_sig_h(SIGHUP , sig_usr) == SIG_ERR ) {
|
428e3b83 |
DPrint("ERROR: no SIGHUP signal handler can be installed\n");
goto error;
}
|
02dae965 |
if (set_sig_h(SIGUSR2 , sig_usr) == SIG_ERR ) {
|
428e3b83 |
DPrint("ERROR: no SIGUSR2 signal handler can be installed\n");
goto error;
}
return 0;
error:
return -1;
}
|
943a9d00 |
/* returns -1 on error, 0 on success
* sets proto */
static int parse_proto(unsigned char* s, long len, int* proto)
{
#define PROTO2UINT(a, b, c) (( (((unsigned int)(a))<<16)+ \
(((unsigned int)(b))<<8)+ \
((unsigned int)(c)) ) | 0x20202020)
unsigned int i;
if (len!=3) return -1;
i=PROTO2UINT(s[0], s[1], s[2]);
switch(i){
case PROTO2UINT('u', 'd', 'p'):
*proto=PROTO_UDP;
break;
#ifdef USE_TCP
case PROTO2UINT('t', 'c', 'p'):
*proto=PROTO_TCP;
break;
#ifdef USE_TLS
case PROTO2UINT('t', 'l', 's'):
*proto=PROTO_TLS;
break;
#endif
#endif
default:
return -1;
}
return 0;
}
/*
* parses [proto:]host[:port]
* where proto= udp|tcp|tls
* returns 0 on success and -1 on failure
*/
static int parse_phostport(char* s, char** host, int* hlen, int* port,
int* proto)
{
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;
}
}
if (p==s) return -1;
if (*(p-1)==':') goto error_colons;
|
b017f49c |
|
943a9d00 |
if (first==0){ /* no ':' => only host */
*host=s;
*hlen=(int)(p-s);
*port=0;
*proto=0;
return 0;
}
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);
return 0;
}
/* 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);
}
return 0;
error_brackets:
LOG(L_ERR, "ERROR: parse_phostport: too many brackets in %s\n", s);
return -1;
error_colons:
LOG(L_ERR, "ERROR: parse_phostport: too many colons in %s\n", s);
return -1;
error_proto:
LOG(L_ERR, "ERROR: parse_phostport: bad protocol in %s\n", s);
return -1;
error_port:
LOG(L_ERR, "ERROR: parse_phostport: bad port number in %s\n", s);
return -1;
}
|
cc2199a9 |
/* main loop */
int main_loop()
{
|
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
|
cc2199a9 |
/* one "main" process and n children handling i/o */
if (dont_fork){
|
f571aa35 |
#ifdef STATS
setstats( 0 );
#endif
|
49de5d20 |
if (udp_listen==0){
LOG(L_ERR, "ERROR: no fork mode requires at least one"
" 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;
|
45a03e3c |
sendipv4=bind_address;
sendipv6=bind_address; /*FIXME*/
|
9f4c52ce |
if (udp_listen->next){
|
e3fc93f4 |
LOG(L_WARN, "WARNING: using only the first listen address"
" (no fork)\n");
|
36ef0329 |
}
|
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 |
*/
|
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) {
LOG(L_ERR, "ERROR: main_dontfork: init_child(PROC_INT) --"
" exiting\n");
goto error;
}
|
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){
|
af93cbdf |
LOG(L_CRIT, "ERROR: main_loop: Cannot fork\n");
goto error;
}
if (pid==0){
/* child */
/* timer!*/
/* process_bit = 0; */
|
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){
|
36ef0329 |
LOG(L_CRIT, "ERROR: main_loop: Cannot fork\n");
|
cd57180a |
goto error;
}
if (pid==0){
/* child */
/* timer!*/
|
a76545c8 |
/* process_bit = 0; */
|
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 |
|
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 |
|
8390f722 |
/* 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) {
LOG(L_ERR, "ERROR: main_dontfork: init_child(PROC_MAIN) -- exiting\n");
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 |
|
cb87691a |
if (init_child(1) < 0) {
LOG(L_ERR, "main_dontfork: init_child failed\n");
|
192ac55b |
goto error;
}
|
391fa285 |
return udp_rcv_loop();
|
8390f722 |
}else{ /* fork: */
|
9e7eed4d |
|
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;
|
36ef0329 |
#ifdef USE_IPV6
|
9f4c52ce |
if((sendipv6==0)&&(si->address.af==AF_INET6))
sendipv6=si;
|
36ef0329 |
#endif
|
9f4c52ce |
}
|
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)&&
|
8b17718a |
((sendipv4_tcp==0)||
(sendipv4_tcp->flags&(SI_IS_LO|SI_IS_MCAST))))
|
9f4c52ce |
sendipv4_tcp=si;
|
5dcfb23d |
#ifdef USE_IPV6
|
9f4c52ce |
if((sendipv6_tcp==0)&&(si->address.af==AF_INET6))
sendipv6_tcp=si;
|
5dcfb23d |
#endif
}
|
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)&&
|
8b17718a |
((sendipv4_tls==0)||
(sendipv4_tls->flags&(SI_IS_LO|SI_IS_MCAST))))
|
9f4c52ce |
sendipv4_tls=si;
|
f22b996b |
#ifdef USE_IPV6
|
9f4c52ce |
if((sendipv6_tls==0)&&(si->address.af==AF_INET6))
sendipv6_tls=si;
|
f22b996b |
#endif
}
|
9f4c52ce |
}
|
f22b996b |
#endif /* USE_TLS */
#endif /* USE_TCP */
|
b3fef92b |
|
53c7e0f1 |
/* all processes should have access to all the sockets (for sending)
|
36ef0329 |
* so we open all first*/
|
53c7e0f1 |
if (do_suid()==-1) goto error; /* try to drop privileges */
|
9e7eed4d |
|
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) {
LOG(L_ERR, "ERROR: main: error in init_child(PROC_INT) --"
" exiting\n");
goto error;
}
|
9f4c52ce |
/* udp processes */
for(si=udp_listen; si; si=si->next){
|
cc2199a9 |
for(i=0;i<children_no;i++){
|
f238de3d |
snprintf(si_desc, MAX_PT_DESC, "receiver child=%d sock=%s:%s",
|
021e7e0e |
i, si->name.s, si->port_no_str.s);
|
3167c744 |
child_rank++;
|
f238de3d |
pid = fork_process(child_rank, si_desc, 1);
|
37209e14 |
if (pid<0){
|
cc2199a9 |
LOG(L_CRIT, "main_loop: Cannot fork\n");
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
|
cc2199a9 |
return udp_rcv_loop();
}
}
|
bf0fab3f |
/*parent*/
/*close(udp_sock)*/; /*if it's closed=>sendto invalid fd errors?*/
|
cc2199a9 |
}
}
|
db249450 |
|
a0196887 |
/*this is the main process*/
|
4c4e112f |
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){
|
af93cbdf |
LOG(L_CRIT, "main_loop: cannot fork \"slow\" timer process\n");
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){
|
6e94f57f |
LOG(L_CRIT, "main_loop: cannot fork timer process\n");
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();
|
0df81fe8 |
}else{
|
cd57180a |
}
|
cc2199a9 |
}
|
f2e1aa50 |
|
021e7e0e |
/* init childs with rank==MAIN before starting tcp main (in case they want to
|
f2e1aa50 |
* 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) {
|
8390f722 |
LOG(L_ERR, "ERROR: main: error in init_child\n");
|
f2e1aa50 |
goto error;
}
|
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){
|
90d859b2 |
LOG(L_CRIT, "main_loop: 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
|
0df81fe8 |
/* main */
|
f51155cf |
strncpy(pt[0].desc, "attendant", MAX_PT_DESC );
|
0c5da34b |
#ifdef USE_TCP
|
5dcfb23d |
if(!tcp_disable){
|
f2e1aa50 |
/* main's tcp sockets are disabled by default from init_pt() */
|
5dcfb23d |
unix_tcp_sock=-1;
}
|
0c5da34b |
#endif
|
55a45269 |
/*DEBUG- remove it*/
#ifdef EXTRA_DEBUG
|
37209e14 |
for (r=0; r<*process_count; r++){
|
55a45269 |
fprintf(stderr, "% 3d % 5d - %s\n", r, pt[r].pid, pt[r].desc);
}
#endif
|
3e999281 |
DBG("Expect maximum %d open fds\n", get_max_open_fds());
|
55a45269 |
|
6e94f57f |
for(;;){
handle_sigs();
|
d4fb00dc |
pause();
|
6e94f57f |
}
|
b017f49c |
|
51eadd0c |
/*return 0; */
|
cc2199a9 |
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;
|
b017f49c |
|
55a45269 |
for (si=udp_listen, udp_listeners=0; si; si=si->next, udp_listeners++);
return
/* receivers and attendant */
(dont_fork ? 1 : children_no * udp_listeners + 1)
/* 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
|
b017f49c |
+((!tcp_disable)?( 1/* tcp main */ + tcp_children_no ):0)
|
55a45269 |
#endif
;
}
|
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;
int socket_types;
|
512dcd98 |
|
3db079b5 |
/*init*/
|
02f62296 |
creator_pid = getpid();
|
3db079b5 |
ret=-1;
|
049f64c2 |
my_argc=argc; my_argv=argv;
|
dcb59e67 |
debug_flag=0;
dont_fork_cnt=0;
|
b017f49c |
|
90907c3f |
/*init pkg mallocs (before parsing cfg or cmd line !)*/
if (init_pkg_mallocs()==-1)
|
d31fcdf0 |
goto error;
|
be125734 |
#ifdef DBG_MSG_QA
fprintf(stderr, "WARNING: ser startup: "
"DBG_MSG_QA enabled, ser may exit abruptly\n");
#endif
|
6e94f57f |
|
f4194f69 |
options= ":f:cm:dVhEb:l:L:n:vrRDTN:W:w:t:u:g:P:G:"
|
f571aa35 |
#ifdef STATS
|
b017f49c |
"s:"
|
f571aa35 |
#endif
|
b017f49c |
;
/* look if there is a -h, e.g. -f -h construction won't catch it later */
opterr = 0;
while((c=getopt(argc,argv,options))!=-1) {
if (c == 'h' || (optarg && strcmp(optarg, "-h") == 0)) {
printf("version: %s\n", version);
printf("%s",help_msg);
exit(0);
break;
}
}
|
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) {
|
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;
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;
};
|
c082177a |
LOG(L_INFO, "ser: shared memory: %ld bytes\n",
|
36ef0329 |
shm_mem_size );
|
40a8d9dd |
break;
|
b017f49c |
case 'd':
debug_flag = 1;
debug++;
break;
case 'V':
printf("version: %s\n", version);
printf("flags: %s\n", flags );
print_ct_constants();
printf("%s\n",id);
printf("%s compiled on %s with %s\n", __FILE__,
compiled, COMPILER );
|
40a8d9dd |
|
b017f49c |
exit(0);
break;
case 'E':
log_stderr=1;
break;
case 'b':
case 'l':
case 'n':
case 'v':
case 'r':
case 'R':
case 'D':
case 'T':
case 'N':
case 'W':
case 'w':
case 't':
case 'u':
case 'g':
case 'P':
|
f4194f69 |
case 'G':
|
b017f49c |
case 's':
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();
}
}
|
021e7e0e |
|
93349b4e |
if (init_routes()<0) goto error;
|
ac34f9f4 |
if (init_nonsip_hooks()<0) goto error;
|
b017f49c |
/* fill missing arguments with the default values*/
if (cfg_file==0) cfg_file=CFG_FILE;
/* 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;
}
/* 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 */
LOG(L_WARN, "WARNING: could not read from /dev/urandom (%d)\n",
errno);
}
DBG("read %u from /dev/urandom\n", seed);
close(rfd);
}else{
LOG(L_WARN, "WARNING: could not open /dev/urandom (%d)\n", errno);
}
seed+=getpid()+time(0);
DBG("seeding PRNG with %u\n", seed);
srand(seed);
|
2c07f591 |
fastrand_seed(rand());
|
27937719 |
srandom(rand()+time(0));
|
2c07f591 |
DBG("test random numbers %u %lu %u\n", rand(), random(), fastrand());
|
b017f49c |
/*register builtin modules*/
register_builtin_modules();
|
65938e0e |
/* init named flags */
init_named_flags();
|
b017f49c |
yyin=cfg_stream;
debug_save = debug;
if ((yyparse()!=0)||(cfg_errors)){
fprintf(stderr, "ERROR: bad config file (%d errors)\n", cfg_errors);
goto error;
}
|
dcb59e67 |
if (cfg_warnings){
fprintf(stderr, "%d config warnings\n", cfg_warnings);
}
|
b017f49c |
if (debug_flag) debug = debug_save;
|
93349b4e |
print_rls();
|
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':
case 'd':
case 'V':
case 'h':
break;
case 'E':
log_stderr=1; // use in both getopt switches
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':
|
943a9d00 |
if (parse_phostport(optarg, &tmp, &tmp_len,
&port, &proto)<0){
fprintf(stderr, "bad -l address specifier: %s\n",
optarg);
goto error;
}
tmp[tmp_len]=0; /* null terminate the host */
|
e7671eb9 |
/* add a new addr. to our address list */
|
943a9d00 |
if (add_listen_iface(tmp, port, proto, 0)!=0){
|
9f4c52ce |
fprintf(stderr, "failed to add new listen address\n");
|
1b1b19d8 |
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;
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
|
5dcfb23d |
tcp_children_no=strtol(optarg, &tmp, 10);
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
|
0ba367ec |
break;
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;
|
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;
|
f4194f69 |
case 'G':
pgid_file=optarg;
break;
|
b017f49c |
case 's':
#ifdef STATS
stat_file=optarg;
#endif
break;
|
1b1b19d8 |
default:
|
b017f49c |
break;
|
7d31b911 |
}
}
|
404073d3 |
|
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;
|
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){
if (tcp_children_no<=0) tcp_children_no=children_no;
|
4bd1673d |
}
|
caf80ae6 |
#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 |
}
}
if (group){
|
71fd3ebd |
if (group2gid(&gid, group)<0){
|
054cb6cf |
fprintf(stderr, "bad group name/gid number: -u %s\n", group);
|
71fd3ebd |
goto error;
}
}
|
dcb59e67 |
if (fix_all_socket_lists(&socket_types)!=0){
|
53c7e0f1 |
fprintf(stderr, "failed to initialize list addresses\n");
|
9f4c52ce |
goto error;
|
e60a9728 |
}
|
dcb59e67 |
if (dns_try_ipv6 && !(socket_types & SOCKET_T_IPV6)){
/* if we are not listening on any ipv6 address => no point
* to try to resovle ipv6 addresses */
dns_try_ipv6=0;
}
|
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 "
|
49de5d20 |
"(will use only the the first one)":""
):"and no udp listen address found" );
|
0df81fe8 |
}
|
dda578ba |
if (config_check){
fprintf(stderr, "config file ok, exiting...\n");
goto error;
}
|
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)
* --andrei */
|
8390f722 |
if (init_shm_mallocs(shm_force_alloc)==-1)
|
dd0e65a8 |
goto error;
|
d307929c |
if (init_atomic_ops()==-1)
goto error;
|
dd0e65a8 |
/*init timer, before parsing the cfg!*/
if (init_timer()<0){
LOG(L_CRIT, "could not initialize timer, exiting...\n");
goto error;
}
|
dcb59e67 |
#ifdef USE_DNS_CACHE
|
dd4ffbb7 |
if (use_dns_cache && init_dns_cache()<0){
|
dcb59e67 |
LOG(L_CRIT, "could not initialize the dns cache, exiting...\n");
goto error;
}
if (use_dns_cache==0)
use_dns_failover=0; /* cannot work w/o dns_cache support */
|
021e7e0e |
#ifdef USE_DNS_CACHE_STATS
/* preinitializing before the nubmer of processes is determined */
if (init_dns_cache_stats(1)<0){
LOG(L_CRIT, "could not initialize the dns cache measurement\n");
goto error;
}
#endif /* USE_DNS_CACHE_STATS */
|
dcb59e67 |
#endif
#ifdef USE_DST_BLACKLIST
if (init_dst_blacklist()<0){
LOG(L_CRIT, "could not initialize the dst blacklist, exiting...\n");
goto error;
}
|
021e7e0e |
#ifdef USE_DST_BLACKLIST_STATS
/* preinitializing before the nubmer of processes is determined */
if (init_dst_blacklist_stats(1)<0){
LOG(L_CRIT, "could not initialize the dst blacklist measurement\n");
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){
LOG(L_CRIT, "could not initialize tcp, exiting...\n");
goto error;
}
}
|
f22b996b |
#endif /* USE_TCP */
|
ed2b50d3 |
/* init_daemon? */
if (!dont_fork){
if ( daemonize(argv[0]) <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);
else set_core_dump(1, shm_mem_size+PKG_MEM_POOL_SIZE+4*1024*1024);
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 |
|
385c63eb |
if (init_modules() != 0) {
fprintf(stderr, "ERROR: error while initializing modules\n");
goto error;
}
|
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()){
LOG(L_WARN, "WARNING: tls support enabled, but no tls engine "
" available (forgot to load the tls module?)\n");
LOG(L_WARN, "WARNING: disabling tls...\n");
tls_disable=1;
}
|
8628de22 |
/* init tls*/
if (init_tls()<0){
LOG(L_CRIT, "could not initialize tls, exiting...\n");
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 !
*/
DBG("Expect (at least) %d SER processes in your process list\n",
get_max_procs());
|
55a45269 |
|
021e7e0e |
#if defined USE_DNS_CACHE && defined USE_DNS_CACHE_STATS
if (init_dns_cache_stats(get_max_procs())<0){
LOG(L_CRIT, "could not initialize the dns cache measurement\n");
goto error;
}
#endif
#if defined USE_DST_BLACKLIST && defined USE_DST_BLACKLIST_STATS
if (init_dst_blacklist_stats(get_max_procs())<0){
LOG(L_CRIT, "could not initialize the dst blacklist measurement\n");
goto error;
}
#endif
|
6bb03a39 |
/* fix routing lists */
if ( (r=fix_rls())!=0){
|
6cd48835 |
fprintf(stderr, "ERROR: error %d while trying to fix configuration\n",
|
6bb03a39 |
r);
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();
/*kill everything*/
|
d4fb00dc |
if (is_main) shutdown_children(SIGTERM, 0);
/* else terminate process */
|
3db079b5 |
return ret;
|
512dcd98 |
error:
|
3db079b5 |
/*kill everything*/
|
d4fb00dc |
if (is_main) shutdown_children(SIGTERM, 0);
|
512dcd98 |
return -1;
}
|