encode_msg.c

Go to the documentation of this file.
00001 /* $Id: encode_msg.c 5192 2008-11-13 10:18:48Z eliasbaixas $
00002  *
00003  * Copyright (C) 2006-2007 VozTelecom Sistemas S.L
00004  *
00005  * This file is part of Kamailio, a free SIP server.
00006  *
00007  * Kamailio is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2 of the License, or
00010  * (at your option) any later version
00011  *
00012  * Kamailio is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License 
00018  * along with this program; if not, write to the Free Software 
00019  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020  */
00021 
00022 /*
00023  * =====================================================================================
00024  * 
00025  *        Filename:  main.c
00026  * 
00027  *     Description:  functions to encode a message
00028  * 
00029  *         Version:  1.0
00030  *         Created:  14/11/05 13:42:53 CET
00031  *        Revision:  none
00032  *        Compiler:  gcc
00033  * 
00034  *          Author:  Elias Baixas (EB), elias@conillera.net
00035  *         Company:  VozTele.com
00036  * 
00037  * =====================================================================================
00038  */
00039 
00040 #define _GNU_SOURCE
00041 #include <stdio.h>
00042 #include <sys/types.h>
00043 #include <sys/stat.h>
00044 #include <fcntl.h>
00045 #include <unistd.h>
00046 #include <stdlib.h>
00047 #include <string.h>
00048 #include <stddef.h>
00049 
00050 #include "../../parser/msg_parser.h"
00051 #include "../../parser/parse_via.h"
00052 #include "../../parser/parse_uri.h"
00053 #include "../../parser/parse_from.h"
00054 #include "../../mem/mem.h"
00055 #include "../../dprint.h"
00056 #include "encode_header.h"
00057 #include "encode_uri.h"
00058 #include "encode_msg.h"
00059 #include "xaddress.h"
00060 
00061 unsigned int theSignal = 0xAA55AA55;/*which is: 10101010-01010101-10101010-01010101*/
00062 
00063 char get_header_code(struct hdr_field *hf)
00064 {
00065    switch(hf->type){
00066       case HDR_CALLID_T:
00067     return 'i';
00068       case HDR_CONTACT_T:
00069     return 'm';
00070       case HDR_CONTENTLENGTH_T:
00071     return 'l';
00072       case HDR_CONTENTTYPE_T:
00073     return 'c';
00074       case HDR_FROM_T:
00075     return 'f';
00076       case HDR_SUBJECT_T:
00077     return 's';
00078       case HDR_SUPPORTED_T:
00079     return 'k';
00080       case HDR_TO_T:
00081     return 't';
00082       case HDR_VIA_T:
00083     return 'v';
00084       case HDR_ROUTE_T:
00085     return 'r';
00086       case HDR_RECORDROUTE_T:
00087     return 'R';
00088       case HDR_ALLOW_T:
00089     return 'a';
00090       case HDR_ACCEPT_T:
00091     return 'A';
00092       case HDR_CSEQ_T:
00093     return 'S';
00094       case HDR_REFER_TO_T:
00095     return 'o';
00096       case HDR_RPID_T:
00097     return 'p';
00098       case HDR_EXPIRES_T:
00099     return 'P';
00100       case HDR_AUTHORIZATION_T:
00101     return 'H';
00102       case HDR_PROXYAUTH_T:
00103     return 'z';
00104       default:
00105     return 'x';
00106    }
00107    return 'x';
00108 }
00109 
00110 /* This function extracts meta-info from the sip_msg structure and
00111  * formats it so that it can be used to rapidly access the message structured
00112  * parts.
00113  *
00114  * RETURNS: LENGTH of structure on success, <0 if failure
00115  * if there was failure, you dont need to pkg_free the payload (it is done inside).
00116  * if there was success, you __NEED_TO_PKG_FREE_THE_PAYLOAD__ from the calling function.
00117  *
00118  * The encoded meta-info is composed by 3 sections:
00119  *
00120  * MSG_META_INFO:
00121  * 2: short int in network-byte-order, if <100, the msg is a REQUEST and the int
00122  * is the code of the METHOD. if >100, it is a RESPONSE and the int is the code
00123  * of the response.
00124  * 2: short int in NBO: payload-start based pointer (index) to where the SIP MSG starts.
00125  * 2: short int in NBO: the sip-message length
00126  * 2: METHOD or CODE string SIP-START-based pointer and length
00127  * 2: R-URI or REASON PHRASE string SIP-START-based pointer and length
00128  * 2: VERSION string SIP-START-based pointer and length
00129  * 2: short int in NBO: start of the content of the SIP message
00130  * [1+N]: in case this is a request, the length of the encoded-uri and the encoded-uri
00131  * 1: how many present headers have been found.
00132  *
00133  * MSG_HEADERS_INDEX:
00134  * N*3: groups of 3 bytes, each one describing a header struct: the first byte
00135  * is a letter that corresponds to a header type, the second and third bytes are a NBO
00136  * inidex to where this struct begins within the HEADERS_META_INFO section.
00137  *
00138  * HEADERS_META_INFO:
00139  * M: all the codified headers meta info structs one after another
00140  *
00141  * SIP_MSG:
00142  * the SIP message as it has been received.
00143  *
00144  * The length of the structure, will be ((short*)payload)[1] + ((short*)payload)[2]
00145  *
00146  * TODO: msg->parsed_uri msg->parsed_orig_uri_ok, msg->first_line->u.request.uri
00147  * buggy and little bit fuzzy
00148  */
00149 int encode_msg(struct sip_msg *msg,char *payload,int len)
00150 {
00151    int i,j,k,u,request;
00152    unsigned short int h;
00153    struct hdr_field* hf;
00154    struct msg_start* ms;
00155    struct sip_uri miuri;
00156    char *myerror=NULL;
00157    ptrdiff_t diff;
00158 
00159    if(len < MAX_ENCODED_MSG + MAX_MESSAGE_LEN)
00160       return -1;
00161    if(parse_headers(msg,HDR_EOH_F,0)<0){
00162       myerror="in parse_headers";
00163       goto error;
00164    }
00165    memset(payload,0,len);
00166    ms=&msg->first_line;
00167    if(ms->type == SIP_REQUEST)
00168       request=1;
00169    else if(ms->type == SIP_REPLY)
00170       request=0;
00171    else{
00172       myerror="message is neither request nor response";
00173       goto error;
00174    }
00175    if(request) {
00176       for(h=0;h<32;j=(0x01<<h),h++)
00177          if(j & ms->u.request.method_value)
00178             break;
00179    } else {
00180       h=(unsigned short)(ms->u.reply.statuscode);
00181    }
00182    if(h==32){/*statuscode wont be 32...*/
00183       myerror="unknown message type\n";
00184       goto error;
00185    }
00186    h=htons(h);
00187    /*first goes the message code type*/
00188    memcpy(payload,&h,2);
00189    h=htons((unsigned short int)msg->len);
00190    /*then goes the message start idx, but we'll put it later*/
00191    /*then goes the message length (we hope it to be less than 65535 bytes...)*/
00192    memcpy(&payload[MSG_LEN_IDX],&h,2);
00193    /*then goes the content start index (starting from SIP MSG START)*/
00194    if(0>(diff=(get_body(msg)-(msg->buf)))){
00195       myerror="body starts before the message (uh ?)";
00196       goto error;
00197    }else
00198       h=htons((unsigned short int)diff);
00199    memcpy(payload+CONTENT_IDX,&h,2);
00200    payload[METHOD_CODE_IDX]=(unsigned char)(request?
00201     (ms->u.request.method.s-msg->buf):
00202     (ms->u.reply.status.s-msg->buf));
00203    payload[METHOD_CODE_IDX+1]=(unsigned char)(request?
00204     (ms->u.request.method.len):
00205     (ms->u.reply.status.len));
00206    payload[URI_REASON_IDX]=(unsigned char)(request?
00207     (ms->u.request.uri.s-msg->buf):
00208     (ms->u.reply.reason.s-msg->buf));
00209    payload[URI_REASON_IDX+1]=(unsigned char)(request?
00210     (ms->u.request.uri.len):
00211     (ms->u.reply.reason.len));
00212    payload[VERSION_IDX]=(unsigned char)(request?
00213     (ms->u.request.version.s-msg->buf):
00214     (ms->u.reply.version.s-msg->buf));
00215    if(request){
00216       if (parse_uri(ms->u.request.uri.s,ms->u.request.uri.len, &miuri)<0){
00217     LM_ERR("<%.*s>\n",ms->u.request.uri.len,ms->u.request.uri.s);
00218     myerror="while parsing the R-URI";
00219     goto error;
00220       }
00221       if(0>(j=encode_uri2(msg->buf,
00222         ms->u.request.method.s-msg->buf+ms->len,
00223         ms->u.request.uri,&miuri,
00224         (unsigned char*)&payload[REQUEST_URI_IDX+1])))
00225       {
00226        myerror="ENCODE_MSG: ERROR while encoding the R-URI";
00227        goto error;
00228       }
00229       payload[REQUEST_URI_IDX]=(unsigned char)j;
00230       k=REQUEST_URI_IDX+1+j;
00231    }else
00232       k=REQUEST_URI_IDX;
00233    u=k;
00234    k++;
00235    for(i=0,hf=msg->headers;hf;hf=hf->next,i++);
00236    i++;/*we do as if there was an extra header, that marks the end of
00237     the previous header in the headers hashtable(read below)*/
00238    j=k+3*i;
00239    for(i=0,hf=msg->headers;hf;hf=hf->next,k+=3){
00240       payload[k]=(unsigned char)(hf->type & 0xFF);
00241       h=htons(j);
00242       /*now goes a payload-based-ptr to where the header-code starts*/
00243       memcpy(&payload[k+1],&h,2);
00244       /*TODO fix this... fixed with k-=3?*/
00245       if(0>(i=encode_header(msg,hf,(unsigned char*)(payload+j),MAX_ENCODED_MSG+MAX_MESSAGE_LEN-j))){
00246     LM_ERR("encoding header %.*s\n",hf->name.len,hf->name.s);
00247     goto error;
00248     k-=3;
00249     continue;
00250       }
00251       j+=(unsigned short int)i;
00252    }
00253    /*now goes the number of headers that have been found, right after the meta-msg-section*/
00254    payload[u]=(unsigned char)((k-u-1)/3);
00255    j=htons(j);
00256    /*now copy the number of bytes that the headers-meta-section has occupied,right afther
00257     * headers-meta-section(the array with ['v',[2:where],'r',[2:where],'R',[2:where],...]
00258     * this is to know where the LAST header ends, since the length of each header-struct
00259     * is calculated substracting the nextHeaderStart - presentHeaderStart 
00260     * the k+1 is because payload[k] is usually the letter*/
00261    memcpy(&payload[k+1],&j,2);
00262    k+=3;
00263    j=ntohs(j);
00264    /*now we copy the headers-meta-section after the msg-headers-meta-section*/
00265    /*memcpy(&payload[k],payload2,j);*/
00266    /*j+=k;*/
00267    /*pkg_free(payload2);*/
00268    /*now we copy the actual message after the headers-meta-section*/
00269    memcpy(&payload[j],msg->buf,msg->len);
00270    LM_DBG("msglen = %d,msg starts at %d\n",msg->len,j);
00271    j=htons(j);
00272    /*now we copy at the beginning, the index to where the actual message starts*/
00273    memcpy(&payload[MSG_START_IDX],&j,2);
00274    return GET_PAY_SIZE( payload );
00275 error:
00276    LM_ERR("%s\n",myerror);
00277    return -1;
00278 }
00279 
00280 int decode_msg(struct sip_msg *msg,char *code, unsigned int len)
00281 {
00282    unsigned short int h;
00283    char *myerror=NULL;
00284 
00285    memcpy(&h,&code[2],2);
00286    h=ntohs(h);
00287    /*TODO use shorcuts in meta-info header.*/
00288 
00289    msg->buf=&code[h];
00290    memcpy(&h,&code[4],2);
00291    h=ntohs(h);
00292    msg->len=h;
00293    if(parse_headers(msg,HDR_EOH_F,0)<0){
00294       myerror="in parse_headers";
00295       goto error;
00296    }
00297 error:
00298    LM_ERR("(%s)\n",myerror);
00299    return -1;
00300 }
00301 
00302 int print_encoded_msg(FILE* fd,char *code,char *prefix)
00303 {
00304    unsigned short int i,j,k,l,m,msglen;
00305    char r,*msg;
00306    unsigned char *payload;
00307    
00308    payload=(unsigned char*)code;
00309    memcpy(&i,code,2);
00310    memcpy(&j,&code[MSG_START_IDX],2);
00311    memcpy(&msglen,&code[MSG_LEN_IDX],2);
00312    i=ntohs(i);
00313    j=ntohs(j);
00314    msglen=ntohs(msglen);
00315    for(k=0;k<j;k++)
00316       fprintf(fd,"%s%d%s",k==0?"ENCODED-MSG:[":":",payload[k],k==j-1?"]\n":"");
00317    msg=(char*)&payload[j];
00318    fprintf(fd,"MESSAGE:\n[%.*s]\n",msglen,msg);
00319    r=(i<100)?1:0;
00320    if(r){
00321       fprintf(fd,"%sREQUEST CODE=%d==%.*s,URI=%.*s,VERSION=%*.s\n",prefix,i,
00322        payload[METHOD_CODE_IDX+1],&msg[payload[METHOD_CODE_IDX]],
00323        payload[URI_REASON_IDX+1],&msg[payload[URI_REASON_IDX]],
00324        payload[VERSION_IDX+1],&msg[payload[VERSION_IDX]]);
00325       print_encoded_uri(fd,&payload[REQUEST_URI_IDX+1],payload[REQUEST_URI_IDX],msg,50,strcat(prefix,"  "));
00326       prefix[strlen(prefix)-2]=0;
00327       i=REQUEST_URI_IDX+1+payload[REQUEST_URI_IDX];
00328    }else{
00329       fprintf(fd,"%sRESPONSE CODE=%d==%.*s,REASON=%.*s,VERSION=%.*s\n",prefix,i,
00330        payload[METHOD_CODE_IDX+1],&msg[payload[METHOD_CODE_IDX]],
00331        payload[URI_REASON_IDX+1],&msg[payload[URI_REASON_IDX]],
00332        payload[VERSION_IDX+1],&msg[payload[VERSION_IDX]]);
00333       i=REQUEST_URI_IDX;
00334    }
00335    k=((payload[CONTENT_IDX]<<8)|payload[CONTENT_IDX+1]);
00336    j=msglen-k;
00337    fprintf(fd,"%sMESSAGE CONTENT:%.*s\n",prefix,j,&msg[k]);
00338    j=payload[i];
00339    fprintf(fd,"%sHEADERS PRESENT(%d):",prefix,j);
00340    i++;
00341    for(k=i;k<i+(j*3);k+=3)
00342       fprintf(fd,"%c%d%c",k==i?'[':',',payload[k],k==(i+3*j-3)?']':' ');
00343    fprintf(fd,"\n");
00344    for(k=i;k<i+(j*3);k+=3){
00345       memcpy(&l,&payload[k+1],2);
00346       memcpy(&m,&payload[k+4],2);
00347       l=ntohs(l);
00348       m=ntohs(m);
00349       print_encoded_header(fd,msg,msglen,&payload[l],m-l,payload[k],prefix);
00350    }
00351    return 1;
00352 }
00353 
00354 /*
00355  * Function to generate testing file, where we dump entire encoded-messages
00356  * preceded by a network-byte-order short int that says how long is the message,
00357  * or just encoded-headers. The last integer, is a flag set of which headers
00358  * must be dumped
00359  */
00360 
00361 int dump_msg_test(char *code,FILE* fd,char header,char segregationLevel)
00362 {
00363    unsigned short int i,j,l,m,msglen;
00364    int k;
00365    char r,*msg;
00366    unsigned char *payload;
00367    payload=(unsigned char*)code;
00368    memcpy(&i,code,2);/*the CODE of the request/response*/
00369    memcpy(&j,&code[MSG_START_IDX],2);/*where the MSG starts*/
00370    memcpy(&msglen,&code[MSG_LEN_IDX],2);/*how long the MSG is*/
00371    i=ntohs(i);
00372    j=ntohs(j);
00373    msglen=ntohs(msglen);
00374    if(header==0){
00375       fwrite(code,1,j+msglen,fd);
00376       fwrite(&theSignal,1,4,fd);
00377       return 0;
00378    }
00379    msg=(char*)&payload[j];
00380    r=(i<100)?1:0;
00381    if(r){
00382       if(segregationLevel & ALSO_RURI){
00383     if(!(segregationLevel & JUNIT)){ 
00384        
00385        k=htonl(payload[REQUEST_URI_IDX+1]+payload[REQUEST_URI_IDX+2]);
00386        fwrite(&k,1,4,fd);
00387        fwrite(msg,1,ntohl(k),fd);
00388        k=htonl((long)payload[REQUEST_URI_IDX]);
00389        fwrite(&k,1,4,fd);
00390        fwrite(&payload[REQUEST_URI_IDX+1],1,payload[REQUEST_URI_IDX],fd);
00391        fwrite(&theSignal,1,4,fd);
00392     }else
00393        print_uri_junit_tests(msg,payload[REQUEST_URI_IDX+1]+payload[REQUEST_URI_IDX+2]
00394         ,&payload[REQUEST_URI_IDX+1],payload[REQUEST_URI_IDX],fd,1,"");
00395       }
00396       i=REQUEST_URI_IDX+1+payload[REQUEST_URI_IDX];
00397    }else{
00398       i=REQUEST_URI_IDX;
00399    }
00400    j=payload[i];
00401    i++;
00402    for(k=i;k<i+(j*3);k+=3){
00403       memcpy(&l,&payload[k+1],2);
00404       memcpy(&m,&payload[k+4],2);
00405       l=ntohs(l);
00406       m=ntohs(m);
00407       if(header==(char)payload[k] ||
00408        (header=='U' &&
00409         (payload[k]=='f' ||
00410          payload[k]=='t' ||
00411          payload[k]=='m' ||
00412          payload[k]=='o' ||
00413          payload[k]=='p')))
00414     dump_headers_test(msg,msglen,&payload[i+(j*3)+l+3],m-l,payload[k],fd,segregationLevel);
00415    }
00416    return 1;
00417 }
00418 
00419 
00420 /*
00421  * Function to generate testing file, where we dump entire encoded-messages
00422  * preceded by a network-byte-order short int that says how long is the message,
00423  * or just encoded-headers. The last integer, is a flag set of which headers
00424  * must be dumped
00425  */
00426 
00427 int print_msg_junit_test(char *code,FILE* fd,char header,char segregationLevel)
00428 {
00429    unsigned short int i,j,l,m,msglen;
00430    int k;
00431    char r,*msg;
00432    unsigned char *payload;
00433    payload=(unsigned char*)code;
00434    memcpy(&i,code,2);/*the CODE of the request/response*/
00435    memcpy(&j,&code[MSG_START_IDX],2);/*where the MSG starts*/
00436    memcpy(&msglen,&code[MSG_LEN_IDX],2);/*how long the MSG is*/
00437    i=ntohs(i);
00438    j=ntohs(j);
00439    msglen=ntohs(msglen);
00440    if(header==0){
00441       fwrite(code,1,j+msglen,fd);
00442       fwrite(&theSignal,1,4,fd);
00443       return 0;
00444    }
00445    msg=(char*)&payload[j];
00446    r=(i<100)?1:0;
00447    if(r){
00448       if(segregationLevel & ALSO_RURI){
00449     k=htonl(50);
00450     fwrite(&k,1,4,fd);
00451     fwrite(msg,1,50,fd);
00452     k=htonl((long)payload[REQUEST_URI_IDX]);
00453     fwrite(&k,1,4,fd);
00454     fwrite(&payload[REQUEST_URI_IDX+1],1,payload[REQUEST_URI_IDX],fd);
00455     fwrite(&theSignal,1,4,fd);
00456       }
00457       i=REQUEST_URI_IDX+1+payload[REQUEST_URI_IDX];
00458    }else{
00459       i=REQUEST_URI_IDX;
00460    }
00461    j=payload[i];
00462    i++;
00463    for(k=i;k<i+(j*3);k+=3){
00464       memcpy(&l,&payload[k+1],2);
00465       memcpy(&m,&payload[k+4],2);
00466       l=ntohs(l);
00467       m=ntohs(m);
00468       if(header==(char)payload[k] ||
00469        (header=='U' &&
00470         (payload[k]=='f' ||
00471          payload[k]=='t' ||
00472          payload[k]=='m' ||
00473          payload[k]=='o' ||
00474          payload[k]=='p')))
00475     dump_headers_test(msg,msglen,&payload[i+(j*3)+l+3],m-l,payload[k],fd,segregationLevel);
00476    }
00477    return 1;
00478 }

Generated on Wed May 23 06:00:45 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6