Pārlūkot izejas kodu

Initial revision

Andrei Pelinescu-Onciul 24 gadi atpakaļ
revīzija
512dcd9838
24 mainītis faili ar 1147 papildinājumiem un 0 dzēšanām
  1. BIN
      .cfg_parser.c.swp
  2. BIN
      .cfg_parser.h.swp
  3. BIN
      .main.c.swp
  4. BIN
      .msg_parser.c.swp
  5. BIN
      .msg_parser.h.swp
  6. BIN
      .parser_f.c.swp
  7. BIN
      .parser_f.h.swp
  8. BIN
      .route.c.swp
  9. BIN
      .route.h.swp
  10. BIN
      .sip_router.cfg.swp
  11. BIN
      .test.c.swp
  12. 126 0
      cfg_parser.c
  13. 29 0
      cfg_parser.h
  14. 21 0
      dprint.c
  15. 20 0
      dprint.h
  16. 51 0
      main.c
  17. 315 0
      msg_parser.c
  18. 75 0
      msg_parser.h
  19. 72 0
      parser_f.c
  20. 15 0
      parser_f.h
  21. 230 0
      route.c
  22. 46 0
      route.h
  23. 13 0
      sip_router.cfg
  24. 134 0
      test.c

BIN
.cfg_parser.c.swp


BIN
.cfg_parser.h.swp


BIN
.main.c.swp


BIN
.msg_parser.c.swp


BIN
.msg_parser.h.swp


BIN
.parser_f.c.swp


BIN
.parser_f.h.swp


BIN
.route.c.swp


BIN
.route.h.swp


BIN
.sip_router.cfg.swp


BIN
.test.c.swp


+ 126 - 0
cfg_parser.c

@@ -0,0 +1,126 @@
+/*
+ * $Id$
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "cfg_parser.h"
+#include "dprint.h"
+#include "parser_f.h"
+#include "route.h"
+
+
+
+
+/* params: null terminated text line => fills cl
+ * returns 0, or on error -1. */
+int cfg_parse_line(char* line, struct cfg_line* cl)
+{
+	/* format:
+		line = rule | comment
+		comment = SP* '#'.*
+		rule = SP* method_re SP* uri_re SP* ip_address comment?
+	*/
+		
+	char* tmp;
+	char* end;
+	
+	end=line+strlen(line);
+	tmp=eat_space(line, end-line);
+	if ((tmp==end)||(is_empty(tmp, end-tmp))) {
+		cl->type=CFG_EMPTY;
+		goto skip;
+	}
+	if (*tmp=='#'){
+		cl->type=CFG_COMMENT;
+		goto skip;
+	}
+	cl->method=tmp;
+	tmp=eat_token(cl->method,end-cl->method);
+	if (tmp==end) goto error;
+	printf("%d\n", tmp-line);
+	*tmp=0;
+	tmp++;
+	cl->uri=eat_space(tmp,end-tmp);
+	if (tmp==end) goto error;
+	tmp=eat_token(cl->uri,end-cl->uri);
+	if (tmp==end) goto error;
+	printf("%d\n", tmp-line);
+	*tmp=0;
+	tmp++;
+	cl->address=eat_space(tmp,end-tmp);
+	if (tmp==end) goto error;
+	tmp=eat_token(cl->address, end-cl->address);
+	printf("%d(%02x)\n", tmp-line, *tmp);
+	if (tmp<end) {
+		*tmp=0;
+		if (tmp+1<end){
+			if (!is_empty(tmp+1,end-tmp-1)){
+				printf("%d(%02x) e: %d\n", tmp-line, *tmp, end-line);
+				/* check if comment */
+				tmp=eat_space(tmp+1, end-tmp-1);
+				printf("%d(%02x) e: %d\n", tmp-line, *tmp, end-line);
+				if (*tmp!='#'){
+					/* extra chars at the end of line */
+					goto error;
+				}
+			}
+		}
+	}
+		
+	cl->type=CFG_RULE;
+skip:
+	return 0;
+error:
+	cl->type=CFG_ERROR;
+	return -1;
+}
+
+
+
+/* parses the cfg, returns 0 on success, line no otherwise */
+int cfg_parse_stream(FILE* stream)
+{
+	int line;
+	struct cfg_line cl;
+	char buf[MAX_LINE_SIZE];
+	int ret;
+
+	line=1;
+	while(!feof(stream)){
+		if (fgets(buf, MAX_LINE_SIZE, stream)){
+			cfg_parse_line(buf, &cl);
+			switch (cl.type){
+				case CFG_RULE:
+					if ((ret=add_rule(&cl, &rlist))!=0){
+						DPrint("ERROR: could not compile rule at line %d\n",
+							line);
+						DPrint(" ----: add_rule returned %d\n", ret);
+						goto error;
+					}
+					break;
+				case CFG_COMMENT:
+				case CFG_SKIP:
+					break;
+				case CFG_ERROR:
+					DPrint("ERROR: bad config line (%d):%s\n", line, buf);
+					goto error;
+					break;
+			}
+			line++;
+		}else{
+			if (ferror(stream)){
+				DPrint("ERROR: reading configuration: %s\n", strerror(errno));
+				goto error;
+			}
+			break;
+		}
+	}
+	return 0;
+
+error:
+	return line;
+}
+

