Browse Source

parser directory cleanup

Jan Janak 23 years ago
parent
commit
2bb60634ee

+ 1 - 1
main.c

@@ -34,7 +34,7 @@
 #include "parser/msg_parser.h"
 #include "ip_addr.h"
 #include "resolve.h"
-
+#include "parser/parse_hname2.h"
 
 
 #include "stats.h"

+ 56 - 0
parser/hf.c

@@ -0,0 +1,56 @@
+/* 
+ * $Id$ 
+ */
+
+#include "hf.h"
+#include "parse_via.h"
+#include "parse_to.h"
+#include "parse_cseq.h"
+#include "../dprint.h"
+#include "../mem/mem.h"
+#include "parse_def.h"
+
+
+/* 
+ * Frees a hdr_field structure,
+ * WARNING: it frees only parsed (and not name.s, body.s)
+ */
+void clean_hdr_field(struct hdr_field* hf)
+{
+	if (hf->parsed){
+		switch(hf->type){
+		case HDR_VIA:
+			free_via_list(hf->parsed);
+			break;
+
+		case HDR_TO:
+			free_to(hf->parsed);
+			break;
+
+		case HDR_CSEQ:
+			free_cseq(hf->parsed);
+			break;
+
+		default:
+			LOG(L_CRIT, "BUG: clean_hdr_field: unknown header type %d\n",
+			    hf->type);
+			break;
+		}
+	}
+}
+
+
+/* 
+ * Frees a hdr_field list,
+ * WARNING: frees only ->parsed and ->next*/
+void free_hdr_field_lst(struct hdr_field* hf)
+{
+	struct hdr_field* foo;
+	
+	while(hf) {
+		foo=hf;
+		hf=hf->next;
+		clean_hdr_field(foo);
+		pkg_free(foo);
+	}
+}

+ 54 - 0
parser/hf.h

@@ -0,0 +1,54 @@
+/* 
+ * $Id$ 
+ */
+
+#ifndef HF_H
+#define HF_H
+
+#include "../str.h"
+
+
+/* Header types and flags */
+#define HDR_EOH              -1  /* End of header found */
+#define HDR_ERROR             0  /* Error while parsing */
+#define HDR_VIA               1  /* Via header field */
+#define HDR_VIA1              1  /* First Via header field */
+#define HDR_VIA2              2  /* only used as flag*/
+#define HDR_TO                4  /* To header field */
+#define HDR_FROM              8  /* From header field */
+#define HDR_CSEQ             16  /* CSeq header field */
+#define HDR_CALLID           32  /* Call-Id header field */
+#define HDR_CONTACT          64  /* Contact header field */
+#define HDR_MAXFORWARDS     128  /* MaxForwards header field */
+#define HDR_ROUTE           256  /* Route header field */
+#define HDR_RECORDROUTE     512  /* Record-Route header field */
+#define HDR_CONTENTTYPE    1024  /* Content-Type header field */
+#define HDR_CONTENTLENGTH  2048  /* Content-Length header field */
+#define HDR_OTHER         65536  /* Unknown header type */ 
+
+
+/* 
+ * Format: name':' body 
+ */
+struct hdr_field {   
+	int type;                /* Header field type */
+	str name;                /* Header field name */
+	str body;                /* Header field body */
+	void* parsed;            /* Parsed data structures */
+	struct hdr_field* next;  /* Next header field in the list */
+};
+
+
+/* frees a hdr_field structure,
+ * WARNING: it frees only parsed (and not name.s, body.s)
+ */
+void clean_hdr_field(struct hdr_field* hf);
+
+
+/* frees a hdr_field list,
+ * WARNING: frees only ->parsed and ->next
+ */
+void free_hdr_field_lst(struct hdr_field* hf);
+
+
+#endif

+ 8 - 520
parser/msg_parser.c

@@ -17,185 +17,20 @@
 #include "../mem/mem.h"
 #include "../error.h"
 #include "../globals.h"
+#include "parse_hname.h"
+#include "parse_hname2.h"
+
 
 #ifdef DEBUG_DMALLOC
 #include <mem/dmalloc.h>
 #endif
 
 
