OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 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/socket_libevent.h" | |
6 | |
7 #include <errno.h> | |
8 #include <netinet/in.h> | |
9 #include <sys/socket.h> | |
10 | |
11 #include "base/callback_helpers.h" | |
12 #include "base/logging.h" | |
13 #include "base/posix/eintr_wrapper.h" | |
14 #include "net/base/io_buffer.h" | |
15 #include "net/base/ip_endpoint.h" | |
16 #include "net/base/net_errors.h" | |
17 #include "net/base/net_util.h" | |
18 | |
19 namespace net { | |
20 | |
21 namespace { | |
22 | |
23 int MapAcceptError(int os_error) { | |
24 switch (os_error) { | |
25 // If the client aborts the connection before the server calls accept, | |
26 // POSIX specifies accept should fail with ECONNABORTED. The server can | |
27 // ignore the error and just call accept again, so we map the error to | |
28 // ERR_IO_PENDING. See UNIX Network Programming, Vol. 1, 3rd Ed., Sec. | |
29 // 5.11, "Connection Abort before accept Returns". | |
30 case ECONNABORTED: | |
31 return ERR_IO_PENDING; | |
32 default: | |
33 return MapSystemError(os_error); | |
34 } | |
35 } | |
36 | |
37 int MapConnectError(int os_error) { | |
38 switch (os_error) { | |
39 case EINPROGRESS: | |
40 return ERR_IO_PENDING; | |
41 case EACCES: | |
42 return ERR_NETWORK_ACCESS_DENIED; | |
43 case ETIMEDOUT: | |
44 return ERR_CONNECTION_TIMED_OUT; | |
45 default: { | |
46 int net_error = MapSystemError(os_error); | |
47 if (net_error == ERR_FAILED) | |
48 return ERR_CONNECTION_FAILED; // More specific than ERR_FAILED. | |
49 return net_error; | |
50 } | |
51 } | |
52 } | |
53 | |
54 void CopyAddress(const SockaddrStorage& from, SockaddrStorage* to) { | |
55 // SockaddrStorage doesn't have correct copy constructor. Need to copy | |
56 // members manually. | |
mmenke
2014/06/26 15:36:11
I think it would make more sense to give SockaddrS
byungchul
2014/06/26 18:09:23
Done.
| |
57 to->addr_len = from.addr_len; | |
58 memcpy(to->addr, from.addr, from.addr_len); | |
59 } | |
60 | |
61 } // namespace | |
62 | |
63 SocketLibevent::SocketLibevent() | |
64 : socket_fd_(kInvalidSocket), | |
65 read_buf_len_(0), | |
66 write_buf_len_(0), | |
67 waiting_connect_(false) { | |
68 } | |
69 | |
70 SocketLibevent::~SocketLibevent() { | |
71 Close(); | |
72 } | |
73 | |
74 int SocketLibevent::Open(int address_family) { | |
75 DCHECK(thread_checker_.CalledOnValidThread()); | |
76 DCHECK_EQ(socket_fd_, kInvalidSocket); | |
mmenke
2014/06/26 15:36:11
Put expected before actual (Matters more for EXPEC
byungchul
2014/06/26 18:09:23
Done.
| |
77 | |
78 socket_fd_ = CreatePlatformSocket( | |
79 address_family, | |
80 SOCK_STREAM, | |
81 address_family == AF_UNIX ? 0 : IPPROTO_TCP); | |
mmenke
2014/06/26 15:36:11
Maybe DCHECK on address family? Or just take prot
byungchul
2014/06/26 18:09:23
Done.
| |
82 if (socket_fd_ < 0) { | |
83 PLOG(ERROR) << "CreatePlatformSocket() returned an error, errno=" << errno; | |
84 return MapSystemError(errno); | |
85 } | |
86 | |
87 if (SetNonBlocking(socket_fd_)) { | |
88 int rv = MapSystemError(errno); | |
89 Close(); | |
90 return rv; | |
91 } | |
92 | |
93 return OK; | |
94 } | |
95 | |
96 int SocketLibevent::AdoptConnectedSocket(SocketDescriptor socket, | |
97 const SockaddrStorage& address) { | |
98 DCHECK(thread_checker_.CalledOnValidThread()); | |
99 DCHECK_EQ(socket_fd_, kInvalidSocket); | |
mmenke
2014/06/26 15:36:11
nit: Switch order (Not going to point out the res
byungchul
2014/06/26 18:09:23
Done.
| |
100 | |
101 socket_fd_ = socket; | |
102 | |
103 if (SetNonBlocking(socket_fd_)) { | |
104 int rv = MapSystemError(errno); | |
105 Close(); | |
106 return rv; | |
107 } | |
108 | |
109 SetPeerAddress(address); | |
110 return OK; | |
111 } | |
112 | |
113 int SocketLibevent::Bind(const SockaddrStorage& address) { | |
114 DCHECK(thread_checker_.CalledOnValidThread()); | |
115 DCHECK_NE(socket_fd_, kInvalidSocket); | |
116 | |
117 int rv = bind(socket_fd_, address.addr, address.addr_len); | |
118 if (rv < 0) { | |
119 PLOG(ERROR) << "bind() returned an error, errno=" << errno; | |
120 return MapSystemError(errno); | |
121 } | |
122 | |
123 return OK; | |
124 } | |
125 | |
126 int SocketLibevent::Listen(int backlog) { | |
127 DCHECK(thread_checker_.CalledOnValidThread()); | |
128 DCHECK_NE(socket_fd_, kInvalidSocket); | |
129 DCHECK_GT(backlog, 0); | |
130 | |
131 int rv = listen(socket_fd_, backlog); | |
132 if (rv < 0) { | |
133 PLOG(ERROR) << "listen() returned an error, errno=" << errno; | |
134 return MapSystemError(errno); | |
135 } | |
136 | |
137 return OK; | |
138 } | |
139 | |
140 int SocketLibevent::Accept(scoped_ptr<SocketLibevent>* socket, | |
141 const CompletionCallback& callback) { | |
142 DCHECK(thread_checker_.CalledOnValidThread()); | |
143 DCHECK_NE(socket_fd_, kInvalidSocket); | |
144 DCHECK(accept_callback_.is_null()); | |
145 DCHECK(socket); | |
146 DCHECK(!callback.is_null()); | |
147 | |
148 int rv = DoAccept(socket); | |
149 if (rv != ERR_IO_PENDING) | |
150 return rv; | |
151 | |
152 if (!base::MessageLoopForIO::current()->WatchFileDescriptor( | |
153 socket_fd_, true, base::MessageLoopForIO::WATCH_READ, | |
154 &accept_socket_watcher_, this)) { | |
155 PLOG(ERROR) << "WatchFileDescriptor failed on accept, errno " << errno; | |
156 return MapSystemError(errno); | |
157 } | |
158 | |
159 accept_socket_ = socket; | |
160 accept_callback_ = callback; | |
161 return ERR_IO_PENDING; | |
162 } | |
163 | |
164 int SocketLibevent::Connect(const SockaddrStorage& address, | |
165 const CompletionCallback& callback) { | |
166 DCHECK(thread_checker_.CalledOnValidThread()); | |
167 DCHECK_NE(socket_fd_, kInvalidSocket); | |
168 DCHECK(!waiting_connect_); | |
169 DCHECK(!callback.is_null()); | |
mmenke
2014/06/26 15:36:11
Maybe throw in a DCHECK(!IsConnected()); while you
byungchul
2014/06/26 18:09:23
I have a bit concern about calling IsConnected() w
| |
170 | |
171 SetPeerAddress(address); | |
172 | |
173 int rv = DoConnect(); | |
174 if (rv != ERR_IO_PENDING) { | |
175 return rv; | |
176 } | |
mmenke
2014/06/26 15:36:10
nit: Should be consistent about using braces for
byungchul
2014/06/26 18:09:23
Done. Though I understand it is common, it introdu
| |
177 | |
178 if (!base::MessageLoopForIO::current()->WatchFileDescriptor( | |
179 socket_fd_, true, base::MessageLoopForIO::WATCH_WRITE, | |
180 &write_socket_watcher_, this)) { | |
181 PLOG(ERROR) << "WatchFileDescriptor failed on connect, errno " << errno; | |
182 return MapSystemError(errno); | |
183 } | |
184 | |
185 write_callback_ = callback; | |
186 waiting_connect_ = true; | |
187 return ERR_IO_PENDING; | |
188 } | |
189 | |
190 bool SocketLibevent::IsConnected() const { | |
191 DCHECK(thread_checker_.CalledOnValidThread()); | |
192 | |
193 if (socket_fd_ == kInvalidSocket || waiting_connect_) | |
194 return false; | |
195 | |
196 // Checks if connection is alive. | |
197 char c; | |
198 int rv = HANDLE_EINTR(recv(socket_fd_, &c, 1, MSG_PEEK)); | |
199 if (rv == 0) | |
200 return false; | |
201 if (rv == -1 && errno != EAGAIN && errno != EWOULDBLOCK) | |
202 return false; | |
203 | |
204 return true; | |
205 } | |
206 | |
207 bool SocketLibevent::IsConnectedAndIdle() const { | |
208 DCHECK(thread_checker_.CalledOnValidThread()); | |
209 | |
210 if (socket_fd_ == kInvalidSocket || waiting_connect_) | |
211 return false; | |
212 | |
213 // Check if connection is alive and we haven't received any data | |
214 // unexpectedly. | |
215 char c; | |
216 int rv = HANDLE_EINTR(recv(socket_fd_, &c, 1, MSG_PEEK)); | |
217 if (rv >= 0) | |
218 return false; | |
219 if (errno != EAGAIN && errno != EWOULDBLOCK) | |
220 return false; | |
221 | |
222 return true; | |
223 } | |
224 | |
225 int SocketLibevent::Read(IOBuffer* buf, | |
226 int buf_len, | |
227 const CompletionCallback& callback) { | |
228 DCHECK(thread_checker_.CalledOnValidThread()); | |
229 DCHECK_NE(socket_fd_, kInvalidSocket); | |
230 DCHECK(!waiting_connect_); | |
231 DCHECK(read_callback_.is_null()); | |
232 // Synchronous operation not supported | |
233 DCHECK(!callback.is_null()); | |
234 DCHECK_GT(buf_len, 0); | |
235 | |
236 int rv = DoRead(buf, buf_len); | |
237 if (rv != ERR_IO_PENDING) | |
238 return rv; | |
239 | |
240 if (!base::MessageLoopForIO::current()->WatchFileDescriptor( | |
241 socket_fd_, true, base::MessageLoopForIO::WATCH_READ, | |
242 &read_socket_watcher_, this)) { | |
243 PLOG(ERROR) << "WatchFileDescriptor failed on read, errno " << errno; | |
244 return MapSystemError(errno); | |
245 } | |
246 | |
247 read_buf_ = buf; | |
248 read_buf_len_ = buf_len; | |
249 read_callback_ = callback; | |
250 return ERR_IO_PENDING; | |
251 } | |
252 | |
253 int SocketLibevent::Write(IOBuffer* buf, | |
254 int buf_len, | |
255 const CompletionCallback& callback) { | |
256 DCHECK(thread_checker_.CalledOnValidThread()); | |
257 DCHECK_NE(socket_fd_, kInvalidSocket); | |
258 DCHECK(!waiting_connect_); | |
259 DCHECK(write_callback_.is_null()); | |
260 // Synchronous operation not supported | |
261 DCHECK(!callback.is_null()); | |
262 DCHECK_GT(buf_len, 0); | |
263 | |
264 int rv = DoWrite(buf, buf_len); | |
265 if (rv == ERR_IO_PENDING) | |
266 rv = WaitForWrite(buf, buf_len, callback); | |
267 return rv; | |
268 } | |
269 | |
270 int SocketLibevent::WaitForWrite(IOBuffer* buf, | |
271 int buf_len, | |
272 const CompletionCallback& callback) { | |
273 DCHECK(thread_checker_.CalledOnValidThread()); | |
274 DCHECK(write_callback_.is_null()); | |
275 // Synchronous operation not supported | |
276 DCHECK(!callback.is_null()); | |
277 DCHECK_GT(buf_len, 0); | |
278 | |
279 if (!base::MessageLoopForIO::current()->WatchFileDescriptor( | |
280 socket_fd_, true, base::MessageLoopForIO::WATCH_WRITE, | |
281 &write_socket_watcher_, this)) { | |
282 PLOG(ERROR) << "WatchFileDescriptor failed on write, errno " << errno; | |
283 return MapSystemError(errno); | |
284 } | |
285 | |
286 write_buf_ = buf; | |
287 write_buf_len_ = buf_len; | |
288 write_callback_ = callback; | |
289 return ERR_IO_PENDING; | |
290 } | |
291 | |
292 int SocketLibevent::GetLocalAddress(SockaddrStorage* address) const { | |
293 DCHECK(thread_checker_.CalledOnValidThread()); | |
294 DCHECK(address); | |
295 | |
296 if (getsockname(socket_fd_, address->addr, &address->addr_len) < 0) | |
297 return MapSystemError(errno); | |
298 return OK; | |
299 } | |
300 | |
301 int SocketLibevent::GetPeerAddress(SockaddrStorage* address) const { | |
302 DCHECK(thread_checker_.CalledOnValidThread()); | |
303 DCHECK(address); | |
304 | |
305 if (!HasPeerAddress()) | |
306 return ERR_SOCKET_NOT_CONNECTED; | |
307 | |
308 CopyAddress(*peer_address_, address); | |
309 return OK; | |
310 } | |
311 | |
312 void SocketLibevent::SetPeerAddress(const SockaddrStorage& address) { | |
313 DCHECK(thread_checker_.CalledOnValidThread()); | |
314 // |peer_address_| will be non-NULL if Connect() has been called. Unless | |
315 // Close() is called to reset the internal state, a second call to Connect() | |
316 // is not allowed. | |
317 // Please note that we don't allow a second Connect() even if the previous | |
318 // Connect() has failed. Connecting the same |socket_| again after a | |
319 // connection attempt failed results in unspecified behavior according to | |
320 // POSIX. | |
321 DCHECK(!peer_address_); | |
322 peer_address_.reset(new SockaddrStorage); | |
323 CopyAddress(address, peer_address_.get()); | |
324 } | |
325 | |
326 bool SocketLibevent::HasPeerAddress() const { | |
327 DCHECK(thread_checker_.CalledOnValidThread()); | |
328 return peer_address_ != NULL; | |
329 } | |
330 | |
331 void SocketLibevent::Close() { | |
332 DCHECK(thread_checker_.CalledOnValidThread()); | |
333 | |
334 bool ok = accept_socket_watcher_.StopWatchingFileDescriptor(); | |
335 DCHECK(ok); | |
336 ok = read_socket_watcher_.StopWatchingFileDescriptor(); | |
337 DCHECK(ok); | |
338 ok = write_socket_watcher_.StopWatchingFileDescriptor(); | |
339 DCHECK(ok); | |
340 | |
341 if (socket_fd_ != kInvalidSocket) { | |
342 if (IGNORE_EINTR(close(socket_fd_)) < 0) | |
343 PLOG(ERROR) << "close() returned an error, errno=" << errno; | |
344 socket_fd_ = kInvalidSocket; | |
345 } | |
346 | |
347 if (!accept_callback_.is_null()) { | |
348 accept_socket_ = NULL; | |
349 accept_callback_.Reset(); | |
350 } | |
351 | |
352 if (!read_callback_.is_null()) { | |
353 read_buf_ = NULL; | |
354 read_buf_len_ = 0; | |
355 read_callback_.Reset(); | |
356 } | |
357 | |
358 if (!write_callback_.is_null()) { | |
359 write_buf_ = NULL; | |
360 write_buf_len_ = 0; | |
361 write_callback_.Reset(); | |
362 } | |
363 | |
364 waiting_connect_ = false; | |
365 peer_address_.reset(); | |
366 } | |
367 | |
368 void SocketLibevent::OnFileCanReadWithoutBlocking(int fd) { | |
369 DCHECK(!accept_callback_.is_null() || !read_callback_.is_null()); | |
370 if (!accept_callback_.is_null()) { | |
371 AcceptCompleted(); | |
372 } else { // !read_callback_.is_null() | |
373 ReadCompleted(); | |
374 } | |
375 } | |
376 | |
377 void SocketLibevent::OnFileCanWriteWithoutBlocking(int fd) { | |
378 DCHECK(!write_callback_.is_null()); | |
379 if (waiting_connect_) { | |
380 ConnectCompleted(); | |
381 } else { | |
382 WriteCompleted(); | |
383 } | |
384 } | |
385 | |
386 int SocketLibevent::DoAccept(scoped_ptr<SocketLibevent>* socket) { | |
387 SockaddrStorage new_peer_address; | |
388 int new_socket = HANDLE_EINTR(accept(socket_fd_, | |
389 new_peer_address.addr, | |
390 &new_peer_address.addr_len)); | |
391 if (new_socket < 0) | |
392 return MapAcceptError(errno); | |
393 | |
394 scoped_ptr<SocketLibevent> accepted_socket(new SocketLibevent); | |
395 int rv = accepted_socket->AdoptConnectedSocket(new_socket, new_peer_address); | |
396 if (rv != OK) | |
397 return rv; | |
398 | |
399 *socket = accepted_socket.Pass(); | |
400 return OK; | |
401 } | |
402 | |
403 void SocketLibevent::AcceptCompleted() { | |
404 DCHECK(accept_socket_); | |
405 int rv = DoAccept(accept_socket_); | |
406 if (rv == ERR_IO_PENDING) | |
407 return; | |
408 | |
409 bool ok = accept_socket_watcher_.StopWatchingFileDescriptor(); | |
410 DCHECK(ok); | |
411 accept_socket_ = NULL; | |
412 base::ResetAndReturn(&accept_callback_).Run(rv); | |
413 } | |
414 | |
415 int SocketLibevent::DoConnect() { | |
416 int rv = HANDLE_EINTR(connect(socket_fd_, | |
417 peer_address_->addr, | |
418 peer_address_->addr_len)); | |
419 DCHECK_LE(rv, 0); | |
420 return rv == OK ? OK : MapConnectError(errno); | |
mmenke
2014/06/26 15:36:11
the first "OK" should be a "0"
byungchul
2014/06/26 18:09:23
Done.
| |
421 } | |
422 | |
423 void SocketLibevent::ConnectCompleted() { | |
424 // Get the error that connect() completed with. | |
425 int os_error = 0; | |
426 socklen_t len = sizeof(os_error); | |
427 if (getsockopt(socket_fd_, SOL_SOCKET, SO_ERROR, &os_error, &len) < 0) | |
428 os_error = errno; | |
429 | |
430 int rv = MapConnectError(os_error); | |
431 if (rv == ERR_IO_PENDING) | |
432 return; | |
433 | |
434 bool ok = write_socket_watcher_.StopWatchingFileDescriptor(); | |
435 DCHECK(ok); | |
436 waiting_connect_ = false; | |
437 base::ResetAndReturn(&write_callback_).Run(rv); | |
438 } | |
439 | |
440 int SocketLibevent::DoRead(IOBuffer* buf, int buf_len) { | |
441 int rv = HANDLE_EINTR(read(socket_fd_, buf->data(), buf_len)); | |
442 return rv >= 0 ? rv : MapSystemError(errno); | |
443 } | |
444 | |
445 void SocketLibevent::ReadCompleted() { | |
446 int rv = DoRead(read_buf_, read_buf_len_); | |
447 if (rv == ERR_IO_PENDING) | |
448 return; | |
449 | |
450 bool ok = read_socket_watcher_.StopWatchingFileDescriptor(); | |
451 DCHECK(ok); | |
452 read_buf_ = NULL; | |
453 read_buf_len_ = 0; | |
454 base::ResetAndReturn(&read_callback_).Run(rv); | |
455 } | |
456 | |
457 int SocketLibevent::DoWrite(IOBuffer* buf, int buf_len) { | |
458 int rv = HANDLE_EINTR(write(socket_fd_, buf->data(), buf_len)); | |
459 return rv >= 0 ? rv : MapSystemError(errno); | |
460 } | |
461 | |
462 void SocketLibevent::WriteCompleted() { | |
463 int rv = DoWrite(write_buf_, write_buf_len_); | |
464 if (rv == ERR_IO_PENDING) | |
465 return; | |
466 | |
467 bool ok = write_socket_watcher_.StopWatchingFileDescriptor(); | |
468 DCHECK(ok); | |
469 write_buf_ = NULL; | |
470 write_buf_len_ = 0; | |
471 base::ResetAndReturn(&write_callback_).Run(rv); | |
472 } | |
473 | |
474 } // namespace net | |
OLD | NEW |