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 "content/browser/renderer_host/p2p/socket_dispatcher_host.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"
20 using content::BrowserMessageFilter
;
21 using content::BrowserThread
;
25 const size_t kMaximumPacketSize
= 32768;
27 class P2PSocketDispatcherHost::DnsRequest
{
29 typedef base::Callback
<void(const net::IPAddressNumber
&)> DoneCallback
;
31 DnsRequest(int32 request_id
, net::HostResolver
* host_resolver
)
32 : request_id_(request_id
),
33 resolver_(host_resolver
) {
36 void Resolve(const std::string
& host_name
,
37 const DoneCallback
& done_callback
) {
38 DCHECK(!done_callback
.is_null());
40 host_name_
= host_name
;
41 done_callback_
= done_callback
;
43 // Return an error if it's an empty string.
44 if (host_name_
.empty()) {
45 done_callback_
.Run(net::IPAddressNumber());
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_
+ '.';
54 net::HostResolver::RequestInfo
info(net::HostPortPair(host_name_
, 0));
55 int result
= resolver_
.Resolve(
57 net::DEFAULT_PRIORITY
,
59 base::Bind(&P2PSocketDispatcherHost::DnsRequest::OnDone
,
60 base::Unretained(this)),
62 if (result
!= net::ERR_IO_PENDING
)
66 int32
request_id() { return request_id_
; }
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());
77 DCHECK(!addresses_
.empty());
78 done_callback_
.Run(addresses_
.front().address());
82 net::AddressList addresses_
;
84 std::string host_name_
;
85 net::SingleRequestHostResolver resolver_
;
87 DoneCallback done_callback_
;
90 P2PSocketDispatcherHost::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) {
98 void P2PSocketDispatcherHost::OnChannelClosing() {
99 // Since the IPC channel is gone, close pending connections.
100 STLDeleteContainerPairSecondPointers(sockets_
.begin(), sockets_
.end());
103 STLDeleteContainerPointers(dns_requests_
.begin(), dns_requests_
.end());
104 dns_requests_
.clear();
106 if (monitoring_networks_
) {
107 net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
108 monitoring_networks_
= false;
112 void P2PSocketDispatcherHost::OnDestruct() const {
113 BrowserThread::DeleteOnIOThread::Destruct(this);
116 bool P2PSocketDispatcherHost::OnMessageReceived(const IPC::Message
& message
,
117 bool* message_was_ok
) {
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()
135 void 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));
142 P2PSocketDispatcherHost::~P2PSocketDispatcherHost() {
143 DCHECK(sockets_
.empty());
144 DCHECK(dns_requests_
.empty());
146 if (monitoring_networks_
)
147 net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
150 P2PSocketHost
* P2PSocketDispatcherHost::LookupSocket(int socket_id
) {
151 SocketsMap::iterator it
= sockets_
.find(socket_id
);
152 return (it
== sockets_
.end()) ? NULL
: it
->second
;
155 void P2PSocketDispatcherHost::OnStartNetworkNotifications(
156 const IPC::Message
& msg
) {
157 if (!monitoring_networks_
) {
158 net::NetworkChangeNotifier::AddIPAddressObserver(this);
159 monitoring_networks_
= true;
162 BrowserThread::PostTask(
163 BrowserThread::FILE, FROM_HERE
, base::Bind(
164 &P2PSocketDispatcherHost::DoGetNetworkList
, this));
167 void P2PSocketDispatcherHost::OnStopNetworkNotifications(
168 const IPC::Message
& msg
) {
169 if (monitoring_networks_
) {
170 net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
171 monitoring_networks_
= false;
175 void P2PSocketDispatcherHost::OnGetHostAddress(const std::string
& host_name
,
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
));
185 void 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.";
195 scoped_ptr
<P2PSocketHost
> socket(P2PSocketHost::Create(
196 this, socket_id
, type
, url_context_
.get(), &throttler_
));
199 Send(new P2PMsg_OnError(socket_id
));
203 if (socket
->Init(local_address
, remote_address
)) {
204 sockets_
[socket_id
] = socket
.release();
208 void P2PSocketDispatcherHost::OnAcceptIncomingTcpConnection(
209 int listen_socket_id
, const net::IPEndPoint
& remote_address
,
210 int connected_socket_id
) {
211 P2PSocketHost
* socket
= LookupSocket(listen_socket_id
);
213 LOG(ERROR
) << "Received P2PHostMsg_AcceptIncomingTcpConnection "
214 "for invalid socket_id.";
217 P2PSocketHost
* accepted_connection
=
218 socket
->AcceptIncomingTcpConnection(remote_address
, connected_socket_id
);
219 if (accepted_connection
) {
220 sockets_
[connected_socket_id
] = accepted_connection
;
224 void P2PSocketDispatcherHost::OnSend(int socket_id
,
225 const net::IPEndPoint
& socket_address
,
226 const std::vector
<char>& data
,
227 net::DiffServCodePoint dscp
,
229 P2PSocketHost
* socket
= LookupSocket(socket_id
);
231 LOG(ERROR
) << "Received P2PHostMsg_Send for invalid socket_id.";
235 if (data
.size() > kMaximumPacketSize
) {
236 LOG(ERROR
) << "Received P2PHostMsg_Send with a packet that is too big: "
238 Send(new P2PMsg_OnError(socket_id
));
240 sockets_
.erase(socket_id
);
244 socket
->Send(socket_address
, data
, dscp
, packet_id
);
247 void P2PSocketDispatcherHost::OnDestroySocket(int socket_id
) {
248 SocketsMap::iterator it
= sockets_
.find(socket_id
);
249 if (it
!= sockets_
.end()) {
253 LOG(ERROR
) << "Received P2PHostMsg_DestroySocket for invalid socket_id.";
257 void 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
));
265 void P2PSocketDispatcherHost::SendNetworkList(
266 const net::NetworkInterfaceList
& list
) {
267 Send(new P2PMsg_NetworkListChanged(list
));
270 void P2PSocketDispatcherHost::OnAddressResolved(
272 const net::IPAddressNumber
& result
) {
273 Send(new P2PMsg_GetHostAddressResult(request
->request_id(), result
));
275 dns_requests_
.erase(request
);
279 } // namespace content