+ 29 - 0
cfg_parser.h

@@ -0,0 +1,29 @@
+/*
+ * $Id$
+ */
+
+#ifndef  cfg_parser_h
+#define cfg_parser_h
+
+#include <stdio.h>
+
+#define CFG_EMPTY   0
+#define CFG_COMMENT 1
+#define CFG_SKIP    2
+#define CFG_RULE    3
+#define CFG_ERROR  -1
+
+#define MAX_LINE_SIZE 800
+
+struct cfg_line{
+	int type;
+	char* method;
+	char* uri;
+	char* address;
+};
+
+
+int cfg_parse_line(char* line, struct cfg_line* cl);
+int cfg_parse_stream(FILE* stream);
+
+#endif

+ 21 - 0
dprint.c

@@ -0,0 +1,21 @@
+/*
+ * $Id$
+ *
+ * debug print 
+ *
+ */
+ 
+#include "dprint.h"
+ 
+#include <stdarg.h>
+#include <stdio.h>
+
+void dprint(char * format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+	vfprintf(stderr,format,ap);
+	fflush(stderr);
+	va_end(ap);
+}

+ 20 - 0
dprint.h

@@ -0,0 +1,20 @@
+/*
+ * $Id$
+ */
+
+
+#ifndef dprint_h
+#define dprint_h
+
+
+
+void dprint (char* format, ...);
+
+#ifdef NO_DEBUG
+	#define DPrint(fmt, args...)
+#else
+	#define DPrint(fmt,args...) dprint(fmt, ## args);
+#endif
+
+
+#endif /* ifndef dprint_h */

+ 51 - 0
main.c

@@ -0,0 +1,51 @@
+/*
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#include "dprint.h"
+#include "route.h"
+
+#define CFG_FILE "./sip_router.cfg"
+
+
+int main(int argc, char** argv)
+{
+
+	char * cfg_file;
+	FILE* cfg_stream;
+
+	cfg_file=CFG_FILE;
+	
+	/* process command line (get port no, cfg. file path etc) */
+	/* ...*/
+
+	/* load config file or die */
+	cfg_stream=fopen (cfg_file, "r");
+	if (cfg_stream==0){
+		DPrint("ERROR: could not load config file: %s\n", strerror(errno));
+		goto error;
+	}
+
+	if (cfg_parse_stream(cfg_stream)!=0){
+		DPrint("ERROR: config parser failure\n");
+		goto error;
+	}
+	
+		
+	print_rl();
+
+
+
+	/* start other processes/threads ? */
+
+	/* receive loop */
+
+
+error:
+	return -1;
+
+}

+ 315 - 0
msg_parser.c

