Home | History | Annotate | Download | only in base
      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.
      4 
      5 #include "base/async_socket_io_handler.h"
      6 
      7 #include <fcntl.h>
      8 
      9 #include "base/posix/eintr_wrapper.h"
     10 
     11 namespace base {
     12 
     13 AsyncSocketIoHandler::AsyncSocketIoHandler()
     14     : socket_(base::SyncSocket::kInvalidHandle),
     15       pending_buffer_(NULL),
     16       pending_buffer_len_(0),
     17       is_watching_(false) {
     18 }
     19 
     20 AsyncSocketIoHandler::~AsyncSocketIoHandler() {
     21   DCHECK(CalledOnValidThread());
     22 }
     23 
     24 void AsyncSocketIoHandler::OnFileCanReadWithoutBlocking(int socket) {
     25   DCHECK(CalledOnValidThread());
     26   DCHECK_EQ(socket, socket_);
     27   DCHECK(!read_complete_.is_null());
     28 
     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);
     36   } else {
     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.
     40     is_watching_ = false;
     41     socket_watcher_.StopWatchingFileDescriptor();
     42   }
     43 }
     44 
     45 bool AsyncSocketIoHandler::Read(char* buffer, int buffer_len) {
     46   DCHECK(CalledOnValidThread());
     47   DCHECK(!read_complete_.is_null());
     48   DCHECK(!pending_buffer_);
     49 
     50   EnsureWatchingSocket();
     51 
     52   int bytes_read = HANDLE_EINTR(read(socket_, buffer, buffer_len));
     53   if (bytes_read < 0) {
     54     if (errno == EAGAIN) {
     55       pending_buffer_ = buffer;
     56       pending_buffer_len_ = buffer_len;
     57     } else {
     58       NOTREACHED() << "read(): " << errno;
     59       return false;
     60     }
     61   } else {
     62     read_complete_.Run(bytes_read);
     63   }
     64   return true;
     65 }
     66 
     67 bool AsyncSocketIoHandler::Initialize(base::SyncSocket::Handle socket,
     68                                       const ReadCompleteCallback& callback) {
     69   DCHECK_EQ(socket_, base::SyncSocket::kInvalidHandle);
     70 
     71   DetachFromThread();
     72 
     73   socket_ = socket;
     74   read_complete_ = callback;
     75 
     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) {
     81       NOTREACHED();
     82       return false;
     83     }
     84   }
     85 
     86   return true;
     87 }
     88 
     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);
     95   }
     96 }
     97 
     98 }  // namespace base.
     99