Index: tools/android/forwarder2/device_listener.cc |
diff --git a/tools/android/forwarder2/device_listener.cc b/tools/android/forwarder2/device_listener.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..68e90fcea7e0d16ab0010697d7bb71f69e5afeac |
--- /dev/null |
+++ b/tools/android/forwarder2/device_listener.cc |
@@ -0,0 +1,167 @@ |
+// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "tools/android/forwarder2/device_listener.h" |
+ |
+#include <errno.h> |
+#include <signal.h> |
+#include <stdio.h> |
+#include <stdlib.h> |
+ |
+#include <string> |
+ |
+#include "base/logging.h" |
+#include "base/memory/scoped_ptr.h" |
+#include "tools/android/forwarder2/command.h" |
+#include "tools/android/forwarder2/forwarder.h" |
+#include "tools/android/forwarder2/socket.h" |
+ |
+namespace { |
+// Timeout for the Listener to be waiting for a new Adb Data Connection. |
+const int kDeviceListenerTimeoutSeconds = 10; |
+} |
+ |
+namespace forwarder { |
+ |
+DeviceListener::~DeviceListener() { |
+ CHECK(!is_alive()); |
+ adb_control_socket_->Close(); |
+ listener_socket_.Close(); |
+} |
+ |
+DeviceListener::DeviceListener(scoped_ptr<Socket> adb_control_socket, int port) |
+ : adb_control_socket_(adb_control_socket.Pass()), |
+ listener_port_(port), |
+ is_alive_(true), |
+ must_exit_(false) { |
+ CHECK(adb_control_socket_.get()); |
+ adb_control_socket_->set_notifier_fd(exit_notifier_.receiver_fd()); |
+ listener_socket_.set_notifier_fd(exit_notifier_.receiver_fd()); |
+ pthread_mutex_init(&adb_data_socket_mutex_, NULL); |
+ pthread_cond_init(&adb_data_socket_cond_, NULL); |
+} |
+ |
+void DeviceListener::SetMustExitLocked() { |
+ must_exit_ = true; |
+ exit_notifier_.Notify(); |
+} |
+ |
+void DeviceListener::ForceExit() { |
+ // Set must_exit and wake up the threads waiting. |
+ pthread_mutex_lock(&adb_data_socket_mutex_); |
+ SetMustExitLocked(); |
+ pthread_cond_broadcast(&adb_data_socket_cond_); |
+ pthread_mutex_unlock(&adb_data_socket_mutex_); |
+} |
+ |
+bool DeviceListener::WaitForAdbDataSocket() { |
+ timespec time_to_wait; |
+ memset(&time_to_wait, 0, sizeof(time_to_wait)); |
+ time_to_wait.tv_sec = time(NULL) + kDeviceListenerTimeoutSeconds; |
+ |
+ pthread_mutex_lock(&adb_data_socket_mutex_); |
+ int ret = 0; |
+ while (!must_exit_ && adb_data_socket_.get() == NULL && ret == 0) { |
+ ret = pthread_cond_timedwait(&adb_data_socket_cond_, |
+ &adb_data_socket_mutex_, |
+ &time_to_wait); |
+ if (ret != 0) { |
+ if (adb_data_socket_.get()) { |
+ adb_data_socket_->Close(); |
+ adb_data_socket_.reset(NULL); |
+ } |
+ LOG(ERROR) << "Error while waiting for Adb Data Socket."; |
+ SetMustExitLocked(); |
+ } |
+ } |
+ pthread_mutex_unlock(&adb_data_socket_mutex_); |
+ if (ret == ETIMEDOUT) { |
+ LOG(ERROR) << "DeviceListener timeout while waiting for " |
+ << "the Adb Data Socket for port: " << listener_port_; |
+ } |
+ // Check both return value and also if set_must_exit() was called. |
+ return ret == 0 && !must_exit_ && adb_data_socket_.get(); |
+} |
+ |
+bool DeviceListener::SetAdbDataSocket(scoped_ptr<Socket> adb_data_socket) { |
+ CHECK(adb_data_socket.get()); |
+ pthread_mutex_lock(&adb_data_socket_mutex_); |
+ adb_data_socket_.swap(adb_data_socket); |
+ int ret = pthread_cond_broadcast(&adb_data_socket_cond_); |
+ if (ret != 0) { |
+ SetMustExitLocked(); |
+ } |
+ if (must_exit_ && adb_data_socket_.get()) { |
+ adb_data_socket_->Close(); |
+ adb_data_socket_.reset(NULL); |
+ } |
+ pthread_mutex_unlock(&adb_data_socket_mutex_); |
+ return ret == 0; |
+} |
+ |
+void DeviceListener::Run() { |
+ if (listener_socket_.BindTcp("", listener_port_)) { |
+ SendCommand(command::BIND_SUCCESS, |
+ listener_port_, |
+ adb_control_socket_.get()); |
+ while (!must_exit_) { |
+ scoped_ptr<Socket> device_data_socket(new Socket); |
+ if (!listener_socket_.Accept(device_data_socket.get())) { |
+ LOG(WARNING) << "Could not Accept in ListenerSocket."; |
+ SendCommand(command::ACCEPT_ERROR, |
+ listener_port_, |
+ adb_control_socket_.get()); |
+ break; |
+ } |
+ SendCommand(command::ACCEPT_SUCCESS, |
+ listener_port_, |
+ adb_control_socket_.get()); |
+ if (!ReceivedCommand(command::HOST_SERVER_SUCCESS, |
+ adb_control_socket_.get())) { |
+ SendCommand(command::ACK, listener_port_, adb_control_socket_.get()); |
+ LOG(ERROR) << "Host could not connect to server."; |
+ device_data_socket->Close(); |
+ if (adb_control_socket_->HasError()) { |
+ LOG(ERROR) << "Adb Control connection lost. " |
+ << "Listener port: " << listener_port_; |
+ break; |
+ } |
+ // It can continue if the host forwarder could not connect to the host |
+ // server but the control connection is still alive (no errors). The |
+ // device acknowledged that (above), and it can re-try later. |
+ continue; |
+ } |
+ if (!WaitForAdbDataSocket()) { |
+ LOG(ERROR) << "Device could not receive an Adb Data connection."; |
+ SendCommand(command::ADB_DATA_SOCKET_ERROR, |
+ listener_port_, |
+ adb_control_socket_.get()); |
+ device_data_socket->Close(); |
+ continue; |
+ } |
+ SendCommand(command::ADB_DATA_SOCKET_SUCCESS, |
+ listener_port_, |
+ adb_control_socket_.get()); |
+ CHECK(adb_data_socket_.get()); |
+ // Forwarder object will self delete after returning from the Run() call. |
+ Forwarder* forwarder = new Forwarder(device_data_socket.Pass(), |
+ adb_data_socket_.Pass()); |
+ forwarder->Start(); |
+ } |
+ } else { |
+ LOG(ERROR) << "Device could not bind and listen to local port."; |
+ SendCommand(command::BIND_ERROR, |
+ listener_port_, |
+ adb_control_socket_.get()); |
+ } |
+ |
+ adb_control_socket_->Close(); |
+ listener_socket_.Close(); |
+ // This must be the last statement of the Run() method of the DeviceListener |
+ // class, since the main thread checks if this thread is dead and deletes |
+ // the object. It will be a race condition otherwise. |
+ is_alive_ = false; |
+} |
+ |
+} // namespace forwarder |