-
-
-
-/* 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;
-	/* int l; */
-	char* end;
-	char s1,s2,s3;
-	char *prn;
-	unsigned int t;
-
-	/* grammar:
-		request  =  method SP uri SP version CRLF
-		response =  version SP status  SP reason  CRLF
-		(version = "SIP/2.0")
-	*/
-	
-
-	end=buffer+len;
-	/* see if it's a reply (status) */
-
-	/* jku  -- parse well-known methods */
-
-	/* drop messages which are so short they are for sure useless;
-           utilize knowledge of minimum size in parsing the first
-	   token 
-        */
-	if (len <=16 ) {
-		LOG(L_INFO, "ERROR: parse_first_line: message too short: %d\n", len);
-		goto error1;
-	}
-
-	tmp=buffer;
-  	/* is it perhaps a reply, ie does it start with "SIP...." ? */
-	if ( 	(*tmp=='S' || *tmp=='s') && 
-		strncasecmp( tmp+1, SIP_VERSION+1, SIP_VERSION_LEN-1)==0 &&
-		(*(tmp+SIP_VERSION_LEN)==' ')) {
-			fl->type=SIP_REPLY;
-			fl->u.reply.version.len=SIP_VERSION_LEN;
-			tmp=buffer+SIP_VERSION_LEN;
-	} else IFISMETHOD( INVITE, 'I' )
-	else IFISMETHOD( CANCEL, 'C')
-	else IFISMETHOD( ACK, 'A' )
-	else IFISMETHOD( BYE, 'B' ) 
-	/* if you want to add another method XXX, include METHOD_XXX in
-           H-file (this is the value which you will take later in
-           processing and define XXX_LEN as length of method name;
-	   then just call IFISMETHOD( XXX, 'X' ) ... 'X' is the first
-	   latter; everything must be capitals
-	*/
-	else {
-		/* neither reply, nor any of known method requests, 
-		   let's believe it is an unknown method request
-        	*/
-		tmp=eat_token_end(buffer,buffer+len);
-		if ((tmp==buffer)||(tmp>=end)){
-			LOG(L_INFO, "ERROR:parse_first_line: empty  or bad first line\n");
-			goto error1;
-		}
-		if (*tmp!=' ') {
-			LOG(L_INFO, "ERROR:parse_first_line: method not followed by SP\n");
-			goto error1;
-		}
-		fl->type=SIP_REQUEST;
-		fl->u.request.method_value=METHOD_OTHER;
-		fl->u.request.method.len=tmp-buffer;
-	}
-
-
-	/* identifying type of message over now; 
-	   tmp points at space after; go ahead */
-
-	fl->u.request.method.s=buffer;  /* store ptr to first token */
-	(*tmp)=0;			/* mark the 1st token end */
-	second=tmp+1;			/* jump to second token */
-	offset=second-buffer;
-
-/* EoJku */
-	
-	/* next element */
-	tmp=eat_token_end(second, second+len-offset);
-	if (tmp>=end){
-		goto error;
-	}
-	offset+=tmp-second;
-	third=eat_space_end(tmp, tmp+len-offset);
-	offset+=third-tmp;
-	if ((third==tmp)||(tmp>=end)){
-		goto error;
-	}
-	*tmp=0; /* mark the end of the token */
-	fl->u.request.uri.s=second;
-	fl->u.request.uri.len=tmp-second;
-
-	/* jku: parse status code */
-	if (fl->type==SIP_REPLY) {
-		if (fl->u.request.uri.len!=3) {
-			LOG(L_INFO, "ERROR:parse_first_line: len(status code)!=3: %s\n",
-				second );
-			goto error;
-		}
-		s1=*second; s2=*(second+1);s3=*(second+2);
-		if (s1>='0' && s1<='9' && 
-		    s2>='0' && s2<='9' &&
-		    s3>='0' && s3<='9' ) {
-			fl->u.reply.statuscode=(s1-'0')*100+10*(s2-'0')+(s3-'0');
-		} else {
-			LOG(L_INFO, "ERROR:parse_first_line: status_code non-numerical: %s\n",
-				second );
-			goto error;
-		}
-	}
-	/* EoJku */
-
-	/*  last part: for a request it must be the version, for a reply
-	 *  it can contain almost anything, including spaces, so we don't care
-	 *  about it*/
-	if (fl->type==SIP_REQUEST){
-		tmp=eat_token_end(third,third+len-offset);
-		offset+=tmp-third;
-		if ((tmp==third)||(tmp>=end)){
-			goto error;
-		}
-		if (! is_empty_end(tmp, tmp+len-offset)){
-			goto error;
-		}
-	}else{
-		tmp=eat_token2_end(third,third+len-offset,'\r'); /* find end of line 
-												  ('\n' or '\r') */
-		if (tmp>=end){ /* no crlf in packet => invalid */
-			goto error;
-		}
-		offset+=tmp-third;
-	}
-	nl=eat_line(tmp,len-offset);
-	if (nl>=end){ /* no crlf in packet or only 1 line > invalid */
-		goto error;
-	}
-	*tmp=0;
-	fl->u.request.version.s=third;
-	fl->u.request.version.len=tmp-third;
-
-	return nl;
-
-error:
-	LOG(L_INFO, "ERROR:parse_first_line: bad %s first line\n",
-		(fl->type==SIP_REPLY)?"reply(status)":"request");
-
-	LOG(L_INFO, "ERROR: at line 0 char %d: \n", offset );
-	prn=pkg_malloc( offset );
-	if (prn) {
-		for (t=0; t<offset; t++)
-			if (*(buffer+t)) *(prn+t)=*(buffer+t);
-			else *(prn+t)='°';
-		LOG(L_INFO, "ERROR: parsed so far: %.*s\n", offset, prn );
-		pkg_free( prn );
-	};
-error1:
-	fl->type=SIP_INVALID;
-	LOG(L_INFO, "ERROR:parse_first_line: bad message\n");
-	/* skip  line */
-	nl=eat_line(buffer,len);
-	return nl;
-}
-
+#ifdef NEW_HNAME
+#	define parse_hname(_b,_e,_h) parse_hname2((_b),(_e),(_h))
+#else
+#	define parse_hname(_b,_e,_h) parse_hname1((_b),(_e),(_h))
+#endif
 
 
 /* returns pointer to next header line, and fill hdr_f ;
@@ -326,267 +161,6 @@ error:
 
 
 
-char* parse_hostport(char* buf, str* host, short int* port)
-{
-	char *tmp;
-	int err;
-
-	host->s=buf;
-	for(tmp=buf;(*tmp)&&(*tmp!=':');tmp++);
-	host->len=tmp-buf;
-	if (*tmp==0){
-		*port=0;
-	}else{
-		*tmp=0;
-		*port=str2s((unsigned char*)(tmp+1), strlen(tmp+1), &err);
-		if (err ){
-			LOG(L_INFO, 
-					"ERROR: hostport: trailing chars in port number: %s\n",
-					tmp+1);
-			/* report error? */
-		}
-	}
-	return host->s;
-}
-
-
-
-/*BUGGY*/
-char * parse_cseq(char *buf, char* end, struct cseq_body* cb)
-{
-	char *t, *m, *m_end;
-	char c;
-
-	cb->error=PARSE_ERROR;
-	t=eat_space_end(buf, end);
-	if (t>=end) goto error;
-	
-	cb->number.s=t;
-	t=eat_token_end(t, end);
-	if (t>=end) goto error;
-	m=eat_space_end(t, end);
-	m_end=eat_token_end(m, end);
-	*t=0; /*null terminate it*/
-	cb->number.len=t-cb->number.s;
-
-	if (m_end>=end) goto error;
-	if (m_end==m){
-		/* null method*/
-		LOG(L_ERR,  "ERROR:parse_cseq: no method found\n");
-		goto error;
-	}
-	cb->method.s=m;
-	t=m_end;
-	c=*t;
-	*t=0; /*null terminate it*/
-	cb->method.len=t-cb->method.s;
-	t++;
-	/*check if the header ends here*/
-	if (c=='\n') goto check_continue;
-	do{
-		for (;(t<end)&&((*t==' ')||(*t=='\t')||(*t=='\r'));t++);
-		if (t>=end) goto error;
-		if (*t!='\n'){
-			LOG(L_ERR, "ERROR:parse_cseq: unexpected char <%c> at end of"
-					" cseq\n", *t);
-			goto error;
-		}
-		t++;
-check_continue:
-		;
-	}while( (t<end) && ((*t==' ')||(*t=='\t')) );
-
-	cb->error=PARSE_OK;
-	return t;
-error:
-	LOG(L_ERR, "ERROR: parse_cseq: bad cseq\n");
-	return t;
-}
-
-
-
-/* buf= pointer to begining of uri (sip:[email protected]:5060;a=b?h=i)
-   len= len of uri
-returns: fills uri & returns <0 on error or 0 if ok */
-int parse_uri(char *buf, int len, struct sip_uri* uri)
-{
-	char* next, *end;
-	char *user, *passwd, *host, *port, *params, *headers, *ipv6;
-	int host_len, port_len, params_len, headers_len;
-	int ret;
-	
-
-	ret=0;
-	host_len=0;
-	end=buf+len;
-	memset(uri, 0, sizeof(struct sip_uri)); /* zero it all, just to be sure */
-	/* look for "sip:"*/;
-	next=q_memchr(buf, ':',  len);
-	if ((next==0)||(strncmp(buf,"sip",next-buf)!=0)){
-		LOG(L_DBG, "ERROR: parse_uri: bad sip uri\n");
-		ser_error=ret=E_BAD_URI;
-		goto error;
-	}
-	buf=next+1; /* next char after ':' */
-	if (buf>end){
-		LOG(L_DBG, "ERROR: parse_uri: uri too short\n");
-		ser_error=ret=E_BAD_URI;
-		goto error;
-	}
-	/*look for '@' */
-	next=q_memchr(buf,'@', end-buf);
-	if (next==0){
-		/* no '@' found, => no userinfo */
-		uri->user.s=0;
-		uri->passwd.s=0;
-		host=buf;
-	}else{
-		/* found it */
-		user=buf;
-		/* try to find passwd */
-		passwd=q_memchr(user,':', next-user);
-		if (passwd==0){
-			/* no ':' found => no password */
-			uri->passwd.s=0;
-			uri->user.s=(char*)pkg_malloc(next-user+1);
-			if (uri->user.s==0){
-				LOG(L_ERR,"ERROR:parse_uri: memory allocation failure\n");
-				ser_error=ret=E_OUT_OF_MEM;
-				goto error;
-			}
-			memcpy(uri->user.s, user, next-user);
-			uri->user.len=next-user;
-			uri->user.s[next-user]=0; /* null terminate it, 
-									   usefull for easy printing*/
-		}else{
-			uri->user.s=(char*)pkg_malloc(passwd-user+1);
-			if (uri->user.s==0){
-				LOG(L_ERR,"ERROR:parse_uri: memory allocation failure\n");
-				ser_error=ret=E_OUT_OF_MEM;
-				goto error;
-			}
-			memcpy(uri->user.s, user, passwd-user);
-			uri->user.len=passwd-user;
-			uri->user.s[passwd-user]=0;
-			passwd++; /*skip ':' */
-			uri->passwd.s=(char*)pkg_malloc(next-passwd+1);
-			if (uri->passwd.s==0){
-				LOG(L_ERR,"ERROR:parse_uri: memory allocation failure\n");
-				ser_error=ret=E_OUT_OF_MEM;
-				goto error;
-			}
-			memcpy(uri->passwd.s, passwd, next-passwd);
-			uri->passwd.len=next-passwd;
-			uri->passwd.s[next-passwd]=0;
-		}
-		host=next+1; /* skip '@' */
-	}
-	/* try to find the rest */
-	if(host>=end){
-		LOG(L_DBG, "ERROR: parse_uri: missing hostport\n");
-		ser_error=ret=E_UNSPEC;
-		goto error;
-	}
-	next=host;
-	ipv6=q_memchr(host, '[', end-host);
-	if (ipv6){
-		host=ipv6+1; /* skip '[' in "[3ffe::abbcd]" */
-		if (host>=end){
-			LOG(L_DBG, "ERROR: parse_uri: bad ipv6 uri\n");
-			ret=E_UNSPEC;
-			goto error;
-		}
-		ipv6=q_memchr(host, ']', end-host);
-		if ((ipv6==0)||(ipv6==host)){
-			LOG(L_DBG, "ERROR: parse_uri: bad ipv6 uri - null address"
-					" or missing ']'\n");
-			ret=E_UNSPEC;
-			goto error;
-		}
-		host_len=ipv6-host;
-		next=ipv6;
-	}
-
-		
-	headers=q_memchr(next,'?',end-next);
-	params=q_memchr(next,';',end-next);
-	port=q_memchr(next,':',end-next);
-	if (host_len==0){ /* host not ipv6 addr */
-		host_len=(port)?port-host:(params)?params-host:(headers)?headers-host:
-				end-host;
-	}
-	/* get host */
-	uri->host.s=pkg_malloc(host_len+1);
-	if (uri->host.s==0){
-		LOG(L_ERR, "ERROR: parse_uri: memory allocation error\n");
-		ret=E_OUT_OF_MEM;
-		goto error;
-	}
-	memcpy(uri->host.s, host, host_len);
-	uri->host.len=host_len;
-	uri->host.s[host_len]=0;
-	/* get port*/
-	if ((port)&&(port+1<end)){
-		port++;
-		if ( ((params) &&(params<port))||((headers) &&(headers<port)) ){
-			/* error -> invalid uri we found ';' or '?' before ':' */
-			LOG(L_DBG, "ERROR: parse_uri: malformed sip uri\n");
-			ser_error=ret=E_BAD_URI;
-			goto error;
-		}
-		port_len=(params)?params-port:(headers)?headers-port:end-port;
-		uri->port.s=pkg_malloc(port_len+1);
-		if (uri->port.s==0){
-			LOG(L_ERR, "ERROR: parse_uri: memory allocation error\n");
-			ser_error=ret=E_OUT_OF_MEM;
-			goto error;
-		}
-		memcpy(uri->port.s, port, port_len);
-		uri->port.len=port_len;
-		uri->port.s[port_len]=0;
-	}else uri->port.s=0;
-	/* get params */
-	if ((params)&&(params+1<end)){
-		params++;
-		if ((headers) && (headers<params)){
-			/* error -> invalid uri we found '?' or '?' before ';' */
-			LOG(L_DBG, "ERROR: parse_uri: malformed sip uri\n");
-			ser_error=ret=E_BAD_URI;
-			goto error;
-		}
-		params_len=(headers)?headers-params:end-params;
-		uri->params.s=pkg_malloc(params_len+1);
-		if (uri->params.s==0){
-			LOG(L_ERR, "ERROR: parse_uri: memory allocation error\n");
-			ser_error=ret=E_OUT_OF_MEM;
-			goto error;
-		}
-		memcpy(uri->params.s, params, params_len);
-		uri->params.len=params_len;
-		uri->params.s[params_len]=0;
-	}else uri->params.s=0;
-	/*get headers */
-	if ((headers)&&(headers+1<end)){
-		headers++;
-		headers_len=end-headers;
-		uri->headers.s=pkg_malloc(headers_len+1);
-		if(uri->headers.s==0){
-			LOG(L_ERR, "ERROR: parse_uri: memory allocation error\n");
-			ser_error=ret=E_OUT_OF_MEM;
-			goto error;
-		}
-		memcpy(uri->headers.s, headers, headers_len);
-		uri->headers.len=headers_len;
-		uri->headers.s[headers_len]=0;
-	}else uri->headers.s=0;
-	
-	return ret;
-error:
-	free_uri(uri);
-	return ret;
-}
-
-
 /* parse the headers and adds them to msg->headers and msg->to, from etc.
  * It stops when all the headers requested in flags were parsed, on error
  * (bad header) or end of headers */
