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