| Index: tools/android/forwarder/forwarder.cc
|
| diff --git a/tools/android/forwarder/forwarder.cc b/tools/android/forwarder/forwarder.cc
|
| deleted file mode 100644
|
| index e72c3bd97ac6f9cd30e040b6a527cbd910e7893b..0000000000000000000000000000000000000000
|
| --- a/tools/android/forwarder/forwarder.cc
|
| +++ /dev/null
|
| @@ -1,428 +0,0 @@
|
| -// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include <errno.h>
|
| -#include <fcntl.h>
|
| -#include <netinet/in.h>
|
| -#include <netinet/tcp.h>
|
| -#include <pthread.h>
|
| -#include <signal.h>
|
| -#include <stddef.h>
|
| -#include <stdio.h>
|
| -#include <stdlib.h>
|
| -#include <string.h>
|
| -#include <sys/select.h>
|
| -#include <sys/socket.h>
|
| -#include <sys/wait.h>
|
| -#include <unistd.h>
|
| -
|
| -#include "base/command_line.h"
|
| -#include "base/logging.h"
|
| -#include "base/macros.h"
|
| -#include "base/posix/eintr_wrapper.h"
|
| -#include "tools/android/common/adb_connection.h"
|
| -#include "tools/android/common/daemon.h"
|
| -#include "tools/android/common/net.h"
|
| -
|
| -namespace {
|
| -
|
| -const pthread_t kInvalidThread = static_cast<pthread_t>(-1);
|
| -volatile bool g_killed = false;
|
| -
|
| -void CloseSocket(int fd) {
|
| - if (fd >= 0) {
|
| - int old_errno = errno;
|
| - close(fd);
|
| - errno = old_errno;
|
| - }
|
| -}
|
| -
|
| -class Buffer {
|
| - public:
|
| - Buffer()
|
| - : bytes_read_(0),
|
| - write_offset_(0) {
|
| - }
|
| -
|
| - bool CanRead() {
|
| - return bytes_read_ == 0;
|
| - }
|
| -
|
| - bool CanWrite() {
|
| - return write_offset_ < bytes_read_;
|
| - }
|
| -
|
| - int Read(int fd) {
|
| - int ret = -1;
|
| - if (CanRead()) {
|
| - ret = HANDLE_EINTR(read(fd, buffer_, kBufferSize));
|
| - if (ret > 0)
|
| - bytes_read_ = ret;
|
| - }
|
| - return ret;
|
| - }
|
| -
|
| - int Write(int fd) {
|
| - int ret = -1;
|
| - if (CanWrite()) {
|
| - ret = HANDLE_EINTR(write(fd, buffer_ + write_offset_,
|
| - bytes_read_ - write_offset_));
|
| - if (ret > 0) {
|
| - write_offset_ += ret;
|
| - if (write_offset_ == bytes_read_) {
|
| - write_offset_ = 0;
|
| - bytes_read_ = 0;
|
| - }
|
| - }
|
| - }
|
| - return ret;
|
| - }
|
| -
|
| - private:
|
| - // A big buffer to let our file-over-http bridge work more like real file.
|
| - static const int kBufferSize = 1024 * 128;
|
| - int bytes_read_;
|
| - int write_offset_;
|
| - char buffer_[kBufferSize];
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(Buffer);
|
| -};
|
| -
|
| -class Server;
|
| -
|
| -struct ForwarderThreadInfo {
|
| - ForwarderThreadInfo(Server* a_server, int a_forwarder_index)
|
| - : server(a_server),
|
| - forwarder_index(a_forwarder_index) {
|
| - }
|
| - Server* server;
|
| - int forwarder_index;
|
| -};
|
| -
|
| -struct ForwarderInfo {
|
| - time_t start_time;
|
| - int socket1;
|
| - time_t socket1_last_byte_time;
|
| - size_t socket1_bytes;
|
| - int socket2;
|
| - time_t socket2_last_byte_time;
|
| - size_t socket2_bytes;
|
| -};
|
| -
|
| -class Server {
|
| - public:
|
| - Server()
|
| - : thread_(kInvalidThread),
|
| - socket_(-1) {
|
| - memset(forward_to_, 0, sizeof(forward_to_));
|
| - memset(&forwarders_, 0, sizeof(forwarders_));
|
| - }
|
| -
|
| - int GetFreeForwarderIndex() {
|
| - for (int i = 0; i < kMaxForwarders; i++) {
|
| - if (forwarders_[i].start_time == 0)
|
| - return i;
|
| - }
|
| - return -1;
|
| - }
|
| -
|
| - void DisposeForwarderInfo(int index) {
|
| - forwarders_[index].start_time = 0;
|
| - }
|
| -
|
| - ForwarderInfo* GetForwarderInfo(int index) {
|
| - return &forwarders_[index];
|
| - }
|
| -
|
| - void DumpInformation() {
|
| - LOG(INFO) << "Server information: " << forward_to_;
|
| - LOG(INFO) << "No.: age up(bytes,idle) down(bytes,idle)";
|
| - int count = 0;
|
| - time_t now = time(NULL);
|
| - for (int i = 0; i < kMaxForwarders; i++) {
|
| - const ForwarderInfo& info = forwarders_[i];
|
| - if (info.start_time) {
|
| - count++;
|
| - LOG(INFO) << count << ": " << now - info.start_time << " up("
|
| - << info.socket1_bytes << ","
|
| - << now - info.socket1_last_byte_time << " down("
|
| - << info.socket2_bytes << ","
|
| - << now - info.socket2_last_byte_time << ")";
|
| - }
|
| - }
|
| - }
|
| -
|
| - void Shutdown() {
|
| - if (socket_ >= 0)
|
| - shutdown(socket_, SHUT_RDWR);
|
| - }
|
| -
|
| - bool InitSocket(const char* arg);
|
| -
|
| - void StartThread() {
|
| - pthread_create(&thread_, NULL, ServerThread, this);
|
| - }
|
| -
|
| - void JoinThread() {
|
| - if (thread_ != kInvalidThread)
|
| - pthread_join(thread_, NULL);
|
| - }
|
| -
|
| - private:
|
| - static void* ServerThread(void* arg);
|
| -
|
| - // There are 3 kinds of threads that will access the array:
|
| - // 1. Server thread will get a free ForwarderInfo and initialize it;
|
| - // 2. Forwarder threads will dispose the ForwarderInfo when it finishes;
|
| - // 3. Main thread will iterate and print the forwarders.
|
| - // Using an array is not optimal, but can avoid locks or other complex
|
| - // inter-thread communication.
|
| - static const int kMaxForwarders = 512;
|
| - ForwarderInfo forwarders_[kMaxForwarders];
|
| -
|
| - pthread_t thread_;
|
| - int socket_;
|
| - char forward_to_[40];
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(Server);
|
| -};
|
| -
|
| -// Forwards all outputs from one socket to another socket.
|
| -void* ForwarderThread(void* arg) {
|
| - ForwarderThreadInfo* thread_info =
|
| - reinterpret_cast<ForwarderThreadInfo*>(arg);
|
| - Server* server = thread_info->server;
|
| - int index = thread_info->forwarder_index;
|
| - delete thread_info;
|
| - ForwarderInfo* info = server->GetForwarderInfo(index);
|
| - int socket1 = info->socket1;
|
| - int socket2 = info->socket2;
|
| - int nfds = socket1 > socket2 ? socket1 + 1 : socket2 + 1;
|
| - fd_set read_fds;
|
| - fd_set write_fds;
|
| - Buffer buffer1;
|
| - Buffer buffer2;
|
| -
|
| - while (!g_killed) {
|
| - FD_ZERO(&read_fds);
|
| - if (buffer1.CanRead())
|
| - FD_SET(socket1, &read_fds);
|
| - if (buffer2.CanRead())
|
| - FD_SET(socket2, &read_fds);
|
| -
|
| - FD_ZERO(&write_fds);
|
| - if (buffer1.CanWrite())
|
| - FD_SET(socket2, &write_fds);
|
| - if (buffer2.CanWrite())
|
| - FD_SET(socket1, &write_fds);
|
| -
|
| - if (HANDLE_EINTR(select(nfds, &read_fds, &write_fds, NULL, NULL)) <= 0) {
|
| - LOG(ERROR) << "Select error: " << strerror(errno);
|
| - break;
|
| - }
|
| -
|
| - int now = time(NULL);
|
| - if (FD_ISSET(socket1, &read_fds)) {
|
| - info->socket1_last_byte_time = now;
|
| - int bytes = buffer1.Read(socket1);
|
| - if (bytes <= 0)
|
| - break;
|
| - info->socket1_bytes += bytes;
|
| - }
|
| - if (FD_ISSET(socket2, &read_fds)) {
|
| - info->socket2_last_byte_time = now;
|
| - int bytes = buffer2.Read(socket2);
|
| - if (bytes <= 0)
|
| - break;
|
| - info->socket2_bytes += bytes;
|
| - }
|
| - if (FD_ISSET(socket1, &write_fds)) {
|
| - if (buffer2.Write(socket1) <= 0)
|
| - break;
|
| - }
|
| - if (FD_ISSET(socket2, &write_fds)) {
|
| - if (buffer1.Write(socket2) <= 0)
|
| - break;
|
| - }
|
| - }
|
| -
|
| - CloseSocket(socket1);
|
| - CloseSocket(socket2);
|
| - server->DisposeForwarderInfo(index);
|
| - return NULL;
|
| -}
|
| -
|
| -// Listens to a server socket. On incoming request, forward it to the host.
|
| -// static
|
| -void* Server::ServerThread(void* arg) {
|
| - Server* server = reinterpret_cast<Server*>(arg);
|
| - while (!g_killed) {
|
| - int forwarder_index = server->GetFreeForwarderIndex();
|
| - if (forwarder_index < 0) {
|
| - LOG(ERROR) << "Too many forwarders";
|
| - continue;
|
| - }
|
| -
|
| - struct sockaddr_in addr;
|
| - socklen_t addr_len = sizeof(addr);
|
| - int socket = HANDLE_EINTR(accept(server->socket_,
|
| - reinterpret_cast<sockaddr*>(&addr),
|
| - &addr_len));
|
| - if (socket < 0) {
|
| - LOG(ERROR) << "Failed to accept: " << strerror(errno);
|
| - break;
|
| - }
|
| - tools::DisableNagle(socket);
|
| -
|
| - int host_socket = tools::ConnectAdbHostSocket(server->forward_to_);
|
| - if (host_socket >= 0) {
|
| - // Set NONBLOCK flag because we use select().
|
| - fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) | O_NONBLOCK);
|
| - fcntl(host_socket, F_SETFL, fcntl(host_socket, F_GETFL) | O_NONBLOCK);
|
| -
|
| - ForwarderInfo* forwarder_info = server->GetForwarderInfo(forwarder_index);
|
| - time_t now = time(NULL);
|
| - forwarder_info->start_time = now;
|
| - forwarder_info->socket1 = socket;
|
| - forwarder_info->socket1_last_byte_time = now;
|
| - forwarder_info->socket1_bytes = 0;
|
| - forwarder_info->socket2 = host_socket;
|
| - forwarder_info->socket2_last_byte_time = now;
|
| - forwarder_info->socket2_bytes = 0;
|
| -
|
| - pthread_t thread;
|
| - pthread_create(&thread, NULL, ForwarderThread,
|
| - new ForwarderThreadInfo(server, forwarder_index));
|
| - } else {
|
| - // Close the unused client socket which is failed to connect to host.
|
| - CloseSocket(socket);
|
| - }
|
| - }
|
| -
|
| - CloseSocket(server->socket_);
|
| - server->socket_ = -1;
|
| - return NULL;
|
| -}
|
| -
|
| -// Format of arg: <Device port>[:<Forward to port>:<Forward to address>]
|
| -bool Server::InitSocket(const char* arg) {
|
| - char* endptr;
|
| - int local_port = static_cast<int>(strtol(arg, &endptr, 10));
|
| - if (local_port < 0)
|
| - return false;
|
| -
|
| - if (*endptr != ':') {
|
| - snprintf(forward_to_, sizeof(forward_to_), "%d:127.0.0.1", local_port);
|
| - } else {
|
| - strncpy(forward_to_, endptr + 1, sizeof(forward_to_) - 1);
|
| - }
|
| -
|
| - socket_ = socket(AF_INET, SOCK_STREAM, 0);
|
| - if (socket_ < 0) {
|
| - perror("server socket");
|
| - return false;
|
| - }
|
| - tools::DisableNagle(socket_);
|
| -
|
| - sockaddr_in addr;
|
| - memset(&addr, 0, sizeof(addr));
|
| - addr.sin_family = AF_INET;
|
| - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
| - addr.sin_port = htons(local_port);
|
| - int reuse_addr = 1;
|
| - setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR,
|
| - &reuse_addr, sizeof(reuse_addr));
|
| - tools::DeferAccept(socket_);
|
| - if (HANDLE_EINTR(bind(socket_, reinterpret_cast<sockaddr*>(&addr),
|
| - sizeof(addr))) < 0 ||
|
| - HANDLE_EINTR(listen(socket_, 5)) < 0) {
|
| - perror("server bind");
|
| - CloseSocket(socket_);
|
| - socket_ = -1;
|
| - return false;
|
| - }
|
| -
|
| - if (local_port == 0) {
|
| - socklen_t addrlen = sizeof(addr);
|
| - if (getsockname(socket_, reinterpret_cast<sockaddr*>(&addr), &addrlen)
|
| - != 0) {
|
| - perror("get listen address");
|
| - CloseSocket(socket_);
|
| - socket_ = -1;
|
| - return false;
|
| - }
|
| - local_port = ntohs(addr.sin_port);
|
| - }
|
| -
|
| - printf("Forwarding device port %d to host %s\n", local_port, forward_to_);
|
| - return true;
|
| -}
|
| -
|
| -int g_server_count = 0;
|
| -Server* g_servers = NULL;
|
| -
|
| -void KillHandler(int unused) {
|
| - g_killed = true;
|
| - for (int i = 0; i < g_server_count; i++)
|
| - g_servers[i].Shutdown();
|
| -}
|
| -
|
| -void DumpInformation(int unused) {
|
| - for (int i = 0; i < g_server_count; i++)
|
| - g_servers[i].DumpInformation();
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -int main(int argc, char** argv) {
|
| - printf("Android device to host TCP forwarder\n");
|
| - printf("Like 'adb forward' but in the reverse direction\n");
|
| -
|
| - base::CommandLine command_line(argc, argv);
|
| - base::CommandLine::StringVector server_args = command_line.GetArgs();
|
| - if (tools::HasHelpSwitch(command_line) || server_args.empty()) {
|
| - tools::ShowHelp(
|
| - argv[0],
|
| - "<Device port>[:<Forward to port>:<Forward to address>] ...",
|
| - " <Forward to port> default is <Device port>\n"
|
| - " <Forward to address> default is 127.0.0.1\n"
|
| - "If <Device port> is 0, a port will by dynamically allocated.\n");
|
| - return 0;
|
| - }
|
| -
|
| - g_servers = new Server[server_args.size()];
|
| - g_server_count = 0;
|
| - int failed_count = 0;
|
| - for (size_t i = 0; i < server_args.size(); i++) {
|
| - if (!g_servers[g_server_count].InitSocket(server_args[i].c_str())) {
|
| - printf("Couldn't start forwarder server for port spec: %s\n",
|
| - server_args[i].c_str());
|
| - ++failed_count;
|
| - } else {
|
| - ++g_server_count;
|
| - }
|
| - }
|
| -
|
| - if (g_server_count == 0) {
|
| - printf("No forwarder servers could be started. Exiting.\n");
|
| - delete [] g_servers;
|
| - return failed_count;
|
| - }
|
| -
|
| - if (!tools::HasNoSpawnDaemonSwitch(command_line))
|
| - tools::SpawnDaemon(failed_count);
|
| -
|
| - signal(SIGTERM, KillHandler);
|
| - signal(SIGUSR2, DumpInformation);
|
| -
|
| - for (int i = 0; i < g_server_count; i++)
|
| - g_servers[i].StartThread();
|
| - for (int i = 0; i < g_server_count; i++)
|
| - g_servers[i].JoinThread();
|
| - g_server_count = 0;
|
| - delete [] g_servers;
|
| -
|
| - return 0;
|
| -}
|
| -
|
|
|