Browse code

sctp: support for older sctp libraries and autoclose fix

- try to compile even if the used sctp library doesn't support all the
sctp socket options that we would like to set, but warn about it both at
compile time and each time ser is started
- ser -V will print a list of unsupported sctp options (due to missing
support in the sctp library/*.h files that ser was compiled against)
- fix: the autoclose sctp socket option was not properly set (paste typo)

Andrei Pelinescu-Onciul authored on 07/10/2008 11:22:43
Showing 3 changed files
... ...
@@ -1548,6 +1548,12 @@ int main(int argc, char** argv)
1548 1548
 					printf("version: %s\n", version);
1549 1549
 					printf("flags: %s\n", flags );
1550 1550
 					print_ct_constants();
1551
+#ifdef USE_SCTP
1552
+					tmp=malloc(256);
1553
+					if (tmp && (sctp_check_compiled_sockopts(tmp, 256)!=0))
1554
+						printf("sctp unsupported socket options: %s\n", tmp);
1555
+					if (tmp) free(tmp);
1556
+#endif
1551 1557
 					printf("%s\n",id);
1552 1558
 					printf("%s compiled on %s with %s\n", __FILE__,
1553 1559
 							compiled, COMPILER );
... ...
@@ -1801,6 +1807,23 @@ try_again:
1801 1807
 		tls_disable=1; /* if no tcp => no tls */
1802 1808
 #endif /* USE_TLS */
1803 1809
 #endif /* USE_TCP */
1810
+#ifdef USE_SCTP
1811
+	if (sctp_disable!=1){
1812
+		/* fix it */
1813
+		if (sctp_check_support()==-1){
1814
+			/* check if sctp support is auto, if not warn about disabling it */
1815
+			if (sctp_disable!=2){
1816
+				fprintf(stderr, "ERROR: " "sctp enabled, but not supported by"
1817
+								" the OS\n");
1818
+				goto error;
1819
+			}
1820
+			sctp_disable=1;
1821
+		}else{
1822
+			/* sctp_disable!=1 and sctp supported => enable sctp */
1823
+			sctp_disable=0;
1824
+		}
1825
+	}
1826
+#endif /* USE_SCTP */
1804 1827
 	/* initialize the configured proto list */
1805 1828
 	init_proto_order();
1806 1829
 	/* init the resolver, before fixing the config */
... ...
@@ -1819,21 +1842,6 @@ try_again:
1819 1842
 	}
1820 1843
 #endif
1821 1844
 #ifdef USE_SCTP
1822
-	if (sctp_disable!=1){
1823
-		/* fix it */
1824
-		if (sctp_check_support()==-1){
1825
-			/* check if sctp support is auto, if not warn about disabling it */
1826
-			if (sctp_disable!=2){
1827
-				fprintf(stderr, "ERROR: " "sctp enabled, but not supported by"
1828
-								" the OS\n");
1829
-				goto error;
1830
-			}
1831
-			sctp_disable=1;
1832
-		}else{
1833
-			/* sctp_disable!=1 and sctp supported => enable sctp */
1834
-			sctp_disable=0;
1835
-		}
1836
-	}
1837 1845
 	if (!sctp_disable){
1838 1846
 		if (sctp_children_no<=0) sctp_children_no=children_no;
1839 1847
 	}
... ...
@@ -57,9 +57,18 @@
57 57
 int sctp_check_support()