@@ -0,0 +1,315 @@
+/*
+ * $Id$
+ *
+ * sip msg. header proxy parser 
+ *
+ */
+
+#include "msg_parser.h"
+#include "string.h"
+
+#include "parser_f.h"
+#include "dprint.h"
+
+
+
+/* parses the first line, returns pointer to  next line  & fills fl;
+   also  modifies buffer (to avoid extra copy ops) */
+char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl)
+{
+	
+	char *tmp;
+	char* second;
+	char* third;
+	char* nl;
+	int offset;
+	
+	/* grammar:
+		request  =  method SP uri SP version CRLF
+		response =  version SP status  SP reason  CRLF
+		(version = "SIP/2.0")
+	*/
+	
+
+	/* see if it's a reply (status) */
+	tmp=eat_token(buffer, len);
+	if (tmp==buffer){
+		DPrint("ERROR: empty  or bad first line\n");
+		goto error1;
+	}
+	if ((strlen(SIP_VERSION)==(tmp-buffer)) &&
+		(memcmp(buffer,SIP_VERSION,tmp-buffer)==0)){
+		
+		fl->type=SIP_REPLY;
+	}else{
+		fl->type=SIP_REQUEST;
+	}
+	
+	offset=tmp-buffer;
+	second=eat_space(tmp, len-offset);
+	offset+=second-tmp;
+	if (second==tmp){
+		goto error;
+	}
+	*tmp=0; /* mark the end of the token */
+	fl->u.request.method=buffer;
+	
+	/* next element */
+	tmp=eat_token(second, len-offset);
+	offset+=tmp-second;
+	third=eat_space(tmp, len-offset);
+	offset+=third-tmp;
+	if(third==tmp){
+		goto error;
+	}
+	*tmp=0; /* mark the end of the token */
+	fl->u.request.uri=second;
+	/*  last part */
+	tmp=eat_token(third,len-offset);
+	offset+=tmp-third;
+	if (tmp==third){
+		goto error;
+	}
+	if (! is_empty(tmp, len-offset)){		
+		goto error;
+	}
+	nl=eat_line(tmp,len-offset);
+	*tmp=0;
+	fl->u.request.version=third;
+	
+	return nl;
+
+error:
+	DPrint("ERROR: bad %s first line\n", 
+		(fl->type==SIP_REPLY)?"reply(status)":"request");
+error1:
+	fl->type=SIP_INVALID;
+	DPrint("ERROR: at line 0 char %d\n", offset);
+	/* skip  line */
+	nl=eat_line(buffer,len);
+	return nl;
+}
+
+
+/* returns integer field name type */
+int field_name(char *s)
+{
+	if ((strcmp(s, "Via")==0 )||(strcmp(s,"v")==0))
+		return  HDR_VIA;
+	if ((strcmp(s, "To")==0)||(strcmp(s,"t")==0))
+		return HDR_TO;
+	return HDR_OTHER;
+}
+
+
+
+
+/* returns pointer to next header line, and fill hdr_f */
+char* get_hdr_field(char *buffer, unsigned int len, struct hdr_field*  hdr_f)
+{
+	/* grammar (rfc822):
+		field = field-name ":" field-body CRLF
+		field-body = text [ CRLF SP field-body ]
+	   (CRLF in the field body must be removed)
+	*/
+
+	char* tmp;
+	char* nl;
+	char* body;
+	int offset;
+
+	if ((*buffer=='\n')||(*buffer=='\r')){
+		/* double crlf */
+		tmp=eat_line(buffer,len);
+		hdr_f->type=HDR_EOH;
+		return tmp;
+	}
+	
+	tmp=eat_token2(buffer, len, ':');
+	if ((tmp==buffer) || (tmp-buffer==len) ||
+		(is_empty(buffer, tmp-buffer-1))|| (*tmp!=':')){
+		hdr_f->type=HDR_ERROR;
+		goto error;
+	}
+	*tmp=0;
+	hdr_f->type=field_name(buffer);
+	body= ++tmp;
+	hdr_f->name=buffer;
+	offset=tmp-buffer;
+	/* get all the lines in this field  body */
+	do{
+		nl=eat_line(tmp, len-offset);
+		offset+=nl-tmp;
+		tmp=nl;
+	
+	}while( (*tmp==' ' ||  *tmp=='\t') && (offset<len) );
+	if (offset==len){
+		hdr_f->type=HDR_ERROR;
+		DPrint("ERROR: field body too  long\n");
+		goto error;
+	}
+	*(tmp-1)=0; /* should be an LF */
+	hdr_f->body=body;
+error:
+	return tmp;
+}
+
+
+
+char* parse_hostport(char* buf, char** host, short int* port)
+{
+	char *tmp;
+	char *invalid;
+	
+	*host=buf;
+	for(tmp=buf;(*tmp)&&(*tmp!=':');tmp++);
+	if (*tmp==0){
+		*port=0;
+	}else{
+		*tmp=0;
+		invalid=0;
+		*port=strtol(tmp+1, &invalid, 10);
+		if ((invalid!=0)&&(*invalid)){
+			DPrint("ERROR: hostport: trailing chars in port number: %s(%x)\n",
+					invalid, invalid);
+			/* report error? */
+		}
+	}
+	return *host;
+}
+
+
+
+/* parses a via body, returns next via (for compact vias) & fills vb,
+ * the buffer should be null terminated! */
+char* parse_via_body(char* buffer,unsigned int len, struct via_body * vb)
+{
+	/* format: sent-proto sent-by  *(";" params) [comment] 
+
+	           sent-proto = name"/"version"/"transport
+		   sent-by    = host [":" port]
+		   
+	*/
+
+	char* tmp;
+	char *name,*version, *transport, *comment, *params, *hostport;
+	char * next_via;
+	char * host;
+	short int port;
+	int offset;
+	
+
+	name=version=transport=comment=params=hostport=next_via=host=0;
+	name=eat_space(buffer, len);
+	if (name-buffer==len) goto error;
+	offset=name-buffer;
+	tmp=name;
+
+	version=eat_token2(tmp,len-offset,'/');
+	if (version+1-buffer>=len) goto error;
+	*version=0;
+	version++;
+	offset+=version-tmp;
+	
+	transport=eat_token2(tmp,len-offset,'/');
+	if (transport+1-buffer>=len) goto error;
+	*transport=0;
+	transport++;
+	offset+=transport-tmp;
+	
+	tmp=eat_token(transport,len-offset);
+	if (tmp+1-buffer>=len) goto error;
+	*tmp=0;
+	tmp++;
+	offset+=tmp-transport;
+	
+	hostport=eat_space(tmp,len-offset);
+	if (hostport+1-buffer>=len) goto error;
+	offset+=hostport-tmp;
+
+	/* find end of hostport */
+ 	for(tmp=hostport; (tmp-buffer)<len &&
+			(*tmp!=' ')&&(*tmp!=';')&&(*tmp!=','); tmp++);
+	if (tmp-buffer<len){
+		switch (*tmp){
+			case ' ':
+				*tmp=0;
+				/*the rest is comment? */
+				if (tmp+1-buffer<len){
+					tmp++;
+					comment=tmp;
+					/* eat the comment */
+					for(;((tmp-buffer)<len)&&
+						(*tmp!=',');tmp++);
+					/* mark end of compact via (also end of comment)*/
+					if (tmp-buffer<len){
+						*tmp=0;
+					}else break;
+					/* eat space & ',' */
+					for(tmp=tmp+1;((tmp-buffer)<len)&&
+						(*tmp==' '|| *tmp==',');tmp++);
+					
+				}
+				break;
+
+			case ';':
+				*tmp=0;
+				if (tmp+1-buffer>=len) goto error;
+				tmp++;
+				params=tmp;
+				/* eat till end, first space  or ',' */
+				for(;((tmp-buffer)<len)&&
+					(*tmp!=' '&& *tmp!=',');tmp++);
+				if (tmp-buffer==len)  break;
+				if (*tmp==' '){
+					/* eat comment */
+					*tmp=0;
+					tmp++;
+					comment=tmp;
+					for(;((tmp-buffer)<len)&&
+						(*tmp!=',');tmp++);
+					if (tmp-buffer==len)  break;
+				}
+				/* mark end of via*/
+				*tmp=0;
+				/* eat space & ',' */
+				for(tmp=tmp+1;((tmp-buffer)<len)&&
+					(*tmp==' '|| *tmp==',');tmp++);
+				break;
+
+			case ',':
+				*tmp=0;
+				if (tmp+1-buffer<len){
+					/* eat space and ',' */
+					for(tmp=tmp+1; 
+						((tmp-buffer)<len)&&
+						(*tmp==' '|| *tmp==',');
+					   tmp++);
+				}
+		}
+	}
+	/* if we are not at the end of the body => we found another compact via */
+	if (tmp-buffer<len) next_via=tmp;
+	
+	/* parse hostport */
+	parse_hostport(hostport, &host, &port);
+	vb->name=name;
+	vb->version=version;
+	vb->transport=transport;
+	vb->host=host;
+	vb->port=port;
+	vb->params=params;
+	vb->comment=comment;
+	vb->next=next_via;
+	vb->error=VIA_PARSE_OK;
+
+	
+	/* tmp points to end of body or to next via (if compact)*/
+	
+	return tmp;
+
+error:
+	vb->error=VIA_PARSE_ERROR;
+	return tmp;
+}
+

