Ver Fonte

sctp: workaround SCTP_DELAYED_SACK lksctp typo

- 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)
Andrei Pelinescu-Onciul há 16 anos atrás
pai
commit
1b83a39eaf
4 ficheiros alterados com 185 adições e 64 exclusões
  1. 35 13
      sctp_options.c
  2. 1 0
      sctp_options.h
  3. 105 51
      sctp_server.c
  4. 44 0
      sctp_sockopts.h

+ 35 - 13
sctp_options.c

@@ -48,6 +48,7 @@ struct cfg_group_sctp sctp_default_cfg;
 
 
 #ifdef USE_SCTP
 #ifdef USE_SCTP
 
 
+#include "sctp_sockopts.h"
 
 
 static int set_autoclose(void* cfg_h, str* gname, str* name, void** val);
 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);
 static int set_assoc_tracking(void* cfg_h, str* gname, str* name, void** val);
@@ -218,12 +219,16 @@ int sctp_register_cfg()
 	int err; \
 	int err; \
 	struct socket_info* si
 	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; \
 	err=0; \
 	for (si=sctp_listen; si; si=si->next){ \
 	for (si=sctp_listen; si; si=si->next){ \
 		err+=(sctp_setsockopt(si->socket, (lev), (opt_name), (void*)(&(val)), \
 		err+=(sctp_setsockopt(si->socket, (lev), (opt_name), (void*)(&(val)), \
 							sizeof((val)), (err_prefix))<0); \
 							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)
 	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
 #if defined SCTP_DELAYED_SACK || defined SCTP_DELAYED_ACK_TIME
 #ifdef SCTP_DELAYED_SACK
 #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 */
 #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;
 	SCTP_SET_SOCKOPT_DECLS;
 	
 	
 	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
 	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
 		*val=(void*)(long)cfg_get(sctp, cfg_h, sack_delay);
 		*val=(void*)(long)cfg_get(sctp, cfg_h, sack_delay);
 		return 0;
 		return 0;
 	}
 	}
-	memset(&sa, 0, sizeof(sa)); /* zero everything we don't care about */
 #ifdef SCTP_DELAYED_SACK
 #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 */
 #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
 #else
 	ERR("no SCTP_DELAYED_SACK support, please upgrade your sctp library\n");
 	ERR("no SCTP_DELAYED_SACK support, please upgrade your sctp library\n");
 	return -1;
 	return -1;

+ 1 - 0
sctp_options.h

@@ -72,5 +72,6 @@ void sctp_options_check();
 int sctp_register_cfg();
 int sctp_register_cfg();
 void sctp_options_get(struct cfg_group_sctp *s);
 void sctp_options_get(struct cfg_group_sctp *s);
 int sctp_get_os_defaults(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 */
 #endif /* _sctp_options_h */

+ 105 - 51
sctp_server.c

@@ -42,6 +42,7 @@
 #include <fcntl.h>
 #include <fcntl.h>
 
 
 
 
+#include "sctp_sockopts.h"
 #include "sctp_server.h"
 #include "sctp_server.h"
 #include "sctp_options.h"
 #include "sctp_options.h"
 #include "globals.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.
 /** get the os defaults for cfg options with os correspondents.
- *  @param s - intialized sctp socket
  *  @param cfg - filled with the os defaults
  *  @param cfg - filled with the os defaults
  *  @return -1 on error, 0 on success
  *  @return -1 on error, 0 on success
  */
  */
 int sctp_get_os_defaults(struct cfg_group_sctp* cfg)
 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;
 	int optval;
 	socklen_t optlen;
 	socklen_t optlen;
-	int s;
 #ifdef SCTP_RTOINFO
 #ifdef SCTP_RTOINFO
 	struct sctp_rtoinfo rto;
 	struct sctp_rtoinfo rto;
 #endif /* SCTP_RTOINFO */
 #endif /* SCTP_RTOINFO */
@@ -245,19 +264,16 @@ int sctp_get_os_defaults(struct cfg_group_sctp* cfg)
 #ifdef SCTP_PEER_ADDR_PARAMS
 #ifdef SCTP_PEER_ADDR_PARAMS
 	struct sctp_paddrparams pp;
 	struct sctp_paddrparams pp;
 #endif /* SCTP_PEER_ADDR_PARAMS */
 #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
 #ifdef SCTP_MAX_BURST
 	struct sctp_assoc_value av;
 	struct sctp_assoc_value av;
 #endif /* SCTP_MAX_BURST */
 #endif /* SCTP_MAX_BURST */
 	
 	
-	s = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
-	if (s==-1)
-		return -1;
-	
 	/* SO_RCVBUF */
 	/* SO_RCVBUF */
 	optlen=sizeof(int);
 	optlen=sizeof(int);
 	if (sctp_getsockopt(s, SOL_SOCKET, SO_RCVBUF, (void*)&optval,
 	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
 		#endif
 		cfg->so_sndbuf=optval;
 		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 */
 	/* SCTP_RTOINFO -> srto_initial, srto_min, srto_max */
 #ifdef SCTP_RTOINFO
 #ifdef SCTP_RTOINFO
 	optlen=sizeof(rto);
 	optlen=sizeof(rto);
@@ -321,23 +345,36 @@ int sctp_get_os_defaults(struct cfg_group_sctp* cfg)
 	}
 	}
 #endif /* SCTP_PEER_ADDR_PARAMS */
 #endif /* SCTP_PEER_ADDR_PARAMS */
 #if defined SCTP_DELAYED_SACK || defined SCTP_DELAYED_ACK_TIME
 #if defined SCTP_DELAYED_SACK || defined SCTP_DELAYED_ACK_TIME
-	optlen=sizeof(sa);
-	memset(&sa, 0, sizeof(sa));
 #ifdef SCTP_DELAYED_SACK
 #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*/
 		/* 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 */
 #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*/
 #endif /* SCTP_DELAYED_SACK  | SCTP_DELAYED_ACK_TIME*/
 #ifdef SCTP_MAX_BURST
 #ifdef SCTP_MAX_BURST
 	optlen=sizeof(av);
 	optlen=sizeof(av);
@@ -349,7 +386,6 @@ int sctp_get_os_defaults(struct cfg_group_sctp* cfg)
 	}
 	}
 #endif /* SCTP_MAX_BURST */
 #endif /* SCTP_MAX_BURST */
 	
 	
