예제 #1
0
파일: t_lookup.c 프로젝트: Danfx/opensips
/* function lookups transaction being canceled by CANCEL in p_msg;
 * it returns:
 *       0 - transaction wasn't found
 *       T - transaction found
 */
struct cell* t_lookupOriginalT(  struct sip_msg* p_msg )
{
	struct cell     *p_cell;
	unsigned int     hash_index;
	struct sip_msg  *t_msg;
	struct via_param *branch;
	int ret;

	/* already looked for it? */
	if (cancelled_T!=T_UNDEFINED)
		return cancelled_T;

	/* start searching in the table */
	hash_index = p_msg->hash_index;
	LM_DBG("searching on hash entry %d\n",hash_index );


	/* first of all, look if there is RFC3261 magic cookie in branch; if
	 * so, we can do very quick matching and skip the old-RFC bizzar
	 * comparison of many header fields
	 */
	if (!p_msg->via1) {
		LM_ERR("no via\n");
		cancelled_T = NULL;
		return 0;
	}
	branch=p_msg->via1->branch;
	if (branch && branch->value.s && branch->value.len>MCOOKIE_LEN
			&& memcmp(branch->value.s,MCOOKIE,MCOOKIE_LEN)==0) {
		/* huhuhu! the cookie is there -- let's proceed fast */
		LOCK_HASH(hash_index);
		ret=matching_3261(p_msg, &p_cell,
				/* we are seeking the original transaction --
				 * skip CANCEL transactions during search
				 */
				METHOD_CANCEL);
		if (ret==1) goto found; else goto notfound;
	}

	/* no cookies --proceed to old-fashioned pre-3261 t-matching */

	LOCK_HASH(hash_index);

