moving files to /server to make merge possible

This commit is contained in:
Timofey Turenko
2013-07-28 05:31:11 +00:00
parent d8978dce1c
commit a7c82310f9
129 changed files with 0 additions and 0 deletions

66
server/Makefile Normal file
View File

@ -0,0 +1,66 @@
# This file is distributed as part of the SkySQL Gateway. It is free
# software: you can redistribute it and/or modify it under the terms of the
# GNU General Public License as published by the Free Software Foundation,
# version 2.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright SkySQL Ab 2013
#
# Revision History
# Date Who Description
# 14/06/13 Mark Riddoch Initial implementation
# 17/06/13 Mark Riddoch Addition of documentation and depend
# targets
# 18/06/13 Mark Riddoch Addition of install target
# 21/06/13 Mark Riddoch Addition of inih
# 08/07/13 Mark Riddoch Addition of monitor modules
# 16/07/13 Mark Riddoch Renamed things to match the new naming
DEST=$(HOME)/usr/local/skysql
all:
(cd inih/extra ; make -f Makefile.static)
(cd core ; make)
(cd modules/routing; make)
(cd modules/routing/readwritesplit; make)
(cd modules/protocol; make)
(cd modules/monitor; make)
clean:
(cd Documentation; rm -rf html)
(cd core; make clean)
(cd modules/routing; make clean)
(cd modules/protocol; make clean)
(cd modules/monitor; make clean)
depend:
(cd core; make depend)
(cd modules/routing; make depend)
(cd modules/protocol; make depend)
(cd modules/monitor; make depend)
documentation:
doxygen doxygate
install:
@mkdir -p $(DEST)
@mkdir -p $(DEST)/MaxScale
@mkdir -p $(DEST)/MaxScale/modules
@mkdir -p $(DEST)/MaxScale/log
@mkdir -p $(DEST)/MaxScale/etc
@mkdir -p $(DEST)/lib
@mkdir -p $(DEST)/Documentation
install MaxScale.cnf $(DEST)/MaxScale/etc
install Documentation/*.pdf $(DEST)/Documentation
(cd core; make DEST=$(DEST) install)
(cd modules/routing; make DEST=$(DEST) install)
(cd modules/protocol; make DEST=$(DEST) install)
(cd modules/monitor; make DEST=$(DEST) install)

107
server/MaxScale.cnf Normal file
View File

@ -0,0 +1,107 @@
#
# Example gateway.cnf configuration file
#
#
#
# A genererate configuration session
# Valid options are:
# threads=<number of epoll threads>
[gateway]
threads=1
# A series service definition
# Valid option are
# router=<name of router module>
# servers=<server name>,<server name>,...
# user=<User to fetch password inforamtion with>
# auth=<Password of the user, plain text currently>
#
# Valid router modules currently are:
# readwritesplit, readconnroute and debugcli
[RW Split Service]
type=service
router=readwritesplit
router_options=slave
servers=server1,server2,server3
user=maxuser
auth=maxpwd
[Test Service]
type=service
router=readconnroute
router_options=slave
servers=server1,server2,server3
user=maxuser
auth=maxpwd
# Definition of the servers
[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
[Debug Service]
type=service
router=debugcli
# Listener definitions for the services
# Valid options are:
# service=<name of service defined elsewhere>
# protocol=<name of protocol module with which to listen>
# port<Listening port>
[Debug Listener]
type=listener
service=Debug Service
protocol=telnetd
port=4442
[Test Listener]
type=listener
service=Test Service
protocol=MySQLClient
port=4008
[RW Split Listener]
type=listener
service=RW Split Service
protocol=MySQLClient
port=4006
# Define a monitor that can be used to determine the state and role of
# the servers.
# Valid options are:
# module=<name of module to load>
# servers=<server name>,<server name>,...
# user=<user name - must have slave replication and slave client privileges>
# passwd=<password of the above user, plain text currently>
[MySQL Monitor]
type=monitor
module=mysqlmon
servers=server1,server2,server3
user=maxuser
passwd=maxpwd
[HTTPD Service]
type=service
router=testroute
[HTTPD Listener]
type=listener
service=HTTPD Service
protocol=HTTPD
port=6444

108
server/core/Makefile Normal file
View File

@ -0,0 +1,108 @@
# This file is distributed as part of the SkySQL Gateway. It is free
# software: you can redistribute it and/or modify it under the terms of the
# GNU General Public License as published by the Free Software Foundation,
# version 2.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright SkySQL Ab 2013
#
# Revision History
# Date Who Description
# 13/06/13 Mark Riddoch Addition of -rdynamic to allow libraries
# to resolve symbols in the main executable
# 17/06/13 Mark Riddoch Addition of dependency generation
# 24/06/13 Massimiliano Pinto Addition of libmysqlclient and its
# includes do this for launching the
# gateway: export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH:/packages/mariadb-5.5.25/libmysql
# 27/06/13 Vilho Raatikka Added logmanager-related libs and
# headers so that liblog_manager.so can
# be linked in.
# 28/06/13 Vilho Raatikka Added query classifier-related libs and
# commented out mysql client headers and
# lib to avoid conflicts. MARIADB_SRC_PATH
# is set in build_gateway.inc. Examples
# are behind SS_DEBUG macros.
# 29/06/13 Vilho Raatikka Reverted Query classifier changes because
# gateway needs mysql client lib, not qc.
# 24/07/13 Mark Ridoch Addition of encryption routines
include ../../build_gateway.inc
LOGPATH := $(ROOT_PATH)/log_manager
UTILSPATH := $(ROOT_PATH)/utils
CC=cc
CFLAGS=-c -I/usr/include -I../include -I../inih \
-I$(MARIADB_SRC_PATH)/include/ \
-I$(LOGPATH) -I$(UTILSPATH) \
-Wall -g
include ../../makefile.inc
LDFLAGS=-rdynamic -L$(LOGPATH) \
-Wl,-rpath,$(DEST)/lib \
-Wl,-rpath,$(LOGPATH) -Wl,-rpath,$(UTILSPATH) \
-Wl,-rpath,$(MARIADB_SRC_PATH)/libmysqld
SRCS= atomic.c buffer.c spinlock.c gateway.c gateway_mysql_protocol.c \
gw_utils.c utils.c dcb.c load_utils.c session.c service.c server.c \
poll.c config.c users.c hashtable.c dbusers.c thread.c gwbitmask.c \
monitor.c adminusers.c secrets.c
HDRS= ../include/atomic.h ../include/buffer.h ../include/dcb.h \
../include/gateway_mysql.h ../include/gw.h ../include/mysql_protocol.h \
../include/session.h ../include/spinlock.h ../include/thread.h \
../include/modules.h ../include/poll.h ../include/config.h \
../include/users.h ../include/hashtable.h ../include/gwbitmask.h \
../include/adminusers.h
OBJ=$(SRCS:.c=.o)
KOBJS=maxkeys.o secrets.o utils.o
POBJS=maxpasswd.o secrets.o utils.o
LIBS=-L../inih/extra -linih -lssl -lstdc++ \
-L$(MARIADB_SRC_PATH)/libmysqld \
-lz -lm -lcrypt -lcrypto -ldl -pthread -llog_manager \
-lmysqld
all: maxscale maxkeys maxpasswd
maxscale: $(OBJ)
$(CC) $(LDFLAGS) $(OBJ) $(UTILSPATH)/skygw_utils.o $(LIBS) -o $@
maxkeys: $(KOBJS)
$(CC) $(LDFLAGS) $(KOBJS) $(UTILSPATH)/skygw_utils.o $(LIBS) -o $@
maxpasswd: $(POBJS)
$(CC) $(LDFLAGS) $(POBJS) $(UTILSPATH)/skygw_utils.o $(LIBS) -o $@
.c.o:
$(CC) $(CFLAGS) $< -o $@
clean:
rm -f $(OBJ) maxscale
- rm *.so
tags:
ctags $(SRCS) $(HDRS)
depend:
@rm -f depend.mk
cc -M $(CFLAGS) $(SRCS) > depend.mk
install: maxscale maxkeys maxpasswd
@mkdir -p $(DEST)/bin
install -D maxscale maxkeys maxpasswd $(DEST)/bin
install -D $(MARIADB_SRC_PATH)/libmysqld/libmysqld.so.18 $(DEST)/lib
include depend.mk

202
server/core/adminusers.c Normal file
View File

@ -0,0 +1,202 @@
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define _XOPEN_SOURCE
#include <unistd.h>
#include <crypt.h>
#include <users.h>
#include <adminusers.h>
#include <skygw_utils.h>
#include <log_manager.h>
/**
* @file adminusers.c - Administration user account management
*
* @verbatim
* Revision History
*
* Date Who Description
* 18/07/13 Mark Riddoch Initial implementation
* 23/07/13 Mark Riddoch Addition of error mechanism to add user
*
* @endverbatim
*/
static USERS *loadUsers();
static void initialise();
static USERS *users = NULL;
static int admin_init = 0;
static char *ADMIN_ERR_NOMEM = "Out of memory";
static char *ADMIN_ERR_FILEOPEN = "Unable to create password file";
static char *ADMIN_ERR_DUPLICATE = "Duplicate username specified";
static char *ADMIN_ERR_FILEAPPEND = "Unable to append to password file";
/**
* Admin Users initialisation
*/
static void
initialise()
{
if (admin_init)
return;
admin_init = 1;
users = loadUsers();
}
/**
* Verify a username and password
*
* @param username Username to verify
* @param password Password to verify
* @return Non-zero if the username/password combination is valid
*/
int
admin_verify(char *username, char *password)
{
char *pw;
initialise();
if (users == NULL)
{
if (strcmp(username, "admin") == 0 && strcmp(password, "skysql") == 0)
return 1;
}
else
{
if ((pw = users_fetch(users, username)) == NULL)
return 0;
if (strcmp(pw, crypt(password, ADMIN_SALT)) == 0)
return 1;
}
return 0;
}
/**
* Load the admin users
*
* @return Table of users
*/
static USERS *
loadUsers()
{
USERS *rval;
FILE *fp;
char fname[1024], *home;
char uname[80], passwd[80];
initialise();
if ((home = getenv("MAXSCALE_HOME")) != NULL)
sprintf(fname, "%s/etc/passwd", home);
else
sprintf(fname, "/usr/local/skysql/MaxScale/etc/passwd");
if ((fp = fopen(fname, "r")) == NULL)
return NULL;
if ((rval = users_alloc()) == NULL)
return NULL;
while (fscanf(fp, "%[^:]:%s\n", uname, passwd) == 2)
{
users_add(rval, uname, passwd);
}
fclose(fp);
return rval;
}
/**
* Add user
*
* @param uname Name of the new user
* @param passwd Password for the new user
* @return NULL on success or an error string on failure
*/
char *
admin_add_user(char *uname, char *passwd)
{
FILE *fp;
char fname[1024], *home, *cpasswd;
initialise();
if ((home = getenv("MAXSCALE_HOME")) != NULL)
sprintf(fname, "%s/etc/passwd", home);
else
sprintf(fname, "/usr/local/skysql/MaxScale/etc/passwd");
if (users == NULL)
{
skygw_log_write(NULL, LOGFILE_MESSAGE, "Create initial password file.\n");
if ((users = users_alloc()) == NULL)
return ADMIN_ERR_NOMEM;
if ((fp = fopen(fname, "w")) == NULL)
{
skygw_log_write(NULL, LOGFILE_ERROR,
"Unable to create password file %s.\n",
fname);
return ADMIN_ERR_FILEOPEN;
}
fclose(fp);
}
if (users_fetch(users, uname) != NULL)
{
return ADMIN_ERR_DUPLICATE;
}
cpasswd = crypt(passwd, ADMIN_SALT);
users_add(users, uname, cpasswd);
if ((fp = fopen(fname, "a")) == NULL)
{
skygw_log_write(NULL, LOGFILE_ERROR,
"Unable to append to password file %s.\n",
fname);
return ADMIN_ERR_FILEAPPEND;
}
fprintf(fp, "%s:%s\n", uname, cpasswd);
fclose(fp);
return NULL;
}
/**
* Check for existance of the user
*
* @param user The user name to test
* @return Non-zero if the user exists
*/
int
admin_test_user(char *user)
{
initialise();
if (users == NULL)
return 0;
return users_fetch(users, user) != NULL;
}
/**
* Print the statistics and user names of the administration users
*
* @param dcb A DCB to send the output to
*/
void
dcb_PrintAdminUsers(DCB *dcb)
{
if (users)
dcb_usersPrint(dcb, users);
else
dcb_printf(dcb, "No administrtion users have been defined.\n");
}

51
server/core/atomic.c Normal file
View File

@ -0,0 +1,51 @@
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
/**
* @file atomic.c - Implementation of atomic opertions for the gateway
*
* @verbatim
* Revision History
*
* Date Who Description
* 10/06/13 Mark Riddoch Initial implementation
*
* @endverbatim
*/
/**
* Implementation of an atomic add operation for the X86 processor.
* Adds a value to the contents of a location pointed to by the first parameter.
* The add operation is atomic and the return value is the value stored in the location
* prior to the operation. The number that is added may be signed, therefore atomic_subtract
* is merely an atomic add with a negative value.
*
* @param variable Pointer the the variable to add to
* @param value Value to be added
* @return The value of *variable before the add occured
*/
int
atomic_add(int *variable, int value)
{
asm volatile(
"lock; xaddl %%eax, %2;"
:"=a" (value)
: "a" (value), "m" (*variable)
: "memory" );
return value;
}

207
server/core/buffer.c Normal file
View File

@ -0,0 +1,207 @@
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
/**
* @file buffer.h - The Gateway buffer management functions
*
* The buffer management is based on the principle of a linked list
* of variable size buffer, the intention beign to allow longer
* content to be buffered in a list and minimise any need to copy
* data between buffers.
*
* @verbatim
* Revision History
*
* Date Who Description
* 10/06/13 Mark Riddoch Initial implementation
* 11/07/13 Mark Riddoch Add reference count mechanism
* 16/07/2013 Massimiliano Pinto Added command type to gwbuf struct
*
* @endverbatim
*/
#include <stdlib.h>
#include <buffer.h>
#include <atomic.h>
/**
* Allocate a new gateway buffer structure of size bytes.
*
* For now we allocate memory directly from malloc for buffer the management
* structure and the actual data buffer itself. We may swap at a future date
* to a more effecient mechanism.
*
* @param size The size in bytes of the data area required
* @return Pointer to the buffer structure or NULL if memory could not
* be allocated.
*/
GWBUF *
gwbuf_alloc(unsigned int size)
{
GWBUF *rval;
SHARED_BUF *sbuf;
// Allocate the buffer header
if ((rval = (GWBUF *)malloc(sizeof(GWBUF))) == NULL)
{
return NULL;
}
// Allocate the shared data buffer
if ((sbuf = (SHARED_BUF *)malloc(sizeof(SHARED_BUF))) == NULL)
{
free(rval);
return NULL;
}
// Allocate the space for the actual data
if ((sbuf->data = (unsigned char *)malloc(size)) == NULL)
{
free(rval);
free(sbuf);
return NULL;
}
rval->start = sbuf->data;
rval->end = rval->start + size;
sbuf->refcount = 1;
rval->sbuf = sbuf;
rval->next = NULL;
rval->command = 0;
return rval;
}
/**
* Free a gateway buffer
*
* @param buf The buffer to free
*/
void
gwbuf_free(GWBUF *buf)
{
atomic_add(&buf->sbuf->refcount, -1);
if (buf->sbuf->refcount == 0)
{
free(buf->sbuf->data);
free(buf->sbuf);
}
free(buf);
}
/**
* Increment the usage count of a gateway buffer. This gets a new
* GWBUF structure that shares the actual data with the existing
* GWBUF structure but allows for the data copy to be avoided and
* also for each GWBUF to point to different portions of the same
* SHARED_BUF.
*
* @param buf The buffer to use
* @return A new GWBUF structure
*/
GWBUF *
gwbuf_clone(GWBUF *buf)
{
GWBUF *rval;
if ((rval = (GWBUF *)malloc(sizeof(GWBUF))) == NULL)
{
return NULL;
}
atomic_add(&buf->sbuf->refcount, 1);
rval->sbuf = buf->sbuf;
rval->start = buf->start;
rval->end = buf->end;
rval->next = NULL;
rval->command = buf->command;
return rval;
}
/**
* Append a buffer onto a linked list of buffer structures.
*
* This call should be made with the caller holding the lock for the linked
* list.
*
* @param head The current head of the linked list
* @param tail The new buffer to make the tail of the linked list
* @return The new head of the linked list
*/
GWBUF *
gwbuf_append(GWBUF *head, GWBUF *tail)
{
GWBUF *ptr = head;
if (!head)
return tail;
while (ptr->next)
{
ptr = ptr->next;
}
ptr->next = tail;
return head;
}
/**
* Consume data from a buffer in the linked list. The assumption is to consume
* n bytes from the buffer chain.
*
* If after consuming the bytes from the first buffer that buffer becomes
* empty it will be freed and the linked list updated.
*
* The return value is the new head of the linked list.
*
* This call should be made with the caller holding the lock for the linked
* list.
*
* @param head The head of the linked list
* @param length The amount of data to consume
* @return The head of the linked list
*/
GWBUF *
gwbuf_consume(GWBUF *head, unsigned int length)
{
GWBUF *rval = head;
GWBUF_CONSUME(head, length);
if (GWBUF_EMPTY(head))
{
rval = head->next;
gwbuf_free(head);
}
return rval;
}
/**
* Return the number of bytes of data in the linked list.
*
* @param head The current head of the linked list
* @return The number of bytes of data in the linked list
*/
unsigned int
gwbuf_length(GWBUF *head)
{
int rval = 0;
while (head)
{
rval += GWBUF_LENGTH(head);
head = head->next;
}
return rval;
}

517
server/core/config.c Normal file
View File

@ -0,0 +1,517 @@
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
/**
* @file config.c - Read the gateway.cnf configuration file
*
* @verbatim
* Revision History
*
* Date Who Description
* 21/06/13 Mark Riddoch Initial implementation
* 08/07/13 Mark Riddoch Addition on monitor module support
* 23/07/13 Mark Riddoch Addition on default monitor password
*
* @endverbatim
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ini.h>
#include <config.h>
#include <service.h>
#include <server.h>
#include <users.h>
#include <monitor.h>
#include <skygw_utils.h>
#include <log_manager.h>
static int process_config_context(CONFIG_CONTEXT *);
static int process_config_update(CONFIG_CONTEXT *);
static void free_config_context(CONFIG_CONTEXT *);
static char *config_get_value(CONFIG_PARAMETER *, const char *);
static int handle_global_item(const char *, const char *);
static void global_defaults();
static char *config_file = NULL;
static GATEWAY_CONF gateway;
/**
* Config item handler for the ini file reader
*
* @param userdata The config context element
* @param section The config file section
* @param name The Parameter name
* @param value The Parameter value
* @return zero on error
*/
static int
handler(void *userdata, const char *section, const char *name, const char *value)
{
CONFIG_CONTEXT *cntxt = (CONFIG_CONTEXT *)userdata;
CONFIG_CONTEXT *ptr = cntxt;
CONFIG_PARAMETER *param;
if (strcmp(section, "gateway") == 0 || strcasecmp(section, "MaxScale") == 0)
{
return handle_global_item(name, value);
}
/*
* If we already have some parameters for the object
* add the parameters to that object. If not create
* a new object.
*/
while (ptr && strcmp(ptr->object, section) != 0)
ptr = ptr->next;
if (!ptr)
{
if ((ptr = (CONFIG_CONTEXT *)malloc(sizeof(CONFIG_CONTEXT))) == NULL)
return 0;
ptr->object = strdup(section);
ptr->parameters = NULL;
ptr->next = cntxt->next;
cntxt->next = ptr;
}
if ((param = (CONFIG_PARAMETER *)malloc(sizeof(CONFIG_PARAMETER))) == NULL)
return 0;
param->name = strdup(name);
param->value = strdup(value);
param->next = ptr->parameters;
ptr->parameters = param;
return 1;
}
/**
* Load the configuration file for the gateway
*
* @param file The filename of the configuration file
*/
int
config_load(char *file)
{
CONFIG_CONTEXT config;
int rval;
global_defaults();
config.object = "";
config.next = NULL;
if (ini_parse(file, handler, &config) < 0)
return 0;
config_file = file;
rval = process_config_context(config.next);
free_config_context(config.next);
return rval;
}
/**
* Relooad the configuration file for the gateway
*
*/
int
config_reload()
{
CONFIG_CONTEXT config;
int rval;
if (!config_file)
return 0;
global_defaults();
config.object = "";
config.next = NULL;
if (ini_parse(config_file, handler, &config) < 0)
return 0;
rval = process_config_update(config.next);
free_config_context(config.next);
return rval;
}
/**
* Process a configuration context and turn it into the set of object
* we need.
*
* @param context The configuration data
*/
static int
process_config_context(CONFIG_CONTEXT *context)
{
CONFIG_CONTEXT *obj;
/**
* Process the data and create the services and servers defined
* in the data.
*/
obj = context;
while (obj)
{
char *type = config_get_value(obj->parameters, "type");
if (type == NULL)
skygw_log_write(NULL, LOGFILE_ERROR, "Object %s has no type\n", obj->object);
else if (!strcmp(type, "service"))
{
char *router = config_get_value(obj->parameters, "router");
if (router)
{
obj->element = service_alloc(obj->object, router);
char *user = config_get_value(obj->parameters, "user");
char *auth = config_get_value(obj->parameters, "auth");
if (obj->element && user && auth)
serviceSetUser(obj->element, user, auth);
}
else
skygw_log_write(NULL, LOGFILE_ERROR, "No router define for service '%s'\n",
obj->object);
}
else if (!strcmp(type, "server"))
{
char *address = config_get_value(obj->parameters, "address");
char *port = config_get_value(obj->parameters, "port");
char *protocol = config_get_value(obj->parameters, "protocol");
char *monuser = config_get_value(obj->parameters, "monitoruser");
char *monpw = config_get_value(obj->parameters, "monitorpw");
if (address && port && protocol)
obj->element = server_alloc(address, protocol, atoi(port));
if (obj->element && monuser && monpw)
serverAddMonUser(obj->element, monuser, monpw);
}
obj = obj->next;
}
/*
* Now we have the services we can add the servers to the services
* add the protocols to the services
*/
obj = context;
while (obj)
{
char *type = config_get_value(obj->parameters, "type");
if (type == NULL)
;
else if (!strcmp(type, "service"))
{
char *servers = config_get_value(obj->parameters, "servers");
char *roptions = config_get_value(obj->parameters, "router_options");
if (servers && obj->element)
{
char *s = strtok(servers, ",");
while (s)
{
CONFIG_CONTEXT *obj1 = context;
while (obj1)
{
if (strcmp(s, obj1->object) == 0 && obj->element && obj1->element)
serviceAddBackend(obj->element, obj1->element);
obj1 = obj1->next;
}
s = strtok(NULL, ",");
}
}
if (roptions && obj->element)
{
char *s = strtok(roptions, ",");
while (s)
{
serviceAddRouterOption(obj->element, s);
s = strtok(NULL, ",");
}
}
}
else if (!strcmp(type, "listener"))
{
char *service = config_get_value(obj->parameters, "service");
char *port = config_get_value(obj->parameters, "port");
char *protocol = config_get_value(obj->parameters, "protocol");
if (service && port && protocol)
{
CONFIG_CONTEXT *ptr = context;
while (ptr && strcmp(ptr->object, service) != 0)
ptr = ptr->next;
if (ptr && ptr->element)
serviceAddProtocol(ptr->element, protocol, atoi(port));
}
}
else if (!strcmp(type, "monitor"))
{
char *module = config_get_value(obj->parameters, "module");
char *servers = config_get_value(obj->parameters, "servers");
char *user = config_get_value(obj->parameters, "user");
char *passwd = config_get_value(obj->parameters, "passwd");
if (module)
{
obj->element = monitor_alloc(obj->object, module);
if (servers && obj->element)
{
char *s = strtok(servers, ",");
while (s)
{
CONFIG_CONTEXT *obj1 = context;
while (obj1)
{
if (strcmp(s, obj1->object) == 0 && obj->element && obj1->element)
monitorAddServer(obj->element, obj1->element);
obj1 = obj1->next;
}
s = strtok(NULL, ",");
}
}
if (obj->element && user && passwd)
{
monitorAddUser(obj->element, user, passwd);
}
}
}
obj = obj->next;
}
return 1;
}
/**
* Get the value of a config parameter
*
* @param params The linked list of config parameters
* @param name The parameter to return
* @return the parameter value or NULL if not found
*/
static char *
config_get_value(CONFIG_PARAMETER *params, const char *name)
{
while (params)
{
if (!strcmp(params->name, name))
return params->value;
params = params->next;
}
return NULL;
}
/**
* Free a config tree
*
* @param context The configuration data
*/
static void
free_config_context(CONFIG_CONTEXT *context)
{
CONFIG_CONTEXT *obj;
CONFIG_PARAMETER *p1, *p2;
while (context)
{
free(context->object);
p1 = context->parameters;
while (p1)
{
free(p1->name);
free(p1->value);
p2 = p1->next;
free(p1);
p1 = p2;
}
obj = context->next;
free(context);
context = obj;
}
}
/**
* Return the number of configured threads
*
* @return The number of threads configured in the config file
*/
int
config_threadcount()
{
return gateway.n_threads;
}
/**
* Configuration handler for items in the global [gateway] section
*
* @param name The item name
* @param value The item value
* @return 0 on error
*/
static int
handle_global_item(const char *name, const char *value)
{
if (!strcmp(name, "threads") == 0)
gateway.n_threads = atoi(value);
else
return 0;
return 1;
}
/**
* Set the defaults for the global configuration options
*/
static void
global_defaults()
{
gateway.n_threads = 1;
}
/**
* Process a configuration context update and turn it into the set of object
* we need.
*
* @param context The configuration data
*/
static int
process_config_update(CONFIG_CONTEXT *context)
{
CONFIG_CONTEXT *obj;
SERVICE *service;
SERVER *server;
/**
* Process the data and create the services and servers defined
* in the data.
*/
obj = context;
while (obj)
{
char *type = config_get_value(obj->parameters, "type");
if (type == NULL)
skygw_log_write(NULL, LOGFILE_ERROR, "Object %s has no type\n", obj->object);
else if (!strcmp(type, "service"))
{
char *router = config_get_value(obj->parameters, "router");
if (router)
{
if ((service = service_find(obj->object)) != NULL)
{
char *user = config_get_value(obj->parameters, "user");
char *auth = config_get_value(obj->parameters, "auth");
service_update(service, router, user, auth);
obj->element = service;
}
else
{
obj->element = service_alloc(obj->object, router);
char *user = config_get_value(obj->parameters, "user");
char *auth = config_get_value(obj->parameters, "auth");
if (obj->element && user && auth)
serviceSetUser(obj->element, user, auth);
}
}
else
skygw_log_write(NULL, LOGFILE_ERROR, "No router defined for service '%s'\n",
obj->object);
}
else if (!strcmp(type, "server"))
{
char *address = config_get_value(obj->parameters, "address");
char *port = config_get_value(obj->parameters, "port");
char *protocol = config_get_value(obj->parameters, "protocol");
char *monuser = config_get_value(obj->parameters, "monitoruser");
char *monpw = config_get_value(obj->parameters, "monitorpw");
if (address && port && protocol)
{
if ((server = server_find(address, atoi(port))) != NULL)
{
server_update(server, protocol, monuser, monpw);
obj->element = server;
}
else
{
obj->element = server_alloc(address, protocol, atoi(port));
if (obj->element && monuser && monpw)
serverAddMonUser(obj->element, monuser, monpw);
}
}
}
obj = obj->next;
}
/*
* Now we have the services we can add the servers to the services
* add the protocols to the services
*/
obj = context;
while (obj)
{
char *type = config_get_value(obj->parameters, "type");
if (type == NULL)
;
else if (!strcmp(type, "service"))
{
char *servers = config_get_value(obj->parameters, "servers");
char *roptions = config_get_value(obj->parameters, "router_options");
if (servers && obj->element)
{
char *s = strtok(servers, ",");
while (s)
{
CONFIG_CONTEXT *obj1 = context;
while (obj1)
{
if (strcmp(s, obj1->object) == 0 && obj->element && obj1->element)
if (!serviceHasBackend(obj->element, obj1->element))
serviceAddBackend(obj->element, obj1->element);
obj1 = obj1->next;
}
s = strtok(NULL, ",");
}
}
if (roptions && obj->element)
{
char *s = strtok(roptions, ",");
serviceClearRouterOptions(obj->element);
while (s)
{
serviceAddRouterOption(obj->element, s);
s = strtok(NULL, ",");
}
}
}
else if (!strcmp(type, "listener"))
{
char *service = config_get_value(obj->parameters, "service");
char *port = config_get_value(obj->parameters, "port");
char *protocol = config_get_value(obj->parameters, "protocol");
if (service && port && protocol)
{
CONFIG_CONTEXT *ptr = context;
while (ptr && strcmp(ptr->object, service) != 0)
ptr = ptr->next;
if (ptr && ptr->element && serviceHasProtocol(ptr->element, protocol, atoi(port)) == 0)
{
serviceAddProtocol(ptr->element, protocol, atoi(port));
serviceStartProtocol(ptr->element, protocol, atoi(port));
}
}
}
obj = obj->next;
}
return 1;
}

181
server/core/dbusers.c Normal file
View File

@ -0,0 +1,181 @@
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
/**
* @file dbusers.c - Loading MySQL users from a MySQL backend server, this needs libmysqlclient.so and header files
*
* @verbatim
* Revision History
*
* Date Who Description
* 24/06/2013 Massimiliano Pinto Initial implementation
*
* @endverbatim
*/
#include <stdio.h>
#include <mysql.h>
#include <dcb.h>
#include <service.h>
#include <users.h>
#include <skygw_utils.h>
#include <log_manager.h>
#include <secrets.h>
static int getUsers(SERVICE *service, struct users *users);
/**
* Load the user/passwd form mysql.user table into the service users' hashtable
* environment.
*
* @param service The current service
* @return -1 on any error or the number of users inserted (0 means no users at all)
*/
int
load_mysql_users(SERVICE *service)
{
return getUsers(service, service->users);
}
/**
* Reload the user/passwd form mysql.user table into the service users' hashtable
* environment.
*
* @param service The current service
* @return -1 on any error or the number of users inserted (0 means no users at all)
*/
int
reload_mysql_users(SERVICE *service)
{
int i;
struct users *newusers, *oldusers;
if ((newusers = users_alloc()) == NULL)
return 0;
i = getUsers(service, newusers);
spinlock_acquire(&service->spin);
oldusers = service->users;
service->users = newusers;
spinlock_release(&service->spin);
users_free(oldusers);
return i;
}
/**
* Load the user/passwd form mysql.user table into the service users' hashtable
* environment.
*
* @param service The current service
* @param users The users table into which to load the users
* @return -1 on any error or the number of users inserted (0 means no users at all)
*/
static int
getUsers(SERVICE *service, struct users *users)
{
MYSQL *con = NULL;
MYSQL_ROW row;
MYSQL_RES *result = NULL;
int num_fields = 0;
char *service_user = NULL;
char *service_passwd = NULL;
char *dpwd;
int total_users = 0;
SERVER *server;
serviceGetUser(service, &service_user, &service_passwd);
/** multi-thread environment requires that thread init succeeds. */
if (mysql_thread_init()) {
skygw_log_write_flush(NULL, LOGFILE_ERROR, "ERROR : mysql_thread_init failed.\n");
return -1;
}
con = mysql_init(NULL);
if (con == NULL) {
skygw_log_write(NULL, LOGFILE_ERROR, "mysql_init: %s\n", mysql_error(con));
return -1;
}
if (mysql_options(con, MYSQL_OPT_USE_REMOTE_CONNECTION, NULL)) {
skygw_log_write_flush(NULL, LOGFILE_ERROR, "Fatal : failed to set external connection. "
"It is needed for backend server connections. Exiting.\n");
return -1;
}
/*
* Attempt to connect to each database in the service in turn until
* we find one that we can connect to or until we run out of databases
* to try
*/
server = service->databases;
dpwd = decryptPassword(service_passwd);
while (server && mysql_real_connect(con,
server->name,
service_user,
dpwd,
NULL,
server->port,
NULL,
0) == NULL)
{
server = server->nextdb;
}
free(dpwd);
if (server == NULL)
{
skygw_log_write(NULL, LOGFILE_ERROR,
"Unable to find a to load user data from for service %s\n",
service->name);
mysql_close(con);
return -1;
}
if (mysql_query(con, "SELECT user, password FROM mysql.user")) {
skygw_log_write(NULL, LOGFILE_ERROR,
"Loading users for service %s encountered error: %s\n",
service->name, mysql_error(con));
mysql_close(con);
return -1;
}
result = mysql_store_result(con);
if (result == NULL) {
skygw_log_write(NULL, LOGFILE_ERROR,
"Loading users for service %s encountered error: %s\n",
service->name, mysql_error(con));
mysql_close(con);
return -1;
}
num_fields = mysql_num_fields(result);
while ((row = mysql_fetch_row(result))) {
// we assume here two fields are returned !!!
// now adding to the hastable user and passwd+1 (escaping the first byte that is '*')
users_add(users, row[0], row[1]+1);
total_users++;
}
mysql_free_result(result);
mysql_close(con);
mysql_thread_end();
return total_users;
}

