parser/msg_parser.c
512dcd98
 /*
  * $Id$
  *
  * sip msg. header proxy parser 
  *
7dd0b342
  *
  * Copyright (C) 2001-2003 Fhg Fokus
  *
  * This file is part of ser, a free SIP server.
  *
  * ser is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version
  *
  * For a license to use the ser software under conditions
  * other than those described here, or to purchase support for this
  * software, please contact iptel.org by e-mail at the following addresses:
  *    info@iptel.org
  *
  * ser is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License 
  * along with this program; if not, write to the Free Software 
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
512dcd98
  */
 
7dd0b342
 
888ca09d
 #include <string.h>
3e429f5c
 #include <stdlib.h>
512dcd98
 
888ca09d
 #include "msg_parser.h"
512dcd98
 #include "parser_f.h"
3881f12c
 #include "../ut.h"
 #include "../error.h"
 #include "../dprint.h"
 #include "../data_lump_rpl.h"
 #include "../mem/mem.h"
1400b772
 #include "../error.h"
 #include "../globals.h"
2bb60634
 #include "parse_hname2.h"
855c2e68
 #include "parse_uri.h"
ec147e2e
 #include "parse_content.h"
2bb60634
 
03150098
 #ifdef DEBUG_DMALLOC
dda9dab1
 #include <mem/dmalloc.h>
03150098
 #endif
 
512dcd98
 
e3c29827
 #define parse_hname(_b,_e,_h) parse_hname2((_b),(_e),(_h))
512dcd98
 
caf80ae6
 /* number of via's encounteded */
 int via_cnt;
512dcd98
 
f8d46776
 /* returns pointer to next header line, and fill hdr_f ;
  * if at end of header returns pointer to the last crlf  (always buf)*/
e72b5b50
 char* get_hdr_field(char* buf, char* end, struct hdr_field* hdr)
