diff options
author | Mark Benvenuto <mark.benvenuto@mongodb.com> | 2014-08-11 18:48:46 -0400 |
---|---|---|
committer | Mark Benvenuto <mark.benvenuto@mongodb.com> | 2014-08-14 16:28:12 -0400 |
commit | 9105b69e1ded5b7d0d384d574103b0ee6bbb6122 (patch) | |
tree | a0d99a076a8017564ac271fe320310729b7577c3 /src/mongo/db/dbmessage.cpp | |
parent | bd14042812b9bab796a83672f95b2d0e2e6b4252 (diff) | |
download | mongo-9105b69e1ded5b7d0d384d574103b0ee6bbb6122.tar.gz |
SERVER-14268: Backport from 2.6 to 2.4
Diffstat (limited to 'src/mongo/db/dbmessage.cpp')
-rw-r--r-- | src/mongo/db/dbmessage.cpp | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/src/mongo/db/dbmessage.cpp b/src/mongo/db/dbmessage.cpp index 3f1e866291f..aebe88b1d07 100644 --- a/src/mongo/db/dbmessage.cpp +++ b/src/mongo/db/dbmessage.cpp @@ -52,6 +52,140 @@ namespace mongo { return ss.str(); } + DbMessage::DbMessage(const Message& msg) : _msg(msg), _nsStart(NULL), _mark(NULL), _nsLen(0) { + // for received messages, Message has only one buffer + _theEnd = _msg.singleData()->_data + _msg.singleData()->dataLen(); + _nextjsobj = _msg.singleData()->_data; + + _reserved = readAndAdvance<int>(); + + // Read packet for NS + if (messageShouldHaveNs()) { + + // Limit = buffer size of message - + // (first int4 in message which is either flags or a zero constant) + size_t limit = _msg.singleData()->dataLen() - sizeof(int); + + _nsStart = _nextjsobj; + _nsLen = strnlen(_nsStart, limit); + + // Validate there is room for a null byte in the buffer + // Strings can be zero length + uassert(18633, "Failed to parse ns string", _nsLen <= (limit - 1)); + + _nextjsobj += _nsLen + 1; // skip namespace + null + } + } + + const char * DbMessage::getns() const { + verify(messageShouldHaveNs()); + return _nsStart; + } + + long long DbMessage::getInt64(int offsetBytes) const { + verify(messageShouldHaveNs()); + const char* p = _nsStart + _nsLen + 1; + checkReadOffset<long long>(p, offsetBytes); + + return ((reinterpret_cast<const long long*>(p + offsetBytes)))[0]; + } + + int DbMessage::getQueryNToReturn() const { + verify(messageShouldHaveNs()); + const char* p = _nsStart + _nsLen + 1; + checkRead<int>(p, 2); + + return ((reinterpret_cast<const int*>(p)))[1]; + } + + + int DbMessage::getFlags() const { + verify(messageShouldHaveNs()); + const char* p = _nsStart + _nsLen + 1; + checkRead<int>(p, 1); + + return ((reinterpret_cast<const int*>(p)))[0]; + } + + void DbMessage::setFlags(int value) { + verify(messageShouldHaveNs()); + char* p = const_cast<char*>(_nsStart) + _nsLen + 1; + checkRead<int>(p, 1); + + ((reinterpret_cast<int*>(p)))[0] = value; + } + + + int DbMessage::pullInt() { + return readAndAdvance<int>(); + } + + long long DbMessage::pullInt64() { + return readAndAdvance<long long>(); + } + + const long long* DbMessage::getArray(size_t count) const { + checkRead<long long>(_nextjsobj, count); + return reinterpret_cast<const long long*>(_nextjsobj); + } + + BSONObj DbMessage::nextJsObj() { + massert(10304, + "Client Error: Remaining data too small for BSON object", + _nextjsobj != NULL && _theEnd - _nextjsobj >= 5); + + if (cmdLine.objcheck) { + Status status = validateBSON(_nextjsobj, _theEnd - _nextjsobj); + massert(10307, + str::stream() << "Client Error: bad object in message: " << status.reason(), + status.isOK()); + } + + BSONObj js(_nextjsobj); + verify(js.objsize() >= 5); + verify(js.objsize() <= (_theEnd - _nextjsobj)); + + _nextjsobj += js.objsize(); + if (_nextjsobj >= _theEnd) + _nextjsobj = NULL; + return js; + } + + void DbMessage::markReset(const char * toMark) { + if (toMark == NULL) { + toMark = _mark; + } + + verify(toMark); + _nextjsobj = toMark; + } + + template<typename T> + void DbMessage::checkRead(const char* start, size_t count) const { + if ((_theEnd - start) < static_cast<int>(sizeof(T) * count)) { + uassert(18634, "Not enough data to read", false); + } + } + + template<typename T> + void DbMessage::checkReadOffset(const char* start, size_t offset) const { + if ((_theEnd - start) < static_cast<int>(offset + sizeof(T))) { + uassert(18626, "Not enough data to read", false); + } + } + + template<typename T> + T DbMessage::read() const { + checkRead<T>(_nextjsobj, 1); + + return *(reinterpret_cast<const T*>(_nextjsobj)); + } + + template<typename T> T DbMessage::readAndAdvance() { + T t = read<T>(); + _nextjsobj += sizeof(T); + return t; + } void replyToQuery(int queryResultFlags, AbstractMessagingPort* p, Message& requestMsg, |