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));
+}