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 219
 	int err; \
219 220
 	struct socket_info* si
220 221
 
221
-#define SCTP_SET_SOCKOPT_BODY(lev, opt_name, val, err_prefix) \
222
+
223
+#define SCTP_SET_SOCKOPT_BODY_NRET(lev, opt_name, val, err_prefix) \
222 224
 	err=0; \
223 225
 	for (si=sctp_listen; si; si=si->next){ \
224 226
 		err+=(sctp_setsockopt(si->socket, (lev), (opt_name), (void*)(&(val)), \
225 227
 							sizeof((val)), (err_prefix))<0); \
226
-	} \
228
+	}
229
+
230
+#define SCTP_SET_SOCKOPT_BODY(lev, opt_name, val, err_prefix) \
231
+	SCTP_SET_SOCKOPT_BODY_NRET(lev, opt_name, val, err_prefix) ; \
227 232
 	return -(err!=0)
228 233
 
229 234
 
... ...
@@ -508,26 +513,43 @@ static int set_sack_delay(void* cfg_h, str* gname, str* name, void** val)
508 513
 {
509 514
 #if defined SCTP_DELAYED_SACK || defined SCTP_DELAYED_ACK_TIME
510 515
 #ifdef SCTP_DELAYED_SACK
511
-	struct sctp_sack_info sa;
512
-#else /* old lib */
513
-	struct sctp_assoc_value sa;
516
+	struct sctp_sack_info sack_info;
514 517
 #endif /* SCTP_DELAYED_SACK */
518
+#ifdef	SCTP_DELAYED_ACK_TIME
519
+	struct sctp_assoc_value sack_val; /* old version, sack delay only */
520
+#endif /* SCTP_DELAYED_ACK_TIME */
515 521
 	SCTP_SET_SOCKOPT_DECLS;
516 522
 	
517 523
 	if ((int)(long)(*val)==0){ /* do nothing for 0, keep the old value */
518 524
 		*val=(void*)(long)cfg_get(sctp, cfg_h, sack_delay);
519 525
 		return 0;
520 526
 	}
521
-	memset(&sa, 0, sizeof(sa)); /* zero everything we don't care about */
522 527
 #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");
528
+	memset(&sack_info, 0, sizeof(sack_info)); /* zero everything we don't
529
+												 care about */
530
+	sack_info.sack_delay=(int)(long)(*val);
531
+	SCTP_SET_SOCKOPT_BODY_NRET(IPPROTO_SCTP, SCTP_DELAYED_SACK, sack_info, 0);
532
+	if (err==0){
533
+		return 0;
534
+	}else
530 535
 #endif /* SCTP_DELAYED_SACK */
536
+	{
537
+		/* setting SCTP_DELAYED_SACK failed or no lib support for 
538
+		   SCTP_DELAYED_SACK => try the old obsolete SCTP_DELAYED_ACK_TIME */
539
+#ifdef	SCTP_DELAYED_ACK_TIME
540
+		memset(&sack_val, 0, sizeof(sack_val)); /* zero everything we don't
541
+												   care about */
542
+		sack_val.assoc_value=(int)(long)(*val);
543
+		SCTP_SET_SOCKOPT_BODY(IPPROTO_SCTP, SCTP_DELAYED_ACK_TIME, sack_val,
544
+								"cfg: setting SCTP_DELAYED_ACK_TIME");
545
+#else	/* SCTP_DELAYED_ACK_TIME */
546
+		/* no SCTP_DELAYED_ACK_TIME support and SCTP_DELAYED_SACK failed
547
+		   => error */
548
+		ERR("cfg: setting SCTP_DELAYED_SACK: %s [%d]\n",
549
+					strerror(errno), errno);
550
+		return -1;
551
+#endif /* SCTP_DELAYED_ACK_TIME */
552
+	}
531 553
 #else
532 554
 	ERR("no SCTP_DELAYED_SACK support, please upgrade your sctp library\n");
533 555
 	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 225
 
225 226
 
226 227
 /** get the os defaults for cfg options with os correspondents.
227
- *  @param s - intialized sctp socket
228 228
  *  @param cfg - filled with the os defaults
229 229
  *  @return -1 on error, 0 on success
230 230
  */
231 231
 int sctp_get_os_defaults(struct cfg_group_sctp* cfg)
232
+{
233
+	int s;
234
+	int ret;
235
+	
236
+	s = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
237
+	if (s==-1)
238
+		return -1;
239
+	ret=sctp_get_cfg_from_sock(s, cfg);
240
+	close(s);
241
+	return ret;
242
+}
243
+
244
+
245
+
246
+/** get the os cfg options from a specific socket.
247
+ *  @param s - intialized sctp socket
248
+ *  @param cfg - filled with the os defaults
249
+ *  @return -1 on error, 0 on success
250
+ */
251
+int sctp_get_cfg_from_sock(int s, struct cfg_group_sctp* cfg)
232 252
 {
233 253
 	int optval;
234 254
 	socklen_t optlen;
235
-	int s;
236 255
 #ifdef SCTP_RTOINFO
237 256
 	struct sctp_rtoinfo rto;
238 257
 #endif /* SCTP_RTOINFO */
... ...
@@ -245,19 +264,16 @@ int sctp_get_os_defaults(struct cfg_group_sctp* cfg)
245 264
 #ifdef SCTP_PEER_ADDR_PARAMS
246 265
 	struct sctp_paddrparams pp;
247 266
 #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 */
267
+#ifdef	SCTP_DELAYED_SACK
268
+	struct sctp_sack_info sack_info;
269
+#endif	/* SCTP_DELAYED_SACK */
270
+#ifdef	SCTP_DELAYED_ACK_TIME
271
+	struct sctp_assoc_value sack_val; /* old version */
272
+#endif /* SCTP_DELAYED_ACK_TIME */
253 273
 #ifdef SCTP_MAX_BURST
254 274
 	struct sctp_assoc_value av;
255 275
 #endif /* SCTP_MAX_BURST */
256 276
 	
257
-	s = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
258
-	if (s==-1)
259
-		return -1;
260
-	
261 277
 	/* SO_RCVBUF */
262 278
 	optlen=sizeof(int);
263 279
 	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 294
 		#endif
279 295
 		cfg->so_sndbuf=optval;
280 296
 	}
297
+	/* SCTP_AUTOCLOSE */
298
+#ifdef SCTP_AUTOCLOSE
299
+	optlen=sizeof(int);
300
+	if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_AUTOCLOSE, (void*)&optval,
301
+							&optlen, "SCTP_AUTOCLOSE")==0){
302
+		cfg->autoclose=optval;
303
+	}
304
+#endif /* SCTP_AUTOCLOSE */
281 305
 	/* SCTP_RTOINFO -> srto_initial, srto_min, srto_max */
