modules/tm/t_msgbuilder.c
1400b772
 /*
  * $Id$
  *
  * message printing
7dd0b342
  *
  * Copyright (C) 2001-2003 Fhg Fokus
  *
  * This file is part of ser, a free SIP server.
  *
  * ser 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
  *
  * For a license to use the ser software under conditions
  * other than those described here, or to purchase support for this
  * software, please contact iptel.org by e-mail at the following addresses:
  *    info@iptel.org
  *
  * ser 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
1400b772
  */
 
7dd0b342
 
caf80ae6
 #include "../../hash_func.h"
 #include "../../globals.h"
1400b772
 #include "t_funcs.h"
 #include "../../dprint.h"
 #include "../../config.h"
 #include "../../parser/parser_f.h"
 #include "../../ut.h"
 #include "../../parser/msg_parser.h"
caf80ae6
 #include "t_msgbuilder.h"
 #include "uac.h"
1400b772
 
 
 
 #define  append_mem_block(_d,_s,_len) \
 		do{\
 			memcpy((_d),(_s),(_len));\
 			(_d) += (_len);\
 		}while(0);
 
90b0b10d
 #define append_str(_p,_str) \
 	do{  \
 		memcpy((_p), (_str).s, (_str).len); \
 		(_p)+=(_str).len;  \
  	} while(0);
1400b772
 
caf80ae6
 /* Build a local request based on a previous request; main
    customers of this function are local ACK and local CANCEL
  */
 char *build_local(struct cell *Trans,unsigned int branch,
 	unsigned int *len, char *method, int method_len, str *to)
1400b772
 {
 	char                *cancel_buf, *p, *via;
caf80ae6
 	unsigned int         via_len;
 	struct hdr_field    *hdr;
 	char branch_buf[MAX_BRANCH_PARAM_LEN];
 	int branch_len;
1400b772
 
caf80ae6
 	if ( Trans->uac[branch].last_received<100)
1400b772
 	{
caf80ae6
 		DBG("DEBUG: build_local: no response ever received"
 			" : dropping local request! \n");
 		goto error;
1400b772
 	}
 
caf80ae6
 	/* method, separators, version: "CANCEL sip:p2@iptel.org SIP/2.0" */
 	*len=SIP_VERSION_LEN + method_len + 2 /* spaces */ + CRLF_LEN;
 	*len+=Trans->uac[branch].uri.len;
9b47a45c
 
1400b772
 	/*via*/
caf80ae6
 	if (!t_calc_branch(Trans,  branch, 
 		branch_buf, &branch_len ))
1400b772
 		goto error;
caf80ae6
 	via=via_builder(&via_len, Trans->uac[branch].request.send_sock,
 		branch_buf, branch_len );
1400b772
 	if (!via)
 	{
 		LOG(L_ERR, "ERROR: t_build_and_send_CANCEL: "
 			"no via header got from builder\n");
 		goto error;
 	}
caf80ae6
 	*len+= via_len;
1400b772
 	/*headers*/
caf80ae6
 	*len+=Trans->from.len+CRLF_LEN
 		+Trans->callid.len+CRLF_LEN
 		+to->len+CRLF_LEN
 		/* CSeq: 101 CANCEL */
 		+Trans->cseq_n.len+1+method_len+CRLF_LEN; 
 
 	/* copy'n'paste Route headers */
 	if (!Trans->local) {
 		for ( hdr=Trans->uas.request->headers ; hdr ; hdr=hdr->next )
 			 if (hdr->type==HDR_ROUTE)
 				len+=((hdr->body.s+hdr->body.len ) - hdr->name.s ) + 
 					CRLF_LEN ;
 	}
 
 	/* User Agent */
 	if (server_signature) {
 		*len += USER_AGENT_LEN + CRLF_LEN;
9b47a45c
 	}
caf80ae6
 	/* Content Length, EoM */
82802743
 	*len+=CONTENT_LENGTH_LEN+1 + CRLF_LEN + CRLF_LEN;
1400b772
 
caf80ae6
 	cancel_buf=shm_malloc( *len+1 );
1400b772
 	if (!cancel_buf)
 	{
 		LOG(L_ERR, "ERROR: t_build_and_send_CANCEL: cannot allocate memory\n");
caf80ae6
 		goto error01;
1400b772
 	}
 	p = cancel_buf;
 
caf80ae6
 	append_mem_block( p, method, method_len );
 	append_mem_block( p, " ", 1 );
 	append_str( p, Trans->uac[branch].uri );
9b47a45c
 	append_mem_block( p, " " SIP_VERSION CRLF, 1+SIP_VERSION_LEN+CRLF_LEN );
 
1400b772
 	/* insert our via */
 	append_mem_block(p,via,via_len);
 
 	/*other headers*/
caf80ae6
 	append_str( p, Trans->from );
 	append_mem_block( p, CRLF, CRLF_LEN );
 	append_str( p, Trans->callid );
 	append_mem_block( p, CRLF, CRLF_LEN );
 	append_str( p, *to );
 	append_mem_block( p, CRLF, CRLF_LEN );
 	append_str( p, Trans->cseq_n );
 	append_mem_block( p, " ", 1 );
 	append_mem_block( p, method, method_len );
 	append_mem_block( p, CRLF, CRLF_LEN );
 
 	if (!Trans->local)  {
 		for ( hdr=Trans->uas.request->headers ; hdr ; hdr=hdr->next )
 			if(hdr->type==HDR_ROUTE) {
 				append_mem_block(p, hdr->name.s,
 					hdr->body.s+hdr->body.len-hdr->name.s );
 				append_mem_block(p, CRLF, CRLF_LEN );
 			}
9b47a45c
 	}
 
caf80ae6
 	/* User Agent header */
 	if (server_signature) {
 		append_mem_block(p,USER_AGENT CRLF, USER_AGENT_LEN+CRLF_LEN );
1400b772
 	}
caf80ae6
 	/* Content Length, EoM */
82802743
 	append_mem_block(p, CONTENT_LENGTH "0" CRLF CRLF ,
 		CONTENT_LENGTH_LEN+1 + CRLF_LEN + CRLF_LEN);
caf80ae6
 	*p=0;
1400b772
 
 	pkg_free(via);
caf80ae6
 	return cancel_buf;
 error01:
 	pkg_free(via);
1400b772
 error:
caf80ae6
 	return NULL;
1400b772
 }
 
 
 
