MySQL 8.3.0
Source Code Documentation
mysql_routing.h
Go to the documentation of this file.
1/*
2 Copyright (c) 2015, 2023, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23*/
24
25#ifndef ROUTING_MYSQLROUTING_INCLUDED
26#define ROUTING_MYSQLROUTING_INCLUDED
27
30
31/** @file
32 * @brief Defining the class MySQLRouting
33 *
34 * This file defines the main class `MySQLRouting` which is used to configure,
35 * start and manage a connection routing from clients and MySQL servers.
36 *
37 */
38
39#include <array>
40#include <atomic>
41#include <chrono>
42#include <iostream>
43#include <map>
44#include <memory>
45#include <mutex>
46#include <stdexcept>
47
48#ifndef _WIN32
49#include <arpa/inet.h>
50#include <netdb.h>
51#include <netinet/in.h>
52#include <netinet/tcp.h>
53#include <sys/socket.h>
54#include <unistd.h>
55#else
56#include <windows.h>
57#include <winsock2.h>
58#include <ws2tcpip.h>
59#endif
60
61#include "connection.h"
63#include "context.h"
64#include "destination.h"
70#include "mysql/harness/plugin.h"
72#include "mysql_router_thread.h"
73#include "mysql_routing_base.h"
75#include "mysqlrouter/routing.h"
78#include "mysqlrouter/uri.h"
79#include "plugin_config.h"
81#include "socket_container.h"
82#include "ssl_mode.h"
83#include "tcp_address.h"
84
85namespace mysql_harness {
86class PluginFuncEnv;
87}
88
89struct Nothing {};
90class MySQLRouting;
91
93 public:
95 const std::string &parent_routing_name)
96 : io_ctx_(io_ctx), parent_routing_name_(parent_routing_name) {}
97
99
102 virtual bool is_open() const = 0;
103
104 virtual void start(MySQLRouting *r, std::list<IoThread> &,
105 WaitableMonitor<Nothing> &waitable) = 0;
106
107 virtual std::string name() = 0;
108
110
111 protected:
113 // used when the acceptor logs
115};
116
118 public:
120 const std::string &parent_routing_name,
121 const std::string &address, uint16_t port);
122
125 bool is_open() const override;
126
127 void start(MySQLRouting *r, std::list<IoThread> &,
128 WaitableMonitor<Nothing> &waitable) override;
129
130 std::string name() override;
131
132 private:
135
136 std::string address_;
137 uint16_t port_;
138};
139
140#ifndef _WIN32
142 public:
144 const std::string &parent_routing_name,
145 const std::string &socket_name);
146
149 bool is_open() const override;
150
151 void start(MySQLRouting *r, std::list<IoThread> &,
152 WaitableMonitor<Nothing> &waitable) override;
153
154 std::string name() override;
155
156 private:
159
160 std::string socket_name_;
161};
162#endif
163
164/** @class MySQLRouting
165 * @brief Manage Connections from clients to MySQL servers
166 *
167 * The class MySQLRouter is used to start a service listening on a particular
168 * TCP port for incoming MySQL Client connection and route these to a MySQL
169 * Server.
170 *
171 * Connection routing will not analyze or parse any MySQL package (except from
172 * those in the handshake phase to be able to discover invalid connection
173 * error) nor will it do any authentication. It will not handle errors from the
174 * MySQL server and not automatically recover. The client communicate through
175 * MySQL Router just like it would directly connecting.
176 *
177 * The MySQL Server is chosen from a given list of hosts or IP addresses
178 * (with or without TCP port) based on the the mode. For example, mode
179 * read-only will go through the list of servers in a round-robin way. The
180 * mode read-write will always go through the list from the beginning and
181 * failover to the next available.
182 *
183 *
184 * Example usage: bind to all IP addresses and use TCP Port 7001
185 *
186 * @code
187 * MySQLRouting r(conf, ioctx);
188 * r.destination_connect_timeout = std::chrono::seconds(1);
189 * r.set_destinations_from_csv("10.0.10.5;10.0.11.6");
190 * r.run();
191 * @endcode
192 *
193 * The above example will, when MySQL running on 10.0.10.5 is not available,
194 * use 10.0.11.6 to setup the connection routing.
195 *
196 */
198 public:
199 /** @brief Default constructor
200 *
201 * @param routing_config routing configuration
202 * @param io_ctx IO context
203 * @param route_name Name of connection routing (can be empty string)
204 * @param client_ssl_ctx SSL context of the client side
205 * @param dest_ssl_ctx SSL contexts of the destinations
206 */
207 MySQLRouting(const RoutingConfig &routing_config, net::io_context &io_ctx,
208 const std::string &route_name = {},
209 TlsServerContext *client_ssl_ctx = nullptr,
210 DestinationTlsContext *dest_ssl_ctx = nullptr);
211
212 /** @brief Runs the service and accept incoming connections
213 *
214 * Runs the connection routing service and starts accepting incoming
215 * MySQL client connections.
216 *
217 * @throw std::runtime_error on errors.
218 *
219 */
221
222 /** @brief Sets the destinations from URI
223 *
224 * Sets destinations using the given string and the given mode. The string
225 * should be a comma separated list of MySQL servers.
226 *
227 * The mode is one of MySQLRouting::Mode, for example
228 * MySQLRouting::Mode::kReadOnly.
229 *
230 * Example of destinations:
231 * "10.0.10.5,10.0.11.6:3307"
232 *
233 * @param csv destinations as comma-separated-values
234 */
235 void set_destinations_from_csv(const std::string &csv);
236
237 void set_destinations_from_uri(const mysqlrouter::URI &uri);
238
239 /** @brief Returns timeout when connecting to destination
240 *
241 * @return Timeout in seconds as int
242 */
243 std::chrono::milliseconds get_destination_connect_timeout() const noexcept {
244 return context_.get_destination_connect_timeout();
245 }
246
247 /** @brief Sets timeout when connecting to destination
248 *
249 * Checks timeout connecting with destination servers.
250 *
251 * @throw std::invalid_argument when an invalid value was provided.
252 *
253 * @param timeout Timeout
254 */
255 void validate_destination_connect_timeout(std::chrono::milliseconds timeout);
256
257 /** @brief Sets maximum active connections
258 *
259 * Sets maximum of active connections. Maximum must be between 1 and
260 * 65535.
261 *
262 * @throw std::invalid_argument when an invalid value was provided.
263 *
264 * @param maximum Max number of connections allowed
265 * @return New value as int
266 */
267 int set_max_connections(int maximum);
268
269 /** @brief Returns maximum active connections
270 *
271 * @return Maximum as int
272 */
273 int get_max_connections() const noexcept override { return max_connections_; }
274
275 /**
276 * create new connection to MySQL Server than can handle client's
277 * traffic and adds it to connection container.
278 *
279 * @param client_socket socket used to transfer data to/from client
280 * @param client_endpoint endpoint of client
281 */
282 template <class ClientProtocol>
283 void create_connection(
284 typename ClientProtocol::socket client_socket,
285 const typename ClientProtocol::endpoint &client_endpoint);
286
288
289 routing::Mode get_mode() const override;
290
291 std::vector<mysql_harness::TCPAddress> get_destinations() const override;
292
293 std::vector<MySQLRoutingAPI::ConnData> get_connections() override;
294
295 MySQLRoutingConnectionBase *get_connection(const std::string &) override;
296
297 RouteDestination *destinations() { return destination_.get(); }
298
299 void disconnect_all();
300
301 /**
302 * Stop accepting new connections on a listening socket.
303 */
304 void stop_socket_acceptors() override;
305
306 /**
307 * Check if we are accepting connections on a routing socket.
308 *
309 * @retval true if we are accepting connections, false otherwise
310 */
311 bool is_accepting_connections() const override;
312
313 /**
314 * Start accepting new connections on a listening socket
315 *
316 * @returns std::string on errors.
317 */
318 stdx::expected<void, std::string> start_accepting_connections() override;
319
320 /**
321 * Start accepting new connections on a listening socket after it has been
322 * quarantined for lack of valid destinations
323 *
324 * @returns std::string on errors.
325 */
326 stdx::expected<void, std::string> restart_accepting_connections() override;
327
328 private:
329 /** @brief Sets unix socket permissions so that the socket is accessible
330 * to all users (no-op on Windows)
331 * @param socket_file path to socket file
332 *
333 * @throw std::runtime_error if chmod() inside fails
334 */
335 static void set_unix_socket_permissions(const char *socket_file);
336
339
340 public:
341 MySQLRoutingContext &get_context() override { return context_; }
342
343 bool is_running() const override { return is_running_; }
344
345 private:
346 /** Monitor for notifying socket acceptor */
347 WaitableMonitor<Nothing> acceptor_waitable_{Nothing{}};
348
349 /** @brief wrapper for data used by all connections */
351
353
354 /** @brief Destination object to use when getting next connection */
355 std::unique_ptr<RouteDestination> destination_;
356
357 bool is_destination_standalone_{false};
358
359 /** @brief Routing strategy to use when getting next destination */
361
362 /** @brief mode of the servers in the routing */
364
365 /** @brief access_mode of the servers in the routing */
367
368 /** @brief Maximum active connections
369 *
370 * Maximum number of incoming connections that will be accepted
371 * by this MySQLRouter instances. There is no maximum for outgoing
372 * connections since it is one-to-one with incoming.
373 */
375
376 /** @brief used to unregister from subscription on allowed nodes changes */
378
379 /** @brief container for connections */
381
382 /** Information if the routing plugin is still running. */
383 std::atomic<bool> is_running_{true};
384
385 /** Used when the accepting port is been reopened and it failed, to schedule
386 * another retry for standalone-destination(s) route. */
387 net::steady_timer accept_port_reopen_retry_timer_{io_ctx_};
388
389#ifdef FRIEND_TEST
390 FRIEND_TEST(RoutingTests, bug_24841281);
391 FRIEND_TEST(RoutingTests, get_routing_thread_name);
392 FRIEND_TEST(ClassicProtocolRoutingTest, NoValidDestinations);
393 FRIEND_TEST(TestSetupTcpService, single_addr_ok);
394 FRIEND_TEST(TestSetupTcpService, getaddrinfo_fails);
395 FRIEND_TEST(TestSetupTcpService, socket_fails_for_all_addr);
396 FRIEND_TEST(TestSetupTcpService, socket_fails);
397 FRIEND_TEST(TestSetupTcpService, bind_fails);
398 FRIEND_TEST(TestSetupTcpService, listen_fails);
399#ifndef _WIN32
400 FRIEND_TEST(TestSetupTcpService, setsockopt_fails);
401 FRIEND_TEST(TestSetupNamedSocketService, unix_socket_permissions_failure);
402#endif
403#endif
404
405 std::vector<std::unique_ptr<AcceptingEndpoint>> accepting_endpoints_;
406};
407
408extern "C" {
409extern mysql_harness::Plugin ROUTING_PLUGIN_EXPORT harness_plugin_routing;
410}
411
412#endif // ROUTING_MYSQLROUTING_INCLUDED
Definition: mysql_routing.h:117
std::string address_
Definition: mysql_routing.h:136
uint16_t port_
Definition: mysql_routing.h:137
net::ip::tcp::acceptor service_
Definition: mysql_routing.h:133
net::ip::tcp::endpoint service_endpoint_
Definition: mysql_routing.h:134
Definition: mysql_routing.h:141
local::stream_protocol::acceptor service_
Definition: mysql_routing.h:157
std::string socket_name_
Definition: mysql_routing.h:160
local::stream_protocol::endpoint service_endpoint_
Definition: mysql_routing.h:158
Definition: mysql_routing.h:92
virtual ~AcceptingEndpoint()
Definition: mysql_routing.h:109
virtual stdx::expected< void, std::error_code > setup()=0
virtual void start(MySQLRouting *r, std::list< IoThread > &, WaitableMonitor< Nothing > &waitable)=0
virtual std::string name()=0
std::string parent_routing_name_
Definition: mysql_routing.h:114
net::io_context & io_ctx_
Definition: mysql_routing.h:112
AcceptingEndpoint(const AcceptingEndpoint &)=delete
virtual bool is_open() const =0
AcceptingEndpoint(net::io_context &io_ctx, const std::string &parent_routing_name)
Definition: mysql_routing.h:94
virtual stdx::expected< void, std::error_code > cancel()=0
container for connections to MySQL Server.
Definition: connection_container.h:166
TlsClientContext per destination.
Definition: destination_ssl_context.h:41
Facade to avoid a tight coupling between Routing component and actual routing endpoint implementation...
Definition: mysql_routing_base.h:40
Definition: connection.h:42
MySQLRoutingContext holds data used by MySQLRouting (1 per plugin instances) and MySQLRoutingConnecti...
Definition: context.h:58
Manage Connections from clients to MySQL servers.
Definition: mysql_routing.h:197
std::chrono::milliseconds get_destination_connect_timeout() const noexcept
Returns timeout when connecting to destination.
Definition: mysql_routing.h:243
routing::Mode mode_
mode of the servers in the routing
Definition: mysql_routing.h:363
std::unique_ptr< RouteDestination > destination_
Destination object to use when getting next connection.
Definition: mysql_routing.h:355
MySQLRoutingContext & get_context() override
Definition: mysql_routing.h:341
ConnectionContainer connection_container_
container for connections
Definition: mysql_routing.h:380
routing::AccessMode access_mode_
access_mode of the servers in the routing
Definition: mysql_routing.h:366
AllowedNodesChangeCallbacksListIterator allowed_nodes_list_iterator_
used to unregister from subscription on allowed nodes changes
Definition: mysql_routing.h:377
std::vector< std::unique_ptr< AcceptingEndpoint > > accepting_endpoints_
Definition: mysql_routing.h:405
MySQLRoutingContext context_
wrapper for data used by all connections
Definition: mysql_routing.h:350
net::io_context & io_ctx_
Definition: mysql_routing.h:352
RouteDestination * destinations()
Definition: mysql_routing.h:297
int max_connections_
Maximum active connections.
Definition: mysql_routing.h:374
bool is_running() const override
Definition: mysql_routing.h:343
int get_max_connections() const noexcept override
Returns maximum active connections.
Definition: mysql_routing.h:273
routing::RoutingStrategy routing_strategy_
Routing strategy to use when getting next destination.
Definition: mysql_routing.h:360
Manage destinations for a Connection Routing.
Definition: destination.h:187
virtual mysql_harness::TCPAddress get(const std::string &address, uint16_t port)
Gets destination based on address and port.
Definition: destination.cc:130
route specific configuration.
Definition: routing_config.h:39
TLS Context for the server side.
Definition: tls_server_context.h:50
Monitor can be waited for.
Definition: monitor.h:61
PluginFuncEnv object.
Definition: loader.h:672
Parse and create URIs according to RFC3986.
Definition: uri.h:69
Definition: socket.h:1292
Definition: timer.h:56
Definition: io_context.h:60
Definition: internet.h:677
Definition: expected.h:943
static int get_connection(MEM_ROOT *mem_root, FEDERATED_SHARE *share)
Definition: ha_federated.cc:607
static void start(mysql_harness::PluginFuncEnv *env)
Definition: http_auth_backend_plugin.cc:176
static void run(mysql_harness::PluginFuncEnv *)
Definition: io_plugin.cc:194
mysql_harness::Plugin ROUTING_PLUGIN_EXPORT harness_plugin_routing
Definition: routing_plugin.cc:588
std::string get_routing_thread_name(const std::string &config_name, const std::string &prefix)
return a short string suitable to be used as a thread name
Definition: mysql_routing_common.cc:29
static bool timeout(bool(*wait_condition)())
Timeout function.
Definition: log0meb.cc:497
Definition: common.h:41
stdx::expected< native_handle_type, error_type > socket(int family, int sock_type, int protocol)
Definition: socket.h:62
RoutingStrategy ROUTING_EXPORT get_routing_strategy(const std::string &value)
Returns RoutingStrategy for its literal representation.
Definition: routing.cc:110
AccessMode
Definition: routing.h:146
RoutingStrategy
Routing strategies supported by Routing plugin.
Definition: routing.h:152
Mode ROUTING_EXPORT get_mode(const std::string &value)
Returns Mode for its literal representation.
Definition: routing.cc:61
RoutingMode
Modes supported by Routing plugin.
Definition: routing.h:133
const mysql_service_registry_t * r
Definition: pfs_example_plugin_employee.cc:85
required uint64 port
Definition: replication_asynchronous_connection_failover.proto:32
#define ROUTING_EXPORT
Definition: routing_export.h:15
#define ROUTING_PLUGIN_EXPORT
Definition: routing_plugin_export.h:15
AllowedNodesChangeCallbacksList::iterator AllowedNodesChangeCallbacksListIterator
Definition: destination.h:63
case opt name
Definition: sslopt-case.h:32
Definition: mysql_routing.h:89