Change next_proto member type.
[chromium-blink-merge.git] / tools / android / forwarder2 / device_controller.cc
bloba4cb9c75dc37a319eb933cf1de18b6a578163fca
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.
5 #include "tools/android/forwarder2/device_controller.h"
7 #include <utility>
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"
21 namespace forwarder2 {
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();
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();
40 DeviceController::~DeviceController() {
41 DCHECK(construction_task_runner_->RunsTasksOnCurrentThread());
44 void DeviceController::Start() {
45 AcceptHostCommandSoon();
48 DeviceController::DeviceController(scoped_ptr<Socket> host_socket,
49 int exit_notifier_fd)
50 : host_socket_(host_socket.Pass()),
51 exit_notifier_fd_(exit_notifier_fd),
52 construction_task_runner_(base::MessageLoopProxy::current()),
53 weak_ptr_factory_(this) {
54 host_socket_->AddEventFd(exit_notifier_fd);
57 void DeviceController::AcceptHostCommandSoon() {
58 base::MessageLoopProxy::current()->PostTask(
59 FROM_HERE,
60 base::Bind(&DeviceController::AcceptHostCommandInternal,
61 base::Unretained(this)));
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;
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;
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_);
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;
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;
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;
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;
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;
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().
158 } // namespace forwarder