예제 #1
0
파일: timer.c 프로젝트: btriller/kamailio
ticks_t wait_handler(ticks_t ti, struct timer_ln *wait_tl, void *data)
{
	struct cell *p_cell;
	ticks_t ret;

	p_cell = (struct cell *)data;
#ifdef TIMER_DEBUG
	LM_DBG("WAIT timer hit @%d for %p (timer_lm %p)\n", ti, p_cell, wait_tl);
#endif

#ifdef TM_DEL_UNREF
	/* stop cancel timers if any running */
	if(is_invite(p_cell))
		cleanup_localcancel_timers(p_cell);
	/* remove the cell from the hash table */
	LOCK_HASH(p_cell->hash_index);
	remove_from_hash_table_unsafe(p_cell);
	UNLOCK_HASH(p_cell->hash_index);
	p_cell->flags |= T_IN_AGONY;
	if(t_linked_timers(p_cell)) {
		UNREF_FREE(p_cell, 0);
	} else {
		UNREF_FREE(p_cell, 1);
	}
	ret = 0;
#else  /* TM_DEL_UNREF */
	if(p_cell->flags & T_IN_AGONY) {
		/* delayed delete */
		/* we call delete now without any locking on hash/ref_count;
		   we can do that because delete_handler is only entered after
		   the delete timer was installed from wait_handler, which
		   removed transaction from hash table and did not destroy it
		   because some processes were using it; that means that the
		   processes currently using the transaction can unref and no
		   new processes can ref -- we can wait until ref_count is
		   zero safely without locking
		*/
		ret = delete_cell(p_cell, 0 /* don't unlock on return */);
	} else {
		/* stop cancel timers if any running */
		if(is_invite(p_cell))
			cleanup_localcancel_timers(p_cell);
		/* remove the cell from the hash table */
		LOCK_HASH(p_cell->hash_index);
		remove_from_hash_table_unsafe(p_cell);
		p_cell->flags |= T_IN_AGONY;
		/* delete (returns with UNLOCK-ed_HASH) */
		ret = delete_cell(p_cell, 1 /* unlock on return */);
	}
#endif /* TM_DEL_UNREF */
	return ret;
}
예제 #2
0
inline static void wait_handler( struct timer_link *wait_tl )
{
	struct cell *p_cell;

	p_cell = get_wait_timer_payload( wait_tl );
#ifdef EXTRA_DEBUG
	if (p_cell->damocles) {
		LM_ERR("transaction %p scheduled for deletion and"
			" called from WAIT timer\n",p_cell);
		abort();
	}
	LM_DBG("WAIT timer hit\n");
#endif

	/* stop cancel timers if any running */
	if ( is_invite(p_cell) ) cleanup_localcancel_timers( p_cell );

	/* the transaction is already removed from WT_LIST by the timer */
	/* remove the cell from the hash table */
	LM_DBG("removing %p from table \n", p_cell );
	LOCK_HASH( p_cell->hash_index );
	remove_from_hash_table_unsafe(  p_cell );
	/* jku: no more here -- we do it when we put a transaction on wait */
#ifdef EXTRA_DEBUG
	p_cell->damocles = 1;
#endif
	/* delete (returns with UNLOCK-ed_HASH) */
	delete_cell( p_cell, 1 /* unlock on return */ );
	LM_DBG("done\n");
}
예제 #3
0
파일: timer.c 프로젝트: btriller/kamailio
/* generate a fake reply
 * it assumes the REPLY_LOCK is already held and returns unlocked */
static void fake_reply(struct cell *t, int branch, int code)
{
	struct cancel_info cancel_data;
	short do_cancel_branch;
	enum rps reply_status;

	init_cancel_info(&cancel_data);
	do_cancel_branch = is_invite(t) && prepare_cancel_branch(t, branch, 0);
	/* mark branch as canceled */
	t->uac[branch].request.flags |= F_RB_CANCELED;
	t->uac[branch].request.flags |= F_RB_RELAYREPLY;
	if(is_local(t)) {
		reply_status = local_reply(t, FAKED_REPLY, branch, code, &cancel_data);
	} else {
		/* rely reply, but don't put on wait, we still need t
		 * to send the cancels */
		reply_status =
				relay_reply(t, FAKED_REPLY, branch, code, &cancel_data, 0);
	}
/* now when out-of-lock do the cancel I/O */
#ifdef CANCEL_REASON_SUPPORT
	if(do_cancel_branch)
		cancel_branch(t, branch, &cancel_data.reason, 0);
#else /* CANCEL_REASON_SUPPORT */
	if(do_cancel_branch)
		cancel_branch(t, branch, 0);
#endif /* CANCEL_REASON_SUPPORT */
	/* it's cleaned up on error; if no error occurred and transaction
	   completed regularly, I have to clean-up myself
	*/
	if(reply_status == RPS_COMPLETED)
		put_on_wait(t);
}
예제 #4
0
파일: acc_logic.c 프로젝트: UIKit0/OpenSIPS
/* parse incoming replies before cloning */
static inline void acc_onreply_in(struct cell *t, struct sip_msg *req,
											struct sip_msg *reply, int code)
{
	/* don't parse replies in which we are not interested */
	/* missed calls enabled ? */
	if ( (reply && reply!=FAKED_REPLY) && (should_acc_reply(req,reply,code)
	|| (is_invite(t) && code>=300 && is_mc_on(req))) ) {
		parse_headers(reply, HDR_TO_F, 0 );
	}
}
예제 #5
0
파일: tm.c 프로젝트: Deni90/opensips
inline static int w_t_cancel_branch(struct sip_msg *msg, char *sflags)
{
	branch_bm_t cancel_bitmap = 0;
	struct cell *t;
	unsigned int flags = (unsigned long)sflags;

	t=get_t();

	if (t==NULL || t==T_UNDEFINED) {
		/* no transaction */
		LM_ERR("cannot cancel a reply with no transaction");
		return -1;
	}
	if (!is_invite(t))
		return -1;

	if (flags&TM_CANCEL_BRANCH_ALL) {
		/* lock and get the branches to cancel */
		if (!onreply_avp_mode) {
			LOCK_REPLIES(t);
			which_cancel( t, &cancel_bitmap );
			UNLOCK_REPLIES(t);
		} else {
			which_cancel( t, &cancel_bitmap );
		}
		if (msg->first_line.u.reply.statuscode>=200)
			/* do not cancel the current branch as we got
			 * a final response here */
			cancel_bitmap &= ~(1<<_tm_branch_index);
	} else if (flags&TM_CANCEL_BRANCH_OTHERS) {
		/* lock and get the branches to cancel */
		if (!onreply_avp_mode) {
			LOCK_REPLIES(t);
			which_cancel( t, &cancel_bitmap );
			UNLOCK_REPLIES(t);
		} else {
			which_cancel( t, &cancel_bitmap );
		}
		/* ignore current branch */
		cancel_bitmap &= ~(1<<_tm_branch_index);
	} else {
		/* cancel only local branch (only if still ongoing) */
		if (msg->first_line.u.reply.statuscode<200)
			cancel_bitmap = 1<<_tm_branch_index;
	}

	/* send cancels out */
	cancel_uacs(t, cancel_bitmap);

	return 1;
}
예제 #6
0
/* initiate a report if we previously enabled MC accounting for this t */
static void failure_handler(struct cell *t, int type, struct tmcb_params* ps)
{
	/* validation */
	if (t->uas.request == 0) {
		DBG("DBG:acc:failure_handler: No uas.request, skipping local transaction\n");
		return;
	}

	if (is_invite(t) && ps->code >= 300) {
		if (is_mc_on(t->uas.request)) {
			log_missed(t, ps->rpl, ps->code, (time_t)*(ps->param));
			resetflag(t->uas.request, log_missed_flag);
		}
	}
}
예제 #7
0
/* parse incoming replies before cloning */
static void replyin_handler(struct cell *t, int type, struct tmcb_params* ps)
{
	     /* validation */
	if (t->uas.request == 0) {
		LOG(L_ERR, "ERROR:acc:replyin_handler:replyin_handler: 0 request\n");
		return;
	}

	     /* don't parse replies in which we are not interested */
	     /* missed calls enabled ? */
	if (((is_invite(t) && ps->code >= 300 && is_mc_on(t->uas.request))
	     || should_acc_reply(t, ps->code))
	    && (ps->rpl && ps->rpl != FAKED_REPLY)) {
		parse_headers(ps->rpl, HDR_TO_F, 0);
	}
}
예제 #8
0
char *build_cancel(struct cell *Trans,unsigned int branch,
	unsigned int *len )
{
	str method = str_init(CANCEL);
	str reason = str_init(CANCEL_REASON CRLF);
	str *extra = NULL;

	/* add the reason hdr, as per RFC 3326 */
	if (is_invite(Trans) && Trans->uas.status==200) {
		extra = &reason;
	} else if (_extra_cancel_hdrs.s) {
		extra = &_extra_cancel_hdrs;
	}
	return build_local( Trans, branch, &method, extra,
		Trans->uac[branch].reply , len );
}
예제 #9
0
static int t_cancel_branches(sip_msg_t* msg, char *k, char *s2)
{
	struct cancel_info cancel_data;
	tm_cell_t *t = 0;
	tm_ctx_t *tcx = 0;
	int n=0;
	int idx = 0;
	t=_tmx_tmb.t_gett();
	if (t==NULL || t==T_UNDEFINED || !is_invite(t))
		return -1;
	tcx = _tmx_tmb.tm_ctx_get();
	if(tcx != NULL)
		idx = tcx->branch_index;
	n = (int)(long)k;
	init_cancel_info(&cancel_data);
	switch(n) {
		case 1:
			/* prepare cancel for every branch except idx (others) */
			_tmx_tmb.prepare_to_cancel(t,
					&cancel_data.cancel_bitmap, 1<<idx);
			break;
		case 2:
			/* prepare cancel for current branch (idx) */
			if(msg->first_line.u.reply.statuscode>=200)
				break;
			cancel_data.cancel_bitmap = 1<<idx;
			break;
		default:
			/* prepare cancel for all branches */
			if (msg->first_line.u.reply.statuscode>=200)
				/* prepare cancel for every branch except idx */
				_tmx_tmb.prepare_to_cancel(t,
						&cancel_data.cancel_bitmap, 1<<idx);
			else
				_tmx_tmb.prepare_to_cancel(t,
						&cancel_data.cancel_bitmap, 0);
	}
	LM_DBG("canceling %d/%d\n", n, (int)cancel_data.cancel_bitmap);
	if(cancel_data.cancel_bitmap==0)
		return -1;
	_tmx_tmb.cancel_uacs(t, &cancel_data, 0);
	return 1;
}
예제 #10
0
char *build_cancel(struct cell *Trans,unsigned int branch,
	unsigned int *len )
{
	str method = str_init(CANCEL);
	str reason = str_init(CANCEL_REASON CRLF);
	str *extra = NULL;

	/* add the reason hdr, as per RFC 3326 */
	if (is_invite(Trans) && Trans->uas.status==200) {
		extra = &reason;
	} else if (_extra_cancel_hdrs.s) {
		extra = &_extra_cancel_hdrs;
	}
	return build_local( Trans, branch, &method, extra,
		NULL /*reply*/ , len );
	/* ^^^^ when CANCELing, there are 0 chances to have a reply stored into
	 * transaction ; set it NULL to avoid using the temporary stored reply 
	 * (by t_should_relay_response) which may lead into races ( building the
	 * cancel versus handling a final response in a different process )*/
}
예제 #11
0
static void fake_reply(struct cell *t, int branch, int code )
{
	branch_bm_t cancel_bitmap;
	short do_cancel_branch;
	enum rps reply_status;

	do_cancel_branch = is_invite(t) && should_cancel_branch(t, branch);

	cancel_bitmap=do_cancel_branch ? 1<<branch : 0;
	if ( is_local(t) ) {
		reply_status=local_reply( t, FAKED_REPLY, branch,
					  code, &cancel_bitmap );
		if (reply_status==RPS_COMPLETED) {
			put_on_wait(t);
		}
	} else {
		reply_status=relay_reply( t, FAKED_REPLY, branch, code,
			&cancel_bitmap );
	}
}
예제 #12
0
/* Continues the SIP request processing previously saved by
 * t_suspend(). The script does not continue from the same
 * point, but a separate route block is executed instead.
 *
 * Return value:
 * 	0  - success
 * 	<0 - failure
 */
