示例#1
0
文件: t_reply.c 项目: iamroger/voip
/* return 1 if a failure_route processes */
static inline int run_failure_handlers(struct cell *t)
{
	static struct sip_msg faked_req;
	struct sip_msg *shmem_msg;
	struct ua_client *uac;
	int on_failure;

	shmem_msg = t->uas.request;
	uac = &t->uac[picked_branch];

	/* failure_route for a local UAC? */
	if (!shmem_msg || REQ_LINE(shmem_msg).method_value==METHOD_CANCEL ) {
		LM_WARN("no UAC or CANCEL support (%d, %d) \n",
				t->on_negative, t->tmcb_hl.reg_types);
		return 0;
	}

	/* don't start faking anything if we don't have to */
	if ( !has_tran_tmcbs( t, TMCB_ON_FAILURE) && !t->on_negative ) {
		LM_WARN("no negative handler (%d, %d)\n",t->on_negative, 
			t->tmcb_hl.reg_types);
		return 1;
	}

	if (!fake_req(&faked_req, shmem_msg, &t->uas, uac)) {
		LM_ERR("fake_req failed\n");
		return 0;
	}
	/* fake also the env. conforming to the fake msg */
	faked_env( t, &faked_req);

	/* DONE with faking ;-) -> run the failure handlers */
	if ( has_tran_tmcbs( t, TMCB_ON_FAILURE) ) {
		run_trans_callbacks( TMCB_ON_FAILURE, t, &faked_req,
				uac->reply, uac->last_received);
	}
	if (t->on_negative) {
		/* update flags in transaction if changed by callbacks */
		shmem_msg->flags = faked_req.flags;
		/* avoid recursion -- if failure_route forwards, and does not 
		 * set next failure route, failure_route will not be reentered
		 * on failure */
		on_failure = t->on_negative;
		t->on_negative=0;
		/* run a reply_route action if some was marked */
		run_top_route(failure_rlist[on_failure].a, &faked_req);
	}

	/* restore original environment and free the fake msg */
	faked_env( t, 0);
	free_faked_req(&faked_req,t);

	/* if failure handler changed flag, update transaction context */
	shmem_msg->flags = faked_req.flags;
	/* branch flags do not need to be updated as this branch will be never
	 * used again */
	return 1;
}
示例#2
0
文件: t_fwd.c 项目: OPSF/uClinux
char *print_uac_request( struct cell *t, struct sip_msg *i_req,
                         int branch, str *uri, unsigned int *len, struct socket_info *send_sock,
                         enum sip_protos proto )
{
    char *buf, *shbuf;

    shbuf=0;

    /* ... we calculate branch ... */
    if (!t_calc_branch(t, branch, i_req->add_to_branch_s,
                       &i_req->add_to_branch_len ))
    {
        LOG(L_ERR, "ERROR: print_uac_request: branch computation failed\n");
        goto error01;
    }

    /* ... update uri ... */
    i_req->new_uri=*uri;

    /* run the specific callbacks for this transaction */
    run_trans_callbacks( TMCB_REQUEST_FWDED , t, i_req, 0, -i_req->REQ_METHOD);

    /* ... and build it now */
    buf=build_req_buf_from_sip_req( i_req, len, send_sock, proto );
#ifdef DBG_MSG_QA
    if (buf[*len-1]==0) {
        LOG(L_ERR, "ERROR: print_uac_request: sanity check failed\n");
        abort();
    }
#endif
    if (!buf) {
        LOG(L_ERR, "ERROR: print_uac_request: no pkg_mem\n");
        ser_error=E_OUT_OF_MEM;
        goto error01;
    }
    /*	clean Via's we created now -- they would accumulate for
    	other branches  and for  shmem i_req they would mix up
     	shmem with pkg_mem
    */
    free_via_clen_lump(&i_req->add_rm);

    shbuf=(char *)shm_malloc(*len);
    if (!shbuf) {
        ser_error=E_OUT_OF_MEM;
        LOG(L_ERR, "ERROR: print_uac_request: no shmem\n");
        goto error02;
    }
    memcpy( shbuf, buf, *len );

error02:
    pkg_free( buf );
error01:
    return shbuf;
}
示例#3
0
void run_trans_callbacks_locked( int type , struct cell *trans,
						struct sip_msg *req, struct sip_msg *rpl, int code )
{
	if (trans->tmcb_hl.first==0 || ((trans->tmcb_hl.reg_types)&type)==0 )
		return;

	LOCK_REPLIES(trans);

	/* run callbacks */
	run_trans_callbacks( type , trans, req, rpl, code );
	/* SHM message cleanup */
	if (trans->uas.request && trans->uas.request->msg_flags&FL_SHM_CLONE)
		clean_msg_clone( trans->uas.request, trans->uas.request,
			trans->uas.end_request);

	UNLOCK_REPLIES(trans);
}
示例#4
0
void cancel_branch( struct cell *t, int branch )
{
	char *cancel;
	unsigned int len;
	struct retr_buf *crb, *irb;

	crb=&t->uac[branch].local_cancel;
	irb=&t->uac[branch].request;

#	ifdef EXTRA_DEBUG
	if (crb->buffer.s!=0 && crb->buffer.s!=BUSY_BUFFER) {
		LM_CRIT("attempt to rewrite cancel buffer failed\n");
		abort();
	}
#	endif

	cancel=build_cancel(t, branch, &len);
	if (!cancel) {
		LM_ERR("attempt to build a CANCEL failed\n");
		return;
	}
	/* install cancel now */
	crb->buffer.s=cancel;
	crb->buffer.len=len;
	crb->dst=irb->dst;
	crb->branch=branch;
	/* label it as cancel so that FR timer can better now how
	 * to deal with it */
	crb->activ_type=TYPE_LOCAL_CANCEL;

	if ( has_tran_tmcbs( t, TMCB_REQUEST_BUILT) ) {
		set_extra_tmcb_params( &crb->buffer, &crb->dst);
		run_trans_callbacks( TMCB_REQUEST_BUILT, t, t->uas.request,0,
			-t->uas.request->REQ_METHOD);
	}

	LM_DBG("sending cancel...\n");
	SEND_BUFFER( crb );

	/*sets and starts the FINAL RESPONSE timer */
	start_retr( crb );
}
示例#5
0
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);
	if (has_tran_tmcbs( T, TMCB_MSG_MATCHED_IN) )
		run_trans_callbacks( TMCB_MSG_MATCHED_IN, T, p_msg, 0,0);
	return 1;
}
示例#6
0
/* Returns 0 - nothing found
 *         1  - T found
 */
