Home | History | Annotate | Download | only in socket
      1 // Copyright 2014 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 "extensions/browser/api/socket/udp_socket.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/lazy_instance.h"
     10 #include "extensions/browser/api/api_resource.h"
     11 #include "net/base/ip_endpoint.h"
     12 #include "net/base/net_errors.h"
     13 #include "net/udp/datagram_socket.h"
     14 #include "net/udp/udp_client_socket.h"
     15 
     16 namespace extensions {
     17 
     18 static base::LazyInstance<
     19     BrowserContextKeyedAPIFactory<ApiResourceManager<ResumableUDPSocket> > >
     20     g_factory = LAZY_INSTANCE_INITIALIZER;
     21 
     22 // static
     23 template <>
     24 BrowserContextKeyedAPIFactory<ApiResourceManager<ResumableUDPSocket> >*
     25 ApiResourceManager<ResumableUDPSocket>::GetFactoryInstance() {
     26   return g_factory.Pointer();
     27 }
     28 
     29 UDPSocket::UDPSocket(const std::string& owner_extension_id)
     30     : Socket(owner_extension_id),
     31       socket_(net::DatagramSocket::DEFAULT_BIND,
     32               net::RandIntCallback(),
     33               NULL,
     34               net::NetLog::Source()) {}
     35 
     36 UDPSocket::~UDPSocket() { Disconnect(); }
     37 
     38 void UDPSocket::Connect(const std::string& address,
     39                         int port,
     40                         const CompletionCallback& callback) {
     41   int result = net::ERR_CONNECTION_FAILED;
     42   do {
     43     if (is_connected_)
     44       break;
     45 
     46     net::IPEndPoint ip_end_point;
     47     if (!StringAndPortToIPEndPoint(address, port, &ip_end_point)) {
     48       result = net::ERR_ADDRESS_INVALID;
     49       break;
     50     }
     51 
     52     result = socket_.Connect(ip_end_point);
     53     is_connected_ = (result == net::OK);
     54   } while (false);
     55 
     56   callback.Run(result);
     57 }
     58 
     59 int UDPSocket::Bind(const std::string& address, int port) {
     60   if (IsBound())
     61     return net::ERR_CONNECTION_FAILED;
     62 
     63   net::IPEndPoint ip_end_point;
     64   if (!StringAndPortToIPEndPoint(address, port, &ip_end_point))
     65     return net::ERR_INVALID_ARGUMENT;
     66 
     67   return socket_.Bind(ip_end_point);
     68 }
     69 
     70 void UDPSocket::Disconnect() {
     71   is_connected_ = false;
     72   socket_.Close();
     73   read_callback_.Reset();
     74   recv_from_callback_.Reset();
     75   send_to_callback_.Reset();
     76   multicast_groups_.clear();
     77 }
     78 
     79 void UDPSocket::Read(int count, const ReadCompletionCallback& callback) {
     80   DCHECK(!callback.is_null());
     81 
     82   if (!read_callback_.is_null()) {
     83     callback.Run(net::ERR_IO_PENDING, NULL);
     84     return;
     85   } else {
     86     read_callback_ = callback;
     87   }
     88 
     89   int result = net::ERR_FAILED;
     90   scoped_refptr<net::IOBuffer> io_buffer;
     91   do {
     92     if (count < 0) {
     93       result = net::ERR_INVALID_ARGUMENT;
     94       break;
     95     }
     96 
     97     if (!socket_.is_connected()) {
     98       result = net::ERR_SOCKET_NOT_CONNECTED;
     99       break;
    100     }
    101 
    102     io_buffer = new net::IOBuffer(count);
    103     result = socket_.Read(
    104         io_buffer.get(),
    105         count,
    106         base::Bind(
    107             &UDPSocket::OnReadComplete, base::Unretained(this), io_buffer));
    108   } while (false);
    109 
    110   if (result != net::ERR_IO_PENDING)
    111     OnReadComplete(io_buffer, result);
    112 }
    113 
    114 int UDPSocket::WriteImpl(net::IOBuffer* io_buffer,
    115                          int io_buffer_size,
    116                          const net::CompletionCallback& callback) {
    117   if (!socket_.is_connected())
    118     return net::ERR_SOCKET_NOT_CONNECTED;
    119   else
    120     return socket_.Write(io_buffer, io_buffer_size, callback);
    121 }
    122 
    123 void UDPSocket::RecvFrom(int count,
    124                          const RecvFromCompletionCallback& callback) {
    125   DCHECK(!callback.is_null());
    126 
    127   if (!recv_from_callback_.is_null()) {
    128     callback.Run(net::ERR_IO_PENDING, NULL, std::string(), 0);
    129     return;
    130   } else {
    131     recv_from_callback_ = callback;
    132   }
    133 
    134   int result = net::ERR_FAILED;
    135   scoped_refptr<net::IOBuffer> io_buffer;
    136   scoped_refptr<IPEndPoint> address;
    137   do {
    138     if (count < 0) {
    139       result = net::ERR_INVALID_ARGUMENT;
    140       break;
    141     }
    142 
    143     if (!socket_.is_connected()) {
    144       result = net::ERR_SOCKET_NOT_CONNECTED;
    145       break;
    146     }
    147 
    148     io_buffer = new net::IOBuffer(count);
    149     address = new IPEndPoint();
    150     result = socket_.RecvFrom(io_buffer.get(),
    151                               count,
    152                               &address->data,
    153                               base::Bind(&UDPSocket::OnRecvFromComplete,
    154                                          base::Unretained(this),
    155                                          io_buffer,
    156                                          address));
    157   } while (false);
    158 
    159   if (result != net::ERR_IO_PENDING)
    160     OnRecvFromComplete(io_buffer, address, result);
    161 }
    162 
    163 void UDPSocket::SendTo(scoped_refptr<net::IOBuffer> io_buffer,
    164                        int byte_count,
    165                        const std::string& address,
    166                        int port,
    167                        const CompletionCallback& callback) {
    168   DCHECK(!callback.is_null());
    169 
    170   if (!send_to_callback_.is_null()) {
    171     // TODO(penghuang): Put requests in a pending queue to support multiple
    172     // sendTo calls.
    173     callback.Run(net::ERR_IO_PENDING);
    174     return;
    175   } else {
    176     send_to_callback_ = callback;
    177   }
    178 
    179   int result = net::ERR_FAILED;
    180   do {
    181     net::IPEndPoint ip_end_point;
    182     if (!StringAndPortToIPEndPoint(address, port, &ip_end_point)) {
    183       result = net::ERR_ADDRESS_INVALID;
    184       break;
    185     }
    186 
    187     if (!socket_.is_connected()) {
    188       result = net::ERR_SOCKET_NOT_CONNECTED;
    189       break;
    190     }
    191 
    192     result = socket_.SendTo(
    193         io_buffer.get(),
    194         byte_count,
    195         ip_end_point,
    196         base::Bind(&UDPSocket::OnSendToComplete, base::Unretained(this)));
    197   } while (false);
    198 
    199   if (result != net::ERR_IO_PENDING)
    200     OnSendToComplete(result);
    201 }
    202 
    203 bool UDPSocket::IsConnected() { return is_connected_; }
    204 
    205 bool UDPSocket::GetPeerAddress(net::IPEndPoint* address) {
    206   return !socket_.GetPeerAddress(address);
    207 }
    208 
    209 bool UDPSocket::GetLocalAddress(net::IPEndPoint* address) {
    210   return !socket_.GetLocalAddress(address);
    211 }
    212 
    213 Socket::SocketType UDPSocket::GetSocketType() const { return Socket::TYPE_UDP; }
    214 
    215 void UDPSocket::OnReadComplete(scoped_refptr<net::IOBuffer> io_buffer,
    216                                int result) {
    217   DCHECK(!read_callback_.is_null());
    218   read_callback_.Run(result, io_buffer);
    219   read_callback_.Reset();
    220 }
    221 
    222 void UDPSocket::OnRecvFromComplete(scoped_refptr<net::IOBuffer> io_buffer,
    223                                    scoped_refptr<IPEndPoint> address,
    224                                    int result) {
    225   DCHECK(!recv_from_callback_.is_null());
    226   std::string ip;
    227   int port = 0;
    228   if (result > 0 && address.get()) {
    229     IPEndPointToStringAndPort(address->data, &ip, &port);
    230   }
    231   recv_from_callback_.Run(result, io_buffer, ip, port);
    232   recv_from_callback_.Reset();
    233 }
    234 
    235 void UDPSocket::OnSendToComplete(int result) {
    236   DCHECK(!send_to_callback_.is_null());
    237   send_to_callback_.Run(result);
    238   send_to_callback_.Reset();
    239 }
    240 
    241 bool UDPSocket::IsBound() { return socket_.is_connected(); }
    242 
    243 int UDPSocket::JoinGroup(const std::string& address) {
    244   net::IPAddressNumber ip;
    245   if (!net::ParseIPLiteralToNumber(address, &ip))
    246     return net::ERR_ADDRESS_INVALID;
    247 
    248   std::string normalized_address = net::IPAddressToString(ip);
    249   std::vector<std::string>::iterator find_result = std::find(
    250       multicast_groups_.begin(), multicast_groups_.end(), normalized_address);
    251   if (find_result != multicast_groups_.end())
    252     return net::ERR_ADDRESS_INVALID;
    253 
    254   int rv = socket_.JoinGroup(ip);
    255   if (rv == 0)
    256     multicast_groups_.push_back(normalized_address);
    257   return rv;
    258 }
    259 
    260 int UDPSocket::LeaveGroup(const std::string& address) {
    261   net::IPAddressNumber ip;
    262   if (!net::ParseIPLiteralToNumber(address, &ip))
    263     return net::ERR_ADDRESS_INVALID;
    264 
    265   std::string normalized_address = net::IPAddressToString(ip);
    266   std::vector<std::string>::iterator find_result = std::find(
    267       multicast_groups_.begin(), multicast_groups_.end(), normalized_address);
    268   if (find_result == multicast_groups_.end())
    269     return net::ERR_ADDRESS_INVALID;
    270 
    271   int rv = socket_.LeaveGroup(ip);
    272   if (rv == 0)
    273     multicast_groups_.erase(find_result);
    274   return rv;
    275 }
    276 
    277 int UDPSocket::SetMulticastTimeToLive(int ttl) {
    278   return socket_.SetMulticastTimeToLive(ttl);
    279 }
    280 
    281 int UDPSocket::SetMulticastLoopbackMode(bool loopback) {
    282   return socket_.SetMulticastLoopbackMode(loopback);
    283 }
    284 
    285 const std::vector<std::string>& UDPSocket::GetJoinedGroups() const {
    286   return multicast_groups_;
    287 }
    288 
    289 ResumableUDPSocket::ResumableUDPSocket(const std::string& owner_extension_id)
    290     : UDPSocket(owner_extension_id),
    291       persistent_(false),
    292       buffer_size_(0),
    293       paused_(false) {}
    294 
    295 bool ResumableUDPSocket::IsPersistent() const { return persistent(); }
    296 
    297 }  // namespace extensions
    298