1 
2 /**
3  *    Copyright (C) 2018-present MongoDB, Inc.
4  *
5  *    This program is free software: you can redistribute it and/or modify
6  *    it under the terms of the Server Side Public License, version 1,
7  *    as published by MongoDB, Inc.
8  *
9  *    This program is distributed in the hope that it will be useful,
10  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *    Server Side Public License for more details.
13  *
14  *    You should have received a copy of the Server Side Public License
15  *    along with this program. If not, see
16  *    <http://www.mongodb.com/licensing/server-side-public-license>.
17  *
18  *    As a special exception, the copyright holders give permission to link the
19  *    code of portions of this program with the OpenSSL library under certain
20  *    conditions as described in each individual source file and distribute
21  *    linked combinations including the program with the OpenSSL library. You
22  *    must comply with the Server Side Public License in all respects for
23  *    all of the code used other than as permitted herein. If you modify file(s)
24  *    with this exception, you may extend this exception to your version of the
25  *    file(s), but you are not obligated to do so. If you do not wish to do so,
26  *    delete this exception statement from your version. If you delete this
27  *    exception statement from all source files in the program, then also delete
28  *    it in the license file.
29  */
30 
31 #pragma once
32 
33 #include <cstdint>
34 
35 #include "mongo/base/string_data.h"
36 #include "mongo/client/connection_string.h"
37 #include "mongo/client/index_spec.h"
38 #include "mongo/client/mongo_uri.h"
39 #include "mongo/client/query.h"
40 #include "mongo/client/read_preference.h"
41 #include "mongo/db/dbmessage.h"
42 #include "mongo/db/jsobj.h"
43 #include "mongo/db/write_concern_options.h"
44 #include "mongo/platform/atomic_word.h"
45 #include "mongo/rpc/metadata.h"
46 #include "mongo/rpc/protocol.h"
47 #include "mongo/rpc/unique_message.h"
48 #include "mongo/stdx/functional.h"
49 #include "mongo/transport/message_compressor_manager.h"
50 #include "mongo/util/mongoutils/str.h"
51 #include "mongo/util/net/abstract_message_port.h"
52 #include "mongo/util/net/message.h"
53 #include "mongo/util/net/op_msg.h"
54 
55 namespace mongo {
56 
57 namespace executor {
58 struct RemoteCommandResponse;
59 }
60 
61 class DBClientCursor;
62 class DBClientCursorBatchIterator;
63 
64 /**
65  * Represents a full query description, including all options required for the query to be passed on
66  * to other hosts
67  */
68 class QuerySpec {
69     std::string _ns;
70     int _ntoskip;
71     int _ntoreturn;
72     int _options;
73     BSONObj _query;
74     BSONObj _fields;
75     Query _queryObj;
76 
77 public:
QuerySpec(const std::string & ns,const BSONObj & query,const BSONObj & fields,int ntoskip,int ntoreturn,int options)78     QuerySpec(const std::string& ns,
79               const BSONObj& query,
80               const BSONObj& fields,
81               int ntoskip,
82               int ntoreturn,
83               int options)
84         : _ns(ns),
85           _ntoskip(ntoskip),
86           _ntoreturn(ntoreturn),
87           _options(options),
88           _query(query.getOwned()),
89           _fields(fields.getOwned()),
90           _queryObj(_query) {}
91 
QuerySpec()92     QuerySpec() {}
93 
isEmpty()94     bool isEmpty() const {
95         return _ns.size() == 0;
96     }
97 
isExplain()98     bool isExplain() const {
99         return _queryObj.isExplain();
100     }
filter()101     BSONObj filter() const {
102         return _queryObj.getFilter();
103     }
104 
hint()105     BSONObj hint() const {
106         return _queryObj.getHint();
107     }
sort()108     BSONObj sort() const {
109         return _queryObj.getSort();
110     }
query()111     BSONObj query() const {
112         return _query;
113     }
fields()114     BSONObj fields() const {
115         return _fields;
116     }
fieldsData()117     BSONObj* fieldsData() {
118         return &_fields;
119     }
120 
121     // don't love this, but needed downstrem
fieldsPtr()122     const BSONObj* fieldsPtr() const {
123         return &_fields;
124     }
125 
ns()126     std::string ns() const {
127         return _ns;
128     }
ntoskip()129     int ntoskip() const {
130         return _ntoskip;
131     }
ntoreturn()132     int ntoreturn() const {
133         return _ntoreturn;
134     }
options()135     int options() const {
136         return _options;
137     }
138 
setFields(BSONObj & o)139     void setFields(BSONObj& o) {
140         _fields = o.getOwned();
141     }
142 
toString()143     std::string toString() const {
144         return str::stream() << "QSpec "
145                              << BSON("ns" << _ns << "n2skip" << _ntoskip << "n2return" << _ntoreturn
146                                           << "options"
147                                           << _options
148                                           << "query"
149                                           << _query
150                                           << "fields"
151                                           << _fields);
152     }
153 };
154 
155 
156 /** Typically one uses the QUERY(...) macro to construct a Query object.
157     Example: QUERY( "age" << 33 << "school" << "UCLA" )
158 */
159 #define QUERY(x) ::mongo::Query(BSON(x))
160 
161 // Useful utilities for namespaces
162 /** @return the database name portion of an ns std::string */
163 std::string nsGetDB(const std::string& ns);
164 
165 /** @return the collection name portion of an ns std::string */
166 std::string nsGetCollection(const std::string& ns);
167 
168 /**
169  abstract class that implements the core db operations
170  */
171 class DBClientBase {
172     MONGO_DISALLOW_COPYING(DBClientBase);
173 
174 public:
DBClientBase()175     DBClientBase()
176         : _logLevel(logger::LogSeverity::Log()),
177           _connectionId(ConnectionIdSequence.fetchAndAdd(1)),
178           _cachedAvailableOptions((enum QueryOptions)0),
179           _haveCachedAvailableOptions(false) {}
180 
~DBClientBase()181     virtual ~DBClientBase() {}
182 
183     /**
184        @return a single object that matches the query.  if none do, then the object is empty
185        @throws AssertionException
186     */
187     virtual BSONObj findOne(const std::string& ns,
188                             const Query& query,
189                             const BSONObj* fieldsToReturn = 0,
190                             int queryOptions = 0);
191 
192     /** query N objects from the database into an array.  makes sense mostly when you want a small
193      * number of results.  if a huge number, use query() and iterate the cursor.
194     */
195     void findN(std::vector<BSONObj>& out,
196                const std::string& ns,
197                Query query,
198                int nToReturn,
199                int nToSkip = 0,
200                const BSONObj* fieldsToReturn = 0,
201                int queryOptions = 0);
202 
203     /**
204      * @return a pair with a single object that matches the filter within the collection specified
205      * by the UUID and the namespace of that collection on the queried node.
206      *
207      * If the command fails, an assertion error is thrown. Otherwise, if no document matches
208      * the query, an empty BSONObj is returned.
209      * @throws AssertionException
210      */
211     virtual std::pair<BSONObj, NamespaceString> findOneByUUID(const std::string& db,
212                                                               UUID uuid,
213                                                               const BSONObj& filter);
214 
215     virtual std::string getServerAddress() const = 0;
216 
217     /** helper function.  run a simple command where the command expression is simply
218           { command : 1 }
219         @param info -- where to put result object.  may be null if caller doesn't need that info
220         @param command -- command name
221         @return true if the command returned "ok".
222      */
223     bool simpleCommand(const std::string& dbname, BSONObj* info, const std::string& command);
224 
225     rpc::ProtocolSet getClientRPCProtocols() const;
226     rpc::ProtocolSet getServerRPCProtocols() const;
227 
228     void setClientRPCProtocols(rpc::ProtocolSet clientProtocols);
229 
230     /**
231      * actualServer is set to the actual server where they call went if there was a choice (for
232      * example SlaveOk).
233      */
234     virtual bool call(Message& toSend,
235                       Message& response,
236                       bool assertOk = true,
237                       std::string* actualServer = nullptr) = 0;
238 
239     virtual void say(Message& toSend,
240                      bool isRetry = false,
241                      std::string* actualServer = nullptr) = 0;
242 
243     /* used by QueryOption_Exhaust.  To use that your subclass must implement this. */
recv(Message & m,int lastRequestId)244     virtual bool recv(Message& m, int lastRequestId) {
245         verify(false);
246         return false;
247     }
248 
249     // In general, for lazy queries, we'll need to say, recv, then checkResponse
250     virtual void checkResponse(const std::vector<BSONObj>& batch,
251                                bool networkError,
252                                bool* retry = nullptr,
253                                std::string* targetHost = nullptr) {
254         if (retry)
255             *retry = false;
256         if (targetHost)
257             *targetHost = "";
258     }
259 
260     virtual bool lazySupported() const = 0;
261 
262     /**
263      * Sets a RequestMetadataWriter on this connection.
264      *
265      * TODO: support multiple metadata writers.
266      */
267     virtual void setRequestMetadataWriter(rpc::RequestMetadataWriter writer);
268 
269     /**
270      * Gets the RequestMetadataWriter that is set on this connection. This may
271      * be an uninitialized stdx::function, so it should be checked for validity
272      * with operator bool() first.
273      */
274     const rpc::RequestMetadataWriter& getRequestMetadataWriter();
275 
276     /**
277      * Sets a ReplyMetadataReader on this connection.
278      *
279      * TODO: support multiple metadata readers.
280      */
281     virtual void setReplyMetadataReader(rpc::ReplyMetadataReader reader);
282 
283     /**
284      * Gets the ReplyMetadataReader that is set on this connection. This may
285      * be an uninitialized stdx::function, so it should be checked for validity
286      * with operator bool() first.
287      */
288     const rpc::ReplyMetadataReader& getReplyMetadataReader();
289 
290     /**
291      * Runs the specified command request.
292      */
293     virtual std::pair<rpc::UniqueReply, DBClientBase*> runCommandWithTarget(OpMsgRequest request);
294 
295     /**
296      * This shared_ptr overload is used to possibly return a shared_ptr to the replica set member
297      * that the command was dispatched to.  It's needed if the caller needs a lifetime for that
298      * connection that extends beyond the lifetime, or subsequent calls, against the top level
299      * client.
300      *
301      * It has this slightly insane api because:
302      * + we don't want to thread enable_shared_from_this pervasively through the dbclient tree
303      * + we use this from places we don't want to know about dbclient_rs (and so don't know if we'll
304      *   get our own ptr back).
305      * + the only caller who needs this is the shell (because other callers have more control over
306      *   lifetime).
307      */
308     virtual std::pair<rpc::UniqueReply, std::shared_ptr<DBClientBase>> runCommandWithTarget(
309         OpMsgRequest request, std::shared_ptr<DBClientBase> me);
310 
311     /**
312      * Runs the specified command request. This thin wrapper just unwraps the reply and ignores the
313      * target connection from the above runCommandWithTarget().
314      */
runCommand(OpMsgRequest request)315     rpc::UniqueReply runCommand(OpMsgRequest request) {
316         return runCommandWithTarget(std::move(request)).first;
317     }
318 
319     /**
320      * Runs the specified command request in fire-and-forget mode and returns the connection that
321      * the command was actually sent on. If the connection doesn't support OP_MSG, the request will
322      * be run as a normal two-way command and the reply will be ignored after parsing.
323      */
324     virtual DBClientBase* runFireAndForgetCommand(OpMsgRequest request);
325 
326     /** Run a database command.  Database commands are represented as BSON objects.  Common database
327         commands have prebuilt helper functions -- see below.  If a helper is not available you can
328         directly call runCommand.
329 
330         @param dbname database name.  Use "admin" for global administrative commands.
331         @param cmd  the command object to execute.  For example, { ismaster : 1 }
332         @param info the result object the database returns. Typically has { ok : ..., errmsg : ... }
333                     fields set.
334         @param options see enum QueryOptions - normally not needed to run a command
335         @param auth if set, the BSONObj representation will be appended to the command object sent
336 
337         @return true if the command returned "ok".
338     */
339     bool runCommand(const std::string& dbname, BSONObj cmd, BSONObj& info, int options = 0);
340 
341     /*
342      * This wraps up the runCommand function avove, but returns the DBClient that actually ran
343      * the command. When called against a replica set, this will return the specific
344      * replica set member the command ran against.
345      *
346      * This is used in the shell so that cursors can send getMore through the correct connection.
347      */
348     std::tuple<bool, DBClientBase*> runCommandWithTarget(const std::string& dbname,
349                                                          BSONObj cmd,
350                                                          BSONObj& info,
351                                                          int options = 0);
352 
353     /**
354      * See the opMsg overload comment for why this function takes a shared_ptr ostensibly to this.
355      */
356     std::tuple<bool, std::shared_ptr<DBClientBase>> runCommandWithTarget(
357         const std::string& dbname,
358         BSONObj cmd,
359         BSONObj& info,
360         std::shared_ptr<DBClientBase> me,
361         int options = 0);
362 
363     /**
364     * Authenticates to another cluster member using appropriate authentication data.
365     * Uses getInternalUserAuthParams() to retrive authentication parameters.
366     * @return true if the authentication was succesful
367     */
368     bool authenticateInternalUser();
369 
370     /**
371      * Authenticate a user.
372      *
373      * The "params" BSONObj should be initialized with some of the fields below.  Which fields
374      * are required depends on the mechanism, which is mandatory.
375      *
376      *     "mechanism": The std::string name of the sasl mechanism to use.  Mandatory.
377      *     "user": The std::string name of the user to authenticate.  Mandatory.
378      *     "db": The database target of the auth command, which identifies the location
379      *         of the credential information for the user.  May be "$external" if
380      *         credential information is stored outside of the mongo cluster.  Mandatory.
381      *     "pwd": The password data.
382      *     "digestPassword": Boolean, set to true if the "pwd" is undigested (default).
383      *     "serviceName": The GSSAPI service name to use.  Defaults to "mongodb".
384      *     "serviceHostname": The GSSAPI hostname to use.  Defaults to the name of the remote
385      *          host.
386      *
387      * Other fields in "params" are silently ignored.
388      *
389      * Returns normally on success, and throws on error.  Throws a DBException with getCode() ==
390      * ErrorCodes::AuthenticationFailed if authentication is rejected.  All other exceptions are
391      * tantamount to authentication failure, but may also indicate more serious problems.
392      */
393     void auth(const BSONObj& params);
394 
395     /** Authorize access to a particular database.
396         Authentication is separate for each database on the server -- you may authenticate for any
397         number of databases on a single connection.
398         The "admin" database is special and once authenticated provides access to all databases on
399         the server.
400         @param      digestPassword  if password is plain text, set this to true.  otherwise assumed
401                                     to be pre-digested
402         @param[out] authLevel       level of authentication for the given user
403         @return true if successful
404     */
405     bool auth(const std::string& dbname,
406               const std::string& username,
407               const std::string& pwd,
408               std::string& errmsg,
409               bool digestPassword = true);
410 
411     /**
412      * Logs out the connection for the given database.
413      *
414      * @param dbname the database to logout from.
415      * @param info the result object for the logout command (provided for backwards
416      *     compatibility with mongo shell)
417      */
418     virtual void logout(const std::string& dbname, BSONObj& info);
419 
420     /** count number of objects in collection ns that match the query criteria specified
421         throws UserAssertion if database returns an error
422     */
423     virtual unsigned long long count(const std::string& ns,
424                                      const BSONObj& query = BSONObj(),
425                                      int options = 0,
426                                      int limit = 0,
427                                      int skip = 0);
428 
429     static std::string createPasswordDigest(const std::string& username,
430                                             const std::string& clearTextPassword);
431 
432     /** returns true in isMaster parm if this db is the current master
433        of a replica pair.
434 
435        pass in info for more details e.g.:
436          { "ismaster" : 1.0 , "msg" : "not paired" , "ok" : 1.0  }
437 
438        returns true if command invoked successfully.
439     */
440     virtual bool isMaster(bool& isMaster, BSONObj* info = 0);
441 
442     /**
443        Create a new collection in the database.  Normally, collection creation is automatic.  You
444        would use this function if you wish to specify special options on creation.
445 
446        If the collection already exists, no action occurs.
447 
448        @param ns     fully qualified collection name
449        @param size   desired initial extent size for the collection.
450                      Must be <= 1000000000 for normal collections.
451                      For fixed size (capped) collections, this size is the total/max size of the
452                      collection.
453        @param capped if true, this is a fixed size collection (where old data rolls out).
454        @param max    maximum number of objects if capped (optional).
455 
456        returns true if successful.
457     */
458     bool createCollection(const std::string& ns,
459                           long long size = 0,
460                           bool capped = false,
461                           int max = 0,
462                           BSONObj* info = 0);
463 
464     /** Get error result from the last write operation (insert/update/delete) on this connection.
465         db doesn't change the command's behavior - it is just for auth checks.
466         @return error message text, or empty std::string if no error.
467     */
468     std::string getLastError(
469         const std::string& db, bool fsync = false, bool j = false, int w = 0, int wtimeout = 0);
470     /**
471      * Same as the form of getLastError that takes a dbname, but just uses the admin DB.
472      */
473     std::string getLastError(bool fsync = false, bool j = false, int w = 0, int wtimeout = 0);
474 
475     /** Get error result from the last write operation (insert/update/delete) on this connection.
476         db doesn't change the command's behavior - it is just for auth checks.
477         @return full error object.
478 
479         If "w" is -1, wait for propagation to majority of nodes.
480         If "wtimeout" is 0, the operation will block indefinitely if needed.
481     */
482     virtual BSONObj getLastErrorDetailed(
483         const std::string& db, bool fsync = false, bool j = false, int w = 0, int wtimeout = 0);
484     /**
485      * Same as the form of getLastErrorDetailed that takes a dbname, but just uses the admin DB.
486      */
487     virtual BSONObj getLastErrorDetailed(bool fsync = false,
488                                          bool j = false,
489                                          int w = 0,
490                                          int wtimeout = 0);
491 
492     /** Can be called with the returned value from getLastErrorDetailed to extract an error string.
493         If all you need is the string, just call getLastError() instead.
494     */
495     static std::string getLastErrorString(const BSONObj& res);
496 
497     /** Return the last error which has occurred, even if not the very last operation.
498 
499        @return { err : <error message>, nPrev : <how_many_ops_back_occurred>, ok : 1 }
500 
501        result.err will be null if no error has occurred.
502     */
503     BSONObj getPrevError();
504 
505     /** Delete the specified collection.
506      *  @param info An optional output parameter that receives the result object the database
507      *  returns from the drop command.  May be null if the caller doesn't need that info.
508      */
509     virtual bool dropCollection(const std::string& ns,
510                                 const WriteConcernOptions& writeConcern = WriteConcernOptions(),
511                                 BSONObj* info = nullptr) {
512         std::string db = nsGetDB(ns);
513         std::string coll = nsGetCollection(ns);
514         uassert(10011, "no collection name", coll.size());
515 
516         BSONObj temp;
517         if (info == nullptr) {
518             info = &temp;
519         }
520 
521         bool res = runCommand(
522             db.c_str(), BSON("drop" << coll << "writeConcern" << writeConcern.toBSON()), *info);
523         return res;
524     }
525 
526     /** Copy database from one server or name to another server or name.
527 
528        Generally, you should dropDatabase() first as otherwise the copied information will MERGE
529        into whatever data is already present in this database.
530 
531        For security reasons this function only works when you are authorized to access the "admin"
532        db.  However, if you have access to said db, you can copy any database from one place to
533        another.
534        TODO: this needs enhancement to be more flexible in terms of security.
535 
536        This method provides a way to "rename" a database by copying it to a new db name and
537        location.  The copy is "repaired" and compacted.
538 
539        fromdb   database name from which to copy.
540        todb     database name to copy to.
541        fromhost hostname of the database (and optionally, ":port") from which to
542                 copy the data.  copies from self if "".
543 
544        returns true if successful
545     */
546     bool copyDatabase(const std::string& fromdb,
547                       const std::string& todb,
548                       const std::string& fromhost = "",
549                       BSONObj* info = 0);
550 
551     /** Run javascript code on the database server.
552        dbname    database SavedContext in which the code runs. The javascript variable 'db' will be
553                  assigned to this database when the function is invoked.
554        jscode    source code for a javascript function.
555        info      the command object which contains any information on the invocation result
556                  including the return value and other information.  If an error occurs running the
557                  jscode, error information will be in info.  (try "log() << info.toString()")
558        retValue  return value from the jscode function.
559        args      args to pass to the jscode function.  when invoked, the 'args' variable will be
560                  defined for use by the jscode.
561 
562        returns true if runs ok.
563 
564        See testDbEval() in dbclient.cpp for an example of usage.
565     */
566     bool eval(const std::string& dbname,
567               const std::string& jscode,
568               BSONObj& info,
569               BSONElement& retValue,
570               BSONObj* args = 0);
571 
572     /** validate a collection, checking for errors and reporting back statistics.
573         this operation is slow and blocking.
574      */
575     bool validate(const std::string& ns, bool scandata = true) {
576         BSONObj cmd = BSON("validate" << nsGetCollection(ns) << "scandata" << scandata);
577         BSONObj info;
578         return runCommand(nsGetDB(ns).c_str(), cmd, info);
579     }
580 
581     /* The following helpers are simply more convenient forms of eval() for certain common cases */
582 
583     /* invocation with no return value of interest -- with or without one simple parameter */
584     bool eval(const std::string& dbname, const std::string& jscode);
585     template <class T>
eval(const std::string & dbname,const std::string & jscode,T parm1)586     bool eval(const std::string& dbname, const std::string& jscode, T parm1) {
587         BSONObj info;
588         BSONElement retValue;
589         BSONObjBuilder b;
590         b.append("0", parm1);
591         BSONObj args = b.done();
592         return eval(dbname, jscode, info, retValue, &args);
593     }
594 
595     /** eval invocation with one parm to server and one numeric field (either int or double)
596      * returned */
597     template <class T, class NumType>
eval(const std::string & dbname,const std::string & jscode,T parm1,NumType & ret)598     bool eval(const std::string& dbname, const std::string& jscode, T parm1, NumType& ret) {
599         BSONObj info;
600         BSONElement retValue;
601         BSONObjBuilder b;
602         b.append("0", parm1);
603         BSONObj args = b.done();
604         if (!eval(dbname, jscode, info, retValue, &args))
605             return false;
606         ret = (NumType)retValue.number();
607         return true;
608     }
609 
610     /**
611      * { name : "<short collection name>",
612      *   options : { }
613      * }
614      */
615     std::list<BSONObj> getCollectionInfos(const std::string& db, const BSONObj& filter = BSONObj());
616 
617     bool exists(const std::string& ns);
618 
619     /** Create an index on the collection 'ns' as described by the given keys. If you wish
620      *  to specify options, see the more flexible overload of 'createIndex' which takes an
621      *  IndexSpec object. Failure to construct the index is reported by throwing a
622      *  AssertionException.
623      *
624      *  @param ns Namespace on which to create the index
625      *  @param keys Document describing keys and index types. You must provide at least one
626      *  field and its direction.
627      */
createIndex(StringData ns,const BSONObj & keys)628     void createIndex(StringData ns, const BSONObj& keys) {
629         return createIndex(ns, IndexSpec().addKeys(keys));
630     }
631 
632     /** Create an index on the collection 'ns' as described by the given
633      *  descriptor. Failure to construct the index is reported by throwing a
634      *  AssertionException.
635      *
636      *  @param ns Namespace on which to create the index
637      *  @param descriptor Configuration object describing the index to create. The
638      *  descriptor must describe at least one key and index type.
639      */
640     virtual void createIndex(StringData ns, const IndexSpec& descriptor);
641 
642     virtual std::list<BSONObj> getIndexSpecs(const std::string& ns, int options = 0);
643 
644     virtual void dropIndex(const std::string& ns, BSONObj keys);
645     virtual void dropIndex(const std::string& ns, const std::string& indexName);
646 
647     /**
648        drops all indexes for the collection
649      */
650     virtual void dropIndexes(const std::string& ns);
651 
652     virtual void reIndex(const std::string& ns);
653 
654     static std::string genIndexName(const BSONObj& keys);
655 
656     /** Erase / drop an entire database */
657     virtual bool dropDatabase(const std::string& dbname,
658                               const WriteConcernOptions& writeConcern = WriteConcernOptions(),
659                               BSONObj* info = nullptr) {
660         BSONObj o;
661         if (info == nullptr)
662             info = &o;
663         return runCommand(
664             dbname, BSON("dropDatabase" << 1 << "writeConcern" << writeConcern.toBSON()), *info);
665     }
666 
667     virtual std::string toString() const = 0;
668 
669     /**
670      * Run a pseudo-command such as sys.inprog/currentOp, sys.killop/killOp
671      * or sys.unlock/fsyncUnlock
672      *
673      * The real command will be tried first, and if the remote server does not
674      * implement the command, it will fall back to the pseudoCommand.
675      *
676      * The cmdArgs parameter should NOT include {<commandName>: 1}.
677      *
678      * TODO: remove after MongoDB 3.2 is released and replace all callers with
679      * a call to plain runCommand
680      */
681     virtual bool runPseudoCommand(StringData db,
682                                   StringData realCommandName,
683                                   StringData pseudoCommandCol,
684                                   const BSONObj& cmdArgs,
685                                   BSONObj& info,
686                                   int options = 0);
687 
688     /**
689      * Reconnect if needed and allowed.
690      */
checkConnection()691     virtual void checkConnection() {}
692 
693     static const uint64_t INVALID_SOCK_CREATION_TIME;
694 
getConnectionId()695     long long getConnectionId() const {
696         return _connectionId;
697     }
698 
699     virtual int getMinWireVersion() = 0;
700     virtual int getMaxWireVersion() = 0;
701 
702     /** send a query to the database.
703      @param ns namespace to query, format is <dbname>.<collectname>[.<collectname>]*
704      @param query query to perform on the collection.  this is a BSONObj (binary JSON)
705      You may format as
706        { query: { ... }, orderby: { ... } }
707      to specify a sort order.
708      @param nToReturn n to return (i.e., limit).  0 = unlimited
709      @param nToSkip start with the nth item
710      @param fieldsToReturn optional template of which fields to select. if unspecified,
711             returns all fields
712      @param queryOptions see options enum at top of this file
713 
714      @return    cursor.   0 if error (connection failure)
715      @throws AssertionException
716     */
717     virtual std::unique_ptr<DBClientCursor> query(const std::string& ns,
718                                                   Query query,
719                                                   int nToReturn = 0,
720                                                   int nToSkip = 0,
721                                                   const BSONObj* fieldsToReturn = 0,
722                                                   int queryOptions = 0,
723                                                   int batchSize = 0);
724 
725 
726     /** Uses QueryOption_Exhaust, when available.
727 
728         Exhaust mode sends back all data queries as fast as possible, with no back-and-forth for
729         OP_GETMORE.  If you are certain you will exhaust the query, it could be useful.
730 
731         Use the DBClientCursorBatchIterator version, below, if you want to do items in large
732         blocks, perhaps to avoid granular locking and such.
733      */
734     virtual unsigned long long query(stdx::function<void(const BSONObj&)> f,
735                                      const std::string& ns,
736                                      Query query,
737                                      const BSONObj* fieldsToReturn = 0,
738                                      int queryOptions = 0);
739 
740     virtual unsigned long long query(stdx::function<void(DBClientCursorBatchIterator&)> f,
741                                      const std::string& ns,
742                                      Query query,
743                                      const BSONObj* fieldsToReturn = 0,
744                                      int queryOptions = 0);
745 
746 
747     /** don't use this - called automatically by DBClientCursor for you
748         @param cursorId id of cursor to retrieve
749         @return an handle to a previously allocated cursor
750         @throws AssertionException
751      */
752     virtual std::unique_ptr<DBClientCursor> getMore(const std::string& ns,
753                                                     long long cursorId,
754                                                     int nToReturn = 0,
755                                                     int options = 0);
756 
757     /**
758        insert an object into the database
759      */
760     virtual void insert(const std::string& ns, BSONObj obj, int flags = 0);
761 
762     /**
763        insert a vector of objects into the database
764      */
765     virtual void insert(const std::string& ns, const std::vector<BSONObj>& v, int flags = 0);
766 
767     /**
768        updates objects matching query
769      */
770     virtual void update(
771         const std::string& ns, Query query, BSONObj obj, bool upsert = false, bool multi = false);
772 
773     virtual void update(const std::string& ns, Query query, BSONObj obj, int flags);
774 
775     virtual void remove(const std::string& ns, Query query, int flags = 0);
776 
777     virtual bool isFailed() const = 0;
778 
779     /**
780      * if not checked recently, checks whether the underlying socket/sockets are still valid
781      */
782     virtual bool isStillConnected() = 0;
783 
784     virtual void killCursor(const NamespaceString& ns, long long cursorID);
785 
786     virtual ConnectionString::ConnectionType type() const = 0;
787 
788     virtual double getSoTimeout() const = 0;
789 
getSockCreationMicroSec()790     virtual uint64_t getSockCreationMicroSec() const {
791         return INVALID_SOCK_CREATION_TIME;
792     }
793 
reset()794     virtual void reset() {}
795 
796     virtual bool isReplicaSetMember() const = 0;
797 
798     virtual bool isMongos() const = 0;
799 
800     /**
801      * Parses command replies and runs them through the metadata reader.
802      * This is virtual and non-const to allow subclasses to act on failures.
803      */
804     virtual rpc::UniqueReply parseCommandReplyMessage(const std::string& host,
805                                                       const Message& replyMsg);
806 
807 protected:
808     /** if the result of a command is ok*/
809     bool isOk(const BSONObj&);
810 
811     /** if the element contains a not master error */
812     bool isNotMasterErrorString(const BSONElement& e);
813 
814     BSONObj _countCmd(
815         const std::string& ns, const BSONObj& query, int options, int limit, int skip);
816 
817     /**
818      * Look up the options available on this client.  Caches the answer from
819      * _lookupAvailableOptions(), below.
820      */
821     QueryOptions availableOptions();
822 
823     virtual QueryOptions _lookupAvailableOptions();
824 
825     virtual void _auth(const BSONObj& params);
826 
827     // should be set by subclasses during connection.
828     void _setServerRPCProtocols(rpc::ProtocolSet serverProtocols);
829 
830     /** controls how chatty the client is about network errors & such.  See log.h */
831     const logger::LogSeverity _logLevel;
832 
833     static AtomicInt64 ConnectionIdSequence;
834     long long _connectionId;  // unique connection id for this connection
835 
836 private:
837     /**
838      * The rpc protocols this client supports.
839      *
840      */
841     rpc::ProtocolSet _clientRPCProtocols{rpc::supports::kAll};
842 
843     /**
844      * The rpc protocol the remote server(s) support. We support 'opQueryOnly' by default unless
845      * we detect support for OP_COMMAND at connection time.
846      */
847     rpc::ProtocolSet _serverRPCProtocols{rpc::supports::kOpQueryOnly};
848 
849     rpc::RequestMetadataWriter _metadataWriter;
850     rpc::ReplyMetadataReader _metadataReader;
851 
852     enum QueryOptions _cachedAvailableOptions;
853     bool _haveCachedAvailableOptions;
854 };  // DBClientBase
855 
856 /**
857     A basic connection to the database.
858     This is the main entry point for talking to a simple Mongo setup
859 */
860 class DBClientConnection : public DBClientBase {
861 public:
862     using DBClientBase::query;
863 
864     /**
865      * A hook used to validate the reply of an 'isMaster' command during connection. If the hook
866      * returns a non-OK Status, the DBClientConnection object will disconnect from the remote
867      * server. This function must not throw - it can only indicate failure by returning a non-OK
868      * status.
869      */
870     using HandshakeValidationHook =
871         stdx::function<Status(const executor::RemoteCommandResponse& isMasterReply)>;
872 
873     /**
874        @param _autoReconnect if true, automatically reconnect on a connection failure
875        @param timeout tcp timeout in seconds - this is for read/write, not connect.
876        Connect timeout is fixed, but short, at 5 seconds.
877      */
878     DBClientConnection(bool _autoReconnect = false,
879                        double so_timeout = 0,
880                        MongoURI uri = {},
881                        const HandshakeValidationHook& hook = HandshakeValidationHook());
882 
~DBClientConnection()883     virtual ~DBClientConnection() {
884         _numConnections.fetchAndAdd(-1);
885     }
886 
887     /**
888      * Connect to a Mongo database server.
889      *
890      * If autoReconnect is true, you can try to use the DBClientConnection even when
891      * false was returned -- it will try to connect again.
892      *
893      * @param server server to connect to.
894      * @param errmsg any relevant error message will appended to the string
895      * @return false if fails to connect.
896      */
897     virtual bool connect(const HostAndPort& server,
898                          StringData applicationName,
899                          std::string& errmsg);
900 
901     /**
902      * Semantically equivalent to the previous connect method, but returns a Status
903      * instead of taking an errmsg out parameter. Also allows optional validation of the reply to
904      * the 'isMaster' command executed during connection.
905      *
906      * @param server The server to connect to.
907      * @param a hook to validate the 'isMaster' reply received during connection. If the hook
908      * fails, the connection will be terminated and a non-OK status will be returned.
909      */
910     Status connect(const HostAndPort& server, StringData applicationName);
911 
912     /**
913      * This version of connect does not run 'isMaster' after creating a TCP connection to the
914      * remote host. This method should be used only when calling 'isMaster' would create a deadlock,
915      * such as in 'isSelf'.
916      *
917      * @param server The server to connect to.
918      */
919     Status connectSocketOnly(const HostAndPort& server);
920 
921     /** Connect to a Mongo database server.  Exception throwing version.
922         Throws a AssertionException if cannot connect.
923 
924        If autoReconnect is true, you can try to use the DBClientConnection even when
925        false was returned -- it will try to connect again.
926 
927        @param serverHostname host to connect to.  can include port number ( 127.0.0.1 ,
928                                127.0.0.1:5555 )
929     */
930 
931     /**
932      * Logs out the connection for the given database.
933      *
934      * @param dbname the database to logout from.
935      * @param info the result object for the logout command (provided for backwards
936      *     compatibility with mongo shell)
937      */
938     virtual void logout(const std::string& dbname, BSONObj& info);
939 
940     virtual std::unique_ptr<DBClientCursor> query(const std::string& ns,
941                                                   Query query = Query(),
942                                                   int nToReturn = 0,
943                                                   int nToSkip = 0,
944                                                   const BSONObj* fieldsToReturn = 0,
945                                                   int queryOptions = 0,
946                                                   int batchSize = 0) {
947         checkConnection();
948         return DBClientBase::query(
949             ns, query, nToReturn, nToSkip, fieldsToReturn, queryOptions, batchSize);
950     }
951 
952     virtual unsigned long long query(stdx::function<void(DBClientCursorBatchIterator&)> f,
953                                      const std::string& ns,
954                                      Query query,
955                                      const BSONObj* fieldsToReturn,
956                                      int queryOptions);
957 
958     using DBClientBase::runCommandWithTarget;
959     std::pair<rpc::UniqueReply, DBClientBase*> runCommandWithTarget(OpMsgRequest request) override;
960     std::pair<rpc::UniqueReply, std::shared_ptr<DBClientBase>> runCommandWithTarget(
961         OpMsgRequest request, std::shared_ptr<DBClientBase> me) override;
962 
963     rpc::UniqueReply parseCommandReplyMessage(const std::string& host,
964                                               const Message& replyMsg) override;
965 
966     /**
967        @return true if this connection is currently in a failed state.  When autoreconnect is on,
968                a connection will transition back to an ok state after reconnecting.
969      */
isFailed()970     bool isFailed() const {
971         return _failed;
972     }
973 
isStillConnected()974     bool isStillConnected() {
975         return _port ? _port->isStillConnected() : true;
976     }
977 
setWireVersions(int minWireVersion,int maxWireVersion)978     void setWireVersions(int minWireVersion, int maxWireVersion) {
979         _minWireVersion = minWireVersion;
980         _maxWireVersion = maxWireVersion;
981     }
982 
getMinWireVersion()983     int getMinWireVersion() final {
984         return _minWireVersion;
985     }
986 
getMaxWireVersion()987     int getMaxWireVersion() final {
988         return _maxWireVersion;
989     }
990 
port()991     AbstractMessagingPort& port() {
992         verify(_port);
993         return *_port;
994     }
995 
toString()996     std::string toString() const {
997         std::stringstream ss;
998         ss << _serverAddress;
999         if (!_resolvedAddress.empty())
1000             ss << " (" << _resolvedAddress << ")";
1001         if (_failed)
1002             ss << " failed";
1003         return ss.str();
1004     }
1005 
getServerAddress()1006     std::string getServerAddress() const {
1007         return _serverAddress.toString();
1008     }
getServerHostAndPort()1009     const HostAndPort& getServerHostAndPort() const {
1010         return _serverAddress;
1011     }
1012 
1013     virtual void say(Message& toSend, bool isRetry = false, std::string* actualServer = 0);
1014     virtual bool recv(Message& m, int lastRequestId);
1015     virtual void checkResponse(const std::vector<BSONObj>& batch,
1016                                bool networkError,
1017                                bool* retry = NULL,
1018                                std::string* host = NULL);
1019     virtual bool call(Message& toSend, Message& response, bool assertOk, std::string* actualServer);
type()1020     virtual ConnectionString::ConnectionType type() const {
1021         return ConnectionString::MASTER;
1022     }
1023     void setSoTimeout(double timeout);
getSoTimeout()1024     double getSoTimeout() const {
1025         return _so_timeout;
1026     }
1027 
lazySupported()1028     virtual bool lazySupported() const {
1029         return true;
1030     }
1031 
getNumConnections()1032     static int getNumConnections() {
1033         return _numConnections.load();
1034     }
1035 
1036     /**
1037      * Set the name of the replica set that this connection is associated to.
1038      * Note: There is no validation on replSetName.
1039      */
1040     void setParentReplSetName(const std::string& replSetName);
1041 
1042     uint64_t getSockCreationMicroSec() const;
1043 
getCompressorManager()1044     MessageCompressorManager& getCompressorManager() {
1045         return _compressorManager;
1046     }
1047 
1048     // throws SocketException if in failed state and not reconnecting or if waiting to reconnect
checkConnection()1049     void checkConnection() override {
1050         if (_failed)
1051             _checkConnection();
1052     }
1053 
isReplicaSetMember()1054     bool isReplicaSetMember() const override {
1055         return _isReplicaSetMember;
1056     }
1057 
isMongos()1058     bool isMongos() const override {
1059         return _isMongos;
1060     }
1061 
1062 protected:
1063     int _minWireVersion{0};
1064     int _maxWireVersion{0};
1065     bool _isReplicaSetMember = false;
1066     bool _isMongos = false;
1067 
1068     virtual void _auth(const BSONObj& params);
1069 
1070     std::unique_ptr<AbstractMessagingPort> _port;
1071 
1072     bool _failed;
1073     const bool autoReconnect;
1074     Backoff autoReconnectBackoff;
1075 
1076     HostAndPort _serverAddress;
1077     std::string _resolvedAddress;
1078     std::string _applicationName;
1079 
1080     void _checkConnection();
1081 
1082     std::map<std::string, BSONObj> authCache;
1083     double _so_timeout;
1084 
1085     static AtomicInt32 _numConnections;
1086 
1087 private:
1088     /**
1089      * Inspects the contents of 'replyBody' and informs the replica set monitor that the host 'this'
1090      * is connected with is no longer the primary if a "not master" error message or error code was
1091      * returned.
1092      */
1093     void handleNotMasterResponse(const BSONObj& replyBody, StringData errorMsgFieldName);
1094 
1095     // Contains the string for the replica set name of the host this is connected to.
1096     // Should be empty if this connection is not pointing to a replica set member.
1097     std::string _parentReplSetName;
1098 
1099     // Hook ran on every call to connect()
1100     HandshakeValidationHook _hook;
1101 
1102     MessageCompressorManager _compressorManager;
1103 
1104     MongoURI _uri;
1105 };
1106 
1107 BSONElement getErrField(const BSONObj& result);
1108 bool hasErrField(const BSONObj& result);
1109 
1110 inline std::ostream& operator<<(std::ostream& s, const Query& q) {
1111     return s << q.toString();
1112 }
1113 
1114 }  // namespace mongo
1115 
1116 #include "mongo/client/dbclientcursor.h"
1117