Move adb to C++.

I keep trying to clean things up and needing std::strings. Might as
well just do this now.

usb_linux_client.c is going to stay as C because GCC isn't smart
enough to deal with the designated initializers it uses (though for
some reason it is in C mode).

The Darwin files are staying as C because I don't have a way to test
that they build.

The Windows files are staying as C because while I can actually build
for them, it's slow and painful.

Change-Id: I75367d29205a9049d34460032b3bb36384f43941
diff --git a/adb_client.cpp b/adb_client.cpp
new file mode 100644
index 0000000..d677db8
--- /dev/null
+++ b/adb_client.cpp
@@ -0,0 +1,363 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "sysdeps.h"
+
+#define  TRACE_TAG  TRACE_ADB
+#include "adb_client.h"
+#include "adb_io.h"
+#include "zipfile/zipfile.h"
+
+static transport_type __adb_transport = kTransportAny;
+static const char* __adb_serial = NULL;
+
+static int __adb_server_port = DEFAULT_ADB_PORT;
+static const char* __adb_server_name = NULL;
+
+void adb_set_transport(transport_type type, const char* serial)
+{
+    __adb_transport = type;
+    __adb_serial = serial;
+}
+
+void adb_set_tcp_specifics(int server_port)
+{
+    __adb_server_port = server_port;
+}
+
+void adb_set_tcp_name(const char* hostname)
+{
+    __adb_server_name = hostname;
+}
+
+int  adb_get_emulator_console_port(void)
+{
+    const char*   serial = __adb_serial;
+    int           port;
+
+    if (serial == NULL) {
+        /* if no specific device was specified, we need to look at */
+        /* the list of connected devices, and extract an emulator  */
+        /* name from it. two emulators is an error                 */
+        char*  tmp = adb_query("host:devices");
+        char*  p   = tmp;
+        if(!tmp) {
+            printf("no emulator connected\n");
+            return -1;
+        }
+        while (*p) {
+            char*  q = strchr(p, '\n');
+            if (q != NULL)
+                *q++ = 0;
+            else
+                q = p + strlen(p);
+
+            if (!memcmp(p, LOCAL_CLIENT_PREFIX, sizeof(LOCAL_CLIENT_PREFIX)-1)) {
+                if (serial != NULL) {  /* more than one emulator listed */
+                    free(tmp);
+                    return -2;
+                }
+                serial = p;
+            }
+
+            p = q;
+        }
+        free(tmp);
+
+        if (serial == NULL)
+            return -1;  /* no emulator found */
+    }
+    else {
+        if (memcmp(serial, LOCAL_CLIENT_PREFIX, sizeof(LOCAL_CLIENT_PREFIX)-1) != 0)
+            return -1;  /* not an emulator */
+    }
+
+    serial += sizeof(LOCAL_CLIENT_PREFIX)-1;
+    port    = strtol(serial, NULL, 10);
+    return port;
+}
+
+static char __adb_error[256] = { 0 };
+
+const char *adb_error(void)
+{
+    return __adb_error;
+}
+
+static int switch_socket_transport(int fd)
+{
+    char service[64];
+    char tmp[5];
+    int len;
+
+    if (__adb_serial)
+        snprintf(service, sizeof service, "host:transport:%s", __adb_serial);
+    else {
+        const char* transport_type = "???";
+
+         switch (__adb_transport) {
+            case kTransportUsb:
+                transport_type = "transport-usb";
+                break;
+            case kTransportLocal:
+                transport_type = "transport-local";
+                break;
+            case kTransportAny:
+                transport_type = "transport-any";
+                break;
+            case kTransportHost:
+                // no switch necessary
+                return 0;
+                break;
+        }
+
+        snprintf(service, sizeof service, "host:%s", transport_type);
+    }
+    len = strlen(service);
+    snprintf(tmp, sizeof tmp, "%04x", len);
+
+    if(!WriteFdExactly(fd, tmp, 4) || !WriteFdExactly(fd, service, len)) {
+        strcpy(__adb_error, "write failure during connection");
+        adb_close(fd);
+        return -1;
+    }
+    D("Switch transport in progress\n");
+
+    if(adb_status(fd)) {
+        adb_close(fd);
+        D("Switch transport failed\n");
+        return -1;
+    }
+    D("Switch transport success\n");
+    return 0;
+}
+
+int adb_status(int fd)
+{
+    unsigned char buf[5];
+    unsigned len;
+
+    if(!ReadFdExactly(fd, buf, 4)) {
+        strcpy(__adb_error, "protocol fault (no status)");
+        return -1;
+    }
+
+    if(!memcmp(buf, "OKAY", 4)) {
+        return 0;
+    }
+
+    if(memcmp(buf, "FAIL", 4)) {
+        sprintf(__adb_error,
+                "protocol fault (status %02x %02x %02x %02x?!)",
+                buf[0], buf[1], buf[2], buf[3]);
+        return -1;
+    }
+
+    if(!ReadFdExactly(fd, buf, 4)) {
+        strcpy(__adb_error, "protocol fault (status len)");
+        return -1;
+    }
+    buf[4] = 0;
+    len = strtoul((char*)buf, 0, 16);
+    if(len > 255) len = 255;
+    if(!ReadFdExactly(fd, __adb_error, len)) {
+        strcpy(__adb_error, "protocol fault (status read)");
+        return -1;
+    }
+    __adb_error[len] = 0;
+    return -1;
+}
+
+int _adb_connect(const char *service)
+{
+    char tmp[5];
+    int len;
+    int fd;
+
+    D("_adb_connect: %s\n", service);
+    len = strlen(service);
+    if((len < 1) || (len > 1024)) {
+        strcpy(__adb_error, "service name too long");
+        return -1;
+    }
+    snprintf(tmp, sizeof tmp, "%04x", len);
+
+    if (__adb_server_name)
+        fd = socket_network_client(__adb_server_name, __adb_server_port, SOCK_STREAM);
+    else
+        fd = socket_loopback_client(__adb_server_port, SOCK_STREAM);
+
+    if(fd < 0) {
+        strcpy(__adb_error, "cannot connect to daemon");
+        return -2;
+    }
+
+    if (memcmp(service,"host",4) != 0 && switch_socket_transport(fd)) {
+        return -1;
+    }
+
+    if(!WriteFdExactly(fd, tmp, 4) || !WriteFdExactly(fd, service, len)) {
+        strcpy(__adb_error, "write failure during connection");
+        adb_close(fd);
+        return -1;
+    }
+
+    if(adb_status(fd)) {
+        adb_close(fd);
+        return -1;
+    }
+
+    D("_adb_connect: return fd %d\n", fd);
+    return fd;
+}
+
+int adb_connect(const char *service)
+{
+    // first query the adb server's version
+    int fd = _adb_connect("host:version");
+
+    D("adb_connect: service %s\n", service);
+    if(fd == -2 && __adb_server_name) {
+        fprintf(stderr,"** Cannot start server on remote host\n");
+        return fd;
+    } else if(fd == -2) {
+        fprintf(stdout,"* daemon not running. starting it now on port %d *\n",
+                __adb_server_port);
+    start_server:
+        if(launch_server(__adb_server_port)) {
+            fprintf(stderr,"* failed to start daemon *\n");
+            return -1;
+        } else {
+            fprintf(stdout,"* daemon started successfully *\n");
+        }
+        /* give the server some time to start properly and detect devices */
+        adb_sleep_ms(3000);
+        // fall through to _adb_connect
+    } else {
+        // if server was running, check its version to make sure it is not out of date
+        char buf[100];
+        size_t n;
+        int version = ADB_SERVER_VERSION - 1;
+
+        // if we have a file descriptor, then parse version result
+        if(fd >= 0) {
+            if(!ReadFdExactly(fd, buf, 4)) goto error;
+
+            buf[4] = 0;
+            n = strtoul(buf, 0, 16);
+            if(n > sizeof(buf)) goto error;
+            if(!ReadFdExactly(fd, buf, n)) goto error;
+            adb_close(fd);
+
+            if (sscanf(buf, "%04x", &version) != 1) goto error;
+        } else {
+            // if fd is -1, then check for "unknown host service",
+            // which would indicate a version of adb that does not support the version command
+            if (strcmp(__adb_error, "unknown host service") != 0)
+                return fd;
+        }
+
+        if(version != ADB_SERVER_VERSION) {
+            printf("adb server is out of date.  killing...\n");
+            fd = _adb_connect("host:kill");
+            adb_close(fd);
+
+            /* XXX can we better detect its death? */
+            adb_sleep_ms(2000);
+            goto start_server;
+        }
+    }
+
+    // if the command is start-server, we are done.
+    if (!strcmp(service, "host:start-server"))
+        return 0;
+
+    fd = _adb_connect(service);
+    if(fd == -1) {
+        D("_adb_connect error: %s", __adb_error);
+    } else if(fd == -2) {
+        fprintf(stderr,"** daemon still not running\n");
+    }
+    D("adb_connect: return fd %d\n", fd);
+
+    return fd;
+error:
+    adb_close(fd);
+    return -1;
+}
+
+
+int adb_command(const char *service)
+{
+    int fd = adb_connect(service);
+    if(fd < 0) {
+        fprintf(stderr, "error: %s\n", adb_error());
+        return -1;
+    }
+
+    if(adb_status(fd)) {
+        adb_close(fd);
+        return -1;
+    }
+
+    return 0;
+}
+
+char *adb_query(const char *service)
+{
+    char buf[5];
+    unsigned long n;
+    char* tmp;
+
+    D("adb_query: %s\n", service);
+    int fd = adb_connect(service);
+    if(fd < 0) {
+        fprintf(stderr,"error: %s\n", __adb_error);
+        return 0;
+    }
+
+    if(!ReadFdExactly(fd, buf, 4)) goto oops;
+
+    buf[4] = 0;
+    n = strtoul(buf, 0, 16);
+    if(n >= 0xffff) {
+        strcpy(__adb_error, "reply is too long (>= 64kB)");
+        goto oops;
+    }
+
+    tmp = reinterpret_cast<char*>(malloc(n + 1));
+    if(tmp == 0) goto oops;
+
+    if(!ReadFdExactly(fd, tmp, n) == 0) {
+        tmp[n] = 0;
+        adb_close(fd);
+        return tmp;
+    }
+    free(tmp);
+
+oops:
+    adb_close(fd);
+    return 0;
+}