int t_continue(unsigned int hash_index, unsigned int label,
		struct action *route)
{
	struct cell	*t;
	struct sip_msg	faked_req;
	struct cancel_info cancel_data;
	int	branch;
	struct ua_client *uac =NULL;
	int	ret;
	int cb_type;
	int msg_status;
	int last_uac_status;
	int reply_status;
	int do_put_on_wait;
	struct hdr_field *hdr, *prev = 0, *tmp = 0;

	if (t_lookup_ident(&t, hash_index, label) < 0) {
		LM_ERR("transaction not found\n");
		return -1;
	}

	if (!(t->flags & T_ASYNC_SUSPENDED)) {
		LM_WARN("transaction is not suspended [%u:%u]\n", hash_index, label);
		return -2;
	}

	if (t->flags & T_CANCELED) {
		t->flags &= ~T_ASYNC_SUSPENDED;
		/* The transaction has already been canceled,
		 * needless to continue */
		UNREF(t); /* t_unref would kill the transaction */
		/* reset T as we have no working T anymore */
		set_t(T_UNDEFINED, T_BR_UNDEFINED);
		return 1;
	}

	/* The transaction has to be locked to protect it
	 * form calling t_continue() multiple times simultaneously */
	LOCK_ASYNC_CONTINUE(t);

	t->flags |= T_ASYNC_CONTINUE;   /* we can now know anywhere in kamailio
					 * that we are executing post a suspend */

	/* which route block type were we in when we were suspended */
	cb_type =  FAILURE_CB_TYPE;;
	switch (t->async_backup.backup_route) {
		case REQUEST_ROUTE:
			cb_type = FAILURE_CB_TYPE;
			break;
		case FAILURE_ROUTE:
			cb_type = FAILURE_CB_TYPE;
			break;
		case TM_ONREPLY_ROUTE:
			cb_type = ONREPLY_CB_TYPE;
			break;
		case BRANCH_ROUTE:
			cb_type = FAILURE_CB_TYPE;
			break;
	}

	if(t->async_backup.backup_route != TM_ONREPLY_ROUTE){
		branch = t->async_backup.blind_uac;	/* get the branch of the blind UAC setup 
			* during suspend */
		if (branch >= 0) {
			stop_rb_timers(&t->uac[branch].request);
 
			if (t->uac[branch].last_received != 0) {
				/* Either t_continue() has already been
				* called or the branch has already timed out.
				* Needless to continue. */
				t->flags &= ~T_ASYNC_SUSPENDED;
				UNLOCK_ASYNC_CONTINUE(t);
				UNREF(t); /* t_unref would kill the transaction */
				return 1;
			}

			/* Set last_received to something >= 200,
			 * the actual value does not matter, the branch
			 * will never be picked up for response forwarding.
			 * If last_received is lower than 200,
			 * then the branch may tried to be cancelled later,
			 * for example when t_reply() is called from
			 * a failure route => deadlock, because both
			 * of them need the reply lock to be held. */
			t->uac[branch].last_received=500;
			uac = &t->uac[branch];
		}
		/* else
			Not a huge problem, fr timer will fire, but CANCEL
			will not be sent. last_received will be set to 408. */

		/* We should not reset kr here to 0 as it's quite possible before continuing the dev. has correctly set the
		 * kr by, for example, sending a transactional reply in code - resetting here will cause a dirty log message
		 * "WARNING: script writer didn't release transaction" to appear in log files. TODO: maybe we need to add 
		 * a special kr for async?
		 * reset_kr();
		 */

		/* fake the request and the environment, like in failure_route */
		if (!fake_req(&faked_req, t->uas.request, 0 /* extra flags */, uac)) {
			LM_ERR("building fake_req failed\n");
			ret = -1;
			goto kill_trans;
		}
		faked_env( t, &faked_req, 1);

		/* execute the pre/post -script callbacks based on original route block */
		if (exec_pre_script_cb(&faked_req, cb_type)>0) {
			if (run_top_route(route, &faked_req, 0)<0)
				LM_ERR("failure inside run_top_route\n");
			exec_post_script_cb(&faked_req, cb_type);
		}

		/* TODO: save_msg_lumps should clone the lumps to shm mem */

		/* restore original environment and free the fake msg */
		faked_env( t, 0, 1);
		free_faked_req(&faked_req, t);

		/* update the flags */
		t->uas.request->flags = faked_req.flags;

		if (t->uas.status < 200) {
			/* No final reply has been sent yet.
			* Check whether or not there is any pending branch.
			*/
			for (	branch = 0;
				branch < t->nr_of_outgoings;
				branch++
			) {
				if (t->uac[branch].last_received < 200)
					break;
			}

			if (branch == t->nr_of_outgoings) {
			/* There is not any open branch so there is
			* no chance that a final response will be received. */
				ret = 0;
				goto kill_trans;
			}
		}

	} else {
		branch = t->async_backup.backup_branch;

		init_cancel_info(&cancel_data);

		LM_DBG("continuing from a suspended reply"
				" - resetting the suspend branch flag\n");

		if (t->uac[branch].reply) {
		t->uac[branch].reply->msg_flags &= ~FL_RPL_SUSPENDED;
                } else {
			LM_WARN("no reply in t_continue for branch. not much we can do\n");
			return 0;
		}
                
		if (t->uas.request) t->uas.request->msg_flags&= ~FL_RPL_SUSPENDED;

		faked_env( t, t->uac[branch].reply, 1);

		if (exec_pre_script_cb(t->uac[branch].reply, cb_type)>0) {
			if (run_top_route(route, t->uac[branch].reply, 0)<0){
				LOG(L_ERR, "ERROR: t_continue_reply: Error in run_top_route\n");
			}
			exec_post_script_cb(t->uac[branch].reply, cb_type);
		}

		LM_DBG("restoring previous environment");
		faked_env( t, 0, 1);

		/*lock transaction replies - will be unlocked when reply is relayed*/
		LOCK_REPLIES( t );
		if ( is_local(t) ) {
			LM_DBG("t is local - sending reply with status code: [%d]\n",
					t->uac[branch].reply->first_line.u.reply.statuscode);
			reply_status = local_reply( t, t->uac[branch].reply, branch,
					t->uac[branch].reply->first_line.u.reply.statuscode,
					&cancel_data );
			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_data, 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 (unlikely(cancel_data.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_data, cfg_get(tm,tm_cfg, cancel_b_flags));
			}

		} else {
			LM_DBG("t is not local - relaying reply with status code: [%d]\n",
					t->uac[branch].reply->first_line.u.reply.statuscode);
			do_put_on_wait = 0;
			if(t->uac[branch].reply->first_line.u.reply.statuscode>=200){
				do_put_on_wait = 1;
			}
			reply_status=relay_reply( t, t->uac[branch].reply, branch,
					t->uac[branch].reply->first_line.u.reply.statuscode,
					&cancel_data, do_put_on_wait );
			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_data.cancel_bitmap) 
					cancel_uacs( t, &cancel_data,  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 (unlikely(cancel_data.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_data, cfg_get(tm,tm_cfg, cancel_b_flags));
			}

		}
		t->uac[branch].request.flags|=F_RB_REPLIED;

		if (reply_status==RPS_ERROR){
			goto done;
		}

		/* update FR/RETR timers on provisional replies */

		msg_status=t->uac[branch].reply->REPLY_STATUS;
		last_uac_status=t->uac[branch].last_received;

		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(& t->uac[branch].request, t->fr_inv_timeout);
			t->uac[branch].request.flags|=F_RB_FR_INV; /* mark fr_inv */
		}
            
	}

