aboutsummaryrefslogtreecommitdiff
path: root/host/frontend/gcastv2/webrtc/AdbWebSocketHandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'host/frontend/gcastv2/webrtc/AdbWebSocketHandler.cpp')
-rw-r--r--host/frontend/gcastv2/webrtc/AdbWebSocketHandler.cpp259
1 files changed, 259 insertions, 0 deletions
diff --git a/host/frontend/gcastv2/webrtc/AdbWebSocketHandler.cpp b/host/frontend/gcastv2/webrtc/AdbWebSocketHandler.cpp
new file mode 100644
index 000000000..dcb6d503d
--- /dev/null
+++ b/host/frontend/gcastv2/webrtc/AdbWebSocketHandler.cpp
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2019 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 <webrtc/AdbWebSocketHandler.h>
+
+#include "Utils.h"
+
+#include <https/BaseConnection.h>
+#include <https/Support.h>
+
+#include <android-base/logging.h>
+
+#include <unistd.h>
+
+using namespace android;
+
+struct AdbWebSocketHandler::AdbConnection : public BaseConnection {
+ explicit AdbConnection(
+ AdbWebSocketHandler *parent,
+ std::shared_ptr<RunLoop> runLoop,
+ int sock);
+
+ void send(const void *_data, size_t size);
+
+protected:
+ ssize_t processClientRequest(const void *data, size_t size) override;
+ void onDisconnect(int err) override;
+
+private:
+ AdbWebSocketHandler *mParent;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+AdbWebSocketHandler::AdbConnection::AdbConnection(
+ AdbWebSocketHandler *parent,
+ std::shared_ptr<RunLoop> runLoop,
+ int sock)
+ : BaseConnection(runLoop, sock),
+ mParent(parent) {
+}
+
+// Thanks for calling it a crc32, adb documentation!
+static uint32_t computeNotACrc32(const void *_data, size_t size) {
+ auto data = static_cast<const uint8_t *>(_data);
+ uint32_t sum = 0;
+ for (size_t i = 0; i < size; ++i) {
+ sum += data[i];
+ }
+
+ return sum;
+}
+
+static int verifyAdbHeader(
+ const void *_data, size_t size, size_t *_payloadLength) {
+ auto data = static_cast<const uint8_t *>(_data);
+
+ *_payloadLength = 0;
+
+ if (size < 24) {
+ return -EAGAIN;
+ }
+
+ uint32_t command = U32LE_AT(data);
+ uint32_t magic = U32LE_AT(data + 20);
+
+ if (command != (magic ^ 0xffffffff)) {
+ return -EINVAL;
+ }
+
+ uint32_t payloadLength = U32LE_AT(data + 12);
+
+ if (size < 24 + payloadLength) {
+ return -EAGAIN;
+ }
+
+ auto payloadCrc = U32LE_AT(data + 16);
+ auto crc32 = computeNotACrc32(data + 24, payloadLength);
+
+ if (payloadCrc != crc32) {
+ return -EINVAL;
+ }
+
+ *_payloadLength = payloadLength;
+
+ return 0;
+}
+
+ssize_t AdbWebSocketHandler::AdbConnection::processClientRequest(
+ const void *_data, size_t size) {
+ auto data = static_cast<const uint8_t *>(_data);
+
+ LOG(VERBOSE)
+ << "AdbConnection::processClientRequest (size = " << size << ")";
+
+ // hexdump(data, size);
+
+ size_t payloadLength;
+ int err = verifyAdbHeader(data, size, &payloadLength);
+
+ if (err) {
+ return err;
+ }
+
+ mParent->sendMessage(
+ data, payloadLength + 24, WebSocketHandler::SendMode::binary);
+
+ return payloadLength + 24;
+}
+
+void AdbWebSocketHandler::AdbConnection::onDisconnect(int err) {
+ LOG(INFO) << "AdbConnection::onDisconnect(err=" << err << ")";
+
+ mParent->sendMessage(
+ nullptr /* data */,
+ 0 /* size */,
+ WebSocketHandler::SendMode::closeConnection);
+}
+
+void AdbWebSocketHandler::AdbConnection::send(const void *_data, size_t size) {
+ BaseConnection::send(_data, size);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+AdbWebSocketHandler::AdbWebSocketHandler(
+ std::shared_ptr<RunLoop> runLoop,
+ const std::string &adb_host_and_port)
+ : mRunLoop(runLoop),
+ mSocket(-1) {
+ LOG(INFO) << "Connecting to " << adb_host_and_port;
+
+ auto err = setupSocket(adb_host_and_port);
+ CHECK(!err);
+
+ mAdbConnection = std::make_shared<AdbConnection>(this, mRunLoop, mSocket);
+}
+
+AdbWebSocketHandler::~AdbWebSocketHandler() {
+ if (mSocket >= 0) {
+ close(mSocket);
+ mSocket = -1;
+ }
+}
+
+void AdbWebSocketHandler::run() {
+ mAdbConnection->run();
+}
+
+int AdbWebSocketHandler::setupSocket(const std::string &adb_host_and_port) {
+ auto colonPos = adb_host_and_port.find(':');
+ if (colonPos == std::string::npos) {
+ return -EINVAL;
+ }
+
+ auto host = adb_host_and_port.substr(0, colonPos);
+
+ const char *portString = adb_host_and_port.c_str() + colonPos + 1;
+ char *end;
+ unsigned long port = strtoul(portString, &end, 10);
+
+ if (end == portString || *end != '\0' || port > 65535) {
+ return -EINVAL;
+ }
+
+ int err;
+
+ int sock = socket(PF_INET, SOCK_STREAM, 0);
+
+ if (sock < 0) {
+ err = -errno;
+ goto bail;
+ }
+
+ makeFdNonblocking(sock);
+
+ sockaddr_in addr;
+ memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = inet_addr(host.c_str());
+ addr.sin_port = htons(port);
+
+ if (connect(sock,
+ reinterpret_cast<const sockaddr *>(&addr),
+ sizeof(addr)) < 0
+ && errno != EINPROGRESS) {
+ err = -errno;
+ goto bail2;
+ }
+
+ mSocket = sock;
+
+ return 0;
+
+bail2:
+ close(sock);
+ sock = -1;
+
+bail:
+ return err;
+}
+
+int AdbWebSocketHandler::handleMessage(
+ uint8_t headerByte, const uint8_t *msg, size_t len) {
+ LOG(VERBOSE)
+ << "headerByte = "
+ << StringPrintf("0x%02x", (unsigned)headerByte);
+
+ // hexdump(msg, len);
+
+ if (!(headerByte & 0x80)) {
+ // I only want to receive whole messages here, not fragments.
+ return -EINVAL;
+ }
+
+ auto opcode = headerByte & 0x1f;
+ switch (opcode) {
+ case 0x8:
+ {
+ // closeConnection.
+ break;
+ }
+
+ case 0x2:
+ {
+ // binary
+
+ size_t payloadLength;
+ int err = verifyAdbHeader(msg, len, &payloadLength);
+
+ if (err || len != 24 + payloadLength) {
+ LOG(ERROR) << "websocket message is not a valid adb message.";
+ return -EINVAL;
+ }
+
+ mAdbConnection->send(msg, len);
+ break;
+ }
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+