Example #1
0
inline static int w_t_newtran( struct sip_msg* p_msg, char* foo, char* bar ) 
{
	/* t_newtran returns 0 on error (negative value means
	   'transaction exists'
	*/
	return t_newtran( p_msg );
}
Example #2
0
inline static int w_t_newtran( struct sip_msg* p_msg, char* foo, char* bar )
{
	/* t_newtran returns 0 on error (negative value means
	   'transaction exists' */
	int ret;
	ret = t_newtran( p_msg );
	if (ret==E_SCRIPT) {
		LOG(L_DBG, "ERROR: t_newtran: "
			"transaction already in process %p\n", get_t() );
	}
	return ret;
}
Example #3
0
int w_t_reply_with_body(struct sip_msg* msg, str* code, str *text,
								str *body)
{
	struct cell *t;
	int r;
	str code_s;
	unsigned int code_i;
	str body_s;

	if(body==0)
	{
		LM_ERR("Wrong argument, body must not be NULL\n");
		return -1;
	}

	if(((pv_elem_p)code)->spec.getf!=NULL) {
		if(pv_printf_s(msg, (pv_elem_p)code, &code_s)!=0)
			return -1;
		if(str2int(&code_s, &code_i)!=0 || code_i<100 || code_i>699)
			return -1;
	} else {
		code_i = ((pv_elem_p)code)->spec.pvp.pvn.u.isname.name.n;
	}

	if(((pv_elem_p)text)->spec.getf!=NULL) {
		if(pv_printf_s(msg, (pv_elem_p)text, &code_s)!=0 || code_s.len <=0)
			return -1;
	} else {
		code_s = ((pv_elem_p)text)->text;
	}

	if(((pv_elem_p)body)->spec.getf!=NULL) {
		if(pv_printf_s(msg, (pv_elem_p)body, &body_s)!=0 || body_s.len <=0)
			return -1;
	} else {
		body_s = ((pv_elem_p)body)->text;
	}

	t=get_t();
	if ( t==0 || t==T_UNDEFINED ) {
		r = t_newtran( msg );
		if (r==0) {
			/* retransmission -> break the script */
			return 0;
		} else if (r<0) {
			LM_ERR("could not create a new transaction\n");
			return -1;
		}
		t=get_t();
	}
	return t_reply_with_body(t, code_i, &code_s, &body_s, 0, 0);
}
Example #4
0
File: tm.c Project: Deni90/opensips
inline static int w_t_reply(struct sip_msg* msg, char* code, char* text)
{
	struct cell *t;
	int r;

	if (msg->REQ_METHOD==METHOD_ACK) {
		LM_DBG("ACKs are not replied\n");
		return 0;
	}
	switch (route_type) {
		case FAILURE_ROUTE:
			/* if called from reply_route, make sure that unsafe version
			 * is called; we are already in a mutex and another mutex in
			 * the safe version would lead to a deadlock */
			t=get_t();
			if ( t==0 || t==T_UNDEFINED ) {
				LM_ERR("BUG - no transaction found in Failure Route\n");
				return -1;
			}
			return t_reply_unsafe(t, msg, (unsigned int)(long)code,(str*)text);
		case REQUEST_ROUTE:
			t=get_t();
			if ( t==0 || t==T_UNDEFINED ) {
				r = t_newtran( msg , 0/*no full UAS cloning*/ );
				if (r==0) {
					/* retransmission -> break the script */
					return 0;
				} else if (r<0) {
					LM_ERR("could not create a new transaction\n");
					return -1;
				}
				t=get_t();
			}
			return t_reply( t, msg, (unsigned int)(long)code, (str*)text);
		default:
			LM_CRIT("unsupported route_type (%d)\n", route_type);
			return -1;
	}
}
Example #5
0
int t_relay_to( struct sip_msg  *p_msg , struct proxy_l *proxy, int flags)
{
	int ret;
	int new_tran;
	int reply_ret;
	struct cell *t;

	ret=0;

	new_tran = t_newtran( p_msg, 1/*full UAS cloning*/ );

	/* parsing error, memory alloc, whatever ... */
	if (new_tran<0) {
		ret =  new_tran;
		goto done;
	}
	/* if that was a retransmission, break from script */
	if (new_tran==0) {
		goto done;
	}

	/* new transaction */

	/* ACKs do not establish a transaction and are fwd-ed statelessly */
	if ( p_msg->REQ_METHOD==METHOD_ACK) {
		LM_DBG("forwarding ACK\n");
		/* send it out */
		if (proxy==0) {
			proxy=uri2proxy(GET_NEXT_HOP(p_msg),
				p_msg->force_send_socket ?
				p_msg->force_send_socket->proto : PROTO_NONE );
			if (proxy==0) {
					ret=E_BAD_ADDRESS;
					goto done;
			}
			ret=forward_request( p_msg , proxy);
			if (ret>=0) ret=1;
			free_proxy( proxy );
			pkg_free( proxy );
		} else {
			ret=forward_request( p_msg , proxy);
			if (ret>=0) ret=1;
		}
		goto done;
	}

	/* if replication flag is set, mark the transaction as local
	   so that replies will not be relaied */
	t=get_t();
	if (flags&TM_T_RELAY_repl_FLAG) t->flags|=T_IS_LOCAL_FLAG;
	if (flags&TM_T_RELAY_nodnsfo_FLAG) t->flags|=T_NO_DNS_FAILOVER_FLAG;
	if (flags&TM_T_RELAY_reason_FLAG) t->flags|=T_CANCEL_REASON_FLAG;
	if ((flags&TM_T_RELAY_do_cancel_dis_FLAG) &&
	tm_has_request_disponsition_no_cancel(p_msg)==0 )
		t->flags|=T_MULTI_200OK_FLAG;

	/* now go ahead and forward ... */
	ret=t_forward_nonack( t, p_msg, proxy, 0/*no reset*/, 0/*unlocked*/);
	if (ret<=0) {
		LM_DBG("t_forward_nonack returned error \n");
		/* we don't want to pass upstream any reply regarding replicating
		 * a request; replicated branch must stop at us*/
		if (!(flags&(TM_T_RELAY_repl_FLAG|TM_T_RELAY_noerr_FLAG))) {
			reply_ret = kill_transaction( t );
			if (reply_ret>0) {
				/* we have taken care of all -- do nothing in
				script */
				LM_DBG("generation of a stateful reply on error succeeded\n");
				ret=0;
			}  else {
				LM_DBG("generation of a stateful reply on error failed\n");
			}
		}
	} else {
		LM_DBG("new transaction fwd'ed\n");
	}

done:
	return ret;
}
Example #6
0
/* WARNING: doesn't work from failure route (deadlock, uses t_reply => tries
 *  to get the reply lock again */