int t_reply_matching( struct sip_msg *p_msg , int *p_branch )
{
	struct cell*  p_cell;
	int hash_index   = 0;
	int entry_label  = 0;
	int branch_id    = 0;
	char  *hashi, *branchi, *p, *n;
	int hashl, branchl;
	int scan_space;
	struct cseq_body *cseq;

	char *loopi;
	int loopl;
	char *syni;
	int synl;

	/* make compiler warnings happy */
	loopi=0;
	loopl=0;
	syni=0;
	synl=0;

	/* split the branch into pieces: loop_detection_check(ignored),
	 hash_table_id, synonym_id, branch_id */

	if (!(p_msg->via1 && p_msg->via1->branch && p_msg->via1->branch->value.s))
		goto nomatch2;

	/* we do RFC 3261 tid matching and want to see first if there is
	 * magic cookie in branch */
	if (p_msg->via1->branch->value.len<=MCOOKIE_LEN)
		goto nomatch2;
	if (memcmp(p_msg->via1->branch->value.s, MCOOKIE, MCOOKIE_LEN)!=0)
		goto nomatch2;

	p=p_msg->via1->branch->value.s+MCOOKIE_LEN;
	scan_space=p_msg->via1->branch->value.len-MCOOKIE_LEN;


	/* hash_id */
	n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR);
	hashl=n-p;
	scan_space-=hashl;
	if (!hashl || scan_space<2 || *n!=BRANCH_SEPARATOR) goto nomatch2;
	hashi=p;
	p=n+1;scan_space--;

	if (!syn_branch) {
		/* md5 value */
		n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR );
		loopl = n-p;
		scan_space-= loopl;
		if (n==p || scan_space<2 || *n!=BRANCH_SEPARATOR)
			goto nomatch2;
		loopi=p;
		p=n+1; scan_space--;
	} else {
		/* synonym id */
		n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR);
		synl=n-p;
		scan_space-=synl;
		if (!synl || scan_space<2 || *n!=BRANCH_SEPARATOR)
			goto nomatch2;
		syni=p;
		p=n+1;scan_space--;
	}

	/* branch id  -  should exceed the scan_space */
	n=eat_token_end( p, p+scan_space );
	branchl=n-p;
	if (!branchl ) goto nomatch2;
	branchi=p;

	/* sanity check */
	if ((hash_index=reverse_hex2int(hashi, hashl))<0
		||hash_index>=TM_TABLE_ENTRIES
		|| (branch_id=reverse_hex2int(branchi, branchl))<0
		||branch_id>=MAX_BRANCHES
		|| (syn_branch ? (entry_label=reverse_hex2int(syni, synl))<0
			: loopl!=MD5_LEN )
	) {
		LM_DBG("poor reply labels %d label %d branch %d\n",
				hash_index, entry_label, branch_id );
		goto nomatch2;
	}

	LM_DBG("hash %d label %d branch %d\n",hash_index, entry_label, branch_id);

	cseq = get_cseq(p_msg);

	/* search the hash table list at entry 'hash_index'; lock the
	   entry first */
	LOCK_HASH(hash_index);

	for (p_cell = get_tm_table()->entrys[hash_index].first_cell; p_cell;
		p_cell=p_cell->next_cell) {

		/* first look if branch matches */
		if (syn_branch) {
			if (p_cell->label != entry_label)
				continue;
		} else {
			if ( memcmp(p_cell->md5, loopi,MD5_LEN)!=0)
					continue;
		}

		/* sanity check ... too high branch ? */
		if ( branch_id>=p_cell->nr_of_outgoings )
			continue;

		/* does method match ? (remember -- CANCELs have the same branch
		   as canceled transactions) */
		if (!( /* it's a local cancel */
			(cseq->method_id==METHOD_CANCEL && is_invite(p_cell)
				&& p_cell->uac[branch_id].local_cancel.buffer.len )
			/* method match */
			|| ((cseq->method_id!=METHOD_OTHER && p_cell->uas.request)?
				(cseq->method_id==REQ_LINE(p_cell->uas.request).method_value)
				:(EQ_STRS(cseq->method,p_cell->method)))
		))
			continue;

		/* we passed all disqualifying factors .... the transaction has been
		   matched !
		*/
		set_t(p_cell);
		*p_branch = branch_id;
		REF_UNSAFE( T );
		UNLOCK_HASH(hash_index);
		LM_DBG("reply matched (T=%p)!\n",T);
		/* if this is a 200 for INVITE, we will wish to store to-tags to be
		 * able to distinguish retransmissions later and not to call
 		 * TMCB_RESPONSE_OUT uselessly; we do it only if callbacks are
		 * enabled -- except callback customers, nobody cares about
		 * retransmissions of multiple 200/INV or ACK/200s
		 */
		if (is_invite(p_cell) && p_msg->REPLY_STATUS>=200
		&& p_msg->REPLY_STATUS<300
		&& ( (!is_local(p_cell) &&
				has_tran_tmcbs(p_cell,
				TMCB_RESPONSE_OUT|TMCB_RESPONSE_PRE_OUT) )
			|| (is_local(p_cell)&&has_tran_tmcbs(p_cell,TMCB_LOCAL_COMPLETED))
		)) {
			if (parse_headers(p_msg, HDR_TO_F, 0)==-1) {
				LM_ERR("to parsing failed\n");
			}
		}
		if (!is_local(p_cell) &&
		!(cseq->method_id==METHOD_CANCEL && is_invite(p_cell)) ) {
			run_trans_callbacks( TMCB_RESPONSE_IN, T, T->uas.request, p_msg,
				p_msg->REPLY_STATUS);
		}
		return 1;
	} /* for cycle */

	/* nothing found */
	UNLOCK_HASH(hash_index);
	LM_DBG("no matching transaction exists\n");

