modules/tm/t_msgbuilder.c
1400b772
 /*
  * $Id$
  *
  * message printing
  */
 
 #include "hash_func.h"
 #include "t_funcs.h"
 #include "../../dprint.h"
 #include "../../config.h"
 #include "../../parser/parser_f.h"
 #include "../../ut.h"
 #include "../../parser/msg_parser.h"
 
 
 
 #define  append_mem_block(_d,_s,_len) \
 		do{\
 			memcpy((_d),(_s),(_len));\
 			(_d) += (_len);\
 		}while(0);
 
 
 /* Builds a CANCEL request based on an INVITE request. CANCEL is send
  * to same address as the INVITE */
 int t_build_and_send_CANCEL(struct cell *Trans,unsigned int branch)
 {
 	struct sip_msg      *p_msg;
 	struct hdr_field    *hdr;
 	char                *cancel_buf, *p, *via;
 	unsigned int         len, via_len;
 
 	if ( !Trans->uac[branch].rpl_received )
 	{
 		DBG("DEBUG: t_build_and_send_CANCEL: no response ever received"
 			" : dropping local cancel! \n");
 		return 1;
 	}
 
 	if (Trans->uac[branch].request.cancel!=NO_CANCEL)
 	{
 		DBG("DEBUG: t_build_and_send_CANCEL: branch (%d)was already canceled"
 			" : dropping local cancel! \n",branch);
 		return 1;
 	}
 
 	cancel_buf = 0;
 	via = 0;
 	p_msg = Trans->uas.request;
 
9b47a45c
 	/* method, separators, version */
 	len=SIP_VERSION_LEN + CANCEL_LEN + 2 /* spaces */ + CRLF_LEN;
 	/* if URL was overridden .... */
1400b772
 	if (Trans->uac[branch].uri.s)
9b47a45c
 		len+=Trans->uac[branch].uri.len;
 	else
 	/* ... otherwise use the inbound URL */
 		len+=REQ_LINE(p_msg).uri.len;
 
1400b772
 	/*via*/
 	if ( add_branch_label(Trans,p_msg,branch)==-1 )
 		goto error;
 	via = via_builder(p_msg , &via_len, Trans->uac[branch].request.send_sock );
 	if (!via)
 	{
 		LOG(L_ERR, "ERROR: t_build_and_send_CANCEL: "
 			"no via header got from builder\n");
 		goto error;
 	}
 	len+= via_len;
 	/*headers*/
9b47a45c
 	for ( hdr=p_msg->headers ; hdr ; hdr=hdr->next ) {
 		if (hdr->type==HDR_FROM || hdr->type==HDR_CALLID 
 			|| hdr->type==HDR_TO )
1400b772
 			len += ((hdr->body.s+hdr->body.len ) - hdr->name.s ) + CRLF_LEN ;
9b47a45c
 		else if (hdr->type==HDR_CSEQ)
 			len += hdr->name.len + 2 + ((struct cseq_body*)hdr->parsed)->number.len +
 				1+CANCEL_LEN+CRLF_LEN;
 	}
 	/* User Agent, Conteny Length, EoM */
 	len += USER_AGENT_LEN + CRLF_LEN +
 		CONTENT_LEN_LEN + CRLF_LEN +
 		CRLF_LEN;
1400b772
 
 	cancel_buf=sh_malloc( len+1 );
 	if (!cancel_buf)
 	{
 		LOG(L_ERR, "ERROR: t_build_and_send_CANCEL: cannot allocate memory\n");
 		goto error;
 	}
 	p = cancel_buf;
 
9b47a45c
 	append_mem_block( p, CANCEL " ", CANCEL_LEN +1 );
 	if (Trans->uac[branch].uri.s) {
 		append_mem_block( p, Trans->uac[branch].uri.s, 
1400b772
 			Trans->uac[branch].uri.len);
9b47a45c
 	} else {
 		append_mem_block(p,REQ_LINE(p_msg).uri.s,
 			REQ_LINE(p_msg).uri.len );
1400b772
 	}
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*/
 	for ( hdr=p_msg->headers ; hdr ; hdr=hdr->next )
 	{
 		if(hdr->type==HDR_FROM||hdr->type==HDR_CALLID||hdr->type==HDR_TO)
 		{
 			append_mem_block(p,hdr->name.s,
 				((hdr->body.s+hdr->body.len)-hdr->name.s) );
 			append_mem_block(p, CRLF, CRLF_LEN );
9b47a45c
 		} else if ( hdr->type==HDR_CSEQ )
1400b772
 		{
9b47a45c
 			append_mem_block(p,hdr->name.s, hdr->name.len );
 			append_mem_block(p,": ", 2 );
 			append_mem_block(p, ((struct cseq_body*)hdr->parsed)->number.s,
 				((struct cseq_body*)hdr->parsed)->number.len );
 			append_mem_block(p, " " CANCEL CRLF, 1+CANCEL_LEN+CRLF_LEN);
1400b772
 		}
9b47a45c
 	}
 
 	/* User Agent header, Content Length, EoM */
 	append_mem_block(p,USER_AGENT CRLF CONTENT_LEN CRLF CRLF ,
 		USER_AGENT_LEN + CRLF_LEN + CONTENT_LEN_LEN + CRLF_LEN + CRLF_LEN);
1400b772
 	*p=0;
 
 	if (Trans->uac[branch].request.cancel) {
 		shm_free( cancel_buf );
 		LOG(L_WARN, "send_cancel: Warning: CANCEL already sent out\n");
 		goto error;
 	}
 
 	Trans->uac[branch].request.activ_type = TYPE_LOCAL_CANCEL;
 	Trans->uac[branch].request.cancel = cancel_buf;
 	Trans->uac[branch].request.cancel_len = len;
 
 	/*sets and starts the FINAL RESPONSE timer */
 	set_timer(hash_table,&(Trans->uac[branch].request.fr_timer),FR_TIMER_LIST);
 	/* sets and starts the RETRANS timer */
 	Trans->uac[branch].request.retr_list = RT_T1_TO_1;
 	set_timer(hash_table,&(Trans->uac[branch].request.retr_timer),RT_T1_TO_1);
 	DBG("DEBUG: T_build_and_send_CANCEL : sending cancel...\n");
 	SEND_CANCEL_BUFFER( &(Trans->uac[branch].request) );
 
 	pkg_free(via);
 	return 1;
 error:
 	if (via) pkg_free(via);
 	return -1;
 }
 
 
 /* Builds an ACK request based on an INVITE request. ACK is send
  * to same address */
 char *build_ack(struct sip_msg* rpl,struct cell *trans,int branch,int *ret_len)
 {
 	struct sip_msg      *p_msg , *r_msg;
 	struct hdr_field    *hdr;
 	char                *ack_buf, *p, *via;
 	unsigned int         len, via_len;
 
 	ack_buf = 0;
 	via =0;
 	p_msg = trans->uas.request;
 	r_msg = rpl;
 
 	if ( parse_headers(rpl,HDR_TO)==-1 || !rpl->to )
 	{
 		LOG(L_ERR, "ERROR: t_build_ACK: "
 			"cannot generate a HBH ACK if key HFs in reply missing\n");
 		goto error;
 	}
 
 	len = 0;
 	/*first line's len */
 	len += 4/*reply code and one space*/+
 		p_msg->first_line.u.request.version.len+CRLF_LEN;
 	/*uri's len*/
 	if (trans->uac[branch].uri.s)
 		len += trans->uac[branch].uri.len +1;
 	else
 		len += p_msg->first_line.u.request.uri.len +1;
 	/*adding branch param*/
 	if ( add_branch_label( trans , trans->uas.request , branch)==-1 )
 		goto error;
 	/*via*/
 	via = via_builder(p_msg , &via_len, trans->uac[branch].request.send_sock );
 	if (!via)
 	{
 		LOG(L_ERR, "ERROR: t_build_ACK: "
 			"no via header got from builder\n");
 		goto error;
 	}
 	len+= via_len;
 	/*headers*/
 	for ( hdr=p_msg->headers ; hdr ; hdr=hdr->next )
 		if (hdr->type==HDR_FROM||hdr->type==HDR_CALLID||hdr->type==HDR_CSEQ)
 			len += ((hdr->body.s+hdr->body.len ) - hdr->name.s ) + CRLF_LEN ;
 		else if ( hdr->type==HDR_TO )
 			len += ((r_msg->to->body.s+r_msg->to->body.len ) -
 				r_msg->to->name.s ) + CRLF_LEN ;
 	/* CSEQ method : from INVITE-> ACK */
 	len -= 3  ;
 	/* end of message */
 	len += CRLF_LEN; /*new line*/
 
 	ack_buf = sh_malloc(len+1);
 	if (!ack_buf)
 	{
 		LOG(L_ERR, "ERROR: t_build_and_ACK: cannot allocate memory\n");
 		goto error1;
 	}
 	p = ack_buf;
 
 	/* first line */
 	memcpy( p , "ACK " , 4);
 	p += 4;
 	/* uri */
 	if ( trans->uac[branch].uri.s )
 	{
 		memcpy(p,trans->uac[branch].uri.s,trans->uac[branch].uri.len);
 		p +=trans->uac[branch].uri.len;
 	}else{
 		memcpy(p,p_msg->orig+(p_msg->first_line.u.request.uri.s-p_msg->buf),
 			p_msg->first_line.u.request.uri.len );
 		p += p_msg->first_line.u.request.uri.len;
 	}
 	/* SIP version */
 	*(p++) = ' ';
 	memcpy(p,p_msg->orig+(p_msg->first_line.u.request.version.s-p_msg->buf),
 		p_msg->first_line.u.request.version.len );
 	p += p_msg->first_line.u.request.version.len;
 	memcpy( p, CRLF, CRLF_LEN );
 	p+=CRLF_LEN;
 
 	/* insert our via */
 	memcpy( p , via , via_len );
 	p += via_len;
 
 	/*other headers*/
 	for ( hdr=p_msg->headers ; hdr ; hdr=hdr->next )
 	{
 		if ( hdr->type==HDR_FROM || hdr->type==HDR_CALLID  )
 		{
 			memcpy( p , p_msg->orig+(hdr->name.s-p_msg->buf) ,
 				((hdr->body.s+hdr->body.len ) - hdr->name.s ) );
 			p += ((hdr->body.s+hdr->body.len ) - hdr->name.s );
 			memcpy( p, CRLF, CRLF_LEN );
 			p+=CRLF_LEN;
 		}
 		else if ( hdr->type==HDR_TO )
 		{
 			memcpy( p , r_msg->orig+(r_msg->to->name.s-r_msg->buf) ,
 				((r_msg->to->body.s+r_msg->to->body.len)-r_msg->to->name.s));
 			p+=((r_msg->to->body.s+r_msg->to->body.len)-r_msg->to->name.s);
 			memcpy( p, CRLF, CRLF_LEN );
 			p+=CRLF_LEN;
 		}
 		else if ( hdr->type==HDR_CSEQ )
 		{
 			memcpy( p , p_msg->orig+(hdr->name.s-p_msg->buf) ,
 				((((struct cseq_body*)hdr->parsed)->method.s)-hdr->name.s));
 			p+=((((struct cseq_body*)hdr->parsed)->method.s)-hdr->name.s);
 			memcpy( p , "ACK" CRLF, 3+CRLF_LEN );
 			p += 3+CRLF_LEN;
 		}
 	}
 
 	/* end of message */
 	memcpy( p , CRLF , CRLF_LEN );
 	p += CRLF_LEN;
 
 	pkg_free( via );
 	DBG("DEBUG: t_build_ACK: ACK generated\n");
 
 	*(ret_len) = p-ack_buf;
 	return ack_buf;
 
 error1:
 	pkg_free(via );
 error:
 	return 0;
 }