⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 t_reply.c

📁 用来作为linux中SIP SERVER,完成VOIP网络电话中服务器的功能
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * $Id: t_reply.c,v 1.98.2.5 2005/09/01 13:53:01 andrei Exp $ * * * Copyright (C) 2001-2003 FhG Fokus * * This file is part of ser, a free SIP server. * * ser is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * For a license to use the ser software under conditions * other than those described here, or to purchase support for this * software, please contact iptel.org by e-mail at the following addresses: *    info@iptel.org * * ser is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License  * along with this program; if not, write to the Free Software  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * * 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-09-01  reverted to the old way of checking response.dst.send_sock *               in t_retransmit_reply & reply_light (andrei) */#include "../../comp_defs.h"#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 "defs.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"/* restart fr timer on each provisional reply, default yes */int restart_fr_on_each_reply=1;/* are we processing original or shmemed request ? */enum route_mode rmode=MODE_REQUEST;/* private place where we create to-tags for replies *//* janakj: made public, I need to access this value to store it in dialogs */char tm_tags[TOTAG_VALUE_LEN];/* bogdan: pack tm_tag buffer and len into a str to pass them to * build_res_buf_from_sip_req() */static str  tm_tag = {tm_tags,TOTAG_VALUE_LEN};char *tm_tag_suffix;/* 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;/* 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		get_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		get_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, 		"SER-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,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 an ACK to a negative reply */static char *build_ack(struct sip_msg* rpl,struct cell *trans,int branch,	unsigned int *ret_len){	str to;    if (parse_headers(rpl,HDR_TO, 0)==-1 || !rpl->to ) {        LOG(L_ERR, "ERROR: build_ack: "            "cannot generate a HBH ACK if key HFs in reply missing\n");        return NULL;    }	to.s=rpl->to->name.s;	to.len=rpl->to->len;    return build_local( trans, branch, ret_len,        ACK, ACK_LEN, &to );}/* * The function builds an ACK to 200 OK of local transactions, honor the * route set, the URI to which the message should be sent will be returned * in next_hop parameter */static char *build_local_ack(struct sip_msg* rpl, struct cell *trans, int branch,			     unsigned int *ret_len, str* next_hop){	str to;	if (parse_headers(rpl, HDR_EOH, 0) == -1 || !rpl->to) {		LOG(L_ERR, "ERROR: build_local_ack: Error while parsing headers\n");		return 0;	}		to.s = rpl->to->name.s;	to.len = rpl->to->len;	return build_dlg_ack(rpl, trans, branch, &to, ret_len, next_hop);}     /*      * The function is used to send a localy generated ACK to INVITE      * (tm generates the ACK on behalf of application using UAC      */static int send_local_ack(struct sip_msg* msg, str* next_hop,							char* ack, int ack_len){	struct socket_info* send_sock;	union sockaddr_union to_su;		if (!next_hop) {		LOG(L_ERR, "send_local_ack: Invalid parameter value\n");		return -1;	}		send_sock = uri2sock(msg, next_hop, &to_su, PROTO_NONE);	if (!send_sock) {		LOG(L_ERR, "send_local_ack: no socket found\n");		return -1;	}		return msg_send(send_sock, send_sock->proto, &to_su, 0, ack, ack_len);}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: _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: _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 ? len : len + REPLY_OVERBUFFER_LEN;	rb->buffer = (char*)shm_resize( rb->buffer, buf_len );	/* puts the reply's buffer to uas.response */	if (! rb->buffer ) {			LOG(L_ERR, "ERROR: _reply_light: cannot allocate shmem buffer\n");			goto error3;	}	update_local_tags(trans, bm, rb->buffer, buf);	rb->buffer_len = len ;	memcpy( rb->buffer , buf , len );	/* needs to be protected too because what timers are set depends	   on current transactions status */	/* t_update_timers_after_sending_reply( rb ); */	update_reply_stats( code );	trans->relaied_reply_branch=-2;	tm_stats->replied_localy++;	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: local transaction completed from _reply\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) )				run_trans_callbacks( TMCB_RESPONSE_OUT, trans,					trans->uas.request, FAKED_REPLY, code);		}		cleanup_uac_timers( trans );		if (is_invite(trans)) cancel_uacs( trans, cancel_bitmap );		set_final_timer(  trans );	}	/* send it out */	/* first check if we managed to resolve topmost Via -- if	   not yet, don't try to retransmit	*/	/*	   response.dst.send_sock might be unset if the process that created	   the original transaction has not finished initialising the 	   retransmission buffer (see t_newtran/ init_rb).	   If reply_to_via is set and via contains a host name (and not an ip)	   the chances for this increase a lot.	 */	if (!trans->uas.response.dst.send_sock) {		LOG(L_ERR, "ERROR: _reply_light: no resolved dst to send reply to\n");	} else {		SEND_PR_BUFFER( rb, buf, len );		DBG("DEBUG: reply sent out. buf=%p: %.9s..., shmem=%p: %.9s\n", 			buf, buf, rb->buffer, rb->buffer );	}	pkg_free( buf ) ;	DBG("DEBUG: _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 */

⌨️ 快捷键说明

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