282 306
 #ifdef SCTP_RTOINFO
283 307
 	optlen=sizeof(rto);
... ...
@@ -321,23 +345,36 @@ int sctp_get_os_defaults(struct cfg_group_sctp* cfg)
321 345
 	}
322 346
 #endif /* SCTP_PEER_ADDR_PARAMS */
323 347
 #if defined SCTP_DELAYED_SACK || defined SCTP_DELAYED_ACK_TIME
324
-	optlen=sizeof(sa);
325
-	memset(&sa, 0, sizeof(sa));
326 348
 #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){
349
+	optlen=sizeof(sack_info);
350
+	memset(&sack_info, 0, sizeof(sack_info));
351
+	if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_SACK, (void*)&sack_info,
352
+							&optlen, 0)==0){
336 353
 		/* success => hack to set the "default" values*/
337
-		cfg->sack_delay=sa.assoc_value;
338
-		cfg->sack_freq=0; /* unknown */
339
-	}
354
+		cfg->sack_delay=sack_info.sack_delay;
355
+		cfg->sack_freq=sack_info.sack_freq;
356
+	}else
340 357
 #endif /* SCTP_DELAYED_SACK */
358
+	{
359
+#ifdef	SCTP_DELAYED_ACK_TIME
360
+		optlen=sizeof(sack_val);
361
+		memset(&sack_val, 0, sizeof(sack_val));
362
+		/* if no SCTP_DELAYED_SACK supported by the sctp lib, or setting it
363
+		   failed (not supported by the kernel) try using the obsolete
364
+		   SCTP_DELAYED_ACK_TIME method */
365
+		if (sctp_getsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_ACK_TIME,
366
+								(void*)&sack_val, &optlen, 
367
+								"SCTP_DELAYED_ACK_TIME")==0){
368
+			/* success => hack to set the "default" values*/
369
+			cfg->sack_delay=sack_val.assoc_value;
370
+			cfg->sack_freq=0; /* unknown */
371
+		}
372
+#else	/* SCTP_DELAYED_ACK_TIME */
373
+		/* no SCTP_DELAYED_ACK_TIME support and SCTP_DELAYED_SACK failed
374
+		   => error */
375
+		ERR("cfg: SCTP_DELAYED_SACK: %s [%d]\n", strerror(errno), errno);
376
+#endif /* SCTP_DELAYED_ACK_TIME */
377
+	}
341 378
 #endif /* SCTP_DELAYED_SACK  | SCTP_DELAYED_ACK_TIME*/
