moving files to /server to make merge possible
This commit is contained in:
66
server/Makefile
Normal file
66
server/Makefile
Normal 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
107
server/MaxScale.cnf
Normal 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
108
server/core/Makefile
Normal 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
202
server/core/adminusers.c
Normal 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
51
server/core/atomic.c
Normal 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
207
server/core/buffer.c
Normal 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
517
server/core/config.c
Normal 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
181
server/core/dbusers.c
Normal 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
690
server/core/dcb.c
Normal 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
686
server/core/depend.mk
Normal 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
455
server/core/gateway.c
Normal 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();
|
||||
}
|
||||
103
server/core/gateway_mysql_protocol.c
Normal file
103
server/core/gateway_mysql_protocol.c
Normal 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
133
server/core/gw_utils.c
Normal 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
205
server/core/gwbitmask.c
Normal 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
505
server/core/hashtable.c
Normal 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
275
server/core/load_utils.c
Normal 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
47
server/core/maxkeys.c
Normal 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
55
server/core/maxpasswd.c
Normal 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
196
server/core/monitor.c
Normal 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
252
server/core/poll.c
Normal 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
237
server/core/secrets.c
Normal 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
320
server/core/server.c
Normal 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
625
server/core/service.c
Normal 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
232
server/core/session.c
Normal 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
100
server/core/spinlock.c
Normal 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
78
server/core/thread.c
Normal 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
189
server/core/users.c
Normal 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
191
server/core/utils.c
Normal 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);
|
||||
}
|
||||
40
server/include/adminusers.h
Normal file
40
server/include/adminusers.h
Normal 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
34
server/include/atomic.h
Normal 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
98
server/include/buffer.h
Normal 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
63
server/include/config.h
Normal 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
36
server/include/dbusers.h
Normal 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
189
server/include/dcb.h
Normal 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
|
||||
126
server/include/gateway_mysql.h
Normal file
126
server/include/gateway_mysql.h
Normal 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
67
server/include/gw.h
Normal 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);
|
||||
53
server/include/gwbitmask.h
Normal file
53
server/include/gwbitmask.h
Normal 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
100
server/include/hashtable.h
Normal 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
58
server/include/modules.h
Normal 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
88
server/include/monitor.h
Normal 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
|
||||
71
server/include/mysql_protocol.h
Normal file
71
server/include/mysql_protocol.h
Normal 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
44
server/include/poll.h
Normal 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
78
server/include/router.h
Normal 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
57
server/include/secrets.h
Normal 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
111
server/include/server.h
Normal 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
130
server/include/service.h
Normal 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
79
server/include/session.h
Normal 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
59
server/include/spinlock.h
Normal 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
38
server/include/thread.h
Normal 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
63
server/include/users.h
Normal 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
BIN
server/inih/._LICENSE.txt
Executable file
Binary file not shown.
BIN
server/inih/._README.txt
Executable file
BIN
server/inih/._README.txt
Executable file
Binary file not shown.
BIN
server/inih/._cpp
Executable file
BIN
server/inih/._cpp
Executable file
Binary file not shown.
BIN
server/inih/._examples
Executable file
BIN
server/inih/._examples
Executable file
Binary file not shown.
BIN
server/inih/._extra
Executable file
BIN
server/inih/._extra
Executable file
Binary file not shown.
BIN
server/inih/._ini.c
Executable file
BIN
server/inih/._ini.c
Executable file
Binary file not shown.
BIN
server/inih/._ini.h
Executable file
BIN
server/inih/._ini.h
Executable file
Binary file not shown.
BIN
server/inih/._tests
Executable file
BIN
server/inih/._tests
Executable file
Binary file not shown.
27
server/inih/LICENSE.txt
Executable file
27
server/inih/LICENSE.txt
Executable 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
5
server/inih/README.txt
Executable 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
BIN
server/inih/cpp/._INIReader.cpp
Executable file
Binary file not shown.
BIN
server/inih/cpp/._INIReader.h
Executable file
BIN
server/inih/cpp/._INIReader.h
Executable file
Binary file not shown.
BIN
server/inih/cpp/._INIReaderTest.cpp
Executable file
BIN
server/inih/cpp/._INIReaderTest.cpp
Executable file
Binary file not shown.
67
server/inih/cpp/INIReader.cpp
Executable file
67
server/inih/cpp/INIReader.cpp
Executable 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
48
server/inih/cpp/INIReader.h
Executable 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__
|
||||
20
server/inih/cpp/INIReaderTest.cpp
Executable file
20
server/inih/cpp/INIReaderTest.cpp
Executable 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
BIN
server/inih/examples/._config.def
Executable file
Binary file not shown.
BIN
server/inih/examples/._ini_dump.c
Executable file
BIN
server/inih/examples/._ini_dump.c
Executable file
Binary file not shown.
BIN
server/inih/examples/._ini_example.c
Executable file
BIN
server/inih/examples/._ini_example.c
Executable file
Binary file not shown.
BIN
server/inih/examples/._ini_xmacros.c
Executable file
BIN
server/inih/examples/._ini_xmacros.c
Executable file
Binary file not shown.
BIN
server/inih/examples/._test.ini
Executable file
BIN
server/inih/examples/._test.ini
Executable file
Binary file not shown.
8
server/inih/examples/config.def
Executable file
8
server/inih/examples/config.def
Executable 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
40
server/inih/examples/ini_dump.c
Executable 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;
|
||||
}
|
||||
44
server/inih/examples/ini_example.c
Executable file
44
server/inih/examples/ini_example.c
Executable 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;
|
||||
}
|
||||
46
server/inih/examples/ini_xmacros.c
Executable file
46
server/inih/examples/ini_xmacros.c
Executable 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
9
server/inih/examples/test.ini
Executable 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
|
||||
BIN
server/inih/extra/._Makefile.static
Executable file
BIN
server/inih/extra/._Makefile.static
Executable file
Binary file not shown.
19
server/inih/extra/Makefile.static
Executable file
19
server/inih/extra/Makefile.static
Executable 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
176
server/inih/ini.c
Executable 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
72
server/inih/ini.h
Executable 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__ */
|
||||
BIN
server/inih/tests/._bad_comment.ini
Executable file
BIN
server/inih/tests/._bad_comment.ini
Executable file
Binary file not shown.
BIN
server/inih/tests/._bad_multi.ini
Executable file
BIN
server/inih/tests/._bad_multi.ini
Executable file
Binary file not shown.
BIN
server/inih/tests/._bad_section.ini
Executable file
BIN
server/inih/tests/._bad_section.ini
Executable file
Binary file not shown.
BIN
server/inih/tests/._baseline_multi.txt
Executable file
BIN
server/inih/tests/._baseline_multi.txt
Executable file
Binary file not shown.
BIN
server/inih/tests/._baseline_single.txt
Executable file
BIN
server/inih/tests/._baseline_single.txt
Executable file
Binary file not shown.
BIN
server/inih/tests/._bom.ini
Executable file
BIN
server/inih/tests/._bom.ini
Executable file
Binary file not shown.
BIN
server/inih/tests/._multi_line.ini
Executable file
BIN
server/inih/tests/._multi_line.ini
Executable file
Binary file not shown.
BIN
server/inih/tests/._normal.ini
Executable file
BIN
server/inih/tests/._normal.ini
Executable file
Binary file not shown.
BIN
server/inih/tests/._unittest.bat
Executable file
BIN
server/inih/tests/._unittest.bat
Executable file
Binary file not shown.
BIN
server/inih/tests/._unittest.c
Executable file
BIN
server/inih/tests/._unittest.c
Executable file
Binary file not shown.
BIN
server/inih/tests/._user_error.ini
Executable file
BIN
server/inih/tests/._user_error.ini
Executable file
Binary file not shown.
1
server/inih/tests/bad_comment.ini
Executable file
1
server/inih/tests/bad_comment.ini
Executable file
@ -0,0 +1 @@
|
||||
This is an error
|
||||
1
server/inih/tests/bad_multi.ini
Executable file
1
server/inih/tests/bad_multi.ini
Executable file
@ -0,0 +1 @@
|
||||
indented
|
||||
5
server/inih/tests/bad_section.ini
Executable file
5
server/inih/tests/bad_section.ini
Executable file
@ -0,0 +1,5 @@
|
||||
[section1]
|
||||
name1=value1
|
||||
[section2
|
||||
[section3 ; comment ]
|
||||
name2=value2
|
||||
47
server/inih/tests/baseline_multi.txt
Executable file
47
server/inih/tests/baseline_multi.txt
Executable 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
|
||||
43
server/inih/tests/baseline_single.txt
Executable file
43
server/inih/tests/baseline_single.txt
Executable 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
3
server/inih/tests/bom.ini
Executable file
@ -0,0 +1,3 @@
|
||||
[bom_section]
|
||||
bom_name=bom_value
|
||||
key“ = value“
|
||||
15
server/inih/tests/multi_line.ini
Executable file
15
server/inih/tests/multi_line.ini
Executable 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
25
server/inih/tests/normal.ini
Executable 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
2
server/inih/tests/unittest.bat
Executable 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
Reference in New Issue
Block a user