1/*
2 * Copyright 2009, The Android Open Source Project
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *  * Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 *  * Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#define LOG_TAG "wdsclient"
27
28#include "AdbConnection.h"
29#include "ClientUtils.h"
30#include "Device.h"
31#include <arpa/inet.h>
32#include <errno.h>
33#include <string.h>
34#include <sys/socket.h>
35#include <sys/types.h>
36#include <utils/Log.h>
37
38void AdbConnection::close() {
39    if (m_fd != -1) {
40        shutdown(m_fd, SHUT_RDWR);
41        ::close(m_fd);
42        m_fd = -1;
43    }
44}
45
46// Default adb port
47#define ADB_PORT 5037
48
49bool AdbConnection::connect() {
50    // Some commands (host:devices for example) close the connection so we call
51    // connect after the response.
52    close();
53
54    m_fd = socket(PF_INET, SOCK_STREAM, 0);
55    if (m_fd < 0) {
56        log_errno("Failed to create socket for connecting to adb");
57        return false;
58    }
59
60    // Create the socket address struct
61    sockaddr_in adb;
62    createTcpSocket(adb, ADB_PORT);
63
64    // Connect to adb
65    if (::connect(m_fd, (sockaddr*) &adb, sizeof(adb)) < 0) {
66        log_errno("Failed to connect to adb");
67        return false;
68    }
69
70    // Connected
71    return true;
72}
73
74// Adb protocol stuff
75#define MAX_COMMAND_LENGTH 1024
76#define PAYLOAD_LENGTH 4
77#define PAYLOAD_FORMAT "%04X"
78
79bool AdbConnection::sendRequest(const char* fmt, ...) const {
80    if (m_fd == -1) {
81        ALOGE("Connection is closed");
82        return false;
83    }
84
85    // Build the command (service)
86    char buf[MAX_COMMAND_LENGTH];
87    va_list args;
88    va_start(args, fmt);
89    int res = vsnprintf(buf, MAX_COMMAND_LENGTH, fmt, args);
90    va_end(args);
91
92    ALOGV("Sending command: %04X%.*s", res, res, buf);
93
94    // Construct the payload length
95    char payloadLen[PAYLOAD_LENGTH + 1];
96    snprintf(payloadLen, sizeof(payloadLen), PAYLOAD_FORMAT, res);
97
98    // First, send the payload length
99    if (send(m_fd, payloadLen, PAYLOAD_LENGTH, 0) < 0) {
100        log_errno("Failure when sending payload");
101        return false;
102    }
103
104    // Send the actual command
105    if (send(m_fd, buf, res, 0) < 0) {
106        log_errno("Failure when sending command");
107        return false;
108    }
109
110    // Check for the OKAY from adb
111    return checkOkayResponse();
112}
113
114static void printFailureMessage(int fd) {
115    // Grab the payload length
116    char lenStr[PAYLOAD_LENGTH + 1];
117    int payloadLen = recv(fd, lenStr, sizeof(lenStr) - 1, 0);
118    ALOG_ASSERT(payloadLen == PAYLOAD_LENGTH, "Incorrect payload size");
119    lenStr[PAYLOAD_LENGTH] = 0;
120
121    // Parse the hex payload
122    payloadLen = strtol(lenStr, NULL, 16);
123    if (payloadLen < 0)
124        return;
125
126    // Grab the message
127    char* msg = new char[payloadLen + 1]; // include null-terminator
128    int res = recv(fd, msg, payloadLen, 0);
129    if (res < 0) {
130        log_errno("Failure reading failure message from adb");
131        return;
132    } else if (res != payloadLen) {
133        ALOGE("Incorrect payload length %d - expected %d", res, payloadLen);
134        return;
135    }
136    msg[res] = 0;
137
138    // Tell somebody about it
139    ALOGE("Received failure from adb: %s", msg);
140
141    // Cleanup
142    delete[] msg;
143}
144
145#define ADB_RESPONSE_LENGTH 4
146
147bool AdbConnection::checkOkayResponse() const {
148    ALOG_ASSERT(m_fd != -1, "Connection has been closed!");
149
150    char buf[ADB_RESPONSE_LENGTH];
151    int res = recv(m_fd, buf, sizeof(buf), 0);
152    if (res < 0) {
153        log_errno("Failure reading response from adb");
154        return false;
155    }
156
157    // Check for a response other than OKAY/FAIL
158    if ((res == ADB_RESPONSE_LENGTH) && (strncmp(buf, "OKAY", res) == 0)) {
159        ALOGV("Command OKAY");
160        return true;
161    } else if (strncmp(buf, "FAIL", ADB_RESPONSE_LENGTH) == 0) {
162        // Something happened, print out the reason for failure
163        printFailureMessage(m_fd);
164        return false;
165    }
166    ALOGE("Incorrect response from adb - '%.*s'", res, buf);
167    return false;
168}
169
170void AdbConnection::clearDevices() {
171    for (unsigned i = 0; i < m_devices.size(); i++)
172        delete m_devices.editItemAt(i);
173    m_devices.clear();
174}
175
176const DeviceList& AdbConnection::getDeviceList() {
177    // Clear the current device list
178    clearDevices();
179
180    if (m_fd == -1) {
181        ALOGE("Connection is closed");
182        return m_devices;
183    }
184
185    // Try to send the device list request
186    if (!sendRequest("host:devices")) {
187        ALOGE("Failed to get device list from adb");
188        return m_devices;
189    }
190
191    // Get the payload length
192    char lenStr[PAYLOAD_LENGTH + 1];
193    int res = recv(m_fd, lenStr, sizeof(lenStr) - 1, 0);
194    if (res < 0) {
195        log_errno("Failure to read payload size of device list");
196        return m_devices;
197    }
198    lenStr[PAYLOAD_LENGTH] = 0;
199
200    // Parse the hex payload
201    int payloadLen = strtol(lenStr, NULL, 16);
202    if (payloadLen < 0)
203        return m_devices;
204
205    // Grab the list of devices. The format is as follows:
206    // <serialno><tab><state><newline>
207    char* msg = new char[payloadLen + 1];
208    res = recv(m_fd, msg, payloadLen, 0);
209    if (res < 0) {
210        log_errno("Failure reading the device list");
211        return m_devices;
212    } else if (res != payloadLen) {
213        ALOGE("Incorrect payload length %d - expected %d", res, payloadLen);
214        return m_devices;
215    }
216    msg[res] = 0;
217
218    char serial[32];
219    char state[32];
220    int numRead;
221    char* ptr = msg;
222    while (sscanf(ptr, "%31s\t%31s\n%n", serial, state, &numRead) > 1) {
223        Device::DeviceType t = Device::DEVICE;
224        static const char emulator[] = "emulator-";
225        if (strncmp(serial, emulator, sizeof(emulator) - 1) == 0)
226            t = Device::EMULATOR;
227        ALOGV("Adding device %s (%s)", serial, state);
228        m_devices.add(new Device(serial, t, this));
229
230        // Reset for the next line
231        ptr += numRead;
232    }
233    // Cleanup
234    delete[] msg;
235
236    return m_devices;
237}
238