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