512dcd98 |
/*
* $Id$
*
* sip msg. header proxy parser
*
*/
|
888ca09d |
#include <string.h>
|
3e429f5c |
#include <stdlib.h>
|
512dcd98 |
|
888ca09d |
#include "msg_parser.h"
|
512dcd98 |
#include "parser_f.h"
|
104316b6 |
#include "ut.h"
|
7268726e |
#include "error.h"
|
512dcd98 |
#include "dprint.h"
|
6fa79282 |
#include "mem.h"
|
512dcd98 |
|
03150098 |
#ifdef DEBUG_DMALLOC
#include <dmalloc.h>
#endif
|
512dcd98 |
|
888ca09d |
|
512dcd98 |
/* 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;
|
f571aa35 |
/* int l; */
|
038e5c9e |
char* end;
|
f571aa35 |
char s1,s2,s3;
|
512dcd98 |
/* grammar:
request = method SP uri SP version CRLF
response = version SP status SP reason CRLF
(version = "SIP/2.0")
*/
|
038e5c9e |
end=buffer+len;
|
512dcd98 |
/* see if it's a reply (status) */
|
f571aa35 |
/* 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\n");
|
512dcd98 |
goto error1;
}
|
f571aa35 |
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;
}
|
512dcd98 |
fl->type=SIP_REQUEST;
|
f571aa35 |
fl->u.request.method_value=METHOD_OTHER;
fl->u.request.method.len=tmp-buffer;
|
512dcd98 |
}
|
f571aa35 |
/* 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 */
|
512dcd98 |
/* next element */
|
f571aa35 |
tmp=eat_token_end(second, second+len-offset);
|
038e5c9e |
if (tmp>=end){
goto error;
}
|
512dcd98 |
offset+=tmp-second;
|
f571aa35 |
third=eat_space_end(tmp, tmp+len-offset);
|
512dcd98 |
offset+=third-tmp;
|
038e5c9e |
if ((third==tmp)||(tmp>=end)){
|
512dcd98 |
goto error;
}
*tmp=0; /* mark the end of the token */
|
f8d46776 |
fl->u.request.uri.s=second;
fl->u.request.uri.len=tmp-second;
|
f571aa35 |
/* 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.statusclass=s1-'0';
fl->u.reply.statuscode=fl->u.reply.statusclass*100+10*(s2-'0')+(s3-'0');
} else {
LOG(L_INFO, "ERROR:parse_first_line: status_code non-numerical: %s\n",
second );
goto error;
}
}
/* EoJku */
|
038e5c9e |
/* 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){
|
f571aa35 |
tmp=eat_token_end(third,third+len-offset);
|
038e5c9e |
offset+=tmp-third;
if ((tmp==third)||(tmp>=end)){
goto error;
}
|
f571aa35 |
if (! is_empty_end(tmp, tmp+len-offset)){
|
038e5c9e |
goto error;
}
}else{
|
f571aa35 |
tmp=eat_token2_end(third,third+len-offset,'\r'); /* find end of line
|
038e5c9e |
('\n' or '\r') */
if (tmp>=end){ /* no crlf in packet => invalid */
goto error;
}
offset+=tmp-third;
|
512dcd98 |
}
|
038e5c9e |
nl=eat_line(tmp,len-offset);
if (nl>=end){ /* no crlf in packet or only 1 line > invalid */
|
512dcd98 |
goto error;
}
*tmp=0;
|
f8d46776 |
fl->u.request.version.s=third;
fl->u.request.version.len=tmp-third;
|
512dcd98 |
return nl;
error:
|
efeaaf53 |
LOG(L_INFO, "ERROR:parse_first_line: bad %s first line\n",
|
512dcd98 |
(fl->type==SIP_REPLY)?"reply(status)":"request");
error1:
fl->type=SIP_INVALID;
|
efeaaf53 |
LOG(L_INFO, "ERROR: at line 0 char %d\n", offset);
|
512dcd98 |
/* skip line */
nl=eat_line(buffer,len);
return nl;
}
|
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;
|
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:
|
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));
|
512dcd98 |
|
e72b5b50 |
hdr->body.s=tmp;
tmp=parse_via(tmp, end, vb);
if (vb->error==VIA_PARSE_ERROR){
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:
case HDR_FROM:
case HDR_CALLID:
case HDR_CONTACT:
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 {
tmp=end;
|
e4067ffb |
LOG(L_ERR,
"ERROR: get_hdr_field: bad body for <%s>(%d)\n",
|
e72b5b50 |
hdr->name.s, hdr->type);
goto error;
}
}while( match<end &&( (*match==' ')||(*match=='\t') ) );
*(match-1)=0; /*null terminate*/
hdr->body.len=match-hdr->body.s;
|
f8d46776 |
tmp=match;
|
e72b5b50 |
break;
default:
LOG(L_CRIT, "BUG: get_hdr_field: unknown header type %d\n",
hdr->type);
|
f8d46776 |
goto error;
}
|
e72b5b50 |
|
f8d46776 |
return tmp;
error:
DBG("get_hdr_field: error exit\n");
hdr->type=HDR_ERROR;
return tmp;
}
|
512dcd98 |
|
f8d46776 |
char* parse_hostport(char* buf, str* host, short int* port)
|
512dcd98 |
{
char *tmp;
|
104316b6 |
int err;
|
512dcd98 |
|
f8d46776 |
host->s=buf;
|
512dcd98 |
for(tmp=buf;(*tmp)&&(*tmp!=':');tmp++);
|
f8d46776 |
host->len=tmp-buf;
|
512dcd98 |
if (*tmp==0){
*port=0;
}else{
*tmp=0;
|
104316b6 |
*port=str2s(tmp+1, strlen(tmp+1), &err);
if (err ){
|
efeaaf53 |
LOG(L_INFO,
|
104316b6 |
"ERROR: hostport: trailing chars in port number: %s\n",
tmp+1);
|
512dcd98 |
/* report error? */
}
}
|
f8d46776 |
return host->s;
|
512dcd98 |
}
|
e4067ffb |
/*BUGGY*/
char * parse_cseq(char *buf, char* end, struct cseq_body* cb)
{
char *t;
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;
*t=0; /*null terminate it*/
cb->number.len=t-cb->number.s;
t++;
t=eat_space_end(t, end);
if (t>=end) goto error;
cb->method.s=t;
t=eat_token_end(t, end);
if (t>=end) goto error;
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;
}
|
7268726e |
/* buf= pointer to begining of uri (sip:x@foo.bar: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;
int host_len, port_len, params_len, headers_len;
int ret;
ret=0;
end=buf+len;
memset(uri, 0, sizeof(struct sip_uri)); /* zero it all, just to be sure */
/* look for "sip:"*/;
|
019d863a |
next=q_memchr(buf, ':', len);
|
7268726e |
if ((next==0)||(strncmp(buf,"sip",next-buf)!=0)){
LOG(L_DBG, "ERROR: parse_uri: bad sip uri\n");
ret=E_UNSPEC;
goto error;
}
buf=next+1; /* next char after ':' */
if (buf>end){
LOG(L_DBG, "ERROR: parse_uri: uri too short\n");
ret=E_UNSPEC;
goto error;
}
/*look for '@' */
|
019d863a |
next=q_memchr(buf,'@', end-buf);
|
7268726e |
if (next==0){
/* no '@' found, => no userinfo */
|
f8d46776 |
uri->user.s=0;
uri->passwd.s=0;
|
7268726e |
host=buf;
}else{
/* found it */
user=buf;
/* try to find passwd */
|
019d863a |
passwd=q_memchr(user,':', next-user);
|
7268726e |
if (passwd==0){
/* no ':' found => no password */
|
f8d46776 |
uri->passwd.s=0;
|
22d4aa5d |
uri->user.s=(char*)pkg_malloc(next-user+1);
|
f8d46776 |
if (uri->user.s==0){
|
7268726e |
LOG(L_ERR,"ERROR:parse_uri: memory allocation failure\n");
ret=E_OUT_OF_MEM;
goto error;
}
|
f8d46776 |
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*/
|
7268726e |
}else{
|
22d4aa5d |
uri->user.s=(char*)pkg_malloc(passwd-user+1);
|
f8d46776 |
if (uri->user.s==0){
|
7268726e |
LOG(L_ERR,"ERROR:parse_uri: memory allocation failure\n");
ret=E_OUT_OF_MEM;
goto error;
}
|
f8d46776 |
memcpy(uri->user.s, user, passwd-user);
uri->user.len=passwd-user;
uri->user.s[passwd-user]=0;
|
7268726e |
passwd++; /*skip ':' */
|
22d4aa5d |
uri->passwd.s=(char*)pkg_malloc(next-passwd+1);
|
f8d46776 |
if (uri->passwd.s==0){
|
7268726e |
LOG(L_ERR,"ERROR:parse_uri: memory allocation failure\n");
ret=E_OUT_OF_MEM;
goto error;
}
|
f8d46776 |
memcpy(uri->passwd.s, passwd, next-passwd);
uri->passwd.len=next-passwd;
uri->passwd.s[next-passwd]=0;
|
7268726e |
}
host=next+1; /* skip '@' */
}
/* try to find the rest */
if(host>=end){
LOG(L_DBG, "ERROR: parse_uri: missing hostport\n");
ret=E_UNSPEC;
goto error;
}
|
019d863a |
headers=q_memchr(host,'?',end-host);
params=q_memchr(host,';',end-host);
port=q_memchr(host,':',end-host);
|
7268726e |
host_len=(port)?port-host:(params)?params-host:(headers)?headers-host:end-host;
/* get host */
|
22d4aa5d |
uri->host.s=pkg_malloc(host_len+1);
|
f8d46776 |
if (uri->host.s==0){
|
7268726e |
LOG(L_ERR, "ERROR: parse_uri: memory allocation error\n");
ret=E_OUT_OF_MEM;
goto error;
}
|
f8d46776 |
memcpy(uri->host.s, host, host_len);
uri->host.len=host_len;
uri->host.s[host_len]=0;
|
7268726e |
/* 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");
ret=E_UNSPEC;
goto error;
}
port_len=(params)?params-port:(headers)?headers-port:end-port;
|
22d4aa5d |
uri->port.s=pkg_malloc(port_len+1);
|
f8d46776 |
if (uri->port.s==0){
|
7268726e |
LOG(L_ERR, "ERROR: parse_uri: memory allocation error\n");
ret=E_OUT_OF_MEM;
goto error;
}
|
f8d46776 |
memcpy(uri->port.s, port, port_len);
uri->port.len=port_len;
uri->port.s[port_len]=0;
}else uri->port.s=0;
|
7268726e |
/* 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");
ret=E_UNSPEC;
goto error;
}
params_len=(headers)?headers-params:end-params;
|
22d4aa5d |
uri->params.s=pkg_malloc(params_len+1);
|
f8d46776 |
if (uri->params.s==0){
|
7268726e |
LOG(L_ERR, "ERROR: parse_uri: memory allocation error\n");
ret=E_OUT_OF_MEM;
goto error;
}
|
f8d46776 |
memcpy(uri->params.s, params, params_len);
uri->params.len=params_len;
uri->params.s[params_len]=0;
}else uri->params.s=0;
|
7268726e |
/*get headers */
if ((headers)&&(headers+1<end)){
headers++;
headers_len=end-headers;
|
22d4aa5d |
uri->headers.s=pkg_malloc(headers_len+1);
|
f8d46776 |
if(uri->headers.s==0){
|
7268726e |
LOG(L_ERR, "ERROR: parse_uri: memory allocation error\n");
ret=E_OUT_OF_MEM;
goto error;
}
|
f8d46776 |
memcpy(uri->headers.s, headers, headers_len);
uri->headers.len=headers_len;
uri->headers.s[headers_len]=0;
}else uri->headers.s=0;
|
7268726e |
return ret;
error:
return ret;
}
|
e72b5b50 |
#ifdef OLD_PARSER
|
512dcd98 |
/* 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;
|
f8d46776 |
int name_len, version_len, transport_len, comment_len, params_len;
|
512dcd98 |
char * next_via;
|
f8d46776 |
str host;
|
512dcd98 |
short int port;
int offset;
|
f8d46776 |
name=version=transport=comment=params=hostport=next_via=host.s=0;
name_len=version_len=transport_len=comment_len=params_len=host.len=0;
|
f571aa35 |
name=eat_space_end(buffer, buffer+len);
|
512dcd98 |
if (name-buffer==len) goto error;
offset=name-buffer;
tmp=name;
|
f571aa35 |
version=eat_token2_end(tmp,tmp+len-offset,'/');
|
512dcd98 |
if (version+1-buffer>=len) goto error;
*version=0;
|
f8d46776 |
name_len=version-name;
|
512dcd98 |
version++;
offset+=version-tmp;
|
f571aa35 |
transport=eat_token2_end(tmp,tmp+len-offset,'/');
|
512dcd98 |
if (transport+1-buffer>=len) goto error;
*transport=0;
|
f8d46776 |
version_len=transport-version;
|
512dcd98 |
transport++;
offset+=transport-tmp;
|
f571aa35 |
tmp=eat_token_end(transport,transport+len-offset);
|
512dcd98 |
if (tmp+1-buffer>=len) goto error;
*tmp=0;
|
f8d46776 |
transport_len=tmp-transport;
|
512dcd98 |
tmp++;
offset+=tmp-transport;
|
f571aa35 |
hostport=eat_space_end(tmp,tmp+len-offset);
|
512dcd98 |
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;
|
038e5c9e |
tmp++;
|
512dcd98 |
/*the rest is comment? */
|
038e5c9e |
if (tmp-buffer<len){
|
512dcd98 |
comment=tmp;
/* eat the comment */
for(;((tmp-buffer)<len)&&
(*tmp!=',');tmp++);
/* mark end of compact via (also end of comment)*/
|
f8d46776 |
comment_len=tmp-comment;
|
512dcd98 |
if (tmp-buffer<len){
*tmp=0;
}else break;
/* eat space & ',' */
for(tmp=tmp+1;((tmp-buffer)<len)&&
(*tmp==' '|| *tmp==',');tmp++);
}
break;
case ';':
*tmp=0;
tmp++;
|
038e5c9e |
if (tmp-buffer>=len) goto error;
|
512dcd98 |
params=tmp;
/* eat till end, first space or ',' */
for(;((tmp-buffer)<len)&&
(*tmp!=' '&& *tmp!=',');tmp++);
|
f8d46776 |
params_len=tmp-params;
|
512dcd98 |
if (tmp-buffer==len) break;
if (*tmp==' '){
/* eat comment */
*tmp=0;
tmp++;
comment=tmp;
for(;((tmp-buffer)<len)&&
(*tmp!=',');tmp++);
|
f8d46776 |
comment_len=tmp-comment;
|
512dcd98 |
if (tmp-buffer==len) break;
}
/* mark end of via*/
*tmp=0;
|
f8d46776 |
|
512dcd98 |
/* eat space & ',' */
for(tmp=tmp+1;((tmp-buffer)<len)&&
(*tmp==' '|| *tmp==',');tmp++);
break;
case ',':
*tmp=0;
|
038e5c9e |
tmp++;
if (tmp-buffer<len){
|
512dcd98 |
/* eat space and ',' */
|
038e5c9e |
for(;((tmp-buffer)<len)&&
|
512dcd98 |
(*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);
|
f8d46776 |
vb->name.s=name;
vb->name.len=name_len;
vb->version.s=version;
vb->version.len=version_len;
vb->transport.s=transport;
vb->transport.len=transport_len;
vb->host.s=host.s;
vb->host.len=host.len;
|
512dcd98 |
vb->port=port;
|
f8d46776 |
vb->params.s=params;
vb->params.len=params_len;
vb->comment.s=comment;
vb->comment.len=comment_len;
|
512dcd98 |
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;
}
|
e72b5b50 |
#endif
/* 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 */
int parse_headers(struct sip_msg* msg, int flags)
{
struct hdr_field* hf;
char* tmp;
char* rest;
char* end;
end=msg->buf+msg->len;
tmp=msg->unparsed;
DBG("parse_headers: flags=%d\n", flags);
while( tmp<end && (flags & msg->parsed_flag) != flags){
|
22d4aa5d |
hf=pkg_malloc(sizeof(struct hdr_field));
|
e72b5b50 |
memset(hf,0, sizeof(struct hdr_field));
if (hf==0){
LOG(L_ERR, "ERROR:parse_headers: memory allocation error\n");
goto error;
}
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;
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;
case HDR_VIA:
msg->parsed_flag|=HDR_VIA;
DBG("parse_headers: Via1 found, flags=%d\n", flags);
if (msg->h_via1==0) {
msg->h_via1=hf;
msg->via1=hf->parsed;
if (msg->via1->next){
msg->via2=msg->via1->next;
msg->parsed_flag|=HDR_VIA2;
}
}else if (msg->h_via2==0){
msg->h_via2=hf;
msg->via2=hf->parsed;
msg->parsed_flag|=HDR_VIA2;
DBG("parse_headers: Via2 found, flags=%d\n", flags);
}
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;
}
#ifdef DEBUG
DBG("header field type %d, name=<%s>, body=<%s>\n",
hf->type, hf->name.s, hf->body.s);
#endif
tmp=rest;
}
skip:
msg->unparsed=tmp;
return 0;
error:
|
22d4aa5d |
if (hf) pkg_free(hf);
|
e72b5b50 |
return -1;
}
|
512dcd98 |
|
888ca09d |
/* returns 0 if ok, -1 for errors */
int parse_msg(char* buf, unsigned int len, struct sip_msg* msg)
{
char *tmp, *bar;
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");
|
f8d46776 |
DBG(" method: <%s>\n",fl->u.request.method);
DBG(" uri: <%s>\n",fl->u.request.uri);
DBG(" version: <%s>\n",fl->u.request.version);
|
e72b5b50 |
flags=HDR_VIA;
|
888ca09d |
break;
case SIP_REPLY:
|
efeaaf53 |
DBG("SIP Reply (status):\n");
|
f8d46776 |
DBG(" version: <%s>\n",fl->u.reply.version);
DBG(" status: <%s>\n",fl->u.reply.status);
DBG(" reason: <%s>\n",fl->u.reply.reason);
|
e72b5b50 |
flags=HDR_VIA|HDR_VIA2;
|
888ca09d |
break;
default:
|
f8d46776 |
DBG("unknown type %d\n",fl->type);
|
888ca09d |
}
|
e72b5b50 |
msg->unparsed=tmp;
|
888ca09d |
/*find first Via: */
first_via=0;
second_via=0;
|
e72b5b50 |
if (parse_headers(msg, flags)==-1) goto error;
|
888ca09d |
#ifdef DEBUG
/* 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,
msg->via1->port_str, msg->via1->port);
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,
msg->via2->port_str, msg->via2->port);
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
#ifdef DEBUG
|
efeaaf53 |
DBG("exiting parse_msg\n");
|
888ca09d |
#endif
return 0;
error:
return -1;
}
|
5ada8f8a |
void free_uri(struct sip_uri* u)
{
if (u){
|
22d4aa5d |
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);
|
5ada8f8a |
}
}
|
e72b5b50 |
|
7f74d1b4 |
void free_via_param_list(struct via_param* vp)
{
struct via_param* foo;
while(vp){
foo=vp;
vp=vp->next;
pkg_free(foo);
}
}
|
e72b5b50 |
void free_via_list(struct via_body* vb)
{
struct via_body* foo;
while(vb){
foo=vb;
vb=vb->next;
|
7f74d1b4 |
if (foo->param_lst) free_via_param_list(foo->param_lst);
|
22d4aa5d |
pkg_free(foo);
|
e72b5b50 |
}
}
/* 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;
|
e4067ffb |
case HDR_CSEQ:
|
22d4aa5d |
pkg_free(hf->parsed);
|
e4067ffb |
break;
|
e72b5b50 |
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);
|
22d4aa5d |
pkg_free(foo);
|
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);
|
6bd84753 |
pkg_free(msg->orig);
pkg_free(msg->buf);
|
22d4aa5d |
}
|