Browse Source

core: forward: tcp fallback for big udp packets

- support for tcp, tls or sctp fallback for udp forwarded requests
  that end up bigger then udp_mtu (configurable, disabled by
  default). For such messages only the Via is changed (for example
  the original built for udp Record-Route is kept untouched so
  that subsequent messages in the dialog will use udp if smaller
  then udp_mtu).
- udp_mtu and udp_mtu_try_proto (fallback proto) can be changed at
  runtime via the cfg framework
  (e.g. sercmd cfg.set_now_int core udp_mtu 1300;
        cfg.set_now_int core udp_mtu_try_proto 2 )
- force_rport can now be set globally using the config framework
  (e.g. sercmd cfg.set_now_int core force_rport 1 )


Author: Andrei Pelinescu-Onciul <[email protected]>
Andrei Pelinescu-Onciul 16 years ago
parent
commit
bf8dfee3a6
5 changed files with 147 additions and 19 deletions
  1. 11 0
      cfg_core.c
  2. 3 0
      cfg_core.h
  3. 126 19
      msg_translator.c
  4. 2 0
      msg_translator.h
  5. 5 0
      parser/msg_parser.h

+ 11 - 0
cfg_core.c

@@ -41,6 +41,7 @@
 #if defined PKG_MALLOC || defined SHM_MEM
 #include "pt.h"
 #endif
+#include "msg_translator.h" /* fix_global_req_flags() */
 #include "cfg/cfg.h"
 #include "cfg_core.h"
 
@@ -88,6 +89,9 @@ struct cfg_group_core default_core_cfg = {
 #ifdef SHM_MEM
 	0, /* mem_dump_shm */
 #endif
+	0, /* udp_mtu (disabled by default) */
+	0, /* udp_mtu_try_proto -> default disabled */
+	0  /* force_rport */ 
 };
 
 void	*core_cfg = &default_core_cfg;
@@ -177,5 +181,12 @@ cfg_def_t core_cfg_def[] = {
 	{"mem_dump_shm",	CFG_VAR_INT,	0, 0, mem_dump_shm_fixup, 0,
 		"dump shared memory status"},
 #endif
+	{"udp_mtu",	CFG_VAR_INT|CFG_ATOMIC,	0, 65535, 0, 0,
+		"fallback to a congestion controlled protocol if send size"
+			" exceeds udp_mtu"},
+	{"udp_mtu_try_proto", CFG_VAR_INT, 1, 4, 0, fix_global_req_flags,
+		"if send size > udp_mtu use proto (1 udp, 2 tcp, 3 tls, 4 sctp)"},
+	{"force_rport",     CFG_VAR_INT, 0, 1,  0, fix_global_req_flags,
+		"force rport for all the received messages" },
 	{0, 0, 0, 0, 0, 0}
 };

+ 3 - 0
cfg_core.h

@@ -85,6 +85,9 @@ struct cfg_group_core {
 #ifdef SHM_MEM
 	int mem_dump_shm;
 #endif
+	int udp_mtu; /**< maximum send size for udp, if > try another protocol*/
+	int udp_mtu_try_proto; /**< if packet> udp_mtu, try proto (e.g. TCP) */
+	int force_rport; /**< if set rport will always be forced*/
 };
 
 extern struct cfg_group_core default_core_cfg;

+ 126 - 19
msg_translator.c

@@ -61,6 +61,10 @@
  *              (rfc3486) (andrei)
  * 2007-08-31  id_builder() and via_builder() are grouped into one function:
  *             create_via_hf() -- tm module needs them as well (Miklos)
+ * 2008-12-17  build_req_from_sip_req() will now fallback to tcp, tls or sctp
+ *              if packet size > udp_mtu and fallback is enabled 
+ *             build_req_from_sip_req() uses now global_req_flags along
+ *               msg->msg_flags  (andrei)
  *
  */
 /* Via special params:
@@ -134,6 +138,8 @@
 #include "resolve.h"
 #include "ut.h"
 #include "pt.h"
+#include "cfg/cfg.h"
+#include "forward.h"
 
 
 #define append_str(_dest,_src,_len) \
@@ -148,9 +154,35 @@
 extern char version[];
 extern int version_len;
 
+/* global flags for build_req_from_sip_req */
+static unsigned int global_req_flags=0;
 
 
 
+/** per process fixup function for global_req_flags.
+  * It should be called from the configuration framework.
+  */
+void fix_global_req_flags( str* name)
+{
+	global_req_flags=0;
+	switch(cfg_get(core, core_cfg, udp_mtu_try_proto)){
+		case PROTO_NONE:
+		case PROTO_UDP:
+			/* do nothing */
+			break;
+		case PROTO_TCP:
+			global_req_flags|=FL_MTU_TCP_FB;
+			break;
+		case PROTO_TLS:
+			global_req_flags|=FL_MTU_TLS_FB;
+			break;
+		case PROTO_SCTP:
+			global_req_flags|=FL_MTU_SCTP_FB;
+			break;
+	}
+	if (cfg_get(core, core_cfg, force_rport))
+		global_req_flags|=FL_FORCE_RPORT;
+}
 
 
 
