• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
20 using content::BrowserMessageFilter;
21 using content::BrowserThread;
22 
23 namespace content {
24 
25 const size_t kMaximumPacketSize = 32768;
26 
27 class P2PSocketDispatcherHost::DnsRequest {
28  public:
29   typedef base::Callback<void(const net::IPAddressList&)> DoneCallback;
30 
DnsRequest(int32 request_id,net::HostResolver * host_resolver)31   DnsRequest(int32 request_id, net::HostResolver* host_resolver)
32       : request_id_(request_id),
33         resolver_(host_resolver) {
34   }
35 
Resolve(const std::string & host_name,const DoneCallback & done_callback)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       net::IPAddressList address_list;
46       done_callback_.Run(address_list);
47       return;
48     }
49 
50     // Add period at the end to make sure that we only resolve
51     // fully-qualified names.
52     if (host_name_.at(host_name_.size() - 1) != '.')
53       host_name_ = host_name_ + '.';
54 
55     net::HostResolver::RequestInfo info(net::HostPortPair(host_name_, 0));
56     int result = resolver_.Resolve(
57         info,
58         net::DEFAULT_PRIORITY,
59         &addresses_,
60         base::Bind(&P2PSocketDispatcherHost::DnsRequest::OnDone,
61                    base::Unretained(this)),
62         net::BoundNetLog());
63     if (result != net::ERR_IO_PENDING)
64       OnDone(result);
65   }
66 
request_id()67   int32 request_id() { return request_id_; }
68 
69  private:
OnDone(int result)70   void OnDone(int result) {
71     net::IPAddressList list;
72     if (result != net::OK) {
73       LOG(ERROR) << "Failed to resolve address for " << host_name_
74                  << ", errorcode: " << result;
75       done_callback_.Run(list);
76       return;
77     }
78 
79     DCHECK(!addresses_.empty());
80     for (net::AddressList::iterator iter = addresses_.begin();
81          iter != addresses_.end(); ++iter) {
82       list.push_back(iter->address());
83     }
84     done_callback_.Run(list);
85   }
86 
87   int32 request_id_;
88   net::AddressList addresses_;
89 
90   std::string host_name_;
91   net::SingleRequestHostResolver resolver_;
92 
93   DoneCallback done_callback_;
94 };
95 
P2PSocketDispatcherHost(content::ResourceContext * resource_context,net::URLRequestContextGetter * url_context)96 P2PSocketDispatcherHost::P2PSocketDispatcherHost(
97     content::ResourceContext* resource_context,
98     net::URLRequestContextGetter* url_context)
99     : BrowserMessageFilter(P2PMsgStart),
100       resource_context_(resource_context),
101       url_context_(url_context),
102       monitoring_networks_(false),
103       dump_incoming_rtp_packet_(false),
104       dump_outgoing_rtp_packet_(false) {
105 }
106 
OnChannelClosing()107 void P2PSocketDispatcherHost::OnChannelClosing() {
108   // Since the IPC sender is gone, close pending connections.
109   STLDeleteContainerPairSecondPointers(sockets_.begin(), sockets_.end());
110   sockets_.clear();
111 
112   STLDeleteContainerPointers(dns_requests_.begin(), dns_requests_.end());
113   dns_requests_.clear();
114 
115   if (monitoring_networks_) {
116     net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
117     monitoring_networks_ = false;
118   }
119 }
120 
OnDestruct() const121 void P2PSocketDispatcherHost::OnDestruct() const {
122   BrowserThread::DeleteOnIOThread::Destruct(this);
123 }
124 
OnMessageReceived(const IPC::Message & message)125 bool P2PSocketDispatcherHost::OnMessageReceived(const IPC::Message& message) {
126   bool handled = true;
127   IPC_BEGIN_MESSAGE_MAP(P2PSocketDispatcherHost, message)
128     IPC_MESSAGE_HANDLER(P2PHostMsg_StartNetworkNotifications,
129                         OnStartNetworkNotifications)
130     IPC_MESSAGE_HANDLER(P2PHostMsg_StopNetworkNotifications,
131                         OnStopNetworkNotifications)
132     IPC_MESSAGE_HANDLER(P2PHostMsg_GetHostAddress, OnGetHostAddress)
133     IPC_MESSAGE_HANDLER(P2PHostMsg_CreateSocket, OnCreateSocket)
134     IPC_MESSAGE_HANDLER(P2PHostMsg_AcceptIncomingTcpConnection,
135                         OnAcceptIncomingTcpConnection)
136     IPC_MESSAGE_HANDLER(P2PHostMsg_Send, OnSend)
137     IPC_MESSAGE_HANDLER(P2PHostMsg_SetOption, OnSetOption)
138     IPC_MESSAGE_HANDLER(P2PHostMsg_DestroySocket, OnDestroySocket)
139     IPC_MESSAGE_UNHANDLED(handled = false)
140   IPC_END_MESSAGE_MAP()
141   return handled;
142 }
143 
OnIPAddressChanged()144 void P2PSocketDispatcherHost::OnIPAddressChanged() {
145   // Notify the renderer about changes to list of network interfaces.
146   BrowserThread::PostTask(
147       BrowserThread::FILE, FROM_HERE, base::Bind(
148           &P2PSocketDispatcherHost::DoGetNetworkList, this));
149 }
150 
StartRtpDump(bool incoming,bool outgoing,const RenderProcessHost::WebRtcRtpPacketCallback & packet_callback)151 void P2PSocketDispatcherHost::StartRtpDump(
152     bool incoming,
153     bool outgoing,
154     const RenderProcessHost::WebRtcRtpPacketCallback& packet_callback) {
155   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
156 
157   if ((!dump_incoming_rtp_packet_ && incoming) ||
158       (!dump_outgoing_rtp_packet_ && outgoing)) {
159     if (incoming)
160       dump_incoming_rtp_packet_ = true;
161 
162     if (outgoing)
163       dump_outgoing_rtp_packet_ = true;
164 
165     packet_callback_ = packet_callback;
166     for (SocketsMap::iterator it = sockets_.begin(); it != sockets_.end(); ++it)
167       it->second->StartRtpDump(incoming, outgoing, packet_callback);
168   }
169 }
170 
StopRtpDumpOnUIThread(bool incoming,bool outgoing)171 void P2PSocketDispatcherHost::StopRtpDumpOnUIThread(bool incoming,
172                                                     bool outgoing) {
173   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
174   BrowserThread::PostTask(
175       BrowserThread::IO,
176       FROM_HERE,
177       base::Bind(&P2PSocketDispatcherHost::StopRtpDumpOnIOThread,
178                  this,
179                  incoming,
180                  outgoing));
181 }
182 
~P2PSocketDispatcherHost()183 P2PSocketDispatcherHost::~P2PSocketDispatcherHost() {
184   DCHECK(sockets_.empty());
185   DCHECK(dns_requests_.empty());
186 
187   if (monitoring_networks_)
188     net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
189 }
190 
LookupSocket(int socket_id)191 P2PSocketHost* P2PSocketDispatcherHost::LookupSocket(int socket_id) {
192   SocketsMap::iterator it = sockets_.find(socket_id);
193   return (it == sockets_.end()) ? NULL : it->second;
194 }
195 
OnStartNetworkNotifications()196 void P2PSocketDispatcherHost::OnStartNetworkNotifications() {
197   if (!monitoring_networks_) {
198     net::NetworkChangeNotifier::AddIPAddressObserver(this);
199     monitoring_networks_ = true;
200   }
201 
202   BrowserThread::PostTask(
203       BrowserThread::FILE, FROM_HERE, base::Bind(
204           &P2PSocketDispatcherHost::DoGetNetworkList, this));
205 }
206 
OnStopNetworkNotifications()207 void P2PSocketDispatcherHost::OnStopNetworkNotifications() {
208   if (monitoring_networks_) {
209     net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
210     monitoring_networks_ = false;
211   }
212 }
213 
OnGetHostAddress(const std::string & host_name,int32 request_id)214 void P2PSocketDispatcherHost::OnGetHostAddress(const std::string& host_name,
215                                                int32 request_id) {
216   DnsRequest* request = new DnsRequest(request_id,
217                                        resource_context_->GetHostResolver());
218   dns_requests_.insert(request);
219   request->Resolve(host_name, base::Bind(
220       &P2PSocketDispatcherHost::OnAddressResolved,
221       base::Unretained(this), request));
222 }
223 
OnCreateSocket(P2PSocketType type,int socket_id,const net::IPEndPoint & local_address,const P2PHostAndIPEndPoint & remote_address)224 void P2PSocketDispatcherHost::OnCreateSocket(
225     P2PSocketType type, int socket_id,
226     const net::IPEndPoint& local_address,
227     const P2PHostAndIPEndPoint& remote_address) {
228   if (LookupSocket(socket_id)) {
229     LOG(ERROR) << "Received P2PHostMsg_CreateSocket for socket "
230         "that already exists.";
231     return;
232   }
233 
234   scoped_ptr<P2PSocketHost> socket(P2PSocketHost::Create(
235       this, socket_id, type, url_context_.get(), &throttler_));
236 
237   if (!socket) {
238     Send(new P2PMsg_OnError(socket_id));
239     return;
240   }
241 
242   if (socket->Init(local_address, remote_address)) {
243     sockets_[socket_id] = socket.release();
244 
245     if (dump_incoming_rtp_packet_ || dump_outgoing_rtp_packet_) {
246       sockets_[socket_id]->StartRtpDump(dump_incoming_rtp_packet_,
247                                         dump_outgoing_rtp_packet_,
248                                         packet_callback_);
249     }
250   }
251 }
252 
OnAcceptIncomingTcpConnection(int listen_socket_id,const net::IPEndPoint & remote_address,int connected_socket_id)253 void P2PSocketDispatcherHost::OnAcceptIncomingTcpConnection(
254     int listen_socket_id, const net::IPEndPoint& remote_address,
255     int connected_socket_id) {
256   P2PSocketHost* socket = LookupSocket(listen_socket_id);
257   if (!socket) {
258     LOG(ERROR) << "Received P2PHostMsg_AcceptIncomingTcpConnection "
259         "for invalid socket_id.";
260     return;
261   }
262   P2PSocketHost* accepted_connection =
263       socket->AcceptIncomingTcpConnection(remote_address, connected_socket_id);
264   if (accepted_connection) {
265     sockets_[connected_socket_id] = accepted_connection;
266   }
267 }
268 
OnSend(int socket_id,const net::IPEndPoint & socket_address,const std::vector<char> & data,const rtc::PacketOptions & options,uint64 packet_id)269 void P2PSocketDispatcherHost::OnSend(int socket_id,
270                                      const net::IPEndPoint& socket_address,
271                                      const std::vector<char>& data,
272                                      const rtc::PacketOptions& options,
273                                      uint64 packet_id) {
274   P2PSocketHost* socket = LookupSocket(socket_id);
275   if (!socket) {
276     LOG(ERROR) << "Received P2PHostMsg_Send for invalid socket_id.";
277     return;
278   }
279 
280   if (data.size() > kMaximumPacketSize) {
281     LOG(ERROR) << "Received P2PHostMsg_Send with a packet that is too big: "
282                << data.size();
283     Send(new P2PMsg_OnError(socket_id));
284     delete socket;
285     sockets_.erase(socket_id);
286     return;
287   }
288 
289   socket->Send(socket_address, data, options, packet_id);
290 }
291 
OnSetOption(int socket_id,P2PSocketOption option,int value)292 void P2PSocketDispatcherHost::OnSetOption(int socket_id,
293                                           P2PSocketOption option,
294                                           int value) {
295   P2PSocketHost* socket = LookupSocket(socket_id);
296   if (!socket) {
297     LOG(ERROR) << "Received P2PHostMsg_SetOption for invalid socket_id.";
298     return;
299   }
300 
301   socket->SetOption(option, value);
302 }
303 
OnDestroySocket(int socket_id)304 void P2PSocketDispatcherHost::OnDestroySocket(int socket_id) {
305   SocketsMap::iterator it = sockets_.find(socket_id);
306   if (it != sockets_.end()) {
307     delete it->second;
308     sockets_.erase(it);
309   } else {
310     LOG(ERROR) << "Received P2PHostMsg_DestroySocket for invalid socket_id.";
311   }
312 }
313 
DoGetNetworkList()314 void P2PSocketDispatcherHost::DoGetNetworkList() {
315   net::NetworkInterfaceList list;
316   net::GetNetworkList(&list, net::EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES |
317                              net::INCLUDE_ONLY_TEMP_IPV6_ADDRESS_IF_POSSIBLE);
318   BrowserThread::PostTask(
319       BrowserThread::IO, FROM_HERE, base::Bind(
320           &P2PSocketDispatcherHost::SendNetworkList, this, list));
321 }
322 
SendNetworkList(const net::NetworkInterfaceList & list)323 void P2PSocketDispatcherHost::SendNetworkList(
324     const net::NetworkInterfaceList& list) {
325   Send(new P2PMsg_NetworkListChanged(list));
326 }
327 
OnAddressResolved(DnsRequest * request,const net::IPAddressList & addresses)328 void P2PSocketDispatcherHost::OnAddressResolved(
329     DnsRequest* request,
330     const net::IPAddressList& addresses) {
331   Send(new P2PMsg_GetHostAddressResult(request->request_id(), addresses));
332 
333   dns_requests_.erase(request);
334   delete request;
335 }
336 
StopRtpDumpOnIOThread(bool incoming,bool outgoing)337 void P2PSocketDispatcherHost::StopRtpDumpOnIOThread(bool incoming,
338                                                     bool outgoing) {
339   if ((dump_incoming_rtp_packet_ && incoming) ||
340       (dump_outgoing_rtp_packet_ && outgoing)) {
341     if (incoming)
342       dump_incoming_rtp_packet_ = false;
343 
344     if (outgoing)
345       dump_outgoing_rtp_packet_ = false;
346 
347     if (!dump_incoming_rtp_packet_ && !dump_outgoing_rtp_packet_)
348       packet_callback_.Reset();
349 
350     for (SocketsMap::iterator it = sockets_.begin(); it != sockets_.end(); ++it)
351       it->second->StopRtpDump(incoming, outgoing);
352   }
353 }
354 
355 }  // namespace content
356