
R=tommi@chromium.org TBR=darin@chromium.org Review URL: https://chromiumcodereview.appspot.com/23058010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@219286 0039d316-1c4b-4281-b951-d872f2087c98
99 lines
2.8 KiB
C++
99 lines
2.8 KiB
C++
// Copyright 2013 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "base/async_socket_io_handler.h"
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include "base/posix/eintr_wrapper.h"
|
|
|
|
namespace base {
|
|
|
|
AsyncSocketIoHandler::AsyncSocketIoHandler()
|
|
: socket_(base::SyncSocket::kInvalidHandle),
|
|
pending_buffer_(NULL),
|
|
pending_buffer_len_(0),
|
|
is_watching_(false) {
|
|
}
|
|
|
|
AsyncSocketIoHandler::~AsyncSocketIoHandler() {
|
|
DCHECK(CalledOnValidThread());
|
|
}
|
|
|
|
void AsyncSocketIoHandler::OnFileCanReadWithoutBlocking(int socket) {
|
|
DCHECK(CalledOnValidThread());
|
|
DCHECK_EQ(socket, socket_);
|
|
DCHECK(!read_complete_.is_null());
|
|
|
|
if (pending_buffer_) {
|
|
int bytes_read = HANDLE_EINTR(read(socket_, pending_buffer_,
|
|
pending_buffer_len_));
|
|
DCHECK_GE(bytes_read, 0);
|
|
pending_buffer_ = NULL;
|
|
pending_buffer_len_ = 0;
|
|
read_complete_.Run(bytes_read > 0 ? bytes_read : 0);
|
|
} else {
|
|
// We're getting notifications that we can read from the socket while
|
|
// we're not waiting for data. In order to not starve the message loop,
|
|
// let's stop watching the fd and restart the watch when Read() is called.
|
|
is_watching_ = false;
|
|
socket_watcher_.StopWatchingFileDescriptor();
|
|
}
|
|
}
|
|
|
|
bool AsyncSocketIoHandler::Read(char* buffer, int buffer_len) {
|
|
DCHECK(CalledOnValidThread());
|
|
DCHECK(!read_complete_.is_null());
|
|
DCHECK(!pending_buffer_);
|
|
|
|
EnsureWatchingSocket();
|
|
|
|
int bytes_read = HANDLE_EINTR(read(socket_, buffer, buffer_len));
|
|
if (bytes_read < 0) {
|
|
if (errno == EAGAIN) {
|
|
pending_buffer_ = buffer;
|
|
pending_buffer_len_ = buffer_len;
|
|
} else {
|
|
NOTREACHED() << "read(): " << errno;
|
|
return false;
|
|
}
|
|
} else {
|
|
read_complete_.Run(bytes_read);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool AsyncSocketIoHandler::Initialize(base::SyncSocket::Handle socket,
|
|
const ReadCompleteCallback& callback) {
|
|
DCHECK_EQ(socket_, base::SyncSocket::kInvalidHandle);
|
|
|
|
DetachFromThread();
|
|
|
|
socket_ = socket;
|
|
read_complete_ = callback;
|
|
|
|
// SyncSocket is blocking by default, so let's convert it to non-blocking.
|
|
int value = fcntl(socket, F_GETFL);
|
|
if (!(value & O_NONBLOCK)) {
|
|
// Set the socket to be non-blocking so we can do async reads.
|
|
if (fcntl(socket, F_SETFL, O_NONBLOCK) == -1) {
|
|
NOTREACHED();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void AsyncSocketIoHandler::EnsureWatchingSocket() {
|
|
DCHECK(CalledOnValidThread());
|
|
if (!is_watching_ && socket_ != base::SyncSocket::kInvalidHandle) {
|
|
is_watching_ = base::MessageLoopForIO::current()->WatchFileDescriptor(
|
|
socket_, true, base::MessageLoopForIO::WATCH_READ,
|
|
&socket_watcher_, this);
|
|
}
|
|
}
|
|
|
|
} // namespace base.
|