58 58
 {
59 59
 	int s;
60
+	char buf[256];
61
+	
60 62
 	s = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
61 63
 	if (s!=-1){
62 64
 		close(s);
65
+		if (sctp_check_compiled_sockopts(buf, sizeof(buf))!=0){
66
+			LOG(L_WARN, "WARNING: sctp: your ser version was compiled"
67
+						" without support for the following sctp options: %s"
68
+						" which might cause unforseen problems \n", buf);
69
+			LOG(L_WARN, "WARNING: sctp: please consider recompiling ser with"
70
+						" an upgraded sctp library version\n");
71
+		}
63 72
 		return 0;
64 73
 	}
65 74
 	return -1;
... ...
@@ -67,6 +76,72 @@ int sctp_check_support()
67 76
 
68 77
 
69 78
 
79
+/* append a token to a buffer (uses space between tokens) */
80
+inline static void append_tok2buf(char* buf, int blen, char* tok)
81
+{
82
+	char* p;
83
+	char* end;
84
+	int len;
85
+	
86
+	if (buf && blen){
87
+		end=buf+blen;
88
+		p=memchr(buf, 0, blen);
89
+		if (p==0) goto error;
90
+		if (p!=buf && p<(end-1)){
91
+			*p=' ';
92
+			p++;
93
+		}
94
+		len=MIN_int(strlen(tok), end-1-p);
95
+		memcpy(p, tok, len);
96
+		p[len]=0;
97
+	}
98
+error:
99
+	return;
100
+}
101
+
102
+
103
+
104
+/* check if support fot all the needed sockopts  was compiled;
105
+   an ascii list of the unsuported options is returned in buf
106
+   returns 0 on success and  -number of unsuported options on failure
107
+   (<0 on failure)
108
+*/
109
+int sctp_check_compiled_sockopts(char* buf, int size)
110
+{
111
+	int err;
112
+
113
+	err=0;
114
+	if (buf && (size>0)) *buf=0; /* "" */
115
+#ifndef SCTP_FRAGMENT_INTERLEAVE
116
+	err++;
117
+	append_tok2buf(buf, size, "SCTP_FRAGMENT_INTERLEAVE");
118
+#endif
119
+#ifndef SCTP_PARTIAL_DELIVERY_POINT
120
+	err++;
121
+	append_tok2buf(buf, size, "SCTP_PARTIAL_DELIVERY_POINT");
122
+#endif
123
+#ifndef SCTP_NODELAY
124
+	err++;
125
+	append_tok2buf(buf, size, "SCTP_NODELAY");
126
+#endif
127
+#ifndef SCTP_DISABLE_FRAGMENTS
128
+	err++;
129
+	append_tok2buf(buf, size, "SCTP_DISABLE_FRAGMENTS");
130
+#endif
131
+#ifndef SCTP_AUTOCLOSE
132
+	err++;
133
+	append_tok2buf(buf, size, "SCTP_AUTOCLOSE");
134
+#endif
135
+#ifndef SCTP_EVENTS
136
+	err++;
137
+	append_tok2buf(buf, size, "SCTP_EVENTS");
138
+#endif
139
+	
140
+	return -err;
141
+}
142
+
143
+
144
+
70 145
 /* init all the sockaddr_union members of the socket_info struct
71 146
    returns 0 on success and -1 on error */
72 147
 inline static int sctp_init_su(struct socket_info* sock_info)
... ...
@@ -101,7 +176,8 @@ error:
101 176
    tries to ignore non-critical errors (it will only log them), for
102 177
    improved portability (for example older linux kernel version support
103 178
    only a limited number of sctp socket options)
104
-   returns 0 on success, -1 on error */
179
+   returns 0 on success, -1 on error
180
+   WARNING: please keep it sync'ed w/ sctp_check_compiled_sockopts() */
105 181
 static int sctp_init_sock_opt_common(int s)
106 182
 {
107 183
 	struct sctp_event_subscribe es;
... ...
@@ -141,6 +217,7 @@ static int sctp_init_sock_opt_common(int s)
141 217
 	/* disable fragments interleave (SCTP_FRAGMENT_INTERLEAVE) --
142 218
 	 * we don't want partial delivery, so fragment interleave must be off too
143 219
 	 */
220
+#ifdef SCTP_FRAGMENT_INTERLEAVE
144 221
 	optval=0;
145 222
 	if (setsockopt(s, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE ,
146 223
 					(void*)&optval, sizeof(optval)) ==-1){
... ...
@@ -148,11 +225,13 @@ static int sctp_init_sock_opt_common(int s)
148 225
 					"SCTP_FRAGMENT_INTERLEAVE: %s\n", strerror(errno));
149 226
 		/* try to continue */
150 227
 	}
228
+#endif /* SCTP_FRAGMENT_INTERLEAVE */
151 229
 	
152 230
 	/* turn off partial delivery: on linux setting SCTP_PARTIAL_DELIVERY_POINT
153 231
 	 * to 0 or a very large number seems to be enough, however the portable
154 232
 	 * way to do it is to set it to the socket receive buffer size
155 233
 	 * (this is the maximum value allowed in the sctp api draft) */
234
+#ifdef SCTP_PARTIAL_DELIVERY_POINT
156 235
 	optlen=sizeof(optval);
157 236
 	if (getsockopt(s, SOL_SOCKET, SO_RCVBUF,
158 237
 					(void*)&optval, &optlen) ==-1){
... ...
@@ -168,8 +247,10 @@ static int sctp_init_sock_opt_common(int s)
168 247
 						optval, strerror(errno));
169 248
 		/* try to continue */
170 249
 	}
