Merge branch 'blr' into develop
Addition of hashtable load and save. Caching of auth information
This commit is contained in:
@ -1315,4 +1315,186 @@ static int gw_mysql_set_timeouts(
|
||||
|
||||
retblock:
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Serialise a key for the dbusers hashtable to a file
|
||||
*
|
||||
* @param fd File descriptor to write to
|
||||
* @param key The key to write
|
||||
* @return 0 on error, 1 if the key was written
|
||||
*/
|
||||
static int
|
||||
dbusers_keywrite(int fd, void *key)
|
||||
{
|
||||
MYSQL_USER_HOST *dbkey = (MYSQL_USER_HOST *)key;
|
||||
int tmp;
|
||||
|
||||
tmp = strlen(dbkey->user);
|
||||
if (write(fd, &tmp, sizeof(tmp)) != sizeof(tmp))
|
||||
return 0;
|
||||
if (write(fd, dbkey->user, tmp) != tmp)
|
||||
return 0;
|
||||
if (write(fd, &dbkey->ipv4, sizeof(dbkey->ipv4)) != sizeof(dbkey->ipv4))
|
||||
return 0;
|
||||
if (write(fd, &dbkey->netmask, sizeof(dbkey->netmask)) != sizeof(dbkey->netmask))
|
||||
return 0;
|
||||
if (dbkey->resource)
|
||||
{
|
||||
tmp = strlen(dbkey->resource);
|
||||
if (write(fd, &tmp, sizeof(tmp)) != sizeof(tmp))
|
||||
return 0;
|
||||
if (write(fd, dbkey->resource, tmp) != tmp)
|
||||
return 0;
|
||||
}
|
||||
else // NULL is valid, so represent with a length of -1
|
||||
{
|
||||
tmp = -1;
|
||||
if (write(fd, &tmp, sizeof(tmp)) != sizeof(tmp))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialise a value for the dbusers hashtable to a file
|
||||
*
|
||||
* @param fd File descriptor to write to
|
||||
* @param value The value to write
|
||||
* @return 0 on error, 1 if the value was written
|
||||
*/
|
||||
static int
|
||||
dbusers_valuewrite(int fd, void *value)
|
||||
{
|
||||
int tmp;
|
||||
|
||||
tmp = strlen(value);
|
||||
if (write(fd, &tmp, sizeof(tmp)) != sizeof(tmp))
|
||||
return 0;
|
||||
if (write(fd, value, tmp) != tmp)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unserialise a key for the dbusers hashtable from a file
|
||||
*
|
||||
* @param fd File descriptor to read from
|
||||
* @return Pointer to the new key or NULL on error
|
||||
*/
|
||||
static void *
|
||||
dbusers_keyread(int fd)
|
||||
{
|
||||
MYSQL_USER_HOST *dbkey;
|
||||
int tmp;
|
||||
|
||||
if ((dbkey = (MYSQL_USER_HOST *)malloc(sizeof(MYSQL_USER_HOST))) == NULL)
|
||||
return NULL;
|
||||
if (read(fd, &tmp, sizeof(tmp)) != sizeof(tmp))
|
||||
{
|
||||
free(dbkey);
|
||||
return NULL;
|
||||
}
|
||||
if ((dbkey->user = (char *)malloc(tmp + 1)) == NULL)
|
||||
{
|
||||
free(dbkey);
|
||||
return NULL;
|
||||
}
|
||||
if (read(fd, dbkey->user, tmp) != tmp)
|
||||
{
|
||||
free(dbkey->user);
|
||||
free(dbkey);
|
||||
return NULL;
|
||||
}
|
||||
dbkey->user[tmp] = 0; // NULL Terminate
|
||||
if (read(fd, &dbkey->ipv4, sizeof(dbkey->ipv4)) != sizeof(dbkey->ipv4))
|
||||
{
|
||||
free(dbkey->user);
|
||||
free(dbkey);
|
||||
return NULL;
|
||||
}
|
||||
if (read(fd, &dbkey->netmask, sizeof(dbkey->netmask)) != sizeof(dbkey->netmask))
|
||||
{
|
||||
free(dbkey->user);
|
||||
free(dbkey);
|
||||
return NULL;
|
||||
}
|
||||
if (read(fd, &tmp, sizeof(tmp)) != sizeof(tmp))
|
||||
{
|
||||
free(dbkey->user);
|
||||
free(dbkey);
|
||||
return NULL;
|
||||
}
|
||||
if (tmp != -1)
|
||||
{
|
||||
if ((dbkey->resource = (char *)malloc(tmp + 1)) == NULL)
|
||||
{
|
||||
free(dbkey->user);
|
||||
free(dbkey);
|
||||
return NULL;
|
||||
}
|
||||
if (read(fd, dbkey->resource, tmp) != tmp)
|
||||
{
|
||||
free(dbkey->resource);
|
||||
free(dbkey->user);
|
||||
free(dbkey);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else // NULL is valid, so represent with a length of -1
|
||||
{
|
||||
dbkey->resource = NULL;
|
||||
}
|
||||
return (void *)dbkey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unserialise a value for the dbusers hashtable from a file
|
||||
*
|
||||
* @param fd File descriptor to read from
|
||||
* @return Return the new value data or NULL on error
|
||||
*/
|
||||
static void *
|
||||
dbusers_valueread(int fd)
|
||||
{
|
||||
char *value;
|
||||
int tmp;
|
||||
|
||||
if (read(fd, &tmp, sizeof(tmp)) != sizeof(tmp))
|
||||
return NULL;
|
||||
if ((value = (char *)malloc(tmp + 1)) == NULL)
|
||||
return NULL;
|
||||
if (read(fd, value, tmp) != tmp)
|
||||
{
|
||||
free(value);
|
||||
return NULL;
|
||||
}
|
||||
value[tmp] = 0;
|
||||
return (void *)value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the dbusers data to a hashtable file
|
||||
*
|
||||
* @param users The hashtable that stores the user data
|
||||
* @param filename The filename to save the data in
|
||||
* @return The number of entries saved
|
||||
*/
|
||||
int
|
||||
dbusers_save(USERS *users, char *filename)
|
||||
{
|
||||
return hashtable_save(users->data, filename, dbusers_keywrite, dbusers_valuewrite);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the dbusers data from a saved hashtable file
|
||||
*
|
||||
* @param users The hashtable that stores the user data
|
||||
* @param filename The filename to laod the data from
|
||||
* @return The number of entries loaded
|
||||
*/
|
||||
int
|
||||
dbusers_load(USERS *users, char *filename)
|
||||
{
|
||||
return hashtable_load(users->data, filename, dbusers_keyread, dbusers_valueread);
|
||||
}
|
||||
|
@ -17,7 +17,11 @@
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <hashtable.h>
|
||||
|
||||
/**
|
||||
@ -55,6 +59,7 @@
|
||||
* 08/01/2014 Massimiliano Pinto Added copy and free funtion pointers for keys and values:
|
||||
* it's possible to copy and free different data types via
|
||||
* kcopyfn/kfreefn, vcopyfn/vfreefn
|
||||
* 06/02/2015 Mark Riddoch Addition of hashtable_save and hashtable_load
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
@ -637,3 +642,109 @@ hashtable_iterator_free(HASHITERATOR *iter)
|
||||
{
|
||||
free(iter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a hashtable to disk
|
||||
*
|
||||
* @param table Hashtable to save
|
||||
* @param filename Filename to write hashtable into
|
||||
* @param keywrite Pointer to function that writes a single key
|
||||
* @param valuewrite Pointer to function that writes a single value
|
||||
* @return Number of entries written or -1 on error
|
||||
*/
|
||||
int
|
||||
hashtable_save(HASHTABLE *table, char *filename,
|
||||
int (*keywrite)(int, void*),
|
||||
int (*valuewrite)(int, void*))
|
||||
{
|
||||
int fd, rval = 0;
|
||||
HASHITERATOR *iter;
|
||||
void *key, *value;
|
||||
|
||||
if ((fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (write(fd, "HASHTABLE", 7) != 7) // Magic number
|
||||
{
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
write(fd, &rval, sizeof(rval)); // Write zero counter, will be overrwriten at end
|
||||
if ((iter = hashtable_iterator(table)) != NULL)
|
||||
{
|
||||
while ((key = hashtable_next(iter)) != NULL)
|
||||
{
|
||||
if (!(*keywrite)(fd, key))
|
||||
{
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
if ((value = hashtable_fetch(table, key)) == NULL ||
|
||||
(*valuewrite)(fd, value) == 0)
|
||||
{
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
rval++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now go back and write the count of entries */
|
||||
lseek(fd, 7L, SEEK_SET);
|
||||
write(fd, &rval, sizeof(rval));
|
||||
|
||||
close(fd);
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a hashtable from disk
|
||||
*
|
||||
* @param table Hashtable to load
|
||||
* @param filename Filename to read hashtable from
|
||||
* @param keyread Pointer to function that reads a single key
|
||||
* @param valueread Pointer to function that reads a single value
|
||||
* @return Number of entries read or -1 on error
|
||||
*/
|
||||
int
|
||||
hashtable_load(HASHTABLE *table, char *filename,
|
||||
void *(*keyread)(int),
|
||||
void *(*valueread)(int))
|
||||
{
|
||||
int fd, count, rval = 0;
|
||||
void *key, *value;
|
||||
char buf[40];
|
||||
|
||||
if ((fd = open(filename, O_RDONLY)) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (read(fd, buf, 7) != 7)
|
||||
{
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
if (strncmp(buf, "HASHTABLE", 7) != 0)
|
||||
{
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
if (read(fd, &count, sizeof(count)) != sizeof(count))
|
||||
{
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
while (count--)
|
||||
{
|
||||
key = keyread(fd);
|
||||
value = valueread(fd);
|
||||
if (key == NULL || value == NULL)
|
||||
break;
|
||||
hashtable_add(table, key, value);
|
||||
rval++;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return rval;
|
||||
}
|
||||
|
@ -33,6 +33,7 @@
|
||||
* 29/05/14 Mark Riddoch Filter API implementation
|
||||
* 09/09/14 Massimiliano Pinto Added service option for localhost authentication
|
||||
* 13/10/14 Massimiliano Pinto Added hashtable for resources (i.e database names for MySQL services)
|
||||
* 06/02/15 Mark Riddoch Added caching of authentication data
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
@ -54,6 +55,8 @@
|
||||
#include <poll.h>
|
||||
#include <skygw_utils.h>
|
||||
#include <log_manager.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/** Defined in log_manager.cc */
|
||||
extern int lm_enabled_logfiles_bitmask;
|
||||
@ -215,7 +218,55 @@ GWPROTOCOL *funcs;
|
||||
(port->address == NULL ? "0.0.0.0" : port->address),
|
||||
port->port,
|
||||
service->name)));
|
||||
|
||||
{
|
||||
/* Try loading authentication data from file cache */
|
||||
char *ptr, path[4096];
|
||||
strcpy(path, "/usr/local/skysql/MaxScale");
|
||||
if ((ptr = getenv("MAXSCALE_HOME")) != NULL)
|
||||
{
|
||||
strncpy(path, ptr, 4096);
|
||||
}
|
||||
strncat(path, "/", 4096);
|
||||
strncat(path, service->name, 4096);
|
||||
strncat(path, "/.cache/dbusers", 4096);
|
||||
loaded = dbusers_load(service->users, path);
|
||||
if (loaded != -1)
|
||||
{
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"Using cached credential information.")));
|
||||
}
|
||||
}
|
||||
if (loaded == -1)
|
||||
{
|
||||
hashtable_free(service->users->data);
|
||||
free(service->users);
|
||||
dcb_free(port->listener);
|
||||
port->listener = NULL;
|
||||
goto retblock;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Save authentication data to file cache */
|
||||
char *ptr, path[4096];
|
||||
strcpy(path, "/usr/local/skysql/MaxScale");
|
||||
if ((ptr = getenv("MAXSCALE_HOME")) != NULL)
|
||||
{
|
||||
strncpy(path, ptr, 4096);
|
||||
}
|
||||
strncat(path, "/", 4096);
|
||||
strncat(path, service->name, 4096);
|
||||
if (access(path, R_OK) == -1)
|
||||
mkdir(path, 0777);
|
||||
strncat(path, "/.cache", 4096);
|
||||
if (access(path, R_OK) == -1)
|
||||
mkdir(path, 0777);
|
||||
strncat(path, "/dbusers", 4096);
|
||||
dbusers_save(service->users, path);
|
||||
}
|
||||
|
||||
/* At service start last update is set to USERS_REFRESH_TIME seconds earlier.
|
||||
* This way MaxScale could try reloading users' just after startup
|
||||
*/
|
||||
@ -823,9 +874,9 @@ struct tm result;
|
||||
char time_buf[30];
|
||||
int i;
|
||||
|
||||
printf("Service %p\n", service);
|
||||
printf("Service %p\n", (void *)service);
|
||||
printf("\tService: %s\n", service->name);
|
||||
printf("\tRouter: %s (%p)\n", service->routerModule, service->router);
|
||||
printf("\tRouter: %s (%p)\n", service->routerModule, (void *)service->router);
|
||||
printf("\tStarted: %s",
|
||||
asctime_r(localtime_r(&service->stats.started, &result), time_buf));
|
||||
printf("\tBackend databases\n");
|
||||
@ -844,7 +895,7 @@ int i;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\tUsers data: %p\n", service->users);
|
||||
printf("\tUsers data: %p\n", (void *)service->users);
|
||||
printf("\tTotal connections: %d\n", service->stats.n_sessions);
|
||||
printf("\tCurrently connected: %d\n", service->stats.n_current);
|
||||
}
|
||||
|
Reference in New Issue
Block a user