modules_k/seas/encode_msg.c
aaf285a6
 /* $Id$
  *
  * Copyright (C) 2006-2007 VozTelecom Sistemas S.L
  *
27642a08
  * This file is part of Kamailio, a free SIP server.
aaf285a6
  *
27642a08
  * Kamailio is free software; you can redistribute it and/or modify
aaf285a6
  * 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
  *
27642a08
  * Kamailio is distributed in the hope that it will be useful,
aaf285a6
  * 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:  main.c
  * 
  *     Description:  functions to encode a message
  * 
  *         Version:  1.0
  *         Created:  14/11/05 13:42:53 CET
  *        Revision:  none
  *        Compiler:  gcc
  * 
  *          Author:  Elias Baixas (EB), elias@conillera.net
  *         Company:  VozTele.com
  * 
  * =====================================================================================
  */
 
 #define _GNU_SOURCE
 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
2c86e4e6
 #include <stddef.h>
d38650d3
 
 #include "../../parser/msg_parser.h"
 #include "../../parser/parse_via.h"
 #include "../../parser/parse_uri.h"
 #include "../../parser/parse_from.h"
 #include "../../mem/mem.h"
 #include "../../dprint.h"
 #include "encode_header.h"
 #include "encode_uri.h"
 #include "encode_msg.h"
 #include "xaddress.h"
 
 unsigned int theSignal = 0xAA55AA55;/*which is: 10101010-01010101-10101010-01010101*/
 
 char get_header_code(struct hdr_field *hf)
 {
    switch(hf->type){
       case HDR_CALLID_T:
 	 return 'i';
       case HDR_CONTACT_T:
 	 return 'm';
       case HDR_CONTENTLENGTH_T:
 	 return 'l';
       case HDR_CONTENTTYPE_T:
 	 return 'c';
       case HDR_FROM_T:
 	 return 'f';
       case HDR_SUBJECT_T:
 	 return 's';
       case HDR_SUPPORTED_T:
 	 return 'k';
       case HDR_TO_T:
 	 return 't';
       case HDR_VIA_T:
 	 return 'v';
       case HDR_ROUTE_T:
 	 return 'r';
       case HDR_RECORDROUTE_T:
 	 return 'R';
       case HDR_ALLOW_T:
 	 return 'a';
       case HDR_ACCEPT_T:
 	 return 'A';
       case HDR_CSEQ_T:
 	 return 'S';
       case HDR_REFER_TO_T:
 	 return 'o';
       case HDR_RPID_T:
 	 return 'p';
       case HDR_EXPIRES_T:
 	 return 'P';
       case HDR_AUTHORIZATION_T:
 	 return 'H';
       case HDR_PROXYAUTH_T:
 	 return 'z';
       default:
 	 return 'x';
    }
    return 'x';
 }
 
 /* This function extracts meta-info from the sip_msg structure and
  * formats it so that it can be used to rapidly access the message structured
  * parts.
  *
  * RETURNS: LENGTH of structure on success, <0 if failure
  * if there was failure, you dont need to pkg_free the payload (it is done inside).
  * if there was success, you __NEED_TO_PKG_FREE_THE_PAYLOAD__ from the calling function.
  *
  * The encoded meta-info is composed by 3 sections:
  *
  * MSG_META_INFO:
  * 2: short int in network-byte-order, if <100, the msg is a REQUEST and the int
  * is the code of the METHOD. if >100, it is a RESPONSE and the int is the code
  * of the response.
  * 2: short int in NBO: payload-start based pointer (index) to where the SIP MSG starts.
  * 2: short int in NBO: the sip-message length
  * 2: METHOD or CODE string SIP-START-based pointer and length
  * 2: R-URI or REASON PHRASE string SIP-START-based pointer and length
  * 2: VERSION string SIP-START-based pointer and length
  * 2: short int in NBO: start of the content of the SIP message
  * [1+N]: in case this is a request, the length of the encoded-uri and the encoded-uri
  * 1: how many present headers have been found.
  *
  * MSG_HEADERS_INDEX:
  * N*3: groups of 3 bytes, each one describing a header struct: the first byte
  * is a letter that corresponds to a header type, the second and third bytes are a NBO
  * inidex to where this struct begins within the HEADERS_META_INFO section.
  *
  * HEADERS_META_INFO:
  * M: all the codified headers meta info structs one after another
  *
  * SIP_MSG:
  * the SIP message as it has been received.
  *
  * The length of the structure, will be ((short*)payload)[1] + ((short*)payload)[2]
  *
  * TODO: msg->parsed_uri msg->parsed_orig_uri_ok, msg->first_line->u.request.uri
  * buggy and little bit fuzzy
  */
 int encode_msg(struct sip_msg *msg,char *payload,int len)
 {
2c86e4e6
    int i,j,k,u,request;
d38650d3
    unsigned short int h;
    struct hdr_field* hf;
    struct msg_start* ms;
2c86e4e6
    struct sip_uri miuri;
    char *myerror=NULL;
    ptrdiff_t diff;
d38650d3
 
    if(len < MAX_ENCODED_MSG + MAX_MESSAGE_LEN)
       return -1;
    if(parse_headers(msg,HDR_EOH_F,0)<0){
       myerror="in parse_headers";
       goto error;
    }
    memset(payload,0,len);
    ms=&msg->first_line;
5512fe6f
 	if(ms->type == SIP_REQUEST)
 		request=1;
 	else if(ms->type == SIP_REPLY)
 		request=0;
 	else{
 		myerror="message is neither request nor response";
 		goto error;
 	}
 	if(request) {
 		for(h=0;h<32;j=(0x01<<h),h++)
 			if(j & ms->u.request.method_value)
 				break;
 	} else {
 		h=(unsigned short)(ms->u.reply.statuscode);
 	}
2c86e4e6
    if(h==32){/*statuscode wont be 32...*/
b26faedd
       myerror="unknown message type\n";
d38650d3
       goto error;
    }
    h=htons(h);
    /*first goes the message code type*/
    memcpy(payload,&h,2);
    h=htons((unsigned short int)msg->len);
    /*then goes the message start idx, but we'll put it later*/
2c86e4e6
    /*then goes the message length (we hope it to be less than 65535 bytes...)*/
d38650d3
    memcpy(&payload[MSG_LEN_IDX],&h,2);
    /*then goes the content start index (starting from SIP MSG START)*/
2c86e4e6
    if(0>(diff=(get_body(msg)-(msg->buf)))){
b26faedd
       myerror="body starts before the message (uh ?)";
2c86e4e6
       goto error;
    }else
       h=htons((unsigned short int)diff);
    memcpy(payload+CONTENT_IDX,&h,2);
d38650d3
    payload[METHOD_CODE_IDX]=(unsigned char)(request?
 	 (ms->u.request.method.s-msg->buf):
 	 (ms->u.reply.status.s-msg->buf));
    payload[METHOD_CODE_IDX+1]=(unsigned char)(request?
 	 (ms->u.request.method.len):
 	 (ms->u.reply.status.len));
    payload[URI_REASON_IDX]=(unsigned char)(request?
 	 (ms->u.request.uri.s-msg->buf):
 	 (ms->u.reply.reason.s-msg->buf));
    payload[URI_REASON_IDX+1]=(unsigned char)(request?
 	 (ms->u.request.uri.len):
 	 (ms->u.reply.reason.len));
    payload[VERSION_IDX]=(unsigned char)(request?
 	 (ms->u.request.version.s-msg->buf):
 	 (ms->u.reply.version.s-msg->buf));
    if(request){
2c86e4e6
       if (parse_uri(ms->u.request.uri.s,ms->u.request.uri.len, &miuri)<0){
de7fe5e9
 	 LM_ERR("<%.*s>\n",ms->u.request.uri.len,ms->u.request.uri.s);
2c86e4e6
 	 myerror="while parsing the R-URI";
 	 goto error;
       }
       if(0>(j=encode_uri2(msg->buf,
d38650d3
 		  ms->u.request.method.s-msg->buf+ms->len,
2c86e4e6
 		  ms->u.request.uri,&miuri,
 		  (unsigned char*)&payload[REQUEST_URI_IDX+1])))
d38650d3
       {
 	    myerror="ENCODE_MSG: ERROR while encoding the R-URI";
 	    goto error;
       }
       payload[REQUEST_URI_IDX]=(unsigned char)j;
       k=REQUEST_URI_IDX+1+j;
    }else
       k=REQUEST_URI_IDX;
    u=k;
    k++;
    for(i=0,hf=msg->headers;hf;hf=hf->next,i++);
    i++;/*we do as if there was an extra header, that marks the end of
 	 the previous header in the headers hashtable(read below)*/
    j=k+3*i;
    for(i=0,hf=msg->headers;hf;hf=hf->next,k+=3){
       payload[k]=(unsigned char)(hf->type & 0xFF);
       h=htons(j);
       /*now goes a payload-based-ptr to where the header-code starts*/
       memcpy(&payload[k+1],&h,2);
       /*TODO fix this... fixed with k-=3?*/
b26faedd
       if(0>(i=encode_header(msg,hf,(unsigned char*)(payload+j),MAX_ENCODED_MSG+MAX_MESSAGE_LEN-j))){
de7fe5e9
 	 LM_ERR("encoding header %.*s\n",hf->name.len,hf->name.s);
d38650d3
 	 goto error;
 	 k-=3;
 	 continue;
       }
       j+=(unsigned short int)i;
    }
    /*now goes the number of headers that have been found, right after the meta-msg-section*/
    payload[u]=(unsigned char)((k-u-1)/3);
    j=htons(j);
    /*now copy the number of bytes that the headers-meta-section has occupied,right afther
     * headers-meta-section(the array with ['v',[2:where],'r',[2:where],'R',[2:where],...]
     * this is to know where the LAST header ends, since the length of each header-struct
     * is calculated substracting the nextHeaderStart - presentHeaderStart 
     * the k+1 is because payload[k] is usually the letter*/
    memcpy(&payload[k+1],&j,2);
    k+=3;
    j=ntohs(j);
    /*now we copy the headers-meta-section after the msg-headers-meta-section*/
    /*memcpy(&payload[k],payload2,j);*/
    /*j+=k;*/
    /*pkg_free(payload2);*/
    /*now we copy the actual message after the headers-meta-section*/
    memcpy(&payload[j],msg->buf,msg->len);
de7fe5e9
    LM_DBG("msglen = %d,msg starts at %d\n",msg->len,j);
d38650d3
    j=htons(j);
    /*now we copy at the beginning, the index to where the actual message starts*/
    memcpy(&payload[MSG_START_IDX],&j,2);
    return GET_PAY_SIZE( payload );
 error:
de7fe5e9
    LM_ERR("%s\n",myerror);
d38650d3
    return -1;
 }
 
 int decode_msg(struct sip_msg *msg,char *code, unsigned int len)
 {
    unsigned short int h;
    char *myerror=NULL;
 
    memcpy(&h,&code[2],2);
    h=ntohs(h);
    /*TODO use shorcuts in meta-info header.*/
 
    msg->buf=&code[h];
    memcpy(&h,&code[4],2);
    h=ntohs(h);
    msg->len=h;
    if(parse_headers(msg,HDR_EOH_F,0)<0){
       myerror="in parse_headers";
       goto error;
    }
 error:
de7fe5e9
    LM_ERR("(%s)\n",myerror);
d38650d3
    return -1;
 }
 
