512dcd98 |
/*
* $Id$
*/
#include <stdio.h>
|
3e429f5c |
#include <stdlib.h>
|
512dcd98 |
#include <errno.h>
|
3e429f5c |
#include <ctype.h>
|
512dcd98 |
#include <string.h>
|
e60a9728 |
#include <netdb.h>
|
1b1b19d8 |
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/utsname.h>
|
512dcd98 |
|
e60a9728 |
#include "config.h"
|
512dcd98 |
#include "dprint.h"
#include "route.h"
|
e60a9728 |
#include "udp_server.h"
|
1b1b19d8 |
#include "globals.h"
static char id[]="@(#) $Id$";
|
3e429f5c |
static char version[]="sip_router 0.5";
|
1b1b19d8 |
static char help_msg[]= "\
Usage: sip_router -l address [-l address] [options]\n\
Options:\n\
-f file Configuration file (default " CFG_FILE ")\n\
-p port Listen on the specified port (default: 5060)\n\
-l address Listen on the specified address (multiple -l mean\n\
listening on more addresses). The default behaviour\n\
is to listen on the addresses returned by uname(2)\n\
\n\
-n processes Number of child processes to fork per interface\n\
(default: 8)\n\
\n\
-r Use dns to check if is necessary to add a \"received=\"\n\
field to a via\n\
-R Same as `-r� but use reverse dns;\n\
(to use both use `-rR�)\n\
\n\
-v Turn on \"via:\" host checking when forwarding replies\n\
-d Debugging mode (multiple -d increase the level)\n\
-D Do not fork into daemon mode\n\
-E Log to stderr\n\
-V Version number\n\
-h This help message\n\
";
|
512dcd98 |
|
888ca09d |
/* debuging function */
|
e60a9728 |
/*
|
888ca09d |
void receive_stdin_loop()
{
#define BSIZE 1024
char buf[BSIZE+1];
int len;
while(1){
len=fread(buf,1,BSIZE,stdin);
buf[len+1]=0;
receive_msg(buf, len);
printf("-------------------------\n");
}
}
|
e60a9728 |
*/
|
888ca09d |
|
1b1b19d8 |
/* global vars */
char* cfg_file = 0;
unsigned short port_no = 0; /* port on which we listen */
|
cc2199a9 |
int children_no = 0; /* number of children processing requests */
|
1b1b19d8 |
int debug = 0;
int dont_fork = 0;
int log_stderr = 0;
int check_via = 0; /* check if reply first via host==us */
int received_dns = 0; /* use dns and/or rdns or to see if we need to
add a ;received=x.x.x.x to via: */
char* names[MAX_LISTEN]; /* our names */
unsigned long addresses[MAX_LISTEN]; /* our ips */
int addresses_no=0; /* number of names/ips */
|
cc2199a9 |
/* ipc related globals */
int process_no = 0;
#ifdef ROUTE_SRV
#endif
|
888ca09d |
|
cc2199a9 |
#define MAX_FD 32 /* maximum number of inherited open file descriptors,
(normally it shouldn't be bigger than 3) */
|
3e429f5c |
extern FILE* yyin;
extern int yyparse();
|
cc2199a9 |
/* daemon init, return 0 on success, -1 on error */
int daemonize(char* name)
{
pid_t pid;
int r;
if (log_stderr==0)
openlog(name, LOG_PID, LOG_DAEMON); /* LOG_CONS, LOG_PERRROR ? */
if (chdir("/")<0){
LOG(L_CRIT,"cannot chroot:%s\n", strerror(errno));
goto error;
}
/* fork to become!= group leader*/
if ((pid=fork())<0){
LOG(L_CRIT, "Cannot fork:%s\n", strerror(errno));
goto error;
}
if (pid!=0){
/* parent process => exit*/
exit(0);
}
/* become session leader to drop the ctrl. terminal */
if (setsid()<0){
LOG(L_WARN, "setsid failed: %s\n",strerror(errno));
}
/* fork again to drop group leadership */
if ((pid=fork())<0){
LOG(L_CRIT, "Cannot fork:%s\n", strerror(errno));
goto error;
}
if (pid!=0){
/*parent process => exit */
exit(0);
}
/* close any open file descriptors */
for (r=0;r<MAX_FD; r++){
if ((r==3) && log_stderr) continue;
close(r);
}
return 0;
error:
return -1;
}
/* main loop */
int main_loop()
{
int r, i;
pid_t pid;
/* one "main" process and n children handling i/o */
if (dont_fork){
/* only one address */
if (udp_init(addresses[0],port_no)==-1) goto error;
/* receive loop */
udp_rcv_loop();
}else{
for(r=0;r<addresses_no;r++){
for(i=0;i<children_no;i++){
if ((pid=fork())<0){
LOG(L_CRIT, "main_loop: Cannot fork\n");
goto error;
}
if (pid==0){
/* child */
if (udp_init(addresses[r], port_no)==-1) goto error;
return udp_rcv_loop();
}
}
}
}
for(;;){
/* debug: instead of select */
sleep(1);
}
return 0;
error:
return -1;
}
|
512dcd98 |
int main(int argc, char** argv)
{
FILE* cfg_stream;
|
e60a9728 |
struct hostent* he;
|
1b1b19d8 |
int c,r;
char *tmp;
struct utsname myname;
|
512dcd98 |
/* process command line (get port no, cfg. file path etc) */
|
1b1b19d8 |
opterr=0;
while((c=getopt(argc,argv,"f:p:l:n:rRvdDEVh"))!=-1){
switch(c){
case 'f':
cfg_file=optarg;
break;
case 'p':
port_no=strtol(optarg, &tmp, 10);
if (tmp &&(*tmp)){
fprintf(stderr, "bad port number: -p %s\n", optarg);
goto error;
}
break;
case 'l':
/* add a new addr. to out address list */
if (addresses_no < MAX_LISTEN){
names[addresses_no]=(char*)malloc(strlen(optarg)+1);
if (names[addresses_no]==0){
fprintf(stderr, "Out of memory.\n");
goto error;
}
strncpy(names[addresses_no], optarg, strlen(optarg)+1);
addresses_no++;
}else{
fprintf(stderr,
"Too many addresses (max. %d).\n",
MAX_LISTEN);
goto error;
}
break;
case 'n':
|
3e429f5c |
children_no=strtol(optarg, &tmp, 10);
if ((tmp==0) ||(*tmp)){
|
1b1b19d8 |
fprintf(stderr, "bad process number: -n %s\n", optarg);
goto error;
}
break;
case 'v':
check_via=1;
break;
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);
|
3e429f5c |
printf("%s\n",id);
|
1b1b19d8 |
exit(0);
break;
case 'h':
printf("version: %s\n", version);
printf("%s",help_msg);
exit(0);
break;
case '?':
if (isprint(optopt))
fprintf(stderr, "Unknown option `-%c'.\n", optopt);
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;
|
cc2199a9 |
if (port_no<=0) port_no=SIP_PORT;
if (children_no<=0) children_no=CHILD_NO;
|
1b1b19d8 |
if (addresses_no==0) {
/* get our address, only the first one */
if (uname (&myname) <0){
fprintf(stderr, "cannot determine hostname, try -l address\n");
goto error;
}
names[addresses_no]=(char*)malloc(strlen(myname.nodename)+1);
if (names[addresses_no]==0){
fprintf(stderr, "Out of memory.\n");
goto error;
}
strncpy(names[addresses_no], myname.nodename,
strlen(myname.nodename)+1);
addresses_no++;
}
/* get ips */
printf("Listening on ");
for (r=0; r<addresses_no;r++){
he=gethostbyname(names[r]);
if (he==0){
DPrint("ERROR: could not resolve %s\n", names[r]);
goto error;
}
addresses[r]=*((long*)he->h_addr_list[0]);
printf("%s [%s] : %d\n",names[r],
inet_ntoa(*(struct in_addr*)&addresses[r]),
(unsigned short)port_no);
|
e60a9728 |
}
|
512dcd98 |
/* load config file or die */
cfg_stream=fopen (cfg_file, "r");
if (cfg_stream==0){
|
efeaaf53 |
fprintf(stderr, "ERROR: loading config file(%s): %s\n", cfg_file,
|
1b1b19d8 |
strerror(errno));
|
512dcd98 |
goto error;
}
|
3e429f5c |
yyin=cfg_stream;
if (yyparse()!=0){
|
efeaaf53 |
fprintf(stderr, "ERROR: config parser failure\n");
|
512dcd98 |
goto error;
}
|
3e429f5c |
|
512dcd98 |
print_rl();
|
e60a9728 |
/* init_daemon? */
|
cc2199a9 |
if (!dont_fork){
if ( daemonize(argv[0]) <0 ) goto error;
}
return main_loop();
|
888ca09d |
|
512dcd98 |
error:
return -1;
}
|