You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kamailio/modules/seas/encode_msg.c

479 lines
15 KiB

/* $Id$
*
* Copyright (C) 2006-2007 VozTelecom Sistemas S.L
*
* This file is part of Kamailio, a free SIP server.
*
* Kamailio 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
*
* Kamailio 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: 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>
#include <stddef.h>
#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)
{
int i,j,k,u,request;
unsigned short int h;
struct hdr_field* hf;
struct msg_start* ms;
struct sip_uri miuri;
char *myerror=NULL;
ptrdiff_t diff;
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;
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);
}
if(h==32){/*statuscode wont be 32...*/
myerror="unknown message type\n";
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*/
/*then goes the message length (we hope it to be less than 65535 bytes...)*/
memcpy(&payload[MSG_LEN_IDX],&h,2);
/*then goes the content start index (starting from SIP MSG START)*/
if(0>(diff=(get_body(msg)-(msg->buf)))){
myerror="body starts before the message (uh ?)";
goto error;
}else
h=htons((unsigned short int)diff);
memcpy(payload+CONTENT_IDX,&h,2);
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){
if (parse_uri(ms->u.request.uri.s,ms->u.request.uri.len, &miuri)<0){
LM_ERR("<%.*s>\n",ms->u.request.uri.len,ms->u.request.uri.s);
myerror="while parsing the R-URI";
goto error;
}
if(0>(j=encode_uri2(msg->buf,
ms->u.request.method.s-msg->buf+ms->len,
ms->u.request.uri,&miuri,
(unsigned char*)&payload[REQUEST_URI_IDX+1])))
{
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?*/
if(0>(i=encode_header(msg,hf,(unsigned char*)(payload+j),MAX_ENCODED_MSG+MAX_MESSAGE_LEN-j))){
LM_ERR("encoding header %.*s\n",hf->name.len,hf->name.s);
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);
LM_DBG("msglen = %d,msg starts at %d\n",msg->len,j);
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:
LM_ERR("%s\n",myerror);
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:
LM_ERR("(%s)\n",myerror);
return -1;
}
int print_encoded_msg(FILE* fd,char *code,char *prefix)
{
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++)
fprintf(fd,"%s%d%s",k==0?"ENCODED-MSG:[":":",payload[k],k==j-1?"]\n":"");
msg=(char*)&payload[j];
fprintf(fd,"MESSAGE:\n[%.*s]\n",msglen,msg);
r=(i<100)?1:0;
if(r){
fprintf(fd,"%sREQUEST CODE=%d==%.*s,URI=%.*s,VERSION=%*.s\n",prefix,i,
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{
fprintf(fd,"%sRESPONSE CODE=%d==%.*s,REASON=%.*s,VERSION=%.*s\n",prefix,i,
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;
fprintf(fd,"%sMESSAGE CONTENT:%.*s\n",prefix,j,&msg[k]);
j=payload[i];
fprintf(fd,"%sHEADERS PRESENT(%d):",prefix,j);
i++;
for(k=i;k<i+(j*3);k+=3)
fprintf(fd,"%c%d%c",k==i?'[':',',payload[k],k==(i+3*j-3)?']':' ');
fprintf(fd,"\n");
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
*/
int dump_msg_test(char *code,FILE* fd,char header,char segregationLevel)
{
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){
fwrite(code,1,j+msglen,fd);
fwrite(&theSignal,1,4,fd);
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]);
fwrite(&k,1,4,fd);
fwrite(msg,1,ntohl(k),fd);
k=htonl((long)payload[REQUEST_URI_IDX]);
fwrite(&k,1,4,fd);
fwrite(&payload[REQUEST_URI_IDX+1],1,payload[REQUEST_URI_IDX],fd);
fwrite(&theSignal,1,4,fd);
}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
*/
int print_msg_junit_test(char *code,FILE* fd,char header,char segregationLevel)
{
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){
fwrite(code,1,j+msglen,fd);
fwrite(&theSignal,1,4,fd);
return 0;
}
msg=(char*)&payload[j];
r=(i<100)?1:0;
if(r){
if(segregationLevel & ALSO_RURI){
k=htonl(50);
fwrite(&k,1,4,fd);
fwrite(msg,1,50,fd);
k=htonl((long)payload[REQUEST_URI_IDX]);
fwrite(&k,1,4,fd);
fwrite(&payload[REQUEST_URI_IDX+1],1,payload[REQUEST_URI_IDX],fd);
fwrite(&theSignal,1,4,fd);
}
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;
}