	/* all the transactions from the entry are compared */
	for (p_cell=get_tm_table()->entrys[hash_index].first_cell;
		p_cell; p_cell = p_cell->next_cell )
	{
		t_msg = p_cell->uas.request;

		if (!t_msg) continue; /* skip UAC transactions */

		/* we don't cancel CANCELs ;-) */
		if (t_msg->REQ_METHOD==METHOD_CANCEL)
			continue;

		/* check lengths now */
		if (!EQ_LEN(callid))
			continue;
		if (get_cseq(t_msg)->number.len!=get_cseq(p_msg)->number.len)
			continue;
		if (!EQ_LEN(from))
			continue;
#ifdef CANCEL_TAG
		if (!EQ_LEN(to))
			continue;
#else
		/* relaxed matching -- we don't care about to-tags anymore,
		 * many broken UACs screw them up and ignoring them does not
		 * actually hurt
		 */
		if (get_to(t_msg)->uri.len!=get_to(p_msg)->uri.len)
			continue;
#endif
		if (ruri_matching && !EQ_REQ_URI_LEN)
			continue;
		if (via1_matching && !EQ_VIA_LEN(via1))
			continue;

		/* check the content now */
		if (!EQ_STR(callid))
			continue;
		if (memcmp(get_cseq(t_msg)->number.s,
			get_cseq(p_msg)->number.s,get_cseq(p_msg)->number.len)!=0)
			continue;
		if (!EQ_STR(from))
			continue;
#ifdef CANCEL_TAG
		if (!EQ_STR(to))
			continue;
#else
		if (memcmp(get_to(t_msg)->uri.s, get_to(p_msg)->uri.s,
					get_to(t_msg)->uri.len)!=0)
			continue;
#endif
		if (ruri_matching && !EQ_REQ_URI_STR)
			continue;
		if (via1_matching && !EQ_VIA_STR(via1))
			continue;

		/* found */
		goto found;
	}

notfound:
	/* no transaction found */
	LM_DBG("no CANCEL matching found! \n" );
	UNLOCK_HASH(hash_index);
	cancelled_T = NULL;
	LM_DBG("t_lookupOriginalT completed\n");
	return 0;

found:
	LM_DBG("canceled transaction found (%p)! \n",p_cell );
	cancelled_T = p_cell;
	REF_UNSAFE( p_cell );
	UNLOCK_HASH(hash_index);
	/* run callback */
	run_trans_callbacks( TMCB_TRANS_CANCELLED, cancelled_T, p_msg, 0,0);
	LM_DBG("t_lookupOriginalT completed\n");
	return p_cell;
}
예제 #2
0
파일: t_lookup.c 프로젝트: Danfx/opensips
int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked )
{
	struct cell         *p_cell;
	unsigned int       isACK;
	struct sip_msg  *t_msg;
	struct via_param *branch;
	int match_status;

	isACK = p_msg->REQ_METHOD==METHOD_ACK;

	if (isACK) {
		if (e2eack_T==NULL)
			return -1;
		if (e2eack_T!=T_UNDEFINED)
			return -2;
	}

	/* parse all*/
	if (check_transaction_quadruple(p_msg)==0) {
		LM_ERR("too few headers\n");
		set_t(0);
		/* stop processing */
		return 0;
	}

	/* start searching into the table */
	if (!p_msg->hash_index)
		p_msg->hash_index=tm_hash( p_msg->callid->body ,
			get_cseq(p_msg)->number ) ;
	LM_DBG("start searching: hash=%d, isACK=%d\n",
		p_msg->hash_index,isACK);


	/* first of all, look if there is RFC3261 magic cookie in branch; if
	 * so, we can do very quick matching and skip the old-RFC bizzar
	 * comparison of many header fields
	 */
	if (!p_msg->via1) {
		LM_ERR("no via\n");
		set_t(0);
		return 0;
	}
	branch=p_msg->via1->branch;
	if (branch && branch->value.s && branch->value.len>MCOOKIE_LEN
			&& memcmp(branch->value.s,MCOOKIE,MCOOKIE_LEN)==0) {
		/* huhuhu! the cookie is there -- let's proceed fast */
		LOCK_HASH(p_msg->hash_index);
		match_status=matching_3261(p_msg,&p_cell,
				/* skip transactions with different method; otherwise CANCEL
				 * would match the previous INVITE trans.  */
				isACK ? ~METHOD_INVITE: ~p_msg->REQ_METHOD);
		switch(match_status) {
				case 0:	goto notfound;	/* no match */
				case 1:	goto found; 	/* match */
				case 2:	goto e2e_ack;	/* e2e proxy ACK */
		}
	}

	/* ok -- it's ugly old-fashioned transaction matching -- it is
	 * a bit simplified to be fast -- we don't do all the comparisons
	 * of parsed uri, which was simply too bloated */
	LM_DBG("proceeding to pre-RFC3261 transaction matching\n");

	/* lock the whole entry*/
	LOCK_HASH(p_msg->hash_index);

	/* all the transactions from the entry are compared */
	for ( p_cell = get_tm_table()->entrys[p_msg->hash_index].first_cell;
		  p_cell; p_cell = p_cell->next_cell )
	{
		t_msg = p_cell->uas.request;

		if (!t_msg) continue; /* skip UAC transactions */

		if (!isACK) {
			/* compare lengths first */
			if (!EQ_LEN(callid)) continue;
			if (!EQ_LEN(cseq)) continue;
			if (!EQ_LEN(from)) continue;
			if (!EQ_LEN(to)) continue;
			if (ruri_matching && !EQ_REQ_URI_LEN) continue;
			if (via1_matching && !EQ_VIA_LEN(via1)) continue;

			/* length ok -- move on */
			if (!EQ_STR(callid)) continue;
			if (!EQ_STR(cseq)) continue;
			if (!EQ_STR(from)) continue;
			if (!EQ_STR(to)) continue;
			if (ruri_matching && !EQ_REQ_URI_STR) continue;
			if (via1_matching && !EQ_VIA_STR(via1)) continue;

			/* request matched ! */
			LM_DBG("non-ACK matched\n");
			goto found;
		} else { /* it's an ACK request*/
			/* ACK's relate only to INVITEs - and we look only for 2 types of
			 * INVITEs : (a) negative INVITEs or (b) pozitive UAS INVITEs */
			if ( t_msg->REQ_METHOD!=METHOD_INVITE || !(p_cell->uas.status>=300
			|| (p_cell->nr_of_outgoings==0 && p_cell->uas.status>=200)) )
				continue;

			/* From|To URI , CallID, CSeq # must be always there */
			/* compare lengths now */
			if (!EQ_LEN(callid)) continue;
			/* CSeq only the number without method ! */
			if (get_cseq(t_msg)->number.len!=get_cseq(p_msg)->number.len)
				continue;
			if (! EQ_LEN(from)) continue;
			/* To only the uri -- to many UACs screw up tags  */
			if (get_to(t_msg)->uri.len!=get_to(p_msg)->uri.len)
				continue;
			if (!EQ_STR(callid)) continue;
			if (memcmp(get_cseq(t_msg)->number.s, get_cseq(p_msg)->number.s,
				get_cseq(p_msg)->number.len)!=0) continue;
			if (!EQ_STR(from)) continue;
			if (memcmp(get_to(t_msg)->uri.s, get_to(p_msg)->uri.s,
				get_to(t_msg)->uri.len)!=0) continue;

			if (p_cell->uas.status<300) {
				/* it's a 2xx local UAS transaction */
				if (dlg_matching(p_cell, p_msg))
					goto e2e_ack;
				continue;
			}

			/* it is not an e2e ACK/200 -- perhaps it is
			 * local negative case; in which case we will want
			 * more elements to match: r-uri and via; allow
			 * mismatching r-uri as an config option for broken
			 * UACs */
			if (ruri_matching && !EQ_REQ_URI_LEN ) continue;
			if (via1_matching && !EQ_VIA_LEN(via1)) continue;
			if (ruri_matching && !EQ_REQ_URI_STR) continue;
			if (via1_matching && !EQ_VIA_STR(via1)) continue;

			/* wow -- we survived all the check! we matched! */
			LM_DBG("non-2xx ACK matched\n");
			goto found;
		} /* ACK */
	} /* synonym loop */

notfound:
	/* no transaction found */
	set_t(0);
	e2eack_T = NULL;
	if (!leave_new_locked || isACK) {
		UNLOCK_HASH(p_msg->hash_index);
	}
	LM_DBG("no transaction found\n");
	return -1;

e2e_ack:
	REF_UNSAFE( p_cell );
	UNLOCK_HASH(p_msg->hash_index);
	e2eack_T = p_cell;
	set_t(0);
	LM_DBG("e2e proxy ACK found\n");
	return -2;

found:
	set_t(p_cell);
	REF_UNSAFE( T );
	set_kr(REQ_EXIST);
	UNLOCK_HASH( p_msg->hash_index );
	LM_DBG("transaction found (T=%p)\n",T);
	return 1;
}
예제 #3
0
파일: t_lookup.c 프로젝트: Danfx/opensips
/* atomic "new_tran" construct; it returns:

	<0	on error

	+1	if a request did not match a transaction
		- it that was an ack, the calling function
		  shall forward statelessly
		- otherwise it means, a new transaction was
		  introduced and the calling function
		  shall reply/relay/whatever_appropriate

	0 on retransmission
*/
int t_newtran( struct sip_msg* p_msg, int full_uas )
{
	int lret, my_err;
	context_p ctx_backup;

	/* is T still up-to-date ? */
	LM_DBG("transaction on entrance=%p\n",T);

	if ( T && T!=T_UNDEFINED  ) {
		LM_DBG("transaction already in process %p\n", T );
		return E_SCRIPT;
	}

	T = T_UNDEFINED;
	/* first of all, parse everything -- we will store in shared memory
	   and need to have all headers ready for generating potential replies
	   later; parsing later on demand is not an option since the request
	   will be in shmem and applying parse_headers to it would intermix
	   shmem with pkg_mem
	*/

	if (parse_headers(p_msg, HDR_EOH_F, 0 )<0) {
		LM_ERR("parse_headers failed\n");
		return E_BAD_REQ;
	}
	if ((p_msg->parsed_flag & HDR_EOH_F)!=HDR_EOH_F) {
			LM_ERR("EoH not parsed\n");
			return E_OUT_OF_MEM;
	}
	/* t_lookup_requests attempts to find the transaction;
	   it also calls check_transaction_quadruple -> it is
	   safe to assume we have from/callid/cseq/to
	*/
	lret = t_lookup_request( p_msg, 1 /* leave locked if not found */ );

	/* on error, pass the error in the stack ... nothing is locked yet
	   if 0 is returned */
	if (lret==0) return E_BAD_TUPEL;

	/* transaction found, it's a retransmission  */
	if (lret>0) {
		if (p_msg->REQ_METHOD==METHOD_ACK) {
			t_release_transaction(T);
		} else {
			t_retransmit_reply(T);
		}
		/* things are done -- return from script */
		return 0;
	}

	/* from now on, be careful -- hash table is locked */

	if (lret==-2) { /* was it an e2e ACK ? if so, trigger a callback */
		if (e2eack_T->relaied_reply_branch==-2) {
			/* if a ACK for a local replied transaction, release the
			 INVITE transaction and break the script -> simply absorb
			 the ACK request */
			t_release_transaction(e2eack_T);
			return 0;
		}
		LM_DBG("building branch for end2end ACK - flags=%X\n",e2eack_T->flags);
		/* to ensure unigueness acros time and space, compute the ACK
		 * branch in the same maner as for INVITE, but put a t->branch
		 * value that cannot exist for that INVITE - as it is compute as
		 * an INVITE, it will not overlapp with other INVITEs or requests.
		 * But the faked value for t->branch guarantee no overalap with
		 * corresponding INVITE  --bogdan */
		if (!t_calc_branch(e2eack_T, e2eack_T->nr_of_outgoings+1,
		p_msg->add_to_branch_s, &p_msg->add_to_branch_len )) {
			LM_ERR("ACK branch computation failed\n");
		}

		return 1;
	}

	/* transaction not found, it's a new request (lret<0, lret!=-2);
	   establish a new transaction ... */
	if (p_msg->REQ_METHOD==METHOD_ACK) /* ... unless it is in ACK */
		return 1;

	my_err=new_t(p_msg, full_uas);
	if (my_err<0) {
		LM_ERR("new_t failed\n");
		goto new_err;
	}


	UNLOCK_HASH(p_msg->hash_index);
	/* now, when the transaction state exists, check if
	   there is a meaningful Via and calculate it; better
	   do it now than later: state is established so that
	   subsequent retransmissions will be absorbed and will
	  not possibly block during Via DNS resolution; doing
	   it later would only burn more CPU as if there is an
	   error, we cannot relay later whatever comes out of the
	   the transaction
	*/
	if (!init_rb( &T->uas.response, p_msg)) {
		LM_ERR("unresolvable via1\n");
		put_on_wait( T );
		t_unref(p_msg);
		return E_BAD_VIA;
	}

	if (auto_100trying && p_msg->REQ_METHOD==METHOD_INVITE) {
		ctx_backup = current_processing_ctx;
		current_processing_ctx = NULL;
		t_reply( T, p_msg , 100 , &relay_reason_100);
		current_processing_ctx = ctx_backup;
	}

	return 1;
new_err:
	UNLOCK_HASH(p_msg->hash_index);
	return my_err;

}
예제 #4
0
파일: t_lookup.c 프로젝트: Danfx/opensips
/* lookup a transaction by callid and cseq, parameters are pure
 * header field content only, e.g. "[email protected]" and "11"
 */
