libcutils: add socket_get_local_port().

Tests that require a local server currently hardcode a test value,
which can run into conflicts depending on what's currently running on
the machine.

This CL adds socket_get_local_port(), which lets us pass 0 so the
system picks an open port and we can query which port it chose.

Bug: http://b/26236380
Change-Id: I01d1558884e7636081d9a357db6faa86929934f6
diff --git a/include/cutils/sockets.h b/include/cutils/sockets.h
index e25c555..6cffe12 100644
--- a/include/cutils/sockets.h
+++ b/include/cutils/sockets.h
@@ -132,6 +132,11 @@
 int socket_set_receive_timeout(cutils_socket_t sock, int timeout_ms);
 
 /*
+ * Returns the local port the socket is bound to or -1 on error.
+ */
+int socket_get_local_port(cutils_socket_t sock);
+
+/*
  * socket_peer_is_trusted - Takes a socket which is presumed to be a
  * connected local socket (e.g. AF_LOCAL) and returns whether the peer
  * (the userid that owns the process on the other end of that socket)
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 25b056b..482e4dd 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -17,21 +17,22 @@
 include $(CLEAR_VARS)
 
 libcutils_common_sources := \
-        hashmap.c \
         atomic.c.arm \
-        native_handle.c \
         config_utils.c \
+        fs_config.c \
+        hashmap.c \
+        iosched_policy.c \
         load_file.c \
-        strlcpy.c \
+        native_handle.c \
         open_memstream.c \
+        process_name.c \
+        record_stream.c \
+        sched_policy.c \
+        sockets.cpp \
         strdup16to8.c \
         strdup8to16.c \
-        record_stream.c \
-        process_name.c \
+        strlcpy.c \
         threads.c \
-        sched_policy.c \
-        iosched_policy.c \
-        fs_config.c
 
 # some files must not be compiled when building against Mingw
 # they correspond to features not used by our host development tools
diff --git a/libcutils/sockets.cpp b/libcutils/sockets.cpp
new file mode 100644
index 0000000..d9ab146
--- /dev/null
+++ b/libcutils/sockets.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+// This file contains socket implementation that can be shared between
+// platforms as long as the correct headers are included.
+
+#include <cutils/sockets.h>
+
+#if !defined(_WIN32)
+#include <netinet/in.h>
+#endif
+
+int socket_get_local_port(cutils_socket_t sock) {
+    sockaddr_storage addr;
+    socklen_t addr_size = sizeof(addr);
+
+    if (getsockname(sock, reinterpret_cast<sockaddr*>(&addr), &addr_size) == 0) {
+        // sockaddr_in and sockaddr_in6 always overlap the port field.
+        return ntohs(reinterpret_cast<sockaddr_in*>(&addr)->sin_port);
+    }
+    return -1;
+}
diff --git a/libcutils/tests/sockets_test.cpp b/libcutils/tests/sockets_test.cpp
index 966dfe7..6c74b9a 100644
--- a/libcutils/tests/sockets_test.cpp
+++ b/libcutils/tests/sockets_test.cpp
@@ -15,9 +15,8 @@
  */
 
 // Tests socket functionality using loopback connections. Requires IPv4 and
-// IPv6 capabilities, and that kTestPort is available for loopback
-// communication. These tests also assume that no UDP packets are lost,
-// which should be the case for loopback communication, but is not guaranteed.
+// IPv6 capabilities. These tests assume that no UDP packets are lost, which
+// should be the case for loopback communication, but is not guaranteed.
 
 #include <cutils/sockets.h>
 
@@ -25,11 +24,6 @@
 
 #include <gtest/gtest.h>
 
-enum {
-    // This port must be available for loopback communication.
-    kTestPort = 54321
-};
-
 // Makes sure the passed sockets are valid, sends data between them, and closes
 // them. Any failures are logged with gtest.
 //
@@ -47,19 +41,19 @@
     // Send client -> server first to get the UDP client's address.
     ASSERT_EQ(3, send(client, "foo", 3, 0));
     if (type == SOCK_DGRAM) {
-      EXPECT_EQ(3, recvfrom(server, buffer, 3, 0,
-                            reinterpret_cast<sockaddr*>(&addr), &addr_size));
+        EXPECT_EQ(3, recvfrom(server, buffer, 3, 0,
+                              reinterpret_cast<sockaddr*>(&addr), &addr_size));
     } else {
-      EXPECT_EQ(3, recv(server, buffer, 3, 0));
+        EXPECT_EQ(3, recv(server, buffer, 3, 0));
     }
     EXPECT_EQ(0, memcmp(buffer, "foo", 3));
 
     // Now send server -> client.
     if (type == SOCK_DGRAM) {
-      ASSERT_EQ(3, sendto(server, "bar", 3, 0,
-                          reinterpret_cast<sockaddr*>(&addr), addr_size));
+        ASSERT_EQ(3, sendto(server, "bar", 3, 0,
+                            reinterpret_cast<sockaddr*>(&addr), addr_size));
     } else {
-      ASSERT_EQ(3, send(server, "bar", 3, 0));
+        ASSERT_EQ(3, send(server, "bar", 3, 0));
     }
     EXPECT_EQ(3, recv(client, buffer, 3, 0));
     EXPECT_EQ(0, memcmp(buffer, "bar", 3));
