A number of updates to do with service startup
Telnet protocol support Debug cli
This commit is contained in:
31
README
31
README
@ -22,4 +22,35 @@ function pointers. This structured is called the "module object".
|
|||||||
|
|
||||||
The code that routes the queries to the database servers is also loaed
|
The code that routes the queries to the database servers is also loaed
|
||||||
as external shared objects and are referred to as routing modules.
|
as external shared objects and are referred to as routing modules.
|
||||||
|
|
||||||
|
\section Building Building the Gateway
|
||||||
|
|
||||||
|
The gateway is designed to be built using make. Simply run the make command
|
||||||
|
from the top level and it will build all the components ofthe system.
|
||||||
|
|
||||||
|
Other make targets are available
|
||||||
|
|
||||||
|
install - Installs the binary and the modules in the location defined by the
|
||||||
|
make variable DEST
|
||||||
|
|
||||||
|
ctags - Build tags files for the vi editor
|
||||||
|
|
||||||
|
documentation - Build the doxygen documentation
|
||||||
|
|
||||||
|
depend - Update the dependencies used by the makefiles
|
||||||
|
|
||||||
|
\section Running Running the Gateway
|
||||||
|
|
||||||
|
The gateway consists of a core executable and a number of modules that implement
|
||||||
|
the different protocols and routing algorithms. These modules are built as
|
||||||
|
shared objects that are loaded on demand. In order for the gateway to find these
|
||||||
|
modules it will search using a predescribed search path. The rules are:
|
||||||
|
|
||||||
|
1. Look in the current directory for the module
|
||||||
|
|
||||||
|
2. Look in $GATEWAY_HOME/modules
|
||||||
|
|
||||||
|
3. Look in /usr/local/skysql/gateway/modules
|
||||||
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
# 17/06/13 Mark Riddoch Addition of dependency generation
|
# 17/06/13 Mark Riddoch Addition of dependency generation
|
||||||
|
|
||||||
CC=cc
|
CC=cc
|
||||||
CFLAGS=-c -I/usr/include -I../include -Wall
|
CFLAGS=-c -I/usr/include -I../include -Wall -g
|
||||||
LDFLAGS=-rdynamic
|
LDFLAGS=-rdynamic
|
||||||
SRCS= atomic.c buffer.c spinlock.c gateway.c gateway_mysql_protocol.c gw_utils.c \
|
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
|
utils.c dcb.c load_utils.c session.c service.c server.c
|
||||||
|
32
core/dcb.c
32
core/dcb.c
@ -378,6 +378,38 @@ DCB *dcb;
|
|||||||
spinlock_release(dcbspin);
|
spinlock_release(dcbspin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Diagnostic to print all DCB allocated in the system
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void dprintAllDCBs(DCB *pdcb)
|
||||||
|
{
|
||||||
|
DCB *dcb;
|
||||||
|
|
||||||
|
if (dcbspin == NULL)
|
||||||
|
{
|
||||||
|
if ((dcbspin = malloc(sizeof(SPINLOCK))) == NULL)
|
||||||
|
return;
|
||||||
|
spinlock_init(dcbspin);
|
||||||
|
}
|
||||||
|
spinlock_acquire(dcbspin);
|
||||||
|
dcb = allDCBs;
|
||||||
|
while (dcb)
|
||||||
|
{
|
||||||
|
dcb_printf(pdcb, "DCB: 0x%p\n", (void *)dcb);
|
||||||
|
dcb_printf(pdcb, "\tDCB state: %s\n", gw_dcb_state2string(dcb->state));
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a string representation of a DCB state.
|
* Return a string representation of a DCB state.
|
||||||
*
|
*
|
||||||
|
@ -285,7 +285,10 @@ load_utils.o: load_utils.c /usr/include/sys/param.h \
|
|||||||
/usr/include/unistd.h /usr/include/bits/posix_opt.h \
|
/usr/include/unistd.h /usr/include/bits/posix_opt.h \
|
||||||
/usr/include/bits/environments.h /usr/include/bits/confname.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/getopt.h /usr/include/string.h /usr/include/xlocale.h \
|
||||||
/usr/include/dlfcn.h /usr/include/bits/dlfcn.h ../include/modules.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
|
||||||
session.o: session.c /usr/include/stdio.h /usr/include/features.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/sys/cdefs.h /usr/include/bits/wordsize.h \
|
||||||
/usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
|
/usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
|
||||||
@ -347,4 +350,4 @@ server.o: server.c /usr/include/stdio.h /usr/include/features.h \
|
|||||||
/usr/include/string.h /usr/include/xlocale.h ../include/session.h \
|
/usr/include/string.h /usr/include/xlocale.h ../include/session.h \
|
||||||
../include/server.h ../include/spinlock.h ../include/thread.h \
|
../include/server.h ../include/spinlock.h ../include/thread.h \
|
||||||
/usr/include/pthread.h /usr/include/sched.h /usr/include/bits/sched.h \
|
/usr/include/pthread.h /usr/include/sched.h /usr/include/bits/sched.h \
|
||||||
/usr/include/bits/setjmp.h
|
/usr/include/bits/setjmp.h ../include/dcb.h ../include/buffer.h
|
||||||
|
@ -176,7 +176,7 @@ struct epoll_event ev;
|
|||||||
int nfds;
|
int nfds;
|
||||||
int n;
|
int n;
|
||||||
unsigned short port = 4406;
|
unsigned short port = 4406;
|
||||||
SERVICE *service;
|
SERVICE *service1, *service2;
|
||||||
SERVER *server1, *server2, *server3;
|
SERVER *server1, *server2, *server3;
|
||||||
|
|
||||||
for (n = 0; n < argc; n++)
|
for (n = 0; n < argc; n++)
|
||||||
@ -185,6 +185,11 @@ SERVER *server1, *server2, *server3;
|
|||||||
{
|
{
|
||||||
port = atoi(&argv[n][2]);
|
port = atoi(&argv[n][2]);
|
||||||
}
|
}
|
||||||
|
if (strcmp(argv[n], "-d") == 0)
|
||||||
|
{
|
||||||
|
// Debug mode
|
||||||
|
daemon_mode = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -193,16 +198,21 @@ SERVER *server1, *server2, *server3;
|
|||||||
* will build a static configuration here
|
* will build a static configuration here
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((service = service_alloc("Test Service", "readconnroute")) == NULL)
|
if ((service1 = service_alloc("Test Service", "readconnroute")) == NULL)
|
||||||
exit(1);
|
exit(1);
|
||||||
serviceAddProtocol(service, "MySQLClient", port);
|
serviceAddProtocol(service1, "MySQLClient", port);
|
||||||
|
|
||||||
server1 = server_alloc("127.0.0.1", "MySQLBackend", 3306);
|
server1 = server_alloc("127.0.0.1", "MySQLBackend", 3306);
|
||||||
server2 = server_alloc("127.0.0.1", "MySQLBackend", 3307);
|
server2 = server_alloc("127.0.0.1", "MySQLBackend", 3307);
|
||||||
server3 = server_alloc("127.0.0.1", "MySQLBackend", 3308);
|
server3 = server_alloc("127.0.0.1", "MySQLBackend", 3308);
|
||||||
serviceAddBackend(service, server1);
|
serviceAddBackend(service1, server1);
|
||||||
serviceAddBackend(service, server2);
|
serviceAddBackend(service1, server2);
|
||||||
serviceAddBackend(service, server3);
|
serviceAddBackend(service1, server3);
|
||||||
|
|
||||||
|
|
||||||
|
if ((service2 = service_alloc("Debug Service", "debugcli")) == NULL)
|
||||||
|
exit(1);
|
||||||
|
serviceAddProtocol(service2, "telnetd", 4442);
|
||||||
|
|
||||||
fprintf(stderr, "(C) SkySQL Ab 2013\n");
|
fprintf(stderr, "(C) SkySQL Ab 2013\n");
|
||||||
|
|
||||||
@ -246,7 +256,8 @@ SERVER *server1, *server2, *server3;
|
|||||||
/*
|
/*
|
||||||
* Start the service that was created above
|
* Start the service that was created above
|
||||||
*/
|
*/
|
||||||
serviceStart(service, epollfd);
|
serviceStart(service1, epollfd);
|
||||||
|
serviceStart(service2, epollfd);
|
||||||
|
|
||||||
fprintf(stderr, ">> GATEWAY epoll maxevents is %i\n", MAX_EVENTS);
|
fprintf(stderr, ">> GATEWAY epoll maxevents is %i\n", MAX_EVENTS);
|
||||||
|
|
||||||
@ -259,7 +270,7 @@ SERVER *server1, *server2, *server3;
|
|||||||
5. bind
|
5. bind
|
||||||
6. epoll add event
|
6. epoll add event
|
||||||
*/
|
*/
|
||||||
MySQLListener(epollfd, port);
|
// MySQLListener(epollfd, port);
|
||||||
|
|
||||||
// event loop for all the descriptors added via epoll_ctl
|
// event loop for all the descriptors added via epoll_ctl
|
||||||
while (1) {
|
while (1) {
|
||||||
|
@ -246,3 +246,22 @@ MODULES *ptr = registered;
|
|||||||
ptr = ptr->next;
|
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 | %-10s | Version\n", "Module Name", "Module Type");
|
||||||
|
dcb_printf(dcb, "-----------------------------------------------------\n");
|
||||||
|
while (ptr)
|
||||||
|
{
|
||||||
|
dcb_printf(dcb, "%-15s | %-10s | %s\n", ptr->module, ptr->type, ptr->version);
|
||||||
|
ptr = ptr->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include <session.h>
|
#include <session.h>
|
||||||
#include <server.h>
|
#include <server.h>
|
||||||
#include <spinlock.h>
|
#include <spinlock.h>
|
||||||
|
#include <dcb.h>
|
||||||
|
|
||||||
static SPINLOCK server_spin = SPINLOCK_INIT;
|
static SPINLOCK server_spin = SPINLOCK_INIT;
|
||||||
static SERVER *allServers = NULL;
|
static SERVER *allServers = NULL;
|
||||||
@ -139,3 +140,27 @@ SERVER *ptr;
|
|||||||
}
|
}
|
||||||
spinlock_release(&server_spin);
|
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, "\tProtocol: %s\n", ptr->protocol);
|
||||||
|
dcb_printf(dcb, "\tPort: %d\n", ptr->port);
|
||||||
|
ptr = ptr->next;
|
||||||
|
}
|
||||||
|
spinlock_release(&server_spin);
|
||||||
|
}
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include <router.h>
|
#include <router.h>
|
||||||
#include <spinlock.h>
|
#include <spinlock.h>
|
||||||
#include <modules.h>
|
#include <modules.h>
|
||||||
|
#include <dcb.h>
|
||||||
|
|
||||||
static SPINLOCK service_spin = SPINLOCK_INIT;
|
static SPINLOCK service_spin = SPINLOCK_INIT;
|
||||||
static SERVICE *allServices = NULL;
|
static SERVICE *allServices = NULL;
|
||||||
@ -96,6 +97,8 @@ int listeners = 0;
|
|||||||
char config_bind[40];
|
char config_bind[40];
|
||||||
GWPROTOCOL *funcs;
|
GWPROTOCOL *funcs;
|
||||||
|
|
||||||
|
service->router_instance = service->router->createInstance(service);
|
||||||
|
|
||||||
port = service->ports;
|
port = service->ports;
|
||||||
while (port)
|
while (port)
|
||||||
{
|
{
|
||||||
@ -111,15 +114,16 @@ GWPROTOCOL *funcs;
|
|||||||
memcpy(&(port->listener->func), funcs, sizeof(GWPROTOCOL));
|
memcpy(&(port->listener->func), funcs, sizeof(GWPROTOCOL));
|
||||||
port->listener->session = NULL;
|
port->listener->session = NULL;
|
||||||
sprintf(config_bind, "0.0.0.0:%d", port->port);
|
sprintf(config_bind, "0.0.0.0:%d", port->port);
|
||||||
if (port->listener->func.listen(efd, config_bind))
|
if (port->listener->func.listen(port->listener, efd, config_bind))
|
||||||
listeners++;
|
listeners++;
|
||||||
|
port->listener->session = session_alloc(service, port->listener);
|
||||||
|
port->listener->session->state = SESSION_STATE_LISTENER;
|
||||||
|
|
||||||
|
port = port->next;
|
||||||
}
|
}
|
||||||
port->listener->session = session_alloc(service, port->listener);
|
|
||||||
port->listener->session->state = SESSION_STATE_LISTENER;
|
|
||||||
if (listeners)
|
if (listeners)
|
||||||
service->stats.started = time(0);
|
service->stats.started = time(0);
|
||||||
|
|
||||||
service->router_instance = service->router->createInstance(service);
|
|
||||||
return listeners;
|
return listeners;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,3 +251,39 @@ SERVICE *ptr;
|
|||||||
}
|
}
|
||||||
spinlock_release(&service_spin);
|
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);
|
||||||
|
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 %s\n", server->name, server->port,
|
||||||
|
server->protocol);
|
||||||
|
server = server->next;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
@ -146,3 +146,27 @@ SESSION *ptr;
|
|||||||
}
|
}
|
||||||
spinlock_release(&session_spin);
|
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
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
dprintAllSessions(DCB *dcb)
|
||||||
|
{
|
||||||
|
SESSION *ptr;
|
||||||
|
|
||||||
|
spinlock_acquire(&session_spin);
|
||||||
|
ptr = allSessions;
|
||||||
|
while (ptr)
|
||||||
|
{
|
||||||
|
dcb_printf(dcb, "Session %p\n", ptr);
|
||||||
|
dcb_printf(dcb, "\tService: %s (%p)\n", ptr->service->name, ptr->service);
|
||||||
|
dcb_printf(dcb, "\tClient DCB: %p\n", ptr->client);
|
||||||
|
dcb_printf(dcb, "\tConnected: %s", asctime(localtime(&ptr->stats.connect)));
|
||||||
|
ptr = ptr->next;
|
||||||
|
}
|
||||||
|
spinlock_release(&session_spin);
|
||||||
|
}
|
||||||
|
@ -73,7 +73,7 @@ typedef struct gw_protocol {
|
|||||||
int (*accept)(struct dcb *, int);
|
int (*accept)(struct dcb *, int);
|
||||||
int (*connect)(struct server *, struct session *, int);
|
int (*connect)(struct server *, struct session *, int);
|
||||||
int (*close)(struct dcb *, int);
|
int (*close)(struct dcb *, int);
|
||||||
int (*listen)(int, char *);
|
int (*listen)(struct dcb *, int, char *);
|
||||||
} GWPROTOCOL;
|
} GWPROTOCOL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -133,6 +133,7 @@ extern int dcb_write(DCB *, GWBUF *); /* Generic write routine */
|
|||||||
extern int dcb_drain_writeq(DCB *); /* Generic write routine */
|
extern int dcb_drain_writeq(DCB *); /* Generic write routine */
|
||||||
extern void printAllDCBs(); /* Debug to print all DCB in the system */
|
extern void printAllDCBs(); /* Debug to print all DCB in the system */
|
||||||
extern void printDCB(DCB *); /* Debug print routine */
|
extern void printDCB(DCB *); /* Debug print routine */
|
||||||
|
extern void dprintAllDCBs(DCB *); /* Debug to print all DCB in the system */
|
||||||
extern const char *gw_dcb_state2string(int); /* DCB state to string */
|
extern const char *gw_dcb_state2string(int); /* DCB state to string */
|
||||||
extern void dcb_printf(DCB *, const char *, ...); /* DCB version of printf */
|
extern void dcb_printf(DCB *, const char *, ...); /* DCB version of printf */
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright SkySQL Ab 2013
|
* Copyright SkySQL Ab 2013
|
||||||
*/
|
*/
|
||||||
|
#include <dcb.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file modules.h Utilities for loading modules
|
* @file modules.h Utilities for loading modules
|
||||||
@ -51,4 +52,5 @@ typedef struct modules {
|
|||||||
extern void *load_module(const char *module, const char *type);
|
extern void *load_module(const char *module, const char *type);
|
||||||
extern void unload_module(const char *module);
|
extern void unload_module(const char *module);
|
||||||
extern void printModules();
|
extern void printModules();
|
||||||
|
extern void dprintAllModules(DCB *);
|
||||||
#endif
|
#endif
|
||||||
|
@ -59,4 +59,5 @@ extern SERVER *server_alloc(char *, char *, unsigned short);
|
|||||||
extern int server_free(SERVER *);
|
extern int server_free(SERVER *);
|
||||||
extern void printServer(SERVER *);
|
extern void printServer(SERVER *);
|
||||||
extern void printAllServers();
|
extern void printAllServers();
|
||||||
|
extern void dprintAllServers();
|
||||||
#endif
|
#endif
|
||||||
|
@ -98,4 +98,5 @@ extern void serviceAddBackend(SERVICE *, SERVER *);
|
|||||||
extern int serviceStart(SERVICE *, int);
|
extern int serviceStart(SERVICE *, int);
|
||||||
extern void printService(SERVICE *);
|
extern void printService(SERVICE *);
|
||||||
extern void printAllServices();
|
extern void printAllServices();
|
||||||
|
extern void dprintAllServices(DCB *);
|
||||||
#endif
|
#endif
|
||||||
|
@ -70,4 +70,5 @@ extern SESSION *session_alloc(struct service *, struct dcb *);
|
|||||||
extern void session_free(SESSION *);
|
extern void session_free(SESSION *);
|
||||||
extern void printAllSessions();
|
extern void printAllSessions();
|
||||||
extern void printSession(SESSION *);
|
extern void printSession(SESSION *);
|
||||||
|
extern void dprintAllSessions(struct dcb *);
|
||||||
#endif
|
#endif
|
||||||
|
60
modules/include/debugcli.h
Normal file
60
modules/include/debugcli.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#ifndef _DEBUGCLI_H
|
||||||
|
#define _DEBUGCLI_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>
|
||||||
|
#include <session.h>
|
||||||
|
#include <spinlock.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file debugcli.h The debug interface to the gateway
|
||||||
|
*
|
||||||
|
* @verbatim
|
||||||
|
* Revision History
|
||||||
|
*
|
||||||
|
* Date Who Description
|
||||||
|
* 18/06/13 Mark Riddoch Initial implementation
|
||||||
|
*
|
||||||
|
* @endverbatim
|
||||||
|
*/
|
||||||
|
struct cli_session;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The CLI_INSTANCE structure. There is one instane of the CLI "router" for
|
||||||
|
* each service that uses the CLI.
|
||||||
|
*/
|
||||||
|
typedef struct cli_instance {
|
||||||
|
SPINLOCK lock; /**< The instance spinlock */
|
||||||
|
SERVICE *service; /**< The debug cli service */
|
||||||
|
struct cli_session
|
||||||
|
*sessions; /**< Linked list of sessions within this instance */
|
||||||
|
struct cli_instance
|
||||||
|
*next; /**< The next pointer for the list of instances */
|
||||||
|
} CLI_INSTANCE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The CLI_SESSION structure. As CLI_SESSION is created for each user that logs into
|
||||||
|
* the DEBUG CLI.
|
||||||
|
*/
|
||||||
|
typedef struct cli_session {
|
||||||
|
char cmdbuf[80]; /**< The command buffer used to build up user commands */
|
||||||
|
SESSION *session; /**< The gateway session */
|
||||||
|
struct cli_session
|
||||||
|
*next; /**< The next pointer for the list of sessions */
|
||||||
|
} CLI_SESSION;
|
||||||
|
#endif
|
@ -20,16 +20,18 @@
|
|||||||
# 17/06/2013 Massimiliano Pinto Added mysql_common top both libraries
|
# 17/06/2013 Massimiliano Pinto Added mysql_common top both libraries
|
||||||
|
|
||||||
CC=cc
|
CC=cc
|
||||||
CFLAGS=-c -fPIC -I/usr/include -I../include -I../../include
|
CFLAGS=-c -fPIC -I/usr/include -I../include -I../../include -g
|
||||||
LDFLAGS=-shared
|
LDFLAGS=-shared
|
||||||
MYSQLCLIENTSRCS=mysql_client.c mysql_common.c
|
MYSQLCLIENTSRCS=mysql_client.c mysql_common.c
|
||||||
MYSQLCLIENTOBJ=$(MYSQLCLIENTSRCS:.c=.o)
|
MYSQLCLIENTOBJ=$(MYSQLCLIENTSRCS:.c=.o)
|
||||||
MYSQLBACKENDSRCS=mysql_backend.c mysql_common.c
|
MYSQLBACKENDSRCS=mysql_backend.c mysql_common.c
|
||||||
MYSQLBACKENDOBJ=$(MYSQLBACKENDSRCS:.c=.o)
|
MYSQLBACKENDOBJ=$(MYSQLBACKENDSRCS:.c=.o)
|
||||||
|
TELNETDSRCS=telnetd.c
|
||||||
|
TELNETDOBJ=$(TELNETDSRCS:.c=.o)
|
||||||
SRCS=$(MYSQLCLIENTSRCS) $(MYSQLBACKENDSRCS)
|
SRCS=$(MYSQLCLIENTSRCS) $(MYSQLBACKENDSRCS)
|
||||||
OBJ=$(SRCS:.c=.o)
|
OBJ=$(SRCS:.c=.o)
|
||||||
LIBS=
|
LIBS=
|
||||||
MODULES=libMySQLClient.so libMySQLBackend.so
|
MODULES=libMySQLClient.so libMySQLBackend.so libtelnetd.so
|
||||||
|
|
||||||
all: $(MODULES)
|
all: $(MODULES)
|
||||||
|
|
||||||
@ -39,11 +41,14 @@ libMySQLClient.so: $(MYSQLCLIENTOBJ)
|
|||||||
libMySQLBackend.so: $(MYSQLBACKENDOBJ)
|
libMySQLBackend.so: $(MYSQLBACKENDOBJ)
|
||||||
$(CC) $(LDFLAGS) $(MYSQLBACKENDOBJ) $(LIBS) -o $@
|
$(CC) $(LDFLAGS) $(MYSQLBACKENDOBJ) $(LIBS) -o $@
|
||||||
|
|
||||||
|
libtelnetd.so: $(TELNETDOBJ)
|
||||||
|
$(CC) $(LDFLAGS) $(TELNETDOBJ) $(LIBS) -o $@
|
||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
$(CC) $(CFLAGS) $< -o $@
|
$(CC) $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(OBJ) libMySQLClient.so libMySQLBackend.so
|
rm -f $(OBJ) $(MODULES)
|
||||||
|
|
||||||
tags:
|
tags:
|
||||||
ctags $(SRCS) $(HDRS)
|
ctags $(SRCS) $(HDRS)
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
static char *version_str = "V1.0.0";
|
static char *version_str = "V1.0.0";
|
||||||
|
|
||||||
static int gw_MySQLAccept(DCB *listener, int efd);
|
static int gw_MySQLAccept(DCB *listener, int efd);
|
||||||
static int gw_MySQLListener(int epfd, char *config_bind);
|
static int gw_MySQLListener(DCB *listener, int epfd, char *config_bind);
|
||||||
static int gw_read_client_event(DCB* dcb, int epfd);
|
static int gw_read_client_event(DCB* dcb, int epfd);
|
||||||
static int gw_write_client_event(DCB *dcb, int epfd);
|
static int gw_write_client_event(DCB *dcb, int epfd);
|
||||||
static int gw_MySQLWrite_client(DCB *dcb, GWBUF *queue);
|
static int gw_MySQLWrite_client(DCB *dcb, GWBUF *queue);
|
||||||
@ -904,8 +904,7 @@ int gw_write_client_event(DCB *dcb, int epfd) {
|
|||||||
///
|
///
|
||||||
// set listener for mysql protocol
|
// set listener for mysql protocol
|
||||||
///
|
///
|
||||||
int gw_MySQLListener(int epfd, char *config_bind) {
|
int gw_MySQLListener(DCB *listener, int epfd, char *config_bind) {
|
||||||
DCB *listener;
|
|
||||||
int l_so;
|
int l_so;
|
||||||
int fl;
|
int fl;
|
||||||
struct sockaddr_in serv_addr;
|
struct sockaddr_in serv_addr;
|
||||||
@ -921,9 +920,6 @@ int gw_MySQLListener(int epfd, char *config_bind) {
|
|||||||
// this gateway, as default, will bind on port 4404 for localhost only
|
// this gateway, as default, will bind on port 4404 for localhost only
|
||||||
(config_bind != NULL) ? (bind_address_and_port = config_bind) : (bind_address_and_port = "127.0.0.1:4406");
|
(config_bind != NULL) ? (bind_address_and_port = config_bind) : (bind_address_and_port = "127.0.0.1:4406");
|
||||||
|
|
||||||
listener = (DCB *) calloc(1, sizeof(DCB));
|
|
||||||
|
|
||||||
listener->state = DCB_STATE_ALLOC;
|
|
||||||
listener->fd = -1;
|
listener->fd = -1;
|
||||||
|
|
||||||
memset(&serv_addr, 0, sizeof serv_addr);
|
memset(&serv_addr, 0, sizeof serv_addr);
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
* Copyright SkySQL Ab 2013
|
* Copyright SkySQL Ab 2013
|
||||||
*/
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#include <dcb.h>
|
#include <dcb.h>
|
||||||
#include <buffer.h>
|
#include <buffer.h>
|
||||||
#include <service.h>
|
#include <service.h>
|
||||||
@ -26,6 +27,7 @@
|
|||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
#include <router.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file telnetd.c - telnet daemon protocol module
|
* @file telnetd.c - telnet daemon protocol module
|
||||||
@ -56,7 +58,7 @@ static int telnetd_error(DCB *dcb, int event);
|
|||||||
static int telnetd_hangup(DCB *dcb, int event);
|
static int telnetd_hangup(DCB *dcb, int event);
|
||||||
static int telnetd_accept(DCB *dcb, int event);
|
static int telnetd_accept(DCB *dcb, int event);
|
||||||
static int telnetd_close(DCB *dcb, int event);
|
static int telnetd_close(DCB *dcb, int event);
|
||||||
static int telnetd_listen(DCB *dcb, int event);
|
static int telnetd_listen(DCB *dcb, int efd, char *config);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The "module object" for the telnetd protocol module.
|
* The "module object" for the telnetd protocol module.
|
||||||
@ -122,7 +124,7 @@ int n;
|
|||||||
GWBUF *head = NULL;
|
GWBUF *head = NULL;
|
||||||
SESSION *session = dcb->session;
|
SESSION *session = dcb->session;
|
||||||
ROUTER_OBJECT *router = session->service->router;
|
ROUTER_OBJECT *router = session->service->router;
|
||||||
ROUTER *router_instanc = session->service->router_instance;
|
ROUTER *router_instance = session->service->router_instance;
|
||||||
void *rsession = session->router_session;
|
void *rsession = session->router_session;
|
||||||
|
|
||||||
if ((n = dcb_read(dcb, &head)) != -1)
|
if ((n = dcb_read(dcb, &head)) != -1)
|
||||||
@ -143,7 +145,7 @@ void *rsession = session->router_session;
|
|||||||
static int
|
static int
|
||||||
telnetd_write_event(DCB *dcb, int epfd)
|
telnetd_write_event(DCB *dcb, int epfd)
|
||||||
{
|
{
|
||||||
int dcb_drain_writeq(dcb);
|
return dcb_drain_writeq(dcb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -188,10 +190,10 @@ telnetd_hangup(DCB *dcb, int event)
|
|||||||
* socket for the protocol.
|
* socket for the protocol.
|
||||||
*
|
*
|
||||||
* @param dcb The descriptor control block
|
* @param dcb The descriptor control block
|
||||||
* @param event The epoll descriptor
|
* @param efd The epoll descriptor
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
telnetd_accept(DCB *dcb, int event)
|
telnetd_accept(DCB *dcb, int efd)
|
||||||
{
|
{
|
||||||
int n_connect = 0;
|
int n_connect = 0;
|
||||||
|
|
||||||
@ -210,14 +212,14 @@ int n_connect = 0;
|
|||||||
atomic_add(&dcb->stats.n_accepts, 1);
|
atomic_add(&dcb->stats.n_accepts, 1);
|
||||||
client = alloc_dcb();
|
client = alloc_dcb();
|
||||||
client->fd = so;
|
client->fd = so;
|
||||||
memcpy(&client->func, MyObject, sizeof(GWPROTOCOL));
|
memcpy(&client->func, &MyObject, sizeof(GWPROTOCOL));
|
||||||
client->session = session_alloc(listener->service, client);
|
client->session = session_alloc(dcb->session->service, client);
|
||||||
|
|
||||||
ee.events = EPOLLIN | EPOLLOUT | EPOLLET;
|
ee.events = EPOLLIN | EPOLLOUT | EPOLLET;
|
||||||
ee.data.ptr = client;
|
ee.data.ptr = client;
|
||||||
client->state = DCB_STATE_IDLE;
|
client->state = DCB_STATE_IDLE;
|
||||||
|
|
||||||
if (epoll_ctl(efd, EPOLL_CTL_ADD, c_sock, &ee) == -1)
|
if (epoll_ctl(efd, EPOLL_CTL_ADD, so, &ee) == -1)
|
||||||
{
|
{
|
||||||
return n_connect;
|
return n_connect;
|
||||||
}
|
}
|
||||||
@ -249,20 +251,15 @@ telnetd_close(DCB *dcb, int event)
|
|||||||
* @param config Configuration (ip:port)
|
* @param config Configuration (ip:port)
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
telnetd_listen(int efd, char *config)
|
telnetd_listen(DCB *listener, int efd, char *config)
|
||||||
{
|
{
|
||||||
DCB *listener;
|
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
char *port;
|
char *port;
|
||||||
struct epoll_event ev;
|
struct epoll_event ev;
|
||||||
int one;
|
int one = 1;
|
||||||
|
short pnum;
|
||||||
|
|
||||||
if ((listener = dcb_alloc()) == NULL)
|
memcpy(&listener->func, &MyObject, sizeof(GWPROTOCOL));
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(&listener->func, MyObject, sizeof(GWPROTOCOL));
|
|
||||||
|
|
||||||
port = strrchr(config, ':');
|
port = strrchr(config, ':');
|
||||||
if (port)
|
if (port)
|
||||||
@ -272,7 +269,9 @@ int one;
|
|||||||
|
|
||||||
addr.sin_family = AF_INET;
|
addr.sin_family = AF_INET;
|
||||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
addr.sin_port = htons(port);
|
pnum = atoi(port);
|
||||||
|
addr.sin_port = htons(pnum);
|
||||||
|
printf("telnetd listen on port %d from %s from %s\n", pnum, port, config);
|
||||||
|
|
||||||
if ((listener->fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
|
if ((listener->fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
|
||||||
{
|
{
|
||||||
@ -283,8 +282,8 @@ int one;
|
|||||||
setsockopt(listener->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
|
setsockopt(listener->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
|
||||||
// set NONBLOCKING mode
|
// set NONBLOCKING mode
|
||||||
setnonblocking(listener->fd);
|
setnonblocking(listener->fd);
|
||||||
bind address and port
|
// bind address and port
|
||||||
if (bind(listener->fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
|
if (bind(listener->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -294,7 +293,7 @@ int one;
|
|||||||
|
|
||||||
ev.events = EPOLLIN;
|
ev.events = EPOLLIN;
|
||||||
ev.data.ptr = listener;
|
ev.data.ptr = listener;
|
||||||
if (epoll_ctl(epfd, EPOLL_CTL_ADD, l_so, &ev) == -1)
|
if (epoll_ctl(efd, EPOLL_CTL_ADD, listener->fd, &ev) == -1)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -19,16 +19,18 @@
|
|||||||
# 13/06/13 Mark Riddoch Initial routing module development
|
# 13/06/13 Mark Riddoch Initial routing module development
|
||||||
|
|
||||||
CC=cc
|
CC=cc
|
||||||
CFLAGS=-c -fPIC -I/usr/include -I../include -I../../include -Wall
|
CFLAGS=-c -fPIC -I/usr/include -I../include -I../../include -Wall -g
|
||||||
LDFLAGS=-shared
|
LDFLAGS=-shared
|
||||||
TESTSRCS=testroute.c
|
TESTSRCS=testroute.c
|
||||||
TESTOBJ=$(TESTSRCS:.c=.o)
|
TESTOBJ=$(TESTSRCS:.c=.o)
|
||||||
READCONSRCS=readconnroute.c
|
READCONSRCS=readconnroute.c
|
||||||
READCONOBJ=$(READCONSRCS:.c=.o)
|
READCONOBJ=$(READCONSRCS:.c=.o)
|
||||||
|
DEBUGSRCS=debugcli.c
|
||||||
|
DEBUGCLIOBJ=$(DEBUGSRCS:.c=.o)
|
||||||
SRCS=$(TESTSRCS) $(READCONSRCS)
|
SRCS=$(TESTSRCS) $(READCONSRCS)
|
||||||
OBJ=$(SRCS:.c=.o)
|
OBJ=$(SRCS:.c=.o)
|
||||||
LIBS=-lssl
|
LIBS=-lssl
|
||||||
MODULES=libtestroute.so libreadconnroute.so
|
MODULES=libtestroute.so libreadconnroute.so libdebugcli.so
|
||||||
|
|
||||||
all: $(MODULES)
|
all: $(MODULES)
|
||||||
|
|
||||||
@ -38,11 +40,14 @@ libtestroute.so: $(TESTOBJ)
|
|||||||
libreadconnroute.so: $(READCONOBJ)
|
libreadconnroute.so: $(READCONOBJ)
|
||||||
$(CC) $(LDFLAGS) $(READCONOBJ) $(LIBS) -o $@
|
$(CC) $(LDFLAGS) $(READCONOBJ) $(LIBS) -o $@
|
||||||
|
|
||||||
|
libdebugcli.so: $(DEBUGCLIOBJ)
|
||||||
|
$(CC) $(LDFLAGS) $(DEBUGCLIOBJ) $(LIBS) -o $@
|
||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
$(CC) $(CFLAGS) $< -o $@
|
$(CC) $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(OBJ) libtestroute.so
|
rm -f $(OBJ) $(MODULES)
|
||||||
|
|
||||||
tags:
|
tags:
|
||||||
ctags $(SRCS) $(HDRS)
|
ctags $(SRCS) $(HDRS)
|
||||||
|
272
modules/routing/debugcli.c
Normal file
272
modules/routing/debugcli.c
Normal file
@ -0,0 +1,272 @@
|
|||||||
|
/*
|
||||||
|
* 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 debugcli.c - A "routing module" that in fact merely gives
|
||||||
|
* access to debug commands 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 <service.h>
|
||||||
|
#include <session.h>
|
||||||
|
#include <router.h>
|
||||||
|
#include <modules.h>
|
||||||
|
#include <atomic.h>
|
||||||
|
#include <spinlock.h>
|
||||||
|
#include <dcb.h>
|
||||||
|
#include <debugcli.h>
|
||||||
|
|
||||||
|
static char *version_str = "V1.0.0";
|
||||||
|
|
||||||
|
/* The router entry points */
|
||||||
|
static ROUTER *createInstance(SERVICE *service);
|
||||||
|
static void *newSession(ROUTER *instance, SESSION *session);
|
||||||
|
static void closeSession(ROUTER *instance, void *router_session);
|
||||||
|
static int execute(ROUTER *instance, void *router_session, GWBUF *queue);
|
||||||
|
|
||||||
|
/** The module object definition */
|
||||||
|
static ROUTER_OBJECT MyObject = { createInstance, newSession, closeSession, execute };
|
||||||
|
|
||||||
|
static void execute_cmd(CLI_SESSION *cli);
|
||||||
|
|
||||||
|
static SPINLOCK instlock;
|
||||||
|
static CLI_INSTANCE *instances;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of the mandatory version entry point
|
||||||
|
*
|
||||||
|
* @return version string of the module
|
||||||
|
*/
|
||||||
|
char *
|
||||||
|
version()
|
||||||
|
{
|
||||||
|
return version_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The module initialisation routine, called when the module
|
||||||
|
* is first loaded.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ModuleInit()
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Initial debug router module.\n");
|
||||||
|
spinlock_init(&instlock);
|
||||||
|
instances = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The module entry point routine. It is this routine that
|
||||||
|
* must populate the structure that is referred to as the
|
||||||
|
* "module object", this is a structure with the set of
|
||||||
|
* external entry points for this module.
|
||||||
|
*
|
||||||
|
* @return The module object
|
||||||
|
*/
|
||||||
|
ROUTER_OBJECT *
|
||||||
|
GetModuleObject()
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Returing debug router module object.\n");
|
||||||
|
return &MyObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an instance of the router for a particular service
|
||||||
|
* within the gateway.
|
||||||
|
*
|
||||||
|
* @param service The service this router is being create for
|
||||||
|
*
|
||||||
|
* @return The instance data for this new instance
|
||||||
|
*/
|
||||||
|
static ROUTER *
|
||||||
|
createInstance(SERVICE *service)
|
||||||
|
{
|
||||||
|
CLI_INSTANCE *inst;
|
||||||
|
|
||||||
|
if ((inst = malloc(sizeof(CLI_INSTANCE))) == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
inst->service = service;
|
||||||
|
spinlock_init(&inst->lock);
|
||||||
|
inst->sessions = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We have completed the creation of the instance data, so now
|
||||||
|
* insert this router instance into the linked list of routers
|
||||||
|
* that have been created with this module.
|
||||||
|
*/
|
||||||
|
spinlock_acquire(&instlock);
|
||||||
|
inst->next = instances;
|
||||||
|
instances = inst;
|
||||||
|
spinlock_release(&instlock);
|
||||||
|
|
||||||
|
return (ROUTER *)inst;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Associate a new session with this instance of the router.
|
||||||
|
*
|
||||||
|
* @param instance The router instance data
|
||||||
|
* @param session The session itself
|
||||||
|
* @return Session specific data for this session
|
||||||
|
*/
|
||||||
|
static void *
|
||||||
|
newSession(ROUTER *instance, SESSION *session)
|
||||||
|
{
|
||||||
|
CLI_INSTANCE *inst = (CLI_INSTANCE *)instance;
|
||||||
|
CLI_SESSION *client;
|
||||||
|
|
||||||
|
if ((client = (CLI_SESSION *)malloc(sizeof(CLI_SESSION))) == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
client->session = session;
|
||||||
|
|
||||||
|
memset(client->cmdbuf, 80, 0);
|
||||||
|
|
||||||
|
spinlock_acquire(&inst->lock);
|
||||||
|
client->next = inst->sessions;
|
||||||
|
inst->sessions = client;
|
||||||
|
spinlock_release(&inst->lock);
|
||||||
|
return (void *)client;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close a session with the router, this is the mechanism
|
||||||
|
* by which a router may cleanup data structure etc.
|
||||||
|
*
|
||||||
|
* @param instance The router instance data
|
||||||
|
* @param router_session The session being closed
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
closeSession(ROUTER *instance, void *router_session)
|
||||||
|
{
|
||||||
|
CLI_INSTANCE *inst = (CLI_INSTANCE *)instance;
|
||||||
|
CLI_SESSION *session = (CLI_SESSION *)router_session;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Close the connection to the backend
|
||||||
|
*/
|
||||||
|
session->session->client->func.close(session->session->client, 0);
|
||||||
|
|
||||||
|
spinlock_acquire(&inst->lock);
|
||||||
|
if (inst->sessions == session)
|
||||||
|
inst->sessions = session->next;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CLI_SESSION *ptr = inst->sessions;
|
||||||
|
while (ptr && ptr->next != session)
|
||||||
|
ptr = ptr->next;
|
||||||
|
if (ptr)
|
||||||
|
ptr->next = session->next;
|
||||||
|
}
|
||||||
|
spinlock_release(&inst->lock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We are no longer in the linked list, free
|
||||||
|
* all the memory and other resources associated
|
||||||
|
* to the client session.
|
||||||
|
*/
|
||||||
|
free(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We have data from the client, we must route it to the backend.
|
||||||
|
* This is simply a case of sending it to the connection that was
|
||||||
|
* chosen when we started the client session.
|
||||||
|
*
|
||||||
|
* @param instance The router instance
|
||||||
|
* @param router_session The router session returned from the newSession call
|
||||||
|
* @param queue The queue of data buffers to route
|
||||||
|
* @return The number of bytes sent
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
execute(ROUTER *instance, void *router_session, GWBUF *queue)
|
||||||
|
{
|
||||||
|
CLI_SESSION *session = (CLI_SESSION *)router_session;
|
||||||
|
|
||||||
|
/* Extract the characters */
|
||||||
|
strncat(session->cmdbuf, GWBUF_DATA(queue), GWBUF_LENGTH(queue));
|
||||||
|
/* Echo back to the user */
|
||||||
|
dcb_write(session->session->client, queue);
|
||||||
|
|
||||||
|
if (strrchr(session->cmdbuf, '\n'))
|
||||||
|
{
|
||||||
|
execute_cmd(session);
|
||||||
|
dcb_printf(session->session->client, "Gateway> ");
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
char *cmd;
|
||||||
|
void (*fn)(DCB *);
|
||||||
|
} cmds[] = {
|
||||||
|
{ "show sessions", dprintAllSessions },
|
||||||
|
{ "show services", dprintAllServices },
|
||||||
|
{ "show servers", dprintAllServers },
|
||||||
|
{ "show modules", dprintAllModules },
|
||||||
|
{ "show dcbs", dprintAllDCBs },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We have a complete line from the user, lookup the commands and execute them
|
||||||
|
*
|
||||||
|
* @param cli The CLI_SESSION
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
execute_cmd(CLI_SESSION *cli)
|
||||||
|
{
|
||||||
|
int i, found = 0;
|
||||||
|
|
||||||
|
if (!strncmp(cli->cmdbuf, "help", 4))
|
||||||
|
{
|
||||||
|
dcb_printf(cli->session->client, "Available commands:\n");
|
||||||
|
for (i = 0; cmds[i].cmd; i++)
|
||||||
|
{
|
||||||
|
dcb_printf(cli->session->client, " %s\n", cmds[i].cmd);
|
||||||
|
}
|
||||||
|
found = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i = 0; cmds[i].cmd; i++)
|
||||||
|
{
|
||||||
|
if (strncmp(cli->cmdbuf, cmds[i].cmd, strlen(cmds[i].cmd)) == 0)
|
||||||
|
{
|
||||||
|
cmds[i].fn(cli->session->client);
|
||||||
|
found = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found)
|
||||||
|
dcb_printf(cli->session->client,
|
||||||
|
"Command not known, type help for a list of available commands\n");
|
||||||
|
memset(cli->cmdbuf, 80, 0);
|
||||||
|
}
|
@ -130,7 +130,7 @@ int i, n;
|
|||||||
for (server = service->databases, n = 0; server; server = server->nextdb)
|
for (server = service->databases, n = 0; server; server = server->nextdb)
|
||||||
n++;
|
n++;
|
||||||
|
|
||||||
inst->servers = (BACKEND **)calloc(n, sizeof(BACKEND *));
|
inst->servers = (BACKEND **)calloc(n + 1, sizeof(BACKEND *));
|
||||||
if (!inst->servers)
|
if (!inst->servers)
|
||||||
{
|
{
|
||||||
free(inst);
|
free(inst);
|
||||||
@ -153,6 +153,7 @@ int i, n;
|
|||||||
inst->servers[n]->count = 0;
|
inst->servers[n]->count = 0;
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
|
inst->servers[n] = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have completed the creation of the instance data, so now
|
* We have completed the creation of the instance data, so now
|
||||||
@ -194,7 +195,7 @@ int i;
|
|||||||
candidate = inst->servers[0];
|
candidate = inst->servers[0];
|
||||||
for (i = 1; inst->servers[i]; i++);
|
for (i = 1; inst->servers[i]; i++);
|
||||||
{
|
{
|
||||||
if (inst->servers[i]->count < candidate->count)
|
if (inst->servers[i] && inst->servers[i]->count < candidate->count)
|
||||||
candidate = inst->servers[i];
|
candidate = inst->servers[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user