void NetworkInterfaceASIO::_recvMessageBody(AsyncOp* op) { // TODO: This error code should be more meaningful. std::error_code ec; // validate message length int len = op->header()->constView().getMessageLength(); if (len == 542393671) { LOG(3) << "attempt to access MongoDB over HTTP on the native driver port."; return _networkErrorCallback(op, ec); } else if (len == -1) { // TODO: An endian check is run after the client connects, we should // set that we've received the client's handshake LOG(3) << "Endian check received from client"; return _networkErrorCallback(op, ec); } else if (static_cast<size_t>(len) < sizeof(MSGHEADER::Value) || static_cast<size_t>(len) > MaxMessageSizeBytes) { warning() << "recv(): message len " << len << " is invalid. " << "Min " << sizeof(MSGHEADER::Value) << " Max: " << MaxMessageSizeBytes; return _networkErrorCallback(op, ec); } // validate response id uint32_t expectedId = op->toSend()->header().getId(); uint32_t actualId = op->header()->constView().getResponseTo(); if (actualId != expectedId) { LOG(3) << "got wrong response:" << " expected response id: " << expectedId << ", got response id: " << actualId; return _networkErrorCallback(op, ec); } int z = (len + 1023) & 0xfffffc00; invariant(z >= len); op->toRecv()->setData(reinterpret_cast<char*>(mongoMalloc(z)), true); MsgData::View mdView = op->toRecv()->buf(); // copy header data into master buffer int headerLen = sizeof(MSGHEADER::Value); memcpy(mdView.view2ptr(), op->header(), headerLen); int bodyLength = len - headerLen; invariant(bodyLength >= 0); // receive remaining data into md->data asio::async_read(op->connection()->sock(), asio::buffer(mdView.data(), bodyLength), [this, op, mdView](asio::error_code ec, size_t bytes) { if (op->canceled()) { return _completeOperation(op, kCanceledStatus); } if (ec) { LOG(3) << "error receiving message body"; return _networkErrorCallback(op, ec); } return _completedWriteCallback(op); }); }
Message CommandReplyBuilder::done() { invariant(_state == State::kOutputDocs); MsgData::View msg = _builder.buf(); msg.setLen(_builder.len()); msg.setOperation(dbCommandReply); _builder.decouple(); // release ownership from BufBuilder _message.setData(msg.view2ptr(), true); // transfer ownership to Message _state = State::kDone; return std::move(_message); }
Message opCommandRequestFromOpMsgRequest(const OpMsgRequest& request) { const auto commandName = request.getCommandName(); BufBuilder builder; builder.skip(mongo::MsgData::MsgDataHeaderSize); // Leave room for message header. builder.appendStr(request.getDatabase()); builder.appendStr(commandName); // OP_COMMAND is only used when communicating with 3.4 nodes and they serialize their metadata // fields differently. In addition to field-level differences, some generic arguments are pulled // out to a metadata object, separate from the body. We do all down-conversion here so that the // rest of the code only has to deal with the current format. BSONObjBuilder metadataBuilder; // Will be appended to the message after we finish the body. { BSONObjBuilder bodyBuilder(builder); for (auto elem : request.body) { const auto fieldName = elem.fieldNameStringData(); if (fieldName == "$configServerState") { metadataBuilder.appendAs(elem, "configsvr"); } else if (fieldName == "$readPreference") { BSONObjBuilder ssmBuilder(metadataBuilder.subobjStart("$ssm")); ssmBuilder.append(elem); ssmBuilder.append("$secondaryOk", uassertStatusOK(ReadPreferenceSetting::fromInnerBSON(elem)) .canRunOnSecondary()); } else if (fieldName == "$db") { // skip } else if (fieldGoesInMetadata(commandName, fieldName)) { metadataBuilder.append(elem); } else { bodyBuilder.append(elem); } } for (auto&& seq : request.sequences) { invariant(seq.name.find('.') == std::string::npos); // Only support top-level for now. dassert(!bodyBuilder.asTempObj().hasField(seq.name)); bodyBuilder.append(seq.name, seq.objs); } } metadataBuilder.obj().appendSelfToBufBuilder(builder); MsgData::View msg = builder.buf(); msg.setLen(builder.len()); msg.setOperation(dbCommand); return Message(builder.release()); }
virtual void process(Message& m, AbstractMessagingPort* port) { while (true) { if (inShutdown()) { log() << "got request after shutdown()" << endl; break; } DbResponse dbresponse; { auto opCtx = getGlobalServiceContext()->makeOperationContext(&cc()); assembleResponse(opCtx.get(), m, dbresponse, port->remote()); // opCtx must go out of scope here so that the operation cannot show up in currentOp // results after the response reaches the client } if (!dbresponse.response.empty()) { port->reply(m, dbresponse.response, dbresponse.responseTo); if (dbresponse.exhaustNS.size() > 0) { MsgData::View header = dbresponse.response.header(); QueryResult::View qr = header.view2ptr(); long long cursorid = qr.getCursorId(); if (cursorid) { verify(dbresponse.exhaustNS.size() && dbresponse.exhaustNS[0]); string ns = dbresponse.exhaustNS; // before reset() free's it... m.reset(); BufBuilder b(512); b.appendNum((int)0 /*size set later in appendData()*/); b.appendNum(header.getId()); b.appendNum(header.getResponseTo()); b.appendNum((int)dbGetMore); b.appendNum((int)0); b.appendStr(ns); b.appendNum((int)0); // ntoreturn b.appendNum(cursorid); m.appendData(b.buf(), b.len()); b.decouple(); DEV log() << "exhaust=true sending more"; continue; // this goes back to top loop } } } break; } }
virtual void process( Message& m , AbstractMessagingPort* port , LastError * le) { OperationContextImpl txn; while ( true ) { if ( inShutdown() ) { log() << "got request after shutdown()" << endl; break; } lastError.startRequest( m , le ); DbResponse dbresponse; assembleResponse(&txn, m, dbresponse, port->remote()); if ( dbresponse.response ) { port->reply(m, *dbresponse.response, dbresponse.responseTo); if( dbresponse.exhaustNS.size() > 0 ) { MsgData::View header = dbresponse.response->header(); QueryResult::View qr = header.view2ptr(); long long cursorid = qr.getCursorId(); if( cursorid ) { verify( dbresponse.exhaustNS.size() && dbresponse.exhaustNS[0] ); string ns = dbresponse.exhaustNS; // before reset() free's it... m.reset(); BufBuilder b(512); b.appendNum((int) 0 /*size set later in appendData()*/); b.appendNum(header.getId()); b.appendNum(header.getResponseTo()); b.appendNum((int) dbGetMore); b.appendNum((int) 0); b.appendStr(ns); b.appendNum((int) 0); // ntoreturn b.appendNum(cursorid); m.appendData(b.buf(), b.len()); b.decouple(); DEV log() << "exhaust=true sending more" << endl; continue; // this goes back to top loop } } } break; } }
DbResponse ServiceEntryPointMock::handleRequest(OperationContext* opCtx, const Message& request, const HostAndPort& client) { // Need to set up our { ok : 1 } response. BufBuilder b{}; // Leave room for the message header b.skip(mongo::MsgData::MsgDataHeaderSize); // Add our response auto okObj = BSON("ok" << 1.0); okObj.appendSelfToBufBuilder(b); // Add some metadata auto metadata = BSONObj(); metadata.appendSelfToBufBuilder(b); // Set Message header fields MsgData::View msg = b.buf(); msg.setLen(b.len()); msg.setOperation(dbCommandReply); return {Message(b.release()), ""}; }
bool MessagingPort::recv(Message& m) { try { #ifdef MONGO_CONFIG_SSL again: #endif // mmm( log() << "* recv() sock:" << this->sock << endl; ) MSGHEADER::Value header; int headerLen = sizeof(MSGHEADER::Value); psock->recv((char*)&header, headerLen); 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().getResponseTo() != 0 && header.constView().getResponseTo() != -1) { uasserted(17133, "SSL handshake requested, SSL feature not available in this build"); } #else if (header.constView().getResponseTo() != 0 && header.constView().getResponseTo() != -1) { uassert(17132, "SSL handshake received but server is started without SSL support", sslGlobalParams.sslMode.load() != SSLParams::SSLMode_disabled); setX509SubjectName( psock->doSSLHandshake(reinterpret_cast<const char*>(&header), sizeof(header))); psock->setHandshakeReceived(); goto again; } uassert(17189, "The server is configured to only allow SSL connections", sslGlobalParams.sslMode.load() != SSLParams::SSLMode_requireSSL); #endif // MONGO_CONFIG_SSL } if (static_cast<size_t>(len) < sizeof(MSGHEADER::Value) || static_cast<size_t>(len) > MaxMessageSizeBytes) { LOG(0) << "recv(): message len " << len << " is invalid. " << "Min " << sizeof(MSGHEADER::Value) << " Max: " << MaxMessageSizeBytes; return false; } psock->setHandshakeReceived(); int z = (len + 1023) & 0xfffffc00; verify(z >= len); MsgData::View md = reinterpret_cast<char*>(mongolMalloc(z)); ScopeGuard guard = MakeGuard(free, md.view2ptr()); verify(md.view2ptr()); memcpy(md.view2ptr(), &header, headerLen); int left = len - headerLen; psock->recv(md.data(), left); guard.Dismiss(); m.setData(md.view2ptr(), true); 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 operator()() const { DBClientConnection dest; string errmsg; Timer connectTimer; while (!dest.connect(HostAndPort(mongoBridgeGlobalParams.destUri), errmsg)) { // If we can't connect for the configured timeout, give up // if (connectTimer.seconds() >= mongoBridgeGlobalParams.connectTimeoutSec) { cout << "Unable to establish connection from " << mp_.psock->remoteString() << " to " << mongoBridgeGlobalParams.destUri << " after " << connectTimer.seconds() << " seconds. Giving up." << endl; mp_.shutdown(); return; } sleepmillis(500); } Message m; while( 1 ) { try { m.reset(); if ( !mp_.recv( m ) ) { cout << "end connection " << mp_.psock->remoteString() << endl; mp_.shutdown(); break; } sleepmillis(mongoBridgeGlobalParams.delay); int oldId = m.header().getId(); if ( m.operation() == dbQuery || m.operation() == dbMsg || m.operation() == dbGetMore ) { bool exhaust = false; if ( m.operation() == dbQuery ) { DbMessage d( m ); QueryMessage q( d ); exhaust = q.queryOptions & QueryOption_Exhaust; } Message response; dest.port().call( m, response ); // nothing to reply with? if ( response.empty() ) cleanup(0); mp_.reply( m, response, oldId ); while ( exhaust ) { MsgData::View header = response.header(); QueryResult::View qr = header.view2ptr(); if ( qr.getCursorId() ) { response.reset(); dest.port().recv( response ); mp_.reply( m, response ); // m argument is ignored anyway } else { exhaust = false; } } } else { dest.port().say( m, oldId ); } } catch ( ... ) { log() << "caught exception in Forwarder, continuing" << endl; } } }