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 "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 
     18 #include "base/posix/eintr_wrapper.h"
     19 #include "net/base/ip_endpoint.h"
     20 #include "net/base/net_errors.h"
     21 #include "net/base/net_util.h"
     22 #include "net/socket/socket_net_log_params.h"
     23 #include "net/socket/tcp_client_socket.h"
     24 
     25 namespace net {
     26 
     27 namespace {
     28 
     29 const int kInvalidSocket = -1;
     30 
     31 }  // namespace
     32 
     33 TCPServerSocketLibevent::TCPServerSocketLibevent(
     34     net::NetLog* net_log,
     35     const net::NetLog::Source& source)
     36     : socket_(kInvalidSocket),
     37       accept_socket_(NULL),
     38       net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) {
     39   net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE,
     40                       source.ToEventParametersCallback());
     41 }
     42 
     43 TCPServerSocketLibevent::~TCPServerSocketLibevent() {
     44   if (socket_ != kInvalidSocket)
     45     Close();
     46   net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE);
     47 }
     48 
     49 int TCPServerSocketLibevent::Listen(const IPEndPoint& address, int backlog) {
     50   DCHECK(CalledOnValidThread());
     51   DCHECK_GT(backlog, 0);
     52   DCHECK_EQ(socket_, kInvalidSocket);
     53 
     54   socket_ = socket(address.GetSockAddrFamily(), SOCK_STREAM, IPPROTO_TCP);
     55   if (socket_ < 0) {
     56     PLOG(ERROR) << "socket() returned an error";
     57     return MapSystemError(errno);
     58   }
     59 
     60   if (SetNonBlocking(socket_)) {
     61     int result = MapSystemError(errno);
     62     Close();
     63     return result;
     64   }
     65 
     66   int result = SetSocketOptions();
     67   if (result != OK) {
     68     Close();
     69     return result;
     70   }
     71 
     72   SockaddrStorage storage;
     73   if (!address.ToSockAddr(storage.addr, &storage.addr_len)) {
     74     Close();
     75     return ERR_ADDRESS_INVALID;
     76   }
     77 
     78   result = bind(socket_, storage.addr, storage.addr_len);
     79   if (result < 0) {
     80     PLOG(ERROR) << "bind() returned an error";
     81     result = MapSystemError(errno);
     82     Close();
     83     return result;
     84   }
     85 
     86   result = listen(socket_, backlog);
     87   if (result < 0) {
     88     PLOG(ERROR) << "listen() returned an error";
     89     result = MapSystemError(errno);
     90     Close();
     91     return result;
     92   }
     93 
     94   return OK;
     95 }
     96 
     97 int TCPServerSocketLibevent::GetLocalAddress(IPEndPoint* address) const {
     98   DCHECK(CalledOnValidThread());
     99   DCHECK(address);
    100 
    101   SockaddrStorage storage;
    102   if (getsockname(socket_, storage.addr, &storage.addr_len) < 0)
    103     return MapSystemError(errno);
    104   if (!address->FromSockAddr(storage.addr, storage.addr_len))
    105     return ERR_FAILED;
    106 
    107   return OK;
    108 }
    109 
    110 int TCPServerSocketLibevent::Accept(
    111     scoped_ptr<StreamSocket>* socket, const CompletionCallback& callback) {
    112   DCHECK(CalledOnValidThread());
    113   DCHECK(socket);
    114   DCHECK(!callback.is_null());
    115   DCHECK(accept_callback_.is_null());
    116 
    117   net_log_.BeginEvent(NetLog::TYPE_TCP_ACCEPT);
    118 
    119   int result = AcceptInternal(socket);
    120 
    121   if (result == ERR_IO_PENDING) {
    122     if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
    123             socket_, true, base::MessageLoopForIO::WATCH_READ,
    124             &accept_socket_watcher_, this)) {
    125       PLOG(ERROR) << "WatchFileDescriptor failed on read";
    126       return MapSystemError(errno);
    127     }
    128 
    129     accept_socket_ = socket;
    130     accept_callback_ = callback;
    131   }
    132 
    133   return result;
    134 }
    135 
    136 int TCPServerSocketLibevent::SetSocketOptions() {
    137   // SO_REUSEADDR is useful for server sockets to bind to a recently unbound
    138   // port. When a socket is closed, the end point changes its state to TIME_WAIT
    139   // and wait for 2 MSL (maximum segment lifetime) to ensure the remote peer
    140   // acknowledges its closure. For server sockets, it is usually safe to
    141   // bind to a TIME_WAIT end point immediately, which is a widely adopted
    142   // behavior.
    143   //
    144   // Note that on *nix, SO_REUSEADDR does not enable the TCP socket to bind to
    145   // an end point that is already bound by another socket. To do that one must
    146   // set SO_REUSEPORT instead. This option is not provided on Linux prior
    147   // to 3.9.
    148   //
    149   // SO_REUSEPORT is provided in MacOS X and iOS.
    150   int true_value = 1;
    151   int rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &true_value,
    152                       sizeof(true_value));
    153   if (rv < 0)
    154     return MapSystemError(errno);
    155   return OK;
    156 }
    157 
    158 int TCPServerSocketLibevent::AcceptInternal(
    159     scoped_ptr<StreamSocket>* socket) {
    160   SockaddrStorage storage;
    161   int new_socket = HANDLE_EINTR(accept(socket_,
    162                                        storage.addr,
    163                                        &storage.addr_len));
    164   if (new_socket < 0) {
    165     int net_error = MapSystemError(errno);
    166     if (net_error != ERR_IO_PENDING)
    167       net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, net_error);
    168     return net_error;
    169   }
    170 
    171   IPEndPoint address;
    172   if (!address.FromSockAddr(storage.addr, storage.addr_len)) {
    173     NOTREACHED();
    174     if (HANDLE_EINTR(close(new_socket)) < 0)
    175       PLOG(ERROR) << "close";
    176     net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, ERR_FAILED);
    177     return ERR_FAILED;
    178   }
    179   scoped_ptr<TCPClientSocket> tcp_socket(new TCPClientSocket(
    180       AddressList(address),
    181       net_log_.net_log(), net_log_.source()));
    182   int adopt_result = tcp_socket->AdoptSocket(new_socket);
    183   if (adopt_result != OK) {
    184     if (HANDLE_EINTR(close(new_socket)) < 0)
    185       PLOG(ERROR) << "close";
    186     net_log_.EndEventWithNetErrorCode(NetLog::TYPE_TCP_ACCEPT, adopt_result);
    187     return adopt_result;
    188   }
    189   socket->reset(tcp_socket.release());
    190   net_log_.EndEvent(NetLog::TYPE_TCP_ACCEPT,
    191                     CreateNetLogIPEndPointCallback(&address));
    192   return OK;
    193 }
    194 
    195 void TCPServerSocketLibevent::Close() {
    196   if (socket_ != kInvalidSocket) {
    197     bool ok = accept_socket_watcher_.StopWatchingFileDescriptor();
    198     DCHECK(ok);
    199     if (HANDLE_EINTR(close(socket_)) < 0)
    200       PLOG(ERROR) << "close";
    201     socket_ = kInvalidSocket;
    202   }
    203 }
    204 
    205 void TCPServerSocketLibevent::OnFileCanReadWithoutBlocking(int fd) {
    206   DCHECK(CalledOnValidThread());
    207 
    208   int result = AcceptInternal(accept_socket_);
    209   if (result != ERR_IO_PENDING) {
    210     accept_socket_ = NULL;
    211     bool ok = accept_socket_watcher_.StopWatchingFileDescriptor();
    212     DCHECK(ok);
    213     CompletionCallback callback = accept_callback_;
    214     accept_callback_.Reset();
    215     callback.Run(result);
    216   }
    217 }
    218 
    219 void TCPServerSocketLibevent::OnFileCanWriteWithoutBlocking(int fd) {
    220   NOTREACHED();
    221 }
    222 
    223 }  // namespace net
    224