1/*
2  Copyright (c) 2015, 2020, 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 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 MYSQL_HARNESS_PLUGIN_INCLUDED
26#define MYSQL_HARNESS_PLUGIN_INCLUDED
27
28#include "harness_export.h"
29
30#include "my_compiler.h"
31
32#include <cstdint>
33#include <cstdlib>
34
35namespace mysql_harness {
36
37/* Forward declarations */
38struct AppInfo;
39class Config;
40class ConfigSection;
41class PluginFuncEnv;
42
43/** @defgroup Harness_API Harness API
44 *
45 * Harness API provides a set of functions that can be called from 4 plugin
46 * functions (`start()`, `stop()`, `init()`, `deinit()`). Each call requires
47 * `PluginFuncEnv*` as first argument - this is an opaque pointer that is passed
48 * to plugin function in its argument list.
49 *
50 * @note Not all API functions can be called from all plugin functions. See
51 * description of each function for details.
52 *
53 * @{
54 */
55
56/**
57 * This is a list of pre-defined error types, which can be used in
58 * set_error() API call. Select the one that best-describes your situation.
59 * As a rule of thumb, use one of kConfig* if the error occurs due to
60 * configuration issue, or kRuntimeError otherwise.
61 *
62 * Since plugin functions are not allowed to throw, it is recommended to
63 * surround your plugin function code with try/catch blocks, and catching
64 * (in addition to any specific exceptions) all exceptions
65 * (using the "catch (...) { .. }" block). In this catch block, using
66 * kUndefinedError is recommended.
67 *
68 * @note There is another enum missing from table below (kNoError),
69 * it is internal to MySQL Router, DO NOT USE it in your plugin.
70 */
71enum ErrorType {
72  // internal to MySQL Router project, DO NOT USE THIS in your plugin
73  kNoError = 0,  // uninitialized error value
74
75  // API
76  kRuntimeError = 1,      /**< runtime error */
77  kConfigInvalidArgument, /**< configuration error */
78  kConfigSyntaxError,     /**< configuration syntax error */
79  kUndefinedError,        /**< typically set from plugin's general safeguard
80                               ('catch (...) {..}' block) */
81};
82
83/** @brief Returns error to Harness
84 *
85 * Function callable from: `init()`, `start()`, `stop()`, `deinit()`
86 *
87 * Plugin functions cannot throw nor return a value. To communicate failure,
88 * this function should be called.
89 *
90 * Calling this function not only passes the error type and string back to
91 * Harness, but also implies that the function has failed. The converse is also
92 * true: not calling this function prior to exiting the function implies
93 * success.  This distinction is important, because Harness may take certain
94 * actions based on the status returned by each function.
95 *
96 * @param env Pointer to PluginFuncEnv object passed to plugin function
97 * @param error_type One of the pre-defined error codes
98 * @param fmt format-string of error-msg to get logged
99 * It can be NULL, but it's recommended to provide a meaningful message.
100 */
101void HARNESS_EXPORT set_error(mysql_harness::PluginFuncEnv *env,
102                              mysql_harness::ErrorType error_type,
103                              const char *fmt, ...) noexcept
104#ifdef __GNUC__
105    __attribute__((format(printf, 3, 4)))
106#endif
107    ;
108
109/** @brief Checks whether plugin shutdown was requested
110 *
111 * Function callable from: `start()`
112 *
113 * Since plugin is running in its own thread (inside its `start()` function),
114 * it needs to be notified when Harness wants it to shut down.  Harness
115 * provides two notification mechanisms: blocking and non-blocking. The plugin
116 * developer can choose the one that is most convenient.
117 *
118 * This is the non-blocking version. It should be regularly polled by `start()`,
119 * and upon returning false, `start()` should shut down the plugin and exit.
120 *
121 * @param env Pointer to PluginFuncEnv object passed to plugin function
122 * @return "running" flag. If true, `start()` may continue running, if false,
123 * `start()` should shut down
124 */
125bool HARNESS_EXPORT
126is_running(const mysql_harness::PluginFuncEnv *env) noexcept;
127
128/** @brief Blocks until shutdown is requested (or optionally timeout)
129 *
130 * Function callable from: `start()`
131 *
132 * Since plugin is running in its own thread (inside its `start()` function),
133 * it needs to be notified when Harness wants it to shut down.  Harness
134 * provides two notification mechanisms: blocking and non-blocking. The plugin
135 * developer can choose the one that is most convenient.
136 *
137 * This is the blocking version. It is a responsive and efficient functional
138 * equivalent of:
139 * @code
140 *
141 *   while (is_running(env)) {
142 *     // sleep a little bit or break on timeout
143 *   }
144 *
145 * @endcode
146 * @param env Pointer to PluginFuncEnv object passed to plugin function
147 * @param milliseconds Timeout in milliseconds, 0 = wait forever
148 * @return true if stop was requested, false on timeout
149 */
150bool HARNESS_EXPORT wait_for_stop(const mysql_harness::PluginFuncEnv *env,
151                                  uint32_t milliseconds) noexcept;
152
153/** @brief Clears "running flag" to induce plugin shutdown
154 *
155 * Function callable from: `start()`
156 *
157 * There may be occassions when the plugin needs to request its own shutdown
158 * (typically after it detects an error). In such case, this function should
159 * be called - it will set the "running" flag to false. Subsequent calls to
160 * is_running() and wait_for_stop() will reflect this new setting.
161 *
162 * @note This only sets "running" flag for the plugin that calls this. Other
163 * plugins have their own "running" flags, which means they are unaffected.
164 *
165 * @param env Pointer to PluginFuncEnv object passed to plugin function
166 */
167
168void HARNESS_EXPORT clear_running(mysql_harness::PluginFuncEnv *env) noexcept;
169
170/** @brief Retrieves information from Harness
171 *
172 * function callable from: `init()`, `deinit()`
173 *
174 * This function returns an AppInfo object, which provides further plugin
175 * environment information.
176 *
177 * @param env Pointer to env object passed to plugin function
178 * @return Pointer to AppInfo object
179 */
180const HARNESS_EXPORT AppInfo *get_app_info(
181    const mysql_harness::PluginFuncEnv *env) noexcept;
182
183/** @brief Retrieves information from Harness
184 *
185 * function callable from: `start()`, `stop()`
186 *
187 * This function returns a ConfigSection object, which provides further
188 * plugin environment information.
189 *
190 * @param env Pointer to PluginFuncEnv object passed to plugin function
191 * @return Pointer to ConfigSection object
192 */
193const HARNESS_EXPORT ConfigSection *get_config_section(
194    const mysql_harness::PluginFuncEnv *env) noexcept;
195
196/**@}*/
197
198/**
199 * Structure with information about the harness.
200 *
201 * @ingroup Loader
202 *
203 * This structure is made available to plugins so that they can get
204 * information about the plugin harness.
205 *
206 * @note We are intentionally using C calls here to avoid issues with
207 * symbol conversions and calling conventions. The file can be
208 * included both as a C and C++ file.
209 *
210 */
211
212struct AppInfo {
213  /**
214   * Program name.
215   *
216   * Name of the application.
217   */
218
219  const char *program;
220
221  /**
222   * Directory name for plugins.
223   *
224   * Name of the directory where extensions can be found and it
225   * depends on how the harness was installed. In a typical
226   * installation with installation prefix `/` it will be
227   * `/var/lib/mysql/<name>`.
228   */
229
230  const char *plugin_folder;
231
232  /**
233   * Directory name for log files.
234   *
235   * Name of the directory where log files should be placed. In a
236   * typical installation with installation prefix `/` this will be
237   * `/var/log/<name>`.
238   */
239
240  const char *logging_folder;
241
242  /**
243   * Directory name for run files.
244   *
245   * Name of the directory where run files should be placed. In a
246   * typical installation with installation prefix `/` this will be
247   * `/var/run/<name>`.
248   */
249
250  const char *runtime_folder;
251
252  /**
253   * Directory name for data files.
254   *
255   * Name of the directory where data files should be placed. In a
256   * typical installation with installation prefix `/` this will be
257   * `/var/lib/<name>`.
258   */
259
260  const char *data_folder;
261
262  /**
263   * Directory name for configuration files.
264   *
265   * Name of the directory where run files should be placed. In a
266   * typical installation with installation prefix `/` this will be
267   * `/etc/<name>`.
268   */
269
270  const char *config_folder;
271
272  /**
273   * Configuration information.
274   */
275
276  const Config *config;
277};
278
279/**
280 * Structure containing information about the plugin.
281 *
282 * @ingroup Loader
283 *
284 * The name of the plugin is give by the filename.
285 */
286
287struct Plugin {
288  /**
289   * Version of the plugin interface the plugin was built for.
290   *
291   * This field contain the ABI version the plugin was built for and
292   * is checked when loading the plugin to determine if the structure
293   * can be safely read. It shall normally be set to
294   * `PLUGIN_ABI_VERSION`, which is the version of the ABI that is
295   * being used.
296   *
297   * The least significant byte contain the minor version, the second
298   * least significant byte contain the major version of the
299   * interface. The most significant two bytes are unused and should
300   * be set to zero.
301   *
302   * @note Whenever new callbacks are added but none of the existing
303   * ones are changed, the minor version will be stepped. If the
304   * existing functions are changed in an incompatible way (something
305   * that could break the calling conventions for a platform), the
306   * major version will be stepped. Typically, the major version have
307   * to be stepped whenever parameters to existing functions are
308   * changed, but there are exceptions.
309   *
310   * @see PLUGIN_ABI_VERSION
311   */
312
313  uint32_t abi_version;
314
315  /**
316   * Architecture descriptor.
317   *
318   * A descriptor for the architecture the plugin was build
319   * for. Normally, `ARCHITECTURE_DESCRIPTOR` should be used.
320   *
321   * The architecture descriptor is a string that contain information
322   * about the architecture the plugin is being compiled with. It need
323   * to match the architecture of the harness.
324   *
325   * The architecture is a C string containing four slash-separated
326   * fields (or a star to denote that this is not checked):
327   *
328   * - CPU
329   * - Operating system
330   * - Naming scheme and calling conventions (essentially the compiler
331   *   and version of compiler being used to build the solution).
332   * - Runtime
333   *
334   * @see ARCHITECTURE_DESCRIPTOR
335   */
336
337  const char *arch_descriptor;
338
339  /**
340   * Brief description of plugin, to show in listings.
341   */
342
343  const char *brief;
344
345  /**
346   * Plugin version.
347   *
348   * Version of the plugin, given as a version number.
349   *
350   * @see VERSION_NUMBER
351   */
352  uint32_t plugin_version;
353
354  /**
355   * Array of names of required plugins.
356   *
357   * Length is given as the number of elements in the array and the
358   * array contain the names of the required plugins as C strings.
359   *
360   * A typical use is:
361   * @code
362   * static const std::array<char *, 2> required = {{
363   *   "first",
364   *   "second",
365   * }};
366   *
367   * Plugin my_plugin = {
368   *   ...
369   *   required.size(), required.data(),
370   *   ...
371   * };
372   * @endcode
373   */
374
375  size_t requires_length;
376  const char *const *requires;
377
378  /**
379   * Array of names of plugins it conflicts with.
380   *
381   * The array is defined in a similar way to how the `requires` array
382   * is defined.
383   */
384
385  size_t conflicts_length;
386  const char *const *conflicts;
387
388  /**
389   * Module initialization function.
390   *
391   * This function is called after the module is loaded. The pointer
392   * can be NULL, in which case no initialization takes place.
393   *
394   * @pre All modules that is in the list of required modules have
395   * their @c init() function called before this modules init
396   * function.
397   *
398   * @param env Pointer to PluginFuncEnv object, which is the basis of
399   * all communication with harness. Please see its documentation
400   * for more information. Particularly, calling get_app_info(env)
401   * will provide information about harness this module was loaded into.
402   *
403   * @note This function must not throw (it is not declared with 'noexcept'
404   * due to certain technical limitations)
405   */
406
407  void (*init)(PluginFuncEnv *env);  // not allowed to throw!
408
409  /**
410   * Module deinitialization function.
411   *
412   * This function is called after module threads have exited but
413   * before the module is unloaded.
414   *
415   * @pre All `deinit` functions in modules will required by this
416   * module are called after the `deinit` function of this module
417   * have exited.
418   *
419   * @param env Pointer to PluginFuncEnv object, which is the basis of
420   * all communication with harness. Please see its documentation
421   * for more information. Particularly, calling get_app_info(env)
422   * will provide information about harness this module was loaded into.
423   *
424   * @note This function must not throw (it is not declared with 'noexcept'
425   * due to certain technical limitations)
426   */
427
428  void (*deinit)(PluginFuncEnv *env);  // not allowed to throw!
429
430  /**
431   * Module thread start function.
432   *
433   * If this field is non-NULL, the plugin will be assigned a new
434   * thread and the start function will be called. The start functions
435   * of different plugins are called in an arbitrary order, so no
436   * expectations on the start order should be made.
437   * This function must respect harness' notification to stop running,
438   * and exit when notified. It shall regularly poll a "running" flag
439   * exposed by harness (see is_running() and wait_for_stop()), it may
440   * also clear this flag via clear_running() if it needs to.
441   *
442   * @param env Pointer to PluginFuncEnv object, which is the basis of
443   * all communication with harness. Please see its documentation
444   * for more information. Particularly, calling get_config_section(
445   * env) will provide pointer to the section that is being started.
446   * You can find both the name and the key in this section object.
447   *
448   * @note This function must not throw (it is not declared with 'noexcept'
449   * due to certain technical limitations)
450   */
451
452  void (*start)(PluginFuncEnv *env);  // not allowed to throw!
453
454  /**
455   * Module thread stop (notification) function.
456   *
457   * This function is called when stopping start(). Since start() runs
458   * in a different thread, no assumptions should be made on whether
459   * stop() runs before, during or after start() exits. Also, the
460   * stop() functions of different plugins are called in an arbitrary
461   * order, so no expectations on stop() calling order should be made.
462   *
463   * @note this function does not cause the plugin running start() to
464   * exit - harness uses another mechanism to facilitate that. Instead,
465   * this function is called *in addition* to stopping the start() function,
466   * as a courtesy notification call, should that be useful.
467   *
468   * @note unlike start(), which runs in its own thread, stop() runs in
469   * harness' thread
470   *
471   * @note under certain circumstances, `stop()` may overlap execution
472   * with `start()`, or even be called before `start()`. stop() must be
473   * able to deal with all such cases.
474   *
475   * @param env Pointer to PluginFuncEnv object, which is the basis of
476   * all communication with harness. Please see its documentation
477   * for more information. Particularly, calling get_config_section(
478   * env) will provide pointer to the section that is being started.
479   * You can find both the name and the key in this section object.
480   *
481   * @note This function must not throw (it is not declared with 'noexcept'
482   * due to certain technical limitations)
483   */
484
485  void (*stop)(PluginFuncEnv *env);  // not allowed to throw!
486};
487
488/**
489 * Current version of the library.
490 *
491 * @ingroup Loader
492 *
493 * This constant is the version of the plugin interface in use. This
494 * should be used when initializing the module structure.
495 *
496 * @see Plugin
497 */
498
499const uint32_t PLUGIN_ABI_VERSION = 0x0200;
500
501/**
502 * Default architecture descriptor.
503 *
504 * @ingroup Loader
505 */
506const char *const ARCHITECTURE_DESCRIPTOR =
507    "@MYSQL_HARNESS_ARCH_CPU@/@MYSQL_HARNESS_ARCH_OS@/"
508    "@MYSQL_HARNESS_ARCH_COMPILER@/@MYSQL_HARNESS_ARCH_RUNTIME@";
509
510/**
511 * Macro to create a version number from a major, minor and patch version.
512 *
513 * @ingroup Loader
514 */
515#define VERSION_NUMBER(MAJ, MIN, PAT) \
516  ((((MAJ)&0xFF) << 24) | (((MIN)&0xFF) << 16) | ((PAT)&0xFFFF))
517
518/**
519 * Macros to extract major/minor/patch version from the full version number.
520 *
521 * @ingroup Loader
522 */
523#define VERSION_MAJOR(VER) (((VER) >> 24) & 0xFF)
524#define VERSION_MINOR(VER) (((VER) >> 16) & 0xFF)
525#define VERSION_PATCH(VER) ((VER)&0xFFFF)
526
527/**
528 * Macro to create ABI version number from a major and minor version.
529 *
530 * @ingroup Loader
531 */
532#define ABI_VERSION_NUMBER(MAJ, MIN) ((((MAJ)&0xFF) << 8) | ((MIN)&0xFF))
533
534/**
535 * Macros to extract major/minor version from the full ABI version number.
536 *
537 * @ingroup Loader
538 */
539#define ABI_VERSION_MAJOR(VER) (((VER) >> 8) & 0xFF)
540#define ABI_VERSION_MINOR(VER) ((VER)&0xFF)
541}  // namespace mysql_harness
542
543#endif /* MYSQL_HARNESS_PLUGIN_INCLUDED */
544