@@ -811,18 +385,6 @@ error:
 
 
 
-void free_uri(struct sip_uri* u)
-{
-	if (u){
-		if (u->user.s)    pkg_free(u->user.s);
-		if (u->passwd.s)  pkg_free(u->passwd.s);
-		if (u->host.s)    pkg_free(u->host.s);
-		if (u->port.s)    pkg_free(u->port.s);
-		if (u->params.s)  pkg_free(u->params.s);
-		if (u->headers.s) pkg_free(u->headers.s);
-	}
-}
-
 void free_reply_lump( struct lump_rpl *lump)
 {
 	struct lump_rpl *foo, *bar;
@@ -834,80 +396,6 @@ void free_reply_lump( struct lump_rpl *lump)
 	}
 }
 
-void free_via_param_list(struct via_param* vp)
-{
-	struct via_param* foo;
-	while(vp){
-		foo=vp;
-		vp=vp->next;
-		pkg_free(foo);
-	}
-}
-
-
-
-void free_via_list(struct via_body* vb)
-{
-	struct via_body* foo;
-	while(vb){
-		foo=vb;
-		vb=vb->next;
-		if (foo->param_lst) free_via_param_list(foo->param_lst);
-		pkg_free(foo);
-	}
-}
-
-void free_to(struct to_body* tb)
-{
-	struct to_param *tp=tb->param_lst;
-	struct to_param *foo;
-	while (tp){
-		foo = tp->next;
-		pkg_free(tp);
-		tp=foo;
-	}
-	pkg_free(tb);
-}
-
-/* frees a hdr_field structure,
- * WARNING: it frees only parsed (and not name.s, body.s)*/
-void clean_hdr_field(struct hdr_field* hf)
-{
-	if (hf->parsed){
-		switch(hf->type){
-			case HDR_VIA:
-				free_via_list(hf->parsed);
-				break;
-			case HDR_TO:
-				free_to(hf->parsed);
-				break;
-			case HDR_CSEQ:
-				pkg_free(hf->parsed);
-				break;
-			default:
-				LOG(L_CRIT, "BUG: clean_hdr_field: unknown header type %d\n",
-						hf->type);
-		}
-	}
-}
-
-
-
-/* frees a hdr_field list,
- * WARNING: frees only ->parsed and ->next*/
-void free_hdr_field_lst(struct hdr_field* hf)
-{
-	struct hdr_field* foo;
-	
-	while(hf){
-		foo=hf;
-		hf=hf->next;
-		clean_hdr_field(foo);
-		pkg_free(foo);
-	}
-}
-
-
 
 /*only the content*/
 void free_sip_msg(struct sip_msg* msg)

+ 42 - 206
parser/msg_parser.h

@@ -9,71 +9,23 @@
 #include "../data_lump.h"
 #include "../flags.h"
 #include "../ip_addr.h"
+#include "parse_def.h"
+#include "parse_cseq.h"
+#include "parse_to.h"
+#include "parse_via.h"
+#include "parse_uri.h"
+#include "parse_fline.h"
+#include "hf.h"
 
-#define SIP_REQUEST 1
-#define SIP_REPLY   2
-#define SIP_INVALID 0
 
-
-
-/*header types and flags*/
-#define HDR_EOH             -1
-#define HDR_ERROR            0
-#define HDR_VIA              1
-#define HDR_VIA1             1
-#define HDR_VIA2             2  /*only used as flag*/
-#define HDR_TO               4
-#define HDR_FROM             8
-#define HDR_CSEQ            16
-#define HDR_CALLID          32
-#define HDR_CONTACT         64
-#define HDR_MAXFORWARDS    128
-#define HDR_ROUTE          256
-#define HDR_RECORDROUTE    512
-#define HDR_CONTENTTYPE   1024
-#define HDR_CONTENTLENGTH 2048
-#define HDR_OTHER        65536 /*unknown header type*/
-
-
-/* maximum length of values appended to Via-branch parameter */
+/* Maximum length of values appended to Via-branch parameter */
 #ifdef USE_SYNONIM
 #define MAX_BRANCH_PARAM_LEN  22
 #else
 #define MAX_BRANCH_PARAM_LEN  48
 #endif
-/* via param types
- * WARNING: keep in sync w/ FIN_*, GEN_PARAM and PARAM_ERROR from via_parse.c*/
-enum{
-		PARAM_HIDDEN=230, PARAM_TTL, PARAM_BRANCH, PARAM_MADDR, PARAM_RECEIVED,
-		GEN_PARAM,
-		PARAM_ERROR
-};
-
-enum{
-		TAG_PARAM=400, GENERAL_PARAM
-};
-
-/* casting macro for accessing CSEQ body */
-#define get_cseq( p_msg)  ((struct cseq_body*)(p_msg)->cseq->parsed)
-#define get_to( p_msg)      ((struct to_body*)(p_msg)->to->parsed)
-
-#ifdef NEW_HNAME
-#	define parse_hname(_b,_e,_h) parse_hname2((_b),(_e),(_h))
-	void init_htable(void);
-#else
-#	define parse_hname(_b,_e,_h) parse_hname1((_b),(_e),(_h))
-#endif
 
 
-#define INVITE_LEN	6
-#define ACK_LEN		3
-#define CANCEL_LEN	6
-#define BYE_LEN		3
-
-#define CANCEL	"CANCEL"
-#define ACK		"ACK"
-#define INVITE "INVITE"
-
 /* convenience short-cut macros */
 #define REQ_LINE(_msg) ((_msg)->first_line.u.request)
 #define REQ_METHOD first_line.u.request.method_value
@@ -93,109 +45,18 @@ if (  (*tmp==(firstchar) || *tmp==((firstchar) | 32)) &&                  \
 }
 
 