250
+#endif /* SCTP_PARTIAL_DELIVERY_POINT */
171 251
 	
172 252
 	/* nagle / no delay */
253
+#ifdef SCTP_NODELAY
173 254
 	optval=1;
174 255
 	if (setsockopt(s, IPPROTO_SCTP, SCTP_NODELAY,
175 256
 					(void*)&optval, sizeof(optval)) ==-1){
... ...
@@ -177,8 +258,10 @@ static int sctp_init_sock_opt_common(int s)
177 258
 						"SCTP_NODELAY: %s\n", strerror(errno));
178 259
 		/* non critical, try to continue */
179 260
 	}
261
+#endif /* SCTP_NODELAY */
180 262
 	
181 263
 	/* enable message fragmentation (SCTP_DISABLE_FRAGMENTS)  (on send) */
264
+#ifdef SCTP_DISABLE_FRAGMENTS
182 265
 	optval=0;
183 266
 	if (setsockopt(s, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS,
184 267
 					(void*)&optval, sizeof(optval)) ==-1){
... ...
@@ -186,15 +269,22 @@ static int sctp_init_sock_opt_common(int s)
186 269
 						"SCTP_DISABLE_FRAGMENTS: %s\n", strerror(errno));
187 270
 		/* non critical, try to continue */
188 271
 	}
272
+#endif /* SCTP_DISABLE_FRAGMENTS */
189 273
 	
190 274
 	/* set autoclose */
275
+#ifdef SCTP_AUTOCLOSE
191 276
 	optval=sctp_options.sctp_autoclose;
192
-	if (setsockopt(s, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS,
277
+	if (setsockopt(s, IPPROTO_SCTP, SCTP_AUTOCLOSE,
193 278
 					(void*)&optval, sizeof(optval)) ==-1){
194 279
 		LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt: "
195
-						"SCTP_DISABLE_FRAGMENTS: %s\n", strerror(errno));
196
-		/* non critical, try to continue */
280
+						"SCTP_AUTOCLOSE: %s (critical)\n", strerror(errno));
281
+		/* critical: w/o autoclose we could have sctp connection living
282
+		   forever (if the remote side doesn't close them) */
283
+		goto error;
197 284
 	}
285
+#else
286
+#error SCTP_AUTOCLOSE not supported, please upgrade your sctp library
287
+#endif /* SCTP_AUTOCLOSE */
198 288
 	
199 289
 	memset(&es, 0, sizeof(es));
200 290
 	/* SCTP_EVENTS for SCTP_SNDRCV (sctp_data_io_event) -> per message
... ...
@@ -211,16 +301,17 @@ static int sctp_init_sock_opt_common(int s)
211 301
 	/* es.sctp_authentication_event=1; -- not supported on linux 2.6.25 */
212 302
 	
213 303
 	/* enable the SCTP_EVENTS */
304
+#ifdef SCTP_EVENTS
214 305
 	if (setsockopt(s, IPPROTO_SCTP, SCTP_EVENTS, &es, sizeof(es))==-1){
215 306
 		LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt: "
216 307
 				"SCTP_EVENTS: %s\n", strerror(errno));
217 308
 		/* non critical, try to continue */
218 309
 	}
310
+#endif /* SCTP_EVENTS */
219 311
 	
220 312
 	return 0;
221
-/*error:
313
+error:
222 314
 	return -1;
223
-*/
224 315
 }
225 316
 
226 317
 
... ...
@@ -29,6 +29,7 @@
29 29
 
30 30
 #include "ip_addr.h"
31 31
 
32
+int sctp_check_compiled_sockopts(char* buf, int size);
32 33
 int sctp_check_support();
33 34
 int sctp_init_sock(struct socket_info* sock_info);
34 35
 int sctp_rcv_loop();