Browse code

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.

Andrei Pelinescu-Onciul authored on 12/11/2009 15:24:08
Showing 4 changed files
... ...
@@ -48,6 +48,7 @@ struct cfg_group_sctp sctp_default_cfg;
48 48
 
49 49
 #ifdef USE_SCTP
50 50
 
51
+#include "sctp_sockopts.h"
51 52
 
52 53
 static int set_autoclose(void* cfg_h, str* gname, str* name, void** val);
53 54
 static int set_assoc_tracking(void* cfg_h, str* gname, str* name, void** val);
... ...
@@ -218,12 +219,16 @@ int sctp_register_cfg()
218 218
 	int err; \
219 219
 	struct socket_info* si
220 220
 
221
-#define SCTP_SET_SOCKOPT_BODY(lev, opt_name, val, err_prefix) \
221
+
222
+#define SCTP_SET_SOCKOPT_BODY_NRET(lev, opt_name, val, err_prefix) \
222 223
 	err=0; \
223 224
 	for (si=sctp_listen; si; si=si->next){ \
224 225
 		err+=(sctp_setsockopt(si->socket, (lev), (opt_name), (void*)(&(val)), \
225 226
 							sizeof((val)), (err_prefix))<0); \
226
-	} \
227
+	}
228
+
229
+#define SCTP_SET_SOCKOPT_BODY(lev, opt_name, val, err_prefix) \
230
+	SCTP_SET_SOCKOPT_BODY_NRET(lev, opt_name, val, err_prefix) ; \
227 231
 	return -(err!=0)
228 232
 
229 233
 
... ...
@@ -508,26 +513,43 @@ static int set_sack_delay(void* cfg_h, str* gname, str* name, void** val)
508 508
 {
509 509
 #if defined SCTP_DELAYED_SACK || defined SCTP_DELAYED_ACK_TIME
510 510
 #ifdef SCTP_DELAYED_SACK
511
-	struct sctp_sack_info sa;
512
-#else /* old lib */
513
-	struct sctp_assoc_value sa;
511
+	struct sctp_sack_info sack_info;
514 512
 #endif /* SCTP_DELAYED_SACK */
513
+#ifdef	SCTP_DELAYED_ACK_TIME
514
+	struct sctp_assoc_value sack_val; /* old version, sack delay only */
515
+#endif /* SCTP_DELAYED_ACK_TIME */
515 516
 	SCTP_SET_SOCKOPT_DECLS;
516 517
 	
517 518
 	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
518 519
 		*val=(void*)(long)cfg_get(sctp, cfg_h, sack_delay);
519 520
 		return 0;
520 521
 	}
521
-	memset(&sa, 0, sizeof(sa)); /* zero everything we don't care about */
522 522
 #ifdef SCTP_DELAYED_SACK
523
-	sa.sack_delay=(int)(long)(*val);
524
-	SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_DELAYED_SACK, sa,
525
-							"cfg: setting SCTP_DELAYED_SACK");
526
-#else /* old sctp lib version which uses SCTP_DELAYED_ACK_TIME */
527
-	sa.assoc_value=(int)(long)(*val);
528
-	SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_DELAYED_ACK_TIME, sa,
529
-							"cfg: setting SCTP_DELAYED_ACK_TIME");
523
+	memset(&sack_info, 0, sizeof(sack_info)); /* zero everything we don't
524
+												 care about */
525
+	sack_info.sack_delay=(int)(long)(*val);
526
+	SCTP_SET_SOCKOPT_BODY_NRET(IPPROTO_SCTP, SCTP_DELAYED_SACK, sack_info, 0);
527
+	if (err==0){
528
+		return 0;
529
+	}else
530 530
 #endif /* SCTP_DELAYED_SACK */