int t_lookup_callid(struct cell ** trans, str callid, str cseq) {
	struct cell* p_cell;
	unsigned int hash_index;

	/* I use MAX_HEADER, not sure if this is a good choice... */
	char callid_header[MAX_HEADER];
	char cseq_header[MAX_HEADER];
	/* save return value of print_* functions here */
	char* endpos;
	UNUSED(endpos);

	/* need method, which is always INVITE in our case */
	/* CANCEL is only useful after INVITE */
	str invite_method;
	char* invite_string = INVITE;

	invite_method.s = invite_string;
	invite_method.len = INVITE_LEN;

	/* lookup the hash index where the transaction is stored */
	hash_index=tm_hash(callid, cseq);

	if(hash_index >= TM_TABLE_ENTRIES){
		LM_ERR("invalid hash_index=%u\n",hash_index);
		return -1;
	}

	/* create header fields the same way tm does itself, then compare headers */
	endpos = print_callid_mini(callid_header, callid);
	LM_DBG("created comparable call_id header field: >%.*s<\n",
			(int)(endpos - callid_header), callid_header);

	endpos = print_cseq_mini(cseq_header, &cseq, &invite_method);
	LM_DBG("created comparable cseq header field: >%.*s<\n",
			(int)(endpos - cseq_header), cseq_header);

	LOCK_HASH(hash_index);

	/* all the transactions from the entry are compared */
	p_cell = get_tm_table()->entrys[hash_index].first_cell;
	for ( ; p_cell; p_cell = p_cell->next_cell ) {

		/* compare complete header fields, casecmp to make sure invite=INVITE */
		LM_DBG(" <%.*s>  <%.*s>\n", p_cell->callid.len, p_cell->callid.s,
			p_cell->cseq_n.len,p_cell->cseq_n.s);
		if ( (strncmp(callid_header, p_cell->callid.s, p_cell->callid.len) == 0)
			&& (strncasecmp(cseq_header, p_cell->cseq_n.s, p_cell->cseq_n.len) == 0) ) {
			LM_DBG("we have a match: callid=>>%.*s<< cseq=>>%.*s<<\n",
				p_cell->callid.len,p_cell->callid.s, p_cell->cseq_n.len,
				p_cell->cseq_n.s);
			REF_UNSAFE(p_cell);
			UNLOCK_HASH(hash_index);
			set_t(p_cell);
			*trans=p_cell;
			LM_DBG("transaction found.\n");
			return 1;
		}
		LM_DBG("NO match: callid=%.*s cseq=%.*s\n",
			p_cell->callid.len, p_cell->callid.s,
			p_cell->cseq_n.len, p_cell->cseq_n.s);
	}

	UNLOCK_HASH(hash_index);
	LM_DBG("transaction not found.\n");

	return -1;
}
예제 #5
0
파일: uac.c 프로젝트: halan/kamailio
/* WARNING: - dst_cell contains the created cell, but it is un-referenced
 *            (before using it make sure you REF() it first)
 *          - if  ACK (method==ACK), a cell will be created but it will not
 *            be added in the hash table (should be either deleted by the 
 *            caller) 
 */
