int t_append_branches(void) { struct cell *t = NULL; struct sip_msg *orig_msg = NULL; short outgoings; int success_branch; str current_uri; str dst_uri, path, instance, ruid, location_ua; struct socket_info* si; int q, i, found; flag_t backup_bflags = 0; flag_t bflags = 0; int new_branch, branch_ret, lowest_ret; branch_bm_t added_branches; int replies_locked = 0; t = get_t(); if(t == NULL) { LM_ERR("cannot get transaction\n"); return -1; } LM_DBG("transaction %u:%u in status %d\n", t->hash_index, t->label, t->uas.status); /* test if transaction has already been canceled */ if (t->flags & T_CANCELED) { ser_error=E_CANCELED; return -1; } if ((t->uas.status >= 200 && t->uas.status<=399) || ((t->uas.status >= 600 && t->uas.status) && !(t->flags & (T_6xx | T_DISABLE_6xx))) ) { LM_DBG("transaction %u:%u in status %d: cannot append new branch\n", t->hash_index, t->label, t->uas.status); return -1; } /* set the lock on the transaction here */ LOCK_REPLIES(t); replies_locked = 1; outgoings = t->nr_of_outgoings; orig_msg = t->uas.request; LM_DBG("Call %.*s: %d (%d) outgoing branches\n",orig_msg->callid->body.len, orig_msg->callid->body.s,outgoings, nr_branches); lowest_ret=E_UNSPEC; added_branches=0; /* it's a "late" branch so the on_branch variable has already been reset by previous execution of t_forward_nonack: we use the saved value */ if (t->on_branch_delayed) { /* tell add_uac that it should run branch route actions */ set_branch_route(t->on_branch_delayed); } outgoings = t->nr_of_outgoings; /* not really sure that the following is needed */ set_branch_iterator(nr_branches-1); found = 0; while((current_uri.s=next_branch( ¤t_uri.len, &q, &dst_uri, &path, &bflags, &si, &ruid, &instance, &location_ua))) { LM_DBG("Current uri %.*s\n",current_uri.len, current_uri.s); for (i=0; i<nr_branches; i++) { if (t->uac[i].ruid.len == ruid.len && !memcmp(t->uac[i].ruid.s, ruid.s, ruid.len)) { LM_DBG("branch already added [%.*s]\n", ruid.len, ruid.s); found = 1; break; } } if (found) continue; setbflagsval(0, bflags); new_branch=add_uac( t, orig_msg, ¤t_uri, (dst_uri.len) ? (&dst_uri) : ¤t_uri, &path, 0, si, orig_msg->fwd_send_flags, orig_msg->rcv.proto, (dst_uri.len)?-1:UAC_SKIP_BR_DST_F, &instance, &ruid, &location_ua); /* test if cancel was received meanwhile */ if (t->flags & T_CANCELED) goto canceled; if (new_branch>=0) added_branches |= 1<<new_branch; else lowest_ret=MIN_int(lowest_ret, new_branch); } clear_branches(); LM_DBG("Call %.*s: %d (%d) outgoing branches after clear_branches()\n", orig_msg->callid->body.len, orig_msg->callid->body.s,outgoings, nr_branches); setbflagsval(0, backup_bflags); /* update message flags, if changed in branch route */ t->uas.request->flags = orig_msg->flags; if (added_branches==0) { if(lowest_ret!=E_CFG) LOG(L_ERR, "ERROR: t_append_branch: failure to add branches\n"); ser_error=lowest_ret; replies_locked = 0; UNLOCK_REPLIES(t); return lowest_ret; } ser_error=0; /* clear branch adding errors */ /* send them out now */ success_branch=0; /* since t_append_branch can only be called from REQUEST_ROUTE, always lock replies */ for (i=outgoings; i<t->nr_of_outgoings; i++) { if (added_branches & (1<<i)) { branch_ret=t_send_branch(t, i, orig_msg , 0, 0 /* replies are already locked */ ); if (branch_ret>=0){ /* some kind of success */ if (branch_ret==i) { /* success */ success_branch++; if (unlikely(has_tran_tmcbs(t, TMCB_REQUEST_OUT))) run_trans_callbacks_with_buf( TMCB_REQUEST_OUT, &t->uac[nr_branches].request, orig_msg, 0, -orig_msg->REQ_METHOD); } else /* new branch added */ added_branches |= 1<<branch_ret; } } } if (success_branch<=0) { /* return always E_SEND for now * (the real reason could be: denied by onsend routes, blacklisted, * send failed or any of the errors listed before + dns failed * when attempting dns failover) */ ser_error=E_SEND; /* else return the last error (?) */ /* the caller should take care and delete the transaction */ replies_locked = 0; UNLOCK_REPLIES(t); return -1; } ser_error=0; /* clear branch send errors, we have overall success */ set_kr(REQ_FWDED); replies_locked = 0; UNLOCK_REPLIES(t); return 1; canceled: DBG("t_append_branches: cannot append branches to a canceled transaction\n"); /* reset processed branches */ clear_branches(); /* restore backup flags from initial env */ setbflagsval(0, backup_bflags); /* update message flags, if changed in branch route */ t->uas.request->flags = orig_msg->flags; /* if needed unlock transaction's replies */ if (likely(replies_locked)) { /* restore the number of outgoing branches * since new branches have not been completed */ t->nr_of_outgoings = outgoings; replies_locked = 0; UNLOCK_REPLIES(t); } ser_error=E_CANCELED; return -1; }
inline static void final_response_handler( struct retr_buf *r_buf, struct cell *t) { int silent; #ifdef USE_DNS_FAILOVER /*int i; int added_branches; */ int branch_ret; int prev_branch; ticks_t now; #endif #ifdef EXTRA_DEBUG if(t->flags & T_IN_AGONY) { LM_ERR("transaction %p scheduled for deletion and" " called from FR timer (flags %x)\n", t, t->flags); abort(); } #endif /* FR for local cancels.... */ if(r_buf->rbtype == TYPE_LOCAL_CANCEL) { #ifdef TIMER_DEBUG LM_DBG("stop retr for local cancel\n"); #endif return; } /* FR for replies (negative INVITE replies) */ if(r_buf->rbtype > 0) { #ifdef EXTRA_DEBUG if(t->uas.request->REQ_METHOD != METHOD_INVITE || t->uas.status < 200) { LM_CRIT("BUG - unknown type reply buffer\n"); abort(); } #endif put_on_wait(t); return; }; /* lock reply processing to determine how to proceed reliably */ LOCK_REPLIES(t); /* now it can be only a request retransmission buffer; try if you can simply discard the local transaction state without compellingly removing it from the world */ silent = /* don't go silent if disallowed globally ... */ cfg_get(tm, tm_cfg, noisy_ctimer) == 0 /* ... or for this particular transaction */ && has_noisy_ctimer(t) == 0 /* not for UACs */ && !is_local(t) /* invites only */ && is_invite(t) /* parallel forking does not allow silent state discarding */ && t->nr_of_outgoings == 1 /* on_negativ reply handler not installed -- serial forking * could occur otherwise */ && t->on_failure == 0 /* the same for FAILURE callbacks */ && !has_tran_tmcbs(t, TMCB_ON_FAILURE_RO | TMCB_ON_FAILURE) /* something received -- we will not be silent on error */ && t->uac[r_buf->branch].last_received == 0; if(silent) { UNLOCK_REPLIES(t); #ifdef EXTRA_DEBUG LM_DBG("transaction silently dropped (%p), branch %d, last_received %d\n", t, r_buf->branch, t->uac[r_buf->branch].last_received); #endif put_on_wait(t); return; } #ifdef EXTRA_DEBUG LM_DBG("stop retr. and send CANCEL (%p)\n", t); #endif if((r_buf->branch < sr_dst_max_branches) && /* r_buf->branch is always >=0 */ (t->uac[r_buf->branch].last_received == 0) && (t->uac[r_buf->branch].request.buffer != NULL) /* not a blind UAC */ ) { /* no reply received */ #ifdef USE_DST_BLACKLIST if(r_buf->my_T && r_buf->my_T->uas.request && (r_buf->my_T->uas.request->REQ_METHOD & cfg_get(tm, tm_cfg, tm_blst_methods_add))) dst_blacklist_add( BLST_ERR_TIMEOUT, &r_buf->dst, r_buf->my_T->uas.request); #endif #ifdef USE_DNS_FAILOVER /* if this is an invite, the destination resolves to more ips, and * it still hasn't passed more than fr_inv_timeout since we * started, add another branch/uac */ if(cfg_get(core, core_cfg, use_dns_failover)) { now = get_ticks_raw(); if((s_ticks_t)(t->end_of_life - now) > 0) { branch_ret = add_uac_dns_fallback( t, t->uas.request, &t->uac[r_buf->branch], 0); 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, 0); } } } #endif } fake_reply(t, r_buf->branch, 408); }