浏览代码

command line support for address lists (-l)

Support for specifying and address list for -l (e.g. -l (foo, bar)). For
sctp all the address in the list will be used for multi-homing.
Andrei Pelinescu-Onciul 17 年之前
父节点
当前提交
72bba9e3dc
共有 1 个文件被更改,包括 131 次插入20 次删除
  1. 131 20
      main.c

+ 131 - 20
main.c

@@ -76,6 +76,8 @@
  *              scheduling policies (andrei)
  * 2007-07-30  dst blacklist and DNS cache measurements added (Gergo)
  * 2008-08-08  sctp support (andrei)
+ * 2008-08-19  -l support for mmultihomed addresses/addresses lists
+ *                (e.g. -l (eth0, 1.2.3.4, foo.bar) ) (andrei)
  */
 
 
@@ -196,10 +198,12 @@ Options:\n\
     -c           Check configuration file for errors\n\
     -l address   Listen on the specified address/interface (multiple -l\n\
                   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\
+                  [proto:]addr_lst[:port], where proto=udp|tcp|tls|sctp, \n\
+                  addr_lst= addr|(addr, addr_lst) and \n\
+                  addr= host|ip_address|interface_name. \n\
+                  E.g: -l locahost, -l udp:127.0.0.1:5080, -l eth0:5062,\n\
+                  -l \"sctp:(eth0)\", -l \"(eth0, eth1, 127.0.0.1):5065\".\n\
+                  The default behaviour is to listen on all the interfaces.\n\
     -n processes Number of child processes to fork per interface\n\
                   (default: 8)\n\
     -r           Use dns to check if is necessary to add a \"received=\"\n\
@@ -845,13 +849,116 @@ static int parse_proto(unsigned char* s, long len, int* proto)
 
 
 
+static struct name_lst* mk_name_lst_elem(char* name, int name_len, int flags)
+{
+	struct name_lst* l;
+	
+	l=pkg_malloc(sizeof(struct name_lst)+name_len+1/* 0 */);
+	if (l){
+		l->name=((char*)l)+sizeof(struct name_lst);
+		memcpy(l->name, name, name_len);
+		l->name[name_len]=0;
+		l->flags=flags;
+		l->next=0;
+	}
+	return l;
+}
+
+
+
+/* free a name_lst list with elements allocated with mk_name_lst_elem
+ * (single block both for the structure and for the name) */
+static void free_name_lst(struct name_lst* lst)
+{
+	struct name_lst* l;
+	
+	while(lst){
+		l=lst;
+		lst=lst->next;
+		pkg_free(l);
+	}
+}
+
+
+
+/* parse h and returns a name lst (flags are set to SI_IS_MHOMED if
+ * h contains more then one name or contains a name surrounded by '(' ')' )
+ * valid formats:    "hostname"
+ *                   "(hostname, hostname1, hostname2)"
+ *                   "(hostname hostname1 hostname2)"
+ *                   "(hostname)"
+ */
+static struct name_lst* parse_name_lst(char* h, int h_len)
+{
+	char* last;
+	char* p;
+	struct name_lst* n_lst;
+	struct name_lst* l;
+	struct name_lst** tail;
+	int flags;
+	
+	n_lst=0;
+	tail=&n_lst;
+	last=h+h_len-1;
+	flags=0;
+	/* eat whitespace */
+	for(; h<=last && ((*h==' ') || (*h=='\t')); h++);
+	for(; last>h && ((*last==' ') || (*last=='\t')); last--);
+	/* catch empty strings and invalid lens */
+	if (h>last) goto error;
+	
+	if (*h=='('){
+		/* list mode */
+		if (*last!=')' || ((h+1)>(last-1)))
+			goto error;
+		h++;
+		last--;
+		flags=SI_IS_MHOMED;
+		for(p=h; p<=last; p++)
+			switch (*p){
+				case ',':
+				case ';':
+				case ' ':
+				case '\t':
+					if ((int)(p-h)>0){
+						l=mk_name_lst_elem(h, (int)(p-h), flags);
+						if (l==0) 
+							goto error;
+						*tail=l;
+						tail=&l->next;
+					}
+					h=p+1;
+					break;
+			}
+	}else{
+		/* single addr. mode */
+		flags=0;
+		p=last+1;
+	}
+	if ((int)(p-h)>0){
+		l=mk_name_lst_elem(h, (int)(p-h), flags);
+		if (l==0) 
+			goto error;
+		*tail=l;
+		tail=&l->next;
+	}
+	return n_lst;
+error:
+	if (n_lst) free_name_lst(n_lst);
+	return 0;
+}
+
+
+
 /*
- * parses [proto:]host[:port]
+ * parses [proto:]host[:port]  or
+ *  [proto:](host_1, host_2, ... host_n)[:port]
  * where proto= udp|tcp|tls
- * returns 0 on success and -1 on failure
+ * returns  fills proto, port, host and returns list of addresses on success
+ * (pkg malloc'ed) and 0 on failure
  */
-static int parse_phostport(char* s, char** host, int* hlen, int* port,
-							int* proto)
+static struct name_lst* parse_phostport(char* s, char** host, int* hlen,
+										int* port, int* proto)
 {
 	char* first; /* first ':' occurrence */
 	char* second; /* second ':' occurrence */
@@ -884,7 +991,7 @@ static int parse_phostport(char* s, char** host, int* hlen, int* port,
 				break;
 		}
 	}
-	if (p==s) return -1;
+	if (p==s) return 0;
 	if (*(p-1)==':') goto error_colons;
 
 	if (first==0){ /* no ':' => only host */
@@ -892,7 +999,7 @@ static int parse_phostport(char* s, char** host, int* hlen, int* port,
 		*hlen=(int)(p-s);
 		*port=0;
 		*proto=0;
-		return 0;
+		goto end;
 	}
 	if (second){ /* 2 ':' found => check if valid */
 		if (parse_proto((unsigned char*)s, first-s, proto)<0) goto error_proto;
@@ -900,7 +1007,7 @@ static int parse_phostport(char* s, char** host, int* hlen, int* port,
 		if ((tmp==0)||(*tmp)||(tmp==second+1)) goto error_port;
 		*host=first+1;
 		*hlen=(int)(second-*host);
-		return 0;
+		goto end;
 	}
 	/* only 1 ':' found => it's either proto:host or host:port */
 	*port=strtol(first+1, &tmp, 10);
@@ -916,19 +1023,20 @@ static int parse_phostport(char* s, char** host, int* hlen, int* port,
 		*host=s;
 		*hlen=(int)(first-*host);
 	}
-	return 0;
+end:
+	return parse_name_lst(*host, *hlen);
 error_brackets:
 	LOG(L_ERR, "ERROR: parse_phostport: too many brackets in %s\n", s);
-	return -1;
+	return 0;
 error_colons:
 	LOG(L_ERR, "ERROR: parse_phostport: too many colons in %s\n", s);
-	return -1;
+	return 0;
 error_proto:
 	LOG(L_ERR, "ERROR: parse_phostport: bad protocol in %s\n", s);
-	return -1;
+	return 0;
 error_port:
 	LOG(L_ERR, "ERROR: parse_phostport: bad port number in %s\n", s);
-	return -1;
+	return 0;
 }
 
 
@@ -1366,6 +1474,7 @@ int main(int argc, char** argv)
 	int rfd;
 	int debug_save, debug_flag;
 	int dont_fork_cnt;
+	struct name_lst* n_lst;
 
 	/*init*/
 	time(&up_since);
@@ -1563,18 +1672,20 @@ try_again:
 					}
 					break;
 			case 'l':
-					if (parse_phostport(optarg, &tmp, &tmp_len,
-											&port, &proto)<0){
+					if ((n_lst=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 */
 					/* add a new addr. to our address list */
-					if (add_listen_iface(tmp,0,  port, proto, 0)!=0){
+					if (add_listen_iface(n_lst->name, n_lst->next,  port,
+											proto, n_lst->flags)!=0){
 						fprintf(stderr, "failed to add new listen address\n");
+						free_name_lst(n_lst);
 						goto error;
 					}
+					free_name_lst(n_lst);
 					break;
 			case 'n':
 					children_no=strtol(optarg, &tmp, 10);