@@ -1419,20 +1451,54 @@ error:
 
 
 
+/** builds a request in memory from another sip request.
+  *
+  * Side-effects: - it adds lumps to the msg which are _not_ cleaned.
+  * All the added lumps are HDR_VIA_T.
+  *               - it might change send_info->proto and send_info->send_socket
+  *                 if proto fallback is enabled (see below).
+  *
+  * Uses also global_req_flags ( OR'ed with msg->msg_flags, see send_info
+  * below).
+  *
+  * @param msg  - sip message structure, complete with lumps
+  * @param returned_len - result length (filled in)
+  * @param send_info  - dest_info structure (value/result), contains where the
+  *                     packet will be sent to (it's needed for building a 
+  *                     correct via, fill RR lumps a.s.o.). If MTU based
+  *                     protocol fall-back is enabled (see flags below),
+  *                     send_info->proto might be updated with the new
+  *                     protocol.
+  *                     msg->msg_flags used:
+  *                     - FL_TCP_MTU_FB, FL_TLS_MTU_FB and FL_SCTP_MTU_FB -
+  *                       fallback to the corresp. proto if the built 
+  *                       message > mtu and send_info->proto==PROTO_UDP. 
+  *                       It will also update send_info->proto.
+  *                     - FL_FORCE_RPORT: add rport to via
+  *
+  * @return pointer to the new request (pkg_malloc'ed, needs freeing when
+  *   done) and sets returned_len or 0 on error.
+  */
 char * build_req_buf_from_sip_req( struct sip_msg* msg,
 								unsigned int *returned_len,
-								struct dest_info* send_info)
+								struct dest_info* send_info
+								)
 {
-	unsigned int len, new_len, received_len, rport_len, uri_len, via_len, body_delta;
+	unsigned int len, new_len, received_len, rport_len, uri_len, via_len,
+				 body_delta;
 	char* line_buf;
 	char* received_buf;
 	char* rport_buf;
 	char* new_buf;
 	char* buf;
 	unsigned int offset, s_offset, size;
-	struct lump* anchor;
+	struct lump* via_anchor;
+	struct lump* via_lump;
 	struct lump* via_insert_param;
 	str branch;
+	unsigned int flags;
+	unsigned int udp_mtu;
+	struct socket_info* ss;
 
 	via_insert_param=0;
 	uri_len=0;
@@ -1445,9 +1511,8 @@ char * build_req_buf_from_sip_req( struct sip_msg* msg,
 	rport_buf=0;
 	line_buf=0;
 
-	     /* Calculate message body difference and adjust
-	      * Content-Length
-	      */
+	flags=msg->msg_flags|global_req_flags;
+	/* Calculate message body difference and adjust Content-Length */
 	body_delta = lumps_len(msg, msg->body_lumps, send_info);
 	if (adjust_clen(msg, body_delta, send_info->proto) < 0) {
 		LOG(L_ERR, "ERROR: build_req_buf_from_sip_req: Error while adjusting"
@@ -1455,13 +1520,14 @@ char * build_req_buf_from_sip_req( struct sip_msg* msg,
 		goto error00;
 	}
 
-	/* create a the via header */
+	/* create the via header */
 	branch.s=msg->add_to_branch_s;
 	branch.len=msg->add_to_branch_len;
 
 	line_buf = create_via_hf( &via_len, msg, send_info, &branch);
 	if (!line_buf){
-		LOG(L_ERR,"ERROR: build_req_buf_from_sip_req: no via received!\n");
+		LOG(L_ERR,"ERROR: build_req_buf_from_sip_req: "
+					"memory allocation failure\n");
 		goto error00;
 	}
 	/* check if received needs to be added */
@@ -1478,7 +1544,7 @@ char * build_req_buf_from_sip_req( struct sip_msg* msg,
 	 *  - if via already contains an rport add it and overwrite the previous
 	 *  rport value if present (if you don't want to overwrite the previous
 	 *  version remove the comments) */
-	if ((msg->msg_flags&FL_FORCE_RPORT)||
+	if ((flags&FL_FORCE_RPORT)||
 			(msg->via1->rport /*&& msg->via1->rport->value.s==0*/)){
 		if ((rport_buf=rport_builder(msg, &rport_len))==0){
 			LOG(L_ERR, "ERROR: build_req_buf_from_sip_req:"
@@ -1487,13 +1553,6 @@ char * build_req_buf_from_sip_req( struct sip_msg* msg,
 		}
 	}
 
-	/* add via header to the list */
-	/* try to add it before msg. 1st via */
-	/* add first via, as an anchor for second via*/
-	anchor=anchor_lump(msg, msg->via1->hdr.s-buf, 0, HDR_VIA_T);
-	if (anchor==0) goto error01;
-	if (insert_new_lump_before(anchor, line_buf, via_len, HDR_VIA_T)==0)
-		goto error01;
 	/* find out where the offset of the first parameter that should be added
 	 * (after host:port), needed by add receive & maybe rport */
 	if (msg->via1->params.s){
@@ -1546,10 +1605,57 @@ char * build_req_buf_from_sip_req( struct sip_msg* msg,
 	}
 
 	/* compute new msg len and fix overlapping zones*/
-	new_len=len+body_delta+lumps_len(msg, msg->add_rm, send_info);
+	new_len=len+body_delta+lumps_len(msg, msg->add_rm, send_info)+via_len;
 #ifdef XL_DEBUG
 	LOG(L_ERR, "DEBUG: new_len(%d)=len(%d)+lumps_len\n", new_len, len);
 #endif
+	udp_mtu=cfg_get(core, core_cfg, udp_mtu);
+	if (unlikely((send_info->proto==PROTO_UDP) && udp_mtu && 
+					(flags & FL_MTU_FB_MASK) && (new_len>udp_mtu))){
+		ss=0;
+#ifdef USE_TCP
+		if (!tcp_disable && (flags & FL_MTU_TCP_FB) &&
+				(ss=get_send_socket(msg, &send_info->to, PROTO_TCP))){
+			send_info->proto=PROTO_TCP;
+		}
+	#ifdef USE_TLS
+		else if (!tls_disable && (flags & FL_MTU_TLS_FB) &&
+				(ss=get_send_socket(msg, &send_info->to, PROTO_TLS))){
+			send_info->proto=PROTO_TLS;
+		}
+	#endif /* USE_TLS */
+#endif /* USE_TCP */
+#ifdef USE_SCTP
+	#ifdef USE_TCP
+		else
+	#endif /* USE_TCP */
+		 if (!sctp_disable && (flags & FL_MTU_SCTP_FB) &&
+				(ss=get_send_socket(msg, &send_info->to, PROTO_SCTP))){
+			send_info->proto=PROTO_SCTP;
+		 }
+#endif /* USE_SCTP */
+		
+		if (ss){
+			send_info->send_sock=ss;
+			new_len-=via_len;
+			pkg_free(line_buf);
+			line_buf = create_via_hf( &via_len, msg, send_info, &branch);
+			if (!line_buf){
+				LOG(L_ERR,"ERROR: build_req_buf_from_sip_req: "
+							"memory allocation failure!\n");
+				goto error00;
+			}
+			new_len+=via_len;
+		}
+	}
+	/* add via header to the list */
+	/* try to add it before msg. 1st via */
+	/* add first via, as an anchor for second via*/
+	via_anchor=anchor_lump(msg, msg->via1->hdr.s-buf, 0, HDR_VIA_T);
+	if (via_anchor==0) goto error04;
+	if ((via_lump=insert_new_lump_before(via_anchor, line_buf, via_len,
+											HDR_VIA_T))==0)
+		goto error04;
 
 	if (msg->new_uri.s){
 		uri_len=msg->new_uri.len;
@@ -1593,11 +1699,12 @@ char * build_req_buf_from_sip_req( struct sip_msg* msg,
 	return new_buf;
 
 error01:
-	if (line_buf) pkg_free(line_buf);
 error02:
 	if (received_buf) pkg_free(received_buf);
 error03:
 	if (rport_buf) pkg_free(rport_buf);
+error04:
+	if (line_buf) pkg_free(line_buf);
 error00:
 	*returned_len=0;
 	return 0;
@@ -1729,7 +1836,7 @@ char * build_res_buf_from_sip_req( unsigned int code, char *text ,str *new_tag,
 		}
 	}
 	/* check if rport needs to be updated */
-	if ( (msg->msg_flags&FL_FORCE_RPORT)||
+	if ( ((msg->msg_flags|global_req_flags)&FL_FORCE_RPORT)||
 		(msg->via1->rport /*&& msg->via1->rport->value.s==0*/)){
 		if ((rport_buf=rport_builder(msg, &rport_len))==0){
 			LOG(L_ERR, "ERROR: build_res_buf_from_sip_req:"

+ 2 - 0
msg_translator.h

@@ -149,5 +149,7 @@ char * build_all( struct sip_msg* msg, int adjust_clen,
 			int *error,
 			struct dest_info* send_info);
 
+/** cfg framework fixup */
+void fix_global_req_flags( str* name);
 
 #endif

+ 5 - 0
parser/msg_parser.h

@@ -92,6 +92,11 @@ enum request_method { METHOD_UNDEF=0, METHOD_INVITE=1, METHOD_CANCEL=2, METHOD_A
                                 (for failure route use) */
 #define FL_HASH_INDEX  128 /* msg->hash_index contains a valid value (tm use)*/
 
+#define FL_MTU_TCP_FB   256
+#define FL_MTU_TLS_FB   512
+#define FL_MTU_SCTP_FB 1024
+#define FL_MTU_FB_MASK  (FL_MTU_TCP_FB|FL_MTU_TLS_FB|FL_MTU_SCTP_FB)
+
 
 #define IFISMETHOD(methodname,firstchar)                                  \
 if (  (*tmp==(firstchar) || *tmp==((firstchar) | 32)) &&                  \