// message_port.cpp /* Copyright 2009 10gen 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::kNetwork #include "mongo/platform/basic.h" #include "mongo/util/net/message_port.h" #include #include #include "mongo/config.h" #include "mongo/util/allocator.h" #include "mongo/util/background.h" #include "mongo/util/log.h" #include "mongo/util/net/listen.h" #include "mongo/util/net/message.h" #include "mongo/util/net/socket_exception.h" #include "mongo/util/net/ssl_manager.h" #include "mongo/util/net/ssl_options.h" #include "mongo/util/scopeguard.h" #include "mongo/util/time_support.h" #ifndef _WIN32 #ifndef __sun #include #endif #include #include #endif namespace mongo { using std::shared_ptr; using std::string; /* messagingport -------------------------------------------------------------- */ MessagingPort::MessagingPort(int fd, const SockAddr& remote) : MessagingPort(std::make_shared(fd, remote)) {} MessagingPort::MessagingPort(double timeout, logger::LogSeverity ll) : MessagingPort(std::make_shared(timeout, ll)) {} MessagingPort::MessagingPort(std::shared_ptr sock) : _x509PeerInfo(), _connectionId(), _tag(), _psock(std::move(sock)) { SockAddr sa = _psock->remoteAddr(); _remoteParsed = HostAndPort(sa.getAddr(), sa.getPort()); } void MessagingPort::setTimeout(Milliseconds millis) { double timeout = double(millis.count()) / 1000; _psock->setTimeout(timeout); } void MessagingPort::shutdown() { _psock->close(); } MessagingPort::~MessagingPort() { shutdown(); } bool MessagingPort::recv(Message& m) { try { #ifdef MONGO_CONFIG_SSL again: #endif MSGHEADER::Value header; _psock->recv((char*)&header, sizeof(header)); int len = header.constView().getMessageLength(); if (len == 542393671) { // an http GET string msg = "It looks like you are trying to access MongoDB over HTTP on the native driver " "port.\n"; LOG(_psock->getLogLevel()) << msg; std::stringstream ss; ss << "HTTP/1.0 200 OK\r\nConnection: close\r\nContent-Type: " "text/plain\r\nContent-Length: " << msg.size() << "\r\n\r\n" << msg; string s = ss.str(); send(s.c_str(), s.size(), "http"); return false; } // If responseTo is not 0 or -1 for first packet assume SSL else if (_psock->isAwaitingHandshake()) { #ifndef MONGO_CONFIG_SSL if (header.constView().getResponseToMsgId() != 0 && header.constView().getResponseToMsgId() != -1) { uasserted(17133, "SSL handshake requested, SSL feature not available in this build"); } #else if (header.constView().getResponseToMsgId() != 0 && header.constView().getResponseToMsgId() != -1) { uassert(17132, "SSL handshake received but server is started without SSL support", sslGlobalParams.sslMode.load() != SSLParams::SSLMode_disabled); setX509PeerInfo( _psock->doSSLHandshake(reinterpret_cast(&header), sizeof(header))); LOG(1) << "new ssl connection, SNI server name [" << _psock->getSNIServerName() << "]"; _psock->setHandshakeReceived(); goto again; } auto sslMode = sslGlobalParams.sslMode.load(); uassert(17189, "The server is configured to only allow SSL connections", sslMode != SSLParams::SSLMode_requireSSL); // For users attempting to upgrade their applications from no SSL to SSL, provide // information about connections that still aren't using SSL (but only once per // connection) if (!sslGlobalParams.disableNonSSLConnectionLogging && (sslMode == SSLParams::SSLMode_preferSSL)) { LOG(0) << "SSL mode is set to 'preferred' and connection " << _connectionId << " to " << remote() << " is not using SSL."; } #endif // MONGO_CONFIG_SSL } if (static_cast(len) < sizeof(header) || static_cast(len) > MaxMessageSizeBytes) { LOG(0) << "recv(): message len " << len << " is invalid. " << "Min " << sizeof(header) << " Max: " << MaxMessageSizeBytes; return false; } _psock->setHandshakeReceived(); auto buf = SharedBuffer::allocate(len); MsgData::View md = buf.get(); memcpy(md.view2ptr(), &header, sizeof(header)); const int left = len - sizeof(header); if (left) _psock->recv(md.data(), left); m.setData(std::move(buf)); return true; } catch (const SocketException& e) { logger::LogSeverity severity = _psock->getLogLevel(); if (!e.shouldPrint()) severity = severity.lessSevere(); LOG(severity) << "SocketException: remote: " << remote() << " error: " << e; m.reset(); return false; } } void MessagingPort::reply(Message& received, Message& response) { say(/*received.from, */ response, received.header().getId()); } void MessagingPort::reply(Message& received, Message& response, int32_t responseToMsgId) { say(/*received.from, */ response, responseToMsgId); } bool MessagingPort::call(Message& toSend, Message& response) { say(toSend); bool success = recv(response); if (success) { invariant(!response.empty()); if (response.header().getResponseToMsgId() != toSend.header().getId()) { response.reset(); uasserted(40134, "Response ID did not match the sent message ID."); } } return success; } void MessagingPort::say(Message& toSend, int responseTo) { invariant(!toSend.empty()); toSend.header().setId(nextMessageId()); toSend.header().setResponseToMsgId(responseTo); return say(const_cast(toSend)); } void MessagingPort::say(const Message& toSend) { invariant(!toSend.empty()); auto buf = toSend.buf(); if (buf) { send(buf, MsgData::ConstView(buf).getLen(), "say"); } } HostAndPort MessagingPort::remote() const { return _remoteParsed; } SockAddr MessagingPort::remoteAddr() const { return _psock->remoteAddr(); } SockAddr MessagingPort::localAddr() const { return _psock->localAddr(); } void MessagingPort::setX509PeerInfo(SSLPeerInfo x509PeerInfo) { _x509PeerInfo = std::move(x509PeerInfo); } const SSLPeerInfo& MessagingPort::getX509PeerInfo() const { return _x509PeerInfo; } void MessagingPort::setConnectionId(const long long connectionId) { _connectionId = connectionId; } long long MessagingPort::connectionId() const { return _connectionId; } void MessagingPort::setTag(const AbstractMessagingPort::Tag tag) { _tag = tag; } AbstractMessagingPort::Tag MessagingPort::getTag() const { return _tag; } } // namespace mongo