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/tcp_socket.h"
      6 
      7 #include "chrome/browser/extensions/api/api_resource.h"
      8 #include "net/base/address_list.h"
      9 #include "net/base/ip_endpoint.h"
     10 #include "net/base/net_errors.h"
     11 #include "net/base/rand_callback.h"
     12 #include "net/socket/tcp_client_socket.h"
     13 
     14 namespace extensions {
     15 
     16 const char kTCPSocketTypeInvalidError[] =
     17     "Cannot call both connect and listen on the same socket.";
     18 const char kSocketListenError[] = "Could not listen on the specified port.";
     19 
     20 TCPSocket::TCPSocket(const std::string& owner_extension_id)
     21     : Socket(owner_extension_id),
     22       socket_mode_(UNKNOWN) {
     23 }
     24 
     25 TCPSocket::TCPSocket(net::TCPClientSocket* tcp_client_socket,
     26                      const std::string& owner_extension_id,
     27                      bool is_connected)
     28     : Socket(owner_extension_id),
     29       socket_(tcp_client_socket),
     30       socket_mode_(CLIENT) {
     31   this->is_connected_ = is_connected;
     32 }
     33 
     34 TCPSocket::TCPSocket(net::TCPServerSocket* tcp_server_socket,
     35                      const std::string& owner_extension_id)
     36     : Socket(owner_extension_id),
     37       server_socket_(tcp_server_socket),
     38       socket_mode_(SERVER) {
     39 }
     40 
     41 // static
     42 TCPSocket* TCPSocket::CreateSocketForTesting(
     43     net::TCPClientSocket* tcp_client_socket,
     44     const std::string& owner_extension_id,
     45     bool is_connected) {
     46   return new TCPSocket(tcp_client_socket, owner_extension_id, is_connected);
     47 }
     48 
     49 // static
     50 TCPSocket* TCPSocket::CreateServerSocketForTesting(
     51     net::TCPServerSocket* tcp_server_socket,
     52     const std::string& owner_extension_id) {
     53   return new TCPSocket(tcp_server_socket, owner_extension_id);
     54 }
     55 
     56 TCPSocket::~TCPSocket() {
     57   Disconnect();
     58 }
     59 
     60 void TCPSocket::Connect(const std::string& address,
     61                         int port,
     62                         const CompletionCallback& callback) {
     63   DCHECK(!callback.is_null());
     64 
     65   if (socket_mode_ == SERVER || !connect_callback_.is_null()) {
     66     callback.Run(net::ERR_CONNECTION_FAILED);
     67     return;
     68   }
     69   DCHECK(!server_socket_.get());
     70   socket_mode_ = CLIENT;
     71   connect_callback_ = callback;
     72 
     73   int result = net::ERR_CONNECTION_FAILED;
     74   do {
     75     if (is_connected_)
     76       break;
     77 
     78     net::AddressList address_list;
     79     if (!StringAndPortToAddressList(address, port, &address_list)) {
     80       result = net::ERR_ADDRESS_INVALID;
     81       break;
     82     }
     83 
     84     socket_.reset(new net::TCPClientSocket(address_list, NULL,
     85                                            net::NetLog::Source()));
     86 
     87     connect_callback_ = callback;
     88     result = socket_->Connect(base::Bind(
     89         &TCPSocket::OnConnectComplete, base::Unretained(this)));
     90   } while (false);
     91 
     92   if (result != net::ERR_IO_PENDING)
     93     OnConnectComplete(result);
     94 }
     95 
     96 void TCPSocket::Disconnect() {
     97   is_connected_ = false;
     98   if (socket_.get())
     99     socket_->Disconnect();
    100   server_socket_.reset(NULL);
    101 }
    102 
    103 int TCPSocket::Bind(const std::string& address, int port) {
    104   return net::ERR_FAILED;
    105 }
    106 
    107 void TCPSocket::Read(int count,
    108                      const ReadCompletionCallback& callback) {
    109   DCHECK(!callback.is_null());
    110 
    111   if (socket_mode_ != CLIENT) {
    112     callback.Run(net::ERR_FAILED, NULL);
    113     return;
    114   }
    115 
    116   if (!read_callback_.is_null()) {
    117     callback.Run(net::ERR_IO_PENDING, NULL);
    118     return;
    119   } else {
    120     read_callback_ = callback;
    121   }
    122 
    123   int result = net::ERR_FAILED;
    124   scoped_refptr<net::IOBuffer> io_buffer;
    125   do {
    126     if (count < 0) {
    127       result = net::ERR_INVALID_ARGUMENT;
    128       break;
    129     }
    130 
    131     if (!socket_.get() || !IsConnected()) {
    132         result = net::ERR_SOCKET_NOT_CONNECTED;
    133         break;
    134     }
    135 
    136     io_buffer = new net::IOBuffer(count);
    137     result = socket_->Read(io_buffer.get(), count,
    138         base::Bind(&TCPSocket::OnReadComplete, base::Unretained(this),
    139             io_buffer));
    140   } while (false);
    141 
    142   if (result != net::ERR_IO_PENDING)
    143     OnReadComplete(io_buffer, result);
    144 }
    145 
    146 void TCPSocket::RecvFrom(int count,
    147                          const RecvFromCompletionCallback& callback) {
    148   callback.Run(net::ERR_FAILED, NULL, NULL, 0);
    149 }
    150 
    151 void TCPSocket::SendTo(scoped_refptr<net::IOBuffer> io_buffer,
    152                        int byte_count,
    153                        const std::string& address,
    154                        int port,
    155                        const CompletionCallback& callback) {
    156   callback.Run(net::ERR_FAILED);
    157 }
    158 
    159 bool TCPSocket::SetKeepAlive(bool enable, int delay) {
    160   if (!socket_.get())
    161     return false;
    162   return socket_->SetKeepAlive(enable, delay);
    163 }
    164 
    165 bool TCPSocket::SetNoDelay(bool no_delay) {
    166   if (!socket_.get())
    167     return false;
    168   return socket_->SetNoDelay(no_delay);
    169 }
    170 
    171 int TCPSocket::Listen(const std::string& address, int port, int backlog,
    172                       std::string* error_msg) {
    173   if (socket_mode_ == CLIENT) {
    174     *error_msg = kTCPSocketTypeInvalidError;
    175     return net::ERR_NOT_IMPLEMENTED;
    176   }
    177   DCHECK(!socket_.get());
    178   socket_mode_ = SERVER;
    179 
    180   scoped_ptr<net::IPEndPoint> bind_address(new net::IPEndPoint());
    181   if (!StringAndPortToIPEndPoint(address, port, bind_address.get()))
    182     return net::ERR_INVALID_ARGUMENT;
    183 
    184   if (!server_socket_.get()) {
    185     server_socket_.reset(new net::TCPServerSocket(NULL,
    186                                                   net::NetLog::Source()));
    187   }
    188   int result = server_socket_->Listen(*bind_address, backlog);
    189   if (result)
    190     *error_msg = kSocketListenError;
    191   return result;
    192 }
    193 
    194 void TCPSocket::Accept(const AcceptCompletionCallback &callback) {
    195   if (socket_mode_ != SERVER || !server_socket_.get()) {
    196     callback.Run(net::ERR_FAILED, NULL);
    197     return;
    198   }
    199 
    200   // Limits to only 1 blocked accept call.
    201   if (!accept_callback_.is_null()) {
    202     callback.Run(net::ERR_FAILED, NULL);
    203     return;
    204   }
    205 
    206   int result = server_socket_->Accept(&accept_socket_, base::Bind(
    207       &TCPSocket::OnAccept, base::Unretained(this)));
    208   if (result == net::ERR_IO_PENDING) {
    209     accept_callback_ = callback;
    210   } else if (result == net::OK) {
    211     accept_callback_ = callback;
    212     this->OnAccept(result);
    213   } else {
    214     callback.Run(result, NULL);
    215   }
    216 }
    217 
    218 bool TCPSocket::IsConnected() {
    219   RefreshConnectionStatus();
    220   return is_connected_;
    221 }
    222 
    223 bool TCPSocket::GetPeerAddress(net::IPEndPoint* address) {
    224   if (!socket_.get())
    225     return false;
    226   return !socket_->GetPeerAddress(address);
    227 }
    228 
    229 bool TCPSocket::GetLocalAddress(net::IPEndPoint* address) {
    230   if (socket_.get()) {
    231     return !socket_->GetLocalAddress(address);
    232   } else if (server_socket_.get()) {
    233     return !server_socket_->GetLocalAddress(address);
    234   } else {
    235     return false;
    236   }
    237 }
    238 
    239 Socket::SocketType TCPSocket::GetSocketType() const {
    240   return Socket::TYPE_TCP;
    241 }
    242 
    243 int TCPSocket::WriteImpl(net::IOBuffer* io_buffer,
    244                          int io_buffer_size,
    245                          const net::CompletionCallback& callback) {
    246   if (socket_mode_ != CLIENT)
    247     return net::ERR_FAILED;
    248   else if (!socket_.get() || !IsConnected())
    249     return net::ERR_SOCKET_NOT_CONNECTED;
    250   else
    251     return socket_->Write(io_buffer, io_buffer_size, callback);
    252 }
    253 
    254 void TCPSocket::RefreshConnectionStatus() {
    255   if (!is_connected_) return;
    256   if (server_socket_) return;
    257   if (!socket_->IsConnected()) {
    258     is_connected_ = false;
    259     socket_->Disconnect();
    260   }
    261 }
    262 
    263 void TCPSocket::OnConnectComplete(int result) {
    264   DCHECK(!connect_callback_.is_null());
    265   DCHECK(!is_connected_);
    266   is_connected_ = result == net::OK;
    267   connect_callback_.Run(result);
    268   connect_callback_.Reset();
    269 }
    270 
    271 void TCPSocket::OnReadComplete(scoped_refptr<net::IOBuffer> io_buffer,
    272                                int result) {
    273   DCHECK(!read_callback_.is_null());
    274   read_callback_.Run(result, io_buffer);
    275   read_callback_.Reset();
    276 }
    277 
    278 void TCPSocket::OnAccept(int result) {
    279   DCHECK(!accept_callback_.is_null());
    280   if (result == net::OK && accept_socket_.get()) {
    281     accept_callback_.Run(
    282         result, static_cast<net::TCPClientSocket*>(accept_socket_.release()));
    283   } else {
    284     accept_callback_.Run(result, NULL);
    285   }
    286   accept_callback_.Reset();
    287 }
    288 
    289 }  // namespace extensions
    290