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