nomatch2:
	LM_DBG("failure to match a transaction\n");
	*p_branch = -1;
	set_t(0);
	return -1;
}
示例#7
0
文件: t_reply.c 项目: iamroger/voip
/* this is the "UAC" above transaction layer; if a final reply
   is received, it triggers a callback; note well -- it assumes
   it is entered locked with REPLY_LOCK and it returns unlocked!
*/
enum rps local_reply( struct cell *t, struct sip_msg *p_msg, int branch, 
	unsigned int msg_status, branch_bm_t *cancel_bitmap)
{
	/* how to deal with replies for local transaction */
	int local_store, local_winner;
	enum rps reply_status;
	struct sip_msg *winning_msg;
	int winning_code;
	int totag_retr;
	/* branch_bm_t cancel_bitmap; */

	/* keep warning 'var might be used un-inited' silent */	
	winning_msg=0;
	winning_code=0;
	totag_retr=0;

	*cancel_bitmap=0;

	reply_status=t_should_relay_response( t, msg_status, branch,
		&local_store, &local_winner, cancel_bitmap, p_msg );
	LM_DBG("branch=%d, save=%d, winner=%d\n",
		branch, local_store, local_winner );
	if (local_store) {
		if (!store_reply(t, branch, p_msg))
			goto error;
	}
	if (local_winner>=0) {
		winning_msg= branch==local_winner 
			? p_msg :  t->uac[local_winner].reply;
		if (winning_msg==FAKED_REPLY) {
			winning_code = branch==local_winner
				? msg_status : t->uac[local_winner].last_received;
		} else {
			winning_code=winning_msg->REPLY_STATUS;
		}
		t->uas.status = winning_code;
		stats_trans_rpl( winning_code, (winning_msg==FAKED_REPLY)?1:0 );
		if (is_invite(t) && winning_msg!=FAKED_REPLY
		&& winning_code>=200 && winning_code <300
		&& has_tran_tmcbs(t,
		TMCB_RESPONSE_OUT|TMCB_RESPONSE_PRE_OUT) )  {
			totag_retr=update_totag_set(t, winning_msg);
		}
	}
	UNLOCK_REPLIES(t);

	if ( local_winner >= 0 ) {
		if (winning_code < 200) {
			if (!totag_retr && has_tran_tmcbs(t,TMCB_LOCAL_RESPONSE_OUT)) {
				LM_DBG("Passing provisional reply %d to FIFO application\n",
						winning_code);
				run_trans_callbacks( TMCB_LOCAL_RESPONSE_OUT, t, 0,
					winning_msg, winning_code);
			}
		} else {
			LM_DBG("local transaction completed\n");
			if (!totag_retr && has_tran_tmcbs(t,TMCB_LOCAL_COMPLETED) ) {
				run_trans_callbacks( TMCB_LOCAL_COMPLETED, t, 0,
					winning_msg, winning_code );
			}
		}
	}
	return reply_status;

error:
	which_cancel(t, cancel_bitmap);
	UNLOCK_REPLIES(t);
	cleanup_uac_timers(t);
	if ( get_cseq(p_msg)->method_id==METHOD_INVITE )
		cancel_uacs( t, *cancel_bitmap );
	put_on_wait(t);
	return RPS_ERROR;
}
示例#8
0
文件: t_reply.c 项目: iamroger/voip
static int _reply_light( struct cell *trans, char* buf, unsigned int len,
			 unsigned int code, char *to_tag, unsigned int to_tag_len,
			 int lock, struct bookmark *bm)
{
	struct retr_buf *rb;
	unsigned int buf_len;
	branch_bm_t cancel_bitmap;
	str cb_s;

	if (!buf)
	{
		LM_DBG("response building failed\n");
		/* determine if there are some branches to be canceled */
		if ( is_invite(trans) ) {
			if (lock) LOCK_REPLIES( trans );
			which_cancel(trans, &cancel_bitmap );
			if (lock) UNLOCK_REPLIES( trans );
		}
		/* and clean-up, including cancellations, if needed */
		goto error;
	}

	cancel_bitmap=0;
	if (lock) LOCK_REPLIES( trans );
	if ( is_invite(trans) ) which_cancel(trans, &cancel_bitmap );
	if (trans->uas.status>=200) {
		LM_ERR("failed to generate %d reply when a final %d was sent out\n",
				code, trans->uas.status);
		goto error2;
	}


	rb = & trans->uas.response;
	rb->activ_type=code;

	trans->uas.status = code;
	buf_len = rb->buffer.s ? len : len + REPLY_OVERBUFFER_LEN;
	rb->buffer.s = (char*)shm_resize( rb->buffer.s, buf_len );
	/* puts the reply's buffer to uas.response */
	if (! rb->buffer.s ) {
			LM_ERR("failed to allocate shmem buffer\n");
			goto error3;
	}
	update_local_tags(trans, bm, rb->buffer.s, buf);

	rb->buffer.len = len ;
	memcpy( rb->buffer.s , buf , len );
	/* needs to be protected too because what timers are set depends
	   on current transactions status */
	/* t_update_timers_after_sending_reply( rb ); */
	trans->relaied_reply_branch=-2;
	if (lock) UNLOCK_REPLIES( trans );
	
	/* do UAC cleanup procedures in case we generated
	   a final answer whereas there are pending UACs */
	if (code>=200) {
		if ( is_local(trans) ) {
			LM_DBG("local transaction completed\n");
			if ( has_tran_tmcbs(trans, TMCB_LOCAL_COMPLETED) ) {
				run_trans_callbacks( TMCB_LOCAL_COMPLETED, trans,
					0, FAKED_REPLY, code);
			}
		} else {
			/* run the PRE send callbacks */
			if ( has_tran_tmcbs(trans, TMCB_RESPONSE_PRE_OUT) ) {
				cb_s.s = buf;
				cb_s.len = len;
				set_extra_tmcb_params( &cb_s, &rb->dst);
				if (lock)
					run_trans_callbacks_locked( TMCB_RESPONSE_PRE_OUT, trans,
						trans->uas.request, FAKED_REPLY, code);
				else
					run_trans_callbacks( TMCB_RESPONSE_PRE_OUT, trans,
						trans->uas.request, FAKED_REPLY, code);
			}
		}

		if (!is_hopbyhop_cancel(trans)) {
			cleanup_uac_timers( trans );
			if (is_invite(trans)) cancel_uacs( trans, cancel_bitmap );
			/* for auth related replies, we do not do retransmission 
			   (via set_final_timer()), but only wait for a final 
			   reply (put_on_wait() ) - see RFC 3261 (26.3.2.4 DoS Protection) */
			if ((code != 401) && (code != 407))
				set_final_timer(  trans );
			else
				put_on_wait(trans);
		}
	}

	/* send it out : response.dst.send_sock is valid all the time now, 
	 * as it's taken from original request -bogdan */
	if (!trans->uas.response.dst.send_sock) {
		LM_CRIT("send_sock is NULL\n");
	}
	SEND_PR_BUFFER( rb, buf, len );
	LM_DBG("reply sent out. buf=%p: %.9s..., "
		"shmem=%p: %.9s\n", buf, buf, rb->buffer.s, rb->buffer.s );

	/* run the POST send callbacks */
	if (code>=200&&!is_local(trans)&&has_tran_tmcbs(trans,TMCB_RESPONSE_OUT)) {
		cb_s.s = buf;
		cb_s.len = len;
		set_extra_tmcb_params( &cb_s, &rb->dst);
		if (lock)
			run_trans_callbacks_locked( TMCB_RESPONSE_OUT, trans,
				trans->uas.request, FAKED_REPLY, code);
		else
			run_trans_callbacks( TMCB_RESPONSE_OUT, trans,
				trans->uas.request, FAKED_REPLY, code);
	}


	pkg_free( buf ) ;
	stats_trans_rpl( code, 1 /*local*/ );
	LM_DBG("finished\n");
	return 1;

error3:
error2:
	if (lock) UNLOCK_REPLIES( trans );
	pkg_free ( buf );
error:
	/* do UAC cleanup */
	cleanup_uac_timers( trans );
	if ( is_invite(trans) ) cancel_uacs( trans, cancel_bitmap );
	/* we did not succeed -- put the transaction on wait */
	put_on_wait(trans);
	return -1;
}
示例#9
0
文件: t_fwd.c 项目: rrb3942/opensips
static inline int pre_print_uac_request( struct cell *t, int branch,
					struct sip_msg *request, struct sip_msg_body **body_clone)
{
	int backup_route_type;
	struct usr_avp **backup_list;
	char *p;

	/* ... we calculate branch ... */
	if (!t_calc_branch(t, branch, request->add_to_branch_s,
			&request->add_to_branch_len ))
	{
		LM_ERR("branch computation failed\n");
		goto error;
	}

	/* from now on, flag all new lumps with LUMPFLAG_BRANCH flag in order to
	 * be able to remove them later --bogdan */
	set_init_lump_flags(LUMPFLAG_BRANCH);

	/* copy path vector into branch */
	if (request->path_vec.len) {
		t->uac[branch].path_vec.s =
			shm_realloc(t->uac[branch].path_vec.s, request->path_vec.len+1);
		if (t->uac[branch].path_vec.s==NULL) {
			LM_ERR("shm_realloc failed\n");
			goto error;
		}
		t->uac[branch].path_vec.len = request->path_vec.len;
		memcpy( t->uac[branch].path_vec.s, request->path_vec.s,
			request->path_vec.len+1);
	}

	/* do the same for the advertised port & address */
	if (request->set_global_address.len) {
		t->uac[branch].adv_address.s = shm_realloc(t->uac[branch].adv_address.s,
			request->set_global_address.len+1);
		if (t->uac[branch].adv_address.s==NULL) {
			LM_ERR("shm_realloc failed for storing the advertised address "
				"(len=%d)\n",request->set_global_address.len);
			goto error;
		}
		t->uac[branch].adv_address.len = request->set_global_address.len;
		memcpy( t->uac[branch].adv_address.s, request->set_global_address.s,
			request->set_global_address.len+1);
	}
	if (request->set_global_port.len) {
		t->uac[branch].adv_port.s = shm_realloc(t->uac[branch].adv_port.s,
			request->set_global_port.len+1);
		if (t->uac[branch].adv_port.s==NULL) {
			LM_ERR("shm_realloc failed for storing the advertised port "
				"(len=%d)\n",request->set_global_port.len);
			goto error;
		}
		t->uac[branch].adv_port.len = request->set_global_port.len;
		memcpy( t->uac[branch].adv_port.s, request->set_global_port.s,
			request->set_global_port.len+1);
	}


	/********** run route & callback ************/