-#define VIA_PARSE_OK	1
-#define VIA_PARSE_ERROR -1
-#define PARSE_ERROR -1
-#define PARSE_OK 1
-
-#define SIP_VERSION	"SIP/2.0"
-#define SIP_VERSION_LEN 7
-
-
-struct msg_start{
-	int type;
-	union {
-		struct {
-			str method;
-			str uri;
-			str version;
-			int method_value;
-		}request;
-		struct {
-			str version;
-			str status;
-			str reason;
-			unsigned int /* statusclass,*/ statuscode;
-		}reply;
-	}u;
-};
-
-struct hdr_field{   /* format: name':' body */
-	int type;
-	str name;
-	str body;
-	void* parsed;
-	struct hdr_field* next;
-};
-
-
-
-struct via_param{
-	int type;
-	str name;
-	str value;
-	int size; /* total size*/
-	struct via_param* next;
-};
-
-struct via_body{  /* format: name/version/transport host:port;params comment */
-	int error;
-	str hdr;   /* contains "Via" or "v" */
-	str name;
-	str version;
-	str transport;
-	str host;
-	int port;
-	str port_str;
-	str params;
-	str comment;
-	int bsize;    /* body size, not including hdr */
-	struct via_param* param_lst; /* list of parameters*/
-	struct via_param* last_param; /*last via parameter, internal use*/
-	/* shortcuts to "important" params*/
-	struct via_param* branch;
-
-	struct via_body* next; /* pointer to next via body string if
-         compact via or null */
-};
-
-
-
-struct to_param{
-	int type;
-	str name;
-	str value;
-	struct to_param* next;
-};
-
-struct to_body{
-	int error;
-	str body;
-	str uri;
-	str tag_value;
-	struct to_param *param_lst;
-	struct to_param *last_param;
-};
-
-
-struct cseq_body{
-	int error;
-	str number;
-	str method;
-};
+struct sip_msg {
+	unsigned int id;               /* message id, unique/process*/
+	struct msg_start first_line;   /* Message first line */
+	struct via_body* via1;         /* The first via */
+	struct via_body* via2;         /* The second via */
+	struct hdr_field* headers;     /* All the parsed headers*/
+	struct hdr_field* last_header; /* Pointer to the last parsed header*/
+	int parsed_flag;               /* Already parsed header field types */
 
+	     /* Via, To, CSeq, Call-Id, From, end of header*/
+	     /* first occurance of it; subsequent occurances saved in 'headers' */
 
-
-struct sip_msg{
-	unsigned int id; /* message id, unique/process*/
-	struct msg_start first_line;
-	struct via_body* via1;
-	struct via_body* via2;
-	struct hdr_field* headers; /* all the parsed headers*/
-	struct hdr_field* last_header; /* pointer to the last parsed header*/
-	int parsed_flag;
-	/* via, to, cseq, call-id, from, end of header*/
-	/* first occurance of it; subsequent occurances saved in 'headers' */
 	struct hdr_field* h_via1;
 	struct hdr_field* h_via2;
 	struct hdr_field* callid;
@@ -208,72 +69,47 @@ struct sip_msg{
 	struct hdr_field* record_route;
 	struct hdr_field* content_type;
 	struct hdr_field* content_length;
-	char* eoh; /* pointer to the end of header (if found) or null */
-	char* unparsed; /* here we stopped parsing*/
+
+	char* eoh;        /* pointer to the end of header (if found) or null */
+	char* unparsed;   /* here we stopped parsing*/
 
 	struct ip_addr src_ip;
 	struct ip_addr dst_ip;
-	char* orig; /* original message copy */
-	char* buf;  /* scratch pad, holds a modfied message,
-				   via, etc. point into it */
+	
+	char* orig;       /* original message copy */
+	char* buf;        /* scratch pad, holds a modfied message,
+			   *  via, etc. point into it 
+			   */
 	unsigned int len; /* message len (orig) */
 
-	/* modifications */
+	     /* modifications */
+	
 	str new_uri; /* changed first line uri*/
-
-	struct lump* add_rm;      /* used for all the forwarded messages */
-	struct lump* repl_add_rm; /* only for localy generated replies !!!*/
+	
+	struct lump* add_rm;         /* used for all the forwarded messages */
+	struct lump* repl_add_rm;    /* only for localy generated replies !!!*/
 	struct lump_rpl *reply_lump;
-
-	/* str add_to_branch; */ /* whatever whoever want to append to branch comes here */
+	
+	     /* str add_to_branch */ 
+	     /* whatever whoever want to append to branch comes here */
 	char add_to_branch_s[MAX_BRANCH_PARAM_LEN];
 	int add_to_branch_len;
-
-	/* index to TM hash table; stored in core to avoid unnecessary calcs */
+	
+	     /* index to TM hash table; stored in core to avoid unnecessary calcs */
 	unsigned int  hash_index;
-
-	/* allows to set various flags on the message; may be used for 
-	   simple inter-module communication or remembering processing state
-	   reached */
-	flag_t flags;
-
 	
+	     /* allows to set various flags on the message; may be used for 
+	      *	simple inter-module communication or remembering processing state
+	      * reached 
+	      */
+	flag_t flags;	
 };
 
 
-struct sip_uri{
-	str user;
-	str passwd;
-	str host;
-	str port;
-	str params;
-	str headers;
-};
-
-
-char* parse_fline(char* buffer, char* end, struct msg_start* fl);
-char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl);
-char* parse_hostport(char* buf, str* host, short int* port);
-
 int parse_msg(char* buf, unsigned int len, struct sip_msg* msg);
-int parse_uri(char *buf, int len, struct sip_uri* uri);
-int parse_headers(struct sip_msg* msg, int flags);
-
-void free_uri(struct sip_uri* u);
 
+int parse_headers(struct sip_msg* msg, int flags);
 
-/* char* parse_hname(char* buf, char* end, struct hdr_field* hdr); */
-char* parse_hname1(char* buf, char* end, struct hdr_field* hdr);
-char* parse_hname2(char* buf, char* end, struct hdr_field* hdr);
-
-char* parse_via(char* buffer, char* end, struct via_body *vb);
-char* parse_to(char* buffer, char* end, struct to_body *to_b);
-char* parse_cseq(char* buffer, char* end, struct cseq_body *cb);
-
-void free_via_param_list(struct via_param *vp);
-void free_via_list(struct via_body *vb);
-void clean_hdr_field(struct hdr_field* hf);
-void free_hdr_field_lst(struct hdr_field* hf);
 void free_sip_msg(struct sip_msg* msg);
 
 /* make sure all HFs needed for transaction identification have been

+ 71 - 0
parser/parse_cseq.c

@@ -0,0 +1,71 @@
+/* 
+ * $Id 
+ */
+
+#include "parse_cseq.h"
+#include "parser_f.h"  /* eat_space_end and so on */
+#include "../dprint.h"
+#include "parse_def.h"
+#include "../mem/mem.h"
+
+/*
+ * Parse CSeq header field
+ */
+
+/*BUGGY*/
+char* parse_cseq(char *buf, char* end, struct cseq_body* cb)
+{
+	char *t, *m, *m_end;
+	char c;
+	
+	cb->error=PARSE_ERROR;
+	t=eat_space_end(buf, end);
+	if (t>=end) goto error;
+	
+	cb->number.s=t;
+	t=eat_token_end(t, end);
+	if (t>=end) goto error;
+	m=eat_space_end(t, end);
+	m_end=eat_token_end(m, end);
+	*t=0; /*null terminate it*/
+	cb->number.len=t-cb->number.s;
+
+	if (m_end>=end) goto error;
+	if (m_end==m){
+		/* null method*/
+		LOG(L_ERR,  "ERROR:parse_cseq: no method found\n");
+		goto error;
+	}
+	cb->method.s=m;
+	t=m_end;
+	c=*t;
+	*t=0; /*null terminate it*/
+	cb->method.len=t-cb->method.s;
+	t++;
+	/*check if the header ends here*/
+	if (c=='\n') goto check_continue;
+	do{
+		for (;(t<end)&&((*t==' ')||(*t=='\t')||(*t=='\r'));t++);
+		if (t>=end) goto error;
+		if (*t!='\n'){
+			LOG(L_ERR, "ERROR:parse_cseq: unexpected char <%c> at end of"
+					" cseq\n", *t);
+			goto error;
+		}
+		t++;
+check_continue:
+		;
+	}while( (t<end) && ((*t==' ')||(*t=='\t')) );
+
+	cb->error=PARSE_OK;
+	return t;
+error:
+	LOG(L_ERR, "ERROR: parse_cseq: bad cseq\n");
+	return t;
+}
+
+
+void free_cseq(struct cseq_body* cb)
+{
+	pkg_free(cb);
+}

+ 34 - 0
parser/parse_cseq.h

@@ -0,0 +1,34 @@
+/*
+ * $Id$
+ */
+
+#ifndef PARSE_CSEQ
+#define PARSE_CSEQ
+
+#include "../str.h"
+
+
+struct cseq_body{
+	int error;  /* Error code */
+	str number; /* CSeq number */
+	str method; /* Associated method */
+};
+
+
+/* casting macro for accessing CSEQ body */
+#define get_cseq(p_msg) ((struct cseq_body*)(p_msg)->cseq->parsed)
+
+
+/*
+ * Parse CSeq header field
+ */
+char* parse_cseq(char *buf, char* end, struct cseq_body* cb);
+
+
+/*
+ * Free all associated memory
+ */
+void free_cseq(struct cseq_body* cb);
+
+
+#endif

+ 11 - 0
parser/parse_def.h

@@ -0,0 +1,11 @@
+/*
+ * $Id$
+ */
+
+#ifndef PARSE_DEF
+#define PARSE_DEF
+
+#define PARSE_ERROR -1
+#define PARSE_OK 1
+
+#endif

+ 185 - 11
parser/parse_fline.c

@@ -9,6 +9,8 @@
 
 #include "../dprint.h"
 #include "msg_parser.h"
+#include "parser_f.h"
+#include "../mem/mem.h"
 
 
 /* grammar:
@@ -19,17 +21,17 @@
 
 /*known methods: INVITE, ACK, CANCEL, BYE*/
 
-enum{ START,
-		INVITE1, INVITE2, INVITE3, INVITE4, INVITE5,
-		ACK1,    ACK2,
-		CANCEL1, CANCEL2, CANCEL3, CANCEL4, CANCEL5,
-		BYE1, BYE2,
-		SIP1, SIP2, SIP3, SIP4, SIP5, SIP6,
-		FIN_INVITE=100, FIN_ACK, FIN_CANCEL, FIN_BYE, FIN_SIP,
-		P_METHOD=200, L_URI, P_URI, L_VER, 
-		VER1, VER2, VER3, VER4, VER5, VER6, FIN_VER,
-		L_STATUS, P_STATUS, L_REASON, P_REASON,
-		L_LF, F_CR, F_LF
+enum { START,
+       INVITE1, INVITE2, INVITE3, INVITE4, INVITE5,
+       ACK1, ACK2,
+       CANCEL1, CANCEL2, CANCEL3, CANCEL4, CANCEL5,
+       BYE1, BYE2,
+       SIP1, SIP2, SIP3, SIP4, SIP5, SIP6,
+       FIN_INVITE = 100, FIN_ACK, FIN_CANCEL, FIN_BYE, FIN_SIP,
+       P_METHOD = 200, L_URI, P_URI, L_VER, 
+       VER1, VER2, VER3, VER4, VER5, VER6, FIN_VER,
+       L_STATUS, P_STATUS, L_REASON, P_REASON,
+       L_LF, F_CR, F_LF
 };
 
 
@@ -1108,3 +1110,175 @@ error:
 	fl->type=SIP_INVALID;
 	return tmp;
 }
+
+
+
+/* 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;
+	/* int l; */
+	char* end;
+	char s1,s2,s3;
+	char *prn;
+	unsigned int t;
+
+	/* grammar:
+		request  =  method SP uri SP version CRLF
+		response =  version SP status  SP reason  CRLF
+		(version = "SIP/2.0")
+	*/
+	
+
+	end=buffer+len;
+	/* see if it's a reply (status) */
+
+	/* jku  -- parse well-known methods */
+
+	/* drop messages which are so short they are for sure useless;
+           utilize knowledge of minimum size in parsing the first
+	   token 
+        */
+	if (len <=16 ) {
+		LOG(L_INFO, "ERROR: parse_first_line: message too short: %d\n", len);
+		goto error1;
+	}
+
+	tmp=buffer;
+  	/* is it perhaps a reply, ie does it start with "SIP...." ? */
+	if ( 	(*tmp=='S' || *tmp=='s') && 
+		strncasecmp( tmp+1, SIP_VERSION+1, SIP_VERSION_LEN-1)==0 &&
+		(*(tmp+SIP_VERSION_LEN)==' ')) {
+			fl->type=SIP_REPLY;
+			fl->u.reply.version.len=SIP_VERSION_LEN;
+			tmp=buffer+SIP_VERSION_LEN;
+	} else IFISMETHOD( INVITE, 'I' )
+	else IFISMETHOD( CANCEL, 'C')
+	else IFISMETHOD( ACK, 'A' )
+	else IFISMETHOD( BYE, 'B' ) 
+	/* if you want to add another method XXX, include METHOD_XXX in
+           H-file (this is the value which you will take later in
+           processing and define XXX_LEN as length of method name;
+	   then just call IFISMETHOD( XXX, 'X' ) ... 'X' is the first
+	   latter; everything must be capitals
+	*/
+	else {
+		/* neither reply, nor any of known method requests, 
+		   let's believe it is an unknown method request
+        	*/
+		tmp=eat_token_end(buffer,buffer+len);
+		if ((tmp==buffer)||(tmp>=end)){
+			LOG(L_INFO, "ERROR:parse_first_line: empty  or bad first line\n");
+			goto error1;
+		}
+		if (*tmp!=' ') {
+			LOG(L_INFO, "ERROR:parse_first_line: method not followed by SP\n");
+			goto error1;
+		}
+		fl->type=SIP_REQUEST;
+		fl->u.request.method_value=METHOD_OTHER;
+		fl->u.request.method.len=tmp-buffer;
+	}
+
+
+	/* identifying type of message over now; 
+	   tmp points at space after; go ahead */
+
+	fl->u.request.method.s=buffer;  /* store ptr to first token */
+	(*tmp)=0;			/* mark the 1st token end */
+	second=tmp+1;			/* jump to second token */
+	offset=second-buffer;
+
+/* EoJku */
+	
+	/* next element */
+	tmp=eat_token_end(second, second+len-offset);
+	if (tmp>=end){
+		goto error;
+	}
+	offset+=tmp-second;
+	third=eat_space_end(tmp, tmp+len-offset);
+	offset+=third-tmp;
+	if ((third==tmp)||(tmp>=end)){
+		goto error;
+	}
+	*tmp=0; /* mark the end of the token */
+	fl->u.request.uri.s=second;
+	fl->u.request.uri.len=tmp-second;
+
+	/* jku: parse status code */
+	if (fl->type==SIP_REPLY) {
+		if (fl->u.request.uri.len!=3) {
+			LOG(L_INFO, "ERROR:parse_first_line: len(status code)!=3: %s\n",
+				second );
+			goto error;
+		}
+		s1=*second; s2=*(second+1);s3=*(second+2);
+		if (s1>='0' && s1<='9' && 
+		    s2>='0' && s2<='9' &&
+		    s3>='0' && s3<='9' ) {
+			fl->u.reply.statuscode=(s1-'0')*100+10*(s2-'0')+(s3-'0');
+		} else {
+			LOG(L_INFO, "ERROR:parse_first_line: status_code non-numerical: %s\n",
+				second );
+			goto error;
+		}
+	}
+	/* EoJku */
+
+	/*  last part: for a request it must be the version, for a reply
+	 *  it can contain almost anything, including spaces, so we don't care
+	 *  about it*/
+	if (fl->type==SIP_REQUEST){
+		tmp=eat_token_end(third,third+len-offset);
+		offset+=tmp-third;
+		if ((tmp==third)||(tmp>=end)){
+			goto error;
+		}
+		if (! is_empty_end(tmp, tmp+len-offset)){
+			goto error;
+		}
+	}else{
+		tmp=eat_token2_end(third,third+len-offset,'\r'); /* find end of line 
+												  ('\n' or '\r') */
+		if (tmp>=end){ /* no crlf in packet => invalid */
+			goto error;
+		}
+		offset+=tmp-third;
+	}
+	nl=eat_line(tmp,len-offset);
+	if (nl>=end){ /* no crlf in packet or only 1 line > invalid */
+		goto error;
+	}
+	*tmp=0;
+	fl->u.request.version.s=third;
+	fl->u.request.version.len=tmp-third;
+
+	return nl;
+
+error:
+	LOG(L_INFO, "ERROR:parse_first_line: bad %s first line\n",
+		(fl->type==SIP_REPLY)?"reply(status)":"request");
+
+	LOG(L_INFO, "ERROR: at line 0 char %d: \n", offset );
+	prn=pkg_malloc( offset );
+	if (prn) {
+		for (t=0; t<offset; t++)
+			if (*(buffer+t)) *(prn+t)=*(buffer+t);
+			else *(prn+t)='°';
+		LOG(L_INFO, "ERROR: parsed so far: %.*s\n", offset, prn );
+		pkg_free( prn );
+	};
+error1:
+	fl->type=SIP_INVALID;
+	LOG(L_INFO, "ERROR:parse_first_line: bad message\n");
+	/* skip  line */
+	nl=eat_line(buffer,len);
+	return nl;
+}

