msg_translator.c
caf80ae6
 /* 
  * $Id$
9d045b03
  *
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
0bf716b8
  * 
  *
  * History:
  * --------
40686bb1
  * 2003-01-20  bug_fix: use of return value of snprintf aligned to C99 (jiri)
  * 2003-01-23  added rport patches, contributed by 
  *              Maxim Sobolev <sobomax@FreeBSD.org> and heavily modified by me
  *              (andrei)
  * 2003-01-24  added i param to via of outgoing requests (used by tcp),
  *              modified via_builder params (andrei)
  * 2003-01-27  more rport fixes (make use of new via_param->start)  (andrei)
  * 2003-01-27  next baby-step to removing ZT - PRESERVE_ZT (jiri)
  * 2003-01-29  scratchpad removed (jiri)
d1e2a411
  * 2003-02-28  scratchpad compatibility abandoned (jiri)
  * 2003-03-01  VOICE_MAIL defs removed (jiri)
  * 2003-03-06  totags in outgoing replies bookmarked to enable
  *             ACK/200 tag matching (andrei)
  * 2003-03-18  killed the build_warning snprintf (andrei)
f15bede1
  * 2003-03-31  added subst lump support (andrei)
d1e2a411
  * 2003-04-01  added opt (conditional) lump support (andrei)
c55adae8
  * 2003-04-02  added more subst lumps: SUBST_{SND,RCV}_ALL  
  *              => ip:port;transport=proto (andrei)
3e8c3475
  * 2003-04-12  added FL_FORCE_RPORT support (andrei)
a2339d9a
  * 2003-04-13  updated warning builder -- fixed (andrei)
785c78c3
  * 2003-07-10  check_via_address knows now how to compare with ipv6 address
  *              references (e.g [::1]) (andrei)
  *             build_req_fomr_sip_req no longer adds 1 for ipv6 via parameter
  *              position calculations ([] are part of host.s now) (andrei)
0bf716b8
  *
9d045b03
  */
3e8c3475
 /* Via special params:
  * requests:
  * - if the address in via is different from the src_ip or an existing
  *   received=something is found, received=src_ip is added (and any preexisting
  *   received is deleted). received is added as the first via parameter if no
  *   receive is previoulsy present or over the old receive.
  * - if the original via contains rport / rport=something or msg->msg_flags
  *   FL_FORCE_RPORT is set (e.g. script force_rport() cmd) rport=src_port
  *   is added (over previous rport / as first via param or after received
  *   if no received was present and received is added too)
  * local replies:
  *    (see also sl_send_reply)
  *  - rport and received are added in mostly the same way as for requests, but 
  *    in the reverse order (first rport and then received). See also 
  *    limitations.
  *  - if reply_to_via is set (default off) the local reply will be sent to
  *    the address in via (received is ignored since it was not set by us). The
  *    destination port is either the message source port if via contains rport
  *    or the FL_FORCE_RPORT flag is set or the port from the via. If either
  *    port or rport are present a normal dns lookup (instead of a srv lookup)
  *    is performed on the address. If no port is present and a srv lookup is 
  *    performed the port is taken from the srv lookup. If the srv lookup failed
  *    or it was not performed, the port is set to the default sip port (5060).
a7e13a89
  *  - if reply_to_via is off (default) the local reply is sent to the message
3e8c3475
  *    source ip address. The destination port is set to the source port if 
  *    rport is present or FL_FORCE_RPORT flag is set, to the via port or to
  *    the default sip port (5060) if neither rport or via port are present.
  * "normal" replies:
  *  - if received is present the message is sent to the received address else
  *    if no port is present (neither a normal via port or rport) a dns srv 
  *    lookup is performed on the host part and the reply is sent to the 
  *    resulting ip. If a port is present or the host part is an ip address 
  *    the dns lookup will be a "normal" one (A or AAAA).
  *  - if rport is present, it's value will be used as the destination port
  *   (and this will also disable srv lookups)
  *  - if no port is present the destination port will be taken from the srv
  *    lookup. If the srv lookup fails or is not performed (e.g. ip address
  *    in host) the destination port will be set to the default sip port (5060).
  *  
  * Known limitations:
  * - when locally replying to a message, rport and received will be appended to
  *   the via header parameters (for forwarded requests they are inserted at the
  *   beginning).
  * - a locally generated reply might get two received via parameters if a
  *   received is already present in the original message (this should not
  *   happen though, but ...)
  *
  *--andrei
 */
7dd0b342
 
381659ac
 #include <sys/types.h>
dd01b806
 #include <sys/socket.h>
e22bbdb8
 #include <netdb.h>
 #include <string.h>
5e39b907
 #include <stdio.h>
20374571
 #include <stdlib.h>
dd01b806
 
1540fad1
 #include "comp_defs.h"
26b939c6
 #include "msg_translator.h"
4e2fdd79
 #include "globals.h"
1400b772
 #include "error.h"
dda9dab1
 #include "mem/mem.h"
26b939c6
 #include "dprint.h"
 #include "config.h"
676eb608
 #include "md5utils.h"
0498ceb9
 #include "data_lump_rpl.h"
4e2fdd79
 #include "ip_addr.h"
 #include "resolve.h"
caf80ae6
 #include "ut.h"
f51155cf
 #include "pt.h"
e22bbdb8
 
26b939c6
 
1540fad1
 #define append_str(_dest,_src,_len) \
340bddb4
 	do{\
 		memcpy( (_dest) , (_src) , (_len) );\
 		(_dest) += (_len) ;\
 	}while(0);
 
049f64c2
 #define append_str_trans(_dest,_src,_len,_msg) \
 	append_str( (_dest), (_src), (_len) );
340bddb4
 
5655ca6f
 extern char version[];
 extern int version_len;
26b939c6
 
 
 
049f64c2
 
 
 /* checks if ip is in host(name) and ?host(ip)=name?
  * ip must be in network byte order!
  *  resolver = DO_DNS | DO_REV_DNS; if 0 no dns check is made
  * return 0 if equal */
 static int check_via_address(struct ip_addr* ip, str *name, 
 				unsigned short port, int resolver)
 {
 	struct hostent* he;
 	int i;
 	char* s;
785c78c3
 	int len;
049f64c2
 
 	/* maybe we are lucky and name it's an ip */
 	s=ip_addr2a(ip);
 	if (s){
785c78c3
 		DBG("check_via_address(%s, %.*s, %d)\n", 
049f64c2
 			s, name->len, name->s, resolver);
785c78c3
 		len=strlen(s);
049f64c2
 
 	#ifdef USE_IPV6
785c78c3
 		/* check if name->s is an ipv6 address or an ipv6 address ref. */
 		if ((ip->af==AF_INET6) &&
 				(	((len==name->len)&&(strncasecmp(name->s, s, name->len)==0))
 					||
 					((len==(name->len-2))&&(name->s[0]=='[')&&
 						(name->s[name->len-1]==']')&&
 						(strncasecmp(name->s+1, s, len)==0))
 				)
 		   )
049f64c2
 			return 0;
 		else
 	#endif
 
 			if (strncmp(name->s, s, name->len)==0) 
 				return 0;
 	}else{
785c78c3
 		LOG(L_CRIT, "check_via_address: BUG: could not convert ip address\n");
049f64c2
 		return -1;
 	}
 
 	if (port==0) port=SIP_PORT;
 	if (resolver&DO_DNS){
785c78c3
 		DBG("check_via_address: doing dns lookup\n");
049f64c2
 		/* try all names ips */
d531a5d5
 		he=sip_resolvehost(name, &port, 0); /* FIXME proto? */
049f64c2
 		if (he && ip->af==he->h_addrtype){
 			for(i=0;he && he->h_addr_list[i];i++){
 				if ( memcmp(&he->h_addr_list[i], ip->u.addr, ip->len)==0)
 					return 0;
 			}
 		}
 	}
 	if (resolver&DO_REV_DNS){
785c78c3
 		DBG("check_via_address: doing rev. dns lookup\n");
049f64c2
 		/* try reverse dns */
 		he=rev_resolvehost(ip);
 		if (he && (strncmp(he->h_name, name->s, name->len)==0))
 			return 0;
 		for (i=0; he && he->h_aliases[i];i++){
 			if (strncmp(he->h_aliases[i],name->s, name->len)==0)
 				return 0;
 		}
 	}
 	return -1;
 }
26b939c6
 
 
0bf716b8
 static char * warning_builder( struct sip_msg *msg, unsigned int *returned_len)
5e39b907
 {
 	static char buf[MAX_WARNING_LEN];
 	str *foo;
40686bb1
 	int print_len, l;
 	int clen;
 	char* t;
 
a2339d9a
 #define str_print(string, string_len) \
40686bb1
 		do{ \
a2339d9a
 			l=(string_len); \
 			if ((clen+l)>MAX_WARNING_LEN) \
 				goto error_overflow; \
 			memcpy(buf+clen, (string), l); \
 			clen+=l; \
 		}while(0)
 	
 #define str_lenpair_print(string, string_len, string2, string2_len) \
 		do{ \
 			str_print(string, string_len); \
 			str_print(string2, string2_len);\
 		}while(0)
 	
 #define str_pair_print( string, string2, string2_len) \
 		str_lenpair_print((string), strlen((string)), (string2), (string2_len))
40686bb1
 		
 #define str_int_print(string, intval)\
 		do{\
 			t=int2str((intval), &print_len); \
 			str_pair_print(string, t, print_len);\
 		} while(0)
 		
 #define str_ipaddr_print(string, ipaddr_val)\
 		do{\
 			t=ip_addr2a((ipaddr_val)); \
 			print_len=strlen(t); \
 			str_pair_print(string, t, print_len);\
 		} while(0)
 	
a2339d9a
 	clen=0;
 	str_lenpair_print(WARNING, WARNING_LEN,
 						msg->rcv.bind_address->name.s,
 						msg->rcv.bind_address->name.len);
 	str_lenpair_print(":", 1, msg->rcv.bind_address->port_no_str.s,
 						msg->rcv.bind_address->port_no_str.len);
 	str_print(WARNING_PHRASE, WARNING_PHRASE_LEN);
40686bb1
 	
5e39b907
 	/*adding out_uri*/
 	if (msg->new_uri.s)
 		foo=&(msg->new_uri);
 	else
 		foo=&(msg->first_line.u.request.uri);
a2339d9a
 	/* pid= */
 	str_int_print(" pid=", my_pid());
 	/* req_src_ip= */
 	str_ipaddr_print(" req_src_ip=", &msg->rcv.src_ip);
 	str_int_print(" req_src_port=", msg->rcv.src_port);
 	str_pair_print(" in_uri=", msg->first_line.u.request.uri.s,
 								msg->first_line.u.request.uri.len);
 	str_pair_print(" out_uri=", foo->s, foo->len);
 	str_pair_print(" via_cnt", msg->parsed_flag & HDR_EOH ? "=" : ">", 1);
 	str_int_print("=", via_cnt);
 	if (clen<MAX_WARNING_LEN){ buf[clen]='"'; clen++; }
 	else goto error_overflow;
40686bb1
 		
 		
a2339d9a
 	*returned_len=clen;
 	return buf;
40686bb1
 error_overflow:
a2339d9a
 	LOG(L_ERR, "ERROR: warning_builder: buffer size exceeded\n");
 	*returned_len=0;
 	return 0;
5e39b907
 }
