sctp: workaround SCTP_DELAYED_SACK lksctp typo
authorAndrei Pelinescu-Onciul <andrei@iptel.org>
Thu, 12 Nov 2009 15:24:08 +0000 (16:24 +0100)
committerDaniel-Constantin Mierla <miconda@gmail.com>
Sun, 15 Nov 2009 16:49:12 +0000 (17:49 +0100)
- workaround typo in linux libsctp api: SCTP_DELAYED_ACK is
  used/defined instead of SCTP_DELAYED_SACK.
- to support older kernels (< 2.6.27), if setting/getting the
  socket options with SCTP_DELAYED_SACK fails, fallback to
  SCTP_DELAYED_ACK_TIME for sctp sack_delay and report an error if
  the user tries to set sack_freq (not supported on older
  kernels).
- split sctp_get_os_default() into sctp_get_os_default() and
  sctp_get_cfg_from_sock() for debugging purposes.
(cherry picked from commit cc16495666e948f2c18dc0bacebecfac85ff59a5)

sctp_options.c
sctp_options.h
sctp_server.c
sctp_sockopts.h [new file with mode: 0644]

index b6d7e36..79dabc8 100644 (file)
@@ -48,6 +48,7 @@ struct cfg_group_sctp sctp_default_cfg;
 
 #ifdef USE_SCTP
 
+#include "sctp_sockopts.h"
 
 static int set_autoclose(void* cfg_h, str* gname, str* name, void** val);
 static int set_assoc_tracking(void* cfg_h, str* gname, str* name, void** val);
@@ -218,12 +219,16 @@ int sctp_register_cfg()
        int err; \
        struct socket_info* si
 
-#define SCTP_SET_SOCKOPT_BODY(lev, opt_name, val, err_prefix) \
+
+#define SCTP_SET_SOCKOPT_BODY_NRET(lev, opt_name, val, err_prefix) \
        err=0; \
        for (si=sctp_listen; si; si=si->next){ \
                err+=(sctp_setsockopt(si->socket, (lev), (opt_name), (void*)(&(val)), \
                                                        sizeof((val)), (err_prefix))<0); \
-       } \
+       }
+
+#define SCTP_SET_SOCKOPT_BODY(lev, opt_name, val, err_prefix) \
+       SCTP_SET_SOCKOPT_BODY_NRET(lev, opt_name, val, err_prefix) ; \
        return -(err!=0)
 
 
@@ -508,26 +513,43 @@ static int set_sack_delay(void* cfg_h, str* gname, str* name, void** val)
 {
 #if defined SCTP_DELAYED_SACK || defined SCTP_DELAYED_ACK_TIME
 #ifdef SCTP_DELAYED_SACK
-       struct sctp_sack_info sa;
-#else /* old lib */
-       struct sctp_assoc_value sa;
+       struct sctp_sack_info sack_info;
 #endif /* SCTP_DELAYED_SACK */
+#ifdef SCTP_DELAYED_ACK_TIME
+       struct sctp_assoc_value sack_val; /* old version, sack delay only */
+#endif /* SCTP_DELAYED_ACK_TIME */
        SCTP_SET_SOCKOPT_DECLS;
        
        if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
                *val=(void*)(long)cfg_get(sctp, cfg_h, sack_delay);
                return 0;
        }
-       memset(&sa, 0, sizeof(sa)); /* zero everything we don't care about */
 #ifdef SCTP_DELAYED_SACK
-       sa.sack_delay=(int)(long)(*val);
-       SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_DELAYED_SACK, sa,
-                                                       "cfg: setting SCTP_DELAYED_SACK");
-#else /* old sctp lib version which uses SCTP_DELAYED_ACK_TIME */
-       sa.assoc_value=(int)(long)(*val);
-       SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_DELAYED_ACK_TIME, sa,
-                                                       "cfg: setting SCTP_DELAYED_ACK_TIME");
+       memset(&sack_info, 0, sizeof(sack_info)); /* zero everything we don't
+                                                                                                care about */
+       sack_info.sack_delay=(int)(long)(*val);
+       SCTP_SET_SOCKOPT_BODY_NRET(IPPROTO_SCTP, SCTP_DELAYED_SACK, sack_info, 0);
+       if (err==0){
+               return 0;
+       }else
 #endif /* SCTP_DELAYED_SACK */
