Home | History | Annotate | Download | only in p2p
      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 
     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       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 
     67   int32 request_id() { return request_id_; }
     68 
     69  private:
     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 
     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 
    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 
    121 void P2PSocketDispatcherHost::OnDestruct() const {
    122   BrowserThread::DeleteOnIOThread::Destruct(this);
    123 }
    124 
    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 
    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 
    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 
    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 
    183 P2PSocketDispatcherHost::~P2PSocketDispatcherHost() {
    184   DCHECK(sockets_.empty());
    185   DCHECK(dns_requests_.empty());
    186 
    187   if (monitoring_networks_)
    188     net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
    189 }
    190 
    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 
    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 
    207 void P2PSocketDispatcherHost::OnStopNetworkNotifications() {
    208   if (monitoring_networks_) {
    209     net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
    210     monitoring_networks_ = false;
    211   }
    212 }
    213 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    323 void P2PSocketDispatcherHost::SendNetworkList(
    324     const net::NetworkInterfaceList& list) {
    325   Send(new P2PMsg_NetworkListChanged(list));
    326 }
    327 
    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 
    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