531
+	{
532
+		/* setting SCTP_DELAYED_SACK failed or no lib support for 
533
+		   SCTP_DELAYED_SACK => try the old obsolete SCTP_DELAYED_ACK_TIME */
534
+#ifdef	SCTP_DELAYED_ACK_TIME
535
+		memset(&sack_val, 0, sizeof(sack_val)); /* zero everything we don't
536
+												   care about */
537
+		sack_val.assoc_value=(int)(long)(*val);
538
+		SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_DELAYED_ACK_TIME, sack_val,
539
+								"cfg: setting SCTP_DELAYED_ACK_TIME");
540
+#else	/* SCTP_DELAYED_ACK_TIME */
541
+		/* no SCTP_DELAYED_ACK_TIME support and SCTP_DELAYED_SACK failed
542
+		   => error */
543
+		ERR("cfg: setting SCTP_DELAYED_SACK: %s [%d]\n",
544
+					strerror(errno), errno);
545
+		return -1;
546
+#endif /* SCTP_DELAYED_ACK_TIME */
547
+	}
531 548
 #else
532 549
 	ERR("no SCTP_DELAYED_SACK support, please upgrade your sctp library\n");
533 550
 	return -1;
... ...
@@ -72,5 +72,6 @@ void sctp_options_check();
72 72
 int sctp_register_cfg();
73 73
 void sctp_options_get(struct cfg_group_sctp *s);
74 74
 int sctp_get_os_defaults(struct cfg_group_sctp *s);
75
+int sctp_get_cfg_from_sock(int s, struct cfg_group_sctp* cfg);
75 76
 
76 77
 #endif /* _sctp_options_h */
... ...
@@ -42,6 +42,7 @@
42 42
 #include <fcntl.h>
43 43
 
44 44
 
45
+#include "sctp_sockopts.h"
45 46
 #include "sctp_server.h"
46 47
 #include "sctp_options.h"
47 48
 #include "globals.h"
... ...
@@ -224,15 +225,33 @@ int sctp_getsockopt(int s, int level, int optname,
224 224
 
225 225
 
226 226
 /** get the os defaults for cfg options with os correspondents.
227
- *  @param s - intialized sctp socket
228 227
  *  @param cfg - filled with the os defaults
229 228
  *  @return -1 on error, 0 on success
230 229
  */
231 230
 int sctp_get_os_defaults(struct cfg_group_sctp* cfg)
232 231
 {
232
+	int s;
233
+	int ret;
234
+	
235
+	s = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
236
+	if (s==-1)
237
+		return -1;
238
+	ret=sctp_get_cfg_from_sock(s, cfg);
239
+	close(s);
240
+	return ret;
241
+}
242
+
243
+
244
+
245
+/** get the os cfg options from a specific socket.
246
+ *  @param s - intialized sctp socket
247
+ *  @param cfg - filled with the os defaults
248
+ *  @return -1 on error, 0 on success
249
+ */
250
+int sctp_get_cfg_from_sock(int s, struct cfg_group_sctp* cfg)
251
+{
233 252
 	int optval;
234 253
 	socklen_t optlen;
235
-	int s;
236 254
 #ifdef SCTP_RTOINFO
237 255
 	struct sctp_rtoinfo rto;
238 256
 #endif /* SCTP_RTOINFO */
... ...
@@ -245,19 +264,16 @@ int sctp_get_os_defaults(struct cfg_group_sctp* cfg)
245 245
 #ifdef SCTP_PEER_ADDR_PARAMS
246 246
 	struct sctp_paddrparams pp;
247 247
 #endif /* SCTP_PEER_ADDR_PARAMS */
248
-#ifdef SCTP_DELAYED_SACK
249
-	struct sctp_sack_info sa;
250
-#elif defined SCTP_DELAYED_ACK_TIME /* old version */
251
-	struct sctp_assoc_value sa;
252
-#endif /* SCTP_DELAYED_SACK */
248
+#ifdef	SCTP_DELAYED_SACK
249
+	struct sctp_sack_info sack_info;
250
+#endif	/* SCTP_DELAYED_SACK */
251
+#ifdef	SCTP_DELAYED_ACK_TIME
252
+	struct sctp_assoc_value sack_val; /* old version */
253
+#endif /* SCTP_DELAYED_ACK_TIME */
253 254
 #ifdef SCTP_MAX_BURST
254 255
 	struct sctp_assoc_value av;
255 256
 #endif /* SCTP_MAX_BURST */
256 257
 	
257
-	s = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
258
-	if (s==-1)
259
-		return -1;
260
-	
261 258
 	/* SO_RCVBUF */
262 259
 	optlen=sizeof(int);
263 260
 	if (sctp_getsockopt(s, SOL_SOCKET, SO_RCVBUF, (void*)&optval,
... ...
@@ -278,6 +294,14 @@ int sctp_get_os_defaults(struct cfg_group_sctp* cfg)
278 278
 		#endif
279 279
 		cfg->so_sndbuf=optval;
280 280
 	}
281
+	/* SCTP_AUTOCLOSE */
282
+#ifdef SCTP_AUTOCLOSE
283
+	optlen=sizeof(int);
284
+	if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_AUTOCLOSE, (void*)&optval,
285
+							&optlen, "SCTP_AUTOCLOSE")==0){
286
+		cfg->autoclose=optval;
287
+	}
288
+#endif /* SCTP_AUTOCLOSE */
281 289
 	/* SCTP_RTOINFO -> srto_initial, srto_min, srto_max */
282 290
 #ifdef SCTP_RTOINFO
283 291
 	optlen=sizeof(rto);
... ...
@@ -321,23 +345,36 @@ int sctp_get_os_defaults(struct cfg_group_sctp* cfg)
321 321
 	}
