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:
Johan Wikman
2016-08-17 08:36:01 +03:00
parent b2035745fc
commit dc7f7b6fb4
360 changed files with 11641 additions and 15856 deletions

View File

@ -4,3 +4,4 @@ add_subdirectory(protocol)
add_subdirectory(monitor)
add_subdirectory(filter)
add_subdirectory(authenticator)
add_subdirectory(include)

View File

@ -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()

View File

@ -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)
{

View 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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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
*/

View 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) {}

View File

@ -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)

View File

@ -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);

View File

@ -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}")

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View 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;
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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

View File

@ -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)

View File

@ -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;
}

View File

@ -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,

View File

@ -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 */

View File

@ -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;

View File

@ -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);

View File

@ -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})

View File

@ -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

View File

@ -1,4 +0,0 @@
[Firewall]
type=filter
module=dbfwfilter
rules=@CMAKE_CURRENT_SOURCE_DIR@/rules

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -1,2 +0,0 @@
threads=2
sessions=4

View File

@ -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

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -1,3 +0,0 @@
[Hint]
type=filter
module=hintfilter

View File

@ -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 */;

View File

@ -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 */;

View File

@ -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

View File

@ -1 +0,0 @@
SELECT * FROM test_table;

View File

@ -1,5 +0,0 @@
[Regex]
type=filter
module=regexfilter
match=wrong
replace=right

View File

@ -1,3 +0,0 @@
select * from mysql.right;
select right from test.table;
select * from test.table where name='right';

View File

@ -1,3 +0,0 @@
select * from mysql.wrong;
select wrong from test.table;
select * from test.table where name='wrong';

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 $?

View File

@ -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;
}

View File

@ -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;
}

View File

@ -0,0 +1,5 @@
file(GLOB HEADERS "*.h")
foreach(var ${HEADERS})
get_filename_component(header ${var} NAME)
install_header(${header} devel)
endforeach()

View File

@ -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);

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -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++;

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -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()

View File

@ -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;
}

View File

@ -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)

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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.

View File

@ -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)

View File

@ -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()

View File

@ -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;
}

View File

@ -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)

View File

@ -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);
}

View File

@ -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

View File

@ -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
{

View File

@ -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;
}
/**

View File

@ -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