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);
                     });
}
예제 #2
0
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());
}
예제 #4
0
파일: db.cpp 프로젝트: riggery/mongo
    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;
        }
    }
예제 #5
0
파일: db.cpp 프로젝트: maxkeller/mongo
        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;
            }
        }
예제 #6
0
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()), ""};
}
예제 #7
0
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;
    }
}
예제 #8
0
파일: bridge.cpp 프로젝트: ANTco/mongo
    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;
            }
        }
    }