done:
	UNLOCK_ASYNC_CONTINUE(t);

	if(t->async_backup.backup_route != TM_ONREPLY_ROUTE){
		/* unref the transaction */
		t_unref(t->uas.request);
	} else {
		tm_ctx_set_branch_index(T_BR_UNDEFINED);        
		/* unref the transaction */
		t_unref(t->uac[branch].reply);
		LOG(L_DBG,"DEBUG: t_continue_reply: Freeing earlier cloned reply\n");

		/* free lumps that were added during reply processing */
		del_nonshm_lump( &(t->uac[branch].reply->add_rm) );
		del_nonshm_lump( &(t->uac[branch].reply->body_lumps) );
		del_nonshm_lump_rpl( &(t->uac[branch].reply->reply_lump) );

		/* free header's parsed structures that were added */
		for( hdr=t->uac[branch].reply->headers ; hdr ; hdr=hdr->next ) {
			if ( hdr->parsed && hdr_allocs_parse(hdr) &&
				(hdr->parsed<(void*)t->uac[branch].reply ||
				hdr->parsed>=(void*)t->uac[branch].end_reply)) {
				clean_hdr_field(hdr);
				hdr->parsed = 0;
			}
		}

		/* now go through hdr_fields themselves and remove the pkg allocated space */
		hdr = t->uac[branch].reply->headers;
		while (hdr) {
			if ( hdr && ((void*)hdr<(void*)t->uac[branch].reply ||
				(void*)hdr>=(void*)t->uac[branch].end_reply)) {
				//this header needs to be freed and removed form the list.
				if (!prev) {
					t->uac[branch].reply->headers = hdr->next;
				} else {
					prev->next = hdr->next;
				}
				tmp = hdr;
				hdr = hdr->next;
				pkg_free(tmp);
			} else {
				prev = hdr;
				hdr = hdr->next;
			}
		}
		sip_msg_free(t->uac[branch].reply);
		t->uac[branch].reply = 0;
	}

	/*This transaction is no longer suspended so unsetting the SUSPEND flag*/
	t->flags &= ~T_ASYNC_SUSPENDED;


	return 0;

kill_trans:
	t->flags &= ~T_ASYNC_SUSPENDED;
	/* The script has hopefully set the error code. If not,
	 * let us reply with a default error. */
	if ((kill_transaction_unsafe(t,
		tm_error ? tm_error : E_UNSPEC)) <=0
	) {
		LOG(L_ERR, "ERROR: t_continue: "
			"reply generation failed\n");
		/* The transaction must be explicitely released,
		 * no more timer is running */
		UNLOCK_ASYNC_CONTINUE(t);
		t_release_transaction(t);
	} else {
		UNLOCK_ASYNC_CONTINUE(t);
	}

	if(t->async_backup.backup_route != TM_ONREPLY_ROUTE){
		t_unref(t->uas.request);
	} else {
		/* unref the transaction */
		t_unref(t->uac[branch].reply);
	}
	return ret;
}
예제 #13
0
/**
 * ac_reply: UAS transaction Reply action. It replies to an incoming request with a response.
 * @param the_as The App Server that sent this action.
 * @param action action
 * @param len length
 *
 * function description
 *
 * Returns: what
 */
int ac_reply(as_p the_as,unsigned char processor_id,unsigned int flags,char *action,int len)
{
   unsigned int hash_index,label,contentlength;
   struct cell *c=NULL;
   struct sip_msg *my_msg;
   struct to_body *tb;
   str new_header,body,totag;
   char *ttag;
   int i,k,retval;
   static char headers[MAX_HEADER];
   struct as_uac_param *the_param;

   contentlength=0;
   ttag=NULL;
   my_msg=NULL;
   i=k=0;
   the_param=NULL;

   net2hostL(hash_index,action,k);
   net2hostL(label,action,k);

   if(seas_f.tmb.t_lookup_ident(&c,hash_index,label)<0){
      LM_ERR("Failed to t_lookup_ident hash_idx=%d,label=%d\n",hash_index,label);
      goto error;
   }
   if(use_stats)
      action_stat(c);
   if(c->uas.status>=200){
      LM_ERR("ac_reply: trying to reply to a \"%.*s\" transaction"
	    "that is already in completed state\n",REQ_LINE(c->uas.request).method.len,REQ_LINE(c->uas.request).method.s);
      goto error;
   }
   if (!(my_msg=parse_ac_msg(HDR_EOH_F,action+k,len-k))) {
      LM_ERR("Failed to parse_ac_msg hash_idx=%d,label=%d\n",hash_index,label);
      goto error;
   }
   tb=(struct to_body*)my_msg->to->parsed;
   if(tb->tag_value.s && tb->tag_value.len){
      totag=tb->tag_value;
   }else{
      totag.s=NULL;
      totag.len=0;
      /*if(!(ttag=pkg_malloc(TOTAG_VALUE_LEN))){
	 LM_ERR("Out of memory !!!\n");
	 goto error;
      }
      totag.s=ttag;
      calc_crc_suffix(c->uas.request,seas_tag_suffix);
      LM_DBG("seas_tags = %.*s\n",TOTAG_VALUE_LEN,seas_tags);
      memcpy(totag.s,seas_tags,TOTAG_VALUE_LEN);
      totag.len=TOTAG_VALUE_LEN;*/
   }
   LM_DBG("Using totag=[%.*s]\n",totag.len,totag.s);
   if(my_msg->content_length)
      contentlength=(unsigned int)(long)my_msg->content_length->parsed;
   if(0>(i=recordroute_diff(c->uas.request,my_msg))){/*not likely..*/
      LM_DBG("Seems that request had more RecordRoutes than response...\n");
      /* This prevents host->proxy->host from working. TODO review recordroute_diff code.
      goto error; */
   }else
      LM_DBG("Recordroute Diff = %d\n",i);

   if(0>(i=extract_allowed_headers(my_msg,0,i,HDR_VIA_F|HDR_TO_F|HDR_FROM_F|HDR_CSEQ_F|HDR_CALLID_F|HDR_CONTENTLENGTH_F,headers,MAX_HEADER))){
      LM_ERR("ac_reply() filtering headers !\n");
      goto error;
   }
   headers[i]=0;
   new_header.s=headers;
   new_header.len=i;

   /* If it is INVITE and response is success (>=200 && <300), we mark it as local so that
    * SER does NOT retransmit the final response (by default, SER retransmit local UAS final
    * responses...*/
   if(is_invite(c) && my_msg->first_line.u.reply.statuscode>=200 && my_msg->first_line.u.reply.statuscode<300){
      c->flags |= T_IS_LOCAL_FLAG;
      if(!(the_param=shm_malloc(sizeof(struct as_uac_param)))){
         LM_ERR("no more share memory\n");
         goto error;
      }
      the_param->processor_id=processor_id;
      the_param->who=my_as;
      the_param->destroy_cb_set=0;
      if (seas_f.tmb.register_tmcb( 0, c, TMCB_E2EACK_IN,uas_e2e_ack_cb, the_param,&param_free)<=0) {
         LM_ERR("cannot register additional callbacks\n");
         goto error;
      }
   }
   /*WARNING casting unsigned int to int*/
   body.len=contentlength;
   body.s=get_body(my_msg);

   LM_DBG("Trying to construct a SipReply with: ReasonPhrase:[%.*s] body:[%.*s] headers:[%.*s] totag:[%.*s]\n",\
	 my_msg->first_line.u.reply.reason.len,my_msg->first_line.u.reply.reason.s,\
	 body.len,body.s,new_header.len,new_header.s,totag.len,totag.s);
   /* t_reply_with_body un-ref-counts the transaction, so dont use it anymore*/
   if(seas_f.tmb.t_reply_with_body(c,my_msg->first_line.u.reply.statuscode,&(my_msg->first_line.u.reply.reason),&body,&new_header,&totag)<0){
      LM_ERR("Failed to t_reply\n");
      goto error;
   }
   retval=0;
   goto exit;
error:
   retval = -1;
   if(c)
      seas_f.tmb.unref_cell(c);
   if(the_param)
      shm_free(the_param);
exit:
   if(ttag)
      pkg_free(ttag);
   if(my_msg){
      free_sip_msg_lite(my_msg);
      pkg_free(my_msg);
   }
   return retval;
}
예제 #14
0
파일: acc_logic.c 프로젝트: UIKit0/OpenSIPS
/* initiate a report if we previously enabled accounting for this t */
static inline void acc_onreply( struct cell* t, struct sip_msg *req,
											struct sip_msg *reply, int code)
{
	str new_uri_bk;
	str dst_uri_bk;
	struct dlg_cell *dlg = NULL;
	str flags_s;
	int_str table;
	struct usr_avp *avp;

	/* acc_onreply is bound to TMCB_REPLY which may be called
	   from _reply, like when FR hits; we should not miss this
	   event for missed calls either */
	if (is_invite(t) && code>=300 && is_mc_on(req) )
		on_missed(t, req, reply, code);

	if (!should_acc_reply(req, reply, code))
		return;

	/* for reply processing, set as new_uri the winning branch */
	if (t->relaied_reply_branch>=0) {
		new_uri_bk = req->new_uri;
		dst_uri_bk = req->dst_uri;
		req->new_uri = t->uac[t->relaied_reply_branch].uri;
		req->dst_uri = t->uac[t->relaied_reply_branch].duri;
		req->parsed_uri_ok = 0;
	} else {
		new_uri_bk.len = dst_uri_bk.len = -1;
		new_uri_bk.s = dst_uri_bk.s = NULL;
	}
	/* set env variables */
	env_set_to( get_rpl_to(t,reply) );
	env_set_code_status( code, reply);

	/* search for table avp */
	table.s = db_table_acc;
	if (db_table_name != -1 && is_db_acc_on(req)) {
		avp = search_first_avp(db_table_name_type, db_table_name, &table, 0);
		if (!avp) {
			LM_DBG("table not set: using default %.*s\n",
					db_table_acc.len, db_table_acc.s);
		} else {
			if (!(avp->flags & AVP_VAL_STR)) {
				LM_WARN("invalid integer table name: using default %.*s\n",
					db_table_acc.len, db_table_acc.s);
				table.s = db_table_acc;
			}
		}
	}

