From: Gerrit Renker <grenker@cscs.ch>
Date: Sat, 13 Mar 2010 12:08:32 +0000 (+0100)
Subject: net: fix broken dccp_available_ccids()
X-Git-Tag: v0.4.2~24
X-Git-Url: https://git.tuebingen.mpg.de/?a=commitdiff_plain;h=23f053fc0a392079213bf2f979b7c098baa9d30c;p=paraslash.git

net: fix broken dccp_available_ccids()

This fixes a dumb programming error in dccp_available_ccids(), where a
pointer to 1-byte address was type cast to a socklent_t (typically 4 byte)
pointer. Changed the interface to not expose internals of call.

In addition, this patch adds a missing close() in the error path of makesock().
---

diff --git a/dccp_recv.c b/dccp_recv.c
index a0f8371e..c22fa84d 100644
--- a/dccp_recv.c
+++ b/dccp_recv.c
@@ -105,10 +105,11 @@ err:
  */
 static bool dccp_recv_ccid_support_check(struct dccp_recv_args_info *conf)
 {
-	uint8_t ccids[DCCP_MAX_HOST_CCIDS];
-	uint8_t nccids = sizeof(ccids), i, j;
+	uint8_t *ccids;
+	int i, j, nccids;
 
-	if (dccp_available_ccids(ccids, &nccids) == NULL)
+	nccids = dccp_available_ccids(&ccids);
+	if (nccids <= 0)
 		return false;
 
 	for (i = 0; i < conf->ccid_given; i++) {
diff --git a/dccp_send.c b/dccp_send.c
index 7d8967cc..e90c63c4 100644
--- a/dccp_send.c
+++ b/dccp_send.c
@@ -140,12 +140,13 @@ static int dccp_com_allow(struct sender_command_data *scd)
  */
 static const char *dccp_list_available_ccids(void)
 {
-	uint8_t ccids[DCCP_MAX_HOST_CCIDS];
-	uint8_t nccids = sizeof(ccids), i, len;
 	/* Worst case length: n * 3 digits + n-1 spaces + '\0' */
 	static char list[DCCP_MAX_HOST_CCIDS * 4];
+	uint8_t *ccids;
+	int i, len, nccids;
 
-	if (dccp_available_ccids(ccids, &nccids) == NULL) {
+	nccids = dccp_available_ccids(&ccids);
+	if (nccids < 0) {
 		snprintf(list, sizeof(list), "Unable to query available CCIDs");
 	} else {
 		for (i = len = 0; i < nccids; i++)
diff --git a/net.c b/net.c
index b9729b69..f34ab852 100644
--- a/net.c
+++ b/net.c
@@ -436,6 +436,7 @@ int makesock(unsigned l4type, bool passive,
 		if (passive && setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
 						  &on, sizeof(on)) == -1) {
 			rc = errno;
+			close(sockfd);
 			PARA_ERROR_LOG("can not set SO_REUSEADDR: %s\n",
 				       strerror(rc));
 			return -ERRNO_TO_PARA_ERROR(rc);
@@ -775,30 +776,35 @@ int para_accept(int fd, void *addr, socklen_t size)
 }
 
 /**
- * Probe the list of DCCP CCIDs supported locally by the host.
- * \param ccids Array to be filled in.
- * \param nccids Length of \a ccids.
- * \return Pointer to \a ccids, NULL on failure.
+ * Probe the list of DCCP CCIDs configured on this host.
+ * \param ccid_array Pointer to return statically allocated array in.
+ * \return Number of elements returned in \a ccid_array or error.
  *
  * NB: This feature is only available on Linux > 2.6.30; on older kernels
  * ENOPROTOOPT ("Protocol not available") will be returned.
  */
-const uint8_t *dccp_available_ccids(uint8_t *ccids, uint8_t *nccids)
+int dccp_available_ccids(uint8_t **ccid_array)
 {
-	int fd = makesock(IPPROTO_DCCP, 1, NULL, 0, NULL);
+	static uint8_t ccids[DCCP_MAX_HOST_CCIDS];
+	socklen_t nccids = sizeof(ccids);
+	int ret, fd;
 
-	if (fd < 0)
-		return NULL;
+	ret = fd = makesock(IPPROTO_DCCP, 1, NULL, 0, NULL);
+	if (ret < 0)
+		return ret;
 
 	if (getsockopt(fd, SOL_DCCP, DCCP_SOCKOPT_AVAILABLE_CCIDS,
-					ccids, (socklen_t *)nccids) < 0) {
+						ccids, &nccids) < 0) {
+		ret = errno;
+		close(fd);
 		PARA_ERROR_LOG("No DCCP_SOCKOPT_AVAILABLE_CCIDS: %s\n",
-				strerror(errno));
-		*nccids = 0;
+				strerror(ret));
+		return -ERRNO_TO_PARA_ERROR(ret);
 	}
-	close(fd);
 
-	return *nccids ? ccids : NULL;
+	close(fd);
+	*ccid_array = ccids;
+	return nccids;
 }
 
 /**
diff --git a/net.h b/net.h
index e9974d1c..4eb79a82 100644
--- a/net.h
+++ b/net.h
@@ -152,4 +152,4 @@ int recv_pattern(int fd, const char *pattern, size_t bufsize);
  */
 /** Hardcoded maximum number of separate CCID modules compiled into a host */
 #define DCCP_MAX_HOST_CCIDS	20
-extern const uint8_t *dccp_available_ccids(uint8_t *ccids, uint8_t *nccids);
+extern int dccp_available_ccids(uint8_t **ccid_array);