322 322
 #endif /* SCTP_PEER_ADDR_PARAMS */
323 323
 #if defined SCTP_DELAYED_SACK || defined SCTP_DELAYED_ACK_TIME
324
-	optlen=sizeof(sa);
325
-	memset(&sa, 0, sizeof(sa));
326 324
 #ifdef SCTP_DELAYED_SACK
327
-	if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_SACK, (void*)&sa,
328
-							&optlen, "SCTP_DELAYED_SACK")==0){
329
-		/* success => hack to set the "default" values*/
330
-		cfg->sack_delay=sa.sack_delay;
331
-		cfg->sack_freq=sa.sack_freq;
332
-	}
333
-#else /* old sctp lib version which uses SCTP_DELAYED_ACK_TIME */
334
-	if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_ACK_TIME, (void*)&sa,
335
-							&optlen, "SCTP_DELAYED_ACK_TIME")==0){
325
+	optlen=sizeof(sack_info);
326
+	memset(&sack_info, 0, sizeof(sack_info));
327
+	if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_SACK, (void*)&sack_info,
328
+							&optlen, 0)==0){
336 329
 		/* success => hack to set the "default" values*/
337
-		cfg->sack_delay=sa.assoc_value;
338
-		cfg->sack_freq=0; /* unknown */
339
-	}
330
+		cfg->sack_delay=sack_info.sack_delay;
331
+		cfg->sack_freq=sack_info.sack_freq;
332
+	}else
340 333
 #endif /* SCTP_DELAYED_SACK */
334
+	{
335
+#ifdef	SCTP_DELAYED_ACK_TIME
336
+		optlen=sizeof(sack_val);
337
+		memset(&sack_val, 0, sizeof(sack_val));
338
+		/* if no SCTP_DELAYED_SACK supported by the sctp lib, or setting it
339
+		   failed (not supported by the kernel) try using the obsolete
340
+		   SCTP_DELAYED_ACK_TIME method */
341
+		if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_ACK_TIME,
342
+								(void*)&sack_val, &optlen, 
343
+								"SCTP_DELAYED_ACK_TIME")==0){
344
+			/* success => hack to set the "default" values*/
345
+			cfg->sack_delay=sack_val.assoc_value;
346
+			cfg->sack_freq=0; /* unknown */
347
+		}
348
+#else	/* SCTP_DELAYED_ACK_TIME */
349
+		/* no SCTP_DELAYED_ACK_TIME support and SCTP_DELAYED_SACK failed
350
+		   => error */
351
+		ERR("cfg: SCTP_DELAYED_SACK: %s [%d]\n", strerror(errno), errno);
352
+#endif /* SCTP_DELAYED_ACK_TIME */
353
+	}
341 354
 #endif /* SCTP_DELAYED_SACK  | SCTP_DELAYED_ACK_TIME*/
