512dcd98 |
/*
* $Id$
|
7dd0b342 |
*
* Copyright (C) 2001-2003 Fhg Fokus
*
* This file is part of ser, a free SIP server.
*
* ser is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version
*
* For a license to use the ser software under conditions
* other than those described here, or to purchase support for this
* software, please contact iptel.org by e-mail at the following addresses:
* info@iptel.org
*
* ser is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
512dcd98 |
*/
|
7dd0b342 |
|
512dcd98 |
#include <stdio.h>
|
3e429f5c |
#include <stdlib.h>
|
512dcd98 |
#include <errno.h>
|
3e429f5c |
#include <ctype.h>
|
512dcd98 |
#include <string.h>
|
e60a9728 |
#include <netdb.h>
|
1b1b19d8 |
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/utsname.h>
|
f571aa35 |
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/fcntl.h>
#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>
|
e998c342 |
#ifdef __sun
|
57e2cd15 |
#include <sys/sockio.h>
#endif
|
e60a9728 |
#include "config.h"
|
512dcd98 |
#include "dprint.h"
#include "route.h"
|
e60a9728 |
#include "udp_server.h"
|
1b1b19d8 |
#include "globals.h"
|
dda9dab1 |
#include "mem/mem.h"
|
628e3a5a |
#ifdef SHM_MEM
|
dda9dab1 |
#include "mem/shm_mem.h"
|
628e3a5a |
#endif
|
bf08223a |
#include "sr_module.h"
|
cd57180a |
#include "timer.h"
|
3881f12c |
#include "parser/msg_parser.h"
|
4e2fdd79 |
#include "ip_addr.h"
#include "resolve.h"
|
2bb60634 |
#include "parser/parse_hname2.h"
|
335d097b |
#include "parser/digest/digest_parser.h"
|
caf80ae6 |
#include "fifo_server.h"
|
e278821b |
#include "name_alias.h"
|
9df1213c |
#include "hash_func.h"
|
f51155cf |
#include "pt.h"
|
1b1b19d8 |
|
0a974a1d |
|
5b253cc6 |
#include "stats.h"
|
726efa25 |
|
03150098 |
#ifdef DEBUG_DMALLOC
#include <dmalloc.h>
#endif
|
1b1b19d8 |
static char id[]="@(#) $Id$";
|
b2dec9c6 |
static char version[]= NAME " " VERSION " (" ARCH "/" OS ")" ;
|
247c2b65 |
static char compiled[]= __TIME__ __DATE__ ;
|
7db4ee8d |
static char flags[]=
"STATS:"
|
af6fb476 |
#ifdef STATS
"On"
#else
"Off"
#endif
|
4e2fdd79 |
#ifdef USE_IPV6
", USE_IPV6"
#endif
|
f8d46776 |
#ifdef NO_DEBUG
", NO_DEBUG"
#endif
#ifdef NO_LOG
", NO_LOG"
#endif
|
25b49bb4 |
#ifdef EXTRA_DEBUG
", EXTRA_DEBUG"
|
f8d46776 |
#endif
|
104316b6 |
#ifdef DNS_IP_HACK
", DNS_IP_HACK"
#endif
|
25b49bb4 |
#ifdef SHM_MEM
", SHM_MEM"
#endif
|
dcb5f364 |
#ifdef SHM_MMAP
", SHM_MMAP"
#endif
|
25b49bb4 |
#ifdef PKG_MALLOC
", PKG_MALLOC"
#endif
|
dda9dab1 |
#ifdef VQ_MALLOC
", VQ_MALLOC"
#endif
|
b2dec9c6 |
#ifdef F_MALLOC
", F_MALLOC"
#endif
|
25b49bb4 |
#ifdef USE_SHM_MEM
", USE_SHM_MEM"
#endif
#ifdef DBG_QM_MALLOC
", DBG_QM_MALLOC"
#endif
#ifdef DEBUG_DMALLOC
", DEBUG_DMALLOC"
#endif
|
b2dec9c6 |
#ifdef FAST_LOCK
", FAST_LOCK"
|
30f1f956 |
#ifdef BUSY_WAIT
"-BUSY_WAIT"
|
b2dec9c6 |
#endif
|
30f1f956 |
#ifdef ADAPTIVE_WAIT
"-ADAPTIVE_WAIT"
#endif
#ifdef NOSMP
"-NOSMP"
#endif
#endif /*FAST_LOCK*/
|
726efa25 |
;
|
1b1b19d8 |
static char help_msg[]= "\
|
36ef0329 |
Usage: " NAME " -l address [-p port] [-l address [-p port]...] [options]\n\
|
1b1b19d8 |
Options:\n\
-f file Configuration file (default " CFG_FILE ")\n\
-p port Listen on the specified port (default: 5060)\n\
|
36ef0329 |
applies to the last address in -l and to all \n\
following that do not have a corespponding -p\n\
|
1b1b19d8 |
-l address Listen on the specified address (multiple -l mean\n\
listening on more addresses). The default behaviour\n\
is to listen on the addresses returned by uname(2)\n\
\n\
-n processes Number of child processes to fork per interface\n\
(default: 8)\n\
\n\
-r Use dns to check if is necessary to add a \"received=\"\n\
field to a via\n\
|
c6016a4c |
-R Same as `-r` but use reverse dns;\n\
(to use both use `-rR`)\n\
|
1b1b19d8 |
\n\
-v Turn on \"via:\" host checking when forwarding replies\n\
-d Debugging mode (multiple -d increase the level)\n\
-D Do not fork into daemon mode\n\
-E Log to stderr\n\
-V Version number\n\
-h This help message\n\
|
c3ce2841 |
-b nr Maximum receive buffer size which will not be exceeded by\n\
|
c9ca45b3 |
auto-probing procedure even if OS allows\n\
|
4e2fdd79 |
-m nr Size of shared memory allocated in Megabytes\n\
|
c9ca45b3 |
-w dir change the working directory to \"dir\" (default \"/\")\n\
-t dir chroot to \"dir\"\n\
-u uid change uid \n\
|
b2934963 |
-g gid change gid \n\
|
97f17e60 |
-P file create a pid file\n\
-i fifo_path create a fifo (usefull for monitoring " NAME ") \n"
|
f571aa35 |
#ifdef STATS
|
97f17e60 |
" -s file File to which statistics is dumped (disabled otherwise)\n"
|
f571aa35 |
#endif
;
|
512dcd98 |
|
af6fb476 |
/* print compile-time constants */
void print_ct_constants()
{
|
30f1f956 |
#ifdef ADAPTIVE_WAIT
printf("ADAPTIVE_WAIT_LOOPS=%d, ", ADAPTIVE_WAIT_LOOPS);
#endif
|
40a8d9dd |
/*
|
30f1f956 |
#ifdef SHM_MEM
printf("SHM_MEM_SIZE=%d, ", SHM_MEM_SIZE);
#endif
|
40a8d9dd |
*/
|
30f1f956 |
printf("MAX_RECV_BUFFER_SIZE %d, MAX_LISTEN %d,"
|
caf80ae6 |
" MAX_URI_SIZE %d, BUF_SIZE %d\n",
MAX_RECV_BUFFER_SIZE, MAX_LISTEN, MAX_URI_SIZE,
|
1f377e97 |
BUF_SIZE );
|
af6fb476 |
}
|
512dcd98 |
|
888ca09d |
/* debuging function */
|
e60a9728 |
/*
|
888ca09d |
void receive_stdin_loop()
{
#define BSIZE 1024
char buf[BSIZE+1];
int len;
|
5655ca6f |
|
888ca09d |
while(1){
len=fread(buf,1,BSIZE,stdin);
buf[len+1]=0;
receive_msg(buf, len);
printf("-------------------------\n");
}
}
|
e60a9728 |
*/
|
888ca09d |
|
1b1b19d8 |
/* global vars */
char* cfg_file = 0;
|
4e2fdd79 |
unsigned int maxbuffer = MAX_RECV_BUFFER_SIZE; /* maximum buffer size we do
not want to exceed durig the
auto-probing procedure; may
be re-configured */
int children_no = 0; /* number of children processing requests */
|
f51155cf |
struct process_table *pt=0; /*array with childrens pids, 0= main proc,
|
4e2fdd79 |
alloc'ed in shared mem if possible*/
|
6e94f57f |
int sig_flag = 0; /* last signal received */
|
1b1b19d8 |
int debug = 0;
int dont_fork = 0;
int log_stderr = 0;
|
caf80ae6 |
/* check if reply first via host==us */
int check_via = 0;
/* shall use stateful synonym branches? faster but not reboot-safe */
|
855c2e68 |
int syn_branch = 1;
|
609ada42 |
/* debugging level for memory stats */
int memlog = L_DBG;
|
caf80ae6 |
/* should replies include extensive warnings? by default yes,
good for trouble-shooting
*/
int sip_warning = 1;
/* should localy-generated messages include server's signature?
be default yes, good for trouble-shooting
*/
int server_signature=1;
/* use dns and/or rdns or to see if we need to add
a ;received=x.x.x.x to via: */
int received_dns = 0;
|
c9ca45b3 |
char* working_dir = 0;
char* chroot_dir = 0;
|
054cb6cf |
char* user=0;
char* group=0;
|
c9ca45b3 |
int uid = 0;
int gid = 0;
|
caf80ae6 |
/* a hint to reply modules whether they should send reply
to IP advertised in Via or IP from which a request came
*/
int reply_to_via=0;
|
1b1b19d8 |
|
36ef0329 |
#if 0
|
1d597ac3 |
char* names[MAX_LISTEN]; /* our names */
int names_len[MAX_LISTEN]; /* lengths of the names*/
|
4e2fdd79 |
struct ip_addr addresses[MAX_LISTEN]; /* our ips */
|
1d597ac3 |
int addresses_no=0; /* number of names/ips */
|
36ef0329 |
#endif
|
e3fc93f4 |
struct socket_info sock_info[MAX_LISTEN];/*all addresses we listen/send from*/
|
36ef0329 |
int sock_no=0; /* number of addresses/open sockets*/
|
e3fc93f4 |
struct socket_info* bind_address; /* pointer to the crt. proc.
listening address*/
|
36ef0329 |
int bind_idx; /* same as above but index in the bound[] array */
struct socket_info* sendipv4; /* ipv4 socket to use when msg. comes from ipv6*/
struct socket_info* sendipv6; /* same as above for ipv6 */
unsigned short port_no=0; /* default port*/
|
1b1b19d8 |
|
e278821b |
struct host_alias* aliases=0; /* name aliases list */
|
cc2199a9 |
/* ipc related globals */
int process_no = 0;
|
a76545c8 |
/* process_bm_t process_bit = 0; */
|
cc2199a9 |
#ifdef ROUTE_SRV
#endif
|
888ca09d |
|
63fa628f |
/* cfg parsing */
int cfg_errors=0;
|
888ca09d |
|
40a8d9dd |
/* shared memory (in MB) */
unsigned int shm_mem_size=SHM_MEM_SIZE * 1024 * 1024;
|
cc2199a9 |
#define MAX_FD 32 /* maximum number of inherited open file descriptors,
(normally it shouldn't be bigger than 3) */
|
3e429f5c |
extern FILE* yyin;
extern int yyparse();
|
71bb231e |
int is_main=0; /* flag = is this the "main" process? */
|
3e429f5c |
|
a7cbdb26 |
char* pid_file = 0; /* filename as asked by use */
|
b2934963 |
|
cc2199a9 |
/* daemon init, return 0 on success, -1 on error */
int daemonize(char* name)
{
|
b2934963 |
FILE *pid_stream;
|
cc2199a9 |
pid_t pid;
|
b2934963 |
int r, p;
|
a7cbdb26 |
|
b2934963 |
p=-1;
|
c9ca45b3 |
if (chroot_dir&&(chroot(chroot_dir)<0)){
LOG(L_CRIT, "Cannot chroot to %s: %s\n", chroot_dir, strerror(errno));
|
cc2199a9 |
goto error;
}
|
c9ca45b3 |
if (chdir(working_dir)<0){
LOG(L_CRIT,"cannot chdir to %s: %s\n", working_dir, strerror(errno));
goto error;
}
if (gid&&(setgid(gid)<0)){
LOG(L_CRIT, "cannot change gid to %d: %s\n", gid, strerror(errno));
goto error;
}
if(uid&&(setuid(uid)<0)){
LOG(L_CRIT, "cannot change uid to %d: %s\n", uid, strerror(errno));
goto error;
}
|
cc2199a9 |
/* fork to become!= group leader*/
if ((pid=fork())<0){
LOG(L_CRIT, "Cannot fork:%s\n", strerror(errno));
goto error;
|
36ef0329 |
}else if (pid!=0){
|
cc2199a9 |
/* parent process => exit*/
exit(0);
}
/* become session leader to drop the ctrl. terminal */
if (setsid()<0){
LOG(L_WARN, "setsid failed: %s\n",strerror(errno));
}
/* fork again to drop group leadership */
if ((pid=fork())<0){
LOG(L_CRIT, "Cannot fork:%s\n", strerror(errno));
goto error;
|
36ef0329 |
}else if (pid!=0){
|
cc2199a9 |
/*parent process => exit */
exit(0);
}
|
b2934963 |
/* added by noh: create a pid file for the main process */
if (pid_file!=0){
|
a7cbdb26 |
|
36ef0329 |
if ((pid_stream=fopen(pid_file, "r"))!=NULL){
|
b2934963 |
fscanf(pid_stream, "%d", &p);
fclose(pid_stream);
if (p==-1){
LOG(L_CRIT, "pid file %s exists, but doesn't contain a valid"
|
36ef0329 |
" pid number\n", pid_file);
|
b2934963 |
goto error;
}
if (kill((pid_t)p, 0)==0 || errno==EPERM){
LOG(L_CRIT, "running process found in the pid file %s\n",
|
36ef0329 |
pid_file);
|
b2934963 |
goto error;
}else{
LOG(L_WARN, "pid file contains old pid, replacing pid\n");
}
}
pid=getpid();
|
36ef0329 |
if ((pid_stream=fopen(pid_file, "w"))==NULL){
|
a7cbdb26 |
LOG(L_WARN, "unable to create pid file %s: %s\n",
|
36ef0329 |
pid_file, strerror(errno));
|
b2934963 |
goto error;
}else{
fprintf(pid_stream, "%i\n", (int)pid);
fclose(pid_stream);
}
}
|
cc2199a9 |
/* close any open file descriptors */
|
1c80cd8d |
for (r=0;r<MAX_FD; r++){
|
8b45313f |
if ((r==2) && log_stderr) continue;
|
676924fb |
close(r);
|
1c80cd8d |
}
|
8b45313f |
if (log_stderr==0)
openlog(name, LOG_PID|LOG_CONS, LOG_LOCAL1 /*LOG_DAEMON*/);
/* LOG_CONS, LOG_PERRROR ? */
|
cc2199a9 |
return 0;
error:
return -1;
}
|
6e94f57f |
void handle_sigs()
{
pid_t chld;
int chld_status;
switch(sig_flag){
case 0: break; /* do nothing*/
case SIGINT:
case SIGPIPE:
case SIGTERM:
/* we end the program in all these cases */
if (sig_flag==SIGINT)
DBG("INT received, program terminates\n");
else if (sig_flag==SIGPIPE)
|
3db079b5 |
DBG("SIGPIPE received, program terminates\n");
|
6e94f57f |
else
DBG("SIGTERM received, program terminates\n");
|
8e8c1478 |
/* first of all, kill the children also */
kill(0, SIGTERM);
|
55ce9059 |
/* Wait for all the children to die */
while(wait(0) > 0);
|
6e94f57f |
destroy_modules();
#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();
/* zero all shmem alloc vars that we still use */
|
f51155cf |
pt=0;
|
6e94f57f |
shm_mem_destroy();
#endif
if (pid_file) unlink(pid_file);
dprint("Thank you for flying " NAME "\n");
exit(0);
break;
case SIGUSR1:
#ifdef STATS
dump_all_statistic();
#endif
#ifdef PKG_MALLOC
|
f51155cf |
LOG(memlog, "Memory status (pkg):\n");
|
6e94f57f |
pkg_status();
#endif
#ifdef SHM_MEM
|
f51155cf |
LOG(memlog, "Memory status (shm):\n");
|
6e94f57f |
shm_status();
#endif
break;
case SIGCHLD:
while ((chld=waitpid( -1, &chld_status, WNOHANG ))>0) {
if (WIFEXITED(chld_status))
LOG(L_INFO, "child process %d exited normally,"
" status=%d\n", chld,
WEXITSTATUS(chld_status));
else if (WIFSIGNALED(chld_status)) {
LOG(L_INFO, "child process %d exited by a signal"
" %d\n", chld, WTERMSIG(chld_status));
#ifdef WCOREDUMP
LOG(L_INFO, "core was %sgenerated\n",
|
a0196887 |
WCOREDUMP(chld_status) ? "" : "not " );
|
6e94f57f |
#endif
}else if (WIFSTOPPED(chld_status))
LOG(L_INFO, "child process %d stopped by a"
" signal %d\n", chld,
WSTOPSIG(chld_status));
}
|
49041f7b |
#ifndef STOP_JIRIS_CHANGES
if (dont_fork) {
LOG(L_INFO, "INFO: dont_fork turned on, living on\n");
break;
}
LOG(L_INFO, "INFO: terminating due to SIGCHLD\n");
#endif
|
6e94f57f |
/* exit */
kill(0, SIGTERM);
DBG("terminating due to SIGCHLD\n");
exit(0);
break;
case SIGHUP: /* ignoring it*/
DBG("SIGHUP received, ignoring it\n");
break;
default:
LOG(L_CRIT, "WARNING: unhandled signal %d\n", sig_flag);
}
sig_flag=0;
}
|
cc2199a9 |
/* main loop */
int main_loop()
{
int r, i;
pid_t pid;
|
2f781952 |
#ifdef WITH_SNMP_MOD
int (*snmp_start)();
/* initialize snmp module */
snmp_start = (int(*)())find_export("snmp_start", 0);
if(snmp_start)
if(snmp_start() == -1)
LOG(L_ERR, "ERROR: Couldn't start snmp agent\n");
#endif
|
cc2199a9 |
/* one "main" process and n children handling i/o */
|
1fb7b1aa |
|
cc2199a9 |
if (dont_fork){
|
f571aa35 |
#ifdef STATS
setstats( 0 );
#endif
|
36ef0329 |
/* only one address, we ignore all the others */
if (udp_init(&sock_info[0])==-1) goto error;
bind_address=&sock_info[0];
bind_idx=0;
if (sock_no>1){
|
e3fc93f4 |
LOG(L_WARN, "WARNING: using only the first listen address"
" (no fork)\n");
|
36ef0329 |
}
|
cd57180a |
|
db249450 |
/* process_no now initialized to zero -- increase from now on
as new processes are forked (while skipping 0 reserved for main
*/
|
cd57180a |
/* we need another process to act as the timer*/
if (timer_list){
|
cbd9fc8b |
process_no++;
|
cd57180a |
if ((pid=fork())<0){
|
36ef0329 |
LOG(L_CRIT, "ERROR: main_loop: Cannot fork\n");
|
cd57180a |
goto error;
}
|
cbd9fc8b |
|
cd57180a |
if (pid==0){
/* child */
/* timer!*/
|
a76545c8 |
/* process_bit = 0; */
|
cd57180a |
for(;;){
sleep(TIMER_TICK);
timer_ticker();
}
|
cbd9fc8b |
}else{
|
f51155cf |
pt[process_no].pid=pid; /*should be shared mem anway*/
strncpy(pt[process_no].desc, "timer", MAX_PT_DESC );
|
cd57180a |
}
}
|
1380e79e |
/* if configured to do so, start a server for accepting FIFO commands */
if (open_fifo_server()<0) {
LOG(L_ERR, "opening fifo server failed\n");
goto error;
}
|
72b7f9a2 |
/* main process, receive loop */
process_no=0; /*main process number*/
|
f51155cf |
pt[process_no].pid=getpid();
snprintf(pt[process_no].desc, MAX_PT_DESC,
"stand-alone receiver @ %s:%s",
bind_address->name.s, bind_address->port_no_str.s );
|
192ac55b |
/* We will call child_init even if we
* do not fork
*/
|
eedd46b1 |
if (init_child(0) < 0) {
|
192ac55b |
LOG(L_ERR, "init_child failed\n");
goto error;
}
|
caf80ae6 |
|
db1b5017 |
is_main=1; /* hack 42: call init_child with is_main=0 in case
some modules wants to fork a child */
|
eedd46b1 |
|
391fa285 |
return udp_rcv_loop();
|
cc2199a9 |
}else{
|
db249450 |
/* process_no now initialized to zero -- increase from now on
|
f51155cf |
as new processes are forked (while skipping 0 reserved for main )
|
db249450 |
*/
|
36ef0329 |
for(r=0;r<sock_no;r++){
|
1fb7b1aa |
/* create the listening socket (for each address)*/
|
36ef0329 |
if (udp_init(&sock_info[r])==-1) goto error;
/* get first ipv4/ipv6 socket*/
if ((sendipv4==0)&&(sock_info[r].address.af==AF_INET))
sendipv4=&sock_info[r];
#ifdef USE_IPV6
if((sendipv6==0)&&(sock_info[r].address.af==AF_INET6))
sendipv6=&sock_info[r];
#endif
/* all procs should have access to all the sockets (for sending)
* so we open all first*/
}
for(r=0; r<sock_no;r++){
|
cc2199a9 |
for(i=0;i<children_no;i++){
|
0df81fe8 |
process_no++;
|
cc2199a9 |
if ((pid=fork())<0){
LOG(L_CRIT, "main_loop: Cannot fork\n");
goto error;
|
36ef0329 |
}else if (pid==0){
|
192ac55b |
/* child */
|
36ef0329 |
bind_address=&sock_info[r]; /* shortcut */
bind_idx=r;
|
192ac55b |
if (init_child(i) < 0) {
LOG(L_ERR, "init_child failed\n");
goto error;
}
|
f571aa35 |
#ifdef STATS
|
0df81fe8 |
setstats( i+r*children_no );
|
f571aa35 |
#endif
|
cc2199a9 |
return udp_rcv_loop();
|
cbd9fc8b |
}else{
|
f51155cf |
pt[process_no].pid=pid; /*should be in shared mem.*/
snprintf(pt[process_no].desc, MAX_PT_DESC,
"receiver child=%d sock=%d @ %s:%s", i, r,
sock_info[r].name.s, sock_info[r].port_no_str.s );
|
cc2199a9 |
}
}
|
bf0fab3f |
/*parent*/
/*close(udp_sock)*/; /*if it's closed=>sendto invalid fd errors?*/
|
cc2199a9 |
}
}
|
db249450 |
|
a0196887 |
/*this is the main process*/
bind_address=&sock_info[0]; /* main proc -> it shoudln't send anything, */
bind_idx=0; /* if it does it will use the first address */
|
caf80ae6 |
/* if configured to do so, start a server for accepting FIFO commands */
if (open_fifo_server()<0) {
LOG(L_ERR, "opening fifo server failed\n");
goto error;
}
|
36ef0329 |
|
cd57180a |
if (timer_list){
|
6e94f57f |
/* fork again for the attendant process*/
|
db249450 |
process_no++;
|
6e94f57f |
if ((pid=fork())<0){
LOG(L_CRIT, "main_loop: cannot fork timer process\n");
goto error;
}else if (pid==0){
/* child */
|
0df81fe8 |
/* is_main=0; */
|
6e94f57f |
for(;;){
/* debug: instead of doing something usefull */
/* (placeholder for timers, etc.) */
sleep(TIMER_TICK);
/* if we received a signal => TIMER_TICK may have not elapsed*/
timer_ticker();
}
|
0df81fe8 |
}else{
|
f51155cf |
pt[process_no].pid=pid;
strncpy(pt[process_no].desc, "timer", MAX_PT_DESC );
|
cd57180a |
}
|
cc2199a9 |
}
|
db249450 |
|
0df81fe8 |
/* main */
|
f51155cf |
pt[0].pid=getpid();
strncpy(pt[0].desc, "attendant", MAX_PT_DESC );
|
0df81fe8 |
/*DEBUG- remove it*/
|
f51155cf |
#ifdef DEBUG
|
e3fc93f4 |
printf("\n% 3d processes, % 3d children * % 3d listening addresses + main"
" + fifo %s\n", process_no+1, children_no, sock_no,
(timer_list)?"+ timer":"");
|
0df81fe8 |
for (r=0; r<=process_no; r++){
|
f51155cf |
printf("% 3d % 5d\n", r, pt[r].pid);
|
0df81fe8 |
}
|
f51155cf |
#endif
|
0df81fe8 |
process_no=0;
|
a76545c8 |
/* process_bit = 0; */
|
db249450 |
is_main=1;
|
cc2199a9 |
|
6e94f57f |
for(;;){
pause();
handle_sigs();
}
|
51eadd0c |
/*return 0; */
|
cc2199a9 |
error:
return -1;
}
|
726efa25 |
|
f571aa35 |
|
726efa25 |
/* added by jku; allows for regular exit on a specific signal;
good for profiling which only works if exited regularly and
not by default signal handlers
|
6e94f57f |
- modified by andrei: moved most of the stuff to handle_sigs,
made it safer for the "fork" case
|
36ef0329 |
*/
|
726efa25 |
static void sig_usr(int signo)
{
|
e9d701db |
|
caf80ae6 |
|
6e94f57f |
if (is_main){
if (sig_flag==0) sig_flag=signo;
else /* previous sig. not processed yet, ignoring? */
return; ;
if (dont_fork)
|
db1b5017 |
/* only one proc, doing everything from the sig handler,
|
6e94f57f |
unsafe, but this is only for debugging mode*/
handle_sigs();
}else{
/* process the important signals */
switch(signo){
case SIGINT:
case SIGPIPE:
case SIGTERM:
|
caf80ae6 |
/* print memory stats for non-main too */
#ifdef PKG_MALLOC
|
f51155cf |
LOG(memlog, "Memory status (pkg):\n");
|
caf80ae6 |
pkg_status();
#endif
|
6e94f57f |
exit(0);
break;
case SIGUSR1:
/* statistics, do nothing, printed only from the main proc */
break;
/* ignored*/
case SIGUSR2:
case SIGHUP:
break;
|
db1b5017 |
case SIGCHLD:
|
49041f7b |
#ifndef STOP_JIRIS_CHANGES
LOG(L_INFO, "INFO: SIGCHLD received: "
"we do not worry about grand-children\n");
#else
|
db1b5017 |
exit(0); /* terminate if one child died */
|
49041f7b |
#endif
|
e9d701db |
}
|
f571aa35 |
}
|
726efa25 |
}
|
cd57180a |
|
6e94f57f |
|
57e2cd15 |
/* add all family type addresses of interface if_name to the socket_info array
* if if_name==0, adds all addresses on all interfaces
* WARNING: it only works with ipv6 addresses on FreeBSD
* return: -1 on error, 0 on success
*/
int add_interfaces(char* if_name, int family, unsigned short port)
{
struct ifconf ifc;
struct ifreq* ifr;
struct ifreq ifrcopy;
char* last;
int size;
int lastlen;
int s;
char* tmp;
struct ip_addr addr;
int ret;
|
53531528 |
#ifdef __FreeBSD__
#define MAX(a,b) ( ((a)>(b))?(a):(b))
#endif
|
57e2cd15 |
/* ipv4 or ipv6 only*/
s=socket(family, SOCK_DGRAM, 0);
ret=-1;
lastlen=0;
ifc.ifc_req=0;
for (size=10; ; size*=2){
ifc.ifc_len=size*sizeof(struct ifreq);
ifc.ifc_req=(struct ifreq*) malloc(size*sizeof(struct ifreq));
if (ifc.ifc_req==0){
fprintf(stderr, "memory allocation failure\n");
goto error;
}
if (ioctl(s, SIOCGIFCONF, &ifc)==-1){
if(errno==EBADF) return 0; /* invalid descriptor => no such ifs*/
fprintf(stderr, "ioctl failed: %s\n", strerror(errno));
goto error;
}
if ((lastlen) && (ifc.ifc_len==lastlen)) break; /*success,
len not changed*/
lastlen=ifc.ifc_len;
/* try a bigger array*/
free(ifc.ifc_req);
}
last=(char*)ifc.ifc_req+ifc.ifc_len;
for(ifr=ifc.ifc_req; (char*)ifr<last;
ifr=(struct ifreq*)((char*)ifr+sizeof(ifr->ifr_name)+
#ifdef __FreeBSD__
MAX(ifr->ifr_addr.sa_len, sizeof(struct sockaddr))
#else
( (ifr->ifr_addr.sa_family==AF_INET)?
sizeof(struct sockaddr_in):
((ifr->ifr_addr.sa_family==AF_INET6)?
sizeof(struct sockaddr_in6):sizeof(struct sockaddr)) )
#endif
)
)
{
if (ifr->ifr_addr.sa_family!=family){
/*printf("strange family %d skipping...\n",
ifr->ifr_addr.sa_family);*/
continue;
}
if (if_name==0){ /* ignore down ifs only if listening on all of them*/
memcpy(&ifrcopy, ifr, sizeof(ifrcopy));
/*get flags*/
if (ioctl(s, SIOCGIFFLAGS, &ifrcopy)!=-1){ /* ignore errors */
/* if if not up, skip it*/
if (!(ifrcopy.ifr_flags & IFF_UP)) continue;
}
}
if ((if_name==0)||
(strncmp(if_name, ifr->ifr_name, sizeof(ifr->ifr_name))==0)){
/*add address*/
if (sock_no<MAX_LISTEN){
sockaddr2ip_addr(&addr, &ifr->ifr_addr);
if ((tmp=ip_addr2a(&addr))==0) goto error;
/* fill the strings*/
sock_info[sock_no].name.s=(char*)malloc(strlen(tmp)+1);
if(sock_info[sock_no].name.s==0){
fprintf(stderr, "Out of memory.\n");
goto error;
}
/* fill in the new name and port */
sock_info[sock_no].name.len=strlen(tmp);
strncpy(sock_info[sock_no].name.s, tmp,
sock_info[sock_no].name.len+1);
sock_info[sock_no].port_no=port;
sock_no++;
ret=0;
}else{
fprintf(stderr, "Too many addresses (max %d)\n", MAX_LISTEN);
goto error;
}
}
/*
printf("%s:\n", ifr->ifr_name);
printf(" ");
print_sockaddr(&(ifr->ifr_addr));
printf(" ");
ls_ifflags(ifr->ifr_name, family, options);
printf("\n");*/
}
free(ifc.ifc_req); /*clean up*/
close(s);
return ret;
error:
if (ifc.ifc_req) free(ifc.ifc_req);
close(s);
return -1;
}
|
cd57180a |
|
512dcd98 |
int main(int argc, char** argv)
{
FILE* cfg_stream;
|
e60a9728 |
struct hostent* he;
|
57e2cd15 |
int c,r,t;
|
1b1b19d8 |
char *tmp;
|
e278821b |
char** h;
struct host_alias* a;
|
1b1b19d8 |
struct utsname myname;
|
f571aa35 |
char *options;
|
36ef0329 |
char port_no_str[MAX_PORT_LEN];
|
3db079b5 |
int port_no_str_len;
int ret;
|
054cb6cf |
struct passwd *pw_entry;
struct group *gr_entry;
|
512dcd98 |
|
3db079b5 |
/*init*/
port_no_str_len=0;
ret=-1;
|
726efa25 |
/* added by jku: add exit handler */
|
628e3a5a |
if (signal(SIGINT, sig_usr) == SIG_ERR ) {
DPrint("ERROR: no SIGINT signal handler can be installed\n");
goto error;
}
|
dda9dab1 |
/* if we debug and write to a pipe, we want to exit nicely too */
if (signal(SIGPIPE, sig_usr) == SIG_ERR ) {
DPrint("ERROR: no SIGINT signal handler can be installed\n");
goto error;
}
|
628e3a5a |
|
f571aa35 |
if (signal(SIGUSR1, sig_usr) == SIG_ERR ) {
|
628e3a5a |
DPrint("ERROR: no SIGUSR1 signal handler can be installed\n");
goto error;
}
|
e9d701db |
if (signal(SIGCHLD , sig_usr) == SIG_ERR ) {
DPrint("ERROR: no SIGCHLD signal handler can be installed\n");
goto error;
}
|
b2934963 |
if (signal(SIGTERM , sig_usr) == SIG_ERR ) {
DPrint("ERROR: no SIGTERM signal handler can be installed\n");
goto error;
}
|
6e94f57f |
if (signal(SIGHUP , sig_usr) == SIG_ERR ) {
DPrint("ERROR: no SIGHUP signal handler can be installed\n");
goto error;
}
if (signal(SIGUSR2 , sig_usr) == SIG_ERR ) {
DPrint("ERROR: no SIGUSR2 signal handler can be installed\n");
goto error;
}
|
be125734 |
#ifdef DBG_MSG_QA
fprintf(stderr, "WARNING: ser startup: "
"DBG_MSG_QA enabled, ser may exit abruptly\n");
#endif
|
6e94f57f |
|
726efa25 |
|
512dcd98 |
/* process command line (get port no, cfg. file path etc) */
|
1b1b19d8 |
opterr=0;
|
f571aa35 |
options=
#ifdef STATS
"s:"
#endif
|
97f17e60 |
"f:p:m:b:l:n:rRvdDEVhw:t:u:g:P:i:";
|
f571aa35 |
while((c=getopt(argc,argv,options))!=-1){
|
1b1b19d8 |
switch(c){
case 'f':
cfg_file=optarg;
break;
|
f571aa35 |
case 's':
|
e4067ffb |
#ifdef STATS
|
f571aa35 |
stat_file=optarg;
|
e4067ffb |
#endif
|
f571aa35 |
break;
|
1b1b19d8 |
case 'p':
port_no=strtol(optarg, &tmp, 10);
if (tmp &&(*tmp)){
fprintf(stderr, "bad port number: -p %s\n", optarg);
goto error;
}
|
36ef0329 |
if (sock_no>0) sock_info[sock_no-1].port_no=port_no;
|
1b1b19d8 |
break;
|
c3ce2841 |
|
40a8d9dd |
case 'm':
shm_mem_size=strtol(optarg, &tmp, 10) * 1024 * 1024;
if (tmp &&(*tmp)){
|
36ef0329 |
fprintf(stderr, "bad shmem size number: -m %s\n",
optarg);
|
40a8d9dd |
goto error;
};
|
36ef0329 |
LOG(L_INFO, "ser: shared memory allocated: %d MByte\n",
shm_mem_size );
|
40a8d9dd |
break;
|
c3ce2841 |
case 'b':
maxbuffer=strtol(optarg, &tmp, 10);
if (tmp &&(*tmp)){
|
36ef0329 |
fprintf(stderr, "bad max buffer size number: -p %s\n",
optarg);
goto error;
}
break;
|
1b1b19d8 |
case 'l':
|
e7671eb9 |
/* add a new addr. to our address list */
|
36ef0329 |
if (sock_no < MAX_LISTEN){
sock_info[sock_no].name.s=
(char*)malloc(strlen(optarg)+1);
if (sock_info[sock_no].name.s==0){
|
1b1b19d8 |
fprintf(stderr, "Out of memory.\n");
goto error;
}
|
36ef0329 |
strncpy(sock_info[sock_no].name.s, optarg,
strlen(optarg)+1);
sock_info[sock_no].name.len=strlen(optarg);
/* set default port */
sock_info[sock_no].port_no=port_no;
sock_no++;
|
1b1b19d8 |
}else{
fprintf(stderr,
"Too many addresses (max. %d).\n",
MAX_LISTEN);
goto error;
}
break;
case 'n':
|
3e429f5c |
children_no=strtol(optarg, &tmp, 10);
if ((tmp==0) ||(*tmp)){
|
36ef0329 |
fprintf(stderr, "bad process number: -n %s\n",
optarg);
|
1b1b19d8 |
goto error;
}
break;
case 'v':
check_via=1;
break;
case 'r':
received_dns|=DO_DNS;
break;
case 'R':
received_dns|=DO_REV_DNS;
case 'd':
debug++;
break;
case 'D':
dont_fork=1;
break;
case 'E':
log_stderr=1;
break;
case 'V':
printf("version: %s\n", version);
|
726efa25 |
printf("flags: %s\n", flags );
|
af6fb476 |
print_ct_constants();
|
3e429f5c |
printf("%s\n",id);
|
e22bbdb8 |
printf("%s compiled on %s with %s\n", __FILE__,
compiled, COMPILER );
|
b2dec9c6 |
|
1b1b19d8 |
exit(0);
break;
case 'h':
printf("version: %s\n", version);
printf("%s",help_msg);
exit(0);
break;
|
c9ca45b3 |
case 'w':
working_dir=optarg;
break;
case 't':
chroot_dir=optarg;
break;
case 'u':
|
054cb6cf |
user=optarg;
|
c9ca45b3 |
break;
case 'g':
|
054cb6cf |
group=optarg;
|
c9ca45b3 |
break;
|
b2934963 |
case 'P':
pid_file=optarg;
break;
|
97f17e60 |
case 'i':
fifo=optarg;
break;
|
1b1b19d8 |
case '?':
if (isprint(optopt))
|
675b7412 |
fprintf(stderr, "Unknown option `-%c�.\n", optopt);
|
1b1b19d8 |
else
fprintf(stderr,
"Unknown option character `\\x%x�.\n",
optopt);
goto error;
case ':':
fprintf(stderr,
"Option `-%c� requires an argument.\n",
optopt);
goto error;
default:
abort();
}
}
/* fill missing arguments with the default values*/
if (cfg_file==0) cfg_file=CFG_FILE;
|
7268726e |
/* load config file or die */
cfg_stream=fopen (cfg_file, "r");
if (cfg_stream==0){
fprintf(stderr, "ERROR: loading config file(%s): %s\n", cfg_file,
strerror(errno));
goto error;
}
|
e8e9c7a9 |
|
93358a54 |
|
97f17e60 |
init_hfname_parser();
|
335d097b |
init_digest_parser();
|
40a8d9dd |
|
9df1213c |
/* init hash fucntion */
if (init_hash()<0) {
LOG(L_ERR, "ERROR: init_hash failed\n");
goto error;
}
|
e8e9c7a9 |
/*init mallocs (before parsing cfg !)*/
|
dda9dab1 |
if (init_mallocs()==-1)
|
e8e9c7a9 |
goto error;
|
d4f2d8b0 |
/*init timer, before parsing the cfg!*/
if (init_timer()<0){
LOG(L_CRIT, "could not initialize timer, exiting...\n");
goto error;
}
|
e8e9c7a9 |
|
caf80ae6 |
/* register a diagnostic FIFO command */
|
90b0b10d |
if (register_core_fifo()<0) {
LOG(L_CRIT, "unable to register core FIFO commands\n");
|
caf80ae6 |
goto error;
}
|
c0b1bfb5 |
|
ad79ca94 |
/*register builtin modules*/
register_builtin_modules();
|
404073d3 |
|
7268726e |
yyin=cfg_stream;
if ((yyparse()!=0)||(cfg_errors)){
fprintf(stderr, "ERROR: bad config file (%d errors)\n", cfg_errors);
goto error;
}
|
16181f18 |
|
2f781952 |
|
ad79ca94 |
|
7268726e |
print_rl();
/* fix parameters */
|
cc2199a9 |
if (port_no<=0) port_no=SIP_PORT;
|
b2e71d5b |
|
cc2199a9 |
if (children_no<=0) children_no=CHILD_NO;
|
caf80ae6 |
#ifdef _OBSOLETED
|
4bd1673d |
else if (children_no >= MAX_PROCESSES ) {
|
c4217e61 |
fprintf(stderr, "ERROR: too many children processes configured;"
" maximum is %d\n",
|
4bd1673d |
MAX_PROCESSES-1 );
goto error;
}
|
caf80ae6 |
#endif
|
c9ca45b3 |
if (working_dir==0) working_dir="/";
|
054cb6cf |
/* get uid/gid */
if (user){
uid=strtol(user, &tmp, 10);
if ((tmp==0) ||(*tmp)){
/* maybe it's a string */
pw_entry=getpwnam(user);
if (pw_entry==0){
fprintf(stderr, "bad user name/uid number: -u %s\n", user);
goto error;
}
uid=pw_entry->pw_uid;
gid=pw_entry->pw_gid;
}
}
if (group){
gid=strtol(user, &tmp, 10);
if ((tmp==0) ||(*tmp)){
/* maybe it's a string */
gr_entry=getgrnam(group);
if (gr_entry==0){
fprintf(stderr, "bad group name/gid number: -u %s\n", group);
goto error;
}
gid=gr_entry->gr_gid;
}
}
|
cbd9fc8b |
|
36ef0329 |
if (sock_no==0) {
|
57e2cd15 |
/* try to get all listening ipv4 interfaces */
if (add_interfaces(0, AF_INET, 0)==-1){
/* if error fall back to get hostname*/
/* get our address, only the first one */
if (uname (&myname) <0){
fprintf(stderr, "cannot determine hostname, try -l address\n");
goto error;
}
sock_info[sock_no].name.s=(char*)malloc(strlen(myname.nodename)+1);
if (sock_info[sock_no].name.s==0){
fprintf(stderr, "Out of memory.\n");
goto error;
}
sock_info[sock_no].name.len=strlen(myname.nodename);
strncpy(sock_info[sock_no].name.s, myname.nodename,
sock_info[sock_no].name.len+1);
sock_no++;
|
1b1b19d8 |
}
}
|
5b253cc6 |
|
57e2cd15 |
/* try to change all the interface names into addresses
* --ugly hack */
for (r=0; r<sock_no;){
if (add_interfaces(sock_info[r].name.s, AF_INET,
sock_info[r].port_no)!=-1){
/* success => remove current entry (shift the entire array)*/
free(sock_info[r].name.s);
memmove(&sock_info[r], &sock_info[r+1],
(sock_no-r)*sizeof(struct socket_info));
sock_no--;
continue;
}
r++;
}
|
36ef0329 |
/* get ips & fill the port numbers*/
|
0bafb279 |
#ifdef EXTRA_DEBUG
|
57e2cd15 |
printf("Listening on \n");
|
0bafb279 |
#endif
|
36ef0329 |
for (r=0; r<sock_no;r++){
he=resolvehost(sock_info[r].name.s);
|
1b1b19d8 |
if (he==0){
|
36ef0329 |
DPrint("ERROR: could not resolve %s\n", sock_info[r].name.s);
|
1b1b19d8 |
goto error;
}
|
e278821b |
/* check if we got the official name */
if (strcasecmp(he->h_name, sock_info[r].name.s)!=0){
if (add_alias(sock_info[r].name.s, sock_info[r].name.len)<0){
LOG(L_ERR, "ERROR: main: add_alias failed\n");
}
/* change the oficial name */
free(sock_info[r].name.s);
sock_info[r].name.s=(char*)malloc(strlen(he->h_name)+1);
if (sock_info[r].name.s==0){
fprintf(stderr, "Out of memory.\n");
goto error;
}
sock_info[r].name.len=strlen(he->h_name);
strncpy(sock_info[r].name.s, he->h_name, sock_info[r].name.len+1);
}
/* add the aliases*/
for(h=he->h_aliases; h && *h; h++)
if (add_alias(*h, strlen(*h))<0){
LOG(L_ERR, "ERROR: main: add_alias failed\n");
}
|
f41ab77e |
hostent2ip_addr(&sock_info[r].address, he, 0); /*convert to ip_addr
format*/
|
57e2cd15 |
if ((tmp=ip_addr2a(&sock_info[r].address))==0) goto error;
|
36ef0329 |
sock_info[r].address_str.s=(char*)malloc(strlen(tmp)+1);
if (sock_info[r].address_str.s==0){
fprintf(stderr, "Out of memory.\n");
goto error;
}
strncpy(sock_info[r].address_str.s, tmp, strlen(tmp)+1);
|
855c2e68 |
/* set is_ip (1 if name is an ip address, 0 otherwise) */
|
36ef0329 |
sock_info[r].address_str.len=strlen(tmp);
|
855c2e68 |
if ( (sock_info[r].address_str.len==sock_info[r].name.len)&&
(strncasecmp(sock_info[r].address_str.s, sock_info[r].name.s,
sock_info[r].address_str.len)==0)
) sock_info[r].is_ip=1;
else sock_info[r].is_ip=0;
|
36ef0329 |
if (sock_info[r].port_no==0) sock_info[r].port_no=port_no;
port_no_str_len=snprintf(port_no_str, MAX_PORT_LEN, ":%d",
(unsigned short) sock_info[r].port_no);
if (port_no_str_len<0){
fprintf(stderr, "ERROR: bad port number: %d\n",
sock_info[r].port_no);
goto error;
}
|
6e94f57f |
/* on some systems snprintf returns really strange things if it does
not have enough space */
|
36ef0329 |
port_no_str_len=
(port_no_str_len<MAX_PORT_LEN)?port_no_str_len:MAX_PORT_LEN;
sock_info[r].port_no_str.s=(char*)malloc(strlen(port_no_str)+1);
if (sock_info[r].port_no_str.s==0){
fprintf(stderr, "Out of memory.\n");
goto error;
}
strncpy(sock_info[r].port_no_str.s, port_no_str, strlen(port_no_str)+1);
sock_info[r].port_no_str.len=strlen(port_no_str);
|
0bafb279 |
#ifdef EXTRA_DEBUG
|
054cb6cf |
printf(" %.*s [%s]:%s\n", sock_info[r].name.len,
sock_info[r].name.s,
|
57e2cd15 |
sock_info[r].address_str.s, sock_info[r].port_no_str.s);
|
0bafb279 |
#endif
|
57e2cd15 |
}
/* removing duplicate addresses*/
for (r=0; r<sock_no; r++){
for (t=r+1; t<sock_no;){
if ((sock_info[r].port_no==sock_info[t].port_no) &&
(sock_info[r].address.af==sock_info[t].address.af) &&
(memcmp(sock_info[r].address.u.addr,
sock_info[t].address.u.addr,
sock_info[r].address.len) == 0)
){
|
0bafb279 |
#ifdef EXTRA_DEBUG
|
57e2cd15 |
printf("removing duplicate (%d) %s [%s] == (%d) %s [%s]\n",
r, sock_info[r].name.s, sock_info[r].address_str.s,
t, sock_info[t].name.s, sock_info[t].address_str.s);
|
0bafb279 |
#endif
|
57e2cd15 |
/* add the name to the alias list*/
if ((!sock_info[t].is_ip) && (
(sock_info[t].name.len!=sock_info[r].name.len)||
(strncmp(sock_info[t].name.s, sock_info[r].name.s,
sock_info[r].name.len)!=0))
)
add_alias(sock_info[t].name.s, sock_info[t].name.len);
/* free space*/
free(sock_info[t].name.s);
free(sock_info[t].address_str.s);
free(sock_info[t].port_no_str.s);
/* shift the array*/
memmove(&sock_info[t], &sock_info[t+1],
(sock_no-t)*sizeof(struct socket_info));
sock_no--;
continue;
}
t++;
}
|
e60a9728 |
}
|
57e2cd15 |
/* print all the listen addresses */
printf("Listening on \n");
for (r=0; r<sock_no; r++)
printf(" %s [%s]:%s\n",sock_info[r].name.s,
sock_info[r].address_str.s, sock_info[r].port_no_str.s);
|
e278821b |
printf("Aliases: ");
for(a=aliases; a; a=a->next) printf("%.*s ", a->alias.len, a->alias.s);
printf("\n");
|
0df81fe8 |
if (sock_no==0){
fprintf(stderr, "ERROR: no listening sockets");
goto error;
}
if (dont_fork){
fprintf(stderr, "WARNING: no fork mode %s\n",
|
e3fc93f4 |
(sock_no>1)?" and more than one listen address found (will"
" use only the the first one)":"");
|
0df81fe8 |
}
|
ed2b50d3 |
/* init_daemon? */
if (!dont_fork){
if ( daemonize(argv[0]) <0 ) goto error;
}
if (init_modules() != 0) {
fprintf(stderr, "ERROR: error while initializing modules\n");
goto error;
}
|
0df81fe8 |
/*alloc pids*/
#ifdef SHM_MEM
|
f51155cf |
pt=shm_malloc(sizeof(struct process_table)*process_count());
|
0df81fe8 |
#else
|
f51155cf |
pt=malloc(sizeof(struct process_table)*process_count());
|
0df81fe8 |
#endif
|
f51155cf |
if (pt==0){
|
0df81fe8 |
fprintf(stderr, "ERROR: out of memory\n");
goto error;
}
|
f51155cf |
memset(pt, 0, sizeof(struct process_table)*process_count());
|
6bb03a39 |
/* fix routing lists */
if ( (r=fix_rls())!=0){
fprintf(stderr, "ERROR: error %x while trying to fix configuration\n",
r);
goto error;
};
|
22d4aa5d |
|
2f781952 |
#ifdef STATS
if (init_stats( dont_fork ? 1 : children_no )==-1) goto error;
#endif
|
3db079b5 |
ret=main_loop();
/*kill everything*/
kill(0, SIGTERM);
return ret;
|
512dcd98 |
error:
|
3db079b5 |
/*kill everything*/
kill(0, SIGTERM);
|
512dcd98 |
return -1;
}
|
dda9dab1 |
|