|
@@ -57,6 +57,7 @@
|
|
|
#include "../../action.h"
|
|
|
#include "../../onsend.h"
|
|
|
#include "t_lookup.h"
|
|
|
+#include "t_fwd.h"
|
|
|
#endif
|
|
|
|
|
|
#define FROM_TAG_LEN (MD5_LEN + 1 /* - */ + CRC16_LEN) /* length of FROM tags */
|
|
@@ -190,6 +191,162 @@ error:
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+#if defined(USE_DNS_FAILOVER) || defined(WITH_EVENT_LOCAL_REQUEST)
|
|
|
+static inline int t_build_msg_from_buf(
|
|
|
+ struct sip_msg *msg, char *buf, int buf_len,
|
|
|
+ uac_req_t *uac_r, struct dest_info *dst)
|
|
|
+{
|
|
|
+ if (unlikely(build_sip_msg_from_buf(msg, buf, buf_len, inc_msg_no()) != 0)) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ msg->force_send_socket = uac_r->dialog->send_sock;
|
|
|
+ msg->rcv.proto = dst->send_sock->proto;
|
|
|
+ msg->rcv.src_ip = dst->send_sock->address;
|
|
|
+ su2ip_addr(&msg->rcv.dst_ip, &dst->to);
|
|
|
+ msg->rcv.src_port = dst->send_sock->port_no;
|
|
|
+ msg->rcv.dst_port = su_getport(&dst->to);
|
|
|
+ msg->rcv.src_su=dst->send_sock->su;
|
|
|
+ msg->rcv.bind_address=dst->send_sock;
|
|
|
+#ifdef USE_COMP
|
|
|
+ msg->rcv.comp=dst->comp;
|
|
|
+#endif /* USE_COMP */
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+#ifdef WITH_EVENT_LOCAL_REQUEST
|
|
|
+static inline int t_run_local_req(
|
|
|
+ char **buf, int *buf_len,
|
|
|
+ uac_req_t *uac_r,
|
|
|
+ struct cell *new_cell, struct retr_buf *request)
|
|
|
+{
|
|
|
+ static struct sip_msg lreq;
|
|
|
+ struct onsend_info onsnd_info;
|
|
|
+ tm_xlinks_t backup_xd;
|
|
|
+ int sflag_bk;
|
|
|
+ char *buf1;
|
|
|
+ int buf_len1;
|
|
|
+ int backup_route_type;
|
|
|
+ struct cell *backup_t;
|
|
|
+ int backup_branch;
|
|
|
+ unsigned int backup_msgid;
|
|
|
+ int refresh_shortcuts = 0;
|
|
|
+
|
|
|
+ DBG("executing event_route[tm:local-request]\n");
|
|
|
+ if (unlikely(t_build_msg_from_buf(&lreq, *buf, *buf_len, uac_r, &request->dst))) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ if (unlikely(set_dst_uri(&lreq, uac_r->dialog->hooks.next_hop))) {
|
|
|
+ LM_ERR("failed to set dst_uri");
|
|
|
+ free_sip_msg(&lreq);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ sflag_bk = getsflags();
|
|
|
+ tm_xdata_swap(new_cell, &backup_xd, 0);
|
|
|
+
|
|
|
+ onsnd_info.to=&request->dst.to;
|
|
|
+ onsnd_info.send_sock=request->dst.send_sock;
|
|
|
+ onsnd_info.buf=*buf;
|
|
|
+ onsnd_info.len=*buf_len;
|
|
|
+ p_onsend=&onsnd_info;
|
|
|
+
|
|
|
+ /* run the route */
|
|
|
+ backup_route_type = get_route_type();
|
|
|
+ set_route_type(LOCAL_ROUTE);
|
|
|
+ /* set T to the current transaction */
|
|
|
+ backup_t=get_t();
|
|
|
+ backup_branch=get_t_branch();
|
|
|
+ backup_msgid=global_msg_id;
|
|
|
+ /* fake transaction and message id */
|
|
|
+ global_msg_id=lreq.id;
|
|
|
+ set_t(new_cell, T_BR_UNDEFINED);
|
|
|
+ run_top_route(event_rt.rlist[goto_on_local_req], &lreq, 0);
|
|
|
+ /* restore original environment */
|
|
|
+ set_t(backup_t, backup_branch);
|
|
|
+ global_msg_id=backup_msgid;
|
|
|
+ set_route_type( backup_route_type );
|
|
|
+ p_onsend=0;
|
|
|
+
|
|
|
+ /* restore original environment */
|
|
|
+ tm_xdata_swap(new_cell, &backup_xd, 1);
|
|
|
+ setsflagsval(sflag_bk);
|
|
|
+
|
|
|
+ /* rebuild the new message content */
|
|
|
+ if(lreq.force_send_socket != uac_r->dialog->send_sock) {
|
|
|
+ LM_DBG("Send socket updated to: %.*s",
|
|
|
+ lreq.force_send_socket->address_str.len,
|
|
|
+ lreq.force_send_socket->address_str.s);
|
|
|
+
|
|
|
+ /* rebuild local Via - remove previous value
|
|
|
+ * and add the one for the new send socket */
|
|
|
+ if (!del_lump(&lreq, lreq.h_via1->name.s - lreq.buf,
|
|
|
+ lreq.h_via1->len, 0)) {
|
|
|
+ LM_ERR("Failed to remove previous local Via\n");
|
|
|
+ /* attempt a normal update to give it a chance */
|
|
|
+ goto normal_update;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* reuse same branch value from previous local Via */
|
|
|
+ memcpy(lreq.add_to_branch_s, lreq.via1->branch->value.s,
|
|
|
+ lreq.via1->branch->value.len);
|
|
|
+ lreq.add_to_branch_len = lreq.via1->branch->value.len;
|
|
|
+
|
|
|
+ /* update also info about new destination and send sock */
|
|
|
+ uac_r->dialog->send_sock=lreq.force_send_socket;
|
|
|
+ request->dst.send_sock = lreq.force_send_socket;
|
|
|
+ request->dst.proto = lreq.force_send_socket->proto;
|
|
|
+
|
|
|
+ LM_DBG("apply new updates with Via to sip msg\n");
|
|
|
+ buf1 = build_req_buf_from_sip_req(&lreq,
|
|
|
+ (unsigned int*)&buf_len1, &request->dst, BUILD_IN_SHM);
|
|
|
+ if (likely(buf1)){
|
|
|
+ shm_free(*buf);
|
|
|
+ *buf = buf1;
|
|
|
+ *buf_len = buf_len1;
|
|
|
+ /* a possible change of the method is not handled! */
|
|
|
+ refresh_shortcuts = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ } else {
|
|
|
+normal_update:
|
|
|
+ if (unlikely(lreq.add_rm || lreq.body_lumps || lreq.new_uri.s)) {
|
|
|
+ LM_DBG("apply new updates without Via to sip msg\n");
|
|
|
+ buf1 = build_req_buf_from_sip_req(&lreq,
|
|
|
+ (unsigned int*)&buf_len1,
|
|
|
+ &request->dst, BUILD_NO_LOCAL_VIA|BUILD_NO_VIA1_UPDATE|
|
|
|
+ BUILD_IN_SHM);
|
|
|
+ if (likely(buf1)){
|
|
|
+ shm_free(*buf);
|
|
|
+ *buf = buf1;
|
|
|
+ *buf_len = buf_len1;
|
|
|
+ /* a possible change of the method is not handled! */
|
|
|
+ refresh_shortcuts = 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* clean local msg structure */
|
|
|
+ if (unlikely(lreq.new_uri.s))
|
|
|
+ {
|
|
|
+ pkg_free(lreq.new_uri.s);
|
|
|
+ lreq.new_uri.s=0;
|
|
|
+ lreq.new_uri.len=0;
|
|
|
+ }
|
|
|
+ if (unlikely(lreq.dst_uri.s))
|
|
|
+ {
|
|
|
+ pkg_free(lreq.dst_uri.s);
|
|
|
+ lreq.dst_uri.s=0;
|
|
|
+ lreq.dst_uri.len=0;
|
|
|
+ }
|
|
|
+ lreq.buf=0; /* covers the obsolete DYN_BUF */
|
|
|
+ free_sip_msg(&lreq);
|
|
|
+ return refresh_shortcuts;
|
|
|
+}
|
|
|
+#endif /* WITH_EVENT_LOCAL_REQUEST */
|
|
|
+#endif /* defined(USE_DNS_FAILOVER) || defined(WITH_EVENT_LOCAL_REQUEST) */
|
|
|
+
|
|
|
+
|
|
|
/* WARNING: - dst_cell contains the created cell, but it is un-referenced
|
|
|
* (before using it make sure you REF() it first)
|
|
|
* - if ACK (method==ACK), a cell will be created but it will not
|
|
@@ -203,29 +360,20 @@ static inline int t_uac_prepare(uac_req_t *uac_r,
|
|
|
struct dest_info dst;
|
|
|
struct cell *new_cell;
|
|
|
struct retr_buf *request;
|
|
|
- char* buf;
|
|
|
+ char *buf;
|
|
|
int buf_len, ret;
|
|
|
unsigned int hi;
|
|
|
int is_ack;
|
|
|
ticks_t lifetime;
|
|
|
-#ifdef USE_DNS_FAILOVER
|
|
|
- struct dns_srv_handle dns_h;
|
|
|
-#endif
|
|
|
long nhtype;
|
|
|
-#ifdef WITH_EVENT_LOCAL_REQUEST
|
|
|
- struct cell *backup_t;
|
|
|
- int backup_branch;
|
|
|
- unsigned int backup_msgid;
|
|
|
- static struct sip_msg lreq;
|
|
|
- char *buf1;
|
|
|
- int buf_len1;
|
|
|
- int sflag_bk;
|
|
|
- int backup_route_type;
|
|
|
-#endif
|
|
|
snd_flags_t snd_flags;
|
|
|
tm_xlinks_t backup_xd;
|
|
|
tm_xdata_t local_xd;
|
|
|
int refresh_shortcuts = 0;
|
|
|
+ int sip_msg_len;
|
|
|
+#ifdef USE_DNS_FAILOVER
|
|
|
+ static struct sip_msg lreq;
|
|
|
+#endif /* USE_DNS_FAILOVER */
|
|
|
|
|
|
ret=-1;
|
|
|
hi=0; /* make gcc happy */
|
|
@@ -237,7 +385,7 @@ static inline int t_uac_prepare(uac_req_t *uac_r,
|
|
|
*/
|
|
|
if ((nhtype = w_calculate_hooks(uac_r->dialog)) < 0)
|
|
|
/* if err's returned, the message is incorrect */
|
|
|
- goto error2;
|
|
|
+ goto error3;
|
|
|
|
|
|
if (!uac_r->dialog->loc_seq.is_set) {
|
|
|
/* this is the first request in the dialog,
|
|
@@ -246,57 +394,40 @@ static inline int t_uac_prepare(uac_req_t *uac_r,
|
|
|
uac_r->dialog->loc_seq.is_set = 1;
|
|
|
}
|
|
|
|
|
|
+ /* build cell sets X/AVP lists to new transaction structure
|
|
|
+ * => backup in a tmp struct and restore afterwards */
|
|
|
+ memset(&local_xd, 0, sizeof(tm_xdata_t));
|
|
|
+ tm_xdata_replace(&local_xd, &backup_xd);
|
|
|
+ new_cell = build_cell(0);
|
|
|
+ tm_xdata_replace(0, &backup_xd);
|
|
|
+
|
|
|
+ if (!new_cell) {
|
|
|
+ ret=E_OUT_OF_MEM;
|
|
|
+ LOG(L_ERR, "t_uac: short of cell shmem\n");
|
|
|
+ goto error3;
|
|
|
+ }
|
|
|
+
|
|
|
DBG("DEBUG:tm:t_uac: next_hop=<%.*s>\n",uac_r->dialog->hooks.next_hop->len,
|
|
|
uac_r->dialog->hooks.next_hop->s);
|
|
|
/* new message => take the dialog send_socket if set, or the default
|
|
|
send_socket if not*/
|
|
|
SND_FLAGS_INIT(&snd_flags);
|
|
|
#ifdef USE_DNS_FAILOVER
|
|
|
- if (cfg_get(core, core_cfg, use_dns_failover)){
|
|
|
- dns_srv_handle_init(&dns_h);
|
|
|
- if ((uri2dst2(&dns_h, &dst, uac_r->dialog->send_sock, snd_flags,
|
|
|
- uac_r->dialog->hooks.next_hop, PROTO_NONE)==0)
|
|
|
+ if ((uri2dst2(cfg_get(core, core_cfg, use_dns_failover) ? &new_cell->uac[0].dns_h : 0,
|
|
|
+ &dst, uac_r->dialog->send_sock, snd_flags,
|
|
|
+ uac_r->dialog->hooks.next_hop, PROTO_NONE)==0)
|
|
|
|| (dst.send_sock==0)){
|
|
|
- dns_srv_handle_put(&dns_h);
|
|
|
- ser_error = E_NO_SOCKET;
|
|
|
- ret=ser_error;
|
|
|
- LOG(L_ERR, "t_uac: no socket found\n");
|
|
|
- goto error2;
|
|
|
- }
|
|
|
- dns_srv_handle_put(&dns_h); /* not needed anymore */
|
|
|
- }else{
|
|
|
- if ((uri2dst2(0, &dst, uac_r->dialog->send_sock, snd_flags,
|
|
|
- uac_r->dialog->hooks.next_hop, PROTO_NONE)==0) ||
|
|
|
- (dst.send_sock==0)){
|
|
|
- ser_error = E_NO_SOCKET;
|
|
|
- ret=ser_error;
|
|
|
- LOG(L_ERR, "t_uac: no socket found\n");
|
|
|
- goto error2;
|
|
|
- }
|
|
|
- }
|
|
|
#else /* USE_DNS_FAILOVER */
|
|
|
if ((uri2dst2(&dst, uac_r->dialog->send_sock, snd_flags,
|
|
|
uac_r->dialog->hooks.next_hop, PROTO_NONE)==0) ||
|
|
|
(dst.send_sock==0)){
|
|
|
+#endif /* USE_DNS_FAILOVER */
|
|
|
ser_error = E_NO_SOCKET;
|
|
|
ret=ser_error;
|
|
|
LOG(L_ERR, "t_uac: no socket found\n");
|
|
|
goto error2;
|
|
|
}
|
|
|
-#endif /* USE_DNS_FAILOVER */
|
|
|
-
|
|
|
- /* build cell sets X/AVP lists to new transaction structure
|
|
|
- * => bakup in a tmp struct and restore afterwards */
|
|
|
- memset(&local_xd, 0, sizeof(tm_xdata_t));
|
|
|
- tm_xdata_replace(&local_xd, &backup_xd);
|
|
|
- new_cell = build_cell(0);
|
|
|
- tm_xdata_replace(0, &backup_xd);
|
|
|
|
|
|
- if (!new_cell) {
|
|
|
- ret=E_OUT_OF_MEM;
|
|
|
- LOG(L_ERR, "t_uac: short of cell shmem\n");
|
|
|
- goto error2;
|
|
|
- }
|
|
|
if (uac_r->method->len==INVITE_LEN && memcmp(uac_r->method->s, INVITE, INVITE_LEN)==0){
|
|
|
new_cell->flags |= T_IS_INVITE_FLAG;
|
|
|
new_cell->flags|=T_AUTO_INV_100 &
|
|
@@ -349,131 +480,31 @@ static inline int t_uac_prepare(uac_req_t *uac_r,
|
|
|
|
|
|
#ifdef WITH_EVENT_LOCAL_REQUEST
|
|
|
if (unlikely(goto_on_local_req>=0)) {
|
|
|
- DBG("executing event_route[tm:local-request]\n");
|
|
|
- if(likely(build_sip_msg_from_buf(&lreq, buf, buf_len, inc_msg_no())
|
|
|
- == 0)) {
|
|
|
- /* fill some field in sip_msg */
|
|
|
- if (unlikely(set_dst_uri(&lreq, uac_r->dialog->hooks.next_hop))) {
|
|
|
- LM_ERR("failed to set dst_uri");
|
|
|
- free_sip_msg(&lreq);
|
|
|
- } else {
|
|
|
- struct onsend_info onsnd_info;
|
|
|
-
|
|
|
- lreq.force_send_socket = uac_r->dialog->send_sock;
|
|
|
- lreq.rcv.proto = dst.send_sock->proto;
|
|
|
- lreq.rcv.src_ip = dst.send_sock->address;
|
|
|
- lreq.rcv.src_port = dst.send_sock->port_no;
|
|
|
- lreq.rcv.dst_port = su_getport(&dst.to);
|
|
|
- su2ip_addr(&lreq.rcv.dst_ip, &dst.to);
|
|
|
- lreq.rcv.src_su=dst.send_sock->su;
|
|
|
- lreq.rcv.bind_address=dst.send_sock;
|
|
|
- #ifdef USE_COMP
|
|
|
- lreq.rcv.comp=dst.comp;
|
|
|
- #endif /* USE_COMP */
|
|
|
- sflag_bk = getsflags();
|
|
|
- tm_xdata_swap(new_cell, &backup_xd, 0);
|
|
|
-
|
|
|
- onsnd_info.to=&dst.to;
|
|
|
- onsnd_info.send_sock=dst.send_sock;
|
|
|
- onsnd_info.buf=buf;
|
|
|
- onsnd_info.len=buf_len;
|
|
|
- p_onsend=&onsnd_info;
|
|
|
-
|
|
|
- /* run the route */
|
|
|
- backup_route_type = get_route_type();
|
|
|
- set_route_type(LOCAL_ROUTE);
|
|
|
- /* set T to the current transaction */
|
|
|
- backup_t=get_t();
|
|
|
- backup_branch=get_t_branch();
|
|
|
- backup_msgid=global_msg_id;
|
|
|
- /* fake transaction and message id */
|
|
|
- global_msg_id=lreq.id;
|
|
|
- set_t(new_cell, T_BR_UNDEFINED);
|
|
|
- run_top_route(event_rt.rlist[goto_on_local_req], &lreq, 0);
|
|
|
- /* restore original environment */
|
|
|
- set_t(backup_t, backup_branch);
|
|
|
- global_msg_id=backup_msgid;
|
|
|
- set_route_type( backup_route_type );
|
|
|
- p_onsend=0;
|
|
|
-
|
|
|
- /* restore original environment */
|
|
|
- tm_xdata_swap(new_cell, &backup_xd, 1);
|
|
|
- setsflagsval(sflag_bk);
|
|
|
-
|
|
|
- /* rebuild the new message content */
|
|
|
- if(lreq.force_send_socket != uac_r->dialog->send_sock) {
|
|
|
- LM_DBG("Send socket updated to: %.*s",
|
|
|
- lreq.force_send_socket->address_str.len,
|
|
|
- lreq.force_send_socket->address_str.s);
|
|
|
-
|
|
|
- /* rebuild local Via - remove previous value
|
|
|
- * and add the one for the new send socket */
|
|
|
- if (!del_lump(&lreq, lreq.h_via1->name.s - lreq.buf,
|
|
|
- lreq.h_via1->len, 0)) {
|
|
|
- LM_ERR("Failed to remove previous local Via\n");
|
|
|
- /* attempt a normal update to give it a chance */
|
|
|
- goto normal_update;
|
|
|
- }
|
|
|
-
|
|
|
- /* reuse same branch value from previous local Via */
|
|
|
- memcpy(lreq.add_to_branch_s, lreq.via1->branch->value.s,
|
|
|
- lreq.via1->branch->value.len);
|
|
|
- lreq.add_to_branch_len = lreq.via1->branch->value.len;
|
|
|
-
|
|
|
- /* update also info about new destination and send sock */
|
|
|
- uac_r->dialog->send_sock=lreq.force_send_socket;
|
|
|
- request->dst.send_sock = lreq.force_send_socket;
|
|
|
- request->dst.proto = lreq.force_send_socket->proto;
|
|
|
-
|
|
|
- LM_DBG("apply new updates with Via to sip msg\n");
|
|
|
- buf1 = build_req_buf_from_sip_req(&lreq,
|
|
|
- (unsigned int*)&buf_len1, &dst, BUILD_IN_SHM);
|
|
|
- if (likely(buf1)){
|
|
|
- shm_free(buf);
|
|
|
- buf = buf1;
|
|
|
- buf_len = buf_len1;
|
|
|
- /* a possible change of the method is not handled! */
|
|
|
- refresh_shortcuts = 1;
|
|
|
- }
|
|
|
-
|
|
|
- } else {
|
|
|
-normal_update:
|
|
|
- if (unlikely(lreq.add_rm || lreq.body_lumps
|
|
|
- || lreq.new_uri.s)) {
|
|
|
- LM_DBG("apply new updates without Via to sip msg\n");
|
|
|
- buf1 = build_req_buf_from_sip_req(&lreq,
|
|
|
- (unsigned int*)&buf_len1,
|
|
|
- &dst, BUILD_NO_LOCAL_VIA|BUILD_NO_VIA1_UPDATE|
|
|
|
- BUILD_IN_SHM);
|
|
|
- if (likely(buf1)){
|
|
|
- shm_free(buf);
|
|
|
- buf = buf1;
|
|
|
- buf_len = buf_len1;
|
|
|
- /* a possible change of the method is not handled! */
|
|
|
- refresh_shortcuts = 1;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ refresh_shortcuts = t_run_local_req(&buf, &buf_len, uac_r, new_cell, request);
|
|
|
+ }
|
|
|
+#endif
|
|
|
|
|
|
- /* clean local msg structure */
|
|
|
- if (unlikely(lreq.new_uri.s))
|
|
|
- {
|
|
|
- pkg_free(lreq.new_uri.s);
|
|
|
- lreq.new_uri.s=0;
|
|
|
- lreq.new_uri.len=0;
|
|
|
- }
|
|
|
- if (unlikely(lreq.dst_uri.s))
|
|
|
- {
|
|
|
- pkg_free(lreq.dst_uri.s);
|
|
|
- lreq.dst_uri.s=0;
|
|
|
- lreq.dst_uri.len=0;
|
|
|
- }
|
|
|
+#ifdef USE_DNS_FAILOVER
|
|
|
+ /* Set the outgoing message as UAS, so the failover code has something to work with */
|
|
|
+ if(cfg_get(core, core_cfg, use_dns_failover)) {
|
|
|
+ if(likely(t_build_msg_from_buf(&lreq, buf, buf_len, uac_r, &dst) == 0)) {
|
|
|
+ if (parse_headers(&lreq, HDR_EOH_F, 0) == -1) {
|
|
|
+ LM_ERR("failed to parse headers on uas for failover\n");
|
|
|
+ } else {
|
|
|
+ new_cell->uas.request = sip_msg_cloner(&lreq, &sip_msg_len);
|
|
|
lreq.buf=0; /* covers the obsolete DYN_BUF */
|
|
|
free_sip_msg(&lreq);
|
|
|
+ if (!new_cell->uas.request) {
|
|
|
+ LM_ERR("no more shmem\n");
|
|
|
+ goto error1;
|
|
|
+ }
|
|
|
+ new_cell->uas.end_request=((char*)new_cell->uas.request)+sip_msg_len;
|
|
|
}
|
|
|
+ } else {
|
|
|
+ LM_WARN("failed to build uas for failover\n");
|
|
|
}
|
|
|
}
|
|
|
-#endif
|
|
|
+#endif /* USE_DNS_FAILOVER */
|
|
|
|
|
|
new_cell->uac[0].on_reply = new_cell->on_reply;
|
|
|
new_cell->uac[0].on_failure = new_cell->on_failure;
|
|
@@ -518,14 +549,16 @@ normal_update:
|
|
|
LOCK_HASH(hi);
|
|
|
remove_from_hash_table_unsafe(new_cell);
|
|
|
UNLOCK_HASH(hi);
|
|
|
+ }
|
|
|
+
|
|
|
+error2:
|
|
|
#ifdef TM_DEL_UNREF
|
|
|
+ if (!is_ack) {
|
|
|
UNREF_FREE(new_cell);
|
|
|
}else
|
|
|
-#else
|
|
|
- }
|
|
|
#endif
|
|
|
free_cell(new_cell);
|
|
|
-error2:
|
|
|
+error3:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -558,23 +591,63 @@ int prepare_req_within(uac_req_t *uac_r,
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
-static inline void send_prepared_request_impl(struct retr_buf *request, int retransmit)
|
|
|
+static inline int send_prepared_request_impl(struct retr_buf *request, int retransmit, int branch)
|
|
|
{
|
|
|
+ struct cell *t;
|
|
|
+ struct sip_msg *p_msg;
|
|
|
+ struct ua_client *uac;
|
|
|
+ struct ip_addr ip; /* logging */
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ t = request->my_T;
|
|
|
+ uac = &t->uac[branch];
|
|
|
+ p_msg = t->uas.request;
|
|
|
+
|
|
|
if (SEND_BUFFER(request) == -1) {
|
|
|
LOG(L_ERR, "t_uac: Attempt to send to precreated request failed\n");
|
|
|
}
|
|
|
- else if (unlikely(has_tran_tmcbs(request->my_T, TMCB_REQUEST_SENT)))
|
|
|
+ else if (unlikely(has_tran_tmcbs(t, TMCB_REQUEST_SENT)))
|
|
|
/* we don't know the method here */
|
|
|
- run_trans_callbacks_with_buf(TMCB_REQUEST_SENT, request, 0, 0,
|
|
|
+ run_trans_callbacks_with_buf(TMCB_REQUEST_SENT, &uac->request, 0, 0,
|
|
|
TMCB_LOCAL_F);
|
|
|
-
|
|
|
- if (retransmit && (start_retr(request)!=0))
|
|
|
- LOG(L_CRIT, "BUG: t_uac: failed to start retr. for %p\n", request);
|
|
|
+
|
|
|
+ su2ip_addr(&ip, &uac->request.dst.to);
|
|
|
+ DBG("send_prepared_request_impl: uac: %p branch: %d to %s:%d\n",
|
|
|
+ uac, branch, ip_addr2a(&ip), su_getport(&uac->request.dst.to));
|
|
|
+
|
|
|
+ if (run_onsend(p_msg, &uac->request.dst, uac->request.buffer,
|
|
|
+ uac->request.buffer_len)==0){
|
|
|
+ uac->last_received=408;
|
|
|
+ su2ip_addr(&ip, &uac->request.dst.to);
|
|
|
+ DBG("t_uac: onsend_route dropped msg. to %s:%d (%d)\n",
|
|
|
+ ip_addr2a(&ip), su_getport(&uac->request.dst.to),
|
|
|
+ uac->request.dst.proto);
|
|
|
+#ifdef USE_DNS_FAILOVER
|
|
|
+ /* if the destination resolves to more ips, add another
|
|
|
+ * branch/uac */
|
|
|
+ ret = add_uac_dns_fallback(t, p_msg, uac, retransmit);
|
|
|
+ if (ret > 0) {
|
|
|
+ su2ip_addr(&ip, &uac->request.dst.to);
|
|
|
+ DBG("t_uac: send on branch %d failed "
|
|
|
+ "(onsend_route), trying another ip %s:%d (%d)\n",
|
|
|
+ branch, ip_addr2a(&ip),
|
|
|
+ su_getport(&uac->request.dst.to),
|
|
|
+ uac->request.dst.proto);
|
|
|
+ /* success, return new branch */
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+#endif /* USE_DNS_FAILOVER*/
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (retransmit && (start_retr(&uac->request)!=0))
|
|
|
+ LOG(L_CRIT, "BUG: t_uac: failed to start retr. for %p\n", &uac->request);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
void send_prepared_request(struct retr_buf *request)
|
|
|
{
|
|
|
- send_prepared_request_impl(request, 1 /* retransmit */);
|
|
|
+ send_prepared_request_impl(request, 1 /* retransmit */, 0);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -596,11 +669,27 @@ int t_uac_with_ids(uac_req_t *uac_r,
|
|
|
struct cell *cell;
|
|
|
int ret;
|
|
|
int is_ack;
|
|
|
+ int branch_ret;
|
|
|
+ int i;
|
|
|
+ branch_bm_t added_branches = 1;
|
|
|
|
|
|
ret = t_uac_prepare(uac_r, &request, &cell);
|
|
|
if (ret < 0) return ret;
|
|
|
is_ack = (uac_r->method->len == 3) && (memcmp("ACK", uac_r->method->s, 3)==0) ? 1 : 0;
|
|
|
- send_prepared_request_impl(request, !is_ack /* retransmit */);
|
|
|
+
|
|
|
+ /* equivalent loop to the one in t_forward_nonack */
|
|
|
+ for (i=0; i<cell->nr_of_outgoings; i++) {
|
|
|
+ if (added_branches & (1<<i)) {
|
|
|
+ branch_ret=send_prepared_request_impl(request, !is_ack /* retransmit */, i);
|
|
|
+ if (branch_ret>=0){ /* some kind of success */
|
|
|
+ if (branch_ret>i) {
|
|
|
+ /* new branch added */
|
|
|
+ added_branches |= 1<<branch_ret;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
if (is_ack) {
|
|
|
if (cell) free_cell(cell);
|
|
|
if (ret_index && ret_label)
|