Browse Source

core: helper functions to lookup local socket from proto:host:port

Daniel-Constantin Mierla 12 years ago
parent
commit
6335d07c4c
3 changed files with 105 additions and 1 deletions
  1. 1 1
      main.c
  2. 94 0
      socket_info.c
  3. 10 0
      socket_info.h

+ 1 - 1
main.c

@@ -924,7 +924,7 @@ error:
 
 /* returns -1 on error, 0 on success
  * sets proto */
-static int parse_proto(unsigned char* s, long len, int* proto)
+int parse_proto(unsigned char* s, long len, int* proto)
 {
 #define PROTO2UINT3(a, b, c) ((	(((unsigned int)(a))<<16)+ \
 								(((unsigned int)(b))<<8)+  \

+ 94 - 0
socket_info.c

@@ -2057,3 +2057,97 @@ void init_proto_order()
 }
 
 
+/**
+ * parse '[port:]host[:port]' string to a broken down structure
+ */
+int parse_protohostport(str* ins, sr_phostp_t *r)
+{
+	char* first; /* first ':' occurrence */
+	char* second; /* second ':' occurrence */
+	char* p;
+	int bracket;
+	char* tmp;
+
+	first=second=0;
+	bracket=0;
+	memset(r, 0, sizeof(sr_phostp_t));
+
+	/* find the first 2 ':', ignoring possible ipv6 addresses
+	 * (substrings between [])
+	 */
+	for(p=ins->s; p<ins->s+ins->len; 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==ins->s) return -1;
+	if (*(p-1)==':') goto error_colons;
+
+	if (first==0) { /* no ':' => only host */
+		r->host.s=ins->s;
+		r->host.len=(int)(p-ins->s);
+		goto end;
+	}
+	if (second) { /* 2 ':' found => check if valid */
+		if (parse_proto((unsigned char*)ins->s, first-ins->s, &r->proto)<0)
+			goto error_proto;
+		r->port=strtol(second+1, &tmp, 10);
+		if ((tmp==0)||(*tmp)||(tmp==second+1)) goto error_port;
+		r->host.s=first+1;
+		r->host.len=(int)(second-r->host.s);
+		goto end;
+	}
+	/* only 1 ':' found => it's either proto:host or host:port */
+	r->port=strtol(first+1, &tmp, 10);
+	if ((tmp==0)||(*tmp)||(tmp==first+1)){
+		/* invalid port => it's proto:host */
+		if (parse_proto((unsigned char*)ins->s, first-ins->s, &r->proto)<0)
+			goto error_proto;
+		r->host.s=first+1;
+		r->host.len=(int)(p-r->host.s);
+	}else{
+		/* valid port => its host:port */
+		r->host.s=ins->s;
+		r->host.len=(int)(first-r->host.s);
+	}
+end:
+	return 0;
+error_brackets:
+	LOG(L_ERR, "too many brackets in %.*s\n", ins->len, ins->s);
+	return -1;
+error_colons:
+	LOG(L_ERR, "too many colons in %.*s\n", ins->len, ins->s);
+	return -1;
+error_proto:
+	LOG(L_ERR, "bad protocol in %.*s\n", ins->len, ins->s);
+	return -1;
+error_port:
+	LOG(L_ERR, "bad port number in %.*s\n", ins->len, ins->s);
+	return -1;
+}
+
+/**
+ * lookup a local socket by '[port:]host[:port]' string
+ */
+struct socket_info* lookup_local_socket(str *phostp)
+{
+	sr_phostp_t r;
+	if(parse_protohostport(phostp, &r)<0)
+		return NULL;
+	return grep_sock_info(&r.host, (unsigned short)r.port,
+			(unsigned short)r.proto);
+}

+ 10 - 0
socket_info.h

@@ -105,6 +105,8 @@ struct socket_info** get_sock_info_list(unsigned short proto);
 int parse_phostport(char* s, char** host, int* hlen,
 								 int* port, int* proto);
 
+int parse_proto(unsigned char* s, long len, int* proto);
+
 char* get_valid_proto_name(unsigned short proto);
 
 /* helper function:
@@ -142,5 +144,13 @@ inline static struct socket_info* get_first_socket(void)
 	return 0;
 }
 
+/* structure to break down 'proto:host:port' */
+typedef struct _sr_phostp {
+	int proto;
+	str host;
+	int port;
+} sr_phostp_t;
+
+struct socket_info* lookup_local_socket(str *phostp);
 
 #endif