static inline int t_uac_prepare(uac_req_t *uac_r, 
		struct retr_buf **dst_req,
		struct cell **dst_cell)
{
	struct dest_info dst;
	struct cell *new_cell;
	struct retr_buf *request;
	char* buf;
	int buf_len, ret;
	unsigned int hi;
	int is_ack;
	ticks_t lifetime;
#ifdef USE_DNS_FAILOVER
	struct dns_srv_handle dns_h;
#endif
	long nhtype;
#ifdef WITH_EVENT_LOCAL_REQUEST
	struct cell *backup_t;
	int backup_branch;
	unsigned int backup_msgid;
	static struct sip_msg lreq;
	char *buf1;
	int buf_len1;
	int sflag_bk;
	int backup_route_type;
#endif
	snd_flags_t snd_flags;
	tm_xlinks_t backup_xd;
	tm_xdata_t local_xd;

	ret=-1;
	hi=0; /* make gcc happy */
	/*if (dst_req) *dst_req = NULL;*/
	is_ack = (((uac_r->method->len == 3) && (memcmp("ACK", uac_r->method->s, 3)==0)) ? 1 : 0);
	
	/*** added by dcm 
	 * - needed by external ua to send a request within a dlg
	 */
	if ((nhtype = w_calculate_hooks(uac_r->dialog)) < 0)
		/* if err's returned, the message is incorrect */
		goto error2;