+ 75 - 0
msg_parser.h

@@ -0,0 +1,75 @@
+/*
+ * $Id$
+ */
+
+#ifndef msg_parser_h
+#define msg_parser_h
+
+
+#define SIP_REQUEST 1
+#define SIP_REPLY   2
+#define SIP_INVALID 0
+
+
+#define HDR_ERROR 0
+/* end of header */
+#define HDR_EOH   -1
+#define HDR_OTHER 1
+#define HDR_VIA   2
+#define HDR_TO    3
+
+#define VIA_PARSE_OK	1
+#define VIA_PARSE_ERROR -1
+
+#define SIP_VERSION	"SIP/2.0"
+
+
+struct msg_start{
+	int type;
+	union {
+		struct {
+			char* method;
+			char* uri;
+			char* version;
+		}request;
+		struct {
+			char* version;
+			char* status;
+			char* reason;
+		}reply;
+	}u;
+};
+
+struct hdr_field{   /* format: name':' body */
+	int type;
+	char* name;
+	char* body;
+};
+
+struct via_body{  /* format: name/version/transport host:port;params comment */
+	int error;
+	char* name;
+	char* version;
+	char* transport;
+	char* host;
+	int port;
+	char* params;
+	char* comment;
+	char* next; /* pointer to next via body string if compact via or null */
+};
+
+
+
+char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl);
+char* get_hdr_field(char *buffer, unsigned int len, struct hdr_field*  hdr_f);
+int field_name(char *s);
+char* parse_hostport(char* buf, char** host, short int* port);
+char* parse_via_body(char* buffer,unsigned int len, struct via_body * vb);
+
+
+
+
+
+#endif
+ 
+

