OLD | NEW |
| (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 | |
OLD | NEW |