Merge branch 'develop' into plainrouter

This commit is contained in:
Markus Makela
2015-03-31 12:56:29 +03:00
18 changed files with 779 additions and 309 deletions

View File

@ -17,7 +17,7 @@
*/
/**
* @file fwfilter.c
* @file dbfwfilter.c
* @author Markus Mäkelä
* @date 13.2.2015
* @version 1.0.0
@ -61,11 +61,9 @@
* users NAME ... match [any|all|strict_all] rules RULE ...
*@endcode
*/
#include <my_config.h>
#include <stdint.h>
#include <ctype.h>
#include <stdio.h>
#include <fcntl.h>
#include <filter.h>
#include <string.h>
#include <atomic.h>
@ -74,13 +72,11 @@
#include <query_classifier.h>
#include <mysql_client_server_protocol.h>
#include <spinlock.h>
#include <session.h>
#include <plugin.h>
#include <skygw_types.h>
#include <skygw_debug.h>
#include <time.h>
#include <assert.h>
#include <regex.h>
MODULE_INFO info = {
MODULE_API_FILTER,
MODULE_ALPHA_RELEASE,
@ -197,7 +193,7 @@ typedef struct rulelist_t{
typedef struct user_t{
char* name;/*< Name of the user */
SPINLOCK* lock;/*< User spinlock */
SPINLOCK lock;/*< User spinlock */
QUERYSPEED* qs_limit;/*< The query speed structure unique to this user */
RULELIST* rules_or;/*< If any of these rules match the action is triggered */
RULELIST* rules_and;/*< All of these rules must match for the action to trigger */
@ -298,24 +294,27 @@ void* rlistdup(void* fval)
static void* hrulefree(void* fval)
{
USER* user = (USER*)fval;
RULELIST *ptr = user->rules_or,*tmp;
RULELIST *ptr = (RULELIST*)fval;
while(ptr){
tmp = ptr;
RULELIST *tmp = ptr;
ptr = ptr->next;
free(tmp);
}
ptr = user->rules_and;
while(ptr){
tmp = ptr;
ptr = ptr->next;
free(tmp);
}
free(user->name);
free(user);
return NULL;
}
static void* huserfree(void* fval)
{
USER* value = (USER*)fval;
hrulefree(value->rules_and);
hrulefree(value->rules_or);
hrulefree(value->rules_strict_and);
free(value->qs_limit);
free(value->name);
free(value);
return NULL;
}
/**
* Strips the single or double quotes from a string.
@ -445,7 +444,7 @@ bool check_time(char* str)
char* ptr = str;
int colons = 0,numbers = 0,dashes = 0;
while(*ptr){
while(*ptr && ptr - str < 18){
if(isdigit(*ptr)){numbers++;}
else if(*ptr == ':'){colons++;}
else if(*ptr == '-'){dashes++;}
@ -486,7 +485,7 @@ TIMERANGE* parse_time(char* str, FW_INSTANCE* instance)
tr = (TIMERANGE*)calloc(1,sizeof(TIMERANGE));
if(tr == NULL){
skygw_log_write(LOGFILE_ERROR, "fwfilter: malloc returned NULL.");
skygw_log_write(LOGFILE_ERROR, "dbfwfilter: malloc returned NULL.");
return NULL;
}
@ -499,7 +498,7 @@ TIMERANGE* parse_time(char* str, FW_INSTANCE* instance)
while(ptr - str < 19){
if(isdigit(*ptr)){
*sdest = *ptr;
}else if(*ptr == ':' ||*ptr == '-' || *ptr == '\0'){
}else if(*ptr == ':' ||*ptr == '-' || *ptr == '\0' || *ptr == ' '){
*sdest = '\0';
*idest++ = atoi(strbuffer);
sdest = strbuffer;
@ -512,7 +511,7 @@ TIMERANGE* parse_time(char* str, FW_INSTANCE* instance)
CHK_TIMES(tmptr);
if(*ptr == '\0'){
if(*ptr == '\0' || *ptr == ' '){
return tr;
}
@ -526,8 +525,8 @@ TIMERANGE* parse_time(char* str, FW_INSTANCE* instance)
sdest++;
}
return tr;
free(tr);
return NULL;
}
@ -636,13 +635,14 @@ void add_users(char* rule, FW_INSTANCE* instance)
* @param rule Rule string to parse
* @param instance The FW_FILTER instance
*/
void link_rules(char* rule, FW_INSTANCE* instance)
bool link_rules(char* orig, FW_INSTANCE* instance)
{
assert(rule != NULL && instance != NULL);
/**Apply rules to users*/
bool match_any = true;
bool rval = true;
char *rule = strdup(orig);
char *tok, *ruleptr, *userptr, *modeptr;
char *saveptr = NULL;
RULELIST* rulelist = NULL;
@ -653,16 +653,30 @@ void link_rules(char* rule, FW_INSTANCE* instance)
if((userptr == NULL || ruleptr == NULL || modeptr == NULL)||
(userptr > modeptr || userptr > ruleptr || modeptr > ruleptr)) {
skygw_log_write(LOGFILE_ERROR, "fwfilter: Rule syntax incorrect, right keywords not found in the correct order: %s",rule);
return;
skygw_log_write(LOGFILE_ERROR, "dbfwfilter: Rule syntax incorrect, right keywords not found in the correct order: %s",orig);
rval = false;
goto parse_err;
}
*modeptr++ = '\0';
*ruleptr++ = '\0';
tok = strtok_r(modeptr," ",&saveptr);
if(tok && strcmp(tok,"match") == 0){
if(tok == NULL)
{
skygw_log_write(LOGFILE_ERROR, "dbfwfilter: Rule syntax incorrect, right keywords not found in the correct order: %s",orig);
rval = false;
goto parse_err;
}
if(strcmp(tok,"match") == 0){
tok = strtok_r(NULL," ",&saveptr);
if(tok == NULL)
{
skygw_log_write(LOGFILE_ERROR, "dbfwfilter: Rule syntax incorrect, missing keyword after 'match': %s",orig);
rval = false;
goto parse_err;
}
if(strcmp(tok,"any") == 0){
match_any = true;
}else if(strcmp(tok,"all") == 0){
@ -671,28 +685,40 @@ void link_rules(char* rule, FW_INSTANCE* instance)
match_any = false;
strict = true;
}else{
skygw_log_write(LOGFILE_ERROR, "fwfilter: Rule syntax incorrect, 'match' was not followed by 'any' or 'all': %s",rule);
return;
skygw_log_write(LOGFILE_ERROR, "dbfwfilter: Rule syntax incorrect, 'match' was not followed by correct keyword: %s",orig);
rval = false;
goto parse_err;
}
}
tok = strtok_r(ruleptr," ",&saveptr);
tok = strtok_r(NULL," ",&saveptr);
while(tok)
{
RULE* rule_found = NULL;
if((rule_found = find_rule(tok,instance)) != NULL)
{
RULELIST* tmp_rl = (RULELIST*)calloc(1,sizeof(RULELIST));
tmp_rl->rule = rule_found;
tmp_rl->next = rulelist;
rulelist = tmp_rl;
}
tok = strtok_r(NULL," ",&saveptr);
}
if(tok == NULL)
{
skygw_log_write(LOGFILE_ERROR, "dbfwfilter: Rule syntax incorrect, no rules given: %s",orig);
rval = false;
goto parse_err;
}
while(tok)
{
RULE* rule_found = NULL;
if((rule_found = find_rule(tok,instance)) != NULL)
{
RULELIST* tmp_rl = (RULELIST*)calloc(1,sizeof(RULELIST));
tmp_rl->rule = rule_found;
tmp_rl->next = rulelist;
rulelist = tmp_rl;
}
else
{
skygw_log_write(LOGFILE_ERROR, "dbfwfilter: Rule syntax incorrect, could not find rule '%s'.",tok);
}
tok = strtok_r(NULL," ",&saveptr);
}
/**
* Apply this list of rules to all the listed users
@ -702,8 +728,22 @@ void link_rules(char* rule, FW_INSTANCE* instance)
userptr = strtok_r(rule," ",&saveptr);
userptr = strtok_r(NULL," ",&saveptr);
if(userptr == NULL)
{
skygw_log_write(LOGFILE_ERROR, "dbfwfilter: Rule syntax incorrect, no users given: %s",orig);
rval = false;
goto parse_err;
}
if(rulelist == NULL)
{
skygw_log_write(LOGFILE_ERROR, "dbfwfilter: Rule syntax incorrect, no rules found: %s",orig);
rval = false;
goto parse_err;
}
while(userptr)
{
{
USER* user;
RULELIST *tl = NULL,*tail = NULL;
@ -713,17 +753,12 @@ void link_rules(char* rule, FW_INSTANCE* instance)
user = (USER*)calloc(1,sizeof(USER));
if(user == NULL){
free(rulelist);
return;
}
if((user->lock = (SPINLOCK*)malloc(sizeof(SPINLOCK))) == NULL){
free(user);
free(rulelist);
return;
skygw_log_write(LOGFILE_ERROR,"Error: dbfwfilter: failed to allocate memory when parsing rules.");
rval = false;
goto parse_err;
}
spinlock_init(user->lock);
spinlock_init(&user->lock);
}
user->name = (char*)strdup(userptr);
@ -753,121 +788,179 @@ void link_rules(char* rule, FW_INSTANCE* instance)
(void *)user);
userptr = strtok_r(NULL," ",&saveptr);
}
parse_err:
free(rule);
while(rulelist)
{
RULELIST *tmp = rulelist;
rulelist = rulelist->next;
free(tmp);
}
return rval;
}
/**
* Free a TIMERANGE struct
* @param tr pointer to a TIMERANGE struct
*/
void tr_free(TIMERANGE* tr)
{
TIMERANGE *node,*tmp;
node = tr;
while(node)
{
tmp = node;
node = node->next;
free(tmp);
}
}
/**
* Parse the configuration value either as a new rule or a list of users.
* @param rule The string to parse
* @param instance The FW_FILTER instance
*/
void parse_rule(char* rule, FW_INSTANCE* instance)
bool parse_rule(char* rule, FW_INSTANCE* instance)
{
ss_dassert(rule != NULL && instance != NULL);
ss_dassert(rule != NULL && instance != NULL);
char *rulecpy = strdup(rule);
char *saveptr = NULL;
char *tok = strtok_r(rulecpy," ,",&saveptr);
bool allow,deny,mode;
RULE* ruledef = NULL;
if(tok == NULL) goto retblock;
char *rulecpy = strdup(rule);
char *saveptr = NULL;
char *tok = strtok_r(rulecpy," ,",&saveptr);
bool allow,deny,mode;
RULE* ruledef = NULL;
bool rval = true;
if(strcmp("rule",tok) == 0){ /**Define a new rule*/
if(tok == NULL)
{
skygw_log_write(LOGFILE_ERROR,"dbfwfilter: Rule parsing failed, no rule rule: %s",rule);
rval = false;
goto retblock;
}
tok = strtok_r(NULL," ,",&saveptr);
if(tok == NULL) goto retblock;
RULELIST* rlist = NULL;
ruledef = (RULE*)calloc(1,sizeof(RULE));
if(ruledef == NULL)
{
skygw_log_write(LOGFILE_ERROR,"Error : Memory allocation failed.");
goto retblock;
}
rlist = (RULELIST*)calloc(1,sizeof(RULELIST));
if(rlist == NULL)
{
free(ruledef);
skygw_log_write(LOGFILE_ERROR,"Error : Memory allocation failed.");
goto retblock;
}
ruledef->name = strdup(tok);
ruledef->type = RT_UNDEFINED;
ruledef->on_queries = QUERY_OP_UNDEFINED;
rlist->rule = ruledef;
rlist->next = instance->rules;
instance->rules = rlist;
if(strcmp("rule",tok) == 0)
{
/**Define a new rule*/
}else if(strcmp("users",tok) == 0){
tok = strtok_r(NULL," ,",&saveptr);
/**Apply rules to users*/
add_users(rule, instance);
goto retblock;
if(tok == NULL)
{
skygw_log_write(LOGFILE_ERROR,"dbfwfilter: Rule parsing failed, incomplete rule: %s",rule);
rval = false;
goto retblock;
}
else
{
skygw_log_write(LOGFILE_ERROR,"Error : Unknown token in rule file: %s",tok);
goto retblock;
}
RULELIST* rlist = NULL;
ruledef = (RULE*)calloc(1,sizeof(RULE));
if(ruledef == NULL)
{
skygw_log_write(LOGFILE_ERROR,"Error: Memory allocation failed.");
rval = false;
goto retblock;
}
rlist = (RULELIST*)calloc(1,sizeof(RULELIST));
if(rlist == NULL)
{
free(ruledef);
skygw_log_write(LOGFILE_ERROR,"Error: Memory allocation failed.");
rval = false;
goto retblock;
}
ruledef->name = strdup(tok);
ruledef->type = RT_UNDEFINED;
ruledef->on_queries = QUERY_OP_UNDEFINED;
rlist->rule = ruledef;
rlist->next = instance->rules;
instance->rules = rlist;
}else if(strcmp("users",tok) == 0)
{
/**Apply rules to users*/
add_users(rule, instance);
goto retblock;
}
else
{
skygw_log_write(LOGFILE_ERROR,"Error : Unknown token in rule file: %s",tok);
rval = false;
goto retblock;
}
tok = strtok_r(NULL, " ,",&saveptr);
if((allow = (strcmp(tok,"allow") == 0)) ||
(deny = (strcmp(tok,"deny") == 0)))
{
mode = allow ? true:false;
ruledef->allow = mode;
ruledef->type = RT_PERMISSION;
tok = strtok_r(NULL, " ,",&saveptr);
if((allow = (strcmp(tok,"allow") == 0)) ||
(deny = (strcmp(tok,"deny") == 0))){
mode = allow ? true:false;
ruledef->allow = mode;
ruledef->type = RT_PERMISSION;
tok = strtok_r(NULL, " ,",&saveptr);
while(tok){
if(strcmp(tok,"wildcard") == 0)
while(tok)
{
if(strcmp(tok,"wildcard") == 0)
{
ruledef->type = RT_WILDCARD;
}
else if(strcmp(tok,"columns") == 0)
else if(strcmp(tok,"columns") == 0)
{
STRLINK *tail = NULL,*current;
ruledef->type = RT_COLUMN;
tok = strtok_r(NULL, " ,",&saveptr);
while(tok && strcmp(tok,"at_times") != 0){
while(tok && strcmp(tok,"at_times") != 0 &&
strcmp(tok,"on_queries") != 0){
current = malloc(sizeof(STRLINK));
current->value = strdup(tok);
current->next = tail;
tail = current;
tok = strtok_r(NULL, " ,",&saveptr);
}
ruledef->data = (void*)tail;
continue;
}
else if(strcmp(tok,"at_times") == 0)
else if(strcmp(tok,"at_times") == 0)
{
tok = strtok_r(NULL, " ,",&saveptr);
TIMERANGE *tr = NULL;
bool not_valid = false;
while(tok){
if(!check_time(tok))
{
not_valid = true;
break;
}
TIMERANGE *tmp = parse_time(tok,instance);
if(IS_RVRS_TIME(tmp)){
if(tmp == NULL)
{
skygw_log_write(LOGFILE_ERROR,"dbfwfilter: Rule parsing failed, unexpected characters after time definition.");
rval = false;
tr_free(tr);
goto retblock;
}
if(IS_RVRS_TIME(tmp))
{
tmp = split_reverse_time(tmp);
}
tmp->next = tr;
@ -875,44 +968,68 @@ void parse_rule(char* rule, FW_INSTANCE* instance)
tok = strtok_r(NULL, " ,",&saveptr);
}
ruledef->active = tr;
if(not_valid)
{
continue;
}
}
else if(strcmp(tok,"regex") == 0)
else if(strcmp(tok,"regex") == 0)
{
bool escaped = false;
regex_t *re;
char* start, *str;
tok = strtok_r(NULL," ",&saveptr);
char delim = '\'';
while(*tok == '\'' || *tok == '"'){
char delim = '\'';
int n_char = 0;
while(*tok == '\'' || *tok == '"')
{
delim = *tok;
tok++;
}
start = tok;
while(isspace(*tok) || *tok == delim){
while(isspace(*tok) || *tok == delim)
{
tok++;
}
while(true){
if((*tok == delim) && !escaped){
while(n_char < 2048)
{
/** Hard-coded regex length cap */
if((*tok == delim) && !escaped)
{
break;
}
escaped = (*tok == '\\');
tok++;
n_char++;
}
if(n_char >= 2048)
{
skygw_log_write_flush(LOGFILE_ERROR, "dbfwfilter: Failed to parse rule, regular expression length is over 2048 characters.");
rval = false;
goto retblock;
}
str = calloc(((tok - start) + 1),sizeof(char));
if(str == NULL)
{
skygw_log_write_flush(LOGFILE_ERROR, "Fatal Error: malloc returned NULL.");
rval = false;
goto retblock;
}
re = (regex_t*)malloc(sizeof(regex_t));
if(re == NULL){
skygw_log_write_flush(LOGFILE_ERROR, "Fatal Error: malloc returned NULL.");
skygw_log_write_flush(LOGFILE_ERROR, "Fatal Error: malloc returned NULL.");
rval = false;
free(str);
goto retblock;
}
@ -920,8 +1037,10 @@ void parse_rule(char* rule, FW_INSTANCE* instance)
memcpy(str, start, (tok-start));
if(regcomp(re, str,REG_NOSUB)){
skygw_log_write(LOGFILE_ERROR, "fwfilter: Invalid regular expression '%s'.", str);
skygw_log_write(LOGFILE_ERROR, "dbfwfilter: Invalid regular expression '%s'.", str);
rval = false;
free(re);
goto retblock;
}
else
{
@ -931,9 +1050,9 @@ void parse_rule(char* rule, FW_INSTANCE* instance)
free(str);
}
else if(strcmp(tok,"limit_queries") == 0)
else if(strcmp(tok,"limit_queries") == 0)
{
QUERYSPEED* qs = (QUERYSPEED*)calloc(1,sizeof(QUERYSPEED));
spinlock_acquire(instance->lock);
@ -943,6 +1062,8 @@ void parse_rule(char* rule, FW_INSTANCE* instance)
tok = strtok_r(NULL," ",&saveptr);
if(tok == NULL){
free(qs);
rval = false;
skygw_log_write(LOGFILE_ERROR, "dbfwfilter: Missing parameter in limit_queries: '%s'.", rule);
goto retblock;
}
qs->limit = atoi(tok);
@ -950,41 +1071,57 @@ void parse_rule(char* rule, FW_INSTANCE* instance)
tok = strtok_r(NULL," ",&saveptr);
if(tok == NULL){
free(qs);
rval = false;
skygw_log_write(LOGFILE_ERROR, "dbfwfilter: Missing parameter in limit_queries: '%s'.", rule);
goto retblock;
}
qs->period = atof(tok);
tok = strtok_r(NULL," ",&saveptr);
if(tok == NULL){
free(qs);
rval = false;
skygw_log_write(LOGFILE_ERROR, "dbfwfilter: Missing parameter in limit_queries: '%s'.", rule);
goto retblock;
}
qs->cooldown = atof(tok);
ruledef->type = RT_THROTTLE;
ruledef->data = (void*)qs;
}
else if(strcmp(tok,"no_where_clause") == 0)
else if(strcmp(tok,"no_where_clause") == 0)
{
ruledef->type = RT_CLAUSE;
ruledef->data = (void*)mode;
}
else if(strcmp(tok,"on_operations") == 0)
else if(strcmp(tok,"on_queries") == 0)
{
tok = strtok_r(NULL," ",&saveptr);
if(!parse_querytypes(tok,ruledef)){
skygw_log_write(LOGFILE_ERROR,
"fwfilter: Invalid query type"
"requirements on where/having clauses: %s."
,tok);
}
}
tok = strtok_r(NULL," ,",&saveptr);
if(tok == NULL)
{
skygw_log_write(LOGFILE_ERROR,
"dbfwfilter: Missing parameter for 'on_queries'.");
rval = false;
goto retblock;
}
goto retblock;
if(!parse_querytypes(tok,ruledef)){
skygw_log_write(LOGFILE_ERROR,
"dbfwfilter: Invalid query type"
"requirements: %s."
,tok);
rval = false;
goto retblock;
}
}
tok = strtok_r(NULL," ,",&saveptr);
}
goto retblock;
}
retblock:
free(rulecpy);
free(rulecpy);
return rval;
}
@ -1006,7 +1143,8 @@ createInstance(char **options, FILTER_PARAMETER **params)
char *filename = NULL, *nl;
char buffer[2048];
FILE* file;
bool err = false;
if ((my_instance = calloc(1, sizeof(FW_INSTANCE))) == NULL ||
(my_instance->lock = (SPINLOCK*)malloc(sizeof(SPINLOCK))) == NULL){
skygw_log_write(LOGFILE_ERROR, "Memory allocation for firewall filter failed.");
@ -1021,7 +1159,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
return NULL;
}
hashtable_memory_fns(ht,(HASHMEMORYFN)strdup,NULL,(HASHMEMORYFN)free,hrulefree);
hashtable_memory_fns(ht,(HASHMEMORYFN)strdup,NULL,(HASHMEMORYFN)free,huserfree);
my_instance->htable = ht;
my_instance->def_op = true;
@ -1077,19 +1215,41 @@ createInstance(char **options, FILTER_PARAMETER **params)
*nl = '\0';
}
parse_rule(buffer,my_instance);
if(!parse_rule(buffer,my_instance))
{
fclose(file);
err = true;
goto retblock;
}
}
fclose(file);
/**Apply the rules to users*/
ptr = my_instance->userstrings;
while(ptr){
link_rules(ptr->value,my_instance);
tmp = ptr;
ptr = ptr->next;
free(tmp->value);
free(tmp);
if(!link_rules(ptr->value,my_instance))
{
skygw_log_write(LOGFILE_ERROR,"dbfwfilter: Failed to parse rule: %s",ptr->value);
err = true;
}
tmp = ptr;
ptr = ptr->next;
free(tmp->value);
free(tmp);
}
retblock:
if(err)
{
hrulefree(my_instance->rules);
hashtable_free(my_instance->htable);
free(my_instance);
my_instance = NULL;
}
return (FILTER *)my_instance;
@ -1340,7 +1500,7 @@ bool rule_matches(FW_INSTANCE* my_instance, FW_SESSION* my_session, GWBUF *queue
if(!rulelist->rule->allow){
msg = strdup("Permission denied, query matched regular expression.");
skygw_log_write(LOGFILE_TRACE, "fwfilter: rule '%s': regex matched on query",rulelist->rule->name);
skygw_log_write(LOGFILE_TRACE, "dbfwfilter: rule '%s': regex matched on query",rulelist->rule->name);
goto queryresolved;
}else{
break;
@ -1353,7 +1513,7 @@ bool rule_matches(FW_INSTANCE* my_instance, FW_SESSION* my_session, GWBUF *queue
if(!rulelist->rule->allow){
matches = true;
msg = strdup("Permission denied at this time.");
skygw_log_write(LOGFILE_TRACE, "fwfilter: rule '%s': query denied at: %s",rulelist->rule->name,asctime(tm_now));
skygw_log_write(LOGFILE_TRACE, "dbfwfilter: rule '%s': query denied at: %s",rulelist->rule->name,asctime(tm_now));
goto queryresolved;
}else{
break;
@ -1376,7 +1536,7 @@ bool rule_matches(FW_INSTANCE* my_instance, FW_SESSION* my_session, GWBUF *queue
if(!rulelist->rule->allow){
sprintf(emsg,"Permission denied to column '%s'.",strln->value);
skygw_log_write(LOGFILE_TRACE, "fwfilter: rule '%s': query targets forbidden column: %s",rulelist->rule->name,strln->value);
skygw_log_write(LOGFILE_TRACE, "dbfwfilter: rule '%s': query targets forbidden column: %s",rulelist->rule->name,strln->value);
msg = strdup(emsg);
goto queryresolved;
}else{
@ -1406,7 +1566,7 @@ bool rule_matches(FW_INSTANCE* my_instance, FW_SESSION* my_session, GWBUF *queue
matches = true;
msg = strdup("Usage of wildcard denied.");
skygw_log_write(LOGFILE_TRACE, "fwfilter: rule '%s': query contains a wildcard.",rulelist->rule->name);
skygw_log_write(LOGFILE_TRACE, "dbfwfilter: rule '%s': query contains a wildcard.",rulelist->rule->name);
goto queryresolved;
}
}
@ -1424,9 +1584,9 @@ bool rule_matches(FW_INSTANCE* my_instance, FW_SESSION* my_session, GWBUF *queue
rule_qs = (QUERYSPEED*)rulelist->rule->data;
spinlock_release(my_instance->lock);
spinlock_acquire(user->lock);
spinlock_acquire(&user->lock);
queryspeed = user->qs_limit;
spinlock_release(user->lock);
spinlock_release(&user->lock);
while(queryspeed){
if(queryspeed->id == rule_qs->id){
@ -1457,7 +1617,7 @@ bool rule_matches(FW_INSTANCE* my_instance, FW_SESSION* my_session, GWBUF *queue
double blocked_for = queryspeed->cooldown - difftime(time_now,queryspeed->triggered);
sprintf(emsg,"Queries denied for %f seconds",blocked_for);
skygw_log_write(LOGFILE_TRACE, "fwfilter: rule '%s': user denied for %f seconds",rulelist->rule->name,blocked_for);
skygw_log_write(LOGFILE_TRACE, "dbfwfilter: rule '%s': user denied for %f seconds",rulelist->rule->name,blocked_for);
msg = strdup(emsg);
matches = true;
@ -1478,7 +1638,7 @@ bool rule_matches(FW_INSTANCE* my_instance, FW_SESSION* my_session, GWBUF *queue
queryspeed->active = true;
skygw_log_write(LOGFILE_TRACE,
"fwfilter: rule '%s': query limit triggered (%d queries in %f seconds), denying queries from user for %f seconds.",
"dbfwfilter: rule '%s': query limit triggered (%d queries in %f seconds), denying queries from user for %f seconds.",
rulelist->rule->name,
queryspeed->limit,
queryspeed->period,
@ -1508,7 +1668,7 @@ bool rule_matches(FW_INSTANCE* my_instance, FW_SESSION* my_session, GWBUF *queue
{
matches = true;
msg = strdup("Required WHERE/HAVING clause is missing.");
skygw_log_write(LOGFILE_TRACE, "fwfilter: rule '%s': query has no where/having clause, query is denied.",
skygw_log_write(LOGFILE_TRACE, "dbfwfilter: rule '%s': query has no where/having clause, query is denied.",
rulelist->rule->name);
}
break;
@ -1600,6 +1760,7 @@ bool check_match_any(FW_INSTANCE* my_instance, FW_SESSION* my_session, GWBUF *qu
bool check_match_all(FW_INSTANCE* my_instance, FW_SESSION* my_session, GWBUF *queue, USER* user,bool strict_all)
{
bool is_sql, rval = true;
bool have_active_rule = false;
int qlen;
unsigned char* memptr = (unsigned char*)queue->start;
char *fullquery = NULL,*ptr;
@ -1640,7 +1801,8 @@ bool check_match_all(FW_INSTANCE* my_instance, FW_SESSION* my_session, GWBUF *qu
rulelist = rulelist->next;
continue;
}
have_active_rule = true;
if(!rule_matches(my_instance,my_session,queue,user,rulelist,fullquery)){
rval = false;
@ -1650,6 +1812,12 @@ bool check_match_all(FW_INSTANCE* my_instance, FW_SESSION* my_session, GWBUF *qu
rulelist = rulelist->next;
}
if(!have_active_rule)
{
/** No active rules */
rval = false;
}
retblock:
free(fullquery);

View File

@ -1063,6 +1063,7 @@ clientReply (FILTER* instance, void *session, GWBUF *reply)
if(!my_session->active)
{
skygw_log_write(LOGFILE_TRACE,"Tee: Failed to return reply, session is closed");
gwbuf_free(reply);
rc = 0;
if(my_session->waiting[PARENT])
@ -1104,6 +1105,7 @@ clientReply (FILTER* instance, void *session, GWBUF *reply)
if(my_session->replies[branch] == 0)
{
skygw_log_write(LOGFILE_TRACE,"Tee: First reply to a query for [%s].",branch == PARENT ? "PARENT":"CHILD");
/* Reply is in a single packet if it is an OK, ERR or LOCAL_INFILE packet.
* Otherwise the reply is a result set and the amount of packets is unknown.
*/
@ -1116,6 +1118,11 @@ clientReply (FILTER* instance, void *session, GWBUF *reply)
{
flags = get_response_flags(ptr,true);
more_results = (flags & 0x08) && my_session->client_multistatement;
if(more_results)
{
skygw_log_write(LOGFILE_TRACE,
"Tee: [%s] waiting for more results.",branch == PARENT ? "PARENT":"CHILD");
}
}
}
#ifdef SS_DEBUG

View File

@ -159,7 +159,20 @@ typedef struct subservice_t{
int state;
int n_res_waiting;
bool mapped;
}SUBSERVICE;
}SUBSERVICE;
/**
* Bitmask values for the router session's initialization. These values are used
* to prevent responses from internal commands being forwarded to the client.
*/
typedef enum shard_init_mask
{
INIT_READY = 0x0,
INIT_MAPPING = 0x1,
INIT_USE_DB = 0x02,
INIT_UNINT = 0x04
} shard_init_mask_t;
/**
* The client session structure used within this router.
@ -172,8 +185,8 @@ struct router_client_session {
int rses_versno; /*< even = no active update, else odd. not used 4/14 */
bool rses_closed; /*< true when closeSession is called */
DCB* rses_client_dcb;
DCB* dummy_dcb; /* DCB used to send the client write messages from the router itself */
DCB* queue_dcb; /* DCB used to send queued queries to the router */
DCB* replydcb; /* DCB used to send the client write messages from the router itself */
DCB* routedcb; /* DCB used to send queued queries to the router */
MYSQL_session* rses_mysql_session;
/** Properties listed by their type */
rses_property_t* rses_properties[RSES_PROP_TYPE_COUNT];
@ -190,6 +203,8 @@ struct router_client_session {
bool hash_init;
SESSION* session;
GWBUF* queue;
char connect_db[MYSQL_DATABASE_MAXLEN+1]; /*< Database the user was trying to connect to */
shard_init_mask_t init; /*< Initialization state bitmask */
#if defined(SS_DEBUG)
skygw_chk_t rses_chk_tail;
#endif

View File

@ -530,6 +530,12 @@ static int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue) {
if (auth_ret == 0) {
dcb->user = strdup(client_data->user);
}
else
{
skygw_log_write(LOGFILE_ERROR,
"%s: login attempt for user '%s', authentication failed.",
dcb->service->name, username);
}
/* let's free the auth_token now */
if (auth_token) {
@ -900,7 +906,7 @@ int gw_read_client_event(
dcb,
ERRACT_NEW_CONNECTION,
&succp);
free(errbuf);
gwbuf_free(errbuf);
/**
* If there are not enough backends close
* session

View File

@ -1530,14 +1530,20 @@ int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_password,
* user@% not found.
*/
LOGIF(LD,
(skygw_log_write_flush(
LOGFILE_DEBUG,
"%lu [MySQL Client Auth], user [%s@%s] not existent",
pthread_self(),
key.user,
dcb->remote)));
break;
LOGIF(LD,
(skygw_log_write_flush(
LOGFILE_DEBUG,
"%lu [MySQL Client Auth], user [%s@%s] not existent",
pthread_self(),
key.user,
dcb->remote)));
LOGIF(LT,skygw_log_write_flush(
LOGFILE_ERROR,
"Authentication Failed: user [%s@%s] not found.",
key.user,
dcb->remote));
break;
}
break;

View File

@ -89,6 +89,8 @@
#include <mysql_client_server_protocol.h>
#include "modutil.h"
/** Defined in log_manager.cc */
extern int lm_enabled_logfiles_bitmask;
extern size_t log_ses_count[];
@ -535,6 +537,7 @@ BACKEND *master_host = NULL;
pthread_self(),
candidate->server->port,
candidate->current_connection_count)));
/*
* Open a backend connection, putting the DCB for this
* connection in the client_rses->backend_dcb
@ -564,7 +567,13 @@ BACKEND *master_host = NULL;
spinlock_release(&inst->lock);
CHK_CLIENT_RSES(client_rses);
skygw_log_write(
LOGFILE_TRACE,
"Readconnroute: New session for server %s. "
"Connections : %d",
candidate->server->unique_name,
candidate->current_connection_count);
return (void *)client_rses;
}
@ -718,10 +727,19 @@ routeQuery(ROUTER *instance, void *router_session, GWBUF *queue)
"Error : Failed to route MySQL command %d to backend "
"server.",
mysql_command)));
skygw_log_write(
LOGFILE_ERROR,
"Error : Failed to route MySQL command %d to backend "
"server %s.",
mysql_command,
router_cli_ses->backend->server->unique_name);
rc = 0;
goto return_rc;
}
char* trc = NULL;
switch(mysql_command) {
case MYSQL_COM_CHANGE_USER:
rc = backend_dcb->func.auth(
@ -730,7 +748,8 @@ routeQuery(ROUTER *instance, void *router_session, GWBUF *queue)
backend_dcb->session,
queue);
break;
case MYSQL_COM_QUERY:
LOGIF(LOGFILE_TRACE,(trc = modutil_get_SQL(queue)));
default:
rc = backend_dcb->func.write(backend_dcb, queue);
break;
@ -745,6 +764,15 @@ routeQuery(ROUTER *instance, void *router_session, GWBUF *queue)
mysql_command,
backend_dcb,
rc)));
LOGIF(LOGFILE_TRACE,skygw_log_write(
LOGFILE_TRACE,
"Routed command [%#x] to '%s'%s%s",
mysql_command,
backend_dcb->server->unique_name,
trc?": ":".",
trc?trc:""));
free(trc);
return_rc:
return rc;
}

View File

@ -402,7 +402,7 @@ int gen_databaselist(ROUTER_INSTANCE* inst, ROUTER_CLIENT_SES* session)
rval);
}
}
gwbuf_free(buffer);
return !rval;
}
@ -514,6 +514,10 @@ char* get_shard_target_name(ROUTER_INSTANCE* router, ROUTER_CLIENT_SES* client,
*/
rval = (char*) hashtable_fetch(ht, client->rses_mysql_session->db);
if(rval)
{
skygw_log_write(LOGFILE_TRACE,"schemarouter: Using active database '%s'",client->rses_mysql_session->db);
}
}
return rval;
@ -1932,6 +1936,7 @@ static int routeQuery(
*/
route_target = TARGET_ANY;
skygw_log_write(LOGFILE_TRACE,"schemarouter: Routing query to first available backend.");
}
else
@ -2008,6 +2013,9 @@ static int routeQuery(
/**No valid backends alive*/
skygw_log_write(LOGFILE_TRACE,"schemarouter: No backends are running");
skygw_log_write(LOGFILE_ERROR,
"Error: Schemarouter: Failed to route query, "
"no backends are available.");
rses_end_locked_router_action(router_cli_ses);
ret = 0;
goto retblock;
@ -2215,6 +2223,7 @@ static void clientReply (
*/
if (!rses_begin_locked_router_action(router_cli_ses))
{
while((writebuf = gwbuf_consume(writebuf,gwbuf_length(writebuf))));
goto lock_failed;
}
/** Holding lock ensures that router session remains open */
@ -2244,6 +2253,7 @@ static void clientReply (
if (!rses_begin_locked_router_action(router_cli_ses))
{
/** Log to debug that router was closed */
while((writebuf = gwbuf_consume(writebuf,gwbuf_length(writebuf))));
goto lock_failed;
}
bref = get_bref_from_dcb(router_cli_ses, backend_dcb);
@ -2252,6 +2262,7 @@ static void clientReply (
{
/** Unlock router session */
rses_end_locked_router_action(router_cli_ses);
while((writebuf = gwbuf_consume(writebuf,gwbuf_length(writebuf))));
goto lock_failed;
}
@ -2299,7 +2310,7 @@ static void clientReply (
}
}
gwbuf_free(writebuf);
while((writebuf = gwbuf_consume(writebuf,gwbuf_length(writebuf))));
if(mapped)
{
@ -2322,7 +2333,10 @@ static void clientReply (
router_cli_ses->connect_db);
router_cli_ses->rses_closed = true;
if(router_cli_ses->queue)
gwbuf_free(router_cli_ses->queue);
{
while((router_cli_ses->queue = gwbuf_consume(
router_cli_ses->queue,gwbuf_length(router_cli_ses->queue))));
}
rses_end_locked_router_action(router_cli_ses);
return;
}
@ -2376,7 +2390,7 @@ static void clientReply (
{
GWBUF* tmp = router_cli_ses->queue;
router_cli_ses->queue = router_cli_ses->queue->next;
tmp->next = NULL;
tmp->next = NULL;
char* querystr = modutil_get_SQL(tmp);
skygw_log_write(LOGFILE_DEBUG,"schemarouter: Sending queued buffer for session %p: %s",
router_cli_ses->rses_client_dcb->session,
@ -2416,6 +2430,8 @@ static void clientReply (
strcpy(router_cli_ses->rses_mysql_session->db,router_cli_ses->connect_db);
ss_dassert(router_cli_ses->init == INIT_READY);
rses_end_locked_router_action(router_cli_ses);
if(writebuf)
while((writebuf = gwbuf_consume(writebuf,gwbuf_length(writebuf))));
return;
}

View File

@ -119,7 +119,6 @@ static route_target_t get_shard_route_target(
static uint8_t getCapabilities(ROUTER* inst, void* router_session);
//bool parse_db_ignore_list(ROUTER_INSTANCE* router, char* param);
static void subsvc_clear_state(SUBSERVICE* svc,subsvc_state_t state);
static void subsvc_set_state(SUBSERVICE* svc,subsvc_state_t state);
static bool get_shard_subsvc(SUBSERVICE** subsvc,ROUTER_CLIENT_SES* session,char* target);
@ -414,8 +413,14 @@ bool subsvc_is_valid(SUBSERVICE* sub)
return false;
}
/**
* Map the databases of all subservices.
* @param inst router instance
* @param session router session
* @return 0 on success, 1 on error
*/
int
gen_tablelist(ROUTER_INSTANCE* inst, ROUTER_CLIENT_SES* session)
gen_subsvc_dblist(ROUTER_INSTANCE* inst, ROUTER_CLIENT_SES* session)
{
const char* query = "SHOW DATABASES;";
GWBUF *buffer, *clone;
@ -475,7 +480,6 @@ get_shard_target_name(ROUTER_INSTANCE* router, ROUTER_CLIENT_SES* client, GWBUF*
if(sz > 0)
{
has_dbs = true;
for(i = 0; i < sz; i++)
{
@ -489,9 +493,8 @@ get_shard_target_name(ROUTER_INSTANCE* router, ROUTER_CLIENT_SES* client, GWBUF*
else
{
skygw_log_write(LOGFILE_TRACE,"shardrouter: Query targets database '%s' on server '%s",dbnms[i],rval);
has_dbs = true;
}
for(j = i; j < sz; j++) free(dbnms[j]);
break;
}
free(dbnms[i]);
}
@ -554,6 +557,10 @@ get_shard_target_name(ROUTER_INSTANCE* router, ROUTER_CLIENT_SES* client, GWBUF*
*/
rval = (char*) hashtable_fetch(ht, client->rses_mysql_session->db);
if(rval)
{
skygw_log_write(LOGFILE_TRACE,"shardrouter: Using active database '%s'",client->rses_mysql_session->db);
}
}
return rval;
@ -612,64 +619,160 @@ filterReply(FILTER* instance, void *session, GWBUF *reply)
ROUTER_CLIENT_SES* rses = (ROUTER_CLIENT_SES*) instance;
SUBSERVICE* subsvc;
int i, rv = 1;
bool mapped = true;
sescmd_cursor_t* scur;
GWBUF* tmp = NULL;
skygw_log_write_flush(LOGFILE_TRACE,"shardrouter: filterReply mapped: %s",rses->hash_init ? "true" : "false");
if(!rses_begin_locked_router_action(rses))
{
tmp = reply;
while((tmp = gwbuf_consume(tmp,gwbuf_length(tmp))));
return 0;
}
subsvc = get_subsvc_from_ses(rses, session);
if(SUBSVC_IS_WAITING(subsvc))
if(rses->init & INIT_MAPPING)
{
subsvc_clear_state(subsvc, SUBSVC_WAITING_RESULT);
bool mapped = true, logged = false;
int i;
for(i = 0; i < rses->n_subservice; i++)
{
if(subsvc->session == rses->subservice[i]->session &&
!SUBSVC_IS_MAPPED(rses->subservice[i]))
{
rses->subservice[i]->state |= SUBSVC_MAPPED;
parse_mapping_response(rses,
rses->subservice[i]->service->name,
reply);
}
if(SUBSVC_IS_OK(rses->subservice[i]) &&
!SUBSVC_IS_MAPPED(rses->subservice[i]))
{
mapped = false;
if(!logged)
{
/*
skygw_log_write(LOGFILE_DEBUG,"schemarouter: Still waiting for reply to SHOW DATABASES from %s for session %p",
bkrf[i].bref_backend->backend_server->unique_name,
rses->rses_client_dcb->session);
*/
logged = true;
}
}
}
if(mapped)
{
/*
* Check if the session is reconnecting with a database name
* that is not in the hashtable. If the database is not found
* then close the session.
*/
rses->init &= ~INIT_MAPPING;
if(rses->init & INIT_USE_DB)
{
char* target;
if((target = hashtable_fetch(rses->dbhash,
rses->connect_db)) == NULL)
{
skygw_log_write_flush(LOGFILE_TRACE,"schemarouter: Connecting to a non-existent database '%s'",
rses->connect_db);
rses->rses_closed = true;
if(rses->queue)
{
while((rses->queue = gwbuf_consume(
rses->queue,gwbuf_length(rses->queue))));
}
rses_end_locked_router_action(rses);
goto retblock;
}
/* Send a COM_INIT_DB packet to the server with the right database
* and set it as the client's active database */
unsigned int qlen;
GWBUF* buffer;
qlen = strlen(rses->connect_db);
buffer = gwbuf_alloc(qlen + 5);
if(buffer == NULL)
{
skygw_log_write_flush(LOGFILE_ERROR,"Error : Buffer allocation failed.");
rses->rses_closed = true;
if(rses->queue)
gwbuf_free(rses->queue);
goto retblock;
}
gw_mysql_set_byte3((unsigned char*)buffer->start,qlen+1);
gwbuf_set_type(buffer,GWBUF_TYPE_MYSQL);
*((unsigned char*)buffer->start + 3) = 0x0;
*((unsigned char*)buffer->start + 4) = 0x2;
memcpy(buffer->start+5,rses->connect_db,qlen);
DCB* dcb = NULL;
SESSION_ROUTE_QUERY(subsvc->session,buffer);
goto retblock;
}
if(rses->queue)
{
GWBUF* tmp = rses->queue;
rses->queue = rses->queue->next;
tmp->next = NULL;
char* querystr = modutil_get_SQL(tmp);
skygw_log_write(LOGFILE_DEBUG,"schemarouter: Sending queued buffer for session %p: %s",
rses->rses_client_dcb->session,
querystr);
poll_add_epollin_event_to_dcb(rses->routedcb,tmp);
free(querystr);
}
skygw_log_write_flush(LOGFILE_DEBUG,"session [%p] database map finished.",
rses);
}
goto retblock;
}
subsvc_clear_state(subsvc, SUBSVC_QUERY_ACTIVE);
if(!rses->hash_init)
{
subsvc_set_state(subsvc, SUBSVC_MAPPED);
parse_mapping_response(rses, subsvc->service->name, reply);
for(i = 0; i < rses->n_subservice; i++)
{
if(SUBSVC_IS_OK(rses->subservice[i]) && !SUBSVC_IS_MAPPED(rses->subservice[i]))
{
mapped = false;
break;
}
}
gwbuf_free(reply);
if(mapped)
{
rses->hash_init = true;
if(rses->queue)
{
tmp = rses->queue;
rses->queue = rses->queue->next;
}
}
goto retblock;
}
if(rses->queue)
{
tmp = rses->queue;
rses->queue = rses->queue->next;
GWBUF* tmp = rses->queue;
rses->queue = rses->queue->next;
tmp->next = NULL;
char* querystr = modutil_get_SQL(tmp);
skygw_log_write(LOGFILE_DEBUG,"schemarouter: Sending queued buffer for session %p: %s",
rses->rses_client_dcb->session,
querystr);
poll_add_epollin_event_to_dcb(rses->routedcb,tmp);
free(querystr);
tmp = NULL;
}
if(rses->init & INIT_USE_DB)
{
skygw_log_write(LOGFILE_DEBUG,"schemarouter: Reply to USE '%s' received for session %p",
rses->connect_db,
rses->rses_client_dcb->session);
rses->init &= ~INIT_USE_DB;
strcpy(rses->rses_mysql_session->db,rses->connect_db);
ss_dassert(rses->init == INIT_READY);
if(reply)
{
tmp = reply;
while((tmp = gwbuf_consume(tmp,gwbuf_length(tmp))));
tmp = NULL;
}
goto retblock;
}
scur = subsvc->scur;
@ -688,12 +791,8 @@ filterReply(FILTER* instance, void *session, GWBUF *reply)
rv = SESSION_ROUTE_REPLY(rses->session, reply);
retblock:
rses_end_locked_router_action(rses);
if(tmp)
{
poll_add_epollin_event_to_dcb(rses->queue_dcb,tmp);
}
retblock:
rses_end_locked_router_action(rses);
return rv;
}
@ -843,7 +942,7 @@ static ROUTER *
createInstance(SERVICE *service, char **options)
{
ROUTER_INSTANCE* router;
char *services, *tok;
char *services, *tok, *saveptr;
SERVICE **res_svc, **temp;
CONFIG_PARAMETER* conf;
int i = 0, sz;
@ -858,7 +957,6 @@ createInstance(SERVICE *service, char **options)
spinlock_init(&router->lock);
conf = config_get_param(service->svc_config_param, "subservices");
/*
if(conf == NULL)
{
@ -869,14 +967,20 @@ createInstance(SERVICE *service, char **options)
}
services = strdup(conf->value);
*/
sz = 2;
res_svc = calloc(sz, sizeof(SERVICE*));
/*
tok = strtok(services, ",");
*/
while(options[i])
if((res_svc = calloc(sz, sizeof(SERVICE*))) == NULL)
{
free(router);
skygw_log_write(LOGFILE_ERROR,"Error: Memory allocation failed.");
return NULL;
}
tok = strtok_r(services, ",",&saveptr);
while(tok)
{
if(sz <= i)
{
@ -884,9 +988,9 @@ createInstance(SERVICE *service, char **options)
if(temp == NULL)
{
skygw_log_write(LOGFILE_ERROR, "Error : Memory reallocation failed.");
skygw_log_write(LOGFILE_DEBUG, "shardrouter.c: realloc returned NULL. "
LOGIF(LD,(skygw_log_write(LOGFILE_DEBUG, "shardrouter.c: realloc returned NULL. "
"service count[%d] buffer size [%u] tried to allocate [%u]",
sz, sizeof(SERVICE*)*(sz), sizeof(SERVICE*)*(sz * 2));
sz, sizeof(SERVICE*)*(sz), sizeof(SERVICE*)*(sz * 2))));
free(res_svc);
free(router);
return NULL;
@ -895,19 +999,27 @@ createInstance(SERVICE *service, char **options)
res_svc = temp;
}
res_svc[i] = service_find(options[i]);
res_svc[i] = service_find(tok);
if(res_svc[i] == NULL)
{
free(res_svc);
free(router);
skygw_log_write(LOGFILE_ERROR, "Error : No service named '%s' found.", options[i]);
return NULL;
}
i++;
tok = strtok_r(NULL,",",&saveptr);
}
/*
free(services);
*/
router->services = res_svc;
router->n_services = i;
if(i < min_nsvc)
{
skygw_log_write(LOGFILE_ERROR, "Error : Not enough services. Shardrouter requires at least %d "
skygw_log_write(LOGFILE_ERROR, "Error : Not enough parameters for 'subservice' router option. Shardrouter requires at least %d "
"configured services to work.", min_nsvc);
free(router->services);
free(router);
@ -980,15 +1092,15 @@ newSession(
client_rses->rses_autocommit_enabled = true;
client_rses->rses_transaction_active = false;
client_rses->session = session;
client_rses->dummy_dcb = dcb_alloc(DCB_ROLE_REQUEST_HANDLER);
client_rses->dummy_dcb->func.read = fakeReply;
client_rses->dummy_dcb->state = DCB_STATE_POLLING;
client_rses->dummy_dcb->session = session;
client_rses->replydcb = dcb_alloc(DCB_ROLE_REQUEST_HANDLER);
client_rses->replydcb->func.read = fakeReply;
client_rses->replydcb->state = DCB_STATE_POLLING;
client_rses->replydcb->session = session;
client_rses->queue_dcb = dcb_alloc(DCB_ROLE_REQUEST_HANDLER);
client_rses->queue_dcb->func.read = fakeQuery;
client_rses->queue_dcb->state = DCB_STATE_POLLING;
client_rses->queue_dcb->session = session;
client_rses->routedcb = dcb_alloc(DCB_ROLE_REQUEST_HANDLER);
client_rses->routedcb->func.read = fakeQuery;
client_rses->routedcb->state = DCB_STATE_POLLING;
client_rses->routedcb->session = session;
spinlock_init(&client_rses->rses_lock);
@ -1168,10 +1280,10 @@ closeSession(
}
router_cli_ses->subservice[i]->state = SUBSVC_CLOSED;
}
router_cli_ses->dummy_dcb->session = NULL;
router_cli_ses->queue_dcb->session = NULL;
dcb_close(router_cli_ses->dummy_dcb);
dcb_close(router_cli_ses->queue_dcb);
router_cli_ses->replydcb->session = NULL;
router_cli_ses->routedcb->session = NULL;
dcb_close(router_cli_ses->replydcb);
dcb_close(router_cli_ses->routedcb);
/** Unlock */
rses_end_locked_router_action(router_cli_ses);
@ -1480,32 +1592,46 @@ routeQuery(ROUTER* instance,
ret = 0;
goto retblock;
}
if(!router_cli_ses->hash_init)
{
gen_tablelist(inst, router_cli_ses);
skygw_log_write(LOGFILE_TRACE,"shardrouter: got a query while mapping databases.");
GWBUF* tmp = router_cli_ses->queue;
while(tmp && tmp->next)
if(!(rses_is_closed = router_cli_ses->rses_closed))
{
tmp = tmp->next;
if(router_cli_ses->init & INIT_UNINT)
{
/* Generate database list */
gen_subsvc_dblist(inst,router_cli_ses);
}
if(router_cli_ses->init & INIT_MAPPING)
{
char* querystr = modutil_get_SQL(querybuf);
skygw_log_write(LOGFILE_DEBUG,"shardrouter: Storing query for session %p: %s",
router_cli_ses->rses_client_dcb->session,
querystr);
free(querystr);
gwbuf_make_contiguous(querybuf);
GWBUF* ptr = router_cli_ses->queue;
while(ptr && ptr->next)
{
ptr = ptr->next;
}
if(ptr == NULL)
{
router_cli_ses->queue = querybuf;
}
else
{
ptr->next = querybuf;
}
rses_end_locked_router_action(router_cli_ses);
return 1;
}
}
if(tmp == NULL)
{
router_cli_ses->queue = querybuf;
}
else
{
tmp->next = querybuf;
}
rses_end_locked_router_action(router_cli_ses);
return 1;
}
rses_end_locked_router_action(router_cli_ses);
packet = GWBUF_DATA(querybuf);
@ -1608,7 +1734,7 @@ routeQuery(ROUTER* instance,
*/
GWBUF* dbres = gen_show_dbs_response(inst,router_cli_ses);
poll_add_epollin_event_to_dcb(router_cli_ses->dummy_dcb,dbres);
poll_add_epollin_event_to_dcb(router_cli_ses->replydcb,dbres);
ret = 1;
goto retblock;
}
@ -2982,7 +3108,7 @@ reply_error:
* Create an incoming event for randomly selected backend DCB which
* will then be notified and replied 'back' to the client.
*/
poll_add_epollin_event_to_dcb(rses->dummy_dcb,
poll_add_epollin_event_to_dcb(rses->replydcb,
gwbuf_clone(errbuf));
gwbuf_free(errbuf);
}