	if (is_invite(t) && is_cdr_acc_on(req) && code >= 200 && code < 300
			&& (dlg=dlg_api.get_dlg()) != NULL) {
		/* if dialog module loaded and INVITE and success reply */
		if (store_core_leg_values(dlg, req) < 0) {
			LM_ERR("cannot store core and leg values\n");
			return;
		}

		if(is_log_acc_on(req) && store_log_extra_values(dlg,req,reply)<0){
			LM_ERR("cannot store string values\n");
			return;
		}

		if(is_aaa_acc_on(req) && store_aaa_extra_values(dlg, req, reply)<0){
			LM_ERR("cannot store aaa extra values\n");
			return;
		}

		if (is_db_acc_on(req) && store_db_extra_values(dlg,req,reply)<0) {
			LM_ERR("cannot store database extra values\n");
			return;
		}

		flags_s.s = (char*)&req->flags;
		flags_s.len = sizeof(unsigned int);
		
		/* store flags into dlg */ 
		if ( dlg_api.store_dlg_value(dlg, &flags_str, &flags_s) < 0) {
			LM_ERR("cannot store flag value into dialog\n");
			return;
		}

		/* store flags into dlg */ 
		if ( dlg_api.store_dlg_value(dlg, &table_str, &table.s) < 0) {
			LM_ERR("cannot store the table name into dialog\n");
			return;
		}
		/* register database callbacks */
		if (dlg_api.register_dlgcb(dlg, DLGCB_TERMINATED |
				DLGCB_EXPIRED, acc_dlg_callback,(void *)(long)req->flags,0) != 0) {
			LM_ERR("cannot register callback for database accounting\n");
			return;
		}
	} else {
		/* do old accounting */
		if ( is_log_acc_on(req) ) {
			env_set_text( ACC_ANSWERED, ACC_ANSWERED_LEN);
			acc_log_request( req, reply );
		}

		if (is_aaa_acc_on(req))
			acc_aaa_request( req, reply );
	
		if (is_db_acc_on(req)) {
			env_set_text( table.s.s, table.s.len);
			acc_db_request( req, reply, &acc_ins_list);
		}
	}

/* DIAMETER */
#ifdef DIAM_ACC
	if (is_diam_acc_on(req))
		acc_diam_request( req, reply );
#endif

	if (new_uri_bk.len>=0) {
		req->new_uri = new_uri_bk;
		req->dst_uri = dst_uri_bk;
		req->parsed_uri_ok = 0;
	}
}
예제 #15
0
파일: timer.c 프로젝트: btriller/kamailio
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);
}
예제 #16
0
파일: t_reply.c 프로젝트: iamroger/voip
/* 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 );
	LM_DBG("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) {
			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;
		stats_trans_rpl( winning_code, (winning_msg==FAKED_REPLY)?1:0 );
		if (is_invite(t) && winning_msg!=FAKED_REPLY
		&& winning_code>=200 && winning_code <300
		&& has_tran_tmcbs(t,
		TMCB_RESPONSE_OUT|TMCB_RESPONSE_PRE_OUT) )  {
			totag_retr=update_totag_set(t, winning_msg);
		}
	}
	UNLOCK_REPLIES(t);

	if ( local_winner >= 0 ) {
		if (winning_code < 200) {
			if (!totag_retr && has_tran_tmcbs(t,TMCB_LOCAL_RESPONSE_OUT)) {
				LM_DBG("Passing provisional reply %d to FIFO application\n",
						winning_code);
				run_trans_callbacks( TMCB_LOCAL_RESPONSE_OUT, t, 0,
					winning_msg, winning_code);
			}
		} else {
			LM_DBG("local transaction completed\n");
			if (!totag_retr && 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_id==METHOD_INVITE )
		cancel_uacs( t, *cancel_bitmap );
	put_on_wait(t);
	return RPS_ERROR;
}
예제 #17
0
/* Returns 0 - nothing found
 *         1  - T found
 */
int t_reply_matching( struct sip_msg *p_msg , int *p_branch )
{
	struct cell*  p_cell;
	unsigned int hash_index   = 0;
	unsigned int entry_label  = 0;
	unsigned int branch_id    = 0;
	char  *hashi, *branchi, *p, *n;
	int hashl, branchl;
	int scan_space;
	str cseq_method;
	str req_method;

	char *loopi;
	int loopl;
	char *syni;
	int synl;
	
	short is_cancel;

	/* make compiler warnings happy */
	loopi=0;
	loopl=0;
	syni=0;
	synl=0;

	/* split the branch into pieces: loop_detection_check(ignored),
	 hash_table_id, synonym_id, branch_id */

	if (!(p_msg->via1 && p_msg->via1->branch && p_msg->via1->branch->value.s))
		goto nomatch2;

	/* we do RFC 3261 tid matching and want to see first if there is
	 * magic cookie in branch */
	if (p_msg->via1->branch->value.len<=MCOOKIE_LEN)
		goto nomatch2;
	if (memcmp(p_msg->via1->branch->value.s, MCOOKIE, MCOOKIE_LEN)!=0)
		goto nomatch2;

	p=p_msg->via1->branch->value.s+MCOOKIE_LEN;
	scan_space=p_msg->via1->branch->value.len-MCOOKIE_LEN;


	/* hash_id */
	n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR);
	hashl=n-p;
	scan_space-=hashl;
	if (!hashl || scan_space<2 || *n!=BRANCH_SEPARATOR) goto nomatch2;
	hashi=p;
	p=n+1;scan_space--;

	if (!syn_branch) {
		/* md5 value */
		n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR );
		loopl = n-p;
		scan_space-= loopl;
		if (n==p || scan_space<2 || *n!=BRANCH_SEPARATOR) 
			goto nomatch2;
		loopi=p;
		p=n+1; scan_space--;
	} else {
		/* synonym id */
		n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR);
		synl=n-p;
		scan_space-=synl;
		if (!synl || scan_space<2 || *n!=BRANCH_SEPARATOR) 
			goto nomatch2;
		syni=p;
		p=n+1;scan_space--;
	}

	/* branch id  -  should exceed the scan_space */
	n=eat_token_end( p, p+scan_space );
	branchl=n-p;
	if (!branchl ) goto nomatch2;
	branchi=p;

	/* sanity check */
	if (reverse_hex2int(hashi, hashl, &hash_index)<0
		||hash_index>=TABLE_ENTRIES
		|| reverse_hex2int(branchi, branchl, &branch_id)<0
		||branch_id>=MAX_BRANCHES
		|| (syn_branch ? (reverse_hex2int(syni, synl, &entry_label))<0 
			: loopl!=MD5_LEN )
	) {
		DBG("DEBUG: t_reply_matching: poor reply labels %d label %d "
			"branch %d\n", hash_index, entry_label, branch_id );
		goto nomatch2;
	}


	DBG("DEBUG: t_reply_matching: hash %d label %d branch %d\n",
		hash_index, entry_label, branch_id );


	/* search the hash table list at entry 'hash_index'; lock the
	   entry first 
	*/
	cseq_method=get_cseq(p_msg)->method;
	is_cancel=cseq_method.len==CANCEL_LEN 
		&& memcmp(cseq_method.s, CANCEL, CANCEL_LEN)==0;
	LOCK_HASH(hash_index);
	for (p_cell = get_tm_table()->entrys[hash_index].first_cell; p_cell; 
		p_cell=p_cell->next_cell) {

		/* first look if branch matches */

		if (syn_branch) {
			if (p_cell->label != entry_label) 
				continue;
		} else {
			if ( memcmp(p_cell->md5, loopi,MD5_LEN)!=0)
					continue;
		}

		/* sanity check ... too high branch ? */
		if ( branch_id>=p_cell->nr_of_outgoings )
			continue;

		/* does method match ? (remember -- CANCELs have the same branch
		   as canceled transactions) */
		req_method=p_cell->method;
		if ( /* method match */
			! ((cseq_method.len==req_method.len 
			&& memcmp( cseq_method.s, req_method.s, cseq_method.len )==0)
			/* or it is a local cancel */
			|| (is_cancel && is_invite(p_cell)
				/* commented out -- should_cancel_branch set it to
				   BUSY_BUFFER to avoid collisions with replies;
				   thus, we test here by buffer size
				*/
				/* && p_cell->uac[branch_id].local_cancel.buffer ))) */
				&& p_cell->uac[branch_id].local_cancel.buffer_len ))) 
			continue;


		/* we passed all disqualifying factors .... the transaction has been
		   matched !
		*/
		set_t(p_cell);
		*p_branch =(int) branch_id;
		REF_UNSAFE( T );
		UNLOCK_HASH(hash_index);
		DBG("DEBUG: t_reply_matching: reply matched (T=%p)!\n",T);
		/* if this is a 200 for INVITE, we will wish to store to-tags to be
		 * able to distinguish retransmissions later and not to call
 		 * TMCB_RESPONSE_OUT uselessly; we do it only if callbacks are
		 * enabled -- except callback customers, nobody cares about 
		 * retransmissions of multiple 200/INV or ACK/200s
		 */
		if (is_invite(p_cell) && p_msg->REPLY_STATUS>=200 
		&& p_msg->REPLY_STATUS<300 
		&& ( (!is_local(p_cell) &&
				has_tran_tmcbs(p_cell,TMCB_RESPONSE_OUT|TMCB_E2EACK_IN) )
			|| (is_local(p_cell)&&has_tran_tmcbs(p_cell,TMCB_LOCAL_COMPLETED))
		)) {
			if (parse_headers(p_msg, HDR_TO_F, 0)==-1) {
				LOG(L_ERR, "ERROR: t_reply_matching: to parsing failed\n");
			}
		}
		if (!is_local(p_cell)) {
			run_trans_callbacks( TMCB_RESPONSE_IN, T, T->uas.request, p_msg,
				p_msg->REPLY_STATUS);
		}
		return 1;
	} /* for cycle */

	/* nothing found */
	UNLOCK_HASH(hash_index);
	DBG("DEBUG: t_reply_matching: no matching transaction exists\n");

nomatch2:
	DBG("DEBUG: t_reply_matching: failure to match a transaction\n");
	*p_branch = -1;
	set_t(0);
	return -1;
}
예제 #18
0
/* initiate a report if we previously enabled accounting for this t */
static inline void acc_onreply( struct cell* t, struct sip_msg *req,
											struct sip_msg *reply, int code)
{
	str new_uri_bk;
	int br = -1;
	hdr_field_t *hdr;
	sip_msg_t tmsg;
	sip_msg_t *preq;

