1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/browser/api/socket/tcp_socket.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/lazy_instance.h"
85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/logging.h"
95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/macros.h"
10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/browser/api/api_resource.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/address_list.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/ip_endpoint.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/rand_callback.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/socket/tcp_client_socket.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions {
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kTCPSocketTypeInvalidError[] =
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "Cannot call both connect and listen on the same socket.";
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kSocketListenError[] = "Could not listen on the specified port.";
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)static base::LazyInstance<
24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    BrowserContextKeyedAPIFactory<ApiResourceManager<ResumableTCPSocket> > >
25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    g_factory = LAZY_INSTANCE_INITIALIZER;
264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// static
284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)template <>
29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)BrowserContextKeyedAPIFactory<ApiResourceManager<ResumableTCPSocket> >*
304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)ApiResourceManager<ResumableTCPSocket>::GetFactoryInstance() {
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return g_factory.Pointer();
324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)static base::LazyInstance<BrowserContextKeyedAPIFactory<
35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ApiResourceManager<ResumableTCPServerSocket> > > g_server_factory =
36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    LAZY_INSTANCE_INITIALIZER;
378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// static
398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)template <>
40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)BrowserContextKeyedAPIFactory<ApiResourceManager<ResumableTCPServerSocket> >*
418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)ApiResourceManager<ResumableTCPServerSocket>::GetFactoryInstance() {
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return g_server_factory.Pointer();
438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TCPSocket::TCPSocket(const std::string& owner_extension_id)
46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : Socket(owner_extension_id), socket_mode_(UNKNOWN) {}
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TCPSocket::TCPSocket(net::TCPClientSocket* tcp_client_socket,
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     const std::string& owner_extension_id,
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     bool is_connected)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : Socket(owner_extension_id),
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      socket_(tcp_client_socket),
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      socket_mode_(CLIENT) {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this->is_connected_ = is_connected;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TCPSocket::TCPSocket(net::TCPServerSocket* tcp_server_socket,
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     const std::string& owner_extension_id)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : Socket(owner_extension_id),
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      server_socket_(tcp_server_socket),
61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      socket_mode_(SERVER) {}
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TCPSocket* TCPSocket::CreateSocketForTesting(
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net::TCPClientSocket* tcp_client_socket,
667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::string& owner_extension_id,
677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    bool is_connected) {
687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return new TCPSocket(tcp_client_socket, owner_extension_id, is_connected);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TCPSocket* TCPSocket::CreateServerSocketForTesting(
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net::TCPServerSocket* tcp_server_socket,
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& owner_extension_id) {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return new TCPSocket(tcp_server_socket, owner_extension_id);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)TCPSocket::~TCPSocket() { Disconnect(); }
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TCPSocket::Connect(const std::string& address,
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        int port,
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        const CompletionCallback& callback) {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!callback.is_null());
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (socket_mode_ == SERVER || !connect_callback_.is_null()) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback.Run(net::ERR_CONNECTION_FAILED);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!server_socket_.get());
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  socket_mode_ = CLIENT;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  connect_callback_ = callback;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int result = net::ERR_CONNECTION_FAILED;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  do {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (is_connected_)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net::AddressList address_list;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!StringAndPortToAddressList(address, port, &address_list)) {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result = net::ERR_ADDRESS_INVALID;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    socket_.reset(
105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        new net::TCPClientSocket(address_list, NULL, net::NetLog::Source()));
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    connect_callback_ = callback;
108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    result = socket_->Connect(
109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        base::Bind(&TCPSocket::OnConnectComplete, base::Unretained(this)));
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } while (false);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result != net::ERR_IO_PENDING)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnConnectComplete(result);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TCPSocket::Disconnect() {
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_connected_ = false;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (socket_.get())
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    socket_->Disconnect();
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  server_socket_.reset(NULL);
1218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  connect_callback_.Reset();
1228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  read_callback_.Reset();
1238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  accept_callback_.Reset();
1248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  accept_socket_.reset(NULL);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TCPSocket::Bind(const std::string& address, int port) {
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return net::ERR_FAILED;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void TCPSocket::Read(int count, const ReadCompletionCallback& callback) {
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!callback.is_null());
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (socket_mode_ != CLIENT) {
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback.Run(net::ERR_FAILED, NULL);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!read_callback_.is_null()) {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback.Run(net::ERR_IO_PENDING, NULL);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (count < 0) {
1458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    callback.Run(net::ERR_INVALID_ARGUMENT, NULL);
1468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
1478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (!socket_.get() || !IsConnected()) {
1508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    callback.Run(net::ERR_SOCKET_NOT_CONNECTED, NULL);
1518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
1528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  read_callback_ = callback;
1558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  scoped_refptr<net::IOBuffer> io_buffer = new net::IOBuffer(count);
156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int result = socket_->Read(
157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      io_buffer.get(),
158a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      count,
159a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(
160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          &TCPSocket::OnReadComplete, base::Unretained(this), io_buffer));
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result != net::ERR_IO_PENDING)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnReadComplete(io_buffer, result);
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TCPSocket::RecvFrom(int count,
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const RecvFromCompletionCallback& callback) {
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  callback.Run(net::ERR_FAILED, NULL, NULL, 0);
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TCPSocket::SendTo(scoped_refptr<net::IOBuffer> io_buffer,
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       int byte_count,
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const std::string& address,
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       int port,
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const CompletionCallback& callback) {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  callback.Run(net::ERR_FAILED);
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TCPSocket::SetKeepAlive(bool enable, int delay) {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!socket_.get())
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return socket_->SetKeepAlive(enable, delay);
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TCPSocket::SetNoDelay(bool no_delay) {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!socket_.get())
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return socket_->SetNoDelay(no_delay);
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
191a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)int TCPSocket::Listen(const std::string& address,
192a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                      int port,
193a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                      int backlog,
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      std::string* error_msg) {
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (socket_mode_ == CLIENT) {
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *error_msg = kTCPSocketTypeInvalidError;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return net::ERR_NOT_IMPLEMENTED;
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!socket_.get());
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  socket_mode_ = SERVER;
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!server_socket_.get()) {
203a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    server_socket_.reset(new net::TCPServerSocket(NULL, net::NetLog::Source()));
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
206116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  int result = server_socket_->ListenWithAddressAndPort(address, port, backlog);
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *error_msg = kSocketListenError;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
212a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void TCPSocket::Accept(const AcceptCompletionCallback& callback) {
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (socket_mode_ != SERVER || !server_socket_.get()) {
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback.Run(net::ERR_FAILED, NULL);
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Limits to only 1 blocked accept call.
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!accept_callback_.is_null()) {
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback.Run(net::ERR_FAILED, NULL);
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
224a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int result = server_socket_->Accept(
225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      &accept_socket_,
226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&TCPSocket::OnAccept, base::Unretained(this)));
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result == net::ERR_IO_PENDING) {
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    accept_callback_ = callback;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (result == net::OK) {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    accept_callback_ = callback;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this->OnAccept(result);
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback.Run(result, NULL);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool TCPSocket::IsConnected() {
2387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  RefreshConnectionStatus();
2397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return is_connected_;
2407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TCPSocket::GetPeerAddress(net::IPEndPoint* address) {
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!socket_.get())
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !socket_->GetPeerAddress(address);
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TCPSocket::GetLocalAddress(net::IPEndPoint* address) {
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (socket_.get()) {
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return !socket_->GetLocalAddress(address);
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (server_socket_.get()) {
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return !server_socket_->GetLocalAddress(address);
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
258a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)Socket::SocketType TCPSocket::GetSocketType() const { return Socket::TYPE_TCP; }
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int TCPSocket::WriteImpl(net::IOBuffer* io_buffer,
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         int io_buffer_size,
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         const net::CompletionCallback& callback) {
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (socket_mode_ != CLIENT)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return net::ERR_FAILED;
2657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  else if (!socket_.get() || !IsConnected())
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return net::ERR_SOCKET_NOT_CONNECTED;
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return socket_->Write(io_buffer, io_buffer_size, callback);
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid TCPSocket::RefreshConnectionStatus() {
272a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!is_connected_)
273a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
274a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (server_socket_)
275a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return;
2767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!socket_->IsConnected()) {
2778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    Disconnect();
2787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
2797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TCPSocket::OnConnectComplete(int result) {
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!connect_callback_.is_null());
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!is_connected_);
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_connected_ = result == net::OK;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  connect_callback_.Run(result);
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  connect_callback_.Reset();
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TCPSocket::OnReadComplete(scoped_refptr<net::IOBuffer> io_buffer,
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               int result) {
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!read_callback_.is_null());
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  read_callback_.Run(result, io_buffer);
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  read_callback_.Reset();
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TCPSocket::OnAccept(int result) {
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!accept_callback_.is_null());
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result == net::OK && accept_socket_.get()) {
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    accept_callback_.Run(
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        result, static_cast<net::TCPClientSocket*>(accept_socket_.release()));
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    accept_callback_.Run(result, NULL);
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  accept_callback_.Reset();
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void TCPSocket::Release() {
3085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Release() is only invoked when the underlying sockets are taken (via
3095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // ClientStream()) by TLSSocket. TLSSocket only supports CLIENT-mode
3105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // sockets.
3115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(!server_socket_.release() && !accept_socket_.release() &&
3125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)         socket_mode_ == CLIENT)
3135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      << "Called in server mode.";
3145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Release() doesn't disconnect the underlying sockets, but it does
3165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // disconnect them from this TCPSocket.
3175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  is_connected_ = false;
3185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  connect_callback_.Reset();
3205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  read_callback_.Reset();
3215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  accept_callback_.Reset();
3225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(socket_.get()) << "Called on null client socket.";
3245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ignore_result(socket_.release());
3255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)net::TCPClientSocket* TCPSocket::ClientStream() {
3285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (socket_mode_ != CLIENT || GetSocketType() != TYPE_TCP)
3295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return NULL;
3305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return socket_.get();
3315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool TCPSocket::HasPendingRead() const {
3345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return !read_callback_.is_null();
3355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)ResumableTCPSocket::ResumableTCPSocket(const std::string& owner_extension_id)
3384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    : TCPSocket(owner_extension_id),
3394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      persistent_(false),
3404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      buffer_size_(0),
341a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      paused_(false) {}
3424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)ResumableTCPSocket::ResumableTCPSocket(net::TCPClientSocket* tcp_client_socket,
3448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       const std::string& owner_extension_id,
3458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                       bool is_connected)
3468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    : TCPSocket(tcp_client_socket, owner_extension_id, is_connected),
3478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      persistent_(false),
3488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      buffer_size_(0),
349a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      paused_(false) {}
3508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
351a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool ResumableTCPSocket::IsPersistent() const { return persistent(); }
3528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
3538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)ResumableTCPServerSocket::ResumableTCPServerSocket(
3548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    const std::string& owner_extension_id)
355a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : TCPSocket(owner_extension_id), persistent_(false), paused_(false) {}
3568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
357a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool ResumableTCPServerSocket::IsPersistent() const { return persistent(); }
3584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace extensions
360