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