f8d46776
 {
e72b5b50
 
f8d46776
 	char* tmp;
 	char *match;
 	struct via_body *vb;
e4067ffb
 	struct cseq_body* cseq_b;
0fcc2741
 	struct to_body* to_b;
ec147e2e
 	int integer;
f8d46776
 
 	if ((*buf)=='\n' || (*buf)=='\r'){
 		/* double crlf or lflf or crcr */
 		DBG("found end of header\n");
 		hdr->type=HDR_EOH;
 		return buf;
 	}
512dcd98
 
f8d46776
 	tmp=parse_hname(buf, end, hdr);
 	if (hdr->type==HDR_ERROR){
 		LOG(L_ERR, "ERROR: get_hdr_field: bad header\n");
 		goto error;
e72b5b50
 	}
 	switch(hdr->type){
 		case HDR_VIA:
caf80ae6
 			/* keep number of vias parsed -- we want to report it in
 			   replies for diagnostic purposes */
 			via_cnt++;
22d4aa5d
 			vb=pkg_malloc(sizeof(struct via_body));
e72b5b50
 			if (vb==0){
 				LOG(L_ERR, "get_hdr_field: out of memory\n");
 				goto error;
 			}
 			memset(vb,0,sizeof(struct via_body));
 			hdr->body.s=tmp;
 			tmp=parse_via(tmp, end, vb);
34af87af
 			if (vb->error==PARSE_ERROR){
e72b5b50
 				LOG(L_ERR, "ERROR: get_hdr_field: bad via\n");
22d4aa5d
 				pkg_free(vb);
e72b5b50
 				goto error;
 			}
 			hdr->parsed=vb;
 			vb->hdr.s=hdr->name.s;
 			vb->hdr.len=hdr->name.len;
 			hdr->body.len=tmp-hdr->body.s;
 			break;
e4067ffb
 		case HDR_CSEQ:
22d4aa5d
 			cseq_b=pkg_malloc(sizeof(struct cseq_body));
e4067ffb
 			if (cseq_b==0){
 				LOG(L_ERR, "get_hdr_field: out of memory\n");
 				goto error;
 			}
 			memset(cseq_b, 0, sizeof(struct cseq_body));
 			hdr->body.s=tmp;
 			tmp=parse_cseq(tmp, end, cseq_b);
 			if (cseq_b->error==PARSE_ERROR){
 				LOG(L_ERR, "ERROR: get_hdr_field: bad cseq\n");
22d4aa5d
 				pkg_free(cseq_b);
e4067ffb
 				goto error;
 			}
 			hdr->parsed=cseq_b;
 			hdr->body.len=tmp-hdr->body.s;
 			DBG("get_hdr_field: cseq <%s>: <%s> <%s>\n",
 					hdr->name.s, cseq_b->number.s, cseq_b->method.s);
 			break;
e72b5b50
 		case HDR_TO:
0fcc2741
 			to_b=pkg_malloc(sizeof(struct to_body));
 			if (to_b==0){
 				LOG(L_ERR, "get_hdr_field: out of memory\n");
 				goto error;
 			}
 			memset(to_b, 0, sizeof(struct to_body));
 			hdr->body.s=tmp;
 			tmp=parse_to(tmp, end,to_b);
 			if (to_b->error==PARSE_ERROR){
 				LOG(L_ERR, "ERROR: get_hdr_field: bad to header\n");
 				pkg_free(to_b);
 				goto error;
0eb1315e
 			}
 			hdr->parsed=to_b;
0fcc2741
 			hdr->body.len=tmp-hdr->body.s;
e65823ce
 			DBG("DEBUG: get_hdr_field: <%s> [%d]; uri=[%.*s] \n",
 				hdr->name.s, hdr->body.len, to_b->uri.len,to_b->uri.s);
 			DBG("DEBUG: to body [%.*s]\n",to_b->body.len,to_b->body.s);
0eb1315e
 			break;
ec147e2e
 		case HDR_CONTENTLENGTH:
 			hdr->body.s=tmp;
 			tmp=parse_content_length(tmp,end, &integer);
 			if (tmp==0){
 				LOG(L_ERR, "ERROR:get_hdr_field: bad content_length header\n");
 				goto error;
 			}
 			hdr->parsed=(void*)integer;
 			hdr->body.len=tmp-hdr->body.s;
 			DBG("DEBUG: get_hdr_body : content_length=%d\n",(int)hdr->parsed);
 			break;
 		case HDR_CONTENTTYPE:
 			hdr->body.s=tmp;
 			tmp=parse_content_type(tmp,end, &integer);
 			if (tmp==0){
 				LOG(L_ERR, "ERROR:get_hdr_field: bad content_type header\n");
 				goto error;
 			}
 			hdr->parsed=(void*)integer;
 			hdr->body.len=tmp-hdr->body.s;
 			DBG("DEBUG: get_hdr_body : content_type=%d\n",(int)hdr->parsed);
 			break;
e72b5b50
 		case HDR_FROM:
 		case HDR_CALLID:
 		case HDR_CONTACT:
51c55780
 		case HDR_ROUTE:
33032483
 		case HDR_RECORDROUTE:
f8cdfdc8
 		case HDR_MAXFORWARDS:
ec147e2e
 		case HDR_AUTHORIZATION:
 		case HDR_EXPIRES:
 		case HDR_PROXYAUTH:
 		case HDR_WWWAUTH:
 		case HDR_SUPPORTED:
 		case HDR_REQUIRE:
 		case HDR_PROXYREQUIRE:
 		case HDR_UNSUPPORTED:
 		case HDR_ALLOW:
 		case HDR_EVENT:
e72b5b50
 		case HDR_OTHER:
 			/* just skip over it */
 			hdr->body.s=tmp;
 			/* find end of header */
 			/* find lf */
 			do{
 				match=q_memchr(tmp, '\n', end-tmp);
 				if (match){
 					match++;
 				}else {
e4067ffb
 					LOG(L_ERR,
 							"ERROR: get_hdr_field: bad body for <%s>(%d)\n",
e72b5b50
 							hdr->name.s, hdr->type);
1f377e97
 					/* abort(); */
 					tmp=end;
e72b5b50
 					goto error;
 				}
25b49bb4
 				tmp=match;
e72b5b50
 			}while( match<end &&( (*match==' ')||(*match=='\t') ) );
 			*(match-1)=0; /*null terminate*/
 			hdr->body.len=match-hdr->body.s;
 			break;
 		default:
 			LOG(L_CRIT, "BUG: get_hdr_field: unknown header type %d\n",
 					hdr->type);
f8d46776
 			goto error;
 	}
dda9dab1
 	/* jku: if \r covered by current length, shrink it */
 	trim_r( hdr->body );
f8d46776
 	return tmp;
 error:
 	DBG("get_hdr_field: error exit\n");
 	hdr->type=HDR_ERROR;
 	return tmp;
 }
 
512dcd98
 
 
e72b5b50
 /* 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 */
0a6afa42
 /* note: it continues where it previously stopped and goes ahead until
    end is encountered or desired HFs are found; if you call it twice
    for the same HF which is present only once, it will fail the second
8350de45
    time; if you call it twice and the HF is found on second time too,
    it's not replaced in the well-known HF pointer but just added to
    header list; if you want to use a dumbie convenience function which will
f27f8905
    give you the first occurance of a header you are interested in,
8350de45
    look at check_transaction_quadruple
0a6afa42
 */
