|  | // 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. |