script: udp_mtu fallback script config & commands
authorAndrei Pelinescu-Onciul <andrei@iptel.org>
Thu, 18 Dec 2008 16:09:16 +0000 (16:09 +0000)
committerAndrei Pelinescu-Onciul <andrei@iptel.org>
Thu, 18 Dec 2008 16:09:16 +0000 (16:09 +0000)
new config variables:
 - udp_mtu = number  - size in bytes after which fallback to
   another protocol will be attempted. Default 0 (off),
   recommended 1300.
 - udp_mtu_try_proto = TCP|TLS|SCTP|UDP - protocol to fallback to.
   Default: UDP (off).
 - force_rport = yes|no - global force_rport().

new script commands:
 - udp_mtu_try_proto(TCP|TLS|SCTP|UDP) - like udp_mtu_try_proto
   above but works on a per packet basis and not globally.

Author: Andrei Pelinescu-Onciul <andrei@iptel.org>

NEWS
action.c
cfg.lex
cfg.y
forward.c
route.c
route_struct.h

diff --git a/NEWS b/NEWS
index f9c0867..88dd565 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -200,6 +200,10 @@ modules:
                         - t_set_retr(t1, t2) - changes the retransmissions
                            intervals on the fly, on a per transaction basis.
 core:
+             - fallback to tcp or other congestion controlled transport 
+               protocol if a forwarded udp sip request is greater then 
+               udp_mtu (config). Default off. See udp_mtu and 
+               udp_mtu_try_proto.
              - sctp support (one-to-many, work in progress, for now linux
                only with no fallback to one-to-one on full send buffers)
              - partial cygwin (windows) support revived: core+static modules, 
@@ -220,6 +224,17 @@ core:
                between the short name and long name in cache as CNAME record
 
 new config variables:
+  udp_mtu = number - fallback to another protocol (udp_mtu_try_proto must be
+                     set also either globally or per packet) if the constructed
+                     request size is greater then udp_mtu.
+                     Recommended size: 1300. Default: 0 (off).
+  udp_mtu_try_proto = TCP|TLS|SCTP|UDP - if udp_mtu !=0 and udp forwarded
+                     request size (after adding all the "local" headers) >
+                     udp_mtu, use this protocol instead of udp. Only the
+                     Via header will be updated (e.g. The Record-Route
+                     will be the one built for udp).
+                     Default: UDP (off). Recommended: TCP.
+  force_rport =yes/no - like force_rport(), but works globally.
   disable_sctp = yes/no - disable sctp support (default auto, see enable_sctp)
   enable_sctp = 0/1/2  - disable (0)/enable (1)/auto (2) sctp support, 
                          default auto (2)
@@ -240,8 +255,8 @@ new config variables:
                       hosts (default: 0).
   server_id = number - A configurable unique server id that can be used to
                        discriminate server instances within a cluster of
-                       servers when all other information, such as IP adddresses
-                       are same.
+                       servers when all other information, such as IP addresses
+                       are the same.
   loadpath = <modules path> - directory where to load the modules from (-L
      equivalent); modules can be loaded simply by specifying their name
      (loadmodule "maxfwd")
@@ -336,6 +351,11 @@ new config variables:
     is not initialized at startup and cannot be enabled runtime,
     that saves some memory.
 