3b32ca4b
 
 
 
 
a9a8cb6e
 char* received_builder(struct sip_msg *msg, unsigned int *received_len)
a2688733
 {
 	char *buf;
 	int  len;
 	struct ip_addr *source_ip;
 	char *tmp;
 	int  tmp_len;
 
f2f969dd
 	source_ip=&msg->rcv.src_ip;
a2688733
 
 	buf=pkg_malloc(sizeof(char)*MAX_RECEIVED_SIZE);
 	if (buf==0){
 		ser_error=E_OUT_OF_MEM;
caf80ae6
 		LOG(L_ERR, "ERROR: received_builder: out of memory\n");
a2688733
 		return 0;
 	}
 	memcpy(buf, RECEIVED, RECEIVED_LEN);
57e2cd15
 	if ( (tmp=ip_addr2a(source_ip))==0)
 		return 0; /* error*/
a2688733
 	tmp_len=strlen(tmp);
bd93aa3e
 	len=RECEIVED_LEN+tmp_len;
a2688733
 	
0cbace85
 	memcpy(buf+RECEIVED_LEN, tmp, tmp_len);
6419a43f
 	buf[len]=0; /*null terminate it */
a2688733
 
 	*received_len = len;
 	return buf;
 }
 
 
 
09f7cd2c
 char* rport_builder(struct sip_msg *msg, unsigned int *rport_len)
 {
 	char* buf;
 	char* tmp;
 	int tmp_len;
 	int len;
 	
 	tmp_len=0;
4c4e112f
 	tmp=int2str(msg->rcv.src_port, &tmp_len);
6419a43f
 	len=RPORT_LEN+tmp_len;
 	buf=pkg_malloc(sizeof(char)*(len+1));/* space for null term */
09f7cd2c
 	if (buf==0){
 		ser_error=E_OUT_OF_MEM;
 		LOG(L_ERR, "ERROR: rport_builder: out of memory\n");
 		return 0;
 	}
 	memcpy(buf, RPORT, RPORT_LEN);
 	memcpy(buf+RPORT_LEN, tmp, tmp_len);
6419a43f
 	buf[len]=0; /*null terminate it*/
09f7cd2c
 	
 	*rport_len=len;
 	return buf;
 }
 
 
 
e1e6c914
 char* id_builder(struct sip_msg* msg, unsigned int *id_len)
 {
 	char* buf;
 	int len, value_len;
 	char revhex[sizeof(int)*2];
 	char* p;
 	int size;
 	
 	size=sizeof(int)*2;
 	p=&revhex[0];
 	if (int2reverse_hex(&p, &size, msg->rcv.proto_reserved1)==-1){
 		LOG(L_CRIT, "BUG: id_builder: not enough space for id\n");
 		return 0;
 	}
 	value_len=p-&revhex[0];
6419a43f
 	len=ID_PARAM_LEN+value_len; 
 	buf=pkg_malloc(sizeof(char)*(len+1));/* place for ending \0 */
e1e6c914
 	if (buf==0){
 		ser_error=E_OUT_OF_MEM;
 		LOG(L_ERR, "ERROR: rport_builder: out of memory\n");
 		return 0;
 	}
 	memcpy(buf, ID_PARAM, ID_PARAM_LEN);
 	memcpy(buf+ID_PARAM_LEN, revhex, value_len);
6419a43f
 	buf[len]=0; /* null terminate it */
e1e6c914
 	*id_len=len;
 	return buf;
 }
 
 
 
ab130758
 char* clen_builder(struct sip_msg* msg, unsigned int *clen_len)
 {
 	char* buf;
 	int len;
 	int value;
 	char* value_s;
 	int value_len;
 	char* body;
 	
 	
 	body=get_body(msg);
 	if (body==0){
 		ser_error=E_BAD_REQ;
 		LOG(L_ERR, "ERROR: clen_builder: no message body found"
 					" (missing crlf?)");
 		return 0;
 	}
 	value=msg->len-(int)(body-msg->buf);
 	value_s=int2str(value, &value_len);
 	DBG("clen_builder: content-length: %d (%s)\n", value, value_s);
 		
 	len=CONTENT_LENGTH_LEN+value_len+CRLF_LEN;
 	buf=pkg_malloc(sizeof(char)*(len+1));
 	if (buf==0){
 		ser_error=E_OUT_OF_MEM;
 		LOG(L_ERR, "ERROR: clen_builder: out of memory\n");
 		return 0;
 	}
 	memcpy(buf, CONTENT_LENGTH, CONTENT_LENGTH_LEN);
 	memcpy(buf+CONTENT_LENGTH_LEN, value_s, value_len);
 	memcpy(buf+CONTENT_LENGTH_LEN+value_len, CRLF, CRLF_LEN);
6419a43f
 	buf[len]=0; /* null terminate it */
ab130758
 	*clen_len=len;
 	return buf;
 }
 
 
 
d1e2a411
 /* checks if a lump opt condition 
  * returns 1 if cond is true, 0 if false */
 static inline int lump_check_opt(	enum lump_conditions cond,
 									struct sip_msg* msg,
 									struct socket_info* snd_s
 									)
 {
 	struct ip_addr* ip;
 	unsigned short port;
 	int proto;
 
 #define get_ip_port_proto \
 			if (snd_s==0){ \
 				LOG(L_CRIT, "ERROR: lump_check_opt: null send socket\n"); \
 				return 1; /* we presume they are different :-) */ \
 			} \
 			if (msg->rcv.bind_address){ \
 				ip=&msg->rcv.bind_address->address; \
 				port=msg->rcv.bind_address->port_no; \
 				proto=msg->rcv.bind_address->proto; \
 			}else{ \
 				ip=&msg->rcv.dst_ip; \
 				port=msg->rcv.dst_port; \
 				proto=msg->rcv.proto; \
 			} \
 			
 	switch(cond){
 		case COND_FALSE:
 			return 0;
 		case COND_TRUE:
 			return 1;
 		case COND_IF_DIFF_REALMS:
 			get_ip_port_proto;
 			/* faster tests first */
 			if ((port==snd_s->port_no)&&(proto==snd_s->proto)&&
 				(ip_addr_cmp(ip, &snd_s->address)))
 				return 0;
 			else return 1;
 		case COND_IF_DIFF_AF:
 			get_ip_port_proto;
 			if (ip->af!=snd_s->address.af) return 1;
 			else return 0;
 		case COND_IF_DIFF_PROTO:
 			get_ip_port_proto;
 			if (proto!=snd_s->proto) return 1;
 			else return 0;
 		case COND_IF_DIFF_PORT:
 			get_ip_port_proto;
 			if (port!=snd_s->port_no) return 1;
 			else return 0;
 		case COND_IF_DIFF_IP:
 			get_ip_port_proto;
 			if (ip_addr_cmp(ip, &snd_s->address)) return 0;
 			else return 1;
 		case COND_IF_RAND:
 			return (rand()>=RAND_MAX/2);
 		default:
 			LOG(L_CRIT, "BUG: lump_check_opt: unknown lump condition %d\n",
 					cond);
 	}
 	return 0; /* false */
 }
 
 
 
b0e03da6
 /* computes the "unpacked" len of a lump list,
    code moved from build_req_from_req */
f15bede1
 static inline int lumps_len(struct sip_msg* msg, struct socket_info* send_sock)
