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/network_interfaces.h"
16 #include "net/base/sys_addrinfo.h"
17 #include "net/dns/single_request_host_resolver.h"
18 #include "net/log/net_log.h"
19 #include "net/url_request/url_request_context_getter.h"
21 using content::BrowserMessageFilter
;
22 using content::BrowserThread
;
26 const size_t kMaximumPacketSize
= 32768;
28 class P2PSocketDispatcherHost::DnsRequest
{
30 typedef base::Callback
<void(const net::IPAddressList
&)> DoneCallback
;
32 DnsRequest(int32 request_id
, net::HostResolver
* host_resolver
)
33 : request_id_(request_id
),
34 resolver_(host_resolver
) {
37 void Resolve(const std::string
& host_name
,
38 const DoneCallback
& done_callback
) {
39 DCHECK(!done_callback
.is_null());
41 host_name_
= host_name
;
42 done_callback_
= done_callback
;
44 // Return an error if it's an empty string.
45 if (host_name_
.empty()) {
46 net::IPAddressList address_list
;
47 done_callback_
.Run(address_list
);
51 // Add period at the end to make sure that we only resolve
52 // fully-qualified names.
53 if (host_name_
.at(host_name_
.size() - 1) != '.')
54 host_name_
= host_name_
+ '.';
56 net::HostResolver::RequestInfo
info(net::HostPortPair(host_name_
, 0));
57 int result
= resolver_
.Resolve(
59 net::DEFAULT_PRIORITY
,
61 base::Bind(&P2PSocketDispatcherHost::DnsRequest::OnDone
,
62 base::Unretained(this)),
64 if (result
!= net::ERR_IO_PENDING
)
68 int32
request_id() { return request_id_
; }
71 void OnDone(int result
) {
72 net::IPAddressList list
;
73 if (result
!= net::OK
) {
74 LOG(ERROR
) << "Failed to resolve address for " << host_name_
75 << ", errorcode: " << result
;
76 done_callback_
.Run(list
);
80 DCHECK(!addresses_
.empty());
81 for (net::AddressList::iterator iter
= addresses_
.begin();
82 iter
!= addresses_
.end(); ++iter
) {
83 list
.push_back(iter
->address());
85 done_callback_
.Run(list
);
89 net::AddressList addresses_
;
91 std::string host_name_
;
92 net::SingleRequestHostResolver resolver_
;
94 DoneCallback done_callback_
;
97 P2PSocketDispatcherHost::P2PSocketDispatcherHost(
98 content::ResourceContext
* resource_context
,
99 net::URLRequestContextGetter
* url_context
)
100 : BrowserMessageFilter(P2PMsgStart
),
101 resource_context_(resource_context
),
102 url_context_(url_context
),
103 monitoring_networks_(false),
104 dump_incoming_rtp_packet_(false),
105 dump_outgoing_rtp_packet_(false) {
108 void P2PSocketDispatcherHost::OnChannelClosing() {
109 // Since the IPC sender is gone, close pending connections.
110 STLDeleteContainerPairSecondPointers(sockets_
.begin(), sockets_
.end());
113 STLDeleteContainerPointers(dns_requests_
.begin(), dns_requests_
.end());
114 dns_requests_
.clear();
116 if (monitoring_networks_
) {
117 net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
118 monitoring_networks_
= false;
122 void P2PSocketDispatcherHost::OnDestruct() const {
123 BrowserThread::DeleteOnIOThread::Destruct(this);
126 bool P2PSocketDispatcherHost::OnMessageReceived(const IPC::Message
& message
) {
128 IPC_BEGIN_MESSAGE_MAP(P2PSocketDispatcherHost
, message
)
129 IPC_MESSAGE_HANDLER(P2PHostMsg_StartNetworkNotifications
,
130 OnStartNetworkNotifications
)
131 IPC_MESSAGE_HANDLER(P2PHostMsg_StopNetworkNotifications
,
132 OnStopNetworkNotifications
)
133 IPC_MESSAGE_HANDLER(P2PHostMsg_GetHostAddress
, OnGetHostAddress
)
134 IPC_MESSAGE_HANDLER(P2PHostMsg_CreateSocket
, OnCreateSocket
)
135 IPC_MESSAGE_HANDLER(P2PHostMsg_AcceptIncomingTcpConnection
,
136 OnAcceptIncomingTcpConnection
)
137 IPC_MESSAGE_HANDLER(P2PHostMsg_Send
, OnSend
)
138 IPC_MESSAGE_HANDLER(P2PHostMsg_SetOption
, OnSetOption
)
139 IPC_MESSAGE_HANDLER(P2PHostMsg_DestroySocket
, OnDestroySocket
)
140 IPC_MESSAGE_UNHANDLED(handled
= false)
141 IPC_END_MESSAGE_MAP()
145 void P2PSocketDispatcherHost::OnIPAddressChanged() {
146 // Notify the renderer about changes to list of network interfaces.
147 BrowserThread::PostTask(
148 BrowserThread::FILE, FROM_HERE
, base::Bind(
149 &P2PSocketDispatcherHost::DoGetNetworkList
, this));
152 void P2PSocketDispatcherHost::StartRtpDump(
155 const RenderProcessHost::WebRtcRtpPacketCallback
& packet_callback
) {
156 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
158 if ((!dump_incoming_rtp_packet_
&& incoming
) ||
159 (!dump_outgoing_rtp_packet_
&& outgoing
)) {
161 dump_incoming_rtp_packet_
= true;
164 dump_outgoing_rtp_packet_
= true;
166 packet_callback_
= packet_callback
;
167 for (SocketsMap::iterator it
= sockets_
.begin(); it
!= sockets_
.end(); ++it
)
168 it
->second
->StartRtpDump(incoming
, outgoing
, packet_callback
);
172 void P2PSocketDispatcherHost::StopRtpDumpOnUIThread(bool incoming
,
174 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
175 BrowserThread::PostTask(
178 base::Bind(&P2PSocketDispatcherHost::StopRtpDumpOnIOThread
,
184 P2PSocketDispatcherHost::~P2PSocketDispatcherHost() {
185 DCHECK(sockets_
.empty());
186 DCHECK(dns_requests_
.empty());
188 if (monitoring_networks_
)
189 net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
192 P2PSocketHost
* P2PSocketDispatcherHost::LookupSocket(int socket_id
) {
193 SocketsMap::iterator it
= sockets_
.find(socket_id
);
194 return (it
== sockets_
.end()) ? NULL
: it
->second
;
197 void P2PSocketDispatcherHost::OnStartNetworkNotifications() {
198 if (!monitoring_networks_
) {
199 net::NetworkChangeNotifier::AddIPAddressObserver(this);
200 monitoring_networks_
= true;
203 BrowserThread::PostTask(
204 BrowserThread::FILE, FROM_HERE
, base::Bind(
205 &P2PSocketDispatcherHost::DoGetNetworkList
, this));
208 void P2PSocketDispatcherHost::OnStopNetworkNotifications() {
209 if (monitoring_networks_
) {
210 net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
211 monitoring_networks_
= false;
215 void P2PSocketDispatcherHost::OnGetHostAddress(const std::string
& host_name
,
217 DnsRequest
* request
= new DnsRequest(request_id
,
218 resource_context_
->GetHostResolver());
219 dns_requests_
.insert(request
);
220 request
->Resolve(host_name
, base::Bind(
221 &P2PSocketDispatcherHost::OnAddressResolved
,
222 base::Unretained(this), request
));
225 void P2PSocketDispatcherHost::OnCreateSocket(
226 P2PSocketType type
, int socket_id
,
227 const net::IPEndPoint
& local_address
,
228 const P2PHostAndIPEndPoint
& remote_address
) {
229 if (LookupSocket(socket_id
)) {
230 LOG(ERROR
) << "Received P2PHostMsg_CreateSocket for socket "
231 "that already exists.";
235 scoped_ptr
<P2PSocketHost
> socket(P2PSocketHost::Create(
236 this, socket_id
, type
, url_context_
.get(), &throttler_
));
239 Send(new P2PMsg_OnError(socket_id
));
243 if (socket
->Init(local_address
, remote_address
)) {
244 sockets_
[socket_id
] = socket
.release();
246 if (dump_incoming_rtp_packet_
|| dump_outgoing_rtp_packet_
) {
247 sockets_
[socket_id
]->StartRtpDump(dump_incoming_rtp_packet_
,
248 dump_outgoing_rtp_packet_
,
254 void P2PSocketDispatcherHost::OnAcceptIncomingTcpConnection(
255 int listen_socket_id
, const net::IPEndPoint
& remote_address
,
256 int connected_socket_id
) {
257 P2PSocketHost
* socket
= LookupSocket(listen_socket_id
);
259 LOG(ERROR
) << "Received P2PHostMsg_AcceptIncomingTcpConnection "
260 "for invalid listen_socket_id.";
263 if (LookupSocket(connected_socket_id
) != NULL
) {
264 LOG(ERROR
) << "Received P2PHostMsg_AcceptIncomingTcpConnection "
265 "for duplicated connected_socket_id.";
269 P2PSocketHost
* accepted_connection
=
270 socket
->AcceptIncomingTcpConnection(remote_address
, connected_socket_id
);
271 if (accepted_connection
) {
272 sockets_
[connected_socket_id
] = accepted_connection
;
276 void P2PSocketDispatcherHost::OnSend(int socket_id
,
277 const net::IPEndPoint
& socket_address
,
278 const std::vector
<char>& data
,
279 const rtc::PacketOptions
& options
,
281 P2PSocketHost
* socket
= LookupSocket(socket_id
);
283 LOG(ERROR
) << "Received P2PHostMsg_Send for invalid socket_id.";
287 if (data
.size() > kMaximumPacketSize
) {
288 LOG(ERROR
) << "Received P2PHostMsg_Send with a packet that is too big: "
290 Send(new P2PMsg_OnError(socket_id
));
292 sockets_
.erase(socket_id
);
296 socket
->Send(socket_address
, data
, options
, packet_id
);
299 void P2PSocketDispatcherHost::OnSetOption(int socket_id
,
300 P2PSocketOption option
,
302 P2PSocketHost
* socket
= LookupSocket(socket_id
);
304 LOG(ERROR
) << "Received P2PHostMsg_SetOption for invalid socket_id.";
308 socket
->SetOption(option
, value
);
311 void P2PSocketDispatcherHost::OnDestroySocket(int socket_id
) {
312 SocketsMap::iterator it
= sockets_
.find(socket_id
);
313 if (it
!= sockets_
.end()) {
317 LOG(ERROR
) << "Received P2PHostMsg_DestroySocket for invalid socket_id.";
321 void P2PSocketDispatcherHost::DoGetNetworkList() {
322 net::NetworkInterfaceList list
;
323 net::GetNetworkList(&list
, net::EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES
);
324 BrowserThread::PostTask(
325 BrowserThread::IO
, FROM_HERE
, base::Bind(
326 &P2PSocketDispatcherHost::SendNetworkList
, this, list
));
329 void P2PSocketDispatcherHost::SendNetworkList(
330 const net::NetworkInterfaceList
& list
) {
331 Send(new P2PMsg_NetworkListChanged(list
));
334 void P2PSocketDispatcherHost::OnAddressResolved(
336 const net::IPAddressList
& addresses
) {
337 Send(new P2PMsg_GetHostAddressResult(request
->request_id(), addresses
));
339 dns_requests_
.erase(request
);
343 void P2PSocketDispatcherHost::StopRtpDumpOnIOThread(bool incoming
,
345 if ((dump_incoming_rtp_packet_
&& incoming
) ||
346 (dump_outgoing_rtp_packet_
&& outgoing
)) {
348 dump_incoming_rtp_packet_
= false;
351 dump_outgoing_rtp_packet_
= false;
353 if (!dump_incoming_rtp_packet_
&& !dump_outgoing_rtp_packet_
)
354 packet_callback_
.Reset();
356 for (SocketsMap::iterator it
= sockets_
.begin(); it
!= sockets_
.end(); ++it
)
357 it
->second
->StopRtpDump(incoming
, outgoing
);
361 } // namespace content