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

📄 t_lookup.c

📁 用来作为linux中SIP SERVER,完成VOIP网络电话中服务器的功能
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * $Id: t_lookup.c,v 1.91.2.3 2005/09/01 13:52:58 andrei Exp $ * * This C-file takes care of matching requests and replies with * existing transactions. Note that we do not do SIP-compliant * request matching as asked by SIP spec. We do bitwise matching of  * all header fields in requests which form a transaction key.  * It is much faster and it works pretty well -- we haven't  * had any interop issue neither in lab nor in bake-offs. The reason * is that retransmissions do look same as original requests * (it would be really silly if they would be mangled). The only * exception is we parse To as To in ACK is compared to To in * reply and both  of them are constructed by different software. *  * As for reply matching, we match based on branch value -- that is * faster too. There are two versions .. with SYNONYMs #define * enabled, the branch includes ordinal number of a transaction * in a synonym list in hash table and is somewhat faster but * not reboot-resilient. SYNONYMs turned off are little slower * but work across reboots as well. * * The branch parameter is formed as follows: * SYNONYMS  on: hash.synonym.branch * SYNONYMS off: hash.md5.branch * * -jiri * * * 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-23  options for disabling r-uri matching introduced (jiri) *              nameser_compat.h (andrei) * 2003-01-27  next baby-step to removing ZT - PRESERVE_ZT (jiri) * 2003-01-28  scratchpad removed (jiri) * 2003-02-13  init_rb() is proto indep. & it uses struct dest_info (andrei) * 2003-02-24  s/T_NULL/T_NULL_CELL/ to avoid redefinition conflict w/ * 2003-02-27  3261 ACK/200 consumption bug removed (jiri) * 2003-02-28 scratchpad compatibility abandoned (jiri) * 2003-03-01  kr set through a function now (jiri) * 2003-03-06  dialog matching introduced for ACKs -- that's important for  *             INVITE UAS (like INVITE) and 200/ACK proxy matching (jiri) * 2003-03-29  optimization: e2e ACK matching only if callback installed *             (jiri) * 2003-03-30  set_kr for requests only (jiri) * 2003-04-04  bug_fix: RESPONSE_IN callback not called for local *             UAC transactions (jiri) * 2003-04-07  new transactions inherit on_negative and on_relpy from script *             variables on instantiation (jiri) * 2003-04-30  t_newtran clean up (jiri) * 2003-08-21  request lookups fixed to skip UAC transactions,  *             thanks Ed (jiri) * 2003-12-04  global TM callbacks switched to per transaction callbacks *             (bogdan) * 2004-02-11  FIFO/CANCEL + alignments (hash=f(callid,cseq)) (uli+jiri) * 2004-02-13: t->is_invite and t->local replaced with flags (bogdan) * 2004-10-10: use of mhomed disabled for replies (jiri) * 2005-02-01: use the incoming request interface for sending the replies *             - changes in init_rb() (bogdan) */#include "defs.h"#include "../../comp_defs.h"#include "../../dprint.h"#include "../../config.h"#include "../../parser/parser_f.h"#include "../../parser/parse_from.h"#include "../../ut.h"#include "../../timer.h"#include "../../hash_func.h"#include "../../globals.h"#include "../../forward.h"#include "t_funcs.h"#include "config.h"#include "sip_msg.h"#include "t_hooks.h"#include "t_lookup.h"#include "dlg.h" /* for t_lookup_callid */#include "t_msgbuilder.h" /* for t_lookup_callid */#define EQ_VIA_LEN(_via)\	( (p_msg->via1->bsize-(p_msg->_via->name.s-(p_msg->_via->hdr.s+p_msg->_via->hdr.len)))==\	  	(t_msg->via1->bsize-(t_msg->_via->name.s-(t_msg->_via->hdr.s+t_msg->_via->hdr.len))) )#define EQ_LEN(_hf) (t_msg->_hf->body.len==p_msg->_hf->body.len)#define EQ_REQ_URI_LEN\	(p_msg->first_line.u.request.uri.len==t_msg->first_line.u.request.uri.len)#define EQ_STR(_hf) (memcmp(t_msg->_hf->body.s,\	p_msg->_hf->body.s, \	p_msg->_hf->body.len)==0)#define EQ_REQ_URI_STR\	( memcmp( t_msg->first_line.u.request.uri.s,\	p_msg->first_line.u.request.uri.s,\	p_msg->first_line.u.request.uri.len)==0)#define EQ_VIA_STR(_via)\	( memcmp( t_msg->_via->name.s,\	 p_msg->_via->name.s,\	 (t_msg->via1->bsize-(t_msg->_via->name.s-(t_msg->_via->hdr.s+t_msg->_via->hdr.len)))\	)==0 )#define HF_LEN(_hf) ((_hf)->len)/* should be request-uri matching used as a part of pre-3261  * transaction matching, as the standard wants us to do so * (and is reasonable to do so, to be able to distinguish * spirals)? turn only off for better interaction with  * devices that are broken and send different r-uri in * CANCEL/ACK than in original INVITE */int ruri_matching=1;int via1_matching=1;/* presumably matching transaction for an e2e ACK */static struct cell *t_ack;/* this is a global variable which keeps pointer to   transaction currently processed by a process; it it   set by t_lookup_request or t_reply_matching; don't   dare to change it anywhere else as it would   break ref_counting*/static struct cell *T;/* number of currently processed message; good to know   to be able to doublecheck whether we are still working   on a current transaction or a new message arrived;   don't even think of changing it*/unsigned int     global_msg_id;struct cell *get_t() { return T; }void set_t(struct cell *t) { T=t; }void init_t() {global_msg_id=0; set_t(T_UNDEFINED);}static inline int parse_dlg( struct sip_msg *msg ){	if (parse_headers(msg, HDR_FROM | HDR_CSEQ | HDR_TO, 0)==-1) {		LOG(L_ERR, "ERROR: parse_dlg: From or Cseq or To invalid\n");		return 0;	}	if ((msg->from==0)||(msg->cseq==0)||(msg->to==0)) {		LOG(L_ERR, "ERROR: parse_dlg: missing From or Cseq or To\n");		return 0;	}	if (parse_from_header(msg)==-1) {		LOG(L_ERR, "ERROR: parse_dlg: From broken\n");		return 0;	}	/* To is automatically parsed through HDR_TO in parse bitmap,	 * we don't need to worry about it now	if (parse_to_header(msg)==-1) {		LOG(L_ERR, "ERROR: tid_matching: To broken\n");		return 0;	}	*/	return 1;}/* is the ACK (p_msg) in p_msg dialog-wise equal to the INVITE (t_msg)  * except to-tags? */static inline int partial_dlg_matching(struct sip_msg *t_msg, struct sip_msg *p_msg){	struct to_body *inv_from;	if (!EQ_LEN(callid)) return 0;	if (get_cseq(t_msg)->number.len!=get_cseq(p_msg)->number.len)		return 0;	inv_from=get_from(t_msg);	if (!inv_from) {		LOG(L_ERR, "ERROR: partial_dlg_matching: INV/From not parsed\n");		return 0;	}	if (inv_from->tag_value.len!=get_from(p_msg)->tag_value.len)		return 0;	if (!EQ_STR(callid)) 		return 0;	if (memcmp(get_cseq(t_msg)->number.s, get_cseq(p_msg)->number.s,			get_cseq(p_msg)->number.len)!=0)		return 0;	if (memcmp(inv_from->tag_value.s, get_from(p_msg)->tag_value.s,			get_from(p_msg)->tag_value.len)!=0)		return 0;	return 1;}/* are to-tags in ACK/200 same as those we sent out? */static inline int dlg_matching(struct cell *p_cell, struct sip_msg *ack ){	if (get_to(ack)->tag_value.len!=p_cell->uas.local_totag.len)		return 0;	if (memcmp(get_to(ack)->tag_value.s,p_cell->uas.local_totag.s,				p_cell->uas.local_totag.len)!=0)		return 0;	return 1;}static inline int ack_matching(struct cell *p_cell, struct sip_msg *p_msg) {	/* partial dialog matching -- no to-tag, only from-tag, 	 * callid, cseq number ; */	if (!partial_dlg_matching(p_cell->uas.request, p_msg)) 		return 0;  	/* if this transaction is proxied (as opposed to UAS) we're	 * done now -- we ignore to-tags; the ACK simply belongs to	 * this UAS part of dialog, whatever to-tag it gained	 */	if (p_cell->relaied_reply_branch!=-2) {		return 2; /* e2e proxied ACK */	}	/* it's a local dialog -- we wish to verify to-tags too */	if (dlg_matching(p_cell, p_msg)) {		return 1;	}	return 0;}/* branch-based transaction matching */static inline int via_matching( struct via_body *inv_via, 				struct via_body *ack_via ){	if (inv_via->tid.len!=ack_via->tid.len)		return 0;	if (memcmp(inv_via->tid.s, ack_via->tid.s,				ack_via->tid.len)!=0)		return 0;	/* ok, tid matches -- now make sure that the	 * originator matches too to avoid confusion with	 * different senders generating the same tid	 */	if (inv_via->host.len!=ack_via->host.len)		return 0;;	if (memcmp(inv_via->host.s, ack_via->host.s,			ack_via->host.len)!=0)		return 0;	if (inv_via->port!=ack_via->port)		return 0;	if (inv_via->transport.len!=ack_via->transport.len)		return 0;	if (memcmp(inv_via->transport.s, ack_via->transport.s,			ack_via->transport.len)!=0)		return 0;	/* everything matched -- we found it */	return 1;}/* transaction matching a-la RFC-3261 using transaction ID in branch   (the function assumes there is magic cookie in branch)    It returns:	 2 if e2e ACK for a proxied transaction found     1  if found (covers ACK for local UAS)	 0  if not found (trans undefined)*/static int matching_3261( struct sip_msg *p_msg, struct cell **trans,			enum request_method skip_method){	struct cell *p_cell;	struct sip_msg  *t_msg;	struct via_body *via1;	int is_ack;	int dlg_parsed;	int ret;	struct cell *e2e_ack_trans;	e2e_ack_trans=0;	via1=p_msg->via1;	is_ack=p_msg->REQ_METHOD==METHOD_ACK;	dlg_parsed=0;	/* update parsed tid */	via1->tid.s=via1->branch->value.s+MCOOKIE_LEN;	via1->tid.len=via1->branch->value.len-MCOOKIE_LEN;	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;  /* don't try matching UAC transactions */		if (skip_method & t_msg->REQ_METHOD) continue;		     /* here we do an exercise which will be removed from future code		      *	versions: we try to match end-2-end ACKs if they appear at our		      * server. This allows some applications bound to TM via callbacks		      * to correlate the e2e ACKs with transaction context, e.g., for		      * purpose of accounting. We think it is a bad place here, among		      * other things because it is not reliable. If a transaction loops		      * via SER the ACK can't be matched to proper INVITE transaction		      * (it is a separate transactino with its own branch ID) and it		      * matches all transaction instances in the loop dialog-wise.		      * Eventually, regardless to which transaction in the loop the		      * ACK belongs, only the first one will match.		      */		/* dialog matching needs to be applied for ACK/200s */		if (is_ack && p_cell->uas.status<300 && e2e_ack_trans==0) {			/* make sure we have parsed all things we need for dialog			 * matching */			if (!dlg_parsed) {				dlg_parsed=1;				if (!parse_dlg(p_msg)) {					LOG(L_ERR, "ERROR: matching_3261: dlg parsing failed\n");					return 0;				}			}			ret=ack_matching(p_cell /* t w/invite */, p_msg /* ack */);			if (ret>0) {				e2e_ack_trans=p_cell;			}			/* this ACK is neither local "negative" one, nor a proxied			 * end-2-end one, nor an end-2-end one for a UAS transaction			 * -- we failed to match */			continue;		}		/* now real tid matching occurs  for negative ACKs and any 	 	 * other requests */		if (!via_matching(t_msg->via1 /* inv via */, via1 /* ack */ ))			continue;		/* all matched -- we found the transaction ! */		DBG("DEBUG: RFC3261 transaction matched, tid=%.*s\n",			via1->tid.len, via1->tid.s);		*trans=p_cell;		return 1;	}	/* :-( ... we didn't find any */		/* just check if it we found an e2e ACK previously */	if (e2e_ack_trans) {		*trans=e2e_ack_trans;		return 2;	}	DBG("DEBUG: RFC3261 transaction matching failed\n");	return 0;}/* function returns: *      negative - transaction wasn't found *			(-2 = possibly e2e ACK matched ) *      positive - transaction found */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;	int ret;	struct via_param *branch;	int match_status;	struct cell *e2e_ack_trans;	/* parse all*/	if (check_transaction_quadruple(p_msg)==0)	{		LOG(L_ERR, "ERROR: TM module: t_lookup_request: 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=hash( p_msg->callid->body , get_cseq(p_msg)->number ) ;	isACK = p_msg->REQ_METHOD==METHOD_ACK;	DBG("t_lookup_request: start searching: hash=%d, isACK=%d\n",		p_msg->hash_index,isACK);	/* assume not found */	ret=-1;	e2e_ack_trans=0;	/* 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) {		LOG(L_ERR, "ERROR: t_lookup_request: 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 */	DBG("DEBUG: 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 ) 

⌨️ 快捷键说明

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