3b32ca4b
 {
b0e03da6
 	int s_offset;
 	int new_len;
 	struct lump* t;
 	struct lump* r;
26b939c6
 
f15bede1
 #define SUBST_LUMP_LEN(subst_l) \
 		switch((subst_l)->u.subst){ \
 			case SUBST_RCV_IP: \
 				if (msg->rcv.bind_address){ \
 					new_len+=msg->rcv.bind_address->address_str.len; \
 					if (msg->rcv.bind_address->address.af!=AF_INET) \
 						new_len+=2; \
 				}else{ \
 					/* FIXME */ \
 					LOG(L_CRIT, "FIXME: null bind_address\n"); \
 				}; \
 				break; \
 			case SUBST_RCV_PORT: \
 				if (msg->rcv.bind_address){ \
 					new_len+=msg->rcv.bind_address->port_no_str.len; \
 				}else{ \
 					/* FIXME */ \
 					LOG(L_CRIT, "FIXME: null bind_address\n"); \
 				}; \
 				break; \
 			case SUBST_RCV_PROTO: \
 				if (msg->rcv.bind_address){ \
4b50480e
 					switch(msg->rcv.bind_address->proto){ \
 						case PROTO_NONE: \
 						case PROTO_UDP: \
 						case PROTO_TCP: \
 						case PROTO_TLS: \
 								new_len+=3; \
 								break; \
 						case PROTO_SCTP: \
 								new_len+=4; \
 								break; \
 						default: \
 						LOG(L_CRIT, "BUG: lumps_len: unknown proto %d\n", \
 								msg->rcv.bind_address->proto); \
 					}\
c55adae8
 				}else{ \
 					/* FIXME */ \
 					LOG(L_CRIT, "FIXME: null bind_address\n"); \
 				}; \
 				break; \
 			case SUBST_RCV_ALL: \
 				if (msg->rcv.bind_address){ \
 					new_len+=msg->rcv.bind_address->address_str.len; \
 					if (msg->rcv.bind_address->address.af!=AF_INET) \
 						new_len+=2; \
 					if (msg->rcv.bind_address->port_no!=SIP_PORT){ \
 						/* add :port_no */ \
 						new_len+=1+msg->rcv.bind_address->port_no_str.len; \
 					}\
 						/*add;transport=xxx*/ \
4b50480e
 					switch(msg->rcv.bind_address->proto){ \
 						case PROTO_NONE: \
 						case PROTO_UDP: \
 								break; /* udp is the default */ \
 						case PROTO_TCP: \
 						case PROTO_TLS: \
 								new_len+=TRANSPORT_PARAM_LEN+3; \
 								break; \
 						case PROTO_SCTP: \
 								new_len+=TRANSPORT_PARAM_LEN+4; \
 								break; \
 						default: \
 						LOG(L_CRIT, "BUG: lumps_len: unknown proto %d\n", \
 								msg->rcv.bind_address->proto); \
c55adae8
 					}\
f15bede1
 				}else{ \
 					/* FIXME */ \
 					LOG(L_CRIT, "FIXME: null bind_address\n"); \
 				}; \
 				break; \
 			case SUBST_SND_IP: \
 				if (send_sock){ \
 					new_len+=send_sock->address_str.len; \
 					if (send_sock->address.af!=AF_INET) \
 						new_len+=2; \
 				}else{ \
 					LOG(L_CRIT, "FIXME: lumps_len called with" \
 							" null send_sock\n"); \
 				}; \
 				break; \
 			case SUBST_SND_PORT: \
 				if (send_sock){ \
 					new_len+=send_sock->port_no_str.len; \
 				}else{ \
 					LOG(L_CRIT, "FIXME: lumps_len called with" \
 							" null send_sock\n"); \
 				}; \
 				break; \
 			case SUBST_SND_PROTO: \
 				if (send_sock){ \
4b50480e
 					switch(send_sock->proto){ \
 						case PROTO_NONE: \
 						case PROTO_UDP: \
 						case PROTO_TCP: \
 						case PROTO_TLS: \
 								new_len+=3; \
 								break; \
 						case PROTO_SCTP: \
 								new_len+=4; \
 								break; \
 						default: \
 						LOG(L_CRIT, "BUG: lumps_len: unknown proto %d\n", \
 								send_sock->proto); \
 					}\
f15bede1
 				}else{ \
 					LOG(L_CRIT, "FIXME: lumps_len called with" \
 							" null send_sock\n"); \
 				}; \
 				break; \
c55adae8
 			case SUBST_SND_ALL: \
 				if (send_sock){ \
 					new_len+=send_sock->address_str.len; \
 					if (send_sock->address.af!=AF_INET) \
 						new_len+=2; \
 					if (send_sock->port_no!=SIP_PORT){ \
 						/* add :port_no */ \
 						new_len+=1+send_sock->port_no_str.len; \
 					}\
4b50480e
 					/*add;transport=xxx*/ \
 					switch(send_sock->proto){ \
 						case PROTO_NONE: \
 						case PROTO_UDP: \
 								break; /* udp is the default */ \
 						case PROTO_TCP: \
 						case PROTO_TLS: \
 								new_len+=TRANSPORT_PARAM_LEN+3; \
 								break; \
 						case PROTO_SCTP: \
 								new_len+=TRANSPORT_PARAM_LEN+4; \
 								break; \
 						default: \
 						LOG(L_CRIT, "BUG: lumps_len: unknown proto %d\n", \
 								send_sock->proto); \
c55adae8
 					}\
 				}else{ \
 					/* FIXME */ \
 					LOG(L_CRIT, "FIXME: lumps_len called with" \
 							" null send_sock\n"); \
 				}; \
 				break; \
f15bede1
 			case SUBST_NOP: /* do nothing */ \
 				break; \
 			default: \
 				LOG(L_CRIT, "BUG: unknown subst type %d\n", \
 						(subst_l)->u.subst); \
 		}
 	
26b939c6
 	s_offset=0;
b0e03da6
 	new_len=0;
f15bede1
 	
 	for(t=msg->add_rm;t;t=t->next){
d1e2a411
 		/* skip if this is an OPT lump and the condition is not satisfied */
 		if ((t->op==LUMP_ADD_OPT) && !lump_check_opt(t->u.cond, msg, send_sock))
 			continue;
26b939c6
 		for(r=t->before;r;r=r->before){
 			switch(r->op){
 				case LUMP_ADD:
 					new_len+=r->len;
 					break;
f15bede1
 				case LUMP_ADD_SUBST:
 					SUBST_LUMP_LEN(r);
 					break;
d1e2a411
 				case LUMP_ADD_OPT:
 					/* skip if this is an OPT lump and the condition is 
 					 * not satisfied */
 					if (!lump_check_opt(r->u.cond, msg, send_sock))
 						goto skip_before;
 					break;
26b939c6
 				default:
 					/* only ADD allowed for before/after */
f15bede1
 						LOG(L_CRIT, "BUG: lumps_len: invalid op "
9d045b03
 							"for data lump (%x)\n", r->op);
26b939c6
 			}
 		}
d1e2a411
 skip_before:
26b939c6
 		switch(t->op){
 			case LUMP_ADD:
 				new_len+=t->len;
 				break;
f15bede1
 			case LUMP_ADD_SUBST:
 				SUBST_LUMP_LEN(t);
 				break;
d1e2a411
 			case LUMP_ADD_OPT:
 				/* we don't do anything here, it's only a condition for
 				 * before & after */
 				break;
26b939c6
 			case LUMP_DEL:
 				/* fix overlapping deleted zones */
 				if (t->u.offset < s_offset){
 					/* change len */
 					if (t->len>s_offset-t->u.offset)
 							t->len-=s_offset-t->u.offset;
 					else t->len=0;
 					t->u.offset=s_offset;
 				}
 				s_offset=t->u.offset+t->len;
 				new_len-=t->len;
 				break;
 			case LUMP_NOP:
 				/* fix offset if overlapping on a deleted zone */
 				if (t->u.offset < s_offset){
 					t->u.offset=s_offset;
 				}else
 					s_offset=t->u.offset;
 				/* do nothing */
 				break;
e22bbdb8
 			default:
caf80ae6
 				LOG(L_CRIT,"BUG:lumps_len: invalid"
26b939c6
 							" op for data lump (%x)\n", r->op);
 		}
 		for (r=t->after;r;r=r->after){
 			switch(r->op){
 				case LUMP_ADD:
 					new_len+=r->len;
 					break;
f15bede1
 				case LUMP_ADD_SUBST:
 					SUBST_LUMP_LEN(r);
 					break;
d1e2a411
 				case LUMP_ADD_OPT:
 					/* skip if this is an OPT lump and the condition is 
 					 * not satisfied */
 					if (!lump_check_opt(r->u.cond, msg, send_sock))
 						goto skip_after;
 					break;
26b939c6
 				default:
 					/* only ADD allowed for before/after */
caf80ae6
 					LOG(L_CRIT, "BUG:lumps_len: invalid"
26b939c6
 								" op for data lump (%x)\n", r->op);
 			}
 		}
d1e2a411
 skip_after:
e09e5e44
 		; /* to make gcc 3.* happy */
26b939c6
 	}
b0e03da6
 	return new_len;
 }
26b939c6
 
 
b0e03da6
 
 /* another helper functions, adds/Removes the lump,
 	code moved form build_req_from_req  */
 
f15bede1
 static inline void process_lumps(	struct sip_msg* msg,	
 									char* new_buf, 
 									unsigned int* new_buf_offs, 
 									unsigned int* orig_offs,
 									struct socket_info* send_sock)