921ef5c0
 int print_encoded_msg(FILE* fd,char *code,char *prefix)
d38650d3
 {
    unsigned short int i,j,k,l,m,msglen;
    char r,*msg;
    unsigned char *payload;
    
    payload=(unsigned char*)code;
    memcpy(&i,code,2);
    memcpy(&j,&code[MSG_START_IDX],2);
    memcpy(&msglen,&code[MSG_LEN_IDX],2);
    i=ntohs(i);
    j=ntohs(j);
    msglen=ntohs(msglen);
    for(k=0;k<j;k++)
921ef5c0
       fprintf(fd,"%s%d%s",k==0?"ENCODED-MSG:[":":",payload[k],k==j-1?"]\n":"");
d38650d3
    msg=(char*)&payload[j];
921ef5c0
    fprintf(fd,"MESSAGE:\n[%.*s]\n",msglen,msg);
d38650d3
    r=(i<100)?1:0;
    if(r){
921ef5c0
       fprintf(fd,"%sREQUEST CODE=%d==%.*s,URI=%.*s,VERSION=%*.s\n",prefix,i,
d38650d3
 	    payload[METHOD_CODE_IDX+1],&msg[payload[METHOD_CODE_IDX]],
 	    payload[URI_REASON_IDX+1],&msg[payload[URI_REASON_IDX]],
 	    payload[VERSION_IDX+1],&msg[payload[VERSION_IDX]]);
       print_encoded_uri(fd,&payload[REQUEST_URI_IDX+1],payload[REQUEST_URI_IDX],msg,50,strcat(prefix,"  "));
       prefix[strlen(prefix)-2]=0;
       i=REQUEST_URI_IDX+1+payload[REQUEST_URI_IDX];
    }else{
921ef5c0
       fprintf(fd,"%sRESPONSE CODE=%d==%.*s,REASON=%.*s,VERSION=%.*s\n",prefix,i,
d38650d3
 	    payload[METHOD_CODE_IDX+1],&msg[payload[METHOD_CODE_IDX]],
 	    payload[URI_REASON_IDX+1],&msg[payload[URI_REASON_IDX]],
 	    payload[VERSION_IDX+1],&msg[payload[VERSION_IDX]]);
       i=REQUEST_URI_IDX;
    }
    k=((payload[CONTENT_IDX]<<8)|payload[CONTENT_IDX+1]);
    j=msglen-k;
921ef5c0
    fprintf(fd,"%sMESSAGE CONTENT:%.*s\n",prefix,j,&msg[k]);
d38650d3
    j=payload[i];
921ef5c0
    fprintf(fd,"%sHEADERS PRESENT(%d):",prefix,j);
d38650d3
    i++;
    for(k=i;k<i+(j*3);k+=3)
921ef5c0
       fprintf(fd,"%c%d%c",k==i?'[':',',payload[k],k==(i+3*j-3)?']':' ');
    fprintf(fd,"\n");
d38650d3
    for(k=i;k<i+(j*3);k+=3){
       memcpy(&l,&payload[k+1],2);
       memcpy(&m,&payload[k+4],2);
       l=ntohs(l);
       m=ntohs(m);
       print_encoded_header(fd,msg,msglen,&payload[l],m-l,payload[k],prefix);
    }
    return 1;
 }
 
 /*
  * Function to generate testing file, where we dump entire encoded-messages
  * preceded by a network-byte-order short int that says how long is the message,
  * or just encoded-headers. The last integer, is a flag set of which headers
  * must be dumped
  */
 
