Procházet zdrojové kódy

- made ipv4<->ipv6 possible
- added different port numbers (eg. ser -l foo -p 1234 -l bar -p 4321 )
- small signal fixes (sigterm to evrybody on exit, exit if 1 child dies a.s.o)

Andrei Pelinescu-Onciul před 23 roky
rodič
revize
36ef03290c
15 změnil soubory, kde provedl 334 přidání a 187 odebrání
  1. 1 1
      Makefile.defs
  2. 8 2
      action.c
  3. 14 14
      cfg.lex
  4. 28 17
      cfg.y
  5. 0 1
      config.h
  6. 67 19
      forward.c
  7. 2 0
      forward.h
  8. 14 2
      globals.h
  9. 21 8
      ip_addr.h
  10. 123 90
      main.c
  11. 26 10
      msg_translator.c
  12. 3 2
      msg_translator.h
  13. 1 1
      receive.c
  14. 23 16
      udp_server.c
  15. 3 4
      udp_server.h

+ 1 - 1
Makefile.defs

@@ -8,7 +8,7 @@
 VERSION = 0
 PATCHLEVEL = 8
 SUBLEVEL = 8
-EXTRAVERSION = -1-ipv6
+EXTRAVERSION = -2-ipv6
 
 RELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 OS = $(shell uname -s)

+ 8 - 2
action.c

@@ -38,6 +38,7 @@ int do_action(struct action* a, struct sip_msg* msg)
 	int ret;
 	int v;
 	union sockaddr_union* to;
+	struct socket_info* send_sock;
 	struct proxy_l* p;
 	char* tmp;
 	char *new_uri, *end, *crt;
@@ -144,8 +145,13 @@ int do_action(struct action* a, struct sip_msg* msg)
 			if (ret==0){
 				p->tx++;
 				p->tx_bytes+=msg->len;
-				ret=udp_send(msg->orig, msg->len, to,
-								sizeof(union sockaddr_union));
+				send_sock=get_send_socket(to);
+				if (send_sock!=0){
+					ret=udp_send(send_sock, msg->orig, msg->len, to,
+									sizeof(union sockaddr_union));
+				}else{
+					ret=-1;
+				}
 			}
 			free(to);
 			if (ret<0){

+ 14 - 14
cfg.lex

@@ -25,7 +25,7 @@
 	
 	static int comment_nest=0;
 	static int state=0;
-	static char* str=0;
+	static char* tstr=0;
 	int line=1;
 	int column=1;
 	int startcolumn=1;
@@ -219,29 +219,29 @@ EAT_ABLE	[\ \t\b\r]
 
 <STRING1>{QUOTES} { count(); state=INITIAL_S; BEGIN(INITIAL); 
 						yytext[yyleng-1]=0; yyleng--;
-						addstr(yytext, &str);
-						yylval.strval=str; str=0;
+						addstr(yytext, &tstr);
+						yylval.strval=tstr; tstr=0;
 						return STRING;
 					}
 <STRING2>{TICK}  { count(); state=INITIAL_S; BEGIN(INITIAL); 
 						yytext[yyleng-1]=0; yyleng--;
-						addstr(yytext, &str);
-						yylval.strval=str;
-						str=0;
+						addstr(yytext, &tstr);
+						yylval.strval=tstr;
+						tstr=0;
 						return STRING;
 					}
 <STRING2>.|{EAT_ABLE}|{CR}	{ yymore(); }
 
 <STRING1>\\n		{ count(); yytext[yyleng-2]='\n';yytext[yyleng-1]=0; 
-						yyleng--; addstr(yytext, &str); }
+						yyleng--; addstr(yytext, &tstr); }
 <STRING1>\\r		{ count(); yytext[yyleng-2]='\r';yytext[yyleng-1]=0; 
-						yyleng--; addstr(yytext, &str); }
+						yyleng--; addstr(yytext, &tstr); }
 <STRING1>\\a		{ count(); yytext[yyleng-2]='\a';yytext[yyleng-1]=0; 
-						yyleng--; addstr(yytext, &str); }
+						yyleng--; addstr(yytext, &tstr); }
 <STRING1>\\t		{ count(); yytext[yyleng-2]='\t';yytext[yyleng-1]=0; 
-						yyleng--; addstr(yytext, &str); }
+						yyleng--; addstr(yytext, &tstr); }
 <STRING1>\\\\		{ count(); yytext[yyleng-2]='\\';yytext[yyleng-1]=0; 
-						yyleng--; addstr(yytext, &str); } 
+						yyleng--; addstr(yytext, &tstr); } 
 <STRING1>.|{EAT_ABLE}|{CR}	{ yymore(); }
 
 
@@ -257,8 +257,8 @@ EAT_ABLE	[\ \t\b\r]
 
 <INITIAL>{COM_LINE}.*{CR}	{ count(); } 
 