int t_relay_to( struct sip_msg  *p_msg , struct proxy_l *proxy, int proto,
				int replicate)
{
	int ret;
	int new_tran;
	/* struct hdr_field *hdr; */
	struct cell *t;
	struct dest_info dst;
	unsigned short port;
	str host;
	short comp;
#ifndef TM_DELAYED_REPLY
	int reply_ret;
#endif

	ret=0;
	
	/* special case for CANCEL */
	if ( p_msg->REQ_METHOD==METHOD_CANCEL){
		ret=t_forward_cancel(p_msg, proxy, proto, &t);
		if (t) goto handle_ret;
		goto done;
	}
	new_tran = t_newtran( p_msg );
	
	/* parsing error, memory alloc, whatever ... if via is bad
	   and we are forced to reply there, return with 0 (->break),
	   pass error status otherwise
	   MMA: return value E_SCRIPT means that transaction was already started
	   from the script so continue with that transaction
	*/
	if (likely(new_tran!=E_SCRIPT)) {
		if (new_tran<0) {
			ret = (ser_error==E_BAD_VIA && reply_to_via) ? 0 : new_tran;
			goto done;
		}
		/* if that was a retransmission, return we are happily done */
		if (new_tran==0) {
			ret = 1;
			goto done;
		}
	}else if (unlikely(p_msg->REQ_METHOD==METHOD_ACK)) {
			/* transaction previously found (E_SCRIPT) and msg==ACK
			    => ack to neg. reply  or ack to local trans.
			    => process it and exit */
			/* FIXME: there's no way to distinguish here between acks to
			   local trans. and neg. acks */
			/* in normal operation we should never reach this point, if we
			   do WARN(), it might hide some real bug (apart from possibly
			   hiding a bug the most harm done is calling the TMCB_ACK_NEG
			   callbacks twice) */
			WARN("negative or local ACK caught, please report\n");
			t=get_t();
			if (unlikely(has_tran_tmcbs(t, TMCB_ACK_NEG_IN)))
				run_trans_callbacks(TMCB_ACK_NEG_IN, t, p_msg, 0, 
										p_msg->REQ_METHOD);
			t_release_transaction(t);
			ret=1;
			goto done;
	}

	/* new transaction */

	/* at this point if the msg is an ACK it is an e2e ACK and
	   e2e ACKs do not establish a transaction and are fwd-ed statelessly */
	if ( p_msg->REQ_METHOD==METHOD_ACK) {
		DBG( "SER: forwarding ACK  statelessly \n");
		if (proxy==0) {
			init_dest_info(&dst);
			dst.proto=proto;
			if (get_uri_send_info(GET_NEXT_HOP(p_msg), &host, &port,
									&dst.proto, &comp)!=0){
				ret=E_BAD_ADDRESS;
				goto done;
			}
#ifdef USE_COMP
			dst.comp=comp;
#endif
			/* dst->send_sock not set, but forward_request will take care
			 * of it */
			ret=forward_request(p_msg, &host, port, &dst);
		} else {
			init_dest_info(&dst);
			dst.proto=get_proto(proto, proxy->proto);
			proxy2su(&dst.to, proxy);
			/* dst->send_sock not set, but forward_request will take care
			 * of it */
			ret=forward_request( p_msg , 0, 0, &dst) ;
		}
		goto done;
	}

	/* if replication flag is set, mark the transaction as local
	   so that replies will not be relayed */
	t=get_t();
	if (replicate) t->flags|=T_IS_LOCAL_FLAG;

	/* INVITE processing might take long, particularly because of DNS
	   look-ups -- let upstream know we're working on it */
	if (p_msg->REQ_METHOD==METHOD_INVITE && (t->flags&T_AUTO_INV_100)
		&& (t->uas.status < 100)
	) {
		DBG( "SER: new INVITE\n");
		if (!t_reply( t, p_msg , 100 ,
			cfg_get(tm, tm_cfg, tm_auto_inv_100_r)))
				DBG("SER: ERROR: t_reply (100)\n");
	} 

	/* now go ahead and forward ... */
	ret=t_forward_nonack(t, p_msg, proxy, proto);
handle_ret:
	if (ret<=0) {
		DBG( "t_forward_nonack returned error %d (%d)\n", ret, ser_error);
		/* we don't want to pass upstream any reply regarding replicating
		 * a request; replicated branch must stop at us*/
		if (likely(!replicate)) {
			if(t->flags&T_DISABLE_INTERNAL_REPLY) {
				/* flag set to don't generate the internal negative reply
				 * - let the transaction live further, processing should
				 *   continue in config */
				DBG("not generating immediate reply for error %d\n", ser_error);
				tm_error=ser_error;
				ret = -4;
				goto done;
			}
#ifdef TM_DELAYED_REPLY
			/* current error in tm_error */
			tm_error=ser_error;
			set_kr(REQ_ERR_DELAYED);
			DBG("%d error reply generation delayed \n", ser_error);
#else

			reply_ret=kill_transaction( t, ser_error );
			if (reply_ret>0) {
				/* we have taken care of all -- do nothing in
			  	script */
				DBG("ERROR: generation of a stateful reply "
					"on error succeeded\n");
				/*ret=0; -- we don't want to stop the script */
			}  else {
				DBG("ERROR: generation of a stateful reply "
					"on error failed\n");
				t_release_transaction(t);
			}
#endif /* TM_DELAYED_REPLY */
		}else{
			t_release_transaction(t); /* kill it  silently */
		}
	} else {
		DBG( "SER: new transaction fwd'ed\n");
	}

done:
	return ret;
}
Example #7
0
int t_handle_async(struct sip_msg *msg, struct action* a , int resume_route)
{
    async_ctx *ctx = NULL;
    async_resume_module *ctx_f;
    void *ctx_p;
    struct cell *t;
    int r;
    int fd;

    /* create transaction and save everything into transaction */
    t=get_t();
    if ( t==0 || t==T_UNDEFINED ) {
        /* create transaction */
        r = t_newtran( msg , 1 /*full uas clone*/ );
        if (r==0) {
            /* retransmission -> no follow up; we return a negative
             * code to indicate do_action that the top route is
             * is completed (there no resume route to follow) */
            return -1;
        } else if (r<0) {
            LM_ERR("could not create a new transaction\n");
            goto failure;
        }
        t=get_t();
    } else {
        /* update the cloned UAS (from transaction)
         * with data from current msg */
        if (t->uas.request)
            update_cloned_msg_from_msg( t->uas.request, msg);
    }

    /* run the function (the action) and get back from it the FD,
     * resume function and param */
    if ( a->type!=AMODULE_T || a->elem[0].type!=ACMD_ST ||
            a->elem[0].u.data==NULL ) {
        LM_CRIT("BUG - invalid action for async I/O - it must be"
                " a MODULE_T ACMD_ST \n");
        goto failure;
    }

    async_status = ASYNC_NO_IO; /*assume defauly status "no IO done" */
    return_code = ((acmd_export_t*)(a->elem[0].u.data))->function(msg,
                  &ctx_f, &ctx_p,
                  (char*)a->elem[1].u.data, (char*)a->elem[2].u.data,
                  (char*)a->elem[3].u.data, (char*)a->elem[4].u.data,
                  (char*)a->elem[5].u.data, (char*)a->elem[6].u.data );
    /* what to do now ? */
    if (async_status>=0) {
        /* async I/O was successfully launched */
        fd = async_status;
        if (msg->REQ_METHOD==METHOD_ACK ||
                /* ^^^ end2end ACK, there is no actual transaction here */
                t->uas.request==NULL
                /* ^^^ local requests do not support async in local route */
           ) {
            goto sync;
        }
    } else if (async_status==ASYNC_NO_IO) {
        /* no IO, so simply go for resume route */
        goto resume;
    } else if (async_status==ASYNC_SYNC) {
        /* IO already done in SYNC'ed way */
        goto resume;
    } else if (async_status==ASYNC_CHANGE_FD) {
        LM_ERR("Incorrect ASYNC_CHANGE_FD status usage!"
               "You should use this status only from the"
               "resume function in case something went wrong"
               "and you have other alternatives!\n");
        /*FIXME should we go to resume or exit?it's quite an invalid scenario */
        goto resume;
    } else {
        /* generic error, go for resume route */
        goto resume;
    }

    /* do we have a reactor in this process, to handle this
       asyn I/O ? */
    if ( 0/*reactor_exists()*/ ) {
        /* no reactor, so we directly call the resume function
           which will block waiting for data */
        goto sync;
    }

    if ( (ctx=shm_malloc(sizeof(async_ctx)))==NULL) {
        LM_ERR("failed to allocate new ctx\n");
        goto sync;
    }

    ctx->resume_f = ctx_f;
    ctx->resume_param = ctx_p;
    ctx->resume_route = resume_route;
    ctx->route_type = route_type;
    ctx->msg_ctx = current_processing_ctx;
    ctx->t = t;
    ctx->kr = get_kr();

    ctx->cancelled_t = get_cancelled_t();
    ctx->e2eack_t = get_e2eack_t();

    current_processing_ctx = NULL;
    set_t(T_UNDEFINED);
    reset_cancelled_t();
    reset_e2eack_t();

    /* place the FD + resume function (as param) into reactor */
    if (reactor_add_reader( fd, F_SCRIPT_ASYNC, RCT_PRIO_ASYNC, (void*)ctx)<0 ) {
        LM_ERR("failed to add async FD to reactor -> act in sync mode\n");
        goto sync;
    }

    /* done, break the script */
    return 0;

sync:
    if (ctx) {
        /*
         * the context was moved in reactor, but the reactor could not
         * fullfil the request - we have to restore the environment -- razvanc
         */
        current_processing_ctx = ctx->msg_ctx;
        set_t(t);
        set_cancelled_t(ctx->cancelled_t);
        set_e2eack_t(ctx->e2eack_t);
        shm_free(ctx);
    }
    /* run the resume function */
    do {
        return_code = ctx_f( fd, msg, ctx_p );
        if (async_status == ASYNC_CHANGE_FD)
            fd = return_code;
    } while(async_status==ASYNC_CONTINUE||async_status==ASYNC_CHANGE_FD);
    /* run the resume route in sync mode */
    run_resume_route( resume_route, msg);

    /* break original script */
    return 0;

failure:
    /* execute here the resume route with failure indication */
    return_code = -1;
resume:
    /* run the resume route */
    run_resume_route( resume_route, msg);
    /* the triggering route is terminated and whole script ended */
    return 0;
}
Example #8
0
int t_relay_to( struct sip_msg  *p_msg , struct proxy_l *proxy, int flags)
{
	int ret;
	int new_tran;
	int reply_ret;
	struct cell *t;
	context_p ctx_backup;

	ret=0;

	new_tran = t_newtran( p_msg, 1/*full UAS cloning*/ );

	/* parsing error, memory alloc, whatever ... */
	if (new_tran<0) {
		ret =  new_tran;
		goto done;
	}
	/* if that was a retransmission, break from script */
	if (new_tran==0) {
		goto done;
	}

	/* new transaction */

	/* ACKs do not establish a transaction and are fwd-ed statelessly */
	if ( p_msg->REQ_METHOD==METHOD_ACK) {
		LM_DBG("forwarding ACK\n");
		/* send it out */
		if (proxy==0) {
			proxy=uri2proxy(GET_NEXT_HOP(p_msg),
				p_msg->force_send_socket ?
				p_msg->force_send_socket->proto : PROTO_NONE );
			if (proxy==0) {
					ret=E_BAD_ADDRESS;
					goto done;
			}
			ret=forward_request( p_msg , proxy);
			if (ret>=0) ret=1;
			free_proxy( proxy );
			pkg_free( proxy );
		} else {
			ret=forward_request( p_msg , proxy);
			if (ret>=0) ret=1;
		}
		goto done;
	}

	/* if replication flag is set, mark the transaction as local
	   so that replies will not be relaied */
	t=get_t();
	if (flags&TM_T_REPLY_repl_FLAG) t->flags|=T_IS_LOCAL_FLAG;
	if (flags&TM_T_REPLY_nodnsfo_FLAG) t->flags|=T_NO_DNS_FAILOVER_FLAG;
	if (flags&TM_T_REPLY_reason_FLAG) t->flags|=T_CANCEL_REASON_FLAG;

	/* INVITE processing might take long, particularly because of DNS
	   look-ups -- let upstream know we're working on it */
	if ( p_msg->REQ_METHOD==METHOD_INVITE &&
	!(flags&(TM_T_REPLY_no100_FLAG|TM_T_REPLY_repl_FLAG)) ) {
		ctx_backup = current_processing_ctx;
		current_processing_ctx = NULL;
		t_reply( t, p_msg , 100 , &relay_reason_100);
		current_processing_ctx = ctx_backup;
	}

	/* now go ahead and forward ... */
	ret=t_forward_nonack( t, p_msg, proxy);
	if (ret<=0) {
		LM_DBG("t_forward_nonack returned error \n");
		/* we don't want to pass upstream any reply regarding replicating
		 * a request; replicated branch must stop at us*/
		if (!(flags&(TM_T_REPLY_repl_FLAG|TM_T_REPLY_noerr_FLAG))) {
			reply_ret = kill_transaction( t );
			if (reply_ret>0) {
				/* we have taken care of all -- do nothing in
				script */
				LM_DBG("generation of a stateful reply on error succeeded\n");
				ret=0;
			}  else {
				LM_DBG("generation of a stateful reply on error failed\n");
			}
		}
	} else {
		LM_DBG("new transaction fwd'ed\n");
	}

done:
	return ret;
}
Example #9
0
File: tm.c Project: Deni90/opensips
inline static int w_t_newtran( struct sip_msg* p_msg)
{
	/* t_newtran returns 0 on error (negative value means
	   'transaction exists' */
	return t_newtran( p_msg , 0 /*no full UAS cloning*/);
}
Example #10
0
/* WARNING: doesn't work from failure route (deadlock, uses t_reply => tries
 *  to get the reply lock again */
