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