fastboot: use cutils socket functions.

Now that cutils has cross-platform socket functionality, we can
restructure fastboot to remove platform-dependent networking code.

This CL adds socket_set_receive_timeout() to libcutils and combines the
fastboot socket code into a single implementation. It also adds TCP
functionality to fastboot sockets, but nothing uses it yet except for
the unit tests. A future CL will add the TCP protocol which will use
this TCP socket implementation.

Bug: http://b/26558551

Change-Id: If613fb348f9332b31fa2c88d67fb1e839923768a
diff --git a/libcutils/sockets_unix.c b/libcutils/sockets_unix.c
index ca3f67e..5eddc4b 100644
--- a/libcutils/sockets_unix.c
+++ b/libcutils/sockets_unix.c
@@ -49,3 +49,10 @@
 int socket_close(int sock) {
   return close(sock);
 }
+
+int socket_set_receive_timeout(cutils_socket_t sock, int timeout_ms) {
+  struct timeval tv;
+  tv.tv_sec = timeout_ms / 1000;
+  tv.tv_usec = (timeout_ms % 1000) * 1000;
+  return setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+}
diff --git a/libcutils/sockets_windows.c b/libcutils/sockets_windows.c
index 92ccf88..1bf2933 100644
--- a/libcutils/sockets_windows.c
+++ b/libcutils/sockets_windows.c
@@ -53,3 +53,8 @@
 int socket_close(cutils_socket_t sock) {
     return closesocket(sock);
 }
+
+int socket_set_receive_timeout(cutils_socket_t sock, int timeout_ms) {
+    return setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout_ms,
+                      sizeof(timeout_ms));
+}
diff --git a/libcutils/tests/sockets_test.cpp b/libcutils/tests/sockets_test.cpp
index 975c305..966dfe7 100644
--- a/libcutils/tests/sockets_test.cpp
+++ b/libcutils/tests/sockets_test.cpp
@@ -21,6 +21,8 @@
 
 #include <cutils/sockets.h>
 
+#include <time.h>
+
 #include <gtest/gtest.h>
 
 enum {
@@ -66,6 +68,25 @@
     EXPECT_EQ(0, socket_close(client));
 }
 
+// Tests receive timeout. The timing verification logic must be very coarse to
+// make sure different systems can all pass these tests.
+void TestReceiveTimeout(cutils_socket_t sock) {
+    time_t start_time;
+    char buffer[32];
+
+    // Make sure a 20ms timeout completes in 1 second or less.
+    EXPECT_EQ(0, socket_set_receive_timeout(sock, 20));
+    start_time = time(nullptr);
+    EXPECT_EQ(-1, recv(sock, buffer, sizeof(buffer), 0));
+    EXPECT_LE(difftime(time(nullptr), start_time), 1.0);
+
+    // Make sure a 1250ms timeout takes 1 second or more.
+    EXPECT_EQ(0, socket_set_receive_timeout(sock, 1250));
+    start_time = time(nullptr);
+    EXPECT_EQ(-1, recv(sock, buffer, sizeof(buffer), 0));
+    EXPECT_LE(1.0, difftime(time(nullptr), start_time));
+}
+
 // 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);
@@ -109,3 +130,29 @@
 
     TestConnectedSockets(handler, client, SOCK_STREAM);
 }
+
+// Tests setting a receive timeout for UDP sockets.
+TEST(SocketsTest, TestUdpReceiveTimeout) {
+    cutils_socket_t sock = socket_inaddr_any_server(kTestPort, SOCK_DGRAM);
+    ASSERT_NE(INVALID_SOCKET, sock);
+
+    TestReceiveTimeout(sock);
+
+    EXPECT_EQ(0, socket_close(sock));
+}
+
+// Tests setting a receive timeout for TCP sockets.
+TEST(SocketsTest, TestTcpReceiveTimeout) {
+    cutils_socket_t server = socket_inaddr_any_server(kTestPort, SOCK_STREAM);
+    ASSERT_NE(INVALID_SOCKET, server);
+
+    cutils_socket_t client = socket_network_client("localhost", kTestPort,
+                                                   SOCK_STREAM);
+    cutils_socket_t handler = accept(server, nullptr, nullptr);
+    EXPECT_EQ(0, socket_close(server));
+
+    TestReceiveTimeout(handler);
+
+    EXPECT_EQ(0, socket_close(client));
+    EXPECT_EQ(0, socket_close(handler));
+}