15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h>
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <fcntl.h>
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <netinet/in.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <netinet/tcp.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <pthread.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <signal.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/select.h>
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/socket.h>
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/wait.h>
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unistd.h>
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/posix/eintr_wrapper.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "tools/android/common/adb_connection.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "tools/android/common/daemon.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "tools/android/common/net.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const pthread_t kInvalidThread = static_cast<pthread_t>(-1);
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)volatile bool g_killed = false;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloseSocket(int fd) {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (fd >= 0) {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int old_errno = errno;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (void) HANDLE_EINTR(close(fd));
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    errno = old_errno;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Buffer {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Buffer()
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : bytes_read_(0),
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        write_offset_(0) {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool CanRead() {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return bytes_read_ == 0;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool CanWrite() {
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return write_offset_ < bytes_read_;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int Read(int fd) {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int ret = -1;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (CanRead()) {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret = HANDLE_EINTR(read(fd, buffer_, kBufferSize));
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (ret > 0)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        bytes_read_ = ret;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ret;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int Write(int fd) {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int ret = -1;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (CanWrite()) {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ret = HANDLE_EINTR(write(fd, buffer_ + write_offset_,
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               bytes_read_ - write_offset_));
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (ret > 0) {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        write_offset_ += ret;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (write_offset_ == bytes_read_) {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          write_offset_ = 0;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          bytes_read_ = 0;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ret;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // A big buffer to let our file-over-http bridge work more like real file.
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const int kBufferSize = 1024 * 128;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int bytes_read_;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int write_offset_;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char buffer_[kBufferSize];
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(Buffer);
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Server;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct ForwarderThreadInfo {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ForwarderThreadInfo(Server* a_server, int a_forwarder_index)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : server(a_server),
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        forwarder_index(a_forwarder_index) {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Server* server;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int forwarder_index;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct ForwarderInfo {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  time_t start_time;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int socket1;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  time_t socket1_last_byte_time;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t socket1_bytes;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int socket2;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  time_t socket2_last_byte_time;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t socket2_bytes;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Server {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Server()
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : thread_(kInvalidThread),
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        socket_(-1) {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memset(forward_to_, 0, sizeof(forward_to_));
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memset(&forwarders_, 0, sizeof(forwarders_));
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int GetFreeForwarderIndex() {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; i < kMaxForwarders; i++) {
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (forwarders_[i].start_time == 0)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return i;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DisposeForwarderInfo(int index) {
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    forwarders_[index].start_time = 0;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ForwarderInfo* GetForwarderInfo(int index) {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return &forwarders_[index];
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DumpInformation() {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(INFO) << "Server information: " << forward_to_;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(INFO) << "No.: age up(bytes,idle) down(bytes,idle)";
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int count = 0;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    time_t now = time(NULL);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int i = 0; i < kMaxForwarders; i++) {
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const ForwarderInfo& info = forwarders_[i];
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (info.start_time) {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        count++;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(INFO) << count << ": " << now - info.start_time << " up("
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  << info.socket1_bytes << ","
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  << now - info.socket1_last_byte_time << " down("
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  << info.socket2_bytes << ","
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  << now - info.socket2_last_byte_time << ")";
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Shutdown() {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (socket_ >= 0)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shutdown(socket_, SHUT_RDWR);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool InitSocket(const char* arg);
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void StartThread() {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pthread_create(&thread_, NULL, ServerThread, this);
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void JoinThread() {
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (thread_ != kInvalidThread)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pthread_join(thread_, NULL);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void* ServerThread(void* arg);
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // There are 3 kinds of threads that will access the array:
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 1. Server thread will get a free ForwarderInfo and initialize it;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 2. Forwarder threads will dispose the ForwarderInfo when it finishes;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 3. Main thread will iterate and print the forwarders.
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Using an array is not optimal, but can avoid locks or other complex
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // inter-thread communication.
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const int kMaxForwarders = 512;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ForwarderInfo forwarders_[kMaxForwarders];
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pthread_t thread_;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int socket_;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char forward_to_[40];
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(Server);
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Forwards all outputs from one socket to another socket.
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* ForwarderThread(void* arg) {
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ForwarderThreadInfo* thread_info =
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<ForwarderThreadInfo*>(arg);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Server* server = thread_info->server;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int index = thread_info->forwarder_index;
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delete thread_info;
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ForwarderInfo* info = server->GetForwarderInfo(index);
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int socket1 = info->socket1;
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int socket2 = info->socket2;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nfds = socket1 > socket2 ? socket1 + 1 : socket2 + 1;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fd_set read_fds;
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fd_set write_fds;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Buffer buffer1;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Buffer buffer2;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (!g_killed) {
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FD_ZERO(&read_fds);
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (buffer1.CanRead())
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FD_SET(socket1, &read_fds);
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (buffer2.CanRead())
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FD_SET(socket2, &read_fds);
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FD_ZERO(&write_fds);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (buffer1.CanWrite())
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FD_SET(socket2, &write_fds);
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (buffer2.CanWrite())
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FD_SET(socket1, &write_fds);
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (HANDLE_EINTR(select(nfds, &read_fds, &write_fds, NULL, NULL)) <= 0) {
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Select error: " << strerror(errno);
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int now = time(NULL);
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (FD_ISSET(socket1, &read_fds)) {
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      info->socket1_last_byte_time = now;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int bytes = buffer1.Read(socket1);
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (bytes <= 0)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      info->socket1_bytes += bytes;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (FD_ISSET(socket2, &read_fds)) {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      info->socket2_last_byte_time = now;
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int bytes = buffer2.Read(socket2);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (bytes <= 0)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      info->socket2_bytes += bytes;
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (FD_ISSET(socket1, &write_fds)) {
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (buffer2.Write(socket1) <= 0)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (FD_ISSET(socket2, &write_fds)) {
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (buffer1.Write(socket2) <= 0)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseSocket(socket1);
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseSocket(socket2);
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  server->DisposeForwarderInfo(index);
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Listens to a server socket. On incoming request, forward it to the host.
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* Server::ServerThread(void* arg) {
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Server* server = reinterpret_cast<Server*>(arg);
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (!g_killed) {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int forwarder_index = server->GetFreeForwarderIndex();
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (forwarder_index < 0) {
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Too many forwarders";
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct sockaddr_in addr;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    socklen_t addr_len = sizeof(addr);
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int socket = HANDLE_EINTR(accept(server->socket_,
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     reinterpret_cast<sockaddr*>(&addr),
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     &addr_len));
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (socket < 0) {
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Failed to accept: " << strerror(errno);
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tools::DisableNagle(socket);
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int host_socket = tools::ConnectAdbHostSocket(server->forward_to_);
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (host_socket >= 0) {
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Set NONBLOCK flag because we use select().
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) | O_NONBLOCK);
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      fcntl(host_socket, F_SETFL, fcntl(host_socket, F_GETFL) | O_NONBLOCK);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ForwarderInfo* forwarder_info = server->GetForwarderInfo(forwarder_index);
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      time_t now = time(NULL);
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      forwarder_info->start_time = now;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      forwarder_info->socket1 = socket;
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      forwarder_info->socket1_last_byte_time = now;
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      forwarder_info->socket1_bytes = 0;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      forwarder_info->socket2 = host_socket;
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      forwarder_info->socket2_last_byte_time = now;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      forwarder_info->socket2_bytes = 0;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pthread_t thread;
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pthread_create(&thread, NULL, ForwarderThread,
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     new ForwarderThreadInfo(server, forwarder_index));
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Close the unused client socket which is failed to connect to host.
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CloseSocket(socket);
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseSocket(server->socket_);
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  server->socket_ = -1;
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Format of arg: <Device port>[:<Forward to port>:<Forward to address>]
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Server::InitSocket(const char* arg) {
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char* endptr;
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int local_port = static_cast<int>(strtol(arg, &endptr, 10));
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (local_port < 0)
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (*endptr != ':') {
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    snprintf(forward_to_, sizeof(forward_to_), "%d:127.0.0.1", local_port);
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    strncpy(forward_to_, endptr + 1, sizeof(forward_to_) - 1);
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  socket_ = socket(AF_INET, SOCK_STREAM, 0);
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (socket_ < 0) {
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    perror("server socket");
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tools::DisableNagle(socket_);
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sockaddr_in addr;
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(&addr, 0, sizeof(addr));
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  addr.sin_family = AF_INET;
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  addr.sin_port = htons(local_port);
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int reuse_addr = 1;
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR,
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             &reuse_addr, sizeof(reuse_addr));
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tools::DeferAccept(socket_);
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (HANDLE_EINTR(bind(socket_, reinterpret_cast<sockaddr*>(&addr),
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        sizeof(addr))) < 0 ||
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      HANDLE_EINTR(listen(socket_, 5)) < 0) {
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    perror("server bind");
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CloseSocket(socket_);
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    socket_ = -1;
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (local_port == 0) {
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    socklen_t addrlen = sizeof(addr);
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (getsockname(socket_, reinterpret_cast<sockaddr*>(&addr), &addrlen)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        != 0) {
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      perror("get listen address");
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CloseSocket(socket_);
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      socket_ = -1;
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    local_port = ntohs(addr.sin_port);
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  printf("Forwarding device port %d to host %s\n", local_port, forward_to_);
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int g_server_count = 0;
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Server* g_servers = NULL;
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void KillHandler(int unused) {
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_killed = true;
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < g_server_count; i++)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_servers[i].Shutdown();
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DumpInformation(int unused) {
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < g_server_count; i++)
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_servers[i].DumpInformation();
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int main(int argc, char** argv) {
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  printf("Android device to host TCP forwarder\n");
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  printf("Like 'adb forward' but in the reverse direction\n");
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandLine command_line(argc, argv);
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandLine::StringVector server_args = command_line.GetArgs();
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (tools::HasHelpSwitch(command_line) || server_args.empty()) {
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tools::ShowHelp(
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        argv[0],
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "<Device port>[:<Forward to port>:<Forward to address>] ...",
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "  <Forward to port> default is <Device port>\n"
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "  <Forward to address> default is 127.0.0.1\n"
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "If <Device port> is 0, a port will by dynamically allocated.\n");
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_servers = new Server[server_args.size()];
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_server_count = 0;
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int failed_count = 0;
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < server_args.size(); i++) {
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!g_servers[g_server_count].InitSocket(server_args[i].c_str())) {
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      printf("Couldn't start forwarder server for port spec: %s\n",
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             server_args[i].c_str());
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++failed_count;
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++g_server_count;
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (g_server_count == 0) {
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    printf("No forwarder servers could be started. Exiting.\n");
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete [] g_servers;
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return failed_count;
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!tools::HasNoSpawnDaemonSwitch(command_line))
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tools::SpawnDaemon(failed_count);
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signal(SIGTERM, KillHandler);
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  signal(SIGUSR2, DumpInformation);
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < g_server_count; i++)
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_servers[i].StartThread();
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < g_server_count; i++)
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_servers[i].JoinThread();
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_server_count = 0;
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delete [] g_servers;
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
427