921ef5c0
 int dump_msg_test(char *code,FILE* fd,char header,char segregationLevel)
d38650d3
 {
    unsigned short int i,j,l,m,msglen;
    int k;
    char r,*msg;
    unsigned char *payload;
    payload=(unsigned char*)code;
    memcpy(&i,code,2);/*the CODE of the request/response*/
    memcpy(&j,&code[MSG_START_IDX],2);/*where the MSG starts*/
    memcpy(&msglen,&code[MSG_LEN_IDX],2);/*how long the MSG is*/
    i=ntohs(i);
    j=ntohs(j);
    msglen=ntohs(msglen);
    if(header==0){
921ef5c0
       fwrite(code,1,j+msglen,fd);
       fwrite(&theSignal,1,4,fd);
d38650d3
       return 0;
    }
    msg=(char*)&payload[j];
    r=(i<100)?1:0;
    if(r){
       if(segregationLevel & ALSO_RURI){
 	 if(!(segregationLevel & JUNIT)){ 
 	    
 	    k=htonl(payload[REQUEST_URI_IDX+1]+payload[REQUEST_URI_IDX+2]);
921ef5c0
 	    fwrite(&k,1,4,fd);
 	    fwrite(msg,1,ntohl(k),fd);
d38650d3
 	    k=htonl((long)payload[REQUEST_URI_IDX]);
921ef5c0
 	    fwrite(&k,1,4,fd);
 	    fwrite(&payload[REQUEST_URI_IDX+1],1,payload[REQUEST_URI_IDX],fd);
 	    fwrite(&theSignal,1,4,fd);
d38650d3
 	 }else
 	    print_uri_junit_tests(msg,payload[REQUEST_URI_IDX+1]+payload[REQUEST_URI_IDX+2]
 		  ,&payload[REQUEST_URI_IDX+1],payload[REQUEST_URI_IDX],fd,1,"");
       }
       i=REQUEST_URI_IDX+1+payload[REQUEST_URI_IDX];
    }else{
       i=REQUEST_URI_IDX;
    }
    j=payload[i];
    i++;
    for(k=i;k<i+(j*3);k+=3){
       memcpy(&l,&payload[k+1],2);
       memcpy(&m,&payload[k+4],2);
       l=ntohs(l);
       m=ntohs(m);
       if(header==(char)payload[k] ||
 	    (header=='U' &&
 	     (payload[k]=='f' ||
 	      payload[k]=='t' ||
 	      payload[k]=='m' ||
 	      payload[k]=='o' ||
 	      payload[k]=='p')))
 	 dump_headers_test(msg,msglen,&payload[i+(j*3)+l+3],m-l,payload[k],fd,segregationLevel);
    }
    return 1;
 }
 
 
 /*
  * Function to generate testing file, where we dump entire encoded-messages
  * preceded by a network-byte-order short int that says how long is the message,
  * or just encoded-headers. The last integer, is a flag set of which headers
  * must be dumped
  */
 