	/* run branch route, if any; run it before RURI's DNS lookup
	 * to allow to be changed --bogdan */
	if (t->on_branch) {
		/* need to pkg_malloc the dst_uri */
		if ( request->dst_uri.s && request->dst_uri.len>0 ) {
			if ( (p=pkg_malloc(request->dst_uri.len))==0 ) {
				LM_ERR("no more pkg mem\n");
				ser_error=E_OUT_OF_MEM;
				goto error;
			}
			memcpy( p, request->dst_uri.s, request->dst_uri.len);
			request->dst_uri.s = p;
		}
		/* need to pkg_malloc the new_uri */
		if ( (p=pkg_malloc(request->new_uri.len))==0 ) {
			LM_ERR("no more pkg mem\n");
			ser_error=E_OUT_OF_MEM;
			goto error;
		}
		memcpy( p, request->new_uri.s, request->new_uri.len);
		request->new_uri.s = p;
		request->parsed_uri_ok = 0;
		/* make a clone of the original body, to restore it later */
		if (clone_sip_msg_body( request, NULL, body_clone, 0)!=0) {
			LM_ERR("faile to clone the body, branch route changes will be"
				" preserved\n");
		}
		/* make available the avp list from transaction */
		backup_list = set_avp_list( &t->user_avps );
		/* run branch route */
		swap_route_type( backup_route_type, BRANCH_ROUTE);

		_tm_branch_index = branch;
		if(run_top_route(sroutes->branch[t->on_branch].a,request)&ACT_FL_DROP){
			LM_DBG("dropping branch <%.*s>\n", request->new_uri.len,
					request->new_uri.s);
			_tm_branch_index = 0;
			/* restore the route type */
			set_route_type( backup_route_type );
			/* restore original avp list */
			set_avp_list( backup_list );
			goto error;
		}

		_tm_branch_index = 0;
		/* restore the route type */
		set_route_type( backup_route_type );
		/* restore original avp list */
		set_avp_list( backup_list );
	}

	/* run the specific callbacks for this transaction */
	run_trans_callbacks( TMCB_REQUEST_FWDED, t, request, 0,
			-request->REQ_METHOD);

	/* copy dst_uri into branch (after branch route possible updated it) */
	if (request->dst_uri.len) {
		t->uac[branch].duri.s =
			shm_realloc(t->uac[branch].duri.s, request->dst_uri.len);
		if (t->uac[branch].duri.s==NULL) {
			LM_ERR("shm_realloc failed\n");
			goto error;
		}
		t->uac[branch].duri.len = request->dst_uri.len;
		memcpy( t->uac[branch].duri.s,request->dst_uri.s,request->dst_uri.len);
	}

	return 0;
error:
	return -1;
}
示例#10
0
文件: t_reply.c 项目: iamroger/voip
/* this is the code which decides what and when shall be relayed
   upstream; note well -- it assumes it is entered locked with 
   REPLY_LOCK and it returns unlocked!
*/
enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch, 
	unsigned int msg_status, branch_bm_t *cancel_bitmap )
{
	int relay;
	int save_clone;
	char *buf;
	/* length of outbound reply */
	unsigned int res_len;
	int relayed_code;
	struct sip_msg *relayed_msg;
	struct bookmark bm;
	int totag_retr;
	enum rps reply_status;
	/* retransmission structure of outbound reply and request */
	struct retr_buf *uas_rb;
	str cb_s;
	str text;

	/* keep compiler warnings about use of uninit vars silent */
	res_len=0;
	buf=0;
	relayed_msg=0;
	relayed_code=0;
	totag_retr=0;


	/* remember, what was sent upstream to know whether we are
	 * forwarding a first final reply or not */

	/* *** store and relay message as needed *** */
	reply_status = t_should_relay_response(t, msg_status, branch, 
		&save_clone, &relay, cancel_bitmap, p_msg );
	LM_DBG("branch=%d, save=%d, relay=%d\n",
		branch, save_clone, relay );

	/* store the message if needed */
	if (save_clone) /* save for later use, typically branch picking */
	{
		if (!store_reply( t, branch, p_msg ))
			goto error01;
	}

	uas_rb = & t->uas.response;
	if (relay >= 0 ) {
		/* initialize sockets for outbound reply */
		uas_rb->activ_type=msg_status;

		t->relaied_reply_branch = relay;

		/* try building the outbound reply from either the current
		 * or a stored message */
		relayed_msg = branch==relay ? p_msg :  t->uac[relay].reply;
		if (relayed_msg==FAKED_REPLY) {
			relayed_code = branch==relay
				? msg_status : t->uac[relay].last_received;

			text.s = error_text(relayed_code);
			text.len = strlen(text.s); /* FIXME - bogdan*/

			if (relayed_code>=180 && t->uas.request->to 
					&& (get_to(t->uas.request)->tag_value.s==0 
					|| get_to(t->uas.request)->tag_value.len==0)) {
				calc_crc_suffix( t->uas.request, tm_tag_suffix );
				buf = build_res_buf_from_sip_req(
						relayed_code,
						&text,
						&tm_tag,
						t->uas.request, &res_len, &bm );
			} else {
				buf = build_res_buf_from_sip_req( relayed_code,
					&text, 0/* no to-tag */,
					t->uas.request, &res_len, &bm );
			}

		} else {
			/* run callbacks for all types of responses -
			 * even if they are shmem-ed or not */
			if (has_tran_tmcbs(t,TMCB_RESPONSE_FWDED) ) {
				run_trans_callbacks( TMCB_RESPONSE_FWDED, t, t->uas.request,
					relayed_msg, msg_status );
			}
			relayed_code=relayed_msg->REPLY_STATUS;
			buf = build_res_buf_from_sip_res( relayed_msg, &res_len,
							uas_rb->dst.send_sock);
			/* remove all lumps which are not in shm 
			 * added either by build_res_buf_from_sip_res, or by
			 * the callbacks that have been called with shmem-ed messages - vlad */
			if (branch!=relay) {
				del_notflaged_lumps( &(relayed_msg->add_rm), LUMPFLAG_SHMEM);
				del_notflaged_lumps( &(relayed_msg->body_lumps), LUMPFLAG_SHMEM);
			}
		}
		if (!buf) {
			LM_ERR("no mem for outbound reply buffer\n");
			goto error02;
		}

		/* attempt to copy the message to UAS's shmem:
		   - copy to-tag for ACK matching as well
		   -  allocate little a bit more for provisional as
		      larger messages are likely to follow and we will be 
		      able to reuse the memory frag 
		*/
		uas_rb->buffer.s = (char*)shm_resize( uas_rb->buffer.s, res_len +
			(msg_status<200 ?  REPLY_OVERBUFFER_LEN : 0));
		if (!uas_rb->buffer.s) {
			LM_ERR("no more share memory\n");
			goto error03;
		}
		uas_rb->buffer.len = res_len;
		memcpy( uas_rb->buffer.s, buf, res_len );
		if (relayed_msg==FAKED_REPLY) { /* to-tags for local replies */
			update_local_tags(t, &bm, uas_rb->buffer.s, buf);
		}
		stats_trans_rpl( relayed_code, (relayed_msg==FAKED_REPLY)?1:0 );

		/* update the status ... */
		t->uas.status = relayed_code;

		if (is_invite(t) && relayed_msg!=FAKED_REPLY
		&& relayed_code>=200 && relayed_code < 300
		&& has_tran_tmcbs( t,
		TMCB_RESPONSE_OUT|TMCB_RESPONSE_PRE_OUT)) {
			totag_retr=update_totag_set(t, relayed_msg);
		}
	}; /* if relay ... */

	UNLOCK_REPLIES( t );

	/* Setup retransmission timer _before_ the reply is sent
	 * to avoid race conditions
	 */
	if (reply_status == RPS_COMPLETED) {
		/* for auth related replies, we do not do retransmission 
		   (via set_final_timer()), but only wait for a final 
		   reply (put_on_wait() ) - see RFC 3261 (26.3.2.4 DoS Protection) */
		if ((relayed_code != 401) && (relayed_code != 407))
			set_final_timer(t);
		else
			put_on_wait(t);
	}

	/* send it now (from the private buffer) */
	if (relay >= 0) {
		/* run the PRE sending out callback */
		if (!totag_retr && has_tran_tmcbs(t, TMCB_RESPONSE_PRE_OUT) ) {
			cb_s.s = buf;
			cb_s.len = res_len;
			set_extra_tmcb_params( &cb_s, &uas_rb->dst);
			run_trans_callbacks_locked(TMCB_RESPONSE_PRE_OUT,t,t->uas.request,
				relayed_msg, relayed_code);
		}
		SEND_PR_BUFFER( uas_rb, buf, res_len );
		LM_DBG("sent buf=%p: %.9s..., shmem=%p: %.9s\n", 
			buf, buf, uas_rb->buffer.s, uas_rb->buffer.s );
		/* run the POST sending out callback */
		if (!totag_retr && has_tran_tmcbs(t, TMCB_RESPONSE_OUT) ) {
			cb_s.s = buf;
			cb_s.len = res_len;
			set_extra_tmcb_params( &cb_s, &uas_rb->dst);
			run_trans_callbacks_locked( TMCB_RESPONSE_OUT, t, t->uas.request,
				relayed_msg, relayed_code);
		}
		pkg_free( buf );
	}

	/* success */
	return reply_status;

error03:
	pkg_free( buf );
error02:
	if (save_clone) {
		if (t->uac[branch].reply!=FAKED_REPLY)
			sip_msg_free( t->uac[branch].reply );
		t->uac[branch].reply = NULL;
	}
error01:
	text.s = "Reply processing error";
	text.len = sizeof("Reply processing error")-1;
	t_reply_unsafe( t, t->uas.request, 500, &text );
	UNLOCK_REPLIES(t);
	if (is_invite(t)) cancel_uacs( t, *cancel_bitmap );
	/* a serious error occurred -- attempt to send an error reply;
	   it will take care of clean-ups  */

	/* failure */
	return RPS_ERROR;
}
示例#11
0
/* WARNING: doesn't work from failure route (deadlock, uses t_reply => tries
 *  to get the reply lock again */
