Răsfoiți Sursa

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 17 ani în urmă
părinte
comite
23ca6c06d0
3 a modificat fișierele cu 121 adăugiri și 21 ștergeri
  1. 23 15
      main.c
  2. 97 6
      sctp_server.c
  3. 1 0
      sctp_server.h

+ 23 - 15
main.c

@@ -1548,6 +1548,12 @@ int main(int argc, char** argv)
 					printf("version: %s\n", version);
 					printf("flags: %s\n", flags );
 					print_ct_constants();
+#ifdef USE_SCTP
+					tmp=malloc(256);
+					if (tmp && (sctp_check_compiled_sockopts(tmp, 256)!=0))
+						printf("sctp unsupported socket options: %s\n", tmp);
+					if (tmp) free(tmp);
+#endif
 					printf("%s\n",id);
 					printf("%s compiled on %s with %s\n", __FILE__,
 							compiled, COMPILER );
@@ -1801,6 +1807,23 @@ try_again:
 		tls_disable=1; /* if no tcp => no tls */
 #endif /* USE_TLS */
 #endif /* USE_TCP */
+#ifdef USE_SCTP
+	if (sctp_disable!=1){
+		/* fix it */
+		if (sctp_check_support()==-1){
+			/* check if sctp support is auto, if not warn about disabling it */
+			if (sctp_disable!=2){
+				fprintf(stderr, "ERROR: " "sctp enabled, but not supported by"
+								" the OS\n");
+				goto error;
+			}
+			sctp_disable=1;
+		}else{
+			/* sctp_disable!=1 and sctp supported => enable sctp */
+			sctp_disable=0;
+		}
+	}
+#endif /* USE_SCTP */
 	/* initialize the configured proto list */
 	init_proto_order();
 	/* init the resolver, before fixing the config */
@@ -1819,21 +1842,6 @@ try_again:
 	}
 #endif
 #ifdef USE_SCTP
-	if (sctp_disable!=1){
-		/* fix it */
-		if (sctp_check_support()==-1){
-			/* check if sctp support is auto, if not warn about disabling it */
-			if (sctp_disable!=2){
-				fprintf(stderr, "ERROR: " "sctp enabled, but not supported by"
-								" the OS\n");
-				goto error;
-			}
-			sctp_disable=1;
-		}else{
-			/* sctp_disable!=1 and sctp supported => enable sctp */
-			sctp_disable=0;
-		}
-	}
 	if (!sctp_disable){
 		if (sctp_children_no<=0) sctp_children_no=children_no;
 	}

+ 97 - 6
sctp_server.c

@@ -57,9 +57,18 @@
 int sctp_check_support()
 {
 	int s;
+	char buf[256];
+	
 	s = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
 	if (s!=-1){
 		close(s);
+		if (sctp_check_compiled_sockopts(buf, sizeof(buf))!=0){
+			LOG(L_WARN, "WARNING: sctp: your ser version was compiled"
+						" without support for the following sctp options: %s"
+						" which might cause unforseen problems \n", buf);
+			LOG(L_WARN, "WARNING: sctp: please consider recompiling ser with"
+						" an upgraded sctp library version\n");
+		}
 		return 0;
 	}
 	return -1;
@@ -67,6 +76,72 @@ int sctp_check_support()
 
 
 
+/* append a token to a buffer (uses space between tokens) */
+inline static void append_tok2buf(char* buf, int blen, char* tok)
+{
+	char* p;
+	char* end;
+	int len;
+	
+	if (buf && blen){
+		end=buf+blen;
+		p=memchr(buf, 0, blen);
+		if (p==0) goto error;
+		if (p!=buf && p<(end-1)){
+			*p=' ';
+			p++;
+		}
+		len=MIN_int(strlen(tok), end-1-p);
+		memcpy(p, tok, len);
+		p[len]=0;
+	}
+error:
+	return;
+}
+
+
+
+/* check if support fot all the needed sockopts  was compiled;
+   an ascii list of the unsuported options is returned in buf
+   returns 0 on success and  -number of unsuported options on failure
+   (<0 on failure)
+*/
+int sctp_check_compiled_sockopts(char* buf, int size)
+{
+	int err;
+
+	err=0;
+	if (buf && (size>0)) *buf=0; /* "" */
+#ifndef SCTP_FRAGMENT_INTERLEAVE
+	err++;
+	append_tok2buf(buf, size, "SCTP_FRAGMENT_INTERLEAVE");
+#endif
+#ifndef SCTP_PARTIAL_DELIVERY_POINT
+	err++;
+	append_tok2buf(buf, size, "SCTP_PARTIAL_DELIVERY_POINT");
+#endif
+#ifndef SCTP_NODELAY
+	err++;
+	append_tok2buf(buf, size, "SCTP_NODELAY");
+#endif
+#ifndef SCTP_DISABLE_FRAGMENTS
+	err++;
+	append_tok2buf(buf, size, "SCTP_DISABLE_FRAGMENTS");
+#endif
+#ifndef SCTP_AUTOCLOSE
+	err++;
+	append_tok2buf(buf, size, "SCTP_AUTOCLOSE");
+#endif
+#ifndef SCTP_EVENTS
+	err++;
+	append_tok2buf(buf, size, "SCTP_EVENTS");
+#endif
+	
+	return -err;
+}
+
+
+
 /* init all the sockaddr_union members of the socket_info struct
    returns 0 on success and -1 on error */
 inline static int sctp_init_su(struct socket_info* sock_info)
@@ -101,7 +176,8 @@ error:
    tries to ignore non-critical errors (it will only log them), for
    improved portability (for example older linux kernel version support
    only a limited number of sctp socket options)
-   returns 0 on success, -1 on error */
+   returns 0 on success, -1 on error
+   WARNING: please keep it sync'ed w/ sctp_check_compiled_sockopts() */
 static int sctp_init_sock_opt_common(int s)
 {
 	struct sctp_event_subscribe es;
@@ -141,6 +217,7 @@ static int sctp_init_sock_opt_common(int s)
 	/* disable fragments interleave (SCTP_FRAGMENT_INTERLEAVE) --
 	 * we don't want partial delivery, so fragment interleave must be off too
 	 */
+#ifdef SCTP_FRAGMENT_INTERLEAVE
 	optval=0;
 	if (setsockopt(s, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE ,
 					(void*)&optval, sizeof(optval)) ==-1){
@@ -148,11 +225,13 @@ static int sctp_init_sock_opt_common(int s)
 					"SCTP_FRAGMENT_INTERLEAVE: %s\n", strerror(errno));
 		/* try to continue */
 	}
+#endif /* SCTP_FRAGMENT_INTERLEAVE */
 	
 	/* turn off partial delivery: on linux setting SCTP_PARTIAL_DELIVERY_POINT
 	 * to 0 or a very large number seems to be enough, however the portable
 	 * way to do it is to set it to the socket receive buffer size
 	 * (this is the maximum value allowed in the sctp api draft) */
+#ifdef SCTP_PARTIAL_DELIVERY_POINT
 	optlen=sizeof(optval);
 	if (getsockopt(s, SOL_SOCKET, SO_RCVBUF,
 					(void*)&optval, &optlen) ==-1){
@@ -168,8 +247,10 @@ static int sctp_init_sock_opt_common(int s)
 						optval, strerror(errno));
 		/* try to continue */
 	}