	if (!uac_r->dialog->loc_seq.is_set) {
		/* this is the first request in the dialog,
		set cseq to default value now - Miklos */
		uac_r->dialog->loc_seq.value = DEFAULT_CSEQ;
		uac_r->dialog->loc_seq.is_set = 1;
	}

	DBG("DEBUG:tm:t_uac: next_hop=<%.*s>\n",uac_r->dialog->hooks.next_hop->len,
			uac_r->dialog->hooks.next_hop->s);
	/* new message => take the dialog send_socket if set, or the default
	  send_socket if not*/
	SND_FLAGS_INIT(&snd_flags);
#ifdef USE_DNS_FAILOVER
	if (cfg_get(core, core_cfg, use_dns_failover)){
		dns_srv_handle_init(&dns_h);
		if ((uri2dst2(&dns_h, &dst, uac_r->dialog->send_sock, snd_flags,
							uac_r->dialog->hooks.next_hop, PROTO_NONE)==0)
				|| (dst.send_sock==0)){
			dns_srv_handle_put(&dns_h);
			ser_error = E_NO_SOCKET;
			ret=ser_error;
			LOG(L_ERR, "t_uac: no socket found\n");
			goto error2;
		}
		dns_srv_handle_put(&dns_h); /* not needed anymore */
	}else{
		if ((uri2dst2(0, &dst, uac_r->dialog->send_sock, snd_flags,
						uac_r->dialog->hooks.next_hop, PROTO_NONE)==0) ||
				(dst.send_sock==0)){
			ser_error = E_NO_SOCKET;
			ret=ser_error;
			LOG(L_ERR, "t_uac: no socket found\n");
			goto error2;
		}
	}
#else /* USE_DNS_FAILOVER */
	if ((uri2dst2(&dst, uac_r->dialog->send_sock, snd_flags,
					uac_r->dialog->hooks.next_hop, PROTO_NONE)==0) ||
			(dst.send_sock==0)){
		ser_error = E_NO_SOCKET;
		ret=ser_error;
		LOG(L_ERR, "t_uac: no socket found\n");
		goto error2;
	}
#endif /* USE_DNS_FAILOVER */