+ 56 - 0
parser/parse_fline.h

@@ -0,0 +1,56 @@
+/*
+ * $Id$
+ */
+
+#ifndef PARSE_FLINE
+#define PARSE_FLINE
+
+#include "../str.h"
+
+/* Message is a request */
+#define SIP_REQUEST 1
+
+/* Message is a reply */
+#define SIP_REPLY   2
+
+/* Invalid message */
+#define SIP_INVALID 0
+
+
+#define SIP_VERSION "SIP/2.0"
+#define SIP_VERSION_LEN 7
+
+#define CANCEL "CANCEL"
+#define ACK    "ACK"
+#define INVITE "INVITE"
+
+#define INVITE_LEN 6
+#define CANCEL_LEN 6
+#define ACK_LEN 3
+#define BYE_LEN 3
+
+struct msg_start {
+	int type;                         /* Type of the Message - Request/Response */
+	union {
+		struct {
+			str method;       /* Method string */
+			str uri;          /* Request URI */
+			str version;      /* SIP version */
+			int method_value;
+		} request;
+		struct {
+			str version;      /* SIP version */
+			str status;       /* Reply status */
+			str reason;       /* Reply reason phrase */
+			unsigned int /* statusclass,*/ statuscode;
+		} reply;
+	}u;
+};
+
+
+char* parse_first_line(char* buffer, unsigned int len, struct msg_start * fl);
+
+char* parse_fline(char* buffer, char* end, struct msg_start* fl);
+
+
+#endif

