13551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
53551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/async_socket_io_handler.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <fcntl.h>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/posix/eintr_wrapper.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)namespace base {
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AsyncSocketIoHandler::AsyncSocketIoHandler()
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : socket_(base::SyncSocket::kInvalidHandle),
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pending_buffer_(NULL),
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pending_buffer_len_(0),
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_watching_(false) {
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AsyncSocketIoHandler::~AsyncSocketIoHandler() {
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AsyncSocketIoHandler::OnFileCanReadWithoutBlocking(int socket) {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(socket, socket_);
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!read_complete_.is_null());
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pending_buffer_) {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int bytes_read = HANDLE_EINTR(read(socket_, pending_buffer_,
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       pending_buffer_len_));
322385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    DCHECK_GE(bytes_read, 0);
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pending_buffer_ = NULL;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pending_buffer_len_ = 0;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    read_complete_.Run(bytes_read > 0 ? bytes_read : 0);
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We're getting notifications that we can read from the socket while
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // we're not waiting for data.  In order to not starve the message loop,
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // let's stop watching the fd and restart the watch when Read() is called.
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_watching_ = false;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    socket_watcher_.StopWatchingFileDescriptor();
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AsyncSocketIoHandler::Read(char* buffer, int buffer_len) {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!read_complete_.is_null());
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!pending_buffer_);
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EnsureWatchingSocket();
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int bytes_read = HANDLE_EINTR(read(socket_, buffer, buffer_len));
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bytes_read < 0) {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (errno == EAGAIN) {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pending_buffer_ = buffer;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pending_buffer_len_ = buffer_len;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "read(): " << errno;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    read_complete_.Run(bytes_read);
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AsyncSocketIoHandler::Initialize(base::SyncSocket::Handle socket,
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      const ReadCompleteCallback& callback) {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(socket_, base::SyncSocket::kInvalidHandle);
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DetachFromThread();
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  socket_ = socket;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  read_complete_ = callback;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // SyncSocket is blocking by default, so let's convert it to non-blocking.
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int value = fcntl(socket, F_GETFL);
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!(value & O_NONBLOCK)) {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Set the socket to be non-blocking so we can do async reads.
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (fcntl(socket, F_SETFL, O_NONBLOCK) == -1) {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AsyncSocketIoHandler::EnsureWatchingSocket() {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!is_watching_ && socket_ != base::SyncSocket::kInvalidHandle) {
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    is_watching_ = base::MessageLoopForIO::current()->WatchFileDescriptor(
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        socket_, true, base::MessageLoopForIO::WATCH_READ,
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        &socket_watcher_, this);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
98424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}  // namespace base.
99