+ 72 - 0
parser_f.c

@@ -0,0 +1,72 @@
+/*
+ * $Id$
+ *
+ * parser helper  functions
+ *
+ */
+
+#include  "parser_f.h"
+
+/* returns pointer to next line or end of buffer */
+char* eat_line(char* buffer, unsigned int len)
+{
+	char* nl;
+	char c;
+
+	for(nl=buffer;(nl<buffer+len)&& (*nl!='\r')&&(*nl!='\n') ;nl++);
+	c=*nl;
+	if (nl+1<buffer+len)  nl++;
+	if ((nl+1<buffer+len) &&
+			((c=='\r' && *nl=='\n')|| (c=='\n' && *nl=='\r'))) 
+		nl++;
+	return nl;
+}
+
+
+
+/* returns pointer to first non  white char or to the end  of the buffer */
+char* eat_space(char* buffer, unsigned int len)
+{
+	char* p;
+
+	for(p=buffer;(p<buffer+len)&& (*p==' ' || *p=='\t') ;p++);
+	return p;
+}
+
+
+
+/* returns pointer after the token (first whitespace char or CR/LF) */
+char* eat_token(char* buffer, unsigned int len)
+{
+	char *p;
+
+	for (p=buffer;(p<buffer+len)&&
+			(*p!=' ')&&(*p!='\t')&&(*p!='\n')&&(*p!='\r');
+		p++);
+	return p;
+}
+
+
+
+/* returns pointer after the token (first delim char or CR/LF) */
+char* eat_token2(char* buffer, unsigned int len, char delim)
+{
+	char *p;
+
+	for (p=buffer;(p<buffer+len)&&
+			(*p!=delim)&&(*p!='\n')&&(*p!='\r');
+		p++);
+	return p;
+}
+
+
+
+/* returns true if line started  at buffer contains only white space */
+int is_empty(char* buffer, unsigned int len)
+{
+	char *p;
+	
+	p=eat_space(buffer, len);
+	if ((p < buffer+len ) && (*p=='\r' || *p=='\n')) return 1;
+	return 0;
+}

+ 15 - 0
parser_f.h

@@ -0,0 +1,15 @@
+/* 
+ * $Id$
+ */
+
+#ifndef parser_f_h
+#define parser_f_h
+
+char* eat_line(char* buffer, unsigned int len);
+char* eat_space(char* buffer, unsigned int len);
+char* eat_token(char* buffer, unsigned int len);
+char* eat_token2(char* buffer, unsigned int len, char delim);
+int is_empty(char* buffer, unsigned int len);
+
+#endif
+ 

+ 230 - 0
route.c

