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 <memory>
34 #include <sstream>
35 #include <string>
36 #include <vector>
37 
38 #include "mongo/base/status_with.h"
39 #include "mongo/base/string_data.h"
40 #include "mongo/bson/util/builder.h"
41 #include "mongo/stdx/mutex.h"
42 #include "mongo/util/assert_util.h"
43 #include "mongo/util/net/hostandport.h"
44 
45 namespace mongo {
46 
47 class DBClientBase;
48 class MongoURI;
49 
50 /**
51  * ConnectionString handles parsing different ways to connect to mongo and determining method
52  * samples:
53  *    server
54  *    server:port
55  *    foo/server:port,server:port   SET
56  *
57  * Typical use:
58  *
59  * ConnectionString cs(uassertStatusOK(ConnectionString::parse(url)));
60  * std::string errmsg;
61  * DBClientBase * conn = cs.connect( errmsg );
62  */
63 class ConnectionString {
64 public:
65     enum ConnectionType { INVALID, MASTER, SET, CUSTOM, LOCAL };
66 
67     ConnectionString() = default;
68 
69     /**
70      * Constructs a connection string representing a replica set.
71      */
72     static ConnectionString forReplicaSet(StringData setName, std::vector<HostAndPort> servers);
73 
74     /**
75      * Constructs a local connection string.
76      */
77     static ConnectionString forLocal();
78 
79     /**
80      * Creates a MASTER connection string with the specified server.
81      */
82     explicit ConnectionString(const HostAndPort& server);
83 
84     /**
85      * Creates a connection string from an unparsed list of servers, type, and setName.
86      */
87     ConnectionString(ConnectionType type, const std::string& s, const std::string& setName);
88 
89     /**
90      * Creates a connection string from a pre-parsed list of servers, type, and setName.
91      */
92     ConnectionString(ConnectionType type,
93                      std::vector<HostAndPort> servers,
94                      const std::string& setName);
95 
96     ConnectionString(const std::string& s, ConnectionType connType);
97 
isValid()98     bool isValid() const {
99         return _type != INVALID;
100     }
101 
toString()102     const std::string& toString() const {
103         return _string;
104     }
105 
getSetName()106     const std::string& getSetName() const {
107         return _setName;
108     }
109 
getServers()110     const std::vector<HostAndPort>& getServers() const {
111         return _servers;
112     }
113 
type()114     ConnectionType type() const {
115         return _type;
116     }
117 
118     /**
119      * Returns true if two connection strings match in terms of their type and the exact order of
120      * their hosts.
121      */
122     bool operator==(const ConnectionString& other) const;
123     bool operator!=(const ConnectionString& other) const;
124 
125     std::unique_ptr<DBClientBase> connect(StringData applicationName,
126                                           std::string& errmsg,
127                                           double socketTimeout = 0,
128                                           const MongoURI* uri = nullptr) const;
129 
130     static StatusWith<ConnectionString> parse(const std::string& url);
131 
132     static std::string typeToString(ConnectionType type);
133 
134     //
135     // Allow overriding the default connection behavior
136     // This is needed for some tests, which otherwise would fail because they are unable to contact
137     // the correct servers.
138     //
139 
140     class ConnectionHook {
141     public:
~ConnectionHook()142         virtual ~ConnectionHook() {}
143 
144         // Returns an alternative connection object for a string
145         virtual std::unique_ptr<DBClientBase> connect(const ConnectionString& c,
146                                                       std::string& errmsg,
147                                                       double socketTimeout) = 0;
148     };
149 
setConnectionHook(ConnectionHook * hook)150     static void setConnectionHook(ConnectionHook* hook) {
151         stdx::lock_guard<stdx::mutex> lk(_connectHookMutex);
152         _connectHook = hook;
153     }
154 
getConnectionHook()155     static ConnectionHook* getConnectionHook() {
156         stdx::lock_guard<stdx::mutex> lk(_connectHookMutex);
157         return _connectHook;
158     }
159 
160     // Allows ConnectionStrings to be stored more easily in sets/maps
161     bool operator<(const ConnectionString& other) const {
162         return _string < other._string;
163     }
164 
165 
166     friend std::ostream& operator<<(std::ostream&, const ConnectionString&);
167     friend StringBuilder& operator<<(StringBuilder&, const ConnectionString&);
168 
169 private:
170     /**
171      * Creates a SET connection string with the specified set name and servers.
172      */
173     ConnectionString(StringData setName, std::vector<HostAndPort> servers);
174 
175     /**
176      * Creates a connection string with the specified type. Used for creating LOCAL strings.
177      */
178     explicit ConnectionString(ConnectionType connType);
179 
180     void _fillServers(std::string s);
181     void _finishInit();
182 
183     ConnectionType _type{INVALID};
184     std::vector<HostAndPort> _servers;
185     std::string _string;
186     std::string _setName;
187 
188     static stdx::mutex _connectHookMutex;
189     static ConnectionHook* _connectHook;
190 };
191 
192 inline std::ostream& operator<<(std::ostream& ss, const ConnectionString& cs) {
193     ss << cs._string;
194     return ss;
195 }
196 
197 inline StringBuilder& operator<<(StringBuilder& sb, const ConnectionString& cs) {
198     sb << cs._string;
199     return sb;
200 }
201 
202 }  // namespace mongo
203