int t_relay_to( struct sip_msg  *p_msg , struct proxy_l *proxy, int proto,
				int replicate)
{
	int ret;
	int new_tran;
	/* struct hdr_field *hdr; */
	struct cell *t;
	struct dest_info dst;
	unsigned short port;
	str host;
	short comp;
#ifndef TM_DELAYED_REPLY
	int reply_ret;
#endif

	ret=0;
	
	/* special case for CANCEL */
	if ( p_msg->REQ_METHOD==METHOD_CANCEL){
		ret=t_forward_cancel(p_msg, proxy, proto, &t);
		if (t) goto handle_ret;
		goto done;
	}
	new_tran = t_newtran( p_msg );
	
	/* parsing error, memory alloc, whatever ... if via is bad
	   and we are forced to reply there, return with 0 (->break),
	   pass error status otherwise
	   MMA: return value E_SCRIPT means that transaction was already started
	   from the script so continue with that transaction
	*/
	if (likely(new_tran!=E_SCRIPT)) {
		if (new_tran<0) {
			ret = (ser_error==E_BAD_VIA && reply_to_via) ? 0 : new_tran;
			goto done;
		}
		/* if that was a retransmission, return we are happily done */
		if (new_tran==0) {
			ret = 1;
			goto done;
		}
	}else if (unlikely(p_msg->REQ_METHOD==METHOD_ACK)) {
			/* transaction previously found (E_SCRIPT) and msg==ACK
			    => ack to neg. reply  or ack to local trans.
			    => process it and exit */
			/* FIXME: there's no way to distinguish here between acks to
			   local trans. and neg. acks */
			/* in normal operation we should never reach this point, if we
			   do WARN(), it might hide some real bug (apart from possibly
			   hiding a bug the most harm done is calling the TMCB_ACK_NEG
			   callbacks twice) */
			WARN("negative or local ACK caught, please report\n");
			t=get_t();
			if (unlikely(has_tran_tmcbs(t, TMCB_ACK_NEG_IN)))
				run_trans_callbacks(TMCB_ACK_NEG_IN, t, p_msg, 0, 
										p_msg->REQ_METHOD);
			t_release_transaction(t);
			ret=1;
			goto done;
	}

	/* new transaction */

	/* at this point if the msg is an ACK it is an e2e ACK and
	   e2e ACKs do not establish a transaction and are fwd-ed statelessly */
	if ( p_msg->REQ_METHOD==METHOD_ACK) {
		DBG( "SER: forwarding ACK  statelessly \n");
		if (proxy==0) {
			init_dest_info(&dst);
			dst.proto=proto;
			if (get_uri_send_info(GET_NEXT_HOP(p_msg), &host, &port,
									&dst.proto, &comp)!=0){
				ret=E_BAD_ADDRESS;
				goto done;
			}
#ifdef USE_COMP
			dst.comp=comp;
#endif
			/* dst->send_sock not set, but forward_request will take care
			 * of it */
			ret=forward_request(p_msg, &host, port, &dst);
		} else {
			init_dest_info(&dst);
			dst.proto=get_proto(proto, proxy->proto);
			proxy2su(&dst.to, proxy);
			/* dst->send_sock not set, but forward_request will take care
			 * of it */
			ret=forward_request( p_msg , 0, 0, &dst) ;
		}
		goto done;
	}

	/* if replication flag is set, mark the transaction as local
	   so that replies will not be relayed */
	t=get_t();
	if (replicate) t->flags|=T_IS_LOCAL_FLAG;

	/* INVITE processing might take long, particularly because of DNS
	   look-ups -- let upstream know we're working on it */
	if (p_msg->REQ_METHOD==METHOD_INVITE && (t->flags&T_AUTO_INV_100)
		&& (t->uas.status < 100)
	) {
		DBG( "SER: new INVITE\n");
		if (!t_reply( t, p_msg , 100 ,
			cfg_get(tm, tm_cfg, tm_auto_inv_100_r)))
				DBG("SER: ERROR: t_reply (100)\n");
	} 

	/* now go ahead and forward ... */
	ret=t_forward_nonack(t, p_msg, proxy, proto);
handle_ret:
	if (ret<=0) {
		DBG( "t_forward_nonack returned error %d (%d)\n", ret, ser_error);
		/* we don't want to pass upstream any reply regarding replicating
		 * a request; replicated branch must stop at us*/
		if (likely(!replicate)) {
			if(t->flags&T_DISABLE_INTERNAL_REPLY) {
				/* flag set to don't generate the internal negative reply
				 * - let the transaction live further, processing should
				 *   continue in config */
				DBG("not generating immediate reply for error %d\n", ser_error);
				tm_error=ser_error;
				ret = -4;
				goto done;
			}
#ifdef TM_DELAYED_REPLY
			/* current error in tm_error */
			tm_error=ser_error;
			set_kr(REQ_ERR_DELAYED);
			DBG("%d error reply generation delayed \n", ser_error);
#else

			reply_ret=kill_transaction( t, ser_error );
			if (reply_ret>0) {
				/* we have taken care of all -- do nothing in
			  	script */
				DBG("ERROR: generation of a stateful reply "
					"on error succeeded\n");
				/*ret=0; -- we don't want to stop the script */
			}  else {
				DBG("ERROR: generation of a stateful reply "
					"on error failed\n");
				t_release_transaction(t);
			}
#endif /* TM_DELAYED_REPLY */
		}else{
			t_release_transaction(t); /* kill it  silently */
		}
	} else {
		DBG( "SER: new transaction fwd'ed\n");
	}

done:
	return ret;
}
示例#12
0
文件: t_fwd.c 项目: rrb3942/opensips
/* function returns:
 *       1 - forward successful
 *      -1 - error during forward
 */
int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
						struct proxy_l * proxy, int reset_bcounter, int locked)
{
	str reply_reason_487 = str_init("Request Terminated");
	str backup_uri;
	str backup_dst;
	int branch_ret, lowest_ret;
	str current_uri;
	branch_bm_t  added_branches;
	int i, q;
	struct cell *t_invite;
	int success_branch;
	str dst_uri;
	struct socket_info *bk_sock;
	unsigned int br_flags, bk_bflags;
	int idx;
	str path;
	str bk_path;

