Home | History | Annotate | Download | only in plugin
      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 "remoting/client/plugin/pepper_packet_socket_factory.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/logging.h"
      9 #include "net/base/io_buffer.h"
     10 #include "ppapi/cpp/net_address.h"
     11 #include "ppapi/cpp/udp_socket.h"
     12 #include "ppapi/utility/completion_callback_factory.h"
     13 #include "remoting/client/plugin/pepper_util.h"
     14 #include "third_party/libjingle/source/talk/base/asyncpacketsocket.h"
     15 
     16 namespace remoting {
     17 
     18 namespace {
     19 
     20 // Size of the buffer to allocate for RecvFrom().
     21 const int kReceiveBufferSize = 65536;
     22 
     23 // Maximum amount of data in the send buffers. This is necessary to
     24 // prevent out-of-memory crashes if the caller sends data faster than
     25 // Pepper's UDP API can handle it. This maximum should never be
     26 // reached under normal conditions.
     27 const int kMaxSendBufferSize = 256 * 1024;
     28 
     29 class UdpPacketSocket : public talk_base::AsyncPacketSocket {
     30  public:
     31   explicit UdpPacketSocket(const pp::InstanceHandle& instance);
     32   virtual ~UdpPacketSocket();
     33 
     34   // |min_port| and |max_port| are set to zero if the port number
     35   // should be assigned by the OS.
     36   bool Init(const talk_base::SocketAddress& local_address,
     37             int min_port,
     38             int max_port);
     39 
     40   // talk_base::AsyncPacketSocket interface.
     41   virtual talk_base::SocketAddress GetLocalAddress() const OVERRIDE;
     42   virtual talk_base::SocketAddress GetRemoteAddress() const OVERRIDE;
     43   virtual int Send(const void* data, size_t data_size,
     44                    talk_base::DiffServCodePoint dscp) OVERRIDE;
     45   virtual int SendTo(const void* data,
     46                      size_t data_size,
     47                      const talk_base::SocketAddress& address,
     48                      talk_base::DiffServCodePoint dscp) OVERRIDE;
     49   virtual int Close() OVERRIDE;
     50   virtual State GetState() const OVERRIDE;
     51   virtual int GetOption(talk_base::Socket::Option opt, int* value) OVERRIDE;
     52   virtual int SetOption(talk_base::Socket::Option opt, int value) OVERRIDE;
     53   virtual int GetError() const OVERRIDE;
     54   virtual void SetError(int error) OVERRIDE;
     55 
     56  private:
     57   struct PendingPacket {
     58     PendingPacket(const void* buffer,
     59                   int buffer_size,
     60                   const pp::NetAddress& address);
     61 
     62     scoped_refptr<net::IOBufferWithSize> data;
     63     pp::NetAddress address;
     64   };
     65 
     66   void OnBindCompleted(int error);
     67 
     68   void DoSend();
     69   void OnSendCompleted(int result);
     70 
     71   void DoRead();
     72   void OnReadCompleted(int result, pp::NetAddress address);
     73   void HandleReadResult(int result, pp::NetAddress address);
     74 
     75   pp::InstanceHandle instance_;
     76 
     77   pp::UDPSocket socket_;
     78 
     79   State state_;
     80   int error_;
     81 
     82   talk_base::SocketAddress local_address_;
     83 
     84   // Used to scan ports when necessary. Both values are set to 0 when
     85   // the port number is assigned by OS.
     86   uint16_t min_port_;
     87   uint16_t max_port_;
     88 
     89   std::vector<char> receive_buffer_;
     90 
     91   bool send_pending_;
     92   std::list<PendingPacket> send_queue_;
     93   int send_queue_size_;
     94 
     95   pp::CompletionCallbackFactory<UdpPacketSocket> callback_factory_;
     96 
     97   DISALLOW_COPY_AND_ASSIGN(UdpPacketSocket);
     98 };
     99 
    100 UdpPacketSocket::PendingPacket::PendingPacket(
    101     const void* buffer,
    102     int buffer_size,
    103     const pp::NetAddress& address)
    104     : data(new net::IOBufferWithSize(buffer_size)),
    105       address(address) {
    106   memcpy(data->data(), buffer, buffer_size);
    107 }
    108 
    109 UdpPacketSocket::UdpPacketSocket(const pp::InstanceHandle& instance)
    110     : instance_(instance),
    111       socket_(instance),
    112       state_(STATE_CLOSED),
    113       error_(0),
    114       min_port_(0),
    115       max_port_(0),
    116       send_pending_(false),
    117       send_queue_size_(0),
    118       callback_factory_(this) {
    119 }
    120 
    121 UdpPacketSocket::~UdpPacketSocket() {
    122   Close();
    123 }
    124 
    125 bool UdpPacketSocket::Init(const talk_base::SocketAddress& local_address,
    126                            int min_port,
    127                            int max_port) {
    128   if (socket_.is_null()) {
    129     return false;
    130   }
    131 
    132   local_address_ = local_address;
    133   max_port_ = max_port;
    134   min_port_ = min_port;
    135 
    136   pp::NetAddress pp_local_address;
    137   if (!SocketAddressToPpNetAddressWithPort(
    138           instance_, local_address_, &pp_local_address, min_port_)) {
    139     return false;
    140   }
    141 
    142   pp::CompletionCallback callback =
    143       callback_factory_.NewCallback(&UdpPacketSocket::OnBindCompleted);
    144   int result = socket_.Bind(pp_local_address, callback);
    145   DCHECK_EQ(result, PP_OK_COMPLETIONPENDING);
    146   state_ = STATE_BINDING;
    147 
    148   return true;
    149 }
    150 
    151 void UdpPacketSocket::OnBindCompleted(int result) {
    152   DCHECK(state_ == STATE_BINDING || state_ == STATE_CLOSED);
    153 
    154   if (result == PP_ERROR_ABORTED) {
    155     // Socket is being destroyed while binding.
    156     return;
    157   }
    158 
    159   if (result == PP_OK) {
    160     pp::NetAddress address = socket_.GetBoundAddress();
    161     PpNetAddressToSocketAddress(address, &local_address_);
    162     state_ = STATE_BOUND;
    163     SignalAddressReady(this, local_address_);
    164     DoRead();
    165     return;
    166   }
    167 
    168   if (min_port_ < max_port_) {
    169     // Try to bind to the next available port.
    170     ++min_port_;
    171     pp::NetAddress pp_local_address;
    172     if (SocketAddressToPpNetAddressWithPort(
    173             instance_, local_address_, &pp_local_address, min_port_)) {
    174       pp::CompletionCallback callback =
    175           callback_factory_.NewCallback(&UdpPacketSocket::OnBindCompleted);
    176       int result = socket_.Bind(pp_local_address, callback);
    177       DCHECK_EQ(result, PP_OK_COMPLETIONPENDING);
    178     }
    179   } else {
    180     LOG(ERROR) << "Failed to bind UDP socket: " << result;
    181   }
    182 }
    183 
    184 talk_base::SocketAddress UdpPacketSocket::GetLocalAddress() const {
    185   DCHECK_EQ(state_, STATE_BOUND);
    186   return local_address_;
    187 }
    188 
    189 talk_base::SocketAddress UdpPacketSocket::GetRemoteAddress() const {
    190   // UDP sockets are not connected - this method should never be called.
    191   NOTREACHED();
    192   return talk_base::SocketAddress();
    193 }
    194 
    195 int UdpPacketSocket::Send(const void* data, size_t data_size,
    196                           talk_base::DiffServCodePoint dscp) {
    197   // UDP sockets are not connected - this method should never be called.
    198   NOTREACHED();
    199   return EWOULDBLOCK;
    200 }
    201 
    202 int UdpPacketSocket::SendTo(const void* data,
    203                             size_t data_size,
    204                             const talk_base::SocketAddress& address,
    205                             talk_base::DiffServCodePoint dscp) {
    206   if (state_ != STATE_BOUND) {
    207     // TODO(sergeyu): StunPort may try to send stun request before we
    208     // are bound. Fix that problem and change this to DCHECK.
    209     return EINVAL;
    210   }
    211 
    212   if (error_ != 0) {
    213     return error_;
    214   }
    215 
    216   pp::NetAddress pp_address;
    217   if (!SocketAddressToPpNetAddress(instance_, address, &pp_address)) {
    218     return EINVAL;
    219   }
    220 
    221   if (send_queue_size_ >= kMaxSendBufferSize) {
    222     return EWOULDBLOCK;
    223   }
    224 
    225   send_queue_.push_back(PendingPacket(data, data_size, pp_address));
    226   send_queue_size_ += data_size;
    227   DoSend();
    228   return data_size;
    229 }
    230 
    231 int UdpPacketSocket::Close() {
    232   state_ = STATE_CLOSED;
    233   socket_.Close();
    234   return 0;
    235 }
    236 
    237 talk_base::AsyncPacketSocket::State UdpPacketSocket::GetState() const {
    238   return state_;
    239 }
    240 
    241 int UdpPacketSocket::GetOption(talk_base::Socket::Option opt, int* value) {
    242   // Options are not supported for Pepper UDP sockets.
    243   return -1;
    244 }
    245 
    246 int UdpPacketSocket::SetOption(talk_base::Socket::Option opt, int value) {
    247   // Options are not supported for Pepper UDP sockets.
    248   return -1;
    249 }
    250 
    251 int UdpPacketSocket::GetError() const {
    252   return error_;
    253 }
    254 
    255 void UdpPacketSocket::SetError(int error) {
    256   error_ = error;
    257 }
    258 
    259 void UdpPacketSocket::DoSend() {
    260   if (send_pending_ || send_queue_.empty())
    261     return;
    262 
    263   pp::CompletionCallback callback =
    264       callback_factory_.NewCallback(&UdpPacketSocket::OnSendCompleted);
    265   int result = socket_.SendTo(
    266       send_queue_.front().data->data(), send_queue_.front().data->size(),
    267       send_queue_.front().address,
    268       callback);
    269   DCHECK_EQ(result, PP_OK_COMPLETIONPENDING);
    270   send_pending_ = true;
    271 }
    272 
    273 void UdpPacketSocket::OnSendCompleted(int result) {
    274   if (result == PP_ERROR_ABORTED) {
    275     // Send is aborted when the socket is being destroyed.
    276     // |send_queue_| may be already destroyed, it's not safe to access
    277     // it here.
    278     return;
    279   }
    280 
    281   send_pending_ = false;
    282 
    283   if (result < 0) {
    284     LOG(ERROR) << "Send failed on a UDP socket: " << result;
    285 
    286     // OS (e.g. OSX) may return EHOSTUNREACH when the peer has the
    287     // same subnet address as the local host but connected to a
    288     // different network. That error must be ingored because the
    289     // socket may still be useful for other ICE canidadates (e.g. for
    290     // STUN candidates with a different address). Unfortunately pepper
    291     // interface currently returns PP_ERROR_FAILED for any error (see
    292     // crbug.com/136406). It's not possible to distinguish that case
    293     // from other errors and so we have to ingore all of them. This
    294     // behavior matchers the libjingle's AsyncUDPSocket used by the
    295     // host.
    296     //
    297     // TODO(sergeyu): Once implementation of the Pepper UDP interface
    298     // is fixed, uncomment the code below, but ignore
    299     // host-unreacheable error.
    300 
    301     // error_ = EINVAL;
    302     // return;
    303   }
    304 
    305   send_queue_size_ -= send_queue_.front().data->size();
    306   send_queue_.pop_front();
    307   DoSend();
    308 }
    309 
    310 void UdpPacketSocket::DoRead() {
    311   receive_buffer_.resize(kReceiveBufferSize);
    312   pp::CompletionCallbackWithOutput<pp::NetAddress> callback =
    313       callback_factory_.NewCallbackWithOutput(
    314           &UdpPacketSocket::OnReadCompleted);
    315   int result =
    316       socket_.RecvFrom(&receive_buffer_[0], receive_buffer_.size(), callback);
    317   DCHECK_EQ(result, PP_OK_COMPLETIONPENDING);
    318 }
    319 
    320 void UdpPacketSocket::OnReadCompleted(int result, pp::NetAddress address) {
    321   HandleReadResult(result, address);
    322   if (result > 0) {
    323     DoRead();
    324   }
    325 }
    326 
    327   void UdpPacketSocket::HandleReadResult(int result, pp::NetAddress address) {
    328   if (result > 0) {
    329     talk_base::SocketAddress socket_address;
    330     PpNetAddressToSocketAddress(address, &socket_address);
    331     SignalReadPacket(this, &receive_buffer_[0], result, socket_address,
    332                      talk_base::CreatePacketTime(0));
    333   } else if (result != PP_ERROR_ABORTED) {
    334     LOG(ERROR) << "Received error when reading from UDP socket: " << result;
    335   }
    336 }
    337 
    338 }  // namespace
    339 
    340 PepperPacketSocketFactory::PepperPacketSocketFactory(
    341     const pp::InstanceHandle& instance)
    342     : pp_instance_(instance) {
    343 }
    344 
    345 PepperPacketSocketFactory::~PepperPacketSocketFactory() {
    346 }
    347 
    348 talk_base::AsyncPacketSocket* PepperPacketSocketFactory::CreateUdpSocket(
    349       const talk_base::SocketAddress& local_address,
    350       int min_port,
    351       int max_port) {
    352   scoped_ptr<UdpPacketSocket> result(new UdpPacketSocket(pp_instance_));
    353   if (!result->Init(local_address, min_port, max_port))
    354     return NULL;
    355   return result.release();
    356 }
    357 
    358 talk_base::AsyncPacketSocket* PepperPacketSocketFactory::CreateServerTcpSocket(
    359     const talk_base::SocketAddress& local_address,
    360     int min_port,
    361     int max_port,
    362     int opts) {
    363   // We don't use TCP sockets for remoting connections.
    364   NOTREACHED();
    365   return NULL;
    366 }
    367 
    368 talk_base::AsyncPacketSocket* PepperPacketSocketFactory::CreateClientTcpSocket(
    369       const talk_base::SocketAddress& local_address,
    370       const talk_base::SocketAddress& remote_address,
    371       const talk_base::ProxyInfo& proxy_info,
    372       const std::string& user_agent,
    373       int opts) {
    374   // We don't use TCP sockets for remoting connections.
    375   NOTREACHED();
    376   return NULL;
    377 }
    378 
    379 talk_base::AsyncResolverInterface*
    380 PepperPacketSocketFactory::CreateAsyncResolver() {
    381   NOTREACHED();
    382   return NULL;
    383 }
    384 
    385 }  // namespace remoting
    386