libsysutils: Add iovec/runOnEachSocket

SocketClient:
* Replace sendDataLocked with sendDataLockedv which takes an iovec.
* Add a version of sendData, sendDatav, which takes an iovec.
* do not preserve iovec content through sendDatav

SocketListener:
* Add runOnEachSocket, which allows to to specify a SocketClientCommand to
  run individually on each socket. This allows you to do broadcast-like
  actions customized for each individual socket.
* Client safe list reference counting for sendBroadcast & runOnEach Socket

Signed-off-by: Nick Kralevich <nnk@google.com>
Signed-off-by: Mark Salyzyn <salyzyn@google.com>

Change-Id: I716f89c01b4cb7af900045c7e41fac1492defb06
diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp
index ae0e077..3625d93 100644
--- a/libsysutils/src/SocketClient.cpp
+++ b/libsysutils/src/SocketClient.cpp
@@ -71,7 +71,7 @@
             ret = asprintf(&buf, "%d %s", code, msg);
         }
     }
-    /* Send the zero-terminated message */
+    // Send the zero-terminated message
     if (ret != -1) {
         ret = sendMsg(buf);
         free(buf);
@@ -79,22 +79,25 @@
     return ret;
 }
 
-/** send 3-digit code, null, binary-length, binary data */
+// send 3-digit code, null, binary-length, binary data
 int SocketClient::sendBinaryMsg(int code, const void *data, int len) {
 
-    /* 4 bytes for the code & null + 4 bytes for the len */
+    // 4 bytes for the code & null + 4 bytes for the len
     char buf[8];
-    /* Write the code */
+    // Write the code
     snprintf(buf, 4, "%.3d", code);
-    /* Write the len */
+    // Write the len
     uint32_t tmp = htonl(len);
     memcpy(buf + 4, &tmp, sizeof(uint32_t));
 
+    struct iovec vec[2];
+    vec[0].iov_base = (void *) buf;
+    vec[0].iov_len = sizeof(buf);
+    vec[1].iov_base = (void *) data;
+    vec[1].iov_len = len;
+
     pthread_mutex_lock(&mWriteMutex);
-    int result = sendDataLocked(buf, sizeof(buf));
-    if (result == 0 && len > 0) {
-        result = sendDataLocked(data, len);
-    }
+    int result = sendDataLockedv(vec, (len > 0) ? 2 : 1);
     pthread_mutex_unlock(&mWriteMutex);
 
     return result;
@@ -147,33 +150,51 @@
 }
 
 int SocketClient::sendData(const void *data, int len) {
+    struct iovec vec[1];
+    vec[0].iov_base = (void *) data;
+    vec[0].iov_len = len;
 
     pthread_mutex_lock(&mWriteMutex);
-    int rc = sendDataLocked(data, len);
+    int rc = sendDataLockedv(vec, 1);
     pthread_mutex_unlock(&mWriteMutex);
 
     return rc;
 }
 
-int SocketClient::sendDataLocked(const void *data, int len) {
-    int rc = 0;
-    const char *p = (const char*) data;
-    int brtw = len;
+int SocketClient::sendDatav(struct iovec *iov, int iovcnt) {
+    pthread_mutex_lock(&mWriteMutex);
+    int rc = sendDataLockedv(iov, iovcnt);
+    pthread_mutex_unlock(&mWriteMutex);
+
+    return rc;
+}
+
+int SocketClient::sendDataLockedv(struct iovec *iov, int iovcnt) {
 
     if (mSocket < 0) {
         errno = EHOSTUNREACH;
         return -1;
     }
 
-    if (len == 0) {
+    if (iovcnt <= 0) {
         return 0;
     }
 
-    while (brtw > 0) {
-        rc = send(mSocket, p, brtw, MSG_NOSIGNAL);
+    int current = 0;
+
+    for (;;) {
+        ssize_t rc = writev(mSocket, iov + current, iovcnt - current);
         if (rc > 0) {
-            p += rc;
-            brtw -= rc;
+            size_t written = rc;
+            while ((current < iovcnt) && (written >= iov[current].iov_len)) {
+                written -= iov[current].iov_len;
+                current++;
+            }
+            if (current == iovcnt) {
+                break;
+            }
+            iov[current].iov_base = (char *)iov[current].iov_base + written;
+            iov[current].iov_len -= written;
             continue;
         }