-<INITIAL>{ID}			{ count(); addstr(yytext, &str);
-						  yylval.strval=str; str=0; return ID; }
+<INITIAL>{ID}			{ count(); addstr(yytext, &tstr);
+						  yylval.strval=tstr; tstr=0; return ID; }
 
 
 <<EOF>>							{
@@ -266,7 +266,7 @@ EAT_ABLE	[\ \t\b\r]
 										case STRING_S: 
 											LOG(L_CRIT, "ERROR: cfg. parser: unexpected EOF in"
 														" unclosed string\n");
-											if (str) {free(str); str=0;}
+											if (tstr) {free(tstr); tstr=0;}
 											break;
 										case COMMENT_S:
 											LOG(L_CRIT, "ERROR: cfg. parser: unexpected EOF:"

+ 28 - 17
cfg.y

@@ -164,7 +164,10 @@ assign_stm:	DEBUG EQUAL NUMBER { debug=$3; }
 		| DNS EQUAL error { yyerror("boolean value expected"); }
 		| REV_DNS EQUAL NUMBER { received_dns|= ($3)?DO_REV_DNS:0; }
 		| REV_DNS EQUAL error { yyerror("boolean value expected"); }
-		| PORT EQUAL NUMBER   { port_no=$3; }
+		| PORT EQUAL NUMBER   { port_no=$3; 
+								if (sock_no>0) 
+									sock_info[sock_no-1].port_no=port_no;
+							  }
 		| STAT EQUAL STRING {
 					#ifdef STATS
 							stat_file=$3;
@@ -180,7 +183,7 @@ assign_stm:	DEBUG EQUAL NUMBER { debug=$3; }
 		| LOOP_CHECKS EQUAL NUMBER { loop_checks=$3; }
 		| LOOP_CHECKS EQUAL error { yyerror("boolean value expected"); }
 		| LISTEN EQUAL ip  {
-								if (addresses_no < MAX_LISTEN){
+								if (sock_no< MAX_LISTEN){
 									tmp=ip_addr2a($3);
 								/*	tmp=inet_ntoa(*(struct in_addr*)&$3);*/
 									if (tmp==0){
@@ -188,15 +191,19 @@ assign_stm:	DEBUG EQUAL NUMBER { debug=$3; }
 											" bad ip address: %s\n",
 											strerror(errno));
 									}else{
-										names[addresses_no]=
+										sock_info[sock_no].name.s=
 												(char*)malloc(strlen(tmp)+1);
-										if (names[addresses_no]==0){
+										if (sock_info[sock_no].name.s==0){
 											LOG(L_CRIT, "ERROR: cfg. parser: "
 														"out of memory.\n");
 										}else{
-											strncpy(names[addresses_no], tmp,
-													strlen(tmp)+1);
-											addresses_no++;
+											strncpy(sock_info[sock_no].name.s,
+													tmp, strlen(tmp)+1);
+											sock_info[sock_no].name.len=
+													strlen(tmp);
+											sock_info[sock_no].port_no=
+													port_no;
+											sock_no++;
 										}
 									}
 								}else{
@@ -206,16 +213,18 @@ assign_stm:	DEBUG EQUAL NUMBER { debug=$3; }
 								}
 							  }
 		| LISTEN EQUAL ID	 {
-								if (addresses_no < MAX_LISTEN){
-									names[addresses_no]=
+								if (sock_no < MAX_LISTEN){
+									sock_info[sock_no].name.s=
 												(char*)malloc(strlen($3)+1);
-									if (names[addresses_no]==0){
+									if (sock_info[sock_no].name.s==0){
 										LOG(L_CRIT, "ERROR: cfg. parser:"
 														" out of memory.\n");
 									}else{
-										strncpy(names[addresses_no], $3,
+										strncpy(sock_info[sock_no].name.s, $3,
 													strlen($3)+1);
-										addresses_no++;
+										sock_info[sock_no].name.len=strlen($3);
+										sock_info[sock_no].port_no= port_no;
+										sock_no++;
 									}
 								}else{
 									LOG(L_CRIT, "ERROR: cfg. parser: "
@@ -224,16 +233,18 @@ assign_stm:	DEBUG EQUAL NUMBER { debug=$3; }
 								}
 							  }
 		| LISTEN EQUAL STRING {
-								if (addresses_no < MAX_LISTEN){
-									names[addresses_no]=
+								if (sock_no < MAX_LISTEN){
+									sock_info[sock_no].name.s=
 										(char*)malloc(strlen($3)+1);
-									if (names[addresses_no]==0){
+									if (sock_info[sock_no].name.s==0){
 										LOG(L_CRIT, "ERROR: cfg. parser:"
 													" out of memory.\n");
 									}else{
-										strncpy(names[addresses_no], $3,
+										strncpy(sock_info[sock_no].name.s, $3,
 												strlen($3)+1);
-										addresses_no++;
+										sock_info[sock_no].name.len=strlen($3);
+										sock_info[sock_no].port_no=port_no;
+										sock_no++;
 									}
 								}else{
 									LOG(L_CRIT, "ERROR: cfg. parser: "

+ 0 - 1
config.h

@@ -64,7 +64,6 @@
 #define SHM_MEM_SIZE 128 
 
 #define TIMER_TICK 1
-#define LONG_SLEEP	3600
 
 /* dimensioning buckets in q_malloc */
 /* size of the size2bucket table; everything beyond that asks for

+ 67 - 19
forward.c

@@ -34,29 +34,50 @@
 
 
 
+/* returns a socket_info pointer to the sending socket or 0 on error
+ * params: destination socke_union pointer
+ */
+struct socket_info* get_send_socket(union sockaddr_union* to)
+{
+	struct socket_info* send_sock;
+	
+	send_sock=0;
+	/* check if we need to change the socket (different address families -
+	 * eg: ipv4 -> ipv6 or ipv6 -> ipv4) */
+	if (to->s.sa_family!=bind_address->address.af){
+		switch(to->s.sa_family){
+			case AF_INET:	send_sock=sendipv4;
+							break;
+#ifdef USE_IPV6
+			case AF_INET6:	send_sock=sendipv6;
+							break;
+#endif
+			default:		LOG(L_ERR, "get_send_socket: BUG: don't know how"
+									" to forward to af %d\n", to->s.sa_family);
+		}
+	}else send_sock=bind_address;
+	return send_sock;
+}
+
+
+
 int forward_request( struct sip_msg* msg, struct proxy_l * p)
 {
 	unsigned int len;
 	char* buf;
 	union sockaddr_union* to;
-
+	struct socket_info* send_sock;
+	
 	to=0;
-	buf = build_req_buf_from_sip_req( msg, &len);
-	if (!buf){
-		LOG(L_ERR, "ERROR: forward_reply: building failed\n");
-		goto error;
-	}
-
+	buf=0;
+	
 	to=(union sockaddr_union*)malloc(sizeof(union sockaddr_union));
 	if (to==0){
 		LOG(L_ERR, "ERROR: forward_request: out of memory\n");
 		goto error;
 	}
-
-	 /* send it! */
-	DBG("Sending:\n%s.\n", buf);
-	DBG("orig. len=%d, new_len=%d\n", msg->len, len );
-
+	
+	
 	/* if error try next ip address if possible */
 	if (p->ok==0){
 		if (p->host.h_addr_list[p->addr_idx+1])
@@ -64,13 +85,31 @@ int forward_request( struct sip_msg* msg, struct proxy_l * p)
 		else p->addr_idx=0;
 		p->ok=1;
 	}
-
+	
 	hostent2su(to, &p->host, p->addr_idx, 
 				(p->port)?htons(p->port):htons(SIP_PORT));
 	p->tx++;
 	p->tx_bytes+=len;
+	
 
-	if (udp_send( buf, len,  to, sizeof(union sockaddr_union))==-1){
+	send_sock=get_send_socket(to);
+	if (send_sock==0){
+		LOG(L_ERR, "forward_req: ERROR: cannot forward to af %d "
+				"no coresponding listening socket\n", to->s.sa_family);
+		goto error;
+	}
+	
+	buf = build_req_buf_from_sip_req( msg, &len, send_sock);
+	if (!buf){
+		LOG(L_ERR, "ERROR: forward_reply: building failed\n");
+		goto error;
+	}
+	 /* send it! */
+	DBG("Sending:\n%s.\n", buf);
+	DBG("orig. len=%d, new_len=%d\n", msg->len, len );
+	
+	if (udp_send( send_sock, buf, len,  to, 
+							sizeof(union sockaddr_union))==-1){
 			p->errors++;
 			p->ok=0;
 			STATS_TX_DROPS;
@@ -145,6 +184,7 @@ int forward_reply(struct sip_msg* msg)
 	int  r;
 	char* new_buf;
 	union sockaddr_union* to;
+	struct socket_info* send_sock;
 	unsigned int new_len;
 	struct sr_module *mod;
 	
@@ -152,11 +192,14 @@ int forward_reply(struct sip_msg* msg)
 	new_buf=0;
 	/*check if first via host = us */
 	if (check_via){
-		for (r=0; r<addresses_no; r++)
-			if(strcmp(msg->via1->host.s, names[r])==0) break;
-		if (r==addresses_no){
+		for (r=0; r<sock_no; r++)
+			if ( (msg->via1->host.len==sock_info[r].name.len) && 
+					(memcmp(msg->via1->host.s, sock_info[r].name.s, 
+										sock_info[r].name.len)==0) )
+				break;
+		if (r==sock_no){
 			LOG(L_NOTICE, "ERROR: forward_reply: host in first via!=me :"
-					" %s\n", msg->via1->host.s);
+					" %.*s\n", msg->via1->host.len, msg->via1->host.s);
 			/* send error msg back? */
 			goto error;
 		}
@@ -192,8 +235,13 @@ int forward_reply(struct sip_msg* msg)
 	}
 
 	if (update_sock_struct_from_via( to, msg->via2 )==-1) goto error;
+	send_sock=get_send_socket(to);
+	if (send_sock==0){
+		LOG(L_ERR, "forward_reply: ERROR: no sending socket found\n");
+		goto error;
+	}
 
-	if (udp_send(new_buf,new_len,  to,
+	if (udp_send(send_sock, new_buf,new_len,  to,
 				sizeof(union sockaddr_union))==-1)
 	{
 		STATS_TX_DROPS;

+ 2 - 0
forward.h

@@ -9,8 +9,10 @@
 #include "parser/msg_parser.h"
 #include "route.h"
 #include "proxy.h"
+#include "ip_addr.h"
 
 
+struct socket_info* get_send_socket(union sockaddr_union* su);
 int forward_request( struct sip_msg* msg,  struct proxy_l* p);
 int update_sock_struct_from_via( union sockaddr_union* to,
 								struct via_body* via );

+ 14 - 2
globals.h

@@ -11,23 +11,35 @@
 
 #include "types.h"
 #include "ip_addr.h"
+#include "str.h"
 
 #define NO_DNS     0
 #define DO_DNS     1
 #define DO_REV_DNS 2
 
 
+
 extern char * cfg_file;
 extern char *stat_file;
+extern struct socket_info sock_info[]; /* all addresses we listen/send from*/
+extern int sock_no; /* number of addresses/open sockets*/
 extern unsigned short port_no;
+/*
 extern char port_no_str[];
 extern int port_no_str_len;
-extern unsigned int maxbuffer;
+*/
+/*
 extern char * names[];
 extern int names_len[];
 extern struct ip_addr addresses[];
 extern int addresses_no;
-extern struct ip_addr* bind_address;
+*/
+extern struct socket_info* bind_address; /* pointer to the crt. proc. listening address */
+extern int bind_idx; /* same as above but index in the bound[] array */
+extern struct socket_info* sendipv4; /* ipv4 socket to use when msg. comes from ipv6*/
+extern struct socket_info* sendipv6; /* same as above for ipv6 */
+
+extern unsigned int maxbuffer;
 extern int children_no;
 extern int dont_fork;
 extern int check_via;

+ 21 - 8
ip_addr.h

@@ -9,6 +9,7 @@
 #include <string.h>
 #include <netinet/in.h>
 #include <netdb.h>
+#include "str.h"
 
 #ifdef USE_IPV6
 	#ifdef FreeBSD			/* freebsd is brain damaged and needs a different
@@ -49,6 +50,15 @@ union sockaddr_union{
 };
 
 
+struct socket_info{
+	int socket;
+	str name; /* name - eg.: foo.bar or 10.0.0.1 */
+	struct ip_addr address; /* ip address */
+	str address_str;        /* ip address converted to string -- optimization*/
+	unsigned short port_no;  /* port number */
+	str port_no_str; /* port number converted to string -- optimization*/
+};
+
 
 
 /* inits an ip_addr with the addr. info from a hostent structure
@@ -215,6 +225,7 @@ static inline char* ip_addr2a(struct ip_addr* ip)
 	register unsigned char a,b,c;
 #ifdef USE_IPV6
 	register unsigned char d;
+	register unsigned short hex4;
 #endif
 	int r;
 	#define HEXDIG(x) (((x)>=10)?(x)-10+'A':(x)+'0')
@@ -225,10 +236,11 @@ static inline char* ip_addr2a(struct ip_addr* ip)
 	#ifdef USE_IPV6
 		case AF_INET6:
 			for(r=0;r<7;r++){
-				a=ip->u.addr16[r]>>12;
-				b=(ip->u.addr16[r]>>8)&0xf;
-				c=(ip->u.addr16[r]>>4)&0xf;
-				d=ip->u.addr16[r]&0xf;
+				hex4=ntohs(ip->u.addr16[r]);
+				a=hex4>>12;
+				b=(hex4>>8)&0xf;
+				c=(hex4>>4)&0xf;
+				d=hex4&0xf;
 				if (a){
 					buff[offset]=HEXDIG(a);
 					buff[offset+1]=HEXDIG(b);
@@ -254,10 +266,11 @@ static inline char* ip_addr2a(struct ip_addr* ip)
 				}
 			}
 			/* last int16*/
-			a=ip->u.addr16[r]>>12;
-			b=(ip->u.addr16[r]>>8)&0xf;
-			c=(ip->u.addr16[r]>>4)&0xf;
-			d=ip->u.addr16[r]&0xf;
+			hex4=ntohs(ip->u.addr16[r]);
+			a=hex4>>12;
+			b=(hex4>>8)&0xf;
+			c=(hex4>>4)&0xf;
+			d=hex4&0xf;
 			if (a){
 				buff[offset]=HEXDIG(a);
 				buff[offset+1]=HEXDIG(b);

+ 123 - 90
main.c

@@ -122,11 +122,13 @@ static char flags[]=
 ;
 
 static char help_msg[]= "\
-Usage: " NAME " -l address [-l address] [options]\n\
+Usage: " NAME " -l address [-p port] [-l address [-p port]...] [options]\n\
 Options:\n\
     -c           Perform loop checks and compute branches\n\
     -f file      Configuration file (default " CFG_FILE ")\n\
     -p port      Listen on the specified port (default: 5060)\n\
+                 applies to the last address in -l and to all \n\
+                 following that do not have a corespponding -p\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\
@@ -195,9 +197,6 @@ void receive_stdin_loop()
 /* global vars */
 
 char* cfg_file = 0;
-unsigned short port_no = 0; /* port on which we listen */
-char port_no_str[MAX_PORT_LEN];
-int port_no_str_len=0;
 unsigned int maxbuffer = MAX_RECV_BUFFER_SIZE; /* maximum buffer size we do
 												  not want to exceed durig the
 												  auto-probing procedure; may 
@@ -217,11 +216,20 @@ char* chroot_dir = 0;
 int uid = 0;
 int gid = 0;
 
+#if 0
 char* names[MAX_LISTEN];              /* our names */
 int names_len[MAX_LISTEN];            /* lengths of the names*/
 struct ip_addr addresses[MAX_LISTEN]; /* our ips */
 int addresses_no=0;                   /* number of names/ips */
-struct ip_addr* bind_address;        /* listen address of the crt. process */
+#endif
+struct socket_info sock_info[MAX_LISTEN]; /* all addresses we listen/send from*/
+int sock_no=0; /* number of addresses/open sockets*/
+struct socket_info* bind_address; /* pointer to the crt. proc. listening address */
+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*/
 
 /* ipc related globals */
 int process_no = 0;
@@ -246,7 +254,6 @@ extern int yyparse();
 static int is_main=0; /* flag = is this the  "main" process? */
 
 char* pid_file = 0; /* filename as asked by use */
-char *pid_fn = 0; /* and with port number appended */
 
 /* daemon init, return 0 on success, -1 on error */
 int daemonize(char*  name)
@@ -255,7 +262,6 @@ int daemonize(char*  name)
 	pid_t pid;
 	int r, p;
 
-	int pid_fn_len;
 
 	p=-1;
 
@@ -288,8 +294,7 @@ int daemonize(char*  name)
 	if ((pid=fork())<0){
 		LOG(L_CRIT, "Cannot fork:%s\n", strerror(errno));
 		goto error;
-	}
-	if (pid!=0){
+	}else if (pid!=0){
 		/* parent process => exit*/
 		exit(0);
 	}
@@ -301,49 +306,34 @@ int daemonize(char*  name)
 	if ((pid=fork())<0){
 		LOG(L_CRIT, "Cannot  fork:%s\n", strerror(errno));
 		goto error;
-	}
-	if (pid!=0){
+	}else if (pid!=0){
 		/*parent process => exit */
 		exit(0);
 	}
 
 	/* added by noh: create a pid file for the main process */
 	if (pid_file!=0){
-
-		/* added port number; -jiri */
-		pid_fn_len = strlen(pid_file) + 5 /* long port number */ 
-			+ 1 /* dot */ + 1 /* ZT */ ;
-		pid_fn = malloc( pid_fn_len );
-		if (!pid_fn) {
-			LOG(L_ERR, "ERROR: There is really no memory for ser\n");
-			goto error;
-		}
-		if (snprintf(pid_fn, pid_fn_len, "%s.%d", pid_file, port_no )==-1) {
-			LOG(L_ERR, "ERROR: pidfile printig failed -- perhaps too high port?\n");
-			goto error;
-		}
 		
-			
-		if ((pid_stream=fopen(pid_fn, "r"))!=NULL){
+		if ((pid_stream=fopen(pid_file, "r"))!=NULL){
 			fscanf(pid_stream, "%d", &p);
 			fclose(pid_stream);
 			if (p==-1){
 				LOG(L_CRIT, "pid file %s exists, but doesn't contain a valid"
-					" pid number\n", pid_fn);
+					" pid number\n", pid_file);
 				goto error;
 			}
 			if (kill((pid_t)p, 0)==0 || errno==EPERM){
 				LOG(L_CRIT, "running process found in the pid file %s\n",
-					pid_fn);
+					pid_file);
 				goto error;
 			}else{
 				LOG(L_WARN, "pid file contains old pid, replacing pid\n");
 			}
 		}
 		pid=getpid();
-		if ((pid_stream=fopen(pid_fn, "w"))==NULL){
+		if ((pid_stream=fopen(pid_file, "w"))==NULL){
 			LOG(L_WARN, "unable to create pid file %s: %s\n", 
-				pid_fn, strerror(errno));
+				pid_file, strerror(errno));
 			goto error;
 		}else{
 			fprintf(pid_stream, "%i\n", (int)pid);
@@ -378,14 +368,19 @@ int main_loop()
 #ifdef STATS
 		setstats( 0 );
 #endif
-		/* only one address */
-		if (udp_init(&addresses[0],port_no)==-1) goto error;
+		/* 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){
+			LOG(L_WARN, "WARNING: using only the first listen address (no fork)\n");
+		}
 
 		/* we need another process to act as the timer*/
 		if (timer_list){
 				process_no++;
 				if ((pid=fork())<0){
-					LOG(L_CRIT,  "ERRROR: main_loop: Cannot fork\n");
+					LOG(L_CRIT,  "ERROR: main_loop: Cannot fork\n");
 					goto error;
 				}
 				
@@ -418,17 +413,28 @@ int main_loop()
 		
 		return udp_rcv_loop();
 	}else{
-		for(r=0;r<addresses_no;r++){
+		for(r=0;r<sock_no;r++){
 			/* create the listening socket (for each address)*/
-			if (udp_init(&addresses[r], port_no)==-1) goto error;
+			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++){
 			for(i=0;i<children_no;i++){
 				if ((pid=fork())<0){
 					LOG(L_CRIT,  "main_loop: Cannot fork\n");
 					goto error;
-				}
-				if (pid==0){
+				}else if (pid==0){
 					     /* child */
-
+					bind_address=&sock_info[r]; /* shortcut */
+					bind_idx=r;
 					if (init_child(i) < 0) {
 						LOG(L_ERR, "init_child failed\n");
 						goto error;
@@ -452,6 +458,9 @@ int main_loop()
 	pids[process_no]=getpid();
 	process_bit = 0;
 	is_main=1;
+	bind_address=&sock_info[0]; /* main proc -> it shoudln't send anything, if it does */
+	bind_idx=0;					/*   it will use the first address */
+
 	if (timer_list){
 		for(;;){
 			/* debug:  instead of doing something usefull */
@@ -461,7 +470,7 @@ int main_loop()
 			timer_ticker();
 		}
 	}else{
-		for(;;) sleep(LONG_SLEEP);
+		for(;;) pause(); 
 	}
 	
 	/*return 0; */
@@ -474,8 +483,7 @@ int main_loop()
 /* 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
-*/	
-
+*/
 static void sig_usr(int signo)
 {
 	pid_t	chld;
@@ -508,6 +516,8 @@ static void sig_usr(int signo)
 		}
 #endif
 		dprint("Thank you for flying " NAME "\n");
+		/* kill children also*/
+		kill(0, SIGTERM);
 		exit(0);
 	} else if (signo==SIGTERM) { /* exit gracefully as daemon */
 		DPrint("TERM received, program terminates\n");
@@ -515,11 +525,11 @@ static void sig_usr(int signo)
 #ifdef STATS
 			dump_all_statistic();
 #endif
-			if (pid_fn) {
-				unlink(pid_fn);
-				free(pid_fn);
+			if (pid_file) {
+				unlink(pid_file);
 			}
 		}
+		kill(0, SIGTERM);
 		exit(0);
 	} else if (signo==SIGUSR1) { /* statistic */
 #ifdef STATS
@@ -549,6 +559,9 @@ static void sig_usr(int signo)
 				LOG(L_INFO, "child process %d stopped by a signal %d\n",
 					chld, WSTOPSIG(chld_status));
 		}
+		/* exit */
+		kill(0, SIGTERM);
+		exit(0);
 	}
 }
 
@@ -564,6 +577,8 @@ int main(int argc, char** argv)
 	char *tmp;
 	struct utsname myname;
 	char *options;
+	char port_no_str[MAX_PORT_LEN];
+	int port_no_str_len=0;
 
 	/* added by jku: add exit handler */
 	if (signal(SIGINT, sig_usr) == SIG_ERR ) {
@@ -589,9 +604,6 @@ int main(int argc, char** argv)
 		goto error;
 	}
 
-	//memtest();
-	//hashtest();
-
 	/* process command line (get port no, cfg. file path etc) */
 	opterr=0;
 	options=
@@ -616,34 +628,43 @@ int main(int argc, char** argv)
 						fprintf(stderr, "bad port number: -p %s\n", optarg);
 						goto error;
 					}
+					if (sock_no>0) sock_info[sock_no-1].port_no=port_no;
 					break;
 
 			case 'm':
 					shm_mem_size=strtol(optarg, &tmp, 10) * 1024 * 1024;
 					if (tmp &&(*tmp)){
-						fprintf(stderr, "bad shmem size number: -m %s\n", optarg);
+						fprintf(stderr, "bad shmem size number: -m %s\n",
+										optarg);
 						goto error;
 					};
-					LOG(L_INFO, "ser: shared memory allocated: %d MByte\n", shm_mem_size );
+					LOG(L_INFO, "ser: shared memory allocated: %d MByte\n",
+									shm_mem_size );
 					break;
 
 			case 'b':
 					maxbuffer=strtol(optarg, &tmp, 10);
 					if (tmp &&(*tmp)){
-                                                fprintf(stderr, "bad max buffer size number: -p %s\n", optarg);
-                                                goto error;
-                                        }
-                                        break;
+						fprintf(stderr, "bad max buffer size number: -p %s\n",
+											optarg);
+						goto error;
+					}
+					break;
 			case 'l':
 					/* add a new addr. to our address list */
-					if (addresses_no < MAX_LISTEN){
-						names[addresses_no]=(char*)malloc(strlen(optarg)+1);
-						if (names[addresses_no]==0){
+					if (sock_no < MAX_LISTEN){
+						sock_info[sock_no].name.s=
+										(char*)malloc(strlen(optarg)+1);
+						if (sock_info[sock_no].name.s==0){
 							fprintf(stderr, "Out of memory.\n");
 							goto error;
 						}
-						strncpy(names[addresses_no], optarg, strlen(optarg)+1);
-						addresses_no++;
+						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++;
 					}else{
 						fprintf(stderr, 
 									"Too many addresses (max. %d).\n",
@@ -654,7 +675,8 @@ int main(int argc, char** argv)
 			case 'n':
 					children_no=strtol(optarg, &tmp, 10);
 					if ((tmp==0) ||(*tmp)){
-						fprintf(stderr, "bad process number: -n %s\n", optarg);
+						fprintf(stderr, "bad process number: -n %s\n",
+									optarg);
 						goto error;
 					}
 					break;
@@ -784,16 +806,6 @@ int main(int argc, char** argv)
 
 	/* fix parameters */
 	if (port_no<=0) port_no=SIP_PORT;
-	port_no_str_len=snprintf(port_no_str, MAX_PORT_LEN, ":%d", 
-				(unsigned short) port_no);
-	if (port_no_str_len<0){
-		fprintf(stderr, "ERROR: bad port number: %d\n", port_no);
-		goto error;
-	}
-	/* on some system snprintf return really strange things if it does not 
-	   have  enough space */
-	port_no_str_len=
-				(port_no_str_len<MAX_PORT_LEN)?port_no_str_len:MAX_PORT_LEN;
 
 	
 	if (children_no<=0) children_no=CHILD_NO;
@@ -817,42 +829,63 @@ int main(int argc, char** argv)
 	}
 	memset(pids, 0, sizeof(int)*(children_no+1));
 
-	if (addresses_no==0) {
+	if (sock_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){
+		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;
 		}
-		strncpy(names[addresses_no], myname.nodename,
+		strncpy(sock_info[sock_no].name.s, myname.nodename,
 				strlen(myname.nodename)+1);
-		addresses_no++;
+		sock_info[sock_no].name.len=strlen(myname.nodename);
+		sock_no++;
 	}
 
-	/*get name lens*/
-	for(r=0; r<addresses_no; r++){
-		names_len[r]=strlen(names[r]);
-	}
-
-	
-	/* get ips */
+	/* get ips & fill the port numbers*/
 	printf("Listening on ");
-	for (r=0; r<addresses_no;r++){
-		he=resolvehost(names[r]);
+	for (r=0; r<sock_no;r++){
+		he=resolvehost(sock_info[r].name.s);
 		if (he==0){
-			DPrint("ERROR: could not resolve %s\n", names[r]);
+			DPrint("ERROR: could not resolve %s\n", sock_info[r].name.s);
 			goto error;
 		}
-		hostent2ip_addr(&addresses[r], he, 0); /*convert to ip_addr format*/
-		/*memcpy(&addresses[r], he->h_addr_list[0], sizeof(int));*/
-		/*addresses[r]=*((long*)he->h_addr_list[0]);*/
-		printf("%s [",names[r]);
-		stdout_print_ip(&addresses[r]);
-		printf("]:%d\n", (unsigned short)port_no);
+		hostent2ip_addr(&sock_info[r].address, he, 0); /*convert to ip_addr format*/
+		tmp=ip_addr2a(&sock_info[r].address);
+		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);
+		sock_info[r].address_str.len=strlen(tmp);
+		
+		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;
+		}
+		/* on some system snprintf return really strange things if it does not 
+			have  enough space */
+		port_no_str_len=
+				(port_no_str_len<MAX_PORT_LEN)?port_no_str_len:MAX_PORT_LEN;
+		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);
+		
+		printf("%s [%s]:%s\n",sock_info[r].name.s, sock_info[r].address_str.s,
+				sock_info[r].port_no_str.s);
 	}
 
 #ifdef STATS

+ 26 - 10
msg_translator.c

@@ -89,30 +89,45 @@ int check_address(struct ip_addr* ip, char *name, int resolver)
 
 
 
-char* via_builder( struct sip_msg *msg , unsigned int *len )
+char* via_builder( struct sip_msg *msg , unsigned int *len, 
+					struct socket_info* send_sock )
 {
-	unsigned int  via_len, branch_len;
+	unsigned int  via_len, branch_len, extra_len;;
 	char               *line_buf;
 
 	line_buf=0;
+	extra_len=0;
 
 	line_buf=pkg_malloc(sizeof(char)*MAX_VIA_LINE_SIZE);
 	if (line_buf==0){
 		LOG(L_ERR, "ERROR: via_builder: out of memory\n");
 		goto error;
 	}
-	via_len=MY_VIA_LEN+names_len[0]; /* space included in MY_VIA*/
+	via_len=MY_VIA_LEN+send_sock->address_str.len; /*space included in MY_VIA*/
+#ifdef USE_IPV6
+	if (send_sock->address.af==AF_INET6) via_len+=2; /* [ ]*/
+#endif
 
 	/* jku: if we compute branches using MD5 it will take 32 bytes */
 	branch_len= (loop_checks ? MY_BRANCH_LEN : MY_BRANCH_LEN -1 + MD5_LEN)+
 					msg->add_to_branch_len;
 
-	if ((via_len+port_no_str_len+branch_len+CRLF_LEN)<MAX_VIA_LINE_SIZE){
+	if ((via_len+send_sock->port_no_str.len+branch_len
+								+CRLF_LEN)<MAX_VIA_LINE_SIZE){
 		memcpy(line_buf, MY_VIA, MY_VIA_LEN);
-		memcpy(line_buf+MY_VIA_LEN, names[0], names_len[0]);
-		if (port_no!=SIP_PORT){
-			memcpy(line_buf+via_len, port_no_str, port_no_str_len);
-			via_len+=port_no_str_len;
+#ifdef USE_IPV6
+	if (send_sock->address.af==AF_INET6) {
+		line_buf[MY_VIA_LEN]='[';
+		line_buf[MY_VIA_LEN+1+send_sock->address_str.len]=']';
+		extra_len=1;
+	}
+#endif
+		memcpy(line_buf+MY_VIA_LEN+extra_len, send_sock->address_str.s,
+									send_sock->address_str.len);
+		if (send_sock->port_no!=SIP_PORT){
+			memcpy(line_buf+via_len, send_sock->port_no_str.s,
+									 send_sock->port_no_str.len);
+			via_len+=send_sock->port_no_str.len;
 		}
 
 		/* jku: branch parameter */
@@ -222,7 +237,8 @@ done:
 
 
 char * build_req_buf_from_sip_req( struct sip_msg* msg,
-								unsigned int *returned_len)
+								unsigned int *returned_len,
+								struct socket_info* send_sock)
 {
 	unsigned int len, new_len, received_len, uri_len, via_len, extra_len;
 	char* line_buf;
@@ -249,7 +265,7 @@ char * build_req_buf_from_sip_req( struct sip_msg* msg,
 	extra_len=0;
 
 
-	line_buf = via_builder( msg, &via_len );
+	line_buf = via_builder( msg, &via_len, send_sock);
 	if (!line_buf){
 		LOG(L_ERR,"ERROR: build_req_buf_from_sip_req: no via received!\n");
 		goto error1;

+ 3 - 2
msg_translator.h

@@ -9,9 +9,10 @@
 #define MY_HF_SEP_LEN 2
 
 #include "parser/msg_parser.h"
+#include "ip_addr.h"
 
 char * build_req_buf_from_sip_req (	struct sip_msg* msg, 
-				unsigned int *returned_len);
+				unsigned int *returned_len, struct socket_info* send_sock);
 
 char * build_res_buf_from_sip_res(	struct sip_msg* msg,
 				unsigned int *returned_len);
@@ -23,7 +24,7 @@ char * build_res_buf_from_sip_req(	unsigned int code ,
 				struct sip_msg* msg,
 				unsigned int *returned_len);
 char* via_builder( 			struct sip_msg *msg ,
-				unsigned int *len );
+				unsigned int *len, struct socket_info* send_sock);
 
 
 #endif

+ 1 - 1
receive.c

@@ -43,7 +43,7 @@ int receive_msg(char* buf, unsigned int len, union sockaddr_union* src_su)
 	msg->buf=buf;
 	msg->len=len;
 	su2ip_addr(&msg->src_ip, src_su);
-	msg->dst_ip=*bind_address; /* won't work if listening on 0.0.0.0 */
+	msg->dst_ip=bind_address->address; /* won't work if listening on 0.0.0.0 */
 	msg->id=msg_no;
 	/* make a copy of the message */
 	msg->orig=(char*) pkg_malloc(len+1);

+ 23 - 16
udp_server.c

@@ -23,7 +23,6 @@
 #include <mem/dmalloc.h>
 #endif
 
-int udp_sock;
 
 int probe_max_receive_buffer( int udp_sock )
 {
@@ -107,7 +106,7 @@ int probe_max_receive_buffer( int udp_sock )
 	/* EoJKU */
 }
 
-int udp_init(struct ip_addr* ip, unsigned short port)
+int udp_init(struct socket_info* sock_info)
 {
 	union sockaddr_union* addr;
 	int optval;
@@ -119,7 +118,7 @@ int udp_init(struct ip_addr* ip, unsigned short port)
 		goto error;
 	}
 	
-	if (init_su(addr, ip, htons(port))<0){
+	if (init_su(addr, &sock_info->address, htons(sock_info->port_no))<0){
 		LOG(L_ERR, "ERROR: udp_init: could not init sockaddr_union\n");
 		goto error;
 	}
@@ -130,25 +129,33 @@ int udp_init(struct ip_addr* ip, unsigned short port)
 	*/
 
 	
-	udp_sock = socket(AF2PF(addr->s.sa_family), SOCK_DGRAM, 0);
-	if (udp_sock==-1){
+	sock_info->socket = socket(AF2PF(addr->s.sa_family), SOCK_DGRAM, 0);
+	if (sock_info->socket==-1){
 		LOG(L_ERR, "ERROR: udp_init: socket: %s\n", strerror(errno));
 		goto error;
 	}
 	/* set sock opts? */
 	optval=1;
-	if (setsockopt(udp_sock, SOL_SOCKET, SO_REUSEADDR ,
+	if (setsockopt(sock_info->socket, SOL_SOCKET, SO_REUSEADDR ,
 					(void*)&optval, sizeof(optval)) ==-1)
 	{
 		LOG(L_ERR, "ERROR: udp_init: setsockopt: %s\n", strerror(errno));
 		goto error;
 	}
 
-	if ( probe_max_receive_buffer(udp_sock)==-1) goto error;
-	bind_address=ip;
-
-	if (bind(udp_sock,  &addr->s, sizeof(union sockaddr_union))==-1){
-		LOG(L_ERR, "ERROR: udp_init: bind: %s\n", strerror(errno));
+	if ( probe_max_receive_buffer(sock_info->socket)==-1) goto error;
+
+	if (bind(sock_info->socket,  &addr->s, sizeof(union sockaddr_union))==-1){
+		LOG(L_ERR, "ERROR: udp_init: bind(%x, %p, %d) on %s: %s\n",
+				sock_info->socket, &addr->s, 
+				sizeof(union sockaddr_union),
+				sock_info->address_str.s,
+				strerror(errno));
+	#ifdef USE_IPV6
+		if (addr->s.sa_family==AF_INET6)
+			LOG(L_ERR, "ERROR: udp_init: might be caused by using a link "
+					" local address, try site local or global\n");
+	#endif
 		goto error;
 	}
 
@@ -191,8 +198,8 @@ int udp_rcv_loop()
 		}
 #endif
 		fromlen=sizeof(union sockaddr_union);
-		len=recvfrom(udp_sock, buf, BUF_SIZE, 0, &from->s,
-						&fromlen);
+		len=recvfrom(bind_address->socket, buf, BUF_SIZE, 0, &from->s,
+											&fromlen);
 		if (len==-1){
 			LOG(L_ERR, "ERROR: udp_rcv_loop:recvfrom:[%d] %s\n",
 						errno, strerror(errno));
@@ -222,15 +229,15 @@ error:
 
 
 /* which socket to use? main socket or new one? */
-int udp_send(char *buf, unsigned len, union sockaddr_union*  to,
-				unsigned tolen)
+int udp_send(struct socket_info *source, char *buf, unsigned len,
+				union sockaddr_union*  to, unsigned tolen)
 {
 
 	int n;
 
 
 again:
-	n=sendto(udp_sock, buf, len, 0, &to->s, tolen);
+	n=sendto(source->socket, buf, len, 0, &to->s, tolen);
 	if (n==-1){
 		LOG(L_ERR, "ERROR: udp_send: sendto(sock,%p,%d,0,%p,%d): %s(%d)\n",
 				buf,len,to,tolen,

+ 3 - 4
udp_server.h

@@ -12,11 +12,10 @@
 #define MAX_RECV_BUFFER_SIZE	256*1024
 #define BUFFER_INCREMENT	2048
 
-extern int udp_sock;
 
-int udp_init(struct ip_addr* ip, unsigned short port);
-int udp_send(char *buf, unsigned len, union sockaddr_union*  to,
-				unsigned tolen);
+int udp_init(struct socket_info* si);
+int udp_send(struct socket_info* source,char *buf, unsigned len,
+				union sockaddr_union*  to, unsigned tolen);
 int udp_rcv_loop();