blob: c8098c37b9f19658608de58b43302c558e868e9b [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>
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
19namespace net {
20
21namespace {
22
23int 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
37int 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} // namespace
55
tfarina4eb7aad82015-09-14 17:10:3456SocketPosix::SocketPosix()
[email protected]2ef2b0e2014-07-09 21:12:3457 : socket_fd_(kInvalidSocket),
58 read_buf_len_(0),
59 write_buf_len_(0),
tfarina4eb7aad82015-09-14 17:10:3460 waiting_connect_(false) {}
[email protected]2ef2b0e2014-07-09 21:12:3461
tfarina4eb7aad82015-09-14 17:10:3462SocketPosix::~SocketPosix() {
[email protected]2ef2b0e2014-07-09 21:12:3463 Close();
64}
65
tfarina4eb7aad82015-09-14 17:10:3466int SocketPosix::Open(int address_family) {
[email protected]2ef2b0e2014-07-09 21:12:3467 DCHECK(thread_checker_.CalledOnValidThread());
68 DCHECK_EQ(kInvalidSocket, socket_fd_);
69 DCHECK(address_family == AF_INET ||
70 address_family == AF_INET6 ||
71 address_family == AF_UNIX);
72
73 socket_fd_ = CreatePlatformSocket(
74 address_family,
75 SOCK_STREAM,
76 address_family == AF_UNIX ? 0 : IPPROTO_TCP);
77 if (socket_fd_ < 0) {
78 PLOG(ERROR) << "CreatePlatformSocket() returned an error, errno=" << errno;
79 return MapSystemError(errno);
80 }
81
82 if (SetNonBlocking(socket_fd_)) {
83 int rv = MapSystemError(errno);
84 Close();
85 return rv;
86 }
87
88 return OK;
89}
90
tfarina4eb7aad82015-09-14 17:10:3491int SocketPosix::AdoptConnectedSocket(SocketDescriptor socket,
92 const SockaddrStorage& address) {
[email protected]2ef2b0e2014-07-09 21:12:3493 DCHECK(thread_checker_.CalledOnValidThread());
94 DCHECK_EQ(kInvalidSocket, socket_fd_);
95
96 socket_fd_ = socket;
97
98 if (SetNonBlocking(socket_fd_)) {
99 int rv = MapSystemError(errno);
100 Close();
101 return rv;
102 }
103
104 SetPeerAddress(address);
105 return OK;
106}
107
tfarina4eb7aad82015-09-14 17:10:34108SocketDescriptor SocketPosix::ReleaseConnectedSocket() {
cmasoneca100d52014-09-03 18:11:11109 StopWatchingAndCleanUp();
110 SocketDescriptor socket_fd = socket_fd_;
111 socket_fd_ = kInvalidSocket;
112 return socket_fd;
113}
114
tfarina4eb7aad82015-09-14 17:10:34115int SocketPosix::Bind(const SockaddrStorage& address) {
[email protected]2ef2b0e2014-07-09 21:12:34116 DCHECK(thread_checker_.CalledOnValidThread());
117 DCHECK_NE(kInvalidSocket, socket_fd_);
118
119 int rv = bind(socket_fd_, address.addr, address.addr_len);
120 if (rv < 0) {
121 PLOG(ERROR) << "bind() returned an error, errno=" << errno;
122 return MapSystemError(errno);
123 }
124
125 return OK;
126}
127
tfarina4eb7aad82015-09-14 17:10:34128int SocketPosix::Listen(int backlog) {
[email protected]2ef2b0e2014-07-09 21:12:34129 DCHECK(thread_checker_.CalledOnValidThread());
130 DCHECK_NE(kInvalidSocket, socket_fd_);
131 DCHECK_LT(0, backlog);
132
133 int rv = listen(socket_fd_, backlog);
134 if (rv < 0) {
135 PLOG(ERROR) << "listen() returned an error, errno=" << errno;
136 return MapSystemError(errno);
137 }
138
139 return OK;
140}
141
tfarina4eb7aad82015-09-14 17:10:34142int SocketPosix::Accept(scoped_ptr<SocketPosix>* socket,
143 const CompletionCallback& callback) {
[email protected]2ef2b0e2014-07-09 21:12:34144 DCHECK(thread_checker_.CalledOnValidThread());
145 DCHECK_NE(kInvalidSocket, socket_fd_);
146 DCHECK(accept_callback_.is_null());
147 DCHECK(socket);
148 DCHECK(!callback.is_null());
149
150 int rv = DoAccept(socket);
151 if (rv != ERR_IO_PENDING)
152 return rv;
153
154 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
155 socket_fd_, true, base::MessageLoopForIO::WATCH_READ,
156 &accept_socket_watcher_, this)) {
157 PLOG(ERROR) << "WatchFileDescriptor failed on accept, errno " << errno;
158 return MapSystemError(errno);
159 }
160
161 accept_socket_ = socket;
162 accept_callback_ = callback;
163 return ERR_IO_PENDING;
164}
165
tfarina4eb7aad82015-09-14 17:10:34166int SocketPosix::Connect(const SockaddrStorage& address,
167 const CompletionCallback& callback) {
[email protected]2ef2b0e2014-07-09 21:12:34168 DCHECK(thread_checker_.CalledOnValidThread());
169 DCHECK_NE(kInvalidSocket, socket_fd_);
170 DCHECK(!waiting_connect_);
171 DCHECK(!callback.is_null());
172
173 SetPeerAddress(address);
174
175 int rv = DoConnect();
176 if (rv != ERR_IO_PENDING)
177 return rv;
178
179 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
180 socket_fd_, true, base::MessageLoopForIO::WATCH_WRITE,
181 &write_socket_watcher_, this)) {
182 PLOG(ERROR) << "WatchFileDescriptor failed on connect, errno " << errno;
183 return MapSystemError(errno);
184 }
185
186 write_callback_ = callback;
187 waiting_connect_ = true;
188 return ERR_IO_PENDING;
189}
190
tfarina4eb7aad82015-09-14 17:10:34191bool SocketPosix::IsConnected() const {
[email protected]2ef2b0e2014-07-09 21:12:34192 DCHECK(thread_checker_.CalledOnValidThread());
193
194 if (socket_fd_ == kInvalidSocket || waiting_connect_)
195 return false;
196
197 // Checks if connection is alive.
198 char c;
199 int rv = HANDLE_EINTR(recv(socket_fd_, &c, 1, MSG_PEEK));
200 if (rv == 0)
201 return false;
202 if (rv == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
203 return false;
204
205 return true;
206}
207
tfarina4eb7aad82015-09-14 17:10:34208bool SocketPosix::IsConnectedAndIdle() const {
[email protected]2ef2b0e2014-07-09 21:12:34209 DCHECK(thread_checker_.CalledOnValidThread());
210
211 if (socket_fd_ == kInvalidSocket || waiting_connect_)
212 return false;
213
214 // Check if connection is alive and we haven't received any data
215 // unexpectedly.
216 char c;
217 int rv = HANDLE_EINTR(recv(socket_fd_, &c, 1, MSG_PEEK));
218 if (rv >= 0)
219 return false;
220 if (errno != EAGAIN && errno != EWOULDBLOCK)
221 return false;
222
223 return true;
224}
225
tfarina4eb7aad82015-09-14 17:10:34226int SocketPosix::Read(IOBuffer* buf,
227 int buf_len,
228 const CompletionCallback& callback) {
[email protected]2ef2b0e2014-07-09 21:12:34229 DCHECK(thread_checker_.CalledOnValidThread());
230 DCHECK_NE(kInvalidSocket, socket_fd_);
231 DCHECK(!waiting_connect_);
vitalybuka63b47542014-09-29 17:14:19232 CHECK(read_callback_.is_null());
[email protected]2ef2b0e2014-07-09 21:12:34233 // Synchronous operation not supported
234 DCHECK(!callback.is_null());
235 DCHECK_LT(0, buf_len);
236
237 int rv = DoRead(buf, buf_len);
238 if (rv != ERR_IO_PENDING)
239 return rv;
240
241 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
242 socket_fd_, true, base::MessageLoopForIO::WATCH_READ,
243 &read_socket_watcher_, this)) {
244 PLOG(ERROR) << "WatchFileDescriptor failed on read, errno " << errno;
245 return MapSystemError(errno);
246 }
247
248 read_buf_ = buf;
249 read_buf_len_ = buf_len;
250 read_callback_ = callback;
251 return ERR_IO_PENDING;
252}
253
tfarina4eb7aad82015-09-14 17:10:34254int SocketPosix::Write(IOBuffer* buf,
255 int buf_len,
256 const CompletionCallback& callback) {
[email protected]2ef2b0e2014-07-09 21:12:34257 DCHECK(thread_checker_.CalledOnValidThread());
258 DCHECK_NE(kInvalidSocket, socket_fd_);
259 DCHECK(!waiting_connect_);
vitalybuka63b47542014-09-29 17:14:19260 CHECK(write_callback_.is_null());
[email protected]2ef2b0e2014-07-09 21:12:34261 // Synchronous operation not supported
262 DCHECK(!callback.is_null());
263 DCHECK_LT(0, buf_len);
264
265 int rv = DoWrite(buf, buf_len);
266 if (rv == ERR_IO_PENDING)
267 rv = WaitForWrite(buf, buf_len, callback);
268 return rv;
269}
270
tfarina4eb7aad82015-09-14 17:10:34271int SocketPosix::WaitForWrite(IOBuffer* buf,
272 int buf_len,
273 const CompletionCallback& callback) {
[email protected]2ef2b0e2014-07-09 21:12:34274 DCHECK(thread_checker_.CalledOnValidThread());
275 DCHECK_NE(kInvalidSocket, socket_fd_);
276 DCHECK(write_callback_.is_null());
277 // Synchronous operation not supported
278 DCHECK(!callback.is_null());
279 DCHECK_LT(0, buf_len);
280
281 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
282 socket_fd_, true, base::MessageLoopForIO::WATCH_WRITE,
283 &write_socket_watcher_, this)) {
284 PLOG(ERROR) << "WatchFileDescriptor failed on write, errno " << errno;
285 return MapSystemError(errno);
286 }
287
288 write_buf_ = buf;
289 write_buf_len_ = buf_len;
290 write_callback_ = callback;
291 return ERR_IO_PENDING;
292}
293
tfarina4eb7aad82015-09-14 17:10:34294int SocketPosix::GetLocalAddress(SockaddrStorage* address) const {
[email protected]2ef2b0e2014-07-09 21:12:34295 DCHECK(thread_checker_.CalledOnValidThread());
296 DCHECK(address);
297
298 if (getsockname(socket_fd_, address->addr, &address->addr_len) < 0)
299 return MapSystemError(errno);
300 return OK;
301}
302
tfarina4eb7aad82015-09-14 17:10:34303int SocketPosix::GetPeerAddress(SockaddrStorage* address) const {
[email protected]2ef2b0e2014-07-09 21:12:34304 DCHECK(thread_checker_.CalledOnValidThread());
305 DCHECK(address);
306
307 if (!HasPeerAddress())
308 return ERR_SOCKET_NOT_CONNECTED;
309
310 *address = *peer_address_;
311 return OK;
312}
313
tfarina4eb7aad82015-09-14 17:10:34314void SocketPosix::SetPeerAddress(const SockaddrStorage& address) {
[email protected]2ef2b0e2014-07-09 21:12:34315 DCHECK(thread_checker_.CalledOnValidThread());
316 // |peer_address_| will be non-NULL if Connect() has been called. Unless
317 // Close() is called to reset the internal state, a second call to Connect()
318 // is not allowed.
319 // Please note that we don't allow a second Connect() even if the previous
320 // Connect() has failed. Connecting the same |socket_| again after a
321 // connection attempt failed results in unspecified behavior according to
322 // POSIX.
323 DCHECK(!peer_address_);
324 peer_address_.reset(new SockaddrStorage(address));
325}
326
tfarina4eb7aad82015-09-14 17:10:34327bool SocketPosix::HasPeerAddress() const {
[email protected]2ef2b0e2014-07-09 21:12:34328 DCHECK(thread_checker_.CalledOnValidThread());
329 return peer_address_ != NULL;
330}
331
tfarina4eb7aad82015-09-14 17:10:34332void SocketPosix::Close() {
[email protected]2ef2b0e2014-07-09 21:12:34333 DCHECK(thread_checker_.CalledOnValidThread());
334
cmasoneca100d52014-09-03 18:11:11335 StopWatchingAndCleanUp();
[email protected]2ef2b0e2014-07-09 21:12:34336
337 if (socket_fd_ != kInvalidSocket) {
338 if (IGNORE_EINTR(close(socket_fd_)) < 0)
339 PLOG(ERROR) << "close() returned an error, errno=" << errno;
340 socket_fd_ = kInvalidSocket;
341 }
[email protected]2ef2b0e2014-07-09 21:12:34342}
343
svaldez58804c402015-10-06 00:13:47344void SocketPosix::DetachFromThread() {
345 thread_checker_.DetachFromThread();
346}
347
tfarina4eb7aad82015-09-14 17:10:34348void SocketPosix::OnFileCanReadWithoutBlocking(int fd) {
[email protected]2ef2b0e2014-07-09 21:12:34349 DCHECK(!accept_callback_.is_null() || !read_callback_.is_null());
350 if (!accept_callback_.is_null()) {
351 AcceptCompleted();
352 } else { // !read_callback_.is_null()
353 ReadCompleted();
354 }
355}
356
tfarina4eb7aad82015-09-14 17:10:34357void SocketPosix::OnFileCanWriteWithoutBlocking(int fd) {
[email protected]2ef2b0e2014-07-09 21:12:34358 DCHECK(!write_callback_.is_null());
359 if (waiting_connect_) {
360 ConnectCompleted();
361 } else {
362 WriteCompleted();
363 }
364}
365
tfarina4eb7aad82015-09-14 17:10:34366int SocketPosix::DoAccept(scoped_ptr<SocketPosix>* socket) {
[email protected]2ef2b0e2014-07-09 21:12:34367 SockaddrStorage new_peer_address;
368 int new_socket = HANDLE_EINTR(accept(socket_fd_,
369 new_peer_address.addr,
370 &new_peer_address.addr_len));
371 if (new_socket < 0)
372 return MapAcceptError(errno);
373
tfarina4eb7aad82015-09-14 17:10:34374 scoped_ptr<SocketPosix> accepted_socket(new SocketPosix);
[email protected]2ef2b0e2014-07-09 21:12:34375 int rv = accepted_socket->AdoptConnectedSocket(new_socket, new_peer_address);
376 if (rv != OK)
377 return rv;
378
379 *socket = accepted_socket.Pass();
380 return OK;
381}
382
tfarina4eb7aad82015-09-14 17:10:34383void SocketPosix::AcceptCompleted() {
[email protected]2ef2b0e2014-07-09 21:12:34384 DCHECK(accept_socket_);
385 int rv = DoAccept(accept_socket_);
386 if (rv == ERR_IO_PENDING)
387 return;
388
389 bool ok = accept_socket_watcher_.StopWatchingFileDescriptor();
390 DCHECK(ok);
391 accept_socket_ = NULL;
392 base::ResetAndReturn(&accept_callback_).Run(rv);
393}
394
tfarina4eb7aad82015-09-14 17:10:34395int SocketPosix::DoConnect() {
[email protected]2ef2b0e2014-07-09 21:12:34396 int rv = HANDLE_EINTR(connect(socket_fd_,
397 peer_address_->addr,
398 peer_address_->addr_len));
399 DCHECK_GE(0, rv);
400 return rv == 0 ? OK : MapConnectError(errno);
401}
402
tfarina4eb7aad82015-09-14 17:10:34403void SocketPosix::ConnectCompleted() {
[email protected]2ef2b0e2014-07-09 21:12:34404 // Get the error that connect() completed with.
405 int os_error = 0;
406 socklen_t len = sizeof(os_error);
407 if (getsockopt(socket_fd_, SOL_SOCKET, SO_ERROR, &os_error, &len) == 0) {
tfarina4eb7aad82015-09-14 17:10:34408 // TCPSocketPosix expects errno to be set.
[email protected]2ef2b0e2014-07-09 21:12:34409 errno = os_error;
410 }
411
412 int rv = MapConnectError(errno);
413 if (rv == ERR_IO_PENDING)
414 return;
415
416 bool ok = write_socket_watcher_.StopWatchingFileDescriptor();
417 DCHECK(ok);
418 waiting_connect_ = false;
419 base::ResetAndReturn(&write_callback_).Run(rv);
420}
421
tfarina4eb7aad82015-09-14 17:10:34422int SocketPosix::DoRead(IOBuffer* buf, int buf_len) {
[email protected]2ef2b0e2014-07-09 21:12:34423 int rv = HANDLE_EINTR(read(socket_fd_, buf->data(), buf_len));
424 return rv >= 0 ? rv : MapSystemError(errno);
425}
426
tfarina4eb7aad82015-09-14 17:10:34427void SocketPosix::ReadCompleted() {
dcheng08ea2af02014-08-25 23:38:09428 int rv = DoRead(read_buf_.get(), read_buf_len_);
[email protected]2ef2b0e2014-07-09 21:12:34429 if (rv == ERR_IO_PENDING)
430 return;
431
432 bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
433 DCHECK(ok);
434 read_buf_ = NULL;
435 read_buf_len_ = 0;
436 base::ResetAndReturn(&read_callback_).Run(rv);
437}
438
tfarina4eb7aad82015-09-14 17:10:34439int SocketPosix::DoWrite(IOBuffer* buf, int buf_len) {
[email protected]2ef2b0e2014-07-09 21:12:34440 int rv = HANDLE_EINTR(write(socket_fd_, buf->data(), buf_len));
441 return rv >= 0 ? rv : MapSystemError(errno);
442}
443
tfarina4eb7aad82015-09-14 17:10:34444void SocketPosix::WriteCompleted() {
dcheng08ea2af02014-08-25 23:38:09445 int rv = DoWrite(write_buf_.get(), write_buf_len_);
[email protected]2ef2b0e2014-07-09 21:12:34446 if (rv == ERR_IO_PENDING)
447 return;
448
449 bool ok = write_socket_watcher_.StopWatchingFileDescriptor();
450 DCHECK(ok);
451 write_buf_ = NULL;
452 write_buf_len_ = 0;
453 base::ResetAndReturn(&write_callback_).Run(rv);
454}
455
tfarina4eb7aad82015-09-14 17:10:34456void SocketPosix::StopWatchingAndCleanUp() {
cmasoneca100d52014-09-03 18:11:11457 bool ok = accept_socket_watcher_.StopWatchingFileDescriptor();
458 DCHECK(ok);
459 ok = read_socket_watcher_.StopWatchingFileDescriptor();
460 DCHECK(ok);
461 ok = write_socket_watcher_.StopWatchingFileDescriptor();
462 DCHECK(ok);
463
464 if (!accept_callback_.is_null()) {
465 accept_socket_ = NULL;
466 accept_callback_.Reset();
467 }
468
469 if (!read_callback_.is_null()) {
470 read_buf_ = NULL;
471 read_buf_len_ = 0;
472 read_callback_.Reset();
473 }
474
475 if (!write_callback_.is_null()) {
476 write_buf_ = NULL;
477 write_buf_len_ = 0;
478 write_callback_.Reset();
479 }
480
481 waiting_connect_ = false;
482 peer_address_.reset();
483}
484
[email protected]2ef2b0e2014-07-09 21:12:34485} // namespace net