t_reply.c

来自「性能优秀的SIP Proxy」· C语言 代码 · 共 1,744 行 · 第 1/4 页

C
1,744
字号
void set_final_timer( /* struct s_table *h_table, */ struct cell *t ){	if ( !is_local(t) && t->uas.request->REQ_METHOD==METHOD_INVITE ) {		/* crank timers for negative replies */		if (t->uas.status>=300) {			start_retr(&t->uas.response);			return;		}		/* local UAS retransmits too */		if (t->relaied_reply_branch==-2 && t->uas.status>=200) {			/* we retransmit 200/INVs regardless of transport --			   even if TCP used, UDP could be used upstream and			   loose the 200, which is not retransmitted by proxies			*/			force_retr( &t->uas.response );			return;		}	} 	put_on_wait(t);}void cleanup_uac_timers( struct cell *t ){	int i;	/* reset FR/retransmission timers */	for (i=t->first_branch; i<t->nr_of_outgoings; i++ )  {		reset_timer( &t->uac[i].request.retr_timer );		reset_timer( &t->uac[i].request.fr_timer );	}	DBG("DEBUG: cleanup_uac_timers: RETR/FR timers reset\n");}static int store_reply( struct cell *trans, int branch, struct sip_msg *rpl){#		ifdef EXTRA_DEBUG		if (trans->uac[branch].reply) {			LOG(L_ERR, "ERROR: replacing stored reply; aborting\n");			abort();		}#		endif		/* when we later do things such as challenge aggregation,	   	   we should parse the message here before we conserve		   it in shared memory; -jiri		*/		if (rpl==FAKED_REPLY)			trans->uac[branch].reply=FAKED_REPLY;		else			trans->uac[branch].reply = sip_msg_cloner( rpl, 0 );		if (! trans->uac[branch].reply ) {			LOG(L_ERR, "ERROR: store_reply: can't alloc' clone memory\n");			return 0;		}		return 1;}/* 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;	/* 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 );	DBG("DEBUG:tm:relay_reply: 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;		/* only messages known to be relayed immediately will be		 * be called on; we do not evoke this callback on messages		 * stored in shmem -- they are fixed and one cannot change them		 * anyway */		if (msg_status<300 && branch==relay		&& has_tran_tmcbs(t,TMCB_RESPONSE_FWDED) ) {			run_trans_callbacks( TMCB_RESPONSE_FWDED, t, t->uas.request,				p_msg, msg_status );		}		/* 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;			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,						error_text(relayed_code),						&tm_tag,						t->uas.request, &res_len, &bm );			} else {				buf = build_res_buf_from_sip_req( relayed_code,					error_text(relayed_code), 0/* no to-tag */,					t->uas.request, &res_len, &bm );			}		} else {			relayed_code=relayed_msg->REPLY_STATUS;			buf = build_res_buf_from_sip_res( relayed_msg, &res_len );			/* if we build a message from shmem, we need to remove			   via delete lumps which are now stirred in the shmem-ed			   structure			*/			if (branch!=relay) {				free_via_clen_lump(&relayed_msg->add_rm);			}		}		if (!buf) {			LOG(L_ERR, "ERROR:tm:relay_reply: "				"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) {			LOG(L_ERR, "ERROR:tm:relay_reply: cannot alloc reply shmem\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;		t->relaied_reply_branch = relay;		if (is_invite(t) && relayed_msg!=FAKED_REPLY		&& relayed_code>=200 && relayed_code < 300		&& has_tran_tmcbs( t, TMCB_RESPONSE_OUT|TMCB_E2EACK_IN) ) {			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) {		set_final_timer(t);	}	/* send it now (from the private buffer) */	if (relay >= 0) {		SEND_PR_BUFFER( uas_rb, buf, res_len );		DBG("DEBUG:tm:relay_reply: sent buf=%p: %.9s..., shmem=%p: %.9s\n", 			buf, buf, uas_rb->buffer.s, uas_rb->buffer.s );		if (!totag_retr && has_tran_tmcbs(t, TMCB_RESPONSE_OUT) ) {			set_extra_tmcb_params( &uas_rb->buffer, &uas_rb->dst);			run_trans_callbacks( 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:	t_reply_unsafe( t, t->uas.request, 500, "Reply processing error" );	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;}/* 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 );	DBG("DEBUG:tm:local_reply: 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_E2EACK_IN) )  {			totag_retr=update_totag_set(t, winning_msg);		}	}	UNLOCK_REPLIES(t);	if ( local_winner >= 0 ) {		if (winning_code < 200) {			if ( pass_provisional_replies ) {				if (!totag_retr && has_tran_tmcbs(t,TMCB_LOCAL_RESPONSE_OUT)) {					DBG("DEBUG: Passing provisional reply %d to FIFO "						"application\n", winning_code);					run_trans_callbacks( TMCB_LOCAL_RESPONSE_OUT, t, 0,						winning_msg, winning_code);				}			}		} else {			DBG("DEBUG:tm:local_reply: 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;}/*  This function is called whenever a reply for our module is received;   * we need to register  this function on module initialization;  *  Returns :   0 - core router stops  *              1 - core router relay statelessly  */int reply_received( struct sip_msg  *p_msg ){	int msg_status;	int last_uac_status;	int branch;	int reply_status;	unsigned int timer;	/* has the transaction completed now and we need to clean-up? */	branch_bm_t cancel_bitmap;	struct ua_client *uac;	struct cell *t;	struct usr_avp **backup_list;	/* make sure we know the associated transaction ... */	if (t_check(p_msg, &branch ) == -1) return 1;		/*... if there is none, tell the core router to fwd statelessly */	t = get_t();	if ((t == 0) || (t == T_UNDEFINED)) return 1;	cancel_bitmap=0;	msg_status=p_msg->REPLY_STATUS;	uac=&t->uac[branch];	DBG("DEBUG:tm:reply_received: org. status uas=%d, "		"uac[%d]=%d local=%d is_invite=%d)\n",		t->uas.status, branch, uac->last_received, 		is_local(t), is_invite(t));	last_uac_status=uac->last_received;	if_update_stat( tm_enable_stats, tm_rcv_rpls , 1);	/* it's a cancel which is not e2e ? */	if ( get_cseq(p_msg)->method_id==METHOD_CANCEL && is_invite(t) ) {		/* ... then just stop timers */		reset_timer( &uac->local_cancel.retr_timer);		if ( msg_status >= 200 ) {				reset_timer( &uac->local_cancel.fr_timer);		}		DBG("DEBUG:tm:reply_received: reply to local CANCEL processed\n");		goto done;	}	/* *** stop timers *** */	/* stop retransmission */	reset_timer(&uac->request.retr_timer);		/* stop final response timer only if I got a final response */	if ( msg_status >= 200 ) {		reset_timer( &uac->request.fr_timer);	}	/* acknowledge negative INVITE replies (do it before detailed	 * on_reply processing, which may take very long, like if it	 * is attempted to establish a TCP connection to a fail-over dst */	if (is_invite(t) &&	((msg_status >= 300) || (is_local(t) && msg_status >= 200) )) {		if (send_ack(p_msg, t, branch)!=0)			LOG(L_ERR, "ERROR:tm:reply_received: failed to send ACK (local=%s)\n",				is_local(t)?"yes":"no");	}	/* processing of on_reply block */	if (t->on_reply) {		/* transfer transaction flag to branch context */		p_msg->flags = ((p_msg->flags | t->uas.request->flags) & gflags_mask) |			t->uac[branch].br_flags;		/* set the as avp_list the one from transaction */		backup_list = set_avp_list(&t->user_avps);		/* run block */		if ( (run_top_route(onreply_rlist[t->on_reply], p_msg)&ACT_FL_DROP) &&		(msg_status<200) ) {			DBG("DEBUG:tm:reply_received: dropping provisional reply %d\n",				msg_status);			goto done;		}		/* transfer current message context back to t */		t->uac[branch].br_flags = p_msg->flags & (~gflags_mask);		t->uas.request->flags = p_msg->flags & gflags_mask;		/* restore original avp list */		set_avp_list( backup_list );	}	/* lock the reply*/	LOCK_REPLIES( t );	/* mark that the UAC received replies */	uac->flags |= T_UAC_HAS_RECV_REPLY;	if (t->uac[branch].flags&T_UAC_TO_CANCEL_FLAG) {		/* reply for an UAC with a pending cancel -> do cancel now */		cancel_branch(t, branch);		/* reset flag */		t->uac[branch].flags &= ~(T_UAC_TO_CANCEL_FLAG);	}	if (is_local(t)) {		reply_status = local_reply(t,p_msg, branch,msg_status,&cancel_bitmap);		if (reply_status == RPS_COMPLETED) {			cleanup_uac_timers(t);			if (is_invite(t)) cancel_uacs(t, cancel_bitmap);			/* There is no need to call set_final_timer because we know			 * that the transaction is local */			put_on_wait(t);		}	} else {		reply_status = relay_reply(t,p_msg,branch,msg_status,&cancel_bitmap);		/* clean-up the transaction when transaction completed */		if (reply_status == RPS_COMPLETED) {			/* no more UAC FR/RETR (if I received a 2xx, there may			 * be still pending branches ...			 */			cleanup_uac_timers(t);			if (is_invite(t)) cancel_uacs(t, cancel_bitmap);			/* FR for negative INVITES, WAIT anything else */			/* set_final_timer(t); */		}	}		if (reply_status == RPS_ERROR)		goto done;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?