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