Example #1
0
/* return (ticks_t)-1 on error/disable and 0 on success */
inline static ticks_t retransmission_handler(struct retr_buf *r_buf)
{
#ifdef EXTRA_DEBUG
	if(r_buf->my_T->flags & T_IN_AGONY) {
		LM_ERR("transaction %p scheduled for deletion and"
			   " called from RETR timer (flags %x)\n",
				r_buf->my_T, r_buf->my_T->flags);
		abort();
	}
#endif
	if(r_buf->rbtype == TYPE_LOCAL_CANCEL
			|| r_buf->rbtype == TYPE_REQUEST) {
#ifdef EXTRA_DEBUG
		LM_DBG("request resending (t=%p, %.9s ... )\n", r_buf->my_T,
				r_buf->buffer);
#endif
		if(SEND_BUFFER(r_buf) == -1) {
			/* disable retr. timers => return -1 */
			fake_reply(r_buf->my_T, r_buf->branch, 503);
			return (ticks_t)-1;
		}
		if(unlikely(has_tran_tmcbs(r_buf->my_T, TMCB_REQUEST_SENT)))
			run_trans_callbacks_with_buf(
					TMCB_REQUEST_SENT, r_buf, 0, 0, TMCB_RETR_F);
	} else {
#ifdef EXTRA_DEBUG
		LM_DBG("reply resending (t=%p, %.9s ... )\n", r_buf->my_T,
				r_buf->buffer);
#endif
		t_retransmit_reply(r_buf->my_T);
	}

	return 0;
}
Example #2
0
inline static void final_response_handler( struct timer_link *fr_tl )
{
#define CANCEL_REASON_SIP_480  \
	"Reason: SIP;cause=480;text=\"NO_ANSWER\"" CRLF

	static context_p my_ctx = NULL;
	context_p old_ctx;
	struct retr_buf* r_buf;
	struct cell *t;

	if (fr_tl==0){
		/* or BUG?, ignoring it for now */
		LM_CRIT("final_response_handler(0) called\n");
		return;
	}
	r_buf = get_fr_timer_payload(fr_tl);
	t=r_buf->my_T;

#	ifdef EXTRA_DEBUG
	if (t->damocles)
	{
		LM_ERR("transaction %p scheduled for deletion and"
			" called from FR timer\n",r_buf->my_T);
		abort();
	}
#	endif

	reset_timer(  &(r_buf->retr_timer) );

	/* the transaction is already removed from FR_LIST by the timer */

	/* FR for local cancels.... */
	if (r_buf->activ_type==TYPE_LOCAL_CANCEL)
	{
		LM_DBG("stop retr for Local Cancel\n");
		return;
	}

	/* FR for replies (negative INVITE replies) */
	if (r_buf->activ_type>0) {
#		ifdef EXTRA_DEBUG
		if (t->uas.request->REQ_METHOD!=METHOD_INVITE
			|| t->uas.status < 200 ) {
			LM_ERR("unknown type reply buffer\n");
			abort();
		}
#		endif
		put_on_wait( t );
		return;
	};

	/* as this processing is outside the scope of other messages (it is
	   trigger from timer), a processing context must be attached to it */
	old_ctx = current_processing_ctx;
	if (my_ctx==NULL) {
		my_ctx = context_alloc(CONTEXT_GLOBAL);
		if (my_ctx==NULL) {
			LM_ERR("failed to alloc new ctx in pkg\n");
		}
	}
	memset( my_ctx, 0, context_size(CONTEXT_GLOBAL) );
	current_processing_ctx = my_ctx;
	/* set the T context too */
	set_t( t );

	/* out-of-lock do the cancel I/O */
	if (is_invite(t) && should_cancel_branch(t, r_buf->branch) ) {
		set_cancel_extra_hdrs( CANCEL_REASON_SIP_480, sizeof(CANCEL_REASON_SIP_480)-1);
		cancel_branch(t, r_buf->branch );
		set_cancel_extra_hdrs( NULL, 0);
	}
	/* lock reply processing to determine how to proceed reliably */
	LOCK_REPLIES( t );
	LM_DBG("Cancel sent out, sending 408 (%p)\n", t);
	fake_reply(t, r_buf->branch, 408 );

	/* flush the context */
	if (current_processing_ctx==NULL)
		my_ctx=NULL;
	else
		context_destroy(CONTEXT_GLOBAL, my_ctx);
	/* switch back to the old context */
	current_processing_ctx = old_ctx;
	/* reset the T context */
	init_t();

	LM_DBG("done\n");
}
Example #3
0
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);
}