b0e03da6
 {
 	struct lump *t;
 	struct lump *r;
f15bede1
 	char* orig;
b0e03da6
 	int size;
 	int offset;
 	int s_offset;
f15bede1
 
 #define SUBST_LUMP(subst_l) \
 	switch((subst_l)->u.subst){ \
 		case SUBST_RCV_IP: \
 			if (msg->rcv.bind_address){  \
5646666d
 				if (msg->rcv.bind_address->address.af!=AF_INET){\
 					new_buf[offset]='['; offset++; \
 				}\
f15bede1
 				memcpy(new_buf+offset, msg->rcv.bind_address->address_str.s, \
 						msg->rcv.bind_address->address_str.len); \
 				offset+=msg->rcv.bind_address->address_str.len; \
5646666d
 				if (msg->rcv.bind_address->address.af!=AF_INET){\
 					new_buf[offset]=']'; offset++; \
 				}\
f15bede1
 			}else{  \
 				/*FIXME*/ \
 				LOG(L_CRIT, "FIXME: process_lumps: null bind_address\n"); \
 			}; \
 			break; \
 		case SUBST_RCV_PORT: \
 			if (msg->rcv.bind_address){  \
 				memcpy(new_buf+offset, msg->rcv.bind_address->port_no_str.s, \
 						msg->rcv.bind_address->port_no_str.len); \
 				offset+=msg->rcv.bind_address->port_no_str.len; \
 			}else{  \
 				/*FIXME*/ \
 				LOG(L_CRIT, "FIXME: process_lumps: null bind_address\n"); \
 			}; \
 			break; \
c55adae8
 		case SUBST_RCV_ALL: \
 			if (msg->rcv.bind_address){  \
 				/* address */ \
 				if (msg->rcv.bind_address->address.af!=AF_INET){\
 					new_buf[offset]='['; offset++; \
 				}\
 				memcpy(new_buf+offset, msg->rcv.bind_address->address_str.s, \
 						msg->rcv.bind_address->address_str.len); \
 				offset+=msg->rcv.bind_address->address_str.len; \
 				if (msg->rcv.bind_address->address.af!=AF_INET){\
 					new_buf[offset]=']'; offset++; \
 				}\
 				/* :port */ \
 				if (msg->rcv.bind_address->port_no!=SIP_PORT){ \
 					new_buf[offset]=':'; offset++; \
 					memcpy(new_buf+offset, \
 							msg->rcv.bind_address->port_no_str.s, \
 							msg->rcv.bind_address->port_no_str.len); \
 					offset+=msg->rcv.bind_address->port_no_str.len; \
 				}\
 				switch(msg->rcv.bind_address->proto){ \
 					case PROTO_NONE: \
 					case PROTO_UDP: \
 						break; /* nothing to do, udp is default*/ \
 					case PROTO_TCP: \
 						memcpy(new_buf+offset, TRANSPORT_PARAM, \
 								TRANSPORT_PARAM_LEN); \
 						offset+=TRANSPORT_PARAM_LEN; \
 						memcpy(new_buf+offset, "tcp", 3); \
 						offset+=3; \
 						break; \
 					case PROTO_TLS: \
 						memcpy(new_buf+offset, TRANSPORT_PARAM, \
 								TRANSPORT_PARAM_LEN); \
 						offset+=TRANSPORT_PARAM_LEN; \
 						memcpy(new_buf+offset, "tls", 3); \
 						offset+=3; \
 						break; \
4b50480e
 					case PROTO_SCTP: \
 						memcpy(new_buf+offset, TRANSPORT_PARAM, \
 								TRANSPORT_PARAM_LEN); \
 						offset+=TRANSPORT_PARAM_LEN; \
 						memcpy(new_buf+offset, "sctp", 4); \
 						offset+=4; \
 						break; \
c55adae8
 					default: \
 						LOG(L_CRIT, "BUG: process_lumps: unknown proto %d\n", \
 								msg->rcv.bind_address->proto); \
 				} \
 			}else{  \
 				/*FIXME*/ \
 				LOG(L_CRIT, "FIXME: process_lumps: null bind_address\n"); \
 			}; \
 			break; \
f15bede1
 		case SUBST_SND_IP: \
 			if (send_sock){  \
5646666d
 				if (send_sock->address.af!=AF_INET){\
 					new_buf[offset]='['; offset++; \
 				}\
f15bede1
 				memcpy(new_buf+offset, send_sock->address_str.s, \
 									send_sock->address_str.len); \
 				offset+=send_sock->address_str.len; \
5646666d
 				if (send_sock->address.af!=AF_INET){\
 					new_buf[offset]=']'; offset++; \
 				}\
f15bede1
 			}else{  \
 				/*FIXME*/ \
 				LOG(L_CRIT, "FIXME: process_lumps: called with" \
 							" null send_sock\n"); \
 			}; \
 			break; \
 		case SUBST_SND_PORT: \
 			if (send_sock){  \
 				memcpy(new_buf+offset, send_sock->port_no_str.s, \
 									send_sock->port_no_str.len); \
 				offset+=send_sock->port_no_str.len; \
 			}else{  \
 				/*FIXME*/ \
 				LOG(L_CRIT, "FIXME: process_lumps: called with" \
 						" null send_sock\n"); \
 			}; \
 			break; \
c55adae8
 		case SUBST_SND_ALL: \
 			if (send_sock){  \
 				/* address */ \
 				if (send_sock->address.af!=AF_INET){\
 					new_buf[offset]='['; offset++; \
 				}\
 				memcpy(new_buf+offset, send_sock->address_str.s, \
 						send_sock->address_str.len); \
 				offset+=send_sock->address_str.len; \
 				if (send_sock->address.af!=AF_INET){\
 					new_buf[offset]=']'; offset++; \
 				}\
 				/* :port */ \
 				if (send_sock->port_no!=SIP_PORT){ \
 					new_buf[offset]=':'; offset++; \
 					memcpy(new_buf+offset, send_sock->port_no_str.s, \
 							send_sock->port_no_str.len); \
 					offset+=send_sock->port_no_str.len; \
 				}\
 				switch(send_sock->proto){ \
 					case PROTO_NONE: \
 					case PROTO_UDP: \
 						break; /* nothing to do, udp is default*/ \
 					case PROTO_TCP: \
 						memcpy(new_buf+offset, TRANSPORT_PARAM, \
 								TRANSPORT_PARAM_LEN); \
 						offset+=TRANSPORT_PARAM_LEN; \
 						memcpy(new_buf+offset, "tcp", 3); \
 						offset+=3; \
 						break; \
 					case PROTO_TLS: \
 						memcpy(new_buf+offset, TRANSPORT_PARAM, \
 								TRANSPORT_PARAM_LEN); \
 						offset+=TRANSPORT_PARAM_LEN; \
 						memcpy(new_buf+offset, "tls", 3); \
 						offset+=3; \
 						break; \
4b50480e
 					case PROTO_SCTP: \
 						memcpy(new_buf+offset, TRANSPORT_PARAM, \
 								TRANSPORT_PARAM_LEN); \
 						offset+=TRANSPORT_PARAM_LEN; \
 						memcpy(new_buf+offset, "sctp", 4); \
 						offset+=4; \
 						break; \
c55adae8
 					default: \
 						LOG(L_CRIT, "BUG: process_lumps: unknown proto %d\n", \
 								send_sock->proto); \
 				} \
 			}else{  \
 				/*FIXME*/ \
 				LOG(L_CRIT, "FIXME: process_lumps: null bind_address\n"); \
 			}; \
 			break; \
f15bede1
 		case SUBST_RCV_PROTO: \
 			if (msg->rcv.bind_address){ \
 				switch(msg->rcv.bind_address->proto){ \
 					case PROTO_NONE: \
 					case PROTO_UDP: \
 						memcpy(new_buf+offset, "udp", 3); \
 						offset+=3; \
 						break; \
 					case PROTO_TCP: \
 						memcpy(new_buf+offset, "tcp", 3); \
 						offset+=3; \
 						break; \
 					case PROTO_TLS: \
 						memcpy(new_buf+offset, "tls", 3); \
 						offset+=3; \
 						break; \
4b50480e
 					case PROTO_SCTP: \
 						memcpy(new_buf+offset, "sctp", 4); \
 						offset+=4; \
 						break; \
f15bede1
 					default: \
 						LOG(L_CRIT, "BUG: process_lumps: unknown proto %d\n", \
 								msg->rcv.bind_address->proto); \
 				} \
 			}else{  \
 				/*FIXME*/ \
c55adae8
 				LOG(L_CRIT, "FIXME: process_lumps: called with null" \
 							" send_sock \n"); \
f15bede1
 			}; \
 			break; \
 		case  SUBST_SND_PROTO: \
 			if (send_sock){ \
 				switch(send_sock->proto){ \
 					case PROTO_NONE: \
 					case PROTO_UDP: \
 						memcpy(new_buf+offset, "udp", 3); \
 						offset+=3; \
 						break; \
 					case PROTO_TCP: \
 						memcpy(new_buf+offset, "tcp", 3); \
 						offset+=3; \
 						break; \
 					case PROTO_TLS: \
 						memcpy(new_buf+offset, "tls", 3); \
 						offset+=3; \
 						break; \
4b50480e
 					case PROTO_SCTP: \
 						memcpy(new_buf+offset, "sctp", 4); \
 						offset+=4; \
 						break; \
f15bede1
 					default: \
 						LOG(L_CRIT, "BUG: process_lumps: unknown proto %d\n", \
 								send_sock->proto); \
 				} \
 			}else{  \
 				/*FIXME*/ \
 				LOG(L_CRIT, "FIXME: process_lumps: called with null" \
 							" send_sock \n"); \
 			}; \
 			break; \
 		default: \
 					LOG(L_CRIT, "BUG: process_lumps: unknown subst type %d\n", \
 							(subst_l)->u.subst); \
 	} \
  \
 	
b0e03da6
 	
f15bede1
 	
 	orig=msg->buf;
b0e03da6
 	offset=*new_buf_offs;
 	s_offset=*orig_offs;
 	
f15bede1
 	for (t=msg->add_rm;t;t=t->next){
26b939c6
 		switch(t->op){
 			case LUMP_ADD:
f15bede1
 			case LUMP_ADD_SUBST:
d1e2a411
 			case LUMP_ADD_OPT:
 				/* skip if this is an OPT lump and the condition is 
 				 * not satisfied */
 				if ((t->op==LUMP_ADD_OPT) &&
 						(!lump_check_opt(t->u.cond, msg, send_sock))) 
 					continue;
26b939c6
 				/* just add it here! */
 				/* process before  */
 				for(r=t->before;r;r=r->before){
 					switch (r->op){
 						case LUMP_ADD:
 							/*just add it here*/
 							memcpy(new_buf+offset, r->u.value, r->len);
 							offset+=r->len;
 							break;
f15bede1
 						case LUMP_ADD_SUBST:
 							SUBST_LUMP(r);
 							break;
d1e2a411
 						case LUMP_ADD_OPT:
 							/* skip if this is an OPT lump and the condition is 
 					 		* not satisfied */
 							if (!lump_check_opt(r->u.cond, msg, send_sock))
 								goto skip_before;
 							break;
26b939c6
 						default:
 							/* only ADD allowed for before/after */
caf80ae6
 							LOG(L_CRIT, "BUG:process_lumps: "
9d045b03
 									"invalid op for data lump (%x)\n", r->op);
26b939c6
 					}
 				}
d1e2a411
 skip_before:
26b939c6
 				/* copy "main" part */
d1e2a411
 				switch(t->op){
 					case LUMP_ADD:
 						memcpy(new_buf+offset, t->u.value, t->len);
 						offset+=t->len;
 						break;
 					case LUMP_ADD_SUBST:
 						SUBST_LUMP(t);
 						break;
 					case LUMP_ADD_OPT:
 						/* do nothing, it's only a condition */
 						break;
 					default: 
 						/* should not ever get here */
 						LOG(L_CRIT, "BUG: process_lumps: unhandled data lump "
 								" op %d\n", t->op);
f15bede1
 				}
26b939c6
 				/* process after */
 				for(r=t->after;r;r=r->after){
 					switch (r->op){
 						case LUMP_ADD:
 							/*just add it here*/
 							memcpy(new_buf+offset, r->u.value, r->len);
 							offset+=r->len;
 							break;
f15bede1
 						case LUMP_ADD_SUBST:
 							SUBST_LUMP(r);
 							break;
d1e2a411
 						case LUMP_ADD_OPT:
 							/* skip if this is an OPT lump and the condition is 
 					 		* not satisfied */
 							if (!lump_check_opt(r->u.cond, msg, send_sock))
 								goto skip_after;
 							break;
26b939c6
 						default:
 							/* only ADD allowed for before/after */
caf80ae6
 							LOG(L_CRIT, "BUG:process_lumps: "
9d045b03
 									"invalid op for data lump (%x)\n", r->op);
26b939c6
 					}
 				}
d1e2a411
 skip_after:
26b939c6
 				break;
 			case LUMP_NOP:
 			case LUMP_DEL:
 				/* copy till offset */
 				if (s_offset>t->u.offset){
 					DBG("Warning: (%d) overlapped lumps offsets,"
 						" ignoring(%x, %x)\n", t->op, s_offset,t->u.offset);
 					/* this should've been fixed above (when computing len) */
 					/* just ignore it*/
 					break;
 				}
 				size=t->u.offset-s_offset;
 				if (size){
 					memcpy(new_buf+offset, orig+s_offset,size);
 					offset+=size;
 					s_offset+=size;
 				}
 				/* process before  */
 				for(r=t->before;r;r=r->before){
 					switch (r->op){
 						case LUMP_ADD:
 							/*just add it here*/
 							memcpy(new_buf+offset, r->u.value, r->len);
 							offset+=r->len;
 							break;
f15bede1
 						case LUMP_ADD_SUBST:
 							SUBST_LUMP(r);
 							break;
d1e2a411
 						case LUMP_ADD_OPT:
 							/* skip if this is an OPT lump and the condition is 
 					 		* not satisfied */
 							if (!lump_check_opt(r->u.cond, msg, send_sock))
 								goto skip_nop_before;
 							break;
26b939c6
 						default:
 							/* only ADD allowed for before/after */
caf80ae6
 							LOG(L_CRIT, "BUG:process_lumps: "
71b771fa
 									"invalid op for data lump (%x)\n",r->op);
26b939c6
 					}
 				}
d1e2a411
 skip_nop_before:
26b939c6
 				/* process main (del only) */
 				if (t->op==LUMP_DEL){
 					/* skip len bytes from orig msg */
 					s_offset+=t->len;
 				}
 				/* process after */
 				for(r=t->after;r;r=r->after){
 					switch (r->op){
 						case LUMP_ADD:
 							/*just add it here*/
 							memcpy(new_buf+offset, r->u.value, r->len);
 							offset+=r->len;
 							break;
f15bede1
 						case LUMP_ADD_SUBST:
 							SUBST_LUMP(r);
 							break;
d1e2a411
 						case LUMP_ADD_OPT:
 							/* skip if this is an OPT lump and the condition is 
 					 		* not satisfied */
 							if (!lump_check_opt(r->u.cond, msg, send_sock)) 
 								goto skip_nop_after;
 							break;
26b939c6
 						default:
 							/* only ADD allowed for before/after */
caf80ae6
 							LOG(L_CRIT, "BUG:process_lumps: "
9d045b03
 									"invalid op for data lump (%x)\n", r->op);
26b939c6
 					}
 				}
d1e2a411
 skip_nop_after:
26b939c6
 				break;
 			default:
caf80ae6
 					LOG(L_CRIT, "BUG: process_lumps: "
9d045b03
 							"unknown op (%x)\n", t->op);
26b939c6
 		}
 	}
b0e03da6
 	*new_buf_offs=offset;
 	*orig_offs=s_offset;
 }
 
 
 
 char * build_req_buf_from_sip_req( struct sip_msg* msg,
 								unsigned int *returned_len,
f2f969dd
 								struct socket_info* send_sock, int proto)