@@ -87,22 +81,43 @@
     EXPECT_LE(1.0, difftime(time(nullptr), start_time));
 }
 
+// Tests socket_get_local_port().
+TEST(SocketsTest, TestGetLocalPort) {
+    cutils_socket_t server;
+
+    // Check a bunch of ports so that we can ignore any conflicts in case
+    // of ports already being taken, but if a server is able to start up we
+    // should always be able to read its port.
+    for (int port : {10000, 12345, 15999, 20202, 25000}) {
+        for (int type : {SOCK_DGRAM, SOCK_STREAM}) {
+            server = socket_inaddr_any_server(port, SOCK_DGRAM);
+            if (server != INVALID_SOCKET) {
+                EXPECT_EQ(port, socket_get_local_port(server));
+            }
+            socket_close(server);
+        }
+    }
+
+    // Check expected failure for an invalid socket.
+    EXPECT_EQ(-1, socket_get_local_port(INVALID_SOCKET));
+}
+
 // Tests socket_inaddr_any_server() and socket_network_client() for IPv4 UDP.
 TEST(SocketsTest, TestIpv4UdpLoopback) {
-    cutils_socket_t server = socket_inaddr_any_server(kTestPort, SOCK_DGRAM);
-    cutils_socket_t client = socket_network_client("127.0.0.1", kTestPort,
-                                                   SOCK_DGRAM);
+    cutils_socket_t server = socket_inaddr_any_server(0, SOCK_DGRAM);
+    cutils_socket_t client = socket_network_client(
+            "127.0.0.1", socket_get_local_port(server), SOCK_DGRAM);
 
     TestConnectedSockets(server, client, SOCK_DGRAM);
 }
 
 // Tests socket_inaddr_any_server() and socket_network_client() for IPv4 TCP.
 TEST(SocketsTest, TestIpv4TcpLoopback) {
-    cutils_socket_t server = socket_inaddr_any_server(kTestPort, SOCK_STREAM);
+    cutils_socket_t server = socket_inaddr_any_server(0, SOCK_STREAM);
     ASSERT_NE(INVALID_SOCKET, server);
 
-    cutils_socket_t client = socket_network_client("127.0.0.1", kTestPort,
-                                                   SOCK_STREAM);
+    cutils_socket_t client = socket_network_client(
+            "127.0.0.1", socket_get_local_port(server), SOCK_STREAM);
     cutils_socket_t handler = accept(server, nullptr, nullptr);
     EXPECT_EQ(0, socket_close(server));
 
@@ -111,20 +126,20 @@
 
 // Tests socket_inaddr_any_server() and socket_network_client() for IPv6 UDP.
 TEST(SocketsTest, TestIpv6UdpLoopback) {
-    cutils_socket_t server = socket_inaddr_any_server(kTestPort, SOCK_DGRAM);
-    cutils_socket_t client = socket_network_client("::1", kTestPort,
-                                                   SOCK_DGRAM);
+    cutils_socket_t server = socket_inaddr_any_server(0, SOCK_DGRAM);
+    cutils_socket_t client = socket_network_client(
+            "::1", socket_get_local_port(server), SOCK_DGRAM);
 
     TestConnectedSockets(server, client, SOCK_DGRAM);
 }
 
 // Tests socket_inaddr_any_server() and socket_network_client() for IPv6 TCP.
 TEST(SocketsTest, TestIpv6TcpLoopback) {
-    cutils_socket_t server = socket_inaddr_any_server(kTestPort, SOCK_STREAM);
+    cutils_socket_t server = socket_inaddr_any_server(0, SOCK_STREAM);
     ASSERT_NE(INVALID_SOCKET, server);
 
-    cutils_socket_t client = socket_network_client("::1", kTestPort,
-                                                   SOCK_STREAM);
+    cutils_socket_t client = socket_network_client(
+            "::1", socket_get_local_port(server), SOCK_STREAM);
     cutils_socket_t handler = accept(server, nullptr, nullptr);
     EXPECT_EQ(0, socket_close(server));
 
@@ -133,7 +148,7 @@
 
 // Tests setting a receive timeout for UDP sockets.
 TEST(SocketsTest, TestUdpReceiveTimeout) {
-    cutils_socket_t sock = socket_inaddr_any_server(kTestPort, SOCK_DGRAM);
+    cutils_socket_t sock = socket_inaddr_any_server(0, SOCK_DGRAM);
     ASSERT_NE(INVALID_SOCKET, sock);
 
     TestReceiveTimeout(sock);
@@ -143,11 +158,11 @@
 
 // Tests setting a receive timeout for TCP sockets.
 TEST(SocketsTest, TestTcpReceiveTimeout) {
-    cutils_socket_t server = socket_inaddr_any_server(kTestPort, SOCK_STREAM);
+    cutils_socket_t server = socket_inaddr_any_server(0, SOCK_STREAM);
     ASSERT_NE(INVALID_SOCKET, server);
 
-    cutils_socket_t client = socket_network_client("localhost", kTestPort,
-                                                   SOCK_STREAM);
+    cutils_socket_t client = socket_network_client(
+            "localhost", socket_get_local_port(server), SOCK_STREAM);
     cutils_socket_t handler = accept(server, nullptr, nullptr);
     EXPECT_EQ(0, socket_close(server));