+new script commands:
+  udp_mtu_try_proto(TCP|TLS|SCTP|UDP) - same as udp_mtu_try_proto=... (see
+    above), but works per packet and not globally.
+
+
 build system:
  - check defines and includes used at compile time and if different 
    force rebuilding everything in the current dir (creates a new file: 
index 6dbbf1f..cfd6145 100644 (file)
--- a/action.c
+++ b/action.c
@@ -46,6 +46,7 @@
  *              (andrei)
  *  2007-06-14  run_actions & do_action need a ctx or handle now, no more 
  *               static vars (andrei)
+ *  2008-12-17  added UDP_MTU_TRY_PROTO_T (andrei)
  */
 
 
@@ -731,6 +732,10 @@ int do_action(struct run_act_ctx* h, struct action* a, struct sip_msg* msg)
                        msg->msg_flags|=FL_FORCE_RPORT;
                        ret=1; /* continue processing */
                        break;
+               case UDP_MTU_TRY_PROTO_T:
+                       msg->msg_flags|= (unsigned int)a->val[0].u.number & FL_MTU_FB_MASK;
+                       ret=1; /* continue processing */
+                       break;
                case SET_ADV_ADDR_T:
                        if (a->val[0].type!=STR_ST){
                                LOG(L_CRIT, "BUG: do_action: bad set_advertised_address() "
diff --git a/cfg.lex b/cfg.lex
index 5af02db..0c4ac17 100644 (file)
--- a/cfg.lex
+++ b/cfg.lex
@@ -143,6 +143,8 @@ ROUTE_SEND onsend_route
 EXEC   exec
 FORCE_RPORT            "force_rport"|"add_rport"
 FORCE_TCP_ALIAS                "force_tcp_alias"|"add_tcp_alias"
+UDP_MTU                "udp_mtu"
+UDP_MTU_TRY_PROTO      "udp_mtu_try_proto"
 SETFLAG                setflag
 RESETFLAG      resetflag
 ISFLAGSET      isflagset
@@ -463,6 +465,9 @@ EAT_ABLE    [\ \t\b\r]
 <INITIAL>{FORCE_RPORT} { count(); yylval.strval=yytext; return FORCE_RPORT; }
 <INITIAL>{FORCE_TCP_ALIAS}     { count(); yylval.strval=yytext;
                                                                return FORCE_TCP_ALIAS; }
+<INITIAL>{UDP_MTU}     { count(); yylval.strval=yytext; return UDP_MTU; }
+<INITIAL>{UDP_MTU_TRY_PROTO}   { count(); yylval.strval=yytext;
+                                                                       return UDP_MTU_TRY_PROTO; }
 <INITIAL>{IF}  { count(); yylval.strval=yytext; return IF; }
 <INITIAL>{ELSE}        { count(); yylval.strval=yytext; return ELSE; }
 
diff --git a/cfg.y b/cfg.y
index 8925c63..8408e1d 100644 (file)
--- a/cfg.y
+++ b/cfg.y
 #include "tcp_init.h"
 #include "tcp_options.h"
 #include "sctp_options.h"
+#include "msg_translator.h"
 
 #include "config.h"
 #include "cfg_core.h"
@@ -244,6 +245,8 @@ static void free_socket_id_lst(struct socket_id* i);
 %token REVERT_URI
 %token FORCE_RPORT
 %token FORCE_TCP_ALIAS
+%token UDP_MTU
+%token UDP_MTU_TRY_PROTO
 %token IF
 %token ELSE
 %token SET_ADV_ADDRESS
@@ -1248,6 +1251,15 @@ assign_stm:
        | STUN_ALLOW_FP EQUAL NUMBER { IF_STUN(stun_allow_fp=$3) ; }
        | STUN_ALLOW_FP EQUAL error{ yyerror("number expected"); }
     | SERVER_ID EQUAL NUMBER { server_id=$3; }
+       | UDP_MTU EQUAL NUMBER { default_core_cfg.udp_mtu=$3; }
+       | UDP_MTU EQUAL error { yyerror("number expected"); }
+       | FORCE_RPORT EQUAL NUMBER 
+               { default_core_cfg.force_rport=$3; fix_global_req_flags(0); }
+       | FORCE_RPORT EQUAL error { yyerror("boolean value expected"); }
+       | UDP_MTU_TRY_PROTO EQUAL proto
+               { default_core_cfg.udp_mtu_try_proto=$3; fix_global_req_flags(0); }
+       | UDP_MTU_TRY_PROTO EQUAL error
+               { yyerror("TCP, TLS, SCTP or UDP expected"); }
        | cfg_var
        | error EQUAL { yyerror("unknown config variable"); }
        ;
@@ -2322,6 +2334,10 @@ cmd:
                #endif
        }
        | FORCE_TCP_ALIAS LPAREN error RPAREN   {$$=0; yyerror("bad argument, number expected"); }
+       | UDP_MTU_TRY_PROTO LPAREN proto RPAREN
+               { $$=mk_action(UDP_MTU_TRY_PROTO_T, 1, NUMBER_ST, $3); }
+       | UDP_MTU_TRY_PROTO LPAREN error RPAREN
+               { $$=0; yyerror("bad argument, UDP, TCP, TLS or SCTP expected"); }
        | SET_ADV_ADDRESS LPAREN listen_id RPAREN {
                $$=0;
                if ((str_tmp=pkg_malloc(sizeof(str)))==0) {
index 9055347..eb1b7c9 100644 (file)
--- a/forward.c
+++ b/forward.c
@@ -342,6 +342,7 @@ int forward_request(struct sip_msg* msg, str* dst, unsigned short port,
        struct socket_info* orig_send_sock; /* initial send_sock */
        int ret;
        struct ip_addr ip; /* debugging only */
+       char proto;
 #ifdef USE_DNS_FAILOVER
        struct socket_info* prev_send_sock;
        int err;
@@ -354,6 +355,7 @@ int forward_request(struct sip_msg* msg, str* dst, unsigned short port,
        
        buf=0;
        orig_send_sock=send_info->send_sock;
+       proto=send_info->proto;
        ret=0;
 
        if(dst){
@@ -361,7 +363,7 @@ int forward_request(struct sip_msg* msg, str* dst, unsigned short port,
                if (cfg_get(core, core_cfg, use_dns_failover)){
                        dns_srv_handle_init(&dns_srv_h);
                        err=dns_sip_resolve2su(&dns_srv_h, &send_info->to, dst, port,
-                                                                       &send_info->proto, dns_flags);
+                                                                       &proto, dns_flags);
                        if (err!=0){
                                LOG(L_ERR, "ERROR: forward_request: resolving \"%.*s\""
                                                " failed: %s [%d]\n", dst->len, ZSW(dst->s),
@@ -371,7 +373,7 @@ int forward_request(struct sip_msg* msg, str* dst, unsigned short port,
                        }
                }else
 #endif
-               if (sip_hostport2su(&send_info->to, dst, port, &send_info->proto)<0){
+               if (sip_hostport2su(&send_info->to, dst, port, &proto)<0){
                        LOG(L_ERR, "ERROR: forward_request: bad host name %.*s,"
                                                " dropping packet\n", dst->len, ZSW(dst->s));
                        ret=E_BAD_ADDRESS;
@@ -410,12 +412,11 @@ int forward_request(struct sip_msg* msg, str* dst, unsigned short port,
        do{
 #endif
                if (orig_send_sock==0) /* no forced send_sock => find it **/
-                       send_info->send_sock=get_send_socket(msg, &send_info->to,
-                                                                                               send_info->proto);
+                       send_info->send_sock=get_send_socket(msg, &send_info->to, proto);
                if (send_info->send_sock==0){
                        LOG(L_ERR, "forward_req: ERROR: cannot forward to af %d, proto %d "
                                                "no corresponding listening socket\n",
-                                               send_info->to.s.sa_family, send_info->proto);
+                                               send_info->to.s.sa_family, proto);
                        ret=ser_error=E_NO_SOCKET;
 #ifdef USE_DNS_FAILOVER
                        /* continue, maybe we find a socket for some other ip */
@@ -431,6 +432,7 @@ int forward_request(struct sip_msg* msg, str* dst, unsigned short port,
                        prev_send_sock=send_info->send_sock;
 #endif
                        if (buf) pkg_free(buf);
+                       send_info->proto=proto;
                        buf = build_req_buf_from_sip_req(msg, &len, send_info);
                        if (!buf){
                                LOG(L_ERR, "ERROR: forward_request: building failed\n");
@@ -496,7 +498,7 @@ int forward_request(struct sip_msg* msg, str* dst, unsigned short port,
        }while(dst && cfg_get(core, core_cfg, use_dns_failover) &&
                        dns_srv_handle_next(&dns_srv_h, err) && 
                        ((err=dns_sip_resolve2su(&dns_srv_h, &send_info->to, dst, port,
-                                                                 &send_info->proto, dns_flags))==0));
+                                                                               &proto, dns_flags))==0));
        if ((err!=0) && (err!=-E_DNS_EOR)){
                LOG(L_ERR, "ERROR:  resolving %.*s host name in uri"
                                                        " failed: %s [%d] (dropping packet)\n",
diff --git a/route.c b/route.c
index d636b85..d553d71 100644 (file)
--- a/route.c
+++ b/route.c
@@ -564,6 +564,32 @@ static int fix_actions(struct action* a)
                                t->val[0].u.data=si;
                                t->val[0].type=SOCKETINFO_ST;
                                break;
+                       case UDP_MTU_TRY_PROTO_T:
+                               if (t->val[0].type!=NUMBER_ST){
+                                       LOG(L_CRIT, "BUG: fix_actions: invalid subtype"
+                                                               "%d for udp_mtu_try_proto\n",
+                                                               t->val[0].type);
+                                       return E_BUG;
+                               }
+                               switch(t->val[0].u.number){
+                                       case PROTO_UDP:
+                                               t->val[0].u.number=0;
+                                               break;
+                                       case PROTO_TCP:
+                                               t->val[0].u.number=FL_MTU_TCP_FB;
+                                               break;
+                                       case PROTO_TLS:
+                                               t->val[0].u.number=FL_MTU_TLS_FB;
+                                               break;
+                                       case PROTO_SCTP:
+                                               t->val[0].u.number=FL_MTU_SCTP_FB;
+                                               break;
+                                       default:
+                                               LOG(L_CRIT, "BUG: fix actions: invalid argument for"
+                                                                       " udp_mtu_try_proto (%d)\n", 
+                                                                       (unsigned int)t->val[0].u.number);
+                               }
+                               break;
                }
        }
        return 0;
index 814517b..2539c36 100644 (file)
@@ -35,6 +35,7 @@
  *  2004-02-24  added LOAD_AVP_T and AVP_TO_URI_T (bogdan)
  *  2005-12-11  added SND{IP,PORT,PROTO,AF}_O & TO{IP,PORT}_O (andrei)
  *  2005-12-19  select framework added SELECT_O and SELECT_ST (mma)
+ *  2008-12-17  added UDP_MTU_TRY_PROTO_T (andrei)
  */
 
 
@@ -89,7 +90,8 @@ enum { FORWARD_T=1, SEND_T, DROP_T, LOG_T, ERROR_T, ROUTE_T, EXEC_T,
                AVP_TO_URI_T,
                FORCE_SEND_SOCKET_T,
                ASSIGN_T,
-               ADD_T
+               ADD_T,
+               UDP_MTU_TRY_PROTO_T
 };
 enum { NOSUBTYPE=0, STRING_ST, NET_ST, NUMBER_ST, IP_ST, RE_ST, PROXY_ST,
                EXPR_ST, ACTIONS_ST, MODEXP_ST, MODFIXUP_ST, URIHOST_ST, URIPORT_ST,