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