1// Copyright (c) 2009 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 "chrome/browser/debugger/devtools_protocol_handler.h"
6
7#include "base/logging.h"
8#include "chrome/browser/debugger/inspectable_tab_proxy.h"
9#include "chrome/browser/debugger/debugger_remote_service.h"
10#include "chrome/browser/debugger/devtools_remote_message.h"
11#include "chrome/browser/debugger/devtools_remote_listen_socket.h"
12#include "chrome/browser/debugger/devtools_remote_service.h"
13#include "chrome/browser/debugger/extension_ports_remote_service.h"
14#include "content/browser/browser_thread.h"
15
16// static
17scoped_refptr<DevToolsProtocolHandler> DevToolsProtocolHandler::Start(
18    int port) {
19  scoped_refptr<DevToolsProtocolHandler> proto_handler =
20      new DevToolsProtocolHandler(port);
21  proto_handler->RegisterDestination(
22      new DevToolsRemoteService(proto_handler),
23      DevToolsRemoteService::kToolName);
24  proto_handler->RegisterDestination(
25      new DebuggerRemoteService(proto_handler),
26      DebuggerRemoteService::kToolName);
27  proto_handler->RegisterDestination(
28      new ExtensionPortsRemoteService(proto_handler),
29      ExtensionPortsRemoteService::kToolName);
30  proto_handler->Start();
31  return proto_handler;
32}
33
34DevToolsProtocolHandler::DevToolsProtocolHandler(int port)
35    : port_(port),
36      connection_(NULL),
37      server_(NULL) {
38  inspectable_tab_proxy_.reset(new InspectableTabProxy);
39}
40
41DevToolsProtocolHandler::~DevToolsProtocolHandler() {
42  // Stop() must be called prior to this being called
43  DCHECK(server_.get() == NULL);
44  DCHECK(connection_.get() == NULL);
45}
46
47void DevToolsProtocolHandler::Start() {
48  BrowserThread::PostTask(
49      BrowserThread::IO, FROM_HERE,
50      NewRunnableMethod(this, &DevToolsProtocolHandler::Init));
51}
52
53void DevToolsProtocolHandler::Init() {
54  server_ = DevToolsRemoteListenSocket::Listen(
55      "127.0.0.1", port_, this);
56}
57
58void DevToolsProtocolHandler::Stop() {
59  BrowserThread::PostTask(
60      BrowserThread::IO, FROM_HERE,
61      NewRunnableMethod(this, &DevToolsProtocolHandler::Teardown));
62  tool_to_listener_map_.clear();  // Releases all scoped_refptr's to listeners
63}
64
65// Run in I/O thread
66void DevToolsProtocolHandler::Teardown() {
67  connection_ = NULL;
68  server_ = NULL;
69}
70
71void DevToolsProtocolHandler::RegisterDestination(
72    DevToolsRemoteListener* listener,
73    const std::string& tool_name) {
74  DCHECK(tool_to_listener_map_.find(tool_name) == tool_to_listener_map_.end());
75  tool_to_listener_map_.insert(std::make_pair(tool_name, listener));
76}
77
78void DevToolsProtocolHandler::UnregisterDestination(
79    DevToolsRemoteListener* listener,
80    const std::string& tool_name) {
81  DCHECK(tool_to_listener_map_.find(tool_name) != tool_to_listener_map_.end());
82  DCHECK(tool_to_listener_map_.find(tool_name)->second == listener);
83  tool_to_listener_map_.erase(tool_name);
84}
85
86void DevToolsProtocolHandler::HandleMessage(
87    const DevToolsRemoteMessage& message) {
88  std::string tool = message.GetHeaderWithEmptyDefault(
89      DevToolsRemoteMessageHeaders::kTool);
90  ToolToListenerMap::const_iterator it = tool_to_listener_map_.find(tool);
91  if (it == tool_to_listener_map_.end()) {
92    NOTREACHED();  // an unsupported tool, bail out
93    return;
94  }
95  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
96  BrowserThread::PostTask(
97      BrowserThread::UI, FROM_HERE,
98      NewRunnableMethod(
99          it->second.get(), &DevToolsRemoteListener::HandleMessage, message));
100}
101
102void DevToolsProtocolHandler::Send(const DevToolsRemoteMessage& message) {
103  if (connection_ != NULL) {
104    connection_->Send(message.ToString());
105  }
106}
107
108void DevToolsProtocolHandler::OnAcceptConnection(ListenSocket *connection) {
109  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
110  connection_ = connection;
111}
112
113void DevToolsProtocolHandler::OnConnectionLost() {
114  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
115  connection_ = NULL;
116  for (ToolToListenerMap::const_iterator it = tool_to_listener_map_.begin(),
117       end = tool_to_listener_map_.end();
118       it != end;
119       ++it) {
120    BrowserThread::PostTask(
121      BrowserThread::UI, FROM_HERE,
122      NewRunnableMethod(
123          it->second.get(), &DevToolsRemoteListener::OnConnectionLost));
124  }
125}
126