	/* acc_onreply is bound to TMCB_REPLY which may be called
	   from _reply, like when FR hits; we should not miss this
	   event for missed calls either */
	if (is_invite(t) && code>=300 && is_mc_on(req) )
		on_missed(t, req, reply, code);

	if (!should_acc_reply(req, reply, code))
		return;

	if(_acc_clone_msg==1) {
		memcpy(&tmsg, req, sizeof(sip_msg_t));
		preq = &tmsg;
	} else {
		preq = req;
	}

	/* get winning branch index, if set */
	if (t->relayed_reply_branch>=0) {
		br = t->relayed_reply_branch;
	} else {
		if(code>=300) {
			br = tmb.t_get_picked_branch();
		}
	}

	/* for reply processing, set as new_uri the one from selected branch */
	if (br>=0) {
		new_uri_bk = preq->new_uri;
		preq->new_uri = t->uac[br].uri;
		preq->parsed_uri_ok = 0;
	} else {
		new_uri_bk.len = -1;
		new_uri_bk.s = 0;
	}
	/* set env variables */
	env_set_to( get_rpl_to(t,reply) );
	env_set_code_status( code, reply);

	if ( is_log_acc_on(preq) ) {
		env_set_text( ACC_ANSWERED, ACC_ANSWERED_LEN);
		acc_log_request(preq);
	}
#ifdef SQL_ACC
	if (is_db_acc_on(preq)) {
		if(acc_db_set_table_name(preq, db_table_acc_data, &db_table_acc)<0) {
			LM_ERR("cannot set acc db table name\n");
		} else {
			acc_db_request(preq);
		}
	}
#endif
#ifdef RAD_ACC
	if (is_rad_acc_on(preq))
		acc_rad_request(preq);
#endif
/* DIAMETER */
#ifdef DIAM_ACC
	if (is_diam_acc_on(preq))
		acc_diam_request(preq);
#endif

	/* run extra acc engines */
	acc_run_engines(preq, 0, NULL);

	if (new_uri_bk.len>=0) {
		req->new_uri = new_uri_bk;
		req->parsed_uri_ok = 0;
	}

	/* free header's parsed structures that were added by resolving acc attributes */
	for( hdr=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 resolving acc attributes -> free it as pkg */
			DBG("removing hdr->parsed %d\n", hdr->type);
			clean_hdr_field(hdr);
			hdr->parsed = 0;
		}
	}
}
예제 #19
0
파일: t_reply.c 프로젝트: iamroger/voip
static int _reply_light( struct cell *trans, char* buf, unsigned int len,
			 unsigned int code, 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;
	str cb_s;

	if (!buf)
	{
		LM_DBG("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) {
		LM_ERR("failed to 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.s ? len : len + REPLY_OVERBUFFER_LEN;
	rb->buffer.s = (char*)shm_resize( rb->buffer.s, buf_len );
	/* puts the reply's buffer to uas.response */
	if (! rb->buffer.s ) {
			LM_ERR("failed to allocate shmem buffer\n");
			goto error3;
	}
	update_local_tags(trans, bm, rb->buffer.s, buf);

	rb->buffer.len = len ;
	memcpy( rb->buffer.s , buf , len );
	/* needs to be protected too because what timers are set depends
	   on current transactions status */
	/* t_update_timers_after_sending_reply( rb ); */
	trans->relaied_reply_branch=-2;
	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) ) {
			LM_DBG("local transaction completed\n");
			if ( has_tran_tmcbs(trans, TMCB_LOCAL_COMPLETED) ) {
				run_trans_callbacks( TMCB_LOCAL_COMPLETED, trans,
					0, FAKED_REPLY, code);
			}
		} else {
			/* run the PRE send callbacks */
			if ( has_tran_tmcbs(trans, TMCB_RESPONSE_PRE_OUT) ) {
				cb_s.s = buf;
				cb_s.len = len;
				set_extra_tmcb_params( &cb_s, &rb->dst);
				if (lock)
					run_trans_callbacks_locked( TMCB_RESPONSE_PRE_OUT, trans,
						trans->uas.request, FAKED_REPLY, code);
				else
					run_trans_callbacks( TMCB_RESPONSE_PRE_OUT, trans,
						trans->uas.request, FAKED_REPLY, code);
			}
		}

		if (!is_hopbyhop_cancel(trans)) {
			cleanup_uac_timers( trans );
			if (is_invite(trans)) cancel_uacs( trans, cancel_bitmap );
			/* for auth related replies, we do not do retransmission 
			   (via set_final_timer()), but only wait for a final 
			   reply (put_on_wait() ) - see RFC 3261 (26.3.2.4 DoS Protection) */
			if ((code != 401) && (code != 407))
				set_final_timer(  trans );
			else
				put_on_wait(trans);
		}
	}

	/* send it out : response.dst.send_sock is valid all the time now, 
	 * as it's taken from original request -bogdan */
	if (!trans->uas.response.dst.send_sock) {
		LM_CRIT("send_sock is NULL\n");
	}
	SEND_PR_BUFFER( rb, buf, len );
	LM_DBG("reply sent out. buf=%p: %.9s..., "
		"shmem=%p: %.9s\n", buf, buf, rb->buffer.s, rb->buffer.s );

	/* run the POST send callbacks */
	if (code>=200&&!is_local(trans)&&has_tran_tmcbs(trans,TMCB_RESPONSE_OUT)) {
		cb_s.s = buf;
		cb_s.len = len;
		set_extra_tmcb_params( &cb_s, &rb->dst);
		if (lock)
			run_trans_callbacks_locked( TMCB_RESPONSE_OUT, trans,
				trans->uas.request, FAKED_REPLY, code);
		else
			run_trans_callbacks( TMCB_RESPONSE_OUT, trans,
				trans->uas.request, FAKED_REPLY, code);
	}


	pkg_free( buf ) ;
	stats_trans_rpl( code, 1 /*local*/ );
	LM_DBG("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 );
	/* we did not succeed -- put the transaction on wait */
	put_on_wait(trans);
	return -1;
}
예제 #20
0
/* initiate a report if we previously enabled accounting for this t */
static inline void acc_onreply( struct cell* t, struct sip_msg *req,
					struct sip_msg *reply, int code, acc_ctx_t* ctx)
{
	str new_uri_bk;
	str dst_uri_bk;
	struct dlg_cell *dlg = NULL;
	str ctx_s;
	str table;

	unsigned long long* flags = &ctx->flags;

	/* acc_onreply is bound to TMCB_REPLY which may be called
	   from _reply, like when FR hits; we should not miss this
	   event for missed calls either */
	if (is_invite(t) && code>=300 && is_mc_acc_on(*flags) ) {
		on_missed(t, req, reply, code, ctx);
	}

	if (!should_acc_reply(req, reply, code, flags))
		return;

	/* for reply processing, set as new_uri the winning branch */
	if (t->relaied_reply_branch>=0) {
		new_uri_bk = req->new_uri;
		dst_uri_bk = req->dst_uri;
		req->new_uri = t->uac[t->relaied_reply_branch].uri;
		req->dst_uri = t->uac[t->relaied_reply_branch].duri;
		req->parsed_uri_ok = 0;
	} else {
		new_uri_bk.len = dst_uri_bk.len = -1;
		new_uri_bk.s = dst_uri_bk.s = NULL;
	}
	/* set env variables */
	env_set_to( get_rpl_to(t,reply) );
	env_set_code_status( code, reply);

	/* search for table avp */
	if (is_db_acc_on(ctx->flags))
		table = ctx->acc_table;
	else {
		table.s = 0;
		table.len = 0;
	}

	if (is_invite(t) && !has_totag(req) && is_cdr_acc_on(ctx->flags) &&
			code >= 200 && code < 300 && (dlg=dlg_api.get_dlg()) != NULL) {
		/* if dialog module loaded and INVITE and success reply */
		if (store_core_leg_values(dlg, req) < 0) {
			LM_ERR("cannot store core and leg values\n");
			return;
		}

		ctx_s.s = (char*)&ctx;
		ctx_s.len = sizeof(acc_ctx_t *);

		/* store context pointer into dialog */
		if (dlg_api.store_dlg_value(dlg, &acc_ctx_str, &ctx_s) < 0) {
			LM_ERR("cannot store context pointer into dlg val!\n");
			return;
		}

		/* report that flags shall be freed only by dialog module
		 * tm must never free it */
		set_dialog_context(*flags);

		/* register program shutdown callback
		 * won't register free function since TERMINATED|EXPIRED callback
		 * free function will be called to free */
		if (dlg_api.register_dlgcb(dlg, DLGCB_DB_WRITE_VP,
					acc_dlg_onshutdown, ctx, NULL) != 0) {
			LM_ERR("cannot register callback for program shutdown!\n");
			return;
		}

		/* register database callbacks */
		if (dlg_api.register_dlgcb(dlg, DLGCB_TERMINATED|DLGCB_EXPIRED,
								acc_dlg_callback, ctx, dlg_free_acc_ctx) != 0) {
			LM_ERR("cannot register callback for database accounting\n");
			return;
		}
	} else {
		/* do old accounting */
		if ( is_evi_acc_on(*flags) ) {
			env_set_event(acc_event);
			acc_evi_request( req, reply, 0 );
		}

		if ( is_log_acc_on(*flags) ) {
			env_set_text( ACC_ANSWERED, ACC_ANSWERED_LEN);
			acc_log_request( req, reply, 0 );
		}

		if (is_aaa_acc_on(*flags))
			acc_aaa_request( req, reply, 0 );

		if (is_db_acc_on(*flags)) {
			env_set_text( table.s, table.len);
			acc_db_request( req, reply, &acc_ins_list, 0);
		}
	}

	if (new_uri_bk.len>=0) {
		req->new_uri = new_uri_bk;
		req->dst_uri = dst_uri_bk;
		req->parsed_uri_ok = 0;
	}
}
예제 #21
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");
}
예제 #22
0
/**
 * ac_reply: UAS transaction Reply action. It replies to an incoming request with a response.
 * @param the_as The App Server that sent this action.
 * @param action action
 * @param len length
 *
 * function description
 *
 * Returns: what
 */
