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 1801
 		tls_disable=1; /* if no tcp => no tls */
1802 1802
 #endif /* USE_TLS */
1803 1803
 #endif /* USE_TCP */
1804
+#ifdef USE_SCTP
1805
+	if (sctp_disable!=1){
1806
+		/* fix it */
1807
+		if (sctp_check_support()==-1){
1808
+			/* check if sctp support is auto, if not warn about disabling it */
1809
+			if (sctp_disable!=2){
1810
+				fprintf(stderr, "ERROR: " "sctp enabled, but not supported by"
1811
+								" the OS\n");
1812
+				goto error;
1813
+			}
1814
+			sctp_disable=1;
1815
+		}else{
1816
+			/* sctp_disable!=1 and sctp supported => enable sctp */
1817
+			sctp_disable=0;
1818
+		}
1819
+	}
1820
+#endif /* USE_SCTP */
1804 1821
 	/* initialize the configured proto list */
1805 1822
 	init_proto_order();
1806 1823
 	/* init the resolver, before fixing the config */
... ...
@@ -1819,21 +1842,6 @@ try_again:
1819 1819
 	}
1820 1820
 #endif
1821 1821
 #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 1822
 	if (!sctp_disable){
1838 1823
 		if (sctp_children_no<=0) sctp_children_no=children_no;
1839 1824
 	}
... ...
@@ -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 67
 
68 68
 
69 69
 
70
+/* append a token to a buffer (uses space between tokens) */
71
+inline static void append_tok2buf(char* buf, int blen, char* tok)
72
+{
73
+	char* p;
74
+	char* end;
75
+	int len;
76
+	
77
+	if (buf && blen){
78
+		end=buf+blen;
79
+		p=memchr(buf, 0, blen);
80
+		if (p==0) goto error;
81
+		if (p!=buf && p<(end-1)){
82
+			*p=' ';
83
+			p++;
84
+		}
85
+		len=MIN_int(strlen(tok), end-1-p);
86
+		memcpy(p, tok, len);
87
+		p[len]=0;
88
+	}
89
+error:
90
+	return;
91
+}
92
+
93
+
94
+
95
+/* check if support fot all the needed sockopts  was compiled;
96
+   an ascii list of the unsuported options is returned in buf
97
+   returns 0 on success and  -number of unsuported options on failure
98
+   (<0 on failure)
99
+*/
100
+int sctp_check_compiled_sockopts(char* buf, int size)
101
+{
102
+	int err;
103
+
104
+	err=0;
105
+	if (buf && (size>0)) *buf=0; /* "" */
106
+#ifndef SCTP_FRAGMENT_INTERLEAVE
107
+	err++;
108
+	append_tok2buf(buf, size, "SCTP_FRAGMENT_INTERLEAVE");
109
+#endif
110
+#ifndef SCTP_PARTIAL_DELIVERY_POINT
111
+	err++;
112
+	append_tok2buf(buf, size, "SCTP_PARTIAL_DELIVERY_POINT");
113
+#endif
114
+#ifndef SCTP_NODELAY
115
+	err++;
116
+	append_tok2buf(buf, size, "SCTP_NODELAY");
117
+#endif
118
+#ifndef SCTP_DISABLE_FRAGMENTS
119
+	err++;
120
+	append_tok2buf(buf, size, "SCTP_DISABLE_FRAGMENTS");
121
+#endif
122
+#ifndef SCTP_AUTOCLOSE
123
+	err++;
124
+	append_tok2buf(buf, size, "SCTP_AUTOCLOSE");
125
+#endif
126
+#ifndef SCTP_EVENTS
127
+	err++;
128
+	append_tok2buf(buf, size, "SCTP_EVENTS");
129
+#endif
130
+	
131
+	return -err;
132
+}
133
+
134
+
135
+
70 136
 /* init all the sockaddr_union members of the socket_info struct
71 137
    returns 0 on success and -1 on error */
72 138
 inline static int sctp_init_su(struct socket_info* sock_info)
... ...
@@ -101,7 +176,8 @@ error:
101 101
    tries to ignore non-critical errors (it will only log them), for
102 102
    improved portability (for example older linux kernel version support
103 103
    only a limited number of sctp socket options)
104
-   returns 0 on success, -1 on error */
104
+   returns 0 on success, -1 on error
105
+   WARNING: please keep it sync'ed w/ sctp_check_compiled_sockopts() */
105 106
 static int sctp_init_sock_opt_common(int s)