+ 13 - 0
parser/parse_hname.h

@@ -0,0 +1,13 @@
+/*
+ * $Id$
+ */
+
+#ifndef PARSE_HNAME_H
+#define PARSE_HNAME_H
+
+#include "hf.h"
+
+/* returns end or pointer to next elem*/
+char* parse_hname1(char* p, char* end, struct hdr_field* hdr);
+
+#endif

+ 1 - 15
parser/parse_hname2.c

@@ -14,6 +14,7 @@
 #include "msg_parser.h"
 #include "../strs.h"
 #include "../dprint.h"
+#include "../ut.h"  /* q_memchr */
 
 /*
  * Size of hash table, this is magic value
@@ -66,26 +67,11 @@ static struct ht_entry *hash_table;
 /*
  * Declarations
  */
-static inline char* q_memchr    (char* p, int c, unsigned int size);
 static inline char* skip_ws     (char* p, unsigned int size);
 void         init_htable (void);
 static void         set_entry   (unsigned int key, unsigned int val);
 static inline int   unify       (int key);
 
-/*
- * Fast replacement of standard memchr function
- */
-static inline char* q_memchr(char* p, int c, unsigned int size)
-{
-	char* end;
-
-	end=p+size;
-	for(;p<end;p++){
-		if (*p==(unsigned char)c) return p;
-	}
-	return 0;
-}
-
 
 /*
  * Skip all whitechars and return position of the first

+ 23 - 0
parser/parse_hname2.h

@@ -0,0 +1,23 @@
+/*
+ * $Id$
+ */
+
+#ifndef PARSE_HNAME2_H
+#define PARSE_HNAME2_H
+
+#include "hf.h"
+
+
+/*
+ * Yet another parse_hname - Ultra Fast version :-)
+ */
+char* parse_hname2(char* begin, char* end, struct hdr_field* hdr);
+
+
+/*
+ * Initialize hash table
+ */
+void init_htable(void);
+
+
+#endif

+ 32 - 0
parser/parse_hostport.c

@@ -0,0 +1,32 @@
+/*
+ * $Id$
+ */
+
+#include "parse_hostport.h"
+#include <string.h>    /* strlen */
+#include "../dprint.h"
+#include "../ut.h"     /* str2s */
+
+char* parse_hostport(char* buf, str* host, short int* port)
+{
+	char *tmp;
+	int err;
+
+	host->s=buf;
+	for(tmp=buf;(*tmp)&&(*tmp!=':');tmp++);
+	host->len=tmp-buf;
+	if (*tmp==0) {
+		*port=0;
+	} else {
+		*tmp=0;
+		*port=str2s((unsigned char*)(tmp+1), strlen(tmp+1), &err);
+		if (err ){
+			LOG(L_INFO, 
+			    "ERROR: hostport: trailing chars in port number: %s\n",
+			    tmp+1);
+			     /* report error? */
+		}
+	}
+
+	return host->s;
+}

+ 12 - 0
parser/parse_hostport.h

@@ -0,0 +1,12 @@
+/*
+ * $Id$
+ */
+
+#ifndef PARSE_HOSTPORT_H
+#define PARSE_HOSTPORT_H
+
+#include "../str.h"
+
+char* parse_hostport(char* buf, str* host, short int* port);
+
+#endif

+ 35 - 11
parser/parse_to.c

@@ -1,5 +1,8 @@
+/*
+ * $Id$
+ */
 
-
+#include "parse_to.h"
 #include <stdlib.h>
 #include <string.h>
 #include "../dprint.h"
@@ -7,16 +10,22 @@
 #include "../ut.h"
 #include "../mem/mem.h"
 
+enum {
+	TAG_PARAM = 400, GENERAL_PARAM
+};
+
+
+enum { 
+	START_TO, DISPLAY_QUOTED, E_DISPLAY_QUOTED, DISPLAY_TOKEN, 
+	S_URI_ENCLOSED, URI_ENCLOSED, E_URI_ENCLOSED, 
+	URI_OR_TOKEN, MAYBE_URI_END, END, F_CR, F_LF, F_CRLF
+};
 
-enum{ START_TO, DISPLAY_QUOTED, E_DISPLAY_QUOTED, DISPLAY_TOKEN
-	, S_URI_ENCLOSED, URI_ENCLOSED, E_URI_ENCLOSED
-	, URI_OR_TOKEN, MAYBE_URI_END
-	, END, F_CR, F_LF, F_CRLF
-	};
 
-enum{ S_PARA_NAME=20, PARA_NAME, S_EQUAL, S_PARA_VALUE, TAG1, TAG2, TAG3
-	, PARA_VALUE_TOKEN , PARA_VALUE_QUOTED, E_PARA_VALUE, PARA_START
-	};
+enum { 
+	S_PARA_NAME=20, PARA_NAME, S_EQUAL, S_PARA_VALUE, TAG1, TAG2, 
+	TAG3, PARA_VALUE_TOKEN , PARA_VALUE_QUOTED, E_PARA_VALUE, PARA_START
+};
 
 
 
