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