+       {
+               /* setting SCTP_DELAYED_SACK failed or no lib support for 
+                  SCTP_DELAYED_SACK => try the old obsolete SCTP_DELAYED_ACK_TIME */
+#ifdef SCTP_DELAYED_ACK_TIME
+               memset(&sack_val, 0, sizeof(sack_val)); /* zero everything we don't
+                                                                                                  care about */
+               sack_val.assoc_value=(int)(long)(*val);
+               SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_DELAYED_ACK_TIME, sack_val,
+                                                               "cfg: setting SCTP_DELAYED_ACK_TIME");
+#else  /* SCTP_DELAYED_ACK_TIME */
+               /* no SCTP_DELAYED_ACK_TIME support and SCTP_DELAYED_SACK failed
+                  => error */
+               ERR("cfg: setting SCTP_DELAYED_SACK: %s [%d]\n",
+                                       strerror(errno), errno);
+               return -1;
+#endif /* SCTP_DELAYED_ACK_TIME */
+       }
 #else
        ERR("no SCTP_DELAYED_SACK support, please upgrade your sctp library\n");
        return -1;
index a5c6b06..f674f3e 100644 (file)
@@ -72,5 +72,6 @@ void sctp_options_check();
 int sctp_register_cfg();
 void sctp_options_get(struct cfg_group_sctp *s);
 int sctp_get_os_defaults(struct cfg_group_sctp *s);
+int sctp_get_cfg_from_sock(int s, struct cfg_group_sctp* cfg);
 
 #endif /* _sctp_options_h */
index b86bbf3..7c5995d 100644 (file)
@@ -42,6 +42,7 @@
 #include <fcntl.h>
 
 
+#include "sctp_sockopts.h"
 #include "sctp_server.h"
 #include "sctp_options.h"
 #include "globals.h"
@@ -224,15 +225,33 @@ int sctp_getsockopt(int s, int level, int optname,
 
 
 /** get the os defaults for cfg options with os correspondents.
- *  @param s - intialized sctp socket
  *  @param cfg - filled with the os defaults
  *  @return -1 on error, 0 on success
  */
 int sctp_get_os_defaults(struct cfg_group_sctp* cfg)
+{
+       int s;
+       int ret;
+       
+       s = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
+       if (s==-1)
+               return -1;
+       ret=sctp_get_cfg_from_sock(s, cfg);
+       close(s);
+       return ret;
+}
+
+
+
+/** get the os cfg options from a specific socket.
+ *  @param s - intialized sctp socket
+ *  @param cfg - filled with the os defaults
+ *  @return -1 on error, 0 on success
+ */
+int sctp_get_cfg_from_sock(int s, struct cfg_group_sctp* cfg)
 {
        int optval;
        socklen_t optlen;
-       int s;
 #ifdef SCTP_RTOINFO
        struct sctp_rtoinfo rto;
 #endif /* SCTP_RTOINFO */
@@ -245,19 +264,16 @@ int sctp_get_os_defaults(struct cfg_group_sctp* cfg)
 #ifdef SCTP_PEER_ADDR_PARAMS
        struct sctp_paddrparams pp;
 #endif /* SCTP_PEER_ADDR_PARAMS */
-#ifdef SCTP_DELAYED_SACK
-       struct sctp_sack_info sa;
-#elif defined SCTP_DELAYED_ACK_TIME /* old version */
-       struct sctp_assoc_value sa;
-#endif /* SCTP_DELAYED_SACK */
+#ifdef SCTP_DELAYED_SACK
+       struct sctp_sack_info sack_info;
+#endif /* SCTP_DELAYED_SACK */
+#ifdef SCTP_DELAYED_ACK_TIME
+       struct sctp_assoc_value sack_val; /* old version */
+#endif /* SCTP_DELAYED_ACK_TIME */
 #ifdef SCTP_MAX_BURST
        struct sctp_assoc_value av;
 #endif /* SCTP_MAX_BURST */
        
-       s = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
-       if (s==-1)
-               return -1;
-       
        /* SO_RCVBUF */
        optlen=sizeof(int);
        if (sctp_getsockopt(s, SOL_SOCKET, SO_RCVBUF, (void*)&optval,
@@ -278,6 +294,14 @@ int sctp_get_os_defaults(struct cfg_group_sctp* cfg)
                #endif
                cfg->so_sndbuf=optval;
        }
+       /* SCTP_AUTOCLOSE */
+#ifdef SCTP_AUTOCLOSE
+       optlen=sizeof(int);
+       if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_AUTOCLOSE, (void*)&optval,
+                                                       &optlen, "SCTP_AUTOCLOSE")==0){
+               cfg->autoclose=optval;
+       }
+#endif /* SCTP_AUTOCLOSE */
        /* SCTP_RTOINFO -> srto_initial, srto_min, srto_max */
 #ifdef SCTP_RTOINFO
        optlen=sizeof(rto);
@@ -321,23 +345,36 @@ int sctp_get_os_defaults(struct cfg_group_sctp* cfg)
        }
 #endif /* SCTP_PEER_ADDR_PARAMS */
 #if defined SCTP_DELAYED_SACK || defined SCTP_DELAYED_ACK_TIME