342 379
 #ifdef SCTP_MAX_BURST
343 380
 	optlen=sizeof(av);
... ...
@@ -349,7 +386,6 @@ int sctp_get_os_defaults(struct cfg_group_sctp* cfg)
349 386
 	}
350 387
 #endif /* SCTP_MAX_BURST */
351 388
 	
352
-	close(s);
353 389
 	return 0;
354 390
 }
355 391
 
... ...
@@ -381,10 +417,11 @@ static int sctp_init_sock_opt_common(int s, int af)
381 417
 	struct sctp_paddrparams pp;
382 418
 #endif /* SCTP_PEER_ADDR_PARAMS */
383 419
 #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 */
420
+	struct sctp_sack_info sack_info;
421
+#endif	/* SCTP_DELAYED_SACK */
422
+#ifdef	SCTP_DELAYED_ACK_TIME
423
+	struct sctp_assoc_value sack_val;
424
+#endif /* defined SCTP_DELAYED_ACK_TIME */
388 425
 #ifdef SCTP_MAX_BURST
389 426
 	struct sctp_assoc_value av;
390 427
 #endif /* SCTP_MAX_BURST */
... ...
@@ -629,34 +666,51 @@ static int sctp_init_sock_opt_common(int s, int af)
629 666
 #endif /* SCTP_PEER_ADDR_PARAMS */
630 667
 	/* set delayed ack options: sack_delay & sack_freq */
631 668
 #if defined SCTP_DELAYED_SACK || defined SCTP_DELAYED_ACK_TIME
632
-	memset(&sa, 0, sizeof(sa));
633 669
 #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){