	/* make -Wall happy */
	current_uri.s=0;

	/* before doing enything, update the t flags from msg */
	t->uas.request->flags = p_msg->flags;

	if (p_msg->REQ_METHOD==METHOD_CANCEL) {
		t_invite=t_lookupOriginalT(  p_msg );
		if (t_invite!=T_NULL_CELL) {
			t_invite->flags |= T_WAS_CANCELLED_FLAG;
			cancel_invite( p_msg, t, t_invite, locked );
			return 1;
		}
	}

	/* do not forward requests which were already cancelled*/
	if (no_new_branches(t)) {
		LM_INFO("discarding fwd for a 6xx transaction\n");
		ser_error = E_NO_DESTINATION;
		return -1;
	}
	if (was_cancelled(t)) {
		/* is this the first attempt of sending a branch out ? */
		if (t->nr_of_outgoings==0) {
			/* if no other signalling was performed on the transaction
			 * and the transaction was already canceled, better
			 * internally generate the 487 reply here */
			if (locked)
				t_reply_unsafe( t, p_msg , 487 , &reply_reason_487);
			else
				t_reply( t, p_msg , 487 , &reply_reason_487);
		}
		LM_INFO("discarding fwd for a cancelled transaction\n");
		ser_error = E_NO_DESTINATION;
		return -1;
	}

	/* backup current uri, sock and flags... add_uac changes it */
	backup_uri = p_msg->new_uri;
	backup_dst = p_msg->dst_uri;
	bk_sock = p_msg->force_send_socket;
	bk_path = p_msg->path_vec;
	bk_bflags = p_msg->ruri_bflags;
	/* advertised address/port are not changed */

	/* check if the UAS retranmission port needs to be updated */
	if ( (p_msg->msg_flags ^ t->uas.request->msg_flags) & FL_FORCE_RPORT )
		su_setport( &t->uas.response.dst.to, p_msg->rcv.src_port );

	/* if no more specific error code is known, use this */
	lowest_ret=E_BUG;
	/* branches added */
	added_branches=0;
	/* branch to begin with */
	if (reset_bcounter) {
		t->first_branch=t->nr_of_outgoings;
		/* check if the previous branch is a PHONY one and if yes
		 * keep it in the set of active branches; that means the 
		 * transaction had a t_wait_for_new_branches() call prior to relay() */
		if ( t->first_branch>0 &&
		(t->uac[t->first_branch-1].flags & T_UAC_IS_PHONY) )
			t->first_branch--;
	}

	/* as first branch, use current uri */
	current_uri = *GET_RURI(p_msg);
	branch_ret = add_uac( t, p_msg, &current_uri, &backup_dst,
		getb0flags(p_msg), &p_msg->path_vec, proxy);
	if (branch_ret>=0)
		added_branches |= 1<<branch_ret;
	else
		lowest_ret=branch_ret;

	/* ....and now add the remaining additional branches */
	for( idx=0; (current_uri.s=get_branch( idx, &current_uri.len, &q,
	&dst_uri, &path, &br_flags, &p_msg->force_send_socket))!=0 ; idx++ ) {
		branch_ret = add_uac( t, p_msg, &current_uri, &dst_uri,
			br_flags, &path, proxy);
		/* pick some of the errors in case things go wrong;
		   note that picking lowest error is just as good as
		   any other algorithm which picks any other negative
		   branch result */
		if (branch_ret>=0)
			added_branches |= 1<<branch_ret;
		else
			lowest_ret=branch_ret;
	}
	/* consume processed branches */
	clear_branches();

	/* restore original stuff */
	p_msg->new_uri=backup_uri;
	p_msg->parsed_uri_ok = 0;/* just to be sure; add_uac may parse other uris*/
	p_msg->dst_uri = backup_dst;
	p_msg->force_send_socket = bk_sock;
	p_msg->path_vec = bk_path;
	p_msg->ruri_bflags = bk_bflags;

	/* update on_branch, _only_ if modified, otherwise it overwrites
	 * whatever it is already in the transaction */
	if (get_on_branch())
		t->on_branch = get_on_branch();

	/* update flags, if changed in branch route */
	t->uas.request->flags = p_msg->flags;

	/* things went wrong ... no new branch has been fwd-ed at all */
	if (added_branches==0) {
		LM_ERR("failure to add branches\n");
		ser_error = lowest_ret;
		return lowest_ret;
	}

	/* send them out now */
	success_branch=0;
	for (i=t->first_branch; i<t->nr_of_outgoings; i++) {
		if (added_branches & (1<<i)) {

			if (t->uac[i].br_flags & tcp_no_new_conn_bflag)
				tcp_no_new_conn = 1;

			do {
				if (check_blacklists( t->uac[i].request.dst.proto,
				&t->uac[i].request.dst.to,
				t->uac[i].request.buffer.s,
				t->uac[i].request.buffer.len)) {
					LM_DBG("blocked by blacklists\n");
					ser_error=E_IP_BLOCKED;
				} else {
					run_trans_callbacks(TMCB_PRE_SEND_BUFFER, t, p_msg, 0, i);

					if (SEND_BUFFER( &t->uac[i].request)==0) {
						ser_error = 0;
						break;
					}

					LM_ERR("sending request failed\n");
					ser_error=E_SEND;
				}
				/* get next dns entry */
				if ( t->uac[i].proxy==0 ||
				get_next_su( t->uac[i].proxy, &t->uac[i].request.dst.to,
				(ser_error==E_IP_BLOCKED)?0:1)!=0 )
					break;
				t->uac[i].request.dst.proto = t->uac[i].proxy->proto;
				/* update branch */
				if ( update_uac_dst( p_msg, &t->uac[i] )!=0)
					break;
			}while(1);

			tcp_no_new_conn = 0;

			if (ser_error) {
				shm_free(t->uac[i].request.buffer.s);
				t->uac[i].request.buffer.s = NULL;
				t->uac[i].request.buffer.len = 0;
				continue;
			}

			success_branch++;

			start_retr( &t->uac[i].request );
			set_kr(REQ_FWDED);

			/* successfully sent out -> run callbacks */
			if ( has_tran_tmcbs( t, TMCB_REQUEST_BUILT|TMCB_MSG_SENT_OUT) ) {
				set_extra_tmcb_params( &t->uac[i].request.buffer,
					&t->uac[i].request.dst);
				run_trans_callbacks( TMCB_REQUEST_BUILT|TMCB_MSG_SENT_OUT, t,
					p_msg, 0, 0);
			}

		}
	}

	return (success_branch>0)?1:-1;
}
示例#13
0
static inline int pre_print_uac_request( struct cell *t, int branch, 
		struct sip_msg *request)
{
	int backup_route_type;
	struct usr_avp **backup_list;
	char *p;

	/* ... we calculate branch ... */
	if (!t_calc_branch(t, branch, request->add_to_branch_s,
			&request->add_to_branch_len ))
	{
		LOG(L_ERR, "ERROR:pre_print_uac_request: branch computation failed\n");
		goto error;
	}

	/* from now on, flag all new lumps with LUMPFLAG_BRANCH flag in order to
	 * be able to remove them later --bogdan */
	set_init_lump_flags(LUMPFLAG_BRANCH);

	/********** run route & callback ************/