342 355
 #ifdef SCTP_MAX_BURST
343 356
 	optlen=sizeof(av);
... ...
@@ -349,7 +386,6 @@ int sctp_get_os_defaults(struct cfg_group_sctp* cfg)
349 349
 	}
350 350
 #endif /* SCTP_MAX_BURST */
351 351
 	
352
-	close(s);
353 352
 	return 0;
354 353
 }
355 354
 
... ...
@@ -381,10 +417,11 @@ static int sctp_init_sock_opt_common(int s, int af)
381 381
 	struct sctp_paddrparams pp;
382 382
 #endif /* SCTP_PEER_ADDR_PARAMS */
383 383
 #ifdef SCTP_DELAYED_SACK
384
-	struct sctp_sack_info sa;
385
-#elif defined SCTP_DELAYED_ACK_TIME /* old version */
386
-	struct sctp_assoc_value sa;
387
-#endif /* SCTP_DELAYED_SACK */
384
+	struct sctp_sack_info sack_info;
385
+#endif	/* SCTP_DELAYED_SACK */
386
+#ifdef	SCTP_DELAYED_ACK_TIME
387
+	struct sctp_assoc_value sack_val;
388
+#endif /* defined SCTP_DELAYED_ACK_TIME */
388 389
 #ifdef SCTP_MAX_BURST
389 390
 	struct sctp_assoc_value av;
390 391
 #endif /* SCTP_MAX_BURST */
... ...
@@ -629,34 +666,51 @@ static int sctp_init_sock_opt_common(int s, int af)
629 629
 #endif /* SCTP_PEER_ADDR_PARAMS */
630 630
 	/* set delayed ack options: sack_delay & sack_freq */
631 631
 #if defined SCTP_DELAYED_SACK || defined SCTP_DELAYED_ACK_TIME
632
-	memset(&sa, 0, sizeof(sa));
633 632
 #ifdef SCTP_DELAYED_SACK
634
-	sa.sack_delay=cfg_get(sctp, sctp_cfg, sack_delay);
635
-	sa.sack_freq=cfg_get(sctp, sctp_cfg, sack_freq);
636
-	if (sa.sack_delay || sa.sack_freq){
637
-		/* if at least one is non-null => we have to set it */
638
-		if (sctp_setsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_SACK, (void*)&sa,
639
-							sizeof(sa), "setsockopt: SCTP_DELAYED_SACK")!=0){
633
+	memset(&sack_info, 0, sizeof(sack_info));
634
+	sack_info.sack_delay=cfg_get(sctp, sctp_cfg, sack_delay);
635
+	sack_info.sack_freq=cfg_get(sctp, sctp_cfg, sack_freq);
636
+	if ((sack_info.sack_delay || sack_info.sack_freq) &&
637
+		(sctp_setsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_SACK,
638
+							(void*)&sack_info, sizeof(sack_info), 0)!=0)) {
639
+		/* if setting SCTP_DELAYED_SACK failed, try the old obsolete
640
+		   SCTP_DELAYED_ACK_TIME */
641
+#endif /* SCTP_DELAYED_SACK */
642
+#ifdef SCTP_DELAYED_ACK_TIME
643
+		memset(&sack_val, 0, sizeof(sack_val));
644
+		sack_val.assoc_value=cfg_get(sctp, sctp_cfg, sack_delay);
645
+		if (sack_val.assoc_value){
646
+			if (sctp_setsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_ACK_TIME,
647
+									(void*)&sack_val, sizeof(sack_val),
648
+									"setsockopt: SCTP_DELAYED_ACK_TIME")!=0){
649
+				sctp_err++;
650
+				/* non critical, try to continue */
651
+			}
652
+		}
653
+#else /* SCTP_DELAYED_ACK_TIME */
654
+		/* no SCTP_DELAYED_ACK_TIME support and SCTP_DELAYED_SACK failed
655
+		   => error */
656
+		if (sack_info.sack_delay){
640 657
 			sctp_err++;
641
-			/* non critical, try to continue */
658
+			ERR("cfg: setting SCTP_DELAYED_SACK: %s [%d]\n",
659
+						strerror(errno), errno);
642 660
 		}
