Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(185)

Unified Diff: tools/android/forwarder/forwarder.cc

Issue 1841863002: Update monet. (Closed) Base URL: https://github.com/domokit/monet.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: tools/android/forwarder/forwarder.cc
diff --git a/tools/android/forwarder/forwarder.cc b/tools/android/forwarder/forwarder.cc
new file mode 100644
index 0000000000000000000000000000000000000000..1d24ad2c5cb4932caf3f69dd025770d06bf6c9dc
--- /dev/null
+++ b/tools/android/forwarder/forwarder.cc
@@ -0,0 +1,426 @@
+// 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 <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/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;
+}
+
« no previous file with comments | « tools/android/findbugs_plugin/test/run_findbugs_plugin_tests.py ('k') | tools/android/forwarder2/command.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698