/** * Copyright (C) 2015 MongoDB Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * As a special exception, the copyright holders give permission to link the * code of portions of this program with the OpenSSL library under certain * conditions as described in each individual source file and distribute * linked combinations including the program with the OpenSSL library. You * must comply with the GNU Affero General Public License in all respects for * all of the code used other than as permitted herein. If you modify file(s) * with this exception, you may extend this exception to your version of the * file(s), but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. If you delete this * exception statement from all source files in the program, then also delete * it in the license file. */ #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kASIO #include "mongo/platform/basic.h" #include "mongo/executor/network_interface_asio.h" #include #include "mongo/base/system_error.h" #include "mongo/config.h" #include "mongo/db/wire_version.h" #include "mongo/executor/async_stream.h" #include "mongo/executor/async_stream_factory.h" #include "mongo/executor/async_stream_interface.h" #include "mongo/stdx/memory.h" #include "mongo/util/log.h" namespace mongo { namespace executor { using asio::ip::tcp; NetworkInterfaceASIO::AsyncConnection::AsyncConnection(std::unique_ptr stream, rpc::ProtocolSet protocols) : _stream(std::move(stream)), _serverProtocols(protocols), _clientProtocols(rpc::computeProtocolSet(WireSpec::instance().outgoing)) {} AsyncStreamInterface& NetworkInterfaceASIO::AsyncConnection::stream() { return *_stream; } void NetworkInterfaceASIO::AsyncConnection::cancel() { _stream->cancel(); } rpc::ProtocolSet NetworkInterfaceASIO::AsyncConnection::serverProtocols() const { return _serverProtocols; } rpc::ProtocolSet NetworkInterfaceASIO::AsyncConnection::clientProtocols() const { return _clientProtocols; } void NetworkInterfaceASIO::AsyncConnection::setServerProtocols(rpc::ProtocolSet protocols) { _serverProtocols = protocols; } void NetworkInterfaceASIO::_connect(AsyncOp* op) { log() << "Connecting to " << op->request().target.toString(); tcp::resolver::query query(op->request().target.host(), std::to_string(op->request().target.port())); // TODO: Investigate how we might hint or use shortcuts to resolve when possible. const auto thenConnect = [this, op](std::error_code ec, tcp::resolver::iterator endpoints) { if (endpoints == tcp::resolver::iterator()) { // Workaround a bug in ASIO returning an invalid resolver iterator (with a non-error // std::error_code) when file descriptors are exhausted. ec = make_error_code(ErrorCodes::HostUnreachable); } _validateAndRun( op, ec, [this, op, endpoints]() { _setupSocket(op, std::move(endpoints)); }); }; op->resolver().async_resolve(query, op->_strand.wrap(std::move(thenConnect))); } void NetworkInterfaceASIO::_setupSocket(AsyncOp* op, tcp::resolver::iterator endpoints) { // TODO: Consider moving this call to post-auth so we only assign completed connections. { auto stream = _streamFactory->makeStream(&op->strand(), op->request().target); op->setConnection({std::move(stream), rpc::supports::kOpQueryOnly}); } auto& stream = op->connection().stream(); stream.connect(std::move(endpoints), [this, op](std::error_code ec) { _validateAndRun(op, ec, [this, op]() { _runIsMaster(op); }); }); } } // namespace executor } // namespace mongo