590e1497
 int parse_headers(struct sip_msg* msg, int flags, int next)
e72b5b50
 {
 	struct hdr_field* hf;
 	char* tmp;
 	char* rest;
 	char* end;
590e1497
 	int orig_flag;
f27f8905
 
e72b5b50
 	end=msg->buf+msg->len;
 	tmp=msg->unparsed;
8dd85148
 	
 	if (next) {
 		orig_flag = msg->parsed_flag;
 		msg->parsed_flag &= ~flags;
219627a2
 	}else
 		orig_flag=0; 
 	
e72b5b50
 	DBG("parse_headers: flags=%d\n", flags);
 	while( tmp<end && (flags & msg->parsed_flag) != flags){
22d4aa5d
 		hf=pkg_malloc(sizeof(struct hdr_field));
e72b5b50
 		if (hf==0){
1400b772
 			ser_error=E_OUT_OF_MEM;
e72b5b50
 			LOG(L_ERR, "ERROR:parse_headers: memory allocation error\n");
 			goto error;
 		}
7f858173
 		memset(hf,0, sizeof(struct hdr_field));
e72b5b50
 		hf->type=HDR_ERROR;
 		rest=get_hdr_field(tmp, msg->buf+msg->len, hf);
 		switch (hf->type){
 			case HDR_ERROR:
 				LOG(L_INFO,"ERROR: bad header  field\n");
 				goto  error;
 			case HDR_EOH:
 				msg->eoh=tmp; /* or rest?*/
 				msg->parsed_flag|=HDR_EOH;
f27f8905
 				pkg_free(hf);
e72b5b50
 				goto skip;
 			case HDR_OTHER: /*do nothing*/
 				break;
 			case HDR_CALLID:
 				if (msg->callid==0) msg->callid=hf;
 				msg->parsed_flag|=HDR_CALLID;
 				break;
 			case HDR_TO:
 				if (msg->to==0) msg->to=hf;
 				msg->parsed_flag|=HDR_TO;
 				break;
 			case HDR_CSEQ:
 				if (msg->cseq==0) msg->cseq=hf;
 				msg->parsed_flag|=HDR_CSEQ;
 				break;
 			case HDR_FROM:
 				if (msg->from==0) msg->from=hf;
 				msg->parsed_flag|=HDR_FROM;
 				break;
 			case HDR_CONTACT:
 				if (msg->contact==0) msg->contact=hf;
 				msg->parsed_flag|=HDR_CONTACT;
 				break;
10febf05
 			case HDR_MAXFORWARDS:
 				if(msg->maxforwards==0) msg->maxforwards=hf;
 				msg->parsed_flag|=HDR_MAXFORWARDS;
 				break;
 			case HDR_ROUTE:
7ff8b055
 				if (msg->route==0) msg->route=hf;
 				msg->parsed_flag|=HDR_ROUTE;
 				break;
6984881e
 			case HDR_RECORDROUTE:
f2278164
 				if (msg->record_route==0) msg->record_route = hf;
 				msg->parsed_flag|=HDR_RECORDROUTE;
 				break;
33032483
 			case HDR_CONTENTTYPE:
 				if (msg->content_type==0) msg->content_type = hf;
 				msg->parsed_flag|=HDR_CONTENTTYPE;
 				break;
 			case HDR_CONTENTLENGTH:
 				if (msg->content_length==0) msg->content_length = hf;
 				msg->parsed_flag|=HDR_CONTENTLENGTH;
 				break;
ec147e2e
 			case HDR_AUTHORIZATION:
 				if (msg->authorization==0) msg->authorization = hf;
e3c29827
 				msg->parsed_flag|=HDR_AUTHORIZATION;
 				break;
ec147e2e
 			case HDR_EXPIRES:
e3c29827
 				if (msg->expires==0) msg->expires = hf;
 				msg->parsed_flag|=HDR_EXPIRES;
 				break;
ec147e2e
 			case HDR_PROXYAUTH:
e3c29827
 				if (msg->proxy_auth==0) msg->proxy_auth = hf;
 				msg->parsed_flag|=HDR_PROXYAUTH;
 				break;
ec147e2e
 			case HDR_WWWAUTH:
e3c29827
 				if (msg->www_auth==0) msg->www_auth = hf;
 				msg->parsed_flag|=HDR_WWWAUTH;
 				break;
ec147e2e
 			case HDR_SUPPORTED:
e3c29827
 				if (msg->supported==0) msg->supported = hf;
 				msg->parsed_flag|=HDR_SUPPORTED;
 				break;
ec147e2e
 			case HDR_REQUIRE:
e3c29827
 				if (msg->require==0) msg->require = hf;
 				msg->parsed_flag|=HDR_REQUIRE;
 				break;
ec147e2e
 			case HDR_PROXYREQUIRE:
e3c29827
 				if (msg->proxy_require==0) msg->proxy_require = hf;
 				msg->parsed_flag|=HDR_PROXYREQUIRE;
 				break;
ec147e2e
 			case HDR_UNSUPPORTED:
e3c29827
 				if (msg->unsupported==0) msg->unsupported=hf;
 				msg->parsed_flag|=HDR_UNSUPPORTED;
 				break;
ec147e2e
 			case HDR_ALLOW:
e3c29827
 				if (msg->allow==0) msg->allow = hf;
 				msg->parsed_flag|=HDR_ALLOW;
 				break;
b0a2e8ef
 			case HDR_EVENT:
 				if (msg->allow==0) msg->event = hf;
 				msg->parsed_flag|=HDR_EVENT;
 				break;
6984881e
 			case HDR_VIA:
e72b5b50
 				msg->parsed_flag|=HDR_VIA;
6984881e
 				DBG("parse_headers: Via found, flags=%d\n", flags);
8c7976a9
 				if (msg->via1==0) {
6984881e
 					DBG("parse_headers: this is the first via\n");
e72b5b50
 					msg->h_via1=hf;
 					msg->via1=hf->parsed;
 					if (msg->via1->next){
 						msg->via2=msg->via1->next;
 						msg->parsed_flag|=HDR_VIA2;
 					}
8c7976a9
 				}else if (msg->via2==0){
e72b5b50
 					msg->h_via2=hf;
 					msg->via2=hf->parsed;
 					msg->parsed_flag|=HDR_VIA2;
6984881e
 					DBG("parse_headers: this is the second via\n");
e72b5b50
 				}
 				break;
 			default:
 				LOG(L_CRIT, "BUG: parse_headers: unknown header type %d\n",
 							hf->type);
 				goto error;
 		}
 		/* add the header to the list*/
 		if (msg->last_header==0){
 			msg->headers=hf;
 			msg->last_header=hf;
 		}else{
 			msg->last_header->next=hf;
 			msg->last_header=hf;
 		}
68adfaee
 #ifdef EXTRA_DEBUG
e72b5b50
 		DBG("header field type %d, name=<%s>, body=<%s>\n",
 			hf->type, hf->name.s, hf->body.s);
68adfaee
 #endif
e72b5b50
 		tmp=rest;
 	}
 skip:
 	msg->unparsed=tmp;
 	return 0;
f27f8905
 
e72b5b50
 error:
1400b772
 	ser_error=E_BAD_REQ;
22d4aa5d
 	if (hf) pkg_free(hf);
590e1497
 	if (next) msg->parsed_flag |= orig_flag;
e72b5b50
 	return -1;
 }
 
 
