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.
7 #include <netinet/in.h>
8 #include <netinet/tcp.h>
14 #include <sys/select.h>
15 #include <sys/socket.h>
19 #include "base/command_line.h"
20 #include "base/logging.h"
21 #include "base/posix/eintr_wrapper.h"
22 #include "tools/android/common/adb_connection.h"
23 #include "tools/android/common/daemon.h"
24 #include "tools/android/common/net.h"
28 const pthread_t kInvalidThread
= static_cast<pthread_t
>(-1);
29 volatile bool g_killed
= false;
31 void CloseSocket(int fd
) {
33 int old_errno
= errno
;
34 (void) HANDLE_EINTR(close(fd
));
47 return bytes_read_
== 0;
51 return write_offset_
< bytes_read_
;
57 ret
= HANDLE_EINTR(read(fd
, buffer_
, kBufferSize
));
67 ret
= HANDLE_EINTR(write(fd
, buffer_
+ write_offset_
,
68 bytes_read_
- write_offset_
));
71 if (write_offset_
== bytes_read_
) {
81 // A big buffer to let our file-over-http bridge work more like real file.
82 static const int kBufferSize
= 1024 * 128;
85 char buffer_
[kBufferSize
];
87 DISALLOW_COPY_AND_ASSIGN(Buffer
);
92 struct ForwarderThreadInfo
{
93 ForwarderThreadInfo(Server
* a_server
, int a_forwarder_index
)
95 forwarder_index(a_forwarder_index
) {
101 struct ForwarderInfo
{
104 time_t socket1_last_byte_time
;
105 size_t socket1_bytes
;
107 time_t socket2_last_byte_time
;
108 size_t socket2_bytes
;
114 : thread_(kInvalidThread
),
116 memset(forward_to_
, 0, sizeof(forward_to_
));
117 memset(&forwarders_
, 0, sizeof(forwarders_
));
120 int GetFreeForwarderIndex() {
121 for (int i
= 0; i
< kMaxForwarders
; i
++) {
122 if (forwarders_
[i
].start_time
== 0)
128 void DisposeForwarderInfo(int index
) {
129 forwarders_
[index
].start_time
= 0;
132 ForwarderInfo
* GetForwarderInfo(int index
) {
133 return &forwarders_
[index
];
136 void DumpInformation() {
137 LOG(INFO
) << "Server information: " << forward_to_
;
138 LOG(INFO
) << "No.: age up(bytes,idle) down(bytes,idle)";
140 time_t now
= time(NULL
);
141 for (int i
= 0; i
< kMaxForwarders
; i
++) {
142 const ForwarderInfo
& info
= forwarders_
[i
];
143 if (info
.start_time
) {
145 LOG(INFO
) << count
<< ": " << now
- info
.start_time
<< " up("
146 << info
.socket1_bytes
<< ","
147 << now
- info
.socket1_last_byte_time
<< " down("
148 << info
.socket2_bytes
<< ","
149 << now
- info
.socket2_last_byte_time
<< ")";
156 shutdown(socket_
, SHUT_RDWR
);
159 bool InitSocket(const char* arg
);
162 pthread_create(&thread_
, NULL
, ServerThread
, this);
166 if (thread_
!= kInvalidThread
)
167 pthread_join(thread_
, NULL
);
171 static void* ServerThread(void* arg
);
173 // There are 3 kinds of threads that will access the array:
174 // 1. Server thread will get a free ForwarderInfo and initialize it;
175 // 2. Forwarder threads will dispose the ForwarderInfo when it finishes;
176 // 3. Main thread will iterate and print the forwarders.
177 // Using an array is not optimal, but can avoid locks or other complex
178 // inter-thread communication.
179 static const int kMaxForwarders
= 512;
180 ForwarderInfo forwarders_
[kMaxForwarders
];
184 char forward_to_
[40];
186 DISALLOW_COPY_AND_ASSIGN(Server
);
189 // Forwards all outputs from one socket to another socket.
190 void* ForwarderThread(void* arg
) {
191 ForwarderThreadInfo
* thread_info
=
192 reinterpret_cast<ForwarderThreadInfo
*>(arg
);
193 Server
* server
= thread_info
->server
;
194 int index
= thread_info
->forwarder_index
;
196 ForwarderInfo
* info
= server
->GetForwarderInfo(index
);
197 int socket1
= info
->socket1
;
198 int socket2
= info
->socket2
;
199 int nfds
= socket1
> socket2
? socket1
+ 1 : socket2
+ 1;
207 if (buffer1
.CanRead())
208 FD_SET(socket1
, &read_fds
);
209 if (buffer2
.CanRead())
210 FD_SET(socket2
, &read_fds
);
213 if (buffer1
.CanWrite())
214 FD_SET(socket2
, &write_fds
);
215 if (buffer2
.CanWrite())
216 FD_SET(socket1
, &write_fds
);
218 if (HANDLE_EINTR(select(nfds
, &read_fds
, &write_fds
, NULL
, NULL
)) <= 0) {
219 LOG(ERROR
) << "Select error: " << strerror(errno
);
223 int now
= time(NULL
);
224 if (FD_ISSET(socket1
, &read_fds
)) {
225 info
->socket1_last_byte_time
= now
;
226 int bytes
= buffer1
.Read(socket1
);
229 info
->socket1_bytes
+= bytes
;
231 if (FD_ISSET(socket2
, &read_fds
)) {
232 info
->socket2_last_byte_time
= now
;
233 int bytes
= buffer2
.Read(socket2
);
236 info
->socket2_bytes
+= bytes
;
238 if (FD_ISSET(socket1
, &write_fds
)) {
239 if (buffer2
.Write(socket1
) <= 0)
242 if (FD_ISSET(socket2
, &write_fds
)) {
243 if (buffer1
.Write(socket2
) <= 0)
248 CloseSocket(socket1
);
249 CloseSocket(socket2
);
250 server
->DisposeForwarderInfo(index
);
254 // Listens to a server socket. On incoming request, forward it to the host.
256 void* Server::ServerThread(void* arg
) {
257 Server
* server
= reinterpret_cast<Server
*>(arg
);
259 int forwarder_index
= server
->GetFreeForwarderIndex();
260 if (forwarder_index
< 0) {
261 LOG(ERROR
) << "Too many forwarders";
265 struct sockaddr_in addr
;
266 socklen_t addr_len
= sizeof(addr
);
267 int socket
= HANDLE_EINTR(accept(server
->socket_
,
268 reinterpret_cast<sockaddr
*>(&addr
),
271 LOG(ERROR
) << "Failed to accept: " << strerror(errno
);
274 tools::DisableNagle(socket
);
276 int host_socket
= tools::ConnectAdbHostSocket(server
->forward_to_
);
277 if (host_socket
>= 0) {
278 // Set NONBLOCK flag because we use select().
279 fcntl(socket
, F_SETFL
, fcntl(socket
, F_GETFL
) | O_NONBLOCK
);
280 fcntl(host_socket
, F_SETFL
, fcntl(host_socket
, F_GETFL
) | O_NONBLOCK
);
282 ForwarderInfo
* forwarder_info
= server
->GetForwarderInfo(forwarder_index
);
283 time_t now
= time(NULL
);
284 forwarder_info
->start_time
= now
;
285 forwarder_info
->socket1
= socket
;
286 forwarder_info
->socket1_last_byte_time
= now
;
287 forwarder_info
->socket1_bytes
= 0;
288 forwarder_info
->socket2
= host_socket
;
289 forwarder_info
->socket2_last_byte_time
= now
;
290 forwarder_info
->socket2_bytes
= 0;
293 pthread_create(&thread
, NULL
, ForwarderThread
,
294 new ForwarderThreadInfo(server
, forwarder_index
));
296 // Close the unused client socket which is failed to connect to host.
301 CloseSocket(server
->socket_
);
302 server
->socket_
= -1;
306 // Format of arg: <Device port>[:<Forward to port>:<Forward to address>]
307 bool Server::InitSocket(const char* arg
) {
309 int local_port
= static_cast<int>(strtol(arg
, &endptr
, 10));
313 if (*endptr
!= ':') {
314 snprintf(forward_to_
, sizeof(forward_to_
), "%d:127.0.0.1", local_port
);
316 strncpy(forward_to_
, endptr
+ 1, sizeof(forward_to_
) - 1);
319 socket_
= socket(AF_INET
, SOCK_STREAM
, 0);
321 perror("server socket");
324 tools::DisableNagle(socket_
);
327 memset(&addr
, 0, sizeof(addr
));
328 addr
.sin_family
= AF_INET
;
329 addr
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
330 addr
.sin_port
= htons(local_port
);
332 setsockopt(socket_
, SOL_SOCKET
, SO_REUSEADDR
,
333 &reuse_addr
, sizeof(reuse_addr
));
334 tools::DeferAccept(socket_
);
335 if (HANDLE_EINTR(bind(socket_
, reinterpret_cast<sockaddr
*>(&addr
),
336 sizeof(addr
))) < 0 ||
337 HANDLE_EINTR(listen(socket_
, 5)) < 0) {
338 perror("server bind");
339 CloseSocket(socket_
);
344 if (local_port
== 0) {
345 socklen_t addrlen
= sizeof(addr
);
346 if (getsockname(socket_
, reinterpret_cast<sockaddr
*>(&addr
), &addrlen
)
348 perror("get listen address");
349 CloseSocket(socket_
);
353 local_port
= ntohs(addr
.sin_port
);
356 printf("Forwarding device port %d to host %s\n", local_port
, forward_to_
);
360 int g_server_count
= 0;
361 Server
* g_servers
= NULL
;
363 void KillHandler(int unused
) {
365 for (int i
= 0; i
< g_server_count
; i
++)
366 g_servers
[i
].Shutdown();
369 void DumpInformation(int unused
) {
370 for (int i
= 0; i
< g_server_count
; i
++)
371 g_servers
[i
].DumpInformation();
376 int main(int argc
, char** argv
) {
377 printf("Android device to host TCP forwarder\n");
378 printf("Like 'adb forward' but in the reverse direction\n");
380 CommandLine
command_line(argc
, argv
);
381 CommandLine::StringVector server_args
= command_line
.GetArgs();
382 if (tools::HasHelpSwitch(command_line
) || server_args
.empty()) {
385 "<Device port>[:<Forward to port>:<Forward to address>] ...",
386 " <Forward to port> default is <Device port>\n"
387 " <Forward to address> default is 127.0.0.1\n"
388 "If <Device port> is 0, a port will by dynamically allocated.\n");
392 g_servers
= new Server
[server_args
.size()];
394 int failed_count
= 0;
395 for (size_t i
= 0; i
< server_args
.size(); i
++) {
396 if (!g_servers
[g_server_count
].InitSocket(server_args
[i
].c_str())) {
397 printf("Couldn't start forwarder server for port spec: %s\n",
398 server_args
[i
].c_str());
405 if (g_server_count
== 0) {
406 printf("No forwarder servers could be started. Exiting.\n");
411 if (!tools::HasNoSpawnDaemonSwitch(command_line
))
412 tools::SpawnDaemon(failed_count
);
414 signal(SIGTERM
, KillHandler
);
415 signal(SIGUSR2
, DumpInformation
);
417 for (int i
= 0; i
< g_server_count
; i
++)
418 g_servers
[i
].StartThread();
419 for (int i
= 0; i
< g_server_count
; i
++)
420 g_servers
[i
].JoinThread();