@@ -0,0 +1,230 @@
+/*
+ * $Id$
+ *
+ * SIP routing engine
+ *
+ */
+ 
+#include <sys/types.h>
+#include <regex.h>
+#include <netdb.h>
+#include <string.h>
+
+#include "route.h"
+#include "cfg_parser.h"
+#include "dprint.h"
+
+/* main routing list */
+struct route_elem* rlist=0;
+
+
+
+void free_re(struct route_elem* r)
+{
+	int i;
+	if (r){
+			regfree(&(r->method));
+			regfree(&(r->uri));
+			
+			if (r->host.h_name)      free(r->host.h_name);
+			if (r->host.h_aliases){
+				for (i=0; r->host.h_aliases[i]; i++)
+					free(r->host.h_aliases[i]);
+				free(r->host.h_aliases);
+			}
+			if (r->host.h_addr_list){
+				for (i=0; r->host.h_addr_list[i]; i++)
+					free(r->host.h_addr_list[i]);
+				free(r->host.h_addr_list);
+			}
+			free(r);
+	}
+}
+
+
+
+struct route_elem* init_re()
+{
+	struct route_elem* r;
+	r=(struct route_elem *) malloc(sizeof(struct route_elem));
+	if (r==0) return 0;
+	memset((void*)r, 0, sizeof (struct route_elem));
+	return r;
+}
+
+
+
+void push(struct route_elem* re, struct route_elem** head)
+{
+	struct route_elem *t;
+	re->next=0;
+	if (*head==0){
+		*head=re;
+		return;
+	}
+	for (t=*head; t->next;t=t->next);
+	t->next=re;
+}
+
+
+
+void clear_rlist(struct route_elem** rl)
+{
+	struct route_elem *t, *u;
+
+	if (*rl==0) return;
+	u=0;
+	for (t=*rl; t; u=t, t=t->next){
+		if (u) free_re(u);
+	}
+	*rl=0;
+}
+
+
+
+int add_rule(struct cfg_line* cl, struct route_elem** head)
+{
+	
+	struct route_elem* re;
+	struct hostent * he;
+	int ret;
+	int i,len, len2;
+
+
+	re=init_re();
+	if (re==0) return E_OUT_OF_MEM;
+
+	if (regcomp(&(re->method), cl->method, REG_EXTENDED|REG_NOSUB|REG_ICASE)){
+		DPrint("ERROR: bad re \"%s\"\n", cl->method);
+		ret=E_BAD_RE;
+		goto error;
+	}
+	if (regcomp(&(re->uri), cl->uri, REG_EXTENDED|REG_NOSUB|REG_ICASE) ){
+		DPrint("ERROR: bad re \"%s\"\n", cl->uri);
+		ret=E_BAD_RE;
+		goto error;
+	}
+
+	
+	he=gethostbyname(cl->address);
+	if (he==0){
+		DPrint("ERROR: cannot resolve \"%s\"\n", cl->address);
+		ret=E_BAD_ADDRESS;
+		goto error;
+	}
+	
+	/* start copying the host entry.. */
+	/* copy h_name */
+	len=strlen(he->h_name)+1;
+	re->host.h_name=(char*)malloc(len);
+	if (re->host.h_name) strncpy(re->host.h_name, he->h_name, len);
+	else{
+		ret=E_OUT_OF_MEM;
+		goto error;
+	}
+
+	/* copy h_aliases */
+	for (len=0;he->h_aliases[len];len++);
+	re->host.h_aliases=(char**)malloc(len+1);
+	if (re->host.h_aliases==0){
+		ret=E_OUT_OF_MEM;
+		goto error;
+	}
+	memset((void*)re->host.h_aliases, 0, sizeof(char*) * (len+1) );
+	for (i=0;i<len;i++){
+		len2=strlen(he->h_aliases[i])+1;
+		re->host.h_aliases[i]=(char*)malloc(len2);
+		if (re->host.h_aliases==0){
+			ret=E_OUT_OF_MEM;
+			goto error;
+		}
+		strncpy(re->host.h_aliases[i], he->h_aliases[i], len2);
+	}
+	/* copy h_addr_list */
+	for (len=0;he->h_addr_list[len];len++);
+	re->host.h_addr_list=(char**)malloc(len+1);
+	if (re->host.h_addr_list==0){
+		ret=E_OUT_OF_MEM;
+		goto error;
+	}
+	memset((void*)re->host.h_addr_list, 0, sizeof(char*) * (len+1) );
+	for (i=0;i<len;i++){
+		re->host.h_addr_list[i]=(char*)malloc(he->h_length+1);
+		if (re->host.h_addr_list==0){
+			ret=E_OUT_OF_MEM;
+			goto error;
+		}
+		memcpy(re->host.h_addr_list[i], he->h_addr_list[i], he->h_length+1);
+	}
+	/* copy h_addr_type & length */
+	re->host.h_addrtype=he->h_addrtype;
+	re->host.h_length=he->h_length;
+	/*finished hostent copy */
+
+	
+	
+	re->current_addr_idx=0;
+	re->ok=1;
+
+	push(re,head);
+	return 0;
+	
+error:
+		free_re(re);
+		return ret;
+}
+
+
+
+struct route_elem* route_match(char* method, char* uri, struct route_elem** rl)
+{
+	struct route_elem* t;
+	if (*rl==0){
+		DPrint("WARNING: empty routing table\n");
+		return 0;
+	}
+	for (t=*rl; t; t=t->next){
+		if (regexec(&(t->method), method, 0, 0, 0)==0){
+			/* we have a method mach !!! */
+			if (regexec(&(t->uri), uri, 0, 0, 0)==0){
+				/* we have a full match */
+				return t;
+			}
+		}
+	}
+	/* no match :( */
+	return 0;
+}
+
+
+
+/* debug function, prints main routing table */
+void print_rl()
+{
+	struct route_elem* t;
+	int i,j;
+
+	if (rlist==0){
+		DPrint("the routing table is emty\n");
+		return;
+	}
+	
+	for (t=rlist,i=0; t; i++, t=t->next){
+		DPrint("%2d.to=%s ; route ok=%d\n", i,
+				t->host.h_name, t->ok);
+		DPrint("   ips: ");
+		for (j=0; t->host.h_addr_list[j]; j++)
+			DPrint("%d.%d.%d.%d ",
+				(unsigned char) t->host.h_addr_list[j][0],
+				(unsigned char) t->host.h_addr_list[j][1],
+			    (unsigned char) t->host.h_addr_list[j][2],
+				(unsigned char) t->host.h_addr_list[j][3]
+				  );
+				
+		DPrint("\n   Statistics: tx=%d, errors=%d, tx_bytes=%d, idx=%d\n",
+				t->tx, t->errors, t->tx_bytes, t->current_addr_idx);
+	}
+
+}
+
+

