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:
@ -1,64 +1,66 @@
|
||||
if(BUILD_RABBITMQ)
|
||||
if(RABBITMQ_FOUND)
|
||||
include_directories(${RABBITMQ_HEADERS})
|
||||
add_library(mqfilter SHARED mqfilter.c)
|
||||
target_link_libraries(mqfilter maxscale-common ${RABBITMQ_LIBRARIES})
|
||||
add_dependencies(mqfilter pcre2)
|
||||
install(TARGETS mqfilter DESTINATION ${MAXSCALE_LIBDIR})
|
||||
else()
|
||||
message(WARNING "Could not find librabbitmq, the mqfilter will not be built.")
|
||||
endif()
|
||||
find_package(RabbitMQ)
|
||||
if(RABBITMQ_FOUND)
|
||||
include_directories(${RABBITMQ_HEADERS})
|
||||
add_library(mqfilter SHARED mqfilter.c)
|
||||
target_link_libraries(mqfilter maxscale-common ${RABBITMQ_LIBRARIES})
|
||||
add_dependencies(mqfilter pcre2)
|
||||
set_target_properties(mqfilter PROPERTIES VERSION "1.0.2")
|
||||
install_module(mqfilter core)
|
||||
else()
|
||||
message(WARNING "Could not find librabbitmq, the mqfilter will not be built.")
|
||||
endif()
|
||||
|
||||
add_library(regexfilter SHARED regexfilter.c)
|
||||
target_link_libraries(regexfilter maxscale-common)
|
||||
add_dependencies(regexfilter pcre2)
|
||||
set_target_properties(regexfilter PROPERTIES VERSION "1.1.0")
|
||||
install(TARGETS regexfilter DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(regexfilter core)
|
||||
|
||||
add_library(testfilter SHARED testfilter.c)
|
||||
target_link_libraries(testfilter maxscale-common)
|
||||
set_target_properties(testfilter PROPERTIES VERSION "1.0.0")
|
||||
install(TARGETS testfilter DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(testfilter core)
|
||||
|
||||
add_library(gatekeeper SHARED gatekeeper.c)
|
||||
target_link_libraries(gatekeeper maxscale-common)
|
||||
set_target_properties(gatekeeper PROPERTIES VERSION "1.0.0")
|
||||
install_module(gatekeeper experimental)
|
||||
|
||||
add_library(qlafilter SHARED qlafilter.c)
|
||||
target_link_libraries(qlafilter maxscale-common)
|
||||
set_target_properties(qlafilter PROPERTIES VERSION "1.1.1")
|
||||
install(TARGETS qlafilter DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(qlafilter core)
|
||||
|
||||
add_library(tee SHARED tee.c)
|
||||
target_link_libraries(tee maxscale-common)
|
||||
set_target_properties(tee PROPERTIES VERSION "1.0.0")
|
||||
install(TARGETS tee DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(tee core)
|
||||
|
||||
add_library(topfilter SHARED topfilter.c)
|
||||
target_link_libraries(topfilter maxscale-common)
|
||||
set_target_properties(topfilter PROPERTIES VERSION "1.0.1")
|
||||
install(TARGETS topfilter DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(topfilter core)
|
||||
|
||||
if(BUILD_LUAFILTER)
|
||||
find_package(Lua)
|
||||
if(LUA_FOUND)
|
||||
include_directories(${LUA_INCLUDE_DIR})
|
||||
add_library(luafilter SHARED luafilter.c)
|
||||
target_link_libraries(luafilter maxscale-common ${LUA_LIBRARIES})
|
||||
install(TARGETS luafilter DESTINATION ${MAXSCALE_LIBDIR})
|
||||
else()
|
||||
message(STATUS "Lua was not found, luafilter will not be built.")
|
||||
endif()
|
||||
find_package(Lua)
|
||||
if(LUA_FOUND)
|
||||
include_directories(${LUA_INCLUDE_DIR})
|
||||
add_library(luafilter SHARED luafilter.c)
|
||||
set_target_properties(luafilter PROPERTIES VERSION "1.0.0")
|
||||
target_link_libraries(luafilter maxscale-common ${LUA_LIBRARIES})
|
||||
install_module(luafilter experimental)
|
||||
else()
|
||||
message(STATUS "Lua was not found, luafilter will not be built.")
|
||||
endif()
|
||||
|
||||
add_library(namedserverfilter SHARED namedserverfilter.c)
|
||||
target_link_libraries(namedserverfilter maxscale-common)
|
||||
set_target_properties(namedserverfilter PROPERTIES VERSION "1.1.0")
|
||||
install(TARGETS namedserverfilter DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(namedserverfilter core)
|
||||
|
||||
if(BUILD_SLAVELAG)
|
||||
add_library(slavelag SHARED slavelag.c)
|
||||
target_link_libraries(slavelag maxscale-common)
|
||||
set_target_properties(slavelag PROPERTIES VERSION "1.1.0")
|
||||
install(TARGETS slavelag DESTINATION ${MAXSCALE_LIBDIR})
|
||||
endif()
|
||||
add_library(ccrfilter SHARED ccrfilter.c)
|
||||
target_link_libraries(ccrfilter maxscale-common)
|
||||
set_target_properties(ccrfilter PROPERTIES VERSION "1.0.0")
|
||||
install_module(ccrfilter experimental)
|
||||
|
||||
add_subdirectory(hint)
|
||||
add_subdirectory(dbfwfilter)
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -20,9 +20,10 @@
|
||||
#include <hint.h>
|
||||
#include <query_classifier.h>
|
||||
#include <regex.h>
|
||||
#include <maxscale/alloc.h>
|
||||
|
||||
/**
|
||||
* @file slavelag.c - a very simple filter designed to send queries to the
|
||||
* @file ccrfilter.c - a very simple filter designed to send queries to the
|
||||
* master server after data modification has occurred. This is done to prevent
|
||||
* replication lag affecting the outcome of a select query.
|
||||
*
|
||||
@ -42,6 +43,7 @@
|
||||
*
|
||||
* Date Who Description
|
||||
* 03/03/2015 Markus Mäkelä Written for demonstrative purposes
|
||||
* 10/08/2016 Markus Mäkelä Cleaned up code and renamed to ccrfilter
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
@ -77,6 +79,8 @@ static FILTER_OBJECT MyObject =
|
||||
diagnostic,
|
||||
};
|
||||
|
||||
#define CCR_DEFAULT_TIME 60
|
||||
|
||||
typedef struct lagstats
|
||||
{
|
||||
int n_add_count; /*< No. of statements diverted based on count */
|
||||
@ -99,7 +103,7 @@ typedef struct
|
||||
LAGSTATS stats;
|
||||
regex_t re; /* Compiled regex text of match */
|
||||
regex_t nore; /* Compiled regex text of ignore */
|
||||
} LAG_INSTANCE;
|
||||
} CCR_INSTANCE;
|
||||
|
||||
/**
|
||||
* The session structure for this filter
|
||||
@ -108,9 +112,8 @@ typedef struct
|
||||
{
|
||||
DOWNSTREAM down; /*< The downstream filter */
|
||||
int hints_left; /*< Number of hints left to add to queries*/
|
||||
time_t last_modification; /*< Time of the last modifying operation */
|
||||
int active; /*< Is filter active */
|
||||
} LAG_SESSION;
|
||||
time_t last_modification; /*< Time of the last data modifying operation */
|
||||
} CCR_SESSION;
|
||||
|
||||
/**
|
||||
* Implementation of the mandatory version entry point
|
||||
@ -161,14 +164,14 @@ GetModuleObject()
|
||||
static FILTER *
|
||||
createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
LAG_INSTANCE *my_instance;
|
||||
CCR_INSTANCE *my_instance;
|
||||
int i;
|
||||
int cflags = 0;
|
||||
int cflags = REG_ICASE;
|
||||
|
||||
if ((my_instance = calloc(1, sizeof(LAG_INSTANCE))) != NULL)
|
||||
if ((my_instance = MXS_CALLOC(1, sizeof(CCR_INSTANCE))) != NULL)
|
||||
{
|
||||
my_instance->count = 0;
|
||||
my_instance->time = 0;
|
||||
my_instance->time = CCR_DEFAULT_TIME;
|
||||
my_instance->stats.n_add_count = 0;
|
||||
my_instance->stats.n_add_time = 0;
|
||||
my_instance->stats.n_modified = 0;
|
||||
@ -187,15 +190,15 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "match"))
|
||||
{
|
||||
my_instance->match = strdup(params[i]->value);
|
||||
my_instance->match = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "ignore"))
|
||||
{
|
||||
my_instance->nomatch = strdup(params[i]->value);
|
||||
my_instance->nomatch = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else
|
||||
else if (!filter_standard_parameter(params[i]->name))
|
||||
{
|
||||
MXS_ERROR("lagfilter: Unexpected parameter '%s'.\n", params[i]->name);
|
||||
MXS_ERROR("ccrfilter: Unexpected parameter '%s'.\n", params[i]->name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -211,9 +214,13 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
cflags &= ~REG_ICASE;
|
||||
}
|
||||
else if (!strcasecmp(options[i], "extended"))
|
||||
{
|
||||
cflags |= REG_EXTENDED;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR("lagfilter: unsupported option '%s'.", options[i]);
|
||||
MXS_ERROR("ccrfilter: unsupported option '%s'.", options[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -222,7 +229,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
if (regcomp(&my_instance->re, my_instance->match, cflags))
|
||||
{
|
||||
MXS_ERROR("lagfilter: Failed to compile regex '%s'.", my_instance->match);
|
||||
MXS_ERROR("ccrfilter: Failed to compile regex '%s'.", my_instance->match);
|
||||
}
|
||||
}
|
||||
|
||||
@ -230,7 +237,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
if (regcomp(&my_instance->nore, my_instance->nomatch, cflags))
|
||||
{
|
||||
MXS_ERROR("lagfilter: Failed to compile regex '%s'.", my_instance->nomatch);
|
||||
MXS_ERROR("ccrfilter: Failed to compile regex '%s'.", my_instance->nomatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -249,12 +256,11 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
static void *
|
||||
newSession(FILTER *instance, SESSION *session)
|
||||
{
|
||||
LAG_INSTANCE *my_instance = (LAG_INSTANCE *)instance;
|
||||
LAG_SESSION *my_session;
|
||||
CCR_INSTANCE *my_instance = (CCR_INSTANCE *)instance;
|
||||
CCR_SESSION *my_session = MXS_MALLOC(sizeof(CCR_SESSION));
|
||||
|
||||
if ((my_session = malloc(sizeof(LAG_SESSION))) != NULL)
|
||||
if (my_session)
|
||||
{
|
||||
my_session->active = 1;
|
||||
my_session->hints_left = 0;
|
||||
my_session->last_modification = 0;
|
||||
}
|
||||
@ -283,7 +289,7 @@ closeSession(FILTER *instance, void *session)
|
||||
static void
|
||||
freeSession(FILTER *instance, void *session)
|
||||
{
|
||||
free(session);
|
||||
MXS_FREE(session);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -296,7 +302,7 @@ freeSession(FILTER *instance, void *session)
|
||||
static void
|
||||
setDownstream(FILTER *instance, void *session, DOWNSTREAM *downstream)
|
||||
{
|
||||
LAG_SESSION *my_session = (LAG_SESSION *)session;
|
||||
CCR_SESSION *my_session = (CCR_SESSION *)session;
|
||||
|
||||
my_session->down = *downstream;
|
||||
}
|
||||
@ -318,19 +324,23 @@ setDownstream(FILTER *instance, void *session, DOWNSTREAM *downstream)
|
||||
static int
|
||||
routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
{
|
||||
LAG_INSTANCE *my_instance = (LAG_INSTANCE *)instance;
|
||||
LAG_SESSION *my_session = (LAG_SESSION *)session;
|
||||
CCR_INSTANCE *my_instance = (CCR_INSTANCE *)instance;
|
||||
CCR_SESSION *my_session = (CCR_SESSION *)session;
|
||||
char *sql;
|
||||
time_t now = time(NULL);
|
||||
|
||||
if (modutil_is_SQL(queue))
|
||||
{
|
||||
if (queue->next != NULL)
|
||||
if (queue->next)
|
||||
{
|
||||
queue = gwbuf_make_contiguous(queue);
|
||||
}
|
||||
|
||||
if (qc_get_operation(queue) & (QUERY_OP_DELETE | QUERY_OP_INSERT | QUERY_OP_UPDATE))
|
||||
/**
|
||||
* Not a simple SELECT statement, possibly modifies data. If we're processing a statement
|
||||
* with unknown query type, the safest thing to do is to treat it as a data modifying statement.
|
||||
*/
|
||||
if ((qc_get_operation(queue) & ~QUERY_OP_SELECT) != 0)
|
||||
{
|
||||
if ((sql = modutil_get_SQL(queue)) != NULL)
|
||||
{
|
||||
@ -346,7 +356,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
}
|
||||
}
|
||||
|
||||
free(sql);
|
||||
MXS_FREE(sql);
|
||||
}
|
||||
}
|
||||
else if (my_session->hints_left > 0)
|
||||
@ -381,12 +391,23 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
static void
|
||||
diagnostic(FILTER *instance, void *fsession, DCB *dcb)
|
||||
{
|
||||
LAG_INSTANCE *my_instance = (LAG_INSTANCE *)instance;
|
||||
LAG_SESSION *my_session = (LAG_SESSION *)fsession;
|
||||
CCR_INSTANCE *my_instance = (CCR_INSTANCE *)instance;
|
||||
CCR_SESSION *my_session = (CCR_SESSION *)fsession;
|
||||
|
||||
dcb_printf(dcb, "Configuration:\n\tCount: %d\n", my_instance->count);
|
||||
dcb_printf(dcb, "\tTime: %d seconds\n\n", my_instance->time);
|
||||
dcb_printf(dcb, "Statistics:\n");
|
||||
dcb_printf(dcb, "\tTime: %d seconds\n", my_instance->time);
|
||||
|
||||
if (my_instance->match)
|
||||
{
|
||||
dcb_printf(dcb, "\tMatch regex: %s\n", my_instance->match);
|
||||
}
|
||||
|
||||
if (my_instance->nomatch)
|
||||
{
|
||||
dcb_printf(dcb, "\tExclude regex: %s\n", my_instance->nomatch);
|
||||
}
|
||||
|
||||
dcb_printf(dcb, "\nStatistics:\n");
|
||||
dcb_printf(dcb, "\tNo. of data modifications: %d\n", my_instance->stats.n_modified);
|
||||
dcb_printf(dcb, "\tNo. of hints added based on count: %d\n", my_instance->stats.n_add_count);
|
||||
dcb_printf(dcb, "\tNo. of hints added based on time: %d\n", my_instance->stats.n_add_time);
|
@ -9,13 +9,13 @@ if(BISON_FOUND AND FLEX_FOUND)
|
||||
add_library(dbfwfilter SHARED dbfwfilter.c ${BISON_ruleparser_OUTPUTS} ${FLEX_token_OUTPUTS})
|
||||
target_link_libraries(dbfwfilter maxscale-common)
|
||||
set_target_properties(dbfwfilter PROPERTIES VERSION "1.0.0")
|
||||
install(TARGETS dbfwfilter DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(dbfwfilter core)
|
||||
|
||||
if(BUILD_TOOLS)
|
||||
add_executable(dbfwruleparser dbfwfilter.c ${BISON_ruleparser_OUTPUTS} ${FLEX_token_OUTPUTS})
|
||||
target_compile_definitions(dbfwruleparser PUBLIC "BUILD_RULE_PARSER")
|
||||
target_link_libraries(dbfwruleparser maxscale-common)
|
||||
install(TARGETS dbfwruleparser DESTINATION ${MAXSCALE_BINDIR})
|
||||
install_module(dbfwruleparser core)
|
||||
endif()
|
||||
else()
|
||||
message(FATAL_ERROR "Could not find Bison or Flex: ${BISON_EXECUTABLE} ${FLEX_EXECUTABLE}")
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -79,6 +79,7 @@
|
||||
#include <ruleparser.yy.h>
|
||||
#include <lex.yy.h>
|
||||
#include <stdlib.h>
|
||||
#include <maxscale/alloc.h>
|
||||
|
||||
/** Older versions of Bison don't include the parsing function in the header */
|
||||
#ifndef dbfw_yyparse
|
||||
@ -291,17 +292,16 @@ bool parse_limit_queries(FW_INSTANCE* instance, RULE* ruledef, const char* rule,
|
||||
*/
|
||||
static STRLINK* strlink_push(STRLINK* head, const char* value)
|
||||
{
|
||||
STRLINK* link = malloc(sizeof(STRLINK));
|
||||
STRLINK* link = MXS_MALLOC(sizeof(STRLINK));
|
||||
|
||||
if (link && (link->value = strdup(value)))
|
||||
if (link && (link->value = MXS_STRDUP(value)))
|
||||
{
|
||||
link->next = head;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(link);
|
||||
MXS_FREE(link);
|
||||
link = NULL;
|
||||
MXS_ERROR("dbfwfilter: Memory allocation failed.");
|
||||
}
|
||||
return link;
|
||||
}
|
||||
@ -316,8 +316,8 @@ static STRLINK* strlink_pop(STRLINK* head)
|
||||
if (head)
|
||||
{
|
||||
STRLINK* next = head->next;
|
||||
free(head->value);
|
||||
free(head);
|
||||
MXS_FREE(head->value);
|
||||
MXS_FREE(head);
|
||||
return next;
|
||||
}
|
||||
return NULL;
|
||||
@ -333,8 +333,8 @@ static void strlink_free(STRLINK* head)
|
||||
{
|
||||
STRLINK* tmp = head;
|
||||
head = head->next;
|
||||
free(tmp->value);
|
||||
free(tmp);
|
||||
MXS_FREE(tmp->value);
|
||||
MXS_FREE(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -366,7 +366,7 @@ static STRLINK* strlink_reverse_clone(STRLINK* head)
|
||||
|
||||
static RULELIST* rulelist_push(RULELIST *head, RULE *rule)
|
||||
{
|
||||
RULELIST *rval = malloc(sizeof(RULELIST));
|
||||
RULELIST *rval = MXS_MALLOC(sizeof(RULELIST));
|
||||
|
||||
if (rval)
|
||||
{
|
||||
@ -385,7 +385,8 @@ static void* rulelist_clone(void* fval)
|
||||
|
||||
while (ptr)
|
||||
{
|
||||
RULELIST* tmp = (RULELIST*) malloc(sizeof(RULELIST));
|
||||
RULELIST* tmp = (RULELIST*) MXS_MALLOC(sizeof(RULELIST));
|
||||
MXS_ABORT_IF_NULL(tmp);
|
||||
tmp->next = rule;
|
||||
tmp->rule = ptr->rule;
|
||||
rule = tmp;
|
||||
@ -402,22 +403,21 @@ static void* rulelist_free(void* fval)
|
||||
{
|
||||
RULELIST *tmp = ptr;
|
||||
ptr = ptr->next;
|
||||
free(tmp);
|
||||
MXS_FREE(tmp);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void* huserfree(void* fval)
|
||||
static void huserfree(void* fval)
|
||||
{
|
||||
USER* value = (USER*) fval;
|
||||
|
||||
rulelist_free(value->rules_and);
|
||||
rulelist_free(value->rules_or);
|
||||
rulelist_free(value->rules_strict_and);
|
||||
free(value->qs_limit);
|
||||
free(value->name);
|
||||
free(value);
|
||||
return NULL;
|
||||
MXS_FREE(value->qs_limit);
|
||||
MXS_FREE(value->name);
|
||||
MXS_FREE(value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -622,7 +622,7 @@ static TIMERANGE* parse_time(const char* str)
|
||||
CHK_TIMES((&start));
|
||||
CHK_TIMES((&end));
|
||||
|
||||
tr = (TIMERANGE*) malloc(sizeof(TIMERANGE));
|
||||
tr = (TIMERANGE*) MXS_MALLOC(sizeof(TIMERANGE));
|
||||
|
||||
if (tr)
|
||||
{
|
||||
@ -630,10 +630,6 @@ static TIMERANGE* parse_time(const char* str)
|
||||
tr->end = end;
|
||||
tr->next = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR("dbfwfilter: malloc returned NULL.");
|
||||
}
|
||||
}
|
||||
}
|
||||
return tr;
|
||||
@ -649,7 +645,8 @@ TIMERANGE* split_reverse_time(TIMERANGE* tr)
|
||||
{
|
||||
TIMERANGE* tmp = NULL;
|
||||
|
||||
tmp = (TIMERANGE*) calloc(1, sizeof(TIMERANGE));
|
||||
tmp = (TIMERANGE*) MXS_CALLOC(1, sizeof(TIMERANGE));
|
||||
MXS_ABORT_IF_NULL(tmp);
|
||||
tmp->next = tr;
|
||||
tmp->start.tm_hour = 0;
|
||||
tmp->start.tm_min = 0;
|
||||
@ -724,15 +721,14 @@ static bool apply_rule_to_user(FW_INSTANCE *instance, char *username,
|
||||
if ((user = (USER*) hashtable_fetch(instance->htable, username)) == NULL)
|
||||
{
|
||||
/**New user*/
|
||||
if ((user = (USER*) calloc(1, sizeof(USER))) == NULL)
|
||||
if ((user = (USER*) MXS_CALLOC(1, sizeof(USER))) == NULL)
|
||||
{
|
||||
MXS_ERROR("dbfwfilter: failed to allocate memory when parsing rules.");
|
||||
return false;
|
||||
}
|
||||
spinlock_init(&user->lock);
|
||||
}
|
||||
|
||||
user->name = (char*) strdup(username);
|
||||
user->name = (char*) MXS_STRDUP_A(username);
|
||||
user->qs_limit = NULL;
|
||||
RULELIST *tl = (RULELIST*) rulelist_clone(rulelist);
|
||||
RULELIST *tail = tl;
|
||||
@ -775,7 +771,7 @@ void tr_free(TIMERANGE* tr)
|
||||
{
|
||||
tmp = node;
|
||||
node = node->next;
|
||||
free(tmp);
|
||||
MXS_FREE(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -874,9 +870,9 @@ void dbfw_yyerror(void* scanner, const char* error)
|
||||
bool create_rule(void* scanner, const char* name)
|
||||
{
|
||||
bool rval = true;
|
||||
RULE *ruledef = malloc(sizeof(RULE));
|
||||
RULE *ruledef = MXS_MALLOC(sizeof(RULE));
|
||||
|
||||
if (ruledef && (ruledef->name = strdup(name)))
|
||||
if (ruledef && (ruledef->name = MXS_STRDUP(name)))
|
||||
{
|
||||
ruledef->type = RT_UNDEFINED;
|
||||
ruledef->on_queries = QUERY_OP_UNDEFINED;
|
||||
@ -890,8 +886,7 @@ bool create_rule(void* scanner, const char* name)
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR("Memory allocation failed when creating rule '%s'.", name);
|
||||
free(ruledef);
|
||||
MXS_FREE(ruledef);
|
||||
rval = false;
|
||||
}
|
||||
|
||||
@ -911,7 +906,7 @@ static void free_rules(RULE* rule)
|
||||
{
|
||||
TIMERANGE *tr = rule->active;
|
||||
rule->active = rule->active->next;
|
||||
free(tr);
|
||||
MXS_FREE(tr);
|
||||
}
|
||||
|
||||
switch (rule->type)
|
||||
@ -921,7 +916,7 @@ static void free_rules(RULE* rule)
|
||||
break;
|
||||
|
||||
case RT_THROTTLE:
|
||||
free(rule->data);
|
||||
MXS_FREE(rule->data);
|
||||
break;
|
||||
|
||||
case RT_REGEX:
|
||||
@ -932,7 +927,7 @@ static void free_rules(RULE* rule)
|
||||
break;
|
||||
}
|
||||
|
||||
free(rule->name);
|
||||
MXS_FREE(rule->name);
|
||||
rule = tmp;
|
||||
}
|
||||
}
|
||||
@ -1021,9 +1016,9 @@ bool create_user_templates(void* scanner)
|
||||
|
||||
while (user)
|
||||
{
|
||||
user_template_t* newtemp = malloc(sizeof(user_template_t));
|
||||
user_template_t* newtemp = MXS_MALLOC(sizeof(user_template_t));
|
||||
STRLINK* tmp;
|
||||
if (newtemp && (newtemp->name = strdup(user->value)) &&
|
||||
if (newtemp && (newtemp->name = MXS_STRDUP(user->value)) &&
|
||||
(newtemp->rulenames = strlink_reverse_clone(rstack->active_rules)))
|
||||
{
|
||||
newtemp->type = rstack->active_mode;
|
||||
@ -1034,13 +1029,12 @@ bool create_user_templates(void* scanner)
|
||||
{
|
||||
if (newtemp)
|
||||
{
|
||||
free(newtemp->name);
|
||||
free(newtemp);
|
||||
MXS_FREE(newtemp->name);
|
||||
MXS_FREE(newtemp);
|
||||
}
|
||||
free(templates->name);
|
||||
MXS_FREE(templates->name);
|
||||
strlink_free(templates->rulenames);
|
||||
free(templates);
|
||||
MXS_ERROR("Memory allocation failed when processing rule file users definitions.");
|
||||
MXS_FREE(templates);
|
||||
return false;
|
||||
}
|
||||
user = user->next;
|
||||
@ -1063,8 +1057,8 @@ void free_user_templates(user_template_t *templates)
|
||||
user_template_t *tmp = templates;
|
||||
templates = templates->next;
|
||||
strlink_free(tmp->rulenames);
|
||||
free(tmp->name);
|
||||
free(tmp);
|
||||
MXS_FREE(tmp->name);
|
||||
MXS_FREE(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1143,7 +1137,7 @@ bool define_limit_queries_rule(void* scanner, int max, int timeperiod, int holdo
|
||||
{
|
||||
struct parser_stack* rstack = dbfw_yyget_extra((yyscan_t) scanner);
|
||||
ss_dassert(rstack);
|
||||
QUERYSPEED* qs = malloc(sizeof(QUERYSPEED));
|
||||
QUERYSPEED* qs = MXS_MALLOC(sizeof(QUERYSPEED));
|
||||
|
||||
if (qs)
|
||||
{
|
||||
@ -1153,10 +1147,6 @@ bool define_limit_queries_rule(void* scanner, int max, int timeperiod, int holdo
|
||||
rstack->rule->type = RT_THROTTLE;
|
||||
rstack->rule->data = qs;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR("dbfwfilter: Memory allocation failed when adding limit_queries rule.");
|
||||
}
|
||||
|
||||
return qs != NULL;
|
||||
}
|
||||
@ -1239,7 +1229,7 @@ static bool process_user_templates(FW_INSTANCE *instance, user_template_t *templ
|
||||
|
||||
if (user == NULL)
|
||||
{
|
||||
if ((user = malloc(sizeof(USER))) && (user->name = strdup(templates->name)))
|
||||
if ((user = MXS_MALLOC(sizeof(USER))) && (user->name = MXS_STRDUP(templates->name)))
|
||||
{
|
||||
user->rules_and = NULL;
|
||||
user->rules_or = NULL;
|
||||
@ -1249,11 +1239,9 @@ static bool process_user_templates(FW_INSTANCE *instance, user_template_t *templ
|
||||
}
|
||||
else
|
||||
{
|
||||
free(user);
|
||||
MXS_FREE(user);
|
||||
rval = false;
|
||||
break;
|
||||
MXS_ERROR("Memory allocation failed when creating user '%s'.",
|
||||
templates->name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1382,23 +1370,22 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
char *filename = NULL;
|
||||
bool err = false;
|
||||
|
||||
if ((my_instance = calloc(1, sizeof(FW_INSTANCE))) == NULL)
|
||||
if ((my_instance = MXS_CALLOC(1, sizeof(FW_INSTANCE))) == NULL)
|
||||
{
|
||||
free(my_instance);
|
||||
MXS_ERROR("Memory allocation for firewall filter failed.");
|
||||
MXS_FREE(my_instance);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
spinlock_init(&my_instance->lock);
|
||||
|
||||
if ((ht = hashtable_alloc(100, simple_str_hash, strcmp)) == NULL)
|
||||
if ((ht = hashtable_alloc(100, hashtable_item_strhash, hashtable_item_strcmp)) == NULL)
|
||||
{
|
||||
MXS_ERROR("Unable to allocate hashtable.");
|
||||
free(my_instance);
|
||||
MXS_FREE(my_instance);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hashtable_memory_fns(ht, (HASHMEMORYFN) strdup, NULL, (HASHMEMORYFN) free, huserfree);
|
||||
hashtable_memory_fns(ht, hashtable_item_strdup, NULL, hashtable_item_free, huserfree);
|
||||
|
||||
my_instance->htable = ht;
|
||||
my_instance->action = FW_ACTION_BLOCK;
|
||||
@ -1459,7 +1446,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
if (err || !process_rule_file(filename, my_instance))
|
||||
{
|
||||
hashtable_free(my_instance->htable);
|
||||
free(my_instance);
|
||||
MXS_FREE(my_instance);
|
||||
my_instance = NULL;
|
||||
}
|
||||
|
||||
@ -1478,7 +1465,7 @@ newSession(FILTER *instance, SESSION *session)
|
||||
{
|
||||
FW_SESSION *my_session;
|
||||
|
||||
if ((my_session = calloc(1, sizeof(FW_SESSION))) == NULL)
|
||||
if ((my_session = MXS_CALLOC(1, sizeof(FW_SESSION))) == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@ -1510,9 +1497,9 @@ freeSession(FILTER *instance, void *session)
|
||||
FW_SESSION *my_session = (FW_SESSION *) session;
|
||||
if (my_session->errmsg)
|
||||
{
|
||||
free(my_session->errmsg);
|
||||
MXS_FREE(my_session->errmsg);
|
||||
}
|
||||
free(my_session);
|
||||
MXS_FREE(my_session);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1555,11 +1542,10 @@ GWBUF* gen_dummy_error(FW_SESSION* session, char* msg)
|
||||
dcb = session->session->client_dcb;
|
||||
mysql_session = (MYSQL_session*) dcb->data;
|
||||
errlen = msg != NULL ? strlen(msg) : 0;
|
||||
errmsg = (char*) malloc((512 + errlen) * sizeof(char));
|
||||
errmsg = (char*) MXS_MALLOC((512 + errlen) * sizeof(char));
|
||||
|
||||
if (errmsg == NULL)
|
||||
{
|
||||
MXS_ERROR("Memory allocation failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1582,7 +1568,7 @@ GWBUF* gen_dummy_error(FW_SESSION* session, char* msg)
|
||||
}
|
||||
|
||||
buf = modutil_create_mysql_err_msg(1, 0, 1141, "HY000", (const char*) errmsg);
|
||||
free(errmsg);
|
||||
MXS_FREE(errmsg);
|
||||
|
||||
return buf;
|
||||
}
|
||||
@ -1679,7 +1665,7 @@ static char* create_parse_error(FW_INSTANCE* my_instance,
|
||||
{
|
||||
char msgbuf[len + 1]; // +1 for the "."
|
||||
sprintf(msgbuf, "%s.", message);
|
||||
msg = strdup(msgbuf);
|
||||
msg = MXS_STRDUP_A(msgbuf);
|
||||
|
||||
if (my_instance->action == FW_ACTION_ALLOW)
|
||||
{
|
||||
@ -1799,7 +1785,7 @@ bool rule_matches(FW_INSTANCE* my_instance,
|
||||
pcre2_match_data_free(mdata);
|
||||
if (matches)
|
||||
{
|
||||
msg = strdup("Permission denied, query matched regular expression.");
|
||||
msg = MXS_STRDUP_A("Permission denied, query matched regular expression.");
|
||||
MXS_INFO("dbfwfilter: rule '%s': regex matched on query", rulelist->rule->name);
|
||||
goto queryresolved;
|
||||
}
|
||||
@ -1815,7 +1801,7 @@ bool rule_matches(FW_INSTANCE* my_instance,
|
||||
case RT_PERMISSION:
|
||||
{
|
||||
matches = true;
|
||||
msg = strdup("Permission denied at this time.");
|
||||
msg = MXS_STRDUP_A("Permission denied at this time.");
|
||||
char buffer[32]; // asctime documentation requires 26
|
||||
asctime_r(&tm_now, buffer);
|
||||
MXS_INFO("dbfwfilter: rule '%s': query denied at: %s", rulelist->rule->name, buffer);
|
||||
@ -1843,15 +1829,15 @@ bool rule_matches(FW_INSTANCE* my_instance,
|
||||
sprintf(emsg, "Permission denied to column '%s'.", strln->value);
|
||||
MXS_INFO("dbfwfilter: rule '%s': query targets forbidden column: %s",
|
||||
rulelist->rule->name, strln->value);
|
||||
msg = strdup(emsg);
|
||||
free(where);
|
||||
msg = MXS_STRDUP_A(emsg);
|
||||
MXS_FREE(where);
|
||||
goto queryresolved;
|
||||
}
|
||||
strln = strln->next;
|
||||
}
|
||||
tok = strtok_r(NULL, ",", &saveptr);
|
||||
}
|
||||
free(where);
|
||||
MXS_FREE(where);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1869,13 +1855,13 @@ bool rule_matches(FW_INSTANCE* my_instance,
|
||||
if (strchr(strptr, '*'))
|
||||
{
|
||||
matches = true;
|
||||
msg = strdup("Usage of wildcard denied.");
|
||||
msg = MXS_STRDUP_A("Usage of wildcard denied.");
|
||||
MXS_INFO("dbfwfilter: rule '%s': query contains a wildcard.",
|
||||
rulelist->rule->name);
|
||||
free(where);
|
||||
MXS_FREE(where);
|
||||
goto queryresolved;
|
||||
}
|
||||
free(where);
|
||||
MXS_FREE(where);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1906,7 +1892,8 @@ bool rule_matches(FW_INSTANCE* my_instance,
|
||||
{
|
||||
|
||||
/**No match found*/
|
||||
queryspeed = (QUERYSPEED*) calloc(1, sizeof(QUERYSPEED));
|
||||
queryspeed = (QUERYSPEED*) MXS_CALLOC(1, sizeof(QUERYSPEED));
|
||||
MXS_ABORT_IF_NULL(queryspeed);
|
||||
queryspeed->period = rule_qs->period;
|
||||
queryspeed->cooldown = rule_qs->cooldown;
|
||||
queryspeed->limit = rule_qs->limit;
|
||||
@ -1926,7 +1913,7 @@ bool rule_matches(FW_INSTANCE* my_instance,
|
||||
sprintf(emsg, "Queries denied for %f seconds", blocked_for);
|
||||
MXS_INFO("dbfwfilter: rule '%s': user denied for %f seconds",
|
||||
rulelist->rule->name, blocked_for);
|
||||
msg = strdup(emsg);
|
||||
msg = MXS_STRDUP_A(emsg);
|
||||
matches = true;
|
||||
}
|
||||
else
|
||||
@ -1952,7 +1939,7 @@ bool rule_matches(FW_INSTANCE* my_instance,
|
||||
double blocked_for =
|
||||
queryspeed->cooldown - difftime(time_now, queryspeed->triggered);
|
||||
sprintf(emsg, "Queries denied for %f seconds", blocked_for);
|
||||
msg = strdup(emsg);
|
||||
msg = MXS_STRDUP_A(emsg);
|
||||
}
|
||||
else if (queryspeed->count > 0 &&
|
||||
difftime(time_now, queryspeed->first_query) <= queryspeed->period)
|
||||
@ -1972,7 +1959,7 @@ bool rule_matches(FW_INSTANCE* my_instance,
|
||||
!qc_query_has_clause(queue))
|
||||
{
|
||||
matches = true;
|
||||
msg = strdup("Required WHERE/HAVING clause is missing.");
|
||||
msg = MXS_STRDUP_A("Required WHERE/HAVING clause is missing.");
|
||||
MXS_INFO("dbfwfilter: rule '%s': query has no where/having "
|
||||
"clause, query is denied.", rulelist->rule->name);
|
||||
}
|
||||
@ -1989,7 +1976,7 @@ queryresolved:
|
||||
{
|
||||
if (my_session->errmsg)
|
||||
{
|
||||
free(my_session->errmsg);
|
||||
MXS_FREE(my_session->errmsg);
|
||||
}
|
||||
|
||||
my_session->errmsg = msg;
|
||||
@ -2031,14 +2018,14 @@ bool check_match_any(FW_INSTANCE* my_instance, FW_SESSION* my_session,
|
||||
}
|
||||
if (rule_matches(my_instance, my_session, queue, user, rulelist, fullquery))
|
||||
{
|
||||
*rulename = strdup(rulelist->rule->name);
|
||||
*rulename = MXS_STRDUP_A(rulelist->rule->name);
|
||||
rval = true;
|
||||
break;
|
||||
}
|
||||
rulelist = rulelist->next;
|
||||
}
|
||||
|
||||
free(fullquery);
|
||||
MXS_FREE(fullquery);
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
@ -2054,7 +2041,7 @@ void append_string(char** dest, size_t* size, const char* src)
|
||||
{
|
||||
if (*dest == NULL)
|
||||
{
|
||||
*dest = strdup(src);
|
||||
*dest = MXS_STRDUP_A(src);
|
||||
*size = strlen(src);
|
||||
}
|
||||
else
|
||||
@ -2062,7 +2049,7 @@ void append_string(char** dest, size_t* size, const char* src)
|
||||
if (*size < strlen(*dest) + strlen(src) + 3)
|
||||
{
|
||||
size_t newsize = strlen(*dest) + strlen(src) + 3;
|
||||
char* tmp = realloc(*dest, newsize);
|
||||
char* tmp = MXS_REALLOC(*dest, newsize);
|
||||
if (tmp)
|
||||
{
|
||||
*size = newsize;
|
||||
@ -2070,7 +2057,6 @@ void append_string(char** dest, size_t* size, const char* src)
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR("Memory allocation failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -2131,7 +2117,7 @@ bool check_match_all(FW_INSTANCE* my_instance, FW_SESSION* my_session,
|
||||
/** No active rules */
|
||||
rval = false;
|
||||
}
|
||||
free(fullquery);
|
||||
MXS_FREE(fullquery);
|
||||
}
|
||||
|
||||
/** Set the list of matched rule names */
|
||||
@ -2198,7 +2184,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
GWBUF* err = gen_dummy_error(my_session, "This filter does not support "
|
||||
"multi-statements.");
|
||||
gwbuf_free(queue);
|
||||
free(my_session->errmsg);
|
||||
MXS_FREE(my_session->errmsg);
|
||||
my_session->errmsg = NULL;
|
||||
rval = dcb->func.write(dcb, err);
|
||||
}
|
||||
@ -2268,7 +2254,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
}
|
||||
}
|
||||
|
||||
free(rname);
|
||||
MXS_FREE(rname);
|
||||
}
|
||||
/** If the instance is in whitelist mode, only users that have a rule
|
||||
* defined for them are allowed */
|
||||
@ -2286,7 +2272,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
{
|
||||
GWBUF* forward = gen_dummy_error(my_session, my_session->errmsg);
|
||||
gwbuf_free(queue);
|
||||
free(my_session->errmsg);
|
||||
MXS_FREE(my_session->errmsg);
|
||||
my_session->errmsg = NULL;
|
||||
rval = dcb->func.write(dcb, forward);
|
||||
}
|
||||
@ -2378,10 +2364,11 @@ int main(int argc, char** argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
home = malloc(sizeof(char) * (PATH_MAX + 1));
|
||||
home = MXS_MALLOC(sizeof(char) * (PATH_MAX + 1));
|
||||
MXS_ABORT_IF_NULL(home);
|
||||
if (getcwd(home, PATH_MAX) == NULL)
|
||||
{
|
||||
free(home);
|
||||
MXS_FREE(home);
|
||||
home = NULL;
|
||||
}
|
||||
|
||||
@ -2399,8 +2386,8 @@ int main(int argc, char** argv)
|
||||
|
||||
|
||||
init_test_env(home);
|
||||
ruleparam.name = strdup("rules");
|
||||
ruleparam.value = strdup(argv[1]);
|
||||
ruleparam.name = MXS_STRDUP_A("rules");
|
||||
ruleparam.value = MXS_STRDUP_A(argv[1]);
|
||||
paramlist[0] = &ruleparam;
|
||||
paramlist[1] = NULL;
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
|
587
server/modules/filter/gatekeeper.c
Normal file
587
server/modules/filter/gatekeeper.c
Normal file
@ -0,0 +1,587 @@
|
||||
/*
|
||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
* Public License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <filter.h>
|
||||
#include <modinfo.h>
|
||||
#include <modutil.h>
|
||||
#include <atomic.h>
|
||||
#include <query_classifier.h>
|
||||
#include <hashtable.h>
|
||||
#include <gwdirs.h>
|
||||
#include <maxscale/alloc.h>
|
||||
|
||||
#define GK_DEFAULT_HASHTABLE_SIZE 1000
|
||||
|
||||
/**
|
||||
* @file gatekeeper.c - A learning firewall
|
||||
*
|
||||
* This filter will learn from input data read during a learning phase.
|
||||
* After learning the characteristics of the input, the filter can then
|
||||
* be set into an enforcing mode. In this mode the filter will block any
|
||||
* queries that do not conform to the training set.
|
||||
*/
|
||||
|
||||
MODULE_INFO info =
|
||||
{
|
||||
MODULE_API_FILTER,
|
||||
MODULE_ALPHA_RELEASE,
|
||||
FILTER_VERSION,
|
||||
"Learning firewall filter"
|
||||
};
|
||||
|
||||
enum firewall_mode
|
||||
{
|
||||
ENFORCE,
|
||||
LEARN
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned long queries; /**< Number of queries received */
|
||||
unsigned int hit; /**< Number of queries that match a pattern */
|
||||
unsigned int miss; /**< Number of queries that do not match a pattern */
|
||||
unsigned int entries; /**< Number of new patterns created */
|
||||
} GK_STATS;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HASHTABLE *queryhash; /**< Canonicalized forms of the queries */
|
||||
char* datadir; /**< The data is stored in this directory as lfw.data */
|
||||
enum firewall_mode mode; /**< Filter mode, either ENFORCE or LEARN */
|
||||
GK_STATS stats; /**< Instance statistics */
|
||||
SPINLOCK lock; /**< Instance lock */
|
||||
bool updating; /**< If the datafile is being updated */
|
||||
bool need_update; /**< If the datafile needs updating */
|
||||
} GK_INSTANCE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DCB* dcb; /**< Client DCB, used to send error messages */
|
||||
DOWNSTREAM down;
|
||||
GK_STATS stats; /**< Session statistics */
|
||||
} GK_SESSION;
|
||||
|
||||
static char *version_str = "V1.0.0";
|
||||
static const char* datafile_name = "gatekeeper.data";
|
||||
|
||||
/** Prefix all log messages with this tag */
|
||||
#define MODNAME "[gatekeeper] "
|
||||
|
||||
/** This is passed as a value to @c hashtable_add to have @c hashtable_fetch
|
||||
* return a non-NULL value when a hash hit is made */
|
||||
static bool trueval = true;
|
||||
|
||||
static FILTER *createInstance(char **options, FILTER_PARAMETER **params);
|
||||
static void *newSession(FILTER *instance, SESSION *session);
|
||||
static void closeSession(FILTER *instance, void *session);
|
||||
static void freeSession(FILTER *instance, void *session);
|
||||
static void setDownstream(FILTER *instance, void *fsession, DOWNSTREAM *downstream);
|
||||
static int routeQuery(FILTER *instance, void *fsession, GWBUF *queue);
|
||||
static void diagnostic(FILTER *instance, void *fsession, DCB *dcb);
|
||||
static bool read_stored_data(GK_INSTANCE *inst);
|
||||
static bool write_stored_data(GK_INSTANCE *inst);
|
||||
|
||||
static FILTER_OBJECT MyObject =
|
||||
{
|
||||
createInstance,
|
||||
newSession,
|
||||
closeSession,
|
||||
freeSession,
|
||||
setDownstream,
|
||||
NULL, // No upstream requirement
|
||||
routeQuery,
|
||||
NULL,
|
||||
diagnostic,
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of the mandatory version entry point
|
||||
*
|
||||
* @return version string of the module
|
||||
*/
|
||||
char* version()
|
||||
{
|
||||
return version_str;
|
||||
}
|
||||
|
||||
/**
|
||||
* The module initialization routine, called when the module
|
||||
* is first loaded.
|
||||
*/
|
||||
void ModuleInit()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* The module entry point routine. It is this routine that
|
||||
* must populate the structure that is referred to as the
|
||||
* "module object", this is a structure with the set of
|
||||
* external entry points for this module.
|
||||
*
|
||||
* @return The module object
|
||||
*/
|
||||
FILTER_OBJECT* GetModuleObject()
|
||||
{
|
||||
return &MyObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of the filter for a particular service
|
||||
* within MaxScale.
|
||||
*
|
||||
* @param options The options for this filter
|
||||
* @param params The array of name/value pair parameters for the filter
|
||||
*
|
||||
* @return The instance data for this new instance
|
||||
*/
|
||||
static FILTER* createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
GK_INSTANCE *inst = MXS_CALLOC(1, sizeof(GK_INSTANCE));
|
||||
|
||||
if (inst)
|
||||
{
|
||||
const char* datadir = get_datadir();
|
||||
bool ok = true;
|
||||
spinlock_init(&inst->lock);
|
||||
inst->mode = LEARN;
|
||||
|
||||
for (int i = 0; params && params[i]; i++)
|
||||
{
|
||||
if (strcmp(params[i]->name, "mode") == 0)
|
||||
{
|
||||
if (strcasecmp(params[i]->value, "enforce") == 0)
|
||||
{
|
||||
inst->mode = ENFORCE;
|
||||
}
|
||||
else if (strcasecmp(params[i]->value, "learn") == 0)
|
||||
{
|
||||
inst->mode = LEARN;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR(MODNAME"Unknown value for 'mode': %s", params[i]->value);
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
else if (strcmp(params[i]->name, "datadir") == 0)
|
||||
{
|
||||
if (access(params[i]->value, F_OK) == 0)
|
||||
{
|
||||
datadir = params[i]->value;
|
||||
}
|
||||
else
|
||||
{
|
||||
char err[STRERROR_BUFLEN];
|
||||
MXS_ERROR(MODNAME"File is not accessible: %d, %s", errno,
|
||||
strerror_r(errno, err, sizeof(err)));
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
else if (!filter_standard_parameter(params[i]->name))
|
||||
{
|
||||
MXS_ERROR(MODNAME"Unknown parameter '%s'.", params[i]->name);
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
inst->queryhash = hashtable_alloc(GK_DEFAULT_HASHTABLE_SIZE,
|
||||
hashtable_item_strhash,
|
||||
hashtable_item_strcasecmp);
|
||||
inst->datadir = MXS_STRDUP(datadir);
|
||||
if (inst->queryhash && inst->datadir)
|
||||
{
|
||||
hashtable_memory_fns(inst->queryhash, NULL, NULL, hashtable_item_free, NULL);
|
||||
if (read_stored_data(inst))
|
||||
{
|
||||
MXS_NOTICE(MODNAME"Started in [%s] mode. Data is stored at: %s",
|
||||
inst->mode == ENFORCE ? "ENFORCE" : "LEARN", inst->datadir);
|
||||
}
|
||||
else
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
hashtable_free(inst->queryhash);
|
||||
MXS_FREE(inst->datadir);
|
||||
MXS_FREE(inst);
|
||||
inst = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return (FILTER*)inst;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate a new session with this instance of the filter.
|
||||
*
|
||||
* @param instance The filter instance data
|
||||
* @param session The session itself
|
||||
* @return Session specific data for this session
|
||||
*/
|
||||
static void* newSession(FILTER *instance, SESSION *session)
|
||||
{
|
||||
GK_INSTANCE *inst = (GK_INSTANCE *) instance;
|
||||
GK_SESSION *ses;
|
||||
|
||||
if ((ses = MXS_CALLOC(1, sizeof(GK_SESSION))) != NULL)
|
||||
{
|
||||
ses->dcb = session->client_dcb;
|
||||
}
|
||||
|
||||
return ses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close a session with the filter, this is the mechanism
|
||||
* by which a filter may cleanup data structure etc.
|
||||
*
|
||||
* The gatekeeper flushes the hashtable to disk every time a session is closed.
|
||||
*
|
||||
* @param instance The filter instance data
|
||||
* @param session The session being closed
|
||||
*/
|
||||
static void closeSession(FILTER *instance, void *session)
|
||||
{
|
||||
GK_INSTANCE *inst = (GK_INSTANCE*) instance;
|
||||
GK_SESSION *ses = (GK_SESSION *) session;
|
||||
|
||||
/** If we added new data into the queryhash, update the datafile on disk */
|
||||
if (ses->stats.entries > 0)
|
||||
{
|
||||
spinlock_acquire(&inst->lock);
|
||||
|
||||
bool update = !inst->updating;
|
||||
if (update)
|
||||
{
|
||||
inst->updating = true;
|
||||
inst->need_update = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/** If another thread is already updating the file, set
|
||||
* the need_update flag */
|
||||
inst->need_update = true;
|
||||
}
|
||||
|
||||
spinlock_release(&inst->lock);
|
||||
|
||||
while (update)
|
||||
{
|
||||
/** Store the hashtable to disk */
|
||||
write_stored_data(inst);
|
||||
|
||||
spinlock_acquire(&inst->lock);
|
||||
|
||||
/** Check if the hashtable has been update while we were writing
|
||||
* the data to disk. */
|
||||
if ((update = inst->need_update))
|
||||
{
|
||||
inst->need_update = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
inst->updating = false;
|
||||
}
|
||||
|
||||
spinlock_release(&inst->lock);
|
||||
}
|
||||
}
|
||||
|
||||
/** Add session stats to instance stats */
|
||||
spinlock_acquire(&inst->lock);
|
||||
inst->stats.entries += ses->stats.entries;
|
||||
inst->stats.hit += ses->stats.hit;
|
||||
inst->stats.miss += ses->stats.miss;
|
||||
inst->stats.queries += ses->stats.queries;
|
||||
spinlock_release(&inst->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the memory associated with this filter session.
|
||||
*
|
||||
* @param instance The filter instance data
|
||||
* @param session The session being closed
|
||||
*/
|
||||
static void freeSession(FILTER *instance, void *session)
|
||||
{
|
||||
MXS_FREE(session);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the downstream component for this filter.
|
||||
*
|
||||
* @param instance The filter instance data
|
||||
* @param session The session being closed
|
||||
* @param downstream The downstream filter or router
|
||||
*/
|
||||
static void setDownstream(FILTER *instance, void *session, DOWNSTREAM *downstream)
|
||||
{
|
||||
GK_SESSION *ses = (GK_SESSION *) session;
|
||||
ses->down = *downstream;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main routing function
|
||||
*
|
||||
* @param instance The filter instance data
|
||||
* @param session The filter session
|
||||
* @param queue The query data
|
||||
* @return 1 on success, 0 on error
|
||||
*/
|
||||
static int routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
{
|
||||
GK_INSTANCE *inst = (GK_INSTANCE*) instance;
|
||||
GK_SESSION *ses = (GK_SESSION *) session;
|
||||
int rval = 1;
|
||||
bool ok = true;
|
||||
char* canon = qc_get_canonical(queue);
|
||||
|
||||
ses->stats.queries++;
|
||||
|
||||
/** Non-COM_QUERY packets are better handled on the backend database. For
|
||||
* example a COM_INIT_DB does not get canonicalized and would be always
|
||||
* denied. For this reason, queries that are not canonicalized are allowed.
|
||||
* This means that the binary protocol and prepared statements are not
|
||||
* processed by this filter. */
|
||||
if (canon)
|
||||
{
|
||||
if (inst->mode == ENFORCE)
|
||||
{
|
||||
if (hashtable_fetch(inst->queryhash, canon))
|
||||
{
|
||||
ses->stats.hit++;
|
||||
}
|
||||
else
|
||||
{
|
||||
ses->stats.miss++;
|
||||
ok = false;
|
||||
MXS_WARNING(MODNAME"Query by %s@%s was not found from queryhash: %s",
|
||||
ses->dcb->user, ses->dcb->remote, canon);
|
||||
GWBUF* errbuf = modutil_create_mysql_err_msg(1, 0, 1, "00000", "Permission denied.");
|
||||
rval = errbuf ? ses->dcb->func.write(ses->dcb, errbuf) : 0;
|
||||
}
|
||||
MXS_FREE(canon);
|
||||
}
|
||||
else if (inst->mode == LEARN)
|
||||
{
|
||||
if (hashtable_add(inst->queryhash, canon, &trueval))
|
||||
{
|
||||
ses->stats.entries++;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_FREE(canon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
rval = ses->down.routeQuery(ses->down.instance, ses->down.session, queue);
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Diagnostics routine
|
||||
*
|
||||
* @param instance The filter instance
|
||||
* @param fsession Filter session
|
||||
* @param dcb The DCB for output
|
||||
*/
|
||||
static void diagnostic(FILTER *instance, void *fsession, DCB *dcb)
|
||||
{
|
||||
GK_INSTANCE *inst = (GK_INSTANCE *) instance;
|
||||
|
||||
dcb_printf(dcb, "\t\tQueries: %lu\n", inst->stats.queries);
|
||||
dcb_printf(dcb, "\t\tQueryhash entries: %u\n", inst->stats.entries);
|
||||
dcb_printf(dcb, "\t\tQueryhash hits: %u\n", inst->stats.hit);
|
||||
dcb_printf(dcb, "\t\tQueryhash misses: %u\n", inst->stats.miss);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write query patterns from memory to disk
|
||||
*
|
||||
* The data is stored as length-encoded strings. A length-encoded string contains
|
||||
* a 4 byte integer, which tells the length of the string, followed by the string
|
||||
* itself. The stored file will consist of multiple consecutive length-encoded strings.
|
||||
*
|
||||
* @param inst Filter instance
|
||||
* @return True on success
|
||||
*/
|
||||
static bool write_stored_data(GK_INSTANCE *inst)
|
||||
{
|
||||
bool rval = false;
|
||||
char filepath[PATH_MAX];
|
||||
sprintf(filepath, "%s/%s.tmp.XXXXXX", inst->datadir, datafile_name);
|
||||
int fd = mkstemp(filepath);
|
||||
HASHITERATOR *iter = hashtable_iterator(inst->queryhash);
|
||||
|
||||
if (fd > 0 && iter)
|
||||
{
|
||||
char *key;
|
||||
bool ok = true;
|
||||
|
||||
while ((key = hashtable_next(iter)))
|
||||
{
|
||||
uint32_t len = strlen(key);
|
||||
|
||||
/** First write the length of the string and then the string itself */
|
||||
if (write(fd, &len, sizeof(len)) != sizeof(len) ||
|
||||
write(fd, key, len) != len)
|
||||
{
|
||||
char err[STRERROR_BUFLEN];
|
||||
MXS_ERROR(MODNAME"Failed to write key '%s' to disk (%d, %s). The datafile at '%s' was "
|
||||
"not updated but it will be updated when the next session closes. ",
|
||||
key, errno, strerror_r(errno, err, sizeof(err)), inst->datadir);
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
/** Update the file by renaming the temporary file to the original one*/
|
||||
char newfilepath[PATH_MAX + 1];
|
||||
snprintf(newfilepath, sizeof(newfilepath), "%s/%s", inst->datadir, datafile_name);
|
||||
rval = rename(filepath, newfilepath) == 0;
|
||||
|
||||
if (!rval)
|
||||
{
|
||||
char err[STRERROR_BUFLEN];
|
||||
MXS_ERROR(MODNAME"Failed to rename file '%s' to '%s' when writing data: %d, %s",
|
||||
filepath, newfilepath, errno, strerror_r(errno, err, sizeof(err)));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (fd == -1)
|
||||
{
|
||||
char err[STRERROR_BUFLEN];
|
||||
MXS_ERROR(MODNAME"Failed to open file '%s' when writing data: %d, %s",
|
||||
filepath, errno, strerror_r(errno, err, sizeof(err)));
|
||||
}
|
||||
|
||||
if (fd > 0)
|
||||
{
|
||||
close(fd);
|
||||
}
|
||||
hashtable_iterator_free(iter);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
static void report_failed_read(FILE *file, int nexpected, int nread)
|
||||
{
|
||||
if (ferror(file))
|
||||
{
|
||||
char err[STRERROR_BUFLEN];
|
||||
MXS_ERROR(MODNAME"Failed to read %d bytes, only %d bytes read: %d, %s",
|
||||
nexpected, nread, errno, strerror_r(errno, err, sizeof(err)));
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR(MODNAME"Partial read, expected %d bytes but read only %d.",
|
||||
nexpected, nread);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read query patterns from disk to memory
|
||||
*
|
||||
* See write_stored_data() for details on how the data is stored.
|
||||
*
|
||||
* @param inst Filter instance
|
||||
* @return True if data was successfully read
|
||||
*/
|
||||
static bool read_stored_data(GK_INSTANCE *inst)
|
||||
{
|
||||
char filepath[PATH_MAX + 1];
|
||||
snprintf(filepath, sizeof(filepath), "%s/%s", inst->datadir, datafile_name);
|
||||
|
||||
if (access(filepath, F_OK) != 0)
|
||||
{
|
||||
if (inst->mode == ENFORCE)
|
||||
{
|
||||
MXS_ERROR(MODNAME"Started in ENFORCE mode but no datafile was found at '%s'.", filepath);
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Not finding a datafile in LEARN mode is OK since it will be created later on */
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rval = true;
|
||||
FILE *file = fopen(filepath, "rb");
|
||||
|
||||
if (file)
|
||||
{
|
||||
do
|
||||
{
|
||||
uint32_t len;
|
||||
size_t nread;
|
||||
char *data;
|
||||
|
||||
/** Read the length of the string */
|
||||
if ((nread = fread(&len, 1, sizeof(len), file)) != sizeof(len))
|
||||
{
|
||||
if (nread > 0 || !feof(file))
|
||||
{
|
||||
report_failed_read(file, sizeof(len), nread);
|
||||
rval = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ((data = MXS_MALLOC(len + 1)) == NULL)
|
||||
{
|
||||
rval = false;
|
||||
break;
|
||||
}
|
||||
|
||||
/** Read the string itself */
|
||||
if ((nread = fread(data, 1, len, file)) != len)
|
||||
{
|
||||
MXS_FREE(data);
|
||||
report_failed_read(file, sizeof(len), nread);
|
||||
rval = false;
|
||||
break;
|
||||
}
|
||||
|
||||
data[len] = '\0';
|
||||
hashtable_add(inst->queryhash, data, &trueval);
|
||||
}
|
||||
while (!feof(file));
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
char err[STRERROR_BUFLEN];
|
||||
MXS_ERROR(MODNAME"Failed to open file '%s' when reading stored data: %d, %s",
|
||||
filepath, errno, strerror_r(errno, err, sizeof(err)));
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
add_library(hintfilter SHARED hintfilter.c hintparser.c)
|
||||
set_target_properties(hintfilter PROPERTIES INSTALL_RPATH ${CMAKE_INSTALL_RPATH}:${MAXSCALE_LIBDIR} VERSION "1.0.0")
|
||||
target_link_libraries(hintfilter maxscale-common)
|
||||
install(TARGETS hintfilter DESTINATION ${MAXSCALE_LIBDIR})
|
||||
install_module(hintfilter core)
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -12,6 +12,7 @@
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <filter.h>
|
||||
#include <maxscale/alloc.h>
|
||||
#include <modinfo.h>
|
||||
#include <modutil.h>
|
||||
#include <mysqlhint.h>
|
||||
@ -105,7 +106,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
HINT_INSTANCE *my_instance;
|
||||
|
||||
if ((my_instance = calloc(1, sizeof(HINT_INSTANCE))) != NULL)
|
||||
if ((my_instance = MXS_CALLOC(1, sizeof(HINT_INSTANCE))) != NULL)
|
||||
{
|
||||
my_instance->sessions = 0;
|
||||
}
|
||||
@ -125,7 +126,7 @@ newSession(FILTER *instance, SESSION *session)
|
||||
HINT_INSTANCE *my_instance = (HINT_INSTANCE *)instance;
|
||||
HINT_SESSION *my_session;
|
||||
|
||||
if ((my_session = calloc(1, sizeof(HINT_SESSION))) != NULL)
|
||||
if ((my_session = MXS_CALLOC(1, sizeof(HINT_SESSION))) != NULL)
|
||||
{
|
||||
my_session->query_len = 0;
|
||||
my_session->request = NULL;
|
||||
@ -177,7 +178,7 @@ closeSession(FILTER *instance, void *session)
|
||||
static void
|
||||
freeSession(FILTER *instance, void *session)
|
||||
{
|
||||
free(session);
|
||||
MXS_FREE(session);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -19,6 +19,7 @@
|
||||
#include <modinfo.h>
|
||||
#include <modutil.h>
|
||||
#include <mysqlhint.h>
|
||||
#include <maxscale/alloc.h>
|
||||
|
||||
/**
|
||||
* hintparser.c - Find any comment in the SQL packet and look for MAXSCALE
|
||||
@ -83,9 +84,9 @@ void token_free(HINT_TOKEN* token)
|
||||
{
|
||||
if (token->value != NULL)
|
||||
{
|
||||
free(token->value);
|
||||
MXS_FREE(token->value);
|
||||
}
|
||||
free(token);
|
||||
MXS_FREE(token);
|
||||
}
|
||||
|
||||
static const char* token_get_keyword(
|
||||
@ -281,7 +282,7 @@ hint_parser(HINT_SESSION *session, GWBUF *request)
|
||||
break;
|
||||
case TOK_STRING:
|
||||
state = HS_NAME;
|
||||
lvalue = strdup(tok->value);
|
||||
lvalue = MXS_STRDUP_A(tok->value);
|
||||
break;
|
||||
case TOK_STOP:
|
||||
/* Action: pop active hint */
|
||||
@ -452,7 +453,7 @@ hint_parser(HINT_SESSION *session, GWBUF *request)
|
||||
/* We starting an already define set of named hints */
|
||||
rval = lookup_named_hint(session, hintname);
|
||||
hint_push(session, hint_dup(rval));
|
||||
free(hintname);
|
||||
MXS_FREE(hintname);
|
||||
rval = NULL;
|
||||
}
|
||||
else if (hintname == NULL && rval == NULL)
|
||||
@ -518,7 +519,7 @@ hint_next_token(GWBUF **buf, char **ptr)
|
||||
int i, found;
|
||||
HINT_TOKEN *tok;
|
||||
|
||||
if ((tok = (HINT_TOKEN *)malloc(sizeof(HINT_TOKEN))) == NULL)
|
||||
if ((tok = (HINT_TOKEN *)MXS_MALLOC(sizeof(HINT_TOKEN))) == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@ -603,7 +604,7 @@ hint_next_token(GWBUF **buf, char **ptr)
|
||||
if (found == 0)
|
||||
{
|
||||
tok->token = TOK_STRING;
|
||||
tok->value = strdup(word);
|
||||
tok->value = MXS_STRDUP_A(word);
|
||||
}
|
||||
|
||||
return tok;
|
||||
@ -629,7 +630,7 @@ hint_pop(HINT_SESSION *session)
|
||||
ptr->hint = hint->next;
|
||||
hint_free(hint);
|
||||
}
|
||||
free(ptr);
|
||||
MXS_FREE(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -645,7 +646,7 @@ hint_push(HINT_SESSION *session, HINT *hint)
|
||||
{
|
||||
HINTSTACK *item;
|
||||
|
||||
if ((item = (HINTSTACK *)malloc(sizeof(HINTSTACK))) == NULL)
|
||||
if ((item = (HINTSTACK *)MXS_MALLOC(sizeof(HINTSTACK))) == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -689,7 +690,7 @@ create_named_hint(HINT_SESSION *session, char *name, HINT *hint)
|
||||
{
|
||||
NAMEDHINTS *block;
|
||||
|
||||
if ((block = (NAMEDHINTS *)malloc(sizeof(NAMEDHINTS))) == NULL)
|
||||
if ((block = (NAMEDHINTS *)MXS_MALLOC(sizeof(NAMEDHINTS))) == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -724,8 +725,8 @@ NAMEDHINTS* free_named_hint(
|
||||
hint_free(named_hint->hints);
|
||||
named_hint->hints = hint;
|
||||
}
|
||||
free(named_hint->name);
|
||||
free(named_hint);
|
||||
MXS_FREE(named_hint->name);
|
||||
MXS_FREE(named_hint);
|
||||
return next;
|
||||
}
|
||||
else
|
||||
@ -758,7 +759,7 @@ HINTSTACK* free_hint_stack(
|
||||
hint_free(hint_stack->hint);
|
||||
hint_stack->hint = hint;
|
||||
}
|
||||
free(hint_stack);
|
||||
MXS_FREE(hint_stack);
|
||||
return next;
|
||||
}
|
||||
else
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -47,6 +47,7 @@
|
||||
#include "lua.h"
|
||||
#include "lualib.h"
|
||||
#include "lauxlib.h"
|
||||
#include <maxscale/alloc.h>
|
||||
|
||||
MODULE_INFO info =
|
||||
{
|
||||
@ -173,7 +174,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
LUA_INSTANCE *my_instance;
|
||||
bool error = false;
|
||||
|
||||
if ((my_instance = (LUA_INSTANCE*) calloc(1, sizeof(LUA_INSTANCE))) == NULL)
|
||||
if ((my_instance = (LUA_INSTANCE*) MXS_CALLOC(1, sizeof(LUA_INSTANCE))) == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@ -184,11 +185,11 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
if (strcmp(params[i]->name, "global_script") == 0)
|
||||
{
|
||||
error = (my_instance->global_script = strdup(params[i]->value)) == NULL;
|
||||
error = (my_instance->global_script = MXS_STRDUP(params[i]->value)) == NULL;
|
||||
}
|
||||
else if (strcmp(params[i]->name, "session_script") == 0)
|
||||
{
|
||||
error = (my_instance->session_script = strdup(params[i]->value)) == NULL;
|
||||
error = (my_instance->session_script = MXS_STRDUP(params[i]->value)) == NULL;
|
||||
}
|
||||
else if (!filter_standard_parameter(params[i]->name))
|
||||
{
|
||||
@ -199,9 +200,9 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
|
||||
if (error)
|
||||
{
|
||||
free(my_instance->global_script);
|
||||
free(my_instance->session_script);
|
||||
free(my_instance);
|
||||
MXS_FREE(my_instance->global_script);
|
||||
MXS_FREE(my_instance->session_script);
|
||||
MXS_FREE(my_instance);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -215,9 +216,9 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
MXS_ERROR("luafilter: Failed to execute global script at '%s':%s.",
|
||||
my_instance->global_script, lua_tostring(my_instance->global_lua_state, -1));
|
||||
free(my_instance->global_script);
|
||||
free(my_instance->session_script);
|
||||
free(my_instance);
|
||||
MXS_FREE(my_instance->global_script);
|
||||
MXS_FREE(my_instance->session_script);
|
||||
MXS_FREE(my_instance);
|
||||
my_instance = NULL;
|
||||
}
|
||||
else if (my_instance->global_lua_state)
|
||||
@ -234,7 +235,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
else
|
||||
{
|
||||
MXS_ERROR("Unable to initialize new Lua state.");
|
||||
free(my_instance);
|
||||
MXS_FREE(my_instance);
|
||||
my_instance = NULL;
|
||||
}
|
||||
}
|
||||
@ -263,7 +264,7 @@ static void * newSession(FILTER *instance, SESSION *session)
|
||||
LUA_SESSION *my_session;
|
||||
LUA_INSTANCE *my_instance = (LUA_INSTANCE*) instance;
|
||||
|
||||
if ((my_session = (LUA_SESSION*) calloc(1, sizeof(LUA_SESSION))) == NULL)
|
||||
if ((my_session = (LUA_SESSION*) MXS_CALLOC(1, sizeof(LUA_SESSION))) == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@ -282,7 +283,7 @@ static void * newSession(FILTER *instance, SESSION *session)
|
||||
my_instance->session_script,
|
||||
lua_tostring(my_session->lua_state, -1));
|
||||
lua_close(my_session->lua_state);
|
||||
free(my_session);
|
||||
MXS_FREE(my_session);
|
||||
my_session = NULL;
|
||||
}
|
||||
else
|
||||
@ -367,7 +368,7 @@ static void freeSession(FILTER *instance, void *session)
|
||||
{
|
||||
LUA_SESSION *my_session = (LUA_SESSION *) session;
|
||||
lua_close(my_session->lua_state);
|
||||
free(my_session);
|
||||
MXS_FREE(my_session);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -526,7 +527,7 @@ static int routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
spinlock_release(&my_instance->lock);
|
||||
}
|
||||
|
||||
free(fullquery);
|
||||
MXS_FREE(fullquery);
|
||||
}
|
||||
|
||||
if (!route)
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -76,6 +76,7 @@
|
||||
#include <spinlock.h>
|
||||
#include <session.h>
|
||||
#include <housekeeper.h>
|
||||
#include <maxscale/alloc.h>
|
||||
|
||||
MODULE_INFO info =
|
||||
{
|
||||
@ -474,11 +475,10 @@ char** parse_optstr(char* str, char* tok, int* szstore)
|
||||
size++;
|
||||
}
|
||||
|
||||
arr = malloc(sizeof(char*)*size);
|
||||
arr = MXS_MALLOC(sizeof(char*)*size);
|
||||
|
||||
if (arr == NULL)
|
||||
{
|
||||
MXS_ERROR("Cannot allocate enough memory.");
|
||||
*szstore = 0;
|
||||
return NULL;
|
||||
}
|
||||
@ -487,7 +487,7 @@ char** parse_optstr(char* str, char* tok, int* szstore)
|
||||
tk = strtok_r(str, tok, &lasts);
|
||||
while (tk && i < size)
|
||||
{
|
||||
arr[i++] = strdup(tk);
|
||||
arr[i++] = MXS_STRDUP_A(tk);
|
||||
tk = strtok_r(NULL, tok, &lasts);
|
||||
}
|
||||
return arr;
|
||||
@ -510,17 +510,18 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
char** arr = NULL;
|
||||
char taskname[512];
|
||||
|
||||
if ((my_instance = calloc(1, sizeof(MQ_INSTANCE))))
|
||||
if ((my_instance = MXS_CALLOC(1, sizeof(MQ_INSTANCE))))
|
||||
{
|
||||
spinlock_init(&my_instance->rconn_lock);
|
||||
spinlock_init(&my_instance->msg_lock);
|
||||
uid_gen = 0;
|
||||
paramlist = malloc(sizeof(FILTER_PARAMETER*) * 64);
|
||||
paramlist = MXS_MALLOC(sizeof(FILTER_PARAMETER*) * 64);
|
||||
MXS_ABORT_IF_NULL(paramlist);
|
||||
|
||||
if ((my_instance->conn = amqp_new_connection()) == NULL)
|
||||
{
|
||||
free(paramlist);
|
||||
free(my_instance);
|
||||
MXS_FREE(paramlist);
|
||||
MXS_FREE(my_instance);
|
||||
return NULL;
|
||||
}
|
||||
my_instance->channel = 1;
|
||||
@ -536,19 +537,19 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
if (!strcmp(params[i]->name, "hostname"))
|
||||
{
|
||||
my_instance->hostname = strdup(params[i]->value);
|
||||
my_instance->hostname = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "username"))
|
||||
{
|
||||
my_instance->username = strdup(params[i]->value);
|
||||
my_instance->username = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "password"))
|
||||
{
|
||||
my_instance->password = strdup(params[i]->value);
|
||||
my_instance->password = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "vhost"))
|
||||
{
|
||||
my_instance->vhost = strdup(params[i]->value);
|
||||
my_instance->vhost = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "port"))
|
||||
{
|
||||
@ -556,35 +557,34 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "exchange"))
|
||||
{
|
||||
my_instance->exchange = strdup(params[i]->value);
|
||||
my_instance->exchange = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "key"))
|
||||
{
|
||||
my_instance->key = strdup(params[i]->value);
|
||||
my_instance->key = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "queue"))
|
||||
{
|
||||
my_instance->queue = strdup(params[i]->value);
|
||||
my_instance->queue = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "ssl_client_certificate"))
|
||||
{
|
||||
|
||||
my_instance->ssl_client_cert = strdup(params[i]->value);
|
||||
my_instance->ssl_client_cert = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "ssl_client_key"))
|
||||
{
|
||||
|
||||
my_instance->ssl_client_key = strdup(params[i]->value);
|
||||
my_instance->ssl_client_key = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "ssl_CA_cert"))
|
||||
{
|
||||
|
||||
my_instance->ssl_CA_cert = strdup(params[i]->value);
|
||||
my_instance->ssl_CA_cert = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "exchange_type"))
|
||||
{
|
||||
|
||||
my_instance->exchange_type = strdup(params[i]->value);
|
||||
my_instance->exchange_type = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "logging_trigger"))
|
||||
{
|
||||
@ -619,9 +619,9 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
for (int x = 0; x < arrsize; x++)
|
||||
{
|
||||
free(arr[x]);
|
||||
MXS_FREE(arr[x]);
|
||||
}
|
||||
free(arr);
|
||||
MXS_FREE(arr);
|
||||
arr = NULL;
|
||||
}
|
||||
arrsize = 0;
|
||||
@ -634,9 +634,10 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
|
||||
if (paramcount < parammax)
|
||||
{
|
||||
paramlist[paramcount] = malloc(sizeof(FILTER_PARAMETER));
|
||||
paramlist[paramcount]->name = strdup(params[i]->name);
|
||||
paramlist[paramcount]->value = strdup(params[i]->value);
|
||||
paramlist[paramcount] = MXS_MALLOC(sizeof(FILTER_PARAMETER));
|
||||
MXS_ABORT_IF_NULL(paramlist[paramcount]);
|
||||
paramlist[paramcount]->name = MXS_STRDUP_A(params[i]->name);
|
||||
paramlist[paramcount]->value = MXS_STRDUP_A(params[i]->value);
|
||||
paramcount++;
|
||||
}
|
||||
}
|
||||
@ -645,7 +646,8 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
if (my_instance->trgtype & TRG_SOURCE)
|
||||
{
|
||||
|
||||
my_instance->src_trg = (SRC_TRIG*) malloc(sizeof(SRC_TRIG));
|
||||
my_instance->src_trg = (SRC_TRIG*) MXS_MALLOC(sizeof(SRC_TRIG));
|
||||
MXS_ABORT_IF_NULL(my_instance->src_trg);
|
||||
my_instance->src_trg->user = NULL;
|
||||
my_instance->src_trg->host = NULL;
|
||||
my_instance->src_trg->usize = 0;
|
||||
@ -656,7 +658,8 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
if (my_instance->trgtype & TRG_SCHEMA)
|
||||
{
|
||||
|
||||
my_instance->shm_trg = (SHM_TRIG*) malloc(sizeof(SHM_TRIG));
|
||||
my_instance->shm_trg = (SHM_TRIG*) MXS_MALLOC(sizeof(SHM_TRIG));
|
||||
MXS_ABORT_IF_NULL(my_instance->shm_trg);
|
||||
my_instance->shm_trg->objects = NULL;
|
||||
my_instance->shm_trg->size = 0;
|
||||
|
||||
@ -665,7 +668,8 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
if (my_instance->trgtype & TRG_OBJECT)
|
||||
{
|
||||
|
||||
my_instance->obj_trg = (OBJ_TRIG*) malloc(sizeof(OBJ_TRIG));
|
||||
my_instance->obj_trg = (OBJ_TRIG*) MXS_MALLOC(sizeof(OBJ_TRIG));
|
||||
MXS_ABORT_IF_NULL(my_instance->obj_trg);
|
||||
my_instance->obj_trg->objects = NULL;
|
||||
my_instance->obj_trg->size = 0;
|
||||
|
||||
@ -732,40 +736,40 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
my_instance->strict_logging = false;
|
||||
}
|
||||
}
|
||||
free(paramlist[i]->name);
|
||||
free(paramlist[i]->value);
|
||||
free(paramlist[i]);
|
||||
MXS_FREE(paramlist[i]->name);
|
||||
MXS_FREE(paramlist[i]->value);
|
||||
MXS_FREE(paramlist[i]);
|
||||
}
|
||||
|
||||
free(paramlist);
|
||||
MXS_FREE(paramlist);
|
||||
|
||||
if (my_instance->hostname == NULL)
|
||||
{
|
||||
my_instance->hostname = strdup("localhost");
|
||||
my_instance->hostname = MXS_STRDUP_A("localhost");
|
||||
}
|
||||
if (my_instance->username == NULL)
|
||||
{
|
||||
my_instance->username = strdup("guest");
|
||||
my_instance->username = MXS_STRDUP_A("guest");
|
||||
}
|
||||
if (my_instance->password == NULL)
|
||||
{
|
||||
my_instance->password = strdup("guest");
|
||||
my_instance->password = MXS_STRDUP_A("guest");
|
||||
}
|
||||
if (my_instance->vhost == NULL)
|
||||
{
|
||||
my_instance->vhost = strdup("/");
|
||||
my_instance->vhost = MXS_STRDUP_A("/");
|
||||
}
|
||||
if (my_instance->exchange == NULL)
|
||||
{
|
||||
my_instance->exchange = strdup("default_exchange");
|
||||
my_instance->exchange = MXS_STRDUP_A("default_exchange");
|
||||
}
|
||||
if (my_instance->key == NULL)
|
||||
{
|
||||
my_instance->key = strdup("key");
|
||||
my_instance->key = MXS_STRDUP_A("key");
|
||||
}
|
||||
if (my_instance->exchange_type == NULL)
|
||||
{
|
||||
my_instance->exchange_type = strdup("direct");
|
||||
my_instance->exchange_type = MXS_STRDUP_A("direct");
|
||||
}
|
||||
|
||||
if (my_instance->ssl_client_cert != NULL &&
|
||||
@ -794,9 +798,9 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
for (int x = 0; x < arrsize; x++)
|
||||
{
|
||||
free(arr[x]);
|
||||
MXS_FREE(arr[x]);
|
||||
}
|
||||
free(arr);
|
||||
MXS_FREE(arr);
|
||||
}
|
||||
}
|
||||
return (FILTER *) my_instance;
|
||||
@ -910,9 +914,9 @@ void sendMessage(void* data)
|
||||
if (err_num == AMQP_STATUS_OK)
|
||||
{
|
||||
/**Message was sent successfully*/
|
||||
free(tmp->prop);
|
||||
free(tmp->msg);
|
||||
free(tmp);
|
||||
MXS_FREE(tmp->prop);
|
||||
MXS_FREE(tmp->msg);
|
||||
MXS_FREE(tmp);
|
||||
|
||||
atomic_add(&instance->stats.n_sent, 1);
|
||||
atomic_add(&instance->stats.n_queued, -1);
|
||||
@ -948,7 +952,7 @@ void sendMessage(void* data)
|
||||
void pushMessage(MQ_INSTANCE *instance, amqp_basic_properties_t* prop, char* msg)
|
||||
{
|
||||
|
||||
mqmessage* newmsg = calloc(1, sizeof(mqmessage));
|
||||
mqmessage* newmsg = MXS_CALLOC(1, sizeof(mqmessage));
|
||||
if (newmsg)
|
||||
{
|
||||
newmsg->msg = msg;
|
||||
@ -956,9 +960,8 @@ void pushMessage(MQ_INSTANCE *instance, amqp_basic_properties_t* prop, char* msg
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR("Cannot allocate enough memory.");
|
||||
free(prop);
|
||||
free(msg);
|
||||
MXS_FREE(prop);
|
||||
MXS_FREE(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -985,23 +988,36 @@ void pushMessage(MQ_INSTANCE *instance, amqp_basic_properties_t* prop, char* msg
|
||||
static void *
|
||||
newSession(FILTER *instance, SESSION *session)
|
||||
{
|
||||
MQ_SESSION *my_session;
|
||||
MYSQL_session* sessauth;
|
||||
MYSQL_session *sessauth = session->client_dcb->data;
|
||||
char *db = sessauth->db;
|
||||
if (db)
|
||||
{
|
||||
if (strnlen(db, 128) > 0)
|
||||
{
|
||||
db = MXS_STRDUP(db);
|
||||
if (!db)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
db = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((my_session = calloc(1, sizeof(MQ_SESSION))) != NULL)
|
||||
MQ_SESSION *my_session;
|
||||
|
||||
if ((my_session = MXS_CALLOC(1, sizeof(MQ_SESSION))) != NULL)
|
||||
{
|
||||
my_session->was_query = false;
|
||||
my_session->uid = NULL;
|
||||
my_session->session = session;
|
||||
sessauth = my_session->session->client_dcb->data;
|
||||
if (sessauth->db && strnlen(sessauth->db, 128) > 0)
|
||||
{
|
||||
my_session->db = strdup(sessauth->db);
|
||||
}
|
||||
else
|
||||
{
|
||||
my_session->db = NULL;
|
||||
}
|
||||
my_session->db = db;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_FREE(db);
|
||||
}
|
||||
|
||||
return my_session;
|
||||
@ -1028,9 +1044,9 @@ static void
|
||||
freeSession(FILTER *instance, void *session)
|
||||
{
|
||||
MQ_SESSION *my_session = (MQ_SESSION *) session;
|
||||
free(my_session->uid);
|
||||
free(my_session->db);
|
||||
free(my_session);
|
||||
MXS_FREE(my_session->uid);
|
||||
MXS_FREE(my_session->db);
|
||||
MXS_FREE(my_session);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1117,10 +1133,11 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
{
|
||||
if (my_session->db)
|
||||
{
|
||||
free(my_session->db);
|
||||
MXS_FREE(my_session->db);
|
||||
}
|
||||
plen = pktlen(queue->start);
|
||||
my_session->db = calloc(plen, sizeof(char));
|
||||
my_session->db = MXS_CALLOC(plen, sizeof(char));
|
||||
MXS_ABORT_IF_NULL(my_session->db);
|
||||
memcpy(my_session->db, queue->start + 5, plen - 1);
|
||||
}
|
||||
|
||||
@ -1229,9 +1246,9 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
{
|
||||
all_remotes = false;
|
||||
}
|
||||
free(tblnames[z]);
|
||||
MXS_FREE(tblnames[z]);
|
||||
}
|
||||
free(tblnames);
|
||||
MXS_FREE(tblnames);
|
||||
|
||||
if (!schema_ok && !all_remotes && my_session->db && strlen(my_session->db) > 0)
|
||||
{
|
||||
@ -1305,9 +1322,9 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
{
|
||||
for (j = 0; j < dbcount; j++)
|
||||
{
|
||||
free(sesstbls[j]);
|
||||
MXS_FREE(sesstbls[j]);
|
||||
}
|
||||
free(sesstbls);
|
||||
MXS_FREE(sesstbls);
|
||||
dbcount = 0;
|
||||
}
|
||||
|
||||
@ -1344,17 +1361,12 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
if (my_session->uid == NULL)
|
||||
{
|
||||
|
||||
my_session->uid = calloc(33, sizeof(char));
|
||||
my_session->uid = MXS_CALLOC(33, sizeof(char));
|
||||
|
||||
if (!my_session->uid)
|
||||
{
|
||||
MXS_ERROR("Out of memory.");
|
||||
}
|
||||
else
|
||||
if (my_session->uid)
|
||||
{
|
||||
genkey(my_session->uid, 32);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (queue->next != NULL)
|
||||
@ -1367,7 +1379,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
|
||||
my_session->was_query = true;
|
||||
|
||||
if ((prop = malloc(sizeof(amqp_basic_properties_t))))
|
||||
if ((prop = MXS_MALLOC(sizeof(amqp_basic_properties_t))))
|
||||
{
|
||||
prop->_flags = AMQP_BASIC_CONTENT_TYPE_FLAG |
|
||||
AMQP_BASIC_DELIVERY_MODE_FLAG |
|
||||
@ -1379,8 +1391,6 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
prop->message_id = amqp_cstring_bytes("query");
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (success)
|
||||
{
|
||||
|
||||
@ -1396,15 +1406,13 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
sprintf(t_buf, "%lu|", (unsigned long) time(NULL));
|
||||
|
||||
int qlen = strnlen(canon_q, length) + strnlen(t_buf, 128);
|
||||
if ((combined = malloc((qlen + 1) * sizeof(char))) == NULL)
|
||||
{
|
||||
MXS_ERROR("Out of memory");
|
||||
}
|
||||
combined = MXS_MALLOC((qlen + 1) * sizeof(char));
|
||||
MXS_ABORT_IF_NULL(combined);
|
||||
strcpy(combined, t_buf);
|
||||
strncat(combined, canon_q, length);
|
||||
|
||||
pushMessage(my_instance, prop, combined);
|
||||
free(canon_q);
|
||||
MXS_FREE(canon_q);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1494,7 +1502,7 @@ unsigned int consume_leitoi(unsigned char** c)
|
||||
char* consume_lestr(unsigned char** c)
|
||||
{
|
||||
unsigned int slen = consume_leitoi(c);
|
||||
char *str = calloc((slen + 1), sizeof(char));
|
||||
char *str = MXS_CALLOC((slen + 1), sizeof(char));
|
||||
if (str)
|
||||
{
|
||||
memcpy(str, *c, slen);
|
||||
@ -1545,7 +1553,7 @@ static int clientReply(FILTER* instance, void *session, GWBUF *reply)
|
||||
|
||||
if (pkt_len > 0)
|
||||
{
|
||||
if ((prop = malloc(sizeof(amqp_basic_properties_t))))
|
||||
if ((prop = MXS_MALLOC(sizeof(amqp_basic_properties_t))))
|
||||
{
|
||||
prop->_flags = AMQP_BASIC_CONTENT_TYPE_FLAG |
|
||||
AMQP_BASIC_DELIVERY_MODE_FLAG |
|
||||
@ -1556,10 +1564,9 @@ static int clientReply(FILTER* instance, void *session, GWBUF *reply)
|
||||
prop->correlation_id = amqp_cstring_bytes(my_session->uid);
|
||||
prop->message_id = amqp_cstring_bytes("reply");
|
||||
}
|
||||
if (!(combined = calloc(GWBUF_LENGTH(reply) + 256, sizeof(char))))
|
||||
{
|
||||
MXS_ERROR("Out of memory");
|
||||
}
|
||||
|
||||
combined = MXS_CALLOC(GWBUF_LENGTH(reply) + 256, sizeof(char));
|
||||
MXS_ABORT_IF_NULL(combined);
|
||||
|
||||
memset(t_buf, 0, 128);
|
||||
sprintf(t_buf, "%lu|", (unsigned long) time(NULL));
|
||||
@ -1627,13 +1634,14 @@ static int clientReply(FILTER* instance, void *session, GWBUF *reply)
|
||||
char *tmp;
|
||||
unsigned int col_cnt = consume_leitoi(&rset);
|
||||
|
||||
tmp = calloc(256, sizeof(char));
|
||||
tmp = MXS_CALLOC(256, sizeof(char));
|
||||
MXS_ABORT_IF_NULL(tmp);
|
||||
sprintf(tmp, "Columns: %d", col_cnt);
|
||||
memcpy(combined + offset, tmp, strnlen(tmp, 256));
|
||||
offset += strnlen(tmp, 256);
|
||||
memcpy(combined + offset, "\n", 1);
|
||||
offset++;
|
||||
free(tmp);
|
||||
MXS_FREE(tmp);
|
||||
|
||||
packet_ok = 1;
|
||||
was_last = 1;
|
||||
@ -1649,7 +1657,7 @@ static int clientReply(FILTER* instance, void *session, GWBUF *reply)
|
||||
|
||||
/**Successful reply received and sent, releasing uid*/
|
||||
|
||||
free(my_session->uid);
|
||||
MXS_FREE(my_session->uid);
|
||||
my_session->uid = NULL;
|
||||
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <maxscale/alloc.h>
|
||||
#include <filter.h>
|
||||
#include <modinfo.h>
|
||||
#include <modutil.h>
|
||||
@ -20,6 +21,7 @@
|
||||
#include <string.h>
|
||||
#include <regex.h>
|
||||
#include <hint.h>
|
||||
#include <maxscale/alloc.h>
|
||||
|
||||
/**
|
||||
* @file namedserverfilter.c - a very simple regular expression based filter
|
||||
@ -143,10 +145,9 @@ GetModuleObject()
|
||||
static FILTER *
|
||||
createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
REGEXHINT_INSTANCE *my_instance;
|
||||
int cflags = REG_ICASE;
|
||||
REGEXHINT_INSTANCE *my_instance = (REGEXHINT_INSTANCE*)MXS_MALLOC(sizeof(REGEXHINT_INSTANCE));
|
||||
|
||||
if ((my_instance = malloc(sizeof(REGEXHINT_INSTANCE))) != NULL)
|
||||
if (my_instance)
|
||||
{
|
||||
my_instance->match = NULL;
|
||||
my_instance->server = NULL;
|
||||
@ -158,19 +159,19 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
if (!strcmp(params[i]->name, "match"))
|
||||
{
|
||||
my_instance->match = strdup(params[i]->value);
|
||||
my_instance->match = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "server"))
|
||||
{
|
||||
my_instance->server = strdup(params[i]->value);
|
||||
my_instance->server = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "source"))
|
||||
{
|
||||
my_instance->source = strdup(params[i]->value);
|
||||
my_instance->source = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "user"))
|
||||
{
|
||||
my_instance->user = strdup(params[i]->value);
|
||||
my_instance->user = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!filter_standard_parameter(params[i]->name))
|
||||
{
|
||||
@ -180,6 +181,8 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
}
|
||||
}
|
||||
|
||||
int cflags = REG_ICASE;
|
||||
|
||||
if (options)
|
||||
{
|
||||
for (int i = 0; options[i]; i++)
|
||||
@ -221,7 +224,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
MXS_ERROR("namedserverfilter: Invalid regular expression '%s'.\n",
|
||||
my_instance->match);
|
||||
free(my_instance->match);
|
||||
MXS_FREE(my_instance->match);
|
||||
my_instance->match = NULL;
|
||||
error = true;
|
||||
}
|
||||
@ -231,12 +234,12 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
if (my_instance->match)
|
||||
{
|
||||
regfree(&my_instance->re);
|
||||
free(my_instance->match);
|
||||
MXS_FREE(my_instance->match);
|
||||
}
|
||||
free(my_instance->server);
|
||||
free(my_instance->source);
|
||||
free(my_instance->user);
|
||||
free(my_instance);
|
||||
MXS_FREE(my_instance->server);
|
||||
MXS_FREE(my_instance->source);
|
||||
MXS_FREE(my_instance->user);
|
||||
MXS_FREE(my_instance);
|
||||
my_instance = NULL;
|
||||
}
|
||||
|
||||
@ -258,7 +261,7 @@ newSession(FILTER *instance, SESSION *session)
|
||||
REGEXHINT_SESSION *my_session;
|
||||
char *remote, *user;
|
||||
|
||||
if ((my_session = calloc(1, sizeof(REGEXHINT_SESSION))) != NULL)
|
||||
if ((my_session = MXS_CALLOC(1, sizeof(REGEXHINT_SESSION))) != NULL)
|
||||
{
|
||||
my_session->n_diverted = 0;
|
||||
my_session->n_undiverted = 0;
|
||||
@ -303,7 +306,7 @@ closeSession(FILTER *instance, void *session)
|
||||
static void
|
||||
freeSession(FILTER *instance, void *session)
|
||||
{
|
||||
free(session);
|
||||
MXS_FREE(session);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -361,7 +364,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
{
|
||||
my_session->n_undiverted++;
|
||||
}
|
||||
free(sql);
|
||||
MXS_FREE(sql);
|
||||
}
|
||||
}
|
||||
return my_session->down.routeQuery(my_session->down.instance,
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -47,6 +47,7 @@
|
||||
#include <regex.h>
|
||||
#include <string.h>
|
||||
#include <atomic.h>
|
||||
#include <maxscale/alloc.h>
|
||||
|
||||
MODULE_INFO info =
|
||||
{
|
||||
@ -173,10 +174,9 @@ GetModuleObject()
|
||||
static FILTER *
|
||||
createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
QLA_INSTANCE *my_instance;
|
||||
int i;
|
||||
QLA_INSTANCE *my_instance = (QLA_INSTANCE*) MXS_MALLOC(sizeof(QLA_INSTANCE));
|
||||
|
||||
if ((my_instance = malloc(sizeof(QLA_INSTANCE))) != NULL)
|
||||
if (my_instance)
|
||||
{
|
||||
my_instance->source = NULL;
|
||||
my_instance->userName = NULL;
|
||||
@ -187,27 +187,27 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
|
||||
if (params)
|
||||
{
|
||||
for (i = 0; params[i]; i++)
|
||||
for (int i = 0; params[i]; i++)
|
||||
{
|
||||
if (!strcmp(params[i]->name, "match"))
|
||||
{
|
||||
my_instance->match = strdup(params[i]->value);
|
||||
my_instance->match = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "exclude"))
|
||||
{
|
||||
my_instance->nomatch = strdup(params[i]->value);
|
||||
my_instance->nomatch = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "source"))
|
||||
{
|
||||
my_instance->source = strdup(params[i]->value);
|
||||
my_instance->source = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "user"))
|
||||
{
|
||||
my_instance->userName = strdup(params[i]->value);
|
||||
my_instance->userName = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "filebase"))
|
||||
{
|
||||
my_instance->filebase = strdup(params[i]->value);
|
||||
my_instance->filebase = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!filter_standard_parameter(params[i]->name))
|
||||
{
|
||||
@ -222,7 +222,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
|
||||
if (options)
|
||||
{
|
||||
for (i = 0; options[i]; i++)
|
||||
for (int i = 0; options[i]; i++)
|
||||
{
|
||||
if (!strcasecmp(options[i], "ignorecase"))
|
||||
{
|
||||
@ -258,7 +258,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
MXS_ERROR("qlafilter: Invalid regular expression '%s'"
|
||||
" for the 'match' parameter.\n",
|
||||
my_instance->match);
|
||||
free(my_instance->match);
|
||||
MXS_FREE(my_instance->match);
|
||||
my_instance->match = NULL;
|
||||
error = true;
|
||||
}
|
||||
@ -268,7 +268,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
MXS_ERROR("qlafilter: Invalid regular expression '%s'"
|
||||
" for the 'nomatch' parameter.",
|
||||
my_instance->nomatch);
|
||||
free(my_instance->nomatch);
|
||||
MXS_FREE(my_instance->nomatch);
|
||||
my_instance->nomatch = NULL;
|
||||
error = true;
|
||||
}
|
||||
@ -277,19 +277,19 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
if (my_instance->match)
|
||||
{
|
||||
free(my_instance->match);
|
||||
MXS_FREE(my_instance->match);
|
||||
regfree(&my_instance->re);
|
||||
}
|
||||
|
||||
if (my_instance->nomatch)
|
||||
{
|
||||
free(my_instance->nomatch);
|
||||
MXS_FREE(my_instance->nomatch);
|
||||
regfree(&my_instance->nore);
|
||||
}
|
||||
free(my_instance->filebase);
|
||||
free(my_instance->source);
|
||||
free(my_instance->userName);
|
||||
free(my_instance);
|
||||
MXS_FREE(my_instance->filebase);
|
||||
MXS_FREE(my_instance->source);
|
||||
MXS_FREE(my_instance->userName);
|
||||
MXS_FREE(my_instance);
|
||||
my_instance = NULL;
|
||||
}
|
||||
}
|
||||
@ -312,16 +312,11 @@ newSession(FILTER *instance, SESSION *session)
|
||||
QLA_SESSION *my_session;
|
||||
char *remote, *userName;
|
||||
|
||||
if ((my_session = calloc(1, sizeof(QLA_SESSION))) != NULL)
|
||||
if ((my_session = MXS_CALLOC(1, sizeof(QLA_SESSION))) != NULL)
|
||||
{
|
||||
if ((my_session->filename = (char *)malloc(strlen(my_instance->filebase) + 20)) == NULL)
|
||||
if ((my_session->filename = (char *)MXS_MALLOC(strlen(my_instance->filebase) + 20)) == NULL)
|
||||
{
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
MXS_ERROR("Memory allocation for qla filter "
|
||||
"file name failed due to %d, %s.",
|
||||
errno,
|
||||
strerror_r(errno, errbuf, sizeof(errbuf)));
|
||||
free(my_session);
|
||||
MXS_FREE(my_session);
|
||||
return NULL;
|
||||
}
|
||||
my_session->active = 1;
|
||||
@ -359,8 +354,8 @@ newSession(FILTER *instance, SESSION *session)
|
||||
"fileter failed due to %d, %s",
|
||||
errno,
|
||||
strerror_r(errno, errbuf, sizeof(errbuf)));
|
||||
free(my_session->filename);
|
||||
free(my_session);
|
||||
MXS_FREE(my_session->filename);
|
||||
MXS_FREE(my_session);
|
||||
my_session = NULL;
|
||||
}
|
||||
}
|
||||
@ -406,8 +401,8 @@ freeSession(FILTER *instance, void *session)
|
||||
{
|
||||
QLA_SESSION *my_session = (QLA_SESSION *) session;
|
||||
|
||||
free(my_session->filename);
|
||||
free(session);
|
||||
MXS_FREE(my_session->filename);
|
||||
MXS_FREE(session);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -467,7 +462,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
fprintf(my_session->fp, "%s,%s@%s,%s\n", buffer, my_session->user,
|
||||
my_session->remote, trim(squeeze_whitespace(ptr)));
|
||||
}
|
||||
free(ptr);
|
||||
MXS_FREE(ptr);
|
||||
}
|
||||
}
|
||||
/* Pass the query downstream */
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -21,6 +21,7 @@
|
||||
#include <string.h>
|
||||
#include <pcre2.h>
|
||||
#include <atomic.h>
|
||||
#include <maxscale/alloc.h>
|
||||
#include "maxconfig.h"
|
||||
|
||||
/**
|
||||
@ -159,11 +160,11 @@ void free_instance(REGEX_INSTANCE *instance)
|
||||
pcre2_match_data_free(instance->match_data);
|
||||
}
|
||||
|
||||
free(instance->match);
|
||||
free(instance->replace);
|
||||
free(instance->source);
|
||||
free(instance->user);
|
||||
free(instance);
|
||||
MXS_FREE(instance->match);
|
||||
MXS_FREE(instance->replace);
|
||||
MXS_FREE(instance->source);
|
||||
MXS_FREE(instance->user);
|
||||
MXS_FREE(instance);
|
||||
}
|
||||
}
|
||||
|
||||
@ -185,7 +186,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
char *logfile = NULL;
|
||||
const char *errmsg;
|
||||
|
||||
if ((my_instance = calloc(1, sizeof(REGEX_INSTANCE))) != NULL)
|
||||
if ((my_instance = MXS_CALLOC(1, sizeof(REGEX_INSTANCE))) != NULL)
|
||||
{
|
||||
my_instance->match = NULL;
|
||||
my_instance->replace = NULL;
|
||||
@ -194,19 +195,19 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
if (!strcmp(params[i]->name, "match"))
|
||||
{
|
||||
my_instance->match = strdup(params[i]->value);
|
||||
my_instance->match = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "replace"))
|
||||
{
|
||||
my_instance->replace = strdup(params[i]->value);
|
||||
my_instance->replace = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "source"))
|
||||
{
|
||||
my_instance->source = strdup(params[i]->value);
|
||||
my_instance->source = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "user"))
|
||||
{
|
||||
my_instance->user = strdup(params[i]->value);
|
||||
my_instance->user = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "log_trace"))
|
||||
{
|
||||
@ -216,9 +217,9 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
if (logfile)
|
||||
{
|
||||
free(logfile);
|
||||
MXS_FREE(logfile);
|
||||
}
|
||||
logfile = strdup(params[i]->value);
|
||||
logfile = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!filter_standard_parameter(params[i]->name))
|
||||
{
|
||||
@ -253,14 +254,14 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
MXS_ERROR("regexfilter: Failed to open file '%s'.", logfile);
|
||||
free_instance(my_instance);
|
||||
free(logfile);
|
||||
MXS_FREE(logfile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fprintf(my_instance->logfile, "\nOpened regex filter log\n");
|
||||
fflush(my_instance->logfile);
|
||||
}
|
||||
free(logfile);
|
||||
MXS_FREE(logfile);
|
||||
|
||||
if (my_instance->match == NULL || my_instance->replace == NULL)
|
||||
{
|
||||
@ -309,7 +310,7 @@ newSession(FILTER *instance, SESSION *session)
|
||||
REGEX_SESSION *my_session;
|
||||
char *remote, *user;
|
||||
|
||||
if ((my_session = calloc(1, sizeof(REGEX_SESSION))) != NULL)
|
||||
if ((my_session = MXS_CALLOC(1, sizeof(REGEX_SESSION))) != NULL)
|
||||
{
|
||||
my_session->no_change = 0;
|
||||
my_session->replacements = 0;
|
||||
@ -354,7 +355,7 @@ closeSession(FILTER *instance, void *session)
|
||||
static void
|
||||
freeSession(FILTER *instance, void *session)
|
||||
{
|
||||
free(session);
|
||||
MXS_FREE(session);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -408,7 +409,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
spinlock_acquire(&my_session->lock);
|
||||
log_match(my_instance, my_instance->match, sql, newsql);
|
||||
spinlock_release(&my_session->lock);
|
||||
free(newsql);
|
||||
MXS_FREE(newsql);
|
||||
my_session->replacements++;
|
||||
}
|
||||
else
|
||||
@ -418,7 +419,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
spinlock_release(&my_session->lock);
|
||||
my_session->no_change++;
|
||||
}
|
||||
free(sql);
|
||||
MXS_FREE(sql);
|
||||
}
|
||||
|
||||
}
|
||||
@ -485,7 +486,7 @@ regex_replace(const char *sql, pcre2_code *re, pcre2_match_data *match_data, con
|
||||
if (pcre2_match(re, (PCRE2_SPTR) sql, PCRE2_ZERO_TERMINATED, 0, 0, match_data, NULL))
|
||||
{
|
||||
result_size = strlen(sql) + strlen(replace);
|
||||
result = malloc(result_size);
|
||||
result = MXS_MALLOC(result_size);
|
||||
|
||||
while (result &&
|
||||
pcre2_substitute(re, (PCRE2_SPTR) sql, PCRE2_ZERO_TERMINATED, 0,
|
||||
@ -494,9 +495,9 @@ regex_replace(const char *sql, pcre2_code *re, pcre2_match_data *match_data, con
|
||||
(PCRE2_UCHAR*) result, (PCRE2_SIZE*) & result_size) == PCRE2_ERROR_NOMEMORY)
|
||||
{
|
||||
char *tmp;
|
||||
if ((tmp = realloc(result, (result_size *= 1.5))) == NULL)
|
||||
if ((tmp = MXS_REALLOC(result, (result_size *= 1.5))) == NULL)
|
||||
{
|
||||
free(result);
|
||||
MXS_FREE(result);
|
||||
result = NULL;
|
||||
}
|
||||
result = tmp;
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -58,6 +58,8 @@
|
||||
#include <maxscale/poll.h>
|
||||
#include <mysql_client_server_protocol.h>
|
||||
#include <housekeeper.h>
|
||||
#include <maxscale/alloc.h>
|
||||
#include <listmanager.h>
|
||||
|
||||
#define MYSQL_COM_QUIT 0x01
|
||||
#define MYSQL_COM_INITDB 0x02
|
||||
@ -209,6 +211,8 @@ int route_single_query(TEE_INSTANCE* my_instance,
|
||||
int reset_session_state(TEE_SESSION* my_session, GWBUF* buffer);
|
||||
void create_orphan(SESSION* ses);
|
||||
|
||||
extern LIST_CONFIG SESSIONlist;
|
||||
|
||||
static void
|
||||
orphan_free(void* data)
|
||||
{
|
||||
@ -293,8 +297,8 @@ orphan_free(void* data)
|
||||
tmp->session->router_session);
|
||||
|
||||
tmp->session->state = SESSION_STATE_FREE;
|
||||
free(tmp->session);
|
||||
free(tmp);
|
||||
list_free_entry(&SESSIONlist, (list_entry_t*)tmp->session);
|
||||
MXS_FREE(tmp);
|
||||
}
|
||||
|
||||
#ifdef SS_DEBUG
|
||||
@ -358,7 +362,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
TEE_INSTANCE *my_instance;
|
||||
int i;
|
||||
|
||||
if ((my_instance = calloc(1, sizeof(TEE_INSTANCE))) != NULL)
|
||||
if ((my_instance = MXS_CALLOC(1, sizeof(TEE_INSTANCE))) != NULL)
|
||||
{
|
||||
if (options)
|
||||
{
|
||||
@ -384,19 +388,19 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "match"))
|
||||
{
|
||||
my_instance->match = strdup(params[i]->value);
|
||||
my_instance->match = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "exclude"))
|
||||
{
|
||||
my_instance->nomatch = strdup(params[i]->value);
|
||||
my_instance->nomatch = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "source"))
|
||||
{
|
||||
my_instance->source = strdup(params[i]->value);
|
||||
my_instance->source = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "user"))
|
||||
{
|
||||
my_instance->userName = strdup(params[i]->value);
|
||||
my_instance->userName = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!filter_standard_parameter(params[i]->name))
|
||||
{
|
||||
@ -434,9 +438,9 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
|
||||
if (my_instance->service == NULL)
|
||||
{
|
||||
free(my_instance->match);
|
||||
free(my_instance->source);
|
||||
free(my_instance);
|
||||
MXS_FREE(my_instance->match);
|
||||
MXS_FREE(my_instance->source);
|
||||
MXS_FREE(my_instance);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -446,10 +450,10 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
MXS_ERROR("tee: Invalid regular expression '%s'"
|
||||
" for the match parameter.",
|
||||
my_instance->match);
|
||||
free(my_instance->match);
|
||||
free(my_instance->nomatch);
|
||||
free(my_instance->source);
|
||||
free(my_instance);
|
||||
MXS_FREE(my_instance->match);
|
||||
MXS_FREE(my_instance->nomatch);
|
||||
MXS_FREE(my_instance->source);
|
||||
MXS_FREE(my_instance);
|
||||
return NULL;
|
||||
}
|
||||
if (my_instance->nomatch &&
|
||||
@ -461,11 +465,11 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
if (my_instance->match)
|
||||
{
|
||||
regfree(&my_instance->re);
|
||||
free(my_instance->match);
|
||||
MXS_FREE(my_instance->match);
|
||||
}
|
||||
free(my_instance->nomatch);
|
||||
free(my_instance->source);
|
||||
free(my_instance);
|
||||
MXS_FREE(my_instance->nomatch);
|
||||
MXS_FREE(my_instance->source);
|
||||
MXS_FREE(my_instance);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@ -496,7 +500,7 @@ newSession(FILTER *instance, SESSION *session)
|
||||
goto retblock;
|
||||
}
|
||||
|
||||
HASHTABLE* ht = hashtable_alloc(100, simple_str_hash, strcmp);
|
||||
HASHTABLE* ht = hashtable_alloc(100, hashtable_item_strhash, hashtable_item_strcmp);
|
||||
bool is_loop = detect_loops(my_instance, ht, session->service);
|
||||
hashtable_free(ht);
|
||||
|
||||
@ -508,7 +512,7 @@ newSession(FILTER *instance, SESSION *session)
|
||||
goto retblock;
|
||||
}
|
||||
|
||||
if ((my_session = calloc(1, sizeof(TEE_SESSION))) != NULL)
|
||||
if ((my_session = MXS_CALLOC(1, sizeof(TEE_SESSION))) != NULL)
|
||||
{
|
||||
my_session->active = 1;
|
||||
my_session->residual = 0;
|
||||
@ -597,7 +601,7 @@ newSession(FILTER *instance, SESSION *session)
|
||||
filter_free(dummy);
|
||||
closeSession(instance, (void*) my_session);
|
||||
dcb_close(dcb);
|
||||
free(my_session);
|
||||
MXS_FREE(my_session);
|
||||
MXS_ERROR("tee: Allocating memory for"
|
||||
"dummy upstream failed."
|
||||
" Terminating session.");
|
||||
@ -608,7 +612,7 @@ newSession(FILTER *instance, SESSION *session)
|
||||
ses->tail = *dummy_upstream;
|
||||
MySQLProtocol* protocol = (MySQLProtocol*) session->client_dcb->protocol;
|
||||
my_session->use_ok = protocol->client_capabilities & (1 << 6);
|
||||
free(dummy_upstream);
|
||||
MXS_FREE(dummy_upstream);
|
||||
}
|
||||
}
|
||||
retblock:
|
||||
@ -707,7 +711,7 @@ freeSession(FILTER *instance, void *session)
|
||||
ses->router_session);
|
||||
/** Free memory of branch client session */
|
||||
ses->state = SESSION_STATE_FREE;
|
||||
free(ses);
|
||||
MXS_FREE(ses);
|
||||
/** This indicates that branch session is not available anymore */
|
||||
my_session->branch_session = NULL;
|
||||
}
|
||||
@ -724,7 +728,7 @@ freeSession(FILTER *instance, void *session)
|
||||
{
|
||||
gwbuf_free(my_session->tee_replybuf);
|
||||
}
|
||||
free(session);
|
||||
MXS_FREE(session);
|
||||
|
||||
orphan_free(NULL);
|
||||
|
||||
@ -1248,7 +1252,7 @@ GWBUF* clone_query(TEE_INSTANCE* my_instance, TEE_SESSION* my_session, GWBUF* bu
|
||||
clone = gwbuf_clone_all(buffer);
|
||||
my_session->residual = residual;
|
||||
}
|
||||
free(ptr);
|
||||
MXS_FREE(ptr);
|
||||
}
|
||||
else if (packet_is_required(buffer))
|
||||
{
|
||||
@ -1357,14 +1361,8 @@ int reset_session_state(TEE_SESSION* my_session, GWBUF* buffer)
|
||||
|
||||
void create_orphan(SESSION* ses)
|
||||
{
|
||||
orphan_session_t* orphan;
|
||||
if ((orphan = malloc(sizeof(orphan_session_t))) == NULL)
|
||||
{
|
||||
MXS_ERROR("Failed to "
|
||||
"allocate memory for orphan session struct, "
|
||||
"child session might leak memory.");
|
||||
}
|
||||
else
|
||||
orphan_session_t* orphan = MXS_MALLOC(sizeof(orphan_session_t));
|
||||
if (orphan)
|
||||
{
|
||||
orphan->session = ses;
|
||||
spinlock_acquire(&orphanLock);
|
||||
|
@ -1,26 +0,0 @@
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
add_executable(harness_ui harness_ui.c harness_common.c)
|
||||
add_executable(harness harness_util.c harness_common.c)
|
||||
target_link_libraries(harness_ui maxscale-common)
|
||||
target_link_libraries(harness maxscale-common)
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy ${ERRMSG} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/harness.cnf ${CMAKE_CURRENT_BINARY_DIR})
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/testdriver.sh ${CMAKE_CURRENT_BINARY_DIR}/testdriver.sh @ONLY)
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/hintfilter/hint_testing.cnf ${CMAKE_CURRENT_BINARY_DIR}/hintfilter/hint_testing.cnf)
|
||||
add_test(TestHintfilter testdriver.sh hintfilter/hint_testing.cnf hintfilter/hint_testing.input hintfilter/hint_testing.output hintfilter/hint_testing.expected)
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/regexfilter/regextest.cnf ${CMAKE_CURRENT_BINARY_DIR}/regexfilter/regextest.cnf)
|
||||
add_test(TestRegexfilter testdriver.sh regexfilter/regextest.cnf regexfilter/regextest.input regexfilter/regextest.output regexfilter/regextest.expected)
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fwfilter/fwtest.cnf.in ${CMAKE_CURRENT_BINARY_DIR}/fwfilter/fwtest.cnf)
|
||||
add_test(TestFwfilter1 testdriver.sh fwfilter/fwtest.cnf fwfilter/fwtest.input fwfilter/fwtest.output fwfilter/fwtest.expected)
|
||||
add_test(TestFwfilter2 testdriver.sh fwfilter/fwtest.cnf fwfilter/fwtest2.input fwfilter/fwtest2.output fwfilter/fwtest2.expected)
|
||||
|
||||
add_test(TestTeeRecursion ${CMAKE_CURRENT_SOURCE_DIR}/tee_recursion.sh
|
||||
${CMAKE_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}
|
||||
${TEST_USER}
|
||||
${TEST_PASSWORD}
|
||||
${TEST_HOST}
|
||||
${TEST_PORT})
|
@ -1,20 +0,0 @@
|
||||
Filter Test Harness
|
||||
|
||||
For a more detailed description of the filter harness, either generate the documentation or read the harness.h file.
|
||||
|
||||
Running the program without arguments enters the interactive mode. Type 'help' for a list of all commands.
|
||||
|
||||
The default values for threads and sessions are stored in the 'harness.cnf' file
|
||||
|
||||
Mandatory parameters for the command line mode are -c and -i.
|
||||
|
||||
Parameters for the command line:
|
||||
|
||||
-h Display this information
|
||||
-c Path to the MaxScale configuration file to parse for filters
|
||||
-i Name of the input file for buffers
|
||||
-o Name of the output file for results
|
||||
-q Suppress printing to stdout
|
||||
-t Number of threads
|
||||
-s Number of sessions
|
||||
-d Routing delay
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +0,0 @@
|
||||
[Firewall]
|
||||
type=filter
|
||||
module=dbfwfilter
|
||||
rules=@CMAKE_CURRENT_SOURCE_DIR@/rules
|
@ -1,8 +0,0 @@
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
@ -1,10 +0,0 @@
|
||||
delete from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
delete from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
@ -1,8 +0,0 @@
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
@ -1,8 +0,0 @@
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
@ -1,10 +0,0 @@
|
||||
select id from t1;
|
||||
select id from t1 union select name from t2;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1;
|
||||
select id from t1 union select name from t2;
|
||||
select id from t1;
|
||||
select id from t1;
|
@ -1,2 +0,0 @@
|
||||
threads=2
|
||||
sessions=4
|
@ -1,371 +0,0 @@
|
||||
#ifndef _FILTER_HARNESS_H
|
||||
#define _FILTER_HARNESS_H
|
||||
/*
|
||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
* Public License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test harness for independent testing of filters
|
||||
*
|
||||
* A test harness that feeds a GWBUF to a chain of filters and prints the results
|
||||
* either into a file or to the standard output.
|
||||
*
|
||||
* The contents of the GWBUF and the filter parameters are either manually set through
|
||||
* the command line or read from a file.
|
||||
* @verbatim
|
||||
* Options for the configuration file 'harness.cnf'':
|
||||
*
|
||||
* threads Number of threads to use when routing buffers
|
||||
* sessions Number of sessions
|
||||
*
|
||||
* Options for the command line:
|
||||
*
|
||||
* -c Path to the MaxScale configuration file to parse for filters
|
||||
* -i Name of the input file for buffers
|
||||
* -o Name of the output file for results
|
||||
* -q Suppress printing to stdout
|
||||
* -s Number of sessions
|
||||
* -t Number of threads
|
||||
* -d Routing delay, in milliseconds
|
||||
*
|
||||
*
|
||||
* Revision History
|
||||
*
|
||||
* Date Who Description
|
||||
* 01/07/14 Markus Makela Initial implementation
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <filter.h>
|
||||
#include <buffer.h>
|
||||
#include <modules.h>
|
||||
#include <modutil.h>
|
||||
#include <skygw_utils.h>
|
||||
#include <log_manager.h>
|
||||
#include <atomic.h>
|
||||
#include <ini.h>
|
||||
#include <hint.h>
|
||||
#include <modutil.h>
|
||||
#include <errno.h>
|
||||
#include <mysql_client_server_protocol.h>
|
||||
|
||||
/**
|
||||
* A single name-value pair and a link to the next item in the
|
||||
* configuration.
|
||||
*/
|
||||
typedef struct CONFIG_ITEM_T
|
||||
{
|
||||
char* name;
|
||||
char* value;
|
||||
struct CONFIG_ITEM_T* next;
|
||||
}CONFIG_ITEM;
|
||||
|
||||
/**
|
||||
*A simplified version of a MaxScale configuration context used to load filters
|
||||
* and their options.
|
||||
*/
|
||||
typedef struct CONFIG_T
|
||||
{
|
||||
char* section;
|
||||
CONFIG_ITEM* item;
|
||||
struct CONFIG_T* next;
|
||||
|
||||
}CONFIG;
|
||||
|
||||
/**
|
||||
*A structure that holds all the necessary information to emulate a working
|
||||
* filter environment.
|
||||
*/
|
||||
struct FILTERCHAIN_T
|
||||
{
|
||||
FILTER* filter; /**An instance of a particular filter*/
|
||||
FILTER_OBJECT* instance; /**Dynamically loaded module*/
|
||||
SESSION** session; /**A list of sessions*/
|
||||
DOWNSTREAM** down; /** A list of next filters downstreams*/
|
||||
UPSTREAM** up; /** A list of next filters upstreams*/
|
||||
char* name; /**Module name*/
|
||||
struct FILTERCHAIN_T* next;
|
||||
};
|
||||
|
||||
typedef struct FILTERCHAIN_T FILTERCHAIN;
|
||||
|
||||
/**
|
||||
* A container for all the filters, query buffers and user specified parameters
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int running;
|
||||
int verbose; /**Whether to print to stdout*/
|
||||
int infile; /**A file where the queries are loaded from*/
|
||||
int expected;
|
||||
int error;
|
||||
char* mod_dir; /**Module directory absolute path*/
|
||||
char* infile_name;
|
||||
int outfile; /**A file where the output of the filters is logged*/
|
||||
char* outfile_name;
|
||||
FILTERCHAIN* head; /**The head of the filter chain*/
|
||||
FILTERCHAIN* tail; /**The tail of the filter chain*/
|
||||
GWBUF** buffer; /**Buffers that are fed to the filter chain*/
|
||||
SESSION* session;
|
||||
int buffer_count;
|
||||
int session_count;
|
||||
DOWNSTREAM dummyrouter; /**Dummy downstream router for data extraction*/
|
||||
UPSTREAM dummyclient; /**Dummy downstream router for data extraction*/
|
||||
CONFIG* conf; /**Configurations loaded from a file*/
|
||||
pthread_mutex_t work_mtx; /**Mutex for buffer routing*/
|
||||
int buff_ind; /**Index of first unrouted buffer*/
|
||||
int sess_ind;/**Index of first unused session*/
|
||||
int last_ind; /**Index of last used session*/
|
||||
pthread_t* thrpool;
|
||||
int thrcount; /**Number of active threads*/
|
||||
int rt_delay; /**Delay each thread waits after routing a query, in milliseconds*/
|
||||
}HARNESS_INSTANCE;
|
||||
|
||||
static HARNESS_INSTANCE instance;
|
||||
|
||||
/**
|
||||
*A list of available actions.
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
UNDEFINED,
|
||||
RUNFILTERS,
|
||||
LOAD_FILTER,
|
||||
DELETE_FILTER,
|
||||
LOAD_CONFIG,
|
||||
SET_INFILE,
|
||||
SET_OUTFILE,
|
||||
THR_COUNT,
|
||||
SESS_COUNT,
|
||||
OK,
|
||||
QUIT
|
||||
} operation_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PACKET_OK,
|
||||
PACKET_ERROR,
|
||||
PACKET_RESULT_SET
|
||||
} packet_t;
|
||||
|
||||
typedef packet_t PACKET;
|
||||
|
||||
/**
|
||||
* Initialize the static instance.
|
||||
*/
|
||||
int harness_init(int argc,char** argv,HARNESS_INSTANCE** inst);
|
||||
|
||||
/**
|
||||
* Frees all the query buffers
|
||||
*/
|
||||
void free_buffers();
|
||||
|
||||
/**
|
||||
* Frees all the loaded filters
|
||||
*/
|
||||
void free_filters();
|
||||
|
||||
/**
|
||||
* Converts the passed string into an operation
|
||||
*
|
||||
* @param tk The string to parse
|
||||
* @return The operation to perform or UNDEFINED, if parsing failed
|
||||
*/
|
||||
operation_t user_input(char* tk);
|
||||
|
||||
/**
|
||||
*Prints a list of available commands.
|
||||
*/
|
||||
void print_help();
|
||||
|
||||
/**
|
||||
* Prints the current status of loaded filters and queries, number of threads
|
||||
* and sessions and possible output files.
|
||||
*/
|
||||
void print_status();
|
||||
|
||||
/**
|
||||
*Opens a file for reading and/or writing with adequate permissions.
|
||||
*
|
||||
* @param str Path to file
|
||||
* @param write Non-zero for write permissions, zero for read only.
|
||||
* @return The assigned file descriptor or -1 in case an error occurred
|
||||
*/
|
||||
int open_file(char* str, unsigned int write);
|
||||
|
||||
/**
|
||||
* Reads filter parameters from the command line as name-value pairs.
|
||||
*
|
||||
*@param paramc The number of parameters read is assigned to this variable
|
||||
*@return The newly allocated list of parameters with the last one being NULL
|
||||
*/
|
||||
FILTER_PARAMETER** read_params(int* paramc);
|
||||
|
||||
/**
|
||||
* Dummy endpoint for the queries of the filter chain
|
||||
*
|
||||
* Prints and logs the contents of the GWBUF after it has passed through all the filters.
|
||||
* The packet is handled as a COM_QUERY packet and the packet header is not printed.
|
||||
*/
|
||||
int routeQuery(void* instance, void* session, GWBUF* queue);
|
||||
|
||||
/**
|
||||
* Dummy endpoint for the replies of the filter chain
|
||||
*
|
||||
* Prints and logs the contents of the GWBUF after it has passed through all the filters.
|
||||
* The packet is handled as a OK packet with no message and the packet header is not printed.
|
||||
*/
|
||||
int clientReply(void* ins, void* session, GWBUF* queue);
|
||||
|
||||
/**
|
||||
*Manual input if a query string
|
||||
*
|
||||
* Reads a single query from the standard input and inserts it into a GWBUF.
|
||||
*/
|
||||
void manual_query();
|
||||
|
||||
/**
|
||||
*Loads the file pointed by @{instance.infile}
|
||||
* @return Zero if successful, non-zero if an error occurred
|
||||
*/
|
||||
int load_query();
|
||||
|
||||
/**
|
||||
* Handler for the INI file parser that builds a linked list
|
||||
* of all the sections and their name-value pairs.
|
||||
* @param user Current configuration.
|
||||
* @param section Name of the section.
|
||||
* @param name Name of the item.
|
||||
* @param value Value of the item.
|
||||
* @return Non-zero on success, zero in case parsing is finished.
|
||||
* @see load_config()
|
||||
*/
|
||||
int handler(void* user, const char* section, const char* name,const char* value);
|
||||
|
||||
/**
|
||||
* Removes all non-filter modules from the configuration
|
||||
*
|
||||
* @param conf A pointer to a configuration struct
|
||||
* @return The stripped version of the configuration
|
||||
* @see load_config()
|
||||
*/
|
||||
CONFIG* process_config(CONFIG* conf);
|
||||
|
||||
/**
|
||||
* Loads the filter module and link it to the filter chain
|
||||
*
|
||||
* The downstream is set to point to the current head of the filter chain
|
||||
*
|
||||
* @param str Name of the filter module
|
||||
* @return Pointer to the newly initialized FILTER_CHAIN element or NULL in case module loading failed
|
||||
* @see load_filter()
|
||||
*/
|
||||
FILTERCHAIN* load_filter_module(char* str);
|
||||
|
||||
/**
|
||||
* Loads a new instance of a filter and starts a new session.
|
||||
* This function assumes that the filter module is already loaded.
|
||||
* Passing NULL as the CONFIG parameter causes the parameters to be
|
||||
* read from the command line one at a time.
|
||||
*
|
||||
* @param fc The FILTERCHAIN where the new instance and session are created
|
||||
* @param cnf A configuration read from a file
|
||||
* @return 1 on success, 0 in case an error occurred
|
||||
* @see load_filter_module()
|
||||
*/
|
||||
int load_filter(FILTERCHAIN* fc, CONFIG* cnf);
|
||||
|
||||
/**
|
||||
* Reads a MaxScale configuration (or any INI file using MaxScale notation) file and loads only the filter modules in it.
|
||||
*
|
||||
* @param fname Configuration file name
|
||||
* @return Non-zero on success, zero in case an error occurred.
|
||||
*/
|
||||
int load_config(char* fname);
|
||||
|
||||
/**
|
||||
* Initializes the indexes used while routing buffers and prints the progress
|
||||
* of the routing process.
|
||||
*/
|
||||
void route_buffers();
|
||||
|
||||
/**
|
||||
* Worker function for threads.
|
||||
* Routes a query buffer if there are unrouted buffers left.
|
||||
*
|
||||
* @param thr_num ID number of the thread
|
||||
*/
|
||||
void work_buffer(void* thr_num);
|
||||
|
||||
/**
|
||||
* Generates a fake packet used to emulate a response from the backend.
|
||||
*
|
||||
* Current implementation only works with PACKET_OK and the packet has no message.
|
||||
* The caller is responsible for freeing the allocated memory by calling gwbuf_free().
|
||||
* @param pkt The packet type
|
||||
* @return The newly generated packet or NULL if an error occurred
|
||||
*/
|
||||
GWBUF* gen_packet(PACKET pkt);
|
||||
|
||||
/**
|
||||
* Process the command line parameters and the harness configuration file.
|
||||
*
|
||||
* Reads the contents of the 'harness.cnf' file and command line parameters
|
||||
* and parses them. Options are interpreted accoding to the following table.
|
||||
* If no command line arguments are given, interactive mode is used.
|
||||
*
|
||||
* By default if no input file is given or no configuration file or specific
|
||||
* filters are given, but other options are, the program exits with 0.
|
||||
*
|
||||
* Options for the configuration file 'harness.cnf'':
|
||||
*
|
||||
* threads Number of threads to use when routing buffers
|
||||
* sessions Number of sessions
|
||||
*
|
||||
* Options for the command line:
|
||||
*
|
||||
* -h Display this information
|
||||
* -c Path to the MaxScale configuration file to parse for filters
|
||||
* -i Name of the input file for buffers
|
||||
* -o Name of the output file for results
|
||||
* -q Suppress printing to stdout
|
||||
* -t Number of threads
|
||||
* -s Number of sessions
|
||||
* -d Routing delay
|
||||
*
|
||||
* @param argc Number of arguments
|
||||
* @param argv List of argument strings
|
||||
* @return 1 if successful, 0 if no input file, configuration file or specific
|
||||
* filters are given, but other options are, or if an error occurs.
|
||||
*/
|
||||
int process_opts(int argc, char** argv);
|
||||
|
||||
/**
|
||||
* Compares the contents of two files.
|
||||
* This function resets the offsets of the file descriptors and leaves them in an
|
||||
* undefined state.
|
||||
* @param a The first file
|
||||
* @param b The second file
|
||||
* @return 0 if the files do not differ and 1 if they do or an error occurred.
|
||||
*/
|
||||
int compare_files(int a, int b);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,400 +0,0 @@
|
||||
#include <harness.h>
|
||||
|
||||
int main(int argc, char** argv){
|
||||
int i;
|
||||
char buffer[256];
|
||||
char* tk;
|
||||
FILTERCHAIN* tmp_chn;
|
||||
FILTERCHAIN* del_chn;
|
||||
HARNESS_INSTANCE* hinstance;
|
||||
|
||||
if(harness_init(argc,argv,&hinstance)){
|
||||
printf("Error: Initialization failed.\n");
|
||||
MXS_ERROR("Initialization failed.\n");
|
||||
mxs_log_finish();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(instance.verbose){
|
||||
printf("\n\n\tFilter Test Harness\n\n");
|
||||
}
|
||||
|
||||
while(instance.running){
|
||||
printf("Harness> ");
|
||||
memset(buffer,0,256);
|
||||
fgets(buffer,256,stdin);
|
||||
tk = strtok(buffer," \n");
|
||||
switch(user_input(tk))
|
||||
{
|
||||
case RUNFILTERS:
|
||||
if(instance.head->next == NULL){
|
||||
printf("No filters loaded.\n");
|
||||
break;
|
||||
}
|
||||
if(instance.buffer == NULL){
|
||||
if(instance.infile<0){
|
||||
manual_query();
|
||||
}else{
|
||||
load_query();
|
||||
}
|
||||
}
|
||||
|
||||
route_buffers();
|
||||
break;
|
||||
|
||||
case LOAD_FILTER:
|
||||
|
||||
tk = strtok(NULL," \n");
|
||||
tmp_chn = load_filter_module(tk);
|
||||
if(!tmp_chn || !load_filter(tmp_chn,instance.conf)){
|
||||
printf("Error creating filter instance.\n");
|
||||
MXS_ERROR("Error creating filter instance.\n");
|
||||
}else{
|
||||
instance.head = tmp_chn;
|
||||
}
|
||||
break;
|
||||
|
||||
case DELETE_FILTER:
|
||||
|
||||
tk = strtok(NULL," \n\0");
|
||||
tmp_chn = instance.head;
|
||||
del_chn = instance.head;
|
||||
if(tk){
|
||||
if(strcmp(instance.head->name,tk) == 0){
|
||||
|
||||
instance.head = instance.head->next;
|
||||
|
||||
}else{
|
||||
|
||||
while(del_chn->next){
|
||||
|
||||
if(strcmp(del_chn->name,tk) == 0){
|
||||
|
||||
tmp_chn->next = del_chn->next;
|
||||
break;
|
||||
|
||||
}else{
|
||||
tmp_chn = del_chn;
|
||||
del_chn = del_chn->next;
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(del_chn && del_chn->next){
|
||||
|
||||
printf("Deleted %s.\n",del_chn->name);
|
||||
|
||||
if(del_chn->instance){
|
||||
|
||||
del_chn->instance->freeSession(del_chn->filter,del_chn->session);
|
||||
|
||||
}
|
||||
|
||||
free(del_chn->filter);
|
||||
free(del_chn->down);
|
||||
free(del_chn->name);
|
||||
free(del_chn);
|
||||
}else{
|
||||
printf("No matching filter found.\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case LOAD_CONFIG:
|
||||
tk = strtok(NULL," \n\0");
|
||||
if(!load_config(tk)){
|
||||
free_filters();
|
||||
}
|
||||
break;
|
||||
|
||||
case SET_INFILE:
|
||||
|
||||
tk = strtok(NULL," \n\0");
|
||||
if(instance.infile >= 0){
|
||||
close(instance.infile);
|
||||
free(instance.infile_name);
|
||||
}
|
||||
if(tk!= NULL){
|
||||
free_buffers();
|
||||
instance.infile = open_file(tk,0);
|
||||
if(instance.infile >= 0){
|
||||
load_query();
|
||||
instance.infile_name = strdup(tk);
|
||||
if(instance.verbose){
|
||||
printf("Loaded %d queries from file '%s'\n",instance.buffer_count,instance.infile_name);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
instance.infile = -1;
|
||||
printf("Queries are read from: command line\n");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SET_OUTFILE:
|
||||
|
||||
tk = strtok(NULL," \n\0");
|
||||
if(instance.outfile >= 0){
|
||||
close(instance.outfile);
|
||||
free(instance.outfile_name);
|
||||
}
|
||||
if(tk!= NULL){
|
||||
|
||||
instance.outfile = open_file(tk,1);
|
||||
if(instance.outfile >= 0){
|
||||
instance.outfile_name = strdup(tk);
|
||||
printf("Output is logged to: %s\n",tk);
|
||||
}
|
||||
}else{
|
||||
instance.outfile = -1;
|
||||
printf("Output logging disabled.\n");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SESS_COUNT:
|
||||
|
||||
tk = strtok(NULL," \n\0");
|
||||
free_buffers();
|
||||
free_filters();
|
||||
instance.session_count = atoi(tk);
|
||||
printf("Sessions set to: %d\n", instance.session_count);
|
||||
break;
|
||||
|
||||
case THR_COUNT:
|
||||
|
||||
instance.running = 0;
|
||||
pthread_mutex_unlock(&instance.work_mtx);
|
||||
for(i = 0;i<instance.thrcount;i++){
|
||||
pthread_join(instance.thrpool[i],NULL);
|
||||
}
|
||||
pthread_mutex_lock(&instance.work_mtx);
|
||||
|
||||
instance.running = 1;
|
||||
tk = strtok(NULL," \n\0");
|
||||
instance.thrcount = atoi(tk);
|
||||
void* t_thr_pool;
|
||||
|
||||
if(!(t_thr_pool = realloc(instance.thrpool,instance.thrcount * sizeof(pthread_t)))){
|
||||
printf("Error: Out of memory\n");
|
||||
MXS_ERROR("Out of memory\n");
|
||||
instance.running = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
instance.thrpool = t_thr_pool;
|
||||
intptr_t thr_num = 1;
|
||||
|
||||
for(i = 0;i<instance.thrcount;i++){
|
||||
|
||||
pthread_create(&instance.thrpool[i],
|
||||
NULL,
|
||||
(void*)work_buffer,
|
||||
(void*)thr_num++);
|
||||
|
||||
}
|
||||
printf("Threads set to: %d\n", instance.thrcount);
|
||||
|
||||
break;
|
||||
|
||||
case QUIT:
|
||||
|
||||
instance.running = 0;
|
||||
pthread_mutex_unlock(&instance.work_mtx);
|
||||
for(i = 0;i<instance.thrcount;i++){
|
||||
pthread_join(instance.thrpool[i],NULL);
|
||||
}
|
||||
break;
|
||||
case UNDEFINED:
|
||||
|
||||
printf("Command not found, enter \"help\" for a list of commands\n");
|
||||
|
||||
break;
|
||||
default:
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(instance.infile >= 0){
|
||||
close(instance.infile);
|
||||
}
|
||||
if(instance.outfile >= 0){
|
||||
close(instance.outfile);
|
||||
}
|
||||
|
||||
free_buffers();
|
||||
free_filters();
|
||||
mxs_log_finish();
|
||||
free(instance.head);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
operation_t user_input(char* tk)
|
||||
{
|
||||
|
||||
if(tk){
|
||||
|
||||
char cmpbuff[256];
|
||||
int tklen = strcspn(tk," \n\0");
|
||||
memset(cmpbuff,0,256);
|
||||
if(tklen > 0 && tklen < 256){
|
||||
strncpy(cmpbuff,tk,tklen);
|
||||
strcat(cmpbuff,"\0");
|
||||
if(strcmp(tk,"run")==0 || strcmp(tk,"r")==0){
|
||||
return RUNFILTERS;
|
||||
|
||||
}else if(strcmp(cmpbuff,"add")==0){
|
||||
return LOAD_FILTER;
|
||||
|
||||
}else if(strcmp(cmpbuff,"delete")==0){
|
||||
return DELETE_FILTER;
|
||||
|
||||
}else if(strcmp(cmpbuff,"clear")==0){
|
||||
tk = strtok(NULL," \n\0");
|
||||
if(tk && !strcmp(tk,"queries")){
|
||||
free_buffers();
|
||||
printf("Queries cleared.\n");
|
||||
}else if(tk && !strcmp(tk,"filters")){
|
||||
printf("Filters cleared.\n");
|
||||
free_filters();
|
||||
}else{
|
||||
printf("All cleared.\n");
|
||||
free_buffers();
|
||||
free_filters();
|
||||
}
|
||||
|
||||
|
||||
return OK;
|
||||
|
||||
}else if(strcmp(cmpbuff,"config")==0){
|
||||
return LOAD_CONFIG;
|
||||
|
||||
}else if(strcmp(cmpbuff,"in")==0){
|
||||
return SET_INFILE;
|
||||
|
||||
}else if(strcmp(cmpbuff,"out")==0){
|
||||
return SET_OUTFILE;
|
||||
|
||||
}else if(strcmp(cmpbuff,"exit")==0 || strcmp(cmpbuff,"quit")==0 || strcmp(cmpbuff,"q")==0){
|
||||
return QUIT;
|
||||
|
||||
}else if(strcmp(cmpbuff,"help")==0){
|
||||
print_help();
|
||||
return OK;
|
||||
}else if(strcmp(cmpbuff,"status")==0){
|
||||
print_status();
|
||||
return OK;
|
||||
}else if(strcmp(cmpbuff,"quiet")==0){
|
||||
instance.verbose = 0;
|
||||
return OK;
|
||||
}else if(strcmp(cmpbuff,"verbose")==0){
|
||||
instance.verbose = 1;
|
||||
return OK;
|
||||
}else if(strcmp(cmpbuff,"sessions")==0){
|
||||
return SESS_COUNT;
|
||||
}else if(strcmp(cmpbuff,"threads")==0){
|
||||
return THR_COUNT;
|
||||
}
|
||||
}
|
||||
}
|
||||
return UNDEFINED;
|
||||
}
|
||||
|
||||
|
||||
void print_help()
|
||||
{
|
||||
|
||||
printf("\nFilter Test Harness\n\n"
|
||||
"List of commands:\n %-32s%s\n %-32s%s\n %-32s%s\n %-32s%s\n %-32s%s\n "
|
||||
"%-32s%s\n %-32s%s\n %-32s%s\n %-32s%s\n %-32s%s\n %-32s%s\n %-32s%s\n "
|
||||
"%-32s%s\n %-32s%s\n"
|
||||
,"help","Prints this help message."
|
||||
,"run","Feeds the contents of the buffer to the filter chain."
|
||||
,"add <filter name>","Loads a filter and appeds it to the end of the chain."
|
||||
,"delete <filter name>","Deletes a filter."
|
||||
,"status","Lists all loaded filters and queries"
|
||||
,"clear","Clears the filter chain."
|
||||
,"config <file name>","Loads filter configurations from a file."
|
||||
,"in <file name>","Source file for the SQL statements."
|
||||
,"out <file name>","Destination file for the SQL statements. Defaults to stdout if no parameters were passed."
|
||||
,"threads <number>","Sets the amount of threads to use"
|
||||
,"sessions <number>","How many sessions to create for each filter. This clears all loaded filters."
|
||||
,"quiet","Print only error messages."
|
||||
,"verbose","Print everything."
|
||||
,"exit","Exit the program"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void manual_query()
|
||||
{
|
||||
char query[1024];
|
||||
unsigned int qlen;
|
||||
GWBUF** tmpbuf;
|
||||
|
||||
free_buffers();
|
||||
|
||||
printf("Enter query: ");
|
||||
fgets(query,1024,stdin);
|
||||
|
||||
qlen = strnlen(query, 1024);
|
||||
if((tmpbuf = malloc(sizeof(GWBUF*)))== NULL){
|
||||
printf("Error: cannot allocate enough memory.\n");
|
||||
MXS_ERROR("Cannot allocate enough memory.\n");
|
||||
return;
|
||||
}
|
||||
instance.buffer = tmpbuf;
|
||||
instance.buffer_count = 1;
|
||||
|
||||
instance.buffer[0] = gwbuf_alloc(qlen + 5);
|
||||
gwbuf_set_type(instance.buffer[0],GWBUF_TYPE_MYSQL);
|
||||
memcpy(instance.buffer[0]->sbuf->data + 5,query,qlen);
|
||||
|
||||
instance.buffer[0]->sbuf->data[0] = (qlen);
|
||||
instance.buffer[0]->sbuf->data[1] = (qlen << 8);
|
||||
instance.buffer[0]->sbuf->data[2] = (qlen << 16);
|
||||
instance.buffer[0]->sbuf->data[3] = 0x00;
|
||||
instance.buffer[0]->sbuf->data[4] = 0x03;
|
||||
|
||||
}
|
||||
|
||||
void print_status()
|
||||
{
|
||||
if(instance.head->filter){
|
||||
printf("Filters currently loaded:\n\n");
|
||||
|
||||
FILTERCHAIN* hd = instance.head;
|
||||
int i = 1;
|
||||
while(hd->filter){
|
||||
printf("%d: %s\n", i++, hd->name);
|
||||
hd = hd->next;
|
||||
}
|
||||
|
||||
}else{
|
||||
printf("No filters loaded.\n");
|
||||
}
|
||||
printf("\n");
|
||||
if(instance.buffer_count > 0){
|
||||
printf("%d queries loaded.\n",instance.buffer_count);
|
||||
}else{
|
||||
printf("No queries loaded.\n");
|
||||
}
|
||||
|
||||
printf("Using %d threads and %d sessions.\n",instance.thrcount,instance.session_count);
|
||||
|
||||
if(instance.infile_name){
|
||||
printf("Input is read from %s.\n",instance.infile_name);
|
||||
}
|
||||
if(instance.outfile_name){
|
||||
printf("Output is written to %s.\n",instance.outfile_name);
|
||||
}
|
||||
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
#include <my_config.h>
|
||||
#include <mysql.h>
|
||||
#include <harness.h>
|
||||
|
||||
int main(int argc,char** argv)
|
||||
{
|
||||
|
||||
static char* server_options[] = {
|
||||
"MariaDB Corporation MaxScale",
|
||||
"--datadir=./",
|
||||
"--language=./",
|
||||
"--skip-innodb",
|
||||
"--default-storage-engine=myisam",
|
||||
NULL
|
||||
};
|
||||
|
||||
const int num_elements = (sizeof(server_options) / sizeof(char *)) - 1;
|
||||
|
||||
static char* server_groups[] = {
|
||||
"embedded",
|
||||
"server",
|
||||
"server",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
HARNESS_INSTANCE* inst;
|
||||
|
||||
if(mysql_library_init(num_elements, server_options, server_groups)){
|
||||
printf("Embedded server init failed.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
if(harness_init(argc,argv,&inst) || inst->error){
|
||||
printf("Error: Initialization failed.\n");
|
||||
MXS_ERROR("Initialization failed.\n");
|
||||
mxs_log_finish();
|
||||
return 1;
|
||||
}
|
||||
|
||||
route_buffers();
|
||||
|
||||
if(inst->expected > 0){
|
||||
return compare_files(inst->outfile,inst->expected);
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
[Hint]
|
||||
type=filter
|
||||
module=hintfilter
|
@ -1,48 +0,0 @@
|
||||
select @@server_id; -- maxscale begin route to master|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id;|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id; -- maxscale route to server server3|HINT_ROUTE_TO_NAMED_SERVER|server3
|
||||
select @@server_id;|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id; -- maxscale end
|
||||
select @@server_id; -- maxscale named1 prepare route to master
|
||||
select @@server_id; -- maxscale named1 begin|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id;|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id; -- maxscale route to server server3|HINT_ROUTE_TO_NAMED_SERVER|server3
|
||||
select @@server_id;|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id; -- maxscale end
|
||||
select @@server_id; -- maxscale shorthand1 begin route to server server2|HINT_ROUTE_TO_NAMED_SERVER|server2
|
||||
select @@server_id;|HINT_ROUTE_TO_NAMED_SERVER|server2
|
||||
select @@server_id; -- maxscale route to server server3|HINT_ROUTE_TO_NAMED_SERVER|server3
|
||||
select @@server_id;|HINT_ROUTE_TO_NAMED_SERVER|server2
|
||||
select @@server_id; -- maxscale end
|
||||
select @@server_id; # maxscale begin route to master|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id;|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id; # maxscale route to server server3|HINT_ROUTE_TO_NAMED_SERVER|server3
|
||||
select @@server_id;|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id; # maxscale end
|
||||
select @@server_id; # maxscale named2 prepare route to master
|
||||
select @@server_id; # maxscale named2 begin|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id;|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id; # maxscale route to server server3|HINT_ROUTE_TO_NAMED_SERVER|server3
|
||||
select @@server_id;|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id; # maxscale end
|
||||
select @@server_id; # maxscale shorthand2 begin route to server server2|HINT_ROUTE_TO_NAMED_SERVER|server2
|
||||
select @@server_id;|HINT_ROUTE_TO_NAMED_SERVER|server2
|
||||
select @@server_id; # maxscale route to server server3|HINT_ROUTE_TO_NAMED_SERVER|server3
|
||||
select @@server_id;|HINT_ROUTE_TO_NAMED_SERVER|server2
|
||||
select @@server_id; # maxscale end
|
||||
select @@server_id/* maxscale begin route to master */;|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id;|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id/* maxscale route to server server3 */;|HINT_ROUTE_TO_NAMED_SERVER|server3
|
||||
select @@server_id;|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id/* maxscale end */;
|
||||
select @@server_id/* maxscale named3 prepare route to master */;
|
||||
select @@server_id/* maxscale named3 begin */;|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id;|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id/* maxscale route to server server3 */;|HINT_ROUTE_TO_NAMED_SERVER|server3
|
||||
select @@server_id;|HINT_ROUTE_TO_MASTER
|
||||
select @@server_id/* maxscale end */;
|
||||
select @@server_id/* maxscale shorthand3 begin route to server server2 */; |HINT_ROUTE_TO_NAMED_SERVER|server2
|
||||
select @@server_id;|HINT_ROUTE_TO_NAMED_SERVER|server2
|
||||
select @@server_id/* maxscale route to server server3 */;|HINT_ROUTE_TO_NAMED_SERVER|server3
|
||||
select @@server_id;|HINT_ROUTE_TO_NAMED_SERVER|server2
|
||||
select @@server_id/* maxscale end */;
|
@ -1,48 +0,0 @@
|
||||
select @@server_id; -- maxscale begin route to master
|
||||
select @@server_id;
|
||||
select @@server_id; -- maxscale route to server server3
|
||||
select @@server_id;
|
||||
select @@server_id; -- maxscale end
|
||||
select @@server_id; -- maxscale named1 prepare route to master
|
||||
select @@server_id; -- maxscale named1 begin
|
||||
select @@server_id;
|
||||
select @@server_id; -- maxscale route to server server3
|
||||
select @@server_id;
|
||||
select @@server_id; -- maxscale end
|
||||
select @@server_id; -- maxscale shorthand1 begin route to server server2
|
||||
select @@server_id;
|
||||
select @@server_id; -- maxscale route to server server3
|
||||
select @@server_id;
|
||||
select @@server_id; -- maxscale end
|
||||
select @@server_id; # maxscale begin route to master
|
||||
select @@server_id;
|
||||
select @@server_id; # maxscale route to server server3
|
||||
select @@server_id;
|
||||
select @@server_id; # maxscale end
|
||||
select @@server_id; # maxscale named2 prepare route to master
|
||||
select @@server_id; # maxscale named2 begin
|
||||
select @@server_id;
|
||||
select @@server_id; # maxscale route to server server3
|
||||
select @@server_id;
|
||||
select @@server_id; # maxscale end
|
||||
select @@server_id; # maxscale shorthand2 begin route to server server2
|
||||
select @@server_id;
|
||||
select @@server_id; # maxscale route to server server3
|
||||
select @@server_id;
|
||||
select @@server_id; # maxscale end
|
||||
select @@server_id/* maxscale begin route to master */;
|
||||
select @@server_id;
|
||||
select @@server_id/* maxscale route to server server3 */;
|
||||
select @@server_id;
|
||||
select @@server_id/* maxscale end */;
|
||||
select @@server_id/* maxscale named3 prepare route to master */;
|
||||
select @@server_id/* maxscale named3 begin */;
|
||||
select @@server_id;
|
||||
select @@server_id/* maxscale route to server server3 */;
|
||||
select @@server_id;
|
||||
select @@server_id/* maxscale end */;
|
||||
select @@server_id/* maxscale shorthand3 begin route to server server2 */;
|
||||
select @@server_id;
|
||||
select @@server_id/* maxscale route to server server3 */;
|
||||
select @@server_id;
|
||||
select @@server_id/* maxscale end */;
|
@ -1,9 +0,0 @@
|
||||
#! /bin/bash
|
||||
./harness -q -i hint_testing.input -c hint_testing.cnf -o hint_testing.output -t 1 -s 1 -q &>/dev/null
|
||||
diff hint_testing.expected hint_testing.output &>/dev/null
|
||||
if [[ "$?" == "0" ]]
|
||||
then
|
||||
echo "PASSED"
|
||||
else
|
||||
echo "FAILED"
|
||||
fi
|
@ -1 +0,0 @@
|
||||
SELECT * FROM test_table;
|
@ -1,5 +0,0 @@
|
||||
[Regex]
|
||||
type=filter
|
||||
module=regexfilter
|
||||
match=wrong
|
||||
replace=right
|
@ -1,3 +0,0 @@
|
||||
select * from mysql.right;
|
||||
select right from test.table;
|
||||
select * from test.table where name='right';
|
@ -1,3 +0,0 @@
|
||||
select * from mysql.wrong;
|
||||
select wrong from test.table;
|
||||
select * from test.table where name='wrong';
|
@ -1,4 +0,0 @@
|
||||
rule union_regex deny regex '.*union.*'
|
||||
rule dont_delete_everything deny no_where_clause on_queries delete|update
|
||||
rule no_wildcard deny wildcard
|
||||
users %@% match any rules union_regex dont_delete_everything no_wildcard
|
@ -1,86 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
function execute_test()
|
||||
{
|
||||
|
||||
RVAL=$(mysql --connect-timeout=5 -u $USER -p$PWD -h $HOST -P $PORT -e "select 1;"|grep -i error)
|
||||
|
||||
if [[ ! -e $MAXPID ]]
|
||||
then
|
||||
echo "Test failed: $MAXPID was not found."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ "$RVAL" != "" ]]
|
||||
then
|
||||
echo "Test failed: Query to backend didn't return an error."
|
||||
return 1
|
||||
fi
|
||||
|
||||
LAST_LOG=$(ls $BINDIR/ -1|grep error|sort|uniq|tail -n 1)
|
||||
TEST_RESULT=$(cat $BINDIR/$LAST_LOG | grep -i recursive)
|
||||
if [[ "$TEST_RESULT" != "" ]]
|
||||
then
|
||||
return 0
|
||||
fi
|
||||
echo "Test failed: Log file didn't mention tee recursion."
|
||||
return 1
|
||||
}
|
||||
|
||||
function reload_conf()
|
||||
{
|
||||
$BINDIR/bin/maxadmin --user=admin --password=mariadb reload config
|
||||
if [[ $? -ne 0 ]]
|
||||
then
|
||||
echo "Test failed: maxadmin returned a non-zero value."
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
if [[ $# -lt 6 ]]
|
||||
then
|
||||
echo "usage: $0 <build dir> <source dir>"
|
||||
exit 1
|
||||
fi
|
||||
BINDIR=$1
|
||||
SRCDIR=$2
|
||||
USER=$3
|
||||
PWD=$4
|
||||
HOST=$5
|
||||
PORT=$6
|
||||
CONF=$BINDIR/etc/maxscale.cnf
|
||||
OLDCONF=$BINDIR/etc/maxscale.cnf.old
|
||||
MAXPID=$BINDIR/log/$(ls -1 $BINDIR/log|grep maxscale)
|
||||
TEST1=$SRCDIR/server/modules/filter/test/tee_recursion1.cnf
|
||||
TEST2=$SRCDIR/server/modules/filter/test/tee_recursion2.cnf
|
||||
|
||||
$BINDIR/bin/maxadmin --user=admin --password=mariadb flush logs
|
||||
|
||||
mv $CONF $OLDCONF
|
||||
cp $TEST1 $CONF
|
||||
reload_conf
|
||||
execute_test
|
||||
T1RVAL=$?
|
||||
mv $CONF $CONF.test1
|
||||
cp $TEST2 $CONF
|
||||
reload_conf
|
||||
execute_test
|
||||
T2RVAL=$?
|
||||
mv $CONF $CONF.test2
|
||||
mv $OLDCONF $CONF
|
||||
reload_conf
|
||||
|
||||
if [[ $T1RVAL -ne 0 ]]
|
||||
then
|
||||
echo "Test 1 failed."
|
||||
exit 1
|
||||
elif [[ $T2RVAL -ne 0 ]]
|
||||
then
|
||||
echo "Test 2 failed"
|
||||
exit 1
|
||||
else
|
||||
echo "Test successful: log mentions recursive tee usage."
|
||||
fi
|
||||
|
||||
exit 0
|
@ -1,114 +0,0 @@
|
||||
[maxscale]
|
||||
threads=4
|
||||
|
||||
[MySQL Monitor]
|
||||
type=monitor
|
||||
module=mysqlmon
|
||||
servers=server1,server2,server3,server4
|
||||
user=maxuser
|
||||
passwd=maxpwd
|
||||
monitor_interval=10000
|
||||
|
||||
[RW Split Router]
|
||||
type=service
|
||||
router=readwritesplit
|
||||
servers=server1,server2,server3,server4
|
||||
user=maxuser
|
||||
passwd=maxpwd
|
||||
filters=recurse1
|
||||
|
||||
[RW Split Hint Router]
|
||||
type=service
|
||||
router=readwritesplit
|
||||
servers=server1,server2,server3,server4
|
||||
user=maxuser
|
||||
passwd=maxpwd
|
||||
filters=recurse2
|
||||
|
||||
|
||||
[Read Connection Router]
|
||||
type=service
|
||||
router=readconnroute
|
||||
router_options=master
|
||||
servers=server1
|
||||
user=maxuser
|
||||
passwd=maxpwd
|
||||
filters=recurse3
|
||||
|
||||
[recurse3]
|
||||
type=filter
|
||||
module=tee
|
||||
service=RW Split Router
|
||||
|
||||
[recurse2]
|
||||
type=filter
|
||||
module=tee
|
||||
service=Read Connection Router
|
||||
|
||||
[recurse1]
|
||||
type=filter
|
||||
module=tee
|
||||
service=RW Split Hint Router
|
||||
|
||||
|
||||
[Debug Interface]
|
||||
type=service
|
||||
router=debugcli
|
||||
|
||||
[CLI]
|
||||
type=service
|
||||
router=cli
|
||||
|
||||
[Read Connection Listener]
|
||||
type=listener
|
||||
service=Read Connection Router
|
||||
protocol=MySQLClient
|
||||
port=4008
|
||||
|
||||
[RW Split Listener]
|
||||
type=listener
|
||||
service=RW Split Router
|
||||
protocol=MySQLClient
|
||||
port=4006
|
||||
|
||||
[RW Split Hint Listener]
|
||||
type=listener
|
||||
service=RW Split Hint Router
|
||||
protocol=MySQLClient
|
||||
port=4009
|
||||
|
||||
[Debug Listener]
|
||||
type=listener
|
||||
service=Debug Interface
|
||||
protocol=telnetd
|
||||
port=4442
|
||||
|
||||
[CLI Listener]
|
||||
type=listener
|
||||
service=CLI
|
||||
protocol=maxscaled
|
||||
port=6603
|
||||
|
||||
[server1]
|
||||
type=server
|
||||
address=127.0.0.1
|
||||
port=3000
|
||||
protocol=MySQLBackend
|
||||
|
||||
[server2]
|
||||
type=server
|
||||
address=127.0.0.1
|
||||
port=3001
|
||||
protocol=MySQLBackend
|
||||
|
||||
[server3]
|
||||
type=server
|
||||
address=127.0.0.1
|
||||
port=3002
|
||||
protocol=MySQLBackend
|
||||
|
||||
[server4]
|
||||
type=server
|
||||
address=127.0.0.1
|
||||
port=3003
|
||||
protocol=MySQLBackend
|
@ -1,112 +0,0 @@
|
||||
[maxscale]
|
||||
threads=4
|
||||
|
||||
[MySQL Monitor]
|
||||
type=monitor
|
||||
module=mysqlmon
|
||||
servers=server1,server2,server3,server4
|
||||
user=maxuser
|
||||
passwd=maxpwd
|
||||
monitor_interval=10000
|
||||
|
||||
[RW Split Router]
|
||||
type=service
|
||||
router=readwritesplit
|
||||
servers=server1,server2,server3,server4
|
||||
user=maxuser
|
||||
passwd=maxpwd
|
||||
filters=recurse1|recurse2
|
||||
|
||||
[RW Split Hint Router]
|
||||
type=service
|
||||
router=readwritesplit
|
||||
servers=server1,server2,server3,server4
|
||||
user=maxuser
|
||||
passwd=maxpwd
|
||||
|
||||
[Read Connection Router]
|
||||
type=service
|
||||
router=readconnroute
|
||||
router_options=master
|
||||
servers=server1
|
||||
user=maxuser
|
||||
passwd=maxpwd
|
||||
filters=recurse3
|
||||
|
||||
[recurse3]
|
||||
type=filter
|
||||
module=tee
|
||||
service=RW Split Router
|
||||
|
||||
[recurse2]
|
||||
type=filter
|
||||
module=tee
|
||||
service=Read Connection Router
|
||||
|
||||
[recurse1]
|
||||
type=filter
|
||||
module=tee
|
||||
service=RW Split Hint Router
|
||||
|
||||
|
||||
[Debug Interface]
|
||||
type=service
|
||||
router=debugcli
|
||||
|
||||
[CLI]
|
||||
type=service
|
||||
router=cli
|
||||
|
||||
[Read Connection Listener]
|
||||
type=listener
|
||||
service=Read Connection Router
|
||||
protocol=MySQLClient
|
||||
port=4008
|
||||
|
||||
[RW Split Listener]
|
||||
type=listener
|
||||
service=RW Split Router
|
||||
protocol=MySQLClient
|
||||
port=4006
|
||||
|
||||
[RW Split Hint Listener]
|
||||
type=listener
|
||||
service=RW Split Hint Router
|
||||
protocol=MySQLClient
|
||||
port=4009
|
||||
|
||||
[Debug Listener]
|
||||
type=listener
|
||||
service=Debug Interface
|
||||
protocol=telnetd
|
||||
port=4442
|
||||
|
||||
[CLI Listener]
|
||||
type=listener
|
||||
service=CLI
|
||||
protocol=maxscaled
|
||||
port=6603
|
||||
|
||||
[server1]
|
||||
type=server
|
||||
address=127.0.0.1
|
||||
port=3000
|
||||
protocol=MySQLBackend
|
||||
|
||||
[server2]
|
||||
type=server
|
||||
address=127.0.0.1
|
||||
port=3001
|
||||
protocol=MySQLBackend
|
||||
|
||||
[server3]
|
||||
type=server
|
||||
address=127.0.0.1
|
||||
port=3002
|
||||
protocol=MySQLBackend
|
||||
|
||||
[server4]
|
||||
type=server
|
||||
address=127.0.0.1
|
||||
port=3003
|
||||
protocol=MySQLBackend
|
@ -1,11 +0,0 @@
|
||||
#! /bin/bash
|
||||
if [[ $# -lt 4 ]]
|
||||
then
|
||||
echo "Usage: $0 <config file> <input> <output> <expected>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TESTDIR=@CMAKE_CURRENT_BINARY_DIR@
|
||||
SRCDIR=@CMAKE_CURRENT_SOURCE_DIR@
|
||||
$TESTDIR/harness -i $SRCDIR/$2 -o $TESTDIR/$3 -c $TESTDIR/$1 -t 1 -s 1 -e $SRCDIR/$4
|
||||
exit $?
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -12,6 +12,7 @@
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <filter.h>
|
||||
#include <maxscale/alloc.h>
|
||||
#include <modinfo.h>
|
||||
#include <modutil.h>
|
||||
#include <atomic.h>
|
||||
@ -128,7 +129,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
TEST_INSTANCE *my_instance;
|
||||
|
||||
if ((my_instance = calloc(1, sizeof(TEST_INSTANCE))) != NULL)
|
||||
if ((my_instance = MXS_CALLOC(1, sizeof(TEST_INSTANCE))) != NULL)
|
||||
{
|
||||
my_instance->sessions = 0;
|
||||
}
|
||||
@ -148,7 +149,7 @@ newSession(FILTER *instance, SESSION *session)
|
||||
TEST_INSTANCE *my_instance = (TEST_INSTANCE *)instance;
|
||||
TEST_SESSION *my_session;
|
||||
|
||||
if ((my_session = calloc(1, sizeof(TEST_SESSION))) != NULL)
|
||||
if ((my_session = MXS_CALLOC(1, sizeof(TEST_SESSION))) != NULL)
|
||||
{
|
||||
atomic_add(&my_instance->sessions, 1);
|
||||
my_session->count = 0;
|
||||
@ -178,7 +179,7 @@ closeSession(FILTER *instance, void *session)
|
||||
static void
|
||||
freeSession(FILTER *instance, void *session)
|
||||
{
|
||||
free(session);
|
||||
MXS_FREE(session);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-01-01
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
@ -44,6 +44,7 @@
|
||||
#include <sys/time.h>
|
||||
#include <regex.h>
|
||||
#include <atomic.h>
|
||||
#include <maxscale/alloc.h>
|
||||
|
||||
MODULE_INFO info =
|
||||
{
|
||||
@ -186,10 +187,9 @@ GetModuleObject()
|
||||
static FILTER *
|
||||
createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
int i;
|
||||
TOPN_INSTANCE *my_instance;
|
||||
TOPN_INSTANCE *my_instance = (TOPN_INSTANCE*)MXS_MALLOC(sizeof(TOPN_INSTANCE));
|
||||
|
||||
if ((my_instance = malloc(sizeof(TOPN_INSTANCE))) != NULL)
|
||||
if (my_instance)
|
||||
{
|
||||
my_instance->topN = 10;
|
||||
my_instance->match = NULL;
|
||||
@ -199,7 +199,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
my_instance->filebase = NULL;
|
||||
bool error = false;
|
||||
|
||||
for (i = 0; params && params[i]; i++)
|
||||
for (int i = 0; params && params[i]; i++)
|
||||
{
|
||||
if (!strcmp(params[i]->name, "count"))
|
||||
{
|
||||
@ -207,23 +207,23 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "filebase"))
|
||||
{
|
||||
my_instance->filebase = strdup(params[i]->value);
|
||||
my_instance->filebase = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "match"))
|
||||
{
|
||||
my_instance->match = strdup(params[i]->value);
|
||||
my_instance->match = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "exclude"))
|
||||
{
|
||||
my_instance->exclude = strdup(params[i]->value);
|
||||
my_instance->exclude = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "source"))
|
||||
{
|
||||
my_instance->source = strdup(params[i]->value);
|
||||
my_instance->source = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!strcmp(params[i]->name, "user"))
|
||||
{
|
||||
my_instance->user = strdup(params[i]->value);
|
||||
my_instance->user = MXS_STRDUP_A(params[i]->value);
|
||||
}
|
||||
else if (!filter_standard_parameter(params[i]->name))
|
||||
{
|
||||
@ -237,7 +237,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
|
||||
if (options)
|
||||
{
|
||||
for (i = 0; options[i]; i++)
|
||||
for (int i = 0; options[i]; i++)
|
||||
{
|
||||
if (!strcasecmp(options[i], "ignorecase"))
|
||||
{
|
||||
@ -274,7 +274,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
" for the 'match' parameter.",
|
||||
my_instance->match);
|
||||
regfree(&my_instance->re);
|
||||
free(my_instance->match);
|
||||
MXS_FREE(my_instance->match);
|
||||
my_instance->match = NULL;
|
||||
error = true;
|
||||
}
|
||||
@ -285,7 +285,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
" for the 'nomatch' parameter.\n",
|
||||
my_instance->exclude);
|
||||
regfree(&my_instance->exre);
|
||||
free(my_instance->exclude);
|
||||
MXS_FREE(my_instance->exclude);
|
||||
my_instance->exclude = NULL;
|
||||
error = true;
|
||||
}
|
||||
@ -295,17 +295,17 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
if (my_instance->exclude)
|
||||
{
|
||||
regfree(&my_instance->exre);
|
||||
free(my_instance->exclude);
|
||||
MXS_FREE(my_instance->exclude);
|
||||
}
|
||||
if (my_instance->match)
|
||||
{
|
||||
regfree(&my_instance->re);
|
||||
free(my_instance->match);
|
||||
MXS_FREE(my_instance->match);
|
||||
}
|
||||
free(my_instance->filebase);
|
||||
free(my_instance->source);
|
||||
free(my_instance->user);
|
||||
free(my_instance);
|
||||
MXS_FREE(my_instance->filebase);
|
||||
MXS_FREE(my_instance->source);
|
||||
MXS_FREE(my_instance->user);
|
||||
MXS_FREE(my_instance);
|
||||
my_instance = NULL;
|
||||
}
|
||||
}
|
||||
@ -329,23 +329,24 @@ newSession(FILTER *instance, SESSION *session)
|
||||
int i;
|
||||
char *remote, *user;
|
||||
|
||||
if ((my_session = calloc(1, sizeof(TOPN_SESSION))) != NULL)
|
||||
if ((my_session = MXS_CALLOC(1, sizeof(TOPN_SESSION))) != NULL)
|
||||
{
|
||||
if ((my_session->filename =
|
||||
(char *) malloc(strlen(my_instance->filebase) + 20))
|
||||
(char *) MXS_MALLOC(strlen(my_instance->filebase) + 20))
|
||||
== NULL)
|
||||
{
|
||||
free(my_session);
|
||||
MXS_FREE(my_session);
|
||||
return NULL;
|
||||
}
|
||||
sprintf(my_session->filename, "%s.%d", my_instance->filebase,
|
||||
my_instance->sessions);
|
||||
atomic_add(&my_instance->sessions, 1);
|
||||
my_session->top = (TOPNQ **) calloc(my_instance->topN + 1,
|
||||
sizeof(TOPNQ *));
|
||||
my_session->top = (TOPNQ **) MXS_CALLOC(my_instance->topN + 1, sizeof(TOPNQ *));
|
||||
MXS_ABORT_IF_NULL(my_session->top);
|
||||
for (i = 0; i < my_instance->topN; i++)
|
||||
{
|
||||
my_session->top[i] = (TOPNQ *) calloc(1, sizeof(TOPNQ));
|
||||
my_session->top[i] = (TOPNQ *) MXS_CALLOC(1, sizeof(TOPNQ));
|
||||
MXS_ABORT_IF_NULL(my_session->top[i]);
|
||||
my_session->top[i]->sql = NULL;
|
||||
}
|
||||
my_session->n_statements = 0;
|
||||
@ -354,7 +355,7 @@ newSession(FILTER *instance, SESSION *session)
|
||||
my_session->current = NULL;
|
||||
if ((remote = session_get_remote(session)) != NULL)
|
||||
{
|
||||
my_session->clientHost = strdup(remote);
|
||||
my_session->clientHost = MXS_STRDUP_A(remote);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -362,7 +363,7 @@ newSession(FILTER *instance, SESSION *session)
|
||||
}
|
||||
if ((user = session_getUser(session)) != NULL)
|
||||
{
|
||||
my_session->userName = strdup(user);
|
||||
my_session->userName = MXS_STRDUP_A(user);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -469,8 +470,8 @@ freeSession(FILTER *instance, void *session)
|
||||
{
|
||||
TOPN_SESSION *my_session = (TOPN_SESSION *) session;
|
||||
|
||||
free(my_session->filename);
|
||||
free(session);
|
||||
MXS_FREE(my_session->filename);
|
||||
MXS_FREE(session);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -539,14 +540,14 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
my_session->n_statements++;
|
||||
if (my_session->current)
|
||||
{
|
||||
free(my_session->current);
|
||||
MXS_FREE(my_session->current);
|
||||
}
|
||||
gettimeofday(&my_session->start, NULL);
|
||||
my_session->current = ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(ptr);
|
||||
MXS_FREE(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -599,7 +600,7 @@ clientReply(FILTER *instance, void *session, GWBUF *reply)
|
||||
(diff.tv_sec == my_session->top[my_instance->topN - 1]->duration.tv_sec &&
|
||||
diff.tv_usec > my_session->top[my_instance->topN - 1]->duration.tv_usec)))
|
||||
{
|
||||
free(my_session->top[my_instance->topN - 1]->sql);
|
||||
MXS_FREE(my_session->top[my_instance->topN - 1]->sql);
|
||||
my_session->top[my_instance->topN - 1]->sql = my_session->current;
|
||||
my_session->top[my_instance->topN - 1]->duration = diff;
|
||||
inserted = 1;
|
||||
@ -612,7 +613,7 @@ clientReply(FILTER *instance, void *session, GWBUF *reply)
|
||||
}
|
||||
else
|
||||
{
|
||||
free(my_session->current);
|
||||
MXS_FREE(my_session->current);
|
||||
}
|
||||
my_session->current = NULL;
|
||||
}
|
||||
|
Reference in New Issue
Block a user