921ef5c0
 int print_msg_junit_test(char *code,FILE* fd,char header,char segregationLevel)
d38650d3
 {
    unsigned short int i,j,l,m,msglen;
    int k;
    char r,*msg;
    unsigned char *payload;
    payload=(unsigned char*)code;
    memcpy(&i,code,2);/*the CODE of the request/response*/
    memcpy(&j,&code[MSG_START_IDX],2);/*where the MSG starts*/
    memcpy(&msglen,&code[MSG_LEN_IDX],2);/*how long the MSG is*/
    i=ntohs(i);
    j=ntohs(j);
    msglen=ntohs(msglen);
    if(header==0){
921ef5c0
       fwrite(code,1,j+msglen,fd);
       fwrite(&theSignal,1,4,fd);
d38650d3
       return 0;
    }
    msg=(char*)&payload[j];
    r=(i<100)?1:0;
    if(r){
       if(segregationLevel & ALSO_RURI){
 	 k=htonl(50);
921ef5c0
 	 fwrite(&k,1,4,fd);
 	 fwrite(msg,1,50,fd);
d38650d3
 	 k=htonl((long)payload[REQUEST_URI_IDX]);
921ef5c0
 	 fwrite(&k,1,4,fd);
 	 fwrite(&payload[REQUEST_URI_IDX+1],1,payload[REQUEST_URI_IDX],fd);
 	 fwrite(&theSignal,1,4,fd);
d38650d3
       }
       i=REQUEST_URI_IDX+1+payload[REQUEST_URI_IDX];
    }else{
       i=REQUEST_URI_IDX;
    }
    j=payload[i];
    i++;
    for(k=i;k<i+(j*3);k+=3){
       memcpy(&l,&payload[k+1],2);
       memcpy(&m,&payload[k+4],2);
       l=ntohs(l);
       m=ntohs(m);
       if(header==(char)payload[k] ||
 	    (header=='U' &&
 	     (payload[k]=='f' ||
 	      payload[k]=='t' ||
 	      payload[k]=='m' ||
 	      payload[k]=='o' ||
 	      payload[k]=='p')))
 	 dump_headers_test(msg,msglen,&payload[i+(j*3)+l+3],m-l,payload[k],fd,segregationLevel);
    }
    return 1;
 }