	/* build cell sets X/AVP lists to new transaction structure
	 * => bakup in a tmp struct and restore afterwards */
	memset(&local_xd, 0, sizeof(tm_xdata_t));
	tm_xdata_replace(&local_xd, &backup_xd);
	new_cell = build_cell(0); 
	tm_xdata_replace(0, &backup_xd);

	if (!new_cell) {
		ret=E_OUT_OF_MEM;
		LOG(L_ERR, "t_uac: short of cell shmem\n");
		goto error2;
	}
	if (uac_r->method->len==INVITE_LEN && memcmp(uac_r->method->s, INVITE, INVITE_LEN)==0){
		new_cell->flags |= T_IS_INVITE_FLAG;
		new_cell->flags|=T_AUTO_INV_100 &
				(!cfg_get(tm, tm_cfg, tm_auto_inv_100) -1);
#ifdef WITH_AS_SUPPORT
		if (uac_r->cb_flags & TMCB_DONT_ACK)
			new_cell->flags |= T_NO_AUTO_ACK;
#endif
		lifetime=cfg_get(tm, tm_cfg, tm_max_inv_lifetime);
	}else
		lifetime=cfg_get(tm, tm_cfg, tm_max_noninv_lifetime);
	new_cell->flags |= T_IS_LOCAL_FLAG;
	/* init timers hack, new_cell->fr_timer and new_cell->fr_inv_timer
	 * must be set, or else the fr will happen immediately
	 * we can't call init_new_t() because we don't have a sip msg
	 * => we'll ignore t_set_fr() or avp timer value and will use directly the
	 * module params fr_inv_timer and fr_timer -- andrei */
	new_cell->fr_timeout=cfg_get(tm, tm_cfg, fr_timeout);
	new_cell->fr_inv_timeout=cfg_get(tm, tm_cfg, fr_inv_timeout);
	new_cell->end_of_life=get_ticks_raw()+lifetime;
#ifdef TM_DIFF_RT_TIMEOUT
	/* same as above for retransmission intervals */
	new_cell->rt_t1_timeout_ms = cfg_get(tm, tm_cfg, rt_t1_timeout_ms);
	new_cell->rt_t2_timeout_ms = cfg_get(tm, tm_cfg, rt_t2_timeout_ms);
#endif

	set_kr(REQ_FWDED);

	request = &new_cell->uac[0].request;
	request->dst = dst;
	request->flags |= nhtype;

	if (!is_ack) {
#ifdef TM_DEL_UNREF
		INIT_REF(new_cell, 1); /* ref'ed only from the hash */
#endif
		hi=dlg2hash(uac_r->dialog);
		LOCK_HASH(hi);
		insert_into_hash_table_unsafe(new_cell, hi);
		UNLOCK_HASH(hi);
	}

