1 2 /** 3 * Copyright (C) 2018-present MongoDB, Inc. 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the Server Side Public License, version 1, 7 * as published by MongoDB, Inc. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * Server Side Public License for more details. 13 * 14 * You should have received a copy of the Server Side Public License 15 * along with this program. If not, see 16 * <http://www.mongodb.com/licensing/server-side-public-license>. 17 * 18 * As a special exception, the copyright holders give permission to link the 19 * code of portions of this program with the OpenSSL library under certain 20 * conditions as described in each individual source file and distribute 21 * linked combinations including the program with the OpenSSL library. You 22 * must comply with the Server Side Public License in all respects for 23 * all of the code used other than as permitted herein. If you modify file(s) 24 * with this exception, you may extend this exception to your version of the 25 * file(s), but you are not obligated to do so. If you do not wish to do so, 26 * delete this exception statement from your version. If you delete this 27 * exception statement from all source files in the program, then also delete 28 * it in the license file. 29 */ 30 31 #pragma once 32 33 #include <functional> 34 #include <string> 35 36 #include "mongo/config.h" 37 #include "mongo/db/server_options.h" 38 #include "mongo/stdx/condition_variable.h" 39 #include "mongo/stdx/memory.h" 40 #include "mongo/stdx/mutex.h" 41 #include "mongo/stdx/thread.h" 42 #include "mongo/transport/ticket_impl.h" 43 #include "mongo/transport/transport_layer.h" 44 #include "mongo/transport/transport_mode.h" 45 #include "mongo/util/net/hostandport.h" 46 #include "mongo/util/net/ssl_options.h" 47 #include "mongo/util/net/ssl_types.h" 48 49 namespace asio { 50 class io_context; 51 52 template <typename Protocol> 53 class basic_socket_acceptor; 54 55 namespace generic { 56 class stream_protocol; 57 } // namespace generic 58 59 namespace ssl { 60 class context; 61 } // namespace ssl 62 } // namespace asio 63 64 namespace mongo { 65 66 class ServiceContext; 67 class ServiceEntryPoint; 68 69 namespace transport { 70 71 /** 72 * A TransportLayer implementation based on ASIO networking primitives. 73 */ 74 class TransportLayerASIO final : public TransportLayer { 75 MONGO_DISALLOW_COPYING(TransportLayerASIO); 76 77 public: 78 struct Options { 79 explicit Options(const ServerGlobalParams* params); 80 81 int port = ServerGlobalParams::DefaultDBPort; // port to bind to 82 std::vector<std::string> ipList; // addresses to bind to 83 #ifndef _WIN32 84 bool useUnixSockets = true; // whether to allow UNIX sockets in ipList 85 #endif 86 bool enableIPv6 = false; // whether to allow IPv6 sockets in ipList 87 Mode transportMode = Mode::kSynchronous; // whether accepted sockets should be put into 88 // non-blocking mode after they're accepted 89 size_t maxConns = DEFAULT_MAX_CONN; // maximum number of active connections 90 }; 91 92 TransportLayerASIO(const Options& opts, ServiceEntryPoint* sep); 93 94 virtual ~TransportLayerASIO(); 95 96 Ticket sourceMessage(const SessionHandle& session, 97 Message* message, 98 Date_t expiration = Ticket::kNoExpirationDate) final; 99 100 Ticket sinkMessage(const SessionHandle& session, 101 const Message& message, 102 Date_t expiration = Ticket::kNoExpirationDate) final; 103 104 Status wait(Ticket&& ticket) final; 105 106 void asyncWait(Ticket&& ticket, TicketCallback callback) final; 107 108 void end(const SessionHandle& session) final; 109 110 Status setup() final; 111 Status start() final; 112 113 void shutdown() final; 114 115 const std::shared_ptr<asio::io_context>& getIOContext(); 116 117 private: 118 class ASIOSession; 119 class ASIOTicket; 120 class ASIOSourceTicket; 121 class ASIOSinkTicket; 122 123 using ASIOSessionHandle = std::shared_ptr<ASIOSession>; 124 using ConstASIOSessionHandle = std::shared_ptr<const ASIOSession>; 125 using GenericAcceptor = asio::basic_socket_acceptor<asio::generic::stream_protocol>; 126 127 void _acceptConnection(GenericAcceptor& acceptor); 128 #ifdef MONGO_CONFIG_SSL 129 SSLParams::SSLModes _sslMode() const; 130 #endif 131 132 stdx::mutex _mutex; 133 134 // There are two IO contexts that are used by TransportLayerASIO. The _workerIOContext 135 // contains all the accepted sockets and all normal networking activity. The 136 // _acceptorIOContext contains all the sockets in _acceptors. 137 // 138 // TransportLayerASIO should never call run() on the _workerIOContext. 139 // In synchronous mode, this will cause a massive performance degradation due to 140 // unnecessary wakeups on the asio thread for sockets we don't intend to interact 141 // with asynchronously. The additional IO context avoids registering those sockets 142 // with the acceptors epoll set, thus avoiding those wakeups. Calling run will 143 // undo that benefit. 144 // 145 // TransportLayerASIO should run its own thread that calls run() on the _acceptorIOContext 146 // to process calls to async_accept - this is the equivalent of the "listener" thread in 147 // other TransportLayers. 148 // 149 // The underlying problem that caused this is here: 150 // https://github.com/chriskohlhoff/asio/issues/240 151 // 152 // It is important that the io_context be declared before the 153 // vector of acceptors (or any other state that is associated with 154 // the io_context), so that we destroy any existing acceptors or 155 // other io_service associated state before we drop the refcount 156 // on the io_context, which may destroy it. 157 std::shared_ptr<asio::io_context> _workerIOContext; 158 std::unique_ptr<asio::io_context> _acceptorIOContext; 159 160 #ifdef MONGO_CONFIG_SSL 161 std::unique_ptr<asio::ssl::context> _sslContext; 162 #endif 163 164 std::vector<std::pair<SockAddr, GenericAcceptor>> _acceptors; 165 166 // Only used if _listenerOptions.async is false. 167 stdx::thread _listenerThread; 168 169 ServiceEntryPoint* const _sep = nullptr; 170 AtomicWord<bool> _running{false}; 171 Options _listenerOptions; 172 }; 173 174 } // namespace transport 175 } // namespace mongo 176