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