b0e03da6
 {
09f7cd2c
 	unsigned int len, new_len, received_len, rport_len, uri_len, via_len;
b0e03da6
 	char* line_buf;
 	char* received_buf;
09f7cd2c
 	char* rport_buf;
b0e03da6
 	char* new_buf;
 	char* buf;
 	unsigned int offset, s_offset, size;
 	struct lump* anchor;
3e8c3475
 	struct lump* via_insert_param;
e1e6c914
 	str branch;
 	str extra_params;
 	
 #ifdef USE_TCP
 	char* id_buf;
6419a43f
 	unsigned int id_len;
ab130758
 	char* clen_buf;
6419a43f
 	unsigned int clen_len;
e1e6c914
 	
 	
 	id_buf=0;
 	id_len=0;
ab130758
 	clen_buf=0;
 	clen_len=0;
e1e6c914
 #endif
3e8c3475
 	via_insert_param=0;
e1e6c914
 	extra_params.len=0;
 	extra_params.s=0;
b0e03da6
 	uri_len=0;
 	buf=msg->buf;
 	len=msg->len;
 	received_len=0;
09f7cd2c
 	rport_len=0;
b0e03da6
 	new_buf=0;
 	received_buf=0;
09f7cd2c
 	rport_buf=0;
e1e6c914
 	line_buf=0;
b0e03da6
 
e1e6c914
 	
 #ifdef USE_TCP
 	/* add id if tcp */
 	if (msg->rcv.proto==PROTO_TCP){
 		if  ((id_buf=id_builder(msg, &id_len))==0){
 			LOG(L_ERR, "ERROR: build_req_buf_from_sip_req:"
 							" id_builder failed\n");
939aaf3b
 			goto error00; /* we don't need to free anything,
 			                 nothing alloc'ed yet*/
e1e6c914
 		}
 		extra_params.s=id_buf;
 		extra_params.len=id_len;
 	}
ab130758
 	/* if sending proto == tcp, check if Content-Length needs to be added*/
 	if (proto==PROTO_TCP){
 		/* first of all parse content-length */
 		if (parse_headers(msg, HDR_CONTENTLENGTH, 0)==-1){
 			LOG(L_ERR, "build_req_buf_from_sip_req:"
 							" error parsing content-length\n");
 			goto skip_clen;
 		}
 		if (msg->content_length==0){
 			/* we need to add it */
 			if ((clen_buf=clen_builder(msg, &clen_len))==0){
 				LOG(L_ERR, "build_req_buf_from_sip_req:" 
 								" clen_builder failed\n");
 				goto skip_clen;
 			}
 		}
 	}
 skip_clen:
e1e6c914
 #endif
 	branch.s=msg->add_to_branch_s;
 	branch.len=msg->add_to_branch_len;
 	line_buf = via_builder( &via_len, send_sock, &branch,
 							extra_params.len?&extra_params:0, proto);
b0e03da6
 	if (!line_buf){
 		LOG(L_ERR,"ERROR: build_req_buf_from_sip_req: no via received!\n");
caf80ae6
 		goto error00;
b0e03da6
 	}
 	/* check if received needs to be added */
3e8c3475
 	if ( msg->via1->received || 
 			check_via_address(&msg->rcv.src_ip, &msg->via1->host, 
 									msg->via1->port, received_dns) ){
1cec1f4e
 		if ((received_buf=received_builder(msg,&received_len))==0){
 			LOG(L_ERR, "ERROR: build_req_buf_from_sip_req:"
 							" received_builder failed\n");
caf80ae6
 			goto error01;  /* free also line_buf */
1cec1f4e
 		}
b0e03da6
 	}
09f7cd2c
 	
3e8c3475
 	/* check if rport needs to be updated:
 	 *  - if FL_FORCE_RPORT is set add it (and del. any previous version)
 	 *  - if via already contains an rport add it and overwrite the previous
 	 *  rport value if present (if you don't want to overwrite the previous
 	 *  version remove the comments) */
 	if ((msg->msg_flags&FL_FORCE_RPORT)||
 			(msg->via1->rport /*&& msg->via1->rport->value.s==0*/)){
1cec1f4e
 		if ((rport_buf=rport_builder(msg, &rport_len))==0){
 			LOG(L_ERR, "ERROR: build_req_buf_from_sip_req:"
 							" rport_builder failed\n");
09f7cd2c
 			goto error01; /* free everything */
1cec1f4e
 		}
09f7cd2c
 	}
b0e03da6
 
 	/* add via header to the list */
 	/* try to add it before msg. 1st via */
 	/* add first via, as an anchor for second via*/
 	anchor=anchor_lump(&(msg->add_rm), msg->via1->hdr.s-buf, 0, HDR_VIA);
caf80ae6
 	if (anchor==0) goto error01;
b0e03da6
 	if (insert_new_lump_before(anchor, line_buf, via_len, HDR_VIA)==0)
caf80ae6
 		goto error01;
3e8c3475
 	/* find out where the offset of the first parameter that should be added
 	 * (after host:port), needed by add receive & maybe rport */
 	if (msg->via1->params.s){
 			size= msg->via1->params.s-msg->via1->hdr.s-1; /*compensate
 														  for ';' */
 	}else{
 			size= msg->via1->host.s-msg->via1->hdr.s+msg->via1->host.len;
 			if (msg->via1->port!=0){
 				/*size+=strlen(msg->via1->hdr.s+size+1)+1;*/
 				size += msg->via1->port_str.len + 1; /* +1 for ':'*/
 			}
785c78c3
 #if 0
 			/* no longer necessary, now hots.s contains [] */
3e8c3475
 		#ifdef USE_IPV6
 			if(send_sock->address.af==AF_INET6) size+=1; /* +1 for ']'*/
 		#endif
785c78c3
 #endif
3e8c3475
 	}
 	/* if received needs to be added, add anchor after host and add it, or 
 	 * overwrite the previous one if already present */
b0e03da6
 	if (received_len){
3e8c3475
 		if (msg->via1->received){ /* received already present => overwrite it*/
 			via_insert_param=del_lump(&(msg->add_rm),
 								msg->via1->received->start-buf-1, /*;*/
 								msg->via1->received->size+1, /*;*/ HDR_VIA);
 		}else if (via_insert_param==0){ /* receive not present, ok */
 			via_insert_param=anchor_lump(&(msg->add_rm),
 										msg->via1->hdr.s-buf+size,0, HDR_VIA);
b0e03da6
 		}
3e8c3475
 		if (via_insert_param==0) goto error02; /* free received_buf */
 		if (insert_new_lump_after(via_insert_param, received_buf, received_len,
 					HDR_VIA) ==0 ) goto error02; /* free received_buf */
09f7cd2c
 	}
3e8c3475
 	/* if rport needs to be updated, delete it if present and add it's value */
09f7cd2c
 	if (rport_len){
3e8c3475
 		if (msg->via1->rport){ /* rport already present */
 			via_insert_param=del_lump(&(msg->add_rm),
 								msg->via1->rport->start-buf-1, /*';'*/
 								msg->via1->rport->size+1 /* ; */, HDR_VIA);
 		}else if (via_insert_param==0){ /*force rport, no rport present */
 			/* no rport, add it */
 			via_insert_param=anchor_lump(&(msg->add_rm),
 										msg->via1->hdr.s-buf+size,0, HDR_VIA);
 		}
 		if (via_insert_param==0) goto error03; /* free rport_buf */
 		if (insert_new_lump_after(via_insert_param, rport_buf, rport_len,
 									HDR_VIA) ==0 )
 			goto error03; /* free rport_buf */
 			
b0e03da6
 	}
ab130758
 #ifdef USE_TCP
 	/* if clen needs to be added, add it */
 	if (clen_len){
 		/* msg->unparsed should point just before the final crlf,
 		 * parse_headers is called from clen_builder */
 		anchor=anchor_lump(&(msg->add_rm), msg->unparsed-buf, 0,
 							 HDR_CONTENTLENGTH);
939aaf3b
 		if (anchor==0) goto error04; /* free clen_buf */
ab130758
 		if (insert_new_lump_after(anchor, clen_buf, clen_len,
 					HDR_CONTENTLENGTH)==0)
 			goto error04; /* free clen_buf*/
 	}
 #endif
b0e03da6
 
 	/* compute new msg len and fix overlapping zones*/
f15bede1
 	new_len=len+lumps_len(msg, send_sock);
548d11fb
 #ifdef XL_DEBUG
 	LOG(L_ERR, "DEBUG: new_len(%d)=len(%d)+lumps_len\n", new_len, len);
 #endif
b0e03da6
 
 	if (msg->new_uri.s){
 		uri_len=msg->new_uri.len;
 		new_len=new_len-msg->first_line.u.request.uri.len+uri_len;
 	}
caf80ae6
 	new_buf=(char*)pkg_malloc(new_len+1);
b0e03da6
 	if (new_buf==0){
 		ser_error=E_OUT_OF_MEM;
 		LOG(L_ERR, "ERROR: build_req_buf_from_sip_req: out of memory\n");
caf80ae6
 		goto error00;
b0e03da6
 	}
 
 	offset=s_offset=0;
 	if (msg->new_uri.s){
 		/* copy message up to uri */
 		size=msg->first_line.u.request.uri.s-buf;
049f64c2
 		memcpy(new_buf, buf, size);
b0e03da6
 		offset+=size;
 		s_offset+=size;
 		/* add our uri */
 		memcpy(new_buf+offset, msg->new_uri.s, uri_len);
 		offset+=uri_len;
 		s_offset+=msg->first_line.u.request.uri.len; /* skip original uri */
 	}
 	new_buf[new_len]=0;
049f64c2
 	/* copy msg adding/removing lumps */
f15bede1
 	process_lumps(msg, new_buf, &offset, &s_offset, send_sock);
049f64c2
 	/* copy the rest of the message */
 	memcpy(new_buf+offset, buf+s_offset, len-s_offset);
26b939c6
 	new_buf[new_len]=0;
 
6cd1dc34
 #ifdef DBG_MSG_QA
 	if (new_buf[new_len-1]==0) {
 		LOG(L_ERR, "ERROR: build_req_buf_from_sip_req: 0 in the end\n");
 		abort();
 	}
 #endif
 
26b939c6
 	*returned_len=new_len;
939aaf3b
 	/* cleanup */
 #ifdef USE_TCP
 	if (id_buf) pkg_free(id_buf); /* it's not in a lump => we don't need it
 									 anymore */
 #endif
26b939c6
 	return new_buf;
 
caf80ae6
 error01:
939aaf3b
 	if (line_buf) pkg_free(line_buf);
caf80ae6
 error02:
4938d15f
 	if (received_buf) pkg_free(received_buf);
09f7cd2c
 error03:
 	if (rport_buf) pkg_free(rport_buf);
ab130758
 #ifdef USE_TCP
 error04:
 	if (clen_buf) pkg_free(clen_buf);
 #endif
caf80ae6
 error00:
939aaf3b
 #ifdef USE_TCP
 	if (id_buf) pkg_free(id_buf);
 #endif
26b939c6
 	*returned_len=0;
 	return 0;
 }
 
 