	buf = build_uac_req(uac_r->method, uac_r->headers, uac_r->body, uac_r->dialog, 0, new_cell,
		&buf_len, &dst);
	if (!buf) {
		LOG(L_ERR, "t_uac: Error while building message\n");
		ret=E_OUT_OF_MEM;
		goto error1;
	}

#ifdef WITH_EVENT_LOCAL_REQUEST
	if (unlikely(goto_on_local_req>=0)) {
		DBG("executing event_route[tm:local-request]\n");
		if(likely(build_sip_msg_from_buf(&lreq, buf, buf_len, inc_msg_no())
					== 0)) {
			/* fill some field in sip_msg */
			if (unlikely(set_dst_uri(&lreq, uac_r->dialog->hooks.next_hop))) {
				LM_ERR("failed to set dst_uri");
				free_sip_msg(&lreq);
			} else {
				struct onsend_info onsnd_info;

				lreq.force_send_socket = uac_r->dialog->send_sock;
				lreq.rcv.proto = dst.send_sock->proto;
				lreq.rcv.src_ip = dst.send_sock->address;
				lreq.rcv.src_port = dst.send_sock->port_no;
				lreq.rcv.dst_port = su_getport(&dst.to);
				su2ip_addr(&lreq.rcv.dst_ip, &dst.to);
				lreq.rcv.src_su=dst.send_sock->su;
				lreq.rcv.bind_address=dst.send_sock;
			#ifdef USE_COMP
				lreq.rcv.comp=dst.comp;
			#endif /* USE_COMP */
				sflag_bk = getsflags();
				tm_xdata_swap(new_cell, &backup_xd, 0);

				onsnd_info.to=&dst.to;
				onsnd_info.send_sock=dst.send_sock;
				onsnd_info.buf=buf;
				onsnd_info.len=buf_len;
				p_onsend=&onsnd_info;

				/* run the route */
				backup_route_type = get_route_type();
				set_route_type(LOCAL_ROUTE);
				/* set T to the current transaction */
				backup_t=get_t();
				backup_branch=get_t_branch();
				backup_msgid=global_msg_id;
				/* fake transaction and message id */
				global_msg_id=lreq.id;
				set_t(new_cell, T_BR_UNDEFINED);
				run_top_route(event_rt.rlist[goto_on_local_req], &lreq, 0);
				/* restore original environment */
				set_t(backup_t, backup_branch);
				global_msg_id=backup_msgid;
				set_route_type( backup_route_type );
				p_onsend=0;

				/* restore original environment */
				tm_xdata_swap(new_cell, &backup_xd, 1);
				setsflagsval(sflag_bk);

				if (unlikely(lreq.new_uri.s))
				{
					pkg_free(lreq.new_uri.s);
					lreq.new_uri.s=0;
					lreq.new_uri.len=0;
				}
				if (unlikely(lreq.dst_uri.s))
				{
					pkg_free(lreq.dst_uri.s);
					lreq.dst_uri.s=0;
					lreq.dst_uri.len=0;
				}

				if (unlikely(lreq.add_rm || lreq.body_lumps)) {
					LM_DBG("apply new updates to sip msg\n");
					buf1 = build_req_buf_from_sip_req(&lreq,
							(unsigned int*)&buf_len1,
							&dst, BUILD_NO_LOCAL_VIA|BUILD_NO_VIA1_UPDATE|
							BUILD_IN_SHM);
					if (likely(buf1)){
						shm_free(buf);
						buf = buf1;
						buf_len = buf_len1;
						/* a possible change of the method is not handled! */
					}
				}
				lreq.buf=0; /* covers the obsolete DYN_BUF */
				free_sip_msg(&lreq);
			}
		}
	}
#endif

	new_cell->method.s = buf;
	new_cell->method.len = uac_r->method->len;

	request->buffer = buf;
	request->buffer_len = buf_len;
	new_cell->nr_of_outgoings++;

	/* Register the callbacks after everything is successful and nothing can fail.
	Otherwise the callback parameter would be freed twise, once from TMCB_DESTROY,
	and again because of the negative return code. */
	if(uac_r->cb && insert_tmcb(&(new_cell->tmcb_hl), uac_r->cb_flags, 
								*(uac_r->cb), uac_r->cbp, NULL)!=1){
		ret=E_OUT_OF_MEM; 
		LOG(L_ERR, "t_uac: short of tmcb shmem\n");
		goto error1;
	}
	if (has_local_reqin_tmcbs())
			run_local_reqin_callbacks(new_cell, 0, 0);
#ifdef DIALOG_CALLBACKS
	run_trans_dlg_callbacks(uac_r->dialog, new_cell, request);
#endif /* DIALOG_CALLBACKS */
	if (dst_req) *dst_req = request;
	if (dst_cell) *dst_cell = new_cell;
	else if(is_ack && dst_req==0){
		free_cell(new_cell);
	}
	
	return 1;

 error1:
 	if (!is_ack) {
		LOCK_HASH(hi);
		remove_from_hash_table_unsafe(new_cell);
		UNLOCK_HASH(hi);
#ifdef TM_DEL_UNREF
		UNREF_FREE(new_cell);
	}else
#else
	}
#endif
		free_cell(new_cell);
error2:
	return ret;
}