512dcd98
 
888ca09d
 
 
 /* returns 0 if ok, -1 for errors */
 int parse_msg(char* buf, unsigned int len, struct sip_msg* msg)
 {
 
e22bbdb8
 	char *tmp;
888ca09d
 	char* rest;
 	char* first_via;
 	char* second_via;
f8d46776
 	struct msg_start *fl;
888ca09d
 	int offset;
e72b5b50
 	int flags;
888ca09d
 
 	/* eat crlf from the beginning */
 	for (tmp=buf; (*tmp=='\n' || *tmp=='\r')&&
 			tmp-buf < len ; tmp++);
 	offset=tmp-buf;
f8d46776
 	fl=&(msg->first_line);
 	rest=parse_first_line(tmp, len-offset, fl);
b6f4c1df
 #if 0
 	rest=parse_fline(tmp, buf+len, fl);
 #endif
888ca09d
 	offset+=rest-tmp;
 	tmp=rest;
f8d46776
 	switch(fl->type){
888ca09d
 		case SIP_INVALID:
efeaaf53
 			DBG("parse_msg: invalid message\n");
888ca09d
 			goto error;
 			break;
 		case SIP_REQUEST:
efeaaf53
 			DBG("SIP Request:\n");
7bab92c7
 			DBG(" method:  <%s>\n",fl->u.request.method.s);
 			DBG(" uri:     <%s>\n",fl->u.request.uri.s);
 			DBG(" version: <%s>\n",fl->u.request.version.s);
e72b5b50
 			flags=HDR_VIA;
888ca09d
 			break;
 		case SIP_REPLY:
efeaaf53
 			DBG("SIP Reply  (status):\n");
7bab92c7
 			DBG(" version: <%s>\n",fl->u.reply.version.s);
 			DBG(" status:  <%s>\n",fl->u.reply.status.s);
 			DBG(" reason:  <%s>\n",fl->u.reply.reason.s);
caf80ae6
 			/* flags=HDR_VIA | HDR_VIA2; */
 			/* we don't try to parse VIA2 for local messages; -Jiri */
 			flags=HDR_VIA;
888ca09d
 			break;
 		default:
f8d46776
 			DBG("unknown type %d\n",fl->type);
e22bbdb8
 			goto error;
888ca09d
 	}
e72b5b50
 	msg->unparsed=tmp;
888ca09d
 	/*find first Via: */
 	first_via=0;
 	second_via=0;
590e1497
 	if (parse_headers(msg, flags, 0)==-1) goto error;
888ca09d
 
25b49bb4
 #ifdef EXTRA_DEBUG
888ca09d
 	/* dump parsed data */
e72b5b50
 	if (msg->via1){
f8d46776
 		DBG(" first  via: <%s/%s/%s> <%s:%s(%d)>",
e72b5b50
 			msg->via1->name.s, msg->via1->version.s,
 			msg->via1->transport.s, msg->via1->host.s,
7bab92c7
 			msg->via1->port_str.s, msg->via1->port);
e72b5b50
 		if (msg->via1->params.s)  DBG(";<%s>", msg->via1->params.s);
 		if (msg->via1->comment.s) DBG(" <%s>", msg->via1->comment.s);
350c5a16
 		DBG ("\n");
 	}
e72b5b50
 	if (msg->via2){
22d4aa5d
 		DBG(" first  via: <%s/%s/%s> <%s:%s(%d)>",
 			msg->via2->name.s, msg->via2->version.s,
 			msg->via2->transport.s, msg->via2->host.s,
7bab92c7
 			msg->via2->port_str.s, msg->via2->port);
22d4aa5d
 		if (msg->via2->params.s)  DBG(";<%s>", msg->via2->params.s);
 		if (msg->via2->comment.s) DBG(" <%s>", msg->via2->comment.s);
 		DBG ("\n");
888ca09d
 	}
 #endif
 	
 
25b49bb4
 #ifdef EXTRA_DEBUG
efeaaf53
 	DBG("exiting parse_msg\n");
888ca09d
 #endif
 
 	return 0;
 	
 error:
96b76347
 	/* more debugging, msg->orig is/should be null terminated*/
6ee62314
 	LOG(L_ERR, "ERROR: parse_msg: message=<%.*s>\n", (int)msg->len, msg->orig);
888ca09d
 	return -1;
 }
 