	/* run branch route, if any; run it before RURI's DNS lookup 
	 * to allow to be changed --bogdan */
	if (t->on_branch) {
		/* need to pkg_malloc the dst_uri */
		if ( request->dst_uri.len ) {
			if ( (p=pkg_malloc(request->dst_uri.len))==0 ) {
				LOG(L_ERR,"ERROR:tm:pre_print_uac_request: no more pkg mem\n");
				ser_error=E_OUT_OF_MEM;
				goto error;
			}
			memcpy( p, request->dst_uri.s, request->dst_uri.len);
			request->dst_uri.s = p;
		}
		/* need to pkg_malloc the new_uri */
		if ( (p=pkg_malloc(request->new_uri.len))==0 ) {
			LOG(L_ERR,"ERROR:tm:pre_print_uac_request: no more pkg mem\n");
			ser_error=E_OUT_OF_MEM;
			goto error;
		}
		memcpy( p, request->new_uri.s, request->new_uri.len);
		request->new_uri.s = p;
		/* make available the avp list from transaction */
		backup_list = set_avp_list( &t->user_avps );
		/* run branch route */
		swap_route_type( backup_route_type, BRANCH_ROUTE);
		if (run_actions(branch_rlist[t->on_branch], request)==0 &&
		(action_flags&ACT_FL_DROP) ) {
			DBG("DEBUG:tm:pre_print_uac_request: dropping branch <%.*s>\n",
				request->dst_uri.len, request->dst_uri.s);
			goto error;
		}
		set_route_type( backup_route_type );
		/* restore original avp list */
		set_avp_list( backup_list );
	}

	/* run the specific callbacks for this transaction */
	run_trans_callbacks( TMCB_REQUEST_FWDED, t, request, 0,
			-request->REQ_METHOD);

	return 0;
error:
	return -1;
}
示例#14
0
/* function returns:
 *       1 - forward successful
 *      -1 - error during forward
 */
int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
	struct proxy_l * proxy)
{
	str backup_uri;
	str backup_dst;
	int branch_ret, lowest_ret;
	str current_uri;
	branch_bm_t  added_branches;
	int i, q;
	struct cell *t_invite;
	int success_branch;
	str dst_uri;
	struct socket_info *bk_sock;
	unsigned int br_flags;
	unsigned int bk_br_flags;
	int idx;
	str path;
	str bk_path;

	/* make -Wall happy */
	current_uri.s=0;

	/* before doing enything, update the t falgs from msg */
	t->uas.request->flags = p_msg->flags;

	if (p_msg->REQ_METHOD==METHOD_CANCEL) {
		t_invite=t_lookupOriginalT(  p_msg );
		if (t_invite!=T_NULL_CELL) {
			t_invite->flags |= T_WAS_CANCELLED_FLAG;
			cancel_invite( p_msg, t, t_invite );
			return 1;
		}
	}

	/* do not forward requests which were already cancelled*/
	if (was_cancelled(t) || no_new_branches(t)) {
		LM_ERR("discarding fwd for a cancelled/6xx transaction\n");
		ser_error = E_NO_DESTINATION;
		return -1;
	}

	/* backup current uri, sock and flags... add_uac changes it */
	backup_uri = p_msg->new_uri;
	backup_dst = p_msg->dst_uri;
	bk_sock = p_msg->force_send_socket;
	bk_br_flags = getb0flags();
	bk_path = p_msg->path_vec;

	/* check if the UAS retranmission port needs to be updated */
	if ( (p_msg->msg_flags ^ t->uas.request->msg_flags) & FL_FORCE_RPORT )
		su_setport( &t->uas.response.dst.to, p_msg->rcv.src_port );

	/* if no more specific error code is known, use this */
	lowest_ret=E_BUG;
	/* branches added */
	added_branches=0;
	/* branch to begin with */
	t->first_branch=t->nr_of_outgoings;

	/* as first branch, use current uri */
	current_uri = *GET_RURI(p_msg);
	branch_ret = add_uac( t, p_msg, &current_uri, &backup_dst,
		&p_msg->path_vec, proxy);
	if (branch_ret>=0)
		added_branches |= 1<<branch_ret;
	else
		lowest_ret=branch_ret;

	/* ....and now add the remaining additional branches */
	for( idx=0; (current_uri.s=get_branch( idx, &current_uri.len, &q,
	&dst_uri, &path, &br_flags, &p_msg->force_send_socket))!=0 ; idx++ ) {
		setb0flags(br_flags);
		branch_ret = add_uac( t, p_msg, &current_uri, &dst_uri, &path, proxy);
		/* pick some of the errors in case things go wrong;
		   note that picking lowest error is just as good as
		   any other algorithm which picks any other negative
		   branch result */
		if (branch_ret>=0)
			added_branches |= 1<<branch_ret;
		else
			lowest_ret=branch_ret;
	}
	/* consume processed branches */
	clear_branches();

	/* restore original stuff */
	p_msg->new_uri=backup_uri;
	p_msg->parsed_uri_ok = 0;/* just to be sure; add_uac may parse other uris*/
	p_msg->dst_uri = backup_dst;
	p_msg->force_send_socket = bk_sock;
	p_msg->path_vec = bk_path;
	setb0flags(bk_br_flags);
	/* update on_branch, if modified */
	t->on_branch = get_on_branch();
	/* update flags, if changed in branch route */
	t->uas.request->flags = p_msg->flags;

	/* things went wrong ... no new branch has been fwd-ed at all */
	if (added_branches==0) {
		LM_ERR("failure to add branches\n");
		ser_error = lowest_ret;
		return lowest_ret;
	}

	/* send them out now */
	success_branch=0;
	for (i=t->first_branch; i<t->nr_of_outgoings; i++) {
		if (added_branches & (1<<i)) {

#ifdef USE_TCP
			if (t->uac[i].br_flags & tcp_no_new_conn_bflag)
				tcp_no_new_conn = 1;
#endif

			do {
				if (check_blacklists( t->uac[i].request.dst.proto,
				&t->uac[i].request.dst.to,
				t->uac[i].request.buffer.s,
				t->uac[i].request.buffer.len)) {
					LM_DBG("blocked by blacklists\n");
					ser_error=E_IP_BLOCKED;
				} else {
					if (SEND_BUFFER( &t->uac[i].request)==0) {
						ser_error = 0;
						break;
					}
					LM_ERR("sending request failed\n");
					ser_error=E_SEND;
				}
				/* get next dns entry */
				if ( t->uac[i].proxy==0 ||
				get_next_su( t->uac[i].proxy, &t->uac[i].request.dst.to,
				(ser_error==E_IP_BLOCKED)?0:1)!=0 )
					break;
				t->uac[i].request.dst.proto = t->uac[i].proxy->proto;
				/* update branch */
				if ( update_uac_dst( p_msg, &t->uac[i] )!=0)
					break;
			}while(1);

#ifdef USE_TCP
			tcp_no_new_conn = 0;
#endif

			if (ser_error) {
				shm_free(t->uac[i].request.buffer.s);
				t->uac[i].request.buffer.s = NULL;
				t->uac[i].request.buffer.len = 0;
				continue;
			}

			success_branch++;

			start_retr( &t->uac[i].request );
			set_kr(REQ_FWDED);

			/* successfully sent out -> run callbacks */
			if ( has_tran_tmcbs( t, TMCB_REQUEST_BUILT) ) {
				set_extra_tmcb_params( &t->uac[i].request.buffer,
					&t->uac[i].request.dst);
				run_trans_callbacks( TMCB_REQUEST_BUILT, t, p_msg,0,
					-p_msg->REQ_METHOD);
			}

		}
	}

	return (success_branch>0)?1:-1;
}
示例#15
0
/* 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;
}
示例#16
0
/* Returns 0 - nothing found
 *         1  - T found
 */
