Browse Source

tm: new param: local_ack_mode

local_ack_mode controls how local 200 ACKs (ACKs to 2xx replies
for local transactions, created via t_uac*) are sent.
There are 3 possible modes:
- 0 (default) - ACK is sent according to the rfc (the next hop is
  found using the contact and the route set and then dns
  resolution is used on it).
- 1 - the ACK is sent to the same address as the corresponding
  INVITE branch.
- 2 - the ACL is sent to the same address as the source of the 2xx
  reply.

Modes 1 and 2 break the rfc, but are useful to deal with
some simple UA behind the NAT cases.
Note that mode 1 is not similar to generating ACKs for negative
replies. Even if the ACK will be sent to the same address as the
INVITE, it will contain the correct route set and uri.
Andrei Pelinescu-Onciul 15 years ago
parent
commit
49218e800d
4 changed files with 47 additions and 21 deletions
  1. 9 1
      modules/tm/config.c
  2. 1 0
      modules/tm/config.h
  3. 36 20
      modules/tm/t_msgbuilder.c
  4. 1 0
      modules/tm/tm.c

+ 9 - 1
modules/tm/config.c

@@ -91,7 +91,8 @@ struct cfg_group_tm	default_tm_cfg = {
 			 * for every method except BYE by default */
 			 * for every method except BYE by default */
 	1,	/* cancel_b_method used for e2e and 6xx cancels*/
 	1,	/* cancel_b_method used for e2e and 6xx cancels*/
 	1,	/* reparse_on_dns_failover */
 	1,	/* reparse_on_dns_failover */
-	0 /* disable_6xx, by default off */
+	0, /* disable_6xx, by default off */
+	0  /* local_ack_mode, default 0 (rfc3261 conformant) */
 };
 };
 
 
 void	*tm_cfg = &default_tm_cfg;
 void	*tm_cfg = &default_tm_cfg;
@@ -186,5 +187,12 @@ cfg_def_t	tm_cfg_def[] = {
 		"branch instead of from the received request"},
 		"branch instead of from the received request"},
 	{"disable_6xx_block",	CFG_VAR_INT | CFG_ATOMIC,	0, 1, 0, 0,
 	{"disable_6xx_block",	CFG_VAR_INT | CFG_ATOMIC,	0, 1, 0, 0,
 		"if set to 1, 6xx is treated like a normal reply (breaks rfc)"},
 		"if set to 1, 6xx is treated like a normal reply (breaks rfc)"},
+	{"local_ack_mode",		CFG_VAR_INT | CFG_ATOMIC,	0, 2, 0, 0,
+		"if set to 1 or 2, local 200 ACKs are sent to the same address as the"
+		" corresponding INVITE (1) or the source of the 200 reply (2) instead"
+		" of using the contact and the route set (it breaks the rfc, if "
+		" it is not set to 0 but allows dealing with NATed contacts in some "
+		"simple cases)"
+		},
 	{0, 0, 0, 0, 0, 0}
 	{0, 0, 0, 0, 0, 0}
 };
 };

+ 1 - 0
modules/tm/config.h

@@ -134,6 +134,7 @@ struct cfg_group_tm {
 	unsigned int	cancel_b_flags;
 	unsigned int	cancel_b_flags;
 	int	reparse_on_dns_failover;
 	int	reparse_on_dns_failover;
 	int disable_6xx;
 	int disable_6xx;
+	int local_ack_mode;
 };
 };
 
 
 extern struct cfg_group_tm	default_tm_cfg;
 extern struct cfg_group_tm	default_tm_cfg;

+ 36 - 20
modules/tm/t_msgbuilder.c

