1 /*
2 * Copyright (c) 2015, 2021, 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, version 2.0, 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
23 * 02110-1301 USA
24 */
25
26 #ifndef _XPL_SERVER_H_
27 #define _XPL_SERVER_H_
28
29 #include <string>
30 #include <vector>
31
32 #include "ngs/server.h"
33 #include "ngs/memory.h"
34 #include "ngs/scheduler.h"
35 #include "ngs_common/connection_vio.h"
36 #include "ngs_common/atomic.h"
37 #include "xpl_session.h"
38 #include "mysql_show_variable_wrapper.h"
39 #include "xpl_global_status_variables.h"
40
41 #include <mysql/plugin.h>
42 #include "xpl_client.h"
43
44
45 namespace xpl
46 {
47
48 class Session;
49 class Sql_data_context;
50 class Server;
51 struct Ssl_config;
52
53 typedef ngs::shared_ptr<Server> Server_ptr;
54
55 class Server : public ngs::Server_delegate
56 {
57 public:
58 Server(ngs::shared_ptr<ngs::Server_acceptors> acceptors,
59 ngs::shared_ptr<ngs::Scheduler_dynamic> wscheduler,
60 ngs::shared_ptr<ngs::Protocol_config> config);
61
62 static int main(MYSQL_PLUGIN p);
63 static int exit(MYSQL_PLUGIN p);
64
65 template <void (Client::*method)(st_mysql_show_var *)>
66 static void session_status_variable(THD *thd, st_mysql_show_var *var, char *buff);
67
68 template <typename ReturnType, ReturnType (ngs::IOptions_session::*method)()>
69 static void session_status_variable(THD *thd, st_mysql_show_var *var, char *buff);
70
71 template <typename ReturnType, ReturnType (Server::*method)()>
72 static void global_status_variable_server_with_return(THD *thd, st_mysql_show_var *var, char *buff);
73
74 template <void (Server::*method)(st_mysql_show_var *)>
75 static void global_status_variable(THD *thd, st_mysql_show_var *var, char *buff);
76
77 template <typename ReturnType, xpl::Global_status_variables::Variable xpl::Global_status_variables::*variable>
78 static void global_status_variable_server(THD *thd, st_mysql_show_var *var, char *buff);
79
80 template <typename ReturnType, xpl::Common_status_variables::Variable xpl::Common_status_variables::*variable>
81 static void common_status_variable(THD *thd, st_mysql_show_var *var, char *buff);
82
83 template <typename ReturnType, ReturnType (ngs::IOptions_context::*method)()>
84 static void global_status_variable(THD *thd, st_mysql_show_var *var, char *buff);
85
server()86 ngs::Server &server() { return m_server; }
87
88 ngs::Error_code kill_client(uint64_t client_id, Session &requester);
89
90 std::string get_socket_file();
91 std::string get_tcp_bind_address();
92 std::string get_tcp_port();
93
94 typedef ngs::Locked_container<Server, ngs::RWLock_readlock, ngs::RWLock> Server_with_lock;
95 typedef ngs::Memory_instrumented<Server_with_lock>::Unique_ptr Server_ref;
96
get_instance()97 static Server_ref get_instance()
98 {
99 //TODO: ngs::Locked_container add container that supports shared_ptrs
100 return instance ? Server_ref(ngs::allocate_object<Server_with_lock>(ngs::ref(*instance), ngs::ref(instance_rwl))) : Server_ref();
101 }
102
103 private:
104 static Client_ptr get_client_by_thd(Server_ref &server, THD *thd);
105 static void verify_mysqlx_user_grants(Sql_data_context &context);
106
107 bool on_net_startup();
108
109 void net_thread();
110
111 void start_verify_server_state_timer();
112 bool on_verify_server_state();
113
114 void plugin_system_variables_changed();
115
116 virtual ngs::shared_ptr<ngs::Client_interface> create_client(ngs::Connection_ptr connection);
117 virtual ngs::shared_ptr<ngs::Session_interface> create_session(ngs::Client_interface &client,
118 ngs::Protocol_encoder &proto,
119 ngs::Session_interface::Session_id session_id);
120
121 virtual bool will_accept_client(const ngs::Client_interface &client);
122 virtual void did_accept_client(const ngs::Client_interface &client);
123 virtual void did_reject_client(ngs::Server_delegate::Reject_reason reason);
124
125 virtual void on_client_closed(const ngs::Client_interface &client);
126 virtual bool is_terminating() const;
127
128 static Server* instance;
129 static ngs::RWLock instance_rwl;
130 static MYSQL_PLUGIN plugin_ref;
131
132 ngs::Client_interface::Client_id m_client_id;
133 ngs::atomic<int> m_num_of_connections;
134 ngs::shared_ptr<ngs::Protocol_config> m_config;
135 ngs::shared_ptr<ngs::Server_acceptors> m_acceptors;
136 ngs::shared_ptr<ngs::Scheduler_dynamic> m_wscheduler;
137 ngs::shared_ptr<ngs::Scheduler_dynamic> m_nscheduler;
138 ngs::Mutex m_accepting_mutex;
139 ngs::Server m_server;
140
141 static bool exiting;
142 static bool is_exiting();
143 };
144
145
146 template <void (Client::*method)(st_mysql_show_var *)>
session_status_variable(THD * thd,st_mysql_show_var * var,char * buff)147 void Server::session_status_variable(THD *thd, st_mysql_show_var *var, char *buff)
148 {
149 var->type= SHOW_UNDEF;
150 var->value= buff;
151
152 Server_ref server(get_instance());
153 if (server)
154 {
155 ngs::unique_ptr<Mutex_lock> lock(new Mutex_lock((*server)->server().get_client_exit_mutex()));
156 Client_ptr client = get_client_by_thd(server, thd);
157
158 if (client)
159 ((*client).*method)(var);
160 }
161 }
162
163
164 template <typename ReturnType, ReturnType (ngs::IOptions_session::*method)()>
session_status_variable(THD * thd,st_mysql_show_var * var,char * buff)165 void Server::session_status_variable(THD *thd, st_mysql_show_var *var, char *buff)
166 {
167 var->type= SHOW_UNDEF;
168 var->value= buff;
169
170 Server_ref server(get_instance());
171 if (server)
172 {
173 ngs::unique_ptr<Mutex_lock> lock(new Mutex_lock((*server)->server().get_client_exit_mutex()));
174 Client_ptr client = get_client_by_thd(server, thd);
175
176 if (client)
177 {
178 ReturnType result = ((*client->connection().options()).*method)();
179 mysqld::xpl_show_var(var).assign(result);
180 }
181 }
182 }
183
184
185 template <void (Server::*method)(st_mysql_show_var *)>
global_status_variable(THD * thd,st_mysql_show_var * var,char * buff)186 void Server::global_status_variable(THD *thd, st_mysql_show_var *var, char *buff)
187 {
188 var->type= SHOW_UNDEF;
189 var->value= buff;
190
191 Server_ref server = get_instance();
192 if (server)
193 {
194 Server* server_ptr = server->container();
195 (server_ptr->*method)(var);
196 }
197 }
198
199 template <typename ReturnType, ReturnType (Server::*method)()>
global_status_variable_server_with_return(THD * thd,st_mysql_show_var * var,char * buff)200 void Server::global_status_variable_server_with_return(THD *thd, st_mysql_show_var *var, char *buff)
201 {
202 var->type= SHOW_UNDEF;
203 var->value= buff;
204
205 Server_ref server = get_instance();
206 if (server)
207 {
208 Server* server_ptr = server->container();
209 ReturnType result = (server_ptr->*method)();
210
211 mysqld::xpl_show_var(var).assign(result);
212 }
213 }
214
215
216 template <typename ReturnType, xpl::Global_status_variables::Variable xpl::Global_status_variables::*variable>
global_status_variable_server(THD * thd,st_mysql_show_var * var,char * buff)217 void Server::global_status_variable_server(THD *thd, st_mysql_show_var *var, char *buff)
218 {
219 var->type= SHOW_UNDEF;
220 var->value= buff;
221
222 ReturnType result = (Global_status_variables::instance().*variable).load();
223 mysqld::xpl_show_var(var).assign(result);
224 }
225
226
227 template <typename ReturnType, xpl::Common_status_variables::Variable xpl::Common_status_variables::*variable>
common_status_variable(THD * thd,st_mysql_show_var * var,char * buff)228 void Server::common_status_variable(THD *thd, st_mysql_show_var *var, char *buff)
229 {
230 var->type = SHOW_UNDEF;
231 var->value = buff;
232
233 Server_ref server(get_instance());
234 if (server)
235 {
236 ngs::unique_ptr<Mutex_lock> lock(new Mutex_lock((*server)->server().get_client_exit_mutex()));
237 Client_ptr client = get_client_by_thd(server, thd);
238
239 if (client)
240 {
241 ngs::shared_ptr<xpl::Session> client_session(client->get_session());
242 if (client_session)
243 {
244 Common_status_variables &common_status = client_session->get_status_variables();
245 ReturnType result = (common_status.*variable).load();
246 mysqld::xpl_show_var(var).assign(result);
247 }
248 return;
249 }
250 }
251
252 Common_status_variables &common_status = Global_status_variables::instance();
253 ReturnType result = (common_status.*variable).load();
254 mysqld::xpl_show_var(var).assign(result);
255 }
256
257
258 template <typename ReturnType, ReturnType (ngs::IOptions_context::*method)()>
global_status_variable(THD * thd,st_mysql_show_var * var,char * buff)259 void Server::global_status_variable(THD *thd, st_mysql_show_var *var, char *buff)
260 {
261 var->type= SHOW_UNDEF;
262 var->value= buff;
263
264 Server_ref server = get_instance();
265 if (!server || !(*server)->server().ssl_context())
266 return;
267 ngs::IOptions_context_ptr context = (*server)->server().ssl_context()->options();
268 if (!context)
269 return;
270
271 ReturnType result = ((*context).*method)();
272
273 mysqld::xpl_show_var(var).assign(result);
274 }
275
276 } // namespace xpl
277
278 #endif // _XPL_SERVER_H_
279