@@ -35,8 +44,8 @@ enum{ S_PARA_NAME=20, PARA_NAME, S_EQUAL, S_PARA_VALUE, TAG1, TAG2, TAG3
 
 
 
-char* parse_to_param(char *buffer, char *end, struct to_body *to_b,
-								int *returned_status)
+static inline char* parse_to_param(char *buffer, char *end, struct to_body *to_b,
+				   int *returned_status)
 {
 	struct to_param *param;
 	int status;
@@ -696,3 +705,18 @@ error:
 
 }
 
+
+void free_to(struct to_body* tb)
+{
+	struct to_param *tp=tb->param_lst;
+	struct to_param *foo;
+	while (tp){
+		foo = tp->next;
+		pkg_free(tp);
+		tp=foo;
+	}
+	pkg_free(tb);
+}
+
+
+

+ 41 - 0
parser/parse_to.h

@@ -0,0 +1,41 @@
+/*
+ * $Id$
+ */
+
+#ifndef PARSE_TO
+#define PARSE_TO
+
+#include "../str.h"
+
+struct to_param{
+	int type;              /* Type of parameter */
+	str name;              /* Name of parameter */
+	str value;             /* Parameter value */
+	struct to_param* next; /* Next parameter in the list */
+};
+
+
+struct to_body{
+	int error;                    /* Error code */
+	str body;                     /* The whole header field body */
+	str uri;                      /* URI */
+	str tag_value;                /* Value of tag */
+	struct to_param *param_lst;   /* Linked list of parameters */
+	struct to_param *last_param;  /* Last parameter in the list */
+};
+
+
+/* casting macro for accessing To body */
+#define get_to( p_msg)      ((struct to_body*)(p_msg)->to->parsed)
+
+
+/*
+ * To header field parser
+ */
+char* parse_to(char* buffer, char *end, struct to_body *to_b);
+
+
+void free_to(struct to_body* tb);
+
+
+#endif

+ 205 - 0
parser/parse_uri.c

@@ -0,0 +1,205 @@
+/*
+ * $Id$
+ */
+
+#include "parse_uri.h"
+#include "../mem/mem.h"
+#include <string.h>
+#include "../dprint.h"
+#include "../ut.h"    /* q_memchr */
+#include "../error.h"
+
+/* buf= pointer to begining of uri (sip:[email protected]:5060;a=b?h=i)
+ * len= len of uri
+ * returns: fills uri & returns <0 on error or 0 if ok 
+ */
+int parse_uri(char *buf, int len, struct sip_uri* uri)
+{
+	char* next, *end;
+	char *user, *passwd, *host, *port, *params, *headers, *ipv6;
+	int host_len, port_len, params_len, headers_len;
+	int ret;
+	
+	
+	ret=0;
+	host_len=0;
+	end=buf+len;
+	memset(uri, 0, sizeof(struct sip_uri)); /* zero it all, just to be sure */
+	/* look for "sip:"*/;
+	next=q_memchr(buf, ':',  len);
+	if ((next==0)||(strncmp(buf,"sip",next-buf)!=0)){
+		LOG(L_DBG, "ERROR: parse_uri: bad sip uri\n");
+		ser_error=ret=E_BAD_URI;
+		goto error;
+	}
+	buf=next+1; /* next char after ':' */
+	if (buf>end){
+		LOG(L_DBG, "ERROR: parse_uri: uri too short\n");
+		ser_error=ret=E_BAD_URI;
+		goto error;
+	}
+	/*look for '@' */
+	next=q_memchr(buf,'@', end-buf);
+	if (next==0){
+		/* no '@' found, => no userinfo */
+		uri->user.s=0;
+		uri->passwd.s=0;
+		host=buf;
+	}else{
+		/* found it */
+		user=buf;
+		/* try to find passwd */
+		passwd=q_memchr(user,':', next-user);
+		if (passwd==0){
+			/* no ':' found => no password */
+			uri->passwd.s=0;
+			uri->user.s=(char*)pkg_malloc(next-user+1);
+			if (uri->user.s==0){
+				LOG(L_ERR,"ERROR:parse_uri: memory allocation failure\n");
+				ser_error=ret=E_OUT_OF_MEM;
+				goto error;
+			}
+			memcpy(uri->user.s, user, next-user);
+			uri->user.len=next-user;
+			uri->user.s[next-user]=0; /* null terminate it, 
+									   usefull for easy printing*/
+		}else{
+			uri->user.s=(char*)pkg_malloc(passwd-user+1);
+			if (uri->user.s==0){
+				LOG(L_ERR,"ERROR:parse_uri: memory allocation failure\n");
+				ser_error=ret=E_OUT_OF_MEM;
+				goto error;
+			}
+			memcpy(uri->user.s, user, passwd-user);
+			uri->user.len=passwd-user;
+			uri->user.s[passwd-user]=0;
+			passwd++; /*skip ':' */
+			uri->passwd.s=(char*)pkg_malloc(next-passwd+1);
+			if (uri->passwd.s==0){
+				LOG(L_ERR,"ERROR:parse_uri: memory allocation failure\n");
+				ser_error=ret=E_OUT_OF_MEM;
+				goto error;
+			}
+			memcpy(uri->passwd.s, passwd, next-passwd);
+			uri->passwd.len=next-passwd;
+			uri->passwd.s[next-passwd]=0;
+		}
+		host=next+1; /* skip '@' */
+	}
+	/* try to find the rest */
+	if(host>=end){
+		LOG(L_DBG, "ERROR: parse_uri: missing hostport\n");
+		ser_error=ret=E_UNSPEC;
+		goto error;
+	}
+	next=host;
+	ipv6=q_memchr(host, '[', end-host);
+	if (ipv6){
+		host=ipv6+1; /* skip '[' in "[3ffe::abbcd]" */
+		if (host>=end){
+			LOG(L_DBG, "ERROR: parse_uri: bad ipv6 uri\n");
+			ret=E_UNSPEC;
+			goto error;
+		}
+		ipv6=q_memchr(host, ']', end-host);
+		if ((ipv6==0)||(ipv6==host)){
+			LOG(L_DBG, "ERROR: parse_uri: bad ipv6 uri - null address"
+					" or missing ']'\n");
+			ret=E_UNSPEC;
+			goto error;
+		}
+		host_len=ipv6-host;
+		next=ipv6;
+	}
+
+		
+	headers=q_memchr(next,'?',end-next);
+	params=q_memchr(next,';',end-next);
+	port=q_memchr(next,':',end-next);
+	if (host_len==0){ /* host not ipv6 addr */
+		host_len=(port)?port-host:(params)?params-host:(headers)?headers-host:
+				end-host;
+	}
+	/* get host */
+	uri->host.s=pkg_malloc(host_len+1);
+	if (uri->host.s==0){
+		LOG(L_ERR, "ERROR: parse_uri: memory allocation error\n");
+		ret=E_OUT_OF_MEM;
+		goto error;
+	}
+	memcpy(uri->host.s, host, host_len);
+	uri->host.len=host_len;
+	uri->host.s[host_len]=0;
+	/* get port*/
+	if ((port)&&(port+1<end)){
+		port++;
+		if ( ((params) &&(params<port))||((headers) &&(headers<port)) ){
+			/* error -> invalid uri we found ';' or '?' before ':' */
+			LOG(L_DBG, "ERROR: parse_uri: malformed sip uri\n");
+			ser_error=ret=E_BAD_URI;
+			goto error;
+		}
+		port_len=(params)?params-port:(headers)?headers-port:end-port;
+		uri->port.s=pkg_malloc(port_len+1);
+		if (uri->port.s==0){
+			LOG(L_ERR, "ERROR: parse_uri: memory allocation error\n");
+			ser_error=ret=E_OUT_OF_MEM;
+			goto error;
+		}
+		memcpy(uri->port.s, port, port_len);
+		uri->port.len=port_len;
+		uri->port.s[port_len]=0;
+	}else uri->port.s=0;
+	/* get params */
+	if ((params)&&(params+1<end)){
+		params++;
+		if ((headers) && (headers<params)){
+			/* error -> invalid uri we found '?' or '?' before ';' */
+			LOG(L_DBG, "ERROR: parse_uri: malformed sip uri\n");
+			ser_error=ret=E_BAD_URI;
+			goto error;
+		}
+		params_len=(headers)?headers-params:end-params;
+		uri->params.s=pkg_malloc(params_len+1);
+		if (uri->params.s==0){
+			LOG(L_ERR, "ERROR: parse_uri: memory allocation error\n");
+			ser_error=ret=E_OUT_OF_MEM;
+			goto error;
+		}
+		memcpy(uri->params.s, params, params_len);
+		uri->params.len=params_len;
+		uri->params.s[params_len]=0;
+	}else uri->params.s=0;
+	/*get headers */
+	if ((headers)&&(headers+1<end)){
+		headers++;
+		headers_len=end-headers;
+		uri->headers.s=pkg_malloc(headers_len+1);
+		if(uri->headers.s==0){
+			LOG(L_ERR, "ERROR: parse_uri: memory allocation error\n");
+			ser_error=ret=E_OUT_OF_MEM;
+			goto error;
+		}
+		memcpy(uri->headers.s, headers, headers_len);
+		uri->headers.len=headers_len;
+		uri->headers.s[headers_len]=0;
+	}else uri->headers.s=0;
+	
+	return ret;
+error:
+	free_uri(uri);
+	return ret;
+}
+
+
+void free_uri(struct sip_uri* u)
+{
+	if (u) {
+		if (u->user.s)    pkg_free(u->user.s);
+		if (u->passwd.s)  pkg_free(u->passwd.s);
+		if (u->host.s)    pkg_free(u->host.s);
+		if (u->port.s)    pkg_free(u->port.s);
+		if (u->params.s)  pkg_free(u->params.s);
+		if (u->headers.s) pkg_free(u->headers.s);
+	}
+}

+ 33 - 0
parser/parse_uri.h

@@ -0,0 +1,33 @@
+/*
+ * $Id$
+ */
+
+#ifndef PARSE_URI_H
+#define PARSE_URI_H
+
+/*
+ * SIP URI parser
+ */
+
+
+#include "../str.h"
+
+struct sip_uri {
+	str user;     /* Username */
+	str passwd;   /* Password */
+	str host;     /* Host name */
+	str port;     /* Port number */
+	str params;   /* Parameters */
+	str headers;  
+};
+
+
+/* buf= pointer to begining of uri (sip:[email protected]:5060;a=b?h=i)
+ * len= len of uri
+ * returns: fills uri & returns <0 on error or 0 if ok 
+ */
+int parse_uri(char *buf, int len, struct sip_uri* uri);
+
+void free_uri(struct sip_uri* u);
+
+#endif

+ 84 - 58
parser/parse_via.c

@@ -20,57 +20,63 @@
 #include <stdlib.h>
 #include <string.h>
 #include "../dprint.h"
-#include "msg_parser.h"
 #include "../ut.h"
 #include "../mem/mem.h"
+#include "parse_via.h"
+#include "parse_def.h"
 
 
 
 /* main via states (uri:port ...) */
-enum{	         F_HOST,    P_HOST,
-		L_PORT,  F_PORT,    P_PORT,
-		L_PARAM, F_PARAM,   P_PARAM,
-		L_VIA,   F_VIA,
-		         F_COMMENT, P_COMMENT,
-				 F_IP6HOST, P_IP6HOST,
-				 F_CRLF,
-				 F_LF,
-				 F_CR,
-				 END_OF_HEADER
-	};
+enum {	         
+	F_HOST, P_HOST,
+	L_PORT, F_PORT, P_PORT,
+	L_PARAM, F_PARAM, P_PARAM,
+	L_VIA, F_VIA,
+	F_COMMENT, P_COMMENT,
+	F_IP6HOST, P_IP6HOST,
+	F_CRLF,
+	F_LF,
+	F_CR,
+	END_OF_HEADER
+};
+
 
 /* first via part state */
-enum{	         F_SIP=100,
-		SIP1, SIP2, FIN_SIP,
-		L_VER, F_VER,
-		VER1, VER2, FIN_VER,
-		L_PROTO, F_PROTO, P_PROTO
-	};
+enum {
+	F_SIP = 100,
+	SIP1, SIP2, FIN_SIP,
+	L_VER, F_VER,
+	VER1, VER2, FIN_VER,
+	L_PROTO, F_PROTO, P_PROTO
+};
+
 
 /* param related states
  * WARNING: keep the FIN*, GEN_PARAM & PARAM_ERROR in sync w/ PARAM_* from
  * msg_parser.h !*/
-enum{	L_VALUE=200,   F_VALUE, P_VALUE, P_STRING,
-		HIDDEN1,   HIDDEN2,   HIDDEN3,   HIDDEN4,   HIDDEN5,
-		TTL1,      TTL2,
-		BRANCH1,   BRANCH2,   BRANCH3,   BRANCH4,   BRANCH5,
-		MADDR1,    MADDR2,    MADDR3,    MADDR4,
-		RECEIVED1, RECEIVED2, RECEIVED3, RECEIVED4, RECEIVED5, RECEIVED6,
-		RECEIVED7,
-		/* fin states (227-...)*/
-		FIN_HIDDEN=230, FIN_TTL, FIN_BRANCH, FIN_MADDR, FIN_RECEIVED,
-		/*GEN_PARAM,
-		PARAM_ERROR*/ /* declared in msg_parser.h*/
-	};
-
+enum {	
+	L_VALUE = 200, F_VALUE, P_VALUE, P_STRING,
+	HIDDEN1, HIDDEN2, HIDDEN3, HIDDEN4, HIDDEN5,
+	TTL1, TTL2,
+	BRANCH1, BRANCH2, BRANCH3, BRANCH4, BRANCH5,
+	MADDR1, MADDR2, MADDR3, MADDR4,
+	RECEIVED1, RECEIVED2, RECEIVED3, RECEIVED4, RECEIVED5, RECEIVED6,
+	RECEIVED7,
+	     /* fin states (227-...)*/
+	FIN_HIDDEN = 230, FIN_TTL, FIN_BRANCH, FIN_MADDR, FIN_RECEIVED,
+	     /*GEN_PARAM,
+	       PARAM_ERROR*/ /* declared in msg_parser.h*/
+};
 
 
 /* entry state must be F_PARAM, or saved_state=F_PARAM and
  * state=F_{LF,CR,CRLF}!
  * output state = L_PARAM or F_PARAM or END_OF_HEADER
- * (and saved_state= last state); everything else => error */
-char* parse_via_param(	char* p, char* end, int* pstate, 
-								int* psaved_state, struct via_param* param)
+ * (and saved_state= last state); everything else => error 
+ */
+static inline char* parse_via_param(char* p, char* end, int* pstate, 
+				    int* psaved_state, struct via_param* param)
 {
 	char* tmp;
 	register int state;
@@ -609,12 +615,12 @@ char* parse_via_param(	char* p, char* end, int* pstate,
 		}
 	}/* for tmp*/
 
-/* end of packet? => error, no cr/lf,',' found!!!*/
-saved_state=state;
-state=END_OF_HEADER;
-goto error;
-
-find_value:
+	/* end of packet? => error, no cr/lf,',' found!!!*/
+	saved_state=state;
+	state=END_OF_HEADER;
+	goto error;
+	
+ find_value:
 	tmp++;
 	for(;*tmp;tmp++){
 		switch(*tmp){
@@ -797,22 +803,22 @@ find_value:
 	} /* for2 tmp*/
 
 	/* end of buff and no CR/LF =>error*/
-saved_state=state;
-state=END_OF_HEADER;
-goto error;
-
-endofparam:
-endofvalue:
+	saved_state=state;
+	state=END_OF_HEADER;
+	goto error;
+	
+ endofparam:
+ endofvalue:
 	param->size=tmp-p;
 	*pstate=state;
 	*psaved_state=saved_state;
 	DBG("Found param type %d, <%s> = <%s>; state=%d\n", param->type,
 			param->name.s, param->value.s, state);
 	return tmp;
-
-end_via:
-	/* if we are here we found an "unexpected" end of via
-	 *  (cr/lf). This is valid only if the param type is GEN_PARAM*/
+	
+ end_via:
+	     /* if we are here we found an "unexpected" end of via
+	      *  (cr/lf). This is valid only if the param type is GEN_PARAM*/
 	if (param->type==GEN_PARAM){
 		saved_state=L_PARAM; /* change the saved_state, we have an unknown
 		                        param. w/o a value */
@@ -823,7 +829,7 @@ end_via:
 	DBG("Error on  param type %d, <%s>, state=%d, saved_state=%d\n",
 		param->type, param->name.s, state, saved_state);
 
-error:
+ error:
 	LOG(L_ERR, "error: parse_via_param\n");
 	param->type=PARAM_ERROR;
 	*pstate=PARAM_ERROR;
@@ -835,7 +841,6 @@ error:
 
 char* parse_via(char* buffer, char* end, struct via_body *vb)
 {
-
 	char* tmp;
 	int state;
 	int saved_state;
@@ -1123,21 +1128,21 @@ parse_again:
 		}
 	} /* for tmp*/
 
-/* we should not be here! if everything is ok > main_via*/
+	/* we should not be here! if everything is ok > main_via*/
 	LOG(L_ERR, "ERROR: parse_via: bad via: end of packet on state=%d\n",
 			state);
 	goto error;
 
-main_via:
-/* inc tmp to point to the next char*/
+ main_via:
+	/* inc tmp to point to the next char*/
 	tmp++;
 	c_nest=0;
 	/*state should always be F_HOST here*/;
 	for(;*tmp;tmp++){
 		switch(*tmp){
-			case ' ':
-			case '\t':
-				switch(state){
+		case ' ':
+		case '\t':
+			switch(state){
 					case F_HOST:/*eat the spaces*/
 						break;
 					case P_HOST:
@@ -1776,3 +1781,24 @@ error:
 }
 
 
+static inline void free_via_param_list(struct via_param* vp)
+{
+	struct via_param* foo;
+	while(vp){
+		foo=vp;
+		vp=vp->next;
+		pkg_free(foo);
+	}
+}
+
+
+void free_via_list(struct via_body* vb)
+{
+	struct via_body* foo;
+	while(vb){
+		foo=vb;
+		vb=vb->next;
+		if (foo->param_lst) free_via_param_list(foo->param_lst);
+		pkg_free(foo);
+	}
+}

+ 68 - 0
parser/parse_via.h

@@ -0,0 +1,68 @@
+/*
+ * $Id$
+ */
+
+#ifndef PARSE_VIA
+#define PARSE_VIA
+
+#include "../str.h"
+
+#define VIA_PARSE_OK	1
+#define VIA_PARSE_ERROR -1
+
+/* via param types
+ * WARNING: keep in sync w/ FIN_*, GEN_PARAM and PARAM_ERROR from via_parse.c
+ */
+enum {
+	PARAM_HIDDEN=230, PARAM_TTL, PARAM_BRANCH, 
+	PARAM_MADDR, PARAM_RECEIVED, GEN_PARAM,
+	PARAM_ERROR
+};
+
+
+struct via_param {
+	int type;               /* Type of the parameter */
+	str name;               /* Name of the parameter */
+	str value;              /* Value of the parameter */
+	int size;               /* total size*/
+	struct via_param* next; /* Next parameter in the list */
+};
+
+
+/* Format: name/version/transport host:port;params comment */
+struct via_body { 
+	int error;
+	str hdr;   /* Contains "Via" or "v" */
+	str name;
+	str version;   
+	str transport;
+	str host;
+	int port;
+	str port_str;
+	str params;
+	str comment;
+	int bsize;                    /* body size, not including hdr */
+	struct via_param* param_lst;  /* list of parameters*/
+	struct via_param* last_param; /*last via parameter, internal use*/
+
+	     /* shortcuts to "important" params*/
+	struct via_param* branch;
+	
+	struct via_body* next; /* pointer to next via body string if
+				  compact via or null */
+};
+
+
+/*
+ * Main Via header field parser
+ */
+char* parse_via(char* buffer, char* end, struct via_body *vb);
+
+
+/*
+ * Free allocated memory
+ */
+void free_via_list(struct via_body *vb);
+
+
+#endif