blob: ae9bb1e3b78f8ca90f1e5c2d9ce4847d45dc2d6d [file] [log] [blame]
[email protected]2ef2b0e2014-07-09 21:12:341// 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
tfarina4eb7aad82015-09-14 17:10:345#include "net/socket/socket_posix.h"
[email protected]2ef2b0e2014-07-09 21:12:346
7#include <errno.h>
8#include <netinet/in.h>
9#include <sys/socket.h>
dchengc7eeda422015-12-26 03:56:4810#include <utility>
[email protected]2ef2b0e2014-07-09 21:12:3411
12#include "base/callback_helpers.h"
tfarina060df7e2015-12-16 05:15:3213#include "base/files/file_util.h"
[email protected]2ef2b0e2014-07-09 21:12:3414#include "base/logging.h"
15#include "base/posix/eintr_wrapper.h"
ssid6d6b40102016-04-05 18:59:5616#include "base/trace_event/trace_event.h"
davidben28150272016-06-06 21:03:1217#include "build/build_config.h"
[email protected]2ef2b0e2014-07-09 21:12:3418#include "net/base/io_buffer.h"
19#include "net/base/ip_endpoint.h"
20#include "net/base/net_errors.h"
tfarina3d87d7cd2016-01-13 02:26:5921#include "net/base/sockaddr_storage.h"
xunjieli0b7f5b62016-12-06 20:43:4822#include "net/base/trace_constants.h"
[email protected]2ef2b0e2014-07-09 21:12:3423
Sergey Ulanovbc1d87a2017-08-16 02:18:3924#if defined(OS_FUCHSIA)
25#include <poll.h>
26#include <sys/ioctl.h>
27#endif // OS_FUCHSIA
28
[email protected]2ef2b0e2014-07-09 21:12:3429namespace net {
30
31namespace {
32
33int MapAcceptError(int os_error) {
34 switch (os_error) {
35 // If the client aborts the connection before the server calls accept,
36 // POSIX specifies accept should fail with ECONNABORTED. The server can
37 // ignore the error and just call accept again, so we map the error to
38 // ERR_IO_PENDING. See UNIX Network Programming, Vol. 1, 3rd Ed., Sec.
39 // 5.11, "Connection Abort before accept Returns".
40 case ECONNABORTED:
41 return ERR_IO_PENDING;
42 default:
43 return MapSystemError(os_error);
44 }
45}
46
47int MapConnectError(int os_error) {
48 switch (os_error) {
49 case EINPROGRESS:
50 return ERR_IO_PENDING;
51 case EACCES:
52 return ERR_NETWORK_ACCESS_DENIED;
53 case ETIMEDOUT:
54 return ERR_CONNECTION_TIMED_OUT;
55 default: {
56 int net_error = MapSystemError(os_error);
57 if (net_error == ERR_FAILED)
58 return ERR_CONNECTION_FAILED; // More specific than ERR_FAILED.
59 return net_error;
60 }
61 }
62}
63
64} // namespace
65
tfarina4eb7aad82015-09-14 17:10:3466SocketPosix::SocketPosix()
[email protected]2ef2b0e2014-07-09 21:12:3467 : socket_fd_(kInvalidSocket),
ssid5dd4fb32017-02-16 23:57:1768 accept_socket_watcher_(FROM_HERE),
69 read_socket_watcher_(FROM_HERE),
[email protected]2ef2b0e2014-07-09 21:12:3470 read_buf_len_(0),
ssid5dd4fb32017-02-16 23:57:1771 write_socket_watcher_(FROM_HERE),
[email protected]2ef2b0e2014-07-09 21:12:3472 write_buf_len_(0),
tfarina4eb7aad82015-09-14 17:10:3473 waiting_connect_(false) {}
[email protected]2ef2b0e2014-07-09 21:12:3474
tfarina4eb7aad82015-09-14 17:10:3475SocketPosix::~SocketPosix() {
[email protected]2ef2b0e2014-07-09 21:12:3476 Close();
77}
78
tfarina4eb7aad82015-09-14 17:10:3479int SocketPosix::Open(int address_family) {
[email protected]2ef2b0e2014-07-09 21:12:3480 DCHECK(thread_checker_.CalledOnValidThread());
81 DCHECK_EQ(kInvalidSocket, socket_fd_);
82 DCHECK(address_family == AF_INET ||
83 address_family == AF_INET6 ||
84 address_family == AF_UNIX);
85
86 socket_fd_ = CreatePlatformSocket(
87 address_family,
88 SOCK_STREAM,
89 address_family == AF_UNIX ? 0 : IPPROTO_TCP);
90 if (socket_fd_ < 0) {
91 PLOG(ERROR) << "CreatePlatformSocket() returned an error, errno=" << errno;
92 return MapSystemError(errno);
93 }
94
tfarina060df7e2015-12-16 05:15:3295 if (!base::SetNonBlocking(socket_fd_)) {
[email protected]2ef2b0e2014-07-09 21:12:3496 int rv = MapSystemError(errno);
97 Close();
98 return rv;
99 }
100
101 return OK;
102}
103
tfarina4eb7aad82015-09-14 17:10:34104int SocketPosix::AdoptConnectedSocket(SocketDescriptor socket,
105 const SockaddrStorage& address) {
rvera26f0a1392017-05-02 22:25:44106 int rv = AdoptUnconnectedSocket(socket);
107 if (rv != OK)
108 return rv;
109
110 SetPeerAddress(address);
111 return OK;
112}
113
114int SocketPosix::AdoptUnconnectedSocket(SocketDescriptor socket) {
[email protected]2ef2b0e2014-07-09 21:12:34115 DCHECK(thread_checker_.CalledOnValidThread());
116 DCHECK_EQ(kInvalidSocket, socket_fd_);
117
118 socket_fd_ = socket;
119
tfarina060df7e2015-12-16 05:15:32120 if (!base::SetNonBlocking(socket_fd_)) {
[email protected]2ef2b0e2014-07-09 21:12:34121 int rv = MapSystemError(errno);
122 Close();
123 return rv;
124 }
125
[email protected]2ef2b0e2014-07-09 21:12:34126 return OK;
127}
128
tfarina4eb7aad82015-09-14 17:10:34129SocketDescriptor SocketPosix::ReleaseConnectedSocket() {
cmasoneca100d52014-09-03 18:11:11130 StopWatchingAndCleanUp();
131 SocketDescriptor socket_fd = socket_fd_;
132 socket_fd_ = kInvalidSocket;
133 return socket_fd;
134}
135
tfarina4eb7aad82015-09-14 17:10:34136int SocketPosix::Bind(const SockaddrStorage& address) {
[email protected]2ef2b0e2014-07-09 21:12:34137 DCHECK(thread_checker_.CalledOnValidThread());
138 DCHECK_NE(kInvalidSocket, socket_fd_);
139
140 int rv = bind(socket_fd_, address.addr, address.addr_len);
141 if (rv < 0) {
142 PLOG(ERROR) << "bind() returned an error, errno=" << errno;
143 return MapSystemError(errno);
144 }
145
146 return OK;
147}
148
tfarina4eb7aad82015-09-14 17:10:34149int SocketPosix::Listen(int backlog) {
[email protected]2ef2b0e2014-07-09 21:12:34150 DCHECK(thread_checker_.CalledOnValidThread());
151 DCHECK_NE(kInvalidSocket, socket_fd_);
152 DCHECK_LT(0, backlog);
153
154 int rv = listen(socket_fd_, backlog);
155 if (rv < 0) {
156 PLOG(ERROR) << "listen() returned an error, errno=" << errno;
157 return MapSystemError(errno);
158 }
159
160 return OK;
161}
162
danakj655b66c2016-04-16 00:51:38163int SocketPosix::Accept(std::unique_ptr<SocketPosix>* socket,
tfarina4eb7aad82015-09-14 17:10:34164 const CompletionCallback& callback) {
[email protected]2ef2b0e2014-07-09 21:12:34165 DCHECK(thread_checker_.CalledOnValidThread());
166 DCHECK_NE(kInvalidSocket, socket_fd_);
167 DCHECK(accept_callback_.is_null());
168 DCHECK(socket);
169 DCHECK(!callback.is_null());
170
171 int rv = DoAccept(socket);
172 if (rv != ERR_IO_PENDING)
173 return rv;
174
175 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
176 socket_fd_, true, base::MessageLoopForIO::WATCH_READ,
177 &accept_socket_watcher_, this)) {
178 PLOG(ERROR) << "WatchFileDescriptor failed on accept, errno " << errno;
179 return MapSystemError(errno);
180 }
181
182 accept_socket_ = socket;
183 accept_callback_ = callback;
184 return ERR_IO_PENDING;
185}
186
tfarina4eb7aad82015-09-14 17:10:34187int SocketPosix::Connect(const SockaddrStorage& address,
188 const CompletionCallback& callback) {
[email protected]2ef2b0e2014-07-09 21:12:34189 DCHECK(thread_checker_.CalledOnValidThread());
190 DCHECK_NE(kInvalidSocket, socket_fd_);
191 DCHECK(!waiting_connect_);
192 DCHECK(!callback.is_null());
193
194 SetPeerAddress(address);
195
196 int rv = DoConnect();
197 if (rv != ERR_IO_PENDING)
198 return rv;
199
200 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
201 socket_fd_, true, base::MessageLoopForIO::WATCH_WRITE,
202 &write_socket_watcher_, this)) {
203 PLOG(ERROR) << "WatchFileDescriptor failed on connect, errno " << errno;
204 return MapSystemError(errno);
205 }
206
sdefresne8df022f2016-09-20 13:54:26207 // There is a race-condition in the above code if the kernel receive a RST
208 // packet for the "connect" call before the registration of the socket file
209 // descriptor to the message loop pump. On most platform it is benign as the
210 // message loop pump is awakened for that socket in an error state, but on
211 // iOS this does not happens. Check the status of the socket at this point
212 // and if in error, consider the connection as failed.
213 int os_error = 0;
214 socklen_t len = sizeof(os_error);
215 if (getsockopt(socket_fd_, SOL_SOCKET, SO_ERROR, &os_error, &len) == 0) {
216 // TCPSocketPosix expects errno to be set.
217 errno = os_error;
218 }
219
220 rv = MapConnectError(errno);
221 if (rv != OK && rv != ERR_IO_PENDING) {
222 write_socket_watcher_.StopWatchingFileDescriptor();
223 return rv;
224 }
225
[email protected]2ef2b0e2014-07-09 21:12:34226 write_callback_ = callback;
227 waiting_connect_ = true;
228 return ERR_IO_PENDING;
229}
230
tfarina4eb7aad82015-09-14 17:10:34231bool SocketPosix::IsConnected() const {
[email protected]2ef2b0e2014-07-09 21:12:34232 DCHECK(thread_checker_.CalledOnValidThread());
233
234 if (socket_fd_ == kInvalidSocket || waiting_connect_)
235 return false;
236
Sergey Ulanovbc1d87a2017-08-16 02:18:39237#if !defined(OS_FUCHSIA)
[email protected]2ef2b0e2014-07-09 21:12:34238 // Checks if connection is alive.
239 char c;
240 int rv = HANDLE_EINTR(recv(socket_fd_, &c, 1, MSG_PEEK));
241 if (rv == 0)
242 return false;
243 if (rv == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
244 return false;
245
246 return true;
Sergey Ulanovbc1d87a2017-08-16 02:18:39247
248#else // OS_FUCHSIA
249 // Fuchsia currently doesn't support MSG_PEEK flag in recv(), so the code
250 // above doesn't work on Fuchsia. IsConnected() must return true if the
251 // connection is alive or if it was terminated but there is still data pending
252 // in the incoming buffer.
253 // 1. Check if the connection is alive using poll(POLLRDHUP).
254 // 2. If closed, then use ioctl(FIONREAD) to check if there is data to be
255 // read.
256 // TODO(bug 738275): Remove once MSG_PEEK is implemented on Fuchsia.
257 struct pollfd pollfd;
258 pollfd.fd = socket_fd_;
259 pollfd.events = POLLRDHUP;
260 pollfd.revents = 0;
261 const int poll_result = HANDLE_EINTR(poll(&pollfd, 1, 0));
262
263 if (poll_result == 1) {
264 int bytes_available;
265 int ioctl_result =
266 HANDLE_EINTR(ioctl(socket_fd_, FIONREAD, &bytes_available));
267 return ioctl_result == 0 && bytes_available > 0;
268 }
269
270 return poll_result == 0;
271#endif // OS_FUCHSIA
[email protected]2ef2b0e2014-07-09 21:12:34272}
273
tfarina4eb7aad82015-09-14 17:10:34274bool SocketPosix::IsConnectedAndIdle() const {
[email protected]2ef2b0e2014-07-09 21:12:34275 DCHECK(thread_checker_.CalledOnValidThread());
276
277 if (socket_fd_ == kInvalidSocket || waiting_connect_)
278 return false;
279
Sergey Ulanovbc1d87a2017-08-16 02:18:39280#if !defined(OS_FUCHSIA)
[email protected]2ef2b0e2014-07-09 21:12:34281 // Check if connection is alive and we haven't received any data
282 // unexpectedly.
283 char c;
284 int rv = HANDLE_EINTR(recv(socket_fd_, &c, 1, MSG_PEEK));
285 if (rv >= 0)
286 return false;
287 if (errno != EAGAIN && errno != EWOULDBLOCK)
288 return false;
289
290 return true;
Sergey Ulanovbc1d87a2017-08-16 02:18:39291
292#else // OS_FUCHSIA
293 // Fuchsia currently doesn't support MSG_PEEK flag in recv(), so the code
294 // above doesn't work on Fuchsia. Use poll(POLLIN) to check state of the
295 // socket. POLLIN is signaled if the socket is readable or if it was closed by
296 // the peer, i.e. the socket is connected and idle if and only if POLLIN is
297 // not signaled.
298 // TODO(bug 738275): Remove once MSG_PEEK is implemented.
299 struct pollfd pollfd;
300 pollfd.fd = socket_fd_;
301 pollfd.events = POLLIN;
302 pollfd.revents = 0;
303 const int poll_result = HANDLE_EINTR(poll(&pollfd, 1, 0));
304 return poll_result == 0;
305#endif // OS_FUCHSIA
[email protected]2ef2b0e2014-07-09 21:12:34306}
307
tfarina4eb7aad82015-09-14 17:10:34308int SocketPosix::Read(IOBuffer* buf,
309 int buf_len,
310 const CompletionCallback& callback) {
xunjieli321a96f32017-03-07 19:42:17311 // Use base::Unretained() is safe here because OnFileCanReadWithoutBlocking()
312 // won't be called if |this| is gone.
313 int rv =
314 ReadIfReady(buf, buf_len,
315 base::Bind(&SocketPosix::RetryRead, base::Unretained(this)));
316 if (rv == ERR_IO_PENDING) {
317 read_buf_ = buf;
318 read_buf_len_ = buf_len;
319 read_callback_ = callback;
320 }
321 return rv;
322}
323
324int SocketPosix::ReadIfReady(IOBuffer* buf,
325 int buf_len,
326 const CompletionCallback& callback) {
[email protected]2ef2b0e2014-07-09 21:12:34327 DCHECK(thread_checker_.CalledOnValidThread());
328 DCHECK_NE(kInvalidSocket, socket_fd_);
329 DCHECK(!waiting_connect_);
xunjieli321a96f32017-03-07 19:42:17330 CHECK(read_if_ready_callback_.is_null());
[email protected]2ef2b0e2014-07-09 21:12:34331 DCHECK(!callback.is_null());
332 DCHECK_LT(0, buf_len);
333
334 int rv = DoRead(buf, buf_len);
335 if (rv != ERR_IO_PENDING)
336 return rv;
337
338 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
339 socket_fd_, true, base::MessageLoopForIO::WATCH_READ,
340 &read_socket_watcher_, this)) {
341 PLOG(ERROR) << "WatchFileDescriptor failed on read, errno " << errno;
342 return MapSystemError(errno);
343 }
344
xunjieli321a96f32017-03-07 19:42:17345 read_if_ready_callback_ = callback;
[email protected]2ef2b0e2014-07-09 21:12:34346 return ERR_IO_PENDING;
347}
348
tfarina4eb7aad82015-09-14 17:10:34349int SocketPosix::Write(IOBuffer* buf,
350 int buf_len,
351 const CompletionCallback& callback) {
[email protected]2ef2b0e2014-07-09 21:12:34352 DCHECK(thread_checker_.CalledOnValidThread());
353 DCHECK_NE(kInvalidSocket, socket_fd_);
354 DCHECK(!waiting_connect_);
vitalybuka63b47542014-09-29 17:14:19355 CHECK(write_callback_.is_null());
[email protected]2ef2b0e2014-07-09 21:12:34356 // Synchronous operation not supported
357 DCHECK(!callback.is_null());
358 DCHECK_LT(0, buf_len);
359
360 int rv = DoWrite(buf, buf_len);
361 if (rv == ERR_IO_PENDING)
362 rv = WaitForWrite(buf, buf_len, callback);
363 return rv;
364}
365
tfarina4eb7aad82015-09-14 17:10:34366int SocketPosix::WaitForWrite(IOBuffer* buf,
367 int buf_len,
368 const CompletionCallback& callback) {
[email protected]2ef2b0e2014-07-09 21:12:34369 DCHECK(thread_checker_.CalledOnValidThread());
370 DCHECK_NE(kInvalidSocket, socket_fd_);
371 DCHECK(write_callback_.is_null());
372 // Synchronous operation not supported
373 DCHECK(!callback.is_null());
374 DCHECK_LT(0, buf_len);
375
376 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
377 socket_fd_, true, base::MessageLoopForIO::WATCH_WRITE,
378 &write_socket_watcher_, this)) {
379 PLOG(ERROR) << "WatchFileDescriptor failed on write, errno " << errno;
380 return MapSystemError(errno);
381 }
382
383 write_buf_ = buf;
384 write_buf_len_ = buf_len;
385 write_callback_ = callback;
386 return ERR_IO_PENDING;
387}
388
tfarina4eb7aad82015-09-14 17:10:34389int SocketPosix::GetLocalAddress(SockaddrStorage* address) const {
[email protected]2ef2b0e2014-07-09 21:12:34390 DCHECK(thread_checker_.CalledOnValidThread());
391 DCHECK(address);
392
393 if (getsockname(socket_fd_, address->addr, &address->addr_len) < 0)
394 return MapSystemError(errno);
395 return OK;
396}
397
tfarina4eb7aad82015-09-14 17:10:34398int SocketPosix::GetPeerAddress(SockaddrStorage* address) const {
[email protected]2ef2b0e2014-07-09 21:12:34399 DCHECK(thread_checker_.CalledOnValidThread());
400 DCHECK(address);
401
402 if (!HasPeerAddress())
403 return ERR_SOCKET_NOT_CONNECTED;
404
405 *address = *peer_address_;
406 return OK;
407}
408
tfarina4eb7aad82015-09-14 17:10:34409void SocketPosix::SetPeerAddress(const SockaddrStorage& address) {
[email protected]2ef2b0e2014-07-09 21:12:34410 DCHECK(thread_checker_.CalledOnValidThread());
411 // |peer_address_| will be non-NULL if Connect() has been called. Unless
412 // Close() is called to reset the internal state, a second call to Connect()
413 // is not allowed.
414 // Please note that we don't allow a second Connect() even if the previous
415 // Connect() has failed. Connecting the same |socket_| again after a
416 // connection attempt failed results in unspecified behavior according to
417 // POSIX.
418 DCHECK(!peer_address_);
419 peer_address_.reset(new SockaddrStorage(address));
420}
421
tfarina4eb7aad82015-09-14 17:10:34422bool SocketPosix::HasPeerAddress() const {
[email protected]2ef2b0e2014-07-09 21:12:34423 DCHECK(thread_checker_.CalledOnValidThread());
424 return peer_address_ != NULL;
425}
426
tfarina4eb7aad82015-09-14 17:10:34427void SocketPosix::Close() {
[email protected]2ef2b0e2014-07-09 21:12:34428 DCHECK(thread_checker_.CalledOnValidThread());
429
cmasoneca100d52014-09-03 18:11:11430 StopWatchingAndCleanUp();
[email protected]2ef2b0e2014-07-09 21:12:34431
432 if (socket_fd_ != kInvalidSocket) {
433 if (IGNORE_EINTR(close(socket_fd_)) < 0)
434 PLOG(ERROR) << "close() returned an error, errno=" << errno;
435 socket_fd_ = kInvalidSocket;
436 }
[email protected]2ef2b0e2014-07-09 21:12:34437}
438
svaldez58804c42015-10-06 00:13:47439void SocketPosix::DetachFromThread() {
440 thread_checker_.DetachFromThread();
441}
442
tfarina4eb7aad82015-09-14 17:10:34443void SocketPosix::OnFileCanReadWithoutBlocking(int fd) {
xunjieli0b7f5b62016-12-06 20:43:48444 TRACE_EVENT0(kNetTracingCategory,
445 "SocketPosix::OnFileCanReadWithoutBlocking");
[email protected]2ef2b0e2014-07-09 21:12:34446 if (!accept_callback_.is_null()) {
447 AcceptCompleted();
xunjieli321a96f32017-03-07 19:42:17448 } else {
449 DCHECK(!read_if_ready_callback_.is_null());
[email protected]2ef2b0e2014-07-09 21:12:34450 ReadCompleted();
451 }
452}
453
tfarina4eb7aad82015-09-14 17:10:34454void SocketPosix::OnFileCanWriteWithoutBlocking(int fd) {
[email protected]2ef2b0e2014-07-09 21:12:34455 DCHECK(!write_callback_.is_null());
456 if (waiting_connect_) {
457 ConnectCompleted();
458 } else {
459 WriteCompleted();
460 }
461}
462
danakj655b66c2016-04-16 00:51:38463int SocketPosix::DoAccept(std::unique_ptr<SocketPosix>* socket) {
[email protected]2ef2b0e2014-07-09 21:12:34464 SockaddrStorage new_peer_address;
465 int new_socket = HANDLE_EINTR(accept(socket_fd_,
466 new_peer_address.addr,
467 &new_peer_address.addr_len));
468 if (new_socket < 0)
469 return MapAcceptError(errno);
470
danakj655b66c2016-04-16 00:51:38471 std::unique_ptr<SocketPosix> accepted_socket(new SocketPosix);
[email protected]2ef2b0e2014-07-09 21:12:34472 int rv = accepted_socket->AdoptConnectedSocket(new_socket, new_peer_address);
473 if (rv != OK)
474 return rv;
475
dchengc7eeda422015-12-26 03:56:48476 *socket = std::move(accepted_socket);
[email protected]2ef2b0e2014-07-09 21:12:34477 return OK;
478}
479
tfarina4eb7aad82015-09-14 17:10:34480void SocketPosix::AcceptCompleted() {
[email protected]2ef2b0e2014-07-09 21:12:34481 DCHECK(accept_socket_);
482 int rv = DoAccept(accept_socket_);
483 if (rv == ERR_IO_PENDING)
484 return;
485
486 bool ok = accept_socket_watcher_.StopWatchingFileDescriptor();
487 DCHECK(ok);
488 accept_socket_ = NULL;
489 base::ResetAndReturn(&accept_callback_).Run(rv);
490}
491
tfarina4eb7aad82015-09-14 17:10:34492int SocketPosix::DoConnect() {
[email protected]2ef2b0e2014-07-09 21:12:34493 int rv = HANDLE_EINTR(connect(socket_fd_,
494 peer_address_->addr,
495 peer_address_->addr_len));
496 DCHECK_GE(0, rv);
497 return rv == 0 ? OK : MapConnectError(errno);
498}
499
tfarina4eb7aad82015-09-14 17:10:34500void SocketPosix::ConnectCompleted() {
[email protected]2ef2b0e2014-07-09 21:12:34501 // Get the error that connect() completed with.
502 int os_error = 0;
503 socklen_t len = sizeof(os_error);
504 if (getsockopt(socket_fd_, SOL_SOCKET, SO_ERROR, &os_error, &len) == 0) {
tfarina4eb7aad82015-09-14 17:10:34505 // TCPSocketPosix expects errno to be set.
[email protected]2ef2b0e2014-07-09 21:12:34506 errno = os_error;
507 }
508
509 int rv = MapConnectError(errno);
510 if (rv == ERR_IO_PENDING)
511 return;
512
513 bool ok = write_socket_watcher_.StopWatchingFileDescriptor();
514 DCHECK(ok);
515 waiting_connect_ = false;
516 base::ResetAndReturn(&write_callback_).Run(rv);
517}
518
tfarina4eb7aad82015-09-14 17:10:34519int SocketPosix::DoRead(IOBuffer* buf, int buf_len) {
[email protected]2ef2b0e2014-07-09 21:12:34520 int rv = HANDLE_EINTR(read(socket_fd_, buf->data(), buf_len));
521 return rv >= 0 ? rv : MapSystemError(errno);
522}
523
xunjieli321a96f32017-03-07 19:42:17524void SocketPosix::RetryRead(int rv) {
525 DCHECK(read_callback_);
526 DCHECK(read_buf_);
527 DCHECK_LT(0, read_buf_len_);
528
529 if (rv == OK) {
530 rv = ReadIfReady(
531 read_buf_.get(), read_buf_len_,
532 base::Bind(&SocketPosix::RetryRead, base::Unretained(this)));
533 if (rv == ERR_IO_PENDING)
534 return;
535 }
536 read_buf_ = nullptr;
537 read_buf_len_ = 0;
538 base::ResetAndReturn(&read_callback_).Run(rv);
539}
540
tfarina4eb7aad82015-09-14 17:10:34541void SocketPosix::ReadCompleted() {
xunjieli321a96f32017-03-07 19:42:17542 DCHECK(read_if_ready_callback_);
[email protected]2ef2b0e2014-07-09 21:12:34543
544 bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
545 DCHECK(ok);
xunjieli321a96f32017-03-07 19:42:17546 base::ResetAndReturn(&read_if_ready_callback_).Run(OK);
[email protected]2ef2b0e2014-07-09 21:12:34547}
548
tfarina4eb7aad82015-09-14 17:10:34549int SocketPosix::DoWrite(IOBuffer* buf, int buf_len) {
davidben28150272016-06-06 21:03:12550#if defined(OS_LINUX) || defined(OS_ANDROID)
551 // Disable SIGPIPE for this write. Although Chromium globally disables
552 // SIGPIPE, the net stack may be used in other consumers which do not do
553 // this. MSG_NOSIGNAL is a Linux-only API. On OS X, this is a setsockopt on
554 // socket creation.
555 int rv = HANDLE_EINTR(send(socket_fd_, buf->data(), buf_len, MSG_NOSIGNAL));
556#else
[email protected]2ef2b0e2014-07-09 21:12:34557 int rv = HANDLE_EINTR(write(socket_fd_, buf->data(), buf_len));
davidben28150272016-06-06 21:03:12558#endif
[email protected]2ef2b0e2014-07-09 21:12:34559 return rv >= 0 ? rv : MapSystemError(errno);
560}
561
tfarina4eb7aad82015-09-14 17:10:34562void SocketPosix::WriteCompleted() {
dcheng08ea2af02014-08-25 23:38:09563 int rv = DoWrite(write_buf_.get(), write_buf_len_);
[email protected]2ef2b0e2014-07-09 21:12:34564 if (rv == ERR_IO_PENDING)
565 return;
566
567 bool ok = write_socket_watcher_.StopWatchingFileDescriptor();
568 DCHECK(ok);
569 write_buf_ = NULL;
570 write_buf_len_ = 0;
571 base::ResetAndReturn(&write_callback_).Run(rv);
572}
573
tfarina4eb7aad82015-09-14 17:10:34574void SocketPosix::StopWatchingAndCleanUp() {
cmasoneca100d52014-09-03 18:11:11575 bool ok = accept_socket_watcher_.StopWatchingFileDescriptor();
576 DCHECK(ok);
577 ok = read_socket_watcher_.StopWatchingFileDescriptor();
578 DCHECK(ok);
579 ok = write_socket_watcher_.StopWatchingFileDescriptor();
580 DCHECK(ok);
581
582 if (!accept_callback_.is_null()) {
583 accept_socket_ = NULL;
584 accept_callback_.Reset();
585 }
586
587 if (!read_callback_.is_null()) {
588 read_buf_ = NULL;
589 read_buf_len_ = 0;
590 read_callback_.Reset();
591 }
592
xunjieli321a96f32017-03-07 19:42:17593 read_if_ready_callback_.Reset();
594
cmasoneca100d52014-09-03 18:11:11595 if (!write_callback_.is_null()) {
596 write_buf_ = NULL;
597 write_buf_len_ = 0;
598 write_callback_.Reset();
599 }
600
601 waiting_connect_ = false;
602 peer_address_.reset();
603}
604
[email protected]2ef2b0e2014-07-09 21:12:34605} // namespace net