int t_relay_to( struct sip_msg  *p_msg , struct proxy_l *proxy, int proto,
				int replicate)
{
	int ret;
	int new_tran;
	int reply_ret;
	/* struct hdr_field *hdr; */
	struct cell *t;
	struct dest_info dst;
	unsigned short port;
	str host;
	short comp;

	ret=0;
	
	new_tran = t_newtran( p_msg );
	
	/* parsing error, memory alloc, whatever ... if via is bad
	   and we are forced to reply there, return with 0 (->break),
	   pass error status otherwise

       MMA: return value E_SCRIPT means that transaction was already started from the script
	   so continue with that transaction
	*/
	if (new_tran!=E_SCRIPT) {
		if (new_tran<0) {
			ret = (ser_error==E_BAD_VIA && reply_to_via) ? 0 : new_tran;
			goto done;
		}
		/* if that was a retransmission, return we are happily done */
		if (new_tran==0) {
			ret = 1;
			goto done;
		}
	}

	/* new transaction */

	/* ACKs do not establish a transaction and are fwd-ed statelessly */
	if ( p_msg->REQ_METHOD==METHOD_ACK) {
		DBG( "SER: forwarding ACK  statelessly \n");
		if (proxy==0) {
			init_dest_info(&dst);
			dst.proto=proto;
			if (get_uri_send_info(GET_NEXT_HOP(p_msg), &host, &port,
									&dst.proto, &comp)!=0){
				ret=E_BAD_ADDRESS;
				goto done;
			}
#ifdef USE_COMP
			dst.comp=comp;
#endif
			/* dst->send_sock not set, but forward_request will take care
			 * of it */
			ret=forward_request(p_msg, &host, port, &dst);
		} else {
			init_dest_info(&dst);
			dst.proto=get_proto(proto, proxy->proto);
			proxy2su(&dst.to, proxy);
			/* dst->send_sock not set, but forward_request will take care
			 * of it */
			ret=forward_request( p_msg , 0, 0, &dst) ;
		}
		goto done;
	}

	/* if replication flag is set, mark the transaction as local
	   so that replies will not be relayed */
	t=get_t();
	if (replicate) t->flags|=T_IS_LOCAL_FLAG;

	/* INVITE processing might take long, particularly because of DNS
	   look-ups -- let upstream know we're working on it */
	if (p_msg->REQ_METHOD==METHOD_INVITE )
	{
		DBG( "SER: new INVITE\n");
		if (!t_reply( t, p_msg , 100 ,
			"trying -- your call is important to us"))
				DBG("SER: ERROR: t_reply (100)\n");
	} 

	/* now go ahead and forward ... */
	ret=t_forward_nonack(t, p_msg, proxy, proto);
	if (ret<=0) {
		DBG( "ERROR:tm:t_relay_to:  t_forward_nonack returned error \n");
		/* we don't want to pass upstream any reply regarding replicating
		 * a request; replicated branch must stop at us*/
		if (!replicate) {
			reply_ret=kill_transaction( t );
			if (reply_ret>0) {
				/* we have taken care of all -- do nothing in
			  	script */
				DBG("ERROR: generation of a stateful reply "
					"on error succeeded\n");
				/*ret=0; -- we don't want to stop the script */
			}  else {
				DBG("ERROR: generation of a stateful reply "
					"on error failed\n");
				t_release_transaction(t);
			}
		}else{
			t_release_transaction(t); /* kill it  silently */
		}
	} else {
		DBG( "SER: new transaction fwd'ed\n");
	}

done:
	return ret;
}
Example #11
0
int t_relay_to( struct sip_msg  *p_msg , struct proxy_l *proxy, int proto,
				int replicate)
{
	int ret;
	int new_tran;
	str *uri;
	int reply_ret;
	/* struct hdr_field *hdr; */
	struct cell *t;

	ret=0;

	new_tran = t_newtran( p_msg );

	/* parsing error, memory alloc, whatever ... if via is bad
	   and we are forced to reply there, return with 0 (->break),
	   pass error status otherwise
	*/
	if (new_tran<0) {
		ret = (ser_error==E_BAD_VIA && reply_to_via) ? 0 : new_tran;
		goto done;
	}
	/* if that was a retransmission, return we are happily done */
	if (new_tran==0) {
		ret = 1;
		goto done;
	}

	/* new transaction */

	/* ACKs do not establish a transaction and are fwd-ed statelessly */
	if ( p_msg->REQ_METHOD==METHOD_ACK) {
		DBG("DEBUG:tm:t_relay: forwarding ACK  statelessly \n");
		if (proxy==0) {
			uri = GET_RURI(p_msg);
			proxy=uri2proxy(GET_NEXT_HOP(p_msg), proto);
			if (proxy==0) {
					ret=E_BAD_ADDRESS;
					goto done;
			}
			proto=proxy->proto; /* uri2proxy set it correctly */
			ret=forward_request( p_msg , proxy, proto) ;
			free_proxy( proxy );	
			pkg_free( proxy );
		} else {
			proto=get_proto(proto, proxy->proto);
			ret=forward_request( p_msg , proxy, proto ) ;
		}
		goto done;
	}

	/* if replication flag is set, mark the transaction as local
	   so that replies will not be relaied */
	t=get_t();
	if (replicate) t->flags|=T_IS_LOCAL_FLAG;

	/* INVITE processing might take long, particularly because of DNS
	   look-ups -- let upstream know we're working on it */
	if (p_msg->REQ_METHOD==METHOD_INVITE )
	{
		DBG("DEBUG:tm:t_relay: new INVITE\n");
		if (!t_reply( t, p_msg , 100 ,
			"trying -- your call is important to us"))
				DBG("SER: ERROR: t_reply (100)\n");
	} 

	/* now go ahead and forward ... */
	ret=t_forward_nonack(t, p_msg, proxy, proto);
	if (ret<=0) {
		DBG( "ERROR:tm:t_relay_to:  t_forward_nonack returned error \n");
		/* we don't want to pass upstream any reply regarding replicating
		 * a request; replicated branch must stop at us*/
		if (!replicate) {
			reply_ret=kill_transaction( t );
			if (reply_ret>0) {
				/* we have taken care of all -- do nothing in
			  	script */
				DBG("ERROR: generation of a stateful reply "
					"on error succeeded\n");
				ret=0;
			}  else {
				DBG("ERROR: generation of a stateful reply "
					"on error failed\n");
			}
		}
	} else {
		DBG( "SER: new transaction fwd'ed\n");
	}

done:
	return ret;
}
Example #12
0
int t_handle_async(struct sip_msg *msg, struct action* a , int resume_route)
{
	async_ctx *ctx;
	async_resume_module *ctx_f;
	void *ctx_p;
	struct cell *t;
	int r;
	int fd;

	/* create transaction and save everything into transaction */
	t=get_t();
	if ( t==0 || t==T_UNDEFINED ) {
		/* create transaction */
		r = t_newtran( msg , 1 /*full uas clone*/ );
		if (r==0) {
			/* retransmission -> break the script, no follow up */
			return 0;
		} else if (r<0) {
			LM_ERR("could not create a new transaction\n");
			goto failure;
		}
		t=get_t();
	} else {
		/* update the cloned UAS (from transaction)
		 * with data from current msg */
		update_cloned_msg_from_msg( t->uas.request, msg);
	}

	/* run the function (the action) and get back from it the FD,
	 * resume function and param */
	if ( a->type!=AMODULE_T || a->elem[0].type!=ACMD_ST ||
	a->elem[0].u.data==NULL ) {
		LM_CRIT("BUG - invalid action for async I/O - it must be"
			" a MODULE_T ACMD_ST \n");
		goto failure;
	}

	async_status = ASYNC_NO_IO; /*assume defauly status "no IO done" */
	return_code = ((acmd_export_t*)(a->elem[0].u.data))->function(msg,
			&ctx_f, &ctx_p,
			(char*)a->elem[1].u.data, (char*)a->elem[2].u.data,
			(char*)a->elem[3].u.data, (char*)a->elem[4].u.data,
			(char*)a->elem[5].u.data, (char*)a->elem[6].u.data );
	/* what to do now ? */
	if (async_status>=0) {
		/* async I/O was succesfully launched */
		fd = async_status;
	} else if (async_status==ASYNC_NO_IO) {
		/* no IO, so simply go for resume route */
		goto resume;
	} else if (async_status==ASYNC_SYNC) {
		/* IO already done in SYNC'ed way */
		goto resume;
	} else {
		/* generic error, go for resume route */
		goto resume;
	}

	/* do we have a reactor in this process, to handle this 
	   asyn I/O ? */
	if ( 0/*reactor_exists()*/ ) {
		/* no reactor, so we directly call the resume function
		   which will block waiting for data */
		goto sync;
	}

	if ( (ctx=shm_malloc(sizeof(async_ctx)))==NULL) {
		LM_ERR("failed to allocate new ctx\n");
		goto sync;
	}

	ctx->resume_f = ctx_f;
	ctx->resume_param = ctx_p;
	ctx->resume_route = resume_route;
	ctx->route_type = route_type;
	ctx->msg_ctx = current_processing_ctx;
	ctx->t = t;
	ctx->kr = get_kr();

	current_processing_ctx = NULL;
	set_t(T_UNDEFINED);

	/* place the FD + resume function (as param) into reactor */
	if (reactor_add_reader( fd, F_SCRIPT_ASYNC, RCT_PRIO_ASYNC, (void*)ctx)<0 ) {
		LM_ERR("failed to add async FD to reactor -> act in sync mode\n");
		shm_free(ctx);
		goto sync;
	}

	/* done, break the script */
	return 0;

sync:
	/* run the resume function */
	do {
		return_code = ctx_f( fd, msg, ctx_p );
	} while(async_status!=ASYNC_CONTINUE);
	/* run the resume route in sync mode */
	run_resume_route( resume_route, msg);
	/* break original script */
	return 0;

failure:
	/* execute here the resume route with failure indication */
	return_code = -1;
resume:
	/* run the resume route */
	run_resume_route( resume_route, msg);
	/* the triggering route is terminated and whole script ended */
	return 0;
}