--- /dev/null
+/*
+ * $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;
+}
+
--- /dev/null
+/*
+ * $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
--- /dev/null
+/*
+ * $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);
+}
--- /dev/null
+/*
+ * $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 */
--- /dev/null
+/*
+ * $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;
+
+}
--- /dev/null
+/*
+ * $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;
+}
+
--- /dev/null
+/*
+ * $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
+
+
--- /dev/null
+/*
+ * $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;
+}
--- /dev/null
+/*
+ * $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
+
--- /dev/null
+/*
+ * $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);
+ }
+
+}
+
+
--- /dev/null
+/*
+ * $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
--- /dev/null
+# $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
--- /dev/null
+/*
+ * 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);
+
+ }
+}
+
+