inline static int _w_t_relay_to( struct sip_msg *p_msg, struct proxy_l *proxy) { struct cell *t; if (route_type==FAILURE_ROUTE) { t=get_t(); if (!t || t==T_UNDEFINED) { LOG(L_CRIT, "BUG: w_t_relay_to: undefined T\n"); return -1; } if (t_forward_nonack(t, p_msg, proxy, PROTO_NONE)<=0 ) { LOG(L_ERR, "ERROR: w_t_relay_to: t_relay_to failed\n"); return -1; } return 1; } if (route_type==REQUEST_ROUTE) { return t_relay_to( p_msg, proxy, PROTO_NONE, 0 /* no replication */ ); } LOG(L_CRIT, "ERROR: w_t_relay_to: unsupported route type: %d\n", route_type); return 0; }
inline static int w_t_relay( struct sip_msg *p_msg , char *proxy, char *flags) { struct proxy_l *p = NULL; struct cell *t; int ret; t=get_t(); if (proxy && (p=clone_proxy((struct proxy_l*)proxy))==0) { LM_ERR("failed to clone proxy, dropping packet\n"); return -1; } if (!t || t==T_UNDEFINED) { /* no transaction yet */ if (route_type==FAILURE_ROUTE) { LM_CRIT("BUG - undefined transaction in failure route\n"); return -1; } ret = t_relay_to( p_msg, p, (int)(long)flags ); if (ret<0) { ret = t_relay_inerr2scripterr(); } } else { /* transaction already created */ if ( route_type!=REQUEST_ROUTE && route_type!=FAILURE_ROUTE ) goto route_err; if (p_msg->REQ_METHOD==METHOD_ACK) { /* local ACK*/ t_release_transaction(t); return 1; } if (((int)(long)flags)&TM_T_REPLY_nodnsfo_FLAG) t->flags|=T_NO_DNS_FAILOVER_FLAG; if (((int)(long)flags)&TM_T_REPLY_reason_FLAG) t->flags|=T_CANCEL_REASON_FLAG; update_cloned_msg_from_msg( t->uas.request, p_msg); ret = t_forward_nonack( t, p_msg, p); if (ret<=0 ) { LM_ERR("t_forward_nonack failed\n"); ret = t_relay_inerr2scripterr(); } } if (p) { free_proxy(p); pkg_free(p); } return ret?ret:1; route_err: LM_CRIT("unsupported route type: %d\n", route_type); return 0; }
int t_replicate(struct sip_msg *p_msg, str *dst, int flags) { /* this is a quite horrible hack -- we just take the message as is, including Route-s, Record-route-s, and Vias , forward it downstream and prevent replies received from relaying by setting the replication/local_trans bit; nevertheless, it should be good enough for the primary customer of this function, REGISTER replication if we want later to make it thoroughly, we need to introduce delete lumps for all the header fields above */ struct cell *t; if ( set_dst_uri( p_msg, dst)!=0 ) { LM_ERR("failed to set dst uri\n"); return -1; } if ( branch_uri2dset( GET_RURI(p_msg) )!=0 ) { LM_ERR("failed to convert uri to dst\n"); return -1; } t=get_t(); if (!t || t==T_UNDEFINED) { /* no transaction yet */ if (route_type==FAILURE_ROUTE) { LM_CRIT("BUG - undefined transaction in failure route\n"); return -1; } return t_relay_to( p_msg, NULL, flags|TM_T_RELAY_repl_FLAG); } else { /* transaction already created */ if (p_msg->REQ_METHOD==METHOD_ACK) /* local ACK */ return -1; t->flags|=T_IS_LOCAL_FLAG; return t_forward_nonack( t, p_msg, NULL, 1/*reset*/, 0/*unlocked*/); } }
static inline int do_dns_failover(struct cell *t) { static struct sip_msg faked_req; struct sip_msg *shmem_msg; struct ua_client *uac; int ret; shmem_msg = t->uas.request; uac = &t->uac[picked_branch]; /* check if the DNS resolver can get at least one new IP */ if ( get_next_su( uac->proxy, &uac->request.dst.to, 1)!=0 ) return -1; LM_DBG("new destination available\n"); if (!fake_req(&faked_req, shmem_msg, &t->uas, uac)) { LM_ERR("fake_req failed\n"); return -1; } /* fake also the env. conforming to the fake msg */ faked_env( t, &faked_req); ret = -1; /* set info as current destination */ if ( set_ruri( &faked_req, &uac->uri)!= 0) goto done; setb0flags( uac->br_flags ); faked_req.force_send_socket = shmem_msg->force_send_socket; /* send it out */ if (t_forward_nonack( t, &faked_req, uac->proxy)==1) ret = 0; done: /* restore original environment and free the fake msg */ faked_env( t, 0); free_faked_req(&faked_req,t); return ret; }
inline static int _w_t_forward_nonack(struct sip_msg* msg, struct proxy_l* proxy, int proto) { struct cell *t; if (t_check( msg , 0 )==-1) { LOG(L_ERR, "ERROR: forward_nonack: " "can't forward when no transaction was set up\n"); return -1; } t=get_t(); if ( t && t!=T_UNDEFINED ) { if (msg->REQ_METHOD==METHOD_ACK) { LOG(L_WARN,"WARNING: you don't really want to fwd hbh ACK\n"); return -1; } return t_forward_nonack(t, msg, proxy, proto ); } else { DBG("DEBUG: forward_nonack: no transaction found\n"); return -1; } }
inline static int _w_t_relay_to( struct sip_msg *p_msg , struct proxy_l *proxy ) { struct cell *t; if (rmode==MODE_ONFAILURE) { t=get_t(); if (!t || t==T_UNDEFINED) { LOG(L_CRIT, "BUG: w_t_relay_to: undefined T\n"); return -1; } if (t_forward_nonack(t, p_msg, proxy, PROTO_NONE)<=0 ) { LOG(L_ERR, "ERROR: failure_route: t_relay_to failed\n"); return -1; } return 1; } if (rmode==MODE_REQUEST) return t_relay_to( p_msg, proxy, PROTO_NONE, 0 /* no replication */ ); LOG(L_CRIT, "ERROR: w_t_relay_to: unsupported mode: %d\n", rmode); return 0; }
inline static int w_t_relay( struct sip_msg *p_msg , char *_foo, char *_bar) { struct cell *t; if (rmode==MODE_ONFAILURE) { t=get_t(); if (!t || t==T_UNDEFINED) { LOG(L_CRIT, "BUG: w_t_relay: undefined T\n"); return -1; } if (t_forward_nonack(t, p_msg, ( struct proxy_l *) 0, PROTO_NONE)<=0) { LOG(L_ERR, "ERROR: w_t_relay (failure mode): forwarding failed\n"); return -1; } return 1; } if (rmode==MODE_REQUEST) return t_relay_to( p_msg, (struct proxy_l *) 0 /* no proxy */, PROTO_NONE, 0 /* no replication */ ); LOG(L_CRIT, "ERROR: w_t_relay: unsupported mode: %d\n", rmode); 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; 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; }
int t_inject_branch( struct cell *t, struct sip_msg *msg, int flags) { static struct sip_msg faked_req; branch_bm_t cancel_bm; str reason = str_init(CANCEL_REASON_200); int rc; /* does the transaction state still accept new branches ? */ if (t->uas.status >= 200) { LM_DBG("cannot add branches to a transaction with %d UAS\n", t->uas.status); return -2; } if (!fake_req( &faked_req, t->uas.request, &t->uas, NULL, 0)) { LM_ERR("fake_req failed\n"); return -1; } /* do we have the branches to be injected ? */ if (flags&TM_INJECT_SRC_EVENT) { /* get the branch from Event AVPs, as populated by EVI/EBR */ if (ul_contact_event_to_msg( &faked_req )<0) { LM_ERR("failed to grab new branch from Event\n"); goto error; } } else { /* use the RURI+dset array as destinations to be injected */ if (msg->first_line.type==SIP_REQUEST) { /* take the RURI branch from the script msg and move it * into the faked msg (that will be used by t_fwd function) */ if (dst_to_msg( msg, &faked_req )<0) { LM_ERR("failed to grab new branch from Event\n"); goto error; } } else { /* current message is a reply, so take the first branch from dset * and move it into the faked msg (that will be used by t_fwd * function)*/ if (move_branch_to_ruri( 0, &faked_req)<0) { LM_ERR("no branch found to be moved as new destination\n"); goto error; } /* remove it from set */ remove_branch(0); } } /* do we have to cancel the existing branches before injecting new ones? */ if (flags&TM_INJECT_FLAG_CANCEL) { which_cancel( t, &cancel_bm ); } /* generated the new branches, without branch counter reset */ rc = t_forward_nonack( t, &faked_req , NULL, 0, 1/*locked*/ ); /* do we have to cancel the existing branches before injecting new ones? */ if (flags&TM_INJECT_FLAG_CANCEL) { set_cancel_extra_hdrs( reason.s, reason.len); cancel_uacs( t, cancel_bm ); set_cancel_extra_hdrs( NULL, 0); } /* cleanup the faked request */ free_faked_req( &faked_req, t); return (rc==1)?1:-3; error: /* cleanup the faked request */ free_faked_req( &faked_req, t); return -1; }
/* 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_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; }
static inline int do_dns_failover(struct cell *t) { static struct sip_msg faked_req; struct sip_msg *shmem_msg; struct sip_msg *req; struct ua_client *uac; dlg_t dialog; int ret, sip_msg_len; uac = &t->uac[picked_branch]; /* check if the DNS resolver can get at least one new IP */ if ( get_next_su( uac->proxy, &uac->request.dst.to, 1)!=0 ) return -1; LM_DBG("new destination available\n"); if (t->uas.request==NULL) { if (!is_local(t)) { LM_CRIT("BUG: proxy transaction without UAS request :-/\n"); return -1; } /* create the cloned SIP msg -> first create a new SIP msg */ memset( &dialog, 0, sizeof(dialog)); dialog.send_sock = uac->request.dst.send_sock; dialog.hooks.next_hop = &uac->uri; req = buf_to_sip_msg(uac->request.buffer.s, uac->request.buffer.len, &dialog); if (req==NULL) { LM_ERR("failed to generate SIP msg from previous buffer\n"); return -1; } /* now do the actual cloning of the SIP message */ t->uas.request = sip_msg_cloner( req, &sip_msg_len, 1); if (t->uas.request==NULL) { LM_ERR("cloning failed\n"); free_sip_msg(req); return -1; } t->uas.end_request = ((char*)t->uas.request) + sip_msg_len; /* free the actual SIP message, keep the clone only */ free_sip_msg(req); /* the sip_msg structure is static in buf_to_sip_msg, so no need to free it */ } shmem_msg = t->uas.request; if (!fake_req(&faked_req, shmem_msg, &t->uas, uac, 1/*with dst_uri*/)) { LM_ERR("fake_req failed\n"); return -1; } /* fake also the env. conforming to the fake msg */ faked_env( t, &faked_req); ret = -1; /* set info as current destination */ if ( set_ruri( &faked_req, &uac->uri)!= 0) goto done; setb0flags( &faked_req, uac->br_flags ); faked_req.force_send_socket = shmem_msg->force_send_socket; /* send it out */ if (t_forward_nonack( t, &faked_req, uac->proxy)==1) ret = 0; done: /* restore original environment and free the fake msg */ faked_env( t, 0); free_faked_req(&faked_req,t); 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; 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; }