690
server/core/dcb.c Normal file
View File

@ -0,0 +1,690 @@
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
/**
* @file dcb.c - Descriptor Control Block generic functions
*
* Descriptor control blocks provide the key mechanism for the interface
* with the non-blocking socket polling routines. The descriptor control
* block is the user data that is handled by the epoll system and contains
* the state data and pointers to other components that relate to the
* use of a file descriptor.
*
* @verbatim
* Revision History
*
* Date Who Description
* 12/06/13 Mark Riddoch Initial implementation
* 21/06/13 Massimiliano Pinto free_dcb is used
* 25/06/13 Massimiliano Pinto Added checks to session and router_session
* 28/06/13 Mark Riddoch Changed the free mechanism ti
* introduce a zombie state for the
* dcb
* 02/07/2013 Massimiliano Pinto Addition of delayqlock, delayq and authlock
* for handling backend asynchronous protocol connection
* and a generic lock for backend authentication
* 16/07/2013 Massimiliano Pinto Added command type for dcb
* 23/07/13 Mark Riddoch Tidy up logging
*
* @endverbatim
*/
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <dcb.h>
#include <spinlock.h>
#include <server.h>
#include <session.h>
#include <service.h>
#include <modules.h>
#include <router.h>
#include <errno.h>
#include <gw.h>
#include <poll.h>
#include <atomic.h>
#include <skygw_utils.h>
#include <log_manager.h>
static DCB *allDCBs = NULL; /* Diagnotics need a list of DCBs */
static DCB *zombies = NULL;
static SPINLOCK dcbspin = SPINLOCK_INIT;
static SPINLOCK zombiespin = SPINLOCK_INIT;
static void dcb_final_free(DCB *dcb);
/**
* Allocate a new DCB.
*
* This routine performs the generic initialisation on the DCB before returning
* the newly allocated DCB.
*
* @return A newly allocated DCB or NULL if non could be allocated.
*/
DCB *
dcb_alloc()
{
DCB *rval;
if ((rval = malloc(sizeof(DCB))) == NULL)
{
return NULL;
}
spinlock_init(&rval->writeqlock);
spinlock_init(&rval->delayqlock);
spinlock_init(&rval->authlock);
rval->writeq = NULL;
rval->delayq = NULL;
rval->remote = NULL;
rval->state = DCB_STATE_ALLOC;
rval->next = NULL;
rval->data = NULL;
rval->protocol = NULL;
rval->session = NULL;
memset(&rval->stats, 0, sizeof(DCBSTATS)); // Zero the statistics
bitmask_init(&rval->memdata.bitmask);
rval->memdata.next = NULL;
rval->command = 0;
spinlock_acquire(&dcbspin);
if (allDCBs == NULL)
allDCBs = rval;
else
{
DCB *ptr = allDCBs;
while (ptr->next)
ptr = ptr->next;
ptr->next = rval;
}
spinlock_release(&dcbspin);
return rval;
}
/**
* Free a DCB, this only marks the DCB as a zombie and adds it
* to the zombie list. The real working of removing it occurs once
* all the threads signal they no longer have access to the DCB
*
* @param dcb The DCB to free
*/
void
dcb_free(DCB *dcb)
{
if (dcb->state == DCB_STATE_ZOMBIE)
{
skygw_log_write(NULL, LOGFILE_ERROR, "Call to free a DCB that is already a zombie.\n");
return;
}
/* Set the bitmask of running pollng threads */
bitmask_copy(&dcb->memdata.bitmask, poll_bitmask());
/* Add the DCB to the Zombie list */
spinlock_acquire(&zombiespin);
if (zombies == NULL)
zombies = dcb;
else
{
DCB *ptr = zombies;
while (ptr->memdata.next)
{
if (ptr == dcb)
{
skygw_log_write(NULL, LOGFILE_ERROR, "Attempt to add DCB to zombie queue "
"when it is already in the queue");
break;
}
ptr = ptr->memdata.next;
}
if (ptr != dcb)
ptr->memdata.next = dcb;
}
spinlock_release(&zombiespin);
dcb->state = DCB_STATE_ZOMBIE;
}
/**
* Free a DCB and remove it from the chain of all DCBs
*
* NB This is called with the caller holding the zombie queue
* spinlock
*
* @param dcb The DCB to free
*/
static void
dcb_final_free(DCB *dcb)
{
dcb->state = DCB_STATE_FREED;
/* First remove this DCB from the chain */
spinlock_acquire(&dcbspin);
if (allDCBs == dcb)
{
/*
* Deal with the special case of removing the DCB at the head of
* the chain.
*/
allDCBs = dcb->next;
}
else
{
/*
* We find the DCB that pont to the one we are removing and then
* set the next pointer of that DCB to the next pointer of the
* DCB we are removing.
*/
DCB *ptr = allDCBs;
while (ptr && ptr->next != dcb)
ptr = ptr->next;
if (ptr)
ptr->next = dcb->next;
}
spinlock_release(&dcbspin);
if (dcb->protocol)
free(dcb->protocol);
if (dcb->data)
free(dcb->data);
if (dcb->remote)
free(dcb->remote);
bitmask_free(&dcb->memdata.bitmask);
free(dcb);
}
/**
* Process the DCB zombie queue
*
* This routine is called by each of the polling threads with
* the thread id of the polling thread. It must clear the bit in
* the memdata btmask for the polling thread that calls it. If the
* operation of clearing this bit means that no bits are set in
* the memdata.bitmask then the DCB is no longer able to be
* referenced and it can be finally removed.
*
* @param threadid The thread ID of the caller
*/
void
dcb_process_zombies(int threadid)
{
DCB *ptr, *lptr;
spinlock_acquire(&zombiespin);
ptr = zombies;
lptr = NULL;
while (ptr)
{
bitmask_clear(&ptr->memdata.bitmask, threadid);
if (bitmask_isallclear(&ptr->memdata.bitmask))
{
/*
* Remove the DCB from the zombie queue
* and call the final free routine for the
* DCB
*
* ptr is the DCB we are processing
* lptr is the previous DCB on the zombie queue
* or NULL if the DCB is at the head of the queue
* tptr is the DCB after the one we are processing
* on the zombie queue
*/
DCB *tptr = ptr->memdata.next;
if (lptr == NULL)
zombies = tptr;
else
lptr->memdata.next = tptr;
dcb_final_free(ptr);
ptr = tptr;
}
else
{
lptr = ptr;
ptr = ptr->memdata.next;
}
}
spinlock_release(&zombiespin);
}
/**
* Connect to a server
*
* This routine will create a server connection
* If succesful the new dcb will be put in
* epoll set by dcb->func.connect
*
* @param server The server to connect to
* @param session The session this connection is being made for
* @param protocol The protocol module to use
* @return The new allocated dcb
*/
DCB *
dcb_connect(SERVER *server, SESSION *session, const char *protocol)
{
DCB *dcb;
GWPROTOCOL *funcs;
if ((dcb = dcb_alloc()) == NULL)
{
return NULL;
}
if ((funcs = (GWPROTOCOL *)load_module(protocol, MODULE_PROTOCOL)) == NULL)
{
dcb_final_free(dcb);
skygw_log_write(NULL, LOGFILE_ERROR,
"Failed to load protocol module for %s, feee dcb %p\n", protocol, dcb);
return NULL;
}
memcpy(&(dcb->func), funcs, sizeof(GWPROTOCOL));
dcb->session = session;
if ((dcb->fd = dcb->func.connect(dcb, server, session)) == -1)
{
dcb_final_free(dcb);
skygw_log_write(NULL, LOGFILE_ERROR, "Failed to connect to server %s:%d, free dcb %p\n",
server->name, server->port, dcb);
return NULL;
}
/*
* The dcb will be addded into poll set by dcb->func.connect
*/
atomic_add(&server->stats.n_connections, 1);
atomic_add(&server->stats.n_current, 1);
/*
* We are now connected, the authentication etc will happen as
* part of the EPOLLOUT event that will be received once the connection
* is established.
*/
return dcb;
}
/**
* General purpose read routine to read data from a socket in the
* Descriptor Control Block and append it to a linked list of buffers.
* The list may be empty, in which case *head == NULL
*
* @param dcb The DCB to read from
* @param head Pointer to linked list to append data to
* @return The numebr of bytes read or -1 on fatal error
*/
int
dcb_read(DCB *dcb, GWBUF **head)
{
GWBUF *buffer = NULL;
int b, n = 0;
ioctl(dcb->fd, FIONREAD, &b);
while (b > 0)
{
int bufsize = b < MAX_BUFFER_SIZE ? b : MAX_BUFFER_SIZE;
if ((buffer = gwbuf_alloc(bufsize)) == NULL)
{
return n ? n : -1;
}
GW_NOINTR_CALL(n = read(dcb->fd, GWBUF_DATA(buffer), bufsize); dcb->stats.n_reads++);
if (n < 0)
{
if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
{
return n;
}
else
{
return n ? n : -1;
}
}
else if (n == 0)
{
return n;
}
// append read data to the gwbuf
*head = gwbuf_append(*head, buffer);
/* Re issue the ioctl as the amount of data buffered may have changed */
ioctl(dcb->fd, FIONREAD, &b);
}
return n;
}
/**
* General purpose routine to write to a DCB
*
* @param dcb The DCB of the client
* @param queue Queue of buffers to write
*/
int
dcb_write(DCB *dcb, GWBUF *queue)
{
int w, saved_errno = 0;
spinlock_acquire(&dcb->writeqlock);
if (dcb->writeq)
{
/*
* We have some queued data, so add our data to
* the write queue and return.
* The assumption is that there will be an EPOLLOUT
* event to drain what is already queued. We are protected
* by the spinlock, which will also be acquired by the
* the routine that drains the queue data, so we should
* not have a race condition on the event.
*/
dcb->writeq = gwbuf_append(dcb->writeq, queue);
dcb->stats.n_buffered++;
}
else
{
int len;
/*
* Loop over the buffer chain that has been passed to us
* from the reading side.
* Send as much of the data in that chain as possible and
* add any balance to the write queue.
*/
while (queue != NULL)
{
len = GWBUF_LENGTH(queue);
GW_NOINTR_CALL(w = write(dcb->fd, GWBUF_DATA(queue), len); dcb->stats.n_writes++);
saved_errno = errno;
if (w < 0)
{
break;
}
/*
* Pull the number of bytes we have written from
* queue with have.
*/
queue = gwbuf_consume(queue, w);
if (w < len)
{
/* We didn't write all the data */
}
}
/* Buffer the balance of any data */
dcb->writeq = queue;
if (queue)
{
dcb->stats.n_buffered++;
}
}
spinlock_release(&dcb->writeqlock);
if (queue && (saved_errno != EAGAIN || saved_errno != EWOULDBLOCK))
{
/* We had a real write failure that we must deal with */
return 0;
}
return 1;
}
/**
* Drain the write queue of a DCB. THis is called as part of the EPOLLOUT handling
* of a socket and will try to send any buffered data from the write queue
* up until the point the write would block.
*
* @param dcb DCB to drain the write queue of
* @return The number of bytes written
*/
int
dcb_drain_writeq(DCB *dcb)
{
int n = 0;
int w;
int saved_errno = 0;
spinlock_acquire(&dcb->writeqlock);
if (dcb->writeq)
{
int len;
/*
* Loop over the buffer chain in the pending writeq
* Send as much of the data in that chain as possible and
* leave any balance on the write queue.
*/
while (dcb->writeq != NULL)
{
len = GWBUF_LENGTH(dcb->writeq);
GW_NOINTR_CALL(w = write(dcb->fd, GWBUF_DATA(dcb->writeq), len););
saved_errno = errno;
if (w < 0)
{
break;
}
/*
* Pull the number of bytes we have written from
* queue with have.
*/
dcb->writeq = gwbuf_consume(dcb->writeq, w);
if (w < len)
{
/* We didn't write all the data */
}
n += w;
}
}
spinlock_release(&dcb->writeqlock);
return n;
}
/**
* Close a DCB
*
* Generic, non-protocol specific close funcitonality
* @param dcb The DCB to close
*/
void
dcb_close(DCB *dcb)
{
poll_remove_dcb(dcb);
close(dcb->fd);
dcb->state = DCB_STATE_DISCONNECTED;
if (dcb_isclient(dcb))
{
/*
* If the DCB we are closing is a client side DCB then shutdown the
* router session. This will close any backend connections.
*/
SERVICE *service = dcb->session->service;
if (service && service->router && dcb->session->router_session)
{
service->router->closeSession(service->router_instance,
dcb->session->router_session);
}
session_free(dcb->session);
}
dcb_free(dcb);
}
/**
* Diagnostic to print a DCB
*
* @param dcb The DCB to print
*
*/
void
printDCB(DCB *dcb)
{
printf("DCB: %p\n", (void *)dcb);
printf("\tDCB state: %s\n", gw_dcb_state2string(dcb->state));
if (dcb->remote)
printf("\tConnected to: %s\n", dcb->remote);
printf("\tQueued write data: %d\n", gwbuf_length(dcb->writeq));
printf("\tStatistics:\n");
printf("\t\tNo. of Reads: %d\n", dcb->stats.n_reads);
printf("\t\tNo. of Writes: %d\n", dcb->stats.n_writes);
printf("\t\tNo. of Buffered Writes: %d\n", dcb->stats.n_buffered);
printf("\t\tNo. of Accepts: %d\n", dcb->stats.n_accepts);
}
/**
* Diagnostic to print all DCB allocated in the system
*
*/
void printAllDCBs()
{
DCB *dcb;
spinlock_acquire(&dcbspin);
dcb = allDCBs;
while (dcb)
{
printDCB(dcb);
dcb = dcb->next;
}
spinlock_release(&dcbspin);
}
/**
* Diagnostic to print all DCB allocated in the system
*
*/
void dprintAllDCBs(DCB *pdcb)
{
DCB *dcb;
spinlock_acquire(&dcbspin);
dcb = allDCBs;
while (dcb)
{
dcb_printf(pdcb, "DCB: %p\n", (void *)dcb);
dcb_printf(pdcb, "\tDCB state: %s\n", gw_dcb_state2string(dcb->state));
if (dcb->session && dcb->session->service)
dcb_printf(pdcb, "\tService: %s\n", dcb->session->service->name);
if (dcb->remote)
dcb_printf(pdcb, "\tConnected to: %s\n", dcb->remote);
dcb_printf(pdcb, "\tQueued write data: %d\n", gwbuf_length(dcb->writeq));
dcb_printf(pdcb, "\tStatistics:\n");
dcb_printf(pdcb, "\t\tNo. of Reads: %d\n", dcb->stats.n_reads);
dcb_printf(pdcb, "\t\tNo. of Writes: %d\n", dcb->stats.n_writes);
dcb_printf(pdcb, "\t\tNo. of Buffered Writes: %d\n", dcb->stats.n_buffered);
dcb_printf(pdcb, "\t\tNo. of Accepts: %d\n", dcb->stats.n_accepts);
dcb = dcb->next;
}
spinlock_release(&dcbspin);
}
/**
* Diagnostic to print a DCB to another DCB
*
* @param pdcb The DCB to which send the output
* @param dcb The DCB to print
*/
void
dprintDCB(DCB *pdcb, DCB *dcb)
{
dcb_printf(pdcb, "DCB: %p\n", (void *)dcb);
dcb_printf(pdcb, "\tDCB state: %s\n", gw_dcb_state2string(dcb->state));
if (dcb->remote)
dcb_printf(pdcb, "\tConnected to: %s\n", dcb->remote);
dcb_printf(pdcb, "\tOwning Session: %d\n", dcb->session);
dcb_printf(pdcb, "\tQueued write data: %d\n", gwbuf_length(dcb->writeq));
dcb_printf(pdcb, "\tStatistics:\n");
dcb_printf(pdcb, "\t\tNo. of Reads: %d\n", dcb->stats.n_reads);
dcb_printf(pdcb, "\t\tNo. of Writes: %d\n", dcb->stats.n_writes);
dcb_printf(pdcb, "\t\tNo. of Buffered Writes: %d\n", dcb->stats.n_buffered);
dcb_printf(pdcb, "\t\tNo. of Accepts: %d\n", dcb->stats.n_accepts);
}
/**
* Return a string representation of a DCB state.
*
* @param state The DCB state
* @return String representation of the state
*
*/
const char *
gw_dcb_state2string (int state) {
switch(state) {
case DCB_STATE_ALLOC:
return "DCB Allocated";
case DCB_STATE_IDLE:
return "DCB not yet in polling";
case DCB_STATE_POLLING:
return "DCB in the polling loop";
case DCB_STATE_PROCESSING:
return "DCB processing event";
case DCB_STATE_LISTENING:
return "DCB for listening socket";
case DCB_STATE_DISCONNECTED:
return "DCB socket closed";
case DCB_STATE_FREED:
return "DCB memory could be freed";
case DCB_STATE_ZOMBIE:
return "DCB Zombie";
default:
return "DCB (unknown)";
}
}
/**
* A DCB based wrapper for printf. Allows formattign printing to
* a descritor control block.
*
* @param dcb Descriptor to write to
* @param fmt A printf format string
* @param ... Variable arguments for the print format
*/
void
dcb_printf(DCB *dcb, const char *fmt, ...)
{
GWBUF *buf;
va_list args;
if ((buf = gwbuf_alloc(10240)) == NULL)
return;
va_start(args, fmt);
vsnprintf(GWBUF_DATA(buf), 10240, fmt, args);
va_end(args);
buf->end = GWBUF_DATA(buf) + strlen(GWBUF_DATA(buf));
dcb->func.write(dcb, buf);
}
/**
* Determine the role that a DCB plays within a session.
*
* @param dcb
* @return Non-zero if the DCB is the client of the session
*/
int
dcb_isclient(DCB *dcb)
{
if(dcb->session) {
if (dcb->session->client) {
return (dcb->session && dcb == dcb->session->client);
}
}
return 0;
}

686
server/core/depend.mk Normal file
View File

