1 // Copyright 2013 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.
5 #include "base/async_socket_io_handler.h"
9 #include "base/posix/eintr_wrapper.h"
13 AsyncSocketIoHandler::AsyncSocketIoHandler()
14 : socket_(base::SyncSocket::kInvalidHandle
),
15 pending_buffer_(NULL
),
16 pending_buffer_len_(0),
20 AsyncSocketIoHandler::~AsyncSocketIoHandler() {
21 DCHECK(CalledOnValidThread());
24 void AsyncSocketIoHandler::OnFileCanReadWithoutBlocking(int socket
) {
25 DCHECK(CalledOnValidThread());
26 DCHECK_EQ(socket
, socket_
);
27 DCHECK(!read_complete_
.is_null());
29 if (pending_buffer_
) {
30 int bytes_read
= HANDLE_EINTR(read(socket_
, pending_buffer_
,
31 pending_buffer_len_
));
32 DCHECK_GE(bytes_read
, 0);
33 pending_buffer_
= NULL
;
34 pending_buffer_len_
= 0;
35 read_complete_
.Run(bytes_read
> 0 ? bytes_read
: 0);
37 // We're getting notifications that we can read from the socket while
38 // we're not waiting for data. In order to not starve the message loop,
39 // let's stop watching the fd and restart the watch when Read() is called.
41 socket_watcher_
.StopWatchingFileDescriptor();
45 bool AsyncSocketIoHandler::Read(char* buffer
, int buffer_len
) {
46 DCHECK(CalledOnValidThread());
47 DCHECK(!read_complete_
.is_null());
48 DCHECK(!pending_buffer_
);
50 EnsureWatchingSocket();
52 int bytes_read
= HANDLE_EINTR(read(socket_
, buffer
, buffer_len
));
54 if (errno
== EAGAIN
) {
55 pending_buffer_
= buffer
;
56 pending_buffer_len_
= buffer_len
;
58 NOTREACHED() << "read(): " << errno
;
62 read_complete_
.Run(bytes_read
);
67 bool AsyncSocketIoHandler::Initialize(base::SyncSocket::Handle socket
,
68 const ReadCompleteCallback
& callback
) {
69 DCHECK_EQ(socket_
, base::SyncSocket::kInvalidHandle
);
74 read_complete_
= callback
;
76 // SyncSocket is blocking by default, so let's convert it to non-blocking.
77 int value
= fcntl(socket
, F_GETFL
);
78 if (!(value
& O_NONBLOCK
)) {
79 // Set the socket to be non-blocking so we can do async reads.
80 if (fcntl(socket
, F_SETFL
, O_NONBLOCK
) == -1) {
89 void AsyncSocketIoHandler::EnsureWatchingSocket() {
90 DCHECK(CalledOnValidThread());
91 if (!is_watching_
&& socket_
!= base::SyncSocket::kInvalidHandle
) {
92 is_watching_
= base::MessageLoopForIO::current()->WatchFileDescriptor(
93 socket_
, true, base::MessageLoopForIO::WATCH_READ
,
94 &socket_watcher_
, this);