modules_k/seas/encode_uri.c
aaf285a6
 /* $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
  */
 
d38650d3
 /*
  * =====================================================================================
  * 
  *        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 <stdio.h>
 #include <assert.h>
 #include <string.h>
 #include <netinet/in.h>
 #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)
 {
b26faedd
    int i=4,j;/* 1*pointer+1*len+2*flags*/
    unsigned int scheme;
d38650d3
    unsigned char flags1=0,flags2=0,uriptr;
 
    uriptr=REL_PTR(hdr,uri_str.s);
    if(uri_str.len>255 || uriptr>hdrlen){
b96cb23e
       LOG(L_ERR,"uri too long, or out of the sip_msg bounds\n");
d38650d3
       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;
    }
b26faedd
    /*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:
d38650d3
    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;
b26faedd
    }*/
 #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;
 	
d38650d3
    payload[2]=flags1;
    payload[3]=flags2;
b26faedd
    j=i;
d38650d3
    i+=encode_parameters(&payload[i],uri_parsed->params.s,uri_str.s,&uri_parsed->params.len,'u');
b26faedd
    if(i<j)
       goto error;
d38650d3
    return i;
b26faedd
 error:
    return -1;
d38650d3
 }
 
 int print_encoded_uri(int fd,unsigned char *payload,int paylen,char *hdrstart,int hdrlen,char *prefix)
 {
    int i=4,j=0;/*1*pointer+1*len+2*flags*/
    unsigned char uriidx=0,flags1=0,flags2=0,urilen;
    char *ch_uriptr,*uritype=NULL,*secure=NULL;
 
    uriidx=payload[0];
    dprintf(fd,"%s",prefix);
    for(j=0;j<paylen;j++)
       dprintf(fd,"%s%d%s",j==0?"ENCODED-URI:[":":",payload[j],j==paylen-1?"]\n":"");
    if(uriidx>hdrlen){
b26faedd
       dprintf(fd,"bad index for start of uri: hdrlen=%d uri_index=%d\n",hdrlen,uriidx);
d38650d3
       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){
b26faedd
       dprintf(fd,"bad index for start of uri: hdrlen=%d uri_index=%d\n",hdrlen,uriidx);
d38650d3
       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*/
f8d73835
 	    dprintf(fd,"%.*s=;",(int)(aux3-aux+k),aux);
d38650d3
 	    aux2=NULL;/*resets the parameterValue-start pointer*/
 	    aux=aux3+1+k;/*points to the next parameter*/
 	 }else 
 	    if((aux3[k]==';'||(k==m)) && aux2!=NULL){
f8d73835
 	       dprintf(fd,"%.*s=%.*s;",(int)(aux2-aux),aux,(int)(aux3-aux2-1+k),aux2+1);
d38650d3
 	       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*/
f8d73835
 	    dprintf(fd,"%.*s=;",(int)(aux3-aux+k),aux);
d38650d3
 	    aux2=NULL;/*resets the parameterValue-start pointer*/
 	    aux=aux3+1+k;/*points to the next parameter*/
 	 }else 
 	    if((aux3[k]==';'||(k==m)) && aux2!=NULL){
f8d73835
 	       dprintf(fd,"%.*s=%.*s;",(int)(aux2-aux),aux,(int)(aux3-aux2-1+k),aux2+1);
d38650d3
 	       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;
 }