Home | History | Annotate | Download | only in socket
      1 // Copyright (c) 2011 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 "net/socket/tcp_server_socket_libevent.h"
      6 
      7 #include <errno.h>
      8 #include <fcntl.h>
      9 #include <netdb.h>
     10 #include <sys/socket.h>
     11 
     12 #include "build/build_config.h"
     13 
     14 #if defined(OS_POSIX)
     15 #include <netinet/in.h>
     16 #endif
     17 #if defined(USE_SYSTEM_LIBEVENT)
     18 #include <event.h>
     19 #else
     20 #include "third_party/libevent/event.h"
     21 #endif
     22 
     23 #include "base/eintr_wrapper.h"
     24 #include "net/base/ip_endpoint.h"
     25 #include "net/base/net_errors.h"
     26 #include "net/base/net_util.h"
     27 #include "net/socket/tcp_client_socket.h"
     28 
     29 namespace net {
     30 
     31 namespace {
     32 
     33 const int kInvalidSocket = -1;
     34 
     35 }  // namespace
     36 
     37 TCPServerSocketLibevent::TCPServerSocketLibevent(
     38     net::NetLog* net_log,
     39     const net::NetLog::Source& source)
     40     : socket_(kInvalidSocket),
     41       accept_socket_(NULL),
     42       accept_callback_(NULL),
     43       net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) {
     44   scoped_refptr<NetLog::EventParameters> params;
     45   if (source.is_valid())
     46     params = new NetLogSourceParameter("source_dependency", source);
     47   net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, params);
     48 }
     49 
     50 TCPServerSocketLibevent::~TCPServerSocketLibevent() {
     51   if (socket_ != kInvalidSocket)
     52     Close();
     53   net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE, NULL);
     54 }
     55 
     56 int TCPServerSocketLibevent::Listen(const IPEndPoint& address, int backlog) {
     57   DCHECK(CalledOnValidThread());
     58   DCHECK_GT(backlog, 0);
     59   DCHECK_EQ(socket_, kInvalidSocket);
     60 
     61   socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     62   if (socket_ < 0) {
     63     PLOG(ERROR) << "socket() returned an error";
     64     return MapSystemError(errno);
     65   }
     66 
     67   if (SetNonBlocking(socket_)) {
     68     int result = MapSystemError(errno);
     69     Close();
     70     return result;
     71   }
     72 
     73   struct sockaddr_storage addr_storage;
     74   size_t addr_len = sizeof(addr_storage);
     75   struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage);
     76   if (!address.ToSockAddr(addr, &addr_len))
     77     return ERR_INVALID_ARGUMENT;
     78 
     79   int result = bind(socket_, addr, addr_len);
     80   if (result < 0) {
     81     PLOG(ERROR) << "bind() returned an error";
     82     result = MapSystemError(errno);
     83     Close();
     84     return result;
     85   }
     86 
     87   result = listen(socket_, backlog);
     88   if (result < 0) {
     89     PLOG(ERROR) << "listen() returned an error";
     90     result = MapSystemError(errno);
     91     Close();
     92     return result;
     93   }
     94 
     95   return OK;
     96 }
     97 
     98 int TCPServerSocketLibevent::GetLocalAddress(IPEndPoint* address) const {
     99   DCHECK(CalledOnValidThread());
    100   DCHECK(address);
    101 
    102   struct sockaddr_storage addr_storage;
    103   socklen_t addr_len = sizeof(addr_storage);
    104   struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage);
    105   if (getsockname(socket_, addr, &addr_len) < 0)
    106     return MapSystemError(errno);
    107   if (!address->FromSockAddr(addr, addr_len))
    108     return ERR_FAILED;
    109 
    110   return OK;
    111 }
    112 
    113 int TCPServerSocketLibevent::Accept(
    114     scoped_ptr<ClientSocket>* socket, CompletionCallback* callback) {
    115   DCHECK(CalledOnValidThread());
    116   DCHECK(socket);
    117   DCHECK(callback);
    118   DCHECK(!accept_callback_);
    119 
    120   net_log_.BeginEvent(NetLog::TYPE_TCP_ACCEPT, NULL);
    121 
    122   int result = AcceptInternal(socket);
    123 
    124   if (result == ERR_IO_PENDING) {
    125     if (!MessageLoopForIO::current()->WatchFileDescriptor(
    126             socket_, true, MessageLoopForIO::WATCH_READ,
    127             &accept_socket_watcher_, this)) {
    128       PLOG(ERROR) << "WatchFileDescriptor failed on read";
    129       return MapSystemError(errno);
    130     }
    131 
    132     accept_socket_ = socket;
    133     accept_callback_ = callback;
    134   }
    135 
    136   return result;
    137 }
    138 
    139 int TCPServerSocketLibevent::AcceptInternal(
    140     scoped_ptr<ClientSocket>* socket) {
    141   struct sockaddr_storage addr_storage;
    142   socklen_t addr_len = sizeof(addr_storage);
    143   struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage);
    144 
    145   int result = HANDLE_EINTR(accept(socket_, addr, &addr_len));
    146   if (result < 0) {
    147     int net_error = MapSystemError(errno);
    148     if (net_error != ERR_IO_PENDING)
    149       net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, net_error);
    150     return net_error;
    151   }
    152 
    153   IPEndPoint address;
    154   if (!address.FromSockAddr(addr, addr_len)) {
    155     NOTREACHED();
    156     if (HANDLE_EINTR(close(result)) < 0)
    157       PLOG(ERROR) << "close";
    158     net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, ERR_FAILED);
    159     return ERR_FAILED;
    160   }
    161   TCPClientSocket* tcp_socket = new TCPClientSocket(
    162       AddressList(address.address(), address.port(), false),
    163       net_log_.net_log(), net_log_.source());
    164   tcp_socket->AdoptSocket(result);
    165   socket->reset(tcp_socket);
    166   net_log_.EndEvent(NetLog::TYPE_TCP_ACCEPT,
    167                     make_scoped_refptr(new NetLogStringParameter(
    168                         "address", address.ToString())));
    169   return OK;
    170 }
    171 
    172 void TCPServerSocketLibevent::Close() {
    173   if (socket_ != kInvalidSocket) {
    174     if (HANDLE_EINTR(close(socket_)) < 0)
    175       PLOG(ERROR) << "close";
    176     socket_ = kInvalidSocket;
    177   }
    178 }
    179 
    180 void TCPServerSocketLibevent::OnFileCanReadWithoutBlocking(int fd) {
    181   DCHECK(CalledOnValidThread());
    182 
    183   int result = AcceptInternal(accept_socket_);
    184   if (result != ERR_IO_PENDING) {
    185     CompletionCallback* c = accept_callback_;
    186     accept_callback_ = NULL;
    187     accept_socket_ = NULL;
    188     c->Run(result);
    189   }
    190 }
    191 
    192 void TCPServerSocketLibevent::OnFileCanWriteWithoutBlocking(int fd) {
    193   NOTREACHED();
    194 }
    195 
    196 }  // namespace net
    197