@ -0,0 +1,686 @@
atomic.o: atomic.c
buffer.o: buffer.c /usr/include/stdlib.h /usr/include/features.h \
/usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
/usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \
/usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \
/usr/include/endian.h /usr/include/bits/endian.h \
/usr/include/bits/byteswap.h /usr/include/sys/types.h \
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
/usr/include/time.h /usr/include/sys/select.h /usr/include/bits/select.h \
/usr/include/bits/sigset.h /usr/include/bits/time.h \
/usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \
/usr/include/alloca.h ../include/buffer.h ../include/atomic.h
spinlock.o: spinlock.c ../include/spinlock.h ../include/thread.h \
/usr/include/pthread.h /usr/include/features.h /usr/include/sys/cdefs.h \
/usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \
/usr/include/gnu/stubs-64.h /usr/include/endian.h \
/usr/include/bits/endian.h /usr/include/bits/byteswap.h \
/usr/include/sched.h /usr/include/bits/types.h \
/usr/include/bits/typesizes.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \
/usr/include/time.h /usr/include/bits/sched.h /usr/include/bits/time.h \
/usr/include/xlocale.h /usr/include/bits/pthreadtypes.h \
/usr/include/bits/setjmp.h ../include/atomic.h
gateway.o: gateway.c ../include/gw.h /usr/include/stdio.h \
/usr/include/features.h /usr/include/sys/cdefs.h \
/usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \
/usr/include/gnu/stubs-64.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
/usr/include/ctype.h /usr/include/endian.h /usr/include/bits/endian.h \
/usr/include/bits/byteswap.h /usr/include/xlocale.h /usr/include/errno.h \
/usr/include/bits/errno.h /usr/include/linux/errno.h \
/usr/include/asm/errno.h /usr/include/asm-generic/errno.h \
/usr/include/asm-generic/errno-base.h /usr/include/netdb.h \
/usr/include/netinet/in.h /usr/include/stdint.h \
/usr/include/bits/wchar.h /usr/include/sys/socket.h \
/usr/include/sys/uio.h /usr/include/sys/types.h /usr/include/time.h \
/usr/include/sys/select.h /usr/include/bits/select.h \
/usr/include/bits/sigset.h /usr/include/bits/time.h \
/usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \
/usr/include/bits/uio.h /usr/include/bits/socket.h \
/usr/include/bits/sockaddr.h /usr/include/asm/socket.h \
/usr/include/asm-generic/socket.h /usr/include/asm/sockios.h \
/usr/include/asm-generic/sockios.h /usr/include/bits/in.h \
/usr/include/rpc/netdb.h /usr/include/bits/netdb.h /usr/include/fcntl.h \
/usr/include/bits/fcntl.h /usr/include/bits/stat.h /usr/include/unistd.h \
/usr/include/bits/posix_opt.h /usr/include/bits/environments.h \
/usr/include/bits/confname.h /usr/include/getopt.h /usr/include/syslog.h \
/usr/include/sys/syslog.h /usr/include/bits/syslog-path.h \
/usr/include/string.h /usr/include/stdlib.h \
/usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \
/usr/include/alloca.h /usr/include/pwd.h /usr/include/sys/epoll.h \
/usr/include/signal.h /usr/include/bits/signum.h \
/usr/include/bits/siginfo.h /usr/include/bits/sigaction.h \
/usr/include/bits/sigcontext.h /usr/include/bits/sigstack.h \
/usr/include/sys/ucontext.h /usr/include/bits/sigthread.h \
/usr/include/sys/ioctl.h /usr/include/bits/ioctls.h \
/usr/include/asm/ioctls.h /usr/include/asm-generic/ioctls.h \
/usr/include/linux/ioctl.h /usr/include/asm/ioctl.h \
/usr/include/asm-generic/ioctl.h /usr/include/bits/ioctl-types.h \
/usr/include/sys/ttydefaults.h /usr/include/arpa/inet.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdbool.h \
../include/gateway_mysql.h ../include/dcb.h ../include/spinlock.h \
../include/thread.h /usr/include/pthread.h /usr/include/sched.h \
/usr/include/bits/sched.h /usr/include/bits/setjmp.h ../include/buffer.h \
../include/gwbitmask.h ../include/mysql_protocol.h ../include/dcb.h \
../include/service.h ../include/server.h ../include/session.h \
../include/modules.h ../include/config.h ../include/poll.h \
/usr/include/mysql/mysql.h /usr/include/mysql/mysql_version.h \
/usr/include/mysql/mysql_com.h /usr/include/mysql/mysql_time.h \
/usr/include/mysql/my_list.h /usr/include/mysql/typelib.h \
/usr/include/mysql/my_alloc.h /usr/include/sys/stat.h \
/home/mriddoch/Repository/skygateway/utils/skygw_utils.h \
/home/mriddoch/Repository/skygateway/utils/skygw_types.h \
/usr/include/math.h /usr/include/bits/huge_val.h \
/usr/include/bits/huge_valf.h /usr/include/bits/huge_vall.h \
/usr/include/bits/inf.h /usr/include/bits/nan.h \
/usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h \
/home/mriddoch/Repository/skygateway/utils/skygw_debug.h \
/usr/include/assert.h \
/home/mriddoch/Repository/skygateway/log_manager/log_manager.h
gateway_mysql_protocol.o: gateway_mysql_protocol.c ../include/gw.h \
/usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h \
/usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \
/usr/include/gnu/stubs-64.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
/usr/include/ctype.h /usr/include/endian.h /usr/include/bits/endian.h \
/usr/include/bits/byteswap.h /usr/include/xlocale.h /usr/include/errno.h \
/usr/include/bits/errno.h /usr/include/linux/errno.h \
/usr/include/asm/errno.h /usr/include/asm-generic/errno.h \
/usr/include/asm-generic/errno-base.h /usr/include/netdb.h \
/usr/include/netinet/in.h /usr/include/stdint.h \
/usr/include/bits/wchar.h /usr/include/sys/socket.h \
/usr/include/sys/uio.h /usr/include/sys/types.h /usr/include/time.h \
/usr/include/sys/select.h /usr/include/bits/select.h \
/usr/include/bits/sigset.h /usr/include/bits/time.h \
/usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \
/usr/include/bits/uio.h /usr/include/bits/socket.h \
/usr/include/bits/sockaddr.h /usr/include/asm/socket.h \
/usr/include/asm-generic/socket.h /usr/include/asm/sockios.h \
/usr/include/asm-generic/sockios.h /usr/include/bits/in.h \
/usr/include/rpc/netdb.h /usr/include/bits/netdb.h /usr/include/fcntl.h \
/usr/include/bits/fcntl.h /usr/include/bits/stat.h /usr/include/unistd.h \
/usr/include/bits/posix_opt.h /usr/include/bits/environments.h \
/usr/include/bits/confname.h /usr/include/getopt.h /usr/include/syslog.h \
/usr/include/sys/syslog.h /usr/include/bits/syslog-path.h \
/usr/include/string.h /usr/include/stdlib.h \
/usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \
/usr/include/alloca.h /usr/include/pwd.h /usr/include/sys/epoll.h \
/usr/include/signal.h /usr/include/bits/signum.h \
/usr/include/bits/siginfo.h /usr/include/bits/sigaction.h \
/usr/include/bits/sigcontext.h /usr/include/bits/sigstack.h \
/usr/include/sys/ucontext.h /usr/include/bits/sigthread.h \
/usr/include/sys/ioctl.h /usr/include/bits/ioctls.h \
/usr/include/asm/ioctls.h /usr/include/asm-generic/ioctls.h \
/usr/include/linux/ioctl.h /usr/include/asm/ioctl.h \
/usr/include/asm-generic/ioctl.h /usr/include/bits/ioctl-types.h \
/usr/include/sys/ttydefaults.h /usr/include/arpa/inet.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdbool.h \
../include/gateway_mysql.h ../include/dcb.h ../include/spinlock.h \
../include/thread.h /usr/include/pthread.h /usr/include/sched.h \
/usr/include/bits/sched.h /usr/include/bits/setjmp.h ../include/buffer.h \
../include/gwbitmask.h ../include/mysql_protocol.h ../include/dcb.h \
../include/session.h /usr/include/openssl/sha.h \
/usr/include/openssl/e_os2.h /usr/include/openssl/opensslconf.h \
/usr/include/openssl/opensslconf-x86_64.h
gw_utils.o: gw_utils.c ../include/gw.h /usr/include/stdio.h \
/usr/include/features.h /usr/include/sys/cdefs.h \
/usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \
/usr/include/gnu/stubs-64.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
/usr/include/ctype.h /usr/include/endian.h /usr/include/bits/endian.h \
/usr/include/bits/byteswap.h /usr/include/xlocale.h /usr/include/errno.h \
/usr/include/bits/errno.h /usr/include/linux/errno.h \
/usr/include/asm/errno.h /usr/include/asm-generic/errno.h \
/usr/include/asm-generic/errno-base.h /usr/include/netdb.h \
/usr/include/netinet/in.h /usr/include/stdint.h \
/usr/include/bits/wchar.h /usr/include/sys/socket.h \
/usr/include/sys/uio.h /usr/include/sys/types.h /usr/include/time.h \
/usr/include/sys/select.h /usr/include/bits/select.h \
/usr/include/bits/sigset.h /usr/include/bits/time.h \
/usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \
/usr/include/bits/uio.h /usr/include/bits/socket.h \
/usr/include/bits/sockaddr.h /usr/include/asm/socket.h \
/usr/include/asm-generic/socket.h /usr/include/asm/sockios.h \
/usr/include/asm-generic/sockios.h /usr/include/bits/in.h \
/usr/include/rpc/netdb.h /usr/include/bits/netdb.h /usr/include/fcntl.h \
/usr/include/bits/fcntl.h /usr/include/bits/stat.h /usr/include/unistd.h \
/usr/include/bits/posix_opt.h /usr/include/bits/environments.h \
/usr/include/bits/confname.h /usr/include/getopt.h /usr/include/syslog.h \
/usr/include/sys/syslog.h /usr/include/bits/syslog-path.h \
/usr/include/string.h /usr/include/stdlib.h \
/usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \
/usr/include/alloca.h /usr/include/pwd.h /usr/include/sys/epoll.h \
/usr/include/signal.h /usr/include/bits/signum.h \
/usr/include/bits/siginfo.h /usr/include/bits/sigaction.h \
/usr/include/bits/sigcontext.h /usr/include/bits/sigstack.h \
/usr/include/sys/ucontext.h /usr/include/bits/sigthread.h \
/usr/include/sys/ioctl.h /usr/include/bits/ioctls.h \
/usr/include/asm/ioctls.h /usr/include/asm-generic/ioctls.h \
/usr/include/linux/ioctl.h /usr/include/asm/ioctl.h \
/usr/include/asm-generic/ioctl.h /usr/include/bits/ioctl-types.h \
/usr/include/sys/ttydefaults.h /usr/include/arpa/inet.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdbool.h \
../include/gateway_mysql.h ../include/dcb.h ../include/spinlock.h \
../include/thread.h /usr/include/pthread.h /usr/include/sched.h \
/usr/include/bits/sched.h /usr/include/bits/setjmp.h ../include/buffer.h \
../include/gwbitmask.h ../include/mysql_protocol.h ../include/dcb.h \
../include/session.h
utils.o: utils.c ../include/gw.h /usr/include/stdio.h \
/usr/include/features.h /usr/include/sys/cdefs.h \
/usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \
/usr/include/gnu/stubs-64.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
/usr/include/ctype.h /usr/include/endian.h /usr/include/bits/endian.h \
/usr/include/bits/byteswap.h /usr/include/xlocale.h /usr/include/errno.h \
/usr/include/bits/errno.h /usr/include/linux/errno.h \
/usr/include/asm/errno.h /usr/include/asm-generic/errno.h \
/usr/include/asm-generic/errno-base.h /usr/include/netdb.h \
/usr/include/netinet/in.h /usr/include/stdint.h \
/usr/include/bits/wchar.h /usr/include/sys/socket.h \
/usr/include/sys/uio.h /usr/include/sys/types.h /usr/include/time.h \
/usr/include/sys/select.h /usr/include/bits/select.h \
/usr/include/bits/sigset.h /usr/include/bits/time.h \
/usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \
/usr/include/bits/uio.h /usr/include/bits/socket.h \
/usr/include/bits/sockaddr.h /usr/include/asm/socket.h \
/usr/include/asm-generic/socket.h /usr/include/asm/sockios.h \
/usr/include/asm-generic/sockios.h /usr/include/bits/in.h \
/usr/include/rpc/netdb.h /usr/include/bits/netdb.h /usr/include/fcntl.h \
/usr/include/bits/fcntl.h /usr/include/bits/stat.h /usr/include/unistd.h \
/usr/include/bits/posix_opt.h /usr/include/bits/environments.h \
/usr/include/bits/confname.h /usr/include/getopt.h /usr/include/syslog.h \
/usr/include/sys/syslog.h /usr/include/bits/syslog-path.h \
/usr/include/string.h /usr/include/stdlib.h \
/usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \
/usr/include/alloca.h /usr/include/pwd.h /usr/include/sys/epoll.h \
/usr/include/signal.h /usr/include/bits/signum.h \
/usr/include/bits/siginfo.h /usr/include/bits/sigaction.h \
/usr/include/bits/sigcontext.h /usr/include/bits/sigstack.h \
/usr/include/sys/ucontext.h /usr/include/bits/sigthread.h \
/usr/include/sys/ioctl.h /usr/include/bits/ioctls.h \
/usr/include/asm/ioctls.h /usr/include/asm-generic/ioctls.h \
/usr/include/linux/ioctl.h /usr/include/asm/ioctl.h \
/usr/include/asm-generic/ioctl.h /usr/include/bits/ioctl-types.h \
/usr/include/sys/ttydefaults.h /usr/include/arpa/inet.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdbool.h \
../include/gateway_mysql.h ../include/dcb.h ../include/spinlock.h \
../include/thread.h /usr/include/pthread.h /usr/include/sched.h \
/usr/include/bits/sched.h /usr/include/bits/setjmp.h ../include/buffer.h \
../include/gwbitmask.h ../include/mysql_protocol.h ../include/dcb.h \
../include/session.h ../include/mysql_protocol.h \
/usr/include/openssl/sha.h /usr/include/openssl/e_os2.h \
/usr/include/openssl/opensslconf.h \
/usr/include/openssl/opensslconf-x86_64.h ../include/poll.h \
/home/mriddoch/Repository/skygateway/utils/skygw_utils.h \
/home/mriddoch/Repository/skygateway/utils/skygw_types.h \
/usr/include/math.h /usr/include/bits/huge_val.h \
/usr/include/bits/huge_valf.h /usr/include/bits/huge_vall.h \
/usr/include/bits/inf.h /usr/include/bits/nan.h \
/usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h \
/home/mriddoch/Repository/skygateway/utils/skygw_debug.h \
/usr/include/assert.h \
/home/mriddoch/Repository/skygateway/log_manager/log_manager.h
dcb.o: dcb.c /usr/include/stdio.h /usr/include/features.h \
/usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
/usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
/usr/include/stdlib.h /usr/include/bits/waitflags.h \
/usr/include/bits/waitstatus.h /usr/include/endian.h \
/usr/include/bits/endian.h /usr/include/bits/byteswap.h \
/usr/include/sys/types.h /usr/include/time.h /usr/include/sys/select.h \
/usr/include/bits/select.h /usr/include/bits/sigset.h \
/usr/include/bits/time.h /usr/include/sys/sysmacros.h \
/usr/include/bits/pthreadtypes.h /usr/include/alloca.h \
/usr/include/string.h /usr/include/xlocale.h ../include/dcb.h \
../include/spinlock.h ../include/thread.h /usr/include/pthread.h \
/usr/include/sched.h /usr/include/bits/sched.h \
/usr/include/bits/setjmp.h ../include/buffer.h ../include/gwbitmask.h \
../include/server.h ../include/session.h ../include/service.h \
../include/modules.h ../include/router.h /usr/include/errno.h \
/usr/include/bits/errno.h /usr/include/linux/errno.h \
/usr/include/asm/errno.h /usr/include/asm-generic/errno.h \
/usr/include/asm-generic/errno-base.h ../include/gw.h \
/usr/include/ctype.h /usr/include/netdb.h /usr/include/netinet/in.h \
/usr/include/stdint.h /usr/include/bits/wchar.h \
/usr/include/sys/socket.h /usr/include/sys/uio.h /usr/include/bits/uio.h \
/usr/include/bits/socket.h /usr/include/bits/sockaddr.h \
/usr/include/asm/socket.h /usr/include/asm-generic/socket.h \
/usr/include/asm/sockios.h /usr/include/asm-generic/sockios.h \
/usr/include/bits/in.h /usr/include/rpc/netdb.h \
/usr/include/bits/netdb.h /usr/include/fcntl.h /usr/include/bits/fcntl.h \
/usr/include/bits/stat.h /usr/include/unistd.h \
/usr/include/bits/posix_opt.h /usr/include/bits/environments.h \
/usr/include/bits/confname.h /usr/include/getopt.h /usr/include/syslog.h \
/usr/include/sys/syslog.h /usr/include/bits/syslog-path.h \
/usr/include/pwd.h /usr/include/sys/epoll.h /usr/include/signal.h \
/usr/include/bits/signum.h /usr/include/bits/siginfo.h \
/usr/include/bits/sigaction.h /usr/include/bits/sigcontext.h \
/usr/include/bits/sigstack.h /usr/include/sys/ucontext.h \
/usr/include/bits/sigthread.h /usr/include/sys/ioctl.h \
/usr/include/bits/ioctls.h /usr/include/asm/ioctls.h \
/usr/include/asm-generic/ioctls.h /usr/include/linux/ioctl.h \
/usr/include/asm/ioctl.h /usr/include/asm-generic/ioctl.h \
/usr/include/bits/ioctl-types.h /usr/include/sys/ttydefaults.h \
/usr/include/arpa/inet.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdbool.h \
../include/gateway_mysql.h ../include/mysql_protocol.h ../include/dcb.h \
../include/poll.h ../include/atomic.h \
/home/mriddoch/Repository/skygateway/utils/skygw_utils.h \
/home/mriddoch/Repository/skygateway/utils/skygw_types.h \
/usr/include/math.h /usr/include/bits/huge_val.h \
/usr/include/bits/huge_valf.h /usr/include/bits/huge_vall.h \
/usr/include/bits/inf.h /usr/include/bits/nan.h \
/usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h \
/home/mriddoch/Repository/skygateway/utils/skygw_debug.h \
/usr/include/assert.h \
/home/mriddoch/Repository/skygateway/log_manager/log_manager.h
load_utils.o: load_utils.c /usr/include/sys/param.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/limits.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/syslimits.h \
/usr/include/limits.h /usr/include/features.h /usr/include/sys/cdefs.h \
/usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \
/usr/include/gnu/stubs-64.h /usr/include/bits/posix1_lim.h \
/usr/include/bits/local_lim.h /usr/include/linux/limits.h \
/usr/include/bits/posix2_lim.h /usr/include/linux/param.h \
/usr/include/asm/param.h /usr/include/asm-generic/param.h \
/usr/include/sys/types.h /usr/include/bits/types.h \
/usr/include/bits/typesizes.h /usr/include/time.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \
/usr/include/endian.h /usr/include/bits/endian.h \
/usr/include/bits/byteswap.h /usr/include/sys/select.h \
/usr/include/bits/select.h /usr/include/bits/sigset.h \
/usr/include/bits/time.h /usr/include/sys/sysmacros.h \
/usr/include/bits/pthreadtypes.h /usr/include/stdio.h \
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
/usr/include/stdlib.h /usr/include/bits/waitflags.h \
/usr/include/bits/waitstatus.h /usr/include/alloca.h \
/usr/include/unistd.h /usr/include/bits/posix_opt.h \
/usr/include/bits/environments.h /usr/include/bits/confname.h \
/usr/include/getopt.h /usr/include/string.h /usr/include/xlocale.h \
/usr/include/dlfcn.h /usr/include/bits/dlfcn.h ../include/modules.h \
../include/dcb.h ../include/spinlock.h ../include/thread.h \
/usr/include/pthread.h /usr/include/sched.h /usr/include/bits/sched.h \
/usr/include/bits/setjmp.h ../include/buffer.h ../include/gwbitmask.h \
/home/mriddoch/Repository/skygateway/utils/skygw_utils.h \
/home/mriddoch/Repository/skygateway/utils/skygw_types.h \
/usr/include/math.h /usr/include/bits/huge_val.h \
/usr/include/bits/huge_valf.h /usr/include/bits/huge_vall.h \
/usr/include/bits/inf.h /usr/include/bits/nan.h \
/usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h \
/home/mriddoch/Repository/skygateway/utils/skygw_debug.h \
/usr/include/assert.h \
/home/mriddoch/Repository/skygateway/log_manager/log_manager.h
session.o: session.c /usr/include/stdio.h /usr/include/features.h \
/usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
/usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
/usr/include/stdlib.h /usr/include/bits/waitflags.h \
/usr/include/bits/waitstatus.h /usr/include/endian.h \
/usr/include/bits/endian.h /usr/include/bits/byteswap.h \
/usr/include/sys/types.h /usr/include/time.h /usr/include/sys/select.h \
/usr/include/bits/select.h /usr/include/bits/sigset.h \
/usr/include/bits/time.h /usr/include/sys/sysmacros.h \
/usr/include/bits/pthreadtypes.h /usr/include/alloca.h \
/usr/include/unistd.h /usr/include/bits/posix_opt.h \
/usr/include/bits/environments.h /usr/include/bits/confname.h \
/usr/include/getopt.h /usr/include/string.h /usr/include/xlocale.h \
../include/session.h ../include/service.h ../include/spinlock.h \
../include/thread.h /usr/include/pthread.h /usr/include/sched.h \
/usr/include/bits/sched.h /usr/include/bits/setjmp.h ../include/dcb.h \
../include/buffer.h ../include/gwbitmask.h ../include/server.h \
../include/router.h ../include/atomic.h
service.o: service.c /usr/include/stdio.h /usr/include/features.h \
/usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
/usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
/usr/include/stdlib.h /usr/include/bits/waitflags.h \
/usr/include/bits/waitstatus.h /usr/include/endian.h \
/usr/include/bits/endian.h /usr/include/bits/byteswap.h \
/usr/include/sys/types.h /usr/include/time.h /usr/include/sys/select.h \
/usr/include/bits/select.h /usr/include/bits/sigset.h \
/usr/include/bits/time.h /usr/include/sys/sysmacros.h \
/usr/include/bits/pthreadtypes.h /usr/include/alloca.h \
/usr/include/string.h /usr/include/xlocale.h ../include/session.h \
../include/service.h ../include/spinlock.h ../include/thread.h \
/usr/include/pthread.h /usr/include/sched.h /usr/include/bits/sched.h \
/usr/include/bits/setjmp.h ../include/dcb.h ../include/buffer.h \
../include/gwbitmask.h ../include/server.h ../include/router.h \
../include/modules.h ../include/users.h ../include/hashtable.h \
../include/atomic.h ../include/dbusers.h ../include/poll.h \
/home/mriddoch/Repository/skygateway/utils/skygw_utils.h \
/home/mriddoch/Repository/skygateway/utils/skygw_types.h \
/usr/include/math.h /usr/include/bits/huge_val.h \
/usr/include/bits/huge_valf.h /usr/include/bits/huge_vall.h \
/usr/include/bits/inf.h /usr/include/bits/nan.h \
/usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h \
/home/mriddoch/Repository/skygateway/utils/skygw_debug.h \
/usr/include/assert.h /usr/include/unistd.h \
/usr/include/bits/posix_opt.h /usr/include/bits/environments.h \
/usr/include/bits/confname.h /usr/include/getopt.h \
/home/mriddoch/Repository/skygateway/log_manager/log_manager.h
server.o: server.c /usr/include/stdio.h /usr/include/features.h \
/usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
/usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
/usr/include/stdlib.h /usr/include/bits/waitflags.h \
/usr/include/bits/waitstatus.h /usr/include/endian.h \
/usr/include/bits/endian.h /usr/include/bits/byteswap.h \
/usr/include/sys/types.h /usr/include/time.h /usr/include/sys/select.h \
/usr/include/bits/select.h /usr/include/bits/sigset.h \
/usr/include/bits/time.h /usr/include/sys/sysmacros.h \
/usr/include/bits/pthreadtypes.h /usr/include/alloca.h \
/usr/include/string.h /usr/include/xlocale.h ../include/session.h \
../include/server.h ../include/dcb.h ../include/spinlock.h \
../include/thread.h /usr/include/pthread.h /usr/include/sched.h \
/usr/include/bits/sched.h /usr/include/bits/setjmp.h ../include/buffer.h \
../include/gwbitmask.h \
/home/mriddoch/Repository/skygateway/utils/skygw_utils.h \
/home/mriddoch/Repository/skygateway/utils/skygw_types.h \
/usr/include/math.h /usr/include/bits/huge_val.h \
/usr/include/bits/huge_valf.h /usr/include/bits/huge_vall.h \
/usr/include/bits/inf.h /usr/include/bits/nan.h \
/usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h \
/home/mriddoch/Repository/skygateway/utils/skygw_debug.h \
/usr/include/assert.h /usr/include/unistd.h \
/usr/include/bits/posix_opt.h /usr/include/bits/environments.h \
/usr/include/bits/confname.h /usr/include/getopt.h \
/home/mriddoch/Repository/skygateway/log_manager/log_manager.h
poll.o: poll.c /usr/include/stdio.h /usr/include/features.h \
/usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
/usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
/usr/include/string.h /usr/include/xlocale.h /usr/include/unistd.h \
/usr/include/bits/posix_opt.h /usr/include/bits/environments.h \
/usr/include/bits/confname.h /usr/include/getopt.h /usr/include/stdlib.h \
/usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \
/usr/include/endian.h /usr/include/bits/endian.h \
/usr/include/bits/byteswap.h /usr/include/sys/types.h \
/usr/include/time.h /usr/include/sys/select.h /usr/include/bits/select.h \
/usr/include/bits/sigset.h /usr/include/bits/time.h \
/usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \
/usr/include/alloca.h /usr/include/sys/epoll.h /usr/include/stdint.h \
/usr/include/bits/wchar.h ../include/poll.h ../include/dcb.h \
../include/spinlock.h ../include/thread.h /usr/include/pthread.h \
/usr/include/sched.h /usr/include/bits/sched.h \
/usr/include/bits/setjmp.h ../include/buffer.h ../include/gwbitmask.h \
../include/atomic.h
config.o: config.c /usr/include/stdio.h /usr/include/features.h \
/usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
/usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
/usr/include/string.h /usr/include/xlocale.h /usr/include/stdlib.h \
/usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \
/usr/include/endian.h /usr/include/bits/endian.h \
/usr/include/bits/byteswap.h /usr/include/sys/types.h \
/usr/include/time.h /usr/include/sys/select.h /usr/include/bits/select.h \
/usr/include/bits/sigset.h /usr/include/bits/time.h \
/usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \
/usr/include/alloca.h ../inih/ini.h ../include/config.h \
../include/service.h ../include/spinlock.h ../include/thread.h \
/usr/include/pthread.h /usr/include/sched.h /usr/include/bits/sched.h \
/usr/include/bits/setjmp.h ../include/dcb.h ../include/buffer.h \
../include/gwbitmask.h ../include/server.h ../include/users.h \
../include/hashtable.h ../include/atomic.h ../include/monitor.h \
/home/mriddoch/Repository/skygateway/utils/skygw_utils.h \
/home/mriddoch/Repository/skygateway/utils/skygw_types.h \
/usr/include/math.h /usr/include/bits/huge_val.h \
/usr/include/bits/huge_valf.h /usr/include/bits/huge_vall.h \
/usr/include/bits/inf.h /usr/include/bits/nan.h \
/usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h \
/home/mriddoch/Repository/skygateway/utils/skygw_debug.h \
/usr/include/assert.h /usr/include/unistd.h \
/usr/include/bits/posix_opt.h /usr/include/bits/environments.h \
/usr/include/bits/confname.h /usr/include/getopt.h \
/home/mriddoch/Repository/skygateway/log_manager/log_manager.h
users.o: users.c /usr/include/stdio.h /usr/include/features.h \
/usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
/usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
/usr/include/stdlib.h /usr/include/bits/waitflags.h \
/usr/include/bits/waitstatus.h /usr/include/endian.h \
/usr/include/bits/endian.h /usr/include/bits/byteswap.h \
/usr/include/sys/types.h /usr/include/time.h /usr/include/sys/select.h \
/usr/include/bits/select.h /usr/include/bits/sigset.h \
/usr/include/bits/time.h /usr/include/sys/sysmacros.h \
/usr/include/bits/pthreadtypes.h /usr/include/alloca.h \
/usr/include/string.h /usr/include/xlocale.h ../include/users.h \
../include/hashtable.h ../include/spinlock.h ../include/thread.h \
/usr/include/pthread.h /usr/include/sched.h /usr/include/bits/sched.h \
/usr/include/bits/setjmp.h ../include/atomic.h ../include/dcb.h \
../include/buffer.h ../include/gwbitmask.h
hashtable.o: hashtable.c /usr/include/stdio.h /usr/include/features.h \
/usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
/usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
/usr/include/stdlib.h /usr/include/bits/waitflags.h \
/usr/include/bits/waitstatus.h /usr/include/endian.h \
/usr/include/bits/endian.h /usr/include/bits/byteswap.h \
/usr/include/sys/types.h /usr/include/time.h /usr/include/sys/select.h \
/usr/include/bits/select.h /usr/include/bits/sigset.h \
/usr/include/bits/time.h /usr/include/sys/sysmacros.h \
/usr/include/bits/pthreadtypes.h /usr/include/alloca.h \
/usr/include/string.h /usr/include/xlocale.h ../include/hashtable.h \
../include/spinlock.h ../include/thread.h /usr/include/pthread.h \
/usr/include/sched.h /usr/include/bits/sched.h \
/usr/include/bits/setjmp.h ../include/atomic.h ../include/dcb.h \
../include/buffer.h ../include/gwbitmask.h
dbusers.o: dbusers.c /usr/include/stdio.h /usr/include/features.h \
/usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
/usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
/usr/include/mysql/mysql.h /usr/include/sys/types.h /usr/include/time.h \
/usr/include/endian.h /usr/include/bits/endian.h \
/usr/include/bits/byteswap.h /usr/include/sys/select.h \
/usr/include/bits/select.h /usr/include/bits/sigset.h \
/usr/include/bits/time.h /usr/include/sys/sysmacros.h \
/usr/include/bits/pthreadtypes.h /usr/include/mysql/mysql_version.h \
/usr/include/mysql/mysql_com.h /usr/include/mysql/mysql_time.h \
/usr/include/mysql/my_list.h /usr/include/mysql/typelib.h \
/usr/include/mysql/my_alloc.h ../include/dcb.h ../include/spinlock.h \
../include/thread.h /usr/include/pthread.h /usr/include/sched.h \
/usr/include/bits/sched.h /usr/include/xlocale.h \
/usr/include/bits/setjmp.h ../include/buffer.h ../include/gwbitmask.h \
../include/service.h ../include/server.h ../include/users.h \
../include/hashtable.h ../include/atomic.h \
/home/mriddoch/Repository/skygateway/utils/skygw_utils.h \
/home/mriddoch/Repository/skygateway/utils/skygw_types.h \
/usr/include/math.h /usr/include/bits/huge_val.h \
/usr/include/bits/huge_valf.h /usr/include/bits/huge_vall.h \
/usr/include/bits/inf.h /usr/include/bits/nan.h \
/usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h \
/home/mriddoch/Repository/skygateway/utils/skygw_debug.h \
/usr/include/assert.h /usr/include/unistd.h \
/usr/include/bits/posix_opt.h /usr/include/bits/environments.h \
/usr/include/bits/confname.h /usr/include/getopt.h \
/home/mriddoch/Repository/skygateway/log_manager/log_manager.h \
../include/secrets.h /usr/include/string.h /usr/include/stdlib.h \
/usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \
/usr/include/alloca.h /usr/include/sys/stat.h /usr/include/bits/stat.h \
/usr/include/fcntl.h /usr/include/bits/fcntl.h /usr/include/errno.h \
/usr/include/bits/errno.h /usr/include/linux/errno.h \
/usr/include/asm/errno.h /usr/include/asm-generic/errno.h \
/usr/include/asm-generic/errno-base.h /usr/include/openssl/aes.h \
/usr/include/openssl/opensslconf.h \
/usr/include/openssl/opensslconf-x86_64.h
thread.o: thread.c ../include/thread.h /usr/include/pthread.h \
/usr/include/features.h /usr/include/sys/cdefs.h \
/usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \
/usr/include/gnu/stubs-64.h /usr/include/endian.h \
/usr/include/bits/endian.h /usr/include/bits/byteswap.h \
/usr/include/sched.h /usr/include/bits/types.h \
/usr/include/bits/typesizes.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \
/usr/include/time.h /usr/include/bits/sched.h /usr/include/bits/time.h \
/usr/include/xlocale.h /usr/include/bits/pthreadtypes.h \
/usr/include/bits/setjmp.h
gwbitmask.o: gwbitmask.c /usr/include/stdlib.h /usr/include/features.h \
/usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
/usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \
/usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \
/usr/include/endian.h /usr/include/bits/endian.h \
/usr/include/bits/byteswap.h /usr/include/sys/types.h \
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
/usr/include/time.h /usr/include/sys/select.h /usr/include/bits/select.h \
/usr/include/bits/sigset.h /usr/include/bits/time.h \
/usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \
/usr/include/alloca.h /usr/include/string.h /usr/include/xlocale.h \
../include/gwbitmask.h ../include/spinlock.h ../include/thread.h \
/usr/include/pthread.h /usr/include/sched.h /usr/include/bits/sched.h \
/usr/include/bits/setjmp.h
monitor.o: monitor.c /usr/include/stdio.h /usr/include/features.h \
/usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
/usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
/usr/include/stdlib.h /usr/include/bits/waitflags.h \
/usr/include/bits/waitstatus.h /usr/include/endian.h \
/usr/include/bits/endian.h /usr/include/bits/byteswap.h \
/usr/include/sys/types.h /usr/include/time.h /usr/include/sys/select.h \
/usr/include/bits/select.h /usr/include/bits/sigset.h \
/usr/include/bits/time.h /usr/include/sys/sysmacros.h \
/usr/include/bits/pthreadtypes.h /usr/include/alloca.h \
/usr/include/string.h /usr/include/xlocale.h ../include/monitor.h \
../include/server.h ../include/dcb.h ../include/spinlock.h \
../include/thread.h /usr/include/pthread.h /usr/include/sched.h \
/usr/include/bits/sched.h /usr/include/bits/setjmp.h ../include/buffer.h \
../include/gwbitmask.h ../include/modules.h \
/home/mriddoch/Repository/skygateway/utils/skygw_utils.h \
/home/mriddoch/Repository/skygateway/utils/skygw_types.h \
/usr/include/math.h /usr/include/bits/huge_val.h \
/usr/include/bits/huge_valf.h /usr/include/bits/huge_vall.h \
/usr/include/bits/inf.h /usr/include/bits/nan.h \
/usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h \
/home/mriddoch/Repository/skygateway/utils/skygw_debug.h \
/usr/include/assert.h /usr/include/unistd.h \
/usr/include/bits/posix_opt.h /usr/include/bits/environments.h \
/usr/include/bits/confname.h /usr/include/getopt.h \
/home/mriddoch/Repository/skygateway/log_manager/log_manager.h
adminusers.o: adminusers.c /usr/include/stdio.h /usr/include/features.h \
/usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
/usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
/usr/include/stdlib.h /usr/include/bits/waitflags.h \
/usr/include/bits/waitstatus.h /usr/include/endian.h \
/usr/include/bits/endian.h /usr/include/bits/byteswap.h \
/usr/include/sys/types.h /usr/include/time.h /usr/include/sys/select.h \
/usr/include/bits/select.h /usr/include/bits/sigset.h \
/usr/include/bits/time.h /usr/include/sys/sysmacros.h \
/usr/include/bits/pthreadtypes.h /usr/include/alloca.h \
/usr/include/string.h /usr/include/xlocale.h /usr/include/unistd.h \
/usr/include/bits/posix_opt.h /usr/include/bits/environments.h \
/usr/include/bits/confname.h /usr/include/getopt.h /usr/include/crypt.h \
../include/users.h ../include/hashtable.h ../include/spinlock.h \
../include/thread.h /usr/include/pthread.h /usr/include/sched.h \
/usr/include/bits/sched.h /usr/include/bits/setjmp.h ../include/atomic.h \
../include/dcb.h ../include/buffer.h ../include/gwbitmask.h \
../include/adminusers.h \
/home/mriddoch/Repository/skygateway/utils/skygw_utils.h \
/home/mriddoch/Repository/skygateway/utils/skygw_types.h \
/usr/include/math.h /usr/include/bits/huge_val.h \
/usr/include/bits/huge_valf.h /usr/include/bits/huge_vall.h \
/usr/include/bits/inf.h /usr/include/bits/nan.h \
/usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h \
/home/mriddoch/Repository/skygateway/utils/skygw_debug.h \
/usr/include/assert.h \
/home/mriddoch/Repository/skygateway/log_manager/log_manager.h
secrets.o: secrets.c ../include/secrets.h /usr/include/stdio.h \
/usr/include/features.h /usr/include/sys/cdefs.h \
/usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \
/usr/include/gnu/stubs-64.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/include/stdarg.h \
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h \
/usr/include/string.h /usr/include/xlocale.h /usr/include/stdlib.h \
/usr/include/bits/waitflags.h /usr/include/bits/waitstatus.h \
/usr/include/endian.h /usr/include/bits/endian.h \
/usr/include/bits/byteswap.h /usr/include/sys/types.h \
/usr/include/time.h /usr/include/sys/select.h /usr/include/bits/select.h \
/usr/include/bits/sigset.h /usr/include/bits/time.h \
/usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h \
/usr/include/alloca.h /usr/include/sys/stat.h /usr/include/bits/stat.h \
/usr/include/fcntl.h /usr/include/bits/fcntl.h /usr/include/errno.h \
/usr/include/bits/errno.h /usr/include/linux/errno.h \
/usr/include/asm/errno.h /usr/include/asm-generic/errno.h \
/usr/include/asm-generic/errno-base.h /usr/include/openssl/aes.h \
/usr/include/openssl/opensslconf.h \
/usr/include/openssl/opensslconf-x86_64.h \
/home/mriddoch/Repository/skygateway/utils/skygw_utils.h \
/home/mriddoch/Repository/skygateway/utils/skygw_types.h \
/usr/include/math.h /usr/include/bits/huge_val.h \
/usr/include/bits/huge_valf.h /usr/include/bits/huge_vall.h \
/usr/include/bits/inf.h /usr/include/bits/nan.h \
/usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h \
/home/mriddoch/Repository/skygateway/utils/skygw_debug.h \
/usr/include/assert.h /usr/include/pthread.h /usr/include/sched.h \
/usr/include/bits/sched.h /usr/include/bits/setjmp.h \
/usr/include/unistd.h /usr/include/bits/posix_opt.h \
/usr/include/bits/environments.h /usr/include/bits/confname.h \
/usr/include/getopt.h \
/home/mriddoch/Repository/skygateway/log_manager/log_manager.h \
/usr/include/ctype.h

455
server/core/gateway.c Normal file
View File

