123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298 |
- /*
- * $Id$
- *
- *
- * 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-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)
- * 2005-11-09 updated to the new timers interface (andrei)
- * 2006-02-07 named routes support (andrei)
- * 2006-09-13 t_pick_branch will skip also over branches with empty reply
- * t_should_relay_response will re-pick the branch if failure
- * route /handlers added new branches (andrei)
- * 2006-10-05 better final reply selection: t_pick_branch will prefer 6xx,
- * if no 6xx reply => lowest class/code; if class==4xx =>
- * prefer 401, 407, 415, 420 and 484 (andrei)
- * 2006-10-12 dns failover when a 503 is received
- * replace a 503 final relayed reply by a 500 (andrei)
- * 2006-10-16 aggregate all the authorization headers/challenges when
- * the final response is 401 or 407 (andrei)
- * 2007-03-08 membar_write() used in update_totag_set(...)(andrei)
- * 2007-03-15 build_local_ack: removed next_hop and replaced with dst to
- * avoid resolving next_hop twice
- * added TMCB_ONSEND callbacks support for replies & ACKs (andrei)
- * 2007-05-28: build_ack() constructs the ACK from the
- * outgoing INVITE instead of the incomming one.
- * (it can be disabled with reparse_invite=0) (Miklos)
- * 2007-09-03: drop_replies() has been introduced (Miklos)
- * 2008-03-12 use cancel_b_method on 6xx (andrei)
- * 2008-05-30 make sure the wait timer is started after we don't need t
- * anymore to allow safe calls from fr_timer (andrei)
- *
- */
- #ifdef EXTRA_DEBUG
- #include <assert.h>
- #endif
- #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 "../../atomic_ops.h" /* membar_write() */
- #include "../../compiler_opt.h"
- #include "../../select_buf.h" /* reset_static_buffer() */
- #ifdef USE_DST_BLACKLIST
- #include "../../dst_blacklist.h"
- #endif
- #ifdef USE_DNS_FAILOVER
- #include "../../dns_cache.h"
- #include "../../cfg_core.h" /* cfg_get(core, core_cfg, use_dns_failover) */
- #endif
- #include "defs.h"
- #include "config.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"
- /* 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;
- /* where to go on receipt of reply without transaction context */
- int goto_on_sl_reply=0;
- /* responses priority (used by t_pick_branch)
- * 0xx is used only for the initial value (=> should have no chance to be
- * selected => the highest value); 1xx is not used */
- static unsigned short resp_class_prio[]={
- 32000, /* 0-99, special */
- 11000, /* 1xx, special, should never be used */
- 0, /* 2xx, high priority (not used, 2xx are immediately
- forwarded and t_pick_branch will never be called if
- a 2xx was received) */
- 3000, /* 3xx */
- 4000, /* 4xx */
- 5000, /* 5xx */
- 1000 /* 6xx, highest priority */
- };
- /* 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_F,0)==-1 ||
- !ack->to ) {
- LOG(L_ERR, "ERROR: unmatched_totag: To invalid\n");
- return 1;
- }
- tag=&get_to(ack)->tag_value;
- i=t->fwded_totags;
- while(i){
- membar_depends(); /* make sure we don't see some old i content
- (needed on CPUs like Alpha) */
- 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);
- /* mark totag as acked and return 0 if this was the first ack
- * and 1 otherwise */
- return atomic_get_and_set_int(&i->acked, 1);
- }
- i=i->next;
- }
- /* 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;
- membar_write(); /* make sure all the changes to n are visible on all cpus
- before we update t->fwded_totags. This is needed for
- three reasons: the compiler might reorder some of the
- writes, the cpu/cache could also reorder them with
- respect to the visibility on other cpus
- (e.g. some of the changes to n could be visible on
- another cpu _after_ seeing t->fwded_totags=n) and
- the "readers" (unmatched_tags()) do not use locks and
- can be called simultaneously on another cpu.*/
- 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_F, 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;
- if (cfg_get(tm, tm_cfg, reparse_invite)) {
- /* build the ACK from the INVITE which was sent out */
- return build_local_reparse( trans, branch, ret_len,
- ACK, ACK_LEN, &to );
- } else {
- /* build the ACK from the reveived INVITE */
- return build_local( trans, branch, ret_len,
- ACK, ACK_LEN, &to );
- }
- }
- /*
- * The function builds an ACK to 200 OK of local transactions, honoring the
- * route set.
- * The destination to which the message should be sent will be returned
- * in the dst parameter.
- * returns 0 on error and a pkg_malloc'ed buffer with length in ret_len
- * and intended destination in dst on success.
- */
- static char *build_local_ack(struct sip_msg* rpl, struct cell *trans,
- int branch, unsigned int *ret_len,
- struct dest_info* dst)
- {
- #ifdef WITH_AS_SUPPORT
- struct retr_buf *local_ack, *old_lack;
- /* do we have the ACK cache, previously build? */
- if ((local_ack = trans->uac[0].local_ack) && local_ack->buffer_len) {
- DEBUG("reusing ACK retr. buffer.\n");
- *ret_len = local_ack->buffer_len;
- *dst = local_ack->dst;
- return local_ack->buffer;
- }
- /* the ACK will be built (and cached) by the AS (ack_local_uac()) */
- if (trans->flags & T_NO_AUTO_ACK)
- return NULL;
- if (! (local_ack = local_ack_rb(rpl, trans, branch, /*hdrs*/NULL,
- /*body*/NULL))) {
- ERR("failed to build local ACK retransmission buffer (T@%p).\n",trans);
- return NULL;
- }
- /* set the new buffer, but only if not already set (concurrent 2xx) */
- if ((old_lack = (struct retr_buf *)atomic_cmpxchg_long(
- (void *)&trans->uac[0].local_ack, 0, (long)local_ack))) {
- /* buffer already set: trash current and use the winning one */
- INFO("concurrent 2xx to local INVITE detected (T@%p).\n", trans);
- free_local_ack(local_ack);
- local_ack = old_lack;
- }
-
- *ret_len = local_ack->buffer_len;
- *dst = local_ack->dst;
- return local_ack->buffer;
- #else /* ! WITH_AS_SUPPORT */
- return build_dlg_ack(rpl, trans, branch, /*hdrs*/NULL, /*body*/NULL,
- ret_len, dst);
- #endif /* WITH_AS_SUPPORT */
- }
- #if 0 /* candidate for removal --andrei */
- /*
- * 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 dest_info dst;
- #ifdef USE_DNS_FAILOVER
- struct dns_srv_handle dns_h;
- #endif
- if (!next_hop) {
- LOG(L_ERR, "send_local_ack: Invalid parameter value\n");
- return -1;
- }
- #ifdef USE_DNS_FAILOVER
- if (cfg_get(core, core_cfg, use_dns_failover)){
- dns_srv_handle_init(&dns_h);
- if ((uri2dst(&dns_h, &dst, msg, next_hop, PROTO_NONE)==0) ||
- (dst.send_sock==0)){
- dns_srv_handle_put(&dns_h);
- LOG(L_ERR, "send_local_ack: no socket found\n");
- return -1;
- }
- dns_srv_handle_put(&dns_h); /* not needed anymore */
- }else{
- if ((uri2dst(0, &dst, msg, next_hop, PROTO_NONE)==0) ||
- (dst.send_sock==0)){
- LOG(L_ERR, "send_local_ack: no socket found\n");
- return -1;
- }
- }
- #else
- if ((uri2dst(&dst, msg, next_hop, PROTO_NONE)==0) || (dst.send_sock==0)){
- LOG(L_ERR, "send_local_ack: no socket found\n");
- return -1;
- }
- #endif
- return msg_send(&dst, ack, ack_len);
- }
- #endif
- inline static void start_final_repl_retr( struct cell *t )
- {
- if (unlikely(!is_local(t) && t->uas.request->REQ_METHOD==METHOD_INVITE )){
- /* crank timers for negative replies */
- if (t->uas.status>=300) {
- if (start_retr(&t->uas.response)!=0)
- LOG(L_CRIT, "BUG: start_final_repl_retr: start retr failed"
- " for %p\n", &t->uas.response);
- return;
- }
- /* local UAS retransmits too */
- if (t->relayed_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
- */
- if (force_retr( &t->uas.response )!=0)
- LOG(L_CRIT, "BUG: start_final_repl_retr: force retr failed for"
- " %p\n", &t->uas.response);
- return;
- }
- }
- }
- 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;
- #ifdef TMCB_ONSEND
- struct tmcb_params onsend_params;
- #endif
- 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->relayed_reply_branch=-2;
- t_stats_replied_locally();
- 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 ( unlikely(has_tran_tmcbs(trans, TMCB_LOCAL_COMPLETED)) )
- run_trans_callbacks( TMCB_LOCAL_COMPLETED, trans,
- 0, FAKED_REPLY, code);
- } else {
- if ( unlikely(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, F_CANCEL_B_KILL );
- start_final_repl_retr( 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 {
- #ifdef TMCB_ONSEND
- if (SEND_PR_BUFFER( rb, buf, len )>=0)
- if (unlikely(has_tran_tmcbs(trans, TMCB_RESPONSE_SENT))){
- INIT_TMCB_ONSEND_PARAMS(onsend_params, 0, 0, rb, &rb->dst,
- buf, len, TMCB_LOCAL_F, rb->branch, code);
- run_onsend_callbacks2(TMCB_RESPONSE_SENT, trans,
- &onsend_params);
- }
- #else
- SEND_PR_BUFFER( rb, buf, len );
- #endif
- DBG("DEBUG: reply sent out. buf=%p: %.9s..., shmem=%p: %.9s\n",
- buf, buf, rb->buffer, rb->buffer );
- }
- if (code>=200) {
- /* start wait timer after finishing with t so that this function can
- * be safely called from a fr_timer which allows quick timer dels
- * (timer_allow_del()) (there's no chance of having the wait handler
- * executed while we still need t) --andrei */
- put_on_wait(trans);
- }
- 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, F_CANCEL_B_KILL);
- /* 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*/,
- p_msg, &len, &bm);
- return _reply_light(trans,buf,len,code,text,
- 0, 0, /* no to-tag */lock, &bm);
- }
- }
- /*if msg is set -> it will fake the env. vars conforming with the msg; if NULL
- * the env. will be restore to original */
- void faked_env( struct cell *t,struct sip_msg *msg)
- {
- static enum route_mode backup_mode;
- static struct cell *backup_t;
- static unsigned int backup_msgid;
- static avp_list_t* backup_user_from, *backup_user_to;
- static avp_list_t* backup_domain_from, *backup_domain_to;
- static avp_list_t* backup_uri_from, *backup_uri_to;
- static struct socket_info* backup_si;
- if (msg) {
- /* remember we are back in request processing, but process
- * a shmem-ed replica of the request; advertise it in rmode;
- * for example t_reply needs to know that
- */
- backup_mode=rmode;
- rmode=MODE_ONFAILURE;
- /* also, tm actions look in beginning whether transaction is
- * set -- whether we are called from a reply-processing
- * or a timer process, we need to set current transaction;
- * otherwise the actions would attempt to look the transaction
- * up (unnecessary overhead, refcounting)
- */
- /* backup */
- backup_t=get_t();
- backup_msgid=global_msg_id;
- /* fake transaction and message id */
- global_msg_id=msg->id;
- set_t(t);
- /* make available the avp list from transaction */
- backup_uri_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, &t->uri_avps_from );
- backup_uri_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, &t->uri_avps_to );
- backup_user_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, &t->user_avps_from );
- backup_user_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, &t->user_avps_to );
- backup_domain_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, &t->domain_avps_from );
- backup_domain_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, &t->domain_avps_to );
- /* set default send address to the saved value */
- backup_si=bind_address;
- bind_address=t->uac[0].request.dst.send_sock;
- } else {
- /* restore original environment */
- set_t(backup_t);
- global_msg_id=backup_msgid;
- rmode=backup_mode;
- /* restore original avp list */
- set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, backup_user_from );
- set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, backup_user_to );
- set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, backup_domain_from );
- set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, backup_domain_to );
- set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, backup_uri_from );
- set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, backup_uri_to );
- bind_address=backup_si;
- }
- }
- int fake_req(struct sip_msg *faked_req,
- struct sip_msg *shmem_msg, int extra_flags)
- {
- /* on_negative_reply faked msg now copied from shmem msg (as opposed
- * to zero-ing) -- more "read-only" actions (exec in particular) will
- * work from reply_route as they will see msg->from, etc.; caution,
- * rw actions may append some pkg stuff to msg, which will possibly be
- * never released (shmem is released in a single block) */
- memcpy( faked_req, shmem_msg, sizeof(struct sip_msg));
- /* if we set msg_id to something different from current's message
- * id, the first t_fork will properly clean new branch URIs */
- faked_req->id=shmem_msg->id-1;
- /* msg->parsed_uri_ok must be reset since msg_parsed_uri is
- * not cloned (and cannot be cloned) */
- faked_req->parsed_uri_ok = 0;
-
- faked_req->msg_flags|=extra_flags; /* set the extra tm flags */
- /* new_uri can change -- make a private copy */
- if (shmem_msg->new_uri.s!=0 && shmem_msg->new_uri.len!=0) {
- faked_req->new_uri.s=pkg_malloc(shmem_msg->new_uri.len+1);
- if (!faked_req->new_uri.s) {
- LOG(L_ERR, "ERROR: fake_req: no uri/pkg mem\n");
- goto error00;
- }
- faked_req->new_uri.len=shmem_msg->new_uri.len;
- memcpy( faked_req->new_uri.s, shmem_msg->new_uri.s,
- faked_req->new_uri.len);
- faked_req->new_uri.s[faked_req->new_uri.len]=0;
- }
- /* dst_uri can change ALSO!!! -- make a private copy */
- if (shmem_msg->dst_uri.s!=0 && shmem_msg->dst_uri.len!=0) {
- faked_req->dst_uri.s=pkg_malloc(shmem_msg->dst_uri.len+1);
- if (!faked_req->dst_uri.s) {
- LOG(L_ERR, "ERROR: fake_req: no uri/pkg mem\n");
- goto error00;
- }
- faked_req->dst_uri.len=shmem_msg->dst_uri.len;
- memcpy( faked_req->dst_uri.s, shmem_msg->dst_uri.s,
- faked_req->dst_uri.len);
- faked_req->dst_uri.s[faked_req->dst_uri.len]=0;
- }
- return 1;
- error00:
- return 0;
- }
- void free_faked_req(struct sip_msg *faked_req, struct cell *t)
- {
- struct hdr_field *hdr;
- if (faked_req->new_uri.s) {
- pkg_free(faked_req->new_uri.s);
- faked_req->new_uri.s = 0;
- }
- if (faked_req->dst_uri.s) {
- pkg_free(faked_req->dst_uri.s);
- faked_req->dst_uri.s = 0;
- }
- /* free all types of lump that were added in failure handlers */
- del_nonshm_lump( &(faked_req->add_rm) );
- del_nonshm_lump( &(faked_req->body_lumps) );
- del_nonshm_lump_rpl( &(faked_req->reply_lump) );
- /* free header's parsed structures that were added by failure handlers */
- for( hdr=faked_req->headers ; hdr ; hdr=hdr->next ) {
- if ( hdr->parsed && hdr_allocs_parse(hdr) &&
- (hdr->parsed<(void*)t->uas.request ||
- hdr->parsed>=(void*)t->uas.end_request)) {
- /* header parsed filed doesn't point inside uas.request memory
- * chunck -> it was added by failure funcs.-> free it as pkg */
- DBG("DBG:free_faked_req: removing hdr->parsed %d\n",
- hdr->type);
- clean_hdr_field(hdr);
- hdr->parsed = 0;
- }
- }
- }
- /* return 1 if a failure_route processes */
- int run_failure_handlers(struct cell *t, struct sip_msg *rpl,
- int code, int extra_flags)
- {
- static struct sip_msg faked_req;
- struct sip_msg *shmem_msg = t->uas.request;
- int on_failure;
- struct run_act_ctx ra_ctx;
- /* failure_route for a local UAC? */
- if (!shmem_msg) {
- LOG(L_WARN,"Warning: run_failure_handlers: no UAC support (%d, %d) \n",
- t->on_negative, t->tmcb_hl.reg_types);
- return 0;
- }
- /* don't start faking anything if we don't have to */
- if (unlikely(!t->on_negative && !has_tran_tmcbs( t, TMCB_ON_FAILURE))) {
- LOG(L_WARN,
- "Warning: run_failure_handlers: no negative handler (%d, %d)\n",
- t->on_negative,
- t->tmcb_hl.reg_types);
- return 1;
- }
- if (!fake_req(&faked_req, shmem_msg, extra_flags)) {
- LOG(L_ERR, "ERROR: run_failure_handlers: fake_req failed\n");
- return 0;
- }
- /* fake also the env. conforming to the fake msg */
- faked_env( t, &faked_req);
- /* DONE with faking ;-) -> run the failure handlers */
- if (unlikely(has_tran_tmcbs( t, TMCB_ON_FAILURE)) ) {
- run_trans_callbacks( TMCB_ON_FAILURE, t, &faked_req, rpl, code);
- }
- if (t->on_negative) {
- /* avoid recursion -- if failure_route forwards, and does not
- * set next failure route, failure_route will not be reentered
- * on failure */
- on_failure = t->on_negative;
- t->on_negative=0;
- reset_static_buffer();
- /* run a reply_route action if some was marked */
- init_run_actions_ctx(&ra_ctx);
- if (run_actions(&ra_ctx, failure_rt.rlist[on_failure], &faked_req)<0)
- LOG(L_ERR, "ERROR: run_failure_handlers: Error in do_action\n");
- }
- /* restore original environment and free the fake msg */
- faked_env( t, 0);
- free_faked_req(&faked_req,t);
- /* if failure handler changed flag, update transaction context */
- shmem_msg->flags = faked_req.flags;
- return 1;
- }
- /* 401, 407, 415, 420, and 484 have priority over the other 4xx*/
- inline static short int get_4xx_prio(unsigned char xx)
- {
- switch(xx){
- case 1:
- case 7:
- case 15:
- case 20:
- case 84:
- return xx;
- break;
- }
- return 100+xx;
- }
- /* returns response priority, lower number => highest prio
- *
- * responses priority val
- * 0-99 32000+reponse (special)
- * 1xx 11000+reponse (special)
- * 700-999 10000+response (very low)
- * 5xx 5000+xx (low)
- * 4xx 4000+xx
- * 3xx 3000+xx
- * 6xx 1000+xx (high)
- * 2xx 0000+xx (highest)
- */
- inline static short int get_prio(unsigned int resp)
- {
- int class;
- int xx;
-
- class=resp/100;
- if (class<7){
- xx=resp%100;
- return resp_class_prio[class]+((class==4)?get_4xx_prio(xx):xx);
- }
- return 10000+resp; /* unknown response class => return very low prio */
- }
- /* select a branch for forwarding; returns:
- * 0..X ... branch number
- * -1 ... error
- * -2 ... can't decide yet -- incomplete branches present
- */
- int t_pick_branch(int inc_branch, int inc_code, struct cell *t, int *res_code)
- {
- int best_b, best_s, b;
- best_b=-1; best_s=0;
- for ( b=0; b<t->nr_of_outgoings ; b++ ) {
- /* "fake" for the currently processed branch */
- if (b==inc_branch) {
- if (get_prio(inc_code)<get_prio(best_s)) {
- best_b=b;
- best_s=inc_code;
- }
- continue;
- }
- /* skip 'empty branches' */
- if (!t->uac[b].request.buffer) continue;
- /* there is still an unfinished UAC transaction; wait now! */
- if ( t->uac[b].last_received<200 )
- return -2;
- /* if reply is null => t_send_branch "faked" reply, skip over it */
- if ( t->uac[b].reply &&
- get_prio(t->uac[b].last_received)<get_prio(best_s) ) {
- best_b =b;
- best_s = t->uac[b].last_received;
- }
- } /* find lowest branch */
-
- *res_code=best_s;
- return best_b;
- }
- /* flag indicating whether it is requested
- * to drop the already saved replies or not */
- static unsigned char drop_replies;
- /* This is the neurological point of reply processing -- called
- * from within a REPLY_LOCK, t_should_relay_response decides
- * how a reply shall be processed and how transaction state is
- * affected.
- *
- * Checks if the new reply (with new_code status) should be sent or not
- * based on the current
- * transaction status.
- * Returns - branch number (0,1,...) which should be relayed
- * -1 if nothing to be relayed
- */
- static enum rps t_should_relay_response( struct cell *Trans , int new_code,
- int branch , int *should_store, int *should_relay,
- branch_bm_t *cancel_bitmap, struct sip_msg *reply )
- {
- int branch_cnt;
- int picked_branch;
- int picked_code;
- int new_branch;
- int inv_through;
- int extra_flags;
- int i;
- /* note: this code never lets replies to CANCEL go through;
- we generate always a local 200 for CANCEL; 200s are
- not relayed because it's not an INVITE transaction;
- >= 300 are not relayed because 200 was already sent
- out
- */
- DBG("->>>>>>>>> T_code=%d, new_code=%d\n",Trans->uas.status,new_code);
- inv_through=new_code>=200 && new_code<300 && is_invite(Trans);
- /* if final response sent out, allow only INVITE 2xx */
- if ( Trans->uas.status >= 200 ) {
- if (inv_through) {
- DBG("DBG: t_should_relay_response: 200 INV after final sent\n");
- *should_store=0;
- Trans->uac[branch].last_received=new_code;
- *should_relay=branch;
- return RPS_PUSHED_AFTER_COMPLETION;
- }
- /* except the exception above, too late messages will
- be discarded */
- goto discard;
- }
- /* if final response received at this branch, allow only INVITE 2xx */
- if (Trans->uac[branch].last_received>=200
- && !(inv_through && Trans->uac[branch].last_received<300)) {
- /* don't report on retransmissions */
- if (Trans->uac[branch].last_received==new_code) {
- DBG("DEBUG: final reply retransmission\n");
- goto discard;
- }
- /* if you FR-timed-out, faked a local 408 and 487 came or
- * faked a CANCEL on a non-replied branch don't
- * report on it either */
- if ((Trans->uac[branch].last_received==487) ||
- (Trans->uac[branch].last_received==408 && new_code==487)) {
- DBG("DEBUG: %d came for a %d branch (ignored)\n",
- new_code, Trans->uac[branch].last_received);
- goto discard;
- }
- /* this looks however how a very strange status rewrite attempt;
- * report on it */
- LOG(L_ERR, "ERROR: t_should_relay_response: status rewrite by UAS: "
- "stored: %d, received: %d\n",
- Trans->uac[branch].last_received, new_code );
- goto discard;
- }
- /* no final response sent yet */
- /* negative replies subject to fork picking */
- if (new_code >=300 ) {
- Trans->uac[branch].last_received=new_code;
- /* if all_final return lowest */
- picked_branch=t_pick_branch(branch,new_code, Trans, &picked_code);
- if (picked_branch==-2) { /* branches open yet */
- *should_store=1;
- *should_relay=-1;
- if (new_code>=600 && new_code<=699){
- if (!(Trans->flags & T_6xx)){
- /* cancel only the first time we get a 6xx */
- which_cancel(Trans, cancel_bitmap);
- Trans->flags|=T_6xx;
- }
- }
- return RPS_STORE;
- }
- if (picked_branch==-1) {
- LOG(L_CRIT, "ERROR: t_should_relay_response: lowest==-1\n");
- goto error;
- }
- /* no more pending branches -- try if that changes after
- a callback; save branch count to be able to determine
- later if new branches were initiated */
- branch_cnt=Trans->nr_of_outgoings;
- /* also append the current reply to the transaction to
- * make it available in failure routes - a kind of "fake"
- * save of the final reply per branch */
- Trans->uac[branch].reply = reply;
- Trans->flags&=~T_6xx; /* clear the 6xx flag , we want to
- allow new branches from the failure route */
- drop_replies = 0;
- /* run ON_FAILURE handlers ( route and callbacks) */
- if (unlikely(has_tran_tmcbs( Trans, TMCB_ON_FAILURE_RO|TMCB_ON_FAILURE)
- || Trans->on_negative )) {
- extra_flags=
- ((Trans->uac[picked_branch].request.flags & F_RB_TIMEOUT)?
- FL_TIMEOUT:0) |
- ((Trans->uac[picked_branch].request.flags & F_RB_REPLIED)?
- FL_REPLIED:0);
- run_failure_handlers( Trans, Trans->uac[picked_branch].reply,
- picked_code, extra_flags);
- if (unlikely(drop_replies)) {
- /* drop all the replies that we have already saved */
- for (i=0; i<branch_cnt; i++) {
- if (Trans->uac[i].reply &&
- (Trans->uac[i].reply != FAKED_REPLY) &&
- (Trans->uac[i].reply->msg_flags & FL_SHM_CLONE))
- /* we have to drop the reply which is already in shm mem */
- sip_msg_free(Trans->uac[i].reply);
- Trans->uac[i].reply = 0;
- }
- /* make sure that the selected reply is not relayed even if
- there is not any new branch added -- should not happen */
- picked_branch = -1;
- }
- }
- /* now reset it; after the failure logic, the reply may
- * not be stored any more and we don't want to keep into
- * transaction some broken reference */
- Trans->uac[branch].reply = 0;
- /* look if the callback perhaps replied transaction; it also
- covers the case in which a transaction is replied localy
- on CANCEL -- then it would make no sense to proceed to
- new branches bellow
- */
- if (Trans->uas.status >= 200) {
- *should_store=0;
- *should_relay=-1;
- /* this might deserve an improvement -- if something
- was already replied, it was put on wait and then,
- returning RPS_COMPLETED will make t_on_reply
- put it on wait again; perhaps splitting put_on_wait
- from send_reply or a new RPS_ code would be healthy
- */
- return RPS_COMPLETED;
- }
- /* look if the callback/failure_route introduced new branches ... */
- if (branch_cnt<Trans->nr_of_outgoings){
- /* the new branches might be already "finished" => we
- * must use t_pick_branch again */
- new_branch=t_pick_branch((drop_replies==0)?
- branch :
- -1, /* make sure we do not pick
- the current branch */
- new_code,
- Trans,
- &picked_code);
- if (new_branch<0){
- if (likely(drop_replies==0)) {
- if (new_branch==-2) { /* branches open yet */
- *should_store=1;
- *should_relay=-1;
- return RPS_STORE;
- }
- /* error, use the old picked_branch */
- } else {
- if (new_branch==-2) { /* branches open yet */
- /* we are not allowed to relay the reply */
- *should_store=0;
- *should_relay=-1;
- return RPS_DISCARDED;
- } else {
- /* There are no open branches,
- and all the newly created branches failed
- as well. We are not allowed to send back
- the previously picked-up branch, thus,
- let us reply with an error instead. */
- goto branches_failed;
- }
- }
- }else{
- /* found a new_branch */
- picked_branch=new_branch;
- }
- } else if (unlikely(drop_replies)) {
- /* Either the script writer did not add new branches
- after calling t_drop_replies(), or tm was unable
- to add the new branches to the transaction. */
- goto branches_failed;
- }
- /* really no more pending branches -- return lowest code */
- *should_store=0;
- *should_relay=picked_branch;
- /* we dont need 'which_cancel' here -- all branches
- known to have completed */
- /* which_cancel( Trans, cancel_bitmap ); */
- return RPS_COMPLETED;
- }
- /* not >=300 ... it must be 2xx or provisional 1xx */
- if (new_code>=100) {
- #ifdef WITH_AS_SUPPORT
- /* need a copy of the message for ACK generation */
- *should_store = (inv_through && is_local(Trans) &&
- (Trans->uac[branch].last_received < 200) &&
- (Trans->flags & T_NO_AUTO_ACK)) ? 1 : 0;
- #else
- *should_store=0;
- #endif
- /* 1xx and 2xx except 100 will be relayed */
- Trans->uac[branch].last_received=new_code;
- *should_relay= new_code==100? -1 : branch;
- if (new_code>=200 ) {
- which_cancel( Trans, cancel_bitmap );
- return RPS_COMPLETED;
- } else return RPS_PROVISIONAL;
- }
- error:
- /* reply_status didn't match -- it must be something weird */
- LOG(L_CRIT, "ERROR: Oh my gooosh! We don't know whether to relay %d\n",
- new_code);
- discard:
- *should_store=0;
- *should_relay=-1;
- return RPS_DISCARDED;
- branches_failed:
- *should_store=0;
- *should_relay=-1;
- /* We have hopefully set tm_error in failure_route when
- the branches failed. If not, reply with E_UNSPEC */
- if ((kill_transaction_unsafe(Trans,
- tm_error ? tm_error : E_UNSPEC)
- ) <=0 ){
- LOG(L_ERR, "ERROR: t_should_relay_response: "
- "reply generation failed\n");
- }
-
- return RPS_COMPLETED;
- }
- /* Retransmits the last sent inbound reply.
- * input: p_msg==request for which I want to retransmit an associated reply
- * Returns -1 - error
- * 1 - OK
- */
- int t_retransmit_reply( struct cell *t )
- {
- static char b[BUF_SIZE];
- int len;
- /* 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 (!t->uas.response.dst.send_sock) {
- LOG(L_WARN, "WARNING: t_retransmit_reply: "
- "no resolved dst to retransmit\n");
- return -1;
- }
- /* we need to lock the transaction as messages from
- upstream may change it continuously
- */
- LOCK_REPLIES( t );
- if (!t->uas.response.buffer) {
- DBG("DBG: t_retransmit_reply: nothing to retransmit\n");
- goto error;
- }
- len=t->uas.response.buffer_len;
- if ( len==0 || len>BUF_SIZE ) {
- DBG("DBG: t_retransmit_reply: "
- "zero length or too big to retransmit: %d\n", len);
- goto error;
- }
- memcpy( b, t->uas.response.buffer, len );
- UNLOCK_REPLIES( t );
- SEND_PR_BUFFER( & t->uas.response, b, len );
- #ifdef TMCB_ONSEND
- if (unlikely(has_tran_tmcbs(t, TMCB_RESPONSE_SENT))){
- /* we don't know if it's a retransmission of a local reply or a
- * forwarded reply */
- run_onsend_callbacks(TMCB_RESPONSE_SENT, &t->uas.response, 0, 0,
- TMCB_RETR_F);
- }
- #endif
- DBG("DEBUG: reply retransmitted. buf=%p: %.9s..., shmem=%p: %.9s\n",
- b, b, t->uas.response.buffer, t->uas.response.buffer );
- return 1;
- error:
- UNLOCK_REPLIES(t);
- return -1;
- }
- int t_reply( struct cell *t, struct sip_msg* p_msg, unsigned int code,
- char * text )
- {
- return _reply( t, p_msg, code, text, 1 /* lock replies */ );
- }
- int t_reply_unsafe( struct cell *t, struct sip_msg* p_msg, unsigned int code,
- char * text )
- {
- return _reply( t, p_msg, code, text, 0 /* don't lock replies */ );
- }
- void set_final_timer( struct cell *t )
- {
- start_final_repl_retr(t);
- put_on_wait(t);
- }
- void cleanup_uac_timers( struct cell *t )
- {
- int i;
- /* reset FR/retransmission timers */
- for (i=0; i<t->nr_of_outgoings; i++ ){
- stop_rb_timers(&t->uac[i].request);
- }
- 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;
- }
- /* returns the number of authenticate replies (401 and 407) received so far
- * (FAKED_REPLYes are excluded)
- * It must be called with the REPLY_LOCK held */
- inline static int auth_reply_count(struct cell *t, struct sip_msg* crt_reply)
- {
- int count;
- int r;
- count=0;
- if (crt_reply && (crt_reply!=FAKED_REPLY) &&
- (crt_reply->REPLY_STATUS ==401 || crt_reply->REPLY_STATUS ==407))
- count=1;
- for (r=0; r<t->nr_of_outgoings; r++){
- if (t->uac[r].reply && (t->uac[r].reply!=FAKED_REPLY) &&
- (t->uac[r].last_received==401 || t->uac[r].last_received==407))
- count++;
- }
- return count;
- }
- /* must be called with the REPY_LOCK held */
- inline static char* reply_aggregate_auth(int code, char* txt, str* new_tag,
- struct cell* t, unsigned int* res_len,
- struct bookmark* bm)
- {
- int r;
- struct hdr_field* hdr;
- struct lump_rpl** first;
- struct lump_rpl** crt;
- struct lump_rpl* lst;
- struct lump_rpl* lst_end;
- struct sip_msg* req;
- char* buf;
-
- first=0;
- lst_end=0;
- req=t->uas.request;
-
- for (r=0; r<t->nr_of_outgoings; r++){
- if (t->uac[r].reply && (t->uac[r].reply!=FAKED_REPLY) &&
- (t->uac[r].last_received==401 || t->uac[r].last_received==407)){
- for (hdr=t->uac[r].reply->headers; hdr; hdr=hdr->next){
- if (hdr->type==HDR_WWW_AUTHENTICATE_T ||
- hdr->type==HDR_PROXY_AUTHENTICATE_T){
- crt=add_lump_rpl2(req, hdr->name.s, hdr->len,
- LUMP_RPL_HDR|LUMP_RPL_NODUP|LUMP_RPL_NOFREE);
- if (crt==0){
- /* some kind of error, better stop */
- LOG(L_ERR, "ERROR: tm:reply_aggregate_auth:"
- " add_lump_rpl2 failed\n");
- goto skip;
- }
- lst_end=*crt;
- if (first==0) first=crt;
- }
- }
- }
- }
- skip:
- buf=build_res_buf_from_sip_req(code, txt, new_tag, req, res_len, bm);
- /* clean the added lumps */
- if (first){
- lst=*first;
- *first=lst_end->next; /* "detach" the list of added rpl_lumps */
- lst_end->next=0; /* terminate lst */
- del_nonshm_lump_rpl(&lst);
- if (lst){
- LOG(L_CRIT, "BUG: tm: repply_aggregate_auth: rpl_lump list"
- "contains shm alloc'ed lumps\n");
- abort();
- }
- }
- return buf;
- }
- /* 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!
- If do_put_on_wait==1 and this is the final reply, the transaction
- wait timer will be started (put_on_wait(t)).
- */
- enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch,
- unsigned int msg_status, branch_bm_t *cancel_bitmap, int do_put_on_wait )
- {
- int relay;
- int save_clone;
- char *buf;
- /* length of outbound reply */
- unsigned int res_len;
- int relayed_code;
- struct sip_msg *relayed_msg;
- struct sip_msg *reply_bak;
- struct bookmark bm;
- int totag_retr;
- enum rps reply_status;
- /* retransmission structure of outbound reply and request */
- struct retr_buf *uas_rb;
- str* to_tag;
- #ifdef TMCB_ONSEND
- struct tmcb_params onsend_params;
- #endif
- /* 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: 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 (unlikely(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;
- /* use to_tag from the original request, or if not present,
- * generate a new one */
- 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 );
- to_tag=&tm_tag;
- } else {
- to_tag=0;
- }
- if (cfg_get(tm, tm_cfg, tm_aggregate_auth) &&
- (relayed_code==401 || relayed_code==407) &&
- (auth_reply_count(t, p_msg)>1)){
- /* aggregate 401 & 407 www & proxy authenticate headers in
- * a "FAKE" reply*/
-
- /* temporarily "store" the current reply */
- reply_bak=t->uac[branch].reply;
- t->uac[branch].reply=p_msg;
- buf=reply_aggregate_auth(relayed_code,
- error_text(relayed_code), to_tag, t, &res_len, &bm);
- /* revert the temporary "store" reply above */
- t->uac[branch].reply=reply_bak;
- }else{
- buf = build_res_buf_from_sip_req( relayed_code,
- error_text(relayed_code), to_tag,
- t->uas.request, &res_len, &bm );
- }
- } else {
- relayed_code=relayed_msg->REPLY_STATUS;
- if (relayed_code==503){
- /* replace a final 503 with a 500:
- * generate a "FAKE" reply and a new to_tag (for easier
- * debugging)*/
- relayed_msg=FAKED_REPLY;
- if ((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 );
- to_tag=&tm_tag;
- } else {
- to_tag=0;
- }
- /* don't relay a 503, replace it w/ 500 (rfc3261) */
- buf=build_res_buf_from_sip_req(500, error_text(relayed_code),
- to_tag, t->uas.request, &res_len, &bm);
- relayed_code=500;
- }else if (cfg_get(tm, tm_cfg, tm_aggregate_auth) &&
- (relayed_code==401 || relayed_code==407) &&
- (auth_reply_count(t, p_msg)>1)){
- /* aggregate 401 & 407 www & proxy authenticate headers in
- * a "FAKE" reply*/
- if ((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 );
- to_tag=&tm_tag;
- } else {
- to_tag=0;
- }
- /* temporarily "store" the current reply */
- reply_bak=t->uac[branch].reply;
- t->uac[branch].reply=p_msg;
- buf=reply_aggregate_auth(relayed_code,
- error_text(relayed_code), to_tag, t, &res_len, &bm);
- /* revert the temporary "store" reply above */
- t->uac[branch].reply=reply_bak;;
- relayed_msg=FAKED_REPLY; /* mark the relayed_msg as a "FAKE" */
- }else{
- 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);
- }
- }
- }
- update_reply_stats( relayed_code );
- if (!buf) {
- LOG(L_ERR, "ERROR: 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 = (char*)shm_resize( uas_rb->buffer, res_len +
- (msg_status<200 ? REPLY_OVERBUFFER_LEN : 0));
- if (!uas_rb->buffer) {
- LOG(L_ERR, "ERROR: relay_reply: cannot alloc reply shmem\n");
- goto error03;
- }
- uas_rb->buffer_len = res_len;
- memcpy( uas_rb->buffer, buf, res_len );
- if (relayed_msg==FAKED_REPLY) { /* to-tags for local replies */
- update_local_tags(t, &bm, uas_rb->buffer, buf);
- t_stats_replied_locally();
- }
-
- /* update the status ... */
- t->uas.status = relayed_code;
- t->relayed_reply_branch = relay;
- if ( unlikely(is_invite(t) && relayed_msg!=FAKED_REPLY
- && relayed_code>=200 && relayed_code < 300
- && has_tran_tmcbs( t,
- TMCB_RESPONSE_OUT|TMCB_E2EACK_IN|TMCB_E2EACK_RETR_IN))) {
- totag_retr=update_totag_set(t, relayed_msg);
- }
- }; /* if relay ... */
- UNLOCK_REPLIES( t );
- /* send it now (from the private buffer) */
- if (relay >= 0) {
- /* Set retransmission timer before the reply is sent out to avoid
- * race conditions
- *
- * Call start_final_repl_retr/put_on_wait() only if we really send out
- * the reply. It can happen that the reply has been already sent from
- * failure_route or from a callback and the timer has been already
- * started. (Miklos)
- */
- if (reply_status == RPS_COMPLETED) {
- start_final_repl_retr(t);
- }
- if (SEND_PR_BUFFER( uas_rb, buf, res_len )>=0){
- if (unlikely(!totag_retr && has_tran_tmcbs(t, TMCB_RESPONSE_OUT))){
- run_trans_callbacks( TMCB_RESPONSE_OUT, t, t->uas.request,
- relayed_msg, relayed_code);
- }
- #ifdef TMCB_ONSEND
- if (unlikely(has_tran_tmcbs(t, TMCB_RESPONSE_SENT))){
- INIT_TMCB_ONSEND_PARAMS(onsend_params, t->uas.request,
- relayed_msg, uas_rb, &uas_rb->dst, buf,
- res_len,
- (relayed_msg==FAKED_REPLY)?TMCB_LOCAL_F:0,
- uas_rb->branch, relayed_code);
- run_onsend_callbacks2(TMCB_RESPONSE_SENT, t, &onsend_params);
- }
- #endif
- }
- /* Call put_on_wait() only if we really send out
- * the reply. It can happen that the reply has been already sent from
- * failure_route or from a callback and the timer has been already
- * started. (Miklos)
- *
- * put_on_wait() should always be called after we finished dealling
- * with t, because otherwise the wait timer might fire before we
- * finish with t, and by the time we want to use t it could
- * be already deleted. This could happen only if this function is
- * called from timer (fr_timer) (the timer doesn't refcnt) and the
- * timer allows quick dels (timer_allow_del()). --andrei
- */
- if (do_put_on_wait && (reply_status == RPS_COMPLETED)) {
- put_on_wait(t);
- }
- 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" );
- *cancel_bitmap=0; /* t_reply_unsafe already canceled everything needed */
- UNLOCK_REPLIES(t);
- /* if (is_invite(t)) cancel_uacs( t, *cancel_bitmap, 0);
- * -- not needed, t_reply_unsafe took care of this */
- /* 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: 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) {
- t_stats_replied_locally();
- 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;
- update_reply_stats( winning_code );
- if (unlikely(is_invite(t) && winning_msg!=FAKED_REPLY &&
- winning_code>=200 && winning_code <300 &&
- has_tran_tmcbs(t, TMCB_LOCAL_COMPLETED) )) {
- totag_retr=update_totag_set(t, winning_msg);
- }
- }
- UNLOCK_REPLIES(t);
-
- if (local_winner >= 0
- && cfg_get(tm, tm_cfg, pass_provisional_replies)
- && winning_code < 200) {
- /* no retr. detection for provisional replies &
- * TMCB_LOCAL_RESPONSE_OUT */
- if (unlikely(has_tran_tmcbs(t, TMCB_LOCAL_RESPONSE_OUT) )) {
- run_trans_callbacks( TMCB_LOCAL_RESPONSE_OUT, t, 0,
- winning_msg, winning_code);
- }
- }
-
- if (local_winner>=0 && winning_code>=200 ) {
- DBG("DEBUG: local transaction completed\n");
- if (!totag_retr) {
- if (unlikely(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.len==INVITE_LEN
- && memcmp( get_cseq(p_msg)->method.s, INVITE, INVITE_LEN)==0)
- cancel_uacs( t, *cancel_bitmap, F_CANCEL_B_KILL);
- *cancel_bitmap=0; /* we've already took care of everything */
- 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;
- char *ack;
- unsigned int ack_len;
- int branch;
- /* has the transaction completed now and we need to clean-up? */
- int reply_status;
- branch_bm_t cancel_bitmap;
- struct ua_client *uac;
- struct cell *t;
- struct dest_info lack_dst;
- avp_list_t* backup_user_from, *backup_user_to;
- avp_list_t* backup_domain_from, *backup_domain_to;
- avp_list_t* backup_uri_from, *backup_uri_to;
- struct run_act_ctx ra_ctx;
- #ifdef USE_DNS_FAILOVER
- int branch_ret;
- int prev_branch;
- #endif
- #ifdef USE_DST_BLACKLIST
- int blst_503_timeout;
- struct dest_info src;
- struct hdr_field* hf;
- #endif
- #ifdef TMCB_ONSEND
- struct tmcb_params onsend_params;
- #endif
- /* make sure we know the associated transaction ... */
- if (t_check( p_msg , &branch )==-1)
- goto trans_not_found;
- /*... if there is none, tell the core router to fwd statelessly */
- t=get_t();
- if ( (t==0)||(t==T_UNDEFINED))
- goto trans_not_found;
- cancel_bitmap=0;
- msg_status=p_msg->REPLY_STATUS;
- uac=&t->uac[branch];
- DBG("DEBUG: 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;
- /* it's a cancel ... ? */
- if (get_cseq(p_msg)->method.len==CANCEL_LEN
- && memcmp( get_cseq(p_msg)->method.s, CANCEL, CANCEL_LEN)==0
- /* .. which is not e2e ? ... */
- && is_invite(t) ) {
- /* ... then just stop timers */
- if ( msg_status >= 200 )
- stop_rb_timers(&uac->local_cancel); /* stop retr & fr */
- else
- stop_rb_retr(&uac->local_cancel); /* stop only retr */
- DBG("DEBUG: reply to local CANCEL processed\n");
- goto done;
- }
- if ( msg_status >= 200 ){
- /* stop final response timer & retr. only if I got a final response */
- stop_rb_timers(&uac->request);
- /* 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)) {
- if (msg_status >= 300) {
- ack = build_ack(p_msg, t, branch, &ack_len);
- if (ack) {
- #ifdef TMCB_ONSEND
- if (SEND_PR_BUFFER(&uac->request, ack, ack_len)>=0)
- if (unlikely(has_tran_tmcbs(t, TMCB_REQUEST_SENT))){
- INIT_TMCB_ONSEND_PARAMS(onsend_params,
- t->uas.request, p_msg, &uac->request,
- &uac->request.dst, ack, ack_len,
- TMCB_LOCAL_F, branch, TYPE_LOCAL_ACK);
- run_onsend_callbacks2(TMCB_REQUEST_SENT, t,
- &onsend_params);
- }
- #else
- SEND_PR_BUFFER(&uac->request, ack, ack_len);
- #endif
- shm_free(ack);
- }
- } else if (is_local(t) /*&& 200 <= msg_status < 300*/) {
- ack = build_local_ack(p_msg, t, branch, &ack_len, &lack_dst);
- if (ack) {
- if (msg_send(&lack_dst, ack, ack_len)<0)
- LOG(L_ERR, "Error while sending local ACK\n");
- #ifdef TMCB_ONSEND
- else if (unlikely(has_tran_tmcbs(t, TMCB_REQUEST_SENT))){
- INIT_TMCB_ONSEND_PARAMS(onsend_params,
- t->uas.request, p_msg, &uac->request,
- &lack_dst, ack, ack_len, TMCB_LOCAL_F,
- branch, TYPE_LOCAL_ACK);
- run_onsend_callbacks2(TMCB_REQUEST_SENT, t,
- &onsend_params);
- }
- #endif
- #ifndef WITH_AS_SUPPORT
- shm_free(ack);
- #endif
- }
- }
- }
- }else{
- /* if branch already canceled re-transmit or generate cancel
- * TODO: check if it really makes sense to do it for non-invites too */
- if (uac->request.flags & F_RB_CANCELED){
- if (uac->local_cancel.buffer_len){
- membar_read(); /* make sure we get the current value of
- local_cancel */
- /* re-transmit if cancel already built */
- DBG("tm: reply_received: branch CANCEL retransmit\n");
- #ifdef TMCB_ONSEND
- if (SEND_BUFFER( &uac->local_cancel)>=0){
- if (unlikely (has_tran_tmcbs(t, TMCB_REQUEST_SENT)))
- run_onsend_callbacks(TMCB_REQUEST_SENT,
- &uac->local_cancel,
- 0, 0, TMCB_LOCAL_F);
- }
- #else
- SEND_BUFFER( &uac->local_cancel );
- #endif
- /* retrs. should be already started so do nothing */
- }else if (atomic_cmpxchg_long((void*)&uac->local_cancel.buffer, 0,
- (long)BUSY_BUFFER)==0){
- /* try to rebuild it if empty (not set or marked as BUSY).
- * if BUSY or set just exit, a cancel will be (or was) sent
- * shortly on this branch */
- DBG("tm: reply_received: branch CANCEL created\n");
- cancel_branch(t, branch, F_CANCEL_B_FORCE_C);
- }
- goto done; /* nothing to do */
- }
- if (is_invite(t)){
- /* stop only retr. (and not fr) */
- stop_rb_retr(&uac->request);
- }else{
- /* non-invite: increase retransmissions interval (slow now) */
- switch_rb_retr_to_t2(&uac->request);
- }
- }
- /* processing of on_reply block */
- if (t->on_reply) {
- rmode=MODE_ONREPLY;
- /* transfer transaction flag to message context */
- if (t->uas.request) p_msg->flags=t->uas.request->flags;
- /* set the as avp_list the one from transaction */
- backup_uri_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, &t->uri_avps_from );
- backup_uri_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, &t->uri_avps_to );
- backup_user_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, &t->user_avps_from );
- backup_user_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, &t->user_avps_to );
- backup_domain_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, &t->domain_avps_from );
- backup_domain_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, &t->domain_avps_to );
- reset_static_buffer();
- init_run_actions_ctx(&ra_ctx);
- if (run_actions(&ra_ctx, onreply_rt.rlist[t->on_reply], p_msg)<0)
- LOG(L_ERR, "ERROR: on_reply processing failed\n");
- /* transfer current message context back to t */
- if (t->uas.request) t->uas.request->flags=p_msg->flags;
- /* restore original avp list */
- set_avp_list( AVP_TRACK_FROM | AVP_CLASS_URI, backup_uri_from );
- set_avp_list( AVP_TRACK_TO | AVP_CLASS_URI, backup_uri_to );
- set_avp_list( AVP_TRACK_FROM | AVP_CLASS_USER, backup_user_from );
- set_avp_list( AVP_TRACK_TO | AVP_CLASS_USER, backup_user_to );
- set_avp_list( AVP_TRACK_FROM | AVP_CLASS_DOMAIN, backup_domain_from );
- set_avp_list( AVP_TRACK_TO | AVP_CLASS_DOMAIN, backup_domain_to );
- }
- #ifdef USE_DST_BLACKLIST
- /* add temporary to the blacklist the source of a 503 reply */
- if (cfg_get(tm, tm_cfg, tm_blst_503)
- && cfg_get(core, core_cfg, use_dst_blacklist)
- && (msg_status==503)
- ){
- blst_503_timeout=cfg_get(tm, tm_cfg, tm_blst_503_default);
- if ((parse_headers(p_msg, HDR_RETRY_AFTER_F, 0)==0) &&
- (p_msg->parsed_flag & HDR_RETRY_AFTER_F)){
- for (hf=p_msg->headers; hf; hf=hf->next)
- if (hf->type==HDR_RETRY_AFTER_T){
- /* found */
- blst_503_timeout=(unsigned)(unsigned long)hf->parsed;
- blst_503_timeout=MAX_unsigned(blst_503_timeout,
- cfg_get(tm, tm_cfg, tm_blst_503_min));
- blst_503_timeout=MIN_unsigned(blst_503_timeout,
- cfg_get(tm, tm_cfg, tm_blst_503_max));
- break;
- }
- }
- if (blst_503_timeout){
- src.send_sock=0;
- src.to=p_msg->rcv.src_su;
- src.id=p_msg->rcv.proto_reserved1;
- src.proto=p_msg->rcv.proto;
- dst_blacklist_add_to(BLST_503, &src, p_msg,
- S_TO_TICKS(blst_503_timeout));
- }
- }
- #endif /* USE_DST_BLACKLIST */
- #ifdef USE_DNS_FAILOVER
- /* if this is a 503 reply, and the destination resolves to more ips,
- * add another branch/uac.
- * This code is out of LOCK_REPLIES() to minimize the time the
- * reply lock is held (the lock won't be held while sending the
- * message)*/
- if (cfg_get(core, core_cfg, use_dns_failover) && (msg_status==503)) {
- branch_ret=add_uac_dns_fallback(t, t->uas.request, uac, 1);
- prev_branch=-1;
- while((branch_ret>=0) &&(branch_ret!=prev_branch)){
- prev_branch=branch_ret;
- branch_ret=t_send_branch(t, branch_ret, t->uas.request , 0, 1);
- }
- }
- #endif
- LOCK_REPLIES( t );
- if ( is_local(t) ) {
- reply_status=local_reply( t, p_msg, branch, msg_status, &cancel_bitmap );
- 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, F_CANCEL_B_KILL);
- /* There is no need to call set_final_timer because we know
- * that the transaction is local */
- put_on_wait(t);
- }else if (cancel_bitmap){
- /* cancel everything, even non-INVITEs (e.g in case of 6xx), use
- * cancel_b_method for canceling unreplied branches */
- cancel_uacs(t, cancel_bitmap, cfg_get(tm,tm_cfg, cancel_b_flags));
- }
- } else {
- reply_status=relay_reply( t, p_msg, branch, msg_status,
- &cancel_bitmap, 1 );
- 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 );
- /* 2xx is a special case: we can have a COMPLETED request
- * with branches still open => we have to cancel them */
- if (is_invite(t) && cancel_bitmap)
- cancel_uacs( t, cancel_bitmap, F_CANCEL_B_KILL);
- /* FR for negative INVITES, WAIT anything else */
- /* Call to set_final_timer is embedded in relay_reply to avoid
- * race conditions when reply is sent out and an ACK to stop
- * retransmissions comes before retransmission timer is set.*/
- }else if (cancel_bitmap){
- /* cancel everything, even non-INVITEs (e.g in case of 6xx), use
- * cancel_b_method for canceling unreplied branches */
- cancel_uacs(t, cancel_bitmap, cfg_get(tm,tm_cfg, cancel_b_flags));
- }
- }
- uac->request.flags|=F_RB_REPLIED;
- if (reply_status==RPS_ERROR)
- goto done;
- /* update FR/RETR timers on provisional replies */
- if (is_invite(t) && msg_status<200 &&
- ( cfg_get(tm, tm_cfg, restart_fr_on_each_reply) ||
- ( (last_uac_status<msg_status) &&
- ((msg_status>=180) || (last_uac_status==0)) )
- ) ) { /* provisional now */
- restart_rb_fr(& uac->request, t->fr_inv_timeout);
- uac->request.flags|=F_RB_FR_INV; /* mark fr_inv */
- } /* provisional replies */
- done:
- /* we are done with the transaction, so unref it - the reference
- * was incremented by t_check() function -bogdan*/
- t_unref(p_msg);
- /* don't try to relay statelessly neither on success
- (we forwarded statefully) nor on error; on troubles,
- simply do nothing; that will make the other party to
- retransmit; hopefuly, we'll then be better off */
- return 0;
- trans_not_found:
- /* transaction context was not found */
- if (goto_on_sl_reply) {
- /* the script writer has a chance to decide whether to
- forward the reply or not */
- init_run_actions_ctx(&ra_ctx);
- return run_actions(&ra_ctx, onreply_rt.rlist[goto_on_sl_reply], p_msg);
- } else {
- /* let the core forward the reply */
- return 1;
- }
- }
- int t_reply_with_body( struct cell *trans, unsigned int code,
- char * text, char * body, char * new_header, char * to_tag )
- {
- struct lump_rpl *hdr_lump;
- struct lump_rpl *body_lump;
- str s_to_tag;
- str rpl;
- int ret;
- struct bookmark bm;
- s_to_tag.s = to_tag;
- if(to_tag)
- s_to_tag.len = strlen(to_tag);
- else
- s_to_tag.len = 0;
- /* mark the transaction as replied */
- if (code>=200) set_kr(REQ_RPLD);
- /* add the lumps for new_header and for body (by bogdan) */
- if (new_header && strlen(new_header)) {
- hdr_lump = add_lump_rpl( trans->uas.request, new_header,
- strlen(new_header), LUMP_RPL_HDR );
- if ( !hdr_lump ) {
- LOG(L_ERR,"ERROR:tm:t_reply_with_body: cannot add hdr lump\n");
- goto error;
- }
- } else {
- hdr_lump = 0;
- }
- /* body lump */
- if(body && strlen(body)) {
- body_lump = add_lump_rpl( trans->uas.request, body, strlen(body),
- LUMP_RPL_BODY );
- if (body_lump==0) {
- LOG(L_ERR,"ERROR:tm:t_reply_with_body: cannot add body lump\n");
- goto error_1;
- }
- } else {
- body_lump = 0;
- }
- rpl.s = build_res_buf_from_sip_req(
- code, text, &s_to_tag,
- trans->uas.request, (unsigned int*)&rpl.len, &bm);
- /* since the msg (trans->uas.request) is a clone into shm memory, to avoid
- * memory leak or crashing (lumps are create in private memory) I will
- * remove the lumps by myself here (bogdan) */
- if ( hdr_lump ) {
- unlink_lump_rpl( trans->uas.request, hdr_lump);
- free_lump_rpl( hdr_lump );
- }
- if( body_lump ) {
- unlink_lump_rpl( trans->uas.request, body_lump);
- free_lump_rpl( body_lump );
- }
- if (rpl.s==0) {
- LOG(L_ERR,"ERROR:tm:t_reply_with_body: failed in doing "
- "build_res_buf_from_sip_req()\n");
- goto error;
- }
- DBG("t_reply_with_body: buffer computed\n");
- // frees 'res.s' ... no panic !
- ret=_reply_light( trans, rpl.s, rpl.len, code, text,
- s_to_tag.s, s_to_tag.len, 1 /* lock replies */, &bm );
- /* this is ugly hack -- the function caller may wish to continue with
- * transaction and I unref; however, there is now only one use from
- * vm/fifo_vm_reply and I'm currently to lazy to export UNREF; -jiri
- */
- UNREF(trans);
- return ret;
- error_1:
- if ( hdr_lump ) {
- unlink_lump_rpl( trans->uas.request, hdr_lump);
- free_lump_rpl( hdr_lump );
- }
- error:
- return -1;
- }
- /* drops all the replies to make sure
- * that none of them is picked up again
- */
- void t_drop_replies(void)
- {
- /* It is too risky to free the replies that are in shm mem
- at the middle of failure_route block, because other functions might
- need them as well. And it can also happen that the current reply is not yet
- in shm mem, we are just going to clone it. So better to set a flag
- and check it after failure_route has ended. (Miklos) */
- drop_replies = 1;
- }
- #if 0
- static int send_reply(struct cell *trans, unsigned int code, str* text, str* body, str* headers, str* to_tag)
- {
- struct lump_rpl *hdr_lump, *body_lump;
- str rpl;
- int ret;
- struct bookmark bm;
- /* mark the transaction as replied */
- if (code >= 200) set_kr(REQ_RPLD);
- /* add the lumps for new_header and for body (by bogdan) */
- if (headers && headers->len) {
- hdr_lump = add_lump_rpl(trans->uas.request, headers->s, headers->len, LUMP_RPL_HDR);
- if (!hdr_lump) {
- LOG(L_ERR, "send_reply: cannot add hdr lump\n");
- goto sr_error;
- }
- } else {
- hdr_lump = 0;
- }
- /* body lump */
- if (body && body->len) {
- body_lump = add_lump_rpl(trans->uas.request, body->s, body->len, LUMP_RPL_BODY);
- if (body_lump == 0) {
- LOG(L_ERR,"send_reply: cannot add body lump\n");
- goto sr_error_1;
- }
- } else {
- body_lump = 0;
- }
- /* We can safely zero-terminate the text here, because it is followed
- * by next line in the received message
- */
- text->s[text->len] = '\0';
- rpl.s = build_res_buf_from_sip_req(code, text->s, to_tag, trans->uas.request, (unsigned int*)&rpl.len, &bm);
- /* since the msg (trans->uas.request) is a clone into shm memory, to avoid
- * memory leak or crashing (lumps are create in private memory) I will
- * remove the lumps by myself here (bogdan) */
- if (hdr_lump) {
- unlink_lump_rpl(trans->uas.request, hdr_lump);
- free_lump_rpl(hdr_lump);
- }
- if (body_lump) {
- unlink_lump_rpl(trans->uas.request, body_lump);
- free_lump_rpl(body_lump);
- }
- if (rpl.s == 0) {
- LOG(L_ERR,"send_reply: failed in build_res_buf_from_sip_req\n");
- goto sr_error;
- }
- ret = _reply_light(trans, rpl.s, rpl.len, code, text->s, to_tag->s, to_tag->len, 1 /* lock replies */, &bm);
- /* this is ugly hack -- the function caller may wish to continue with
- * transaction and I unref; however, there is now only one use from
- * vm/fifo_vm_reply and I'm currently to lazy to export UNREF; -jiri
- */
- UNREF(trans);
- return ret;
- sr_error_1:
- if (hdr_lump) {
- unlink_lump_rpl(trans->uas.request, hdr_lump);
- free_lump_rpl(hdr_lump);
- }
- sr_error:
- return -1;
- }
- #endif
- const char* rpc_reply_doc[2] = {
- "Reply transaction",
- 0
- };
- /*
- Syntax:
- ":tm.reply:[response file]\n
- code\n
- reason\n
- trans_id\n
- to_tag\n
- [new headers]\n
- \n
- [Body]\n
- .\n
- \n"
- */
- void rpc_reply(rpc_t* rpc, void* c)
- {
- int ret;
- struct cell *trans;
- unsigned int hash_index, label, code;
- str ti;
- char* reason, *body, *headers, *tag;
- if (rpc->scan(c, "d", &code) < 1) {
- rpc->fault(c, 400, "Reply code expected");
- return;
- }
- if (rpc->scan(c, "s", &reason) < 1) {
- rpc->fault(c, 400, "Reason phrase expected");
- return;
- }
- if (rpc->scan(c, "s", &ti.s) < 1) {
- rpc->fault(c, 400, "Transaction ID expected");
- return;
- }
- ti.len = strlen(ti.s);
- if (rpc->scan(c, "s", &tag) < 1) {
- rpc->fault(c, 400, "To tag expected");
- return;
- }
- if (rpc->scan(c, "s", &headers) < 0) return;
- if (rpc->scan(c, "s", &body) < 0) return;
- if(sscanf(ti.s,"%u:%u", &hash_index, &label) != 2) {
- ERR("Invalid trans_id (%s)\n", ti.s);
- rpc->fault(c, 400, "Invalid transaction ID");
- return;
- }
- DBG("hash_index=%u label=%u\n", hash_index, label);
- if( t_lookup_ident(&trans, hash_index, label) < 0 ) {
- ERR("Lookup failed\n");
- rpc->fault(c, 481, "No such transaction");
- return;
- }
- /* it's refcounted now, t_reply_with body unrefs for me -- I can
- * continue but may not use T anymore */
- ret = t_reply_with_body(trans, code, reason, body, headers, tag);
- if (ret < 0) {
- ERR("Reply failed\n");
- rpc->fault(c, 500, "Reply failed");
- return;
- }
- }
|