1 // dbmessage.cpp
2 
3 
4 /**
5  *    Copyright (C) 2018-present MongoDB, Inc.
6  *
7  *    This program is free software: you can redistribute it and/or modify
8  *    it under the terms of the Server Side Public License, version 1,
9  *    as published by MongoDB, Inc.
10  *
11  *    This program is distributed in the hope that it will be useful,
12  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *    Server Side Public License for more details.
15  *
16  *    You should have received a copy of the Server Side Public License
17  *    along with this program. If not, see
18  *    <http://www.mongodb.com/licensing/server-side-public-license>.
19  *
20  *    As a special exception, the copyright holders give permission to link the
21  *    code of portions of this program with the OpenSSL library under certain
22  *    conditions as described in each individual source file and distribute
23  *    linked combinations including the program with the OpenSSL library. You
24  *    must comply with the Server Side Public License in all respects for
25  *    all of the code used other than as permitted herein. If you modify file(s)
26  *    with this exception, you may extend this exception to your version of the
27  *    file(s), but you are not obligated to do so. If you do not wish to do so,
28  *    delete this exception statement from your version. If you delete this
29  *    exception statement from all source files in the program, then also delete
30  *    it in the license file.
31  */
32 
33 #include "mongo/platform/basic.h"
34 
35 #include "mongo/db/dbmessage.h"
36 
37 #include "mongo/platform/strnlen.h"
38 #include "mongo/rpc/object_check.h"
39 
40 namespace mongo {
41 
DbMessage(const Message & msg)42 DbMessage::DbMessage(const Message& msg) : _msg(msg), _nsStart(NULL), _mark(NULL), _nsLen(0) {
43     // for received messages, Message has only one buffer
44     _theEnd = _msg.singleData().data() + _msg.singleData().dataLen();
45     _nextjsobj = _msg.singleData().data();
46 
47     _reserved = readAndAdvance<int>();
48 
49     // Read packet for NS
50     if (messageShouldHaveNs()) {
51         // Limit = buffer size of message -
52         //        (first int4 in message which is either flags or a zero constant)
53         size_t limit = _msg.singleData().dataLen() - sizeof(int);
54 
55         _nsStart = _nextjsobj;
56         _nsLen = strnlen(_nsStart, limit);
57 
58         // Validate there is room for a null byte in the buffer
59         // Strings can be zero length
60         uassert(18633, "Failed to parse ns string", _nsLen < limit);
61 
62         _nextjsobj += _nsLen + 1;  // skip namespace + null
63     }
64 }
65 
getns() const66 const char* DbMessage::getns() const {
67     verify(messageShouldHaveNs());
68     return _nsStart;
69 }
70 
getQueryNToReturn() const71 int DbMessage::getQueryNToReturn() const {
72     verify(messageShouldHaveNs());
73     const char* p = _nsStart + _nsLen + 1;
74     checkRead<int>(p, 2);
75 
76     return ConstDataView(p).read<LittleEndian<int32_t>>(sizeof(int32_t));
77 }
78 
pullInt()79 int DbMessage::pullInt() {
80     return readAndAdvance<int32_t>();
81 }
82 
pullInt64()83 long long DbMessage::pullInt64() {
84     return readAndAdvance<int64_t>();
85 }
86 
getArray(size_t count) const87 const char* DbMessage::getArray(size_t count) const {
88     checkRead<long long>(_nextjsobj, count);
89     return _nextjsobj;
90 }
91 
nextJsObj()92 BSONObj DbMessage::nextJsObj() {
93     uassert(ErrorCodes::InvalidBSON,
94             "Client Error: Remaining data too small for BSON object",
95             _nextjsobj != NULL && _theEnd - _nextjsobj >= 5);
96 
97     if (serverGlobalParams.objcheck) {
98         Status status = validateBSON(
99             _nextjsobj, _theEnd - _nextjsobj, Validator<BSONObj>::enabledBSONVersion());
100         uassert(ErrorCodes::InvalidBSON,
101                 str::stream() << "Client Error: bad object in message: " << status.reason(),
102                 status.isOK());
103     }
104 
105     BSONObj js(_nextjsobj);
106     verify(js.objsize() >= 5);
107     verify(js.objsize() <= (_theEnd - _nextjsobj));
108 
109     _nextjsobj += js.objsize();
110     if (_nextjsobj >= _theEnd)
111         _nextjsobj = NULL;
112     return js;
113 }
114 
markReset(const char * toMark=NULL)115 void DbMessage::markReset(const char* toMark = NULL) {
116     if (toMark == NULL) {
117         toMark = _mark;
118     }
119 
120     verify(toMark);
121     _nextjsobj = toMark;
122 }
123 
124 template <typename T>
checkRead(const char * start,size_t count) const125 void DbMessage::checkRead(const char* start, size_t count) const {
126     if ((_theEnd - start) < static_cast<int>(sizeof(T) * count)) {
127         uassert(18634, "Not enough data to read", false);
128     }
129 }
130 
131 template <typename T>
read() const132 T DbMessage::read() const {
133     checkRead<T>(_nextjsobj, 1);
134 
135     return ConstDataView(_nextjsobj).read<LittleEndian<T>>();
136 }
137 
138 template <typename T>
readAndAdvance()139 T DbMessage::readAndAdvance() {
140     T t = read<T>();
141     _nextjsobj += sizeof(T);
142     return t;
143 }
144 
145 namespace {
146 template <typename Func>
makeMessage(NetworkOp op,Func && bodyBuilder)147 Message makeMessage(NetworkOp op, Func&& bodyBuilder) {
148     BufBuilder b;
149     b.skip(sizeof(MSGHEADER::Layout));
150 
151     bodyBuilder(b);
152 
153     const int size = b.len();
154     auto out = Message(b.release());
155     out.header().setOperation(op);
156     out.header().setLen(size);
157     return out;
158 }
159 }
160 
makeInsertMessage(StringData ns,const BSONObj * objs,size_t count,int flags)161 Message makeInsertMessage(StringData ns, const BSONObj* objs, size_t count, int flags) {
162     return makeMessage(dbInsert, [&](BufBuilder& b) {
163         int reservedFlags = 0;
164         if (flags & InsertOption_ContinueOnError)
165             reservedFlags |= InsertOption_ContinueOnError;
166 
167         b.appendNum(reservedFlags);
168         b.appendStr(ns);
169 
170         for (size_t i = 0; i < count; i++) {
171             objs[i].appendSelfToBufBuilder(b);
172         }
173     });
174 }
175 
makeUpdateMessage(StringData ns,BSONObj query,BSONObj update,int flags)176 Message makeUpdateMessage(StringData ns, BSONObj query, BSONObj update, int flags) {
177     return makeMessage(dbUpdate, [&](BufBuilder& b) {
178         const int reservedFlags = 0;
179         b.appendNum(reservedFlags);
180         b.appendStr(ns);
181         b.appendNum(flags);
182 
183         query.appendSelfToBufBuilder(b);
184         update.appendSelfToBufBuilder(b);
185     });
186 }
187 
makeRemoveMessage(StringData ns,BSONObj query,int flags)188 Message makeRemoveMessage(StringData ns, BSONObj query, int flags) {
189     return makeMessage(dbDelete, [&](BufBuilder& b) {
190         const int reservedFlags = 0;
191         b.appendNum(reservedFlags);
192         b.appendStr(ns);
193         b.appendNum(flags);
194 
195         query.appendSelfToBufBuilder(b);
196     });
197 }
198 
makeKillCursorsMessage(long long cursorId)199 Message makeKillCursorsMessage(long long cursorId) {
200     return makeMessage(dbKillCursors, [&](BufBuilder& b) {
201         b.appendNum((int)0);  // reserved
202         b.appendNum((int)1);  // number
203         b.appendNum(cursorId);
204     });
205 }
206 
makeGetMoreMessage(StringData ns,long long cursorId,int nToReturn,int flags)207 Message makeGetMoreMessage(StringData ns, long long cursorId, int nToReturn, int flags) {
208     return makeMessage(dbGetMore, [&](BufBuilder& b) {
209         b.appendNum(flags);
210         b.appendStr(ns);
211         b.appendNum(nToReturn);
212         b.appendNum(cursorId);
213     });
214 }
215 
OpQueryReplyBuilder()216 OpQueryReplyBuilder::OpQueryReplyBuilder() : _buffer(32768) {
217     _buffer.skip(sizeof(QueryResult::Value));
218 }
219 
toQueryReply(int queryResultFlags,int nReturned,int startingFrom,long long cursorId)220 Message OpQueryReplyBuilder::toQueryReply(int queryResultFlags,
221                                           int nReturned,
222                                           int startingFrom,
223                                           long long cursorId) {
224     QueryResult::View qr = _buffer.buf();
225     qr.setResultFlags(queryResultFlags);
226     qr.msgdata().setLen(_buffer.len());
227     qr.msgdata().setOperation(opReply);
228     qr.setCursorId(cursorId);
229     qr.setStartingFrom(startingFrom);
230     qr.setNReturned(nReturned);
231     return Message(_buffer.release());
232 }
233 
replyToQuery(int queryResultFlags,const void * data,int size,int nReturned,int startingFrom,long long cursorId)234 DbResponse replyToQuery(int queryResultFlags,
235                         const void* data,
236                         int size,
237                         int nReturned,
238                         int startingFrom,
239                         long long cursorId) {
240     OpQueryReplyBuilder reply;
241     reply.bufBuilderForResults().appendBuf(data, size);
242     return DbResponse{reply.toQueryReply(queryResultFlags, nReturned, startingFrom, cursorId)};
243 }
244 }
245