示例#1
0
uint32_t OpMsg::flags(const Message& message) {
    if (message.operation() != dbMsg)
        return 0;  // Other command protocols are the same as no flags set.

    return BufReader(message.singleData().data(), message.dataSize())
        .read<LittleEndian<uint32_t>>();
}
示例#2
0
OpMsg OpMsg::parse(const Message& message) try {
    // TODO some validation may make more sense in the IDL parser. I've tagged them with comments.
    OpMsg msg;
    // Use a separate BufReader for the flags since the flags can change how much room we have
    // for sections.
    BufReader(message.singleData().data(), message.dataSize()).read(msg.flags);
    uassert(40429,
            str::stream() << "Message contains illegal flags value: " << msg.flags,
            !containsUnknownRequiredFlags(msg.flags));

    invariant(!msg.isFlagSet(kChecksumPresent));  // TODO SERVER-28679 check checksum here.

    constexpr int kCrc32Size = 4;
    const int checksumSize = msg.isFlagSet(kChecksumPresent) ? kCrc32Size : 0;
    BufReader sectionsBuf(message.singleData().data() + sizeof(msg.flags),
                          message.dataSize() - sizeof(msg.flags) - checksumSize);
    bool haveBody = false;
    while (!sectionsBuf.atEof()) {
        const auto sectionKind = sectionsBuf.read<Section>();
        switch (sectionKind) {
            case Section::kBody: {
                uassert(40430, "Multiple body sections in message", !haveBody);
                haveBody = true;
                msg.body = sectionsBuf.read<Validated<BSONObj>>();
                break;
            }

            case Section::kDocSequence: {
                // The first 4 bytes are the total size, including themselves.
                const auto remainingSize = sectionsBuf.read<int32_t>() - sizeof(int32_t);
                BufReader seqBuf(sectionsBuf.skip(remainingSize), remainingSize);
                const auto name = seqBuf.readCStr();
                uassert(40431,
                        str::stream() << "Duplicate document sequence: " << name,
                        !msg.getSequence(name));  // TODO IDL

                msg.sequences.push_back({name.toString()});
                while (!seqBuf.atEof()) {
                    msg.sequences.back().objs.push_back(seqBuf.read<Validated<BSONObj>>());
                }
                break;
            }

            default:
                // Using uint32_t so we append as a decimal number rather than as a char.
                uasserted(40432, str::stream() << "Unknown section kind " << uint32_t(sectionKind));
        }
    }

    // Detect duplicates between doc sequences and body. TODO IDL
    // Technically this is O(N*M) but N is at most 2.
    for (const auto& docSeq : msg.sequences) {
        const char* name = docSeq.name.c_str();  // Pointer is redirected by next call.
        auto inBody =
            !dotted_path_support::extractElementAtPathOrArrayAlongPath(msg.body, name).eoo();
        uassert(40433,
                str::stream() << "Duplicate field between body and document sequence "
                              << docSeq.name,
                !inBody);
    }

    return msg;
} catch (const DBException& ex) {
    // TODO change to LOG(1).
    log() << "invalid message: " << redact(ex) << ' '
          << hexdump(message.singleData().view2ptr(), message.size());
    throw;
}