Initial revision
authorAndrei Pelinescu-Onciul <andrei@iptel.org>
Mon, 3 Sep 2001 21:27:11 +0000 (21:27 +0000)
committerAndrei Pelinescu-Onciul <andrei@iptel.org>
Mon, 3 Sep 2001 21:27:11 +0000 (21:27 +0000)
24 files changed:
.cfg_parser.c.swp [new file with mode: 0644]
.cfg_parser.h.swp [new file with mode: 0644]
.main.c.swp [new file with mode: 0644]
.msg_parser.c.swp [new file with mode: 0644]
.msg_parser.h.swp [new file with mode: 0644]
.parser_f.c.swp [new file with mode: 0644]
.parser_f.h.swp [new file with mode: 0644]
.route.c.swp [new file with mode: 0644]
.route.h.swp [new file with mode: 0644]
.sip_router.cfg.swp [new file with mode: 0644]
.test.c.swp [new file with mode: 0644]
cfg_parser.c [new file with mode: 0644]
cfg_parser.h [new file with mode: 0644]
dprint.c [new file with mode: 0644]
dprint.h [new file with mode: 0644]
main.c [new file with mode: 0644]
msg_parser.c [new file with mode: 0644]
msg_parser.h [new file with mode: 0644]
parser_f.c [new file with mode: 0644]
parser_f.h [new file with mode: 0644]
route.c [new file with mode: 0644]
route.h [new file with mode: 0644]
sip_router.cfg [new file with mode: 0644]
test.c [new file with mode: 0644]

diff --git a/.cfg_parser.c.swp b/.cfg_parser.c.swp
new file mode 100644 (file)
index 0000000..8301019
Binary files /dev/null and b/.cfg_parser.c.swp differ
diff --git a/.cfg_parser.h.swp b/.cfg_parser.h.swp
new file mode 100644 (file)
index 0000000..08e7493
Binary files /dev/null and b/.cfg_parser.h.swp differ
diff --git a/.main.c.swp b/.main.c.swp
new file mode 100644 (file)
index 0000000..8891072
Binary files /dev/null and b/.main.c.swp differ
diff --git a/.msg_parser.c.swp b/.msg_parser.c.swp
new file mode 100644 (file)
index 0000000..25438c7
Binary files /dev/null and b/.msg_parser.c.swp differ
diff --git a/.msg_parser.h.swp b/.msg_parser.h.swp
new file mode 100644 (file)
index 0000000..285ef5a
Binary files /dev/null and b/.msg_parser.h.swp differ
diff --git a/.parser_f.c.swp b/.parser_f.c.swp
new file mode 100644 (file)
index 0000000..5375d2f
Binary files /dev/null and b/.parser_f.c.swp differ
diff --git a/.parser_f.h.swp b/.parser_f.h.swp
new file mode 100644 (file)
index 0000000..5724bcf
Binary files /dev/null and b/.parser_f.h.swp differ
diff --git a/.route.c.swp b/.route.c.swp
new file mode 100644 (file)
index 0000000..bcca88c
Binary files /dev/null and b/.route.c.swp differ
diff --git a/.route.h.swp b/.route.h.swp
new file mode 100644 (file)
index 0000000..e3452d2
Binary files /dev/null and b/.route.h.swp differ
diff --git a/.sip_router.cfg.swp b/.sip_router.cfg.swp
new file mode 100644 (file)
index 0000000..ea4adaa
Binary files /dev/null and b/.sip_router.cfg.swp differ
diff --git a/.test.c.swp b/.test.c.swp
new file mode 100644 (file)
index 0000000..85711a8
Binary files /dev/null and b/.test.c.swp differ
diff --git a/cfg_parser.c b/cfg_parser.c
new file mode 100644 (file)
index 0000000..85ec804
--- /dev/null
@@ -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;
+}
+
diff --git a/cfg_parser.h b/cfg_parser.h
new file mode 100644 (file)
index 0000000..627afbf
--- /dev/null
@@ -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
diff --git a/dprint.c b/dprint.c
new file mode 100644 (file)
index 0000000..3a94e15
--- /dev/null
+++ b/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);
+}
diff --git a/dprint.h b/dprint.h
new file mode 100644 (file)
index 0000000..356a79a
--- /dev/null
+++ b/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 */
diff --git a/main.c b/main.c
new file mode 100644 (file)
index 0000000..d07bd80
--- /dev/null
+++ b/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;
+
+}
diff --git a/msg_parser.c b/msg_parser.c
new file mode 100644 (file)
index 0000000..b800142
--- /dev/null
@@ -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;
+}
+
diff --git a/msg_parser.h b/msg_parser.h
new file mode 100644 (file)
index 0000000..7a243a0
--- /dev/null
@@ -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
+
diff --git a/parser_f.c b/parser_f.c
new file mode 100644 (file)
index 0000000..69bd018
--- /dev/null
@@ -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;
+}
diff --git a/parser_f.h b/parser_f.h
new file mode 100644 (file)
index 0000000..48f9701
--- /dev/null
@@ -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
diff --git a/route.c b/route.c
new file mode 100644 (file)
index 0000000..06cb2b7
--- /dev/null
+++ b/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);
+       }
+
+}
+
+
diff --git a/route.h b/route.h
new file mode 100644 (file)
index 0000000..bb27f7f
--- /dev/null
+++ b/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
diff --git a/sip_router.cfg b/sip_router.cfg
new file mode 100644 (file)
index 0000000..56d90c1
--- /dev/null
@@ -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
diff --git a/test.c b/test.c
new file mode 100644 (file)
index 0000000..d395060
--- /dev/null
+++ b/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);
+               
+       }
+}
+                               
+