1 /*
2    Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved.
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 02110-1301  USA
23 */
24 
25 #include <my_config.h>
26 
27 #include <mysql/plugin.h>
28 #include <mysql_version.h>
29 
30 #include "xpl_session.h"
31 #include "xpl_system_variables.h"
32 #include "xpl_server.h"
33 #include "xpl_performance_schema.h"
34 #include "mysqlx_version.h"
35 #include "xpl_log.h"
36 
37 #include <stdio.h>                            // Solaris header file bug.
38 #include <limits>
39 
40 #define BYTE(X)  (X)
41 #define KBYTE(X) ((X) * 1024)
42 #define MBYTE(X) ((X) * 1024 * 1024)
43 #define GBYTE(X) ((X) * 1024 * 1024 * 1024)
44 
45 namespace
46 {
47 
48 typedef void (*Xpl_status_variable_get)(THD *, st_mysql_show_var *, char *);
49 
xpl_func_ptr(Xpl_status_variable_get callback)50 char *xpl_func_ptr(Xpl_status_variable_get callback)
51 {
52   union
53   {
54     char *ptr;
55     Xpl_status_variable_get callback;
56   } ptr_cast;
57 
58   ptr_cast.callback = callback;
59 
60   return ptr_cast.ptr;
61 }
62 
exit_hook()63 void exit_hook()
64 {
65   google::protobuf::ShutdownProtobufLibrary();
66 }
67 
68 } // namespace
69 
70 
71 /*
72   Start the plugin: start webservers
73 
74   SYNOPSIS
75     xpl_plugin_init()
76     p plugin handle
77 
78   RETURN
79      0  success
80      1  error
81  */
xpl_plugin_init(MYSQL_PLUGIN p)82 int xpl_plugin_init(MYSQL_PLUGIN p)
83 {
84   static bool atexit_installed = false;
85   if (!atexit_installed)
86   {
87     atexit_installed = true;
88     atexit(exit_hook);
89   }
90 
91   xpl::Plugin_system_variables::clean_callbacks();
92 
93   xpl_init_performance_schema();
94 
95   return xpl::Server::main(p);
96 }
97 
98 /*
99   Shutdown the plugin: stop webservers
100 
101   SYNOPSIS
102     xpl_plugin_deinit()
103     p plugin handle
104 
105   RETURN
106      0  success
107      1  error
108  */
xpl_plugin_deinit(MYSQL_PLUGIN p)109 int xpl_plugin_deinit(MYSQL_PLUGIN p)
110 {
111   return xpl::Server::exit(p);
112 }
113 
114 
115 static struct st_mysql_daemon xpl_plugin_info ={
116   MYSQL_DAEMON_INTERFACE_VERSION
117 };
118 
119 
120 static MYSQL_SYSVAR_UINT(port, xpl::Plugin_system_variables::port,
121     PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
122     "Port on which X Plugin is going to accept incoming connections.",
123     NULL, NULL, MYSQLX_TCP_PORT, 1, std::numeric_limits<uint16>::max(), 0);
124 
125 static MYSQL_SYSVAR_INT(max_connections, xpl::Plugin_system_variables::max_connections,
126     PLUGIN_VAR_OPCMDARG,
127     "Maximum number of concurrent X protocol connections. Actual number of connections is also affected by the general max_connections.",
128     NULL, NULL, 100, 1, std::numeric_limits<unsigned short>::max(), 0);
129 
130 static MYSQL_SYSVAR_UINT(min_worker_threads, xpl::Plugin_system_variables::min_worker_threads,
131     PLUGIN_VAR_OPCMDARG,
132     "Minimal number of worker threads.",
133     NULL, &xpl::Plugin_system_variables::update_func<unsigned int>, 2U, 1, 100, 0);
134 
135 static MYSQL_SYSVAR_UINT(idle_worker_thread_timeout, xpl::Plugin_system_variables::idle_worker_thread_timeout,
136     PLUGIN_VAR_OPCMDARG,
137     "Time after which an idle worker thread is terminated (in seconds).",
138     NULL, &xpl::Plugin_system_variables::update_func<unsigned int>, 60, 0, 60 * 60, 0);
139 
140 static MYSQL_SYSVAR_UINT(max_allowed_packet, xpl::Plugin_system_variables::max_allowed_packet,
141     PLUGIN_VAR_OPCMDARG,
142     "Size of largest message that client is going to handle.",
143     NULL, &xpl::Plugin_system_variables::update_func<unsigned int>, MBYTE(1), BYTE(512), GBYTE(1), 0);
144 
145 static MYSQL_SYSVAR_UINT(connect_timeout, xpl::Plugin_system_variables::connect_timeout,
146     PLUGIN_VAR_OPCMDARG,
147     "Maximum allowed waiting time for connection to setup a session (in seconds).",
148     NULL, &xpl::Plugin_system_variables::update_func<unsigned int>, 30, 1, 1000000000, 0);
149 
150 static MYSQL_SYSVAR_STR(ssl_key, xpl::Plugin_system_variables::ssl_config.ssl_key,
151       PLUGIN_VAR_READONLY | PLUGIN_VAR_MEMALLOC,
152       "X509 key in PEM format.", NULL, NULL, NULL);
153 
154 static MYSQL_SYSVAR_STR(ssl_ca, xpl::Plugin_system_variables::ssl_config.ssl_ca,
155       PLUGIN_VAR_READONLY | PLUGIN_VAR_MEMALLOC,
156       "CA file in PEM format.", NULL, NULL, NULL);
157 
158 static MYSQL_SYSVAR_STR(ssl_capath, xpl::Plugin_system_variables::ssl_config.ssl_capath,
159       PLUGIN_VAR_READONLY | PLUGIN_VAR_MEMALLOC,
160       "CA directory.", NULL, NULL, NULL);
161 
162 static MYSQL_SYSVAR_STR(ssl_cert, xpl::Plugin_system_variables::ssl_config.ssl_cert,
163       PLUGIN_VAR_READONLY | PLUGIN_VAR_MEMALLOC,
164       "X509 cert in PEM format.", NULL, NULL, NULL);
165 
166 static MYSQL_SYSVAR_STR(ssl_cipher, xpl::Plugin_system_variables::ssl_config.ssl_cipher,
167       PLUGIN_VAR_READONLY | PLUGIN_VAR_MEMALLOC,
168       "SSL cipher to use.", NULL, NULL, NULL);
169 
170 static MYSQL_SYSVAR_STR(ssl_crl, xpl::Plugin_system_variables::ssl_config.ssl_crl,
171       PLUGIN_VAR_READONLY | PLUGIN_VAR_MEMALLOC,
172       "Certificate revocation list.", NULL, NULL, NULL);
173 
174 static MYSQL_SYSVAR_STR(ssl_crlpath, xpl::Plugin_system_variables::ssl_config.ssl_crlpath,
175       PLUGIN_VAR_READONLY,
176       "Certificate revocation list path.", NULL, NULL, NULL);
177 
178 static MYSQL_SYSVAR_STR(socket, xpl::Plugin_system_variables::socket,
179       PLUGIN_VAR_READONLY | PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_MEMALLOC,
180       "X Plugin's unix socket for local connection.", NULL, NULL, NULL);
181 
182 static MYSQL_SYSVAR_STR(bind_address, xpl::Plugin_system_variables::bind_address,
183       PLUGIN_VAR_READONLY | PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_MEMALLOC,
184       "Address to which X Plugin should bind the TCP socket.", NULL, NULL, "*");
185 
186 static MYSQL_SYSVAR_UINT(port_open_timeout, xpl::Plugin_system_variables::port_open_timeout,
187       PLUGIN_VAR_READONLY | PLUGIN_VAR_OPCMDARG ,
188       "How long X Plugin is going to retry binding of server socket (in case of failure)",
189       NULL, &xpl::Plugin_system_variables::update_func<unsigned int>, 0, 0, 120, 0);
190 
191 static struct st_mysql_sys_var* xpl_plugin_system_variables[]= {
192   MYSQL_SYSVAR(port),
193   MYSQL_SYSVAR(max_connections),
194   MYSQL_SYSVAR(min_worker_threads),
195   MYSQL_SYSVAR(idle_worker_thread_timeout),
196   MYSQL_SYSVAR(max_allowed_packet),
197   MYSQL_SYSVAR(connect_timeout),
198   MYSQL_SYSVAR(ssl_key),
199   MYSQL_SYSVAR(ssl_ca),
200   MYSQL_SYSVAR(ssl_capath),
201   MYSQL_SYSVAR(ssl_cert),
202   MYSQL_SYSVAR(ssl_cipher),
203   MYSQL_SYSVAR(ssl_crl),
204   MYSQL_SYSVAR(ssl_crlpath),
205   MYSQL_SYSVAR(socket),
206   MYSQL_SYSVAR(bind_address),
207   MYSQL_SYSVAR(port_open_timeout),
208   NULL
209 };
210 
211 #define SESSION_STATUS_VARIABLE_ENTRY_LONGLONG(NAME, METHOD)                 \
212     { MYSQLX_STATUS_VARIABLE_PREFIX(NAME),                                   \
213       xpl_func_ptr(xpl::Server::common_status_variable<long long, &METHOD>), \
214       SHOW_FUNC,                                                             \
215       SHOW_SCOPE_GLOBAL }
216 
217 #define GLOBAL_STATUS_VARIABLE_ENTRY_LONGLONG(NAME, METHOD)                         \
218     { MYSQLX_STATUS_VARIABLE_PREFIX(NAME),                                          \
219       xpl_func_ptr(xpl::Server::global_status_variable_server<long long, &METHOD>), \
220       SHOW_FUNC,                                                                    \
221       SHOW_SCOPE_GLOBAL }
222 
223 #define GLOBAL_SSL_STATUS_VARIABLE_ENTRY(NAME, TYPE, METHOD)            \
224     { MYSQLX_STATUS_VARIABLE_PREFIX(NAME),                              \
225       xpl_func_ptr(xpl::Server::global_status_variable<TYPE, &METHOD>), \
226       SHOW_FUNC,                                                        \
227       SHOW_SCOPE_GLOBAL }
228 
229 #define SESSION_SSL_STATUS_VARIABLE_ENTRY(NAME, TYPE, METHOD)            \
230     { MYSQLX_STATUS_VARIABLE_PREFIX(NAME),                               \
231       xpl_func_ptr(xpl::Server::session_status_variable<TYPE, &METHOD>), \
232       SHOW_FUNC,                                                         \
233       SHOW_SCOPE_GLOBAL }
234 
235 #define SESSION_SSL_STATUS_VARIABLE_ENTRY_ARRAY(NAME, METHOD)      \
236     { MYSQLX_STATUS_VARIABLE_PREFIX(NAME),                         \
237       xpl_func_ptr(xpl::Server::session_status_variable<&METHOD>), \
238       SHOW_FUNC,                                                   \
239       SHOW_SCOPE_GLOBAL }
240 
241 #define GLOBAL_CUSTOM_STATUS_VARIABLE_ENTRY(NAME, TYPE, METHOD)                            \
242     { MYSQLX_STATUS_VARIABLE_PREFIX(NAME),                                                 \
243       xpl_func_ptr(xpl::Server::global_status_variable_server_with_return<TYPE, &METHOD>), \
244       SHOW_FUNC,                                                                           \
245       SHOW_SCOPE_GLOBAL }
246 
247 static struct st_mysql_show_var xpl_plugin_status[]=
248 {
249   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("stmt_execute_sql",        xpl::Common_status_variables::m_stmt_execute_sql),
250   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("stmt_execute_xplugin",    xpl::Common_status_variables::m_stmt_execute_xplugin),
251   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("stmt_execute_mysqlx",     xpl::Common_status_variables::m_stmt_execute_mysqlx),
252   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("crud_update",             xpl::Common_status_variables::m_crud_update),
253   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("crud_delete",             xpl::Common_status_variables::m_crud_delete),
254   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("crud_find",               xpl::Common_status_variables::m_crud_find),
255   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("crud_insert",             xpl::Common_status_variables::m_crud_insert),
256   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("crud_create_view",        xpl::Common_status_variables::m_crud_create_view),
257   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("crud_modify_view",        xpl::Common_status_variables::m_crud_modify_view),
258   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("crud_drop_view",          xpl::Common_status_variables::m_crud_drop_view),
259   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("expect_open",             xpl::Common_status_variables::m_expect_open),
260   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("expect_close",            xpl::Common_status_variables::m_expect_close),
261   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("stmt_create_collection",       xpl::Common_status_variables::m_stmt_create_collection),
262   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("stmt_create_collection_index", xpl::Common_status_variables::m_stmt_create_collection_index),
263   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("stmt_drop_collection",         xpl::Common_status_variables::m_stmt_drop_collection),
264   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("stmt_ensure_collection",       xpl::Common_status_variables::m_stmt_ensure_collection),
265   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("stmt_drop_collection_index",   xpl::Common_status_variables::m_stmt_drop_collection_index),
266   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("stmt_list_objects",       xpl::Common_status_variables::m_stmt_list_objects),
267   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("stmt_enable_notices",     xpl::Common_status_variables::m_stmt_enable_notices),
268   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("stmt_disable_notices",    xpl::Common_status_variables::m_stmt_disable_notices),
269   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("stmt_list_notices",       xpl::Common_status_variables::m_stmt_list_notices),
270   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("stmt_list_clients",       xpl::Common_status_variables::m_stmt_list_clients),
271   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("stmt_kill_client",        xpl::Common_status_variables::m_stmt_kill_client),
272   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("stmt_ping",               xpl::Common_status_variables::m_stmt_ping),
273   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("bytes_sent",              xpl::Common_status_variables::m_bytes_sent),
274   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("bytes_received",          xpl::Common_status_variables::m_bytes_received),
275   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("errors_sent",             xpl::Common_status_variables::m_errors_sent),
276   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("rows_sent",               xpl::Common_status_variables::m_rows_sent),
277   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("notice_warning_sent",     xpl::Common_status_variables::m_notice_warning_sent),
278   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("notice_other_sent",       xpl::Common_status_variables::m_notice_other_sent),
279   SESSION_STATUS_VARIABLE_ENTRY_LONGLONG("errors_unknown_message_type",    xpl::Common_status_variables::m_errors_unknown_message_type),
280   GLOBAL_STATUS_VARIABLE_ENTRY_LONGLONG("sessions",                 xpl::Global_status_variables::m_sessions_count),
281   GLOBAL_STATUS_VARIABLE_ENTRY_LONGLONG("sessions_closed",          xpl::Global_status_variables::m_closed_sessions_count),
282   GLOBAL_STATUS_VARIABLE_ENTRY_LONGLONG("sessions_fatal_error",     xpl::Global_status_variables::m_sessions_fatal_errors_count),
283   GLOBAL_STATUS_VARIABLE_ENTRY_LONGLONG("init_error",               xpl::Global_status_variables::m_init_errors_count),
284   GLOBAL_STATUS_VARIABLE_ENTRY_LONGLONG("sessions_accepted",        xpl::Global_status_variables::m_accepted_sessions_count),
285   GLOBAL_STATUS_VARIABLE_ENTRY_LONGLONG("sessions_rejected",        xpl::Global_status_variables::m_rejected_sessions_count),
286   GLOBAL_STATUS_VARIABLE_ENTRY_LONGLONG("sessions_killed",          xpl::Global_status_variables::m_killed_sessions_count),
287   GLOBAL_STATUS_VARIABLE_ENTRY_LONGLONG("connections_closed",       xpl::Global_status_variables::m_closed_connections_count),
288   GLOBAL_STATUS_VARIABLE_ENTRY_LONGLONG("connections_accepted",     xpl::Global_status_variables::m_accepted_connections_count),
289   GLOBAL_STATUS_VARIABLE_ENTRY_LONGLONG("connections_rejected",     xpl::Global_status_variables::m_rejected_connections_count),
290   GLOBAL_STATUS_VARIABLE_ENTRY_LONGLONG("connection_accept_errors", xpl::Global_status_variables::m_connection_accept_errors_count),
291   GLOBAL_STATUS_VARIABLE_ENTRY_LONGLONG("connection_errors",        xpl::Global_status_variables::m_connection_errors_count),
292   GLOBAL_STATUS_VARIABLE_ENTRY_LONGLONG("worker_threads",           xpl::Global_status_variables::m_worker_thread_count),
293   GLOBAL_STATUS_VARIABLE_ENTRY_LONGLONG("worker_threads_active",    xpl::Global_status_variables::m_active_worker_thread_count),
294 
295   SESSION_SSL_STATUS_VARIABLE_ENTRY_ARRAY("ssl_cipher_list", xpl::Client::get_status_ssl_cipher_list),
296   SESSION_SSL_STATUS_VARIABLE_ENTRY("ssl_active",       bool,        ngs::IOptions_session::active_tls),
297   SESSION_SSL_STATUS_VARIABLE_ENTRY("ssl_cipher",       std::string, ngs::IOptions_session::ssl_cipher),
298   SESSION_SSL_STATUS_VARIABLE_ENTRY("ssl_version",      std::string, ngs::IOptions_session::ssl_version),
299   SESSION_SSL_STATUS_VARIABLE_ENTRY("ssl_verify_depth", long,        ngs::IOptions_session::ssl_verify_depth),
300   SESSION_SSL_STATUS_VARIABLE_ENTRY("ssl_verify_mode",  long,        ngs::IOptions_session::ssl_verify_mode),
301   GLOBAL_SSL_STATUS_VARIABLE_ENTRY("ssl_ctx_verify_depth",  long,        ngs::IOptions_context::ssl_ctx_verify_depth),
302   GLOBAL_SSL_STATUS_VARIABLE_ENTRY("ssl_ctx_verify_mode",   long,        ngs::IOptions_context::ssl_ctx_verify_mode),
303   GLOBAL_SSL_STATUS_VARIABLE_ENTRY("ssl_finished_accepts",  long,        ngs::IOptions_context::ssl_sess_accept_good),
304   GLOBAL_SSL_STATUS_VARIABLE_ENTRY("ssl_accepts",           long,        ngs::IOptions_context::ssl_sess_accept),
305   GLOBAL_SSL_STATUS_VARIABLE_ENTRY("ssl_server_not_after",  std::string, ngs::IOptions_context::ssl_server_not_after),
306   GLOBAL_SSL_STATUS_VARIABLE_ENTRY("ssl_server_not_before", std::string, ngs::IOptions_context::ssl_server_not_before),
307 
308   GLOBAL_CUSTOM_STATUS_VARIABLE_ENTRY("socket",  std::string, xpl::Server::get_socket_file),
309   GLOBAL_CUSTOM_STATUS_VARIABLE_ENTRY("port",    std::string, xpl::Server::get_tcp_port),
310   GLOBAL_CUSTOM_STATUS_VARIABLE_ENTRY("address", std::string, xpl::Server::get_tcp_bind_address),
311 
312   { NULL, NULL, SHOW_BOOL, SHOW_SCOPE_GLOBAL}
313 };
314 
315 
mysql_declare_plugin(xpl)316 mysql_declare_plugin(xpl)
317 {
318   MYSQL_DAEMON_PLUGIN,
319   &xpl_plugin_info,
320   MYSQLX_PLUGIN_NAME,
321   "Oracle Corp",
322   "X Plugin for MySQL",
323   PLUGIN_LICENSE_GPL,
324   xpl_plugin_init,              /* init       */
325   xpl_plugin_deinit,            /* deinit     */
326   MYSQLX_PLUGIN_VERSION,        /* version    */
327   xpl_plugin_status,            /* status var */
328   xpl_plugin_system_variables,  /* system var */
329   NULL,                         /* options    */
330   0                             /* flags      */
331 }
332 mysql_declare_plugin_end;
333