1//
2// Connection.cpp
3//
4// Library: MongoDB
5// Package: MongoDB
6// Module: Connection
7//
8// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/Net/SocketStream.h"
16#include "Poco/MongoDB/Connection.h"
17#include "Poco/MongoDB/Database.h"
18#include "Poco/URI.h"
19#include "Poco/Format.h"
20#include "Poco/NumberParser.h"
21#include "Poco/Exception.h"
22
23
24namespace Poco {
25namespace MongoDB {
26
27
28Connection::SocketFactory::SocketFactory()
29{
30}
31
32
33Connection::SocketFactory::~SocketFactory()
34{
35}
36
37
38Poco::Net::StreamSocket Connection::SocketFactory::createSocket(const std::string& host, int port, Poco::Timespan connectTimeout, bool secure)
39{
40 if (!secure)
41 {
42 Poco::Net::SocketAddress addr(host, static_cast<UInt16>(port));
43 Poco::Net::StreamSocket socket;
44 if (connectTimeout > 0)
45 socket.connect(addr, connectTimeout);
46 else
47 socket.connect(addr);
48 return socket;
49 }
50 else throw Poco::NotImplementedException("Default SocketFactory implementation does not support SecureStreamSocket");
51}
52
53
54Connection::Connection():
55 _address(),
56 _socket()
57{
58}
59
60
61Connection::Connection(const std::string& hostAndPort):
62 _address(hostAndPort),
63 _socket()
64{
65 connect();
66}
67
68
69Connection::Connection(const std::string& uri, SocketFactory& socketFactory):
70 _address(),
71 _socket()
72{
73 connect(uri, socketFactory);
74}
75
76
77Connection::Connection(const std::string& host, int port):
78 _address(host, static_cast<UInt16>(port)),
79 _socket()
80{
81 connect();
82}
83
84
85Connection::Connection(const Poco::Net::SocketAddress& addrs):
86 _address(addrs),
87 _socket()
88{
89 connect();
90}
91
92
93Connection::Connection(const Poco::Net::StreamSocket& socket):
94 _address(socket.peerAddress()),
95 _socket(socket)
96{
97}
98
99
100Connection::~Connection()
101{
102 try
103 {
104 disconnect();
105 }
106 catch (...)
107 {
108 }
109}
110
111
112void Connection::connect()
113{
114 _socket.connect(_address);
115}
116
117
118void Connection::connect(const std::string& hostAndPort)
119{
120 _address = Poco::Net::SocketAddress(hostAndPort);
121 connect();
122}
123
124
125void Connection::connect(const std::string& host, int port)
126{
127 _address = Poco::Net::SocketAddress(host, static_cast<UInt16>(port));
128 connect();
129}
130
131
132void Connection::connect(const Poco::Net::SocketAddress& addrs)
133{
134 _address = addrs;
135 connect();
136}
137
138
139void Connection::connect(const Poco::Net::StreamSocket& socket)
140{
141 _address = socket.peerAddress();
142 _socket = socket;
143}
144
145
146void Connection::connect(const std::string& uri, SocketFactory& socketFactory)
147{
148 Poco::URI theURI(uri);
149 if (theURI.getScheme() != "mongodb") throw Poco::UnknownURISchemeException(uri);
150
151 std::string userInfo = theURI.getUserInfo();
152 std::string host = theURI.getHost();
153 Poco::UInt16 port = theURI.getPort();
154 if (port == 0) port = 27017;
155
156 std::string databaseName = theURI.getPath();
157 if (!databaseName.empty() && databaseName[0] == '/') databaseName.erase(0, 1);
158 if (databaseName.empty()) databaseName = "admin";
159
160 bool ssl = false;
161 Poco::Timespan connectTimeout;
162 Poco::Timespan socketTimeout;
163 std::string authMechanism = Database::AUTH_SCRAM_SHA1;
164
165 Poco::URI::QueryParameters params = theURI.getQueryParameters();
166 for (Poco::URI::QueryParameters::const_iterator it = params.begin(); it != params.end(); ++it)
167 {
168 if (it->first == "ssl")
169 {
170 ssl = (it->second == "true");
171 }
172 else if (it->first == "connectTimeoutMS")
173 {
174 connectTimeout = static_cast<Poco::Timespan::TimeDiff>(1000)*Poco::NumberParser::parse(it->second);
175 }
176 else if (it->first == "socketTimeoutMS")
177 {
178 socketTimeout = static_cast<Poco::Timespan::TimeDiff>(1000)*Poco::NumberParser::parse(it->second);
179 }
180 else if (it->first == "authMechanism")
181 {
182 authMechanism = it->second;
183 }
184 }
185
186 connect(socketFactory.createSocket(host, port, connectTimeout, ssl));
187
188 if (socketTimeout > 0)
189 {
190 _socket.setSendTimeout(socketTimeout);
191 _socket.setReceiveTimeout(socketTimeout);
192 }
193
194 if (!userInfo.empty())
195 {
196 std::string username;
197 std::string password;
198 std::string::size_type pos = userInfo.find(':');
199 if (pos != std::string::npos)
200 {
201 username.assign(userInfo, 0, pos++);
202 password.assign(userInfo, pos, userInfo.size() - pos);
203 }
204 else username = userInfo;
205
206 Database database(databaseName);
207 if (!database.authenticate(*this, username, password, authMechanism))
208 throw Poco::NoPermissionException(Poco::format("Access to MongoDB database %s denied for user %s", databaseName, username));
209 }
210}
211
212
213void Connection::disconnect()
214{
215 _socket.close();
216}
217
218
219void Connection::sendRequest(RequestMessage& request)
220{
221 Poco::Net::SocketOutputStream sos(_socket);
222 request.send(sos);
223}
224
225
226void Connection::sendRequest(RequestMessage& request, ResponseMessage& response)
227{
228 sendRequest(request);
229
230 Poco::Net::SocketInputStream sis(_socket);
231 response.read(sis);
232}
233
234
235} } // Poco::MongoDB
236