643
-	}
644
-#else /* old sctp lib version which uses SCTP_DELAYED_ACK_TIME */
645
-	sa.assoc_value=cfg_get(sctp, sctp_cfg, sack_delay);
646
-	if (sa.assoc_value){
647
-		if (sctp_setsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_ACK_TIME, (void*)&sa,
648
-						sizeof(sa), "setsockopt: SCTP_DELAYED_ACK_TIME")!=0){
661
+#endif /* SCTP_DELAYED_ACK_TIME */
662
+		if (cfg_get(sctp, sctp_cfg, sack_freq)){
663
+#ifdef SCTP_DELAYED_SACK
649 664
 			sctp_err++;
650
-			/* non critical, try to continue */
665
+			WARN("could not set sctp sack_freq, please upgrade your kernel\n");
666
+#else /* SCTP_DELAYED_SACK */
667
+			WARN("could not set sctp sack_freq, please upgrade your sctp"
668
+					" library\n");
669
+#endif /* SCTP_DELAYED_SACK */
670
+			((struct cfg_group_sctp*)sctp_cfg)->sack_freq=0;
651 671
 		}
652
-	}
653
-	if (cfg_get(sctp, sctp_cfg, sack_freq)){
654
-		WARN("could not set sctp sack_freq, please upgrade your sctp"
655
-				" library\n");
656
-		((struct cfg_group_sctp*)sctp_cfg)->sack_freq=0;
672
+#ifdef SCTP_DELAYED_SACK
657 673
 	}
658 674
 #endif /* SCTP_DELAYED_SACK */
659
-#else /* SCTP_DELAYED_SACK  | SCTP_DELAYED_ACK*/
675
+	
676
+#else /* SCTP_DELAYED_SACK  | SCTP_DELAYED_ACK_TIME*/
660 677
 #warning no sctp lib support for SCTP_DELAYED_SACK, consider upgrading
661 678
 #endif /* SCTP_DELAYED_SACK  | SCTP_DELAYED_ACK_TIME*/
662 679
 	/* set max burst option */
663 680
new file mode 100644
... ...
@@ -0,0 +1,44 @@
0
+/* 
1
+ * $Id$
2
+ * 
3
+ * Copyright (C) 2009 iptelorg GmbH
4
+ *
5
+ * Permission to use, copy, modify, and distribute this software for any
6
+ * purpose with or without fee is hereby granted, provided that the above
7
+ * copyright notice and this permission notice appear in all copies.
8
+ *
9
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
+ */
17
+/*
18
+ * sctp_sockopts.h - portability fixes / compatibility defines for some
19
+ *                   sctp socket options
20
+ */
21
+/*
22
+ * History:
23
+ * --------
24
+ *  2009-11-12  initial version (andrei)
25
+*/
26
+
27
+#ifndef __sctp_sockopts_h
28
+#define __sctp_sockopts_h
29
+
30
+#include <netinet/sctp.h>
31
+
32
+#ifndef SCTP_DELAYED_SACK
33
+#ifdef	SCTP_DELAYED_ACK
34
+/* on linux lksctp/libsctp <= 1.0.11 (and possible future versions)
35
+ * SCTP_DELAYED_ACK is used instead of SCTP_DELAYED_SACK (typo?)
36
+ */
37
+#define	SCTP_DELAYED_SACK SCTP_DELAYED_ACK
38
+#endif	/* SCTP_DELAYED_ACK */
39
+#endif /* SCTP_DELAYED_SACK */
40
+
41
+#endif /*__sctp_sockopts_h*/
42
+
43
+/* vi: set ts=4 sw=4 tw=79:ai:cindent: */