106 107
 {
107 108
 	struct sctp_event_subscribe es;
... ...
@@ -141,6 +217,7 @@ static int sctp_init_sock_opt_common(int s)
141 141
 	/* disable fragments interleave (SCTP_FRAGMENT_INTERLEAVE) --
142 142
 	 * we don't want partial delivery, so fragment interleave must be off too
143 143
 	 */
144
+#ifdef SCTP_FRAGMENT_INTERLEAVE
144 145
 	optval=0;
145 146
 	if (setsockopt(s, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE ,
146 147
 					(void*)&optval, sizeof(optval)) ==-1){
... ...
@@ -148,11 +225,13 @@ static int sctp_init_sock_opt_common(int s)
148 148
 					"SCTP_FRAGMENT_INTERLEAVE: %s\n", strerror(errno));
149 149
 		/* try to continue */
150 150
 	}
151
+#endif /* SCTP_FRAGMENT_INTERLEAVE */
151 152
 	
152 153
 	/* turn off partial delivery: on linux setting SCTP_PARTIAL_DELIVERY_POINT
153 154
 	 * to 0 or a very large number seems to be enough, however the portable
154 155
 	 * way to do it is to set it to the socket receive buffer size
155 156
 	 * (this is the maximum value allowed in the sctp api draft) */
157
+#ifdef SCTP_PARTIAL_DELIVERY_POINT
156 158
 	optlen=sizeof(optval);
157 159
 	if (getsockopt(s, SOL_SOCKET, SO_RCVBUF,
158 160
 					(void*)&optval, &optlen) ==-1){
... ...
@@ -168,8 +247,10 @@ static int sctp_init_sock_opt_common(int s)
168 168
 						optval, strerror(errno));
169 169
 		/* try to continue */
170 170
 	}
171
+#endif /* SCTP_PARTIAL_DELIVERY_POINT */
171 172
 	
172 173
 	/* nagle / no delay */
174
+#ifdef SCTP_NODELAY
173 175
 	optval=1;
174 176
 	if (setsockopt(s, IPPROTO_SCTP, SCTP_NODELAY,
175 177
 					(void*)&optval, sizeof(optval)) ==-1){
... ...
@@ -177,8 +258,10 @@ static int sctp_init_sock_opt_common(int s)
177 177
 						"SCTP_NODELAY: %s\n", strerror(errno));
178 178
 		/* non critical, try to continue */
179 179
 	}
180
+#endif /* SCTP_NODELAY */
180 181
 	
181 182
 	/* enable message fragmentation (SCTP_DISABLE_FRAGMENTS)  (on send) */
183
+#ifdef SCTP_DISABLE_FRAGMENTS
182 184
 	optval=0;
183 185
 	if (setsockopt(s, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS,
184 186
 					(void*)&optval, sizeof(optval)) ==-1){
... ...
@@ -186,15 +269,22 @@ static int sctp_init_sock_opt_common(int s)
186 186
 						"SCTP_DISABLE_FRAGMENTS: %s\n", strerror(errno));
187 187
 		/* non critical, try to continue */
188 188
 	}
189
+#endif /* SCTP_DISABLE_FRAGMENTS */
189 190
 	
190 191
 	/* set autoclose */
192
+#ifdef SCTP_AUTOCLOSE
191 193
 	optval=sctp_options.sctp_autoclose;
192
-	if (setsockopt(s, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS,
194
+	if (setsockopt(s, IPPROTO_SCTP, SCTP_AUTOCLOSE,
193 195
 					(void*)&optval, sizeof(optval)) ==-1){
194 196
 		LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt: "
195
-						"SCTP_DISABLE_FRAGMENTS: %s\n", strerror(errno));
196
-		/* non critical, try to continue */
197
+						"SCTP_AUTOCLOSE: %s (critical)\n", strerror(errno));
198
+		/* critical: w/o autoclose we could have sctp connection living
199
+		   forever (if the remote side doesn't close them) */
200
+		goto error;
197 201
 	}
202
+#else
203
+#error SCTP_AUTOCLOSE not supported, please upgrade your sctp library
204
+#endif /* SCTP_AUTOCLOSE */
198 205
 	
199 206
 	memset(&es, 0, sizeof(es));
200 207
 	/* 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 211
 	/* es.sctp_authentication_event=1; -- not supported on linux 2.6.25 */
212 212
 	
213 213
 	/* enable the SCTP_EVENTS */
214
+#ifdef SCTP_EVENTS
214 215
 	if (setsockopt(s, IPPROTO_SCTP, SCTP_EVENTS, &es, sizeof(es))==-1){
215 216
 		LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt: "
216 217
 				"SCTP_EVENTS: %s\n", strerror(errno));
217 218
 		/* non critical, try to continue */
218 219
 	}
220
+#endif /* SCTP_EVENTS */
219 221
 	
220 222
 	return 0;
221
-/*error:
223
+error:
222 224
 	return -1;
223
-*/
224 225
 }
225 226
 
226 227
 
... ...
@@ -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();