int ac_reply(as_p the_as,char *action,int len)
{
   unsigned int flags,hash_index,label;
   struct cell *c;
   struct sip_msg *my_msg;
   struct to_body *tb;
   str new_header,body,totag;
   char *ttag;
   int i,k,retval;
   static char headers[MAX_HEADER];

   ttag=NULL;
   my_msg=NULL;
   i=k=0;

   net2hostL(flags,action,k);
   net2hostL(hash_index,action,k);
   net2hostL(label,action,k);

   if(seas_f.tmb.t_lookup_ident(&c,hash_index,label)<0){
      LM_ERR("Failed to t_lookup_ident hash_idx=%d,label=%d\n",hash_index,label);
      goto error;
   }
   if(use_stats)
      action_stat(c);
   if(c->uas.status>=200){
      LM_ERR("ac_reply: trying to reply to a \"%.*s\" transaction"
	    "that is already in completed state\n",REQ_LINE(c->uas.request).method.len,REQ_LINE(c->uas.request).method.s);
      goto error;
   }
   if (!(my_msg=parse_ac_msg(HDR_EOH_F,action+k,len-k))) {
      LM_ERR("Failed to parse_ac_msg hash_idx=%d,label=%d\n",hash_index,label);
      goto error;
   }
   tb=(struct to_body*)my_msg->to->parsed;
   if(tb->tag_value.s && tb->tag_value.len){
      totag=tb->tag_value;
   }else{
      totag.s=NULL;
      totag.len=0;
      /*if(!(ttag=pkg_malloc(TOTAG_VALUE_LEN))){
	 LM_ERR("Out of memory !!!\n");
	 goto error;
      }
      totag.s=ttag;
      calc_crc_suffix(c->uas.request,seas_tag_suffix);
      LM_DBG("seas_tags = %.*s\n",TOTAG_VALUE_LEN,seas_tags);
      memcpy(totag.s,seas_tags,TOTAG_VALUE_LEN);
      totag.len=TOTAG_VALUE_LEN;*/
   }
   LM_DBG("Using totag=[%.*s]\n",totag.len,totag.s);
   if(0>(i=recordroute_diff(c->uas.request,my_msg))){/*not likely..*/
      LM_DBG("Seems that request had more RecordRoutes than response...\n");
      goto error;
   }else
      LM_DBG("Recordroute Diff = %d\n",i);

   if(0>(i=extract_allowed_headers(my_msg,0,i,HDR_VIA_F|HDR_TO_F|HDR_FROM_F|HDR_CSEQ_F|HDR_CALLID_F|HDR_CONTENTLENGTH_F,headers,MAX_HEADER))){
      LM_ERR("ac_reply() filtering headers !\n");
      goto error;
   }
   headers[i]=0;
   new_header.s=headers;
   new_header.len=i;

   /* If it is INVITE and response is success (>=200 && <300), we mark it as local so that
    * SER does NOT retransmit the final response (by default, SER retransmit local UAS final
    * responses...*/
   if(is_invite(c) && my_msg->first_line.u.reply.statuscode>=200 && my_msg->first_line.u.reply.statuscode<300)
      c->flags |= T_IS_LOCAL_FLAG;
   /*WARNING casting unsigned int to int*/
   get_body(my_msg, &body);

   LM_DBG("Trying to construct a SipReply with: ReasonPhrase:[%.*s] body:[%.*s] headers:[%.*s] totag:[%.*s]\n",\
	 my_msg->first_line.u.reply.reason.len,my_msg->first_line.u.reply.reason.s,\
	 body.len,body.s,new_header.len,new_header.s,totag.len,totag.s);

   if(seas_f.tmb.t_reply_with_body(c,my_msg->first_line.u.reply.statuscode,
   &(my_msg->first_line.u.reply.reason),&body,&new_header,&totag)<0){
      LM_ERR("Failed to t_reply\n");
      goto error;
   }

   seas_f.tmb.unref_cell(c);
   retval=0;
   goto exit;
error:
   retval = -1;
   seas_f.tmb.unref_cell(c);
exit:
   if(ttag)
      pkg_free(ttag);
   if(my_msg){
      free_sip_msg_lite(my_msg);
      pkg_free(my_msg);
   }
   return retval;
}
예제 #23
0
파일: uac.c 프로젝트: tsudot/kamailio
/**
 * @return: 
 * 	0: success
 * 	-1: internal error
 * 	-2: insane call :)
 */