c430ed7b
 char *build_uac_request(  str msg_type, str dst, str from,
82802743
 	str fromtag, int cseq, str callid, str headers, 
 	str body, int branch, 
 	struct cell *t, unsigned int *len)
caf80ae6
 {
 	char *via;
2efb293b
 	unsigned int via_len;
caf80ae6
 	char content_len[10];
 	int content_len_len;
82802743
 	char cseq_str[10];
 	int cseq_str_len;
caf80ae6
 	char *buf;
 	char *w;
82802743
 #ifdef _OBSOLETED
caf80ae6
 	int dummy;
82802743
 #endif
caf80ae6
 
 	char branch_buf[MAX_BRANCH_PARAM_LEN];
 	int branch_len;
 
c430ed7b
 	int from_len;
 	char *from_str;
caf80ae6
 
 	buf=0;
c430ed7b
 
82802743
 	/* print content length */
 	content_len_len=snprintf(
 		content_len, sizeof(content_len), 
 		"%d", body.len );
 	if (content_len_len==-1) {
 		LOG(L_ERR, "ERROR: uac: content_len too big\n");
 		return 0;
 	}
 	/* print cseq */
 	cseq_str_len=snprintf( 
 		cseq_str, sizeof(cseq_str),
 		"%d", cseq );
 	if (cseq_str_len==-1) {
 		LOG(L_ERR, "ERROR: uac: cseq too big\n");
 		return 0;
 	}
 
c430ed7b
 	if (from.len) {
 		from_len=from.len;
 		from_str=from.s;
 	} else {
 		from_len=strlen(uac_from);
 		from_str=uac_from;
 	}
caf80ae6
 	
 	*len=SIP_VERSION_LEN+msg_type.len+2/*spaces*/+CRLF_LEN+
 		dst.len;
 
 	if (!t_calc_branch(t, branch, branch_buf, &branch_len )) {
 		LOG(L_ERR, "ERROR: build_uac_request: branch calculation failed\n");
1400b772
 		goto error;
 	}
caf80ae6
 	via=via_builder(&via_len, t->uac[branch].request.send_sock,
 		branch_buf, branch_len );
 	
 	if (!via) {
 		LOG(L_ERR, "ERROR: build_uac_request: via building failed\n");
1400b772
 		goto error;
 	}
caf80ae6
 	*len+=via_len;
 	/* header names and separators */
 	*len+=
 		+CSEQ_LEN+CRLF_LEN
 		+TO_LEN+CRLF_LEN
 		+CALLID_LEN+CRLF_LEN
 		+CONTENT_LENGTH_LEN+CRLF_LEN
 		+ (server_signature ? USER_AGENT_LEN + CRLF_LEN : 0 )
 		+FROM_LEN+CRLF_LEN
 		+CRLF_LEN; /* EoM */
 	/* header field value and body length */
82802743
 	*len+= msg_type.len+1+cseq_str_len /* CSeq: method, delimitor, number  */
caf80ae6
 		+ dst.len /* To */
82802743
 		+ callid.len /* call-id */
 		+ from_len+FROMTAG_LEN+fromtag.len
caf80ae6
 		+ content_len_len
 		+ headers.len
 		+ body.len;
 	
 	buf=shm_malloc( *len+1 );
 	if (!buf) {
 		LOG(L_ERR, "ERROR: t_uac: no shmem\n");
1400b772
 		goto error1;
 	}
caf80ae6
 	w=buf;
 	memapp( w, msg_type.s, msg_type.len ); 
 	memapp( w, " ", 1); 
 	t->uac[branch].uri.s=w; t->uac[branch].uri.len=dst.len;
 	memapp( w, dst.s, dst.len ); 
 	memapp( w, " " SIP_VERSION CRLF, 1+SIP_VERSION_LEN+CRLF_LEN );
 	memapp( w, via, via_len );
82802743
 
 	/* CSeq */
 	t->cseq_n.s=w; 
 	t->cseq_n.len=CSEQ_LEN+cseq_str_len;
 	memapp(w, CSEQ, CSEQ_LEN );
 	memapp(w, cseq_str, cseq_str_len );
 	memapp(w, " ", 1 );
 
caf80ae6
 	memapp( w, msg_type.s, msg_type.len );
 	t->to.s=w+CRLF_LEN; t->to.len=TO_LEN+dst.len;
 	memapp( w, CRLF TO, CRLF_LEN + TO_LEN  );
 	memapp( w, dst.s, dst.len );
82802743
 	t->callid.s=w+CRLF_LEN; t->callid.len=callid.len;
caf80ae6
 	memapp( w, CRLF CALLID, CRLF_LEN + CALLID_LEN  );
82802743
 	memapp( w, callid.s, callid.len );
 	memapp( w, CRLF CONTENT_LENGTH, CRLF_LEN + CONTENT_LENGTH_LEN);
caf80ae6
 	memapp( w, content_len, content_len_len );
 	if (server_signature) {
 		memapp( w, CRLF USER_AGENT CRLF FROM, 
 			CRLF_LEN+USER_AGENT_LEN+CRLF_LEN+FROM_LEN);
 	} else {
 		memapp( w, CRLF  FROM, 
 			CRLF_LEN+FROM_LEN);
1400b772
 	}
82802743
 	t->from.s=w-FROM_LEN; 
 	t->from.len=FROM_LEN+from_len+FROMTAG_LEN+fromtag.len;
c430ed7b
 	memapp( w, from_str, from_len );
caf80ae6
 	memapp( w, FROMTAG, FROMTAG_LEN );
82802743
 	memapp( w, fromtag.s, fromtag.len );
caf80ae6
 	memapp( w, CRLF, CRLF_LEN );
 
 	memapp( w, headers.s, headers.len );
 	/* EoH */
 	memapp( w, CRLF, CRLF_LEN );
 	if ( body.s ) {
 		memapp( w, body.s, body.len );
1400b772
 	}
82802743
 #ifdef _OBSOLETED
caf80ae6
 	/* ugly HACK -- debugging has shown len shorter by one */
 	dummy=*len+1;
 	*len=dummy;
82802743
 #endif
caf80ae6
 #	ifdef EXTRA_DEBUG
 	if (w-buf != *len ) abort();
 #	endif
 	
 	
1400b772
 error1:
caf80ae6
 	pkg_free(via);	
1400b772
 error:
caf80ae6
 	return buf;
 	
1400b772
 }
 
 
caf80ae6
 int t_calc_branch(struct cell *t, 
 	int b, char *branch, int *branch_len)
 {
 	return syn_branch ?
 		branch_builder( t->hash_index,
 			t->label, 0,
 			b, branch, branch_len )
 		: branch_builder( t->hash_index,
 			0, t->md5,
 			b, branch, branch_len );
 }
1400b772