// 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" namespace base { AsyncSocketIoHandler::AsyncSocketIoHandler() : socket_(base::SyncSocket::kInvalidHandle), context_(NULL), is_pending_(false) {} AsyncSocketIoHandler::~AsyncSocketIoHandler() { // We need to be deleted on the correct thread to avoid racing with the // message loop thread. DCHECK(CalledOnValidThread()); if (context_) { if (is_pending_) { // Make the context be deleted by the message pump when done. context_->handler = NULL; } else { delete context_; } } } // Implementation of IOHandler on Windows. void AsyncSocketIoHandler::OnIOCompleted( base::MessageLoopForIO::IOContext* context, DWORD bytes_transfered, DWORD error) { DCHECK(CalledOnValidThread()); DCHECK_EQ(context_, context); DCHECK(!read_complete_.is_null()); is_pending_ = false; read_complete_.Run(error == ERROR_SUCCESS ? bytes_transfered : 0); } bool AsyncSocketIoHandler::Read(char* buffer, int buffer_len) { DCHECK(CalledOnValidThread()); DCHECK(!read_complete_.is_null()); DCHECK(!is_pending_); DCHECK_NE(socket_, base::SyncSocket::kInvalidHandle); DWORD bytes_read = 0; BOOL ok = ::ReadFile(socket_, buffer, buffer_len, &bytes_read, &context_->overlapped); // The completion port will be signaled regardless of completing the read // straight away or asynchronously (ERROR_IO_PENDING). OnIOCompleted() will // be called regardless and we don't need to explicitly run the callback // in the case where ok is FALSE and GLE==ERROR_IO_PENDING. is_pending_ = !ok && (GetLastError() == ERROR_IO_PENDING); return ok || is_pending_; } bool AsyncSocketIoHandler::Initialize(base::SyncSocket::Handle socket, const ReadCompleteCallback& callback) { DCHECK(!context_); DCHECK_EQ(socket_, base::SyncSocket::kInvalidHandle); DetachFromThread(); socket_ = socket; read_complete_ = callback; base::MessageLoopForIO::current()->RegisterIOHandler(socket, this); context_ = new base::MessageLoopForIO::IOContext(); context_->handler = this; memset(&context_->overlapped, 0, sizeof(context_->overlapped)); return true; } } // namespace base.