@ -0,0 +1,455 @@
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*
*/
/**
* @file gateway.c - The gateway entry point.
*
* @verbatim
* Revision History
*
* Date Who Description
* 23-05-2013 Massimiliano Pinto epoll loop test
* 12-06-2013 Mark Riddoch Add the -p option to set the
* listening port
* and bind addr is 0.0.0.0
* 19/06/13 Mark Riddoch Extract the epoll functionality
* 21/06/13 Mark Riddoch Added initial config support
* 27/06/13
* 28/06/13 Vilho Raatikka Added necessary headers, example functions and
* calls to log manager and to query classifier.
* Put example code behind SS_DEBUG macros.
*
* @endverbatim
*/
#include <gw.h>
#include <unistd.h>
#include <service.h>
#include <server.h>
#include <dcb.h>
#include <session.h>
#include <modules.h>
#include <config.h>
#include <poll.h>
#include <stdlib.h>
#include <mysql.h>
#include <monitor.h>
#include <sys/stat.h>
#include <sys/types.h>
# include <skygw_utils.h>
# include <log_manager.h>
/*
* Server options are passed to the mysql_server_init. Each gateway must have a unique
* data directory that is passed to the mysql_server_init, therefore the data directory
* is not fixed here and will be updated elsewhere.
*/
static char* server_options[] = {
"SkySQL Gateway",
"--datadir=",
"--skip-innodb",
"--default-storage-engine=myisam",
NULL
};
const int num_elements = (sizeof(server_options) / sizeof(char *)) - 1;
static char* server_groups[] = {
"embedded",
"server",
"server",
"server",
NULL
};
/* The data directory we created for this gateway instance */
static char datadir[1024] = "";
/**
* Handler for SIGHUP signal. Reload the configuration for the
* gateway.
*/
static void sighup_handler (int i)
{
skygw_log_write(NULL, LOGFILE_MESSAGE, "Refreshing configuration following SIGHUP\n");
config_reload();
}
static void sigterm_handler (int i) {
extern void shutdown_gateway();
skygw_log_write(NULL, LOGFILE_ERROR, "Signal SIGTERM %i received ...Exiting!\n", i);
shutdown_gateway();
}
/* wrapper for sigaction */
static void signal_set (int sig, void (*handler)(int)) {
static struct sigaction sigact;
static int err;
memset(&sigact, 0, sizeof(struct sigaction));
sigact.sa_handler = handler;
GW_NOINTR_CALL(err = sigaction(sig, &sigact, NULL));
if (err < 0) {
skygw_log_write(NULL, LOGFILE_ERROR,"sigaction() error %s\n", strerror(errno));
exit(1);
}
}
int handle_event_errors(DCB *dcb) {
fprintf(stderr, "#### Handle error function for [%i] is [%s]\n", dcb->state, gw_dcb_state2string(dcb->state));
if (dcb->state == DCB_STATE_DISCONNECTED) {
fprintf(stderr, "#### Handle error function, session is %p\n", dcb->session);
return 1;
}
#ifdef GW_EVENT_DEBUG
if (event != -1) {
fprintf(stderr, ">>>>>> DCB state %i, Protocol State %i: event %i, %i\n", dcb->state, protocol->state, event & EPOLLERR, event & EPOLLHUP);
if(event & EPOLLHUP)
fprintf(stderr, "EPOLLHUP\n");
if(event & EPOLLERR)
fprintf(stderr, "EPOLLERR\n");
if(event & EPOLLPRI)
fprintf(stderr, "EPOLLPRI\n");
}
#endif
if (dcb->state != DCB_STATE_LISTENING) {
if (poll_remove_dcb(dcb) == -1) {
fprintf(stderr, "poll_remove_dcb: from events check failed to delete %i, [%i]:[%s]\n", dcb->fd, errno, strerror(errno));
}
#ifdef GW_EVENT_DEBUG
fprintf(stderr, "closing fd [%i]=[%i], from events\n", dcb->fd, protocol->fd);
#endif
if (dcb->fd) {
//fprintf(stderr, "Client protocol dcb->protocol %p\n", dcb->protocol);
gw_mysql_close((MySQLProtocol **)&dcb->protocol);
fprintf(stderr, "Client protocol dcb->protocol %p\n", dcb->protocol);
dcb->state = DCB_STATE_DISCONNECTED;
}
}
fprintf(stderr, "Return from error handling, dcb is %p\n", dcb);
//free(dcb->session);
dcb->state = DCB_STATE_FREED;
fprintf(stderr, "#### Handle error function RETURN for [%i] is [%s]\n", dcb->state, gw_dcb_state2string(dcb->state));
//free(dcb);
return 1;
}
int handle_event_errors_backend(DCB *dcb) {
fprintf(stderr, "#### Handle Backend error function for %i\n", dcb->fd);
#ifdef GW_EVENT_DEBUG
if (event != -1) {
fprintf(stderr, ">>>>>> Backend DCB state %i, Protocol State %i: event %i, %i\n", dcb->state, dcb->proto_state, event & EPOLLERR, event & EPOLLHUP);
if(event & EPOLLHUP)
fprintf(stderr, "EPOLLHUP\n");
if(event & EPOLLERR)
fprintf(stderr, "EPOLLERR\n");
if(event & EPOLLPRI)
fprintf(stderr, "EPOLLPRI\n");
}
#endif
if (dcb->state != DCB_STATE_LISTENING) {
if (poll_remove_dcb(dcb) == -1) {
fprintf(stderr, "Backend poll_remove_dcb: from events check failed to delete %i, [%i]:[%s]\n", dcb->fd, errno, strerror(errno));
}
#ifdef GW_EVENT_DEBUG
fprintf(stderr, "Backend closing fd [%i]=%i, from events check\n", dcb->fd, protocol->fd);
#endif
if (dcb->fd) {
dcb->state = DCB_STATE_DISCONNECTED;
fprintf(stderr, "Freeing backend MySQL conn %p, %p\n", dcb->protocol, &dcb->protocol);
gw_mysql_close((MySQLProtocol **)&dcb->protocol);
fprintf(stderr, "Freeing backend MySQL conn %p, %p\n", dcb->protocol, &dcb->protocol);
}
}
return 0;
}
/**
* Cleanup the temporary data directory we created for the gateway
*/
void
datadir_cleanup()
{
char buf[1024];
if (datadir[0] && access(datadir, F_OK) == 0)
{
sprintf(buf, "rm -rf %s", datadir);
system(buf);
}
}
/**
* The main entry point into the gateway
*
* @param argc The argument count
* @param argv The arguments themselves
*/
int
main(int argc, char **argv)
{
int daemon_mode = 1;
sigset_t sigset;
int i, n, n_threads, n_services;
void **threads;
char mysql_home[1024], buf[1024], *home, *cnf_file = NULL;
char ddopt[1024];
int l;
l = atexit(skygw_logmanager_exit);
if (l != 0) {
fprintf(stderr, "Couldn't register exit function.\n");
}
atexit(datadir_cleanup);
for (n = 0; n < argc; n++)
{
if (strcmp(argv[n], "-d") == 0)
{
/** Debug mode, maxscale runs in this same process */
daemon_mode = 0;
}
if (strncmp(argv[n], "-c", 2) == 0)
{
int s=2;
while (argv[n][s] == 0 && s<10) s++;
if (s==10) {
skygw_log_write(
NULL, LOGFILE_ERROR,
"Fatal : missing file name. \n"
"Unable to find a MaxScale configuration file, "
"either install one in /etc/MaxScale.cnf, "
"$MAXSCALE_HOME/etc/MaxScale.cnf "
"or use the -c option with configuration file name. "
"Exiting.\n");
}
cnf_file = &argv[n][s];
}
}
/**
* Maxscale must be daemonized before opening files, initializing
* embedded MariaDB and in general, as early as possible.
*/
if (daemon_mode == 1)
{
if (sigfillset(&sigset) != 0) {
skygw_log_write(NULL,
LOGFILE_ERROR,
"sigfillset() error %s\n",
strerror(errno));
return 1;
}
if (sigdelset(&sigset, SIGHUP) != 0) {
skygw_log_write(NULL,
LOGFILE_ERROR,
"sigdelset(SIGHUP) error %s\n",
strerror(errno));
}
if (sigdelset(&sigset, SIGTERM) != 0) {
skygw_log_write(NULL,
LOGFILE_ERROR,
"sigdelset(SIGTERM) error %s\n",
strerror(errno));
}
if (sigprocmask(SIG_SETMASK, &sigset, NULL) != 0) {
skygw_log_write(NULL,
LOGFILE_ERROR,
"sigprocmask() error %s\n",
strerror(errno));
}
signal_set(SIGHUP, sighup_handler);
signal_set(SIGTERM, sigterm_handler);
gw_daemonize();
}
l = atexit(mysql_library_end);
if (l != 0) {
fprintf(stderr, "Couldn't register exit function.\n");
}
if ((home = getenv("MAXSCALE_HOME")) != NULL)
{
sprintf(mysql_home, "%s/mysql", home);
setenv("MYSQL_HOME", mysql_home, 1);
sprintf(buf, "%s/etc/MaxScale.cnf", home);
if (access(buf, R_OK) == 0)
cnf_file = buf;
}
if (cnf_file == NULL && access("/etc/MaxScale.cnf", R_OK) == 0)
cnf_file = "/etc/MaxScale.cnf";
/*
* Set a data directory for the mysqld library, we use
* a unique directory name to avoid clauses if multiple
* instances of the gateway are beign run on the same
* machine.
*/
if (home)
{
sprintf(datadir, "%s/data%d", home, getpid());
mkdir(datadir, 0777);
}
else
{
sprintf(datadir, "/tmp/MaxScale/data%d", getpid());
mkdir("/tmp/MaxScale", 0777);
mkdir(datadir, 0777);
}
/*
* If $MAXSCALE_HOME is set then write the logs into $MAXSCALE_HOME/log.
* The skygw_logmanager_init expects to take arguments as passed to main
* and proesses them with getopt, therefore we need to give it a dummy
* argv[0]
*/
if (home)
{
char buf[1024];
char *argv[4];
sprintf(buf, "%s/log", home);
mkdir(buf, 0777);
argv[0] = "MaxScale";
argv[1] = "-g";
argv[2] = buf;
argv[3] = NULL;
skygw_logmanager_init(NULL, 3, argv);
}
if (cnf_file == NULL) {
skygw_log_write(
NULL, LOGFILE_ERROR,
"Fatal : Unable to find a MaxScale configuration file, either "
"install one in /etc/MaxScale.cnf, $MAXSCALE_HOME/etc/MaxScale.cnf "
"or use the -c option. Exiting.\n");
exit(1);
}
/* Update the server options */
for (i = 0; server_options[i]; i++)
{
if (!strcmp(server_options[i], "--datadir="))
{
sprintf(ddopt, "--datadir=%s", datadir);
server_options[i] = ddopt;
}
}
if (mysql_library_init(num_elements, server_options, server_groups))
{
skygw_log_write_flush(
NULL,
LOGFILE_ERROR,
"Fatal : mysql_library_init failed, %s. This is mandatory "
"component, required by router services and the MaxScale core, "
"the MaxScale can't continue without it. Exiting.\n"
"%s : %d\n",
mysql_error(NULL),
__FILE__,
__LINE__);
exit(1);
}
if (!config_load(cnf_file))
{
skygw_log_write(NULL,
LOGFILE_ERROR,
"Failed to load MaxScale configuration file %s\n", cnf_file);
exit(1);
}
skygw_log_write(NULL, LOGFILE_MESSAGE, "SkySQL MaxScale (C) SkySQL Ab 2013\n");
skygw_log_write_flush(NULL,
LOGFILE_MESSAGE,
"MaxScale is starting, PID %i\n",
getpid());
poll_init();
/*
* Start the services that were created above
*/
n_services = serviceStartAll();
skygw_log_write(NULL, LOGFILE_MESSAGE, "Started %i services\n", getpid());
/*
* Start the polling threads, note this is one less than is
* configured as the main thread will also poll.
*/
n_threads = config_threadcount();
threads = (void **)calloc(n_threads, sizeof(void *));
for (n = 0; n < n_threads - 1; n++)
threads[n] = thread_start(poll_waitevents, (void *)(n + 1));
poll_waitevents((void *)0);
for (n = 0; n < n_threads - 1; n++)
thread_wait(threads[n]);
/* Stop all the monitors */
monitorStopAll();
skygw_log_write(NULL, LOGFILE_MESSAGE, "MaxScale shutdown, PID %i\n", getpid());
return 0;
} // End of main
/**
* Shutdown the gateway
*/
void
shutdown_gateway()
{
poll_shutdown();
}

View File

@ -0,0 +1,103 @@
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*
*/
/*
* Revision History
*
* Date Who Description
* 23-05-2013 Massimiliano Pinto Empty mysql_protocol_handling
* 1)send handshake in accept
* 2) read data
* 3) alway send OK
* 12-06-2013 Mark Riddoch Move mysql_send_ok and MySQLSendHandshake
* to use the new buffer management scheme
* 13-06-2013 Massimiliano Pinto Added mysql_authentication check
* 14-06-2013 Massimiliano Pinto gw_mysql_do_authentication puts user, db, and client_sha1 in the
(MYSQL_session *) session->data of client DCB.
gw_mysql_connect can now access this session->data for
transparent authentication
*/
#include <gw.h>
#include <dcb.h>
#include <session.h>
#include <buffer.h>
#include <openssl/sha.h>
///////////////////////////////////////
// MYSQL_conn structure setup
///////////////////////////////////////
MySQLProtocol *gw_mysql_init(MySQLProtocol *data) {
MySQLProtocol *input = NULL;
if (input == NULL) {
// structure allocation
input = calloc(1, sizeof(MySQLProtocol));
if (input == NULL)
return NULL;
}
#ifdef MYSQL_CONN_DEBUG
fprintf(stderr, "gw_mysql_init() called\n");
#endif
return input;
}
//////////////////////////////////////
// close a connection if opened
// free data scructure
//////////////////////////////////////
void gw_mysql_close(MySQLProtocol **ptr) {
MySQLProtocol *conn = *ptr;
if (*ptr == NULL)
return;
fprintf(stderr, "Closing MySQL connection %i, [%s]\n", conn->fd, conn->scramble);
if (conn->fd > 0) {
//write COM_QUIT
//write
#ifdef MYSQL_CONN_DEBUG
fprintf(stderr, "mysqlgw_mysql_close() called for %i\n", conn->fd);
#endif
close(conn->fd);
} else {
#ifdef MYSQL_CONN_DEBUG
fprintf(stderr, "mysqlgw_mysql_close() called, no socket %i\n", conn->fd);
#endif
}
free(*ptr);
*ptr = NULL;
#ifdef MYSQL_CONN_DEBUG
fprintf(stderr, "mysqlgw_mysql_close() free(conn)\n");
#endif
}

133
server/core/gw_utils.c Normal file
View File

@ -0,0 +1,133 @@
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*
*/
/**
* @file gw_utils.c - A set if utility functions useful within the context
* of the gateway.
*
* Revision History
*
* Date Who Description
* 03-06-2013 Massimiliano Pinto gateway utils
* 12-06-2013 Massimiliano Pinto gw_read_gwbuff
* with error detection
* and its handling
* 01-07-2013 Massimiliano Pinto Removed session->backends
from gw_read_gwbuff()
*/
#include <gw.h>
#include <dcb.h>
#include <session.h>
/**
* Set IP address in socket structure in_addr
*
* @param a Pointer to a struct in_addr into which the address is written
* @param p The hostname to lookup
*/
void
setipaddress(struct in_addr *a, char *p) {
struct hostent *h = gethostbyname(p);
if (h == NULL) {
if ((a->s_addr = inet_addr(p)) == -1) {
fprintf(stderr, "unknown or invalid address [%s]\n", p);
}
} else {
memcpy(a, h->h_addr, h->h_length);
}
}
/**
* Daemonize the process by forking and putting the process into the
* background.
*/
void gw_daemonize(void) {
pid_t pid;
pid = fork();
if (pid < 0) {
fprintf(stderr, "fork() error %s\n", strerror(errno));
exit(1);
}
if (pid != 0) {
// exit from main
exit(0);
}
if (setsid() < 0) {
fprintf(stderr, "setsid() error %s\n", strerror(errno));
exit(1);
}
}
/////////////////////////////////////////////////
// Read data from dcb and store it in the gwbuf
/////////////////////////////////////////////////
int gw_read_gwbuff(DCB *dcb, GWBUF **head, int b) {
GWBUF *buffer = NULL;
int n = -1;
if (b <= 0) {
//fprintf(stderr, "||| read_gwbuff called with 0 bytes for %i, closing\n", dcb->fd);
dcb->func.close(dcb);
return 1;
}
while (b > 0) {
int bufsize = b < MAX_BUFFER_SIZE ? b : MAX_BUFFER_SIZE;
if ((buffer = gwbuf_alloc(bufsize)) == NULL) {
/* Bad news, we have run out of memory */
/* Error handling */
(dcb->func).close(dcb);
return 1;
}
GW_NOINTR_CALL(n = read(dcb->fd, GWBUF_DATA(buffer), bufsize); dcb->stats.n_reads++);
if (n < 0) {
if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
fprintf(stderr, "Client connection %i: continue for %i, %s\n", dcb->fd, errno, strerror(errno));
return 1;
} else {
fprintf(stderr, "Client connection %i error: %i, %s\n", dcb->fd, errno, strerror(errno));;
(dcb->func).close(dcb);
return 1;
}
}
if (n == 0) {
// socket closed
fprintf(stderr, "Client connection %i closed: %i, %s\n", dcb->fd, errno, strerror(errno));
(dcb->func).close(dcb);
return 1;
}
// append read data to the gwbuf
*head = gwbuf_append(*head, buffer);
// how many bytes left
b -= n;
}
return 0;
}

205
server/core/gwbitmask.c Normal file
View File

@ -0,0 +1,205 @@
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
#include <stdlib.h>
#include <string.h>
#include <gwbitmask.h>
/**
* @file gwbitmask.c - Implementation of bitmask opertions for the gateway
*
* We provide basic bitmask manipulation routines, the size of
* the bitmask will grow dynamically based on the highest bit
* number that is set or cleared within the bitmask.
*
* Bitmsk growth happens in increments rather than via a single bit as
* a time.
*
* @verbatim
* Revision History
*
* Date Who Description
* 28/06/13 Mark Riddoch Initial implementation
*
* @endverbatim
*/
/**
* Initialise a bitmask
*
* @param bitmask Pointer the bitmask
* @return The value of *variable before the add occured
*/
void
bitmask_init(GWBITMASK *bitmask)
{
bitmask->length = BIT_LENGTH_INITIAL;
bitmask->bits = malloc(bitmask->length / 8);
memset(bitmask->bits, 0, bitmask->length / 8);
spinlock_init(&bitmask->lock);
}
/**
* Free a bitmask that is no longer required
*
* @param bitmask
*/
void
bitmask_free(GWBITMASK *bitmask)
{
if (bitmask->length)
{
free(bitmask->bits);
bitmask->length = 0;
}
}
/**
* Set the bit at the specified bit position in the bitmask.
* The bitmask will automatically be extended if the bit is
* beyond the current bitmask length
*
* @param bitmask Pointer the bitmask
* @param bit Bit to set
*/
void
bitmask_set(GWBITMASK *bitmask, int bit)
{
unsigned char *ptr;
unsigned char mask;
spinlock_acquire(&bitmask->lock);
if (bit >= bitmask->length)
{
bitmask->bits = realloc(bitmask->bits,
(bitmask->length + BIT_LENGTH_INC) / 8);
memset(bitmask + (bitmask->length / 8), 0,
BIT_LENGTH_INC / 8);
bitmask->length += (BIT_LENGTH_INC / 8);
}
ptr = bitmask->bits + (bit / 8);
mask = 1 << (bit % 8);
*ptr |= mask;
spinlock_release(&bitmask->lock);
}
/**
* Clear the bit at the specified bit position in the bitmask.
* The bitmask will automatically be extended if the bit is
* beyond the current bitmask length
*
* @param bitmask Pointer the bitmask
* @param bit Bit to clear
*/
void
bitmask_clear(GWBITMASK *bitmask, int bit)
{
unsigned char *ptr;
unsigned char mask;
if (bit >= bitmask->length)
{
bitmask->bits = realloc(bitmask->bits,
(bitmask->length + BIT_LENGTH_INC) / 8);
memset(bitmask + (bitmask->length / 8), 0,
BIT_LENGTH_INC / 8);
bitmask->length += (BIT_LENGTH_INC / 8);
}
ptr = bitmask->bits + (bit / 8);
mask = 1 << (bit % 8);
*ptr &= ~mask;
}
/**
* Return a non-zero value if the bit at the specified bit
* position in the bitmask is set.
* The bitmask will automatically be extended if the bit is
* beyond the current bitmask length
*
* @param bitmask Pointer the bitmask
* @param bit Bit to clear
*/
int
bitmask_isset(GWBITMASK *bitmask, int bit)
{
unsigned char *ptr;
unsigned char mask;
spinlock_acquire(&bitmask->lock);
if (bit >= bitmask->length)
{
bitmask->bits = realloc(bitmask->bits,
(bitmask->length + BIT_LENGTH_INC) / 8);
memset(bitmask + (bitmask->length / 8), 0,
BIT_LENGTH_INC / 8);
bitmask->length += (BIT_LENGTH_INC / 8);
}
ptr = bitmask->bits + (bit / 8);
mask = 1 << (bit % 8);
spinlock_release(&bitmask->lock);
return *ptr & mask;
}
/**
* Return a non-zero value of the bitmask has no bits set
* in it.
*
* @param bitmask Pointer the bitmask
* @return Non-zero if the bitmask has no bits set
*/
int
bitmask_isallclear(GWBITMASK *bitmask)
{
unsigned char *ptr, *eptr;
spinlock_acquire(&bitmask->lock);
ptr = bitmask->bits;
eptr = ptr + (bitmask->length / 8);
while (ptr < eptr)
{
if (*ptr != 0)
{
spinlock_release(&bitmask->lock);
return 0;
}
ptr++;
}
spinlock_release(&bitmask->lock);
return 1;
}
/**
* Copy the contents of one bitmap to another.
*
* @param dest Bitmap tp update
* @param src Bitmap to copy
*/
void
bitmask_copy(GWBITMASK *dest, GWBITMASK *src)
{
spinlock_acquire(&src->lock);
spinlock_acquire(&dest->lock);
if (dest->length)
free(dest->bits);
dest->bits = malloc(src->length / 8);
dest->length = src->length;
memcpy(dest->bits, src->bits, src->length / 8);
spinlock_release(&dest->lock);
spinlock_release(&src->lock);
}

505
server/core/hashtable.c Normal file
View File

@ -0,0 +1,505 @@
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <hashtable.h>
/**
* @file hashtable.c General purpose hashtable routines
*
* The hashtable can be create with a custom number of hash buckets,
* a hash function and optional functions to call make copies of the key
* and value and to free them.
*
* The hashtable is arrange as a set of linked lists, the number of linked
* lists beign the hashsize as requested by the user. Entries are hashed by
* calling the hash function that is passed in by the user, this is used as
* an index into the array of linked lists, usign modulo hashsize.
*
* The linked lists are searched using the key comparison function that is
* passed into the hash table creation routine.
*
* By default the hash table keeps the original pointers that are passed in
* for the keys and values, however two functions can be supplied to copy these
* a copy function and a free function. Please note the same function is used for
* the key and the value, if the actions required are different the called functions
* must understand how to differenate the key and value.
*
* The hash table implements a single write, multiple reader locking policy by
* using a pair of counters and a spinlock. The spinlock is used to protect the
* number of readers and writers counters when taking out locks. Releasing of
* locks uses pure atomic actions and thus does not require spinlock protection.
*
* @verbatim
* Revision History
*
* Date Who Description
* 23/06/13 Mark Riddoch Initial implementation
* 23/07/13 Mark Riddoch Addition of hashtable iterator
*
* @endverbatim
*/
static void hashtable_read_lock(HASHTABLE *table);
static void hashtable_read_unlock(HASHTABLE *table);
static void hashtable_write_lock(HASHTABLE *table);
static void hashtable_write_unlock(HASHTABLE *table);
/**
* Special null function used as default memory allfunctions in the hashtable
* implementation. This avoids having to special case the code that manipulates
* the keys and values
*
* @param data The data pointer
* @return Return the value we were called with
*/
static void *
nullfn(void *data)
{
return data;
}
/**
* Allocate a new hash table
*
* @param size The size of the hash table
* @param hashfn The user supplied hash function
* @param cmpfn The user supplied key comparison function
* @return The hashtable table
*/
HASHTABLE *
hashtable_alloc(int size, int (*hashfn)(), int (*cmpfn)())
{
HASHTABLE *rval;
if ((rval = malloc(sizeof(HASHTABLE))) == NULL)
return NULL;
rval->hashsize = size;
rval->hashfn = hashfn;
rval->cmpfn = cmpfn;
rval->copyfn = nullfn;
rval->freefn = nullfn;
rval->n_readers = 0;
rval->writelock = 0;
spinlock_init(&rval->spin);
if ((rval->entries = (HASHENTRIES **)calloc(size, sizeof(HASHENTRIES *))) == NULL)
{
free(rval);
return NULL;
}
memset(rval->entries, 0, size * sizeof(HASHENTRIES *));
return rval;
}
/**
* Delete an entire hash table
*
* @param table The hash table to delete
*/
void
hashtable_free(HASHTABLE *table)
{
int i;
HASHENTRIES *entry, *ptr;
hashtable_write_lock(table);
for (i = 0; i < table->hashsize; i++)
{
entry = table->entries[i];
while (entry)
{
ptr = entry->next;
table->freefn(entry->key);
table->freefn(entry->value);
free(entry);
entry = ptr;
}
}
free(table->entries);
free(table);
}
/**
* Provide memory management functions to the hash table. This allows
* function pointers to be registered that can make copies of the
* key and value.
*
* @param table The hash table
* @param copyfn The copy function
* @param freefn The free function
*/
void
hashtable_memory_fns(HASHTABLE *table, HASHMEMORYFN copyfn, HASHMEMORYFN freefn)
{
table->copyfn = copyfn;
table->freefn = freefn;
}
/**
* Add an item to the hash table.
*
* @param table The hash table to which to add the item
* @param key The key of the item
* @param value The value for the item
* @return Return the number of items added
*/
int
hashtable_add(HASHTABLE *table, void *key, void *value)
{
int hashkey = table->hashfn(key) % table->hashsize;
HASHENTRIES *entry;
hashtable_write_lock(table);
entry = table->entries[hashkey % table->hashsize];
while (entry && table->cmpfn(key, entry->key) != 0)
{
entry = entry->next;
}
if (entry && table->cmpfn(key, entry->key) == 0)
{
/* Duplicate key value */
hashtable_write_unlock(table);
return 0;
}
else
{
HASHENTRIES *ptr = (HASHENTRIES *)malloc(sizeof(HASHENTRIES));
if (ptr == NULL)
{
hashtable_write_unlock(table);
return 0;
}
ptr->key = table->copyfn(key);
ptr->value = table->copyfn(value);
ptr->next = table->entries[hashkey % table->hashsize];
table->entries[hashkey % table->hashsize] = ptr;
}
hashtable_write_unlock(table);
return 1;
}
/**
* Delete an item from the hash table that has a given key
*
* @param table The hash table to delete from
* @param key The key value of the item to remove
* @return Return the number of items deleted
*/
int
hashtable_delete(HASHTABLE *table, void *key)
{
int hashkey = table->hashfn(key) % table->hashsize;
HASHENTRIES *entry, *ptr;
hashtable_write_lock(table);
entry = table->entries[hashkey % table->hashsize];
while (entry && entry->key && table->cmpfn(key, entry->key) != 0)
{
entry = entry->next;
}
if (entry == NULL)
{
/* Not found */
hashtable_write_unlock(table);
return 0;
}
if (entry == table->entries[hashkey % table->hashsize])
{
/* We are removing from the first entry */
table->entries[hashkey % table->hashsize] = entry->next;
table->freefn(entry->key);
table->freefn(entry->value);
entry->key = entry->next->key;
entry->value = entry->next->value;
free(entry);
}
else
{
ptr = table->entries[hashkey % table->hashsize];
while (ptr && ptr->next != entry)
ptr = ptr->next;
if (ptr == NULL)
{
hashtable_write_unlock(table);
return 0; /* This should never happen */
}
ptr->next = entry->next;
table->freefn(entry->key);
table->freefn(entry->value);
free(entry);
}
hashtable_write_unlock(table);
return 1;
}
/**
* Fetch an item with a given key value from the hash table
*
* @param table The hash table
* @param key The key value
* @return The item or NULL if the item was not found
*/
void *
hashtable_fetch(HASHTABLE *table, void *key)
{
int hashkey = table->hashfn(key) % table->hashsize;
HASHENTRIES *entry;
hashtable_read_lock(table);
entry = table->entries[hashkey % table->hashsize];
while (entry && entry->key && table->cmpfn(key, entry->key) != 0)
{
entry = entry->next;
}
if (entry == NULL)
{
hashtable_read_unlock(table);
return NULL;
}
else
{
hashtable_read_unlock(table);
return entry->value;
}
}
/**
* Print hash table statistics to the standard output
*
* @param table The hash table
*/
void
hashtable_stats(HASHTABLE *table)
{
int total, longest, i, j;
HASHENTRIES *entries;
printf("Hashtable: %p, size %d\n", table, table->hashsize);
total = 0;
longest = 0;
hashtable_read_lock(table);
for (i = 0; i < table->hashsize; i++)
{
j = 0;
entries = table->entries[i];
while (entries)
{
j++;
entries = entries->next;
}
total += j;
if (j > longest)
longest = j;
}
hashtable_read_unlock(table);
printf("\tNo. of entries: %d\n", total);
printf("\tAverage chain length: %.1f\n", (float)total / table->hashsize);
printf("\tLongest chain length: %d\n", longest);
}
/**
* Print hash table statistics to a DCB
*
* @param dcb The DCB to send the information to
* @param table The hash table
*/
void
dcb_hashtable_stats(DCB *dcb, HASHTABLE *table)
{
int total, longest, i, j;
HASHENTRIES *entries;
dcb_printf(dcb, "Hashtable: %p, size %d\n", table, table->hashsize);
total = 0;
longest = 0;
hashtable_read_lock(table);
for (i = 0; i < table->hashsize; i++)
{
j = 0;
entries = table->entries[i];
while (entries)
{
j++;
entries = entries->next;
}
total += j;
if (j > longest)
longest = j;
}
hashtable_read_unlock(table);
dcb_printf(dcb, "\tNo. of entries: %d\n", total);
dcb_printf(dcb, "\tAverage chain length: %.1f\n", (float)total / table->hashsize);
dcb_printf(dcb, "\tLongest chain length: %d\n", longest);
}
/**
* Take a read lock on the hashtable.
*
* The hashtable support multiple readers and a single writer,
* we have a spinlock to protect the two counts, n_readers and
* writelock.
*
* We take the hashtable spinlock and then check that writelock
* is set to zero. If not we release the spinlock and do dirty
* reads of writelock until it goes to 0. Once it is zero we
* acquire the spinlock again and test that writelock is still
* 0.
*
* With writelock set to zero we increment n_readers with the
* spinlock still held.
*
* @param table The hashtable to lock.
*/
static void
hashtable_read_lock(HASHTABLE *table)
{
spinlock_acquire(&table->spin);
while (table->writelock)
{
spinlock_release(&table->spin);
while (table->writelock)
;
spinlock_acquire(&table->spin);
}
table->n_readers++;
spinlock_release(&table->spin);
}
/**
* Release a previously obtained readlock.
*
* Simply decrement the n_readers value for the hash table
*
* @param table The hash table to unlock
*/
static void
hashtable_read_unlock(HASHTABLE *table)
{
atomic_add(&table->n_readers, -1);
}
/**
* Obtain an exclusive write lock for the hash table.
*
* We acquire the hashtable spinlock, check for the number of
* readers beign zero. If it is not we hold the spinlock and
* loop waiting for the n_readers to reach zero. This will prevent
* any new readers beign granted access but will not prevent current
* readers releasing the read lock.
*
* Once we have no readers we increment writelock and test if we are
* the only writelock holder, if not we repeat the process. We hold
* the spinlock throughout the process since both read and write
* locks do not require the spinlock to be acquired.
*
* @param table The table to lock for updates
*/
static void
hashtable_write_lock(HASHTABLE *table)
{
int available;
spinlock_acquire(&table->spin);
do {
while (table->n_readers)
;
available = atomic_add(&table->writelock, 1);
if (available != 0)
atomic_add(&table->writelock, -1);
} while (available != 0);
spinlock_release(&table->spin);
}
/**
* Release the write lock on the hash table.
*
* @param table The hash table to unlock
*/
static void
hashtable_write_unlock(HASHTABLE *table)
{
atomic_add(&table->writelock, -1);
}
/**
* Create an iterator on a hash table
*
* @param table The table to ceate an iterator on
* @return An iterator to use in future calls
*/
HASHITERATOR *
hashtable_iterator(HASHTABLE *table)
{
HASHITERATOR *rval;
if ((rval = (HASHITERATOR *)malloc(sizeof(HASHITERATOR))) != NULL)
{
rval->table = table;
rval->chain = 0;
rval->depth = -1;
}
return rval;
}
/**
* Return the next key for a hashtable iterator
*
* @param iter The hashtable iterator
* @return The next key value or NULL
*/
void *
hashtable_next(HASHITERATOR *iter)
{
int i;
HASHENTRIES *entries;
iter->depth++;
while (iter->chain < iter->table->hashsize)
{
if ((entries = iter->table->entries[iter->chain]) != NULL)
{
i = 0;
hashtable_read_lock(iter->table);
while (entries && i < iter->depth)
{
entries = entries->next;
i++;
}
hashtable_read_unlock(iter->table);
if (entries)
return entries->key;
}
iter->depth = 0;
iter->chain++;
}
return NULL;
}
/**
* Free a hashtable iterator
*
* @param iter The iterator to free
*/
void
hashtable_iterator_free(HASHITERATOR *iter)
{
free(iter);
}

275
server/core/load_utils.c Normal file
View File

