t_reply.c

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

C
1,744
字号
/* * $Id: t_reply.c,v 1.28 2006/06/27 14:58:33 bogdan_iancu Exp $ * * Copyright (C) 2001-2003 FhG Fokus * * This file is part of openser, a free SIP server. * * openser is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * openser is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License  * along with this program; if not, write to the Free Software  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * * History: * -------- *  2003-01-19  faked lump list created in on_reply handlers *  2003-01-27  next baby-step to removing ZT - PRESERVE_ZT (jiri) *  2003-02-13  updated to use rb->dst (andrei) *  2003-02-18  replaced TOTAG_LEN w/ TOTAG_VALUE_LEN (TOTAG_LEN was defined *               twice with different values!)  (andrei) *  2003-02-28  scratchpad compatibility abandoned (jiri) *  2003-03-01  kr set through a function now (jiri) *  2003-03-06  saving of to-tags for ACK/200 matching introduced,  *              voicemail changes accepted, updated to new callback *              names (jiri) *  2003-03-10  fixed new to tag bug/typo (if w/o {})  (andrei) *  2003-03-16  removed _TOTAG (jiri) *  2003-03-31  200 for INVITE/UAS resent even for UDP (jiri) *  2003-03-31  removed msg->repl_add_rm (andrei) *  2003-04-05  s/reply_route/failure_route, onreply_route introduced (jiri) *  2003-04-14  local acks generated before reply processing to avoid *              delays in length reply processing (like opening TCP *              connection to an unavailable destination) (jiri) *  2003-09-11  updates to new build_res_buf_from_sip_req() interface (bogdan) *  2003-09-11  t_reply_with_body() reshaped to use reply_lumps + *              build_res_buf_from_sip_req() instead of *              build_res_buf_with_body_from_sip_req() (bogdan) *  2003-11-05  flag context updated from failure/reply handlers back *              to transaction context (jiri) *  2003-11-11: build_lump_rpl() removed, add_lump_rpl() has flags (bogdan) *  2003-12-04  global TM callbacks switched to per transaction callbacks *              (bogdan) *  2004-02-06: support for user pref. added - destroy_avps (bogdan) *  2003-11-05  flag context updated from failure/reply handlers back *              to transaction context (jiri) *  2003-11-11: build_lump_rpl() removed, add_lump_rpl() has flags (bogdan) *  2004-02-13: t->is_invite and t->local replaced with flags (bogdan) *  2004-02-18  fifo_t_reply imported from vm module (bogdan) *  2004-08-23  avp list is available from failure/on_reply routes (bogdan) *  2004-10-01  added a new param.: restart_fr_on_each_reply (andrei) *  2005-03-01  force for statefull replies the incoming interface of  *              the request (bogdan) *  2005-03-01  local ACK sent to same address as INVITE -> *              all [build|send]_[local]_ack functions merged into  *              send_ack() (bogdan) */#include "../../hash_func.h"#include "../../dprint.h"#include "../../config.h"#include "../../parser/parser_f.h"#include "../../ut.h"#include "../../timer.h"#include "../../error.h"#include "../../action.h"#include "../../dset.h"#include "../../tags.h"#include "../../data_lump.h"#include "../../data_lump_rpl.h"#include "../../usr_avp.h"#include "../../fifo_server.h"#include "../../unixsock_server.h"#include "h_table.h"#include "t_hooks.h"#include "t_funcs.h"#include "t_reply.h"#include "t_cancel.h"#include "t_msgbuilder.h"#include "t_lookup.h"#include "t_fwd.h"#include "fix_lumps.h"#include "t_stats.h"#include "uac.h"/* restart fr timer on each provisional reply, default yes */int restart_fr_on_each_reply=1;/* private place where we create to-tags for replies */char tm_tags[TOTAG_VALUE_LEN];static str  tm_tag = {tm_tags,TOTAG_VALUE_LEN};char *tm_tag_suffix;static int picked_branch=-1;/* where to go if there is no positive reply */static int goto_on_negative=0;/* where to go on receipt of reply */static int goto_on_reply=0;/* returns the picked branch */int t_get_picked_branch(){	return picked_branch;}/* we store the reply_route # in private memory which is   then processed during t_relay; we cannot set this value   before t_relay creates transaction context or after   t_relay when a reply may arrive after we set this   value; that's why we do it how we do it, i.e.,   *inside*  t_relay using hints stored in private memory   before t_relay is called*/void t_on_negative( unsigned int go_to ){	struct cell *t = get_t();	/* in MODE_REPLY and MODE_ONFAILURE T will be set to current transaction;	 * in MODE_REQUEST T will be set only if the transaction was already 	 * created; if not -> use the static variable */	if (!t || t==T_UNDEFINED )		goto_on_negative=go_to;	else		t->on_negative = go_to;}void t_on_reply( unsigned int go_to ){	struct cell *t = get_t();	/* in MODE_REPLY and MODE_ONFAILURE T will be set to current transaction;	 * in MODE_REQUEST T will be set only if the transaction was already 	 * created; if not -> use the static variable */	if (!t || t==T_UNDEFINED )		goto_on_reply=go_to;	else		t->on_reply = go_to;}unsigned int get_on_negative(){	return goto_on_negative;}unsigned int get_on_reply(){	return goto_on_reply;}void tm_init_tags(){	init_tags(tm_tags, &tm_tag_suffix, 		"OpenSER-TM/tags", TM_TAG_SEPARATOR );}/* returns 0 if the message was previously acknowledged * (i.e., no E2EACK callback is needed) and one if the * callback shall be executed */int unmatched_totag(struct cell *t, struct sip_msg *ack){	struct totag_elem *i;	str *tag;	if (parse_headers(ack, HDR_TO_F,0)==-1 || 				!ack->to ) {		LOG(L_ERR, "ERROR: unmatched_totag: To invalid\n");		return 1;	}	tag=&get_to(ack)->tag_value;	for (i=t->fwded_totags; i; i=i->next) {		if (i->tag.len==tag->len				&& memcmp(i->tag.s, tag->s, tag->len)==0) {			DBG("DEBUG: totag for e2e ACK found: %d\n", i->acked);			/* to-tag recorded, and an ACK has been received for it */			if (i->acked) return 0;			/* to-tag recorded, but this ACK came for the first time */			i->acked=1;			return 1;		}	}	/* surprising: to-tag never sighted before */	return 1;}static inline void update_local_tags(struct cell *trans, 				struct bookmark *bm, char *dst_buffer,				char *src_buffer /* to which bm refers */){	if (bm->to_tag_val.s) {		trans->uas.local_totag.s=bm->to_tag_val.s-src_buffer+dst_buffer;		trans->uas.local_totag.len=bm->to_tag_val.len;	}}/* append a newly received tag from a 200/INVITE to  * transaction's set; (only safe if called from within * a REPLY_LOCK); it returns 1 if such a to tag already * exists */inline static int update_totag_set(struct cell *t, struct sip_msg *ok){	struct totag_elem *i, *n;	str *tag;	char *s;	if (!ok->to || !ok->to->parsed) {		LOG(L_ERR, "ERROR: update_totag_set: to not parsed\n");		return 0;	}	tag=&get_to(ok)->tag_value;	if (!tag->s) {		DBG("ERROR: update_totag_set: no tag in to\n");		return 0;	}	for (i=t->fwded_totags; i; i=i->next) {		if (i->tag.len==tag->len				&& memcmp(i->tag.s, tag->s, tag->len) ==0 ){			/* to tag already recorded */#ifdef XL_DEBUG			LOG(L_CRIT, "DEBUG: update_totag_set: totag retransmission\n");#else			DBG("DEBUG: update_totag_set: totag retransmission\n");#endif			return 1;		}	}	/* that's a new to-tag -- record it */	shm_lock();	n=(struct totag_elem*) shm_malloc_unsafe(sizeof(struct totag_elem));	s=(char *)shm_malloc_unsafe(tag->len);	shm_unlock();	if (!s || !n) {		LOG(L_ERR, "ERROR: update_totag_set: no  memory \n");		if (n) shm_free(n);		if (s) shm_free(s);		return 0;	}	memset(n, 0, sizeof(struct totag_elem));	memcpy(s, tag->s, tag->len );	n->tag.s=s;n->tag.len=tag->len;	n->next=t->fwded_totags;	t->fwded_totags=n;	DBG("DEBUG: update_totag_set: new totag \n");	return 0;}/* * Build and send an ACK to a negative reply */static int send_ack(struct sip_msg* rpl, struct cell *trans, int branch){	str to;	char *ack_p;	unsigned int  ack_len;	if (parse_headers( rpl, is_local(trans)?HDR_EOH_F:HDR_TO_F, 0)==-1	|| !rpl->to ) {		LOG(L_ERR, "ERROR:tm:send_ack: "			"cannot generate a HBH ACK if key HFs in reply missing\n");		goto error;	}	to.s=rpl->to->name.s;	to.len=rpl->to->len;	ack_p = is_local(trans)?		build_dlg_ack(rpl, trans, branch, &to, &ack_len):		build_local( trans, branch, &ack_len, ACK, ACK_LEN, &to );	if (ack_p==0) {		LOG(L_ERR, "ERROR:tm:send_ack: failed to build ACK\n");		goto error;	}	SEND_PR_BUFFER(&trans->uac[branch].request, ack_p, ack_len);	shm_free(ack_p);	return 0;error:	return -1;}static int _reply_light( struct cell *trans, char* buf, unsigned int len,			 unsigned int code, char * text, 			 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;	if (!buf)	{		DBG("DEBUG:tm:_reply_light: 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) {		LOG( L_ERR, "ERROR:tm: _reply_light: can't 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 ) {			LOG(L_ERR,"ERROR:tm:_reply_light: cannot 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) ) {			DBG("DEBUG:tm:_reply_light: local transaction completed\n");			if ( has_tran_tmcbs(trans, TMCB_LOCAL_COMPLETED) ) {				run_trans_callbacks( TMCB_LOCAL_COMPLETED, trans,					0, FAKED_REPLY, code);			}		} else {			if ( has_tran_tmcbs(trans, TMCB_RESPONSE_OUT) ) {				set_extra_tmcb_params( &rb->buffer, &rb->dst);				run_trans_callbacks( TMCB_RESPONSE_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 );			set_final_timer(  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) {		LOG(L_CRIT,"BUG:tm:_reply_light: send_sock is NULL\n");	}	SEND_PR_BUFFER( rb, buf, len );	DBG("DEBUG:tm:_reply_light: reply sent out. buf=%p: %.9s..., "		"shmem=%p: %.9s\n", buf, buf, rb->buffer.s, rb->buffer.s );	pkg_free( buf ) ;	stats_trans_rpl( code, 1 /*local*/ );	DBG("DEBUG:tm:_reply_light: 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;}/* send a UAS reply * returns 1 if everything was OK or -1 for error */static int _reply( struct cell *trans, struct sip_msg* p_msg, 	unsigned int code, char * text, int lock ){	unsigned int len;	char * buf, *dset;	struct bookmark bm;	int dset_len;	if (code>=200) set_kr(REQ_RPLD);	/* compute the buffer in private memory prior to entering lock;	 * create to-tag if needed */	/* if that is a redirection message, dump current message set to it */	if (code>=300 && code<400) {		dset=print_dset(p_msg, &dset_len);		if (dset) {			add_lump_rpl(p_msg, dset, dset_len, LUMP_RPL_HDR);		}	}	if (code>=180 && p_msg->to 				&& (get_to(p_msg)->tag_value.s==0 			    || get_to(p_msg)->tag_value.len==0)) {		calc_crc_suffix( p_msg, tm_tag_suffix );		buf = build_res_buf_from_sip_req(code,text, &tm_tag, p_msg, &len, &bm);		return _reply_light( trans, buf, len, code, text,			tm_tag.s, TOTAG_VALUE_LEN, lock, &bm);	} else {		buf = build_res_buf_from_sip_req(code,text, 0 /*no to-tag*/,

⌨️ 快捷键说明

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