libcutils/fastboot: improve multi-buffer write.

Fixes libcutils multi-buffer write interface to be more friendly and
hooks into it from the fastboot Socket class.

Bug: http://b/26558551
Change-Id: Ibb3a8428fc379755602de52722c1260f9e345bc0
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 482e4dd..51c6d9d 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -46,7 +46,7 @@
         socket_loopback_client_unix.c \
         socket_loopback_server_unix.c \
         socket_network_client_unix.c \
-        sockets_unix.c \
+        sockets_unix.cpp \
         str_parms.c \
 
 libcutils_nonwindows_host_sources := \
@@ -56,7 +56,7 @@
 libcutils_windows_host_sources := \
         socket_inaddr_any_server_windows.c \
         socket_network_client_windows.c \
-        sockets_windows.c \
+        sockets_windows.cpp \
 
 # Shared and static library for host
 # Note: when linking this library on Windows, you must also link to Winsock2
diff --git a/libcutils/sockets_unix.c b/libcutils/sockets_unix.cpp
similarity index 69%
rename from libcutils/sockets_unix.c
rename to libcutils/sockets_unix.cpp
index 3e7cea0..8747d69 100644
--- a/libcutils/sockets_unix.c
+++ b/libcutils/sockets_unix.cpp
@@ -15,6 +15,9 @@
  */
 
 #include <cutils/sockets.h>
+
+#include <sys/uio.h>
+
 #include <log/log.h>
 
 #if defined(__ANDROID__)
@@ -25,10 +28,9 @@
 #define __android_unused __attribute__((__unused__))
 #endif
 
-bool socket_peer_is_trusted(int fd __android_unused)
-{
+bool socket_peer_is_trusted(int fd __android_unused) {
 #if defined(__ANDROID__)
-    struct ucred cr;
+    ucred cr;
     socklen_t len = sizeof(cr);
     int n = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
 
@@ -51,21 +53,27 @@
 }
 
 int socket_set_receive_timeout(cutils_socket_t sock, int timeout_ms) {
-    struct timeval tv;
+    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));
 }
 
-cutils_socket_buffer_t make_cutils_socket_buffer(void* data, size_t length) {
-    cutils_socket_buffer_t buffer;
-    buffer.iov_base = data;
-    buffer.iov_len = length;
-    return buffer;
-}
-
 ssize_t socket_send_buffers(cutils_socket_t sock,
-                            cutils_socket_buffer_t* buffers,
+                            const cutils_socket_buffer_t* buffers,
                             size_t num_buffers) {
-    return writev(sock, buffers, num_buffers);
+    if (num_buffers > SOCKET_SEND_BUFFERS_MAX_BUFFERS) {
+        return -1;
+    }
+
+    iovec iovec_buffers[SOCKET_SEND_BUFFERS_MAX_BUFFERS];
+    for (size_t i = 0; i < num_buffers; ++i) {
+        // It's safe to cast away const here; iovec declares non-const
+        // void* because it's used for both send and receive, but since
+        // we're only sending, the data won't be modified.
+        iovec_buffers[i].iov_base = const_cast<void*>(buffers[i].data);
+        iovec_buffers[i].iov_len = buffers[i].length;
+    }
+
+    return writev(sock, iovec_buffers, num_buffers);
 }
diff --git a/libcutils/sockets_windows.c b/libcutils/sockets_windows.cpp
similarity index 74%
rename from libcutils/sockets_windows.c
rename to libcutils/sockets_windows.cpp
index 8153688..ed6b1a7 100644
--- a/libcutils/sockets_windows.c
+++ b/libcutils/sockets_windows.cpp
@@ -37,7 +37,7 @@
 // Both adb (1) and Chrome (2) purposefully avoid WSACleanup() with no issues.
 // (1) https://android.googlesource.com/platform/system/core.git/+/master/adb/sysdeps_win32.cpp
 // (2) https://code.google.com/p/chromium/codesearch#chromium/src/net/base/winsock_init.cc
-bool initialize_windows_sockets() {
+extern "C" bool initialize_windows_sockets() {
     // There's no harm in calling WSAStartup() multiple times but no benefit
     // either, we may as well skip it after the first.
     static bool init_success = false;
@@ -55,25 +55,32 @@
 }
 
 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));
-}
-
-cutils_socket_buffer_t make_cutils_socket_buffer(void* data, size_t length) {
-    cutils_socket_buffer_t buffer;
-    buffer.buf = data;
-    buffer.len = length;
-    return buffer;
+    return setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
+                      reinterpret_cast<char*>(&timeout_ms), sizeof(timeout_ms));
 }
 
 ssize_t socket_send_buffers(cutils_socket_t sock,
-                            cutils_socket_buffer_t* buffers,
+                            const cutils_socket_buffer_t* buffers,
                             size_t num_buffers) {
-    DWORD bytes_sent = 0;
+    if (num_buffers > SOCKET_SEND_BUFFERS_MAX_BUFFERS) {
+        return -1;
+    }
 
-    if (WSASend(sock, buffers, num_buffers, &bytes_sent, 0, NULL, NULL) !=
-            SOCKET_ERROR) {
+    WSABUF wsa_buffers[SOCKET_SEND_BUFFERS_MAX_BUFFERS];
+    for (size_t i = 0; i < num_buffers; ++i) {
+        // It's safe to cast away const here; WSABUF declares non-const
+        // void* because it's used for both send and receive, but since
+        // we're only sending, the data won't be modified.
+        wsa_buffers[i].buf =
+                reinterpret_cast<char*>(const_cast<void*>(buffers[i].data));
+        wsa_buffers[i].len = buffers[i].length;
+    }
+
+    DWORD bytes_sent = 0;
+    if (WSASend(sock, wsa_buffers, num_buffers, &bytes_sent, 0, nullptr,
+                nullptr) != SOCKET_ERROR) {
         return bytes_sent;
     }
+
     return -1;
 }
diff --git a/libcutils/tests/sockets_test.cpp b/libcutils/tests/sockets_test.cpp
index 40fa9b1..0f682a2 100644
--- a/libcutils/tests/sockets_test.cpp
+++ b/libcutils/tests/sockets_test.cpp
@@ -60,11 +60,9 @@
 
     // Send multiple buffers using socket_send_buffers().
     std::string data[] = {"foo", "bar", "12345"};
-    cutils_socket_buffer_t socket_buffers[3];
-    for (int i = 0; i < 3; ++i) {
-        socket_buffers[i] = make_cutils_socket_buffer(&data[i][0],
-                                                      data[i].length());
-    }
+    cutils_socket_buffer_t socket_buffers[] = { {data[0].data(), data[0].length()},
+                                                {data[1].data(), data[1].length()},
+                                                {data[2].data(), data[2].length()} };
     EXPECT_EQ(11, socket_send_buffers(client, socket_buffers, 3));
     EXPECT_EQ(11, recv(server, buffer, sizeof(buffer), 0));
     EXPECT_EQ(0, memcmp(buffer, "foobar12345", 11));