All changes 2.0.0...develop
973b983 Merge branch 'release-2.0.0' into develop 255dd23 Make spinlock functions take const argument 6e23bab Fix bitmask reallocation 338c189 Rename and clean up slavelag filter 3ea8f28 Fix possible NULL pointer dereference bfe6738 MXS-830: Add module information to logged messages 1fad962 Fix strncat usage d38997a Adjust log throttling policy 0be4e4b Add hashtable_item_strcasecmp 726100e Take hashtable convenience functions into use 5e7744a Fix typo in maxadmin.md c5778c8 Merge branch 'release-2.0.0' into develop b5762af Move from tmpnam to mkstemp d6f2c71 Add convenience functions to hashtable 359058a MXS-825: Add support for --execdir 636347c Enable runtime reconfiguration of log throttling ef9fba9 Improve log throttling documentation aef917a Implement log throttling e3a5349 Remove shardrouter.c 8051e80 Remove custom qc_sqlite allocation functions fd34d60 Initial implementation of the learning firewall a8752a8 Removed "filestem option" from example 1ef2519 Removed "filestem option" from example 0815cc8 Cleanup spinlock.h ab4dc99 Clean up hashtable.h ef2c078 Add prototypes for hashtable copy and free functions fb5cfaf Add 'log_throttling' configuration entry 300d823 Add proper prototypes for hashtable hash and cmp functions 1c649aa qc_mysqlembedded: Include skygw_...h without path. d276160 Add missing RPM scripts e70e644 Fix HTTPAuth installation 1b2b389 Combine utils into the server directory 3ff9913 Add missing utils headers to devel package 407efb2 Fix minor packaging problems 99aa6ad Split MaxScale into core, experimental and devel packages 1290386 Merge branch 'develop' of ssh://github.com/mariadb-corporation/maxscale-new into develop e59f148 Make scripts POSIX sh compatible 7319266 Fixed SHOW SLAVE STATUS in bonlog router f8d760a Update Binlogrouter.md 0a904ed Update Replication-Proxy-Binlog-Router-Tutorial.md 75d4202 Update Replication-Proxy-Binlog-Router-Tutorial.md b8651fc Add missing newline in listmanager.h c7ad047 Add note about user data caches to release notes 70ccc2b Merge branch 'release-2.0.0' into develop 575d1b6 Mistake - dummy session needs list markers set. 8364508 Merge branch 'develop' into binlog_server_semisync 868b902 Update MaxScale limitations 2c8b327 Store listener caches in separate directories 6e183ec Create unique user data caches for each listeners f643685 Don't free orphaned tee filter sessions 4179afa Allow binlogrouter to be used without a listener 7ad79af Add function for freeing a listener 677a0a2 Move authentication data from services to listeners 4f12af7 Merge remote-tracking branch 'origin/MXS-677' into develop 1419b81 Semi-Sync support to binlog server: code review updtate 0ea0f01 Semi-Sync support to binlog server: added missing routine 4aad909 Semi-Sync support to binlog server b824e1e Add authenticator support to httpd.c 705a688 Change tabs to spaces d0c419e Change method of adding list fields to e.g. DCB 25504fc Document the changed routing priority of hints 41666d1 Remove use_ssl_if_enabled global option a3584e9 Make routing hints have highest priority 34a1d24 Updated document with new binlog router option 01eedc5 Updated documentation with SSL usage 8a4c0f6 Update Replication-Proxy-Binlog-Router-Tutorial.md 4e374aa Update Replication-Proxy-Binlog-Router-Tutorial.md f3f3c57 Update Replication-Proxy-Binlog-Router-Tutorial.md 617b79f Binlog Server: error messages typo fix fa8dfae Binlog Server: error messages review 1b8819c Fix freeing of schemarouter session memory 07f49e1 MXS-788: new code review fix 1fd3b09 MXS-788: show services now displays SSL info 6ca2584 MXS-788 code review fix ae6a7d0 MXS-788 code review 43d3474 Master server SSL connection 90b2377 Use correct variable in listmanager pre-allocation 9a5b238 Fix listmanager pre-allocation 9c78625 Fix a memory leak when backend authentication fails e59a966 Fix hang in list_find_free ff30223 Fix freeing of shared data in schemarouter fc8f9d3 Add missing include in luafilter ecf7f53 Add missing NULL value to filter parameter array 636d849 Update memory allocation approach f0d1d38 Add new allocation functions 97d00a0 Fix writing of uninitialized data to logs e72c9b2 Merge branch 'release-2.0.0' into develop cf2b712 Merge branch 'release-2.0.0' into develop 8917c5c Change the logic behind valid list entry checks c10deff Improve documentation about version_string f59f1f7 Merge branch 'develop' of ssh://github.com/mariadb-corporation/maxscale-new into develop c88edb3 Backend authentication failure improvement abd5bee Revert "Backend authentication failure improvement" 5bb3107 Backend authentication failure improvement b7f434a Add new allocation functions 3f022fa Fix stupid mistake 99c4317 Merge remote-tracking branch 'origin/MXS-677' into develop 3c1ded6 Added connection/authentication failure error reporting in SHOW SLAVE STATUS 0a60f7b Tidy up and deal with review points. ba103ff blr_slave.c: Update strncpy usage 467331e blr_master.c: Strncpy usage updates d2b7c0c Merge remote-tracking branch 'origin/develop-nullauth-merge' into develop 5a8c1d0 qc: Measure execution time at the right place. bccdb93 Merge branch 'NullAuthDeny' into develop 2e6511c Add 5.5.5 prefix to all version strings that lack it 314655a Improve DCB and session initialization and list handling e1c43f0 MXS-655: Make MaxScale logging logrotate(8) compatible ce36afd MXS-626: Don't log a header unless maxlog enabled dcd47a7 blr_file.c: Replace uses of strncpy 6b8f576 bls_slave.c: Replace strncpy with memcpy 68a0039 Add list preallocation, tidy up, simplify init. cb37d1b Fix copyright etc headers. 11a400d Tidy; comment; fix bad copies and mistakes. 7e36ec4 Add list manager files. c4794e3 Initial code for list manager. 1b42e25 Merge remote-tracking branch 'origin/MXS-765' into develop d50f617 Fix problems, extend tests, respond to review. dcb4a91 Filter test folder removed 0b60dbe Add a couple of comments. 83cdba0 Fix overwriting problem. ba5d353 Fix overwriting problem. 53671cb Small fixes in response to review. 173d049 blr.c: Review strncpy usage 4ff6ef2 binlog_common.c: Replace strncpy with memcpy f238e03 maxbinlogcheck.s: Replace strncpy 9807f8d harness: Replace unnecessary use of strncpy 8c7fe6a avro: Modify strncpy usage 9b8008e Small improvements. b7f784f Fix mistakes in testqueuemanager.c cc26962 Restore missing poll.c code; add testqueuemanager.c. 2e91806 Format the filter harness 22059e6 Initial implementation connection queueing. c604dc2 readwritesplit.c: Improve COM_INIT_DB handling 454d920 schemarouter.c: Replace strncpy with strcpy 8e85d66 sharding_common.c: Too long a database name handled explicitly 77f4446 Astyle schemarouter 491f7c2 maxinfo.c: Replace strncpy with memcpy 6b98105 maxinfo: Reformat with astyle c1dbf08 Handle oversize user and database names 5fa4a0f Merge branch 'develop' of ssh://github.com/mariadb-corporation/maxscale-new into develop 706963b BLR_DBUSERS_TAIL new var in blr.h d75b9af Tweak comments, remove trailing blanks. ab2400a Optimise statistics gathering by inline & simpler fns. fb59ddc Remove unnecessary strncpy/strncat usage in Binlog Server bdcd551 resultset.c: Change strncpy to memcpy c6b1c5e Reject rather than cut too long a path 6d8f112 Remove unnecessary strncpy/strncat usage 18bf5ed Remove unnecessary strncpy usage dc0e2db Make maxpasswd more userfriendly c9c8695 Fix calculation of padded_len in encryptPassword 2cfd2c6 dbusers.c: Check strncpy usage 7ab9342 Make more thorough checks in secrets_readKeys be7d593 Format cli.c debugcli.c testroute.c webserver.c 1ee5efb config.c: Check usage of strncpy 3043b12 gq_utils.c: Unnecessary use of strncpy removed 77874ac Add help to maxkeys 38392a3 Update secrets_writeKeys documentation 2d1325c Make SSL optional in MaxScale's own communication bda00da Fix avro build failures b2cb31a Add more OOM macros 41ccf17 Fix strdup usage a48f732 Fix realloc calls 20771f6 Add forgotten extern "C" block 8faf35a Add maxscale allocation functions bb47890 Add macros for OOM logging afea388 Fix silly mistakes. 6dafd22 Make deny default for null auth; move code from common to auth.
This commit is contained in:
@ -4,3 +4,4 @@ add_subdirectory(protocol)
|
||||
add_subdirectory(monitor)
|
||||
add_subdirectory(filter)
|
||||
add_subdirectory(authenticator)
|
||||
add_subdirectory(include)
|
||||
|
@ -1,28 +1,38 @@
|
||||
add_library(MySQLAuth SHARED mysql_auth.c)
|
||||
target_link_libraries(MySQLAuth maxscale-common)
|
||||
set_target_properties(MySQLAuth PROPERTIES VERSION "1.0.0")
|
||||
install(TARGETS MySQLAuth DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(MySQLAuth core)
|
||||
|
||||
add_library(NullAuth SHARED null_auth.c)
|
||||
target_link_libraries(NullAuth maxscale-common)
|
||||
set_target_properties(NullAuth PROPERTIES VERSION "1.0.0")
|
||||
install(TARGETS NullAuth DESTINATION ${MAXSCALE_LIBDIR})
|
||||
add_library(NullAuthAllow SHARED null_auth_allow.c)
|
||||
target_link_libraries(NullAuthAllow maxscale-common)
|
||||
set_target_properties(NullAuthAllow PROPERTIES VERSION "1.0.0")
|
||||
install_module(NullAuthAllow core)
|
||||
|
||||
add_library(NullAuthDeny SHARED null_auth_deny.c)
|
||||
target_link_libraries(NullAuthDeny maxscale-common)
|
||||
set_target_properties(NullAuthDeny PROPERTIES VERSION "1.0.0")
|
||||
install_module(NullAuthDeny core)
|
||||
|
||||
add_library(MaxAdminAuth SHARED max_admin_auth.c)
|
||||
target_link_libraries(MaxAdminAuth maxscale-common)
|
||||
set_target_properties(MaxAdminAuth PROPERTIES VERSION "1.0.0")
|
||||
install(TARGETS MaxAdminAuth DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(MaxAdminAuth core)
|
||||
|
||||
add_library(HTTPAuth SHARED http_auth.c)
|
||||
target_link_libraries(HTTPAuth maxscale-common)
|
||||
set_target_properties(HTTPAuth PROPERTIES VERSION "1.0.0")
|
||||
install_module(HTTPAuth core)
|
||||
|
||||
# if(BUILD_TESTS)
|
||||
# add_library(testprotocol SHARED testprotocol.c)
|
||||
# set_target_properties(testprotocol PROPERTIES VERSION "1.0.0")
|
||||
# target_link_libraries(testprotocol maxscale-common)
|
||||
# install(TARGETS testprotocol DESTINATION ${MAXSCALE_LIBDIR})
|
||||
# install_module(testprotocol core)
|
||||
# endif()
|
||||
if(BUILD_CDC)
|
||||
add_library(CDCPlainAuth SHARED cdc_plain_auth.c)
|
||||
target_link_libraries(CDCPlainAuth maxscale-common)
|
||||
set_target_properties(CDCPlainAuth PROPERTIES VERSION "1.0.0")
|
||||
install(TARGETS CDCPlainAuth DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(CDCPlainAuth core)
|
||||
endif()
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -30,6 +30,7 @@
|
||||
#include <modutil.h>
|
||||
#include <users.h>
|
||||
#include <sys/stat.h>
|
||||
#include <maxscale/alloc.h>
|
||||
|
||||
/* Allowed time interval (in seconds) after last update*/
|
||||
#define CDC_USERS_REFRESH_TIME 30
|
||||
@ -53,11 +54,11 @@ static bool cdc_auth_is_client_ssl_capable(DCB *dcb);
|
||||
static int cdc_auth_authenticate(DCB *dcb);
|
||||
static void cdc_auth_free_client_data(DCB *dcb);
|
||||
|
||||
static int cdc_set_service_user(SERVICE *service);
|
||||
static int cdc_set_service_user(SERV_LISTENER *listener);
|
||||
static int cdc_read_users(USERS *users, char *usersfile);
|
||||
static int cdc_load_users(SERVICE *service);
|
||||
static int cdc_refresh_users(SERVICE *service);
|
||||
static int cdc_replace_users(SERVICE *service);
|
||||
static int cdc_load_users(SERV_LISTENER *listener);
|
||||
static int cdc_refresh_users(SERV_LISTENER *listener);
|
||||
static int cdc_replace_users(SERV_LISTENER *listener);
|
||||
|
||||
extern char *gw_bin2hex(char *out, const uint8_t *in, unsigned int len);
|
||||
extern void gw_sha1_str(const uint8_t *in, int in_len, uint8_t *out);
|
||||
@ -140,15 +141,15 @@ static int cdc_auth_check(DCB *dcb, CDC_protocol *protocol, char *username, uint
|
||||
if (!cdc_load_users_init)
|
||||
{
|
||||
/* Load db users or set service user */
|
||||
if (cdc_load_users(dcb->service) < 1)
|
||||
if (cdc_load_users(dcb->listener) < 1)
|
||||
{
|
||||
cdc_set_service_user(dcb->service);
|
||||
cdc_set_service_user(dcb->listener);
|
||||
}
|
||||
|
||||
cdc_load_users_init = 1;
|
||||
}
|
||||
|
||||
user_password = users_fetch(dcb->service->users, username);
|
||||
user_password = users_fetch(dcb->listener->users, username);
|
||||
|
||||
if (!user_password)
|
||||
{
|
||||
@ -200,7 +201,7 @@ cdc_auth_authenticate(DCB *dcb)
|
||||
auth_ret = cdc_auth_check(dcb, protocol, client_data->user, client_data->auth_data, client_data->flags);
|
||||
|
||||
/* On failed authentication try to reload user table */
|
||||
if (CDC_STATE_AUTH_OK != auth_ret && 0 == cdc_refresh_users(dcb->service))
|
||||
if (CDC_STATE_AUTH_OK != auth_ret && 0 == cdc_refresh_users(dcb->listener))
|
||||
{
|
||||
/* Call protocol authentication */
|
||||
auth_ret = cdc_auth_check(dcb, protocol, client_data->user, client_data->auth_data, client_data->flags);
|
||||
@ -209,7 +210,7 @@ cdc_auth_authenticate(DCB *dcb)
|
||||
/* on successful authentication, set user into dcb field */
|
||||
if (CDC_STATE_AUTH_OK == auth_ret)
|
||||
{
|
||||
dcb->user = strdup(client_data->user);
|
||||
dcb->user = MXS_STRDUP_A(client_data->user);
|
||||
}
|
||||
else if (dcb->service->log_auth_warnings)
|
||||
{
|
||||
@ -248,7 +249,7 @@ cdc_auth_set_protocol_data(DCB *dcb, GWBUF *buf)
|
||||
CHK_PROTOCOL(protocol);
|
||||
if (dcb->data == NULL)
|
||||
{
|
||||
if (NULL == (client_data = (CDC_session *)calloc(1, sizeof(CDC_session))))
|
||||
if (NULL == (client_data = (CDC_session *)MXS_CALLOC(1, sizeof(CDC_session))))
|
||||
{
|
||||
return CDC_STATE_AUTH_ERR;
|
||||
}
|
||||
@ -356,7 +357,7 @@ cdc_auth_is_client_ssl_capable(DCB *dcb)
|
||||
static void
|
||||
cdc_auth_free_client_data(DCB *dcb)
|
||||
{
|
||||
free(dcb->data);
|
||||
MXS_FREE(dcb->data);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -367,8 +368,9 @@ cdc_auth_free_client_data(DCB *dcb)
|
||||
* @return 0 on success, 1 on failure
|
||||
*/
|
||||
static int
|
||||
cdc_set_service_user(SERVICE *service)
|
||||
cdc_set_service_user(SERV_LISTENER *listener)
|
||||
{
|
||||
SERVICE *service = listener->service;
|
||||
char *dpwd = NULL;
|
||||
char *newpasswd = NULL;
|
||||
char *service_user = NULL;
|
||||
@ -400,15 +402,15 @@ cdc_set_service_user(SERVICE *service)
|
||||
MXS_ERROR("create hex_sha1_sha1_password failed for service user %s",
|
||||
service_user);
|
||||
|
||||
free(dpwd);
|
||||
MXS_FREE(dpwd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* add service user */
|
||||
(void)users_add(service->users, service->credentials.name, newpasswd);
|
||||
(void)users_add(listener->users, service->credentials.name, newpasswd);
|
||||
|
||||
free(newpasswd);
|
||||
free(dpwd);
|
||||
MXS_FREE(newpasswd);
|
||||
MXS_FREE(dpwd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -420,8 +422,9 @@ cdc_set_service_user(SERVICE *service)
|
||||
* @return -1 on failure, 0 for no users found, > 0 for found users
|
||||
*/
|
||||
static int
|
||||
cdc_load_users(SERVICE *service)
|
||||
cdc_load_users(SERV_LISTENER *listener)
|
||||
{
|
||||
SERVICE *service = listener->service;
|
||||
int loaded = -1;
|
||||
char path[PATH_MAX + 1] = "";
|
||||
|
||||
@ -429,13 +432,13 @@ cdc_load_users(SERVICE *service)
|
||||
snprintf(path, PATH_MAX, "%s/%s/cdcusers", get_datadir(), service->name);
|
||||
|
||||
/* Allocate users table */
|
||||
if (service->users == NULL)
|
||||
if (listener->users == NULL)
|
||||
{
|
||||
service->users = users_alloc();
|
||||
listener->users = users_alloc();
|
||||
}
|
||||
|
||||
/* Try loading authentication data from file cache */
|
||||
loaded = cdc_read_users(service->users, path);
|
||||
loaded = cdc_read_users(listener->users, path);
|
||||
|
||||
if (loaded == -1)
|
||||
{
|
||||
@ -491,11 +494,8 @@ cdc_read_users(USERS *users, char *usersfile)
|
||||
filelen = statb.st_size;
|
||||
}
|
||||
|
||||
if ((all_users_data = malloc(filelen + 1)) == NULL)
|
||||
if ((all_users_data = MXS_MALLOC(filelen + 1)) == NULL)
|
||||
{
|
||||
MXS_ERROR("failed to allocate %i for service user data load %s",
|
||||
filelen + 1,
|
||||
usersfile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -532,7 +532,7 @@ cdc_read_users(USERS *users, char *usersfile)
|
||||
|
||||
memcpy(users->cksum, hash, SHA_DIGEST_LENGTH);
|
||||
|
||||
free(all_users_data);
|
||||
MXS_FREE(all_users_data);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
@ -549,9 +549,11 @@ cdc_read_users(USERS *users, char *usersfile)
|
||||
* * @return 0 on success and 1 on error
|
||||
* */
|
||||
static int
|
||||
cdc_refresh_users(SERVICE *service)
|
||||
cdc_refresh_users(SERV_LISTENER *listener)
|
||||
{
|
||||
int ret = 1;
|
||||
SERVICE *service = listener->service;
|
||||
|
||||
/* check for another running getUsers request */
|
||||
if (!spinlock_acquire_nowait(&service->users_table_spin))
|
||||
{
|
||||
@ -582,7 +584,7 @@ cdc_refresh_users(SERVICE *service)
|
||||
service->rate_limit.last = time(NULL);
|
||||
}
|
||||
|
||||
ret = cdc_replace_users(service);
|
||||
ret = cdc_replace_users(listener);
|
||||
|
||||
/* remove lock */
|
||||
spinlock_release(&service->users_table_spin);
|
||||
@ -604,11 +606,11 @@ cdc_refresh_users(SERVICE *service)
|
||||
* @return -1 on any error or the number of users inserted (0 means no users at all)
|
||||
* */
|
||||
static int
|
||||
cdc_replace_users(SERVICE *service)
|
||||
cdc_replace_users(SERV_LISTENER *listener)
|
||||
{
|
||||
SERVICE *service = listener->service;
|
||||
int i;
|
||||
USERS *newusers, *oldusers;
|
||||
HASHTABLE *oldresources;
|
||||
char path[PATH_MAX + 1] = "";
|
||||
|
||||
/* File path for router cached authentication data */
|
||||
@ -629,8 +631,8 @@ cdc_replace_users(SERVICE *service)
|
||||
return i;
|
||||
}
|
||||
|
||||
spinlock_acquire(&service->spin);
|
||||
oldusers = service->users;
|
||||
spinlock_acquire(&listener->lock);
|
||||
oldusers = listener->users;
|
||||
|
||||
/* digest compare */
|
||||
if (oldusers != NULL && memcmp(oldusers->cksum, newusers->cksum,
|
||||
@ -649,10 +651,10 @@ cdc_replace_users(SERVICE *service)
|
||||
/* replace the service with effective new data */
|
||||
MXS_DEBUG("%lu [cdc_replace_users] users' tables replaced, checksum differs",
|
||||
pthread_self());
|
||||
service->users = newusers;
|
||||
listener->users = newusers;
|
||||
}
|
||||
|
||||
spinlock_release(&service->spin);
|
||||
spinlock_release(&listener->lock);
|
||||
|
||||
if (i && oldusers)
|
||||
{
|
||||
|
223
server/modules/authenticator/http_auth.c
Normal file
223
server/modules/authenticator/http_auth.c
Normal file
@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
* Public License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file http_ba__auth.c
|
||||
*
|
||||
* MaxScale HTTP Basic Access authentication for the HTTPD protocol module.
|
||||
*
|
||||
* @verbatim
|
||||
* Revision History
|
||||
* Date Who Description
|
||||
* 20/07/2016 Markus Makela Initial version
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
#include <gw_authenticator.h>
|
||||
#include <maxscale/alloc.h>
|
||||
#include <modinfo.h>
|
||||
#include <dcb.h>
|
||||
#include <buffer.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <service.h>
|
||||
#include <secrets.h>
|
||||
|
||||
/* @see function load_module in load_utils.c for explanation of the following
|
||||
* lint directives.
|
||||
*/
|
||||
/*lint -e14 */
|
||||
MODULE_INFO info =
|
||||
{
|
||||
MODULE_API_AUTHENTICATOR,
|
||||
MODULE_GA,
|
||||
GWAUTHENTICATOR_VERSION,
|
||||
"The MaxScale HTTP BA authenticator"
|
||||
};
|
||||
/*lint +e14 */
|
||||
|
||||
static char *version_str = "V1.0.0";
|
||||
|
||||
static int http_auth_set_protocol_data(DCB *dcb, GWBUF *buf);
|
||||
static bool http_auth_is_client_ssl_capable(DCB *dcb);
|
||||
static int http_auth_authenticate(DCB *dcb);
|
||||
static void http_auth_free_client_data(DCB *dcb);
|
||||
|
||||
/*
|
||||
* The "module object" for mysql client authenticator module.
|
||||
*/
|
||||
static GWAUTHENTICATOR MyObject =
|
||||
{
|
||||
http_auth_set_protocol_data, /* Extract data into structure */
|
||||
http_auth_is_client_ssl_capable, /* Check if client supports SSL */
|
||||
http_auth_authenticate, /* Authenticate user credentials */
|
||||
http_auth_free_client_data, /* Free the client data held in DCB */
|
||||
};
|
||||
|
||||
typedef struct http_auth
|
||||
{
|
||||
char* user;
|
||||
char* pw;
|
||||
}HTTP_AUTH;
|
||||
|
||||
/**
|
||||
* Implementation of the mandatory version entry point
|
||||
*
|
||||
* @return version string of the module
|
||||
*/
|
||||
/* @see function load_module in load_utils.c for explanation of the following
|
||||
* lint directives.
|
||||
*/
|
||||
/*lint -e14 */
|
||||
char* version()
|
||||
{
|
||||
return version_str;
|
||||
}
|
||||
|
||||
/**
|
||||
* The module initialisation routine, called when the module
|
||||
* is first loaded.
|
||||
*/
|
||||
void ModuleInit()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* The module entry point routine. It is this routine that
|
||||
* must populate the structure that is referred to as the
|
||||
* "module object", this is a structure with the set of
|
||||
* external entry points for this module.
|
||||
*
|
||||
* @return The module object
|
||||
*/
|
||||
GWAUTHENTICATOR* GetModuleObject()
|
||||
{
|
||||
return &MyObject;
|
||||
}
|
||||
/*lint +e14 */
|
||||
|
||||
/**
|
||||
* @brief Authentication of a user/password combination.
|
||||
*
|
||||
* The validation is already done, the result is returned.
|
||||
*
|
||||
* @param dcb Request handler DCB connected to the client
|
||||
* @return Authentication status - always 0 to denote success
|
||||
*/
|
||||
static int
|
||||
http_auth_authenticate(DCB *dcb)
|
||||
{
|
||||
int rval = 1;
|
||||
HTTP_AUTH *ses = (HTTP_AUTH*)dcb->data;
|
||||
char *user, *pw;
|
||||
serviceGetUser(dcb->service, &user, &pw);
|
||||
pw = decryptPassword(pw);
|
||||
|
||||
if (ses && strcmp(ses->user, user) == 0 && strcmp(ses->pw, pw) == 0)
|
||||
{
|
||||
rval = 0;
|
||||
}
|
||||
|
||||
free(pw);
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transfer data from the authentication request to the DCB.
|
||||
*
|
||||
* Expects a buffer containing a Base64 encoded username and password
|
||||
* contatenated together by a semicolon as is specificed by HTTP Basic
|
||||
* Access authentication.
|
||||
*
|
||||
* @param dcb Request handler DCB connected to the client
|
||||
* @param buffer Pointer to pointer to buffers containing data from client
|
||||
* @return Authentication status - 0 for success, 1 for failure
|
||||
*/
|
||||
static int
|
||||
http_auth_set_protocol_data(DCB *dcb, GWBUF *buf)
|
||||
{
|
||||
int rval = 1;
|
||||
char* value = (char*)GWBUF_DATA(buf);
|
||||
char* tok = strstr(value, "Basic");
|
||||
tok = tok ? strchr(tok, ' ') : NULL;
|
||||
if (tok)
|
||||
{
|
||||
tok++;
|
||||
char outbuf[strlen(tok) * 2 + 1];
|
||||
|
||||
BIO *b64 = BIO_new(BIO_f_base64());
|
||||
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
|
||||
|
||||
BIO *bio = BIO_new_mem_buf(tok, -1);
|
||||
BIO_push(b64, bio);
|
||||
int nread = BIO_read(b64, outbuf, sizeof(outbuf));
|
||||
outbuf[nread] = '\0';
|
||||
BIO_free_all(b64);
|
||||
char *pw_start = strchr(outbuf, ':');
|
||||
if (pw_start)
|
||||
{
|
||||
*pw_start++ = '\0';
|
||||
HTTP_AUTH *ses = MXS_MALLOC(sizeof(*ses));
|
||||
char* user = MXS_STRDUP(outbuf);
|
||||
char* pw = MXS_STRDUP(pw_start);
|
||||
|
||||
if (ses && user && pw)
|
||||
{
|
||||
ses->user = user;
|
||||
ses->pw = pw;
|
||||
dcb->data = ses;
|
||||
rval = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_FREE(ses);
|
||||
MXS_FREE(user);
|
||||
MXS_FREE(pw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determine whether the client is SSL capable
|
||||
*
|
||||
* Always say that client is not SSL capable. Support for SSL is not yet
|
||||
* available.
|
||||
*
|
||||
* @param dcb Request handler DCB connected to the client
|
||||
* @return Boolean indicating whether client is SSL capable - false
|
||||
*/
|
||||
static bool
|
||||
http_auth_is_client_ssl_capable(DCB *dcb)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Free the client data pointed to by the passed DCB.
|
||||
*
|
||||
* The authentication data stored in the DCB is a pointer to a HTTP_AUTH
|
||||
* structure allocated in http_auth_set_protocol_data().
|
||||
*
|
||||
* @param dcb Request handler DCB connected to the client
|
||||
*/
|
||||
static void
|
||||
http_auth_free_client_data(DCB *dcb)
|
||||
{
|
||||
HTTP_AUTH *ses = (HTTP_AUTH*)dcb->data;
|
||||
MXS_FREE(ses->user);
|
||||
MXS_FREE(ses->pw);
|
||||
MXS_FREE(ses);
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -27,6 +27,7 @@
|
||||
*/
|
||||
|
||||
#include <gw_authenticator.h>
|
||||
#include <maxscale/alloc.h>
|
||||
#include <modinfo.h>
|
||||
#include <dcb.h>
|
||||
#include <buffer.h>
|
||||
@ -130,7 +131,7 @@ max_admin_auth_set_protocol_data(DCB *dcb, GWBUF *buf)
|
||||
|
||||
max_admin_auth_free_client_data(dcb);
|
||||
|
||||
if ((session_data = (ADMIN_session *)calloc(1, sizeof(ADMIN_session))) != NULL)
|
||||
if ((session_data = (ADMIN_session *)MXS_CALLOC(1, sizeof(ADMIN_session))) != NULL)
|
||||
{
|
||||
int user_len = (GWBUF_LENGTH(buf) > ADMIN_USER_MAXLEN) ? ADMIN_USER_MAXLEN : GWBUF_LENGTH(buf);
|
||||
#if defined(SS_DEBUG)
|
||||
@ -170,12 +171,12 @@ max_admin_auth_is_client_ssl_capable(DCB *dcb)
|
||||
* @brief Free the client data pointed to by the passed DCB.
|
||||
*
|
||||
* The max_admin authenticator uses a simple structure that can be freed with
|
||||
* a single call to free().
|
||||
* a single call to MXS_FREE().
|
||||
*
|
||||
* @param dcb Request handler DCB connected to the client
|
||||
*/
|
||||
static void
|
||||
max_admin_auth_free_client_data(DCB *dcb)
|
||||
{
|
||||
free(dcb->data);
|
||||
MXS_FREE(dcb->data);
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -28,6 +28,7 @@
|
||||
#include <mysql_auth.h>
|
||||
#include <mysql_client_server_protocol.h>
|
||||
#include <gw_authenticator.h>
|
||||
#include <maxscale/alloc.h>
|
||||
#include <maxscale/poll.h>
|
||||
|
||||
/* @see function load_module in load_utils.c for explanation of the following
|
||||
@ -181,7 +182,7 @@ mysql_auth_authenticate(DCB *dcb)
|
||||
/* on successful authentication, set user into dcb field */
|
||||
if (MYSQL_AUTH_SUCCEEDED == auth_ret)
|
||||
{
|
||||
dcb->user = strdup(client_data->user);
|
||||
dcb->user = MXS_STRDUP_A(client_data->user);
|
||||
}
|
||||
else if (dcb->service->log_auth_warnings)
|
||||
{
|
||||
@ -200,7 +201,7 @@ mysql_auth_authenticate(DCB *dcb)
|
||||
/* let's free the auth_token now */
|
||||
if (client_data->auth_token)
|
||||
{
|
||||
free(client_data->auth_token);
|
||||
MXS_FREE(client_data->auth_token);
|
||||
client_data->auth_token = NULL;
|
||||
}
|
||||
}
|
||||
@ -236,7 +237,7 @@ mysql_auth_set_protocol_data(DCB *dcb, GWBUF *buf)
|
||||
CHK_PROTOCOL(protocol);
|
||||
if (dcb->data == NULL)
|
||||
{
|
||||
if (NULL == (client_data = (MYSQL_session *)calloc(1, sizeof(MYSQL_session))))
|
||||
if (NULL == (client_data = (MYSQL_session *)MXS_CALLOC(1, sizeof(MYSQL_session))))
|
||||
{
|
||||
return MYSQL_FAILED_AUTH;
|
||||
}
|
||||
@ -345,7 +346,7 @@ mysql_auth_set_client_data(
|
||||
(packet_length_used + client_data->auth_token_len))
|
||||
{
|
||||
/* Packet is large enough for authentication token */
|
||||
if (NULL != (client_data->auth_token = (uint8_t *)malloc(client_data->auth_token_len)))
|
||||
if (NULL != (client_data->auth_token = (uint8_t *)MXS_MALLOC(client_data->auth_token_len)))
|
||||
{
|
||||
/* The extra 1 is for the token length byte, just extracted*/
|
||||
memcpy(client_data->auth_token,
|
||||
@ -414,7 +415,7 @@ mysql_auth_is_client_ssl_capable(DCB *dcb)
|
||||
* gw_find_mysql_user_password_sha1
|
||||
*
|
||||
* The routine fetches an user from the MaxScale users' table
|
||||
* The users' table is dcb->service->users or a different one specified with void *repository
|
||||
* The users' table is dcb->listener->users or a different one specified with void *repository
|
||||
* The user lookup uses username,host and db name (if passed in connection or change user)
|
||||
*
|
||||
* If found the HEX password, representing sha1(sha1(password)), is converted in binary data and
|
||||
@ -428,20 +429,17 @@ mysql_auth_is_client_ssl_capable(DCB *dcb)
|
||||
*/
|
||||
int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_password, DCB *dcb)
|
||||
{
|
||||
SERVICE *service = NULL;
|
||||
struct sockaddr_in *client;
|
||||
char *user_password = NULL;
|
||||
MYSQL_USER_HOST key;
|
||||
MYSQL_session *client_data = NULL;
|
||||
|
||||
client_data = (MYSQL_session *) dcb->data;
|
||||
service = (SERVICE *) dcb->service;
|
||||
client = (struct sockaddr_in *) &dcb->ipv4;
|
||||
MYSQL_session *client_data = (MYSQL_session *) dcb->data;
|
||||
SERVICE *service = (SERVICE *) dcb->service;
|
||||
SERV_LISTENER *listener = dcb->listener;
|
||||
struct sockaddr_in *client = (struct sockaddr_in *) &dcb->ipv4;
|
||||
|
||||
MYSQL_USER_HOST key = {};
|
||||
key.user = username;
|
||||
memcpy(&key.ipv4, client, sizeof(struct sockaddr_in));
|
||||
key.netmask = 32;
|
||||
key.resource = client_data->db;
|
||||
|
||||
if (strlen(dcb->remote) < MYSQL_HOST_MAXLEN)
|
||||
{
|
||||
strcpy(key.hostname, dcb->remote);
|
||||
@ -455,7 +453,7 @@ int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_password,
|
||||
key.resource != NULL ? key.resource : "");
|
||||
|
||||
/* look for user@current_ipv4 now */
|
||||
user_password = mysql_users_fetch(service->users, &key);
|
||||
char *user_password = mysql_users_fetch(listener->users, &key);
|
||||
|
||||
if (!user_password)
|
||||
{
|
||||
@ -482,7 +480,7 @@ int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_password,
|
||||
key.ipv4.sin_addr.s_addr &= 0x00FFFFFF;
|
||||
key.netmask -= 8;
|
||||
|
||||
user_password = mysql_users_fetch(service->users, &key);
|
||||
user_password = mysql_users_fetch(listener->users, &key);
|
||||
|
||||
if (user_password)
|
||||
{
|
||||
@ -493,7 +491,7 @@ int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_password,
|
||||
key.ipv4.sin_addr.s_addr &= 0x0000FFFF;
|
||||
key.netmask -= 8;
|
||||
|
||||
user_password = mysql_users_fetch(service->users, &key);
|
||||
user_password = mysql_users_fetch(listener->users, &key);
|
||||
|
||||
if (user_password)
|
||||
{
|
||||
@ -504,7 +502,7 @@ int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_password,
|
||||
key.ipv4.sin_addr.s_addr &= 0x000000FF;
|
||||
key.netmask -= 8;
|
||||
|
||||
user_password = mysql_users_fetch(service->users, &key);
|
||||
user_password = mysql_users_fetch(listener->users, &key);
|
||||
|
||||
if (user_password)
|
||||
{
|
||||
@ -524,7 +522,7 @@ int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_password,
|
||||
key.user,
|
||||
dcb->remote);
|
||||
|
||||
user_password = mysql_users_fetch(service->users, &key);
|
||||
user_password = mysql_users_fetch(listener->users, &key);
|
||||
|
||||
if (user_password)
|
||||
{
|
||||
@ -723,9 +721,9 @@ check_db_name_after_auth(DCB *dcb, char *database, int auth_ret)
|
||||
if (database && strlen(database))
|
||||
{
|
||||
/* if database names are loaded we can check if db name exists */
|
||||
if (dcb->service->resources != NULL)
|
||||
if (dcb->listener->resources != NULL)
|
||||
{
|
||||
if (hashtable_fetch(dcb->service->resources, database))
|
||||
if (hashtable_fetch(dcb->listener->resources, database))
|
||||
{
|
||||
db_exists = 1;
|
||||
}
|
||||
@ -811,5 +809,5 @@ static int combined_auth_check(
|
||||
static void
|
||||
mysql_auth_free_client_data(DCB *dcb)
|
||||
{
|
||||
free(dcb->data);
|
||||
MXS_FREE(dcb->data);
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -12,7 +12,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file null_auth.c
|
||||
* @file null_auth_allow.c
|
||||
*
|
||||
* Null Authentication module for handling the checking of clients credentials
|
||||
* for protocols that do not have authentication, either temporarily or
|
||||
@ -22,6 +22,7 @@
|
||||
* Revision History
|
||||
* Date Who Description
|
||||
* 14/03/2016 Martin Brampton Initial version
|
||||
* 17/05/2016 Martin Brampton Renamed
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
154
server/modules/authenticator/null_auth_deny.c
Normal file
154
server/modules/authenticator/null_auth_deny.c
Normal file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
* Public License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file null_auth_deny.c
|
||||
*
|
||||
* Null Authentication module for handling the checking of clients credentials
|
||||
* for protocols that do not have authentication, either temporarily or
|
||||
* permanently. Always fails the authentication.
|
||||
*
|
||||
* @verbatim
|
||||
* Revision History
|
||||
* Date Who Description
|
||||
* 14/03/2016 Martin Brampton Initial version
|
||||
* 17/05/2016 Martin Brampton Version to fail, instead of succeed.
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
#include <gw_authenticator.h>
|
||||
#include <modinfo.h>
|
||||
#include <dcb.h>
|
||||
#include <buffer.h>
|
||||
|
||||
/* @see function load_module in load_utils.c for explanation of the following
|
||||
* lint directives.
|
||||
*/
|
||||
/*lint -e14 */
|
||||
MODULE_INFO info =
|
||||
{
|
||||
MODULE_API_AUTHENTICATOR,
|
||||
MODULE_GA,
|
||||
GWAUTHENTICATOR_VERSION,
|
||||
"The Null client authenticator implementation"
|
||||
};
|
||||
/*lint +e14 */
|
||||
|
||||
static char *version_str = "V1.0.0";
|
||||
|
||||
static int null_auth_set_protocol_data(DCB *dcb, GWBUF *buf);
|
||||
static bool null_auth_is_client_ssl_capable(DCB *dcb);
|
||||
static int null_auth_authenticate(DCB *dcb);
|
||||
static void null_auth_free_client_data(DCB *dcb);
|
||||
|
||||
/*
|
||||
* The "module object" for mysql client authenticator module.
|
||||
*/
|
||||
static GWAUTHENTICATOR MyObject =
|
||||
{
|
||||
null_auth_set_protocol_data, /* Extract data into structure */
|
||||
null_auth_is_client_ssl_capable, /* Check if client supports SSL */
|
||||
null_auth_authenticate, /* Authenticate user credentials */
|
||||
null_auth_free_client_data, /* Free the client data held in DCB */
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of the mandatory version entry point
|
||||
*
|
||||
* @return version string of the module
|
||||
*
|
||||
* @see function load_module in load_utils.c for explanation of the following
|
||||
* lint directives.
|
||||
*/
|
||||
/*lint -e14 */
|
||||
char* version()
|
||||
{
|
||||
return version_str;
|
||||
}
|
||||
|
||||
/**
|
||||
* The module initialisation routine, called when the module
|
||||
* is first loaded.
|
||||
*/
|
||||
void ModuleInit()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* The module entry point routine. It is this routine that
|
||||
* must populate the structure that is referred to as the
|
||||
* "module object", this is a structure with the set of
|
||||
* external entry points for this module.
|
||||
*
|
||||
* @return The module object
|
||||
*/
|
||||
GWAUTHENTICATOR* GetModuleObject()
|
||||
{
|
||||
return &MyObject;
|
||||
}
|
||||
/*lint +e14 */
|
||||
|
||||
/**
|
||||
* @brief Null authentication of a user.
|
||||
*
|
||||
* Always returns success
|
||||
*
|
||||
* @param dcb Request handler DCB connected to the client
|
||||
* @return Authentication status - always 1 to denote failure
|
||||
*/
|
||||
static int
|
||||
null_auth_authenticate(DCB *dcb)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transfer data from the authentication request to the DCB.
|
||||
*
|
||||
* Does not actually transfer any data
|
||||
*
|
||||
* @param dcb Request handler DCB connected to the client
|
||||
* @param buffer Pointer to pointer to buffer containing data from client
|
||||
* @return Authentication status - always 0 to indicate success
|
||||
*/
|
||||
static int
|
||||
null_auth_set_protocol_data(DCB *dcb, GWBUF *buf)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determine whether the client is SSL capable
|
||||
*
|
||||
* Always say that client is SSL capable. The null authenticator cannot be
|
||||
* used in a context where the client is not SSL capable.
|
||||
*
|
||||
* @param dcb Request handler DCB connected to the client
|
||||
* @return Boolean indicating whether client is SSL capable - always true
|
||||
*/
|
||||
static bool
|
||||
null_auth_is_client_ssl_capable(DCB *dcb)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Free the client data pointed to by the passed DCB.
|
||||
*
|
||||
* The null authenticator does not allocate any data, so nothing to do.
|
||||
*
|
||||
* @param dcb Request handler DCB connected to the client
|
||||
*/
|
||||
static void
|
||||
null_auth_free_client_data(DCB *dcb) {}
|
@ -1,64 +1,66 @@
|
||||
if(BUILD_RABBITMQ)
|
||||
if(RABBITMQ_FOUND)
|
||||
include_directories(${RABBITMQ_HEADERS})
|
||||
add_library(mqfilter SHARED mqfilter.c)
|
||||
target_link_libraries(mqfilter maxscale-common ${RABBITMQ_LIBRARIES})
|
||||
add_dependencies(mqfilter pcre2)
|
||||
install(TARGETS mqfilter DESTINATION ${MAXSCALE_LIBDIR})
|
||||
else()
|
||||
message(WARNING "Could not find librabbitmq, the mqfilter will not be built.")
|
||||
endif()
|
||||
find_package(RabbitMQ)
|
||||
if(RABBITMQ_FOUND)
|
||||
include_directories(${RABBITMQ_HEADERS})
|
||||
add_library(mqfilter SHARED mqfilter.c)
|
||||
target_link_libraries(mqfilter maxscale-common ${RABBITMQ_LIBRARIES})
|
||||
add_dependencies(mqfilter pcre2)
|
||||
set_target_properties(mqfilter PROPERTIES VERSION "1.0.2")
|
||||
install_module(mqfilter core)
|
||||
else()
|
||||
message(WARNING "Could not find librabbitmq, the mqfilter will not be built.")
|
||||
endif()
|
||||
|
||||
add_library(regexfilter SHARED regexfilter.c)
|
||||
target_link_libraries(regexfilter maxscale-common)
|
||||
add_dependencies(regexfilter pcre2)
|
||||
set_target_properties(regexfilter PROPERTIES VERSION "1.1.0")
|
||||
install(TARGETS regexfilter DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(regexfilter core)
|
||||
|
||||
add_library(testfilter SHARED testfilter.c)
|
||||
target_link_libraries(testfilter maxscale-common)
|
||||
set_target_properties(testfilter PROPERTIES VERSION "1.0.0")
|
||||
install(TARGETS testfilter DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(testfilter core)
|
||||
|
||||
add_library(gatekeeper SHARED gatekeeper.c)
|
||||
target_link_libraries(gatekeeper maxscale-common)
|
||||
set_target_properties(gatekeeper PROPERTIES VERSION "1.0.0")
|
||||
install_module(gatekeeper experimental)
|
||||
|
||||
add_library(qlafilter SHARED qlafilter.c)
|
||||
target_link_libraries(qlafilter maxscale-common)
|
||||
set_target_properties(qlafilter PROPERTIES VERSION "1.1.1")
|
||||
install(TARGETS qlafilter DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(qlafilter core)
|
||||
|
||||
add_library(tee SHARED tee.c)
|
||||
target_link_libraries(tee maxscale-common)
|
||||
set_target_properties(tee PROPERTIES VERSION "1.0.0")
|
||||
install(TARGETS tee DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(tee core)
|
||||
|
||||
add_library(topfilter SHARED topfilter.c)
|
||||
target_link_libraries(topfilter maxscale-common)
|
||||
set_target_properties(topfilter PROPERTIES VERSION "1.0.1")
|
||||
install(TARGETS topfilter DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(topfilter core)
|
||||
|
||||
if(BUILD_LUAFILTER)
|
||||
find_package(Lua)
|
||||
if(LUA_FOUND)
|
||||
include_directories(${LUA_INCLUDE_DIR})
|
||||
add_library(luafilter SHARED luafilter.c)
|
||||
target_link_libraries(luafilter maxscale-common ${LUA_LIBRARIES})
|
||||
install(TARGETS luafilter DESTINATION ${MAXSCALE_LIBDIR})
|
||||
else()
|
||||
message(STATUS "Lua was not found, luafilter will not be built.")
|
||||
endif()
|
||||
find_package(Lua)
|
||||
if(LUA_FOUND)
|
||||
include_directories(${LUA_INCLUDE_DIR})
|
||||
add_library(luafilter SHARED luafilter.c)
|
||||
set_target_properties(luafilter PROPERTIES VERSION "1.0.0")
|
||||
target_link_libraries(luafilter maxscale-common ${LUA_LIBRARIES})
|
||||
install_module(luafilter experimental)
|
||||
else()
|
||||
message(STATUS "Lua was not found, luafilter will not be built.")
|
||||
endif()
|
||||
|
||||
add_library(namedserverfilter SHARED namedserverfilter.c)
|
||||
target_link_libraries(namedserverfilter maxscale-common)
|
||||
set_target_properties(namedserverfilter PROPERTIES VERSION "1.1.0")
|
||||
install(TARGETS namedserverfilter DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(namedserverfilter core)
|
||||
|
||||
if(BUILD_SLAVELAG)
|
||||
add_library(slavelag SHARED slavelag.c)
|
||||
target_link_libraries(slavelag maxscale-common)
|
||||
set_target_properties(slavelag PROPERTIES VERSION "1.1.0")
|
||||
install(TARGETS slavelag DESTINATION ${MAXSCALE_LIBDIR})
|
||||
endif()
|
||||
add_library(ccrfilter SHARED ccrfilter.c)
|
||||
target_link_libraries(ccrfilter maxscale-common)
|
||||
set_target_properties(ccrfilter PROPERTIES VERSION "1.0.0")
|
||||
install_module(ccrfilter experimental)
|
||||
|
||||
add_subdirectory(hint)
|
||||
add_subdirectory(dbfwfilter)
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -20,9 +20,10 @@
|
||||
#include <hint.h>
|
||||
#include <query_classifier.h>
|
||||
#include <regex.h>
|
||||
#include <maxscale/alloc.h>
|
||||
|
||||
/**
|
||||
* @file slavelag.c - a very simple filter designed to send queries to the
|
||||
* @file ccrfilter.c - a very simple filter designed to send queries to the
|
||||
* master server after data modification has occurred. This is done to prevent
|
||||
* replication lag affecting the outcome of a select query.
|
||||
*
|
||||
@ -42,6 +43,7 @@
|
||||
*
|
||||
* Date Who Description
|
||||
* 03/03/2015 Markus Mäkelä Written for demonstrative purposes
|
||||
* 10/08/2016 Markus Mäkelä Cleaned up code and renamed to ccrfilter
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
@ -77,6 +79,8 @@ static FILTER_OBJECT MyObject =
|
||||
diagnostic,
|
||||
};
|
||||
|
||||
#define CCR_DEFAULT_TIME 60
|
||||
|
||||
typedef struct lagstats
|
||||
{
|
||||
int n_add_count; /*< No. of statements diverted based on count */
|
||||
@ -99,7 +103,7 @@ typedef struct
|
||||
LAGSTATS stats;
|
||||
regex_t re; /* Compiled regex text of match */
|
||||
regex_t nore; /* Compiled regex text of ignore */
|
||||
} LAG_INSTANCE;
|
||||
} CCR_INSTANCE;
|
||||
|
||||
/**
|
||||
* The session structure for this filter
|
||||
@ -108,9 +112,8 @@ typedef struct
|
||||
{
|
||||
DOWNSTREAM down; /*< The downstream filter */
|
||||
int hints_left; /*< Number of hints left to add to queries*/
|
||||
time_t last_modification; /*< Time of the last modifying operation */
|
||||
int active; /*< Is filter active */
|
||||
} LAG_SESSION;
|
||||
time_t last_modification; /*< Time of the last data modifying operation */
|
||||
} CCR_SESSION;
|
||||
|
||||
/**
|
||||
* Implementation of the mandatory version entry point
|
||||
@ -161,14 +164,14 @@ GetModuleObject()
|
||||
static FILTER *
|
||||
createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
LAG_INSTANCE *my_instance;
|
||||
CCR_INSTANCE *my_instance;
|
||||
int i;
|
||||
int cflags = 0;
|
||||
int cflags = REG_ICASE;
|
||||
|
||||
if ((my_instance = calloc(1, sizeof(LAG_INSTANCE))) != NULL)
|
||||
if ((my_instance = MXS_CALLOC(1, sizeof(CCR_INSTANCE))) != NULL)
|
||||
{
|
||||
my_instance->count = 0;
|
||||
my_instance->time = 0;
|
||||
my_instance->time = CCR_DEFAULT_TIME;
|
||||
my_instance->stats.n_add_count = 0;
|
||||
my_instance->stats.n_add_time = 0;
|
||||
my_instance->stats.n_modified = 0;
|
||||
@ -187,15 +190,15 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "match"))
|
||||
{
|
||||
my_instance->match = strdup(params[i]->value);
|
||||
my_instance->match = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "ignore"))
|
||||
{
|
||||
my_instance->nomatch = strdup(params[i]->value);
|
||||
my_instance->nomatch = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else
|
||||
else if (!filter_standard_parameter(params[i]->name))
|
||||
{
|
||||
MXS_ERROR("lagfilter: Unexpected parameter '%s'.\n", params[i]->name);
|
||||
MXS_ERROR("ccrfilter: Unexpected parameter '%s'.\n", params[i]->name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -211,9 +214,13 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
cflags &= ~REG_ICASE;
|
||||
}
|
||||
else if (!strcasecmp(options[i], "extended"))
|
||||
{
|
||||
cflags |= REG_EXTENDED;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR("lagfilter: unsupported option '%s'.", options[i]);
|
||||
MXS_ERROR("ccrfilter: unsupported option '%s'.", options[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -222,7 +229,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
if (regcomp(&my_instance->re, my_instance->match, cflags))
|
||||
{
|
||||
MXS_ERROR("lagfilter: Failed to compile regex '%s'.", my_instance->match);
|
||||
MXS_ERROR("ccrfilter: Failed to compile regex '%s'.", my_instance->match);
|
||||
}
|
||||
}
|
||||
|
||||
@ -230,7 +237,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
if (regcomp(&my_instance->nore, my_instance->nomatch, cflags))
|
||||
{
|
||||
MXS_ERROR("lagfilter: Failed to compile regex '%s'.", my_instance->nomatch);
|
||||
MXS_ERROR("ccrfilter: Failed to compile regex '%s'.", my_instance->nomatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -249,12 +256,11 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
static void *
|
||||
newSession(FILTER *instance, SESSION *session)
|
||||
{
|
||||
LAG_INSTANCE *my_instance = (LAG_INSTANCE *)instance;
|
||||
LAG_SESSION *my_session;
|
||||
CCR_INSTANCE *my_instance = (CCR_INSTANCE *)instance;
|
||||
CCR_SESSION *my_session = MXS_MALLOC(sizeof(CCR_SESSION));
|
||||
|
||||
if ((my_session = malloc(sizeof(LAG_SESSION))) != NULL)
|
||||
if (my_session)
|
||||
{
|
||||
my_session->active = 1;
|
||||
my_session->hints_left = 0;
|
||||
my_session->last_modification = 0;
|
||||
}
|
||||
@ -283,7 +289,7 @@ closeSession(FILTER *instance, void *session)
|
||||
static void
|
||||
freeSession(FILTER *instance, void *session)
|
||||
{
|
||||
free(session);
|
||||
MXS_FREE(session);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -296,7 +302,7 @@ freeSession(FILTER *instance, void *session)
|
||||
static void
|
||||
setDownstream(FILTER *instance, void *session, DOWNSTREAM *downstream)
|
||||
{
|
||||
LAG_SESSION *my_session = (LAG_SESSION *)session;
|
||||
CCR_SESSION *my_session = (CCR_SESSION *)session;
|
||||
|
||||
my_session->down = *downstream;
|
||||
}
|
||||
@ -318,19 +324,23 @@ setDownstream(FILTER *instance, void *session, DOWNSTREAM *downstream)
|
||||
static int
|
||||
routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
{
|
||||
LAG_INSTANCE *my_instance = (LAG_INSTANCE *)instance;
|
||||
LAG_SESSION *my_session = (LAG_SESSION *)session;
|
||||
CCR_INSTANCE *my_instance = (CCR_INSTANCE *)instance;
|
||||
CCR_SESSION *my_session = (CCR_SESSION *)session;
|
||||
char *sql;
|
||||
time_t now = time(NULL);
|
||||
|
||||
if (modutil_is_SQL(queue))
|
||||
{
|
||||
if (queue->next != NULL)
|
||||
if (queue->next)
|
||||
{
|
||||
queue = gwbuf_make_contiguous(queue);
|
||||
}
|
||||
|
||||
if (qc_get_operation(queue) & (QUERY_OP_DELETE | QUERY_OP_INSERT | QUERY_OP_UPDATE))
|
||||
/**
|
||||
* Not a simple SELECT statement, possibly modifies data. If we're processing a statement
|
||||
* with unknown query type, the safest thing to do is to treat it as a data modifying statement.
|
||||
*/
|
||||
if ((qc_get_operation(queue) & ~QUERY_OP_SELECT) != 0)
|
||||
{
|
||||
if ((sql = modutil_get_SQL(queue)) != NULL)
|
||||
{
|
||||
@ -346,7 +356,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
}
|
||||
}
|
||||
|
||||
free(sql);
|
||||
MXS_FREE(sql);
|
||||
}
|
||||
}
|
||||
else if (my_session->hints_left > 0)
|
||||
@ -381,12 +391,23 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
static void
|
||||
diagnostic(FILTER *instance, void *fsession, DCB *dcb)
|
||||
{
|
||||
LAG_INSTANCE *my_instance = (LAG_INSTANCE *)instance;
|
||||
LAG_SESSION *my_session = (LAG_SESSION *)fsession;
|
||||
CCR_INSTANCE *my_instance = (CCR_INSTANCE *)instance;
|
||||
CCR_SESSION *my_session = (CCR_SESSION *)fsession;
|
||||
|
||||
dcb_printf(dcb, "Configuration:\n\tCount: %d\n", my_instance->count);
|
||||
dcb_printf(dcb, "\tTime: %d seconds\n\n", my_instance->time);
|
||||
dcb_printf(dcb, "Statistics:\n");
|
||||
dcb_printf(dcb, "\tTime: %d seconds\n", my_instance->time);
|
||||
|
||||
if (my_instance->match)
|
||||
{
|
||||
dcb_printf(dcb, "\tMatch regex: %s\n", my_instance->match);
|
||||
}
|
||||
|
||||
if (my_instance->nomatch)
|
||||
{
|
||||
dcb_printf(dcb, "\tExclude regex: %s\n", my_instance->nomatch);
|
||||
}
|
||||
|
||||
dcb_printf(dcb, "\nStatistics:\n");
|
||||
dcb_printf(dcb, "\tNo. of data modifications: %d\n", my_instance->stats.n_modified);
|
||||
dcb_printf(dcb, "\tNo. of hints added based on count: %d\n", my_instance->stats.n_add_count);
|
||||
dcb_printf(dcb, "\tNo. of hints added based on time: %d\n", my_instance->stats.n_add_time);
|
@ -9,13 +9,13 @@ if(BISON_FOUND AND FLEX_FOUND)
|
||||
add_library(dbfwfilter SHARED dbfwfilter.c ${BISON_ruleparser_OUTPUTS} ${FLEX_token_OUTPUTS})
|
||||
target_link_libraries(dbfwfilter maxscale-common)
|
||||
set_target_properties(dbfwfilter PROPERTIES VERSION "1.0.0")
|
||||
install(TARGETS dbfwfilter DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(dbfwfilter core)
|
||||
|
||||
if(BUILD_TOOLS)
|
||||
add_executable(dbfwruleparser dbfwfilter.c ${BISON_ruleparser_OUTPUTS} ${FLEX_token_OUTPUTS})
|
||||
target_compile_definitions(dbfwruleparser PUBLIC "BUILD_RULE_PARSER")
|
||||
target_link_libraries(dbfwruleparser maxscale-common)
|
||||
install(TARGETS dbfwruleparser DESTINATION ${MAXSCALE_BINDIR})
|
||||
install_module(dbfwruleparser core)
|
||||
endif()
|
||||
else()
|
||||
message(FATAL_ERROR "Could not find Bison or Flex: ${BISON_EXECUTABLE} ${FLEX_EXECUTABLE}")
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -79,6 +79,7 @@
|
||||
#include <ruleparser.yy.h>
|
||||
#include <lex.yy.h>
|
||||
#include <stdlib.h>
|
||||
#include <maxscale/alloc.h>
|
||||
|
||||
/** Older versions of Bison don't include the parsing function in the header */
|
||||
#ifndef dbfw_yyparse
|
||||
@ -291,17 +292,16 @@ bool parse_limit_queries(FW_INSTANCE* instance, RULE* ruledef, const char* rule,
|
||||
*/
|
||||
static STRLINK* strlink_push(STRLINK* head, const char* value)
|
||||
{
|
||||
STRLINK* link = malloc(sizeof(STRLINK));
|
||||
STRLINK* link = MXS_MALLOC(sizeof(STRLINK));
|
||||
|
||||
if (link && (link->value = strdup(value)))
|
||||
if (link && (link->value = MXS_STRDUP(value)))
|
||||
{
|
||||
link->next = head;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(link);
|
||||
MXS_FREE(link);
|
||||
link = NULL;
|
||||
MXS_ERROR("dbfwfilter: Memory allocation failed.");
|
||||
}
|
||||
return link;
|
||||
}
|
||||
@ -316,8 +316,8 @@ static STRLINK* strlink_pop(STRLINK* head)
|
||||
if (head)
|
||||
{
|
||||
STRLINK* next = head->next;
|
||||
free(head->value);
|
||||
free(head);
|
||||
MXS_FREE(head->value);
|
||||
MXS_FREE(head);
|
||||
return next;
|
||||
}
|
||||
return NULL;
|
||||
@ -333,8 +333,8 @@ static void strlink_free(STRLINK* head)
|
||||
{
|
||||
STRLINK* tmp = head;
|
||||
head = head->next;
|
||||
free(tmp->value);
|
||||
free(tmp);
|
||||
MXS_FREE(tmp->value);
|
||||
MXS_FREE(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -366,7 +366,7 @@ static STRLINK* strlink_reverse_clone(STRLINK* head)
|
||||
|
||||
static RULELIST* rulelist_push(RULELIST *head, RULE *rule)
|
||||
{
|
||||
RULELIST *rval = malloc(sizeof(RULELIST));
|
||||
RULELIST *rval = MXS_MALLOC(sizeof(RULELIST));
|
||||
|
||||
if (rval)
|
||||
{
|
||||
@ -385,7 +385,8 @@ static void* rulelist_clone(void* fval)
|
||||
|
||||
while (ptr)
|
||||
{
|
||||
RULELIST* tmp = (RULELIST*) malloc(sizeof(RULELIST));
|
||||
RULELIST* tmp = (RULELIST*) MXS_MALLOC(sizeof(RULELIST));
|
||||
MXS_ABORT_IF_NULL(tmp);
|
||||
tmp->next = rule;
|
||||
tmp->rule = ptr->rule;
|
||||
rule = tmp;
|
||||
@ -402,22 +403,21 @@ static void* rulelist_free(void* fval)
|
||||
{
|
||||
RULELIST *tmp = ptr;
|
||||
ptr = ptr->next;
|
||||
free(tmp);
|
||||
MXS_FREE(tmp);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void* huserfree(void* fval)
|
||||
static void huserfree(void* fval)
|
||||
{
|
||||
USER* value = (USER*) fval;
|
||||
|
||||
rulelist_free(value->rules_and);
|
||||
rulelist_free(value->rules_or);
|
||||
rulelist_free(value->rules_strict_and);
|
||||
free(value->qs_limit);
|
||||
free(value->name);
|
||||
free(value);
|
||||
return NULL;
|
||||
MXS_FREE(value->qs_limit);
|
||||
MXS_FREE(value->name);
|
||||
MXS_FREE(value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -622,7 +622,7 @@ static TIMERANGE* parse_time(const char* str)
|
||||
CHK_TIMES((&start));
|
||||
CHK_TIMES((&end));
|
||||
|
||||
tr = (TIMERANGE*) malloc(sizeof(TIMERANGE));
|
||||
tr = (TIMERANGE*) MXS_MALLOC(sizeof(TIMERANGE));
|
||||
|
||||
if (tr)
|
||||
{
|
||||
@ -630,10 +630,6 @@ static TIMERANGE* parse_time(const char* str)
|
||||
tr->end = end;
|
||||
tr->next = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR("dbfwfilter: malloc returned NULL.");
|
||||
}
|
||||
}
|
||||
}
|
||||
return tr;
|
||||
@ -649,7 +645,8 @@ TIMERANGE* split_reverse_time(TIMERANGE* tr)
|
||||
{
|
||||
TIMERANGE* tmp = NULL;
|
||||
|
||||
tmp = (TIMERANGE*) calloc(1, sizeof(TIMERANGE));
|
||||
tmp = (TIMERANGE*) MXS_CALLOC(1, sizeof(TIMERANGE));
|
||||
MXS_ABORT_IF_NULL(tmp);
|
||||
tmp->next = tr;
|
||||
tmp->start.tm_hour = 0;
|
||||
tmp->start.tm_min = 0;
|
||||
@ -724,15 +721,14 @@ static bool apply_rule_to_user(FW_INSTANCE *instance, char *username,
|
||||
if ((user = (USER*) hashtable_fetch(instance->htable, username)) == NULL)
|
||||
{
|
||||
/**New user*/
|
||||
if ((user = (USER*) calloc(1, sizeof(USER))) == NULL)
|
||||
if ((user = (USER*) MXS_CALLOC(1, sizeof(USER))) == NULL)
|
||||
{
|
||||
MXS_ERROR("dbfwfilter: failed to allocate memory when parsing rules.");
|
||||
return false;
|
||||
}
|
||||
spinlock_init(&user->lock);
|
||||
}
|
||||
|
||||
user->name = (char*) strdup(username);
|
||||
user->name = (char*) MXS_STRDUP_A(username);
|
||||
user->qs_limit = NULL;
|
||||
RULELIST *tl = (RULELIST*) rulelist_clone(rulelist);
|
||||
RULELIST *tail = tl;
|
||||
@ -775,7 +771,7 @@ void tr_free(TIMERANGE* tr)
|
||||
{
|
||||
tmp = node;
|
||||
node = node->next;
|
||||
free(tmp);
|
||||
MXS_FREE(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -874,9 +870,9 @@ void dbfw_yyerror(void* scanner, const char* error)
|
||||
bool create_rule(void* scanner, const char* name)
|
||||
{
|
||||
bool rval = true;
|
||||
RULE *ruledef = malloc(sizeof(RULE));
|
||||
RULE *ruledef = MXS_MALLOC(sizeof(RULE));
|
||||
|
||||
if (ruledef && (ruledef->name = strdup(name)))
|
||||
if (ruledef && (ruledef->name = MXS_STRDUP(name)))
|
||||
{
|
||||
ruledef->type = RT_UNDEFINED;
|
||||
ruledef->on_queries = QUERY_OP_UNDEFINED;
|
||||
@ -890,8 +886,7 @@ bool create_rule(void* scanner, const char* name)
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR("Memory allocation failed when creating rule '%s'.", name);
|
||||
free(ruledef);
|
||||
MXS_FREE(ruledef);
|
||||
rval = false;
|
||||
}
|
||||
|
||||
@ -911,7 +906,7 @@ static void free_rules(RULE* rule)
|
||||
{
|
||||
TIMERANGE *tr = rule->active;
|
||||
rule->active = rule->active->next;
|
||||
free(tr);
|
||||
MXS_FREE(tr);
|
||||
}
|
||||
|
||||
switch (rule->type)
|
||||
@ -921,7 +916,7 @@ static void free_rules(RULE* rule)
|
||||
break;
|
||||
|
||||
case RT_THROTTLE:
|
||||
free(rule->data);
|
||||
MXS_FREE(rule->data);
|
||||
break;
|
||||
|
||||
case RT_REGEX:
|
||||
@ -932,7 +927,7 @@ static void free_rules(RULE* rule)
|
||||
break;
|
||||
}
|
||||
|
||||
free(rule->name);
|
||||
MXS_FREE(rule->name);
|
||||
rule = tmp;
|
||||
}
|
||||
}
|
||||
@ -1021,9 +1016,9 @@ bool create_user_templates(void* scanner)
|
||||
|
||||
while (user)
|
||||
{
|
||||
user_template_t* newtemp = malloc(sizeof(user_template_t));
|
||||
user_template_t* newtemp = MXS_MALLOC(sizeof(user_template_t));
|
||||
STRLINK* tmp;
|
||||
if (newtemp && (newtemp->name = strdup(user->value)) &&
|
||||
if (newtemp && (newtemp->name = MXS_STRDUP(user->value)) &&
|
||||
(newtemp->rulenames = strlink_reverse_clone(rstack->active_rules)))
|
||||
{
|
||||
newtemp->type = rstack->active_mode;
|
||||
@ -1034,13 +1029,12 @@ bool create_user_templates(void* scanner)
|
||||
{
|
||||
if (newtemp)
|
||||
{
|
||||
free(newtemp->name);
|
||||
free(newtemp);
|
||||
MXS_FREE(newtemp->name);
|
||||
MXS_FREE(newtemp);
|
||||
}
|
||||
free(templates->name);
|
||||
MXS_FREE(templates->name);
|
||||
strlink_free(templates->rulenames);
|
||||
free(templates);
|
||||
MXS_ERROR("Memory allocation failed when processing rule file users definitions.");
|
||||
MXS_FREE(templates);
|
||||
return false;
|
||||
}
|
||||
user = user->next;
|
||||
@ -1063,8 +1057,8 @@ void free_user_templates(user_template_t *templates)
|
||||
user_template_t *tmp = templates;
|
||||
templates = templates->next;
|
||||
strlink_free(tmp->rulenames);
|
||||
free(tmp->name);
|
||||
free(tmp);
|
||||
MXS_FREE(tmp->name);
|
||||
MXS_FREE(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1143,7 +1137,7 @@ bool define_limit_queries_rule(void* scanner, int max, int timeperiod, int holdo
|
||||
{
|
||||
struct parser_stack* rstack = dbfw_yyget_extra((yyscan_t) scanner);
|
||||
ss_dassert(rstack);
|
||||
QUERYSPEED* qs = malloc(sizeof(QUERYSPEED));
|
||||
QUERYSPEED* qs = MXS_MALLOC(sizeof(QUERYSPEED));
|
||||
|
||||
if (qs)
|
||||
{
|
||||
@ -1153,10 +1147,6 @@ bool define_limit_queries_rule(void* scanner, int max, int timeperiod, int holdo
|
||||
rstack->rule->type = RT_THROTTLE;
|
||||
rstack->rule->data = qs;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR("dbfwfilter: Memory allocation failed when adding limit_queries rule.");
|
||||
}
|
||||
|
||||
return qs != NULL;
|
||||
}
|
||||
@ -1239,7 +1229,7 @@ static bool process_user_templates(FW_INSTANCE *instance, user_template_t *templ
|
||||
|
||||
if (user == NULL)
|
||||
{
|
||||
if ((user = malloc(sizeof(USER))) && (user->name = strdup(templates->name)))
|
||||
if ((user = MXS_MALLOC(sizeof(USER))) && (user->name = MXS_STRDUP(templates->name)))
|
||||
{
|
||||
user->rules_and = NULL;
|
||||
user->rules_or = NULL;
|
||||
@ -1249,11 +1239,9 @@ static bool process_user_templates(FW_INSTANCE *instance, user_template_t *templ
|
||||
}
|
||||
else
|
||||
{
|
||||
free(user);
|
||||
MXS_FREE(user);
|
||||
rval = false;
|
||||
break;
|
||||
MXS_ERROR("Memory allocation failed when creating user '%s'.",
|
||||
templates->name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1382,23 +1370,22 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
char *filename = NULL;
|
||||
bool err = false;
|
||||
|
||||
if ((my_instance = calloc(1, sizeof(FW_INSTANCE))) == NULL)
|
||||
if ((my_instance = MXS_CALLOC(1, sizeof(FW_INSTANCE))) == NULL)
|
||||
{
|
||||
free(my_instance);
|
||||
MXS_ERROR("Memory allocation for firewall filter failed.");
|
||||
MXS_FREE(my_instance);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
spinlock_init(&my_instance->lock);
|
||||
|
||||
if ((ht = hashtable_alloc(100, simple_str_hash, strcmp)) == NULL)
|
||||
if ((ht = hashtable_alloc(100, hashtable_item_strhash, hashtable_item_strcmp)) == NULL)
|
||||
{
|
||||
MXS_ERROR("Unable to allocate hashtable.");
|
||||
free(my_instance);
|
||||
MXS_FREE(my_instance);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hashtable_memory_fns(ht, (HASHMEMORYFN) strdup, NULL, (HASHMEMORYFN) free, huserfree);
|
||||
hashtable_memory_fns(ht, hashtable_item_strdup, NULL, hashtable_item_free, huserfree);
|
||||
|
||||
my_instance->htable = ht;
|
||||
my_instance->action = FW_ACTION_BLOCK;
|
||||
@ -1459,7 +1446,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
if (err || !process_rule_file(filename, my_instance))
|
||||
{
|
||||
hashtable_free(my_instance->htable);
|
||||
free(my_instance);
|
||||
MXS_FREE(my_instance);
|
||||
my_instance = NULL;
|
||||
}
|
||||
|
||||
@ -1478,7 +1465,7 @@ newSession(FILTER *instance, SESSION *session)
|
||||
{
|
||||
FW_SESSION *my_session;
|
||||
|
||||
if ((my_session = calloc(1, sizeof(FW_SESSION))) == NULL)
|
||||
if ((my_session = MXS_CALLOC(1, sizeof(FW_SESSION))) == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@ -1510,9 +1497,9 @@ freeSession(FILTER *instance, void *session)
|
||||
FW_SESSION *my_session = (FW_SESSION *) session;
|
||||
if (my_session->errmsg)
|
||||
{
|
||||
free(my_session->errmsg);
|
||||
MXS_FREE(my_session->errmsg);
|
||||
}
|
||||
free(my_session);
|
||||
MXS_FREE(my_session);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1555,11 +1542,10 @@ GWBUF* gen_dummy_error(FW_SESSION* session, char* msg)
|
||||
dcb = session->session->client_dcb;
|
||||
mysql_session = (MYSQL_session*) dcb->data;
|
||||
errlen = msg != NULL ? strlen(msg) : 0;
|
||||
errmsg = (char*) malloc((512 + errlen) * sizeof(char));
|
||||
errmsg = (char*) MXS_MALLOC((512 + errlen) * sizeof(char));
|
||||
|
||||
if (errmsg == NULL)
|
||||
{
|
||||
MXS_ERROR("Memory allocation failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1582,7 +1568,7 @@ GWBUF* gen_dummy_error(FW_SESSION* session, char* msg)
|
||||
}
|
||||
|
||||
buf = modutil_create_mysql_err_msg(1, 0, 1141, "HY000", (const char*) errmsg);
|
||||
free(errmsg);
|
||||
MXS_FREE(errmsg);
|
||||
|
||||
return buf;
|
||||
}
|
||||
@ -1679,7 +1665,7 @@ static char* create_parse_error(FW_INSTANCE* my_instance,
|
||||
{
|
||||
char msgbuf[len + 1]; // +1 for the "."
|
||||
sprintf(msgbuf, "%s.", message);
|
||||
msg = strdup(msgbuf);
|
||||
msg = MXS_STRDUP_A(msgbuf);
|
||||
|
||||
if (my_instance->action == FW_ACTION_ALLOW)
|
||||
{
|
||||
@ -1799,7 +1785,7 @@ bool rule_matches(FW_INSTANCE* my_instance,
|
||||
pcre2_match_data_free(mdata);
|
||||
if (matches)
|
||||
{
|
||||
msg = strdup("Permission denied, query matched regular expression.");
|
||||
msg = MXS_STRDUP_A("Permission denied, query matched regular expression.");
|
||||
MXS_INFO("dbfwfilter: rule '%s': regex matched on query", rulelist->rule->name);
|
||||
goto queryresolved;
|
||||
}
|
||||
@ -1815,7 +1801,7 @@ bool rule_matches(FW_INSTANCE* my_instance,
|
||||
case RT_PERMISSION:
|
||||
{
|
||||
matches = true;
|
||||
msg = strdup("Permission denied at this time.");
|
||||
msg = MXS_STRDUP_A("Permission denied at this time.");
|
||||
char buffer[32]; // asctime documentation requires 26
|
||||
asctime_r(&tm_now, buffer);
|
||||
MXS_INFO("dbfwfilter: rule '%s': query denied at: %s", rulelist->rule->name, buffer);
|
||||
@ -1843,15 +1829,15 @@ bool rule_matches(FW_INSTANCE* my_instance,
|
||||
sprintf(emsg, "Permission denied to column '%s'.", strln->value);
|
||||
MXS_INFO("dbfwfilter: rule '%s': query targets forbidden column: %s",
|
||||
rulelist->rule->name, strln->value);
|
||||
msg = strdup(emsg);
|
||||
free(where);
|
||||
msg = MXS_STRDUP_A(emsg);
|
||||
MXS_FREE(where);
|
||||
goto queryresolved;
|
||||
}
|
||||
strln = strln->next;
|
||||
}
|
||||
tok = strtok_r(NULL, ",", &saveptr);
|
||||
}
|
||||
free(where);
|
||||
MXS_FREE(where);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1869,13 +1855,13 @@ bool rule_matches(FW_INSTANCE* my_instance,
|
||||
if (strchr(strptr, '*'))
|
||||
{
|
||||
matches = true;
|
||||
msg = strdup("Usage of wildcard denied.");
|
||||
msg = MXS_STRDUP_A("Usage of wildcard denied.");
|
||||
MXS_INFO("dbfwfilter: rule '%s': query contains a wildcard.",
|
||||
rulelist->rule->name);
|
||||
free(where);
|
||||
MXS_FREE(where);
|
||||
goto queryresolved;
|
||||
}
|
||||
free(where);
|
||||
MXS_FREE(where);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1906,7 +1892,8 @@ bool rule_matches(FW_INSTANCE* my_instance,
|
||||
{
|
||||
|
||||
/**No match found*/
|
||||
queryspeed = (QUERYSPEED*) calloc(1, sizeof(QUERYSPEED));
|
||||
queryspeed = (QUERYSPEED*) MXS_CALLOC(1, sizeof(QUERYSPEED));
|
||||
MXS_ABORT_IF_NULL(queryspeed);
|
||||
queryspeed->period = rule_qs->period;
|
||||
queryspeed->cooldown = rule_qs->cooldown;
|
||||
queryspeed->limit = rule_qs->limit;
|
||||
@ -1926,7 +1913,7 @@ bool rule_matches(FW_INSTANCE* my_instance,
|
||||
sprintf(emsg, "Queries denied for %f seconds", blocked_for);
|
||||
MXS_INFO("dbfwfilter: rule '%s': user denied for %f seconds",
|
||||
rulelist->rule->name, blocked_for);
|
||||
msg = strdup(emsg);
|
||||
msg = MXS_STRDUP_A(emsg);
|
||||
matches = true;
|
||||
}
|
||||
else
|
||||
@ -1952,7 +1939,7 @@ bool rule_matches(FW_INSTANCE* my_instance,
|
||||
double blocked_for =
|
||||
queryspeed->cooldown - difftime(time_now, queryspeed->triggered);
|
||||
sprintf(emsg, "Queries denied for %f seconds", blocked_for);
|
||||
msg = strdup(emsg);
|
||||
msg = MXS_STRDUP_A(emsg);
|
||||
}
|
||||
else if (queryspeed->count > 0 &&
|
||||
difftime(time_now, queryspeed->first_query) <= queryspeed->period)
|
||||
@ -1972,7 +1959,7 @@ bool rule_matches(FW_INSTANCE* my_instance,
|
||||
!qc_query_has_clause(queue))
|
||||
{
|
||||
matches = true;
|
||||
msg = strdup("Required WHERE/HAVING clause is missing.");
|
||||
msg = MXS_STRDUP_A("Required WHERE/HAVING clause is missing.");
|
||||
MXS_INFO("dbfwfilter: rule '%s': query has no where/having "
|
||||
"clause, query is denied.", rulelist->rule->name);
|
||||
}
|
||||
@ -1989,7 +1976,7 @@ queryresolved:
|
||||
{
|
||||
if (my_session->errmsg)
|
||||
{
|
||||
free(my_session->errmsg);
|
||||
MXS_FREE(my_session->errmsg);
|
||||
}
|
||||
|
||||
my_session->errmsg = msg;
|
||||
@ -2031,14 +2018,14 @@ bool check_match_any(FW_INSTANCE* my_instance, FW_SESSION* my_session,
|
||||
}
|
||||
if (rule_matches(my_instance, my_session, queue, user, rulelist, fullquery))
|
||||
{
|
||||
*rulename = strdup(rulelist->rule->name);
|
||||
*rulename = MXS_STRDUP_A(rulelist->rule->name);
|
||||
rval = true;
|
||||
break;
|
||||
}
|
||||
rulelist = rulelist->next;
|
||||
}
|
||||
|
||||
free(fullquery);
|
||||
MXS_FREE(fullquery);
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
@ -2054,7 +2041,7 @@ void append_string(char** dest, size_t* size, const char* src)
|
||||
{
|
||||
if (*dest == NULL)
|
||||
{
|
||||
*dest = strdup(src);
|
||||
*dest = MXS_STRDUP_A(src);
|
||||
*size = strlen(src);
|
||||
}
|
||||
else
|
||||
@ -2062,7 +2049,7 @@ void append_string(char** dest, size_t* size, const char* src)
|
||||
if (*size < strlen(*dest) + strlen(src) + 3)
|
||||
{
|
||||
size_t newsize = strlen(*dest) + strlen(src) + 3;
|
||||
char* tmp = realloc(*dest, newsize);
|
||||
char* tmp = MXS_REALLOC(*dest, newsize);
|
||||
if (tmp)
|
||||
{
|
||||
*size = newsize;
|
||||
@ -2070,7 +2057,6 @@ void append_string(char** dest, size_t* size, const char* src)
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR("Memory allocation failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -2131,7 +2117,7 @@ bool check_match_all(FW_INSTANCE* my_instance, FW_SESSION* my_session,
|
||||
/** No active rules */
|
||||
rval = false;
|
||||
}
|
||||
free(fullquery);
|
||||
MXS_FREE(fullquery);
|
||||
}
|
||||
|
||||
/** Set the list of matched rule names */
|
||||
@ -2198,7 +2184,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
GWBUF* err = gen_dummy_error(my_session, "This filter does not support "
|
||||
"multi-statements.");
|
||||
gwbuf_free(queue);
|
||||
free(my_session->errmsg);
|
||||
MXS_FREE(my_session->errmsg);
|
||||
my_session->errmsg = NULL;
|
||||
rval = dcb->func.write(dcb, err);
|
||||
}
|
||||
@ -2268,7 +2254,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
}
|
||||
}
|
||||
|
||||
free(rname);
|
||||
MXS_FREE(rname);
|
||||
}
|
||||
/** If the instance is in whitelist mode, only users that have a rule
|
||||
* defined for them are allowed */
|
||||
@ -2286,7 +2272,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
{
|
||||
GWBUF* forward = gen_dummy_error(my_session, my_session->errmsg);
|
||||
gwbuf_free(queue);
|
||||
free(my_session->errmsg);
|
||||
MXS_FREE(my_session->errmsg);
|
||||
my_session->errmsg = NULL;
|
||||
rval = dcb->func.write(dcb, forward);
|
||||
}
|
||||
@ -2378,10 +2364,11 @@ int main(int argc, char** argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
home = malloc(sizeof(char) * (PATH_MAX + 1));
|
||||
home = MXS_MALLOC(sizeof(char) * (PATH_MAX + 1));
|
||||
MXS_ABORT_IF_NULL(home);
|
||||
if (getcwd(home, PATH_MAX) == NULL)
|
||||
{
|
||||
free(home);
|
||||
MXS_FREE(home);
|
||||
home = NULL;
|
||||
}
|
||||
|
||||
@ -2399,8 +2386,8 @@ int main(int argc, char** argv)
|
||||
|
||||
|
||||
init_test_env(home);
|
||||
ruleparam.name = strdup("rules");
|
||||
ruleparam.value = strdup(argv[1]);
|
||||
ruleparam.name = MXS_STRDUP_A("rules");
|
||||
ruleparam.value = MXS_STRDUP_A(argv[1]);
|
||||
paramlist[0] = &ruleparam;
|
||||
paramlist[1] = NULL;
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
|
587
server/modules/filter/gatekeeper.c
Normal file
587
server/modules/filter/gatekeeper.c
Normal file
@ -0,0 +1,587 @@
|
||||
/*
|
||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
* Public License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <filter.h>
|
||||
#include <modinfo.h>
|
||||
#include <modutil.h>
|
||||
#include <atomic.h>
|
||||
#include <query_classifier.h>
|
||||
#include <hashtable.h>
|
||||
#include <gwdirs.h>
|
||||
#include <maxscale/alloc.h>
|
||||
|
||||
#define GK_DEFAULT_HASHTABLE_SIZE 1000
|
||||
|
||||
/**
|
||||
* @file gatekeeper.c - A learning firewall
|
||||
*
|
||||
* This filter will learn from input data read during a learning phase.
|
||||
* After learning the characteristics of the input, the filter can then
|
||||
* be set into an enforcing mode. In this mode the filter will block any
|
||||
* queries that do not conform to the training set.
|
||||
*/
|
||||
|
||||
MODULE_INFO info =
|
||||
{
|
||||
MODULE_API_FILTER,
|
||||
MODULE_ALPHA_RELEASE,
|
||||
FILTER_VERSION,
|
||||
"Learning firewall filter"
|
||||
};
|
||||
|
||||
enum firewall_mode
|
||||
{
|
||||
ENFORCE,
|
||||
LEARN
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned long queries; /**< Number of queries received */
|
||||
unsigned int hit; /**< Number of queries that match a pattern */
|
||||
unsigned int miss; /**< Number of queries that do not match a pattern */
|
||||
unsigned int entries; /**< Number of new patterns created */
|
||||
} GK_STATS;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HASHTABLE *queryhash; /**< Canonicalized forms of the queries */
|
||||
char* datadir; /**< The data is stored in this directory as lfw.data */
|
||||
enum firewall_mode mode; /**< Filter mode, either ENFORCE or LEARN */
|
||||
GK_STATS stats; /**< Instance statistics */
|
||||
SPINLOCK lock; /**< Instance lock */
|
||||
bool updating; /**< If the datafile is being updated */
|
||||
bool need_update; /**< If the datafile needs updating */
|
||||
} GK_INSTANCE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DCB* dcb; /**< Client DCB, used to send error messages */
|
||||
DOWNSTREAM down;
|
||||
GK_STATS stats; /**< Session statistics */
|
||||
} GK_SESSION;
|
||||
|
||||
static char *version_str = "V1.0.0";
|
||||
static const char* datafile_name = "gatekeeper.data";
|
||||
|
||||
/** Prefix all log messages with this tag */
|
||||
#define MODNAME "[gatekeeper] "
|
||||
|
||||
/** This is passed as a value to @c hashtable_add to have @c hashtable_fetch
|
||||
* return a non-NULL value when a hash hit is made */
|
||||
static bool trueval = true;
|
||||
|
||||
static FILTER *createInstance(char **options, FILTER_PARAMETER **params);
|
||||
static void *newSession(FILTER *instance, SESSION *session);
|
||||
static void closeSession(FILTER *instance, void *session);
|
||||
static void freeSession(FILTER *instance, void *session);
|
||||
static void setDownstream(FILTER *instance, void *fsession, DOWNSTREAM *downstream);
|
||||
static int routeQuery(FILTER *instance, void *fsession, GWBUF *queue);
|
||||
static void diagnostic(FILTER *instance, void *fsession, DCB *dcb);
|
||||
static bool read_stored_data(GK_INSTANCE *inst);
|
||||
static bool write_stored_data(GK_INSTANCE *inst);
|
||||
|
||||
static FILTER_OBJECT MyObject =
|
||||
{
|
||||
createInstance,
|
||||
newSession,
|
||||
closeSession,
|
||||
freeSession,
|
||||
setDownstream,
|
||||
NULL, // No upstream requirement
|
||||
routeQuery,
|
||||
NULL,
|
||||
diagnostic,
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of the mandatory version entry point
|
||||
*
|
||||
* @return version string of the module
|
||||
*/
|
||||
char* version()
|
||||
{
|
||||
return version_str;
|
||||
}
|
||||
|
||||
/**
|
||||
* The module initialization routine, called when the module
|
||||
* is first loaded.
|
||||
*/
|
||||
void ModuleInit()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* The module entry point routine. It is this routine that
|
||||
* must populate the structure that is referred to as the
|
||||
* "module object", this is a structure with the set of
|
||||
* external entry points for this module.
|
||||
*
|
||||
* @return The module object
|
||||
*/
|
||||
FILTER_OBJECT* GetModuleObject()
|
||||
{
|
||||
return &MyObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of the filter for a particular service
|
||||
* within MaxScale.
|
||||
*
|
||||
* @param options The options for this filter
|
||||
* @param params The array of name/value pair parameters for the filter
|
||||
*
|
||||
* @return The instance data for this new instance
|
||||
*/
|
||||
static FILTER* createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
GK_INSTANCE *inst = MXS_CALLOC(1, sizeof(GK_INSTANCE));
|
||||
|
||||
if (inst)
|
||||
{
|
||||
const char* datadir = get_datadir();
|
||||
bool ok = true;
|
||||
spinlock_init(&inst->lock);
|
||||
inst->mode = LEARN;
|
||||
|
||||
for (int i = 0; params && params[i]; i++)
|
||||
{
|
||||
if (strcmp(params[i]->name, "mode") == 0)
|
||||
{
|
||||
if (strcasecmp(params[i]->value, "enforce") == 0)
|
||||
{
|
||||
inst->mode = ENFORCE;
|
||||
}
|
||||
else if (strcasecmp(params[i]->value, "learn") == 0)
|
||||
{
|
||||
inst->mode = LEARN;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR(MODNAME"Unknown value for 'mode': %s", params[i]->value);
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
else if (strcmp(params[i]->name, "datadir") == 0)
|
||||
{
|
||||
if (access(params[i]->value, F_OK) == 0)
|
||||
{
|
||||
datadir = params[i]->value;
|
||||
}
|
||||
else
|
||||
{
|
||||
char err[STRERROR_BUFLEN];
|
||||
MXS_ERROR(MODNAME"File is not accessible: %d, %s", errno,
|
||||
strerror_r(errno, err, sizeof(err)));
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
else if (!filter_standard_parameter(params[i]->name))
|
||||
{
|
||||
MXS_ERROR(MODNAME"Unknown parameter '%s'.", params[i]->name);
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
inst->queryhash = hashtable_alloc(GK_DEFAULT_HASHTABLE_SIZE,
|
||||
hashtable_item_strhash,
|
||||
hashtable_item_strcasecmp);
|
||||
inst->datadir = MXS_STRDUP(datadir);
|
||||
if (inst->queryhash && inst->datadir)
|
||||
{
|
||||
hashtable_memory_fns(inst->queryhash, NULL, NULL, hashtable_item_free, NULL);
|
||||
if (read_stored_data(inst))
|
||||
{
|
||||
MXS_NOTICE(MODNAME"Started in [%s] mode. Data is stored at: %s",
|
||||
inst->mode == ENFORCE ? "ENFORCE" : "LEARN", inst->datadir);
|
||||
}
|
||||
else
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
hashtable_free(inst->queryhash);
|
||||
MXS_FREE(inst->datadir);
|
||||
MXS_FREE(inst);
|
||||
inst = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return (FILTER*)inst;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate a new session with this instance of the filter.
|
||||
*
|
||||
* @param instance The filter instance data
|
||||
* @param session The session itself
|
||||
* @return Session specific data for this session
|
||||
*/
|
||||
static void* newSession(FILTER *instance, SESSION *session)
|
||||
{
|
||||
GK_INSTANCE *inst = (GK_INSTANCE *) instance;
|
||||
GK_SESSION *ses;
|
||||
|
||||
if ((ses = MXS_CALLOC(1, sizeof(GK_SESSION))) != NULL)
|
||||
{
|
||||
ses->dcb = session->client_dcb;
|
||||
}
|
||||
|
||||
return ses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close a session with the filter, this is the mechanism
|
||||
* by which a filter may cleanup data structure etc.
|
||||
*
|
||||
* The gatekeeper flushes the hashtable to disk every time a session is closed.
|
||||
*
|
||||
* @param instance The filter instance data
|
||||
* @param session The session being closed
|
||||
*/
|
||||
static void closeSession(FILTER *instance, void *session)
|
||||
{
|
||||
GK_INSTANCE *inst = (GK_INSTANCE*) instance;
|
||||
GK_SESSION *ses = (GK_SESSION *) session;
|
||||
|
||||
/** If we added new data into the queryhash, update the datafile on disk */
|
||||
if (ses->stats.entries > 0)
|
||||
{
|
||||
spinlock_acquire(&inst->lock);
|
||||
|
||||
bool update = !inst->updating;
|
||||
if (update)
|
||||
{
|
||||
inst->updating = true;
|
||||
inst->need_update = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/** If another thread is already updating the file, set
|
||||
* the need_update flag */
|
||||
inst->need_update = true;
|
||||
}
|
||||
|
||||
spinlock_release(&inst->lock);
|
||||
|
||||
while (update)
|
||||
{
|
||||
/** Store the hashtable to disk */
|
||||
write_stored_data(inst);
|
||||
|
||||
spinlock_acquire(&inst->lock);
|
||||
|
||||
/** Check if the hashtable has been update while we were writing
|
||||
* the data to disk. */
|
||||
if ((update = inst->need_update))
|
||||
{
|
||||
inst->need_update = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
inst->updating = false;
|
||||
}
|
||||
|
||||
spinlock_release(&inst->lock);
|
||||
}
|
||||
}
|
||||
|
||||
/** Add session stats to instance stats */
|
||||
spinlock_acquire(&inst->lock);
|
||||
inst->stats.entries += ses->stats.entries;
|
||||
inst->stats.hit += ses->stats.hit;
|
||||
inst->stats.miss += ses->stats.miss;
|
||||
inst->stats.queries += ses->stats.queries;
|
||||
spinlock_release(&inst->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the memory associated with this filter session.
|
||||
*
|
||||
* @param instance The filter instance data
|
||||
* @param session The session being closed
|
||||
*/
|
||||
static void freeSession(FILTER *instance, void *session)
|
||||
{
|
||||
MXS_FREE(session);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the downstream component for this filter.
|
||||
*
|
||||
* @param instance The filter instance data
|
||||
* @param session The session being closed
|
||||
* @param downstream The downstream filter or router
|
||||
*/
|
||||
static void setDownstream(FILTER *instance, void *session, DOWNSTREAM *downstream)
|
||||
{
|
||||
GK_SESSION *ses = (GK_SESSION *) session;
|
||||
ses->down = *downstream;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main routing function
|
||||
*
|
||||
* @param instance The filter instance data
|
||||
* @param session The filter session
|
||||
* @param queue The query data
|
||||
* @return 1 on success, 0 on error
|
||||
*/
|
||||
static int routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
{
|
||||
GK_INSTANCE *inst = (GK_INSTANCE*) instance;
|
||||
GK_SESSION *ses = (GK_SESSION *) session;
|
||||
int rval = 1;
|
||||
bool ok = true;
|
||||
char* canon = qc_get_canonical(queue);
|
||||
|
||||
ses->stats.queries++;
|
||||
|
||||
/** Non-COM_QUERY packets are better handled on the backend database. For
|
||||
* example a COM_INIT_DB does not get canonicalized and would be always
|
||||
* denied. For this reason, queries that are not canonicalized are allowed.
|
||||
* This means that the binary protocol and prepared statements are not
|
||||
* processed by this filter. */
|
||||
if (canon)
|
||||
{
|
||||
if (inst->mode == ENFORCE)
|
||||
{
|
||||
if (hashtable_fetch(inst->queryhash, canon))
|
||||
{
|
||||
ses->stats.hit++;
|
||||
}
|
||||
else
|
||||
{
|
||||
ses->stats.miss++;
|
||||
ok = false;
|
||||
MXS_WARNING(MODNAME"Query by %s@%s was not found from queryhash: %s",
|
||||
ses->dcb->user, ses->dcb->remote, canon);
|
||||
GWBUF* errbuf = modutil_create_mysql_err_msg(1, 0, 1, "00000", "Permission denied.");
|
||||
rval = errbuf ? ses->dcb->func.write(ses->dcb, errbuf) : 0;
|
||||
}
|
||||
MXS_FREE(canon);
|
||||
}
|
||||
else if (inst->mode == LEARN)
|
||||
{
|
||||
if (hashtable_add(inst->queryhash, canon, &trueval))
|
||||
{
|
||||
ses->stats.entries++;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_FREE(canon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
rval = ses->down.routeQuery(ses->down.instance, ses->down.session, queue);
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Diagnostics routine
|
||||
*
|
||||
* @param instance The filter instance
|
||||
* @param fsession Filter session
|
||||
* @param dcb The DCB for output
|
||||
*/
|
||||
static void diagnostic(FILTER *instance, void *fsession, DCB *dcb)
|
||||
{
|
||||
GK_INSTANCE *inst = (GK_INSTANCE *) instance;
|
||||
|
||||
dcb_printf(dcb, "\t\tQueries: %lu\n", inst->stats.queries);
|
||||
dcb_printf(dcb, "\t\tQueryhash entries: %u\n", inst->stats.entries);
|
||||
dcb_printf(dcb, "\t\tQueryhash hits: %u\n", inst->stats.hit);
|
||||
dcb_printf(dcb, "\t\tQueryhash misses: %u\n", inst->stats.miss);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write query patterns from memory to disk
|
||||
*
|
||||
* The data is stored as length-encoded strings. A length-encoded string contains
|
||||
* a 4 byte integer, which tells the length of the string, followed by the string
|
||||
* itself. The stored file will consist of multiple consecutive length-encoded strings.
|
||||
*
|
||||
* @param inst Filter instance
|
||||
* @return True on success
|
||||
*/
|
||||
static bool write_stored_data(GK_INSTANCE *inst)
|
||||
{
|
||||
bool rval = false;
|
||||
char filepath[PATH_MAX];
|
||||
sprintf(filepath, "%s/%s.tmp.XXXXXX", inst->datadir, datafile_name);
|
||||
int fd = mkstemp(filepath);
|
||||
HASHITERATOR *iter = hashtable_iterator(inst->queryhash);
|
||||
|
||||
if (fd > 0 && iter)
|
||||
{
|
||||
char *key;
|
||||
bool ok = true;
|
||||
|
||||
while ((key = hashtable_next(iter)))
|
||||
{
|
||||
uint32_t len = strlen(key);
|
||||
|
||||
/** First write the length of the string and then the string itself */
|
||||
if (write(fd, &len, sizeof(len)) != sizeof(len) ||
|
||||
write(fd, key, len) != len)
|
||||
{
|
||||
char err[STRERROR_BUFLEN];
|
||||
MXS_ERROR(MODNAME"Failed to write key '%s' to disk (%d, %s). The datafile at '%s' was "
|
||||
"not updated but it will be updated when the next session closes. ",
|
||||
key, errno, strerror_r(errno, err, sizeof(err)), inst->datadir);
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
/** Update the file by renaming the temporary file to the original one*/
|
||||
char newfilepath[PATH_MAX + 1];
|
||||
snprintf(newfilepath, sizeof(newfilepath), "%s/%s", inst->datadir, datafile_name);
|
||||
rval = rename(filepath, newfilepath) == 0;
|
||||
|
||||
if (!rval)
|
||||
{
|
||||
char err[STRERROR_BUFLEN];
|
||||
MXS_ERROR(MODNAME"Failed to rename file '%s' to '%s' when writing data: %d, %s",
|
||||
filepath, newfilepath, errno, strerror_r(errno, err, sizeof(err)));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (fd == -1)
|
||||
{
|
||||
char err[STRERROR_BUFLEN];
|
||||
MXS_ERROR(MODNAME"Failed to open file '%s' when writing data: %d, %s",
|
||||
filepath, errno, strerror_r(errno, err, sizeof(err)));
|
||||
}
|
||||
|
||||
if (fd > 0)
|
||||
{
|
||||
close(fd);
|
||||
}
|
||||
hashtable_iterator_free(iter);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
static void report_failed_read(FILE *file, int nexpected, int nread)
|
||||
{
|
||||
if (ferror(file))
|
||||
{
|
||||
char err[STRERROR_BUFLEN];
|
||||
MXS_ERROR(MODNAME"Failed to read %d bytes, only %d bytes read: %d, %s",
|
||||
nexpected, nread, errno, strerror_r(errno, err, sizeof(err)));
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR(MODNAME"Partial read, expected %d bytes but read only %d.",
|
||||
nexpected, nread);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read query patterns from disk to memory
|
||||
*
|
||||
* See write_stored_data() for details on how the data is stored.
|
||||
*
|
||||
* @param inst Filter instance
|
||||
* @return True if data was successfully read
|
||||
*/
|
||||
static bool read_stored_data(GK_INSTANCE *inst)
|
||||
{
|
||||
char filepath[PATH_MAX + 1];
|
||||
snprintf(filepath, sizeof(filepath), "%s/%s", inst->datadir, datafile_name);
|
||||
|
||||
if (access(filepath, F_OK) != 0)
|
||||
{
|
||||
if (inst->mode == ENFORCE)
|
||||
{
|
||||
MXS_ERROR(MODNAME"Started in ENFORCE mode but no datafile was found at '%s'.", filepath);
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Not finding a datafile in LEARN mode is OK since it will be created later on */
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rval = true;
|
||||
FILE *file = fopen(filepath, "rb");
|
||||
|
||||
if (file)
|
||||
{
|
||||
do
|
||||
{
|
||||
uint32_t len;
|
||||
size_t nread;
|
||||
char *data;
|
||||
|
||||
/** Read the length of the string */
|
||||
if ((nread = fread(&len, 1, sizeof(len), file)) != sizeof(len))
|
||||
{
|
||||
if (nread > 0 || !feof(file))
|
||||
{
|
||||
report_failed_read(file, sizeof(len), nread);
|
||||
rval = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ((data = MXS_MALLOC(len + 1)) == NULL)
|
||||
{
|
||||
rval = false;
|
||||
break;
|
||||
}
|
||||
|
||||
/** Read the string itself */
|
||||
if ((nread = fread(data, 1, len, file)) != len)
|
||||
{
|
||||
MXS_FREE(data);
|
||||
report_failed_read(file, sizeof(len), nread);
|
||||
rval = false;
|
||||
break;
|
||||
}
|
||||
|
||||
data[len] = '\0';
|
||||
hashtable_add(inst->queryhash, data, &trueval);
|
||||
}
|
||||
while (!feof(file));
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
char err[STRERROR_BUFLEN];
|
||||
MXS_ERROR(MODNAME"Failed to open file '%s' when reading stored data: %d, %s",
|
||||
filepath, errno, strerror_r(errno, err, sizeof(err)));
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
add_library(hintfilter SHARED hintfilter.c hintparser.c)
|
||||
set_target_properties(hintfilter PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_RPATH}:${MAXSCALE_LIBDIR} VERSION "1.0.0")
|
||||
target_link_libraries(hintfilter maxscale-common)
|
||||
install(TARGETS hintfilter DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(hintfilter core)
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -12,6 +12,7 @@
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <filter.h>
|
||||
#include <maxscale/alloc.h>
|
||||
#include <modinfo.h>
|
||||
#include <modutil.h>
|
||||
#include <mysqlhint.h>
|
||||
@ -105,7 +106,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
HINT_INSTANCE *my_instance;
|
||||
|
||||
if ((my_instance = calloc(1, sizeof(HINT_INSTANCE))) != NULL)
|
||||
if ((my_instance = MXS_CALLOC(1, sizeof(HINT_INSTANCE))) != NULL)
|
||||
{
|
||||
my_instance->sessions = 0;
|
||||
}
|
||||
@ -125,7 +126,7 @@ newSession(FILTER *instance, SESSION *session)
|
||||
HINT_INSTANCE *my_instance = (HINT_INSTANCE *)instance;
|
||||
HINT_SESSION *my_session;
|
||||
|
||||
if ((my_session = calloc(1, sizeof(HINT_SESSION))) != NULL)
|
||||
if ((my_session = MXS_CALLOC(1, sizeof(HINT_SESSION))) != NULL)
|
||||
{
|
||||
my_session->query_len = 0;
|
||||
my_session->request = NULL;
|
||||
@ -177,7 +178,7 @@ closeSession(FILTER *instance, void *session)
|
||||
static void
|
||||
freeSession(FILTER *instance, void *session)
|
||||
{
|
||||
free(session);
|
||||
MXS_FREE(session);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -19,6 +19,7 @@
|
||||
#include <modinfo.h>
|
||||
#include <modutil.h>
|
||||
#include <mysqlhint.h>
|
||||
#include <maxscale/alloc.h>
|
||||
|
||||
/**
|
||||
* hintparser.c - Find any comment in the SQL packet and look for MAXSCALE
|
||||
@ -83,9 +84,9 @@ void token_free(HINT_TOKEN* token)
|
||||
{
|
||||
if (token->value != NULL)
|
||||
{
|
||||
free(token->value);
|
||||
MXS_FREE(token->value);
|
||||
}
|
||||
free(token);
|
||||
MXS_FREE(token);
|
||||
}
|
||||
|
||||
static const char* token_get_keyword(
|
||||
@ -281,7 +282,7 @@ hint_parser(HINT_SESSION *session, GWBUF *request)
|
||||
break;
|
||||
case TOK_STRING:
|
||||
state = HS_NAME;
|
||||
lvalue = strdup(tok->value);
|
||||
lvalue = MXS_STRDUP_A(tok->value);
|
||||
break;
|
||||
case TOK_STOP:
|
||||
/* Action: pop active hint */
|
||||
@ -452,7 +453,7 @@ hint_parser(HINT_SESSION *session, GWBUF *request)
|
||||
/* We starting an already define set of named hints */
|
||||
rval = lookup_named_hint(session, hintname);
|
||||
hint_push(session, hint_dup(rval));
|
||||
free(hintname);
|
||||
MXS_FREE(hintname);
|
||||
rval = NULL;
|
||||
}
|
||||
else if (hintname == NULL && rval == NULL)
|
||||
@ -518,7 +519,7 @@ hint_next_token(GWBUF **buf, char **ptr)
|
||||
int i, found;
|
||||
HINT_TOKEN *tok;
|
||||
|
||||
if ((tok = (HINT_TOKEN *)malloc(sizeof(HINT_TOKEN))) == NULL)
|
||||
if ((tok = (HINT_TOKEN *)MXS_MALLOC(sizeof(HINT_TOKEN))) == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@ -603,7 +604,7 @@ hint_next_token(GWBUF **buf, char **ptr)
|
||||
if (found == 0)
|
||||
{
|
||||
tok->token = TOK_STRING;
|
||||
tok->value = strdup(word);
|
||||
tok->value = MXS_STRDUP_A(word);
|
||||
}
|
||||
|
||||
return tok;
|
||||
@ -629,7 +630,7 @@ hint_pop(HINT_SESSION *session)
|
||||
ptr->hint = hint->next;
|
||||
hint_free(hint);
|
||||
}
|
||||
free(ptr);
|
||||
MXS_FREE(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -645,7 +646,7 @@ hint_push(HINT_SESSION *session, HINT *hint)
|
||||
{
|
||||
HINTSTACK *item;
|
||||
|
||||
if ((item = (HINTSTACK *)malloc(sizeof(HINTSTACK))) == NULL)
|
||||
if ((item = (HINTSTACK *)MXS_MALLOC(sizeof(HINTSTACK))) == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -689,7 +690,7 @@ create_named_hint(HINT_SESSION *session, char *name, HINT *hint)
|
||||
{
|
||||
NAMEDHINTS *block;
|
||||
|
||||
if ((block = (NAMEDHINTS *)malloc(sizeof(NAMEDHINTS))) == NULL)
|
||||
if ((block = (NAMEDHINTS *)MXS_MALLOC(sizeof(NAMEDHINTS))) == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -724,8 +725,8 @@ NAMEDHINTS* free_named_hint(
|
||||
hint_free(named_hint->hints);
|
||||
named_hint->hints = hint;
|
||||
}
|
||||
free(named_hint->name);
|
||||
free(named_hint);
|
||||
MXS_FREE(named_hint->name);
|
||||
MXS_FREE(named_hint);
|
||||
return next;
|
||||
}
|
||||
else
|
||||
@ -758,7 +759,7 @@ HINTSTACK* free_hint_stack(
|
||||
hint_free(hint_stack->hint);
|
||||
hint_stack->hint = hint;
|
||||
}
|
||||
free(hint_stack);
|
||||
MXS_FREE(hint_stack);
|
||||
return next;
|
||||
}
|
||||
else
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -47,6 +47,7 @@
|
||||
#include "lua.h"
|
||||
#include "lualib.h"
|
||||
#include "lauxlib.h"
|
||||
#include <maxscale/alloc.h>
|
||||
|
||||
MODULE_INFO info =
|
||||
{
|
||||
@ -173,7 +174,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
LUA_INSTANCE *my_instance;
|
||||
bool error = false;
|
||||
|
||||
if ((my_instance = (LUA_INSTANCE*) calloc(1, sizeof(LUA_INSTANCE))) == NULL)
|
||||
if ((my_instance = (LUA_INSTANCE*) MXS_CALLOC(1, sizeof(LUA_INSTANCE))) == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@ -184,11 +185,11 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
if (strcmp(params[i]->name, "global_script") == 0)
|
||||
{
|
||||
error = (my_instance->global_script = strdup(params[i]->value)) == NULL;
|
||||
error = (my_instance->global_script = MXS_STRDUP(params[i]->value)) == NULL;
|
||||
}
|
||||
else if (strcmp(params[i]->name, "session_script") == 0)
|
||||
{
|
||||
error = (my_instance->session_script = strdup(params[i]->value)) == NULL;
|
||||
error = (my_instance->session_script = MXS_STRDUP(params[i]->value)) == NULL;
|
||||
}
|
||||
else if (!filter_standard_parameter(params[i]->name))
|
||||
{
|
||||
@ -199,9 +200,9 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
|
||||
if (error)
|
||||
{
|
||||
free(my_instance->global_script);
|
||||
free(my_instance->session_script);
|
||||
free(my_instance);
|
||||
MXS_FREE(my_instance->global_script);
|
||||
MXS_FREE(my_instance->session_script);
|
||||
MXS_FREE(my_instance);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -215,9 +216,9 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
MXS_ERROR("luafilter: Failed to execute global script at '%s':%s.",
|
||||
my_instance->global_script, lua_tostring(my_instance->global_lua_state, -1));
|
||||
free(my_instance->global_script);
|
||||
free(my_instance->session_script);
|
||||
free(my_instance);
|
||||
MXS_FREE(my_instance->global_script);
|
||||
MXS_FREE(my_instance->session_script);
|
||||
MXS_FREE(my_instance);
|
||||
my_instance = NULL;
|
||||
}
|
||||
else if (my_instance->global_lua_state)
|
||||
@ -234,7 +235,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
else
|
||||
{
|
||||
MXS_ERROR("Unable to initialize new Lua state.");
|
||||
free(my_instance);
|
||||
MXS_FREE(my_instance);
|
||||
my_instance = NULL;
|
||||
}
|
||||
}
|
||||
@ -263,7 +264,7 @@ static void * newSession(FILTER *instance, SESSION *session)
|
||||
LUA_SESSION *my_session;
|
||||
LUA_INSTANCE *my_instance = (LUA_INSTANCE*) instance;
|
||||
|
||||
if ((my_session = (LUA_SESSION*) calloc(1, sizeof(LUA_SESSION))) == NULL)
|
||||
if ((my_session = (LUA_SESSION*) MXS_CALLOC(1, sizeof(LUA_SESSION))) == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@ -282,7 +283,7 @@ static void * newSession(FILTER *instance, SESSION *session)
|
||||
my_instance->session_script,
|
||||
lua_tostring(my_session->lua_state, -1));
|
||||
lua_close(my_session->lua_state);
|
||||
free(my_session);
|
||||
MXS_FREE(my_session);
|
||||
my_session = NULL;
|
||||
}
|
||||
else
|
||||
@ -367,7 +368,7 @@ static void freeSession(FILTER *instance, void *session)
|
||||
{
|
||||
LUA_SESSION *my_session = (LUA_SESSION *) session;
|
||||
lua_close(my_session->lua_state);
|
||||
free(my_session);
|
||||
MXS_FREE(my_session);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -526,7 +527,7 @@ static int routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
spinlock_release(&my_instance->lock);
|
||||
}
|
||||
|
||||
free(fullquery);
|
||||
MXS_FREE(fullquery);
|
||||
}
|
||||
|
||||
if (!route)
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -76,6 +76,7 @@
|
||||
#include <spinlock.h>
|
||||
#include <session.h>
|
||||
#include <housekeeper.h>
|
||||
#include <maxscale/alloc.h>
|
||||
|
||||
MODULE_INFO info =
|
||||
{
|
||||
@ -474,11 +475,10 @@ char** parse_optstr(char* str, char* tok, int* szstore)
|
||||
size++;
|
||||
}
|
||||
|
||||
arr = malloc(sizeof(char*)*size);
|
||||
arr = MXS_MALLOC(sizeof(char*)*size);
|
||||
|
||||
if (arr == NULL)
|
||||
{
|
||||
MXS_ERROR("Cannot allocate enough memory.");
|
||||
*szstore = 0;
|
||||
return NULL;
|
||||
}
|
||||
@ -487,7 +487,7 @@ char** parse_optstr(char* str, char* tok, int* szstore)
|
||||
tk = strtok_r(str, tok, &lasts);
|
||||
while (tk && i < size)
|
||||
{
|
||||
arr[i++] = strdup(tk);
|
||||
arr[i++] = MXS_STRDUP_A(tk);
|
||||
tk = strtok_r(NULL, tok, &lasts);
|
||||
}
|
||||
return arr;
|
||||
@ -510,17 +510,18 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
char** arr = NULL;
|
||||
char taskname[512];
|
||||
|
||||
if ((my_instance = calloc(1, sizeof(MQ_INSTANCE))))
|
||||
if ((my_instance = MXS_CALLOC(1, sizeof(MQ_INSTANCE))))
|
||||
{
|
||||
spinlock_init(&my_instance->rconn_lock);
|
||||
spinlock_init(&my_instance->msg_lock);
|
||||
uid_gen = 0;
|
||||
paramlist = malloc(sizeof(FILTER_PARAMETER*) * 64);
|
||||
paramlist = MXS_MALLOC(sizeof(FILTER_PARAMETER*) * 64);
|
||||
MXS_ABORT_IF_NULL(paramlist);
|
||||
|
||||
if ((my_instance->conn = amqp_new_connection()) == NULL)
|
||||
{
|
||||
free(paramlist);
|
||||
free(my_instance);
|
||||
MXS_FREE(paramlist);
|
||||
MXS_FREE(my_instance);
|
||||
return NULL;
|
||||
}
|
||||
my_instance->channel = 1;
|
||||
@ -536,19 +537,19 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
if (!strcmp(params[i]->name, "hostname"))
|
||||
{
|
||||
my_instance->hostname = strdup(params[i]->value);
|
||||
my_instance->hostname = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "username"))
|
||||
{
|
||||
my_instance->username = strdup(params[i]->value);
|
||||
my_instance->username = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "password"))
|
||||
{
|
||||
my_instance->password = strdup(params[i]->value);
|
||||
my_instance->password = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "vhost"))
|
||||
{
|
||||
my_instance->vhost = strdup(params[i]->value);
|
||||
my_instance->vhost = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "port"))
|
||||
{
|
||||
@ -556,35 +557,34 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "exchange"))
|
||||
{
|
||||
my_instance->exchange = strdup(params[i]->value);
|
||||
my_instance->exchange = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "key"))
|
||||
{
|
||||
my_instance->key = strdup(params[i]->value);
|
||||
my_instance->key = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "queue"))
|
||||
{
|
||||
my_instance->queue = strdup(params[i]->value);
|
||||
my_instance->queue = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "ssl_client_certificate"))
|
||||
{
|
||||
|
||||
my_instance->ssl_client_cert = strdup(params[i]->value);
|
||||
my_instance->ssl_client_cert = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "ssl_client_key"))
|
||||
{
|
||||
|
||||
my_instance->ssl_client_key = strdup(params[i]->value);
|
||||
my_instance->ssl_client_key = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "ssl_CA_cert"))
|
||||
{
|
||||
|
||||
my_instance->ssl_CA_cert = strdup(params[i]->value);
|
||||
my_instance->ssl_CA_cert = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "exchange_type"))
|
||||
{
|
||||
|
||||
my_instance->exchange_type = strdup(params[i]->value);
|
||||
my_instance->exchange_type = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "logging_trigger"))
|
||||
{
|
||||
@ -619,9 +619,9 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
for (int x = 0; x < arrsize; x++)
|
||||
{
|
||||
free(arr[x]);
|
||||
MXS_FREE(arr[x]);
|
||||
}
|
||||
free(arr);
|
||||
MXS_FREE(arr);
|
||||
arr = NULL;
|
||||
}
|
||||
arrsize = 0;
|
||||
@ -634,9 +634,10 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
|
||||
if (paramcount < parammax)
|
||||
{
|
||||
paramlist[paramcount] = malloc(sizeof(FILTER_PARAMETER));
|
||||
paramlist[paramcount]->name = strdup(params[i]->name);
|
||||
paramlist[paramcount]->value = strdup(params[i]->value);
|
||||
paramlist[paramcount] = MXS_MALLOC(sizeof(FILTER_PARAMETER));
|
||||
MXS_ABORT_IF_NULL(paramlist[paramcount]);
|
||||
paramlist[paramcount]->name = MXS_STRDUP_A(params[i]->name);
|
||||
paramlist[paramcount]->value = MXS_STRDUP_A(params[i]->value);
|
||||
paramcount++;
|
||||
}
|
||||
}
|
||||
@ -645,7 +646,8 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
if (my_instance->trgtype & TRG_SOURCE)
|
||||
{
|
||||
|
||||
my_instance->src_trg = (SRC_TRIG*) malloc(sizeof(SRC_TRIG));
|
||||
my_instance->src_trg = (SRC_TRIG*) MXS_MALLOC(sizeof(SRC_TRIG));
|
||||
MXS_ABORT_IF_NULL(my_instance->src_trg);
|
||||
my_instance->src_trg->user = NULL;
|
||||
my_instance->src_trg->host = NULL;
|
||||
my_instance->src_trg->usize = 0;
|
||||
@ -656,7 +658,8 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
if (my_instance->trgtype & TRG_SCHEMA)
|
||||
{
|
||||
|
||||
my_instance->shm_trg = (SHM_TRIG*) malloc(sizeof(SHM_TRIG));
|
||||
my_instance->shm_trg = (SHM_TRIG*) MXS_MALLOC(sizeof(SHM_TRIG));
|
||||
MXS_ABORT_IF_NULL(my_instance->shm_trg);
|
||||
my_instance->shm_trg->objects = NULL;
|
||||
my_instance->shm_trg->size = 0;
|
||||
|
||||
@ -665,7 +668,8 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
if (my_instance->trgtype & TRG_OBJECT)
|
||||
{
|
||||
|
||||
my_instance->obj_trg = (OBJ_TRIG*) malloc(sizeof(OBJ_TRIG));
|
||||
my_instance->obj_trg = (OBJ_TRIG*) MXS_MALLOC(sizeof(OBJ_TRIG));
|
||||
MXS_ABORT_IF_NULL(my_instance->obj_trg);
|
||||
my_instance->obj_trg->objects = NULL;
|
||||
my_instance->obj_trg->size = 0;
|
||||
|
||||
@ -732,40 +736,40 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
my_instance->strict_logging = false;
|
||||
}
|
||||
}
|
||||
free(paramlist[i]->name);
|
||||
free(paramlist[i]->value);
|
||||
free(paramlist[i]);
|
||||
MXS_FREE(paramlist[i]->name);
|
||||
MXS_FREE(paramlist[i]->value);
|
||||
MXS_FREE(paramlist[i]);
|
||||
}
|
||||
|
||||
free(paramlist);
|
||||
MXS_FREE(paramlist);
|
||||
|
||||
if (my_instance->hostname == NULL)
|
||||
{
|
||||
my_instance->hostname = strdup("localhost");
|
||||
my_instance->hostname = MXS_STRDUP_A("localhost");
|
||||
}
|
||||
if (my_instance->username == NULL)
|
||||
{
|
||||
my_instance->username = strdup("guest");
|
||||
my_instance->username = MXS_STRDUP_A("guest");
|
||||
}
|
||||
if (my_instance->password == NULL)
|
||||
{
|
||||
my_instance->password = strdup("guest");
|
||||
my_instance->password = MXS_STRDUP_A("guest");
|
||||
}
|
||||
if (my_instance->vhost == NULL)
|
||||
{
|
||||
my_instance->vhost = strdup("/");
|
||||
my_instance->vhost = MXS_STRDUP_A("/");
|
||||
}
|
||||
if (my_instance->exchange == NULL)
|
||||
{
|
||||
my_instance->exchange = strdup("default_exchange");
|
||||
my_instance->exchange = MXS_STRDUP_A("default_exchange");
|
||||
}
|
||||
if (my_instance->key == NULL)
|
||||
{
|
||||
my_instance->key = strdup("key");
|
||||
my_instance->key = MXS_STRDUP_A("key");
|
||||
}
|
||||
if (my_instance->exchange_type == NULL)
|
||||
{
|
||||
my_instance->exchange_type = strdup("direct");
|
||||
my_instance->exchange_type = MXS_STRDUP_A("direct");
|
||||
}
|
||||
|
||||
if (my_instance->ssl_client_cert != NULL &&
|
||||
@ -794,9 +798,9 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
for (int x = 0; x < arrsize; x++)
|
||||
{
|
||||
free(arr[x]);
|
||||
MXS_FREE(arr[x]);
|
||||
}
|
||||
free(arr);
|
||||
MXS_FREE(arr);
|
||||
}
|
||||
}
|
||||
return (FILTER *) my_instance;
|
||||
@ -910,9 +914,9 @@ void sendMessage(void* data)
|
||||
if (err_num == AMQP_STATUS_OK)
|
||||
{
|
||||
/**Message was sent successfully*/
|
||||
free(tmp->prop);
|
||||
free(tmp->msg);
|
||||
free(tmp);
|
||||
MXS_FREE(tmp->prop);
|
||||
MXS_FREE(tmp->msg);
|
||||
MXS_FREE(tmp);
|
||||
|
||||
atomic_add(&instance->stats.n_sent, 1);
|
||||
atomic_add(&instance->stats.n_queued, -1);
|
||||
@ -948,7 +952,7 @@ void sendMessage(void* data)
|
||||
void pushMessage(MQ_INSTANCE *instance, amqp_basic_properties_t* prop, char* msg)
|
||||
{
|
||||
|
||||
mqmessage* newmsg = calloc(1, sizeof(mqmessage));
|
||||
mqmessage* newmsg = MXS_CALLOC(1, sizeof(mqmessage));
|
||||
if (newmsg)
|
||||
{
|
||||
newmsg->msg = msg;
|
||||
@ -956,9 +960,8 @@ void pushMessage(MQ_INSTANCE *instance, amqp_basic_properties_t* prop, char* msg
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR("Cannot allocate enough memory.");
|
||||
free(prop);
|
||||
free(msg);
|
||||
MXS_FREE(prop);
|
||||
MXS_FREE(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -985,23 +988,36 @@ void pushMessage(MQ_INSTANCE *instance, amqp_basic_properties_t* prop, char* msg
|
||||
static void *
|
||||
newSession(FILTER *instance, SESSION *session)
|
||||
{
|
||||
MQ_SESSION *my_session;
|
||||
MYSQL_session* sessauth;
|
||||
MYSQL_session *sessauth = session->client_dcb->data;
|
||||
char *db = sessauth->db;
|
||||
if (db)
|
||||
{
|
||||
if (strnlen(db, 128) > 0)
|
||||
{
|
||||
db = MXS_STRDUP(db);
|
||||
if (!db)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
db = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((my_session = calloc(1, sizeof(MQ_SESSION))) != NULL)
|
||||
MQ_SESSION *my_session;
|
||||
|
||||
if ((my_session = MXS_CALLOC(1, sizeof(MQ_SESSION))) != NULL)
|
||||
{
|
||||
my_session->was_query = false;
|
||||
my_session->uid = NULL;
|
||||
my_session->session = session;
|
||||
sessauth = my_session->session->client_dcb->data;
|
||||
if (sessauth->db && strnlen(sessauth->db, 128) > 0)
|
||||
{
|
||||
my_session->db = strdup(sessauth->db);
|
||||
}
|
||||
else
|
||||
{
|
||||
my_session->db = NULL;
|
||||
}
|
||||
my_session->db = db;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_FREE(db);
|
||||
}
|
||||
|
||||
return my_session;
|
||||
@ -1028,9 +1044,9 @@ static void
|
||||
freeSession(FILTER *instance, void *session)
|
||||
{
|
||||
MQ_SESSION *my_session = (MQ_SESSION *) session;
|
||||
free(my_session->uid);
|
||||
free(my_session->db);
|
||||
free(my_session);
|
||||
MXS_FREE(my_session->uid);
|
||||
MXS_FREE(my_session->db);
|
||||
MXS_FREE(my_session);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1117,10 +1133,11 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
{
|
||||
if (my_session->db)
|
||||
{
|
||||
free(my_session->db);
|
||||
MXS_FREE(my_session->db);
|
||||
}
|
||||
plen = pktlen(queue->start);
|
||||
my_session->db = calloc(plen, sizeof(char));
|
||||
my_session->db = MXS_CALLOC(plen, sizeof(char));
|
||||
MXS_ABORT_IF_NULL(my_session->db);
|
||||
memcpy(my_session->db, queue->start + 5, plen - 1);
|
||||
}
|
||||
|
||||
@ -1229,9 +1246,9 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
{
|
||||
all_remotes = false;
|
||||
}
|
||||
free(tblnames[z]);
|
||||
MXS_FREE(tblnames[z]);
|
||||
}
|
||||
free(tblnames);
|
||||
MXS_FREE(tblnames);
|
||||
|
||||
if (!schema_ok && !all_remotes && my_session->db && strlen(my_session->db) > 0)
|
||||
{
|
||||
@ -1305,9 +1322,9 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
{
|
||||
for (j = 0; j < dbcount; j++)
|
||||
{
|
||||
free(sesstbls[j]);
|
||||
MXS_FREE(sesstbls[j]);
|
||||
}
|
||||
free(sesstbls);
|
||||
MXS_FREE(sesstbls);
|
||||
dbcount = 0;
|
||||
}
|
||||
|
||||
@ -1344,17 +1361,12 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
if (my_session->uid == NULL)
|
||||
{
|
||||
|
||||
my_session->uid = calloc(33, sizeof(char));
|
||||
my_session->uid = MXS_CALLOC(33, sizeof(char));
|
||||
|
||||
if (!my_session->uid)
|
||||
{
|
||||
MXS_ERROR("Out of memory.");
|
||||
}
|
||||
else
|
||||
if (my_session->uid)
|
||||
{
|
||||
genkey(my_session->uid, 32);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (queue->next != NULL)
|
||||
@ -1367,7 +1379,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
|
||||
my_session->was_query = true;
|
||||
|
||||
if ((prop = malloc(sizeof(amqp_basic_properties_t))))
|
||||
if ((prop = MXS_MALLOC(sizeof(amqp_basic_properties_t))))
|
||||
{
|
||||
prop->_flags = AMQP_BASIC_CONTENT_TYPE_FLAG |
|
||||
AMQP_BASIC_DELIVERY_MODE_FLAG |
|
||||
@ -1379,8 +1391,6 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
prop->message_id = amqp_cstring_bytes("query");
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (success)
|
||||
{
|
||||
|
||||
@ -1396,15 +1406,13 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
sprintf(t_buf, "%lu|", (unsigned long) time(NULL));
|
||||
|
||||
int qlen = strnlen(canon_q, length) + strnlen(t_buf, 128);
|
||||
if ((combined = malloc((qlen + 1) * sizeof(char))) == NULL)
|
||||
{
|
||||
MXS_ERROR("Out of memory");
|
||||
}
|
||||
combined = MXS_MALLOC((qlen + 1) * sizeof(char));
|
||||
MXS_ABORT_IF_NULL(combined);
|
||||
strcpy(combined, t_buf);
|
||||
strncat(combined, canon_q, length);
|
||||
|
||||
pushMessage(my_instance, prop, combined);
|
||||
free(canon_q);
|
||||
MXS_FREE(canon_q);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1494,7 +1502,7 @@ unsigned int consume_leitoi(unsigned char** c)
|
||||
char* consume_lestr(unsigned char** c)
|
||||
{
|
||||
unsigned int slen = consume_leitoi(c);
|
||||
char *str = calloc((slen + 1), sizeof(char));
|
||||
char *str = MXS_CALLOC((slen + 1), sizeof(char));
|
||||
if (str)
|
||||
{
|
||||
memcpy(str, *c, slen);
|
||||
@ -1545,7 +1553,7 @@ static int clientReply(FILTER* instance, void *session, GWBUF *reply)
|
||||
|
||||
if (pkt_len > 0)
|
||||
{
|
||||
if ((prop = malloc(sizeof(amqp_basic_properties_t))))
|
||||
if ((prop = MXS_MALLOC(sizeof(amqp_basic_properties_t))))
|
||||
{
|
||||
prop->_flags = AMQP_BASIC_CONTENT_TYPE_FLAG |
|
||||
AMQP_BASIC_DELIVERY_MODE_FLAG |
|
||||
@ -1556,10 +1564,9 @@ static int clientReply(FILTER* instance, void *session, GWBUF *reply)
|
||||
prop->correlation_id = amqp_cstring_bytes(my_session->uid);
|
||||
prop->message_id = amqp_cstring_bytes("reply");
|
||||
}
|
||||
if (!(combined = calloc(GWBUF_LENGTH(reply) + 256, sizeof(char))))
|
||||
{
|
||||
MXS_ERROR("Out of memory");
|
||||
}
|
||||
|
||||
combined = MXS_CALLOC(GWBUF_LENGTH(reply) + 256, sizeof(char));
|
||||
MXS_ABORT_IF_NULL(combined);
|
||||
|
||||
memset(t_buf, 0, 128);
|
||||
sprintf(t_buf, "%lu|", (unsigned long) time(NULL));
|
||||
@ -1627,13 +1634,14 @@ static int clientReply(FILTER* instance, void *session, GWBUF *reply)
|
||||
char *tmp;
|
||||
unsigned int col_cnt = consume_leitoi(&rset);
|
||||
|
||||
tmp = calloc(256, sizeof(char));
|
||||
tmp = MXS_CALLOC(256, sizeof(char));
|
||||
MXS_ABORT_IF_NULL(tmp);
|
||||
sprintf(tmp, "Columns: %d", col_cnt);
|
||||
memcpy(combined + offset, tmp, strnlen(tmp, 256));
|
||||
offset += strnlen(tmp, 256);
|
||||
memcpy(combined + offset, "\n", 1);
|
||||
offset++;
|
||||
free(tmp);
|
||||
MXS_FREE(tmp);
|
||||
|
||||
packet_ok = 1;
|
||||
was_last = 1;
|
||||
@ -1649,7 +1657,7 @@ static int clientReply(FILTER* instance, void *session, GWBUF *reply)
|
||||
|
||||
/**Successful reply received and sent, releasing uid*/
|
||||
|
||||
free(my_session->uid);
|
||||
MXS_FREE(my_session->uid);
|
||||
my_session->uid = NULL;
|
||||
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <maxscale/alloc.h>
|
||||
#include <filter.h>
|
||||
#include <modinfo.h>
|
||||
#include <modutil.h>
|
||||
@ -20,6 +21,7 @@
|
||||
#include <string.h>
|
||||
#include <regex.h>
|
||||
#include <hint.h>
|
||||
#include <maxscale/alloc.h>
|
||||
|
||||
/**
|
||||
* @file namedserverfilter.c - a very simple regular expression based filter
|
||||
@ -143,10 +145,9 @@ GetModuleObject()
|
||||
static FILTER *
|
||||
createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
REGEXHINT_INSTANCE *my_instance;
|
||||
int cflags = REG_ICASE;
|
||||
REGEXHINT_INSTANCE *my_instance = (REGEXHINT_INSTANCE*)MXS_MALLOC(sizeof(REGEXHINT_INSTANCE));
|
||||
|
||||
if ((my_instance = malloc(sizeof(REGEXHINT_INSTANCE))) != NULL)
|
||||
if (my_instance)
|
||||
{
|
||||
my_instance->match = NULL;
|
||||
my_instance->server = NULL;
|
||||
@ -158,19 +159,19 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
if (!strcmp(params[i]->name, "match"))
|
||||
{
|
||||
my_instance->match = strdup(params[i]->value);
|
||||
my_instance->match = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "server"))
|
||||
{
|
||||
my_instance->server = strdup(params[i]->value);
|
||||
my_instance->server = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "source"))
|
||||
{
|
||||
my_instance->source = strdup(params[i]->value);
|
||||
my_instance->source = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "user"))
|
||||
{
|
||||
my_instance->user = strdup(params[i]->value);
|
||||
my_instance->user = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!filter_standard_parameter(params[i]->name))
|
||||
{
|
||||
@ -180,6 +181,8 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
}
|
||||
}
|
||||
|
||||
int cflags = REG_ICASE;
|
||||
|
||||
if (options)
|
||||
{
|
||||
for (int i = 0; options[i]; i++)
|
||||
@ -221,7 +224,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
MXS_ERROR("namedserverfilter: Invalid regular expression '%s'.\n",
|
||||
my_instance->match);
|
||||
free(my_instance->match);
|
||||
MXS_FREE(my_instance->match);
|
||||
my_instance->match = NULL;
|
||||
error = true;
|
||||
}
|
||||
@ -231,12 +234,12 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
if (my_instance->match)
|
||||
{
|
||||
regfree(&my_instance->re);
|
||||
free(my_instance->match);
|
||||
MXS_FREE(my_instance->match);
|
||||
}
|
||||
free(my_instance->server);
|
||||
free(my_instance->source);
|
||||
free(my_instance->user);
|
||||
free(my_instance);
|
||||
MXS_FREE(my_instance->server);
|
||||
MXS_FREE(my_instance->source);
|
||||
MXS_FREE(my_instance->user);
|
||||
MXS_FREE(my_instance);
|
||||
my_instance = NULL;
|
||||
}
|
||||
|
||||
@ -258,7 +261,7 @@ newSession(FILTER *instance, SESSION *session)
|
||||
REGEXHINT_SESSION *my_session;
|
||||
char *remote, *user;
|
||||
|
||||
if ((my_session = calloc(1, sizeof(REGEXHINT_SESSION))) != NULL)
|
||||
if ((my_session = MXS_CALLOC(1, sizeof(REGEXHINT_SESSION))) != NULL)
|
||||
{
|
||||
my_session->n_diverted = 0;
|
||||
my_session->n_undiverted = 0;
|
||||
@ -303,7 +306,7 @@ closeSession(FILTER *instance, void *session)
|
||||
static void
|
||||
freeSession(FILTER *instance, void *session)
|
||||
{
|
||||
free(session);
|
||||
MXS_FREE(session);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -361,7 +364,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
{
|
||||
my_session->n_undiverted++;
|
||||
}
|
||||
free(sql);
|
||||
MXS_FREE(sql);
|
||||
}
|
||||
}
|
||||
return my_session->down.routeQuery(my_session->down.instance,
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -47,6 +47,7 @@
|
||||
#include <regex.h>
|
||||
#include <string.h>
|
||||
#include <atomic.h>
|
||||
#include <maxscale/alloc.h>
|
||||
|
||||
MODULE_INFO info =
|
||||
{
|
||||
@ -173,10 +174,9 @@ GetModuleObject()
|
||||
static FILTER *
|
||||
createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
QLA_INSTANCE *my_instance;
|
||||
int i;
|
||||
QLA_INSTANCE *my_instance = (QLA_INSTANCE*) MXS_MALLOC(sizeof(QLA_INSTANCE));
|
||||
|
||||
if ((my_instance = malloc(sizeof(QLA_INSTANCE))) != NULL)
|
||||
if (my_instance)
|
||||
{
|
||||
my_instance->source = NULL;
|
||||
my_instance->userName = NULL;
|
||||
@ -187,27 +187,27 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
|
||||
if (params)
|
||||
{
|
||||
for (i = 0; params[i]; i++)
|
||||
for (int i = 0; params[i]; i++)
|
||||
{
|
||||
if (!strcmp(params[i]->name, "match"))
|
||||
{
|
||||
my_instance->match = strdup(params[i]->value);
|
||||
my_instance->match = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "exclude"))
|
||||
{
|
||||
my_instance->nomatch = strdup(params[i]->value);
|
||||
my_instance->nomatch = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "source"))
|
||||
{
|
||||
my_instance->source = strdup(params[i]->value);
|
||||
my_instance->source = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "user"))
|
||||
{
|
||||
my_instance->userName = strdup(params[i]->value);
|
||||
my_instance->userName = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "filebase"))
|
||||
{
|
||||
my_instance->filebase = strdup(params[i]->value);
|
||||
my_instance->filebase = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!filter_standard_parameter(params[i]->name))
|
||||
{
|
||||
@ -222,7 +222,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
|
||||
if (options)
|
||||
{
|
||||
for (i = 0; options[i]; i++)
|
||||
for (int i = 0; options[i]; i++)
|
||||
{
|
||||
if (!strcasecmp(options[i], "ignorecase"))
|
||||
{
|
||||
@ -258,7 +258,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
MXS_ERROR("qlafilter: Invalid regular expression '%s'"
|
||||
" for the 'match' parameter.\n",
|
||||
my_instance->match);
|
||||
free(my_instance->match);
|
||||
MXS_FREE(my_instance->match);
|
||||
my_instance->match = NULL;
|
||||
error = true;
|
||||
}
|
||||
@ -268,7 +268,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
MXS_ERROR("qlafilter: Invalid regular expression '%s'"
|
||||
" for the 'nomatch' parameter.",
|
||||
my_instance->nomatch);
|
||||
free(my_instance->nomatch);
|
||||
MXS_FREE(my_instance->nomatch);
|
||||
my_instance->nomatch = NULL;
|
||||
error = true;
|
||||
}
|
||||
@ -277,19 +277,19 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
if (my_instance->match)
|
||||
{
|
||||
free(my_instance->match);
|
||||
MXS_FREE(my_instance->match);
|
||||
regfree(&my_instance->re);
|
||||
}
|
||||
|
||||
if (my_instance->nomatch)
|
||||
{
|
||||
free(my_instance->nomatch);
|
||||
MXS_FREE(my_instance->nomatch);
|
||||
regfree(&my_instance->nore);
|
||||
}
|
||||
free(my_instance->filebase);
|
||||
free(my_instance->source);
|
||||
free(my_instance->userName);
|
||||
free(my_instance);
|
||||
MXS_FREE(my_instance->filebase);
|
||||
MXS_FREE(my_instance->source);
|
||||
MXS_FREE(my_instance->userName);
|
||||
MXS_FREE(my_instance);
|
||||
my_instance = NULL;
|
||||
}
|
||||
}
|
||||
@ -312,16 +312,11 @@ newSession(FILTER *instance, SESSION *session)
|
||||
QLA_SESSION *my_session;
|
||||
char *remote, *userName;
|
||||
|
||||
if ((my_session = calloc(1, sizeof(QLA_SESSION))) != NULL)
|
||||
if ((my_session = MXS_CALLOC(1, sizeof(QLA_SESSION))) != NULL)
|
||||
{
|
||||
if ((my_session->filename = (char *)malloc(strlen(my_instance->filebase) + 20)) == NULL)
|
||||
if ((my_session->filename = (char *)MXS_MALLOC(strlen(my_instance->filebase) + 20)) == NULL)
|
||||
{
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
MXS_ERROR("Memory allocation for qla filter "
|
||||
"file name failed due to %d, %s.",
|
||||
errno,
|
||||
strerror_r(errno, errbuf, sizeof(errbuf)));
|
||||
free(my_session);
|
||||
MXS_FREE(my_session);
|
||||
return NULL;
|
||||
}
|
||||
my_session->active = 1;
|
||||
@ -359,8 +354,8 @@ newSession(FILTER *instance, SESSION *session)
|
||||
"fileter failed due to %d, %s",
|
||||
errno,
|
||||
strerror_r(errno, errbuf, sizeof(errbuf)));
|
||||
free(my_session->filename);
|
||||
free(my_session);
|
||||
MXS_FREE(my_session->filename);
|
||||
MXS_FREE(my_session);
|
||||
my_session = NULL;
|
||||
}
|
||||
}
|
||||
@ -406,8 +401,8 @@ freeSession(FILTER *instance, void *session)
|
||||
{
|
||||
QLA_SESSION *my_session = (QLA_SESSION *) session;
|
||||
|
||||
free(my_session->filename);
|
||||
free(session);
|
||||
MXS_FREE(my_session->filename);
|
||||
MXS_FREE(session);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -467,7 +462,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
fprintf(my_session->fp, "%s,%s@%s,%s\n", buffer, my_session->user,
|
||||
my_session->remote, trim(squeeze_whitespace(ptr)));
|
||||
}
|
||||
free(ptr);
|
||||
MXS_FREE(ptr);
|
||||
}
|
||||
}
|
||||
/* Pass the query downstream */
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -21,6 +21,7 @@
|
||||
#include <string.h>
|
||||
#include <pcre2.h>
|
||||
#include <atomic.h>
|
||||
#include <maxscale/alloc.h>
|
||||
#include "maxconfig.h"
|
||||
|
||||
/**
|
||||
@ -159,11 +160,11 @@ void free_instance(REGEX_INSTANCE *instance)
|
||||
pcre2_match_data_free(instance->match_data);
|
||||
}
|
||||
|
||||
free(instance->match);
|
||||
free(instance->replace);
|
||||
free(instance->source);
|
||||
free(instance->user);
|
||||
free(instance);
|
||||
MXS_FREE(instance->match);
|
||||
MXS_FREE(instance->replace);
|
||||
MXS_FREE(instance->source);
|
||||
MXS_FREE(instance->user);
|
||||
MXS_FREE(instance);
|
||||
}
|
||||
}
|
||||
|
||||
@ -185,7 +186,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
char *logfile = NULL;
|
||||
const char *errmsg;
|
||||
|
||||
if ((my_instance = calloc(1, sizeof(REGEX_INSTANCE))) != NULL)
|
||||
if ((my_instance = MXS_CALLOC(1, sizeof(REGEX_INSTANCE))) != NULL)
|
||||
{
|
||||
my_instance->match = NULL;
|
||||
my_instance->replace = NULL;
|
||||
@ -194,19 +195,19 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
if (!strcmp(params[i]->name, "match"))
|
||||
{
|
||||
my_instance->match = strdup(params[i]->value);
|
||||
my_instance->match = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "replace"))
|
||||
{
|
||||
my_instance->replace = strdup(params[i]->value);
|
||||
my_instance->replace = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "source"))
|
||||
{
|
||||
my_instance->source = strdup(params[i]->value);
|
||||
my_instance->source = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "user"))
|
||||
{
|
||||
my_instance->user = strdup(params[i]->value);
|
||||
my_instance->user = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "log_trace"))
|
||||
{
|
||||
@ -216,9 +217,9 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
if (logfile)
|
||||
{
|
||||
free(logfile);
|
||||
MXS_FREE(logfile);
|
||||
}
|
||||
logfile = strdup(params[i]->value);
|
||||
logfile = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!filter_standard_parameter(params[i]->name))
|
||||
{
|
||||
@ -253,14 +254,14 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
MXS_ERROR("regexfilter: Failed to open file '%s'.", logfile);
|
||||
free_instance(my_instance);
|
||||
free(logfile);
|
||||
MXS_FREE(logfile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fprintf(my_instance->logfile, "\nOpened regex filter log\n");
|
||||
fflush(my_instance->logfile);
|
||||
}
|
||||
free(logfile);
|
||||
MXS_FREE(logfile);
|
||||
|
||||
if (my_instance->match == NULL || my_instance->replace == NULL)
|
||||
{
|
||||
@ -309,7 +310,7 @@ newSession(FILTER *instance, SESSION *session)
|
||||
REGEX_SESSION *my_session;
|
||||
char *remote, *user;
|
||||
|
||||
if ((my_session = calloc(1, sizeof(REGEX_SESSION))) != NULL)
|
||||
if ((my_session = MXS_CALLOC(1, sizeof(REGEX_SESSION))) != NULL)
|
||||
{
|
||||
my_session->no_change = 0;
|
||||
my_session->replacements = 0;
|
||||
@ -354,7 +355,7 @@ closeSession(FILTER *instance, void *session)
|
||||
static void
|
||||
freeSession(FILTER *instance, void *session)
|
||||
{
|
||||
free(session);
|
||||
MXS_FREE(session);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -408,7 +409,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
spinlock_acquire(&my_session->lock);
|
||||
log_match(my_instance, my_instance->match, sql, newsql);
|
||||
spinlock_release(&my_session->lock);
|
||||
free(newsql);
|
||||
MXS_FREE(newsql);
|
||||
my_session->replacements++;
|
||||
}
|
||||
else
|
||||
@ -418,7 +419,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
spinlock_release(&my_session->lock);
|
||||
my_session->no_change++;
|
||||
}
|
||||
free(sql);
|
||||
MXS_FREE(sql);
|
||||
}
|
||||
|
||||
}
|
||||
@ -485,7 +486,7 @@ regex_replace(const char *sql, pcre2_code *re, pcre2_match_data *match_data, con
|
||||
if (pcre2_match(re, (PCRE2_SPTR) sql, PCRE2_ZERO_TERMINATED, 0, 0, match_data, NULL))
|
||||
{
|
||||
result_size = strlen(sql) + strlen(replace);
|
||||
result = malloc(result_size);
|
||||
result = MXS_MALLOC(result_size);
|
||||
|
||||
while (result &&
|
||||
pcre2_substitute(re, (PCRE2_SPTR) sql, PCRE2_ZERO_TERMINATED, 0,
|
||||
@ -494,9 +495,9 @@ regex_replace(const char *sql, pcre2_code *re, pcre2_match_data *match_data, con
|
||||
(PCRE2_UCHAR*) result, (PCRE2_SIZE*) & result_size) == PCRE2_ERROR_NOMEMORY)
|
||||
{
|
||||
char *tmp;
|
||||
if ((tmp = realloc(result, (result_size *= 1.5))) == NULL)
|
||||
if ((tmp = MXS_REALLOC(result, (result_size *= 1.5))) == NULL)
|
||||
{
|
||||
free(result);
|
||||
MXS_FREE(result);
|
||||
result = NULL;
|
||||
}
|
||||
result = tmp;
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -58,6 +58,8 @@
|
||||
#include <maxscale/poll.h>
|
||||
#include <mysql_client_server_protocol.h>
|
||||
#include <housekeeper.h>
|
||||
#include <maxscale/alloc.h>
|
||||
#include <listmanager.h>
|
||||
|
||||
#define MYSQL_COM_QUIT 0x01
|
||||
#define MYSQL_COM_INITDB 0x02
|
||||
@ -209,6 +211,8 @@ int route_single_query(TEE_INSTANCE* my_instance,
|
||||
int reset_session_state(TEE_SESSION* my_session, GWBUF* buffer);
|
||||
void create_orphan(SESSION* ses);
|
||||
|
||||
extern LIST_CONFIG SESSIONlist;
|
||||
|
||||
static void
|
||||
orphan_free(void* data)
|
||||
{
|
||||
@ -293,8 +297,8 @@ orphan_free(void* data)
|
||||
tmp->session->router_session);
|
||||
|
||||
tmp->session->state = SESSION_STATE_FREE;
|
||||
free(tmp->session);
|
||||
free(tmp);
|
||||
list_free_entry(&SESSIONlist, (list_entry_t*)tmp->session);
|
||||
MXS_FREE(tmp);
|
||||
}
|
||||
|
||||
#ifdef SS_DEBUG
|
||||
@ -358,7 +362,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
TEE_INSTANCE *my_instance;
|
||||
int i;
|
||||
|
||||
if ((my_instance = calloc(1, sizeof(TEE_INSTANCE))) != NULL)
|
||||
if ((my_instance = MXS_CALLOC(1, sizeof(TEE_INSTANCE))) != NULL)
|
||||
{
|
||||
if (options)
|
||||
{
|
||||
@ -384,19 +388,19 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "match"))
|
||||
{
|
||||
my_instance->match = strdup(params[i]->value);
|
||||
my_instance->match = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "exclude"))
|
||||
{
|
||||
my_instance->nomatch = strdup(params[i]->value);
|
||||
my_instance->nomatch = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "source"))
|
||||
{
|
||||
my_instance->source = strdup(params[i]->value);
|
||||
my_instance->source = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "user"))
|
||||
{
|
||||
my_instance->userName = strdup(params[i]->value);
|
||||
my_instance->userName = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!filter_standard_parameter(params[i]->name))
|
||||
{
|
||||
@ -434,9 +438,9 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
|
||||
if (my_instance->service == NULL)
|
||||
{
|
||||
free(my_instance->match);
|
||||
free(my_instance->source);
|
||||
free(my_instance);
|
||||
MXS_FREE(my_instance->match);
|
||||
MXS_FREE(my_instance->source);
|
||||
MXS_FREE(my_instance);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -446,10 +450,10 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
MXS_ERROR("tee: Invalid regular expression '%s'"
|
||||
" for the match parameter.",
|
||||
my_instance->match);
|
||||
free(my_instance->match);
|
||||
free(my_instance->nomatch);
|
||||
free(my_instance->source);
|
||||
free(my_instance);
|
||||
MXS_FREE(my_instance->match);
|
||||
MXS_FREE(my_instance->nomatch);
|
||||
MXS_FREE(my_instance->source);
|
||||
MXS_FREE(my_instance);
|
||||
return NULL;
|
||||
}
|
||||
if (my_instance->nomatch &&
|
||||
@ -461,11 +465,11 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
if (my_instance->match)
|
||||
{
|
||||
regfree(&my_instance->re);
|
||||
free(my_instance->match);
|
||||
MXS_FREE(my_instance->match);
|
||||
}
|
||||
free(my_instance->nomatch);
|
||||
free(my_instance->source);
|
||||
free(my_instance);
|
||||
MXS_FREE(my_instance->nomatch);
|
||||
MXS_FREE(my_instance->source);
|
||||
MXS_FREE(my_instance);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@ -496,7 +500,7 @@ newSession(FILTER *instance, SESSION *session)
|
||||
goto retblock;
|
||||
}
|
||||
|
||||
HASHTABLE* ht = hashtable_alloc(100, simple_str_hash, strcmp);
|
||||
HASHTABLE* ht = hashtable_alloc(100, hashtable_item_strhash, hashtable_item_strcmp);
|
||||
bool is_loop = detect_loops(my_instance, ht, session->service);
|
||||
hashtable_free(ht);
|
||||
|
||||
@ -508,7 +512,7 @@ newSession(FILTER *instance, SESSION *session)
|
||||
goto retblock;
|
||||
}
|
||||
|
||||
if ((my_session = calloc(1, sizeof(TEE_SESSION))) != NULL)
|
||||
if ((my_session = MXS_CALLOC(1, sizeof(TEE_SESSION))) != NULL)
|
||||
{
|
||||
my_session->active = 1;
|
||||
my_session->residual = 0;
|
||||
@ -597,7 +601,7 @@ newSession(FILTER *instance, SESSION *session)
|
||||
filter_free(dummy);
|
||||
closeSession(instance, (void*) my_session);
|
||||
dcb_close(dcb);
|
||||
free(my_session);
|
||||
MXS_FREE(my_session);
|
||||
MXS_ERROR("tee: Allocating memory for"
|
||||
"dummy upstream failed."
|
||||
" Terminating session.");
|
||||
@ -608,7 +612,7 @@ newSession(FILTER *instance, SESSION *session)
|
||||
ses->tail = *dummy_upstream;
|
||||
MySQLProtocol* protocol = (MySQLProtocol*) session->client_dcb->protocol;
|
||||
my_session->use_ok = protocol->client_capabilities & (1 << 6);
|
||||
free(dummy_upstream);
|
||||
MXS_FREE(dummy_upstream);
|
||||
}
|
||||
}
|
||||
retblock:
|
||||
@ -707,7 +711,7 @@ freeSession(FILTER *instance, void *session)
|
||||
ses->router_session);
|
||||
/** Free memory of branch client session */
|
||||
ses->state = SESSION_STATE_FREE;
|
||||
free(ses);
|
||||
MXS_FREE(ses);
|
||||
/** This indicates that branch session is not available anymore */
|
||||
my_session->branch_session = NULL;
|
||||
}
|
||||
@ -724,7 +728,7 @@ freeSession(FILTER *instance, void *session)
|
||||
{
|
||||
gwbuf_free(my_session->tee_replybuf);
|
||||
}
|
||||
free(session);
|
||||
MXS_FREE(session);
|
||||
|
||||
orphan_free(NULL);
|
||||
|
||||
@ -1248,7 +1252,7 @@ GWBUF* clone_query(TEE_INSTANCE* my_instance, TEE_SESSION* my_session, GWBUF* bu
|
||||
clone = gwbuf_clone_all(buffer);
|
||||
my_session->residual = residual;
|
||||
}
|
||||
free(ptr);
|
||||
MXS_FREE(ptr);
|
||||
}
|
||||
else if (packet_is_required(buffer))
|
||||
{
|
||||
@ -1357,14 +1361,8 @@ int reset_session_state(TEE_SESSION* my_session, GWBUF* buffer)
|
||||
|
||||
void create_orphan(SESSION* ses)
|
||||
{
|
||||
orphan_session_t* orphan;
|
||||
if ((orphan = malloc(sizeof(orphan_session_t))) == NULL)
|
||||
{
|
||||
MXS_ERROR("Failed to "
|
||||
"allocate memory for orphan session struct, "
|
||||
"child session might leak memory.");
|
||||
}
|
||||
else
|
||||
orphan_session_t* orphan = MXS_MALLOC(sizeof(orphan_session_t));
|
||||
if (orphan)
|
||||
{
|
||||
orphan->session = ses;
|
||||
spinlock_acquire(&orphanLock);
|
||||
|
@ -1,26 +0,0 @@
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
add_executable(harness_ui harness_ui.c harness_common.c)
|
||||
add_executable(harness harness_util.c harness_common.c)
|
||||
target_link_libraries(harness_ui maxscale-common)
|
||||
target_link_libraries(harness maxscale-common)
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy ${ERRMSG} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/harness.cnf ${CMAKE_CURRENT_BINARY_DIR})
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/testdriver.sh ${CMAKE_CURRENT_BINARY_DIR}/testdriver.sh @ONLY)
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/hintfilter/hint_testing.cnf ${CMAKE_CURRENT_BINARY_DIR}/hintfilter/hint_testing.cnf)
|
||||
add_test(TestHintfilter testdriver.sh hintfilter/hint_testing.cnf hintfilter/hint_testing.input hintfilter/hint_testing.output hintfilter/hint_testing.expected)
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/regexfilter/regextest.cnf ${CMAKE_CURRENT_BINARY_DIR}/regexfilter/regextest.cnf)
|
||||
add_test(TestRegexfilter testdriver.sh regexfilter/regextest.cnf regexfilter/regextest.input regexfilter/regextest.output regexfilter/regextest.expected)
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fwfilter/fwtest.cnf.in ${CMAKE_CURRENT_BINARY_DIR}/fwfilter/fwtest.cnf)
|
||||
add_test(TestFwfilter1 testdriver.sh fwfilter/fwtest.cnf fwfilter/fwtest.input fwfilter/fwtest.output fwfilter/fwtest.expected)
|
||||
add_test(TestFwfilter2 testdriver.sh fwfilter/fwtest.cnf fwfilter/fwtest2.input fwfilter/fwtest2.output fwfilter/fwtest2.expected)
|
||||
|
||||
add_test(TestTeeRecursion ${CMAKE_CURRENT_SOURCE_DIR}/tee_recursion.sh
|
||||
${CMAKE_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}
|
||||
${TEST_USER}
|
||||
${TEST_PASSWORD}
|
||||
${TEST_HOST}
|
||||
${TEST_PORT})
|
@ -1,20 +0,0 @@
|
||||
Filter Test Harness
|
||||
|
||||
For a more detailed description of the filter harness, either generate the documentation or read the harness.h file.
|
||||
|
||||
Running the program without arguments enters the interactive mode. Type 'help' for a list of all commands.
|
||||
|
||||
The default values for threads and sessions are stored in the 'harness.cnf' file
|
||||
|
||||
Mandatory parameters for the command line mode are -c and -i.
|
||||
|
||||
Parameters for the command line:
|
||||
|
||||
-h Display this information
|
||||
-c Path to the MaxScale configuration file to parse for filters
|
||||
-i Name of the input file for buffers
|
||||
-o Name of the output file for results
|
||||
-q Suppress printing to stdout
|
||||
-t Number of threads
|
||||
-s Number of sessions
|
||||
-d Routing delay
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +0,0 @@
|
||||
[Firewall]
|
||||
type=filter
|
||||
module=dbfwfilter
|
||||
rules=@CMAKE_CURRENT_SOURCE_DIR@/rules
|
@ -1,8 +0,0 @@
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
@ -1,10 +0,0 @@
|
||||
delete from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
delete from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
@ -1,8 +0,0 @@
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
@ -1,8 +0,0 @@
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
@ -1,10 +0,0 @@
|
||||
select id from t1;
|
||||
select id from t1 union select name from t2;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1 union select name from t2;
|
||||
select id from t1;
|
||||
select id from t1;
|
@ -1,2 +0,0 @@
|
||||
threads=2
|
||||
sessions=4
|
@ -1,371 +0,0 @@
|
||||
#ifndef _FILTER_HARNESS_H
|
||||
#define _FILTER_HARNESS_H
|
||||
/*
|
||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
* Public License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test harness for independent testing of filters
|
||||
*
|
||||
* A test harness that feeds a GWBUF to a chain of filters and prints the results
|
||||
* either into a file or to the standard output.
|
||||
*
|
||||
* The contents of the GWBUF and the filter parameters are either manually set through
|
||||
* the command line or read from a file.
|
||||
* @verbatim
|
||||
* Options for the configuration file 'harness.cnf'':
|
||||
*
|
||||
* threads Number of threads to use when routing buffers
|
||||
* sessions Number of sessions
|
||||
*
|
||||
* Options for the command line:
|
||||
*
|
||||
* -c Path to the MaxScale configuration file to parse for filters
|
||||
* -i Name of the input file for buffers
|
||||
* -o Name of the output file for results
|
||||
* -q Suppress printing to stdout
|
||||
* -s Number of sessions
|
||||
* -t Number of threads
|
||||
* -d Routing delay, in milliseconds
|
||||
*
|
||||
*
|
||||
* Revision History
|
||||
*
|
||||
* Date Who Description
|
||||
* 01/07/14 Markus Makela Initial implementation
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <filter.h>
|
||||
#include <buffer.h>
|
||||
#include <modules.h>
|
||||
#include <modutil.h>
|
||||
#include <skygw_utils.h>
|
||||
#include <log_manager.h>
|
||||
#include <atomic.h>
|
||||
#include <ini.h>
|
||||
#include <hint.h>
|
||||
#include <modutil.h>
|
||||
#include <errno.h>
|
||||
#include <mysql_client_server_protocol.h>
|
||||
|
||||
/**
|
||||
* A single name-value pair and a link to the next item in the
|
||||
* configuration.
|
||||
*/
|
||||
typedef struct CONFIG_ITEM_T
|
||||
{
|
||||
char* name;
|
||||
char* value;
|
||||
struct CONFIG_ITEM_T* next;
|
||||
}CONFIG_ITEM;
|
||||
|
||||
/**
|
||||
*A simplified version of a MaxScale configuration context used to load filters
|
||||
* and their options.
|
||||
*/
|
||||
typedef struct CONFIG_T
|
||||
{
|
||||
char* section;
|
||||
CONFIG_ITEM* item;
|
||||
struct CONFIG_T* next;
|
||||
|
||||
}CONFIG;
|
||||
|
||||
/**
|
||||
*A structure that holds all the necessary information to emulate a working
|
||||
* filter environment.
|
||||
*/
|
||||
struct FILTERCHAIN_T
|
||||
{
|
||||
FILTER* filter; /**An instance of a particular filter*/
|
||||
FILTER_OBJECT* instance; /**Dynamically loaded module*/
|
||||
SESSION** session; /**A list of sessions*/
|
||||
DOWNSTREAM** down; /** A list of next filters downstreams*/
|
||||
UPSTREAM** up; /** A list of next filters upstreams*/
|
||||
char* name; /**Module name*/
|
||||
struct FILTERCHAIN_T* next;
|
||||
};
|
||||
|
||||
typedef struct FILTERCHAIN_T FILTERCHAIN;
|
||||
|
||||
/**
|
||||
* A container for all the filters, query buffers and user specified parameters
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int running;
|
||||
int verbose; /**Whether to print to stdout*/
|
||||
int infile; /**A file where the queries are loaded from*/
|
||||
int expected;
|
||||
int error;
|
||||
char* mod_dir; /**Module directory absolute path*/
|
||||
char* infile_name;
|
||||
int outfile; /**A file where the output of the filters is logged*/
|
||||
char* outfile_name;
|
||||
FILTERCHAIN* head; /**The head of the filter chain*/
|
||||
FILTERCHAIN* tail; /**The tail of the filter chain*/
|
||||
GWBUF** buffer; /**Buffers that are fed to the filter chain*/
|
||||
SESSION* session;
|
||||
int buffer_count;
|
||||
int session_count;
|
||||
DOWNSTREAM dummyrouter; /**Dummy downstream router for data extraction*/
|
||||
UPSTREAM dummyclient; /**Dummy downstream router for data extraction*/
|
||||
CONFIG* conf; /**Configurations loaded from a file*/
|
||||
pthread_mutex_t work_mtx; /**Mutex for buffer routing*/
|
||||
int buff_ind; /**Index of first unrouted buffer*/
|
||||
int sess_ind;/**Index of first unused session*/
|
||||
int last_ind; /**Index of last used session*/
|
||||
pthread_t* thrpool;
|
||||
int thrcount; /**Number of active threads*/
|
||||
int rt_delay; /**Delay each thread waits after routing a query, in milliseconds*/
|
||||
}HARNESS_INSTANCE;
|
||||
|
||||
static HARNESS_INSTANCE instance;
|
||||
|
||||
/**
|
||||
*A list of available actions.
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
UNDEFINED,
|
||||
RUNFILTERS,
|
||||
LOAD_FILTER,
|
||||
DELETE_FILTER,
|
||||
LOAD_CONFIG,
|
||||
SET_INFILE,
|
||||
SET_OUTFILE,
|
||||
THR_COUNT,
|
||||
SESS_COUNT,
|
||||
OK,
|
||||
QUIT
|
||||
} operation_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PACKET_OK,
|
||||
PACKET_ERROR,
|
||||
PACKET_RESULT_SET
|
||||
} packet_t;
|
||||
|
||||
typedef packet_t PACKET;
|
||||
|
||||
/**
|
||||
* Initialize the static instance.
|
||||
*/
|
||||
int harness_init(int argc,char** argv,HARNESS_INSTANCE** inst);
|
||||
|
||||
/**
|
||||
* Frees all the query buffers
|
||||
*/
|
||||
void free_buffers();
|
||||
|
||||
/**
|
||||
* Frees all the loaded filters
|
||||
*/
|
||||
void free_filters();
|
||||
|
||||
/**
|
||||
* Converts the passed string into an operation
|
||||
*
|
||||
* @param tk The string to parse
|
||||
* @return The operation to perform or UNDEFINED, if parsing failed
|
||||
*/
|
||||
operation_t user_input(char* tk);
|
||||
|
||||
/**
|
||||
*Prints a list of available commands.
|
||||
*/
|
||||
void print_help();
|
||||
|
||||
/**
|
||||
* Prints the current status of loaded filters and queries, number of threads
|
||||
* and sessions and possible output files.
|
||||
*/
|
||||
void print_status();
|
||||
|
||||
/**
|
||||
*Opens a file for reading and/or writing with adequate permissions.
|
||||
*
|
||||
* @param str Path to file
|
||||
* @param write Non-zero for write permissions, zero for read only.
|
||||
* @return The assigned file descriptor or -1 in case an error occurred
|
||||
*/
|
||||
int open_file(char* str, unsigned int write);
|
||||
|
||||
/**
|
||||
* Reads filter parameters from the command line as name-value pairs.
|
||||
*
|
||||
*@param paramc The number of parameters read is assigned to this variable
|
||||
*@return The newly allocated list of parameters with the last one being NULL
|
||||
*/
|
||||
FILTER_PARAMETER** read_params(int* paramc);
|
||||
|
||||
/**
|
||||
* Dummy endpoint for the queries of the filter chain
|
||||
*
|
||||
* Prints and logs the contents of the GWBUF after it has passed through all the filters.
|
||||
* The packet is handled as a COM_QUERY packet and the packet header is not printed.
|
||||
*/
|
||||
int routeQuery(void* instance, void* session, GWBUF* queue);
|
||||
|
||||
/**
|
||||
* Dummy endpoint for the replies of the filter chain
|
||||
*
|
||||
* Prints and logs the contents of the GWBUF after it has passed through all the filters.
|
||||
* The packet is handled as a OK packet with no message and the packet header is not printed.
|
||||
*/
|
||||
int clientReply(void* ins, void* session, GWBUF* queue);
|
||||
|
||||
/**
|
||||
*Manual input if a query string
|
||||
*
|
||||
* Reads a single query from the standard input and inserts it into a GWBUF.
|
||||
*/
|
||||
void manual_query();
|
||||
|
||||
/**
|
||||
*Loads the file pointed by @{instance.infile}
|
||||
* @return Zero if successful, non-zero if an error occurred
|
||||
*/
|
||||
int load_query();
|
||||
|
||||
/**
|
||||
* Handler for the INI file parser that builds a linked list
|
||||
* of all the sections and their name-value pairs.
|
||||
* @param user Current configuration.
|
||||
* @param section Name of the section.
|
||||
* @param name Name of the item.
|
||||
* @param value Value of the item.
|
||||
* @return Non-zero on success, zero in case parsing is finished.
|
||||
* @see load_config()
|
||||
*/
|
||||
int handler(void* user, const char* section, const char* name,const char* value);
|
||||
|
||||
/**
|
||||
* Removes all non-filter modules from the configuration
|
||||
*
|
||||
* @param conf A pointer to a configuration struct
|
||||
* @return The stripped version of the configuration
|
||||
* @see load_config()
|
||||
*/
|
||||
CONFIG* process_config(CONFIG* conf);
|
||||
|
||||
/**
|
||||
* Loads the filter module and link it to the filter chain
|
||||
*
|
||||
* The downstream is set to point to the current head of the filter chain
|
||||
*
|
||||
* @param str Name of the filter module
|
||||
* @return Pointer to the newly initialized FILTER_CHAIN element or NULL in case module loading failed
|
||||
* @see load_filter()
|
||||
*/
|
||||
FILTERCHAIN* load_filter_module(char* str);
|
||||
|
||||
/**
|
||||
* Loads a new instance of a filter and starts a new session.
|
||||
* This function assumes that the filter module is already loaded.
|
||||
* Passing NULL as the CONFIG parameter causes the parameters to be
|
||||
* read from the command line one at a time.
|
||||
*
|
||||
* @param fc The FILTERCHAIN where the new instance and session are created
|
||||
* @param cnf A configuration read from a file
|
||||
* @return 1 on success, 0 in case an error occurred
|
||||
* @see load_filter_module()
|
||||
*/
|
||||
int load_filter(FILTERCHAIN* fc, CONFIG* cnf);
|
||||
|
||||
/**
|
||||
* Reads a MaxScale configuration (or any INI file using MaxScale notation) file and loads only the filter modules in it.
|
||||
*
|
||||
* @param fname Configuration file name
|
||||
* @return Non-zero on success, zero in case an error occurred.
|
||||
*/
|
||||
int load_config(char* fname);
|
||||
|
||||
/**
|
||||
* Initializes the indexes used while routing buffers and prints the progress
|
||||
* of the routing process.
|
||||
*/
|
||||
void route_buffers();
|
||||
|
||||
/**
|
||||
* Worker function for threads.
|
||||
* Routes a query buffer if there are unrouted buffers left.
|
||||
*
|
||||
* @param thr_num ID number of the thread
|
||||
*/
|
||||
void work_buffer(void* thr_num);
|
||||
|
||||
/**
|
||||
* Generates a fake packet used to emulate a response from the backend.
|
||||
*
|
||||
* Current implementation only works with PACKET_OK and the packet has no message.
|
||||
* The caller is responsible for freeing the allocated memory by calling gwbuf_free().
|
||||
* @param pkt The packet type
|
||||
* @return The newly generated packet or NULL if an error occurred
|
||||
*/
|
||||
GWBUF* gen_packet(PACKET pkt);
|
||||
|
||||
/**
|
||||
* Process the command line parameters and the harness configuration file.
|
||||
*
|
||||
* Reads the contents of the 'harness.cnf' file and command line parameters
|
||||
* and parses them. Options are interpreted accoding to the following table.
|
||||
* If no command line arguments are given, interactive mode is used.
|
||||
*
|
||||
* By default if no input file is given or no configuration file or specific
|
||||
* filters are given, but other options are, the program exits with 0.
|
||||
*
|
||||
* Options for the configuration file 'harness.cnf'':
|
||||
*
|
||||
* threads Number of threads to use when routing buffers
|
||||
* sessions Number of sessions
|
||||
*
|
||||
* Options for the command line:
|
||||
*
|
||||
* -h Display this information
|
||||
* -c Path to the MaxScale configuration file to parse for filters
|
||||
* -i Name of the input file for buffers
|
||||
* -o Name of the output file for results
|
||||
* -q Suppress printing to stdout
|
||||
* -t Number of threads
|
||||
* -s Number of sessions
|
||||
* -d Routing delay
|
||||
*
|
||||
* @param argc Number of arguments
|
||||
* @param argv List of argument strings
|
||||
* @return 1 if successful, 0 if no input file, configuration file or specific
|
||||
* filters are given, but other options are, or if an error occurs.
|
||||
*/
|
||||
int process_opts(int argc, char** argv);
|
||||
|
||||
/**
|
||||
* Compares the contents of two files.
|
||||
* This function resets the offsets of the file descriptors and leaves them in an
|
||||
* undefined state.
|
||||
* @param a The first file
|
||||
* @param b The second file
|
||||
* @return 0 if the files do not differ and 1 if they do or an error occurred.
|
||||
*/
|
||||
int compare_files(int a, int b);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,400 +0,0 @@
|
||||
#include <harness.h>
|
||||
|
||||
int main(int argc, char** argv){
|
||||
int i;
|
||||
char buffer[256];
|
||||
char* tk;
|
||||
FILTERCHAIN* tmp_chn;
|
||||
FILTERCHAIN* del_chn;
|
||||
HARNESS_INSTANCE* hinstance;
|
||||
|
||||
if(harness_init(argc,argv,&hinstance)){
|
||||
printf("Error: Initialization failed.\n");
|
||||
MXS_ERROR("Initialization failed.\n");
|
||||
mxs_log_finish();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(instance.verbose){
|
||||
printf("\n\n\tFilter Test Harness\n\n");
|
||||
}
|
||||
|
||||
while(instance.running){
|
||||
printf("Harness> ");
|
||||
memset(buffer,0,256);
|
||||
fgets(buffer,256,stdin);
|
||||
tk = strtok(buffer," \n");
|
||||
switch(user_input(tk))
|
||||
{
|
||||
case RUNFILTERS:
|
||||
if(instance.head->next == NULL){
|
||||
printf("No filters loaded.\n");
|
||||
break;
|
||||
}
|
||||
if(instance.buffer == NULL){
|
||||
if(instance.infile<0){
|
||||
manual_query();
|
||||
}else{
|
||||
load_query();
|
||||
}
|
||||
}
|
||||
|
||||
route_buffers();
|
||||
break;
|
||||
|
||||
case LOAD_FILTER:
|
||||
|
||||
tk = strtok(NULL," \n");
|
||||
tmp_chn = load_filter_module(tk);
|
||||
if(!tmp_chn || !load_filter(tmp_chn,instance.conf)){
|
||||
printf("Error creating filter instance.\n");
|
||||
MXS_ERROR("Error creating filter instance.\n");
|
||||
}else{
|
||||
instance.head = tmp_chn;
|
||||
}
|
||||
break;
|
||||
|
||||
case DELETE_FILTER:
|
||||
|
||||
tk = strtok(NULL," \n\0");
|
||||
tmp_chn = instance.head;
|
||||
del_chn = instance.head;
|
||||
if(tk){
|
||||
if(strcmp(instance.head->name,tk) == 0){
|
||||
|
||||
instance.head = instance.head->next;
|
||||
|
||||
}else{
|
||||
|
||||
while(del_chn->next){
|
||||
|
||||
if(strcmp(del_chn->name,tk) == 0){
|
||||
|
||||
tmp_chn->next = del_chn->next;
|
||||
break;
|
||||
|
||||
}else{
|
||||
tmp_chn = del_chn;
|
||||
del_chn = del_chn->next;
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(del_chn && del_chn->next){
|
||||
|
||||
printf("Deleted %s.\n",del_chn->name);
|
||||
|
||||
if(del_chn->instance){
|
||||
|
||||
del_chn->instance->freeSession(del_chn->filter,del_chn->session);
|
||||
|
||||
}
|
||||
|
||||
free(del_chn->filter);
|
||||
free(del_chn->down);
|
||||
free(del_chn->name);
|
||||
free(del_chn);
|
||||
}else{
|
||||
printf("No matching filter found.\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case LOAD_CONFIG:
|
||||
tk = strtok(NULL," \n\0");
|
||||
if(!load_config(tk)){
|
||||
free_filters();
|
||||
}
|
||||
break;
|
||||
|
||||
case SET_INFILE:
|
||||
|
||||
tk = strtok(NULL," \n\0");
|
||||
if(instance.infile >= 0){
|
||||
close(instance.infile);
|
||||
free(instance.infile_name);
|
||||
}
|
||||
if(tk!= NULL){
|
||||
free_buffers();
|
||||
instance.infile = open_file(tk,0);
|
||||
if(instance.infile >= 0){
|
||||
load_query();
|
||||
instance.infile_name = strdup(tk);
|
||||
if(instance.verbose){
|
||||
printf("Loaded %d queries from file '%s'\n",instance.buffer_count,instance.infile_name);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
instance.infile = -1;
|
||||
printf("Queries are read from: command line\n");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SET_OUTFILE:
|
||||
|
||||
tk = strtok(NULL," \n\0");
|
||||
if(instance.outfile >= 0){
|
||||
close(instance.outfile);
|
||||
free(instance.outfile_name);
|
||||
}
|
||||
if(tk!= NULL){
|
||||
|
||||
instance.outfile = open_file(tk,1);
|
||||
if(instance.outfile >= 0){
|
||||
instance.outfile_name = strdup(tk);
|
||||
printf("Output is logged to: %s\n",tk);
|
||||
}
|
||||
}else{
|
||||
instance.outfile = -1;
|
||||
printf("Output logging disabled.\n");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SESS_COUNT:
|
||||
|
||||
tk = strtok(NULL," \n\0");
|
||||
free_buffers();
|
||||
free_filters();
|
||||
instance.session_count = atoi(tk);
|
||||
printf("Sessions set to: %d\n", instance.session_count);
|
||||
break;
|
||||
|
||||
case THR_COUNT:
|
||||
|
||||
instance.running = 0;
|
||||
pthread_mutex_unlock(&instance.work_mtx);
|
||||
for(i = 0;i<instance.thrcount;i++){
|
||||
pthread_join(instance.thrpool[i],NULL);
|
||||
}
|
||||
pthread_mutex_lock(&instance.work_mtx);
|
||||
|
||||
instance.running = 1;
|
||||
tk = strtok(NULL," \n\0");
|
||||
instance.thrcount = atoi(tk);
|
||||
void* t_thr_pool;
|
||||
|
||||
if(!(t_thr_pool = realloc(instance.thrpool,instance.thrcount * sizeof(pthread_t)))){
|
||||
printf("Error: Out of memory\n");
|
||||
MXS_ERROR("Out of memory\n");
|
||||
instance.running = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
instance.thrpool = t_thr_pool;
|
||||
intptr_t thr_num = 1;
|
||||
|
||||
for(i = 0;i<instance.thrcount;i++){
|
||||
|
||||
pthread_create(&instance.thrpool[i],
|
||||
NULL,
|
||||
(void*)work_buffer,
|
||||
(void*)thr_num++);
|
||||
|
||||
}
|
||||
printf("Threads set to: %d\n", instance.thrcount);
|
||||
|
||||
break;
|
||||
|
||||
case QUIT:
|
||||
|
||||
instance.running = 0;
|
||||
pthread_mutex_unlock(&instance.work_mtx);
|
||||
for(i = 0;i<instance.thrcount;i++){
|
||||
pthread_join(instance.thrpool[i],NULL);
|
||||
}
|
||||
break;
|
||||
case UNDEFINED:
|
||||
|
||||
printf("Command not found, enter \"help\" for a list of commands\n");
|
||||
|
||||
break;
|
||||
default:
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(instance.infile >= 0){
|
||||
close(instance.infile);
|
||||
}
|
||||
if(instance.outfile >= 0){
|
||||
close(instance.outfile);
|
||||
}
|
||||
|
||||
free_buffers();
|
||||
free_filters();
|
||||
mxs_log_finish();
|
||||
free(instance.head);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
operation_t user_input(char* tk)
|
||||
{
|
||||
|
||||
if(tk){
|
||||
|
||||
char cmpbuff[256];
|
||||
int tklen = strcspn(tk," \n\0");
|
||||
memset(cmpbuff,0,256);
|
||||
if(tklen > 0 && tklen < 256){
|
||||
strncpy(cmpbuff,tk,tklen);
|
||||
strcat(cmpbuff,"\0");
|
||||
if(strcmp(tk,"run")==0 || strcmp(tk,"r")==0){
|
||||
return RUNFILTERS;
|
||||
|
||||
}else if(strcmp(cmpbuff,"add")==0){
|
||||
return LOAD_FILTER;
|
||||
|
||||
}else if(strcmp(cmpbuff,"delete")==0){
|
||||
return DELETE_FILTER;
|
||||
|
||||
}else if(strcmp(cmpbuff,"clear")==0){
|
||||
tk = strtok(NULL," \n\0");
|
||||
if(tk && !strcmp(tk,"queries")){
|
||||
free_buffers();
|
||||
printf("Queries cleared.\n");
|
||||
}else if(tk && !strcmp(tk,"filters")){
|
||||
printf("Filters cleared.\n");
|
||||
free_filters();
|
||||
}else{
|
||||
printf("All cleared.\n");
|
||||
free_buffers();
|
||||
free_filters();
|
||||
}
|
||||
|
||||
|
||||
return OK;
|
||||
|
||||
}else if(strcmp(cmpbuff,"config")==0){
|
||||
return LOAD_CONFIG;
|
||||
|
||||
}else if(strcmp(cmpbuff,"in")==0){
|
||||
return SET_INFILE;
|
||||
|
||||
}else if(strcmp(cmpbuff,"out")==0){
|
||||
return SET_OUTFILE;
|
||||
|
||||
}else if(strcmp(cmpbuff,"exit")==0 || strcmp(cmpbuff,"quit")==0 || strcmp(cmpbuff,"q")==0){
|
||||
return QUIT;
|
||||
|
||||
}else if(strcmp(cmpbuff,"help")==0){
|
||||
print_help();
|
||||
return OK;
|
||||
}else if(strcmp(cmpbuff,"status")==0){
|
||||
print_status();
|
||||
return OK;
|
||||
}else if(strcmp(cmpbuff,"quiet")==0){
|
||||
instance.verbose = 0;
|
||||
return OK;
|
||||
}else if(strcmp(cmpbuff,"verbose")==0){
|
||||
instance.verbose = 1;
|
||||
return OK;
|
||||
}else if(strcmp(cmpbuff,"sessions")==0){
|
||||
return SESS_COUNT;
|
||||
}else if(strcmp(cmpbuff,"threads")==0){
|
||||
return THR_COUNT;
|
||||
}
|
||||
}
|
||||
}
|
||||
return UNDEFINED;
|
||||
}
|
||||
|
||||
|
||||
void print_help()
|
||||
{
|
||||
|
||||
printf("\nFilter Test Harness\n\n"
|
||||
"List of commands:\n %-32s%s\n %-32s%s\n %-32s%s\n %-32s%s\n %-32s%s\n "
|
||||
"%-32s%s\n %-32s%s\n %-32s%s\n %-32s%s\n %-32s%s\n %-32s%s\n %-32s%s\n "
|
||||
"%-32s%s\n %-32s%s\n"
|
||||
,"help","Prints this help message."
|
||||
,"run","Feeds the contents of the buffer to the filter chain."
|
||||
,"add <filter name>","Loads a filter and appeds it to the end of the chain."
|
||||
,"delete <filter name>","Deletes a filter."
|
||||
,"status","Lists all loaded filters and queries"
|
||||
,"clear","Clears the filter chain."
|
||||
,"config <file name>","Loads filter configurations from a file."
|
||||
,"in <file name>","Source file for the SQL statements."
|
||||
,"out <file name>","Destination file for the SQL statements. Defaults to stdout if no parameters were passed."
|
||||
,"threads <number>","Sets the amount of threads to use"
|
||||
,"sessions <number>","How many sessions to create for each filter. This clears all loaded filters."
|
||||
,"quiet","Print only error messages."
|
||||
,"verbose","Print everything."
|
||||
,"exit","Exit the program"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void manual_query()
|
||||
{
|
||||
char query[1024];
|
||||
unsigned int qlen;
|
||||
GWBUF** tmpbuf;
|
||||
|
||||
free_buffers();
|
||||
|
||||
printf("Enter query: ");
|
||||
fgets(query,1024,stdin);
|
||||
|
||||
qlen = strnlen(query, 1024);
|
||||
if((tmpbuf = malloc(sizeof(GWBUF*)))== NULL){
|
||||
printf("Error: cannot allocate enough memory.\n");
|
||||
MXS_ERROR("Cannot allocate enough memory.\n");
|
||||
return;
|
||||
}
|
||||
instance.buffer = tmpbuf;
|
||||
instance.buffer_count = 1;
|
||||
|
||||
instance.buffer[0] = gwbuf_alloc(qlen + 5);
|
||||
gwbuf_set_type(instance.buffer[0],GWBUF_TYPE_MYSQL);
|
||||
memcpy(instance.buffer[0]->sbuf->data + 5,query,qlen);
|
||||
|
||||
instance.buffer[0]->sbuf->data[0] = (qlen);
|
||||
instance.buffer[0]->sbuf->data[1] = (qlen << 8);
|
||||
instance.buffer[0]->sbuf->data[2] = (qlen << 16);
|
||||
instance.buffer[0]->sbuf->data[3] = 0x00;
|
||||
instance.buffer[0]->sbuf->data[4] = 0x03;
|
||||
|
||||
}
|
||||
|
||||
void print_status()
|
||||
{
|
||||
if(instance.head->filter){
|
||||
printf("Filters currently loaded:\n\n");
|
||||
|
||||
FILTERCHAIN* hd = instance.head;
|
||||
int i = 1;
|
||||
while(hd->filter){
|
||||
printf("%d: %s\n", i++, hd->name);
|
||||
hd = hd->next;
|
||||
}
|
||||
|
||||
}else{
|
||||
printf("No filters loaded.\n");
|
||||
}
|
||||
printf("\n");
|
||||
if(instance.buffer_count > 0){
|
||||
printf("%d queries loaded.\n",instance.buffer_count);
|
||||
}else{
|
||||
printf("No queries loaded.\n");
|
||||
}
|
||||
|
||||
printf("Using %d threads and %d sessions.\n",instance.thrcount,instance.session_count);
|
||||
|
||||
if(instance.infile_name){
|
||||
printf("Input is read from %s.\n",instance.infile_name);
|
||||
}
|
||||
if(instance.outfile_name){
|
||||
printf("Output is written to %s.\n",instance.outfile_name);
|
||||
}
|
||||
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
#include <my_config.h>
|
||||
#include <mysql.h>
|
||||
#include <harness.h>
|
||||
|
||||
int main(int argc,char** argv)
|
||||
{
|
||||
|
||||
static char* server_options[] = {
|
||||
"MariaDB Corporation MaxScale",
|
||||
"--datadir=./",
|
||||
"--language=./",
|
||||
"--skip-innodb",
|
||||
"--default-storage-engine=myisam",
|
||||
NULL
|
||||
};
|
||||
|
||||
const int num_elements = (sizeof(server_options) / sizeof(char *)) - 1;
|
||||
|
||||
static char* server_groups[] = {
|
||||
"embedded",
|
||||
"server",
|
||||
"server",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
HARNESS_INSTANCE* inst;
|
||||
|
||||
if(mysql_library_init(num_elements, server_options, server_groups)){
|
||||
printf("Embedded server init failed.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
if(harness_init(argc,argv,&inst) || inst->error){
|
||||
printf("Error: Initialization failed.\n");
|
||||
MXS_ERROR("Initialization failed.\n");
|
||||
mxs_log_finish();
|
||||
return 1;
|
||||
}
|
||||
|
||||
route_buffers();
|
||||
|
||||
if(inst->expected > 0){
|
||||
return compare_files(inst->outfile,inst->expected);
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
[Hint]
|
||||
type=filter
|
||||
module=hintfilter
|
@ -1,48 +0,0 @@
|
||||
select @@server_id; -- maxscale begin route to master|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id;|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id; -- maxscale route to server server3|HINT_ROUTE_TO_NAMED_SERVER|server3
|
||||
select @@server_id;|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id; -- maxscale end
|
||||
select @@server_id; -- maxscale named1 prepare route to master
|
||||
select @@server_id; -- maxscale named1 begin|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id;|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id; -- maxscale route to server server3|HINT_ROUTE_TO_NAMED_SERVER|server3
|
||||
select @@server_id;|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id; -- maxscale end
|
||||
select @@server_id; -- maxscale shorthand1 begin route to server server2|HINT_ROUTE_TO_NAMED_SERVER|server2
|
||||
select @@server_id;|HINT_ROUTE_TO_NAMED_SERVER|server2
|
||||
select @@server_id; -- maxscale route to server server3|HINT_ROUTE_TO_NAMED_SERVER|server3
|
||||
select @@server_id;|HINT_ROUTE_TO_NAMED_SERVER|server2
|
||||
select @@server_id; -- maxscale end
|
||||
select @@server_id; # maxscale begin route to master|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id;|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id; # maxscale route to server server3|HINT_ROUTE_TO_NAMED_SERVER|server3
|
||||
select @@server_id;|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id; # maxscale end
|
||||
select @@server_id; # maxscale named2 prepare route to master
|
||||
select @@server_id; # maxscale named2 begin|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id;|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id; # maxscale route to server server3|HINT_ROUTE_TO_NAMED_SERVER|server3
|
||||
select @@server_id;|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id; # maxscale end
|
||||
select @@server_id; # maxscale shorthand2 begin route to server server2|HINT_ROUTE_TO_NAMED_SERVER|server2
|
||||
select @@server_id;|HINT_ROUTE_TO_NAMED_SERVER|server2
|
||||
select @@server_id; # maxscale route to server server3|HINT_ROUTE_TO_NAMED_SERVER|server3
|
||||
select @@server_id;|HINT_ROUTE_TO_NAMED_SERVER|server2
|
||||
select @@server_id; # maxscale end
|
||||
select @@server_id/* maxscale begin route to master */;|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id;|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id/* maxscale route to server server3 */;|HINT_ROUTE_TO_NAMED_SERVER|server3
|
||||
select @@server_id;|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id/* maxscale end */;
|
||||
select @@server_id/* maxscale named3 prepare route to master */;
|
||||
select @@server_id/* maxscale named3 begin */;|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id;|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id/* maxscale route to server server3 */;|HINT_ROUTE_TO_NAMED_SERVER|server3
|
||||
select @@server_id;|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id/* maxscale end */;
|
||||
select @@server_id/* maxscale shorthand3 begin route to server server2 */; |HINT_ROUTE_TO_NAMED_SERVER|server2
|
||||
select @@server_id;|HINT_ROUTE_TO_NAMED_SERVER|server2
|
||||
select @@server_id/* maxscale route to server server3 */;|HINT_ROUTE_TO_NAMED_SERVER|server3
|
||||
select @@server_id;|HINT_ROUTE_TO_NAMED_SERVER|server2
|
||||
select @@server_id/* maxscale end */;
|
@ -1,48 +0,0 @@
|
||||
select @@server_id; -- maxscale begin route to master
|
||||
select @@server_id;
|
||||
select @@server_id; -- maxscale route to server server3
|
||||
select @@server_id;
|
||||
select @@server_id; -- maxscale end
|
||||
select @@server_id; -- maxscale named1 prepare route to master
|
||||
select @@server_id; -- maxscale named1 begin
|
||||
select @@server_id;
|
||||
select @@server_id; -- maxscale route to server server3
|
||||
select @@server_id;
|
||||
select @@server_id; -- maxscale end
|
||||
select @@server_id; -- maxscale shorthand1 begin route to server server2
|
||||
select @@server_id;
|
||||
select @@server_id; -- maxscale route to server server3
|
||||
select @@server_id;
|
||||
select @@server_id; -- maxscale end
|
||||
select @@server_id; # maxscale begin route to master
|
||||
select @@server_id;
|
||||
select @@server_id; # maxscale route to server server3
|
||||
select @@server_id;
|
||||
select @@server_id; # maxscale end
|
||||
select @@server_id; # maxscale named2 prepare route to master
|
||||
select @@server_id; # maxscale named2 begin
|
||||
select @@server_id;
|
||||
select @@server_id; # maxscale route to server server3
|
||||
select @@server_id;
|
||||
select @@server_id; # maxscale end
|
||||
select @@server_id; # maxscale shorthand2 begin route to server server2
|
||||
select @@server_id;
|
||||
select @@server_id; # maxscale route to server server3
|
||||
select @@server_id;
|
||||
select @@server_id; # maxscale end
|
||||
select @@server_id/* maxscale begin route to master */;
|
||||
select @@server_id;
|
||||
select @@server_id/* maxscale route to server server3 */;
|
||||
select @@server_id;
|
||||
select @@server_id/* maxscale end */;
|
||||
select @@server_id/* maxscale named3 prepare route to master */;
|
||||
select @@server_id/* maxscale named3 begin */;
|
||||
select @@server_id;
|
||||
select @@server_id/* maxscale route to server server3 */;
|
||||
select @@server_id;
|
||||
select @@server_id/* maxscale end */;
|
||||
select @@server_id/* maxscale shorthand3 begin route to server server2 */;
|
||||
select @@server_id;
|
||||
select @@server_id/* maxscale route to server server3 */;
|
||||
select @@server_id;
|
||||
select @@server_id/* maxscale end */;
|
@ -1,9 +0,0 @@
|
||||
#! /bin/bash
|
||||
./harness -q -i hint_testing.input -c hint_testing.cnf -o hint_testing.output -t 1 -s 1 -q &>/dev/null
|
||||
diff hint_testing.expected hint_testing.output &>/dev/null
|
||||
if [[ "$?" == "0" ]]
|
||||
then
|
||||
echo "PASSED"
|
||||
else
|
||||
echo "FAILED"
|
||||
fi
|
@ -1 +0,0 @@
|
||||
SELECT * FROM test_table;
|
@ -1,5 +0,0 @@
|
||||
[Regex]
|
||||
type=filter
|
||||
module=regexfilter
|
||||
match=wrong
|
||||
replace=right
|
@ -1,3 +0,0 @@
|
||||
select * from mysql.right;
|
||||
select right from test.table;
|
||||
select * from test.table where name='right';
|
@ -1,3 +0,0 @@
|
||||
select * from mysql.wrong;
|
||||
select wrong from test.table;
|
||||
select * from test.table where name='wrong';
|
@ -1,4 +0,0 @@
|
||||
rule union_regex deny regex '.*union.*'
|
||||
rule dont_delete_everything deny no_where_clause on_queries delete|update
|
||||
rule no_wildcard deny wildcard
|
||||
users %@% match any rules union_regex dont_delete_everything no_wildcard
|
@ -1,86 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
function execute_test()
|
||||
{
|
||||
|
||||
RVAL=$(mysql --connect-timeout=5 -u $USER -p$PWD -h $HOST -P $PORT -e "select 1;"|grep -i error)
|
||||
|
||||
if [[ ! -e $MAXPID ]]
|
||||
then
|
||||
echo "Test failed: $MAXPID was not found."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ "$RVAL" != "" ]]
|
||||
then
|
||||
echo "Test failed: Query to backend didn't return an error."
|
||||
return 1
|
||||
fi
|
||||
|
||||
LAST_LOG=$(ls $BINDIR/ -1|grep error|sort|uniq|tail -n 1)
|
||||
TEST_RESULT=$(cat $BINDIR/$LAST_LOG | grep -i recursive)
|
||||
if [[ "$TEST_RESULT" != "" ]]
|
||||
then
|
||||
return 0
|
||||
fi
|
||||
echo "Test failed: Log file didn't mention tee recursion."
|
||||
return 1
|
||||
}
|
||||
|
||||
function reload_conf()
|
||||
{
|
||||
$BINDIR/bin/maxadmin --user=admin --password=mariadb reload config
|
||||
if [[ $? -ne 0 ]]
|
||||
then
|
||||
echo "Test failed: maxadmin returned a non-zero value."
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
if [[ $# -lt 6 ]]
|
||||
then
|
||||
echo "usage: $0 <build dir> <source dir>"
|
||||
exit 1
|
||||
fi
|
||||
BINDIR=$1
|
||||
SRCDIR=$2
|
||||
USER=$3
|
||||
PWD=$4
|
||||
HOST=$5
|
||||
PORT=$6
|
||||
CONF=$BINDIR/etc/maxscale.cnf
|
||||
OLDCONF=$BINDIR/etc/maxscale.cnf.old
|
||||
MAXPID=$BINDIR/log/$(ls -1 $BINDIR/log|grep maxscale)
|
||||
TEST1=$SRCDIR/server/modules/filter/test/tee_recursion1.cnf
|
||||
TEST2=$SRCDIR/server/modules/filter/test/tee_recursion2.cnf
|
||||
|
||||
$BINDIR/bin/maxadmin --user=admin --password=mariadb flush logs
|
||||
|
||||
mv $CONF $OLDCONF
|
||||
cp $TEST1 $CONF
|
||||
reload_conf
|
||||
execute_test
|
||||
T1RVAL=$?
|
||||
mv $CONF $CONF.test1
|
||||
cp $TEST2 $CONF
|
||||
reload_conf
|
||||
execute_test
|
||||
T2RVAL=$?
|
||||
mv $CONF $CONF.test2
|
||||
mv $OLDCONF $CONF
|
||||
reload_conf
|
||||
|
||||
if [[ $T1RVAL -ne 0 ]]
|
||||
then
|
||||
echo "Test 1 failed."
|
||||
exit 1
|
||||
elif [[ $T2RVAL -ne 0 ]]
|
||||
then
|
||||
echo "Test 2 failed"
|
||||
exit 1
|
||||
else
|
||||
echo "Test successful: log mentions recursive tee usage."
|
||||
fi
|
||||
|
||||
exit 0
|
@ -1,114 +0,0 @@
|
||||
[maxscale]
|
||||
threads=4
|
||||
|
||||
[MySQL Monitor]
|
||||
type=monitor
|
||||
module=mysqlmon
|
||||
servers=server1,server2,server3,server4
|
||||
user=maxuser
|
||||
passwd=maxpwd
|
||||
monitor_interval=10000
|
||||
|
||||
[RW Split Router]
|
||||
type=service
|
||||
router=readwritesplit
|
||||
servers=server1,server2,server3,server4
|
||||
user=maxuser
|
||||
passwd=maxpwd
|
||||
filters=recurse1
|
||||
|
||||
[RW Split Hint Router]
|
||||
type=service
|
||||
router=readwritesplit
|
||||
servers=server1,server2,server3,server4
|
||||
user=maxuser
|
||||
passwd=maxpwd
|
||||
filters=recurse2
|
||||
|
||||
|
||||
[Read Connection Router]
|
||||
type=service
|
||||
router=readconnroute
|
||||
router_options=master
|
||||
servers=server1
|
||||
user=maxuser
|
||||
passwd=maxpwd
|
||||
filters=recurse3
|
||||
|
||||
[recurse3]
|
||||
type=filter
|
||||
module=tee
|
||||
service=RW Split Router
|
||||
|
||||
[recurse2]
|
||||
type=filter
|
||||
module=tee
|
||||
service=Read Connection Router
|
||||
|
||||
[recurse1]
|
||||
type=filter
|
||||
module=tee
|
||||
service=RW Split Hint Router
|
||||
|
||||
|
||||
[Debug Interface]
|
||||
type=service
|
||||
router=debugcli
|
||||
|
||||
[CLI]
|
||||
type=service
|
||||
router=cli
|
||||
|
||||
[Read Connection Listener]
|
||||
type=listener
|
||||
service=Read Connection Router
|
||||
protocol=MySQLClient
|
||||
port=4008
|
||||
|
||||
[RW Split Listener]
|
||||
type=listener
|
||||
service=RW Split Router
|
||||
protocol=MySQLClient
|
||||
port=4006
|
||||
|
||||
[RW Split Hint Listener]
|
||||
type=listener
|
||||
service=RW Split Hint Router
|
||||
protocol=MySQLClient
|
||||
port=4009
|
||||
|
||||
[Debug Listener]
|
||||
type=listener
|
||||
service=Debug Interface
|
||||
protocol=telnetd
|
||||
port=4442
|
||||
|
||||
[CLI Listener]
|
||||
type=listener
|
||||
service=CLI
|
||||
protocol=maxscaled
|
||||
port=6603
|
||||
|
||||
[server1]
|
||||
type=server
|
||||
address=127.0.0.1
|
||||
port=3000
|
||||
protocol=MySQLBackend
|
||||
|
||||
[server2]
|
||||
type=server
|
||||
address=127.0.0.1
|
||||
port=3001
|
||||
protocol=MySQLBackend
|
||||
|
||||
[server3]
|
||||
type=server
|
||||
address=127.0.0.1
|
||||
port=3002
|
||||
protocol=MySQLBackend
|
||||
|
||||
[server4]
|
||||
type=server
|
||||
address=127.0.0.1
|
||||
port=3003
|
||||
protocol=MySQLBackend
|
@ -1,112 +0,0 @@
|
||||
[maxscale]
|
||||
threads=4
|
||||
|
||||
[MySQL Monitor]
|
||||
type=monitor
|
||||
module=mysqlmon
|
||||
servers=server1,server2,server3,server4
|
||||
user=maxuser
|
||||
passwd=maxpwd
|
||||
monitor_interval=10000
|
||||
|
||||
[RW Split Router]
|
||||
type=service
|
||||
router=readwritesplit
|
||||
servers=server1,server2,server3,server4
|
||||
user=maxuser
|
||||
passwd=maxpwd
|
||||
filters=recurse1|recurse2
|
||||
|
||||
[RW Split Hint Router]
|
||||
type=service
|
||||
router=readwritesplit
|
||||
servers=server1,server2,server3,server4
|
||||
user=maxuser
|
||||
passwd=maxpwd
|
||||
|
||||
[Read Connection Router]
|
||||
type=service
|
||||
router=readconnroute
|
||||
router_options=master
|
||||
servers=server1
|
||||
user=maxuser
|
||||
passwd=maxpwd
|
||||
filters=recurse3
|
||||
|
||||
[recurse3]
|
||||
type=filter
|
||||
module=tee
|
||||
service=RW Split Router
|
||||
|
||||
[recurse2]
|
||||
type=filter
|
||||
module=tee
|
||||
service=Read Connection Router
|
||||
|
||||
[recurse1]
|
||||
type=filter
|
||||
module=tee
|
||||
service=RW Split Hint Router
|
||||
|
||||
|
||||
[Debug Interface]
|
||||
type=service
|
||||
router=debugcli
|
||||
|
||||
[CLI]
|
||||
type=service
|
||||
router=cli
|
||||
|
||||
[Read Connection Listener]
|
||||
type=listener
|
||||
service=Read Connection Router
|
||||
protocol=MySQLClient
|
||||
port=4008
|
||||
|
||||
[RW Split Listener]
|
||||
type=listener
|
||||
service=RW Split Router
|
||||
protocol=MySQLClient
|
||||
port=4006
|
||||
|
||||
[RW Split Hint Listener]
|
||||
type=listener
|
||||
service=RW Split Hint Router
|
||||
protocol=MySQLClient
|
||||
port=4009
|
||||
|
||||
[Debug Listener]
|
||||
type=listener
|
||||
service=Debug Interface
|
||||
protocol=telnetd
|
||||
port=4442
|
||||
|
||||
[CLI Listener]
|
||||
type=listener
|
||||
service=CLI
|
||||
protocol=maxscaled
|
||||
port=6603
|
||||
|
||||
[server1]
|
||||
type=server
|
||||
address=127.0.0.1
|
||||
port=3000
|
||||
protocol=MySQLBackend
|
||||
|
||||
[server2]
|
||||
type=server
|
||||
address=127.0.0.1
|
||||
port=3001
|
||||
protocol=MySQLBackend
|
||||
|
||||
[server3]
|
||||
type=server
|
||||
address=127.0.0.1
|
||||
port=3002
|
||||
protocol=MySQLBackend
|
||||
|
||||
[server4]
|
||||
type=server
|
||||
address=127.0.0.1
|
||||
port=3003
|
||||
protocol=MySQLBackend
|
@ -1,11 +0,0 @@
|
||||
#! /bin/bash
|
||||
if [[ $# -lt 4 ]]
|
||||
then
|
||||
echo "Usage: $0 <config file> <input> <output> <expected>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TESTDIR=@CMAKE_CURRENT_BINARY_DIR@
|
||||
SRCDIR=@CMAKE_CURRENT_SOURCE_DIR@
|
||||
$TESTDIR/harness -i $SRCDIR/$2 -o $TESTDIR/$3 -c $TESTDIR/$1 -t 1 -s 1 -e $SRCDIR/$4
|
||||
exit $?
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -12,6 +12,7 @@
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <filter.h>
|
||||
#include <maxscale/alloc.h>
|
||||
#include <modinfo.h>
|
||||
#include <modutil.h>
|
||||
#include <atomic.h>
|
||||
@ -128,7 +129,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
TEST_INSTANCE *my_instance;
|
||||
|
||||
if ((my_instance = calloc(1, sizeof(TEST_INSTANCE))) != NULL)
|
||||
if ((my_instance = MXS_CALLOC(1, sizeof(TEST_INSTANCE))) != NULL)
|
||||
{
|
||||
my_instance->sessions = 0;
|
||||
}
|
||||
@ -148,7 +149,7 @@ newSession(FILTER *instance, SESSION *session)
|
||||
TEST_INSTANCE *my_instance = (TEST_INSTANCE *)instance;
|
||||
TEST_SESSION *my_session;
|
||||
|
||||
if ((my_session = calloc(1, sizeof(TEST_SESSION))) != NULL)
|
||||
if ((my_session = MXS_CALLOC(1, sizeof(TEST_SESSION))) != NULL)
|
||||
{
|
||||
atomic_add(&my_instance->sessions, 1);
|
||||
my_session->count = 0;
|
||||
@ -178,7 +179,7 @@ closeSession(FILTER *instance, void *session)
|
||||
static void
|
||||
freeSession(FILTER *instance, void *session)
|
||||
{
|
||||
free(session);
|
||||
MXS_FREE(session);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -44,6 +44,7 @@
|
||||
#include <sys/time.h>
|
||||
#include <regex.h>
|
||||
#include <atomic.h>
|
||||
#include <maxscale/alloc.h>
|
||||
|
||||
MODULE_INFO info =
|
||||
{
|
||||
@ -186,10 +187,9 @@ GetModuleObject()
|
||||
static FILTER *
|
||||
createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
int i;
|
||||
TOPN_INSTANCE *my_instance;
|
||||
TOPN_INSTANCE *my_instance = (TOPN_INSTANCE*)MXS_MALLOC(sizeof(TOPN_INSTANCE));
|
||||
|
||||
if ((my_instance = malloc(sizeof(TOPN_INSTANCE))) != NULL)
|
||||
if (my_instance)
|
||||
{
|
||||
my_instance->topN = 10;
|
||||
my_instance->match = NULL;
|
||||
@ -199,7 +199,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
my_instance->filebase = NULL;
|
||||
bool error = false;
|
||||
|
||||
for (i = 0; params && params[i]; i++)
|
||||
for (int i = 0; params && params[i]; i++)
|
||||
{
|
||||
if (!strcmp(params[i]->name, "count"))
|
||||
{
|
||||
@ -207,23 +207,23 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "filebase"))
|
||||
{
|
||||
my_instance->filebase = strdup(params[i]->value);
|
||||
my_instance->filebase = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "match"))
|
||||
{
|
||||
my_instance->match = strdup(params[i]->value);
|
||||
my_instance->match = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "exclude"))
|
||||
{
|
||||
my_instance->exclude = strdup(params[i]->value);
|
||||
my_instance->exclude = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "source"))
|
||||
{
|
||||
my_instance->source = strdup(params[i]->value);
|
||||
my_instance->source = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "user"))
|
||||
{
|
||||
my_instance->user = strdup(params[i]->value);
|
||||
my_instance->user = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!filter_standard_parameter(params[i]->name))
|
||||
{
|
||||
@ -237,7 +237,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
|
||||
if (options)
|
||||
{
|
||||
for (i = 0; options[i]; i++)
|
||||
for (int i = 0; options[i]; i++)
|
||||
{
|
||||
if (!strcasecmp(options[i], "ignorecase"))
|
||||
{
|
||||
@ -274,7 +274,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
" for the 'match' parameter.",
|
||||
my_instance->match);
|
||||
regfree(&my_instance->re);
|
||||
free(my_instance->match);
|
||||
MXS_FREE(my_instance->match);
|
||||
my_instance->match = NULL;
|
||||
error = true;
|
||||
}
|
||||
@ -285,7 +285,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
" for the 'nomatch' parameter.\n",
|
||||
my_instance->exclude);
|
||||
regfree(&my_instance->exre);
|
||||
free(my_instance->exclude);
|
||||
MXS_FREE(my_instance->exclude);
|
||||
my_instance->exclude = NULL;
|
||||
error = true;
|
||||
}
|
||||
@ -295,17 +295,17 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
if (my_instance->exclude)
|
||||
{
|
||||
regfree(&my_instance->exre);
|
||||
free(my_instance->exclude);
|
||||
MXS_FREE(my_instance->exclude);
|
||||
}
|
||||
if (my_instance->match)
|
||||
{
|
||||
regfree(&my_instance->re);
|
||||
free(my_instance->match);
|
||||
MXS_FREE(my_instance->match);
|
||||
}
|
||||
free(my_instance->filebase);
|
||||
free(my_instance->source);
|
||||
free(my_instance->user);
|
||||
free(my_instance);
|
||||
MXS_FREE(my_instance->filebase);
|
||||
MXS_FREE(my_instance->source);
|
||||
MXS_FREE(my_instance->user);
|
||||
MXS_FREE(my_instance);
|
||||
my_instance = NULL;
|
||||
}
|
||||
}
|
||||
@ -329,23 +329,24 @@ newSession(FILTER *instance, SESSION *session)
|
||||
int i;
|
||||
char *remote, *user;
|
||||
|
||||
if ((my_session = calloc(1, sizeof(TOPN_SESSION))) != NULL)
|
||||
if ((my_session = MXS_CALLOC(1, sizeof(TOPN_SESSION))) != NULL)
|
||||
{
|
||||
if ((my_session->filename =
|
||||
(char *) malloc(strlen(my_instance->filebase) + 20))
|
||||
(char *) MXS_MALLOC(strlen(my_instance->filebase) + 20))
|
||||
== NULL)
|
||||
{
|
||||
free(my_session);
|
||||
MXS_FREE(my_session);
|
||||
return NULL;
|
||||
}
|
||||
sprintf(my_session->filename, "%s.%d", my_instance->filebase,
|
||||
my_instance->sessions);
|
||||
atomic_add(&my_instance->sessions, 1);
|
||||
my_session->top = (TOPNQ **) calloc(my_instance->topN + 1,
|
||||
sizeof(TOPNQ *));
|
||||
my_session->top = (TOPNQ **) MXS_CALLOC(my_instance->topN + 1, sizeof(TOPNQ *));
|
||||
MXS_ABORT_IF_NULL(my_session->top);
|
||||
for (i = 0; i < my_instance->topN; i++)
|
||||
{
|
||||
my_session->top[i] = (TOPNQ *) calloc(1, sizeof(TOPNQ));
|
||||
my_session->top[i] = (TOPNQ *) MXS_CALLOC(1, sizeof(TOPNQ));
|
||||
MXS_ABORT_IF_NULL(my_session->top[i]);
|
||||
my_session->top[i]->sql = NULL;
|
||||
}
|
||||
my_session->n_statements = 0;
|
||||
@ -354,7 +355,7 @@ newSession(FILTER *instance, SESSION *session)
|
||||
my_session->current = NULL;
|
||||
if ((remote = session_get_remote(session)) != NULL)
|
||||
{
|
||||
my_session->clientHost = strdup(remote);
|
||||
my_session->clientHost = MXS_STRDUP_A(remote);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -362,7 +363,7 @@ newSession(FILTER *instance, SESSION *session)
|
||||
}
|
||||
if ((user = session_getUser(session)) != NULL)
|
||||
{
|
||||
my_session->userName = strdup(user);
|
||||
my_session->userName = MXS_STRDUP_A(user);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -469,8 +470,8 @@ freeSession(FILTER *instance, void *session)
|
||||
{
|
||||
TOPN_SESSION *my_session = (TOPN_SESSION *) session;
|
||||
|
||||
free(my_session->filename);
|
||||
free(session);
|
||||
MXS_FREE(my_session->filename);
|
||||
MXS_FREE(session);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -539,14 +540,14 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
my_session->n_statements++;
|
||||
if (my_session->current)
|
||||
{
|
||||
free(my_session->current);
|
||||
MXS_FREE(my_session->current);
|
||||
}
|
||||
gettimeofday(&my_session->start, NULL);
|
||||
my_session->current = ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(ptr);
|
||||
MXS_FREE(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -599,7 +600,7 @@ clientReply(FILTER *instance, void *session, GWBUF *reply)
|
||||
(diff.tv_sec == my_session->top[my_instance->topN - 1]->duration.tv_sec &&
|
||||
diff.tv_usec > my_session->top[my_instance->topN - 1]->duration.tv_usec)))
|
||||
{
|
||||
free(my_session->top[my_instance->topN - 1]->sql);
|
||||
MXS_FREE(my_session->top[my_instance->topN - 1]->sql);
|
||||
my_session->top[my_instance->topN - 1]->sql = my_session->current;
|
||||
my_session->top[my_instance->topN - 1]->duration = diff;
|
||||
inserted = 1;
|
||||
@ -612,7 +613,7 @@ clientReply(FILTER *instance, void *session, GWBUF *reply)
|
||||
}
|
||||
else
|
||||
{
|
||||
free(my_session->current);
|
||||
MXS_FREE(my_session->current);
|
||||
}
|
||||
my_session->current = NULL;
|
||||
}
|
||||
|
5
server/modules/include/CMakeLists.txt
Normal file
5
server/modules/include/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
file(GLOB HEADERS "*.h")
|
||||
foreach(var ${HEADERS})
|
||||
get_filename_component(header ${var} NAME)
|
||||
install_header(${header} devel)
|
||||
endforeach()
|
@ -267,9 +267,9 @@ typedef struct avro_instance
|
||||
extern void read_table_info(uint8_t *ptr, uint8_t post_header_len, uint64_t *table_id,
|
||||
char* dest, size_t len);
|
||||
extern TABLE_MAP *table_map_alloc(uint8_t *ptr, uint8_t hdr_len, TABLE_CREATE* create);
|
||||
extern void* table_map_free(TABLE_MAP *map);
|
||||
extern void table_map_free(TABLE_MAP *map);
|
||||
extern TABLE_CREATE* table_create_alloc(const char* sql, const char* db);
|
||||
extern void* table_create_free(TABLE_CREATE* value);
|
||||
extern void table_create_free(TABLE_CREATE* value);
|
||||
extern bool table_create_save(TABLE_CREATE *create, const char *filename);
|
||||
extern bool table_create_alter(TABLE_CREATE *create, const char *sql, const char *end);
|
||||
extern void read_alter_identifier(const char *sql, const char *end, char *dest, int size);
|
||||
@ -279,7 +279,7 @@ extern bool avro_open_binlog(const char *binlogdir, const char *file, int *fd);
|
||||
extern void avro_close_binlog(int fd);
|
||||
extern avro_binlog_end_t avro_read_all_events(AVRO_INSTANCE *router);
|
||||
extern AVRO_TABLE* avro_table_alloc(const char* filepath, const char* json_schema);
|
||||
extern void* avro_table_free(AVRO_TABLE *table);
|
||||
extern void avro_table_free(AVRO_TABLE *table);
|
||||
extern void avro_flush_all_tables(AVRO_INSTANCE *router);
|
||||
extern char* json_new_schema_from_table(TABLE_MAP *map);
|
||||
extern void save_avro_schema(const char *path, const char* schema, TABLE_MAP *map);
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -31,6 +31,8 @@
|
||||
* 05/08/15 Massimiliano Pinto Initial implementation of transaction safety
|
||||
* 23/10/15 Markus Makela Added current_safe_event
|
||||
* 26/04/16 Massimiliano Pinto Added MariaDB 10.0 and 10.1 GTID event flags detection
|
||||
* 11/07/16 Massimiliano Pinto Added SSL backend support
|
||||
* 22/07/16 Massimiliano Pinto Added Semi-Sync replication support
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
@ -39,6 +41,7 @@
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#include <memlog.h>
|
||||
#include <thread.h>
|
||||
#include <zlib.h>
|
||||
#include <mysql_client_server_protocol.h>
|
||||
|
||||
@ -189,6 +192,10 @@
|
||||
#define MARIADB_FL_DDL 32
|
||||
#define MARIADB_FL_STANDALONE 1
|
||||
|
||||
/* Saved credential file name's tail */
|
||||
static const char BLR_DBUSERS_DIR[] = "cache/users";
|
||||
static const char BLR_DBUSERS_FILE[] = "dbusers";
|
||||
|
||||
/**
|
||||
* Some useful macros for examining the MySQL Response packets
|
||||
*/
|
||||
@ -221,6 +228,12 @@ typedef struct master_server_config
|
||||
char *user;
|
||||
char *password;
|
||||
char *filestem;
|
||||
/* SSL options */
|
||||
char *ssl_key;
|
||||
char *ssl_cert;
|
||||
char *ssl_ca;
|
||||
int ssl_enabled;
|
||||
char *ssl_version;
|
||||
} MASTER_SERVER_CFG;
|
||||
|
||||
/* Config struct for CHANGE MASTER TO options */
|
||||
@ -232,6 +245,12 @@ typedef struct change_master_options
|
||||
char *binlog_pos;
|
||||
char *user;
|
||||
char *password;
|
||||
/* SSL options */
|
||||
char *ssl_key;
|
||||
char *ssl_cert;
|
||||
char *ssl_ca;
|
||||
char *ssl_enabled;
|
||||
char *ssl_version;
|
||||
} CHANGE_MASTER_OPTIONS;
|
||||
|
||||
/**
|
||||
@ -499,6 +518,16 @@ typedef struct router_instance
|
||||
char *set_master_uuid; /*< Send custom Master UUID to slaves */
|
||||
char *set_master_server_id; /*< Send custom Master server_id to slaves */
|
||||
int send_slave_heartbeat; /*< Enable sending heartbeat to slaves */
|
||||
bool ssl_enabled; /*< Use SSL connection to master */
|
||||
int ssl_cert_verification_depth; /*< The maximum length of the certificate
|
||||
* authority chain that will be accepted.
|
||||
*/
|
||||
char *ssl_key; /*< config Certificate Key for Master SSL connection */
|
||||
char *ssl_ca; /*< config CA Certificate for Master SSL connection */
|
||||
char *ssl_cert; /*< config Certificate for Master SSL connection */
|
||||
char *ssl_version; /*< config TLS Version for Master SSL connection */
|
||||
bool request_semi_sync; /*< Request Semi-Sync replication to master */
|
||||
int master_semi_sync; /*< Semi-Sync replication status of master server */
|
||||
struct router_instance *next;
|
||||
} ROUTER_INSTANCE;
|
||||
|
||||
@ -514,32 +543,35 @@ typedef struct router_instance
|
||||
#define BLRM_HBPERIOD 0x0006
|
||||
#define BLRM_CHKSUM1 0x0007
|
||||
#define BLRM_CHKSUM2 0x0008
|
||||
#define BLRM_GTIDMODE 0x0009
|
||||
#define BLRM_MUUID 0x000A
|
||||
#define BLRM_SUUID 0x000B
|
||||
#define BLRM_LATIN1 0x000C
|
||||
#define BLRM_UTF8 0x000D
|
||||
#define BLRM_SELECT1 0x000E
|
||||
#define BLRM_SELECTVER 0x000F
|
||||
#define BLRM_SELECTVERCOM 0x0010
|
||||
#define BLRM_SELECTHOSTNAME 0x0011
|
||||
#define BLRM_MAP 0x0012
|
||||
#define BLRM_REGISTER 0x0013
|
||||
#define BLRM_BINLOGDUMP 0x0014
|
||||
#define BLRM_SLAVE_STOPPED 0x0015
|
||||
#define BLRM_MARIADB10 0x0016
|
||||
#define BLRM_MARIADB10 0x0009
|
||||
#define BLRM_GTIDMODE 0x000A
|
||||
#define BLRM_MUUID 0x000B
|
||||
#define BLRM_SUUID 0x000C
|
||||
#define BLRM_LATIN1 0x000D
|
||||
#define BLRM_UTF8 0x000E
|
||||
#define BLRM_SELECT1 0x000F
|
||||
#define BLRM_SELECTVER 0x0010
|
||||
#define BLRM_SELECTVERCOM 0x0011
|
||||
#define BLRM_SELECTHOSTNAME 0x0012
|
||||
#define BLRM_MAP 0x0013
|
||||
#define BLRM_REGISTER 0x0014
|
||||
#define BLRM_CHECK_SEMISYNC 0x0015
|
||||
#define BLRM_REQUEST_SEMISYNC 0x0016
|
||||
#define BLRM_REQUEST_BINLOGDUMP 0x0017
|
||||
#define BLRM_BINLOGDUMP 0x0018
|
||||
#define BLRM_SLAVE_STOPPED 0x0019
|
||||
|
||||
#define BLRM_MAXSTATE 0x0016
|
||||
#define BLRM_MAXSTATE 0x0019
|
||||
|
||||
static char *blrm_states[] =
|
||||
{
|
||||
"Unconfigured", "Unconnected", "Connecting", "Authenticated", "Timestamp retrieval",
|
||||
"Server ID retrieval", "HeartBeat Period setup", "binlog checksum config",
|
||||
"binlog checksum rerieval", "GTID Mode retrieval", "Master UUID retrieval",
|
||||
"Set Slave UUID", "Set Names latin1", "Set Names utf8", "select 1",
|
||||
"binlog checksum rerieval", "Set MariaDB slave capability", "GTID Mode retrieval",
|
||||
"Master UUID retrieval", "Set Slave UUID", "Set Names latin1", "Set Names utf8", "select 1",
|
||||
"select version()", "select @@version_comment", "select @@hostname",
|
||||
"select @@max_allowed_packet", "Register slave", "Binlog Dump", "Slave stopped",
|
||||
"Set MariaDB slave capability"
|
||||
"select @@max_allowed_packet", "Register slave", "Semi-Sync Support retrivial",
|
||||
"Request Semi-Sync Replication", "Request Binlog Dump", "Binlog Dump", "Slave stopped"
|
||||
};
|
||||
|
||||
#define BLRS_CREATED 0x0000
|
||||
@ -629,6 +661,7 @@ char *blr_get_event_description(ROUTER_INSTANCE *router, uint8_t event);
|
||||
void blr_file_append(ROUTER_INSTANCE *router, char *file);
|
||||
void blr_cache_response(ROUTER_INSTANCE *router, char *response, GWBUF *buf);
|
||||
char * blr_last_event_description(ROUTER_INSTANCE *router);
|
||||
void blr_free_ssl_data(ROUTER_INSTANCE *inst);
|
||||
|
||||
extern bool blr_send_event(blr_thread_role_t role,
|
||||
const char* binlog_name,
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -49,11 +49,11 @@ typedef struct cli_instance
|
||||
* The CLI_SESSION structure. As CLI_SESSION is created for each user that logs into
|
||||
* the DEBUG CLI.
|
||||
*/
|
||||
enum { cmdbuflen = 80 };
|
||||
enum { CMDBUFLEN = 80 };
|
||||
|
||||
typedef struct cli_session
|
||||
{
|
||||
char cmdbuf[cmdbuflen]; /*< The command buffer used to build up user commands */
|
||||
char cmdbuf[CMDBUFLEN]; /*< The command buffer used to build up user commands */
|
||||
int mode; /*< The CLI Mode for this session */
|
||||
SESSION *session; /*< The gateway session */
|
||||
struct cli_session
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -20,18 +20,19 @@
|
||||
* 01-06-2013 Mark Riddoch Initial implementation
|
||||
* 14-06-2013 Massimiliano Pinto Added specific data
|
||||
* for MySQL session
|
||||
* 04-07-2013 Massimiliano Pinto Added new MySQL protocol status for asynchronous connection
|
||||
* Added authentication reply status
|
||||
* 12-07-2013 Massimiliano Pinto Added routines for change_user
|
||||
* 14-02-2014 Massimiliano Pinto setipaddress returns int
|
||||
* 25-02-2014 Massimiliano Pinto Added dcb parameter to gw_find_mysql_user_password_sha1()
|
||||
* and repository to gw_check_mysql_scramble_data()
|
||||
* It's now possible to specify a different users' table than
|
||||
* dcb->service->users default
|
||||
* 26-02-2014 Massimiliano Pinto Removed previously added parameters to gw_check_mysql_scramble_data() and
|
||||
* gw_find_mysql_user_password_sha1()
|
||||
* 28-02-2014 Massimiliano Pinto MYSQL_DATABASE_MAXLEN,MYSQL_USER_MAXLEN moved to dbusers.h
|
||||
* 07-02-2016 Martin Brampton Extend MYSQL_session type; add MYSQL_AUTH_SUCCEEDED
|
||||
* 04-07-2013 Massimiliano Pinto Added new MySQL protocol status for asynchronous connection
|
||||
* Added authentication reply status
|
||||
* 12-07-2013 Massimiliano Pinto Added routines for change_user
|
||||
* 14-02-2014 Massimiliano Pinto setipaddress returns int
|
||||
* 25-02-2014 Massimiliano Pinto Added dcb parameter to gw_find_mysql_user_password_sha1()
|
||||
* and repository to gw_check_mysql_scramble_data()
|
||||
* It's now possible to specify a different users' table than
|
||||
* dcb->service->users default
|
||||
* 26-02-2014 Massimiliano Pinto Removed previously added parameters to gw_check_mysql_scramble_data() and
|
||||
* gw_find_mysql_user_password_sha1()
|
||||
* 28-02-2014 Massimiliano Pinto MYSQL_DATABASE_MAXLEN,MYSQL_USER_MAXLEN moved to dbusers.h
|
||||
* 07-02-2016 Martin Brampton Extend MYSQL_session type; add MYSQL_AUTH_SUCCEEDED
|
||||
* 17-05-2016 Martin Brampton Moved gw_find_mysql_user_password_sha1 to mysql_auth.c
|
||||
*
|
||||
*/
|
||||
|
||||
@ -344,11 +345,6 @@ int mysql_send_standard_error(DCB *dcb,
|
||||
int error_number,
|
||||
const char *error_message);
|
||||
|
||||
int gw_find_mysql_user_password_sha1(
|
||||
char *username,
|
||||
uint8_t *gateway_password,
|
||||
DCB *dcb);
|
||||
|
||||
int mysql_send_auth_error (
|
||||
DCB *dcb,
|
||||
int packet_number,
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
|
@ -2,24 +2,22 @@ add_library(mysqlmon SHARED mysql_mon.c)
|
||||
target_link_libraries(mysqlmon maxscale-common)
|
||||
add_dependencies(mysqlmon pcre2)
|
||||
set_target_properties(mysqlmon PROPERTIES VERSION "1.4.0")
|
||||
install(TARGETS mysqlmon DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(mysqlmon core)
|
||||
|
||||
add_library(galeramon SHARED galeramon.c)
|
||||
target_link_libraries(galeramon maxscale-common)
|
||||
add_dependencies(galeramon pcre2)
|
||||
set_target_properties(galeramon PROPERTIES VERSION "2.0.0")
|
||||
install(TARGETS galeramon DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(galeramon core)
|
||||
|
||||
add_library(ndbclustermon SHARED ndbclustermon.c)
|
||||
target_link_libraries(ndbclustermon maxscale-common)
|
||||
add_dependencies(ndbclustermon pcre2)
|
||||
set_target_properties(ndbclustermon PROPERTIES VERSION "2.1.0")
|
||||
install(TARGETS ndbclustermon DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(ndbclustermon core)
|
||||
|
||||
if(BUILD_MMMON)
|
||||
add_library(mmmon SHARED mmmon.c)
|
||||
target_link_libraries(mmmon maxscale-common)
|
||||
add_dependencies(mmmon pcre2)
|
||||
set_target_properties(mmmon PROPERTIES VERSION "1.1.1")
|
||||
install(TARGETS mmmon DESTINATION ${MAXSCALE_LIBDIR})
|
||||
endif()
|
||||
add_library(mmmon SHARED mmmon.c)
|
||||
target_link_libraries(mmmon maxscale-common)
|
||||
add_dependencies(mmmon pcre2)
|
||||
set_target_properties(mmmon PROPERTIES VERSION "1.1.1")
|
||||
install_module(mmmon core)
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -36,6 +36,7 @@
|
||||
|
||||
#include <galeramon.h>
|
||||
#include <dcb.h>
|
||||
#include <maxscale/alloc.h>
|
||||
|
||||
static void monitorMain(void *);
|
||||
|
||||
@ -135,7 +136,7 @@ startMonitor(void *arg, void* opt)
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((handle = (GALERA_MONITOR *) malloc(sizeof(GALERA_MONITOR))) == NULL)
|
||||
if ((handle = (GALERA_MONITOR *) MXS_MALLOC(sizeof(GALERA_MONITOR))) == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@ -174,8 +175,8 @@ startMonitor(void *arg, void* opt)
|
||||
{
|
||||
if (externcmd_can_execute(params->value))
|
||||
{
|
||||
free(handle->script);
|
||||
handle->script = strdup(params->value);
|
||||
MXS_FREE(handle->script);
|
||||
handle->script = MXS_STRDUP_A(params->value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -201,8 +202,8 @@ startMonitor(void *arg, void* opt)
|
||||
if (!check_monitor_permissions(mon, "SHOW STATUS LIKE 'wsrep_local_state'"))
|
||||
{
|
||||
MXS_ERROR("Failed to start monitor. See earlier errors for more information.");
|
||||
free(handle->script);
|
||||
free(handle);
|
||||
MXS_FREE(handle->script);
|
||||
MXS_FREE(handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -210,7 +211,7 @@ startMonitor(void *arg, void* opt)
|
||||
{
|
||||
MXS_ERROR("Errors were found in the script configuration parameters "
|
||||
"for the monitor '%s'. The script will not be used.", mon->name);
|
||||
free(handle->script);
|
||||
MXS_FREE(handle->script);
|
||||
handle->script = NULL;
|
||||
}
|
||||
/** If no specific events are given, enable them all */
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -27,6 +27,7 @@
|
||||
|
||||
#include <mmmon.h>
|
||||
#include <dcb.h>
|
||||
#include <maxscale/alloc.h>
|
||||
|
||||
static void monitorMain(void *);
|
||||
|
||||
@ -121,7 +122,7 @@ startMonitor(void *arg, void* opt)
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((handle = (MM_MONITOR *) malloc(sizeof(MM_MONITOR))) == NULL)
|
||||
if ((handle = (MM_MONITOR *) MXS_MALLOC(sizeof(MM_MONITOR))) == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@ -144,8 +145,8 @@ startMonitor(void *arg, void* opt)
|
||||
{
|
||||
if (externcmd_can_execute(params->value))
|
||||
{
|
||||
free(handle->script);
|
||||
handle->script = strdup(params->value);
|
||||
MXS_FREE(handle->script);
|
||||
handle->script = MXS_STRDUP_A(params->value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -170,8 +171,8 @@ startMonitor(void *arg, void* opt)
|
||||
if (!check_monitor_permissions(mon, "SHOW SLAVE STATUS"))
|
||||
{
|
||||
MXS_ERROR("Failed to start monitor. See earlier errors for more information.");
|
||||
free(handle->script);
|
||||
free(handle);
|
||||
MXS_FREE(handle->script);
|
||||
MXS_FREE(handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -179,7 +180,7 @@ startMonitor(void *arg, void* opt)
|
||||
{
|
||||
MXS_ERROR("Errors were found in the script configuration parameters "
|
||||
"for the monitor '%s'. The script will not be used.", mon->name);
|
||||
free(handle->script);
|
||||
MXS_FREE(handle->script);
|
||||
handle->script = NULL;
|
||||
}
|
||||
/** If no specific events are given, enable them all */
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -48,6 +48,7 @@
|
||||
#include <mysqlmon.h>
|
||||
#include <dcb.h>
|
||||
#include <modutil.h>
|
||||
#include <maxscale/alloc.h>
|
||||
|
||||
extern char *strcasestr(const char *haystack, const char *needle);
|
||||
|
||||
@ -152,7 +153,7 @@ startMonitor(void *arg, void* opt)
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((handle = (MYSQL_MONITOR *) malloc(sizeof(MYSQL_MONITOR))) == NULL)
|
||||
if ((handle = (MYSQL_MONITOR *) MXS_MALLOC(sizeof(MYSQL_MONITOR))) == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@ -186,8 +187,8 @@ startMonitor(void *arg, void* opt)
|
||||
{
|
||||
if (externcmd_can_execute(params->value))
|
||||
{
|
||||
free(handle->script);
|
||||
handle->script = strdup(params->value);
|
||||
MXS_FREE(handle->script);
|
||||
handle->script = MXS_STRDUP_A(params->value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -215,8 +216,8 @@ startMonitor(void *arg, void* opt)
|
||||
if (!check_monitor_permissions(monitor, "SHOW SLAVE STATUS"))
|
||||
{
|
||||
MXS_ERROR("Failed to start monitor. See earlier errors for more information.");
|
||||
free(handle->script);
|
||||
free(handle);
|
||||
MXS_FREE(handle->script);
|
||||
MXS_FREE(handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -224,7 +225,7 @@ startMonitor(void *arg, void* opt)
|
||||
{
|
||||
MXS_ERROR("Errors were found in the script configuration parameters "
|
||||
"for the monitor '%s'. The script will not be used.", monitor->name);
|
||||
free(handle->script);
|
||||
MXS_FREE(handle->script);
|
||||
handle->script = NULL;
|
||||
}
|
||||
/** If no specific events are given, enable them all */
|
||||
@ -840,10 +841,11 @@ monitorMain(void *arg)
|
||||
/* reset the slave list of current node */
|
||||
if (ptr->server->slaves)
|
||||
{
|
||||
free(ptr->server->slaves);
|
||||
MXS_FREE(ptr->server->slaves);
|
||||
}
|
||||
/* create a new slave list */
|
||||
ptr->server->slaves = (long *) calloc(MONITOR_MAX_NUM_SLAVES, sizeof(long));
|
||||
ptr->server->slaves = (long *) MXS_CALLOC(MONITOR_MAX_NUM_SLAVES, sizeof(long));
|
||||
MXS_ABORT_IF_NULL(ptr->server->slaves);
|
||||
|
||||
num_servers++;
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -27,6 +27,7 @@
|
||||
|
||||
|
||||
#include <mysqlmon.h>
|
||||
#include <maxscale/alloc.h>
|
||||
|
||||
static void monitorMain(void *);
|
||||
|
||||
@ -118,7 +119,7 @@ startMonitor(void *arg, void* opt)
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((handle = (MYSQL_MONITOR *) malloc(sizeof(MYSQL_MONITOR))) == NULL)
|
||||
if ((handle = (MYSQL_MONITOR *) MXS_MALLOC(sizeof(MYSQL_MONITOR))) == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@ -135,8 +136,8 @@ startMonitor(void *arg, void* opt)
|
||||
{
|
||||
if (externcmd_can_execute(params->value))
|
||||
{
|
||||
free(handle->script);
|
||||
handle->script = strdup(params->value);
|
||||
MXS_FREE(handle->script);
|
||||
handle->script = MXS_STRDUP_A(params->value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -162,8 +163,8 @@ startMonitor(void *arg, void* opt)
|
||||
if (!check_monitor_permissions(mon, "SHOW STATUS LIKE 'Ndb_number_of_ready_data_nodes'"))
|
||||
{
|
||||
MXS_ERROR("Failed to start monitor. See earlier errors for more information.");
|
||||
free(handle->script);
|
||||
free(handle);
|
||||
MXS_FREE(handle->script);
|
||||
MXS_FREE(handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -171,7 +172,7 @@ startMonitor(void *arg, void* opt)
|
||||
{
|
||||
MXS_ERROR("Errors were found in the script configuration parameters "
|
||||
"for the monitor '%s'. The script will not be used.", mon->name);
|
||||
free(handle->script);
|
||||
MXS_FREE(handle->script);
|
||||
handle->script = NULL;
|
||||
}
|
||||
/** If no specific events are given, enable them all */
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
|
@ -1,37 +1,37 @@
|
||||
add_library(MySQLClient SHARED mysql_client.c mysql_common.c)
|
||||
target_link_libraries(MySQLClient maxscale-common MySQLAuth)
|
||||
set_target_properties(MySQLClient PROPERTIES VERSION "1.0.0")
|
||||
install(TARGETS MySQLClient DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(MySQLClient core)
|
||||
|
||||
add_library(MySQLBackend SHARED mysql_backend.c mysql_common.c)
|
||||
target_link_libraries(MySQLBackend maxscale-common MySQLAuth)
|
||||
set_target_properties(MySQLBackend PROPERTIES VERSION "2.0.0")
|
||||
install(TARGETS MySQLBackend DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(MySQLBackend core)
|
||||
|
||||
add_library(telnetd SHARED telnetd.c)
|
||||
target_link_libraries(telnetd maxscale-common)
|
||||
set_target_properties(telnetd PROPERTIES VERSION "1.0.1")
|
||||
install(TARGETS telnetd DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(telnetd core)
|
||||
|
||||
add_library(HTTPD SHARED httpd.c)
|
||||
target_link_libraries(HTTPD maxscale-common)
|
||||
set_target_properties(HTTPD PROPERTIES VERSION "1.0.1")
|
||||
install(TARGETS HTTPD DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(HTTPD core)
|
||||
|
||||
if(BUILD_TESTS)
|
||||
add_library(testprotocol SHARED testprotocol.c)
|
||||
set_target_properties(testprotocol PROPERTIES VERSION "1.0.0")
|
||||
install(TARGETS testprotocol DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(testprotocol core)
|
||||
endif()
|
||||
|
||||
add_library(maxscaled SHARED maxscaled.c)
|
||||
target_link_libraries(maxscaled maxscale-common)
|
||||
set_target_properties(maxscaled PROPERTIES VERSION "1.0.0")
|
||||
install(TARGETS maxscaled DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(maxscaled core)
|
||||
|
||||
if(BUILD_CDC)
|
||||
add_library(CDC SHARED cdc.c)
|
||||
target_link_libraries(CDC maxscale-common)
|
||||
set_target_properties(CDC PROPERTIES VERSION "1.0.1")
|
||||
install(TARGETS CDC DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(CDC core)
|
||||
endif()
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -31,6 +31,7 @@
|
||||
*/
|
||||
|
||||
#include <cdc.h>
|
||||
#include <maxscale/alloc.h>
|
||||
#include <gw.h>
|
||||
#include <modinfo.h>
|
||||
#include <log_manager.h>
|
||||
@ -321,7 +322,7 @@ cdc_accept(DCB *listener)
|
||||
|
||||
/* create the session data for CDC */
|
||||
/* this coud be done in anothe routine, let's keep it here for now */
|
||||
client_data = (CDC_session *) calloc(1, sizeof(CDC_session));
|
||||
client_data = (CDC_session *) MXS_CALLOC(1, sizeof(CDC_session));
|
||||
if (client_data == NULL)
|
||||
{
|
||||
dcb_close(client_dcb);
|
||||
@ -388,18 +389,10 @@ cdc_protocol_init(DCB* dcb)
|
||||
{
|
||||
CDC_protocol* p;
|
||||
|
||||
p = (CDC_protocol *) calloc(1, sizeof(CDC_protocol));
|
||||
p = (CDC_protocol *) MXS_CALLOC(1, sizeof(CDC_protocol));
|
||||
|
||||
if (p == NULL)
|
||||
{
|
||||
int eno = errno;
|
||||
errno = 0;
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
MXS_ERROR("%lu [CDC_protocol_init] CDC protocol init failed : "
|
||||
"memory allocation due error %d, %s.",
|
||||
pthread_self(),
|
||||
eno,
|
||||
strerror_r(eno, errbuf, sizeof(errbuf)));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -33,6 +33,7 @@
|
||||
*/
|
||||
|
||||
#include <httpd.h>
|
||||
#include <maxscale/alloc.h>
|
||||
#include <gw_protocol.h>
|
||||
#include <gw.h>
|
||||
#include <modinfo.h>
|
||||
@ -54,7 +55,7 @@ MODULE_INFO info =
|
||||
|
||||
#define ISspace(x) isspace((int)(x))
|
||||
#define HTTP_SERVER_STRING "MaxScale(c) v.1.0.0"
|
||||
static char *version_str = "V1.1.1";
|
||||
static char *version_str = "V1.2.0";
|
||||
|
||||
static int httpd_read_event(DCB* dcb);
|
||||
static int httpd_write_event(DCB *dcb);
|
||||
@ -65,7 +66,7 @@ static int httpd_accept(DCB *dcb);
|
||||
static int httpd_close(DCB *dcb);
|
||||
static int httpd_listen(DCB *dcb, char *config);
|
||||
static int httpd_get_line(int sock, char *buf, int size);
|
||||
static void httpd_send_headers(DCB *dcb, int final);
|
||||
static void httpd_send_headers(DCB *dcb, int final, bool auth_ok);
|
||||
static char *httpd_default_auth();
|
||||
|
||||
/**
|
||||
@ -124,6 +125,8 @@ GWPROTOCOL* GetModuleObject()
|
||||
}
|
||||
/*lint +e14 */
|
||||
|
||||
static const char* default_auth = "NullAuthAllow";
|
||||
|
||||
/**
|
||||
* The default authenticator name for this protocol
|
||||
*
|
||||
@ -131,7 +134,7 @@ GWPROTOCOL* GetModuleObject()
|
||||
*/
|
||||
static char *httpd_default_auth()
|
||||
{
|
||||
return "NullAuth";
|
||||
return (char*)default_auth;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -212,6 +215,10 @@ static int httpd_read_event(DCB* dcb)
|
||||
}
|
||||
}
|
||||
|
||||
/** If listener->authenticator is NULL, it means we're using the default
|
||||
* authenticator and we don't need to check the user credentials. */
|
||||
bool auth_ok = dcb->listener->authenticator == 0;
|
||||
|
||||
/**
|
||||
* Get the request headers
|
||||
*/
|
||||
@ -236,6 +243,21 @@ static int httpd_read_event(DCB* dcb)
|
||||
{
|
||||
strcpy(client_data->useragent, value);
|
||||
}
|
||||
|
||||
if (strcmp(buf, "Authorization") == 0)
|
||||
{
|
||||
GWBUF *auth_data = gwbuf_alloc_and_load(strlen(value), value);
|
||||
MXS_OOM_IFNULL(auth_data);
|
||||
|
||||
if (auth_data)
|
||||
{
|
||||
/** The freeing entry point is called automatically when
|
||||
* the client DCB is closed */
|
||||
dcb->authfunc.extract(dcb, auth_data);
|
||||
auth_ok = dcb->authfunc.authenticate(dcb) == 0;
|
||||
gwbuf_free(auth_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -250,7 +272,7 @@ static int httpd_read_event(DCB* dcb)
|
||||
*/
|
||||
|
||||
/* send all the basic headers and close with \r\n */
|
||||
httpd_send_headers(dcb, 1);
|
||||
httpd_send_headers(dcb, 1, auth_ok);
|
||||
|
||||
#if 0
|
||||
/**
|
||||
@ -281,7 +303,7 @@ static int httpd_read_event(DCB* dcb)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if ((uri = gwbuf_alloc(strlen(url) + 1)) != NULL)
|
||||
if (auth_ok && (uri = gwbuf_alloc(strlen(url) + 1)) != NULL)
|
||||
{
|
||||
strcpy((char *)GWBUF_DATA(uri), url);
|
||||
gwbuf_set_type(uri, GWBUF_TYPE_HTTP);
|
||||
@ -359,7 +381,7 @@ static int httpd_accept(DCB *listener)
|
||||
HTTPD_session *client_data = NULL;
|
||||
|
||||
/* create the session data for HTTPD */
|
||||
if ((client_data = (HTTPD_session *)calloc(1, sizeof(HTTPD_session))) == NULL)
|
||||
if ((client_data = (HTTPD_session *)MXS_CALLOC(1, sizeof(HTTPD_session))) == NULL)
|
||||
{
|
||||
dcb_close(client_dcb);
|
||||
continue;
|
||||
@ -449,7 +471,7 @@ static int httpd_get_line(int sock, char *buf, int size)
|
||||
/**
|
||||
* HTTPD send basic headers with 200 OK
|
||||
*/
|
||||
static void httpd_send_headers(DCB *dcb, int final)
|
||||
static void httpd_send_headers(DCB *dcb, int final, bool auth_ok)
|
||||
{
|
||||
char date[64] = "";
|
||||
const char *fmt = "%a, %d %b %Y %H:%M:%S GMT";
|
||||
@ -458,11 +480,15 @@ static void httpd_send_headers(DCB *dcb, int final)
|
||||
struct tm tm;
|
||||
localtime_r(&httpd_current_time, &tm);
|
||||
strftime(date, sizeof(date), fmt, &tm);
|
||||
|
||||
const char *response = auth_ok ? "200 OK" : "401 Unauthorized";
|
||||
dcb_printf(dcb,
|
||||
"HTTP/1.1 200 OK\r\nDate: %s\r\nServer: %s\r\nConnection: "
|
||||
"close\r\nContent-Type: application/json\r\n",
|
||||
date, HTTP_SERVER_STRING);
|
||||
"HTTP/1.1 %s\r\n"
|
||||
"Date: %s\r\n"
|
||||
"Server: %s\r\n"
|
||||
"Connection: close\r\n"
|
||||
"WWW-Authenticate: Basic realm=\"MaxInfo\"\r\n"
|
||||
"Content-Type: application/json\r\n",
|
||||
response, date, HTTP_SERVER_STRING);
|
||||
|
||||
/* close the headers */
|
||||
if (final)
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -35,6 +35,7 @@
|
||||
#include <modinfo.h>
|
||||
#include <maxscaled.h>
|
||||
#include <maxadmin.h>
|
||||
#include <maxscale/alloc.h>
|
||||
|
||||
/* @see function load_module in load_utils.c for explanation of the following
|
||||
* lint directives.
|
||||
@ -242,7 +243,7 @@ static int maxscaled_accept(DCB *listener)
|
||||
{
|
||||
MAXSCALED *maxscaled_protocol = NULL;
|
||||
|
||||
if ((maxscaled_protocol = (MAXSCALED *)calloc(1, sizeof(MAXSCALED))) == NULL)
|
||||
if ((maxscaled_protocol = (MAXSCALED *)MXS_CALLOC(1, sizeof(MAXSCALED))) == NULL)
|
||||
{
|
||||
dcb_close(client_dcb);
|
||||
continue;
|
||||
@ -270,7 +271,7 @@ static int maxscaled_accept(DCB *listener)
|
||||
GWBUF *username;
|
||||
|
||||
/* Set user in protocol */
|
||||
maxscaled_protocol->username = strdup(pw_entry.pw_name);
|
||||
maxscaled_protocol->username = MXS_STRDUP_A(pw_entry.pw_name);
|
||||
|
||||
username = gwbuf_alloc(strlen(maxscaled_protocol->username) + 1);
|
||||
|
||||
@ -282,7 +283,7 @@ static int maxscaled_accept(DCB *listener)
|
||||
{
|
||||
dcb_printf(client_dcb, "OK----");
|
||||
maxscaled_protocol->state = MAXSCALED_STATE_DATA;
|
||||
client_dcb->user = strdup(maxscaled_protocol->username);
|
||||
client_dcb->user = MXS_STRDUP_A(maxscaled_protocol->username);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -332,7 +333,7 @@ static int maxscaled_close(DCB *dcb)
|
||||
spinlock_acquire(&maxscaled->lock);
|
||||
if (maxscaled->username)
|
||||
{
|
||||
free(maxscaled->username);
|
||||
MXS_FREE(maxscaled->username);
|
||||
maxscaled->username = NULL;
|
||||
}
|
||||
spinlock_release(&maxscaled->lock);
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -51,6 +51,7 @@ uint8_t null_client_sha1[MYSQL_SCRAMBLE_LEN]="";
|
||||
* 23/05/2016 Martin Brampton Provide for backend SSL
|
||||
*
|
||||
*/
|
||||
#include <maxscale/alloc.h>
|
||||
#include <modinfo.h>
|
||||
#include <gw_protocol.h>
|
||||
#include <mysql_auth.h>
|
||||
@ -652,7 +653,7 @@ gw_read_backend_handshake(MySQLProtocol *conn)
|
||||
server_set_status(dcb->server, SERVER_MAINT);
|
||||
}
|
||||
|
||||
free(bufstr);
|
||||
MXS_FREE(bufstr);
|
||||
}
|
||||
//get mysql packet size, 3 bytes
|
||||
packet_len = gw_mysql_get_byte3(payload);
|
||||
@ -1779,8 +1780,17 @@ static int gw_change_user(DCB *backend,
|
||||
|
||||
/* now get the user, after 4 bytes header and 1 byte command */
|
||||
client_auth_packet += 5;
|
||||
size_t len = strlen((char *)client_auth_packet);
|
||||
if (len > MYSQL_USER_MAXLEN)
|
||||
{
|
||||
MXS_ERROR("Client sent user name \"%s\",which is %lu characters long, "
|
||||
"while a maximum length of %d is allowed. Cutting trailing "
|
||||
"characters.", (char*)client_auth_packet, len, MYSQL_USER_MAXLEN);
|
||||
}
|
||||
strncpy(username, (char *)client_auth_packet, MYSQL_USER_MAXLEN);
|
||||
client_auth_packet += strlen(username) + 1;
|
||||
username[MYSQL_USER_MAXLEN] = 0;
|
||||
|
||||
client_auth_packet += (len + 1);
|
||||
|
||||
/* get the auth token len */
|
||||
memcpy(&auth_token_len, client_auth_packet, 1);
|
||||
@ -1790,7 +1800,7 @@ static int gw_change_user(DCB *backend,
|
||||
/* allocate memory for token only if auth_token_len > 0 */
|
||||
if (auth_token_len > 0)
|
||||
{
|
||||
auth_token = (uint8_t *)malloc(auth_token_len);
|
||||
auth_token = (uint8_t *)MXS_MALLOC(auth_token_len);
|
||||
ss_dassert(auth_token != NULL);
|
||||
|
||||
if (auth_token == NULL)
|
||||
@ -1802,19 +1812,19 @@ static int gw_change_user(DCB *backend,
|
||||
}
|
||||
|
||||
/* get new database name */
|
||||
len = strlen((char *)client_auth_packet);
|
||||
if (len > MYSQL_DATABASE_MAXLEN)
|
||||
{
|
||||
MXS_ERROR("Client sent database name \"%s\", which is %lu characters long, "
|
||||
"while a maximum length of %d is allowed. Cutting trailing "
|
||||
"characters.", (char*)client_auth_packet, len, MYSQL_DATABASE_MAXLEN);
|
||||
}
|
||||
strncpy(database, (char *)client_auth_packet, MYSQL_DATABASE_MAXLEN);
|
||||
database[MYSQL_DATABASE_MAXLEN] = 0;
|
||||
|
||||
/* get character set */
|
||||
if (strlen(database))
|
||||
{
|
||||
client_auth_packet += strlen(database) + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
client_auth_packet++;
|
||||
}
|
||||
client_auth_packet += (len + 1);
|
||||
|
||||
if (client_auth_packet && *client_auth_packet)
|
||||
if (*client_auth_packet)
|
||||
{
|
||||
memcpy(&backend_protocol->charset, client_auth_packet, sizeof(int));
|
||||
}
|
||||
@ -1822,13 +1832,13 @@ static int gw_change_user(DCB *backend,
|
||||
spinlock_acquire(&in_session->ses_lock);
|
||||
|
||||
/* save current_database name */
|
||||
strncpy(current_database, current_session->db, MYSQL_DATABASE_MAXLEN);
|
||||
strcpy(current_database, current_session->db);
|
||||
|
||||
/*
|
||||
* Now clear database name in dcb as we don't do local authentication on db name for change user.
|
||||
* Local authentication only for user@host and if successful the database name change is sent to backend.
|
||||
*/
|
||||
strncpy(current_session->db, "", MYSQL_DATABASE_MAXLEN);
|
||||
*current_session->db = 0;
|
||||
|
||||
/*
|
||||
* Decode the token and check the password.
|
||||
@ -1839,7 +1849,7 @@ static int gw_change_user(DCB *backend,
|
||||
client_protocol->scramble,
|
||||
sizeof(client_protocol->scramble),
|
||||
username, client_sha1);
|
||||
strncpy(current_session->db, current_database, MYSQL_DATABASE_MAXLEN);
|
||||
strcpy(current_session->db, current_database);
|
||||
spinlock_release(&in_session->ses_lock);
|
||||
|
||||
if (auth_ret != 0)
|
||||
@ -1849,14 +1859,14 @@ static int gw_change_user(DCB *backend,
|
||||
/* Try authentication again with new repository data */
|
||||
/* Note: if no auth client authentication will fail */
|
||||
spinlock_acquire(&in_session->ses_lock);
|
||||
strncpy(current_session->db, "", MYSQL_DATABASE_MAXLEN);
|
||||
*current_session->db = 0;
|
||||
auth_ret = gw_check_mysql_scramble_data(
|
||||
backend->session->client_dcb,
|
||||
auth_token, auth_token_len,
|
||||
client_protocol->scramble,
|
||||
sizeof(client_protocol->scramble),
|
||||
username, client_sha1);
|
||||
strncpy(current_session->db, current_database, MYSQL_DATABASE_MAXLEN);
|
||||
strcpy(current_session->db, current_database);
|
||||
spinlock_release(&in_session->ses_lock);
|
||||
}
|
||||
}
|
||||
@ -1864,7 +1874,7 @@ static int gw_change_user(DCB *backend,
|
||||
/* let's free the auth_token now */
|
||||
if (auth_token)
|
||||
{
|
||||
free(auth_token);
|
||||
MXS_FREE(auth_token);
|
||||
}
|
||||
|
||||
if (auth_ret != 0)
|
||||
@ -2279,8 +2289,8 @@ gw_receive_backend_auth(MySQLProtocol *protocol)
|
||||
err,
|
||||
bufstr);
|
||||
|
||||
free(bufstr);
|
||||
free(err);
|
||||
MXS_FREE(bufstr);
|
||||
MXS_FREE(err);
|
||||
rc = -1;
|
||||
}
|
||||
else
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -47,6 +47,7 @@
|
||||
*/
|
||||
#include <gw_protocol.h>
|
||||
#include <skygw_utils.h>
|
||||
#include <maxscale/alloc.h>
|
||||
#include <log_manager.h>
|
||||
#include <mysql_client_server_protocol.h>
|
||||
#include <mysql_auth.h>
|
||||
@ -94,6 +95,7 @@ static int gw_read_normal_data(DCB *dcb, GWBUF *read_buffer, int nbytes_read);
|
||||
static int gw_read_finish_processing(DCB *dcb, GWBUF *read_buffer, uint8_t capabilities);
|
||||
extern char* create_auth_fail_str(char *username, char *hostaddr, char *sha1, char *db,int);
|
||||
static bool ensure_complete_packet(DCB *dcb, GWBUF **read_buffer, int nbytes_read);
|
||||
static void gw_process_one_new_client(DCB *client_dcb);
|
||||
|
||||
/*
|
||||
* The "module object" for the mysqld client protocol module.
|
||||
@ -990,7 +992,8 @@ mysql_client_auth_error_handling(DCB *dcb, int auth_val)
|
||||
/** Send error 1049 to client */
|
||||
message_len = 25 + MYSQL_DATABASE_MAXLEN;
|
||||
|
||||
fail_str = calloc(1, message_len+1);
|
||||
fail_str = MXS_CALLOC(1, message_len+1);
|
||||
MXS_ABORT_IF_NULL(fail_str);
|
||||
snprintf(fail_str, message_len, "Unknown database '%s'",
|
||||
(char*)((MYSQL_session *)dcb->data)->db);
|
||||
|
||||
@ -1046,7 +1049,7 @@ mysql_client_auth_error_handling(DCB *dcb, int auth_val)
|
||||
(char*)((MYSQL_session *)dcb->data)->db, auth_val);
|
||||
modutil_send_mysql_err_packet(dcb, packet_number, 0, 1045, "28000", fail_str);
|
||||
}
|
||||
free(fail_str);
|
||||
MXS_FREE(fail_str);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1151,68 +1154,90 @@ int gw_MySQLAccept(DCB *listener)
|
||||
|
||||
CHK_DCB(listener);
|
||||
|
||||
while ((client_dcb = dcb_accept(listener, &MyObject)) != NULL)
|
||||
if (DCB_STATE_WAITING == listener->state)
|
||||
{
|
||||
CHK_DCB(client_dcb);
|
||||
protocol = mysql_protocol_init(client_dcb, client_dcb->fd);
|
||||
|
||||
if (protocol == NULL)
|
||||
gw_process_one_new_client(listener);
|
||||
}
|
||||
else
|
||||
{
|
||||
while ((client_dcb = dcb_accept(listener, &MyObject)) != NULL)
|
||||
{
|
||||
/** delete client_dcb */
|
||||
dcb_close(client_dcb);
|
||||
MXS_ERROR("%lu [gw_MySQLAccept] Failed to create "
|
||||
"protocol object for client connection.",
|
||||
pthread_self());
|
||||
continue;
|
||||
}
|
||||
CHK_PROTOCOL(protocol);
|
||||
client_dcb->protocol = protocol;
|
||||
atomic_add(&client_dcb->service->client_count, 1);
|
||||
//send handshake to the client_dcb
|
||||
MySQLSendHandshake(client_dcb);
|
||||
|
||||
// client protocol state change
|
||||
protocol->protocol_auth_state = MYSQL_AUTH_SENT;
|
||||
|
||||
/**
|
||||
* Set new descriptor to event set. At the same time,
|
||||
* change state to DCB_STATE_POLLING so that
|
||||
* thread which wakes up sees correct state.
|
||||
*/
|
||||
if (poll_add_dcb(client_dcb) == -1)
|
||||
{
|
||||
/* Send a custom error as MySQL command reply */
|
||||
mysql_send_custom_error(client_dcb,
|
||||
1,
|
||||
0,
|
||||
"MaxScale encountered system limit while "
|
||||
"attempting to register on an epoll instance.");
|
||||
|
||||
/** close client_dcb */
|
||||
dcb_close(client_dcb);
|
||||
|
||||
/** Previous state is recovered in poll_add_dcb. */
|
||||
MXS_ERROR("%lu [gw_MySQLAccept] Failed to add dcb %p for "
|
||||
"fd %d to epoll set.",
|
||||
pthread_self(),
|
||||
client_dcb,
|
||||
client_dcb->fd);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_DEBUG("%lu [gw_MySQLAccept] Added dcb %p for fd "
|
||||
"%d to epoll set.",
|
||||
pthread_self(),
|
||||
client_dcb,
|
||||
client_dcb->fd);
|
||||
}
|
||||
} /**< while client_dcb != NULL */
|
||||
gw_process_one_new_client(client_dcb);
|
||||
} /**< while client_dcb != NULL */
|
||||
}
|
||||
|
||||
/* Must have broken out of while loop or received NULL client_dcb */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void gw_process_one_new_client(DCB *client_dcb)
|
||||
{
|
||||
MySQLProtocol *protocol;
|
||||
|
||||
CHK_DCB(client_dcb);
|
||||
protocol = mysql_protocol_init(client_dcb, client_dcb->fd);
|
||||
|
||||
if (protocol == NULL)
|
||||
{
|
||||
/** delete client_dcb */
|
||||
dcb_close(client_dcb);
|
||||
MXS_ERROR("%lu [gw_MySQLAccept] Failed to create "
|
||||
"protocol object for client connection.",
|
||||
pthread_self());
|
||||
return;
|
||||
}
|
||||
CHK_PROTOCOL(protocol);
|
||||
client_dcb->protocol = protocol;
|
||||
if (DCB_STATE_WAITING == client_dcb->state)
|
||||
{
|
||||
client_dcb->state = DCB_STATE_ALLOC;
|
||||
}
|
||||
else
|
||||
{
|
||||
atomic_add(&client_dcb->service->client_count, 1);
|
||||
}
|
||||
//send handshake to the client_dcb
|
||||
MySQLSendHandshake(client_dcb);
|
||||
|
||||
// client protocol state change
|
||||
protocol->protocol_auth_state = MYSQL_AUTH_SENT;
|
||||
|
||||
/**
|
||||
* Set new descriptor to event set. At the same time,
|
||||
* change state to DCB_STATE_POLLING so that
|
||||
* thread which wakes up sees correct state.
|
||||
*/
|
||||
if (poll_add_dcb(client_dcb) == -1)
|
||||
{
|
||||
/* Send a custom error as MySQL command reply */
|
||||
mysql_send_custom_error(client_dcb,
|
||||
1,
|
||||
0,
|
||||
"MaxScale encountered system limit while "
|
||||
"attempting to register on an epoll instance.");
|
||||
|
||||
/** close client_dcb */
|
||||
dcb_close(client_dcb);
|
||||
|
||||
/** Previous state is recovered in poll_add_dcb. */
|
||||
MXS_ERROR("%lu [gw_MySQLAccept] Failed to add dcb %p for "
|
||||
"fd %d to epoll set.",
|
||||
pthread_self(),
|
||||
client_dcb,
|
||||
client_dcb->fd);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_DEBUG("%lu [gw_MySQLAccept] Added dcb %p for fd "
|
||||
"%d to epoll set.",
|
||||
pthread_self(),
|
||||
client_dcb,
|
||||
client_dcb->fd);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static int gw_error_client_event(DCB* dcb)
|
||||
{
|
||||
SESSION* session;
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -44,7 +44,8 @@
|
||||
|
||||
#include <gw.h>
|
||||
#include <utils.h>
|
||||
#include "mysql_client_server_protocol.h"
|
||||
#include <mysql_client_server_protocol.h>
|
||||
#include <maxscale/alloc.h>
|
||||
#include <skygw_types.h>
|
||||
#include <skygw_utils.h>
|
||||
#include <log_manager.h>
|
||||
@ -69,19 +70,11 @@ MySQLProtocol* mysql_protocol_init(DCB* dcb, int fd)
|
||||
{
|
||||
MySQLProtocol* p;
|
||||
|
||||
p = (MySQLProtocol *) calloc(1, sizeof(MySQLProtocol));
|
||||
p = (MySQLProtocol *) MXS_CALLOC(1, sizeof(MySQLProtocol));
|
||||
ss_dassert(p != NULL);
|
||||
|
||||
if (p == NULL)
|
||||
{
|
||||
int eno = errno;
|
||||
errno = 0;
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
MXS_ERROR("%lu [mysql_init_protocol] MySQL protocol init failed : "
|
||||
"memory allocation due error %d, %s.",
|
||||
pthread_self(),
|
||||
eno,
|
||||
strerror_r(eno, errbuf, sizeof(errbuf)));
|
||||
goto return_p;
|
||||
}
|
||||
p->protocol_state = MYSQL_PROTOCOL_ALLOC;
|
||||
@ -130,7 +123,7 @@ void mysql_protocol_done(DCB* dcb)
|
||||
while (scmd != NULL)
|
||||
{
|
||||
scmd2 = scmd->scom_next;
|
||||
free(scmd);
|
||||
MXS_FREE(scmd);
|
||||
scmd = scmd2;
|
||||
}
|
||||
p->protocol_state = MYSQL_PROTOCOL_DONE;
|
||||
@ -423,7 +416,6 @@ int mysql_send_custom_error(DCB *dcb,
|
||||
}
|
||||
|
||||
/**
|
||||
>>>>>>> origin/develop
|
||||
* mysql_send_auth_error
|
||||
*
|
||||
* Send a MySQL protocol ERR message, for gateway authentication error to the dcb
|
||||
@ -619,7 +611,7 @@ static server_command_t* server_command_init(server_command_t* srvcmd,
|
||||
}
|
||||
else
|
||||
{
|
||||
c = (server_command_t *)malloc(sizeof(server_command_t));
|
||||
c = (server_command_t *)MXS_MALLOC(sizeof(server_command_t));
|
||||
}
|
||||
if (c != NULL)
|
||||
{
|
||||
@ -634,12 +626,8 @@ static server_command_t* server_command_init(server_command_t* srvcmd,
|
||||
|
||||
static server_command_t* server_command_copy(server_command_t* srvcmd)
|
||||
{
|
||||
server_command_t* c = (server_command_t *)malloc(sizeof(server_command_t));
|
||||
if (NULL == c)
|
||||
{
|
||||
MXS_ERROR("Memory failure while attempting server_command_copy");
|
||||
}
|
||||
else
|
||||
server_command_t* c = (server_command_t *)MXS_MALLOC(sizeof(server_command_t));
|
||||
if (c)
|
||||
{
|
||||
*c = *srvcmd;
|
||||
}
|
||||
@ -692,7 +680,7 @@ void protocol_archive_srv_command(MySQLProtocol* p)
|
||||
{
|
||||
server_command_t* c = p->protocol_cmd_history;
|
||||
p->protocol_cmd_history = p->protocol_cmd_history->scom_next;
|
||||
free(c);
|
||||
MXS_FREE(c);
|
||||
}
|
||||
|
||||
/** Remove from command list */
|
||||
@ -703,7 +691,7 @@ void protocol_archive_srv_command(MySQLProtocol* p)
|
||||
else
|
||||
{
|
||||
p->protocol_command = *(s1->scom_next);
|
||||
free(s1->scom_next);
|
||||
MXS_FREE(s1->scom_next);
|
||||
}
|
||||
|
||||
retblock:
|
||||
@ -783,7 +771,7 @@ void protocol_remove_srv_command(MySQLProtocol* p)
|
||||
else
|
||||
{
|
||||
p->protocol_command = *(s->scom_next);
|
||||
free(s->scom_next);
|
||||
MXS_FREE(s->scom_next);
|
||||
}
|
||||
|
||||
spinlock_release(&p->protocol_lock);
|
||||
@ -928,7 +916,7 @@ char* create_auth_failed_msg(GWBUF*readbuf,
|
||||
const char* ferrstr = "Access denied for user '%s'@'%s' (using password: %s)";
|
||||
|
||||
/** -4 comes from 2X'%s' minus terminating char */
|
||||
errstr = (char *)malloc(strlen(uname) + strlen(ferrstr) + strlen(hostaddr) + strlen("YES") - 6 + 1);
|
||||
errstr = (char *)MXS_MALLOC(strlen(uname) + strlen(ferrstr) + strlen(hostaddr) + strlen("YES") - 6 + 1);
|
||||
|
||||
if (errstr != NULL)
|
||||
{
|
||||
@ -979,15 +967,12 @@ char *create_auth_fail_str(char *username,
|
||||
{
|
||||
ferrstr = "Access denied for user '%s'@'%s' (using password: %s)";
|
||||
}
|
||||
errstr = (char *)malloc(strlen(username) + strlen(ferrstr) +
|
||||
strlen(hostaddr) + strlen("YES") - 6 +
|
||||
db_len + ((db_len > 0) ? (strlen(" to database ") +2) : 0) + 1);
|
||||
errstr = (char *)MXS_MALLOC(strlen(username) + strlen(ferrstr) +
|
||||
strlen(hostaddr) + strlen("YES") - 6 +
|
||||
db_len + ((db_len > 0) ? (strlen(" to database ") + 2) : 0) + 1);
|
||||
|
||||
if (errstr == NULL)
|
||||
{
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
MXS_ERROR("Memory allocation failed due to %s.",
|
||||
strerror_r(errno, errbuf, sizeof(errbuf)));
|
||||
goto retblock;
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -14,6 +14,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <maxscale/alloc.h>
|
||||
#include <dcb.h>
|
||||
#include <buffer.h>
|
||||
#include <service.h>
|
||||
@ -148,7 +149,7 @@ GWPROTOCOL* GetModuleObject()
|
||||
*/
|
||||
static char *telnetd_default_auth()
|
||||
{
|
||||
return "NullAuth";
|
||||
return "NullAuthAllow";
|
||||
}
|
||||
|
||||
/**
|
||||
@ -213,10 +214,10 @@ static int telnetd_read_event(DCB* dcb)
|
||||
dcb_printf(dcb, "\n\rLogin incorrect\n\rLogin: ");
|
||||
telnetd_echo(dcb, 1);
|
||||
telnetd->state = TELNETD_STATE_LOGIN;
|
||||
free(telnetd->username);
|
||||
MXS_FREE(telnetd->username);
|
||||
}
|
||||
gwbuf_consume(head, GWBUF_LENGTH(head));
|
||||
free(password);
|
||||
MXS_FREE(password);
|
||||
break;
|
||||
case TELNETD_STATE_DATA:
|
||||
SESSION_ROUTE_QUERY(session, head);
|
||||
@ -296,7 +297,7 @@ static int telnetd_accept(DCB *listener)
|
||||
{
|
||||
TELNETD* telnetd_protocol = NULL;
|
||||
|
||||
if ((telnetd_protocol = (TELNETD *)calloc(1, sizeof(TELNETD))) == NULL)
|
||||
if ((telnetd_protocol = (TELNETD *)MXS_CALLOC(1, sizeof(TELNETD))) == NULL)
|
||||
{
|
||||
dcb_close(client_dcb);
|
||||
continue;
|
||||
@ -333,7 +334,7 @@ static int telnetd_close(DCB *dcb)
|
||||
|
||||
if (telnetd && telnetd->username)
|
||||
{
|
||||
free(telnetd->username);
|
||||
MXS_FREE(telnetd->username);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -56,7 +56,7 @@ static int test_close(DCB *dcb){ return 1;}
|
||||
static int test_listen(DCB *dcb, char *config){ return 1;}
|
||||
static int test_auth(DCB* dcb, struct server *srv, struct session *ses, GWBUF *buf){ return 1;}
|
||||
static int test_session(DCB *dcb, void* data){ return 1;}
|
||||
static char *test_default_auth(){return "NullAuth";}
|
||||
static char *test_default_auth(){return "NullAuthAllow";}
|
||||
static int test_connection_limit(DCB *dcb, int limit){return 0;}
|
||||
/**
|
||||
* The "module object" for the httpd protocol module.
|
||||
|
@ -2,23 +2,23 @@ if(BUILD_TESTS)
|
||||
add_library(testroute SHARED testroute.c)
|
||||
target_link_libraries(testroute maxscale-common)
|
||||
set_target_properties(testroute PROPERTIES VERSION "1.0.0")
|
||||
install(TARGETS testroute DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(testroute core)
|
||||
endif()
|
||||
|
||||
add_library(readconnroute SHARED readconnroute.c)
|
||||
target_link_libraries(readconnroute maxscale-common)
|
||||
set_target_properties(readconnroute PROPERTIES VERSION "1.1.0")
|
||||
install(TARGETS readconnroute DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(readconnroute core)
|
||||
|
||||
add_library(debugcli SHARED debugcli.c debugcmd.c)
|
||||
target_link_libraries(debugcli maxscale-common)
|
||||
set_target_properties(debugcli PROPERTIES VERSION "1.1.1")
|
||||
install(TARGETS debugcli DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(debugcli core)
|
||||
|
||||
add_library(cli SHARED cli.c debugcmd.c)
|
||||
target_link_libraries(cli maxscale-common)
|
||||
set_target_properties(cli PROPERTIES VERSION "1.0.0")
|
||||
install(TARGETS cli DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(cli core)
|
||||
|
||||
add_subdirectory(readwritesplit)
|
||||
add_subdirectory(schemarouter)
|
||||
|
@ -4,12 +4,12 @@ if(AVRO_FOUND)
|
||||
set_target_properties(avrorouter PROPERTIES VERSION "1.0.0")
|
||||
set_target_properties(avrorouter PROPERTIES LINK_FLAGS -Wl,-z,defs)
|
||||
target_link_libraries(avrorouter maxscale-common jansson ${AVRO_LIBRARIES} maxavro sqlite3 lzma)
|
||||
install(TARGETS avrorouter DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install(PROGRAMS cdc DESTINATION ${MAXSCALE_BINDIR})
|
||||
install(PROGRAMS cdc_users DESTINATION ${MAXSCALE_BINDIR})
|
||||
install(PROGRAMS cdc_last_transaction DESTINATION ${MAXSCALE_BINDIR})
|
||||
install(PROGRAMS cdc_kafka_producer DESTINATION ${MAXSCALE_BINDIR})
|
||||
install(FILES cdc_schema.go DESTINATION ${MAXSCALE_SHAREDIR})
|
||||
install_module(avrorouter core)
|
||||
install_script(cdc core)
|
||||
install_script(cdc_users core)
|
||||
install_script(cdc_last_transaction core)
|
||||
install_script(cdc_kafka_producer core)
|
||||
install_file(cdc_schema.go core)
|
||||
else()
|
||||
message(STATUS "Avro C libraries were not found, avrorouter will not be built.")
|
||||
endif()
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -51,6 +51,7 @@
|
||||
#include <random_jkiss.h>
|
||||
#include <binlog_common.h>
|
||||
#include <avro/errors.h>
|
||||
#include <maxscale/alloc.h>
|
||||
|
||||
#ifndef BINLOG_NAMEFMT
|
||||
#define BINLOG_NAMEFMT "%s.%06d"
|
||||
@ -149,20 +150,6 @@ GetModuleObject()
|
||||
return &MyObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Safe hashtable key freeing function
|
||||
*
|
||||
* This function conforms to the HASHMEMORYFN type by returning a NULL pointer
|
||||
*
|
||||
* @param data Data to free
|
||||
* @return Always NULL
|
||||
*/
|
||||
void* safe_key_free(void *data)
|
||||
{
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the required tables in the sqlite database
|
||||
*
|
||||
@ -266,7 +253,7 @@ void read_source_service_options(AVRO_INSTANCE *inst, const char** options)
|
||||
for (int i = 0; options[i]; i++)
|
||||
{
|
||||
char option[strlen(options[i]) + 1];
|
||||
strncpy(option, options[i], sizeof(option));
|
||||
strcpy(option, options[i]);
|
||||
|
||||
char *value = strchr(option, '=');
|
||||
if (value)
|
||||
@ -276,18 +263,45 @@ void read_source_service_options(AVRO_INSTANCE *inst, const char** options)
|
||||
|
||||
if (strcmp(option, "binlogdir") == 0)
|
||||
{
|
||||
inst->binlogdir = strdup(value);
|
||||
inst->binlogdir = MXS_STRDUP_A(value);
|
||||
MXS_INFO("Reading MySQL binlog files from %s", inst->binlogdir);
|
||||
}
|
||||
else if (strcmp(option, "filestem") == 0)
|
||||
{
|
||||
inst->fileroot = strdup(value);
|
||||
inst->fileroot = MXS_STRDUP_A(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TABLE_CREATE free function for use with hashtable.
|
||||
* @param v Pointer to a TABLE_CREATE
|
||||
*/
|
||||
static void table_create_hfree(void* v)
|
||||
{
|
||||
table_create_free((TABLE_CREATE*)v);
|
||||
}
|
||||
|
||||
/**
|
||||
* AVRO_TABLE free function for use with hashtable.
|
||||
* @param v Pointer to a AVRO_TABLE
|
||||
*/
|
||||
static void avro_table_hfree(void* v)
|
||||
{
|
||||
avro_table_free((AVRO_TABLE*)v);
|
||||
}
|
||||
|
||||
/**
|
||||
* TABLE_MAP free function for use with hashtable.
|
||||
* @param v Pointer to a TABLE_MAP
|
||||
*/
|
||||
static void table_map_hfree(void* v)
|
||||
{
|
||||
table_map_free((TABLE_MAP*)v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of the router for a particular service
|
||||
* within MaxScale.
|
||||
@ -307,10 +321,8 @@ createInstance(SERVICE *service, char **options)
|
||||
AVRO_INSTANCE *inst;
|
||||
int i;
|
||||
|
||||
if ((inst = calloc(1, sizeof(AVRO_INSTANCE))) == NULL)
|
||||
if ((inst = MXS_CALLOC(1, sizeof(AVRO_INSTANCE))) == NULL)
|
||||
{
|
||||
MXS_ERROR("%s: Error: failed to allocate memory for router instance.",
|
||||
service->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -376,19 +388,19 @@ createInstance(SERVICE *service, char **options)
|
||||
|
||||
if (strcmp(options[i], "binlogdir") == 0)
|
||||
{
|
||||
free(inst->binlogdir);
|
||||
inst->binlogdir = strdup(value);
|
||||
MXS_FREE(inst->binlogdir);
|
||||
inst->binlogdir = MXS_STRDUP_A(value);
|
||||
MXS_INFO("Reading MySQL binlog files from %s", inst->binlogdir);
|
||||
}
|
||||
else if (strcmp(options[i], "avrodir") == 0)
|
||||
{
|
||||
inst->avrodir = strdup(value);
|
||||
inst->avrodir = MXS_STRDUP_A(value);
|
||||
MXS_INFO("AVRO files stored in %s", inst->avrodir);
|
||||
}
|
||||
else if (strcmp(options[i], "filestem") == 0)
|
||||
{
|
||||
free(inst->fileroot);
|
||||
inst->fileroot = strdup(value);
|
||||
MXS_FREE(inst->fileroot);
|
||||
inst->fileroot = MXS_STRDUP_A(value);
|
||||
}
|
||||
else if (strcmp(options[i], "group_rows") == 0)
|
||||
{
|
||||
@ -432,13 +444,13 @@ createInstance(SERVICE *service, char **options)
|
||||
{
|
||||
MXS_NOTICE("[%s] No 'filestem' option specified, using default binlog name '%s'.",
|
||||
service->name, BINLOG_NAME_ROOT);
|
||||
inst->fileroot = strdup(BINLOG_NAME_ROOT);
|
||||
inst->fileroot = MXS_STRDUP_A(BINLOG_NAME_ROOT);
|
||||
}
|
||||
|
||||
/** Use the binlogdir as the default if no avrodir is specified. */
|
||||
if (inst->avrodir == NULL && inst->binlogdir)
|
||||
{
|
||||
inst->avrodir = strdup(inst->binlogdir);
|
||||
inst->avrodir = MXS_STRDUP_A(inst->binlogdir);
|
||||
}
|
||||
|
||||
if (ensure_dir_ok(inst->avrodir, W_OK))
|
||||
@ -455,16 +467,16 @@ createInstance(SERVICE *service, char **options)
|
||||
snprintf(inst->binlog_name, sizeof(inst->binlog_name), BINLOG_NAMEFMT, inst->fileroot, first_file);
|
||||
inst->prevbinlog[0] = '\0';
|
||||
|
||||
if ((inst->table_maps = hashtable_alloc(1000, simple_str_hash, strcmp)) &&
|
||||
(inst->open_tables = hashtable_alloc(1000, simple_str_hash, strcmp)) &&
|
||||
(inst->created_tables = hashtable_alloc(1000, simple_str_hash, strcmp)))
|
||||
if ((inst->table_maps = hashtable_alloc(1000, hashtable_item_strhash, hashtable_item_strcmp)) &&
|
||||
(inst->open_tables = hashtable_alloc(1000, hashtable_item_strhash, hashtable_item_strcmp)) &&
|
||||
(inst->created_tables = hashtable_alloc(1000, hashtable_item_strhash, hashtable_item_strcmp)))
|
||||
{
|
||||
hashtable_memory_fns(inst->table_maps, (HASHMEMORYFN)strdup, NULL,
|
||||
safe_key_free, (HASHMEMORYFN)table_map_free);
|
||||
hashtable_memory_fns(inst->open_tables, (HASHMEMORYFN)strdup, NULL,
|
||||
safe_key_free, (HASHMEMORYFN)avro_table_free);
|
||||
hashtable_memory_fns(inst->created_tables, (HASHMEMORYFN)strdup, NULL,
|
||||
safe_key_free, (HASHMEMORYFN)table_create_free);
|
||||
hashtable_memory_fns(inst->table_maps, hashtable_item_strdup, NULL,
|
||||
hashtable_item_free, table_map_hfree);
|
||||
hashtable_memory_fns(inst->open_tables, hashtable_item_strdup, NULL,
|
||||
hashtable_item_free, avro_table_hfree);
|
||||
hashtable_memory_fns(inst->created_tables, hashtable_item_strdup, NULL,
|
||||
hashtable_item_free, table_create_hfree);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -518,10 +530,10 @@ createInstance(SERVICE *service, char **options)
|
||||
hashtable_free(inst->table_maps);
|
||||
hashtable_free(inst->open_tables);
|
||||
hashtable_free(inst->created_tables);
|
||||
free(inst->avrodir);
|
||||
free(inst->binlogdir);
|
||||
free(inst->fileroot);
|
||||
free(inst);
|
||||
MXS_FREE(inst->avrodir);
|
||||
MXS_FREE(inst->binlogdir);
|
||||
MXS_FREE(inst->fileroot);
|
||||
MXS_FREE(inst);
|
||||
return NULL;
|
||||
}
|
||||
/**
|
||||
@ -575,9 +587,8 @@ newSession(ROUTER *instance, SESSION *session)
|
||||
MXS_DEBUG("avrorouter: %lu [newSession] new router session with "
|
||||
"session %p, and inst %p.", pthread_self(), session, inst);
|
||||
|
||||
if ((client = (AVRO_CLIENT *) calloc(1, sizeof(AVRO_CLIENT))) == NULL)
|
||||
if ((client = (AVRO_CLIENT *) MXS_CALLOC(1, sizeof(AVRO_CLIENT))) == NULL)
|
||||
{
|
||||
MXS_ERROR("Insufficient memory to create new client session for AVRO router");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -679,7 +690,7 @@ static void freeSession(ROUTER* router_instance, void* router_client_ses)
|
||||
}
|
||||
spinlock_release(&router->lock);
|
||||
|
||||
free(client);
|
||||
MXS_FREE(client);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -911,7 +922,7 @@ extract_message(GWBUF *errpkt)
|
||||
int len;
|
||||
|
||||
len = EXTRACT24(errpkt->start);
|
||||
if ((rval = (char *) malloc(len)) == NULL)
|
||||
if ((rval = (char *) MXS_MALLOC(len)) == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -41,8 +41,9 @@
|
||||
#include <version.h>
|
||||
#include <avrorouter.h>
|
||||
#include <maxavro.h>
|
||||
#include <maxscale/alloc.h>
|
||||
#include <dbusers.h>
|
||||
|
||||
extern int load_mysql_users(SERVICE *service);
|
||||
extern char *blr_extract_column(GWBUF *buf, int col);
|
||||
extern uint32_t extract_field(uint8_t *src, int bits);
|
||||
|
||||
@ -140,8 +141,8 @@ avro_client_do_registration(AVRO_INSTANCE *router, AVRO_CLIENT *client, GWBUF *d
|
||||
char *sep_ptr;
|
||||
int uuid_len = (data_len > CDC_UUID_LEN) ? CDC_UUID_LEN : data_len;
|
||||
/* 36 +1 */
|
||||
char uuid[CDC_UUID_LEN + 1];
|
||||
strncpy(uuid, request + reg_uuid_len, uuid_len);
|
||||
char uuid[uuid_len + 1];
|
||||
memcpy(uuid, request + reg_uuid_len, uuid_len);
|
||||
uuid[uuid_len] = '\0';
|
||||
|
||||
if ((sep_ptr = strchr(uuid, ',')) != NULL)
|
||||
@ -164,7 +165,7 @@ avro_client_do_registration(AVRO_INSTANCE *router, AVRO_CLIENT *client, GWBUF *d
|
||||
|
||||
uuid_len = strlen(uuid);
|
||||
|
||||
client->uuid = strdup(uuid);
|
||||
client->uuid = MXS_STRDUP_A(uuid);
|
||||
|
||||
if (data_len > 0)
|
||||
{
|
||||
@ -412,7 +413,7 @@ void send_gtid_info(AVRO_INSTANCE *router, gtid_pos_t *gtid_pos, DCB *dcb)
|
||||
char *js = json_dumps(obj, 0);
|
||||
size_t size = strlen(js);
|
||||
GWBUF *buffer = gwbuf_alloc_and_load(size, js);
|
||||
free(js);
|
||||
MXS_FREE(js);
|
||||
dcb->func.write(dcb, buffer);
|
||||
}
|
||||
}
|
||||
@ -567,7 +568,7 @@ static int send_row(DCB *dcb, json_t* row)
|
||||
MXS_ERROR("Failed to dump JSON value.");
|
||||
rc = 0;
|
||||
}
|
||||
free(json);
|
||||
MXS_FREE(json);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -890,7 +891,19 @@ GWBUF* read_avro_binary_schema(const char *avrofile, const char* dir)
|
||||
static void rotate_avro_file(AVRO_CLIENT *client, char *fullname)
|
||||
{
|
||||
char *filename = strrchr(fullname, '/') + 1;
|
||||
strncpy(client->avro_binfile, filename, sizeof(client->avro_binfile));
|
||||
size_t len = strlen(filename);
|
||||
if (len > AVRO_MAX_FILENAME_LEN)
|
||||
{
|
||||
// TODO: This function is in need of a return value. It would
|
||||
// TODO: be better to abort if the name is too long and also
|
||||
// TODO: if the opening of the file fails.
|
||||
MXS_ERROR("Filename %s of length %lu is longer than maximum allowed "
|
||||
"length %d. Trailing data will be cut.",
|
||||
filename, len, AVRO_MAX_FILENAME_LEN);
|
||||
len = AVRO_MAX_FILENAME_LEN;
|
||||
}
|
||||
strncpy(client->avro_binfile, filename, len);
|
||||
client->avro_binfile[len] = 0;
|
||||
client->last_sent_pos = 0;
|
||||
|
||||
spinlock_acquire(&client->file_lock);
|
||||
@ -919,7 +932,7 @@ static void rotate_avro_file(AVRO_CLIENT *client, char *fullname)
|
||||
static void print_next_filename(const char *file, const char *dir, char *dest, size_t len)
|
||||
{
|
||||
char buffer[strlen(file) + 1];
|
||||
strncpy(buffer, file, sizeof(buffer));
|
||||
strcpy(buffer, file);
|
||||
char *ptr = strrchr(buffer, '.');
|
||||
|
||||
if (ptr)
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -39,6 +39,7 @@
|
||||
#include <ini.h>
|
||||
#include <stdlib.h>
|
||||
#include <glob.h>
|
||||
#include <maxscale/alloc.h>
|
||||
|
||||
static const char *statefile_section = "avro-conversion";
|
||||
static const char *ddl_list_name = "table-ddl.list";
|
||||
@ -102,14 +103,14 @@ void avro_close_binlog(int fd)
|
||||
*/
|
||||
AVRO_TABLE* avro_table_alloc(const char* filepath, const char* json_schema)
|
||||
{
|
||||
AVRO_TABLE *table = calloc(1, sizeof(AVRO_TABLE));
|
||||
AVRO_TABLE *table = MXS_CALLOC(1, sizeof(AVRO_TABLE));
|
||||
if (table)
|
||||
{
|
||||
if (avro_schema_from_json_length(json_schema, strlen(json_schema),
|
||||
&table->avro_schema))
|
||||
{
|
||||
MXS_ERROR("Avro error: %s", avro_strerror());
|
||||
free(table);
|
||||
MXS_FREE(table);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -128,7 +129,7 @@ AVRO_TABLE* avro_table_alloc(const char* filepath, const char* json_schema)
|
||||
{
|
||||
MXS_ERROR("Avro error: %s", avro_strerror());
|
||||
avro_schema_decref(table->avro_schema);
|
||||
free(table);
|
||||
MXS_FREE(table);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -137,12 +138,12 @@ AVRO_TABLE* avro_table_alloc(const char* filepath, const char* json_schema)
|
||||
MXS_ERROR("Avro error: %s", avro_strerror());
|
||||
avro_schema_decref(table->avro_schema);
|
||||
avro_file_writer_close(table->avro_file);
|
||||
free(table);
|
||||
MXS_FREE(table);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
table->json_schema = strdup(json_schema);
|
||||
table->filename = strdup(filepath);
|
||||
table->json_schema = MXS_STRDUP_A(json_schema);
|
||||
table->filename = MXS_STRDUP_A(filepath);
|
||||
}
|
||||
return table;
|
||||
}
|
||||
@ -233,7 +234,16 @@ static int conv_state_handler(void* data, const char* section, const char* key,
|
||||
}
|
||||
else if (strcmp(key, "file") == 0)
|
||||
{
|
||||
strncpy(router->binlog_name, value, sizeof(router->binlog_name));
|
||||
size_t len = strlen(value);
|
||||
|
||||
if (len > BINLOG_FNAMELEN)
|
||||
{
|
||||
MXS_ERROR("Provided value %s for key 'file' is too long. "
|
||||
"The maximum allowed length is %d.", value, BINLOG_FNAMELEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
strcpy(router->binlog_name, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -297,9 +307,8 @@ bool avro_load_conversion_state(AVRO_INSTANCE *router)
|
||||
* @brief Free an AVRO_TABLE
|
||||
*
|
||||
* @param table Table to free
|
||||
* @return Always NULL
|
||||
*/
|
||||
void* avro_table_free(AVRO_TABLE *table)
|
||||
void avro_table_free(AVRO_TABLE *table)
|
||||
{
|
||||
if (table)
|
||||
{
|
||||
@ -307,10 +316,9 @@ void* avro_table_free(AVRO_TABLE *table)
|
||||
avro_file_writer_close(table->avro_file);
|
||||
avro_value_iface_decref(table->avro_writer_iface);
|
||||
avro_schema_decref(table->avro_schema);
|
||||
free(table->json_schema);
|
||||
free(table->filename);
|
||||
MXS_FREE(table->json_schema);
|
||||
MXS_FREE(table->filename);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -329,27 +337,34 @@ static avro_binlog_end_t rotate_to_next_file_if_exists(AVRO_INSTANCE* router, ui
|
||||
if (binlog_next_file_exists(router->binlogdir, router->binlog_name))
|
||||
{
|
||||
char next_binlog[BINLOG_FNAMELEN + 1];
|
||||
snprintf(next_binlog, sizeof(next_binlog),
|
||||
BINLOG_NAMEFMT, router->fileroot,
|
||||
blr_file_get_next_binlogname(router->binlog_name));
|
||||
|
||||
if (stop_seen)
|
||||
if (snprintf(next_binlog, sizeof(next_binlog),
|
||||
BINLOG_NAMEFMT, router->fileroot,
|
||||
blr_file_get_next_binlogname(router->binlog_name)) >= sizeof(next_binlog))
|
||||
{
|
||||
MXS_NOTICE("End of binlog file [%s] at %lu with a "
|
||||
"close event. Rotating to next binlog file [%s].",
|
||||
router->binlog_name, pos, next_binlog);
|
||||
MXS_ERROR("Next binlog name did not fit into the allocated buffer "
|
||||
"but was truncated, aborting: %s", next_binlog);
|
||||
rval = AVRO_BINLOG_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_NOTICE("End of binlog file [%s] at %lu with no "
|
||||
"close or rotate event. Rotating to next binlog file [%s].",
|
||||
router->binlog_name, pos, next_binlog);
|
||||
}
|
||||
if (stop_seen)
|
||||
{
|
||||
MXS_NOTICE("End of binlog file [%s] at %lu with a "
|
||||
"close event. Rotating to next binlog file [%s].",
|
||||
router->binlog_name, pos, next_binlog);
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_NOTICE("End of binlog file [%s] at %lu with no "
|
||||
"close or rotate event. Rotating to next binlog file [%s].",
|
||||
router->binlog_name, pos, next_binlog);
|
||||
}
|
||||
|
||||
rval = AVRO_OK;
|
||||
strncpy(router->binlog_name, next_binlog, sizeof(router->binlog_name));
|
||||
router->binlog_position = 4;
|
||||
router->current_pos = 4;
|
||||
rval = AVRO_OK;
|
||||
strcpy(router->binlog_name, next_binlog);
|
||||
router->binlog_position = 4;
|
||||
router->current_pos = 4;
|
||||
}
|
||||
}
|
||||
else if (stop_seen)
|
||||
{
|
||||
@ -375,7 +390,7 @@ static void rotate_to_file(AVRO_INSTANCE* router, uint64_t pos, const char *next
|
||||
/** Binlog file is processed, prepare for next one */
|
||||
MXS_NOTICE("End of binlog file [%s] at %lu. Rotating to file [%s].",
|
||||
router->binlog_name, pos, next_binlog);
|
||||
strncpy(router->binlog_name, next_binlog, sizeof(router->binlog_name));
|
||||
strcpy(router->binlog_name, next_binlog); // next_binlog is as big as router->binlog_name.
|
||||
router->binlog_position = 4;
|
||||
router->current_pos = 4;
|
||||
}
|
||||
@ -984,11 +999,13 @@ void handle_query_event(AVRO_INSTANCE *router, REP_HEADER *hdr, int *pending_tra
|
||||
int len = hdr->event_size - BINLOG_EVENT_HDR_LEN - (PHDR_OFF + vblklen + 1 + dblen) + 1;
|
||||
char *sql = (char *) ptr + PHDR_OFF + vblklen + 1 + dblen;
|
||||
char db[dblen + 1];
|
||||
strncpy(db, (char*) ptr + PHDR_OFF + vblklen, sizeof(db));
|
||||
memcpy(db, (char*) ptr + PHDR_OFF + vblklen, dblen);
|
||||
db[dblen] = 0;
|
||||
|
||||
unify_whitespace(sql, len);
|
||||
size_t sqlsz = len, tmpsz = len;
|
||||
char *tmp = malloc(len);
|
||||
char *tmp = MXS_MALLOC(len);
|
||||
MXS_ABORT_IF_NULL(tmp);
|
||||
remove_mysql_comments((const char**)&sql, &sqlsz, &tmp, &tmpsz);
|
||||
sql = tmp;
|
||||
len = tmpsz;
|
||||
@ -1005,18 +1022,28 @@ void handle_query_event(AVRO_INSTANCE *router, REP_HEADER *hdr, int *pending_tra
|
||||
else if (is_alter_table_statement(router, sql, len))
|
||||
{
|
||||
char ident[MYSQL_TABLE_MAXLEN + MYSQL_DATABASE_MAXLEN + 2];
|
||||
char full_ident[MYSQL_TABLE_MAXLEN + MYSQL_DATABASE_MAXLEN + 2];
|
||||
read_alter_identifier(sql, sql + len, ident, sizeof(ident));
|
||||
|
||||
if (strnlen(db, 1) && strchr(ident, '.') == NULL)
|
||||
bool combine = (strnlen(db, 1) && strchr(ident, '.') == NULL);
|
||||
|
||||
size_t len = strlen(ident) + 1; // + 1 for the NULL
|
||||
|
||||
if (combine)
|
||||
{
|
||||
snprintf(full_ident, sizeof(full_ident), "%s.%s", db, ident);
|
||||
len += (strlen(db) + 1); // + 1 for the "."
|
||||
}
|
||||
else
|
||||
|
||||
char full_ident[len];
|
||||
full_ident[0] = 0; // Set full_ident to "".
|
||||
|
||||
if (combine)
|
||||
{
|
||||
strncpy(full_ident, ident, sizeof(full_ident));
|
||||
strcat(full_ident, db);
|
||||
strcat(full_ident, ".");
|
||||
}
|
||||
|
||||
strcat(full_ident, ident);
|
||||
|
||||
TABLE_CREATE *created = hashtable_fetch(router->created_tables, full_ident);
|
||||
ss_dassert(created);
|
||||
|
||||
@ -1041,5 +1068,5 @@ void handle_query_event(AVRO_INSTANCE *router, REP_HEADER *hdr, int *pending_tra
|
||||
*pending_transaction = 0;
|
||||
}
|
||||
|
||||
free(tmp);
|
||||
MXS_FREE(tmp);
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -14,6 +14,7 @@
|
||||
|
||||
#include <mysql_utils.h>
|
||||
#include <jansson.h>
|
||||
#include <maxscale/alloc.h>
|
||||
#include <avrorouter.h>
|
||||
#include <strings.h>
|
||||
|
||||
@ -131,7 +132,7 @@ bool handle_table_map_event(AVRO_INSTANCE *router, REP_HEADER *hdr, uint8_t *ptr
|
||||
{
|
||||
MXS_ERROR("Failed to open new Avro file for writing.");
|
||||
}
|
||||
free(json_schema);
|
||||
MXS_FREE(json_schema);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -31,6 +31,7 @@
|
||||
#include <skygw_debug.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <maxscale/alloc.h>
|
||||
|
||||
/**
|
||||
* @brief Convert the MySQL column type to a compatible Avro type
|
||||
@ -173,7 +174,7 @@ bool json_extract_field_names(const char* filename, TABLE_CREATE *table)
|
||||
if (json_is_array(arr))
|
||||
{
|
||||
int array_size = json_array_size(arr);
|
||||
table->column_names = (char**)malloc(sizeof(char*) * (array_size));
|
||||
table->column_names = (char**)MXS_MALLOC(sizeof(char*) * (array_size));
|
||||
|
||||
if (table->column_names)
|
||||
{
|
||||
@ -192,7 +193,7 @@ bool json_extract_field_names(const char* filename, TABLE_CREATE *table)
|
||||
const char *name_str = json_string_value(name);
|
||||
if (not_generated_field(name_str))
|
||||
{
|
||||
table->column_names[columns++] = strdup(name_str);
|
||||
table->column_names[columns++] = MXS_STRDUP_A(name_str);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -505,12 +506,10 @@ static int process_column_definition(const char *nameptr, char*** dest)
|
||||
size_t chunks = 1;
|
||||
const size_t chunk_size = 8;
|
||||
int i = 0;
|
||||
char **names = malloc(sizeof(char*) * (chunks * chunk_size + 1));
|
||||
char **names = MXS_MALLOC(sizeof(char*) * (chunks * chunk_size + 1));
|
||||
|
||||
if (names == NULL)
|
||||
{
|
||||
MXS_ERROR("Memory allocation failed when trying allocate %ld bytes of memory.",
|
||||
sizeof(char*) * chunks);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -520,30 +519,26 @@ static int process_column_definition(const char *nameptr, char*** dest)
|
||||
{
|
||||
if (i >= chunks * chunk_size)
|
||||
{
|
||||
char **tmp = realloc(names, (++chunks * chunk_size + 1) * sizeof(char*));
|
||||
char **tmp = MXS_REALLOC(names, (++chunks * chunk_size + 1) * sizeof(char*));
|
||||
if (tmp == NULL)
|
||||
{
|
||||
for (int x = 0; x < i; x++)
|
||||
{
|
||||
free(names[x]);
|
||||
MXS_FREE(names[x]);
|
||||
}
|
||||
free(names);
|
||||
MXS_ERROR("Memory allocation failed when trying allocate %ld bytes of memory.",
|
||||
sizeof(char*) * chunks);
|
||||
MXS_FREE(names);
|
||||
return -1;
|
||||
}
|
||||
names = tmp;
|
||||
}
|
||||
|
||||
if ((names[i++] = strdup(colname)) == NULL)
|
||||
if ((names[i++] = MXS_STRDUP(colname)) == NULL)
|
||||
{
|
||||
for (int x = 0; x < i; x++)
|
||||
{
|
||||
free(names[x]);
|
||||
MXS_FREE(names[x]);
|
||||
}
|
||||
free(names);
|
||||
MXS_ERROR("Memory allocation failed when trying allocate %lu bytes "
|
||||
"of memory.", strlen(colname));
|
||||
MXS_FREE(names);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -556,22 +551,31 @@ static int process_column_definition(const char *nameptr, char*** dest)
|
||||
TABLE_CREATE* table_create_from_schema(const char* file, const char* db,
|
||||
const char* table, int version)
|
||||
{
|
||||
TABLE_CREATE* newtable = NULL;
|
||||
db = MXS_STRDUP(db);
|
||||
table = MXS_STRDUP(table);
|
||||
|
||||
if ((newtable = malloc(sizeof(TABLE_CREATE))))
|
||||
TABLE_CREATE* newtable = (TABLE_CREATE*)MXS_MALLOC(sizeof(TABLE_CREATE));
|
||||
|
||||
if (!db || !table || !newtable)
|
||||
{
|
||||
newtable->table = strdup(table);
|
||||
newtable->database = strdup(db);
|
||||
newtable->version = version;
|
||||
newtable->was_used = true;
|
||||
MXS_FREE((void*)db);
|
||||
MXS_FREE((void*)table);
|
||||
MXS_FREE(newtable);
|
||||
|
||||
if (!newtable->table || !newtable->database || !json_extract_field_names(file, newtable))
|
||||
{
|
||||
free(newtable->table);
|
||||
free(newtable->database);
|
||||
free(newtable);
|
||||
newtable = NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
newtable->table = (char*)table;
|
||||
newtable->database = (char*)db;
|
||||
newtable->version = version;
|
||||
newtable->was_used = true;
|
||||
|
||||
if (!json_extract_field_names(file, newtable))
|
||||
{
|
||||
MXS_FREE(newtable->table);
|
||||
MXS_FREE(newtable->database);
|
||||
MXS_FREE(newtable);
|
||||
newtable = NULL;
|
||||
}
|
||||
|
||||
return newtable;
|
||||
@ -621,32 +625,31 @@ TABLE_CREATE* table_create_alloc(const char* sql, const char* event_db)
|
||||
TABLE_CREATE *rval = NULL;
|
||||
if (n_columns > 0)
|
||||
{
|
||||
if ((rval = malloc(sizeof(TABLE_CREATE))))
|
||||
if ((rval = MXS_MALLOC(sizeof(TABLE_CREATE))))
|
||||
{
|
||||
rval->version = 1;
|
||||
rval->was_used = false;
|
||||
rval->column_names = names;
|
||||
rval->columns = n_columns;
|
||||
rval->database = strdup(db);
|
||||
rval->table = strdup(table);
|
||||
rval->database = MXS_STRDUP(db);
|
||||
rval->table = MXS_STRDUP(table);
|
||||
}
|
||||
|
||||
if (rval == NULL || rval->database == NULL || rval->table == NULL)
|
||||
{
|
||||
if (rval)
|
||||
{
|
||||
free(rval->database);
|
||||
free(rval->table);
|
||||
free(rval);
|
||||
MXS_FREE(rval->database);
|
||||
MXS_FREE(rval->table);
|
||||
MXS_FREE(rval);
|
||||
}
|
||||
|
||||
for (int i = 0; i < n_columns; i++)
|
||||
{
|
||||
free(names[i]);
|
||||
MXS_FREE(names[i]);
|
||||
}
|
||||
|
||||
free(names);
|
||||
MXS_ERROR("Memory allocation failed when processing a CREATE TABLE statement.");
|
||||
MXS_FREE(names);
|
||||
rval = NULL;
|
||||
}
|
||||
}
|
||||
@ -661,20 +664,19 @@ TABLE_CREATE* table_create_alloc(const char* sql, const char* event_db)
|
||||
* Free a TABLE_CREATE structure
|
||||
* @param value Value to free
|
||||
*/
|
||||
void* table_create_free(TABLE_CREATE* value)
|
||||
void table_create_free(TABLE_CREATE* value)
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
for (uint64_t i = 0; i < value->columns; i++)
|
||||
{
|
||||
free(value->column_names[i]);
|
||||
MXS_FREE(value->column_names[i]);
|
||||
}
|
||||
free(value->column_names);
|
||||
free(value->table);
|
||||
free(value->database);
|
||||
free(value);
|
||||
MXS_FREE(value->column_names);
|
||||
MXS_FREE(value->table);
|
||||
MXS_FREE(value->database);
|
||||
MXS_FREE(value);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char* get_next_def(const char* sql, const char* end)
|
||||
@ -817,7 +819,7 @@ bool table_create_alter(TABLE_CREATE *create, const char *sql, const char *end)
|
||||
{
|
||||
tok = get_tok(tok + len, &len, end);
|
||||
|
||||
char ** tmp = realloc(create->column_names, sizeof(char*) * create->columns + 1);
|
||||
char ** tmp = MXS_REALLOC(create->column_names, sizeof(char*) * create->columns + 1);
|
||||
ss_dassert(tmp);
|
||||
|
||||
if (tmp == NULL)
|
||||
@ -828,7 +830,7 @@ bool table_create_alter(TABLE_CREATE *create, const char *sql, const char *end)
|
||||
create->column_names = tmp;
|
||||
char avro_token[len + 1];
|
||||
make_avro_token(avro_token, tok, len);
|
||||
create->column_names[create->columns] = strdup(avro_token);
|
||||
create->column_names[create->columns] = MXS_STRDUP_A(avro_token);
|
||||
create->columns++;
|
||||
updates++;
|
||||
tok = get_next_def(tok, end);
|
||||
@ -838,8 +840,8 @@ bool table_create_alter(TABLE_CREATE *create, const char *sql, const char *end)
|
||||
{
|
||||
tok = get_tok(tok + len, &len, end);
|
||||
|
||||
free(create->column_names[create->columns - 1]);
|
||||
char ** tmp = realloc(create->column_names, sizeof(char*) * create->columns - 1);
|
||||
MXS_FREE(create->column_names[create->columns - 1]);
|
||||
char ** tmp = MXS_REALLOC(create->column_names, sizeof(char*) * create->columns - 1);
|
||||
ss_dassert(tmp);
|
||||
|
||||
if (tmp == NULL)
|
||||
@ -856,7 +858,7 @@ bool table_create_alter(TABLE_CREATE *create, const char *sql, const char *end)
|
||||
else if (tok_eq(ptok, "change", plen) && tok_eq(tok, "column", len))
|
||||
{
|
||||
tok = get_tok(tok + len, &len, end);
|
||||
free(create->column_names[create->columns - 1]);
|
||||
MXS_FREE(create->column_names[create->columns - 1]);
|
||||
create->column_names[create->columns - 1] = strndup(tok, len);
|
||||
updates++;
|
||||
tok = get_next_def(tok, end);
|
||||
@ -962,7 +964,7 @@ TABLE_MAP *table_map_alloc(uint8_t *ptr, uint8_t hdr_len, TABLE_CREATE* create)
|
||||
uint8_t* metadata = (uint8_t*)lestr_consume(&ptr, &metadata_size);
|
||||
uint8_t *nullmap = ptr;
|
||||
size_t nullmap_size = (column_count + 7) / 8;
|
||||
TABLE_MAP *map = malloc(sizeof(TABLE_MAP));
|
||||
TABLE_MAP *map = MXS_MALLOC(sizeof(TABLE_MAP));
|
||||
|
||||
if (map)
|
||||
{
|
||||
@ -971,13 +973,13 @@ TABLE_MAP *table_map_alloc(uint8_t *ptr, uint8_t hdr_len, TABLE_CREATE* create)
|
||||
map->flags = flags;
|
||||
ss_dassert(column_count == create->columns);
|
||||
map->columns = column_count;
|
||||
map->column_types = malloc(column_count);
|
||||
map->column_types = MXS_MALLOC(column_count);
|
||||
/** Allocate at least one byte for the metadata */
|
||||
map->column_metadata = calloc(1, metadata_size + 1);
|
||||
map->column_metadata = MXS_CALLOC(1, metadata_size + 1);
|
||||
map->column_metadata_size = metadata_size;
|
||||
map->null_bitmap = malloc(nullmap_size);
|
||||
map->database = strdup(schema_name);
|
||||
map->table = strdup(table_name);
|
||||
map->null_bitmap = MXS_MALLOC(nullmap_size);
|
||||
map->database = MXS_STRDUP(schema_name);
|
||||
map->table = MXS_STRDUP(table_name);
|
||||
map->table_create = create;
|
||||
if (map->column_types && map->database && map->table &&
|
||||
map->column_metadata && map->null_bitmap)
|
||||
@ -988,20 +990,15 @@ TABLE_MAP *table_map_alloc(uint8_t *ptr, uint8_t hdr_len, TABLE_CREATE* create)
|
||||
}
|
||||
else
|
||||
{
|
||||
free(map->null_bitmap);
|
||||
free(map->column_metadata);
|
||||
free(map->column_types);
|
||||
free(map->database);
|
||||
free(map->table);
|
||||
free(map);
|
||||
MXS_FREE(map->null_bitmap);
|
||||
MXS_FREE(map->column_metadata);
|
||||
MXS_FREE(map->column_types);
|
||||
MXS_FREE(map->database);
|
||||
MXS_FREE(map->table);
|
||||
MXS_FREE(map);
|
||||
map = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
free(map);
|
||||
map = NULL;
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
@ -1010,16 +1007,15 @@ TABLE_MAP *table_map_alloc(uint8_t *ptr, uint8_t hdr_len, TABLE_CREATE* create)
|
||||
* @brief Free a table map
|
||||
* @param map Table map to free
|
||||
*/
|
||||
void* table_map_free(TABLE_MAP *map)
|
||||
void table_map_free(TABLE_MAP *map)
|
||||
{
|
||||
if (map)
|
||||
{
|
||||
free(map->column_types);
|
||||
free(map->database);
|
||||
free(map->table);
|
||||
free(map);
|
||||
MXS_FREE(map->column_types);
|
||||
MXS_FREE(map->database);
|
||||
MXS_FREE(map->table);
|
||||
MXS_FREE(map);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -5,7 +5,7 @@
|
||||
# Use of this software is governed by the Business Source License included
|
||||
# in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
#
|
||||
# Change Date: 2019-01-01
|
||||
# Change Date: 2019-07-01
|
||||
#
|
||||
# On the date above, in accordance with the Business Source License, use
|
||||
# of this software will be governed by version 2 or later of the General
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user