@ -0,0 +1,275 @@
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
/**
* @file load_utils.c Utility functions to aid the loading of dynamic modules
* into the gateway
*
* @verbatim
* Revision History
*
* Date Who Description
* 13/06/13 Mark Riddoch Initial implementation
* 14/06/13 Mark Riddoch Updated to add call to ModuleInit if one is defined
* in the loaded module.
* Also updated to call fixed GetModuleObject
*
* @endverbatim
*/
#include <sys/param.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <dlfcn.h>
#include <modules.h>
#include <skygw_utils.h>
#include <log_manager.h>
static MODULES *registered = NULL;
static MODULES *find_module(const char *module);
static void register_module(const char *module, const char *type, void *dlhandle, char *version, void *modobj);
static void unregister_module(const char *module);
/**
* Load the dynamic library related to a gateway module. The routine
* will look for library files in the current directory,
* $MAXSCALE_HOME/modules and /usr/local/skysql/MaxScale/modules.
*
* @param module Name of the module to load
* @param type Type of module, used purely for registration
* @return The module specific entry point structure or NULL
*/
void *
load_module(const char *module, const char *type)
{
char *home, *version;
char fname[MAXPATHLEN];
void *dlhandle, *sym;
char *(*ver)();
void *(*ep)(), *modobj;
MODULES *mod;
if ((mod = find_module(module)) == NULL)
{
/*
* The module is not already loaded
*
* Search of the shared object.
*/
sprintf(fname, "./lib%s.so", module);
if (access(fname, F_OK) == -1)
{
if ((home = getenv("MAXSCALE_HOME")) == NULL)
home = "/usr/local/skysql/MaxScale";
sprintf(fname, "%s/modules/lib%s.so", home, module);
if (access(fname, F_OK) == -1)
{
skygw_log_write(NULL, LOGFILE_ERROR,
"Unable to find library for module: %s\n", module);
return NULL;
}
}
if ((dlhandle = dlopen(fname, RTLD_NOW|RTLD_LOCAL)) == NULL)
{
skygw_log_write(NULL, LOGFILE_ERROR,
"Unable to load library for module: %s, %s\n", module, dlerror());
return NULL;
}
if ((sym = dlsym(dlhandle, "version")) == NULL)
{
skygw_log_write(NULL, LOGFILE_ERROR,
"Version interface not supported by module: %s, %s\n", module, dlerror());
dlclose(dlhandle);
return NULL;
}
ver = sym;
version = ver();
/*
* If the module has a ModuleInit function cal it now.
*/
if ((sym = dlsym(dlhandle, "ModuleInit")) != NULL)
{
void (*ModuleInit)() = sym;
ModuleInit();
}
if ((sym = dlsym(dlhandle, "GetModuleObject")) == NULL)
{
skygw_log_write(NULL, LOGFILE_ERROR,
"Expected entry point interface missing from module: %s, %s\n", module, dlerror());
dlclose(dlhandle);
return NULL;
}
ep = sym;
modobj = ep();
skygw_log_write(NULL, LOGFILE_MESSAGE, "Loaded module %s: %s\n", module, version);
register_module(module, type, dlhandle, version, modobj);
}
else
{
/*
* The module is already loaded, get the entry points again and
* return a reference to the already loaded module.
*/
modobj = mod->modobj;
}
return modobj;
}
/**
* Unload a module.
*
* No errors are returned since it is not clear that much can be done
* to fix issues relating to unloading modules.
*
* @param module The name of the module
*/
void
unload_module(const char *module)
{
MODULES *mod = find_module(module);
void *handle;
if (!mod)
return;
handle = mod->handle;
unregister_module(module);
dlclose(handle);
}
/**
* Find a module that has been previously loaded and return the handle for that
* library
*
* @param module The name of the module
* @return The module handle or NULL if it was not found
*/
static MODULES *
find_module(const char *module)
{
MODULES *mod = registered;
while (mod)
if (strcmp(mod->module, module) == 0)
return mod;
else
mod = mod->next;
return NULL;
}
/**
* Register a newly loaded module. The registration allows for single copies
* to be loaded and cached entry point information to be return.
*
* @param module The name of the module loaded
* @param type The type of the module loaded
* @param dlhandle The handle returned by dlopen
* @param version The version string returned by the module
* @param modobj The module object
*/
static void
register_module(const char *module, const char *type, void *dlhandle, char *version, void *modobj)
{
MODULES *mod;
if ((mod = malloc(sizeof(MODULES))) == NULL)
return;
mod->module = strdup(module);
mod->type = strdup(type);
mod->handle = dlhandle;
mod->version = strdup(version);
mod->modobj = modobj;
mod->next = registered;
registered = mod;
}
/**
* Unregister a module
*
* @param module The name of the module to remove
*/
static void
unregister_module(const char *module)
{
MODULES *mod = find_module(module);
MODULES *ptr;
if (!mod)
return; // Module not found
if (registered == mod)
registered = mod->next;
else
{
ptr = registered;
while (ptr && ptr->next != mod)
ptr = ptr->next;
}
/*
* The module is now not in the linked list and all
* memory related to it can be freed
*/
free(mod->module);
free(mod->type);
free(mod->version);
free(mod);
}
/**
* Print Modules
*
* Diagnostic routine to display all the loaded modules
*/
void
printModules()
{
MODULES *ptr = registered;
printf("%-15s | %-11s | Version\n", "Module Name", "Module Type");
printf("-----------------------------------------------------\n");
while (ptr)
{
printf("%-15s | %-11s | %s\n", ptr->module, ptr->type, ptr->version);
ptr = ptr->next;
}
}
/**
* Print Modules to a DCB
*
* Diagnostic routine to display all the loaded modules
*/
void
dprintAllModules(DCB *dcb)
{
MODULES *ptr = registered;
dcb_printf(dcb, "%-15s | %-11s | Version\n", "Module Name", "Module Type");
dcb_printf(dcb, "-----------------------------------------------------\n");
while (ptr)
{
dcb_printf(dcb, "%-15s | %-11s | %s\n", ptr->module, ptr->type, ptr->version);
ptr = ptr->next;
}
}

47
server/core/maxkeys.c Normal file
View File

@ -0,0 +1,47 @@
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
/**
* @file maxkeys.c - Create the random encryption keys for maxscale
*
* @verbatim
* Revision History
*
* Date Who Description
* 24/07/13 Mark Riddoch Initial implementation
*
* @endverbatim
*/
#include <stdio.h>
#include <secrets.h>
main(int argc, char **argv)
{
if (argc != 2)
{
fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
exit(1);
}
if (secrets_writeKeys(argv[1]))
{
fprintf(stderr, "Failed to encode the password\n");
exit(1);
}
exit(0);
}

55
server/core/maxpasswd.c Normal file
View File

@ -0,0 +1,55 @@
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
/**
* @file maxpasswd.c - Implementation of pasword encoding
*
* @verbatim
* Revision History
*
* Date Who Description
* 24/07/13 Mark Riddoch Initial implementation
*
* @endverbatim
*/
#include <stdio.h>
#include <secrets.h>
/**
* Encrypt a password for storing in the MaxScale.cnf file
*
* @param argc Argument count
* @param arv Argument vector
*/
int
main(int argc, char **argv)
{
char *enc;
if (argc != 2)
{
fprintf(stderr, "Usage: %s <password>\n", argv[0]);
exit(1);
}
if ((enc = encryptPassword(argv[1])) != NULL)
printf("%s\n", enc);
else
fprintf(stderr, "Failed to encode the password\n");
return 0;
}

196
server/core/monitor.c Normal file
View File

@ -0,0 +1,196 @@
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
/**
* @file monitor.c - The monitor module management routines
*
* @verbatim
* Revision History
*
* Date Who Description
* 08/07/13 Mark Riddoch Initial implementation
*
* @endverbatim
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <monitor.h>
#include <spinlock.h>
#include <modules.h>
#include <skygw_utils.h>
#include <log_manager.h>
static MONITOR *allMonitors = NULL;
static SPINLOCK monLock = SPINLOCK_INIT;
/**
* Allocate a new monitor, load the associated module for the monitor
* and start execution on the monitor.
*
* @param name The name of the monitor module to load
* @param module The module to load
* @return The newly created monitor
*/
MONITOR *
monitor_alloc(char *name, char *module)
{
MONITOR *mon;
if ((mon = (MONITOR *)malloc(sizeof(MONITOR))) == NULL)
{
return NULL;
}
mon->name = strdup(name);
if ((mon->module = load_module(module, MODULE_MONITOR)) == NULL)
{
skygw_log_write(NULL, LOGFILE_ERROR, "Unable to load monitor module '%s'\n", name);
free(mon->name);
free(mon);
return NULL;
}
mon->handle = (*mon->module->startMonitor)(NULL);
spinlock_acquire(&monLock);
mon->next = allMonitors;
allMonitors = mon;
spinlock_release(&monLock);
return mon;
}
/**
* Free a monitor, first stop the monitor and then remove the monitor from
* the chain of monitors and free the memory.
*
* @param mon The monitor to free
*/
void
monitor_free(MONITOR *mon)
{
MONITOR *ptr;
mon->module->stopMonitor(mon->handle);
spinlock_acquire(&monLock);
if (allMonitors == mon)
allMonitors = mon->next;
else
{
ptr = allMonitors;
while (ptr->next && ptr->next != mon)
ptr = ptr->next;
if (ptr->next)
ptr->next = mon->next;
}
spinlock_release(&monLock);
free(mon->name);
free(mon);
}
/**
* Start an individual monitor that has previoulsy been stopped.
*
* @param monitor The Monitor that should be started
*/
void
monitorStart(MONITOR *monitor)
{
monitor->handle = (*monitor->module->startMonitor)(monitor->handle);
}
/**
* Stop a given monitor
*
* @param monitor The monitor to stop
*/
void
monitorStop(MONITOR *monitor)
{
monitor->module->stopMonitor(monitor->handle);
}
/**
* Shutdown all running monitors
*/
void
monitorStopAll()
{
MONITOR *ptr;
spinlock_acquire(&monLock);
ptr = allMonitors;
while (ptr)
{
monitorStop(ptr);
ptr = ptr->next;
}
spinlock_release(&monLock);
}
/**
* Add a server to a monitor. Simply register the server that needs to be
* monitored to the running monitor module.
*
* @param mon The Monitor instance
* @param server The Server to add to the monitoring
*/
void
monitorAddServer(MONITOR *mon, SERVER *server)
{
mon->module->registerServer(mon->handle, server);
}
/**
* Add a default user to the monitor. This user is used to connect to the
* monitored databases but may be overriden on a per server basis.
*
* @param mon The monitor instance
* @param user The default username to use when connecting
* @param passwd The default password associated to the default user.
*/
void
monitorAddUser(MONITOR *mon, char *user, char *passwd)
{
mon->module->defaultUser(mon->handle, user, passwd);
}
/**
* Show all monitors
*
* @param dcb DCB for printing output
*/
void
monitorShowAll(DCB *dcb)
{
MONITOR *ptr;
spinlock_acquire(&monLock);
ptr = allMonitors;
while (ptr)
{
dcb_printf(dcb, "Monitor: %p\n", ptr);
dcb_printf(dcb, "\tName: %s\n", ptr->name);
if (ptr->module->diagnostics)
ptr->module->diagnostics(dcb, ptr->handle);
ptr = ptr->next;
}
spinlock_release(&monLock);
}

252
server/core/poll.c Normal file
View File

@ -0,0 +1,252 @@
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <poll.h>
#include <dcb.h>
#include <atomic.h>
#include <gwbitmask.h>
/**
* @file poll.c - Abstraction of the epoll functionality
*
* @verbatim
* Revision History
*
* Date Who Description
* 19/06/13 Mark Riddoch Initial implementation
* 28/06/13 Mark Riddoch Added poll mask support and DCB
* zombie management
*
* @endverbatim
*/
static int epoll_fd = -1; /**< The epoll file descriptor */
static int shutdown = 0; /**< Flag the shutdown of the poll subsystem */
static GWBITMASK poll_mask;
/**
* The polling statistics
*/
static struct {
int n_read; /**< Number of read events */
int n_write; /**< Number of write events */
int n_error; /**< Number of error events */
int n_hup; /**< Number of hangup events */
int n_accept; /**< Number of accept events */
int n_polls; /**< Number of poll cycles */
} pollStats;
/**
* Initialise the polling system we are using for the gateway.
*
* In this case we are using the Linux epoll mechanism
*/
void
poll_init()
{
if (epoll_fd != -1)
return;
if ((epoll_fd = epoll_create(MAX_EVENTS)) == -1)
{
perror("epoll_create");
exit(-1);
}
memset(&pollStats, 0, sizeof(pollStats));
bitmask_init(&poll_mask);
}
/**
* Add a DCB to the set of descriptors within the polling
* environment.
*
* @param dcb The descriptor to add to the poll
* @return -1 on error or 0 on success
*/
int
poll_add_dcb(DCB *dcb)
{
struct epoll_event ev;
ev.events = EPOLLIN | EPOLLOUT | EPOLLET;
ev.data.ptr = dcb;
return epoll_ctl(epoll_fd, EPOLL_CTL_ADD, dcb->fd, &ev);
}
/**
* Remove a descriptor from the set of descriptors within the
* polling environment.
*
* @param dcb The descriptor to remove
* @return -1 on error or 0 on success
*/
int
poll_remove_dcb(DCB *dcb)
{
struct epoll_event ev;
return epoll_ctl(epoll_fd, EPOLL_CTL_DEL, dcb->fd, &ev);
}
#define BLOCKINGPOLL 0 /* Set BLOCKING POLL to 1 if using a single thread and to make
* debugging easier.
*/
/**
* The main polling loop
*
* This routine does the polling and despatches of IO events
* to the DCB's. It may be called either directly or as the entry point
* of a polling thread within the gateway.
*
* The routine will loop as long as the variable "shutdown" is set to zero,
* setting this to a non-zero value will cause the polling loop to return.
*
* There are two options for the polling, a debug option that is only useful if
* you have a single thread. This blocks in epoll_wait until an event occurs.
*
* The non-debug option does an epoll with a time out. This allows the checking of
* shutdown value to be checked in all threads. The algorithm for polling in this
* mode is to do a poll with no-wait, if no events are detected then the poll is
* repeated with a time out. This allows for a quick check before making the call
* with timeout. The call with the timeout differs in that the Linux scheduler may
* deschedule a process if a timeout is included, but will not do this if a 0 timeout
* value is given. this improves performance when the gateway is under heavy load.
*
* @param arg The thread ID passed as a void * to satisfy the threading package
*/
void
poll_waitevents(void *arg)
{
struct epoll_event events[MAX_EVENTS];
int i, nfds;
int thread_id = (int)arg;
/* Add this thread to the bitmask of running polling threads */
bitmask_set(&poll_mask, thread_id);
while (1)
{
#if BLOCKINGPOLL
if ((nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1)) == -1)
{
}
#else
if ((nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, 0)) == -1)
{
}
else if (nfds == 0)
{
if ((nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, EPOLL_TIMEOUT)) == -1)
{
}
}
#endif
if (nfds > 0)
{
atomic_add(&pollStats.n_polls, 1);
for (i = 0; i < nfds; i++)
{
DCB *dcb = (DCB *)events[i].data.ptr;
__uint32_t ev = events[i].events;
if (DCB_ISZOMBIE(dcb))
continue;
if (ev & EPOLLERR)
{
atomic_add(&pollStats.n_error, 1);
dcb->func.error(dcb);
if (DCB_ISZOMBIE(dcb))
continue;
}
if (ev & EPOLLHUP)
{
atomic_add(&pollStats.n_hup, 1);
dcb->func.hangup(dcb);
if (DCB_ISZOMBIE(dcb))
continue;
}
if (ev & EPOLLOUT)
{
atomic_add(&pollStats.n_write, 1);
dcb->func.write_ready(dcb);
}
if (ev & EPOLLIN)
{
if (dcb->state == DCB_STATE_LISTENING)
{
atomic_add(&pollStats.n_accept, 1);
dcb->func.accept(dcb);
}
else
{
atomic_add(&pollStats.n_read, 1);
dcb->func.read(dcb);
}
}
}
}
dcb_process_zombies(thread_id);
if (shutdown)
{
/* Remove this thread from the bitmask of running polling threads */
bitmask_clear(&poll_mask, thread_id);
return;
}
}
}
/**
* Shutdown the polling loop
*/
void
poll_shutdown()
{
shutdown = 1;
}
/**
* Return the bitmask of polling threads
*
* @return The bitmask of the running polling threads
*/
GWBITMASK *
poll_bitmask()
{
return &poll_mask;
}
/**
* Debug routine to print the polling statistics
*
* @param dcb DCB to print to
*/
void
dprintPollStats(DCB *dcb)
{
dcb_printf(dcb, "Number of epoll cycles: %d\n", pollStats.n_polls);
dcb_printf(dcb, "Number of read events: %d\n", pollStats.n_read);
dcb_printf(dcb, "Number of write events: %d\n", pollStats.n_write);
dcb_printf(dcb, "Number of error events: %d\n", pollStats.n_error);
dcb_printf(dcb, "Number of hangup events: %d\n", pollStats.n_hup);
dcb_printf(dcb, "Number of accept events: %d\n", pollStats.n_accept);
}

237
server/core/secrets.c Normal file
View File