670
+	memset(&sack_info, 0, sizeof(sack_info));
671
+	sack_info.sack_delay=cfg_get(sctp, sctp_cfg, sack_delay);
672
+	sack_info.sack_freq=cfg_get(sctp, sctp_cfg, sack_freq);
673
+	if ((sack_info.sack_delay || sack_info.sack_freq) &&
674
+		(sctp_setsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_SACK,
675
+							(void*)&sack_info, sizeof(sack_info), 0)!=0)) {
676
+		/* if setting SCTP_DELAYED_SACK failed, try the old obsolete
677
+		   SCTP_DELAYED_ACK_TIME */
678
+#endif /* SCTP_DELAYED_SACK */
679
+#ifdef SCTP_DELAYED_ACK_TIME
680
+		memset(&sack_val, 0, sizeof(sack_val));
681
+		sack_val.assoc_value=cfg_get(sctp, sctp_cfg, sack_delay);
682
+		if (sack_val.assoc_value){
683
+			if (sctp_setsockopt(s, IPPROTO_SCTP, SCTP_DELAYED_ACK_TIME,
684
+									(void*)&sack_val, sizeof(sack_val),
685
+									"setsockopt: SCTP_DELAYED_ACK_TIME")!=0){
686
+				sctp_err++;
687
+				/* non critical, try to continue */
688
+			}
689
+		}
690
+#else /* SCTP_DELAYED_ACK_TIME */
691
+		/* no SCTP_DELAYED_ACK_TIME support and SCTP_DELAYED_SACK failed
692
+		   => error */
693
+		if (sack_info.sack_delay){
640 694
 			sctp_err++;
641
-			/* non critical, try to continue */
695
+			ERR("cfg: setting SCTP_DELAYED_SACK: %s [%d]\n",
696
+						strerror(errno), errno);
642 697
 		}
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){
698
+#endif /* SCTP_DELAYED_ACK_TIME */
699
+		if (cfg_get(sctp, sctp_cfg, sack_freq)){
700
+#ifdef SCTP_DELAYED_SACK
649 701
 			sctp_err++;
650
-			/* non critical, try to continue */
702
+			WARN("could not set sctp sack_freq, please upgrade your kernel\n");
703
+#else /* SCTP_DELAYED_SACK */
704
+			WARN("could not set sctp sack_freq, please upgrade your sctp"
705
+					" library\n");
706
+#endif /* SCTP_DELAYED_SACK */
707
+			((struct cfg_group_sctp*)sctp_cfg)->sack_freq=0;
651 708
 		}
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;
709
+#ifdef SCTP_DELAYED_SACK
657 710
 	}
658 711
 #endif /* SCTP_DELAYED_SACK */
659
-#else /* SCTP_DELAYED_SACK  | SCTP_DELAYED_ACK*/
712
+	
713
+#else /* SCTP_DELAYED_SACK  | SCTP_DELAYED_ACK_TIME*/
660 714
 #warning no sctp lib support for SCTP_DELAYED_SACK, consider upgrading
661 715
 #endif /* SCTP_DELAYED_SACK  | SCTP_DELAYED_ACK_TIME*/
662 716
 	/* set max burst option */
663 717
new file mode 100644
... ...
@@ -0,0 +1,44 @@
1
+/* 
2
+ * $Id$
3
+ * 
4
+ * Copyright (C) 2009 iptelorg GmbH
5
+ *
6
+ * Permission to use, copy, modify, and distribute this software for any
7
+ * purpose with or without fee is hereby granted, provided that the above
8
+ * copyright notice and this permission notice appear in all copies.
9
+ *
10
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
+ */
18
+/*
19
+ * sctp_sockopts.h - portability fixes / compatibility defines for some
20
+ *                   sctp socket options
21
+ */
22
+/*
23
+ * History:
24
+ * --------
25
+ *  2009-11-12  initial version (andrei)
26
+*/
27
+
28
+#ifndef __sctp_sockopts_h
29
+#define __sctp_sockopts_h
30
+
31
+#include <netinet/sctp.h>
32
+
33
+#ifndef SCTP_DELAYED_SACK
34
+#ifdef	SCTP_DELAYED_ACK
35
+/* on linux lksctp/libsctp <= 1.0.11 (and possible future versions)
36
+ * SCTP_DELAYED_ACK is used instead of SCTP_DELAYED_SACK (typo?)
37
+ */
38
+#define	SCTP_DELAYED_SACK SCTP_DELAYED_ACK
39
+#endif	/* SCTP_DELAYED_ACK */
40
+#endif /* SCTP_DELAYED_SACK */
41
+
42
+#endif /*__sctp_sockopts_h*/
43
+
44
+/* vi: set ts=4 sw=4 tw=79:ai:cindent: */