int ack_local_uac(struct cell *trans, str *hdrs, str *body)
{
	struct retr_buf *local_ack, *old_lack;
	int ret;
	struct tmcb_params onsend_params;

	/* sanity checks */

#ifdef EXTRA_DEBUG
	if (! trans) {
		BUG("no transaction to ACK.\n");
		abort();
	}
#endif

#define RET_INVALID \
		ret = -2; \
		goto fin

	if (! is_local(trans)) {
		ERR("trying to ACK non local transaction (T@%p).\n", trans);
		RET_INVALID;
	}
	if (! is_invite(trans)) {
		ERR("trying to ACK non INVITE local transaction (T@%p).\n", trans);
		RET_INVALID;
	}
	if (! trans->uac[0].reply) {
		ERR("trying to ACK un-completed INVITE transaction (T@%p).\n", trans);
		RET_INVALID;
	}

	if (! (trans->flags & T_NO_AUTO_ACK)) {
		ERR("trying to ACK an auto-ACK transaction (T@%p).\n", trans);
		RET_INVALID;
	}
	if (trans->uac[0].local_ack) {
		ERR("trying to rebuild ACK retransmission buffer (T@%p).\n", trans);
		RET_INVALID;
	}

	/* looks sane: build the retransmission buffer */

	if (! (local_ack = local_ack_rb(trans->uac[0].reply, trans, /*branch*/0, 
			hdrs, body))) {
		ERR("failed to build ACK retransmission buffer");
		RET_INVALID;
	} else {
		/* set the new buffer, but only if not already set (conc. invok.) */
		if ((old_lack = (struct retr_buf *)atomic_cmpxchg_long(
				(void *)&trans->uac[0].local_ack, 0, (long)local_ack))) {
			/* buffer already set: deny current attempt */
			ERR("concurrent ACKing for local INVITE detected (T@%p).\n",trans);
			free_local_ack(local_ack);
			RET_INVALID;
		}
	}

	if (msg_send(&local_ack->dst, local_ack->buffer, local_ack->buffer_len)<0){
		/* hopefully will succeed on next 2xx retransmission */
		ERR("failed to send local ACK (T@%p).\n", trans);
		ret = -1;
		goto fin;
	}
	else {
		INIT_TMCB_ONSEND_PARAMS(onsend_params, 0, 0, &trans->uac[0].request,
								&local_ack->dst,
								local_ack->buffer, local_ack->buffer_len,
								TMCB_LOCAL_F, 0 /* branch */, TYPE_LOCAL_ACK);
		run_trans_callbacks_off_params(TMCB_REQUEST_SENT, trans, &onsend_params);
	}

	ret = 0;
fin:
	/* TODO: ugly! */
	/* FIXME: the T had been obtain by t_lookup_ident()'ing for it, so, it is
	 * ref-counted. The t_unref() can not be used, as it requests a valid SIP
	 * message (all available might be the reply, but if AS goes wrong and
	 * tries to ACK before the final reply is received, we still have to
	 * lookup the T to find this out). */
	UNREF( trans );
	return ret;

#undef RET_INVALID
}
예제 #24
0
파일: t_reply.c 프로젝트: iamroger/voip
/* 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!
*/
enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch, 
	unsigned int msg_status, branch_bm_t *cancel_bitmap )
{
	int relay;
	int save_clone;
	char *buf;
	/* length of outbound reply */
	unsigned int res_len;
	int relayed_code;
	struct sip_msg *relayed_msg;
	struct bookmark bm;
	int totag_retr;
	enum rps reply_status;
	/* retransmission structure of outbound reply and request */
	struct retr_buf *uas_rb;
	str cb_s;
	str text;

	/* 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 );
	LM_DBG("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;

		t->relaied_reply_branch = relay;

		/* 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;

			text.s = error_text(relayed_code);
			text.len = strlen(text.s); /* FIXME - bogdan*/

			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 );
				buf = build_res_buf_from_sip_req(
						relayed_code,
						&text,
						&tm_tag,
						t->uas.request, &res_len, &bm );
			} else {
				buf = build_res_buf_from_sip_req( relayed_code,
					&text, 0/* no to-tag */,
					t->uas.request, &res_len, &bm );
			}

		} else {
			/* run callbacks for all types of responses -
			 * even if they are shmem-ed or not */
			if (has_tran_tmcbs(t,TMCB_RESPONSE_FWDED) ) {
				run_trans_callbacks( TMCB_RESPONSE_FWDED, t, t->uas.request,
					relayed_msg, msg_status );
			}
			relayed_code=relayed_msg->REPLY_STATUS;
			buf = build_res_buf_from_sip_res( relayed_msg, &res_len,
							uas_rb->dst.send_sock);
			/* remove all lumps which are not in shm 
			 * added either by build_res_buf_from_sip_res, or by
			 * the callbacks that have been called with shmem-ed messages - vlad */
			if (branch!=relay) {
				del_notflaged_lumps( &(relayed_msg->add_rm), LUMPFLAG_SHMEM);
				del_notflaged_lumps( &(relayed_msg->body_lumps), LUMPFLAG_SHMEM);
			}
		}
		if (!buf) {
			LM_ERR("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.s = (char*)shm_resize( uas_rb->buffer.s, res_len +
			(msg_status<200 ?  REPLY_OVERBUFFER_LEN : 0));
		if (!uas_rb->buffer.s) {
			LM_ERR("no more share memory\n");
			goto error03;
		}
		uas_rb->buffer.len = res_len;
		memcpy( uas_rb->buffer.s, buf, res_len );
		if (relayed_msg==FAKED_REPLY) { /* to-tags for local replies */
			update_local_tags(t, &bm, uas_rb->buffer.s, buf);
		}
		stats_trans_rpl( relayed_code, (relayed_msg==FAKED_REPLY)?1:0 );

		/* update the status ... */
		t->uas.status = relayed_code;

		if (is_invite(t) && relayed_msg!=FAKED_REPLY
		&& relayed_code>=200 && relayed_code < 300
		&& has_tran_tmcbs( t,
		TMCB_RESPONSE_OUT|TMCB_RESPONSE_PRE_OUT)) {
			totag_retr=update_totag_set(t, relayed_msg);
		}
	}; /* if relay ... */

	UNLOCK_REPLIES( t );

	/* Setup retransmission timer _before_ the reply is sent
	 * to avoid race conditions
	 */
	if (reply_status == RPS_COMPLETED) {
		/* for auth related replies, we do not do retransmission 
		   (via set_final_timer()), but only wait for a final 
		   reply (put_on_wait() ) - see RFC 3261 (26.3.2.4 DoS Protection) */
		if ((relayed_code != 401) && (relayed_code != 407))
			set_final_timer(t);
		else
			put_on_wait(t);
	}

	/* send it now (from the private buffer) */
	if (relay >= 0) {
		/* run the PRE sending out callback */
		if (!totag_retr && has_tran_tmcbs(t, TMCB_RESPONSE_PRE_OUT) ) {
			cb_s.s = buf;
			cb_s.len = res_len;
			set_extra_tmcb_params( &cb_s, &uas_rb->dst);
			run_trans_callbacks_locked(TMCB_RESPONSE_PRE_OUT,t,t->uas.request,
				relayed_msg, relayed_code);
		}
		SEND_PR_BUFFER( uas_rb, buf, res_len );
		LM_DBG("sent buf=%p: %.9s..., shmem=%p: %.9s\n", 
			buf, buf, uas_rb->buffer.s, uas_rb->buffer.s );
		/* run the POST sending out callback */
		if (!totag_retr && has_tran_tmcbs(t, TMCB_RESPONSE_OUT) ) {
			cb_s.s = buf;
			cb_s.len = res_len;
			set_extra_tmcb_params( &cb_s, &uas_rb->dst);
			run_trans_callbacks_locked( TMCB_RESPONSE_OUT, t, t->uas.request,
				relayed_msg, relayed_code);
		}
		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:
	text.s = "Reply processing error";
	text.len = sizeof("Reply processing error")-1;
	t_reply_unsafe( t, t->uas.request, 500, &text );
	UNLOCK_REPLIES(t);
	if (is_invite(t)) cancel_uacs( t, *cancel_bitmap );
	/* a serious error occurred -- attempt to send an error reply;
	   it will take care of clean-ups  */

	/* failure */
	return RPS_ERROR;
}
예제 #25
0
static void trace_onreq_out(struct cell* t, int type, struct tmcb_params *ps)
{
	struct _siptrace_data sto;
	sip_msg_t *msg;
	struct ip_addr to_ip;
	int len;
	struct dest_info *dst;

	if(t==NULL || ps==NULL) {
		LM_DBG("very weird\n");
		return;
	}

	if(ps->flags&TMCB_RETR_F) {
		LM_DBG("retransmission\n");
		return;
	}
	msg=ps->req;
	if(msg==NULL) {
		/* check if it is outgoing cancel, t is INVITE
		 * and send_buf starts with CANCEL */
		if(is_invite(t) && ps->send_buf.len>7
				&& strncmp(ps->send_buf.s, "CANCEL ", 7)==0) {
			msg = t->uas.request;
			if(msg==NULL) {
				LM_DBG("no uas msg for INVITE transaction\n");
				return;
			} else {
				LM_DBG("recording CANCEL based on INVITE transaction\n");
			}
		} else {
			LM_DBG("no uas msg, local transaction\n");
			return;
		}
	}
	memset(&sto, 0, sizeof(struct _siptrace_data));

	if(traced_user_avp.n!=0)
		sto.avp=search_first_avp(traced_user_avp_type, traced_user_avp,
				&sto.avp_value, &sto.state);

	if((sto.avp==NULL) && trace_is_off(msg) ) {
		LM_DBG("trace off...\n");
		return;
	}

	if(sip_trace_prepare(msg)<0)
		return;

	if(ps->send_buf.len>0) {
		sto.body = ps->send_buf;
	} else {
		sto.body.s   = "No request buffer";
		sto.body.len = sizeof("No request buffer")-1;
	}

	sto.callid = msg->callid->body;

	if(ps->send_buf.len>10) {
		sto.method.s = ps->send_buf.s;
		sto.method.len = 0;
		while(sto.method.len<ps->send_buf.len) {
			if(ps->send_buf.s[sto.method.len]==' ')
				break;
			sto.method.len++;
		}
		if(sto.method.len==ps->send_buf.len)
			sto.method.len = 10;
	} else {
		sto.method = t->method;
	}

	sto.status.s = "";
	sto.status.len = 0;

	memset(&to_ip, 0, sizeof(struct ip_addr));
	dst = ps->dst;

	if (trace_local_ip.s && trace_local_ip.len > 0) {
		sto.fromip = trace_local_ip;
	} else {
		if(dst==0 || dst->send_sock==0 || dst->send_sock->sock_str.s==0) {
			siptrace_copy_proto(msg->rcv.proto, sto.fromip_buff);
			strcat(sto.fromip_buff, ip_addr2a(&msg->rcv.dst_ip));
			strcat(sto.fromip_buff,":");
			strcat(sto.fromip_buff, int2str(msg->rcv.dst_port, NULL));
			sto.fromip.s = sto.fromip_buff;
			sto.fromip.len = strlen(sto.fromip_buff);
		} else {
			sto.fromip = dst->send_sock->sock_str;
		}
	}

	if(dst==0) {
		sto.toip.s = "any:255.255.255.255";
		sto.toip.len = 19;
	} else {
		su2ip_addr(&to_ip, &dst->to);
		siptrace_copy_proto(dst->proto, sto.toip_buff);
		strcat(sto.toip_buff, ip_addr2a(&to_ip));
		strcat(sto.toip_buff, ":");
		strcat(sto.toip_buff,
				int2str((unsigned long)su_getport(&dst->to), &len));
		sto.toip.s = sto.toip_buff;
		sto.toip.len = strlen(sto.toip_buff);
	}

	sto.dir = "out";

	sto.fromtag = get_from(msg)->tag_value;
	sto.totag = get_to(msg)->tag_value;

#ifdef STATISTICS
	sto.stat = siptrace_req;
#endif

	sip_trace_store(&sto, NULL);
	return;
}
예제 #26
0
파일: t_reply.c 프로젝트: iamroger/voip
/*  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->flags;
		setb0flags(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();
		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
			 */
			backup_list = set_avp_list(&t->user_avps);
			if (!fr_inv_avp2timer(&timer)) {
				LM_DBG("FR_INV_TIMER = %lld\n", timer);
				set_timer(&uac->request.fr_timer,
					FR_INV_TIMER_LIST, &timer);
			} else {
				set_timer(& uac->request.fr_timer, FR_INV_TIMER_LIST, 0);
			}
			set_avp_list(backup_list);
		} 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;
}
예제 #27
0
파일: t_lookup.c 프로젝트: rrb3942/opensips
/* Returns 0 - nothing found
 *         1  - T found
 */
int t_reply_matching( struct sip_msg *p_msg , int *p_branch )
{
	struct cell*  p_cell;
	unsigned int hash_index   = 0;
	unsigned int entry_label  = 0;
	unsigned int branch_id    = 0;
	char  *hashi, *branchi, *p, *n;
	int hashl, branchl;
	int scan_space;
	struct cseq_body *cseq;

	char *loopi;
	int loopl;
	char *syni;
	int synl;

	/* make compiler warnings happy */
	loopi=0;
	loopl=0;
	syni=0;
	synl=0;

	/* split the branch into pieces: loop_detection_check(ignored),
	 hash_table_id, synonym_id, branch_id */

	if (!(p_msg->via1 && p_msg->via1->branch && p_msg->via1->branch->value.s))
		goto nomatch2;

	/* we do RFC 3261 tid matching and want to see first if there is
	 * magic cookie in branch */
	if (p_msg->via1->branch->value.len<=MCOOKIE_LEN)
		goto nomatch2;
	if (memcmp(p_msg->via1->branch->value.s, MCOOKIE, MCOOKIE_LEN)!=0)
		goto nomatch2;

	p=p_msg->via1->branch->value.s+MCOOKIE_LEN;
	scan_space=p_msg->via1->branch->value.len-MCOOKIE_LEN;


	/* hash_id */
	n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR);
	hashl=n-p;
	scan_space-=hashl;
	if (!hashl || scan_space<2 || *n!=BRANCH_SEPARATOR) goto nomatch2;
	hashi=p;
	p=n+1;scan_space--;

	if (!syn_branch) {
		/* md5 value */
		n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR );
		loopl = n-p;
		scan_space-= loopl;
		if (n==p || scan_space<2 || *n!=BRANCH_SEPARATOR)
			goto nomatch2;
		loopi=p;
		p=n+1; scan_space--;
	} else {
		/* synonym id */
		n=eat_token2_end( p, p+scan_space, BRANCH_SEPARATOR);
		synl=n-p;
		scan_space-=synl;
		if (!synl || scan_space<2 || *n!=BRANCH_SEPARATOR)
			goto nomatch2;
		syni=p;
		p=n+1;scan_space--;
	}

	/* branch id  -  should exceed the scan_space */
	n=eat_token_end( p, p+scan_space );
	branchl=n-p;
	if (!branchl ) goto nomatch2;
	branchi=p;

	/* sanity check */
	if (reverse_hex2int(hashi, hashl, &hash_index)<0
		||hash_index>=TM_TABLE_ENTRIES
		|| reverse_hex2int(branchi, branchl, &branch_id)<0
		||branch_id>=MAX_BRANCHES
		|| (syn_branch ? reverse_hex2int(syni, synl, &entry_label)<0
			: loopl!=MD5_LEN )
	) {
		LM_DBG("poor reply labels %u label %u branch %u\n",
				hash_index, entry_label, branch_id );
		goto nomatch2;
	}

	LM_DBG("hash %u label %d branch %u\n",hash_index, entry_label, branch_id);

	cseq = get_cseq(p_msg);

	/* search the hash table list at entry 'hash_index'; lock the
	   entry first */
	LOCK_HASH(hash_index);

	for (p_cell = get_tm_table()->entrys[hash_index].first_cell; p_cell;
		p_cell=p_cell->next_cell) {

		/* first look if branch matches */
		if (syn_branch) {
			if (p_cell->label != entry_label)
				continue;
		} else {
			if ( memcmp(p_cell->md5, loopi,MD5_LEN)!=0)
					continue;
		}

		/* sanity check ... too high branch ? */
		if ( branch_id>=p_cell->nr_of_outgoings )
			continue;

		/* does method match ? (remember -- CANCELs have the same branch
		   as canceled transactions) */
		if (!( /* it's a local cancel */
			(cseq->method_id==METHOD_CANCEL && is_invite(p_cell)
				&& p_cell->uac[branch_id].local_cancel.buffer.len )
			/* method match */
			|| ((cseq->method_id!=METHOD_OTHER && p_cell->uas.request)?
				(cseq->method_id==REQ_LINE(p_cell->uas.request).method_value)
				:(EQ_STRS(cseq->method,p_cell->method)))
		))
			continue;

		/* we passed all disqualifying factors .... the transaction has been
		   matched !
		*/
		set_t(p_cell);
		*p_branch = branch_id;
		REF_UNSAFE( T );
		UNLOCK_HASH(hash_index);
		LM_DBG("reply matched (T=%p)!\n",T);
		/* if this is a 200 for INVITE, we will wish to store to-tags to be
		 * able to distinguish retransmissions later and not to call
 		 * TMCB_RESPONSE_OUT uselessly; we do it only if callbacks are
		 * enabled -- except callback customers, nobody cares about
		 * retransmissions of multiple 200/INV or ACK/200s
		 */
		if (is_invite(p_cell) && p_msg->REPLY_STATUS>=200
		&& p_msg->REPLY_STATUS<300
		&& ( (!is_local(p_cell) &&
				has_tran_tmcbs(p_cell,
				TMCB_RESPONSE_OUT|TMCB_RESPONSE_PRE_OUT) )
			|| (is_local(p_cell)&&has_tran_tmcbs(p_cell,TMCB_LOCAL_COMPLETED))
		)) {
			if (parse_headers(p_msg, HDR_TO_F, 0)==-1) {
				LM_ERR("to parsing failed\n");
			}
		}

		return 1;
	} /* for cycle */

	/* nothing found */
	UNLOCK_HASH(hash_index);
	LM_DBG("no matching transaction exists\n");