-       optlen=sizeof(sa);
-       memset(&sa, 0, sizeof(sa));
 #ifdef SCTP_DELAYED_SACK
-       if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_SACK, (void*)&sa,
-                                                       &optlen, "SCTP_DELAYED_SACK")==0){
-               /* success => hack to set the "default" values*/
-               cfg->sack_delay=sa.sack_delay;
-               cfg->sack_freq=sa.sack_freq;
-       }
-#else /* old sctp lib version which uses SCTP_DELAYED_ACK_TIME */
-       if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_ACK_TIME, (void*)&sa,
-                                                       &optlen, "SCTP_DELAYED_ACK_TIME")==0){
+       optlen=sizeof(sack_info);
+       memset(&sack_info, 0, sizeof(sack_info));
+       if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_SACK, (void*)&sack_info,
+                                                       &optlen, 0)==0){
                /* success => hack to set the "default" values*/
-               cfg->sack_delay=sa.assoc_value;
-               cfg->sack_freq=0; /* unknown */
-       }
+               cfg->sack_delay=sack_info.sack_delay;
+               cfg->sack_freq=sack_info.sack_freq;
+       }else
 #endif /* SCTP_DELAYED_SACK */
+       {
+#ifdef SCTP_DELAYED_ACK_TIME
+               optlen=sizeof(sack_val);
+               memset(&sack_val, 0, sizeof(sack_val));
+               /* if no SCTP_DELAYED_SACK supported by the sctp lib, or setting it
+                  failed (not supported by the kernel) try using the obsolete
+                  SCTP_DELAYED_ACK_TIME method */
+               if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_ACK_TIME,
+                                                               (void*)&sack_val, &optlen, 
+                                                               "SCTP_DELAYED_ACK_TIME")==0){
+                       /* success => hack to set the "default" values*/
+                       cfg->sack_delay=sack_val.assoc_value;
+                       cfg->sack_freq=0; /* unknown */
+               }
+#else  /* SCTP_DELAYED_ACK_TIME */
+               /* no SCTP_DELAYED_ACK_TIME support and SCTP_DELAYED_SACK failed
+                  => error */
+               ERR("cfg: SCTP_DELAYED_SACK: %s [%d]\n", strerror(errno), errno);
+#endif /* SCTP_DELAYED_ACK_TIME */
+       }
 #endif /* SCTP_DELAYED_SACK  | SCTP_DELAYED_ACK_TIME*/
 #ifdef SCTP_MAX_BURST
        optlen=sizeof(av);
@@ -349,7 +386,6 @@ int sctp_get_os_defaults(struct cfg_group_sctp* cfg)
        }
 #endif /* SCTP_MAX_BURST */
        
-       close(s);
        return 0;
 }
 
@@ -381,10 +417,11 @@ static int sctp_init_sock_opt_common(int s, int af)
        struct sctp_paddrparams pp;
 #endif /* SCTP_PEER_ADDR_PARAMS */
 #ifdef SCTP_DELAYED_SACK
-       struct sctp_sack_info sa;
-#elif defined SCTP_DELAYED_ACK_TIME /* old version */
-       struct sctp_assoc_value sa;
-#endif /* SCTP_DELAYED_SACK */
+       struct sctp_sack_info sack_info;
+#endif /* SCTP_DELAYED_SACK */
+#ifdef SCTP_DELAYED_ACK_TIME
+       struct sctp_assoc_value sack_val;
+#endif /* defined SCTP_DELAYED_ACK_TIME */
 #ifdef SCTP_MAX_BURST
        struct sctp_assoc_value av;
 #endif /* SCTP_MAX_BURST */
@@ -629,34 +666,51 @@ static int sctp_init_sock_opt_common(int s, int af)
 #endif /* SCTP_PEER_ADDR_PARAMS */
        /* set delayed ack options: sack_delay & sack_freq */
 #if defined SCTP_DELAYED_SACK || defined SCTP_DELAYED_ACK_TIME
-       memset(&sa, 0, sizeof(sa));
 #ifdef SCTP_DELAYED_SACK