ab130758
 
170e2306
 char * build_res_buf_from_sip_res( struct sip_msg* msg,
 				unsigned int *returned_len)
8cc98445
 {
e22bbdb8
 	unsigned int new_len, via_len;
8cc98445
 	char* new_buf;
b0e03da6
 	unsigned offset, s_offset, via_offset;
8cc98445
 	char* buf;
 	unsigned int len;
ab130758
 #ifdef USE_TCP
 	struct lump* anchor;
 	char* clen_buf;
6419a43f
 	unsigned int clen_len;
ab130758
 	
 	clen_buf=0;
 	clen_len=0;
 #endif
8cc98445
 	buf=msg->buf;
 	len=msg->len;
 	new_buf=0;
 	/* we must remove the first via */
1540fad1
 	if (msg->via1->next) {
 		via_len=msg->via1->bsize;
 		via_offset=msg->h_via1->body.s-buf;
 	} else {
 		via_len=msg->h_via1->len;
 		via_offset=msg->h_via1->name.s-buf;
 	}
ab130758
 
 #ifdef USE_TCP
 
 	/* if sending proto == tcp, check if Content-Length needs to be added*/
 	if (msg->via2 && (msg->via2->proto==PROTO_TCP)){
 		DBG("build_res_from_sip_res: checking content-length for \n%.*s\n",
 				(int)msg->len, msg->buf);
 		/* first of all parse content-length */
 		if (parse_headers(msg, HDR_CONTENTLENGTH, 0)==-1){
 			LOG(L_ERR, "build_res_buf_from_sip_res:"
 							" error parsing content-length\n");
 			goto skip_clen;
 		}
 		if (msg->content_length==0){
 			DBG("build_res_from_sip_res: no content_length hdr found\n");
 			/* we need to add it */
 			if ((clen_buf=clen_builder(msg, &clen_len))==0){
 				LOG(L_ERR, "build_res_buf_from_sip_res:" 
 								" clen_builder failed\n");
 				goto skip_clen;
 			}
 		}
 	}
 skip_clen:
 #endif
 	
b0e03da6
 	/* remove the first via*/
f15bede1
 	if (del_lump( &(msg->add_rm), via_offset, via_len, HDR_VIA)==0){
b0e03da6
 		LOG(L_ERR, "build_res_buf_from_sip_res: error trying to remove first"
 					"via\n");
 		goto error;
 	}
ab130758
 #ifdef USE_TCP
 	/* if clen needs to be added, add it */
 	if (clen_len){
 		/* msg->unparsed should point just before the final crlf,
 		 * parse_headers is called from clen_builder */
f15bede1
 		anchor=anchor_lump(&(msg->add_rm), msg->unparsed-buf, 0, 
ab130758
 							HDR_CONTENTLENGTH);
 		DBG("build_res_from_sip_res: adding content-length: %.*s\n",
61967897
 				(int)clen_len, clen_buf);
ab130758
 		if (anchor==0) goto error_clen; /* free clen_buf*/
 		if (insert_new_lump_after(anchor, clen_buf, clen_len,
 					HDR_CONTENTLENGTH)==0)
 			goto error_clen; /* free clen_buf*/
 	}
 #endif
f15bede1
 	new_len=len+lumps_len(msg, 0); /*FIXME: we don't know the send sock */
 	
8cc98445
 	DBG(" old size: %d, new size: %d\n", len, new_len);
e3fc93f4
 	new_buf=(char*)pkg_malloc(new_len+1); /* +1 is for debugging 
 											 (\0 to print it )*/
8cc98445
 	if (new_buf==0){
caf80ae6
 		LOG(L_ERR, "ERROR: build_res_buf_from_sip_res: out of mem\n");
8cc98445
 		goto error;
 	}
 	new_buf[new_len]=0; /* debug: print the message */
b0e03da6
 	offset=s_offset=0;
f15bede1
 	process_lumps(msg, new_buf, &offset, &s_offset, 0); /*FIXME: no send sock*/
b0e03da6
 	/* copy the rest of the message */
049f64c2
 	memcpy(new_buf+offset,
 		buf+s_offset, 
 		len-s_offset);
8cc98445
 	 /* send it! */
ab130758
 	DBG("build_res_from_sip_res: copied size: orig:%d, new: %d, rest: %d"
 			" msg=\n%s\n", s_offset, offset, len-s_offset, new_buf);
8cc98445
 
 	*returned_len=new_len;
 	return new_buf;
ab130758
 #ifdef USE_TCP
 error_clen:
 	if (clen_buf) pkg_free(clen_buf);
 #endif
8cc98445
 error:
 	*returned_len=0;
 	return 0;
 }
 
 
