/* * $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(sizeof(char) * 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(sizeof(char*)*(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(sizeof(char)*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(sizeof(char*)*(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(sizeof(char)*he->h_length); if (re->host.h_addr_list[i]==0){ ret=E_OUT_OF_MEM; goto error; } memcpy(re->host.h_addr_list[i], he->h_addr_list[i], he->h_length); } /* copy h_addr_type & length */ re->host.h_addrtype=he->h_addrtype; re->host.h_length=he->h_length; /*finished hostent copy */ re->port=cl->port; 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 empty\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"); DPrint(" port:%d\n", (unsigned short)t->port); DPrint(" Statistics: tx=%d, errors=%d, tx_bytes=%d, idx=%d\n", t->tx, t->errors, t->tx_bytes, t->current_addr_idx); } }