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

Side by Side Diff: tools/android/forwarder/forwarder.cc

Issue 2378773002: [Android] Remove //tools/android/forwarder. (Closed)
Patch Set: rebase Created 4 years, 2 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 unified diff | Download patch
« no previous file with comments | « tools/android/forwarder/BUILD.gn ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <errno.h>
6 #include <fcntl.h>
7 #include <netinet/in.h>
8 #include <netinet/tcp.h>
9 #include <pthread.h>
10 #include <signal.h>
11 #include <stddef.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/select.h>
16 #include <sys/socket.h>
17 #include <sys/wait.h>
18 #include <unistd.h>
19
20 #include "base/command_line.h"
21 #include "base/logging.h"
22 #include "base/macros.h"
23 #include "base/posix/eintr_wrapper.h"
24 #include "tools/android/common/adb_connection.h"
25 #include "tools/android/common/daemon.h"
26 #include "tools/android/common/net.h"
27
28 namespace {
29
30 const pthread_t kInvalidThread = static_cast<pthread_t>(-1);
31 volatile bool g_killed = false;
32
33 void CloseSocket(int fd) {
34 if (fd >= 0) {
35 int old_errno = errno;
36 close(fd);
37 errno = old_errno;
38 }
39 }
40
41 class Buffer {
42 public:
43 Buffer()
44 : bytes_read_(0),
45 write_offset_(0) {
46 }
47
48 bool CanRead() {
49 return bytes_read_ == 0;
50 }
51
52 bool CanWrite() {
53 return write_offset_ < bytes_read_;
54 }
55
56 int Read(int fd) {
57 int ret = -1;
58 if (CanRead()) {
59 ret = HANDLE_EINTR(read(fd, buffer_, kBufferSize));
60 if (ret > 0)
61 bytes_read_ = ret;
62 }
63 return ret;
64 }
65
66 int Write(int fd) {
67 int ret = -1;
68 if (CanWrite()) {
69 ret = HANDLE_EINTR(write(fd, buffer_ + write_offset_,
70 bytes_read_ - write_offset_));
71 if (ret > 0) {
72 write_offset_ += ret;
73 if (write_offset_ == bytes_read_) {
74 write_offset_ = 0;
75 bytes_read_ = 0;
76 }
77 }
78 }
79 return ret;
80 }
81
82 private:
83 // A big buffer to let our file-over-http bridge work more like real file.
84 static const int kBufferSize = 1024 * 128;
85 int bytes_read_;
86 int write_offset_;
87 char buffer_[kBufferSize];
88
89 DISALLOW_COPY_AND_ASSIGN(Buffer);
90 };
91
92 class Server;
93
94 struct ForwarderThreadInfo {
95 ForwarderThreadInfo(Server* a_server, int a_forwarder_index)
96 : server(a_server),
97 forwarder_index(a_forwarder_index) {
98 }
99 Server* server;
100 int forwarder_index;
101 };
102
103 struct ForwarderInfo {
104 time_t start_time;
105 int socket1;
106 time_t socket1_last_byte_time;
107 size_t socket1_bytes;
108 int socket2;
109 time_t socket2_last_byte_time;
110 size_t socket2_bytes;
111 };
112
113 class Server {
114 public:
115 Server()
116 : thread_(kInvalidThread),
117 socket_(-1) {
118 memset(forward_to_, 0, sizeof(forward_to_));
119 memset(&forwarders_, 0, sizeof(forwarders_));
120 }
121
122 int GetFreeForwarderIndex() {
123 for (int i = 0; i < kMaxForwarders; i++) {
124 if (forwarders_[i].start_time == 0)
125 return i;
126 }
127 return -1;
128 }
129
130 void DisposeForwarderInfo(int index) {
131 forwarders_[index].start_time = 0;
132 }
133
134 ForwarderInfo* GetForwarderInfo(int index) {
135 return &forwarders_[index];
136 }
137
138 void DumpInformation() {
139 LOG(INFO) << "Server information: " << forward_to_;
140 LOG(INFO) << "No.: age up(bytes,idle) down(bytes,idle)";
141 int count = 0;
142 time_t now = time(NULL);
143 for (int i = 0; i < kMaxForwarders; i++) {
144 const ForwarderInfo& info = forwarders_[i];
145 if (info.start_time) {
146 count++;
147 LOG(INFO) << count << ": " << now - info.start_time << " up("
148 << info.socket1_bytes << ","
149 << now - info.socket1_last_byte_time << " down("
150 << info.socket2_bytes << ","
151 << now - info.socket2_last_byte_time << ")";
152 }
153 }
154 }
155
156 void Shutdown() {
157 if (socket_ >= 0)
158 shutdown(socket_, SHUT_RDWR);
159 }
160
161 bool InitSocket(const char* arg);
162
163 void StartThread() {
164 pthread_create(&thread_, NULL, ServerThread, this);
165 }
166
167 void JoinThread() {
168 if (thread_ != kInvalidThread)
169 pthread_join(thread_, NULL);
170 }
171
172 private:
173 static void* ServerThread(void* arg);
174
175 // There are 3 kinds of threads that will access the array:
176 // 1. Server thread will get a free ForwarderInfo and initialize it;
177 // 2. Forwarder threads will dispose the ForwarderInfo when it finishes;
178 // 3. Main thread will iterate and print the forwarders.
179 // Using an array is not optimal, but can avoid locks or other complex
180 // inter-thread communication.
181 static const int kMaxForwarders = 512;
182 ForwarderInfo forwarders_[kMaxForwarders];
183
184 pthread_t thread_;
185 int socket_;
186 char forward_to_[40];
187
188 DISALLOW_COPY_AND_ASSIGN(Server);
189 };
190
191 // Forwards all outputs from one socket to another socket.
192 void* ForwarderThread(void* arg) {
193 ForwarderThreadInfo* thread_info =
194 reinterpret_cast<ForwarderThreadInfo*>(arg);
195 Server* server = thread_info->server;
196 int index = thread_info->forwarder_index;
197 delete thread_info;
198 ForwarderInfo* info = server->GetForwarderInfo(index);
199 int socket1 = info->socket1;
200 int socket2 = info->socket2;
201 int nfds = socket1 > socket2 ? socket1 + 1 : socket2 + 1;
202 fd_set read_fds;
203 fd_set write_fds;
204 Buffer buffer1;
205 Buffer buffer2;
206
207 while (!g_killed) {
208 FD_ZERO(&read_fds);
209 if (buffer1.CanRead())
210 FD_SET(socket1, &read_fds);
211 if (buffer2.CanRead())
212 FD_SET(socket2, &read_fds);
213
214 FD_ZERO(&write_fds);
215 if (buffer1.CanWrite())
216 FD_SET(socket2, &write_fds);
217 if (buffer2.CanWrite())
218 FD_SET(socket1, &write_fds);
219
220 if (HANDLE_EINTR(select(nfds, &read_fds, &write_fds, NULL, NULL)) <= 0) {
221 LOG(ERROR) << "Select error: " << strerror(errno);
222 break;
223 }
224
225 int now = time(NULL);
226 if (FD_ISSET(socket1, &read_fds)) {
227 info->socket1_last_byte_time = now;
228 int bytes = buffer1.Read(socket1);
229 if (bytes <= 0)
230 break;
231 info->socket1_bytes += bytes;
232 }
233 if (FD_ISSET(socket2, &read_fds)) {
234 info->socket2_last_byte_time = now;
235 int bytes = buffer2.Read(socket2);
236 if (bytes <= 0)
237 break;
238 info->socket2_bytes += bytes;
239 }
240 if (FD_ISSET(socket1, &write_fds)) {
241 if (buffer2.Write(socket1) <= 0)
242 break;
243 }
244 if (FD_ISSET(socket2, &write_fds)) {
245 if (buffer1.Write(socket2) <= 0)
246 break;
247 }
248 }
249
250 CloseSocket(socket1);
251 CloseSocket(socket2);
252 server->DisposeForwarderInfo(index);
253 return NULL;
254 }
255
256 // Listens to a server socket. On incoming request, forward it to the host.
257 // static
258 void* Server::ServerThread(void* arg) {
259 Server* server = reinterpret_cast<Server*>(arg);
260 while (!g_killed) {
261 int forwarder_index = server->GetFreeForwarderIndex();
262 if (forwarder_index < 0) {
263 LOG(ERROR) << "Too many forwarders";
264 continue;
265 }
266
267 struct sockaddr_in addr;
268 socklen_t addr_len = sizeof(addr);
269 int socket = HANDLE_EINTR(accept(server->socket_,
270 reinterpret_cast<sockaddr*>(&addr),
271 &addr_len));
272 if (socket < 0) {
273 LOG(ERROR) << "Failed to accept: " << strerror(errno);
274 break;
275 }
276 tools::DisableNagle(socket);
277
278 int host_socket = tools::ConnectAdbHostSocket(server->forward_to_);
279 if (host_socket >= 0) {
280 // Set NONBLOCK flag because we use select().
281 fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) | O_NONBLOCK);
282 fcntl(host_socket, F_SETFL, fcntl(host_socket, F_GETFL) | O_NONBLOCK);
283
284 ForwarderInfo* forwarder_info = server->GetForwarderInfo(forwarder_index);
285 time_t now = time(NULL);
286 forwarder_info->start_time = now;
287 forwarder_info->socket1 = socket;
288 forwarder_info->socket1_last_byte_time = now;
289 forwarder_info->socket1_bytes = 0;
290 forwarder_info->socket2 = host_socket;
291 forwarder_info->socket2_last_byte_time = now;
292 forwarder_info->socket2_bytes = 0;
293
294 pthread_t thread;
295 pthread_create(&thread, NULL, ForwarderThread,
296 new ForwarderThreadInfo(server, forwarder_index));
297 } else {
298 // Close the unused client socket which is failed to connect to host.
299 CloseSocket(socket);
300 }
301 }
302
303 CloseSocket(server->socket_);
304 server->socket_ = -1;
305 return NULL;
306 }
307
308 // Format of arg: <Device port>[:<Forward to port>:<Forward to address>]
309 bool Server::InitSocket(const char* arg) {
310 char* endptr;
311 int local_port = static_cast<int>(strtol(arg, &endptr, 10));
312 if (local_port < 0)
313 return false;
314
315 if (*endptr != ':') {
316 snprintf(forward_to_, sizeof(forward_to_), "%d:127.0.0.1", local_port);
317 } else {
318 strncpy(forward_to_, endptr + 1, sizeof(forward_to_) - 1);
319 }
320
321 socket_ = socket(AF_INET, SOCK_STREAM, 0);
322 if (socket_ < 0) {
323 perror("server socket");
324 return false;
325 }
326 tools::DisableNagle(socket_);
327
328 sockaddr_in addr;
329 memset(&addr, 0, sizeof(addr));
330 addr.sin_family = AF_INET;
331 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
332 addr.sin_port = htons(local_port);
333 int reuse_addr = 1;
334 setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR,
335 &reuse_addr, sizeof(reuse_addr));
336 tools::DeferAccept(socket_);
337 if (HANDLE_EINTR(bind(socket_, reinterpret_cast<sockaddr*>(&addr),
338 sizeof(addr))) < 0 ||
339 HANDLE_EINTR(listen(socket_, 5)) < 0) {
340 perror("server bind");
341 CloseSocket(socket_);
342 socket_ = -1;
343 return false;
344 }
345
346 if (local_port == 0) {
347 socklen_t addrlen = sizeof(addr);
348 if (getsockname(socket_, reinterpret_cast<sockaddr*>(&addr), &addrlen)
349 != 0) {
350 perror("get listen address");
351 CloseSocket(socket_);
352 socket_ = -1;
353 return false;
354 }
355 local_port = ntohs(addr.sin_port);
356 }
357
358 printf("Forwarding device port %d to host %s\n", local_port, forward_to_);
359 return true;
360 }
361
362 int g_server_count = 0;
363 Server* g_servers = NULL;
364
365 void KillHandler(int unused) {
366 g_killed = true;
367 for (int i = 0; i < g_server_count; i++)
368 g_servers[i].Shutdown();
369 }
370
371 void DumpInformation(int unused) {
372 for (int i = 0; i < g_server_count; i++)
373 g_servers[i].DumpInformation();
374 }
375
376 } // namespace
377
378 int main(int argc, char** argv) {
379 printf("Android device to host TCP forwarder\n");
380 printf("Like 'adb forward' but in the reverse direction\n");
381
382 base::CommandLine command_line(argc, argv);
383 base::CommandLine::StringVector server_args = command_line.GetArgs();
384 if (tools::HasHelpSwitch(command_line) || server_args.empty()) {
385 tools::ShowHelp(
386 argv[0],
387 "<Device port>[:<Forward to port>:<Forward to address>] ...",
388 " <Forward to port> default is <Device port>\n"
389 " <Forward to address> default is 127.0.0.1\n"
390 "If <Device port> is 0, a port will by dynamically allocated.\n");
391 return 0;
392 }
393
394 g_servers = new Server[server_args.size()];
395 g_server_count = 0;
396 int failed_count = 0;
397 for (size_t i = 0; i < server_args.size(); i++) {
398 if (!g_servers[g_server_count].InitSocket(server_args[i].c_str())) {
399 printf("Couldn't start forwarder server for port spec: %s\n",
400 server_args[i].c_str());
401 ++failed_count;
402 } else {
403 ++g_server_count;
404 }
405 }
406
407 if (g_server_count == 0) {
408 printf("No forwarder servers could be started. Exiting.\n");
409 delete [] g_servers;
410 return failed_count;
411 }
412
413 if (!tools::HasNoSpawnDaemonSwitch(command_line))
414 tools::SpawnDaemon(failed_count);
415
416 signal(SIGTERM, KillHandler);
417 signal(SIGUSR2, DumpInformation);
418
419 for (int i = 0; i < g_server_count; i++)
420 g_servers[i].StartThread();
421 for (int i = 0; i < g_server_count; i++)
422 g_servers[i].JoinThread();
423 g_server_count = 0;
424 delete [] g_servers;
425
426 return 0;
427 }
428
OLDNEW
« no previous file with comments | « tools/android/forwarder/BUILD.gn ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698