26b939c6
 
5843cd1b
 
 
5e39b907
 char * build_res_buf_from_sip_req( unsigned int code, char *text,
 					char *new_tag, unsigned int new_tag_len,
fde02f64
 					struct sip_msg* msg, unsigned int *returned_len,
 					struct bookmark *bmark)
96dd9e9f
 {
     return build_res_buf_with_body_from_sip_req(code,text,new_tag,new_tag_len,
 						0,0, /* no body */
 						0,0, /* no content type */
fde02f64
 						msg,returned_len, bmark);
96dd9e9f
 }
 
 char * build_res_buf_with_body_from_sip_req( unsigned int code, char *text ,
 					     char *new_tag, unsigned int new_tag_len ,
 					     char *body, unsigned int body_len,
 					     char *content_type, unsigned int content_type_len,
fde02f64
 					     struct sip_msg* msg, unsigned int *returned_len,
 						 struct bookmark *bmark)
5843cd1b
 {
5e39b907
 	char              *buf, *p;
 	unsigned int      len,foo;
b644f031
 	struct hdr_field  *hdr;
5e39b907
 	struct lump_rpl   *lump;
 	int               i;
a2688733
 	char              backup;
 	char              *received_buf;
1cec1f4e
 	char              *rport_buf;
f178e851
 	unsigned int      received_len;
 	unsigned int      rport_len;
 	unsigned int      delete_len;
5e39b907
 	char              *warning;
 	unsigned int      warning_len;
049f64c2
 	unsigned int	  text_len;
74ed389d
 	int  content_len_len;
a5b16152
 	char *content_len;
74ed389d
 	char content_len_buf[MAX_CONTENT_LEN_BUF];
1540fad1
 	char *after_body;
74ed389d
 	str  to_tag;
fde02f64
 	char *totags;
f360250e
 	int rcvd;
68a3fc65
 
a2688733
 	received_buf=0;
 	received_len=0;
1cec1f4e
 	rport_buf=0;
 	rport_len=0;
f178e851
 	delete_len=0;
a2688733
 	buf=0;
caf80ae6
 	/* make -Wall happy */
 	warning=0;
a5b16152
 	content_len=0;
a2688733
 
049f64c2
 	text_len=strlen(text);
 
8df23b70
 	/* force parsing all headers -- we want to return all
 	Via's in the reply and they may be scattered down to the
 	end of header (non-block Vias are a really poor property
 	of SIP :( ) */
caf80ae6
 	if (parse_headers( msg, HDR_EOH, 0 )==-1) {
 		LOG(L_ERR, "ERROR: build_res_buf_from_sip_req: "
 			"alas, parse_headers failed\n");
 		goto error00;
 	}
b644f031
 
a2688733
 	/* check if received needs to be added */
 	backup = msg->via1->host.s[msg->via1->host.len];
 	msg->via1->host.s[msg->via1->host.len] = 0;
f360250e
 	rcvd=msg->via1->received 
 			|| check_via_address(&msg->rcv.src_ip, &msg->via1->host, 
 						msg->via1->port, received_dns);
a2688733
 	msg->via1->host.s[msg->via1->host.len] = backup;
f360250e
 	if (rcvd) {
caf80ae6
 		if ((received_buf=received_builder(msg,&received_len))==0) {
 			LOG(L_ERR, "ERROR: build_res_buf_from_sip_req: "
 				"alas, received_builder failed\n");
 			goto error00;
 		}
 	}
1cec1f4e
 	/* check if rport needs to be updated */
3e8c3475
 	if ( (msg->msg_flags&FL_FORCE_RPORT)||
 		(msg->via1->rport /*&& msg->via1->rport->value.s==0*/)){
1cec1f4e
 		if ((rport_buf=rport_builder(msg, &rport_len))==0){
 			LOG(L_ERR, "ERROR: build_res_buf_from_sip_req:"
 							" rport_builder failed\n");
 			goto error01; /* free everything */
 		}
3e8c3475
 		if (msg->via1->rport) 
 			delete_len=msg->via1->rport->size+1; /* include ';' */
1cec1f4e
 	}
a2688733
 
b644f031
 	/*computes the lenght of the new response buffer*/
 	len = 0;
 	/* first line */
5e39b907
 	len += SIP_VERSION_LEN + 1/*space*/ + 3/*code*/ + 1/*space*/ +
049f64c2
 		text_len + CRLF_LEN/*new line*/;
8df23b70
 	/*headers that will be copied (TO, FROM, CSEQ,CALLID,VIA)*/
814bd485
 	for ( hdr=msg->headers ; hdr ; hdr=hdr->next ) {
 		if (hdr->type==HDR_TO) {
 			if (new_tag)
 			{
 				to_tag=get_to(msg)->tag_value;
 				if (to_tag.s )
 					len+=new_tag_len-to_tag.len;
 				else
2c60a4c3
 					len+=new_tag_len+TOTAG_TOKEN_LEN/*";tag="*/;
814bd485
 			}
1540fad1
 			else {
 				len+=hdr->len;
 				continue;
 			}
814bd485
 		} else if (hdr->type==HDR_VIA) {
6419a43f
 				/* we always add CRLF to via*/
 				len+=(hdr->body.s+hdr->body.len)-hdr->name.s+CRLF_LEN;
f178e851
 				if (hdr==msg->h_via1) len += received_len+rport_len;
6419a43f
 				continue;
814bd485
 		} else if (hdr->type==HDR_RECORDROUTE) {
 				/* RR only for 1xx and 2xx replies */
 				if (code<180 || code>=300) continue;
 		} else if (!(hdr->type==HDR_FROM 
 					|| hdr->type==HDR_CALLID
 					|| hdr->type==HDR_CSEQ)) {
 			continue;
340bddb4
 		}
6419a43f
 		len += hdr->len; /* we keep the original termination for these 
 							headers*/
814bd485
 	}
f178e851
 	len-=delete_len;
0498ceb9
 	/*lumps length*/
 	for(lump=msg->reply_lump;lump;lump=lump->next)
 		len += lump->text.len;
caf80ae6
 	if (server_signature) {
 		/*server header*/
 		len += SERVER_HDR_LEN + CRLF_LEN;
a5b16152
 	}
 
 	if (body_len) {
 		content_len=int2str(body_len, &content_len_len);
74ed389d
 		memcpy(content_len_buf,content_len,content_len_len+1);
 		content_len = content_len_buf;
a5b16152
 		len += CONTENT_LENGTH_LEN + content_len_len + CRLF_LEN;
74ed389d
 		len += body_len;
a5b16152
 	} else {
82802743
 		len +=CONTENT_LENGTH_LEN+1 + CRLF_LEN;
caf80ae6
 	}
a5b16152
 	if(content_type_len) {
96dd9e9f
 	    len += content_type_len + CRLF_LEN;
a5b16152
 	}
 
caf80ae6
 	if (sip_warning) {
 		warning = warning_builder(msg,&warning_len);
0bf716b8
 		if (warning) len += warning_len + CRLF_LEN;
 		else LOG(L_WARN, "WARNING: warning skipped -- too big\n");
caf80ae6
 	}
b644f031
 	/* end of message */
68a3fc65
 	len += CRLF_LEN; /*new line*/
96dd9e9f
 
b644f031
 	/*allocating mem*/
caf80ae6
 	buf = (char*) pkg_malloc( len+1 );
b644f031
 	if (!buf)
 	{
0498ceb9
 		LOG(L_ERR, "ERROR: build_res_buf_from_sip_req: out of memory "
 			" ; needs %d\n",len);
caf80ae6
 		goto error01;
b644f031
 	}
 
 	/* filling the buffer*/
8df23b70
 	p=buf;
b644f031
 	/* first line */
8b863d8c
 	memcpy( p , SIP_VERSION , SIP_VERSION_LEN );
 	p += SIP_VERSION_LEN;
 	*(p++) = ' ' ;
 	/*code*/
b644f031
 	for ( i=2 , foo = code  ;  i>=0  ;  i-- , foo=foo/10 )
8df23b70
 		*(p+i) = '0' + foo - ( foo/10 )*10;
b644f031
 	p += 3;
 	*(p++) = ' ' ;
049f64c2
 	memcpy( p , text , text_len );
 	p += text_len;
68a3fc65
 	memcpy( p, CRLF, CRLF_LEN );
 	p+=CRLF_LEN;
b644f031
 	/* headers*/
 	for ( hdr=msg->headers ; hdr ; hdr=hdr->next )
340bddb4
 		switch (hdr->type)
b644f031
 		{
340bddb4
 			case HDR_VIA:
1cec1f4e
 				if (hdr==msg->h_via1){
 					if (rport_buf){
3e8c3475
 						if (msg->via1->rport){ /* delete the old one */
 							/* copy until rport */
 							append_str_trans( p, hdr->name.s ,
 								msg->via1->rport->start-hdr->name.s-1,msg);
 							/* copy new rport */
 							append_str(p, rport_buf, rport_len);
 							/* copy the rest of the via */
 							append_str_trans(p, msg->via1->rport->start+
 												msg->via1->rport->size, 
 												hdr->body.s+hdr->body.len-
 												msg->via1->rport->start-
 												msg->via1->rport->size, msg);
 						}else{ /* just append the new one */
 							/* normal whole via copy */
 							append_str_trans( p, hdr->name.s , 
 								(hdr->body.s+hdr->body.len)-hdr->name.s, msg);
 							append_str(p, rport_buf, rport_len);
 						}
1cec1f4e
 					}else{
 						/* normal whole via copy */
6419a43f
 						append_str_trans( p, hdr->name.s , 
 								(hdr->body.s+hdr->body.len)-hdr->name.s, msg);
1cec1f4e
 					}
 					if (received_buf)
1540fad1
 						append_str( p, received_buf, received_len);
1cec1f4e
 				}else{
 					/* normal whole via copy */
6419a43f
 					append_str_trans( p, hdr->name.s,
 							(hdr->body.s+hdr->body.len)-hdr->name.s, msg);
1cec1f4e
 				}
1540fad1
 				append_str( p, CRLF,CRLF_LEN);
a2688733
 				break;
814bd485
 			case HDR_RECORDROUTE:
 				/* RR only for 1xx and 2xx replies */
 				if (code<180 || code>=300) break;
6419a43f
 				append_str(p, hdr->name.s, hdr->len);
 				break;
1540fad1
 			case HDR_TO:
 				if (new_tag){
 					if (to_tag.s ) { /* replacement */
 						/* before to-tag */
 						append_str( p, hdr->name.s, to_tag.s-hdr->name.s);
 						/* to tag replacement */
fde02f64
 						bmark->to_tag_val.s=p;
 						bmark->to_tag_val.len=new_tag_len;
1540fad1
 						append_str( p, new_tag,new_tag_len);
 						/* the rest after to-tag */
 						append_str( p, to_tag.s+to_tag.len,
 							hdr->name.s+hdr->len-(to_tag.s+to_tag.len));
 					}else{ /* adding a new to-tag */
 						after_body=hdr->body.s+hdr->body.len;
 						append_str( p, hdr->name.s, after_body-hdr->name.s);
 						append_str(p, TOTAG_TOKEN, TOTAG_TOKEN_LEN);
fde02f64
 						bmark->to_tag_val.s=p;
 						bmark->to_tag_val.len=new_tag_len;
1540fad1
 						append_str( p, new_tag,new_tag_len);
 						append_str( p, after_body, 
 										hdr->name.s+hdr->len-after_body);
 					}
 					break;
 				} /* no new to-tag -- proceed to 1:1 copying  */
fde02f64
 				totags=((struct to_body*)(hdr->parsed))->tag_value.s;
 				if (totags) {
 					bmark->to_tag_val.s=p+(totags-hdr->name.s);
 					bmark->to_tag_val.len=
 							((struct to_body*)(hdr->parsed))->tag_value.len;
 				};
340bddb4
 			case HDR_FROM:
 			case HDR_CALLID:
 			case HDR_CSEQ:
1540fad1
 					append_str(p, hdr->name.s, hdr->len);
814bd485
 		} /* for switch */
0498ceb9
 	/*lumps*/
 	for(lump=msg->reply_lump;lump;lump=lump->next)
 	{
 		memcpy(p,lump->text.s,lump->text.len);
 		p += lump->text.len;
 	}
caf80ae6
 	if (server_signature) {
 		/*server header*/
 		memcpy( p, SERVER_HDR , SERVER_HDR_LEN );
 		p+=SERVER_HDR_LEN;
 		memcpy( p, CRLF, CRLF_LEN );
 		p+=CRLF_LEN;
a5b16152
 	}
 	
 	if (body_len) {
 		memcpy(p, CONTENT_LENGTH, CONTENT_LENGTH_LEN );
 		p+=CONTENT_LENGTH_LEN;
 		memcpy( p, content_len, content_len_len );
 		p+=content_len_len;
caf80ae6
 		memcpy( p, CRLF, CRLF_LEN );
 		p+=CRLF_LEN;
a5b16152
 	} else {
 		/* content length header*/
 		memcpy( p, CONTENT_LENGTH "0" CRLF, CONTENT_LENGTH_LEN+1+CRLF_LEN );
 		p+=CONTENT_LENGTH_LEN+1+CRLF_LEN;
96dd9e9f
 	}
 	if(content_type_len){
 	    memcpy( p, content_type, content_type_len );
 	    p+=content_type_len;
 	    memcpy( p, CRLF, CRLF_LEN );
 	    p+=CRLF_LEN;
caf80ae6
 	}
0bf716b8
 	if (sip_warning && warning) {
caf80ae6
 		memcpy( p, warning, warning_len);
 		p+=warning_len;
 		memcpy( p, CRLF, CRLF_LEN);
 		p+=CRLF_LEN;
 	}
af64f4fb
 	/*end of message*/
68a3fc65
 	memcpy( p, CRLF, CRLF_LEN );
8b299ebc
 	p+=CRLF_LEN;
96dd9e9f
 	if(body_len){
 	    memcpy ( p, body, body_len );
 	    p+=body_len;
 	}
0938e8b5
 	*(p) = 0;
d9c55ba4
 	*returned_len = len;
caf80ae6
 	/* in req2reply, received_buf is not introduced to lumps and
 	   needs to be deleted here
 	*/
 	if (received_buf) pkg_free(received_buf);
1cec1f4e
 	if (rport_buf) pkg_free(rport_buf);
b644f031
 	return buf;
caf80ae6
 
 error01:
 	if (received_buf) pkg_free(received_buf);
1cec1f4e
 	if (rport_buf) pkg_free(rport_buf);
caf80ae6
 error00:
b644f031
 	*returned_len=0;
 	return 0;
5843cd1b
 }