+ 46 - 0
route.h

@@ -0,0 +1,46 @@
+/*
+ * $Id$
+ */
+
+#ifndef route_h
+#define route_h
+
+#include <sys/types.h>
+#include <regex.h>
+#include <netdb.h>
+
+#include "cfg_parser.h"
+
+#define E_OUT_OF_MEM  -2
+#define E_BAD_RE      -3
+#define E_BAD_ADDRESS -4
+
+struct route_elem{
+	struct route_elem* next;
+	regex_t method;
+	regex_t uri;
+	struct hostent host;
+	int current_addr_idx;
+	int ok; /* set to 0 if an error was found sendig a pkt*/
+	/*counters*/
+	int errors;
+	int tx;
+	int tx_bytes;
+};
+
+/* main "routing table" */
+extern struct route_elem* rlist;
+
+
+void free_re(struct route_elem* re);
+struct route_elem* init_re();
+void push(struct route_elem* re, struct route_elem** head);
+void clear_rlist(struct route_elem** rl);
+int add_rule(struct cfg_line* cl, struct route_elem** head);
+struct route_elem* route_match(char* method, char* uri, struct route_elem** rl);void print_rl();
+
+
+
+
+
+#endif

+ 13 - 0
sip_router.cfg

@@ -0,0 +1,13 @@
+# $Id$
+
+# format:
+#  method_re   sip_uri_re      dest_host
+# (warning: re cannot contain space)
+
+^R.*        ^sip:.*@dorian.*   ekina.fokus.gmd.de        
+^INVITE     .*                 ape             # my laptop
+.           .                  192.168.46.55
+.*			.*andrei		   helios.fokus.gmd.de
+
+
+# end

+ 134 - 0
test.c