@ -0,0 +1,237 @@
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
#include <secrets.h>
#include <time.h>
#include <skygw_utils.h>
#include <log_manager.h>
#include <ctype.h>
/**
* Generate a random printable character
*
* @return A random printable character
*/
static unsigned char
secrets_randomchar()
{
return (char)((rand() % ('~' - ' ')) + ' ');
}
static int
secrets_random_str(unsigned char *output, int len)
{
int i;
srand((unsigned long )time(0L) ^ (unsigned long )output);
for ( i = 0; i < len; ++i )
{
output[i] = secrets_randomchar();
}
return 0;
}
/**
* secrets_readKeys
*
* This routine reads data from a binary file and extracts the AES encryption key
* and the AES Init Vector
*
* @return The keys structure or NULL on error
*/
static MAXKEYS *
secrets_readKeys()
{
char secret_file[180];
char *home;
MAXKEYS *keys;
struct stat secret_stats;
int fd;
if ((home = getenv("MAXSCALE_HOME")) == NULL)
home = "/usr/local/skysql/MaxScale";
sprintf(secret_file, "%s/etc/.secrets", home);
/* open secret file */
if ((fd = open(secret_file, O_RDONLY)) < 0)
{
skygw_log_write(NULL, LOGFILE_ERROR, "secrets_readKeys, failed opening secret file [%s]. Error %i, %s\n", secret_file, errno, strerror(errno));
return NULL;
}
/* accessing file details */
if (fstat(fd, &secret_stats) < 0) {
skygw_log_write(NULL, LOGFILE_ERROR, "secrets_readKeys, failed accessing secret file details [%s]. Error %i, %s\n", secret_file, errno, strerror(errno));
return NULL;
}
if (secret_stats.st_size != sizeof(MAXKEYS))
{
skygw_log_write(NULL, LOGFILE_ERROR, "Secrets file %s is incorrect size\n", secret_file);
return NULL;
}
if (secret_stats.st_mode != (S_IRUSR|S_IFREG))
{
skygw_log_write(NULL, LOGFILE_ERROR, "Ignoring secrets file, permissions must be read only fo rthe owner\n");
return NULL;
}
if ((keys = (MAXKEYS *)malloc(sizeof(MAXKEYS))) == NULL)
{
skygw_log_write(NULL, LOGFILE_ERROR,
"Insufficient memory to create the keys structure.\n");
return NULL;
}
/* read all data from file */
if (read(fd, keys, sizeof(MAXKEYS)) != sizeof(MAXKEYS))
{
skygw_log_write(NULL, LOGFILE_ERROR, "secrets_readKeys, failed reading from secret file [%s]. Error %i, %s\n", secret_file, errno, strerror(errno));
return NULL;
}
/* Close the file */
if (close(fd) < 0) {
skygw_log_write(NULL, LOGFILE_ERROR, "secrets_readKeys, failed closing the secret file [%s]. Error %i, %s\n", secret_file, errno, strerror(errno));
return NULL;
}
return keys;
}
/**
* secrets_writeKeys
*
* This routine writes into a binary file the AES encryption key
* and the AES Init Vector
*
* @param secret_file The file with secret keys
* @return 0 on success and 1 on failure
*/
int secrets_writeKeys(char *secret_file)
{
int fd;
MAXKEYS key;
/* Open for writing | Create | Truncate the file for writing */
if ((fd = open(secret_file, O_CREAT | O_WRONLY | O_TRUNC), S_IRUSR) < 0)
{
skygw_log_write(NULL, LOGFILE_ERROR, "secrets_createKeys, failed opening secret file [%s]. Error %i, %s\n", secret_file, errno, strerror(errno));
return 1;
}
srand(time(NULL));
secrets_random_str(key.enckey, MAXSCALE_KEYLEN);
secrets_random_str(key.initvector, MAXSCALE_IV_LEN);
/* Write data */
if (write(fd, &key, sizeof(key)) < 0)
{
skygw_log_write(NULL, LOGFILE_ERROR, "secrets_createKeys, failed writing into secret file [%s]. Error %i, %s\n", secret_file, errno, strerror(errno));
return 1;
}
/* close file */
if (close(fd) < 0)
{
skygw_log_write(NULL, LOGFILE_ERROR, "secrets_createKeys, failed closing the secret file [%s]. Error %i, %s\n", secret_file, errno, strerror(errno));
}
chmod(secret_file, S_IRUSR);
return 0;
}
/**
* Decrypt a password that is stored inthe MaxScale configuration file.
* If the password is not encrypted, ie is not a HEX string, then the
* original is returned, this allows for backward compatibility with
* unencrypted password.
*
* Note the return is always a malloc'd string that the caller must free
*
* @param crypt The encrypted password
* @return The decrypted password
*/
char *
decryptPassword(char *crypt)
{
MAXKEYS *keys;
AES_KEY aeskey;
unsigned char *plain;
char *ptr;
unsigned char encrypted[80];
int enlen;
keys = secrets_readKeys();
if (!keys)
return strdup(crypt);
/* If the input is not a HEX string return the input - it probably was not encrypted */
for (ptr = crypt; *ptr; ptr++)
if (!isxdigit(*ptr))
return strdup(crypt);
enlen = strlen(crypt) / 2;
gw_hex2bin(encrypted, crypt, strlen(crypt));
if ((plain = (unsigned char *)malloc(80)) == NULL)
return NULL;
AES_set_decrypt_key(keys->enckey, 8 * MAXSCALE_KEYLEN, &aeskey);
AES_cbc_encrypt(encrypted, plain, enlen, &aeskey, keys->initvector, AES_DECRYPT);
free(keys);
return (char *)plain;
}
/**
* Encrypt a password that can be stored in the MaxScale configuration file.
*
* Note the return is always a malloc'd string that the caller must free
*
* @param password The password to encrypt
* @return The encrypted password
*/
char *
encryptPassword(char *password)
{
MAXKEYS *keys;
AES_KEY aeskey;
int padded_len;
char *hex_output;
unsigned char padded_passwd[80];
unsigned char encrypted[80];
if ((keys = secrets_readKeys()) == NULL)
return NULL;
memset(padded_passwd, 0, 80);
strcpy((char *)padded_passwd, password);
padded_len = ((strlen(password) / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE;
AES_set_encrypt_key(keys->enckey, 8 * MAXSCALE_KEYLEN, &aeskey);
AES_cbc_encrypt(padded_passwd, encrypted, padded_len, &aeskey, keys->initvector, AES_ENCRYPT);
hex_output = (char *)malloc(padded_len * 2);
gw_bin2hex(hex_output, encrypted, padded_len);
free(keys);
return hex_output;
}

320
server/core/server.c Normal file
View File

@ -0,0 +1,320 @@
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
/**
* @file server.c - A representation of a backend server within the gateway.
*
* @verbatim
* Revision History
*
* Date Who Description
* 18/06/13 Mark Riddoch Initial implementation
*
* @endverbatim
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <session.h>
#include <server.h>
#include <spinlock.h>
#include <dcb.h>
#include <skygw_utils.h>
#include <log_manager.h>
static SPINLOCK server_spin = SPINLOCK_INIT;
static SERVER *allServers = NULL;
/**
* Allocate a new server withn the gateway
*
*
* @param servname The server name
* @param protocol The protocol to use to connect to the server
* @param port The port to connect to
*
* @return The newly created server or NULL if an error occured
*/
SERVER *
server_alloc(char *servname, char *protocol, unsigned short port)
{
SERVER *server;
if ((server = (SERVER *)malloc(sizeof(SERVER))) == NULL)
return NULL;
server->name = strdup(servname);
server->protocol = strdup(protocol);
server->port = port;
memset(&server->stats, 0, sizeof(SERVER_STATS));
server->status = SERVER_RUNNING;
server->nextdb = NULL;
server->monuser = NULL;
server->monpw = NULL;
spinlock_acquire(&server_spin);
server->next = allServers;
allServers = server;
spinlock_release(&server_spin);
return server;
}
/**
* Deallocate the specified server
*
* @param server The service to deallocate
* @return Returns true if the server was freed
*/
int
server_free(SERVER *server)
{
SERVER *ptr;
/* First of all remove from the linked list */
spinlock_acquire(&server_spin);
if (allServers == server)
{
allServers = server->next;
}
else
{
ptr = allServers;
while (ptr && ptr->next != server)
{
ptr = ptr->next;
}
if (ptr)
ptr->next = server->next;
}
spinlock_release(&server_spin);
/* Clean up session and free the memory */
free(server->name);
free(server->protocol);
free(server);
return 1;
}
/**
* Find an existing server
*
* @param servname The Server name or address
* @param port The server port
* @return The server or NULL if not found
*/
SERVER *
server_find(char *servname, unsigned short port)
{
SERVER *server;
spinlock_acquire(&server_spin);
server = allServers;
while (server)
{
if (strcmp(server->name, servname) == 0 && server->port == port)
break;
server = server->next;
}
spinlock_release(&server_spin);
return server;
}
/**
* Print details of an individual server
*
* @param server Server to print
*/
void
printServer(SERVER *server)
{
printf("Server %p\n", server);
printf("\tServer: %s\n", server->name);
printf("\tProtocol: %s\n", server->protocol);
printf("\tPort: %d\n", server->port);
printf("\tTotal connections: %d\n", server->stats.n_connections);
printf("\tCurrent connections: %d\n", server->stats.n_current);
}
/**
* Print all servers
*
* Designed to be called within a debugger session in order
* to display all active servers within the gateway
*/
void
printAllServers()
{
SERVER *ptr;
spinlock_acquire(&server_spin);
ptr = allServers;
while (ptr)
{
printServer(ptr);
ptr = ptr->next;
}
spinlock_release(&server_spin);
}
/**
* Print all servers to a DCB
*
* Designed to be called within a debugger session in order
* to display all active servers within the gateway
*/
void
dprintAllServers(DCB *dcb)
{
SERVER *ptr;
spinlock_acquire(&server_spin);
ptr = allServers;
while (ptr)
{
dcb_printf(dcb, "Server %p\n", ptr);
dcb_printf(dcb, "\tServer: %s\n", ptr->name);
dcb_printf(dcb, "\tStatus: %s\n", server_status(ptr));
dcb_printf(dcb, "\tProtocol: %s\n", ptr->protocol);
dcb_printf(dcb, "\tPort: %d\n", ptr->port);
dcb_printf(dcb, "\tNumber of connections: %d\n", ptr->stats.n_connections);
dcb_printf(dcb, "\tCurrent no. of connections: %d\n", ptr->stats.n_current);
ptr = ptr->next;
}
spinlock_release(&server_spin);
}
/**
* Print server details to a DCB
*
* Designed to be called within a debugger session in order
* to display all active servers within the gateway
*/
void
dprintServer(DCB *dcb, SERVER *server)
{
dcb_printf(dcb, "Server %p\n", server);
dcb_printf(dcb, "\tServer: %s\n", server->name);
dcb_printf(dcb, "\tStatus: %s\n", server_status(server));
dcb_printf(dcb, "\tProtocol: %s\n", server->protocol);
dcb_printf(dcb, "\tPort: %d\n", server->port);
dcb_printf(dcb, "\tNumber of connections: %d\n", server->stats.n_connections);
dcb_printf(dcb, "\tCurrent No. of connections: %d\n", server->stats.n_current);
}
/**
* Convert a set of server status flags to a string, the returned
* string has been malloc'd and must be free'd by the caller
*
* @param server The server to return the status of
* @return A string representation of the status flags
*/
char *
server_status(SERVER *server)
{
char *status = NULL;
if ((status = (char *)malloc(200)) == NULL)
return NULL;
status[0] = 0;
if (server->status & SERVER_MASTER)
strcat(status, "Master, ");
if (server->status & SERVER_SLAVE)
strcat(status, "Slave, ");
if (server->status & SERVER_JOINED)
strcat(status, "Joined, ");
if (server->status & SERVER_RUNNING)
strcat(status, "Running");
else
strcat(status, "Down");
return status;
}
/**
* Set a status bit in the server
*
* @param server The server to update
* @param bit The bit to set for the server
*/
void
server_set_status(SERVER *server, int bit)
{
server->status |= bit;
}
/**
* Clear a status bit in the server
*
* @param server The server to update
* @param bit The bit to clear for the server
*/
void
server_clear_status(SERVER *server, int bit)
{
server->status &= ~bit;
}
/**
* Add a user name and password to use for monitoring the
* state of the server.
*
* @param server The server to update
* @param user The user name to use
* @param passwd The password of the user
*/
void
serverAddMonUser(SERVER *server, char *user, char *passwd)
{
server->monuser = strdup(user);
server->monpw = strdup(passwd);
}
/**
* Check and update a server definition following a configuration
* update. Changes will not affect any current connections to this
* server, however all new connections will use the new settings.
*
* If the new settings are different from those already applied to the
* server then a message will be written to the log.
*
* @param server The server to update
* @param protocol The new protocol for the server
* @param user The monitor user for the server
* @param passwd The password to use for the monitor user
*/
void
server_update(SERVER *server, char *protocol, char *user, char *passwd)
{
if (!strcmp(server->protocol, protocol))
{
skygw_log_write(NULL, LOGFILE_MESSAGE, "Update server protocol for server %s to protocol %s",
server->name, protocol);
free(server->protocol);
server->protocol = strdup(protocol);
}
if (strcmp(server->monuser, user) == 0 || strcmp(server->monpw, passwd) == 0)
{
skygw_log_write(NULL, LOGFILE_MESSAGE, "Update server monitor credentials for server %s",
server->name);
free(server->monuser);
free(server->monpw);
serverAddMonUser(server, user, passwd);
}
}

625
server/core/service.c Normal file
View File

@ -0,0 +1,625 @@
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
/**
* @file service.c - A representation of the service within the gateway.
*
* @verbatim
* Revision History
*
* Date Who Description
* 18/06/13 Mark Riddoch Initial implementation
* 24/06/13 Massimiliano Pinto Added: Loading users from mysql backend in serviceStart
* @endverbatim
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <session.h>
#include <service.h>
#include <server.h>
#include <router.h>
#include <spinlock.h>
#include <modules.h>
#include <dcb.h>
#include <users.h>
#include <dbusers.h>
#include <poll.h>
#include <skygw_utils.h>
#include <log_manager.h>
static SPINLOCK service_spin = SPINLOCK_INIT;
static SERVICE *allServices = NULL;
/**
* Allocate a new service for the gateway to support
*
*
* @param servname The service name
* @param router Name of the router module this service uses
*
* @return The newly created service or NULL if an error occured
*/
SERVICE *
service_alloc(char *servname, char *router)
{
SERVICE *service;
if ((service = (SERVICE *)malloc(sizeof(SERVICE))) == NULL)
return NULL;
if ((service->router = load_module(router, MODULE_ROUTER)) == NULL)
{
free(service);
return NULL;
}
service->name = strdup(servname);
service->routerModule = strdup(router);
memset(&service->stats, 0, sizeof(SERVICE_STATS));
service->ports = NULL;
service->stats.started = time(0);
service->state = SERVICE_STATE_ALLOC;
service->credentials.name = NULL;
service->credentials.authdata = NULL;
service->users = users_alloc();
service->routerOptions = NULL;
service->databases = NULL;
spinlock_init(&service->spin);
spinlock_acquire(&service_spin);
service->next = allServices;
allServices = service;
spinlock_release(&service_spin);
return service;
}
/**
* Start an individual port/protocol pair
*
* @param service The service
* @param port The port to start
* @return The number of listeners started
*/
static int
serviceStartPort(SERVICE *service, SERV_PROTOCOL *port)
{
int listeners = 0;
char config_bind[40];
GWPROTOCOL *funcs;
if ((port->listener = dcb_alloc()) == NULL)
{
return 0;
}
if (strcmp(port->protocol, "MySQLClient") == 0) {
int loaded = -1;
loaded = load_mysql_users(service);
skygw_log_write(NULL, LOGFILE_MESSAGE, "MySQL Users loaded: %i\n", loaded);
}
if ((funcs = (GWPROTOCOL *)load_module(port->protocol, MODULE_PROTOCOL)) == NULL)
{
free(port->listener);
port->listener = NULL;
}
memcpy(&(port->listener->func), funcs, sizeof(GWPROTOCOL));
port->listener->session = NULL;
sprintf(config_bind, "0.0.0.0:%d", port->port);
if (port->listener->func.listen(port->listener, config_bind))
listeners++;
port->listener->session = session_alloc(service, port->listener);
port->listener->session->state = SESSION_STATE_LISTENER;
return listeners;
}
/**
* Start a service
*
* This function loads the protocol modules for each port on which the
* service listens and starts the listener on that port
*
* Also create the router_instance for the service.
*
* @param service The Service that should be started
* @return Returns the number of listeners created
*/
int
serviceStart(SERVICE *service)
{
SERV_PROTOCOL *port;
int listeners = 0;
service->router_instance = service->router->createInstance(service,
service->routerOptions);
port = service->ports;
while (port)
{
listeners += serviceStartPort(service, port);
port = port->next;
}
if (listeners)
service->stats.started = time(0);
return listeners;
}
/**
* Start an individual listener
*
* @param service The service to start the listener for
* @param protocol The name of the protocol
* @param port The port number
*/
void
serviceStartProtocol(SERVICE *service, char *protocol, int port)
{
SERV_PROTOCOL *ptr;
ptr = service->ports;
while (ptr)
{
if (strcmp(ptr->protocol, protocol) == 0 && ptr->port == port)
serviceStartPort(service, ptr);
ptr = ptr->next;
}
}
/**
* Start all the services
*
* @return Return the number of services started
*/
int
serviceStartAll()
{
SERVICE *ptr;
int n = 0;
ptr = allServices;
while (ptr)
{
n += serviceStart(ptr);
ptr = ptr->next;
}
return n;
}
/**
* Stop a service
*
* This function stops the listener for the service
*
* @param service The Service that should be stopped
* @return Returns the number of listeners restarted
*/
int
serviceStop(SERVICE *service)
{
SERV_PROTOCOL *port;
int listeners = 0;
port = service->ports;
while (port)
{
poll_remove_dcb(port->listener);
port->listener->session->state = SESSION_STATE_LISTENER_STOPPED;
listeners++;
port = port->next;
}
return listeners;
}
/**
* Restart a service
*
* This function stops the listener for the service
*
* @param service The Service that should be restarted
* @return Returns the number of listeners restarted
*/
int
serviceRestart(SERVICE *service)
{
SERV_PROTOCOL *port;
int listeners = 0;
port = service->ports;
while (port)
{
poll_add_dcb(port->listener);
port->listener->session->state = SESSION_STATE_LISTENER;
listeners++;
port = port->next;
}
return listeners;
}
/**
* Deallocate the specified service
*
* @param service The service to deallocate
* @return Returns true if the service was freed
*/
int
service_free(SERVICE *service)
{
SERVICE *ptr;
if (service->stats.n_current)
return 0;
/* First of all remove from the linked list */
spinlock_acquire(&service_spin);
if (allServices == service)
{
allServices = service->next;
}
else
{
ptr = allServices;
while (ptr && ptr->next != service)
{
ptr = ptr->next;
}
if (ptr)
ptr->next = service->next;
}
spinlock_release(&service_spin);
/* Clean up session and free the memory */
free(service->name);
free(service->routerModule);
if (service->credentials.name)
free(service->credentials.name);
if (service->credentials.authdata)
free(service->credentials.authdata);
free(service);
return 1;
}
/**
* Add a protocol/port pair to the service
*
* @param service The service
* @param protocol The name of the protocol module
* @param port The port to listen on
* @return TRUE if the protocol/port could be added
*/
int
serviceAddProtocol(SERVICE *service, char *protocol, unsigned short port)
{
SERV_PROTOCOL *proto;
if ((proto = (SERV_PROTOCOL *)malloc(sizeof(SERV_PROTOCOL))) == NULL)
{
return 0;
}
proto->protocol = strdup(protocol);
proto->port = port;
spinlock_acquire(&service->spin);
proto->next = service->ports;
service->ports = proto;
spinlock_release(&service->spin);
return 1;
}
/**
* Check if a protocol/port pair si part of the service
*
* @param service The service
* @param protocol The name of the protocol module
* @param port The port to listen on
* @return TRUE if the protocol/port is already part of the service
*/
int
serviceHasProtocol(SERVICE *service, char *protocol, unsigned short port)
{
SERV_PROTOCOL *proto;
spinlock_acquire(&service->spin);
proto = service->ports;
while (proto)
{
if (strcmp(proto->protocol, protocol) == 0 && proto->port == port)
break;
proto = proto->next;
}
spinlock_release(&service->spin);
return proto != NULL;
}
/**
* Add a backend database server to a service
*
* @param service The service to add the server to
* @param server The server to add
*/
void
serviceAddBackend(SERVICE *service, SERVER *server)
{
spinlock_acquire(&service->spin);
server->nextdb = service->databases;
service->databases = server;
spinlock_release(&service->spin);
}
/**
* Test if a server is part of a service
*
* @param service The service to add the server to
* @param server The server to add
* @return Non-zero if the server is already part of the service
*/
int
serviceHasBackend(SERVICE *service, SERVER *server)
{
SERVER *ptr;
spinlock_acquire(&service->spin);
ptr = service->databases;
while (ptr && ptr != server)
ptr = ptr->nextdb;
spinlock_release(&service->spin);
return ptr != NULL;
}
/**
* Add a router option to a service
*
* @param service The service to add the router option to
* @param option The option string
*/
void
serviceAddRouterOption(SERVICE *service, char *option)
{
int i;
spinlock_acquire(&service->spin);
if (service->routerOptions == NULL)
{
service->routerOptions = (char **)calloc(2, sizeof(char *));
service->routerOptions[0] = strdup(option);
service->routerOptions[1] = NULL;
}
else
{
for (i = 0; service->routerOptions[i]; i++)
;
service->routerOptions = (char **)realloc(service->routerOptions,
(i + 2) * sizeof(char *));
service->routerOptions[i] = strdup(option);
service->routerOptions[i+1] = NULL;
}
spinlock_release(&service->spin);
}
/**
* Remove the router options for the service
*
* @param service The service to remove the options from
*/
void
serviceClearRouterOptions(SERVICE *service)
{
int i;
spinlock_acquire(&service->spin);
for (i = 0; service->routerOptions[i]; i++)
free(service->routerOptions[i]);
free(service->routerOptions);
service->routerOptions = NULL;
spinlock_release(&service->spin);
}
/**
* Set the service user that is used to log in to the backebd servers
* associated with this service.
*
* @param service The service we are setting the data for
* @param user The user name to use for connections
* @param auth The authentication data we need, e.g. MySQL SHA1 password
* @return 0 on failure
*/
int
serviceSetUser(SERVICE *service, char *user, char *auth)
{
if (service->credentials.name)
free(service->credentials.name);
if (service->credentials.authdata)
free(service->credentials.authdata);
service->credentials.name = strdup(user);
service->credentials.authdata = strdup(auth);
if (service->credentials.name == NULL || service->credentials.authdata == NULL)
return 0;
return 1;
}
/**
* Get the service user that is used to log in to the backebd servers
* associated with this service.
*
* @param service The service we are setting the data for
* @param user The user name to use for connections
* @param auth The authentication data we need, e.g. MySQL SHA1 password
* @return 0 on failure
*/
int
serviceGetUser(SERVICE *service, char **user, char **auth)
{
if (service->credentials.name == NULL || service->credentials.authdata == NULL)
return 0;
*user = service->credentials.name;
*auth = service->credentials.authdata;
return 1;
}
/**
* Return a named service
*
* @param servname The name of the service to find
* @return The service or NULL if not found
*/
SERVICE *
service_find(char *servname)
{
SERVICE *service;
spinlock_acquire(&service_spin);
service = allServices;
while (service && strcmp(service->name, servname) != 0)
service = service->next;
spinlock_release(&service_spin);
return service;
}
/**
* Print details of an individual service
*
* @param service Service to print
*/
void
printService(SERVICE *service)
{
SERVER *ptr = service->databases;
printf("Service %p\n", service);
printf("\tService: %s\n", service->name);
printf("\tRouter: %s (%p)\n", service->routerModule, service->router);
printf("\tStarted: %s", asctime(localtime(&service->stats.started)));
printf("\tBackend databases\n");
while (ptr)
{
printf("\t\t%s:%d Protocol: %s\n", ptr->name, ptr->port, ptr->protocol);
ptr = ptr->nextdb;
}
printf("\tUsers data: %p\n", service->users);
printf("\tTotal connections: %d\n", service->stats.n_sessions);
printf("\tCurrently connected: %d\n", service->stats.n_current);
}
/**
* Print all services
*
* Designed to be called within a debugger session in order
* to display all active services within the gateway
*/
void
printAllServices()
{
SERVICE *ptr;
spinlock_acquire(&service_spin);
ptr = allServices;
while (ptr)
{
printService(ptr);
ptr = ptr->next;
}
spinlock_release(&service_spin);
}
/**
* Print all services to a DCB
*
* Designed to be called within a debugger session in order
* to display all active services within the gateway
*/
void
dprintAllServices(DCB *dcb)
{
SERVICE *ptr;
spinlock_acquire(&service_spin);
ptr = allServices;
while (ptr)
{
SERVER *server = ptr->databases;
dcb_printf(dcb, "Service %p\n", ptr);
dcb_printf(dcb, "\tService: %s\n", ptr->name);
dcb_printf(dcb, "\tRouter: %s (%p)\n", ptr->routerModule,
ptr->router);
if (ptr->router)
ptr->router->diagnostics(ptr->router_instance, dcb);
dcb_printf(dcb, "\tStarted: %s",
asctime(localtime(&ptr->stats.started)));
dcb_printf(dcb, "\tBackend databases\n");
while (server)
{
dcb_printf(dcb, "\t\t%s:%d Protocol: %s\n", server->name, server->port,
server->protocol);
server = server->nextdb;
}
dcb_printf(dcb, "\tUsers data: %p\n", ptr->users);
dcb_printf(dcb, "\tTotal connections: %d\n", ptr->stats.n_sessions);
dcb_printf(dcb, "\tCurrently connected: %d\n", ptr->stats.n_current);
ptr = ptr->next;
}
spinlock_release(&service_spin);
}
/**
* Update the definition of a service
*
* @param service The service to update
* @param router The router module to use
* @param user The user to use to extract information from the database
* @param auth The password for the user above
*/
void
service_update(SERVICE *service, char *router, char *user, char *auth)
{
void *router_obj;
if (!strcmp(service->routerModule, router))
{
if ((router_obj = load_module(router, MODULE_ROUTER)) == NULL)
{
skygw_log_write(NULL, LOGFILE_ERROR, "Failed to update router for service %s to %s",
service->name, router);
}
else
{
skygw_log_write(NULL, LOGFILE_MESSAGE, "Update router for service %s to %s",
service->name, router);
free(service->routerModule);
service->routerModule = strdup(router);
service->router = router_obj;
}
}
if (user && (strcmp(service->credentials.name, user) != 0 || strcmp(service->credentials.authdata, auth) != 0))
{
skygw_log_write(NULL, LOGFILE_MESSAGE, "Update credentials for service %s", service->name);
serviceSetUser(service, user, auth);
}
}

232
server/core/session.c Normal file
View File

@ -0,0 +1,232 @@
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
/**
* @file session.c - A representation of the session within the gateway.
*
* @verbatim
* Revision History
*
* Date Who Description
* 17/06/13 Mark Riddoch Initial implementation
*
* @endverbatim
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <session.h>
#include <service.h>
#include <router.h>
#include <dcb.h>
#include <spinlock.h>
#include <atomic.h>
static SPINLOCK session_spin = SPINLOCK_INIT;
static SESSION *allSessions = NULL;
/**
* Allocate a new session for a new client of the specified service.
*
* Create the link to the router session by calling the newSession
* entry point of the router using the router instance of the
* service this session is part of.
*
* @param service The service this connection was established by
* @param client The client side DCB
* @return The newly created session or NULL if an error occured
*/
SESSION *
session_alloc(SERVICE *service, DCB *client)
{
SESSION *session;
if ((session = (SESSION *)malloc(sizeof(SESSION))) == NULL)
return NULL;
session->service = service;
session->client = client;
memset(&session->stats, 0, sizeof(SESSION_STATS));
session->stats.connect = time(0);
session->state = SESSION_STATE_ALLOC;
client->session = session;
/*
* Only create a router session if we are not the listening
* DCB. Creating a router session may create a connection to a
* backend server, depending upon the router module implementation
* and should be avoided for the listener session
*/
if (client->state != DCB_STATE_LISTENING)
{
session->router_session = service->router->newSession(service->router_instance, session);
}
spinlock_acquire(&session_spin);
session->next = allSessions;
allSessions = session;
spinlock_release(&session_spin);
atomic_add(&service->stats.n_sessions, 1);
atomic_add(&service->stats.n_current, 1);
return session;
}
/**
* Deallocate the specified session
*
* @param session The session to deallocate
*/
void
session_free(SESSION *session)
{
SESSION *ptr;
/* First of all remove from the linked list */
spinlock_acquire(&session_spin);
if (allSessions == session)
{
allSessions = session->next;
}
else
{
ptr = allSessions;
while (ptr && ptr->next != session)
{
ptr = ptr->next;
}
if (ptr)
ptr->next = session->next;
}
spinlock_release(&session_spin);
atomic_add(&session->service->stats.n_current, -1);
/* Clean up session and free the memory */
free(session);
}
/**
* Print details of an individual session
*
* @param session Session to print
*/
void
printSession(SESSION *session)
{
printf("Session %p\n", session);
printf("\tState: %s\n", session_state(session->state));
printf("\tService: %s (%p)\n", session->service->name, session->service);
printf("\tClient DCB: %p\n", session->client);
printf("\tConnected: %s", asctime(localtime(&session->stats.connect)));
}
/**
* Print all sessions
*
* Designed to be called within a debugger session in order
* to display all active sessions within the gateway
*/
void
printAllSessions()
{
SESSION *ptr;
spinlock_acquire(&session_spin);
ptr = allSessions;
while (ptr)
{
printSession(ptr);
ptr = ptr->next;
}
spinlock_release(&session_spin);
}
/**
* Print all sessions to a DCB
*
* Designed to be called within a debugger session in order
* to display all active sessions within the gateway
*
* @param dcb The DCB to print to
*/
void
dprintAllSessions(DCB *dcb)
{
SESSION *ptr;
spinlock_acquire(&session_spin);
ptr = allSessions;
while (ptr)
{
dcb_printf(dcb, "Session %p\n", ptr);
dcb_printf(dcb, "\tState: %s\n", session_state(ptr->state));
dcb_printf(dcb, "\tService: %s (%p)\n", ptr->service->name, ptr->service);
dcb_printf(dcb, "\tClient DCB: %p\n", ptr->client);
if (ptr->client && ptr->client->remote)
dcb_printf(dcb, "\tClient Address: %s\n", ptr->client->remote);
dcb_printf(dcb, "\tConnected: %s", asctime(localtime(&ptr->stats.connect)));
ptr = ptr->next;
}
spinlock_release(&session_spin);
}
/**
* Print a particular session to a DCB
*
* Designed to be called within a debugger session in order
* to display all active sessions within the gateway
*
* @param dcb The DCB to print to
* @param ptr The session to print
*/
void
dprintSession(DCB *dcb, SESSION *ptr)
{
dcb_printf(dcb, "Session %p\n", ptr);
dcb_printf(dcb, "\tState: %s\n", session_state(ptr->state));
dcb_printf(dcb, "\tService: %s (%p)\n", ptr->service->name, ptr->service);
dcb_printf(dcb, "\tClient DCB: %p\n", ptr->client);
if (ptr->client && ptr->client->remote)
dcb_printf(dcb, "\tClient Address: %s\n", ptr->client->remote);
dcb_printf(dcb, "\tConnected: %s", asctime(localtime(&ptr->stats.connect)));
}
/**
* Convert a session state to a string representation
*
* @param state The session state
* @return A string representation of the session state
*/
char *
session_state(int state)
{
switch (state)
{
case SESSION_STATE_ALLOC:
return "Session Allocated";
case SESSION_STATE_READY:
return "Session Ready";
case SESSION_STATE_LISTENER:
return "Listener Session";
case SESSION_STATE_LISTENER_STOPPED:
return "Stopped Listener Session";
default:
return "Invalid State";
}
}

100
server/core/spinlock.c Normal file
View File

@ -0,0 +1,100 @@
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
/**
* @file spinlock.c - Spinlock operations for the SkySQL Gateway
*
* @verbatim
* Revision History
*
* Date Who Description
* 10/06/13 Mark Riddoch Initial implementation
*
* @endverbatim
*/
#include <spinlock.h>
#include <atomic.h>
/**
* Initialise a spinlock.
*
* @param lock The spinlock to initialise.
*/
void
spinlock_init(SPINLOCK *lock)
{
lock->lock = 0;
#ifdef DEBUG
lock->spins = 0;
lock->acquired = 0;
#endif
}
/**
* Acquire a spinlock.
*
* @param lock The spinlock to acquire
*/
void
spinlock_acquire(SPINLOCK *lock)
{
while (atomic_add(&(lock->lock), 1) != 0)
{
atomic_add(&(lock->lock), -1);
#ifdef DEBUG
atomic_add(&(lock->spins), 1);
#endif
}
#ifdef DEBUG
lock->acquired++;
lock->owner = THREAD_SHELF();
#endif
}
/**
* Acquire a spinlock if it is not already locked.
*
* @param lock The spinlock to acquire
* @return True ifthe spinlock was acquired, otherwise false
*/
int
spinlock_acquire_nowait(SPINLOCK *lock)
{
if (atomic_add(&(lock->lock), 1) != 0)
{
atomic_add(&(lock->lock), -1);
return FALSE;
}
#ifdef DEBUG
lock->acquired++;
lock->owner = THREAD_SHELF();
#endif
return TRUE;
}
/*
* Release a spinlock.
*
* @param lock The spinlock to release
*/
void
spinlock_release(SPINLOCK *lock)
{
atomic_add(&(lock->lock), -1);
}

78
server/core/thread.c Normal file
View File

@ -0,0 +1,78 @@
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
#include <thread.h>
#include <pthread.h>
/**
* @file thread.c - Implementation of thread related operations
*
* @verbatim
* Revision History
*
* Date Who Description
* 25/06/13 Mark Riddoch Initial implementation
*
* @endverbatim
*/
/**
* Start a polling thread
*
* @param entry The entry point to call
* @param arg The argument to pass the thread entry point
* @return The thread handle
*/
void *
thread_start(void (*entry)(void *), void *arg)
{
pthread_t thd;
if (pthread_create(&thd, NULL, (void *(*)(void *))entry, arg) != 0)
{
return NULL;
}
return (void *)thd;
}
/**
* Wait for a running threads to complete.
*
* @param thd The thread handle
*/
void
thread_wait(void *thd)
{
void *rval;
pthread_join((pthread_t)thd, &rval);
}
/**
* Put the thread to sleep for a number of milliseconds
*
* @param ms Number of milliseconds to sleep
*/
void
thread_millisleep(int ms)
{
struct timespec req;
req.tv_sec = ms / 1000;
req.tv_nsec = (ms % 1000) * 1000000;
nanosleep(&req, NULL);
}

189
server/core/users.c Normal file
View File

@ -0,0 +1,189 @@
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <users.h>
#include <atomic.h>
/**
* @file users.c User table maintenance routines
*
* @verbatim
* Revision History
*
* Date Who Description
* 23/06/13 Mark Riddoch Initial implementation
*
* @endverbatim
*/
/**
* The hash function we user for storing users.
*
* @param key The key value, i.e. username
* @return The hash key
*/
static int
user_hash(char *key)
{
return (*key + *(key + 1));
}
/**
* Allocate a new users table
*
* @return The users table
*/
USERS *
users_alloc()
{
USERS *rval;
if ((rval = malloc(sizeof(USERS))) == NULL)
return NULL;
if ((rval->data = hashtable_alloc(52, user_hash, strcmp)) == NULL)
{
free(rval);
return NULL;
}
hashtable_memory_fns(rval->data, (HASHMEMORYFN)strdup, (HASHMEMORYFN)free);
return rval;
}
/**
* Remove the users table
*
* @param users The users table to remove
*/
void
users_free(USERS *users)
{
hashtable_free(users->data);
free(users);
}
/**
* Add a new user to the user table. The user name must be unique
*
* @param users The users table
* @param user The user name
* @param auth The authentication data
* @return The number of users added to the table
*/
int
users_add(USERS *users, char *user, char *auth)
{
int add;
atomic_add(&users->stats.n_adds, 1);
add = hashtable_add(users->data, user, auth);
atomic_add(&users->stats.n_entries, add);
return add;
}
/**
* Delete a user from the user table.
*
* @param users The users table
* @param user The user name
* @return The number of users deleted from the table
*/
int
users_delete(USERS *users, char *user)
{
int del;
atomic_add(&users->stats.n_deletes, 1);
del = hashtable_delete(users->data, user);
atomic_add(&users->stats.n_entries, del * -1);
return del;
}
/**
* Fetch the authentication data for a particular user from the users table
*
* @param users The users table
* @param user The user name
* @return The authentication data or NULL on error
*/
char
*users_fetch(USERS *users, char *user)
{
atomic_add(&users->stats.n_fetches, 1);
return hashtable_fetch(users->data, user);
}
/**
* Change the password data associated with a user in the users
* table.
*
* @param users The users table
* @param user The user name
* @param auth The new authentication details
* @return Number of users updated
*/
int
users_update(USERS *users, char *user, char *auth)
{
if (hashtable_delete(users->data, user) == 0)
return 0;
return hashtable_add(users->data, user, auth);
}
/**
* Print details of the users storage mechanism
*
* @param users The users table
*/
void
usersPrint(USERS *users)
{
printf("Users table data\n");
hashtable_stats(users->data);
}
/**
* Print details of the users storage mechanism to a DCB
*
* @param dcb DCB to print to
* @param users The users table
*/
void
dcb_usersPrint(DCB *dcb, USERS *users)
{
HASHITERATOR *iter;
char *sep, *user;
dcb_printf(dcb, "Users table data\n");
dcb_hashtable_stats(dcb, users->data);
if ((iter = hashtable_iterator(users->data)) != NULL)
{
dcb_printf(dcb, "User names: ");
sep = "";
while ((user = hashtable_next(iter)) != NULL)
{
dcb_printf(dcb, "%s%s", sep, user);
sep = ", ";
}
dcb_printf(dcb, "\n");
}
}

191
server/core/utils.c Normal file
View File

@ -0,0 +1,191 @@
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*
*/
/**
* @file utils.c - General utility functions
*
* @verbatim
* Revision History
*
* Date Who Description
* 10-06-2013 Massimiliano Pinto Initial implementation
* 12-06-2013 Massimiliano Pinto Read function trought
* the gwbuff strategy
* 13-06-2013 Massimiliano Pinto Gateway local authentication
* basics
*
* @endverbatim
*/
#include <gw.h>
#include <dcb.h>
#include <session.h>
#include <mysql_protocol.h>
#include <openssl/sha.h>
#include <poll.h>
#include <skygw_utils.h>
#include <log_manager.h>
// used in the hex2bin function
#define char_val(X) (X >= '0' && X <= '9' ? X-'0' :\
X >= 'A' && X <= 'Z' ? X-'A'+10 :\
X >= 'a' && X <= 'z' ? X-'a'+10 :\
'\177')
// used in the bin2hex function
char hex_upper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char hex_lower[] = "0123456789abcdefghijklmnopqrstuvwxyz";
//////////////////////////////////////////
//backend read event triggered by EPOLLIN
//////////////////////////////////////////
int setnonblocking(int fd) {
int fl;
if ((fl = fcntl(fd, F_GETFL, 0)) == -1) {
skygw_log_write(NULL, LOGFILE_ERROR, "Can't GET fcntl for %i, errno = %d, %s", fd, errno, strerror(errno));
return 1;
}
if (fcntl(fd, F_SETFL, fl | O_NONBLOCK) == -1) {
skygw_log_write(NULL, LOGFILE_ERROR, "Can't SET fcntl for %i, errno = %d, %s", fd, errno, strerror(errno));
return 1;
}
return 0;
}
char *gw_strend(register const char *s) {
while (*s++);
return (char*) (s-1);
}
///////////////////////////////
// generate a random char
//////////////////////////////
static char gw_randomchar() {
return (char)((rand() % 78) + 30);
}
/////////////////////////////////
// generate a random string
// output must be pre allocated
/////////////////////////////////
int gw_generate_random_str(char *output, int len) {
int i;
srand(time(0L));
for ( i = 0; i < len; ++i ) {
output[i] = gw_randomchar();
}
output[len]='\0';
return 0;
}
/////////////////////////////////
// hex string to binary data
// output must be pre allocated
/////////////////////////////////
int gw_hex2bin(uint8_t *out, const char *in, unsigned int len) {
const char *in_end= in + len;
if (len == 0 || in == NULL) {
return 1;
}
while (in < in_end) {
register unsigned char b1 = char_val(*in);
uint8_t b2 = 0;
in++;
b2 = (b1 << 4) | char_val(*in);
*out++ = b2;
in++;
}
return 0;
}
/////////////////////////////////
// binary data to hex string
// output must be pre allocated
/////////////////////////////////
char *gw_bin2hex(char *out, const uint8_t *in, unsigned int len) {
const uint8_t *in_end= in + len;
if (len == 0 || in == NULL) {
return NULL;
}
for (; in != in_end; ++in) {
*out++= hex_upper[((uint8_t) *in) >> 4];
*out++= hex_upper[((uint8_t) *in) & 0x0F];
}
*out= '\0';
return out;
}
///////////////////////////////////////////////////////
// fill a preallocated buffer with XOR(str1, str2)
// XOR between 2 equal len strings
// note that XOR(str1, XOR(str1 CONCAT str2)) == str2
// and that XOR(str1, str2) == XOR(str2, str1)
///////////////////////////////////////////////////////
void gw_str_xor(uint8_t *output, const uint8_t *input1, const uint8_t *input2, unsigned int len) {
const uint8_t *input1_end = NULL;
input1_end = input1 + len;
while (input1 < input1_end)
*output++= *input1++ ^ *input2++;
*output = '\0';
}
/////////////////////////////////////////////////////////////
// fill a 20 bytes preallocated with SHA1 digest (160 bits)
// for one input on in_len bytes
/////////////////////////////////////////////////////////////
void gw_sha1_str(const uint8_t *in, int in_len, uint8_t *out) {
unsigned char hash[SHA_DIGEST_LENGTH];
SHA1(in, in_len, hash);
memcpy(out, hash, SHA_DIGEST_LENGTH);
}
/////////////////////////////////////////////////////////////
// fill 20 bytes preallocated with SHA1 digest (160 bits)
// for two inputs, in_len and in2_len bytes
/////////////////////////////////////////////////////////////
void gw_sha1_2_str(const uint8_t *in, int in_len, const uint8_t *in2, int in2_len, uint8_t *out) {
SHA_CTX context;
unsigned char hash[SHA_DIGEST_LENGTH];
SHA1_Init(&context);
SHA1_Update(&context, in, in_len);
SHA1_Update(&context, in2, in2_len);
SHA1_Final(hash, &context);
memcpy(out, hash, SHA_DIGEST_LENGTH);
}

View File

@ -0,0 +1,40 @@
#ifndef _ADMINUSERS_H
#define _ADMINUSERS_H
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
/**
* @file adminusers.h - Administration users support routines
*
* @verbatim
* Revision History
*
* Date Who Description
* 18/07/13 Mark Riddoch Initial implementation
*
* @endverbatim
*/
#define ADMIN_SALT "MS"
extern int admin_verify(char *, char *);
extern char *admin_add_user(char *, char *);
extern int admin_test_user(char *);
extern void dcb_PrintAdminUsers(DCB *dcb);
#endif

34
server/include/atomic.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef _ATOMIC_H
#define _ATOMIC_H
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
/**
* @file atomic.h The atomic operations used within the gateway
*
* @verbatim
* Revision History
*
* Date Who Description
* 10/06/13 Mark Riddoch Initial implementation
*
* @endverbatim
*/
extern int atomic_add(int *variable, int value);
#endif

98
server/include/buffer.h Normal file
View File

@ -0,0 +1,98 @@
#ifndef _BUFFER_H
#define _BUFFER_H
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
/**
* @file buffer.h Definitions relating the gateway buffer manipulation facilities.
*
* These are used to store all data coming in form or going out to the client and the
* backend structures.
*
* The buffers are designed to be used in linked lists and such that they may be passed
* from one side of the gateway to another without the need to copy data. It may be the case
* that not all of the data in the buffer is valid, to this end a start and end pointer are
* included that point to the first valid byte in the buffer and the first byte after the
* last valid byte. This allows data to be consumed from either end of the buffer whilst
* still allowing for the copy free semantics of the buffering system.
*
* @verbatim
* Revision History
*
* Date Who Description
* 10/06/2013 Mark Riddoch Initial implementation
* 11/07/2013 Mark Riddoch Addition of reference count in the gwbuf
* 16/07/2013 Massimiliano Pinto Added command type for the queue
*
* @endverbatim
*/
/**
* A structure to encapsualte the data in a form that the data itself can be
* shared between multiple GWBUF's without the need to make multiple copies
* but still maintain separate data pointers.
*/
typedef struct {
unsigned char *data; /**< Physical memory that was allocated */
int refcount; /**< Reference count on the buffer */
} SHARED_BUF;
/**
* The buffer structure used by the descriptor control blocks.
*
* Linked lists of buffers are created as data is read from a descriptor
* or written to a descriptor. The use of linked lists of buffers with
* flexible data pointers is designed to minimise the need for data to
* be copied within the gateway.
*/
typedef struct gwbuf {
struct gwbuf *next; /**< Next buffer in a linked chain of buffers */
void *start; /**< Start of the valid data */
void *end; /**< First byte after the valid data */
SHARED_BUF *sbuf; /**< The shared buffer with the real data */
int command; /**< The command type for the queue */
} GWBUF;
/*
* Macros to access the data in the buffers
*/
#define GWBUF_DATA(b) ((b)->start) /**< First valid, uncomsumed
* byte in the buffer
*/
#define GWBUF_LENGTH(b) ((b)->end - (b)->start) /**< Number of bytes in the
* individual buffer
*/
#define GWBUF_EMPTY(b) ((b)->start == (b)->end) /**< True if all bytes in the
* buffer have been consumed
*/
#define GWBUF_CONSUME(b, bytes) (b)->start += bytes /**< Consume a number of bytes
* in the buffer
*/
/*
* Function prototypes for the API to maniplate the buffers
*/
extern GWBUF *gwbuf_alloc(unsigned int size);
extern void gwbuf_free(GWBUF *buf);
extern GWBUF *gwbuf_clone(GWBUF *buf);
extern GWBUF *gwbuf_append(GWBUF *head, GWBUF *tail);
extern GWBUF *gwbuf_consume(GWBUF *head, unsigned int length);
extern unsigned int gwbuf_length(GWBUF *head);
#endif

63
server/include/config.h Normal file
View File

@ -0,0 +1,63 @@
#ifndef _CONFIG_H
#define _CONFIG_H
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
/**
* @file config.h The configuration handling elements
*
* @verbatim
* Revision History
*
* Date Who Description
* 21/06/13 Mark Riddoch Initial implementation
*
* @endverbatim
*/
/**
* The config parameter
*/
typedef struct config_parameter {
char *name; /**< The name of the parameter */
char *value; /**< The value of the parameter */
struct config_parameter *next; /**< Next pointer in the linked list */
} CONFIG_PARAMETER;
/**
* The config context structure, used to build the configuration
* data during the parse process
*/
typedef struct config_context {
char *object; /**< The name of the object being configured */
CONFIG_PARAMETER *parameters; /**< The list of parameter values */
void *element; /**< The element created from the data */
struct config_context *next; /**< Next pointer in the linked list */
} CONFIG_CONTEXT;
/**
* The gateway global configuration data
*/
typedef struct {
int n_threads; /**< Number of polling threads */
} GATEWAY_CONF;
extern int config_load(char *);
extern int config_reload();
extern int config_threadcount();
#endif

36
server/include/dbusers.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef _DBUSERS_H
#define _DBUSERS_H
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
#include <service.h>
/**
* @file dbusers.h Extarct user information form the backend database
*
* @verbatim
* Revision History
*
* Date Who Description
* 25/06/13 Mark Riddoch Initial implementation
*
* @endverbatim
*/
extern int load_mysql_users(SERVICE *service);
extern int reload_mysql_users(SERVICE *service);
#endif

189
server/include/dcb.h Normal file
View File

@ -0,0 +1,189 @@
#ifndef _DCB_H
#define _DCB_H
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
#include <spinlock.h>
#include <buffer.h>
#include <gwbitmask.h>
struct session;
struct server;
struct service;
/**
* @file dcb.h The Descriptor Control Block
*
* The function pointer table used by descriptors to call relevant functions
* within the protocol specific code.
*
* @verbatim
* Revision History
*
* Date Who Description
* 01/06/2013 Mark Riddoch Initial implementation
* 11/06/2013 Mark Riddoch Updated GWPROTOCOL structure with new
* entry points
* 18/06/2013 Mark Riddoch Addition of the listener entry point
* 02/07/2013 Massimiliano Pinto Addition of delayqlock, delayq and authlock
* for handling backend asynchronous protocol connection
* and a generic lock for backend authentication
* 12/07/2013 Massimiliano Pinto Added auth entry point
* 15/07/2013 Massimiliano Pinto Added session entry point
* 16/07/2013 Massimiliano Pinto Added command type for dcb
*
* @endverbatim
*/
struct dcb;
/**
* @verbatim
* The operations that can be performed on the descriptor
*
* read EPOLLIN handler for the socket
* write Gateway data write entry point
* write_ready EPOLLOUT handler for the socket, indicates
* that the socket is ready to send more data
* error EPOLLERR handler for the socket
* hangup EPOLLHUP handler for the socket
* accept Accept handler for listener socket only
* connect Create a connection to the specified server
* for the session pased in
* close Gateway close entry point for the socket
* listen Create a listener for the protocol
* auth Authentication entry point
* session Session handling entry point
* @endverbatim
*
* This forms the "module object" for protocol modules within the gateway.
*
* @see load_module
*/
typedef struct gw_protocol {
int (*read)(struct dcb *);
int (*write)(struct dcb *, GWBUF *);
int (*write_ready)(struct dcb *);
int (*error)(struct dcb *);
int (*hangup)(struct dcb *);
int (*accept)(struct dcb *);
int (*connect)(struct dcb *, struct server *, struct session *);
int (*close)(struct dcb *);
int (*listen)(struct dcb *, char *);
int (*auth)(struct dcb *, struct server *, struct session *, GWBUF *);
int (*session)(struct dcb *, void *);
} GWPROTOCOL;
/**
* The statitics gathered on a descriptor control block
*/
typedef struct dcbstats {
int n_reads; /**< Number of reads on this descriptor */
int n_writes; /**< Number of writes on this descriptor */
int n_accepts; /**< Number of accepts on this descriptor */
int n_buffered; /**< Number of buffered writes */
} DCBSTATS;
/**
* The data structure that is embedded witin a DCB and manages the complex memory
* management issues of a DCB.
*
* The DCB structures are used as the user data within the polling loop. This means that
* polling threads may aschronously wake up and access these structures. It is not possible
* to simple remove the DCB from the epoll system and then free the data, as every thread
* that is currently running an epoll call must wake up and re-issue the epoll_wait system
* call, the is the only way we can be sure that no polling thread is pending a wakeup or
* processing an event that will access the DCB.
*
* We solve this issue by making the dcb_free routine merely mark a DCB as a zombie and
* place it on a special zombie list. Before placing the DCB on the zombie list we create
* a bitmask with a bit set in it for each active polling thread. Each thread will call
* a routine to process the zombie list at the end of the polling loop. This routine
* will clear the bit value that corresponds to the calling thread. Once the bitmask
* is completely cleared the DCB can finally be freed and removed from the zombie list.
*/
typedef struct {
GWBITMASK bitmask; /**< The bitmask of threads */
struct dcb *next; /**< Next pointer for the zombie list */
} DCBMM;
/**
* Descriptor Control Block
*
* A wrapper for a network descriptor within the gateway, it contains all the
* state information necessary to allow for the implementation of the asynchronous
* operation of the potocol and gateway functions. It also provides links to the service
* and session data that is required to route the information within the gateway.
*
* It is important to hold the state information here such that any thread within the
* gateway may be selected to execute the required actions when a network event occurs.
*/
typedef struct dcb {
int fd; /**< The descriptor */
int state; /**< Current descriptor state */
char *remote; /**< Address of remote end */
void *protocol; /**< The protocol specific state */
struct session *session; /**< The owning session */
GWPROTOCOL func; /**< The functions for this descrioptor */
SPINLOCK writeqlock; /**< Write Queue spinlock */
GWBUF *writeq; /**< Write Data Queue */
SPINLOCK delayqlock; /**< Delay Backend Write Queue spinlock */
GWBUF *delayq; /**< Delay Backend Write Data Queue */
SPINLOCK authlock; /**< Generic Authorization spinlock */
DCBSTATS stats; /**< DCB related statistics */
struct dcb *next; /**< Next DCB in the chain of allocated DCB's */
struct service *service; /**< The related service */
void *data; /**< Specific client data */
DCBMM memdata; /**< The data related to DCB memory management */
int command; /**< Specific client command type */
} DCB;
/* DCB states */
#define DCB_STATE_ALLOC 0 /**< Memory allocated but not populated */
#define DCB_STATE_IDLE 1 /**< Not yet in the poll mask */
#define DCB_STATE_POLLING 2 /**< Waiting in the poll loop */
#define DCB_STATE_PROCESSING 4 /**< Processing an event */
#define DCB_STATE_LISTENING 5 /**< The DCB is for a listening socket */
#define DCB_STATE_DISCONNECTED 6 /**< The socket is now closed */
#define DCB_STATE_FREED 7 /**< Memory freed */
#define DCB_STATE_ZOMBIE 8 /**< DCB is no longer active, waiting to free it */
/* A few useful macros */
#define DCB_SESSION(x) (x)->session
#define DCB_PROTOCOL(x, type) (type *)((x)->protocol)
#define DCB_ISZOMBIE(x) ((x)->state == DCB_STATE_ZOMBIE)
extern DCB *dcb_alloc(); /* Allocate a DCB */
extern void dcb_free(DCB *); /* Free a DCB */
extern DCB *dcb_connect(struct server *, struct session *, const char *); /* prepare Backend connection */
extern int dcb_read(DCB *, GWBUF **); /* Generic read routine */
extern int dcb_write(DCB *, GWBUF *); /* Generic write routine */
extern int dcb_drain_writeq(DCB *); /* Generic write routine */
extern void dcb_close(DCB *); /* Generic close functionality */
extern void dcb_process_zombies(int); /* Process Zombies */
extern void printAllDCBs(); /* Debug to print all DCB in the system */
extern void printDCB(DCB *); /* Debug print routine */
extern void dprintAllDCBs(DCB *); /* Debug to print all DCB in the system */
extern void dprintDCB(DCB *, DCB *); /* Debug to print a DCB in the system */
extern const char *gw_dcb_state2string(int); /* DCB state to string */
extern void dcb_printf(DCB *, const char *, ...); /* DCB version of printf */
extern int dcb_isclient(DCB *); /* the DCB is the client of the session */
#endif

View File

@ -0,0 +1,126 @@
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*
*/
/*
* MYSQL mysql protocol header file
* Revision History
*
* Date Who Description
* 10/06/13 Massimiliano Pinto Initial implementation
*
*/
#include <dcb.h>
/* Protocol packing macros. */
#define gw_mysql_set_byte2(__buffer, __int) do { \
(__buffer)[0]= (uint8_t)((__int) & 0xFF); \
(__buffer)[1]= (uint8_t)(((__int) >> 8) & 0xFF); } while (0)
#define gw_mysql_set_byte3(__buffer, __int) do { \
(__buffer)[0]= (uint8_t)((__int) & 0xFF); \
(__buffer)[1]= (uint8_t)(((__int) >> 8) & 0xFF); \
(__buffer)[2]= (uint8_t)(((__int) >> 16) & 0xFF); } while (0)
#define gw_mysql_set_byte4(__buffer, __int) do { \
(__buffer)[0]= (uint8_t)((__int) & 0xFF); \
(__buffer)[1]= (uint8_t)(((__int) >> 8) & 0xFF); \
(__buffer)[2]= (uint8_t)(((__int) >> 16) & 0xFF); \
(__buffer)[3]= (uint8_t)(((__int) >> 24) & 0xFF); } while (0)
/* Protocol unpacking macros. */
#define gw_mysql_get_byte2(__buffer) \
(uint16_t)((__buffer)[0] | \
((__buffer)[1] << 8))
#define gw_mysql_get_byte3(__buffer) \
(uint32_t)((__buffer)[0] | \
((__buffer)[1] << 8) | \
((__buffer)[2] << 16))
#define gw_mysql_get_byte4(__buffer) \
(uint32_t)((__buffer)[0] | \
((__buffer)[1] << 8) | \
((__buffer)[2] << 16) | \
((__buffer)[3] << 24))
#define gw_mysql_get_byte8(__buffer) \
((uint64_t)(__buffer)[0] | \
((uint64_t)(__buffer)[1] << 8) | \
((uint64_t)(__buffer)[2] << 16) | \
((uint64_t)(__buffer)[3] << 24) | \
((uint64_t)(__buffer)[4] << 32) | \
((uint64_t)(__buffer)[5] << 40) | \
((uint64_t)(__buffer)[6] << 48) | \
((uint64_t)(__buffer)[7] << 56))
typedef enum
{
GW_MYSQL_CAPABILITIES_NONE= 0,
GW_MYSQL_CAPABILITIES_LONG_PASSWORD= (1 << 0),
GW_MYSQL_CAPABILITIES_FOUND_ROWS= (1 << 1),
GW_MYSQL_CAPABILITIES_LONG_FLAG= (1 << 2),
GW_MYSQL_CAPABILITIES_CONNECT_WITH_DB= (1 << 3),
GW_MYSQL_CAPABILITIES_NO_SCHEMA= (1 << 4),
GW_MYSQL_CAPABILITIES_COMPRESS= (1 << 5),
GW_MYSQL_CAPABILITIES_ODBC= (1 << 6),
GW_MYSQL_CAPABILITIES_LOCAL_FILES= (1 << 7),
GW_MYSQL_CAPABILITIES_IGNORE_SPACE= (1 << 8),
GW_MYSQL_CAPABILITIES_PROTOCOL_41= (1 << 9),
GW_MYSQL_CAPABILITIES_INTERACTIVE= (1 << 10),
GW_MYSQL_CAPABILITIES_SSL= (1 << 11),
GW_MYSQL_CAPABILITIES_IGNORE_SIGPIPE= (1 << 12),
GW_MYSQL_CAPABILITIES_TRANSACTIONS= (1 << 13),
GW_MYSQL_CAPABILITIES_RESERVED= (1 << 14),
GW_MYSQL_CAPABILITIES_SECURE_CONNECTION= (1 << 15),
GW_MYSQL_CAPABILITIES_MULTI_STATEMENTS= (1 << 16),
GW_MYSQL_CAPABILITIES_MULTI_RESULTS= (1 << 17),
GW_MYSQL_CAPABILITIES_PS_MULTI_RESULTS= (1 << 18),
GW_MYSQL_CAPABILITIES_PLUGIN_AUTH= (1 << 19),
GW_MYSQL_CAPABILITIES_SSL_VERIFY_SERVER_CERT= (1 << 30),
GW_MYSQL_CAPABILITIES_REMEMBER_OPTIONS= (1 << 31),
GW_MYSQL_CAPABILITIES_CLIENT= (GW_MYSQL_CAPABILITIES_LONG_PASSWORD |
GW_MYSQL_CAPABILITIES_FOUND_ROWS |
GW_MYSQL_CAPABILITIES_LONG_FLAG |
GW_MYSQL_CAPABILITIES_CONNECT_WITH_DB |
GW_MYSQL_CAPABILITIES_LOCAL_FILES |
GW_MYSQL_CAPABILITIES_PLUGIN_AUTH |
GW_MYSQL_CAPABILITIES_TRANSACTIONS |
GW_MYSQL_CAPABILITIES_PROTOCOL_41 |
GW_MYSQL_CAPABILITIES_MULTI_STATEMENTS |
GW_MYSQL_CAPABILITIES_MULTI_RESULTS |
GW_MYSQL_CAPABILITIES_PS_MULTI_RESULTS |
GW_MYSQL_CAPABILITIES_SECURE_CONNECTION),
GW_MYSQL_CAPABILITIES_CLIENT_COMPRESS= (GW_MYSQL_CAPABILITIES_LONG_PASSWORD |
GW_MYSQL_CAPABILITIES_FOUND_ROWS |
GW_MYSQL_CAPABILITIES_LONG_FLAG |
GW_MYSQL_CAPABILITIES_CONNECT_WITH_DB |
GW_MYSQL_CAPABILITIES_LOCAL_FILES |
GW_MYSQL_CAPABILITIES_PLUGIN_AUTH |
GW_MYSQL_CAPABILITIES_TRANSACTIONS |
GW_MYSQL_CAPABILITIES_PROTOCOL_41 |
GW_MYSQL_CAPABILITIES_MULTI_STATEMENTS |
GW_MYSQL_CAPABILITIES_MULTI_RESULTS |
GW_MYSQL_CAPABILITIES_PS_MULTI_RESULTS |
GW_MYSQL_CAPABILITIES_COMPRESS
),
} gw_mysql_capabilities_t;
#define SMALL_CHUNK 1024
#define MAX_CHUNK SMALL_CHUNK * 8 * 4
#define ToHex(Y) (Y>='0'&&Y<='9'?Y-'0':Y-'A'+10)
extern int mysql_send_ok(DCB *, int, int, const char *);
extern int MySQLSendHandshake(DCB *);