+#endif /* SCTP_PARTIAL_DELIVERY_POINT */
 	
 	/* nagle / no delay */
+#ifdef SCTP_NODELAY
 	optval=1;
 	if (setsockopt(s, IPPROTO_SCTP, SCTP_NODELAY,
 					(void*)&optval, sizeof(optval)) ==-1){
@@ -177,8 +258,10 @@ static int sctp_init_sock_opt_common(int s)
 						"SCTP_NODELAY: %s\n", strerror(errno));
 		/* non critical, try to continue */
 	}
+#endif /* SCTP_NODELAY */
 	
 	/* enable message fragmentation (SCTP_DISABLE_FRAGMENTS)  (on send) */
+#ifdef SCTP_DISABLE_FRAGMENTS
 	optval=0;
 	if (setsockopt(s, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS,
 					(void*)&optval, sizeof(optval)) ==-1){
@@ -186,15 +269,22 @@ static int sctp_init_sock_opt_common(int s)
 						"SCTP_DISABLE_FRAGMENTS: %s\n", strerror(errno));
 		/* non critical, try to continue */
 	}
+#endif /* SCTP_DISABLE_FRAGMENTS */
 	
 	/* set autoclose */
+#ifdef SCTP_AUTOCLOSE
 	optval=sctp_options.sctp_autoclose;
-	if (setsockopt(s, IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS,
+	if (setsockopt(s, IPPROTO_SCTP, SCTP_AUTOCLOSE,
 					(void*)&optval, sizeof(optval)) ==-1){
 		LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt: "
-						"SCTP_DISABLE_FRAGMENTS: %s\n", strerror(errno));
-		/* non critical, try to continue */
+						"SCTP_AUTOCLOSE: %s (critical)\n", strerror(errno));
+		/* critical: w/o autoclose we could have sctp connection living
+		   forever (if the remote side doesn't close them) */
+		goto error;
 	}
+#else
+#error SCTP_AUTOCLOSE not supported, please upgrade your sctp library
+#endif /* SCTP_AUTOCLOSE */
 	
 	memset(&es, 0, sizeof(es));
 	/* SCTP_EVENTS for SCTP_SNDRCV (sctp_data_io_event) -> per message
@@ -211,16 +301,17 @@ static int sctp_init_sock_opt_common(int s)
 	/* es.sctp_authentication_event=1; -- not supported on linux 2.6.25 */
 	
 	/* enable the SCTP_EVENTS */
+#ifdef SCTP_EVENTS
 	if (setsockopt(s, IPPROTO_SCTP, SCTP_EVENTS, &es, sizeof(es))==-1){
 		LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt: "
 				"SCTP_EVENTS: %s\n", strerror(errno));
 		/* non critical, try to continue */
 	}
+#endif /* SCTP_EVENTS */
 	
 	return 0;
-/*error:
+error:
 	return -1;
-*/
 }
 
 

+ 1 - 0
sctp_server.h

@@ -29,6 +29,7 @@
 
 #include "ip_addr.h"
 
+int sctp_check_compiled_sockopts(char* buf, int size);
 int sctp_check_support();
 int sctp_init_sock(struct socket_info* sock_info);
 int sctp_rcv_loop();