@@ -0,0 +1,134 @@
+/*
+ * tst  
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "msg_parser.h"
+#include "dprint.h"
+
+#define BSIZE 1024
+char buf[BSIZE+1];
+
+void main()
+{
+	char* rest;
+	char* tmp;
+	char* first_via;
+	char* second_via;
+	struct msg_start fl;
+	struct hdr_field hf;
+	struct via_body vb1, vb2;
+
+	int len;
+	int offset;
+	int r;
+
+	while(!feof(stdin)){
+		len=fread(buf,1,BSIZE,stdin);
+		buf[len+1]=0;
+		printf("read <%s>(%d)\n",buf,strlen(buf));
+		fflush(stdin);
+	
+		/* eat crlf from the beginning */
+		for (tmp=buf; (*tmp=='\n' || *tmp=='\r')&&
+				tmp-buf < len ; tmp++);
+		offset=tmp-buf;
+		rest=parse_first_line(tmp, len-offset, &fl);
+		offset+=rest-tmp;
+		tmp=rest;
+		switch(fl.type){
+			case SIP_INVALID:
+				printf("invalid message\n");
+				break;
+			case SIP_REQUEST:
+				printf("SIP Request:\n");
+				printf(" method:  <%s>\n",fl.u.request.method);
+				printf(" uri:     <%s>\n",fl.u.request.uri);
+				printf(" version: <%s>\n",fl.u.request.version);
+				break;
+			case SIP_REPLY:
+				printf("SIP Reply  (status):\n");
+				printf(" version: <%s>\n",fl.u.reply.version);
+				printf(" status:  <%s>\n",fl.u.reply.status);
+				printf(" reason:  <%s>\n",fl.u.reply.reason);
+				break;
+			default:
+				printf("unknown type %d\n",fl.type);
+		}
+		
+		/*find first Via: */
+		hf.type=HDR_ERROR;
+		first_via=0;
+		second_via=0;
+		do{
+			rest=get_hdr_field(tmp, len-offset, &hf);
+			offset+=rest-tmp;
+			tmp=rest;
+			switch (hf.type){
+				case HDR_ERROR:
+					DPrint("ERROR: bad header  field\n");
+					goto  error;
+				case HDR_EOH: 
+					goto eoh;
+				case HDR_VIA:
+					if (first_via==0) first_via=hf.body;
+					else if (second_via==0) second_via=hf.body;
+					break;
+			}
+			printf("header field type %d, name=<%s>, body=<%s>\n",
+				hf.type, hf.name, hf.body);
+
+		
+		}while(hf.type!=HDR_EOH && rest-buf < len);
+
+	eoh:
+		/* replace cr/lf with space in first via */
+		for (tmp=first_via;(first_via) && (*tmp);tmp++)
+			if ((*tmp=='\r')||(*tmp=='\n'))	*tmp=' ';
+
+		printf("first via: <%s>\n", first_via);
+		tmp=parse_via_body(first_via, strlen(first_via), &vb1);
+		if (vb1.error!=VIA_PARSE_OK){
+			DPrint("ERROR: parsing via body: %s\n", first_via);
+			goto error;
+		}
+		/* compact via */
+		if (vb1.next) second_via=vb1.next;
+		if (second_via) {
+			tmp=parse_via_body(second_via, strlen(second_via), &vb2);
+			if (vb2.error!=VIA_PARSE_OK){
+				DPrint("ERROR: parsing via body: %s\n", second_via);
+				goto error;
+			}
+		}
+		
+		/* dump parsed data */
+		printf(" first  via: <%s/%s/%s> <%s:%d>",
+				vb1.name, vb1.version, vb1.transport, vb1.host, vb1.port);
+		if (vb1.params) printf(";<%s>", vb1.params);
+		if (vb1.comment) printf(" <%s>", vb1.comment);
+		printf ("\n");
+		if (second_via){
+			printf(" second via: <%s/%s/%s> <%s:%d>",
+					vb2.name, vb2.version, vb2.transport, vb2.host, vb2.port);
+			if (vb2.params) printf(";<%s>", vb2.params);
+			if (vb2.comment) printf(" <%s>", vb2.comment);
+			printf ("\n");
+		}
+
+		
+
+	error:
+		/* find endof msg */
+		printf("rest:(buffer=%x, rest=%x)\n%s\n.\n",buf,rest,rest);
+
+		for (r=0; r<len+1;r++)
+			printf("%02x ", buf[r]);
+		printf("\n*rest=%02x\n",*rest);
+		
+	}
+}
+				
+