-       sa.sack_delay=cfg_get(sctp, sctp_cfg, sack_delay);
-       sa.sack_freq=cfg_get(sctp, sctp_cfg, sack_freq);
-       if (sa.sack_delay || sa.sack_freq){
-               /* if at least one is non-null => we have to set it */
-               if (sctp_setsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_SACK, (void*)&sa,
-                                                       sizeof(sa), "setsockopt: SCTP_DELAYED_SACK")!=0){
+       memset(&sack_info, 0, sizeof(sack_info));
+       sack_info.sack_delay=cfg_get(sctp, sctp_cfg, sack_delay);
+       sack_info.sack_freq=cfg_get(sctp, sctp_cfg, sack_freq);
+       if ((sack_info.sack_delay || sack_info.sack_freq) &&
+               (sctp_setsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_SACK,
+                                                       (void*)&sack_info, sizeof(sack_info), 0)!=0)) {
+               /* if setting SCTP_DELAYED_SACK failed, try the old obsolete
+                  SCTP_DELAYED_ACK_TIME */
+#endif /* SCTP_DELAYED_SACK */
+#ifdef SCTP_DELAYED_ACK_TIME
+               memset(&sack_val, 0, sizeof(sack_val));
+               sack_val.assoc_value=cfg_get(sctp, sctp_cfg, sack_delay);
+               if (sack_val.assoc_value){
+                       if (sctp_setsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_ACK_TIME,
+                                                                       (void*)&sack_val, sizeof(sack_val),
+                                                                       "setsockopt: SCTP_DELAYED_ACK_TIME")!=0){
+                               sctp_err++;
+                               /* non critical, try to continue */
+                       }
+               }
+#else /* SCTP_DELAYED_ACK_TIME */
+               /* no SCTP_DELAYED_ACK_TIME support and SCTP_DELAYED_SACK failed
+                  => error */
+               if (sack_info.sack_delay){
                        sctp_err++;
-                       /* non critical, try to continue */
+                       ERR("cfg: setting SCTP_DELAYED_SACK: %s [%d]\n",
+                                               strerror(errno), errno);
                }
-       }
-#else /* old sctp lib version which uses SCTP_DELAYED_ACK_TIME */
-       sa.assoc_value=cfg_get(sctp, sctp_cfg, sack_delay);
-       if (sa.assoc_value){
-               if (sctp_setsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_ACK_TIME, (void*)&sa,
-                                               sizeof(sa), "setsockopt: SCTP_DELAYED_ACK_TIME")!=0){
+#endif /* SCTP_DELAYED_ACK_TIME */
+               if (cfg_get(sctp, sctp_cfg, sack_freq)){
+#ifdef SCTP_DELAYED_SACK
                        sctp_err++;
-                       /* non critical, try to continue */
+                       WARN("could not set sctp sack_freq, please upgrade your kernel\n");
+#else /* SCTP_DELAYED_SACK */
+                       WARN("could not set sctp sack_freq, please upgrade your sctp"
+                                       " library\n");
+#endif /* SCTP_DELAYED_SACK */
+                       ((struct cfg_group_sctp*)sctp_cfg)->sack_freq=0;
                }
-       }
-       if (cfg_get(sctp, sctp_cfg, sack_freq)){
-               WARN("could not set sctp sack_freq, please upgrade your sctp"
-                               " library\n");
-               ((struct cfg_group_sctp*)sctp_cfg)->sack_freq=0;
+#ifdef SCTP_DELAYED_SACK
        }
 #endif /* SCTP_DELAYED_SACK */
-#else /* SCTP_DELAYED_SACK  | SCTP_DELAYED_ACK*/
+       
+#else /* SCTP_DELAYED_SACK  | SCTP_DELAYED_ACK_TIME*/
 #warning no sctp lib support for SCTP_DELAYED_SACK, consider upgrading
 #endif /* SCTP_DELAYED_SACK  | SCTP_DELAYED_ACK_TIME*/
        /* set max burst option */
diff --git a/sctp_sockopts.h b/sctp_sockopts.h
new file mode 100644 (file)
index 0000000..91cceb8
--- /dev/null
@@ -0,0 +1,44 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2009 iptelorg GmbH
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * sctp_sockopts.h - portability fixes / compatibility defines for some
+ *                   sctp socket options
+ */
+/*
+ * History:
+ * --------
+ *  2009-11-12  initial version (andrei)
+*/
+
+#ifndef __sctp_sockopts_h
+#define __sctp_sockopts_h
+
+#include <netinet/sctp.h>
+
+#ifndef SCTP_DELAYED_SACK
+#ifdef SCTP_DELAYED_ACK
+/* on linux lksctp/libsctp <= 1.0.11 (and possible future versions)
+ * SCTP_DELAYED_ACK is used instead of SCTP_DELAYED_SACK (typo?)
+ */
+#define        SCTP_DELAYED_SACK SCTP_DELAYED_ACK
+#endif /* SCTP_DELAYED_ACK */
+#endif /* SCTP_DELAYED_SACK */
+
+#endif /*__sctp_sockopts_h*/
+
+/* vi: set ts=4 sw=4 tw=79:ai:cindent: */