• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
TCPServerSocketLibevent(net::NetLog * net_log,const net::NetLog::Source & source)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 
~TCPServerSocketLibevent()50 TCPServerSocketLibevent::~TCPServerSocketLibevent() {
51   if (socket_ != kInvalidSocket)
52     Close();
53   net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE, NULL);
54 }
55 
Listen(const IPEndPoint & address,int backlog)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 
GetLocalAddress(IPEndPoint * address) const98 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 
Accept(scoped_ptr<ClientSocket> * socket,CompletionCallback * callback)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 
AcceptInternal(scoped_ptr<ClientSocket> * socket)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 
Close()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 
OnFileCanReadWithoutBlocking(int fd)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 
OnFileCanWriteWithoutBlocking(int fd)192 void TCPServerSocketLibevent::OnFileCanWriteWithoutBlocking(int fd) {
193   NOTREACHED();
194 }
195 
196 }  // namespace net
197