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