nomatch2:
	LM_DBG("failure to match a transaction\n");
	*p_branch = -1;
	set_t(0);
	return -1;
}
예제 #28
0
파일: t_reply.c 프로젝트: iamroger/voip
/* 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_code;
	int inv_through;
	int do_cancel;

	/* 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
	*/
	LM_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) {
			LM_DBG("200 OK for INVITE after final sent\n");
			*should_store=0;
			Trans->uac[branch].last_received=new_code;
			*should_relay=branch;
			return RPS_PUSHED_AFTER_COMPLETION;
		} 
		if ( is_hopbyhop_cancel(Trans) && new_code>=200) {
			*should_store=0;
			*should_relay=-1;
			picked_branch=-1;
			return RPS_COMPLETED;
		}
		/* 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)) {
#ifdef EXTRA_DEBUG
		/* don't report on retransmissions */
		if (Trans->uac[branch].last_received==new_code) {
			LM_DBG("final reply retransmission\n");
		} else
		/* if you FR-timed-out, faked a local 408 and 487 came, don't
		 * report on it either */
		if (Trans->uac[branch].last_received==408 && new_code==487) {
			LM_DBG("487 reply came for a timed-out branch\n");
		} else {
		/* this looks however how a very strange status rewrite attempt;
		 * report on it */
			LM_DBG("status rewrite by UAS: stored: %d, received: %d\n",
				Trans->uac[branch].last_received, new_code );
		}
#endif
		goto discard;
	}

	/* no final response sent yet */
	/* negative replies subject to fork picking */
	if (new_code >=300 ) {

		Trans->uac[branch].last_received=new_code;
		/* 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;

		if (new_code>=600 && !disable_6xx_block) {
			/* this is a winner and close all branches */
			which_cancel( Trans, cancel_bitmap );
			picked_branch=branch;
			/* no more new branches should be added to this transaction */
			Trans->flags |= T_NO_NEW_BRANCHES_FLAG;
		} else {
			/* if all_final return lowest */
			picked_branch = t_pick_branch( Trans, &picked_code, &do_cancel);
			if (picked_branch==-2) { /* branches open yet */
				*should_store=1;
				*should_relay=-1;
				picked_branch=-1;
				Trans->uac[branch].reply = 0;
				return RPS_STORE;
			}
			if (picked_branch==-1) {
				LM_CRIT("pick_branch failed (lowest==-1) for code %d\n",new_code);
				Trans->uac[branch].reply = 0;
				goto discard;
			}
			if (do_cancel) {
				branch_bm_t cb = 0;
				which_cancel( Trans, &cb );
				cleanup_uac_timers(Trans);
				cancel_uacs( Trans, cb);
			}
		}

		/* 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;
		reset_kr();

		if ( !(Trans->flags&T_NO_DNS_FAILOVER_FLAG) &&
		Trans->uac[picked_branch].proxy!=NULL ) {
			/* is is a DNS failover scenario, according to RFC 3263 ? */
			if (is_3263_failure(Trans)) {
				LM_DBG("trying DNS-based failover\n");
				/* do DNS failover -> add new branches */
				if (do_dns_failover( Trans )!=0) {
					/* skip the failed added branches */
					branch_cnt = Trans->nr_of_outgoings;
				}
			}
		}

		/* run ON_FAILURE handlers ( route and callbacks) */
		if ( branch_cnt==Trans->nr_of_outgoings &&
		(has_tran_tmcbs( Trans, TMCB_ON_FAILURE) || Trans->on_negative) ) {
			run_failure_handlers( Trans );
		}

		/* 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
			*/
			picked_branch=-1;
			return RPS_COMPLETED;
		}
		/* look if the callback/failure_route introduced new branches ... */
		if (branch_cnt<Trans->nr_of_outgoings && get_kr()==REQ_FWDED)  {
			/* await then result of new branches */
			*should_store=1;
			*should_relay=-1;
			picked_branch=-1;
			return RPS_STORE;
		}

		/* really no more pending branches -- return selected code */
		*should_store=0;
		*should_relay=picked_branch;
		picked_branch=-1;
		return RPS_COMPLETED;
	} 

	/* not >=300 ... it must be 2xx or provisional 1xx */
	if (new_code>=100) {
		/* 1xx and 2xx except 100 will be relayed */
		Trans->uac[branch].last_received=new_code;
		*should_store=0;
		*should_relay= new_code==100? -1 : branch;
		if (new_code>=200 ) {
			which_cancel( Trans, cancel_bitmap );
			return RPS_COMPLETED;
		} else return RPS_PROVISIONAL;
	}

discard:
	*should_store=0;
	*should_relay=-1;
	return RPS_DISCARDED;
}
예제 #29
0
/* initiate a report if we previously enabled accounting for this t */
static void acc_onreply(tm_cell_t *t, sip_msg_t *req, sip_msg_t *reply, int code)
{
	str new_uri_bk;
	int br = -1;
	hdr_field_t *hdr;
	sip_msg_t *cmsg = 0;
	int cmsg_len = 0;
	sip_msg_t *preq = 0;
	void *mstart;
	void *mend;

	/* acc_onreply is bound to TMCB_REPLY which may be called
	   from _reply, like when FR hits; we should not miss this
	   event for missed calls either */
	if (is_invite(t) && code>=300 && is_mc_on(req) )
		on_missed(t, req, reply, code);

	if (!should_acc_reply(req, reply, code))
		return;

	if(_acc_clone_msg==1) {
		/* make a clone so eventual new parsed headers in pkg are not visible
		 * to other processes -- other attributes should be already parsed,
		 * available in the req structure and propagated by cloning */
		cmsg = sip_msg_shm_clone(req, &cmsg_len, 1);
		if(cmsg==NULL) {
			LM_ERR("failed to clone the request - acc aborted\n");
			return;
		}
		mstart = cmsg;
		mend = ((char*)cmsg) + cmsg_len;
		preq = cmsg;
	} else {
		mstart = t->uas.request;
		mend = t->uas.end_request;
		preq = req;
	}

	/* get winning branch index, if set */
	if (t->relayed_reply_branch>=0) {
		br = t->relayed_reply_branch;
	} else {
		if(code>=300) {
			br = tmb.t_get_picked_branch();
		}
	}

	/* for reply processing, set as new_uri the one from selected branch */
	if (br>=0) {
		new_uri_bk = preq->new_uri;
		preq->new_uri = t->uac[br].uri;
		preq->parsed_uri_ok = 0;
	} else {
		new_uri_bk.len = -1;
		new_uri_bk.s = 0;
	}
	/* set env variables */
	env_set_to( get_rpl_to(t,reply) );
	env_set_code_status( code, reply);

	if ( is_log_acc_on(preq) ) {
		env_set_text( ACC_ANSWERED, ACC_ANSWERED_LEN);
		acc_log_request(preq);
	}
#ifdef SQL_ACC
	if (is_db_acc_on(preq)) {
		if(acc_db_set_table_name(preq, db_table_acc_data, &db_table_acc)<0) {
			LM_ERR("cannot set acc db table name\n");
		} else {
			acc_db_request(preq);
		}
	}
#endif

/* DIAMETER */
#ifdef DIAM_ACC
	if (is_diam_acc_on(preq))
		acc_diam_request(preq);
#endif

	/* run extra acc engines */
	acc_run_engines(preq, 0, NULL);

	if (new_uri_bk.len>=0) {
		preq->new_uri = new_uri_bk;
		preq->parsed_uri_ok = 0;
	}

	/* free header's parsed structures that were added by resolving acc attributes */
	for( hdr=preq->headers ; hdr ; hdr=hdr->next ) {
		if (hdr->parsed && hdr_allocs_parse(hdr) &&
					(hdr->parsed<mstart || hdr->parsed>=mend)) {
			/* header parsed filed doesn't point inside cloned request memory
			 * chunck -> it was added by resolving acc attributes -> free it as pkg */
			DBG("removing hdr->parsed %d\n", hdr->type);
			clean_hdr_field(hdr);
			hdr->parsed = 0;
		}
	}
	if(cmsg!=NULL) {
		shm_free(cmsg);
	}
}