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 "content/browser/renderer_host/p2p/socket_dispatcher_host.h"
6
7#include "base/bind.h"
8#include "base/stl_util.h"
9#include "content/browser/renderer_host/p2p/socket_host.h"
10#include "content/common/p2p_messages.h"
11#include "content/public/browser/resource_context.h"
12#include "net/base/address_list.h"
13#include "net/base/completion_callback.h"
14#include "net/base/net_errors.h"
15#include "net/base/net_log.h"
16#include "net/base/sys_addrinfo.h"
17#include "net/dns/single_request_host_resolver.h"
18#include "net/url_request/url_request_context_getter.h"
19
20using content::BrowserMessageFilter;
21using content::BrowserThread;
22
23namespace content {
24
25const size_t kMaximumPacketSize = 32768;
26
27class P2PSocketDispatcherHost::DnsRequest {
28 public:
29  typedef base::Callback<void(const net::IPAddressNumber&)> DoneCallback;
30
31  DnsRequest(int32 request_id, net::HostResolver* host_resolver)
32      : request_id_(request_id),
33        resolver_(host_resolver) {
34  }
35
36  void Resolve(const std::string& host_name,
37               const DoneCallback& done_callback) {
38    DCHECK(!done_callback.is_null());
39
40    host_name_ = host_name;
41    done_callback_ = done_callback;
42
43    // Return an error if it's an empty string.
44    if (host_name_.empty()) {
45      done_callback_.Run(net::IPAddressNumber());
46      return;
47    }
48
49    // Add period at the end to make sure that we only resolve
50    // fully-qualified names.
51    if (host_name_.at(host_name_.size() - 1) != '.')
52      host_name_ = host_name_ + '.';
53
54    net::HostResolver::RequestInfo info(net::HostPortPair(host_name_, 0));
55    int result = resolver_.Resolve(
56        info,
57        net::DEFAULT_PRIORITY,
58        &addresses_,
59        base::Bind(&P2PSocketDispatcherHost::DnsRequest::OnDone,
60                   base::Unretained(this)),
61        net::BoundNetLog());
62    if (result != net::ERR_IO_PENDING)
63      OnDone(result);
64  }
65
66  int32 request_id() { return request_id_; }
67
68 private:
69  void OnDone(int result) {
70    if (result != net::OK) {
71      LOG(ERROR) << "Failed to resolve address for " << host_name_
72                 << ", errorcode: " << result;
73      done_callback_.Run(net::IPAddressNumber());
74      return;
75    }
76
77    DCHECK(!addresses_.empty());
78    done_callback_.Run(addresses_.front().address());
79  }
80
81  int32 request_id_;
82  net::AddressList addresses_;
83
84  std::string host_name_;
85  net::SingleRequestHostResolver resolver_;
86
87  DoneCallback done_callback_;
88};
89
90P2PSocketDispatcherHost::P2PSocketDispatcherHost(
91    content::ResourceContext* resource_context,
92    net::URLRequestContextGetter* url_context)
93    : resource_context_(resource_context),
94      url_context_(url_context),
95      monitoring_networks_(false) {
96}
97
98void P2PSocketDispatcherHost::OnChannelClosing() {
99  // Since the IPC channel is gone, close pending connections.
100  STLDeleteContainerPairSecondPointers(sockets_.begin(), sockets_.end());
101  sockets_.clear();
102
103  STLDeleteContainerPointers(dns_requests_.begin(), dns_requests_.end());
104  dns_requests_.clear();
105
106  if (monitoring_networks_) {
107    net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
108    monitoring_networks_ = false;
109  }
110}
111
112void P2PSocketDispatcherHost::OnDestruct() const {
113  BrowserThread::DeleteOnIOThread::Destruct(this);
114}
115
116bool P2PSocketDispatcherHost::OnMessageReceived(const IPC::Message& message,
117                                                bool* message_was_ok) {
118  bool handled = true;
119  IPC_BEGIN_MESSAGE_MAP_EX(P2PSocketDispatcherHost, message, *message_was_ok)
120    IPC_MESSAGE_HANDLER(P2PHostMsg_StartNetworkNotifications,
121                        OnStartNetworkNotifications)
122    IPC_MESSAGE_HANDLER(P2PHostMsg_StopNetworkNotifications,
123                        OnStopNetworkNotifications)
124    IPC_MESSAGE_HANDLER(P2PHostMsg_GetHostAddress, OnGetHostAddress)
125    IPC_MESSAGE_HANDLER(P2PHostMsg_CreateSocket, OnCreateSocket)
126    IPC_MESSAGE_HANDLER(P2PHostMsg_AcceptIncomingTcpConnection,
127                        OnAcceptIncomingTcpConnection)
128    IPC_MESSAGE_HANDLER(P2PHostMsg_Send, OnSend)
129    IPC_MESSAGE_HANDLER(P2PHostMsg_DestroySocket, OnDestroySocket)
130    IPC_MESSAGE_UNHANDLED(handled = false)
131  IPC_END_MESSAGE_MAP_EX()
132  return handled;
133}
134
135void P2PSocketDispatcherHost::OnIPAddressChanged() {
136  // Notify the renderer about changes to list of network interfaces.
137  BrowserThread::PostTask(
138      BrowserThread::FILE, FROM_HERE, base::Bind(
139          &P2PSocketDispatcherHost::DoGetNetworkList, this));
140}
141
142P2PSocketDispatcherHost::~P2PSocketDispatcherHost() {
143  DCHECK(sockets_.empty());
144  DCHECK(dns_requests_.empty());
145
146  if (monitoring_networks_)
147    net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
148}
149
150P2PSocketHost* P2PSocketDispatcherHost::LookupSocket(int socket_id) {
151  SocketsMap::iterator it = sockets_.find(socket_id);
152  return (it == sockets_.end()) ? NULL : it->second;
153}
154
155void P2PSocketDispatcherHost::OnStartNetworkNotifications(
156    const IPC::Message& msg) {
157  if (!monitoring_networks_) {
158    net::NetworkChangeNotifier::AddIPAddressObserver(this);
159    monitoring_networks_ = true;
160  }
161
162  BrowserThread::PostTask(
163      BrowserThread::FILE, FROM_HERE, base::Bind(
164          &P2PSocketDispatcherHost::DoGetNetworkList, this));
165}
166
167void P2PSocketDispatcherHost::OnStopNetworkNotifications(
168    const IPC::Message& msg) {
169  if (monitoring_networks_) {
170    net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
171    monitoring_networks_ = false;
172  }
173}
174
175void P2PSocketDispatcherHost::OnGetHostAddress(const std::string& host_name,
176                                               int32 request_id) {
177  DnsRequest* request = new DnsRequest(request_id,
178                                       resource_context_->GetHostResolver());
179  dns_requests_.insert(request);
180  request->Resolve(host_name, base::Bind(
181      &P2PSocketDispatcherHost::OnAddressResolved,
182      base::Unretained(this), request));
183}
184
185void P2PSocketDispatcherHost::OnCreateSocket(
186    P2PSocketType type, int socket_id,
187    const net::IPEndPoint& local_address,
188    const net::IPEndPoint& remote_address) {
189  if (LookupSocket(socket_id)) {
190    LOG(ERROR) << "Received P2PHostMsg_CreateSocket for socket "
191        "that already exists.";
192    return;
193  }
194
195  scoped_ptr<P2PSocketHost> socket(P2PSocketHost::Create(
196      this, socket_id, type, url_context_.get(), &throttler_));
197
198  if (!socket) {
199    Send(new P2PMsg_OnError(socket_id));
200    return;
201  }
202
203  if (socket->Init(local_address, remote_address)) {
204    sockets_[socket_id] = socket.release();
205  }
206}
207
208void P2PSocketDispatcherHost::OnAcceptIncomingTcpConnection(
209    int listen_socket_id, const net::IPEndPoint& remote_address,
210    int connected_socket_id) {
211  P2PSocketHost* socket = LookupSocket(listen_socket_id);
212  if (!socket) {
213    LOG(ERROR) << "Received P2PHostMsg_AcceptIncomingTcpConnection "
214        "for invalid socket_id.";
215    return;
216  }
217  P2PSocketHost* accepted_connection =
218      socket->AcceptIncomingTcpConnection(remote_address, connected_socket_id);
219  if (accepted_connection) {
220    sockets_[connected_socket_id] = accepted_connection;
221  }
222}
223
224void P2PSocketDispatcherHost::OnSend(int socket_id,
225                                     const net::IPEndPoint& socket_address,
226                                     const std::vector<char>& data,
227                                     net::DiffServCodePoint dscp,
228                                     uint64 packet_id) {
229  P2PSocketHost* socket = LookupSocket(socket_id);
230  if (!socket) {
231    LOG(ERROR) << "Received P2PHostMsg_Send for invalid socket_id.";
232    return;
233  }
234
235  if (data.size() > kMaximumPacketSize) {
236    LOG(ERROR) << "Received P2PHostMsg_Send with a packet that is too big: "
237               << data.size();
238    Send(new P2PMsg_OnError(socket_id));
239    delete socket;
240    sockets_.erase(socket_id);
241    return;
242  }
243
244  socket->Send(socket_address, data, dscp, packet_id);
245}
246
247void P2PSocketDispatcherHost::OnDestroySocket(int socket_id) {
248  SocketsMap::iterator it = sockets_.find(socket_id);
249  if (it != sockets_.end()) {
250    delete it->second;
251    sockets_.erase(it);
252  } else {
253    LOG(ERROR) << "Received P2PHostMsg_DestroySocket for invalid socket_id.";
254  }
255}
256
257void P2PSocketDispatcherHost::DoGetNetworkList() {
258  net::NetworkInterfaceList list;
259  net::GetNetworkList(&list);
260  BrowserThread::PostTask(
261      BrowserThread::IO, FROM_HERE, base::Bind(
262          &P2PSocketDispatcherHost::SendNetworkList, this, list));
263}
264
265void P2PSocketDispatcherHost::SendNetworkList(
266    const net::NetworkInterfaceList& list) {
267  Send(new P2PMsg_NetworkListChanged(list));
268}
269
270void P2PSocketDispatcherHost::OnAddressResolved(
271    DnsRequest* request,
272    const net::IPAddressNumber& result) {
273  Send(new P2PMsg_GetHostAddressResult(request->request_id(), result));
274
275  dns_requests_.erase(request);
276  delete request;
277}
278
279}  // namespace content
280