int t_reply_matching( struct sip_msg *p_msg , int *p_branch )
{
	struct cell*  p_cell;
	unsigned int hash_index   = 0;
	unsigned int entry_label  = 0;
	unsigned int branch_id    = 0;
	char  *hashi, *branchi, *p, *n;
	int hashl, branchl;
	int scan_space;
	str cseq_method;
	str req_method;

	char *loopi;
	int loopl;
	char *syni;
	int synl;
	
	short is_cancel;

	/* make compiler warnings happy */
	loopi=0;
	loopl=0;
	syni=0;
	synl=0;

	/* split the branch into pieces: loop_detection_check(ignored),
	 hash_table_id, synonym_id, branch_id */

	if (!(p_msg->via1 && p_msg->via1->branch && p_msg->via1->branch->value.s))
		goto nomatch2;

	/* we do RFC 3261 tid matching and want to see first if there is
	 * magic cookie in branch */
	if (p_msg->via1->branch->value.len<=MCOOKIE_LEN)
		goto nomatch2;
	if (memcmp(p_msg->via1->branch->value.s, MCOOKIE, MCOOKIE_LEN)!=0)
		goto nomatch2;

	p=p_msg->via1->branch->value.s+MCOOKIE_LEN;
	scan_space=p_msg->via1->branch->value.len-MCOOKIE_LEN;


	/* hash_id */
	n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR);
	hashl=n-p;
	scan_space-=hashl;
	if (!hashl || scan_space<2 || *n!=BRANCH_SEPARATOR) goto nomatch2;
	hashi=p;
	p=n+1;scan_space--;

	if (!syn_branch) {
		/* md5 value */
		n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR );
		loopl = n-p;
		scan_space-= loopl;
		if (n==p || scan_space<2 || *n!=BRANCH_SEPARATOR) 
			goto nomatch2;
		loopi=p;
		p=n+1; scan_space--;
	} else {
		/* synonym id */
		n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR);
		synl=n-p;
		scan_space-=synl;
		if (!synl || scan_space<2 || *n!=BRANCH_SEPARATOR) 
			goto nomatch2;
		syni=p;
		p=n+1;scan_space--;
	}

	/* branch id  -  should exceed the scan_space */
	n=eat_token_end( p, p+scan_space );
	branchl=n-p;
	if (!branchl ) goto nomatch2;
	branchi=p;

	/* sanity check */
	if (reverse_hex2int(hashi, hashl, &hash_index)<0
		||hash_index>=TABLE_ENTRIES
		|| reverse_hex2int(branchi, branchl, &branch_id)<0
		||branch_id>=MAX_BRANCHES
		|| (syn_branch ? (reverse_hex2int(syni, synl, &entry_label))<0 
			: loopl!=MD5_LEN )
	) {
		DBG("DEBUG: t_reply_matching: poor reply labels %d label %d "
			"branch %d\n", hash_index, entry_label, branch_id );
		goto nomatch2;
	}


	DBG("DEBUG: t_reply_matching: hash %d label %d branch %d\n",
		hash_index, entry_label, branch_id );


	/* search the hash table list at entry 'hash_index'; lock the
	   entry first 
	*/
	cseq_method=get_cseq(p_msg)->method;
	is_cancel=cseq_method.len==CANCEL_LEN 
		&& memcmp(cseq_method.s, CANCEL, CANCEL_LEN)==0;
	LOCK_HASH(hash_index);
	for (p_cell = get_tm_table()->entrys[hash_index].first_cell; p_cell; 
		p_cell=p_cell->next_cell) {

		/* first look if branch matches */

		if (syn_branch) {
			if (p_cell->label != entry_label) 
				continue;
		} else {
			if ( memcmp(p_cell->md5, loopi,MD5_LEN)!=0)
					continue;
		}

		/* sanity check ... too high branch ? */
		if ( branch_id>=p_cell->nr_of_outgoings )
			continue;

		/* does method match ? (remember -- CANCELs have the same branch
		   as canceled transactions) */
		req_method=p_cell->method;
		if ( /* method match */
			! ((cseq_method.len==req_method.len 
			&& memcmp( cseq_method.s, req_method.s, cseq_method.len )==0)
			/* or it is a local cancel */
			|| (is_cancel && is_invite(p_cell)
				/* commented out -- should_cancel_branch set it to
				   BUSY_BUFFER to avoid collisions with replies;
				   thus, we test here by buffer size
				*/
				/* && p_cell->uac[branch_id].local_cancel.buffer ))) */
				&& p_cell->uac[branch_id].local_cancel.buffer_len ))) 
			continue;


		/* we passed all disqualifying factors .... the transaction has been
		   matched !
		*/
		set_t(p_cell);
		*p_branch =(int) branch_id;
		REF_UNSAFE( T );
		UNLOCK_HASH(hash_index);
		DBG("DEBUG: t_reply_matching: reply matched (T=%p)!\n",T);
		/* if this is a 200 for INVITE, we will wish to store to-tags to be
		 * able to distinguish retransmissions later and not to call
 		 * TMCB_RESPONSE_OUT uselessly; we do it only if callbacks are
		 * enabled -- except callback customers, nobody cares about 
		 * retransmissions of multiple 200/INV or ACK/200s
		 */
		if (is_invite(p_cell) && p_msg->REPLY_STATUS>=200 
		&& p_msg->REPLY_STATUS<300 
		&& ( (!is_local(p_cell) &&
				has_tran_tmcbs(p_cell,TMCB_RESPONSE_OUT|TMCB_E2EACK_IN) )
			|| (is_local(p_cell)&&has_tran_tmcbs(p_cell,TMCB_LOCAL_COMPLETED))
		)) {
			if (parse_headers(p_msg, HDR_TO_F, 0)==-1) {
				LOG(L_ERR, "ERROR: t_reply_matching: to parsing failed\n");
			}
		}
		if (!is_local(p_cell)) {
			run_trans_callbacks( TMCB_RESPONSE_IN, T, T->uas.request, p_msg,
				p_msg->REPLY_STATUS);
		}
		return 1;
	} /* for cycle */

	/* nothing found */
	UNLOCK_HASH(hash_index);
	DBG("DEBUG: t_reply_matching: no matching transaction exists\n");

nomatch2:
	DBG("DEBUG: t_reply_matching: failure to match a transaction\n");
	*p_branch = -1;
	set_t(0);
	return -1;
}
示例#17
0
/* 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 lret, my_err;
	int canceled;


	/* is T still up-to-date ? */
	DBG("DEBUG: t_newtran: msg id=%d , global msg id=%d ,"
		" T on entrance=%p\n",p_msg->id,global_msg_id,T);

	if ( T && T!=T_UNDEFINED  ) {
		/* ERROR message moved to w_t_newtran */
		DBG("DEBUG: t_newtran: "
			"transaction already in process %p\n", T );
		return E_SCRIPT;
	}

	global_msg_id = p_msg->id;
	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 )) {
		LOG(L_ERR, "ERROR: t_newtran: parse_headers failed\n");
		return E_BAD_REQ;
	}
	if ((p_msg->parsed_flag & HDR_EOH_F)!=HDR_EOH_F) {
			LOG(L_ERR, "ERROR: t_newtran: 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 */,
								&canceled );

	/* 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 */
		/* no callbacks? complete quickly */
		if ( !has_tran_tmcbs(t_ack,TMCB_E2EACK_IN) ) {
			UNLOCK_HASH(p_msg->hash_index);
			return 1;
		} 
		REF_UNSAFE(t_ack);
		UNLOCK_HASH(p_msg->hash_index);
		/* we don't call from within REPLY_LOCK -- that introduces
		 * a race condition; however, it is so unlikely and the
		 * impact is so small (callback called multiple times of
		 * multiple ACK/200s received in parallel), that we do not
		 * better waste time in locks  */
		if (unmatched_totag(t_ack, p_msg)) {
			run_trans_callbacks( TMCB_E2EACK_IN , t_ack, p_msg, 0,
				-p_msg->REQ_METHOD );
		}
		UNREF(t_ack);
		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 */
		my_err=1;
		goto new_err;
	}

	my_err=new_t(p_msg);
	if (my_err<0) {
		LOG(L_ERR, "ERROR: t_newtran: new_t failed\n");
		goto new_err;
	}
	if (canceled) T->flags|=T_CANCELED; /* mark it for future ref. */


	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)) {
		LOG(L_ERR, "ERROR: t_newtran: unresolvable via1\n");
		put_on_wait( T );
		t_unref(p_msg);
		return E_BAD_VIA;
	}

	return 1;


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

}