Home | History | Annotate | Download | only in forwarder2
      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 "tools/android/forwarder2/device_controller.h"
      6 
      7 #include <utility>
      8 
      9 #include "base/basictypes.h"
     10 #include "base/bind.h"
     11 #include "base/callback_helpers.h"
     12 #include "base/logging.h"
     13 #include "base/memory/scoped_ptr.h"
     14 #include "base/message_loop/message_loop_proxy.h"
     15 #include "base/single_thread_task_runner.h"
     16 #include "tools/android/forwarder2/command.h"
     17 #include "tools/android/forwarder2/device_listener.h"
     18 #include "tools/android/forwarder2/socket.h"
     19 #include "tools/android/forwarder2/util.h"
     20 
     21 namespace forwarder2 {
     22 
     23 // static
     24 scoped_ptr<DeviceController> DeviceController::Create(
     25     const std::string& adb_unix_socket,
     26     int exit_notifier_fd) {
     27   scoped_ptr<DeviceController> device_controller;
     28   scoped_ptr<Socket> host_socket(new Socket());
     29   if (!host_socket->BindUnix(adb_unix_socket)) {
     30     PLOG(ERROR) << "Could not BindAndListen DeviceController socket on port "
     31                 << adb_unix_socket << ": ";
     32     return device_controller.Pass();
     33   }
     34   LOG(INFO) << "Listening on Unix Domain Socket " << adb_unix_socket;
     35   device_controller.reset(
     36       new DeviceController(host_socket.Pass(), exit_notifier_fd));
     37   return device_controller.Pass();
     38 }
     39 
     40 DeviceController::~DeviceController() {
     41   DCHECK(construction_task_runner_->RunsTasksOnCurrentThread());
     42 }
     43 
     44 void DeviceController::Start() {
     45   AcceptHostCommandSoon();
     46 }
     47 
     48 DeviceController::DeviceController(scoped_ptr<Socket> host_socket,
     49                                    int exit_notifier_fd)
     50     : weak_ptr_factory_(this),
     51       host_socket_(host_socket.Pass()),
     52       exit_notifier_fd_(exit_notifier_fd),
     53       construction_task_runner_(base::MessageLoopProxy::current()) {
     54   host_socket_->AddEventFd(exit_notifier_fd);
     55 }
     56 
     57 void DeviceController::AcceptHostCommandSoon() {
     58   base::MessageLoopProxy::current()->PostTask(
     59       FROM_HERE,
     60       base::Bind(&DeviceController::AcceptHostCommandInternal,
     61                  base::Unretained(this)));
     62 }
     63 
     64 void DeviceController::AcceptHostCommandInternal() {
     65   scoped_ptr<Socket> socket(new Socket);
     66   if (!host_socket_->Accept(socket.get())) {
     67     if (!host_socket_->DidReceiveEvent())
     68       PLOG(ERROR) << "Could not Accept DeviceController socket";
     69     else
     70       LOG(INFO) << "Received exit notification";
     71     return;
     72   }
     73   base::ScopedClosureRunner accept_next_client(
     74       base::Bind(&DeviceController::AcceptHostCommandSoon,
     75                  base::Unretained(this)));
     76   // So that |socket| doesn't block on read if it has notifications.
     77   socket->AddEventFd(exit_notifier_fd_);
     78   int port;
     79   command::Type command;
     80   if (!ReadCommand(socket.get(), &port, &command)) {
     81     LOG(ERROR) << "Invalid command received.";
     82     return;
     83   }
     84   const ListenersMap::iterator listener_it = listeners_.find(port);
     85   DeviceListener* const listener = listener_it == listeners_.end()
     86       ? static_cast<DeviceListener*>(NULL) : listener_it->second.get();
     87   switch (command) {
     88     case command::LISTEN: {
     89       if (listener != NULL) {
     90         LOG(WARNING) << "Already forwarding port " << port
     91                      << ". Attempting to restart the listener.\n";
     92         DeleteRefCountedValueInMapFromIterator(listener_it, &listeners_);
     93       }
     94       scoped_ptr<DeviceListener> new_listener(
     95           DeviceListener::Create(
     96               socket.Pass(), port,
     97               base::Bind(&DeviceController::DeleteListenerOnError,
     98                          weak_ptr_factory_.GetWeakPtr())));
     99       if (!new_listener)
    100         return;
    101       new_listener->Start();
    102       // |port| can be zero, to allow dynamically allocated port, so instead, we
    103       // call DeviceListener::listener_port() to retrieve the currently
    104       // allocated port to this new listener.
    105       const int listener_port = new_listener->listener_port();
    106       listeners_.insert(
    107           std::make_pair(listener_port,
    108                          linked_ptr<DeviceListener>(new_listener.release())));
    109       LOG(INFO) << "Forwarding device port " << listener_port << " to host.";
    110       break;
    111     }
    112     case command::DATA_CONNECTION:
    113       if (listener == NULL) {
    114         LOG(ERROR) << "Data Connection command received, but "
    115                    << "listener has not been set up yet for port " << port;
    116         // After this point it is assumed that, once we close our Adb Data
    117         // socket, the Adb forwarder command will propagate the closing of
    118         // sockets all the way to the host side.
    119         break;
    120       }
    121       listener->SetAdbDataSocket(socket.Pass());
    122       break;
    123     case command::UNLISTEN:
    124       LOG(INFO) << "Unmapping port " << port;
    125       if (!listener) {
    126         LOG(ERROR) << "No listener found for port " << port;
    127         SendCommand(command::UNLISTEN_ERROR, port, socket.get());
    128         break;
    129       }
    130       DeleteRefCountedValueInMapFromIterator(listener_it, &listeners_);
    131       SendCommand(command::UNLISTEN_SUCCESS, port, socket.get());
    132       break;
    133     default:
    134       // TODO(felipeg): add a KillAllListeners command.
    135       LOG(ERROR) << "Invalid command received. Port: " << port
    136                  << " Command: " << command;
    137   }
    138 }
    139 
    140 // static
    141 void DeviceController::DeleteListenerOnError(
    142       const base::WeakPtr<DeviceController>& device_controller_ptr,
    143       scoped_ptr<DeviceListener> device_listener) {
    144   DeviceListener* const listener = device_listener.release();
    145   DeviceController* const controller = device_controller_ptr.get();
    146   if (!controller) {
    147     // |listener| was already deleted by the controller that did have its
    148     // ownership.
    149     return;
    150   }
    151   DCHECK(controller->construction_task_runner_->RunsTasksOnCurrentThread());
    152   bool listener_did_exist = DeleteRefCountedValueInMap(
    153       listener->listener_port(), &controller->listeners_);
    154   DCHECK(listener_did_exist);
    155   // Note that |listener| was deleted by DeleteRefCountedValueInMap().
    156 }
    157 
    158 }  // namespace forwarder
    159