/* $Id$ * * Copyright (C) 2006-2007 VozTelecom Sistemas S.L * * This file is part of openser, a free SIP server. * * openser 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 * * openser 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 */ /* * ===================================================================================== * * Filename: xuri.c * * Description: first trial to implement xuri * * Version: 1.0 * Created: 16/11/05 18:07:24 CET * Revision: none * Compiler: gcc * * Author: Elias Baixas (EB), elias@conillera.net * Company: VozTele.com * * ===================================================================================== */ #define _GNU_SOURCE #include #include #include #include #include "../../mem/mem.h" #include "../../parser/msg_parser.h" #include "../../dprint.h" #include "encode_uri.h" #include "encode_parameters.h" #include "encode_header.h" #include "xaddress.h" #define REL_PTR(a,b) ((unsigned char)(b-a)) /*The XURI is one of the most important parts in SEAS, as * most of the SIP MESSAGE structured headers (that is, * headers which have a well-specified body construction) * use the URI as the body (ie. via, route, record-route, * contact, from, to, RURI) * * the XURI is a codified structure of flags and pointers * that ease the parsing of the URI string. * * 1: The first byte of the structure, is a * HEADER_START-based pointer to the beginning of the URI * (including the "sip:"). * 1: The next byte is the length of the uri, so URIMAX * is 256 (enough...) * 2: Flags specifying the parts that are present in the URI * * as follows: * 1: first byte * SIP_OR_TEL_F 0x01 it is SIP or TEL uri. * SECURE_F 0x02 it is secure or not (SIPS,TELS) * USER_F 0x04 it as a user part (user@host) * PASSWORD_F 0x08 it has a password part * HOST_F 0x10 it has a host part * PORT_F 0x20 it has a port part * PARAMETERS_F 0x40 it has a port part * HEADERS_F 0x80 it has a port part * 1: second byte * TRANSPORT_F 0x01 it has other parameters * TTL_F 0x02 it has headers * USER_F 0x04 it has the transport parameter * METHOD_F 0x08 it has the ttl parameter * MADDR_F 0x10 it has the user parameter * LR_F 0x20 it has the method parameter * * All the following bytes are URI_START-based pointers to * the fields that are present in the uri, as specified by * the flags. They must appear in the same order shown in * the flags, and only appear if the flag was set to 1. * * the end of the field, will be the place where the * following pointer points to, minus one (note that all the * fields present in a URI are preceded by 1 character, ie * sip[:user][:passwod][@host][:port][;param1=x][;param2=y][?hdr1=a][&hdr2=b]$p * it will be necessary to have a pointer at the end, * pointing two past the end of the uri, so that the length * of the last header can be computed. * * The reason to have the OTHER and HEADERS flags at the * beginning(just after the strictly-uri stuff), is that it * will be necessary to know the length of the parameters * section and the headers section. * * The parameters can * appear in an arbitrary order, so they won't be following * the convention of transport-ttl-user-method-maddr-lr, so * we can't rely on the next pointer to compute the length * of the previous pointer field, as the ttl param can * appear before the transport param. so the parameter * pointers must have 2 bytes: pointer+length. * */ int encode_uri2(char *hdr,int hdrlen,str uri_str, struct sip_uri *uri_parsed,unsigned char *payload) { int i=4,j;/* 1*pointer+1*len+2*flags*/ unsigned int scheme; unsigned char flags1=0,flags2=0,uriptr; uriptr=REL_PTR(hdr,uri_str.s); if(uri_str.len>255 || uriptr>hdrlen){ LOG(L_ERR,"uri too long, or out of the sip_msg bounds\n"); return -1; } payload[0]=uriptr; payload[1]=(unsigned char)uri_str.len; if(uri_parsed->user.s && uri_parsed->user.len){ flags1 |= USER_F; payload[i++]=REL_PTR(uri_str.s,uri_parsed->user.s); } if(uri_parsed->passwd.s && uri_parsed->passwd.len){ flags1 |= PASSWORD_F; payload[i++]=REL_PTR(uri_str.s,uri_parsed->passwd.s); } if(uri_parsed->host.s && uri_parsed->host.len){ flags1 |= HOST_F; payload[i++]=REL_PTR(uri_str.s,uri_parsed->host.s); } if(uri_parsed->port.s && uri_parsed->port.len){ flags1 |= PORT_F; payload[i++]=REL_PTR(uri_str.s,uri_parsed->port.s); } if(uri_parsed->params.s && uri_parsed->params.len){ flags1 |= PARAMETERS_F; payload[i++]=REL_PTR(uri_str.s,uri_parsed->params.s); } if(uri_parsed->headers.s && uri_parsed->headers.len){ flags1 |= HEADERS_F; payload[i++]=REL_PTR(uri_str.s,uri_parsed->headers.s); } payload[i]=(unsigned char)(uri_str.len+1); i++; if(uri_parsed->transport.s && uri_parsed->transport.len){ flags2 |= TRANSPORT_F; payload[i]=REL_PTR(uri_str.s,uri_parsed->transport.s); payload[i+1]=(unsigned char)(uri_parsed->transport.len); i+=2; } if(uri_parsed->ttl.s && uri_parsed->ttl.len){ flags2 |= TTL_F; payload[i]=REL_PTR(uri_str.s,uri_parsed->ttl.s); payload[i+1]=(unsigned char)uri_parsed->ttl.len; i+=2; } if(uri_parsed->user_param.s && uri_parsed->user_param.len){ flags2 |= USER_F; payload[i]=REL_PTR(uri_str.s,uri_parsed->user_param.s); payload[i+1]=(unsigned char)uri_parsed->user_param.len; i+=2; } if(uri_parsed->method.s && uri_parsed->method.len){ flags2 |= METHOD_F; payload[i]=REL_PTR(uri_str.s,uri_parsed->method.s); payload[i+1]=(unsigned char)uri_parsed->method.len; i+=2; } if(uri_parsed->maddr.s && uri_parsed->maddr.len){ flags2 |= MADDR_F; payload[i]=REL_PTR(uri_str.s,uri_parsed->maddr.s); payload[i+1]=(unsigned char)uri_parsed->maddr.len; i+=2; } if(uri_parsed->lr.s && uri_parsed->lr.len){ flags2 |= LR_F; payload[i]=REL_PTR(uri_str.s,uri_parsed->lr.s); payload[i+1]=(unsigned char)uri_parsed->lr.len; i+=2; } /*in parse_uri, when there's a user=phone, the type * is set to TEL_URI_T, even if there's a sip: in the beginning * so lets check it by ourselves: switch(uri_parsed->type){ case SIP_URI_T: flags1 |= SIP_OR_TEL_F; break; case SIPS_URI_T: flags1 |= (SIP_OR_TEL_F|SECURE_F); break; case TEL_URI_T: break; case TELS_URI_T: flags1 |= SECURE_F; break; default: return -1; }*/ #define SIP_SCH 0x3a706973 #define SIPS_SCH 0x73706973 #define TEL_SCH 0x3a6c6574 #define TELS_SCH 0x736c6574 scheme=uri_str.s[0]+(uri_str.s[1]<<8)+(uri_str.s[2]<<16)+(uri_str.s[3]<<24); scheme|=0x20202020; if (scheme==SIP_SCH){ flags1 |= SIP_OR_TEL_F; }else if(scheme==SIPS_SCH){ if(uri_str.s[4]==':'){ flags1 |= (SIP_OR_TEL_F|SECURE_F); }else goto error; }else if (scheme==TEL_SCH){ /*nothing*/ }else if (scheme==TELS_SCH){ if(uri_str.s[4]==':'){ flags1 |= SECURE_F; } }else goto error; payload[2]=flags1; payload[3]=flags2; j=i; i+=encode_parameters(&payload[i],uri_parsed->params.s,uri_str.s,&uri_parsed->params.len,'u'); if(ihdrlen){ dprintf(fd,"bad index for start of uri: hdrlen=%d uri_index=%d\n",hdrlen,uriidx); return -1; } ch_uriptr = hdrstart+uriidx; urilen=payload[1]; flags1=payload[2]; flags2=payload[3]; dprintf(fd,"%sURI:[%.*s]\n",prefix,urilen,ch_uriptr); uritype=flags1&SIP_OR_TEL_F?"SIP":"TEL"; secure=flags1&SECURE_F?"S":""; dprintf(fd,"%s TYPE:[%s%s]\n",prefix,uritype,secure); if(flags1 & USER_F){ dprintf(fd,"%s USER:[%.*s]\n",prefix,(payload[i+1]-1)-payload[i],&ch_uriptr[payload[i]]); ++i; } if(flags1 & PASSWORD_F){ dprintf(fd,"%s PASSWORD=[%.*s]\n",prefix,(payload[i+1]-1)-payload[i],&ch_uriptr[payload[i]]); ++i; } if(flags1 & HOST_F){ dprintf(fd,"%s HOST=[%.*s]\n",prefix,(payload[i+1]-1)-payload[i],&ch_uriptr[payload[i]]); ++i; } if(flags1 & PORT_F){ dprintf(fd,"%s PORT=[%.*s]\n",prefix,(payload[i+1]-1)-payload[i],&ch_uriptr[payload[i]]); ++i; } if(flags1 & PARAMETERS_F){ dprintf(fd,"%s PARAMETERS=[%.*s]\n",prefix,(payload[i+1]-1)-payload[i],&ch_uriptr[payload[i]]); ++i; } if(flags1 & HEADERS_F){ dprintf(fd,"%s HEADERS=[%.*s]\n",prefix,(payload[i+1]-1)-payload[i],&ch_uriptr[payload[i]]); ++i; } ++i; if(flags2 & TRANSPORT_F){ dprintf(fd,"%s TRANSPORT=[%.*s]\n",prefix,payload[i+1],&ch_uriptr[payload[i]]); i+=2; } if(flags2 & TTL_F){ dprintf(fd,"%s TTL_F=[%.*s]\n",prefix,payload[i+1],&ch_uriptr[payload[i]]); i+=2; } if(flags2 & USER_F){ dprintf(fd,"%s USER_F=[%.*s]\n",prefix,payload[i+1],&ch_uriptr[payload[i]]); i+=2; } if(flags2 & METHOD_F){ dprintf(fd,"%s METHOD_F=[%.*s]\n",prefix,payload[i+1],&ch_uriptr[payload[i]]); i+=2; } if(flags2 & MADDR_F){ dprintf(fd,"%s MADDR_F=[%.*s]\n",prefix,payload[i+1],&ch_uriptr[payload[i]]); i+=2; } if(flags2 & LR_F){ dprintf(fd,"%s LR_F=[%.*s]\n",prefix,payload[i+1],&ch_uriptr[payload[i]]); i+=2; } print_encoded_parameters(fd,&payload[i],ch_uriptr,paylen-i,prefix); return 0; } int print_uri_junit_tests(char *hdrstart,int hdrlen,unsigned char *payload,int paylen,int fd,char also_hdr,char *prefix) { int i=4,k=0,m=0;/*1*pointer+1*len+2*flags*/ unsigned char uriidx=0,flags1=0,flags2=0,urilen; char *ch_uriptr,*aux,*aux2,*aux3,*uritype=NULL,*secure=NULL; uriidx=payload[0]; if(uriidx>hdrlen){ dprintf(fd,"bad index for start of uri: hdrlen=%d uri_index=%d\n",hdrlen,uriidx); return -1; } if(also_hdr) dump_standard_hdr_test(hdrstart,hdrlen,payload,paylen,fd); ch_uriptr = hdrstart+uriidx; urilen=payload[1]; flags1=payload[2]; flags2=payload[3]; dprintf(fd,"%stoString=(S)%.*s\n",prefix,urilen,ch_uriptr); uritype=flags1&SIP_OR_TEL_F?"sip":"tel"; secure=flags1&SECURE_F?"s":""; dprintf(fd,"%sgetScheme=(S)%s%s\n",prefix,uritype,secure); dprintf(fd,"%sisSecure=(B)%s\n",prefix,flags1&SECURE_F?"true":"false"); dprintf(fd,"%sisSipURI=(B)%s\n",prefix,"true"); dprintf(fd,"%sgetUser=(S)",prefix); if(flags1 & USER_F){ dprintf(fd,"%.*s\n",(payload[i+1]-1)-payload[i],&ch_uriptr[payload[i]]); ++i; }else dprintf(fd,"(null)\n"); dprintf(fd,"%sgetUserPassword=(S)",prefix); if(flags1 & PASSWORD_F){ dprintf(fd,"%.*s\n",(payload[i+1]-1)-payload[i],&ch_uriptr[payload[i]]); ++i; }else dprintf(fd,"(null)\n"); dprintf(fd,"%sgetHost=(S)",prefix); if(flags1 & HOST_F){ dprintf(fd,"%.*s\n",(payload[i+1]-1)-payload[i],&ch_uriptr[payload[i]]); ++i; }else dprintf(fd,"(null)\n");/*can't happen*/ dprintf(fd,"%sgetPort=(I)",prefix); if(flags1 & PORT_F){ dprintf(fd,"%.*s\n",(payload[i+1]-1)-payload[i],&ch_uriptr[payload[i]]); ++i; }else dprintf(fd,"(null)\n"); /*user=phone;transport=udp*/ if(flags1 & PARAMETERS_F){ aux=&ch_uriptr[payload[i]]; aux2=NULL; aux3=aux; m=(payload[i+1]-1-payload[i]); dprintf(fd,"%sgetParameter=(SAVP)",prefix);/*SVP = Attribute Value Pair*/ for(k=0;k<=m;k++){ if((aux3[k]==';'||(k==m)) && aux2==NULL){/*no parameterValue was found*/ dprintf(fd,"%.*s=;",(int)(aux3-aux+k),aux); aux2=NULL;/*resets the parameterValue-start pointer*/ aux=aux3+1+k;/*points to the next parameter*/ }else if((aux3[k]==';'||(k==m)) && aux2!=NULL){ dprintf(fd,"%.*s=%.*s;",(int)(aux2-aux),aux,(int)(aux3-aux2-1+k),aux2+1); aux2=NULL; aux=aux3+1+k; } else if(aux3[k]=='='){ aux2=aux3+k; } } dprintf(fd,"\n"); ++i; } if(flags1 & HEADERS_F){ aux=&ch_uriptr[payload[i]]; aux2=NULL; aux3=aux; m=(payload[i+1]-1-payload[i]); dprintf(fd,"%sgetHeader=(SAVP)",prefix); for(k=0;k<=m;k++){ if((aux3[k]==';'||(k==m)) && aux2==NULL){/*no parameterValue was found*/ dprintf(fd,"%.*s=;",(int)(aux3-aux+k),aux); aux2=NULL;/*resets the parameterValue-start pointer*/ aux=aux3+1+k;/*points to the next parameter*/ }else if((aux3[k]==';'||(k==m)) && aux2!=NULL){ dprintf(fd,"%.*s=%.*s;",(int)(aux2-aux),aux,(int)(aux3-aux2-1+k),aux2+1); aux2=NULL; aux=aux3+1+k; } else if(aux3[k]=='='){ aux2=aux3+k; } } dprintf(fd,"\n"); ++i; } ++i; dprintf(fd,"%sgetTransportParam=(S)",prefix); if(flags2 & TRANSPORT_F){ dprintf(fd,"%.*s\n",payload[i+1],&ch_uriptr[payload[i]]); i+=2; }else dprintf(fd,"(null)\n"); dprintf(fd,"%sgetTTLparam=(I)",prefix); if(flags2 & TTL_F){ dprintf(fd,"%.*s\n",payload[i+1],&ch_uriptr[payload[i]]); i+=2; }else dprintf(fd,"(null)\n"); dprintf(fd,"%sgetUserParam=(S)",prefix); if(flags2 & USER_F){ dprintf(fd,"%.*s\n",payload[i+1],&ch_uriptr[payload[i]]); i+=2; }else dprintf(fd,"(null)\n"); dprintf(fd,"%sgetMethodParam=(S)",prefix); if(flags2 & METHOD_F){ dprintf(fd,"%.*s\n",payload[i+1],&ch_uriptr[payload[i]]); i+=2; }else dprintf(fd,"(null)\n"); dprintf(fd,"%sgetMAddrParam=(S)",prefix); if(flags2 & MADDR_F){ dprintf(fd,"%.*s\n",payload[i+1],&ch_uriptr[payload[i]]); i+=2; }else dprintf(fd,"(null)\n"); if(flags2 & LR_F){ i+=2; } dprintf(fd,"\n"); return 0; }