5ada8f8a
 
 
0498ceb9
 void free_reply_lump( struct lump_rpl *lump)
 {
 	struct lump_rpl *foo, *bar;
 	for(foo=lump;foo;)
 	{
 		bar=foo->next;
 		free_lump_rpl(foo);
 		foo = bar;
 	}
 }
e72b5b50
 
22d4aa5d
 
 /*only the content*/
 void free_sip_msg(struct sip_msg* msg)
 {
 	if (msg->new_uri.s) { pkg_free(msg->new_uri.s); msg->new_uri.len=0; }
6bd84753
 	if (msg->headers)     free_hdr_field_lst(msg->headers);
22d4aa5d
 	if (msg->add_rm)      free_lump_list(msg->add_rm);
 	if (msg->repl_add_rm) free_lump_list(msg->repl_add_rm);
0498ceb9
 	if (msg->reply_lump)   free_reply_lump(msg->reply_lump);
6bd84753
 	pkg_free(msg->orig);
dda9dab1
 	/* don't free anymore -- now a pointer to a static buffer */
 #	ifdef DYN_BUF
b2dec9c6
 	pkg_free(msg->buf); 
dda9dab1
 #	endif
22d4aa5d
 }
 
 
0a6afa42
 /* make sure all HFs needed for transaction identification have been
    parsed; return 0 if those HFs can't be found
 */
caf80ae6
 
0a6afa42
 int check_transaction_quadruple( struct sip_msg* msg )
 {
caf80ae6
 	if ( parse_headers(msg, HDR_FROM|HDR_TO|HDR_CALLID|HDR_CSEQ,0)!=-1
 		&& msg->from && msg->to && msg->callid && msg->cseq ) {
 		return 1;
 	} else {
 		ser_error=E_BAD_TUPEL;
 		return 0;
 	}
0a6afa42
 }