-	close(s);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -381,10 +417,11 @@ static int sctp_init_sock_opt_common(int s, int af)
 	struct sctp_paddrparams pp;
 	struct sctp_paddrparams pp;
 #endif /* SCTP_PEER_ADDR_PARAMS */
 #endif /* SCTP_PEER_ADDR_PARAMS */
 #ifdef SCTP_DELAYED_SACK
 #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
 #ifdef SCTP_MAX_BURST
 	struct sctp_assoc_value av;
 	struct sctp_assoc_value av;
 #endif /* SCTP_MAX_BURST */
 #endif /* SCTP_MAX_BURST */
@@ -629,34 +666,51 @@ static int sctp_init_sock_opt_common(int s, int af)
 #endif /* SCTP_PEER_ADDR_PARAMS */
 #endif /* SCTP_PEER_ADDR_PARAMS */
 	/* set delayed ack options: sack_delay & sack_freq */
 	/* set delayed ack options: sack_delay & sack_freq */
 #if defined SCTP_DELAYED_SACK || defined SCTP_DELAYED_ACK_TIME
 #if defined SCTP_DELAYED_SACK || defined SCTP_DELAYED_ACK_TIME
-	memset(&sa, 0, sizeof(sa));
 #ifdef SCTP_DELAYED_SACK
 #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++;
 			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++;
 			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 */
 #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
 #warning no sctp lib support for SCTP_DELAYED_SACK, consider upgrading
 #endif /* SCTP_DELAYED_SACK  | SCTP_DELAYED_ACK_TIME*/
 #endif /* SCTP_DELAYED_SACK  | SCTP_DELAYED_ACK_TIME*/
 	/* set max burst option */
 	/* set max burst option */

+ 44 - 0
sctp_sockopts.h

@@ -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: */