int add_phony_uac( struct cell *t) { str dummy_buffer = str_init("DUMMY"); unsigned short branch; utime_t timer; branch=t->nr_of_outgoings; if (branch==MAX_BRANCHES) { LM_ERR("maximum number of branches exceeded\n"); return E_CFG; } /* check existing buffer -- rewriting should never occur */ if (t->uac[branch].request.buffer.s) { LM_CRIT("buffer rewrite attempt\n"); ser_error=E_BUG; return E_BUG; } /* we attach a dummy buffer just to pass all the "tests" for a * valid branch */ t->uac[branch].request.buffer.s = (char*)shm_malloc(dummy_buffer.len); if (t->uac[branch].request.buffer.s==NULL) { LM_ERR("failed to alloc dummy buffer for phony branch\n"); /* there is nothing to reset on the branch */ return E_OUT_OF_MEM; } memcpy( t->uac[branch].request.buffer.s, dummy_buffer.s, dummy_buffer.len); t->uac[branch].request.buffer.len = dummy_buffer.len; t->uac[branch].request.my_T = t; t->uac[branch].request.branch = branch; t->uac[branch].flags = T_UAC_IS_PHONY; /* in invalid proto will prevent adding this retransmission buffer * to the retransmission timer (there is nothing to retransmit here :P */ t->uac[branch].request.dst.proto = PROTO_NONE; t->nr_of_outgoings++; /* we set here only FR (final response) timer, to be sure this branch * comes to an end - as timeout value we use exactly the same value the * transaction has set as FR_INV_TIMEOUT */ if (is_timeout_set(t->fr_inv_timeout)) { timer = t->fr_inv_timeout; set_1timer(&t->uac[branch].request.fr_timer, FR_INV_TIMER_LIST,&timer); } else { set_1timer(&t->uac[branch].request.fr_timer, FR_INV_TIMER_LIST, NULL); } set_kr(REQ_FWDED); return 0; }
inline void _set_fr_retr( struct retr_buf *rb, int retr ) { utime_t timer; if (retr && !rb->retr_timer.deleted) { rb->retr_list=RT_T1_TO_1; set_timer( &rb->retr_timer, RT_T1_TO_1, NULL ); } if (!rb->my_T || !is_timeout_set(rb->my_T->fr_timeout)) set_1timer(&rb->fr_timer, FR_TIMER_LIST, NULL); else { timer = rb->my_T->fr_timeout; set_1timer(&rb->fr_timer, FR_TIMER_LIST, &timer); } }
/* 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; int branch; int reply_status; utime_t timer; /* has the transaction completed now and we need to clean-up? */ branch_bm_t cancel_bitmap; struct ua_client *uac; struct cell *t; struct usr_avp **backup_list; unsigned int has_reply_route; set_t(T_UNDEFINED); /* make sure we know the associated transaction ... */ if (t_check(p_msg, &branch ) == -1) goto not_found; /*... if there is none, tell the core router to fwd statelessly */ t = get_t(); if ((t == 0) || (t == T_UNDEFINED)) goto not_found; cancel_bitmap=0; msg_status=p_msg->REPLY_STATUS; uac=&t->uac[branch]; LM_DBG("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; if_update_stat( tm_enable_stats, tm_rcv_rpls , 1); /* it's a cancel which is not e2e ? */ if ( get_cseq(p_msg)->method_id==METHOD_CANCEL && is_invite(t) ) { /* ... then just stop timers */ reset_timer( &uac->local_cancel.retr_timer); if ( msg_status >= 200 ) { reset_timer( &uac->local_cancel.fr_timer); } LM_DBG("reply to local CANCEL processed\n"); goto done; } /* *** stop timers *** */ /* stop retransmission */ reset_timer(&uac->request.retr_timer); /* stop final response timer only if I got a final response */ if ( msg_status >= 200 ) { reset_timer( &uac->request.fr_timer); } /* 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) && ((msg_status >= 300) || (is_local(t) && !no_autoack(t) && msg_status >= 200) )) { if (send_ack(p_msg, t, branch)!=0) LM_ERR("failed to send ACK (local=%s)\n", is_local(t)?"yes":"no"); } _tm_branch_index = branch; /* processing of on_reply block */ has_reply_route = (t->on_reply) || (t->uac[branch].on_reply); if (has_reply_route) { if (onreply_avp_mode) { /* lock the reply*/ LOCK_REPLIES( t ); /* set the as avp_list the one from transaction */ backup_list = set_avp_list(&t->user_avps); } else { backup_list = 0; } /* transfer transaction flag to branch context */ p_msg->flags = t->uas.request ? t->uas.request->flags : 0; setb0flags( p_msg, t->uac[branch].br_flags); /* run block - first per branch and then global one */ if ( t->uac[branch].on_reply && (run_top_route(onreply_rlist[t->uac[branch].on_reply].a,p_msg) &ACT_FL_DROP) && (msg_status<200) ) { if (onreply_avp_mode) { UNLOCK_REPLIES( t ); set_avp_list( backup_list ); } LM_DBG("dropping provisional reply %d\n", msg_status); goto done; } if ( t->on_reply && (run_top_route(onreply_rlist[t->on_reply].a,p_msg) &ACT_FL_DROP) && (msg_status<200) ) { if (onreply_avp_mode) { UNLOCK_REPLIES( t ); set_avp_list( backup_list ); } LM_DBG("dropping provisional reply %d\n", msg_status); goto done; } /* transfer current message context back to t */ t->uac[branch].br_flags = getb0flags(p_msg); if (t->uas.request) t->uas.request->flags = p_msg->flags; if (onreply_avp_mode) /* restore original avp list */ set_avp_list( backup_list ); } if (!onreply_avp_mode || !has_reply_route) /* lock the reply*/ LOCK_REPLIES( t ); /* mark that the UAC received replies */ uac->flags |= T_UAC_HAS_RECV_REPLY; /* we fire a cancel on spot if (a) branch is marked "to be canceled" or (b) * the whole transaction was canceled (received cancel) and no cancel sent * yet on this branch; and of course, only if a provisional reply :) */ if (t->uac[branch].flags&T_UAC_TO_CANCEL_FLAG || ((t->flags&T_WAS_CANCELLED_FLAG) && !t->uac[branch].local_cancel.buffer.s)) { if ( msg_status < 200 ) /* reply for an UAC with a pending cancel -> do cancel now */ cancel_branch(t, branch); /* reset flag */ t->uac[branch].flags &= ~(T_UAC_TO_CANCEL_FLAG); } if (is_local(t)) { reply_status = local_reply(t,p_msg, branch,msg_status,&cancel_bitmap); if (reply_status == RPS_COMPLETED) { cleanup_uac_timers(t); if (is_invite(t)) cancel_uacs(t, cancel_bitmap); /* There is no need to call set_final_timer because we know * that the transaction is local */ put_on_wait(t); } } else { reply_status = relay_reply(t,p_msg,branch,msg_status,&cancel_bitmap); /* clean-up the transaction when transaction completed */ 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); /* FR for negative INVITES, WAIT anything else */ /* set_final_timer(t); */ } } if (reply_status!=RPS_PROVISIONAL) goto done; /* update FR/RETR timers on provisional replies */ if (msg_status < 200 && (restart_fr_on_each_reply || ((last_uac_status<msg_status) && ((msg_status >= 180) || (last_uac_status == 0))) ) ) { /* provisional now */ if (is_invite(t)) { /* invite: change FR to longer FR_INV, do not * attempt to restart retransmission any more */ timer = is_timeout_set(t->fr_inv_timeout) ? t->fr_inv_timeout : timer_id2timeout[FR_INV_TIMER_LIST]; LM_DBG("FR_INV_TIMER = %lld\n", timer); set_timer(&uac->request.fr_timer, FR_INV_TIMER_LIST, &timer); } else { /* non-invite: restart retransmissions (slow now) */ uac->request.retr_list = RT_T2; set_timer(&uac->request.retr_timer, RT_T2, 0); } } /* 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 */ _tm_branch_index = 0; return 0; not_found: set_t(T_UNDEFINED); return 1; }