caf80ae6
 
 /* return number of chars printed or 0 if space exceeded;
    assumes buffer sace of at least MAX_BRANCH_PARAM_LEN
  */
 
 int branch_builder( unsigned int hash_index,
 	/* only either parameter useful */
 	unsigned int label, char * char_v,
 	int branch,
 	char *branch_str, int *len )
 {
 
 	char *begin;
 	int size;
 
 	/* hash id provided ... start with it */
 	size=MAX_BRANCH_PARAM_LEN;
 	begin=branch_str;
 	*len=0;
7958eeae
 
 	memcpy(begin, MCOOKIE, MCOOKIE_LEN );
 	size-=MCOOKIE_LEN;begin+=MCOOKIE_LEN;
 
caf80ae6
 	if (int2reverse_hex( &begin, &size, hash_index)==-1)
 		return 0;
 
 	if (size) {
 		*begin=BRANCH_SEPARATOR;
 		begin++; size--;
 	} else return 0;
 
e5a9bc72
 	/* string with request's characteristic value ... use it ... */
 	if (char_v) {
caf80ae6
 		if (memcpy(begin,char_v,MD5_LEN)) {
 			begin+=MD5_LEN; size-=MD5_LEN;
 		} else return 0;
e5a9bc72
 	} else { /* ... use the "label" value otherwise */
 		if (int2reverse_hex( &begin, &size, label )==-1)
 			return 0;
caf80ae6
 	}
 
 	if (size) {
 		*begin=BRANCH_SEPARATOR;
 		begin++; size--;
 	} else return 0;
 
 	if (int2reverse_hex( &begin, &size, branch)==-1)
 		return 0;
 
 	*len=MAX_BRANCH_PARAM_LEN-size;
 	return size;
 		
 }
 
 
 char* via_builder( unsigned int *len, 
 	struct socket_info* send_sock,
e1e6c914
 	str* branch, str* extra_params, int proto )
caf80ae6
 {
 	unsigned int  via_len, extra_len;
 	char               *line_buf;
 	int max_len;
 
 
 	max_len=MY_VIA_LEN+send_sock->address_str.len /* space in MY_VIA */
e1e6c914
 		+2 /* just in case it is a v6 address ... [ ] */
19710544
 		+1 /*':'*/+send_sock->port_no_str.len
c94efc41
 		+(branch?(MY_BRANCH_LEN+branch->len):0)
 		+(extra_params?extra_params->len:0)
e1e6c914
 		+CRLF_LEN+1;
caf80ae6
 	line_buf=pkg_malloc( max_len );
 	if (line_buf==0){
 		ser_error=E_OUT_OF_MEM;
 		LOG(L_ERR, "ERROR: via_builder: out of memory\n");
 		return 0;
 	}
 
 	extra_len=0;
 
 	via_len=MY_VIA_LEN+send_sock->address_str.len; /*space included in MY_VIA*/
 
c55adae8
 	memcpy(line_buf, MY_VIA, MY_VIA_LEN); 
 	if (proto==PROTO_UDP){
 		/* dop nothing */
 	}else if (proto==PROTO_TCP){
f2f969dd
 		memcpy(line_buf+MY_VIA_LEN-4, "TCP ", 4);
c55adae8
 	}else{
f2f969dd
 		LOG(L_CRIT, "BUG: via_builder: unknown proto %d\n", proto);
 		return 0;
 	}
caf80ae6
 #	ifdef USE_IPV6
 	if (send_sock->address.af==AF_INET6) {
 		line_buf[MY_VIA_LEN]='[';
 		line_buf[MY_VIA_LEN+1+send_sock->address_str.len]=']';
 		extra_len=1;
 		via_len+=2; /* [ ]*/
 	}
 #	endif
 	memcpy(line_buf+MY_VIA_LEN+extra_len, send_sock->address_str.s,
 		send_sock->address_str.len);
 	if (send_sock->port_no!=SIP_PORT){
19710544
 		line_buf[via_len]=':'; via_len++;
caf80ae6
 		memcpy(line_buf+via_len, send_sock->port_no_str.s,
 			 send_sock->port_no_str.len);
 		via_len+=send_sock->port_no_str.len;
 	}
 
 	/* branch parameter */
e1e6c914
 	if (branch){
 		memcpy(line_buf+via_len, MY_BRANCH, MY_BRANCH_LEN );
 		via_len+=MY_BRANCH_LEN;
 		memcpy(line_buf+via_len, branch->s, branch->len );
 		via_len+=branch->len;
 	}
 	/* extra params  */
 	if (extra_params){
 		memcpy(line_buf+via_len, extra_params->s, extra_params->len);
 		via_len+=extra_params->len;
 	}
 	
caf80ae6
 	memcpy(line_buf+via_len, CRLF, CRLF_LEN);
 	via_len+=CRLF_LEN;
 	line_buf[via_len]=0; /* null terminate the string*/
 
 	*len = via_len;
 	return line_buf;
 }