blob: a18e22d2c2b924c562535138d65b10975cea3c35 [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"
16#include "net/base/io_buffer.h"
17#include "net/base/ip_endpoint.h"
18#include "net/base/net_errors.h"
19#include "net/base/net_util.h"
20
21namespace net {
22
23namespace {
24
25int MapAcceptError(int os_error) {
26 switch (os_error) {
27 // If the client aborts the connection before the server calls accept,
28 // POSIX specifies accept should fail with ECONNABORTED. The server can
29 // ignore the error and just call accept again, so we map the error to
30 // ERR_IO_PENDING. See UNIX Network Programming, Vol. 1, 3rd Ed., Sec.
31 // 5.11, "Connection Abort before accept Returns".
32 case ECONNABORTED:
33 return ERR_IO_PENDING;
34 default:
35 return MapSystemError(os_error);
36 }
37}
38
39int MapConnectError(int os_error) {
40 switch (os_error) {
41 case EINPROGRESS:
42 return ERR_IO_PENDING;
43 case EACCES:
44 return ERR_NETWORK_ACCESS_DENIED;
45 case ETIMEDOUT:
46 return ERR_CONNECTION_TIMED_OUT;
47 default: {
48 int net_error = MapSystemError(os_error);
49 if (net_error == ERR_FAILED)
50 return ERR_CONNECTION_FAILED; // More specific than ERR_FAILED.
51 return net_error;
52 }
53 }
54}
55
56} // namespace
57
tfarina4eb7aad82015-09-14 17:10:3458SocketPosix::SocketPosix()
[email protected]2ef2b0e2014-07-09 21:12:3459 : socket_fd_(kInvalidSocket),
60 read_buf_len_(0),
61 write_buf_len_(0),
tfarina4eb7aad82015-09-14 17:10:3462 waiting_connect_(false) {}
[email protected]2ef2b0e2014-07-09 21:12:3463
tfarina4eb7aad82015-09-14 17:10:3464SocketPosix::~SocketPosix() {
[email protected]2ef2b0e2014-07-09 21:12:3465 Close();
66}
67
tfarina4eb7aad82015-09-14 17:10:3468int SocketPosix::Open(int address_family) {
[email protected]2ef2b0e2014-07-09 21:12:3469 DCHECK(thread_checker_.CalledOnValidThread());
70 DCHECK_EQ(kInvalidSocket, socket_fd_);
71 DCHECK(address_family == AF_INET ||
72 address_family == AF_INET6 ||
73 address_family == AF_UNIX);
74
75 socket_fd_ = CreatePlatformSocket(
76 address_family,
77 SOCK_STREAM,
78 address_family == AF_UNIX ? 0 : IPPROTO_TCP);
79 if (socket_fd_ < 0) {
80 PLOG(ERROR) << "CreatePlatformSocket() returned an error, errno=" << errno;
81 return MapSystemError(errno);
82 }
83
tfarina060df7e2015-12-16 05:15:3284 if (!base::SetNonBlocking(socket_fd_)) {
[email protected]2ef2b0e2014-07-09 21:12:3485 int rv = MapSystemError(errno);
86 Close();
87 return rv;
88 }
89
90 return OK;
91}
92
tfarina4eb7aad82015-09-14 17:10:3493int SocketPosix::AdoptConnectedSocket(SocketDescriptor socket,
94 const SockaddrStorage& address) {
[email protected]2ef2b0e2014-07-09 21:12:3495 DCHECK(thread_checker_.CalledOnValidThread());
96 DCHECK_EQ(kInvalidSocket, socket_fd_);
97
98 socket_fd_ = socket;
99
tfarina060df7e2015-12-16 05:15:32100 if (!base::SetNonBlocking(socket_fd_)) {
[email protected]2ef2b0e2014-07-09 21:12:34101 int rv = MapSystemError(errno);
102 Close();
103 return rv;
104 }
105
106 SetPeerAddress(address);
107 return OK;
108}
109
tfarina4eb7aad82015-09-14 17:10:34110SocketDescriptor SocketPosix::ReleaseConnectedSocket() {
cmasoneca100d52014-09-03 18:11:11111 StopWatchingAndCleanUp();
112 SocketDescriptor socket_fd = socket_fd_;
113 socket_fd_ = kInvalidSocket;
114 return socket_fd;
115}
116
tfarina4eb7aad82015-09-14 17:10:34117int SocketPosix::Bind(const SockaddrStorage& address) {
[email protected]2ef2b0e2014-07-09 21:12:34118 DCHECK(thread_checker_.CalledOnValidThread());
119 DCHECK_NE(kInvalidSocket, socket_fd_);
120
121 int rv = bind(socket_fd_, address.addr, address.addr_len);
122 if (rv < 0) {
123 PLOG(ERROR) << "bind() returned an error, errno=" << errno;
124 return MapSystemError(errno);
125 }
126
127 return OK;
128}
129
tfarina4eb7aad82015-09-14 17:10:34130int SocketPosix::Listen(int backlog) {
[email protected]2ef2b0e2014-07-09 21:12:34131 DCHECK(thread_checker_.CalledOnValidThread());
132 DCHECK_NE(kInvalidSocket, socket_fd_);
133 DCHECK_LT(0, backlog);
134
135 int rv = listen(socket_fd_, backlog);
136 if (rv < 0) {
137 PLOG(ERROR) << "listen() returned an error, errno=" << errno;
138 return MapSystemError(errno);
139 }
140
141 return OK;
142}
143
tfarina4eb7aad82015-09-14 17:10:34144int SocketPosix::Accept(scoped_ptr<SocketPosix>* socket,
145 const CompletionCallback& callback) {
[email protected]2ef2b0e2014-07-09 21:12:34146 DCHECK(thread_checker_.CalledOnValidThread());
147 DCHECK_NE(kInvalidSocket, socket_fd_);
148 DCHECK(accept_callback_.is_null());
149 DCHECK(socket);
150 DCHECK(!callback.is_null());
151
152 int rv = DoAccept(socket);
153 if (rv != ERR_IO_PENDING)
154 return rv;
155
156 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
157 socket_fd_, true, base::MessageLoopForIO::WATCH_READ,
158 &accept_socket_watcher_, this)) {
159 PLOG(ERROR) << "WatchFileDescriptor failed on accept, errno " << errno;
160 return MapSystemError(errno);
161 }
162
163 accept_socket_ = socket;
164 accept_callback_ = callback;
165 return ERR_IO_PENDING;
166}
167
tfarina4eb7aad82015-09-14 17:10:34168int SocketPosix::Connect(const SockaddrStorage& address,
169 const CompletionCallback& callback) {
[email protected]2ef2b0e2014-07-09 21:12:34170 DCHECK(thread_checker_.CalledOnValidThread());
171 DCHECK_NE(kInvalidSocket, socket_fd_);
172 DCHECK(!waiting_connect_);
173 DCHECK(!callback.is_null());
174
175 SetPeerAddress(address);
176
177 int rv = DoConnect();
178 if (rv != ERR_IO_PENDING)
179 return rv;
180
181 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
182 socket_fd_, true, base::MessageLoopForIO::WATCH_WRITE,
183 &write_socket_watcher_, this)) {
184 PLOG(ERROR) << "WatchFileDescriptor failed on connect, errno " << errno;
185 return MapSystemError(errno);
186 }
187
188 write_callback_ = callback;
189 waiting_connect_ = true;
190 return ERR_IO_PENDING;
191}
192
tfarina4eb7aad82015-09-14 17:10:34193bool SocketPosix::IsConnected() const {
[email protected]2ef2b0e2014-07-09 21:12:34194 DCHECK(thread_checker_.CalledOnValidThread());
195
196 if (socket_fd_ == kInvalidSocket || waiting_connect_)
197 return false;
198
199 // Checks if connection is alive.
200 char c;
201 int rv = HANDLE_EINTR(recv(socket_fd_, &c, 1, MSG_PEEK));
202 if (rv == 0)
203 return false;
204 if (rv == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
205 return false;
206
207 return true;
208}
209
tfarina4eb7aad82015-09-14 17:10:34210bool SocketPosix::IsConnectedAndIdle() const {
[email protected]2ef2b0e2014-07-09 21:12:34211 DCHECK(thread_checker_.CalledOnValidThread());
212
213 if (socket_fd_ == kInvalidSocket || waiting_connect_)
214 return false;
215
216 // Check if connection is alive and we haven't received any data
217 // unexpectedly.
218 char c;
219 int rv = HANDLE_EINTR(recv(socket_fd_, &c, 1, MSG_PEEK));
220 if (rv >= 0)
221 return false;
222 if (errno != EAGAIN && errno != EWOULDBLOCK)
223 return false;
224
225 return true;
226}
227
tfarina4eb7aad82015-09-14 17:10:34228int SocketPosix::Read(IOBuffer* buf,
229 int buf_len,
230 const CompletionCallback& callback) {
[email protected]2ef2b0e2014-07-09 21:12:34231 DCHECK(thread_checker_.CalledOnValidThread());
232 DCHECK_NE(kInvalidSocket, socket_fd_);
233 DCHECK(!waiting_connect_);
vitalybuka63b47542014-09-29 17:14:19234 CHECK(read_callback_.is_null());
[email protected]2ef2b0e2014-07-09 21:12:34235 // Synchronous operation not supported
236 DCHECK(!callback.is_null());
237 DCHECK_LT(0, buf_len);
238
239 int rv = DoRead(buf, buf_len);
240 if (rv != ERR_IO_PENDING)
241 return rv;
242
243 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
244 socket_fd_, true, base::MessageLoopForIO::WATCH_READ,
245 &read_socket_watcher_, this)) {
246 PLOG(ERROR) << "WatchFileDescriptor failed on read, errno " << errno;
247 return MapSystemError(errno);
248 }
249
250 read_buf_ = buf;
251 read_buf_len_ = buf_len;
252 read_callback_ = callback;
253 return ERR_IO_PENDING;
254}
255
tfarina4eb7aad82015-09-14 17:10:34256int SocketPosix::Write(IOBuffer* buf,
257 int buf_len,
258 const CompletionCallback& callback) {
[email protected]2ef2b0e2014-07-09 21:12:34259 DCHECK(thread_checker_.CalledOnValidThread());
260 DCHECK_NE(kInvalidSocket, socket_fd_);
261 DCHECK(!waiting_connect_);
vitalybuka63b47542014-09-29 17:14:19262 CHECK(write_callback_.is_null());
[email protected]2ef2b0e2014-07-09 21:12:34263 // Synchronous operation not supported
264 DCHECK(!callback.is_null());
265 DCHECK_LT(0, buf_len);
266
267 int rv = DoWrite(buf, buf_len);
268 if (rv == ERR_IO_PENDING)
269 rv = WaitForWrite(buf, buf_len, callback);
270 return rv;
271}
272
tfarina4eb7aad82015-09-14 17:10:34273int SocketPosix::WaitForWrite(IOBuffer* buf,
274 int buf_len,
275 const CompletionCallback& callback) {
[email protected]2ef2b0e2014-07-09 21:12:34276 DCHECK(thread_checker_.CalledOnValidThread());
277 DCHECK_NE(kInvalidSocket, socket_fd_);
278 DCHECK(write_callback_.is_null());
279 // Synchronous operation not supported
280 DCHECK(!callback.is_null());
281 DCHECK_LT(0, buf_len);
282
283 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
284 socket_fd_, true, base::MessageLoopForIO::WATCH_WRITE,
285 &write_socket_watcher_, this)) {
286 PLOG(ERROR) << "WatchFileDescriptor failed on write, errno " << errno;
287 return MapSystemError(errno);
288 }
289
290 write_buf_ = buf;
291 write_buf_len_ = buf_len;
292 write_callback_ = callback;
293 return ERR_IO_PENDING;
294}
295
tfarina4eb7aad82015-09-14 17:10:34296int SocketPosix::GetLocalAddress(SockaddrStorage* address) const {
[email protected]2ef2b0e2014-07-09 21:12:34297 DCHECK(thread_checker_.CalledOnValidThread());
298 DCHECK(address);
299
300 if (getsockname(socket_fd_, address->addr, &address->addr_len) < 0)
301 return MapSystemError(errno);
302 return OK;
303}
304
tfarina4eb7aad82015-09-14 17:10:34305int SocketPosix::GetPeerAddress(SockaddrStorage* address) const {
[email protected]2ef2b0e2014-07-09 21:12:34306 DCHECK(thread_checker_.CalledOnValidThread());
307 DCHECK(address);
308
309 if (!HasPeerAddress())
310 return ERR_SOCKET_NOT_CONNECTED;
311
312 *address = *peer_address_;
313 return OK;
314}
315
tfarina4eb7aad82015-09-14 17:10:34316void SocketPosix::SetPeerAddress(const SockaddrStorage& address) {
[email protected]2ef2b0e2014-07-09 21:12:34317 DCHECK(thread_checker_.CalledOnValidThread());
318 // |peer_address_| will be non-NULL if Connect() has been called. Unless
319 // Close() is called to reset the internal state, a second call to Connect()
320 // is not allowed.
321 // Please note that we don't allow a second Connect() even if the previous
322 // Connect() has failed. Connecting the same |socket_| again after a
323 // connection attempt failed results in unspecified behavior according to
324 // POSIX.
325 DCHECK(!peer_address_);
326 peer_address_.reset(new SockaddrStorage(address));
327}
328
tfarina4eb7aad82015-09-14 17:10:34329bool SocketPosix::HasPeerAddress() const {
[email protected]2ef2b0e2014-07-09 21:12:34330 DCHECK(thread_checker_.CalledOnValidThread());
331 return peer_address_ != NULL;
332}
333
tfarina4eb7aad82015-09-14 17:10:34334void SocketPosix::Close() {
[email protected]2ef2b0e2014-07-09 21:12:34335 DCHECK(thread_checker_.CalledOnValidThread());
336
cmasoneca100d52014-09-03 18:11:11337 StopWatchingAndCleanUp();
[email protected]2ef2b0e2014-07-09 21:12:34338
339 if (socket_fd_ != kInvalidSocket) {
340 if (IGNORE_EINTR(close(socket_fd_)) < 0)
341 PLOG(ERROR) << "close() returned an error, errno=" << errno;
342 socket_fd_ = kInvalidSocket;
343 }
[email protected]2ef2b0e2014-07-09 21:12:34344}
345
svaldez58804c42015-10-06 00:13:47346void SocketPosix::DetachFromThread() {
347 thread_checker_.DetachFromThread();
348}
349
tfarina4eb7aad82015-09-14 17:10:34350void SocketPosix::OnFileCanReadWithoutBlocking(int fd) {
[email protected]2ef2b0e2014-07-09 21:12:34351 DCHECK(!accept_callback_.is_null() || !read_callback_.is_null());
352 if (!accept_callback_.is_null()) {
353 AcceptCompleted();
354 } else { // !read_callback_.is_null()
355 ReadCompleted();
356 }
357}
358
tfarina4eb7aad82015-09-14 17:10:34359void SocketPosix::OnFileCanWriteWithoutBlocking(int fd) {
[email protected]2ef2b0e2014-07-09 21:12:34360 DCHECK(!write_callback_.is_null());
361 if (waiting_connect_) {
362 ConnectCompleted();
363 } else {
364 WriteCompleted();
365 }
366}
367
tfarina4eb7aad82015-09-14 17:10:34368int SocketPosix::DoAccept(scoped_ptr<SocketPosix>* socket) {
[email protected]2ef2b0e2014-07-09 21:12:34369 SockaddrStorage new_peer_address;
370 int new_socket = HANDLE_EINTR(accept(socket_fd_,
371 new_peer_address.addr,
372 &new_peer_address.addr_len));
373 if (new_socket < 0)
374 return MapAcceptError(errno);
375
tfarina4eb7aad82015-09-14 17:10:34376 scoped_ptr<SocketPosix> accepted_socket(new SocketPosix);
[email protected]2ef2b0e2014-07-09 21:12:34377 int rv = accepted_socket->AdoptConnectedSocket(new_socket, new_peer_address);
378 if (rv != OK)
379 return rv;
380
dchengc7eeda422015-12-26 03:56:48381 *socket = std::move(accepted_socket);
[email protected]2ef2b0e2014-07-09 21:12:34382 return OK;
383}
384
tfarina4eb7aad82015-09-14 17:10:34385void SocketPosix::AcceptCompleted() {
[email protected]2ef2b0e2014-07-09 21:12:34386 DCHECK(accept_socket_);
387 int rv = DoAccept(accept_socket_);
388 if (rv == ERR_IO_PENDING)
389 return;
390
391 bool ok = accept_socket_watcher_.StopWatchingFileDescriptor();
392 DCHECK(ok);
393 accept_socket_ = NULL;
394 base::ResetAndReturn(&accept_callback_).Run(rv);
395}
396
tfarina4eb7aad82015-09-14 17:10:34397int SocketPosix::DoConnect() {
[email protected]2ef2b0e2014-07-09 21:12:34398 int rv = HANDLE_EINTR(connect(socket_fd_,
399 peer_address_->addr,
400 peer_address_->addr_len));
401 DCHECK_GE(0, rv);
402 return rv == 0 ? OK : MapConnectError(errno);
403}
404
tfarina4eb7aad82015-09-14 17:10:34405void SocketPosix::ConnectCompleted() {
[email protected]2ef2b0e2014-07-09 21:12:34406 // Get the error that connect() completed with.
407 int os_error = 0;
408 socklen_t len = sizeof(os_error);
409 if (getsockopt(socket_fd_, SOL_SOCKET, SO_ERROR, &os_error, &len) == 0) {
tfarina4eb7aad82015-09-14 17:10:34410 // TCPSocketPosix expects errno to be set.
[email protected]2ef2b0e2014-07-09 21:12:34411 errno = os_error;
412 }
413
414 int rv = MapConnectError(errno);
415 if (rv == ERR_IO_PENDING)
416 return;
417
418 bool ok = write_socket_watcher_.StopWatchingFileDescriptor();
419 DCHECK(ok);
420 waiting_connect_ = false;
421 base::ResetAndReturn(&write_callback_).Run(rv);
422}
423
tfarina4eb7aad82015-09-14 17:10:34424int SocketPosix::DoRead(IOBuffer* buf, int buf_len) {
[email protected]2ef2b0e2014-07-09 21:12:34425 int rv = HANDLE_EINTR(read(socket_fd_, buf->data(), buf_len));
426 return rv >= 0 ? rv : MapSystemError(errno);
427}
428
tfarina4eb7aad82015-09-14 17:10:34429void SocketPosix::ReadCompleted() {
dcheng08ea2af02014-08-25 23:38:09430 int rv = DoRead(read_buf_.get(), read_buf_len_);
[email protected]2ef2b0e2014-07-09 21:12:34431 if (rv == ERR_IO_PENDING)
432 return;
433
434 bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
435 DCHECK(ok);
436 read_buf_ = NULL;
437 read_buf_len_ = 0;
438 base::ResetAndReturn(&read_callback_).Run(rv);
439}
440
tfarina4eb7aad82015-09-14 17:10:34441int SocketPosix::DoWrite(IOBuffer* buf, int buf_len) {
[email protected]2ef2b0e2014-07-09 21:12:34442 int rv = HANDLE_EINTR(write(socket_fd_, buf->data(), buf_len));
443 return rv >= 0 ? rv : MapSystemError(errno);
444}
445
tfarina4eb7aad82015-09-14 17:10:34446void SocketPosix::WriteCompleted() {
dcheng08ea2af02014-08-25 23:38:09447 int rv = DoWrite(write_buf_.get(), write_buf_len_);
[email protected]2ef2b0e2014-07-09 21:12:34448 if (rv == ERR_IO_PENDING)
449 return;
450
451 bool ok = write_socket_watcher_.StopWatchingFileDescriptor();
452 DCHECK(ok);
453 write_buf_ = NULL;
454 write_buf_len_ = 0;
455 base::ResetAndReturn(&write_callback_).Run(rv);
456}
457
tfarina4eb7aad82015-09-14 17:10:34458void SocketPosix::StopWatchingAndCleanUp() {
cmasoneca100d52014-09-03 18:11:11459 bool ok = accept_socket_watcher_.StopWatchingFileDescriptor();
460 DCHECK(ok);
461 ok = read_socket_watcher_.StopWatchingFileDescriptor();
462 DCHECK(ok);
463 ok = write_socket_watcher_.StopWatchingFileDescriptor();
464 DCHECK(ok);
465
466 if (!accept_callback_.is_null()) {
467 accept_socket_ = NULL;
468 accept_callback_.Reset();
469 }
470
471 if (!read_callback_.is_null()) {
472 read_buf_ = NULL;
473 read_buf_len_ = 0;
474 read_callback_.Reset();
475 }
476
477 if (!write_callback_.is_null()) {
478 write_buf_ = NULL;
479 write_buf_len_ = 0;
480 write_callback_.Reset();
481 }
482
483 waiting_connect_ = false;
484 peer_address_.reset();
485}
486
[email protected]2ef2b0e2014-07-09 21:12:34487} // namespace net