67
server/include/gw.h Normal file
View File

@ -0,0 +1,67 @@
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <netdb.h>
#include <fcntl.h>
#include <unistd.h>
#include <syslog.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <pwd.h>
#include <sys/types.h>
#include <sys/epoll.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdbool.h>
#define EXIT_FAILURE 1
// network buffer is 32K
#define MAX_BUFFER_SIZE 32768
// socket send buffer for backend
#define GW_BACKEND_SO_SNDBUF 1024
#define GW_NOINTR_CALL(A) do { errno = 0; A; } while (errno == EINTR)
#define GW_VERSION "0.1.0"
#define GW_MYSQL_VERSION "5.5.22-SKYSQL-" GW_VERSION
#define GW_MYSQL_LOOP_TIMEOUT 300000000
#define GW_MYSQL_READ 0
#define GW_MYSQL_WRITE 1
#define GW_MYSQL_PROTOCOL_VERSION 10 // version is 10
#define GW_MYSQL_HANDSHAKE_FILLER 0x00
#define GW_MYSQL_SERVER_CAPABILITIES_BYTE1 0xff
#define GW_MYSQL_SERVER_CAPABILITIES_BYTE2 0xf7
#define GW_MYSQL_SERVER_LANGUAGE 0x08
#define GW_MYSQL_MAX_PACKET_LEN 0xffffffL;
#define GW_MYSQL_SCRAMBLE_SIZE 20
// debug for mysql_* functions
#define MYSQL_CONN_DEBUG
#undef MYSQL_CONN_DEBUG
#include "gateway_mysql.h"
#include "mysql_protocol.h"
#include "dcb.h"
extern void gw_daemonize(void);
extern int do_read_dcb(DCB *dcb);
extern int handle_event_errors(DCB *dcb);
extern int handle_event_errors_backend(DCB *dcb);
extern void MySQLListener(int epfd, char *config_bind);
extern int MySQLAccept(DCB *listener);
extern int gw_mysql_do_authentication(DCB *dcb, GWBUF *);
extern void gw_mysql_close(MySQLProtocol **ptr);
extern char *gw_strend(register const char *s);
extern int do_read_dcb(DCB *dcb);
extern int do_read_10(DCB *dcb, uint8_t *buffer);
extern MySQLProtocol * gw_mysql_init(MySQLProtocol *ptr);
extern int MySQLWrite(DCB *dcb, GWBUF *queue);
extern int gw_write_backend_event(DCB *dcb);
extern int gw_read_backend_event(DCB *dcb);
extern int setnonblocking(int fd);

View File

@ -0,0 +1,53 @@
#ifndef _GWBITMASK_H
#define _GWBITMASK_H
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
#include <spinlock.h>
/**
* @file gwbitmask.h An implementation of an arbitarly long bitmask
*
* @verbatim
* Revision History
*
* Date Who Description
* 28/06/13 Mark Riddoch Initial implementation
*
* @endverbatim
*/
#define BIT_LENGTH_INITIAL 32 /**< Initial number of bits in the bitmask */
#define BIT_LENGTH_INC 32 /**< Number of bits to add on each increment */
/**
* The bitmask structure used to store an arbitary large bitmask
*/
typedef struct {
SPINLOCK lock; /**< Lock to protect the bitmask */
unsigned char *bits; /**< Pointer to the bits themselves */
unsigned int length; /**< The number of bits in the bitmask */
} GWBITMASK;
extern void bitmask_init(GWBITMASK *);
extern void bitmask_free(GWBITMASK *);
extern void bitmask_set(GWBITMASK *, int);
extern void bitmask_clear(GWBITMASK *, int);
extern int bitmask_isset(GWBITMASK *, int);
extern int bitmask_isallclear(GWBITMASK *);
extern void bitmask_copy(GWBITMASK *, GWBITMASK *);
#endif

100
server/include/hashtable.h Normal file
View File

@ -0,0 +1,100 @@
#ifndef _HASTABLE_H
#define _HASTABLE_H
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
/**
* @file hashtable.h A general purpose hashtable mechanism for use within the
* gateway
*
* @verbatim
* Revision History
*
* Date Who Description
* 23/06/13 Mark Riddoch Initial implementation
* 23/07/13 Mark Riddoch Addition of iterator mechanism
*
* @endverbatim
*/
#include <spinlock.h>
#include <atomic.h>
#include <dcb.h>
/**
* The entries within a hashtable.
*
* A NULL value for key indicates an empty entry.
* The next pointer is the overflow chain for this hashentry.
*/
typedef struct hashentry {
void *key; /**< The value of the key or NULL if empty entry */
void *value; /**< The value associated with key */
struct hashentry *next; /**< The overflow chain */
} HASHENTRIES;
/**
* HASHTABLE iterator - used to walk the hashtable in a thread safe
* way
*/
typedef struct hashiterator {
struct hashtable
*table; /**< The hashtable the iterator refers to */
int chain; /**< The current chain we are walking */
int depth; /**< The current depth down the chain */
} HASHITERATOR;
/**
* The type definition for the memory allocation functions
*/
typedef void *(*HASHMEMORYFN)(void *);
/**
* The general purpose hashtable struct.
*/
typedef struct hashtable {
int hashsize; /**< The number of HASHENTRIES */
HASHENTRIES **entries; /**< The entries themselves */
int (*hashfn)(void *); /**< The hash function */
int (*cmpfn)(void *, void *); /**< The key comparison function */
HASHMEMORYFN copyfn; /**< Optional copy function */
HASHMEMORYFN freefn; /**< Optional free function */
SPINLOCK spin; /**< Internal spinlock for the hashtable */
int n_readers; /**< Number of clients reading the table */
int writelock; /**< The table is locked by a writer */
} HASHTABLE;
extern HASHTABLE *hashtable_alloc(int, int (*hashfn)(), int (*cmpfn)());
/**< Allocate a hashtable */
extern void hashtable_memory_fns(HASHTABLE *, HASHMEMORYFN, HASHMEMORYFN);
/**< Provide an interface to control key/value memory
* manipulation
*/
extern void hashtable_free(HASHTABLE *); /**< Free a hashtable */
extern int hashtable_add(HASHTABLE *, void *, void *); /**< Add an entry */
extern int hashtable_delete(HASHTABLE *, void *);
/**< Delete an entry table */
extern void *hashtable_fetch(HASHTABLE *, void *);
/**< Fetch the data for a given key */
extern void hashtable_stats(HASHTABLE *); /**< Print statisitics */
extern void dcb_hashtable_stats(DCB *, HASHTABLE *); /**< Print statisitics */
extern HASHITERATOR *hashtable_iterator(HASHTABLE *);
/**< Allocate an iterator on the hashtable */
extern void *hashtable_next(HASHITERATOR *);
/**< Return the key of the hash table iterator */
extern void hashtable_iterator_free(HASHITERATOR *);
#endif

58
server/include/modules.h Normal file
View File

@ -0,0 +1,58 @@
#ifndef _MODULES_H
#define _MODULES_H
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
#include <dcb.h>
/**
* @file modules.h Utilities for loading modules
*
* The module interface used within the gateway
*
* @verbatim
* Revision History
*
* Date Who Description
* 13/06/13 Mark Riddoch Initial implementation
* 08/07/13 Mark Riddoch Addition of monitor modules
* @endverbatim
*/
typedef struct modules {
char *module; /**< The name of the module */
char *type; /**< The module type */
char *version; /**< Module version */
void *handle; /**< The handle returned by dlopen */
void *modobj; /**< The module "object" this is the set of entry points */
struct modules
*next; /**< Next module in the linked list */
} MODULES;
/**
* Module types
*/
#define MODULE_PROTOCOL "Protocol" /**< A protocol module type */
#define MODULE_ROUTER "Router" /**< A router module type */
#define MODULE_MONITOR "Monitor" /**< A database monitor module type */
extern void *load_module(const char *module, const char *type);
extern void unload_module(const char *module);
extern void printModules();
extern void dprintAllModules(DCB *);
#endif

88
server/include/monitor.h Normal file
View File

@ -0,0 +1,88 @@
#ifndef _MONITOR_H
#define _MONITOR_H
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
#include <server.h>
#include <dcb.h>
/**
* @file monitor.h The interface to the monitor module
*
* @verbatim
* Revision History
*
* Date Who Description
* 07/07/13 Mark Riddoch Initial implementation
* 25/07/13 Mark Riddoch Addition of diagnotics
*
* @endverbatim
*/
/**
* The "Module Object" for a monitor module.
*
* The monitor modules are designed to monitor the backend databases that the gateway
* connects to and provide information regarding the status of the databases that
* is used in the routing decisions.
*
* startMonitor is called to start the monitoring process, it is called on the main
* thread of the gateway and is responsible for creating a thread for the monitor
* itself to run on. This should use the entry points defined in the thread.h
* header file rather than make direct calls to the operating system thrading libraries.
* The return from startMonitor is a void * handle that will be passed to all other monitor
* API calls.
*
* stopMonitor is responsible for shuting down and destroying a monitor, it is called
* with the void * handle that was returned by startMonitor.
*
* registerServer is called to register a server that must be monitored with a running
* monitor. this will be called with the handle returned from the startMonitor call and
* the SERVER structure that the monitor must update and monitor. The SERVER structure
* contains the information required to connect to the monitored server.
*
* unregisterServer is called to remove a server from the set of servers that need to be
* monitored.
*/
typedef struct {
void *(*startMonitor)(void *);
void (*stopMonitor)(void *);
void (*registerServer)(void *, SERVER *);
void (*unregisterServer)(void *, SERVER *);
void (*defaultUser)(void *, char *, char *);
void (*diagnostics)(DCB *, void *);
} MONITOR_OBJECT;
/**
* Representation of the running monitor.
*/
typedef struct monitor {
char *name; /**< The name of the monitor module */
MONITOR_OBJECT *module; /**< The "monitor object" */
void *handle; /**< Handle returned from startMonitor */
struct monitor *next; /**< Next monitor in the linked list */
} MONITOR;
extern MONITOR *monitor_alloc(char *, char *);
extern void monitor_free(MONITOR *);
extern void monitorAddServer(MONITOR *, SERVER *);
extern void monitorAddUser(MONITOR *, char *, char *);
extern void monitorStop(MONITOR *);
extern void monitorStart(MONITOR *);
extern void monitorStopAll();
extern void monitorShowAll(DCB *);
#endif

View File

@ -0,0 +1,71 @@
#ifndef _MYSQL_PROTOCOL_H
#define _MYSQL_PROTOCOL_H
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
/*
* Revision History
*
* Date Who Description
* 01-06-2013 Mark Riddoch Initial implementation
* 14-06-2013 Massimiliano Pinto Added specific data
* for MySQL session
*/
#ifndef MYSQL_SCRAMBLE_LEN
#define MYSQL_SCRAMBLE_LEN GW_MYSQL_SCRAMBLE_SIZE
#endif
#define MYSQL_USER_MAXLEN 128
#define MYSQL_DATABASE_MAXLEN 128
struct dcb;
/**
* MySQL Protocol specific state data
*/
typedef struct {
int fd; /**< The socket descriptor */
struct dcb *descriptor; /**< The DCB of the socket we are running on */
int state; /**< Current descriptor state */
char scramble[MYSQL_SCRAMBLE_LEN]; /**< server scramble, created or received */
uint32_t server_capabilities; /**< server capabilities, created or received */
uint32_t client_capabilities; /**< client capabilities, created or received */
unsigned long tid; /**< MySQL Thread ID, in handshake */
} MySQLProtocol;
/**
* MySQL session specific data
*
*/
typedef struct mysql_session {
uint8_t client_sha1[MYSQL_SCRAMBLE_LEN]; /**< SHA1(passowrd) */
char user[MYSQL_USER_MAXLEN]; /**< username */
char db[MYSQL_DATABASE_MAXLEN]; /**< database */
} MYSQL_session;
/* MySQL Protocol States */
#define MYSQL_ALLOC 0 /**< Allocate data */
#define MYSQL_AUTH_SENT 1 /**< Authentication handshake has been sent */
#define MYSQL_AUTH_RECV 2 /**< Received user, password, db and capabilities */
#define MYSQL_AUTH_FAILED 3 /**< Auth failed, return error packet */
#define MYSQL_IDLE 4 /**< Auth done. Protocol is idle, waiting for statements */
#define MYSQL_ROUTING 5 /**< The received command has been routed to backend(s) */
#define MYSQL_WAITING_RESULT 6 /**< Waiting for result set */
#endif

44
server/include/poll.h Normal file
View File

@ -0,0 +1,44 @@
#ifndef _POLL_H
#define _POLL_H
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
#include <dcb.h>
#include <gwbitmask.h>
/**
* @file poll.h The poll related functionality
*
* @verbatim
* Revision History
*
* Date Who Description
* 19/06/13 Mark Riddoch Initial implementation
*
* @endverbatim
*/
#define MAX_EVENTS 1000
#define EPOLL_TIMEOUT 1000 /**< The epoll timeout we use (milliseconds) */
extern void poll_init();
extern int poll_add_dcb(DCB *);
extern int poll_remove_dcb(DCB *);
extern void poll_waitevents(void *);
extern void poll_shutdown();
extern GWBITMASK *poll_bitmask();
extern void dprintPollStats(DCB *);
#endif

78
server/include/router.h Normal file
View File

@ -0,0 +1,78 @@
#ifndef _ROUTER_H
#define _ROUTER_H
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
/**
* @file router.h - The query router interface mechanisms
*
* Revision History
*
* Date Who Description
* 14/06/2013 Mark Riddoch Initial implementation
* 26/06/2013 Mark Riddoch Addition of router options
* and the diagnostic entry point
* 15/07/2013 Massimiliano Pinto Added clientReply entry point
* 16/07/2013 Massimiliano Pinto Added router commands values
*
*/
#include <service.h>
#include <session.h>
#include <buffer.h>
/**
* The ROUTER handle points to module specific data, so the best we can do
* is to make it a void * externally.
*/
typedef void *ROUTER;
/**
* @verbatim
* The "module object" structure for a query router module
*
* The entry points are:
* createInstance Called by the service to create a new
* instance of the query router
* newSession Called to create a new user session
* within the query router
* closeSession Called when a session is closed
* routeQuery Called on each query that requires
* routing
* diagnostics Called to force the router to print
* diagnostic output
* clientReply Called to reply to client the data from one or all backends
*
* @endverbatim
*
* @see load_module
*/
typedef struct router_object {
ROUTER *(*createInstance)(SERVICE *service, char **options);
void *(*newSession)(ROUTER *instance, SESSION *session);
void (*closeSession)(ROUTER *instance, void *router_session);
int (*routeQuery)(ROUTER *instance, void *router_session, GWBUF *queue);
void (*diagnostics)(ROUTER *instance, DCB *dcb);
void (*clientReply)(ROUTER* instance, void* router_session, GWBUF* queue, DCB *backend_dcb);
} ROUTER_OBJECT;
/* Router commands */
#define ROUTER_DEFAULT 0 /**< Standard routing */
#define ROUTER_CHANGE_SESSION 1 /**< Route a change session */
#endif

57
server/include/secrets.h Normal file
View File

@ -0,0 +1,57 @@
#ifndef _SECRETS_H
#define _SECRETS_H
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
/**
* @file secrets.h
*
* @verbatim
* Revision History
*
* Date Who Description
* 23/06/2013 Massimiliano Pinto Initial implementation
*
* @endverbatim
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <openssl/aes.h>
#define MAXSCALE_KEYLEN 32
#define MAXSCALE_IV_LEN 16
/**
* The key structure held in the secrets file
*/
typedef struct maxkeys {
unsigned char enckey[MAXSCALE_KEYLEN];
unsigned char initvector[MAXSCALE_IV_LEN];
} MAXKEYS;
extern int secrets_writeKeys(char *filename);
extern char *decryptPassword(char *);
extern char *encryptPassword(char *);
#endif

111
server/include/server.h Normal file
View File

