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_listener.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/callback.h"
10#include "base/logging.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/message_loop/message_loop_proxy.h"
13#include "base/single_thread_task_runner.h"
14#include "tools/android/forwarder2/command.h"
15#include "tools/android/forwarder2/forwarder.h"
16#include "tools/android/forwarder2/socket.h"
17
18namespace forwarder2 {
19
20// static
21scoped_ptr<DeviceListener> DeviceListener::Create(
22    scoped_ptr<Socket> host_socket,
23    int listener_port,
24    const ErrorCallback& error_callback) {
25  scoped_ptr<Socket> listener_socket(new Socket());
26  scoped_ptr<DeviceListener> device_listener;
27  if (!listener_socket->BindTcp("", listener_port)) {
28    LOG(ERROR) << "Device could not bind and listen to local port "
29               << listener_port;
30    SendCommand(command::BIND_ERROR, listener_port, host_socket.get());
31    return device_listener.Pass();
32  }
33  // In case the |listener_port_| was zero, GetPort() will return the
34  // currently (non-zero) allocated port for this socket.
35  listener_port = listener_socket->GetPort();
36  SendCommand(command::BIND_SUCCESS, listener_port, host_socket.get());
37  device_listener.reset(
38      new DeviceListener(listener_socket.Pass(), host_socket.Pass(),
39                         listener_port, error_callback));
40  return device_listener.Pass();
41}
42
43DeviceListener::~DeviceListener() {
44  DCHECK(deletion_task_runner_->RunsTasksOnCurrentThread());
45  deletion_notifier_.Notify();
46}
47
48void DeviceListener::Start() {
49  thread_.Start();
50  AcceptNextClientSoon();
51}
52
53void DeviceListener::SetAdbDataSocket(scoped_ptr<Socket> adb_data_socket) {
54  thread_.message_loop_proxy()->PostTask(
55      FROM_HERE,
56      base::Bind(&DeviceListener::OnAdbDataSocketReceivedOnInternalThread,
57                 base::Unretained(this), base::Passed(&adb_data_socket)));
58}
59
60DeviceListener::DeviceListener(scoped_ptr<Socket> listener_socket,
61                               scoped_ptr<Socket> host_socket,
62                               int port,
63                               const ErrorCallback& error_callback)
64    : self_deleter_helper_(this, error_callback),
65      listener_socket_(listener_socket.Pass()),
66      host_socket_(host_socket.Pass()),
67      listener_port_(port),
68      deletion_task_runner_(base::MessageLoopProxy::current()),
69      thread_("DeviceListener") {
70  CHECK(host_socket_.get());
71  DCHECK(deletion_task_runner_.get());
72  host_socket_->AddEventFd(deletion_notifier_.receiver_fd());
73  listener_socket_->AddEventFd(deletion_notifier_.receiver_fd());
74}
75
76void DeviceListener::AcceptNextClientSoon() {
77  thread_.message_loop_proxy()->PostTask(
78      FROM_HERE,
79      base::Bind(&DeviceListener::AcceptClientOnInternalThread,
80                 base::Unretained(this)));
81}
82
83void DeviceListener::AcceptClientOnInternalThread() {
84  device_data_socket_.reset(new Socket());
85  if (!listener_socket_->Accept(device_data_socket_.get())) {
86    if (listener_socket_->DidReceiveEvent()) {
87      LOG(INFO) << "Received exit notification, stopped accepting clients.";
88      OnInternalThreadError();
89      return;
90    }
91    LOG(WARNING) << "Could not Accept in ListenerSocket.";
92    SendCommand(command::ACCEPT_ERROR, listener_port_, host_socket_.get());
93    OnInternalThreadError();
94    return;
95  }
96  SendCommand(command::ACCEPT_SUCCESS, listener_port_, host_socket_.get());
97  if (!ReceivedCommand(command::HOST_SERVER_SUCCESS,
98                       host_socket_.get())) {
99    SendCommand(command::ACK, listener_port_, host_socket_.get());
100    LOG(ERROR) << "Host could not connect to server.";
101    device_data_socket_->Close();
102    if (host_socket_->has_error()) {
103      LOG(ERROR) << "Adb Control connection lost. "
104                 << "Listener port: " << listener_port_;
105      OnInternalThreadError();
106      return;
107    }
108    // It can continue if the host forwarder could not connect to the host
109    // server but the control connection is still alive (no errors). The device
110    // acknowledged that (above), and it can re-try later.
111    AcceptNextClientSoon();
112    return;
113  }
114}
115
116void DeviceListener::OnAdbDataSocketReceivedOnInternalThread(
117    scoped_ptr<Socket> adb_data_socket) {
118  DCHECK(adb_data_socket);
119  SendCommand(command::ADB_DATA_SOCKET_SUCCESS, listener_port_,
120              host_socket_.get());
121  forwarders_manager_.CreateAndStartNewForwarder(
122      device_data_socket_.Pass(), adb_data_socket.Pass());
123  AcceptNextClientSoon();
124}
125
126void DeviceListener::OnInternalThreadError() {
127  self_deleter_helper_.MaybeSelfDeleteSoon();
128}
129
130}  // namespace forwarder
131