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