Răsfoiți Sursa

sctp: fix partial delivery point setting on linux

To disable partial delivery, the partial delivery point should be
set to the socket receive buffer size. However on linux SO_RCVBUF
will return twice the value (the "real" value, which is twice the
value used when setting SO_RCVBUF) and SCTP_PARTIAL_DELIVERY_POINT
expects value/2.
Andrei Pelinescu-Onciul 16 ani în urmă
părinte
comite
f9437a7d00
1 a modificat fișierele cu 28 adăugiri și 5 ștergeri
  1. 28 5
      sctp_server.c

+ 28 - 5
sctp_server.c

@@ -195,6 +195,8 @@ static int sctp_init_sock_opt_common(int s)
 {
 	struct sctp_event_subscribe es;
 	int optval;
+	int pd_point;
+	int saved_errno;
 	socklen_t optlen;
 	int sctp_err;
 	
@@ -267,13 +269,34 @@ static int sctp_init_sock_opt_common(int s)
 		/* try to continue */
 		optval=0;
 	}
-	if (setsockopt(s, IPPROTO_SCTP, SCTP_PARTIAL_DELIVERY_POINT,
-					(void*)&optval, sizeof(optval)) ==-1){
-		LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt: "
+#ifdef __OS_linux
+	optval/=2; /* in linux getsockopt() returns twice the set value */
+#endif
+	pd_point=optval;
+	saved_errno=0;
+	while(pd_point &&
+			setsockopt(s, IPPROTO_SCTP, SCTP_PARTIAL_DELIVERY_POINT,
+					(void*)&pd_point, sizeof(pd_point)) ==-1){
+		if (!saved_errno)
+			saved_errno=errno;
+		pd_point--;
+	}
+	
+	if (pd_point!=optval){
+		if (pd_point==0){
+			/* all attempts failed */
+			LOG(L_ERR, "ERROR: sctp_init_sock_opt_common: setsockopt: "
 						"SCTP_PARTIAL_DELIVERY_POINT (%d): %s\n",
 						optval, strerror(errno));
-		sctp_err++;
-		/* try to continue */
+			sctp_err++;
+			/* try to continue */
+		}else{
+			/* success but to a lower value (might not be disabled) */
+			LOG(L_WARN, "setsockopt SCTP_PARTIAL_DELIVERY_POINT set to %d, but"
+				" the socket rcvbuf is %d (higher values fail with"
+				" \"%s\" [%d])\n",
+				pd_point, optval, strerror(saved_errno), saved_errno);
+		}
 	}
 #else
 #warning no sctp lib support for SCTP_PARTIAL_DELIVERY_POINT, consider upgrading