@ -0,0 +1,111 @@
#ifndef _SERVER_H
#define _SERVER_H
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
#include <dcb.h>
/**
* @file service.h
*
* The server level definitions within the gateway
*
* @verbatim
* Revision History
*
* Date Who Description
* 14/06/13 Mark Riddoch Initial implementation
* 21/06/13 Mark Riddoch Addition of server status flags
* 22/07/13 Mark Riddoch Addition of JOINED status for Galera
*
* @endverbatim
*/
/**
* The server statistics structure
*
*/
typedef struct {
int n_connections; /**< Number of connections */
int n_current; /**< Current connections */
} SERVER_STATS;
/**
* The SERVER structure defines a backend server. Each server has a name
* or IP address for the server, a port that the server listens on and
* the name of a protocol module that is loaded to implement the protocol
* between the gateway and the server.
*/
typedef struct server {
char *name; /**< Server name/IP address*/
unsigned short port; /**< Port to listen on */
char *protocol; /**< Protocol module to use */
unsigned int status; /**< Status flag bitmap for the server */
char *monuser; /**< User name to use to monitor the db */
char *monpw; /**< Password to use to monitor the db */
SERVER_STATS stats; /**< The server statistics */
struct server *next; /**< Next server */
struct server *nextdb; /**< Next server in list attached to a service */
} SERVER;
/**
* Status bits in the server->status member.
*
* These are a bitmap of attributes that may be applied to a server
*/
#define SERVER_RUNNING 0x0001 /**<< The server is up and running */
#define SERVER_MASTER 0x0002 /**<< The server is a master, i.e. can handle writes */
#define SERVER_SLAVE 0x0004 /**<< The server is a slave, i.e. can handle reads */
#define SERVER_JOINED 0x0008 /**<< The server is joined in a Galera cluster */
/**
* Is the server running - the macro returns true if the server is marked as running
* regardless of it's state as a master or slave
*/
#define SERVER_IS_RUNNING(server) ((server)->status & SERVER_RUNNING)
/**
* Is the server marked as down - the macro returns true if the server is beleived
* to be inoperable.
*/
#define SERVER_IS_DOWN(server) (((server)->status & SERVER_RUNNING) == 0)
/**
* Is the server a master? The server must be both running and marked as master
* in order for the macro to return true
*/
#define SERVER_IS_MASTER(server) \
(((server)->status & (SERVER_RUNNING|SERVER_MASTER|SERVER_SLAVE)) == (SERVER_RUNNING|SERVER_MASTER))
/**
* Is the server a slave? The server must be both running and marked as a slave
* in order for the macro to return true
*/
#define SERVER_IS_SLAVE(server) \
(((server)->status & (SERVER_RUNNING|SERVER_MASTER|SERVER_SLAVE)) == (SERVER_RUNNING|SERVER_SLAVE))
extern SERVER *server_alloc(char *, char *, unsigned short);
extern int server_free(SERVER *);
extern SERVER *server_find(char *, unsigned short);
extern void printServer(SERVER *);
extern void printAllServers();
extern void dprintAllServers(DCB *);
extern void dprintServer(DCB *, SERVER *);
extern char *server_status(SERVER *);
extern void server_set_status(SERVER *, int);
extern void server_clear_status(SERVER *, int);
extern void serverAddMonUser(SERVER *, char *, char *);
extern void server_update(SERVER *, char *, char *, char *);
#endif

130
server/include/service.h Normal file
View File

@ -0,0 +1,130 @@
#ifndef _SERVICE_H
#define _SERVICE_H
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
#include <time.h>
#include <spinlock.h>
#include <dcb.h>
#include <server.h>
/**
* @file service.h
*
* The service level definitions within the gateway
*
* @verbatim
* Revision History
*
* Date Who Description
* 14/06/13 Mark Riddoch Initial implementation
* 18/06/13 Mark Riddoch Addition of statistics and function
* prototypes
* 23/06/13 Mark Riddoch Added service user and users
*
* @endverbatim
*/
struct server;
struct router;
struct router_object;
struct users;
/**
* The servprotocol structure is used to link a service to the protocols that
* are used to support that service. It defines the name of the protocol module
* that should be loaded to support the client connection and the port that the
* protocol should use to listen for incoming client connections.
*/
typedef struct servprotocol {
char *protocol; /**< Protocol module to load */
unsigned short port; /**< Port to listen on */
DCB *listener; /**< The DCB for the listener */
struct servprotocol
*next; /**< Next service protocol */
} SERV_PROTOCOL;
/**
* The service statistics structure
*/
typedef struct {
time_t started; /**< The time when the service was started */
int n_sessions; /**< Number of sessions created on service since start */
int n_current; /**< Current number of sessions */
} SERVICE_STATS;
/**
* The service user structure holds the information that is needed for this service to
* allow the gateway to login to the backend database and extact information such as
* the user table or other database status or configuration data.
*/
typedef struct {
char *name; /**< The user name to use to extract information */
char *authdata; /**< The authentication data requied */
} SERVICE_USER;
/**
* Defines a service within the gateway.
*
* A service is a combination of a set of backend servers, a routing mechanism
* and a set of client side protocol/port pairs used to listen for new connections
* to the service.
*/
typedef struct service {
char *name; /**< The service name */
int state; /**< The service state */
SERV_PROTOCOL *ports; /**< Linked list of ports and protocols
* that this service will listen on.
*/
char *routerModule; /**< Name of router module to use */
char **routerOptions;/**< Router specific option strings */
struct router_object
*router; /**< The router we are using */
void *router_instance;
/**< The router instance for this service */
struct server *databases; /**< The set of servers in the backend */
SERVICE_USER credentials; /**< The cedentials of the service user */
SPINLOCK spin; /**< The service spinlock */
SERVICE_STATS stats; /**< The service statistics */
struct users *users; /**< The user data for this service */
struct service *next; /**< The next service in the linked list */
} SERVICE;
#define SERVICE_STATE_ALLOC 1 /**< The service has been allocated */
#define SERVICE_STATE_STARTED 2 /**< The service has been started */
extern SERVICE *service_alloc(char *, char *);
extern int service_free(SERVICE *);
extern SERVICE *service_find(char *);
extern int serviceAddProtocol(SERVICE *, char *, unsigned short);
extern int serviceHasProtocol(SERVICE *, char *, unsigned short);
extern void serviceAddBackend(SERVICE *, SERVER *);
extern int serviceHasBackend(SERVICE *, SERVER *);
extern void serviceAddRouterOption(SERVICE *, char *);
extern void serviceClearRouterOptions(SERVICE *);
extern int serviceStart(SERVICE *);
extern int serviceStartAll();
extern void serviceStartProtocol(SERVICE *, char *, int);
extern int serviceStop(SERVICE *);
extern int serviceRestart(SERVICE *);
extern int serviceSetUser(SERVICE *, char *, char *);
extern int serviceGetUser(SERVICE *, char **, char **);
extern void service_update(SERVICE *, char *, char *, char *);
extern void printService(SERVICE *);
extern void printAllServices();
extern void dprintAllServices(DCB *);
#endif

79
server/include/session.h Normal file
View File

@ -0,0 +1,79 @@
#ifndef _SESSION_H
#define _SESSION_H
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
/**
* @file session.h
*
* @verbatim
* Revision History
*
* Date Who Description
* 01-06-2013 Mark Riddoch Initial implementation
* 14-06-2013 Massimiliano Pinto Added void *data to session
* for session specific data
* 01-07-2013 Massimiliano Pinto Removed backends pointer
from struct session
* @endverbatim
*/
#include <time.h>
struct dcb;
struct service;
/**
* The session statistics structure
*/
typedef struct {
time_t connect; /**< Time when the session was started */
} SESSION_STATS;
/**
* The session status block
*
* A session status block is created for each user (client) connection
* to the database, it links the descriptors, routing implementation
* and originating service together for the client session.
*/
typedef struct session {
int state; /**< Current descriptor state */
struct dcb *client; /**< The client connection */
struct dcb *backends; /**< The set of backend servers */
void *data; /**< The session data */
void *router_session;/**< The router instance data */
SESSION_STATS stats; /**< Session statistics */
struct service *service; /**< The service this session is using */
struct session *next; /**< Linked list of all sessions */
} SESSION;
#define SESSION_STATE_ALLOC 0 /**< The session has been allocated */
#define SESSION_STATE_READY 1 /**< The session is ready to route queries */
#define SESSION_STATE_LISTENER 2 /**< The session is a running listener */
#define SESSION_STATE_LISTENER_STOPPED 3 /**< The session listener is stopped */
#define SESSION_PROTOCOL(x, type) DCB_PROTOCOL((x)->client, type)
extern SESSION *session_alloc(struct service *, struct dcb *);
extern void session_free(SESSION *);
extern void printAllSessions();
extern void printSession(SESSION *);
extern void dprintAllSessions(struct dcb *);
extern void dprintSession(struct dcb *, SESSION *);
extern char *session_state(int);
#endif

59
server/include/spinlock.h Normal file
View File

@ -0,0 +1,59 @@
#ifndef _SPINLOCK_H
#define _SPINLOCK_H
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
/**
* @file spinlock.h
*
* Spinlock implementation for ther gateway.
*
* Spinlocks are cheap locks that can be used to protect short code blocks, they are
* generally wasteful as any blocked threads will spin, consuming CPU cycles, waiting
* for the lock to be released. However they are useful in that they do not involve
* system calls and are light weight when the expected wait time for a lock is low.
*/
#include <thread.h>
typedef struct spinlock {
int lock;
#if DEBUG
int spins;
int acquired;
THREAD owner;
#endif
} SPINLOCK;
#ifndef TRUE
#define TRUE (1 == 1)
#endif
#ifndef FALSE
#define FALSE (1 == 0)
#endif
#if DEBUG
#define SPINLOCK_INIT { 0, 0, 0, NULL }
#else
#define SPINLOCK_INIT { 0 }
#endif
extern void spinlock_init(SPINLOCK *lock);
extern void spinlock_acquire(SPINLOCK *lock);
extern int spinlock_acquire_nowait(SPINLOCK *lock);
extern void spinlock_release(SPINLOCK *lock);
#endif

38
server/include/thread.h Normal file
View File

@ -0,0 +1,38 @@
#ifndef _THREAD_H
#define _THREAD_H
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
#include <pthread.h>
/**
* @file thread.h The gateway threading interface
*
* An encapsulation of the threading used by the gateway. This is designed to
* isolate the majority of the gateway code from th epthread library, enabling
* the gateway to be ported to a different threading package with the minimum
* of changes.
*/
#define THREAD pthread_t
#define THREAD_SHELF pthread_self
extern void *thread_start(void (*entry)(void *), void *arg);
extern void thread_wait(void *thd);
extern void thread_millisleep(int ms);
#endif

63
server/include/users.h Normal file
View File

@ -0,0 +1,63 @@
#ifndef _USERS_H
#define _USERS_H
/*
* This file is distributed as part of the SkySQL Gateway. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright SkySQL Ab 2013
*/
#include <hashtable.h>
#include <dcb.h>
/**
* @file users.h The functions to manipulate the table of users maintained
* for each service
*
* @verbatim
* Revision History
*
* Date Who Description
* 23/06/13 Mark Riddoch Initial implementation
*
* @endverbatim
*/
/**
* The users table statistics structure
*/
typedef struct {
int n_entries; /**< The number of entries */
int n_adds; /**< The number of inserts */
int n_deletes; /**< The number of deletes */
int n_fetches; /**< The number of fetchs */
} USERS_STATS;
/**
* The user table, this contains the username and authentication data required
* for the authentication implementation within the gateway.
*/
typedef struct users {
HASHTABLE *data; /**< The hashtable containing the actual data */
USERS_STATS stats; /**< The statistics for the users table */
} USERS;
extern USERS *users_alloc(); /**< Allocate a users table */
extern void users_free(USERS *); /**< Free a users table */
extern int users_add(USERS *, char *, char *); /**< Add a user to the users table */
extern int users_delete(USERS *, char *); /**< Delete a user from the users table */
extern char *users_fetch(USERS *, char *); /**< Fetch the authentication data for a user */
extern int users_update(USERS *, char *, char *); /**< Change the password data for a user in the users table */
extern void usersPrint(USERS *); /**< Print data about the users loaded */
extern void dcb_usersPrint(DCB *, USERS *); /**< Print data about the users loaded */
#endif

BIN
server/inih/._LICENSE.txt Executable file

Binary file not shown.

BIN
server/inih/._README.txt Executable file

Binary file not shown.

BIN
server/inih/._cpp Executable file

Binary file not shown.

BIN
server/inih/._examples Executable file

Binary file not shown.

BIN
server/inih/._extra Executable file

Binary file not shown.

BIN
server/inih/._ini.c Executable file

Binary file not shown.

BIN
server/inih/._ini.h Executable file

Binary file not shown.

BIN
server/inih/._tests Executable file

Binary file not shown.

27
server/inih/LICENSE.txt Executable file
View File

@ -0,0 +1,27 @@
The "inih" library is distributed under the New BSD license:
Copyright (c) 2009, Brush Technology
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Brush Technology nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY BRUSH TECHNOLOGY ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL BRUSH TECHNOLOGY BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

5
server/inih/README.txt Executable file
View File

@ -0,0 +1,5 @@
inih is a simple .INI file parser written in C, released under the New BSD
license (see LICENSE.txt). Go to the project home page for more info:
http://code.google.com/p/inih/

BIN
server/inih/cpp/._INIReader.cpp Executable file

Binary file not shown.

BIN
server/inih/cpp/._INIReader.h Executable file

Binary file not shown.

Binary file not shown.

67
server/inih/cpp/INIReader.cpp Executable file
View File

@ -0,0 +1,67 @@
// Read an INI file into easy-to-access name/value pairs.
#include <algorithm>
#include <cctype>
#include <cstdlib>
#include "../ini.h"
#include "INIReader.h"
using std::string;
INIReader::INIReader(string filename)
{
_error = ini_parse(filename.c_str(), ValueHandler, this);
}
int INIReader::ParseError()
{
return _error;
}
string INIReader::Get(string section, string name, string default_value)
{
string key = MakeKey(section, name);
return _values.count(key) ? _values[key] : default_value;
}
long INIReader::GetInteger(string section, string name, long default_value)
{
string valstr = Get(section, name, "");
const char* value = valstr.c_str();
char* end;
// This parses "1234" (decimal) and also "0x4D2" (hex)
long n = strtol(value, &end, 0);
return end > value ? n : default_value;
}
bool INIReader::GetBoolean(string section, string name, bool default_value)
{
string valstr = Get(section, name, "");
// Convert to lower case to make string comparisons case-insensitive
std::transform(valstr.begin(), valstr.end(), valstr.begin(), ::tolower);
if (valstr == "true" || valstr == "yes" || valstr == "on" || valstr == "1")
return true;
else if (valstr == "false" || valstr == "no" || valstr == "off" || valstr == "0")
return false;
else
return default_value;
}
string INIReader::MakeKey(string section, string name)
{
string key = section + "." + name;
// Convert to lower case to make section/name lookups case-insensitive
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
return key;
}
int INIReader::ValueHandler(void* user, const char* section, const char* name,
const char* value)
{
INIReader* reader = (INIReader*)user;
string key = MakeKey(section, name);
if (reader->_values[key].size() > 0)
reader->_values[key] += "\n";
reader->_values[key] += value;
return 1;
}

48
server/inih/cpp/INIReader.h Executable file
View File

@ -0,0 +1,48 @@
// Read an INI file into easy-to-access name/value pairs.
// inih and INIReader are released under the New BSD license (see LICENSE.txt).
// Go to the project home page for more info:
//
// http://code.google.com/p/inih/
#ifndef __INIREADER_H__
#define __INIREADER_H__
#include <map>
#include <string>
// Read an INI file into easy-to-access name/value pairs. (Note that I've gone
// for simplicity here rather than speed, but it should be pretty decent.)
class INIReader
{
public:
// Construct INIReader and parse given filename. See ini.h for more info
// about the parsing.
INIReader(std::string filename);
// Return the result of ini_parse(), i.e., 0 on success, line number of
// first error on parse error, or -1 on file open error.
int ParseError();
// Get a string value from INI file, returning default_value if not found.
std::string Get(std::string section, std::string name,
std::string default_value);
// Get an integer (long) value from INI file, returning default_value if
// not found or not a valid integer (decimal "1234", "-1234", or hex "0x4d2").
long GetInteger(std::string section, std::string name, long default_value);
// Get a boolean value from INI file, returning default_value if not found or if
// not a valid true/false value. Valid true values are "true", "yes", "on", "1",
// and valid false values are "false", "no", "off", "0" (not case sensitive).
bool GetBoolean(std::string section, std::string name, bool default_value);
private:
int _error;
std::map<std::string, std::string> _values;
static std::string MakeKey(std::string section, std::string name);
static int ValueHandler(void* user, const char* section, const char* name,
const char* value);
};
#endif // __INIREADER_H__

View File

@ -0,0 +1,20 @@
// Example that shows simple usage of the INIReader class
#include <iostream>
#include "INIReader.h"
int main()
{
INIReader reader("../examples/test.ini");
if (reader.ParseError() < 0) {
std::cout << "Can't load 'test.ini'\n";
return 1;
}
std::cout << "Config loaded from 'test.ini': version="
<< reader.GetInteger("protocol", "version", -1) << ", name="
<< reader.Get("user", "name", "UNKNOWN") << ", email="
<< reader.Get("user", "email", "UNKNOWN") << ", active="
<< reader.GetBoolean("user", "active", true) << "\n";
return 0;
}

BIN
server/inih/examples/._config.def Executable file

Binary file not shown.

BIN
server/inih/examples/._ini_dump.c Executable file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
server/inih/examples/._test.ini Executable file

Binary file not shown.

View File

@ -0,0 +1,8 @@
// CFG(section, name, default)
CFG(protocol, version, "0")
CFG(user, name, "Fatty Lumpkin")
CFG(user, email, "fatty@lumpkin.com")
#undef CFG

40
server/inih/examples/ini_dump.c Executable file
View File

@ -0,0 +1,40 @@
/* ini.h example that simply dumps an INI file without comments */
#include <stdio.h>
#include <string.h>
#include "../ini.h"
static int dumper(void* user, const char* section, const char* name,
const char* value)
{
static char prev_section[50] = "";
if (strcmp(section, prev_section)) {
printf("%s[%s]\n", (prev_section[0] ? "\n" : ""), section);
strncpy(prev_section, section, sizeof(prev_section));
prev_section[sizeof(prev_section) - 1] = '\0';
}
printf("%s = %s\n", name, value);
return 1;
}
int main(int argc, char* argv[])
{
int error;
if (argc <= 1) {
printf("Usage: ini_dump filename.ini\n");
return 1;
}
error = ini_parse(argv[1], dumper, NULL);
if (error < 0) {
printf("Can't read '%s'!\n", argv[1]);
return 2;
}
else if (error) {
printf("Bad config file (first error on line %d)!\n", error);
return 3;
}
return 0;
}

View File

@ -0,0 +1,44 @@
/* Example: parse a simple configuration file */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../ini.h"
typedef struct
{
int version;
const char* name;
const char* email;
} configuration;
static int handler(void* user, const char* section, const char* name,
const char* value)
{
configuration* pconfig = (configuration*)user;
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
if (MATCH("protocol", "version")) {
pconfig->version = atoi(value);
} else if (MATCH("user", "name")) {
pconfig->name = strdup(value);
} else if (MATCH("user", "email")) {
pconfig->email = strdup(value);
} else {
return 0; /* unknown section/name, error */
}
return 1;
}
int main(int argc, char* argv[])
{
configuration config;
if (ini_parse("test.ini", handler, &config) < 0) {
printf("Can't load 'test.ini'\n");
return 1;
}
printf("Config loaded from 'test.ini': version=%d, name=%s, email=%s\n",
config.version, config.name, config.email);
return 0;
}

View File

@ -0,0 +1,46 @@
/* Parse a configuration file into a struct using X-Macros */
#include <stdio.h>
#include <string.h>
#include "../ini.h"
/* define the config struct type */
typedef struct {
#define CFG(s, n, default) char *s##_##n;
#include "config.def"
} config;
/* create one and fill in its default values */
config Config = {
#define CFG(s, n, default) default,
#include "config.def"
};
/* process a line of the INI file, storing valid values into config struct */
int handler(void *user, const char *section, const char *name,
const char *value)
{
config *cfg = (config *)user;
if (0) ;
#define CFG(s, n, default) else if (strcmp(section, #s)==0 && \
strcmp(name, #n)==0) cfg->s##_##n = strdup(value);
#include "config.def"
return 1;
}
/* print all the variables in the config, one per line */
void dump_config(config *cfg)
{
#define CFG(s, n, default) printf("%s_%s = %s\n", #s, #n, cfg->s##_##n);
#include "config.def"
}
int main(int argc, char* argv[])
{
if (ini_parse("test.ini", handler, &Config) < 0)
printf("Can't load 'test.ini', using defaults\n");
dump_config(&Config);
return 0;
}

9
server/inih/examples/test.ini Executable file
View File

@ -0,0 +1,9 @@
; Test config file for ini_example.c and INIReaderTest.cpp
[protocol] ; Protocol configuration
version=6 ; IPv6
[user]
name = Bob Smith ; Spaces around '=' are stripped
email = bob@smith.com ; And comments (like this) ignored
active = true ; Test a boolean

Binary file not shown.

View File

@ -0,0 +1,19 @@
# Simple makefile to build inih as a static library using g++
SRC = ../ini.c
OBJ = $(SRC:.c=.o)
OUT = libinih.a
INCLUDES = -I..
CCFLAGS = -g -O2
CC = g++
default: $(OUT)
.c.o:
$(CC) $(INCLUDES) $(CCFLAGS) $(EXTRACCFLAGS) -c $< -o $@
$(OUT): $(OBJ)
ar rcs $(OUT) $(OBJ) $(EXTRAARFLAGS)
clean:
rm -f $(OBJ) $(OUT)

176
server/inih/ini.c Executable file
View File

@ -0,0 +1,176 @@
/* inih -- simple .INI file parser
inih is released under the New BSD license (see LICENSE.txt). Go to the project
home page for more info:
http://code.google.com/p/inih/
*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "ini.h"
#if !INI_USE_STACK
#include <stdlib.h>
#endif
#define MAX_SECTION 50
#define MAX_NAME 50
/* Strip whitespace chars off end of given string, in place. Return s. */
static char* rstrip(char* s)
{
char* p = s + strlen(s);
while (p > s && isspace((unsigned char)(*--p)))
*p = '\0';
return s;
}
/* Return pointer to first non-whitespace char in given string. */
static char* lskip(const char* s)
{
while (*s && isspace((unsigned char)(*s)))
s++;
return (char*)s;
}
/* Return pointer to first char c or ';' comment in given string, or pointer to
null at end of string if neither found. ';' must be prefixed by a whitespace
character to register as a comment. */
static char* find_char_or_comment(const char* s, char c)
{
int was_whitespace = 0;
while (*s && *s != c && !(was_whitespace && *s == ';')) {
was_whitespace = isspace((unsigned char)(*s));
s++;
}
return (char*)s;
}
/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
static char* strncpy0(char* dest, const char* src, size_t size)
{
strncpy(dest, src, size);
dest[size - 1] = '\0';
return dest;
}
/* See documentation in header file. */
int ini_parse_file(FILE* file,
int (*handler)(void*, const char*, const char*,
const char*),
void* user)
{
/* Uses a fair bit of stack (use heap instead if you need to) */
#if INI_USE_STACK
char line[INI_MAX_LINE];
#else
char* line;
#endif
char section[MAX_SECTION] = "";
char prev_name[MAX_NAME] = "";
char* start;
char* end;
char* name;
char* value;
int lineno = 0;
int error = 0;
#if !INI_USE_STACK
line = (char*)malloc(INI_MAX_LINE);
if (!line) {
return -2;
}
#endif
/* Scan through file line by line */
while (fgets(line, INI_MAX_LINE, file) != NULL) {
lineno++;
start = line;
#if INI_ALLOW_BOM
if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
(unsigned char)start[1] == 0xBB &&
(unsigned char)start[2] == 0xBF) {
start += 3;
}
#endif
start = lskip(rstrip(start));
if (*start == ';' || *start == '#') {
/* Per Python ConfigParser, allow '#' comments at start of line */
}
#if INI_ALLOW_MULTILINE
else if (*prev_name && *start && start > line) {
/* Non-black line with leading whitespace, treat as continuation
of previous name's value (as per Python ConfigParser). */
if (!handler(user, section, prev_name, start) && !error)
error = lineno;
}
#endif
else if (*start == '[') {
/* A "[section]" line */
end = find_char_or_comment(start + 1, ']');
if (*end == ']') {
*end = '\0';
strncpy0(section, start + 1, sizeof(section));
*prev_name = '\0';
}
else if (!error) {
/* No ']' found on section line */
error = lineno;
}
}
else if (*start && *start != ';') {
/* Not a comment, must be a name[=:]value pair */
end = find_char_or_comment(start, '=');
if (*end != '=') {
end = find_char_or_comment(start, ':');
}
if (*end == '=' || *end == ':') {
*end = '\0';
name = rstrip(start);
value = lskip(end + 1);
end = find_char_or_comment(value, '\0');
if (*end == ';')
*end = '\0';
rstrip(value);
/* Valid name[=:]value pair found, call handler */
strncpy0(prev_name, name, sizeof(prev_name));
if (!handler(user, section, name, value) && !error)
error = lineno;
}
else if (!error) {
/* No '=' or ':' found on name[=:]value line */
error = lineno;
}
}
}
#if !INI_USE_STACK
free(line);
#endif
return error;
}
/* See documentation in header file. */
int ini_parse(const char* filename,
int (*handler)(void*, const char*, const char*, const char*),
void* user)
{
FILE* file;
int error;
file = fopen(filename, "r");
if (!file)
return -1;
error = ini_parse_file(file, handler, user);
fclose(file);
return error;
}

72
server/inih/ini.h Executable file
View File

@ -0,0 +1,72 @@
/* inih -- simple .INI file parser
inih is released under the New BSD license (see LICENSE.txt). Go to the project
home page for more info:
http://code.google.com/p/inih/
*/
#ifndef __INI_H__
#define __INI_H__
/* Make this header file easier to include in C++ code */
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
/* Parse given INI-style file. May have [section]s, name=value pairs
(whitespace stripped), and comments starting with ';' (semicolon). Section
is "" if name=value pair parsed before any section heading. name:value
pairs are also supported as a concession to Python's ConfigParser.
For each name=value pair parsed, call handler function with given user
pointer as well as section, name, and value (data only valid for duration
of handler call). Handler should return nonzero on success, zero on error.
Returns 0 on success, line number of first error on parse error (doesn't
stop on first error), -1 on file open error, or -2 on memory allocation
error (only when INI_USE_STACK is zero).
*/
int ini_parse(const char* filename,
int (*handler)(void* user, const char* section,
const char* name, const char* value),
void* user);
/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't
close the file when it's finished -- the caller must do that. */
int ini_parse_file(FILE* file,
int (*handler)(void* user, const char* section,
const char* name, const char* value),
void* user);
/* Nonzero to allow multi-line value parsing, in the style of Python's
ConfigParser. If allowed, ini_parse() will call the handler with the same
name for each subsequent line parsed. */
#ifndef INI_ALLOW_MULTILINE
#define INI_ALLOW_MULTILINE 1
#endif
/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of
the file. See http://code.google.com/p/inih/issues/detail?id=21 */
#ifndef INI_ALLOW_BOM
#define INI_ALLOW_BOM 1
#endif
/* Nonzero to use stack, zero to use heap (malloc/free). */
#ifndef INI_USE_STACK
#define INI_USE_STACK 1
#endif
/* Maximum line length for any line in INI file. */
#ifndef INI_MAX_LINE
#define INI_MAX_LINE 200
#endif
#ifdef __cplusplus
}
#endif
#endif /* __INI_H__ */

Binary file not shown.

BIN
server/inih/tests/._bad_multi.ini Executable file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
server/inih/tests/._bom.ini Executable file

Binary file not shown.

Binary file not shown.

BIN
server/inih/tests/._normal.ini Executable file

Binary file not shown.

BIN
server/inih/tests/._unittest.bat Executable file

Binary file not shown.

BIN
server/inih/tests/._unittest.c Executable file

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1 @@
This is an error

View File

@ -0,0 +1 @@
indented

View File

@ -0,0 +1,5 @@
[section1]
name1=value1
[section2
[section3 ; comment ]
name2=value2

View File

@ -0,0 +1,47 @@
no_file.ini: e=-1 user=0
... [section1]
... one=This is a test;
... two=1234;
... [ section 2 ]
... happy=4;
... sad=;
... [comment_test]
... test1=1;2;3;
... test2=2;3;4;this won't be a comment, needs whitespace before ';';
... test;3=345;
... test4=4#5#6;
... [colon_tests]
... Content-Type=text/html;
... foo=bar;
... adams=42;
normal.ini: e=0 user=101
... [section1]
... name1=value1;
... name2=value2;
bad_section.ini: e=3 user=102
bad_comment.ini: e=1 user=102
... [section]
... a=b;
... user=parse_error;
... c=d;
user_error.ini: e=3 user=104
... [section1]
... single1=abc;
... multi=this is a;
... multi=multi-line value;
... single2=xyz;
... [section2]
... multi=a;
... multi=b;
... multi=c;
... [section3]
... single=ghi;
... multi=the quick;
... multi=brown fox;
... name=bob smith;
multi_line.ini: e=0 user=105
bad_multi.ini: e=1 user=105
... [bom_section]
... bom_name=bom_value;
... key“=value“;
bom.ini: e=0 user=107

View File

@ -0,0 +1,43 @@
no_file.ini: e=-1 user=0
... [section1]
... one=This is a test;
... two=1234;
... [ section 2 ]
... happy=4;
... sad=;
... [comment_test]
... test1=1;2;3;
... test2=2;3;4;this won't be a comment, needs whitespace before ';';
... test;3=345;
... test4=4#5#6;
... [colon_tests]
... Content-Type=text/html;
... foo=bar;
... adams=42;
normal.ini: e=0 user=101
... [section1]
... name1=value1;
... name2=value2;
bad_section.ini: e=3 user=102
bad_comment.ini: e=1 user=102
... [section]
... a=b;
... user=parse_error;
... c=d;
user_error.ini: e=3 user=104
... [section1]
... single1=abc;
... multi=this is a;
... single2=xyz;
... [section2]
... multi=a;
... [section3]
... single=ghi;
... multi=the quick;
... name=bob smith;
multi_line.ini: e=4 user=105
bad_multi.ini: e=1 user=105
... [bom_section]
... bom_name=bom_value;
... key“=value“;
bom.ini: e=0 user=107

3
server/inih/tests/bom.ini Executable file
View File

@ -0,0 +1,3 @@
[bom_section]
bom_name=bom_value
key“ = value“

View File

@ -0,0 +1,15 @@
[section1]
single1 = abc
multi = this is a
multi-line value
single2 = xyz
[section2]
multi = a
b
c
[section3]
single: ghi
multi: the quick
brown fox
name = bob smith ; comment line 1
; comment line 2

25
server/inih/tests/normal.ini Executable file
View File

@ -0,0 +1,25 @@
; This is an INI file
[section1] ; section comment
one=This is a test ; name=value comment
two = 1234
; x=y
[ section 2 ]
happy = 4
sad =
[empty]
; do nothing
[comment_test]
test1 = 1;2;3 ; only this will be a comment
test2 = 2;3;4;this won't be a comment, needs whitespace before ';'
test;3 = 345 ; key should be "test;3"
test4 = 4#5#6 ; '#' only starts a comment at start of line
#test5 = 567 ; entire line commented
# test6 = 678 ; entire line commented, except in MULTILINE mode
[colon_tests]
Content-Type: text/html
foo:bar
adams : 42

2
server/inih/tests/unittest.bat Executable file
View File

@ -0,0 +1,2 @@
@call tcc ..\ini.c -I..\ -run unittest.c > baseline_multi.txt
@call tcc ..\ini.c -I..\ -DINI_ALLOW_MULTILINE=0 -run unittest.c > baseline_single.txt

Some files were not shown because too many files have changed in this diff Show More