| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424 |
- /*
- * $Id$
- *
- * 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:
- * [email protected]
- *
- * 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)
- * 2005-12-09 added t_set_fr() (andrei)
- * 2006-01-27 transaction lookup function will set up a cancel flag
- * if the searched transaction was pre-canceled (andrei)
- *
- */
- #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 "../../timer_ticks.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_fwd.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_F | HDR_CSEQ_F | HDR_TO_F, 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->relayed_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)
- It also sets *cancel if a cancel was found for the searched transaction
- */
- static int matching_3261( struct sip_msg *p_msg, struct cell **trans,
- enum request_method skip_method, int* cancel)
- {
- struct cell *p_cell;
- struct sip_msg *t_msg;
- struct via_body *via1;
- int is_ack;
- int dlg_parsed;
- int ret = 0;
- struct cell *e2e_ack_trans;
- *cancel=0;
- 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 */
- /* we want to set *cancel for transaction for which there is
- * already a canceled transaction (e.g. re-ordered INV-CANCEL, or
- * INV blocked in dns lookup); we don't care about ACKs */
- if ((is_ack || (t_msg->REQ_METHOD!=METHOD_CANCEL)) &&
- (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;
- break;
- }
- /* 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;
- if (t_msg->REQ_METHOD==METHOD_CANCEL){
- if ((p_msg->REQ_METHOD!=METHOD_CANCEL) && !is_ack){
- /* found an existing cancel for the searched transaction */
- *cancel=1;
- }
- if (skip_method & t_msg->REQ_METHOD) 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 ret;
- }
- DBG("DEBUG: RFC3261 transaction matching failed\n");
- return 0;
- }
- /* function returns:
- * negative - transaction wasn't found
- * (-2 = possibly e2e ACK matched )
- * positive - transaction found
- * It also sets *cancel if a there is already a cancel transaction
- */
- int t_lookup_request( struct sip_msg* p_msg , int leave_new_locked,
- int* cancel)
- {
- 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,
- cancel);
- 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");
- *cancel=0;
- /* 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) {
- /* for non-ACKs we want same method matching, we
- * make an exception for pre-exisiting CANCELs because we
- * want to set *cancel */
- if ((t_msg->REQ_METHOD!=p_msg->REQ_METHOD) &&
- (t_msg->REQ_METHOD!=METHOD_CANCEL))
- continue;
- /* compare lengths first */
- 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;
- 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 (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 (!EQ_STR(to)) continue;
- if (ruri_matching && !EQ_REQ_URI_STR) continue;
- if (via1_matching && !EQ_VIA_STR(via1)) continue;
-
- if ((t_msg->REQ_METHOD==METHOD_CANCEL) &&
- (p_msg->REQ_METHOD!=METHOD_CANCEL)){
- /* we've matched an existing CANCEL */
- *cancel=1;
- continue;
- }
-
- /* request matched ! */
- DBG("DEBUG: non-ACK matched\n");
- goto found;
- } else { /* it's an ACK request*/
- /* ACK's relate only to INVITEs */
- if (t_msg->REQ_METHOD!=METHOD_INVITE) 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;
- /* it is e2e ACK/200 */
- if (p_cell->uas.status<300 && e2e_ack_trans==0) {
- /* all criteria for proxied ACK are ok */
- if (p_cell->relayed_reply_branch!=-2) {
- e2e_ack_trans=p_cell;
- continue;
- }
- /* it's a local UAS transaction */
- if (dlg_matching(p_cell, p_msg))
- goto found;
- 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! */
- DBG("DEBUG: non-2xx ACK matched\n");
- goto found;
- } /* ACK */
- } /* synonym loop */
- notfound:
- if (e2e_ack_trans) {
- p_cell=e2e_ack_trans;
- goto e2e_ack;
- }
-
- /* no transaction found */
- set_t(0);
- if (!leave_new_locked) {
- UNLOCK_HASH(p_msg->hash_index);
- }
- DBG("DEBUG: t_lookup_request: no transaction found\n");
- return -1;
- e2e_ack:
- t_ack=p_cell; /* e2e proxied ACK */
- set_t(0);
- if (!leave_new_locked) {
- UNLOCK_HASH(p_msg->hash_index);
- }
- DBG("DEBUG: t_lookup_request: 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 );
- DBG("DEBUG: t_lookup_request: transaction found (T=%p)\n",T);
- return 1;
- }
- /* 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 foo;
- int ret;
- /* start searching in the table */
- hash_index = p_msg->hash_index;
- DBG("DEBUG: t_lookupOriginalT: 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) {
- LOG(L_ERR, "ERROR: t_lookupOriginalT: 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(hash_index);
- ret=matching_3261(p_msg, &p_cell,
- /* we are seeking the original transaction --
- * skip CANCEL transactions during search
- */
- METHOD_CANCEL, &foo);
- 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 */
- DBG("DEBUG: t_lookupOriginalT: no CANCEL matching found! \n" );
- UNLOCK_HASH(hash_index);
- DBG("DEBUG: t_lookupOriginalT completed\n");
- return 0;
- found:
- DBG("DEBUG: t_lookupOriginalT: canceled transaction"
- " found (%p)! \n",p_cell );
- REF_UNSAFE( p_cell );
- UNLOCK_HASH(hash_index);
- DBG("DEBUG: t_lookupOriginalT completed\n");
- return p_cell;
- }
- /* 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;
- }
- /* Determine current transaction
- *
- * Found Not Found Error (e.g. parsing)
- * Return Value 1 0 -1
- * T ptr 0 T_UNDEFINED
- */
- int t_check( struct sip_msg* p_msg , int *param_branch )
- {
- int local_branch;
- int canceled;
- /* is T still up-to-date ? */
- DBG("DEBUG: t_check: msg id=%d global id=%d T start=%p\n",
- p_msg->id,global_msg_id,T);
- if ( p_msg->id != global_msg_id || T==T_UNDEFINED )
- {
- global_msg_id = p_msg->id;
- T = T_UNDEFINED;
- /* transaction lookup */
- if ( p_msg->first_line.type==SIP_REQUEST ) {
- /* force parsing all the needed headers*/
- if (parse_headers(p_msg, HDR_EOH_F, 0 )==-1) {
- LOG(L_ERR, "ERROR: t_check: parsing error\n");
- return -1;
- }
- /* in case, we act as UAS for INVITE and reply with 200,
- * we will need to run dialog-matching for subsequent
- * ACK, for which we need From-tag; We also need from-tag
- * in case people want to have proxied e2e ACKs accounted
- */
- if (p_msg->REQ_METHOD==METHOD_INVITE
- && parse_from_header(p_msg)==-1) {
- LOG(L_ERR, "ERROR: t_check: from parsing failed\n");
- return -1;
- }
- t_lookup_request( p_msg , 0 /* unlock before returning */,
- &canceled);
- } else {
- /* we need Via for branch and Cseq method to distinguish
- replies with the same branch/cseqNr (CANCEL)
- */
- if ( parse_headers(p_msg, HDR_VIA1_F|HDR_CSEQ_F, 0 )==-1
- || !p_msg->via1 || !p_msg->cseq ) {
- LOG(L_ERR, "ERROR: reply cannot be parsed\n");
- return -1;
- }
- /* if that is an INVITE, we will also need to-tag
- for later ACK matching
- */
- if ( get_cseq(p_msg)->method.len==INVITE_LEN
- && memcmp( get_cseq(p_msg)->method.s, INVITE, INVITE_LEN )==0 ) {
- if (parse_headers(p_msg, HDR_TO_F, 0)==-1
- || !p_msg->to) {
- LOG(L_ERR, "ERROR: INVITE reply cannot be parsed\n");
- return -1;
- }
- }
- t_reply_matching( p_msg ,
- param_branch!=0?param_branch:&local_branch );
- }
- #ifdef EXTRA_DEBUG
- if ( T && T!=T_UNDEFINED && T->flags & (T_IN_AGONY)) {
- LOG( L_ERR, "ERROR: transaction %p scheduled for deletion "
- "and called from t_check (flags=%x)\n", T, T->flags);
- abort();
- }
- #endif
- DBG("DEBUG: t_check: msg id=%d global id=%d T end=%p\n",
- p_msg->id,global_msg_id,T);
- } else {
- if (T)
- DBG("DEBUG: t_check: T already found!\n");
- else
- DBG("DEBUG: t_check: T previously sought and not found\n");
- }
- return T ? (T==T_UNDEFINED ? -1 : 1 ) : 0;
- }
- int init_rb( struct retr_buf *rb, struct sip_msg *msg)
- {
- /*struct socket_info* send_sock;*/
- struct via_body* via;
- int proto;
- int backup_mhomed;
- /* rb. timers are init. init_t()/new_cell() */
- via=msg->via1;
- if (!reply_to_via) {
- update_sock_struct_from_ip( &rb->dst.to, msg );
- proto=msg->rcv.proto;
- } else {
- /*init retrans buffer*/
- if (update_sock_struct_from_via( &(rb->dst.to), msg, via )==-1) {
- LOG(L_ERR, "ERROR: init_rb: cannot lookup reply dst: %.*s\n",
- via->host.len, via->host.s );
- ser_error=E_BAD_VIA;
- return 0;
- }
- proto=via->proto;
- }
- rb->dst.proto=proto;
- rb->dst.id=msg->rcv.proto_reserved1;
- /* turn off mhomed for generating replies -- they are ideally sent to where
- request came from to make life with NATs and other beasts easier
- */
- backup_mhomed=mhomed;
- mhomed=0;
- mhomed=backup_mhomed;
- /* use for sending replies the incoming interface of the request -bogdan */
- /*send_sock=get_send_socket(msg, &rb->dst.to, proto);
- if (send_sock==0) {
- LOG(L_ERR, "ERROR: init_rb: cannot fwd to af %d, proto %d "
- "no socket\n", rb->dst.to.s.sa_family, proto);
- ser_error=E_BAD_VIA;
- return 0;
- }*/
- rb->dst.send_sock=msg->rcv.bind_address;
- return 1;
- }
- static inline void init_new_t(struct cell *new_cell, struct sip_msg *p_msg)
- {
- struct sip_msg *shm_msg;
- unsigned int timeout; /* avp timeout gets stored here (in s) */
- shm_msg=new_cell->uas.request;
- new_cell->from.s=shm_msg->from->name.s;
- new_cell->from.len=HF_LEN(shm_msg->from);
- new_cell->to.s=shm_msg->to->name.s;
- new_cell->to.len=HF_LEN(shm_msg->to);
- new_cell->callid.s=shm_msg->callid->name.s;
- new_cell->callid.len=HF_LEN(shm_msg->callid);
- new_cell->cseq_n.s=shm_msg->cseq->name.s;
- new_cell->cseq_n.len=get_cseq(shm_msg)->number.s
- +get_cseq(shm_msg)->number.len
- -shm_msg->cseq->name.s;
- new_cell->method=new_cell->uas.request->first_line.u.request.method;
- if (p_msg->REQ_METHOD==METHOD_INVITE) new_cell->flags |= T_IS_INVITE_FLAG;
- new_cell->on_negative=get_on_negative();
- new_cell->on_reply=get_on_reply();
- new_cell->fr_timeout=(ticks_t)get_msgid_val(user_fr_timeout,
- p_msg->id, int);
- new_cell->fr_inv_timeout=(ticks_t)get_msgid_val(user_fr_inv_timeout,
- p_msg->id, int);
- if (new_cell->fr_timeout==0){
- if (!fr_avp2timer(&timeout)) {
- DBG("init_new_t: FR__TIMER = %d s\n", timeout);
- new_cell->fr_timeout=S_TO_TICKS((ticks_t)timeout);
- }else{
- new_cell->fr_timeout=fr_timeout;
- }
- }
- if (new_cell->fr_inv_timeout==0){
- if (!fr_inv_avp2timer(&timeout)) {
- DBG("init_new_t: FR_INV_TIMER = %d s\n", timeout);
- new_cell->fr_inv_timeout=S_TO_TICKS((ticks_t)timeout);
- new_cell->flags |= T_NOISY_CTIMER_FLAG;
- }else{
- new_cell->fr_inv_timeout=fr_inv_timeout;
- }
- }
- new_cell->on_branch=get_on_branch();
- }
- static inline int new_t(struct sip_msg *p_msg)
- {
- struct cell *new_cell;
- /* for ACK-dlw-wise matching, we want From-tags */
- if (p_msg->REQ_METHOD==METHOD_INVITE && parse_from_header(p_msg)<0) {
- LOG(L_ERR, "ERROR: new_t: no valid From in INVITE\n");
- return E_BAD_REQ;
- }
- /* make sure uri will be parsed before cloning */
- if (parse_sip_msg_uri(p_msg)<0) {
- LOG(L_ERR, "ERROR: new_t: uri invalid\n");
- return E_BAD_REQ;
- }
-
- /* add new transaction */
- new_cell = build_cell( p_msg ) ;
- if ( !new_cell ){
- LOG(L_ERR, "ERROR: new_t: out of mem:\n");
- return E_OUT_OF_MEM;
- }
- insert_into_hash_table_unsafe( new_cell, p_msg->hash_index );
- set_t(new_cell);
- INIT_REF_UNSAFE(T);
- /* init pointers to headers needed to construct local
- requests such as CANCEL/ACK
- */
- init_new_t(new_cell, p_msg);
- return 1;
- }
- /* 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 ) {
- LOG(L_ERR, "ERROR: 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;
- }
- int t_unref( struct sip_msg* p_msg )
- {
- enum kill_reason kr;
- if (T==T_UNDEFINED || T==T_NULL_CELL)
- return -1;
- if (p_msg->first_line.type==SIP_REQUEST){
- kr=get_kr();
- if (kr==0
- ||(p_msg->REQ_METHOD==METHOD_ACK && !(kr & REQ_RLSD))) {
- LOG(L_WARN, "WARNING: script writer didn't release transaction\n");
- t_release_transaction(T);
- }
- }
- UNREF( T );
- set_t(T_UNDEFINED);
- return 1;
- }
- int t_get_trans_ident(struct sip_msg* p_msg, unsigned int* hash_index, unsigned int* label)
- {
- struct cell* t;
- if(t_check(p_msg,0) != 1){
- LOG(L_ERR,"ERROR: t_get_trans_ident: no transaction found\n");
- return -1;
- }
- t = get_t();
- if(!t){
- LOG(L_ERR,"ERROR: t_get_trans_ident: transaction found is NULL\n");
- return -1;
- }
-
- *hash_index = t->hash_index;
- *label = t->label;
- return 1;
- }
- int t_lookup_ident(struct cell ** trans, unsigned int hash_index, unsigned int label)
- {
- struct cell* p_cell;
- if(hash_index >= TABLE_ENTRIES){
- LOG(L_ERR,"ERROR: t_lookup_ident: invalid hash_index=%u\n",hash_index);
- return -1;
- }
- 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 )
- {
- if(p_cell->label == label){
- REF_UNSAFE(p_cell);
- UNLOCK_HASH(hash_index);
- set_t(p_cell);
- *trans=p_cell;
- DBG("DEBUG: t_lookup_ident: transaction found\n");
- return 1;
- }
- }
-
- UNLOCK_HASH(hash_index);
- set_t(0);
- *trans=p_cell;
- DBG("DEBUG: t_lookup_ident: transaction not found\n");
-
- return -1;
- }
- int t_is_local(struct sip_msg* p_msg)
- {
- struct cell* t;
- if(t_check(p_msg,0) != 1){
- LOG(L_ERR,"ERROR: t_is_local: no transaction found\n");
- return -1;
- }
- t = get_t();
- if(!t){
- LOG(L_ERR,"ERROR: t_is_local: transaction found is NULL\n");
- return -1;
- }
-
- return is_local(t);
- }
- /* lookup a transaction by callid and cseq, parameters are pure
- * header field content only, e.g. "[email protected]" and "11"
- */
- int t_lookup_callid(struct cell ** trans, str callid, str cseq) {
- struct cell* p_cell;
- unsigned hash_index;
- /* I use MAX_HEADER, not sure if this is a good choice... */
- char callid_header[MAX_HEADER];
- char cseq_header[MAX_HEADER];
- /* save return value of print_* functions here */
- char* endpos;
- /* need method, which is always INVITE in our case */
- /* CANCEL is only useful after INVITE */
- str invite_method;
- char* invite_string = INVITE;
-
- invite_method.s = invite_string;
- invite_method.len = INVITE_LEN;
-
- /* lookup the hash index where the transaction is stored */
- hash_index=hash(callid, cseq);
- if(hash_index >= TABLE_ENTRIES){
- LOG(L_ERR,"ERROR: t_lookup_callid: invalid hash_index=%u\n",hash_index);
- return -1;
- }
- /* create header fields the same way tm does itself, then compare headers */
- endpos = print_callid_mini(callid_header, callid);
- DBG("created comparable call_id header field: >%.*s<\n",
- (int)(endpos - callid_header), callid_header);
- endpos = print_cseq_mini(cseq_header, &cseq, &invite_method);
- DBG("created comparable cseq header field: >%.*s<\n",
- (int)(endpos - cseq_header), cseq_header);
- LOCK_HASH(hash_index);
- DBG("just locked hash index %u, looking for transactions there:\n", 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 ) {
-
- /* compare complete header fields, casecmp to make sure invite=INVITE */
- if ( (strncmp(callid_header, p_cell->callid.s, p_cell->callid.len) == 0)
- && (strncasecmp(cseq_header, p_cell->cseq_n.s, p_cell->cseq_n.len) == 0) ) {
- DBG("we have a match: callid=>>%.*s<< cseq=>>%.*s<<\n", p_cell->callid.len,
- p_cell->callid.s, p_cell->cseq_n.len, p_cell->cseq_n.s);
- REF_UNSAFE(p_cell);
- UNLOCK_HASH(hash_index);
- set_t(p_cell);
- *trans=p_cell;
- DBG("DEBUG: t_lookup_callid: transaction found.\n");
- return 1;
- }
- DBG("NO match: callid=%.*s cseq=%.*s\n", p_cell->callid.len,
- p_cell->callid.s, p_cell->cseq_n.len, p_cell->cseq_n.s);
-
- }
- UNLOCK_HASH(hash_index);
- DBG("DEBUG: t_lookup_callid: transaction not found.\n");
-
- return -1;
- }
- /* params: fr_inv & fr value in ms, 0 means "do not touch"
- * ret: 1 on success, -1 on error (script safe)*/
- int t_set_fr(struct sip_msg* msg, unsigned int fr_inv_to, unsigned int fr_to)
- {
- struct cell *t;
- ticks_t fr_inv, fr;
-
-
- fr_inv=MS_TO_TICKS((ticks_t)fr_inv_to);
- if ((fr_inv==0) && (fr_inv_to!=0)){
- ERR("t_set_fr_inv: fr_inv_timeout too small (%d)\n", fr_inv_to);
- return -1;
- }
- fr=MS_TO_TICKS((ticks_t)fr_to);
- if ((fr==0) && (fr_to!=0)){
- ERR("t_set_fr_inv: fr_timeout too small (%d)\n", fr_to);
- return -1;
- }
-
- 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 ){
- set_msgid_val(user_fr_inv_timeout, msg->id, int, (int)fr_inv);
- set_msgid_val(user_fr_timeout, msg->id, int, (int)fr);
- }else{
- change_fr(t, fr_inv, fr); /* change running uac timers */
- }
- return 1;
- }
|