@@ -982,33 +982,49 @@ char *build_dlg_ack(struct sip_msg* rpl, struct cell *Trans,
 	*len = SIP_VERSION_LEN + ACK_LEN + 2 /* spaces */ + CRLF_LEN;
 	*len = SIP_VERSION_LEN + ACK_LEN + 2 /* spaces */ + CRLF_LEN;
 	*len += ruri.len;
 	*len += ruri.len;
 	
 	
-	
-	 /* via */
+	/* dst */
+	switch(cfg_get(tm, tm_cfg, local_ack_mode)){
+		case 1:
+			/* send the local 200 ack to the same dst as the corresp. invite*/
+			*dst=Trans->uac[branch].request.dst;
+			break;
+		case 2: 
+			/* send the local 200 ack to the same dst as the 200 reply source*/
+			init_dst_from_rcv(dst, &rpl->rcv);
+			dst->send_flags=rpl->fwd_send_flags;
+			break;
+		case 0:
+		default:
+			/* rfc conformant behaviour: use the next_hop determined from the
+			   contact and the route set */
 #ifdef USE_DNS_FAILOVER
 #ifdef USE_DNS_FAILOVER
-	if (cfg_get(core, core_cfg, use_dns_failover)){
-		dns_srv_handle_init(&dns_h);
-		if ((uri2dst(&dns_h , dst, rpl, &next_hop, PROTO_NONE)==0) ||
-				(dst->send_sock==0)){
-			dns_srv_handle_put(&dns_h);
-			LOG(L_ERR, "build_dlg_ack: no socket found\n");
-			goto error;
+		if (cfg_get(core, core_cfg, use_dns_failover)){
+			dns_srv_handle_init(&dns_h);
+			if ((uri2dst(&dns_h , dst, rpl, &next_hop, PROTO_NONE)==0) ||
+					(dst->send_sock==0)){
+				dns_srv_handle_put(&dns_h);
+				LOG(L_ERR, "build_dlg_ack: no socket found\n");
+				goto error;
+			}
+			dns_srv_handle_put(&dns_h); /* not needed any more */
+		}else{
+			if ((uri2dst(0 , dst, rpl, &next_hop, PROTO_NONE)==0) ||
+					(dst->send_sock==0)){
+				LOG(L_ERR, "build_dlg_ack: no socket found\n");
+				goto error;
+			}
 		}
 		}
-		dns_srv_handle_put(&dns_h); /* not needed any more */
-	}else{
-		if ((uri2dst(0 , dst, rpl, &next_hop, PROTO_NONE)==0) ||
+#else /* USE_DNS_FAILOVER */
+		if ( (uri2dst( dst, rpl, &next_hop, PROTO_NONE)==0) ||
 				(dst->send_sock==0)){
 				(dst->send_sock==0)){
-			LOG(L_ERR, "build_dlg_ack: no socket found\n");
+				LOG(L_ERR, "build_dlg_ack: no socket found\n");
 			goto error;
 			goto error;
 		}
 		}
+#endif /* USE_DNS_FAILOVER */
+		break;
 	}
 	}
-#else
-	if ( (uri2dst( dst, rpl, &next_hop, PROTO_NONE)==0) ||
-			(dst->send_sock==0)){
-			LOG(L_ERR, "build_dlg_ack: no socket found\n");
-		goto error;
-	}
-#endif
 	
 	
+	 /* via */
 	if (!t_calc_branch(Trans,  branch, branch_buf, &branch_len)) goto error;
 	if (!t_calc_branch(Trans,  branch, branch_buf, &branch_len)) goto error;
 	branch_str.s = branch_buf;
 	branch_str.s = branch_buf;
 	branch_str.len = branch_len;
 	branch_str.len = branch_len;

+ 1 - 0
modules/tm/tm.c

@@ -470,6 +470,7 @@ static param_export_t params[]={
 	{"on_sl_reply",         PARAM_STRING|PARAM_USE_FUNC, fixup_on_sl_reply   },
 	{"on_sl_reply",         PARAM_STRING|PARAM_USE_FUNC, fixup_on_sl_reply   },
 	{"contacts_avp",        PARAM_STRING, &contacts_avp_param                },
 	{"contacts_avp",        PARAM_STRING, &contacts_avp_param                },
 	{"disable_6xx_block",   PARAM_INT, &default_tm_cfg.disable_6xx           },
 	{"disable_6xx_block",   PARAM_INT, &default_tm_cfg.disable_6xx           },
+	{"local_ack_mode",      PARAM_INT, &default_tm_cfg.local_ack_mode        },
 	{0,0,0}
 	{0,0,0}
 };
 };