
The MXS_MODULDE object now contains optinal pointers for functions to be called att process and thread startup and shutdown. Since the functions were added to the end, strictly speaking, all structures would not have needed to have been modified, but better to be explicit. In a subsequent change, these will be called. C++ does not support flexible arrays, so for the time being C++ modules are restricted to 10 parameters. Better approach is to factor out the parameters to a separate array and then just store a pointer to that array in MXS_MODULE.
298 lines
7.2 KiB
C
298 lines
7.2 KiB
C
/*
|
|
* Copyright (c) 2016 MariaDB Corporation Ab
|
|
*
|
|
* Use of this software is governed by the Business Source License included
|
|
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
|
*
|
|
* Change Date: 2019-07-01
|
|
*
|
|
* On the date above, in accordance with the Business Source License, use
|
|
* of this software will be governed by version 2 or later of the General
|
|
* Public License.
|
|
*/
|
|
|
|
/**
|
|
* @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 <maxscale/service.h>
|
|
#include <maxscale/session.h>
|
|
#include <maxscale/router.h>
|
|
#include <maxscale/modules.h>
|
|
#include <maxscale/modinfo.h>
|
|
#include <maxscale/atomic.h>
|
|
#include <maxscale/spinlock.h>
|
|
#include <maxscale/dcb.h>
|
|
#include <maxscale/alloc.h>
|
|
#include <maxscale/poll.h>
|
|
#include <debugcli.h>
|
|
#include <maxscale/log_manager.h>
|
|
|
|
/* The router entry points */
|
|
static ROUTER *createInstance(SERVICE *service, char **options);
|
|
static void *newSession(ROUTER *instance, SESSION *session);
|
|
static void closeSession(ROUTER *instance, void *router_session);
|
|
static void freeSession(ROUTER *instance, void *router_session);
|
|
static int execute(ROUTER *instance, void *router_session, GWBUF *queue);
|
|
static void diagnostics(ROUTER *instance, DCB *dcb);
|
|
static uint64_t getCapabilities ();
|
|
|
|
extern int execute_cmd(CLI_SESSION *cli);
|
|
|
|
static SPINLOCK instlock;
|
|
static CLI_INSTANCE *instances;
|
|
|
|
/**
|
|
* 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
|
|
*/
|
|
MXS_MODULE* MXS_CREATE_MODULE()
|
|
{
|
|
MXS_NOTICE("Initialise debug CLI router module.");
|
|
spinlock_init(&instlock);
|
|
instances = NULL;
|
|
|
|
static ROUTER_OBJECT MyObject =
|
|
{
|
|
createInstance,
|
|
newSession,
|
|
closeSession,
|
|
freeSession,
|
|
execute,
|
|
diagnostics,
|
|
NULL,
|
|
NULL,
|
|
getCapabilities,
|
|
NULL
|
|
};
|
|
|
|
static MXS_MODULE info =
|
|
{
|
|
MXS_MODULE_API_ROUTER,
|
|
MXS_MODULE_GA,
|
|
ROUTER_VERSION,
|
|
"The debug user interface",
|
|
"V1.1.1",
|
|
&MyObject,
|
|
NULL, /* Process init. */
|
|
NULL, /* Process finish. */
|
|
NULL, /* Thread init. */
|
|
NULL, /* Thread finish. */
|
|
{
|
|
{MXS_END_MODULE_PARAMS}
|
|
}
|
|
};
|
|
|
|
return &info;
|
|
}
|
|
|
|
/**
|
|
* Create an instance of the router for a particular service
|
|
* within the gateway.
|
|
*
|
|
* @param service The service this router is being create for
|
|
* @param options Any array of options for the query router
|
|
*
|
|
* @return The instance data for this new instance
|
|
*/
|
|
static ROUTER *
|
|
createInstance(SERVICE *service, char **options)
|
|
{
|
|
CLI_INSTANCE *inst;
|
|
int i;
|
|
|
|
if ((inst = MXS_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 *)MXS_MALLOC(sizeof(CLI_SESSION))) == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
client->session = session;
|
|
|
|
memset(client->cmdbuf, 0, 80);
|
|
|
|
spinlock_acquire(&inst->lock);
|
|
client->next = inst->sessions;
|
|
inst->sessions = client;
|
|
spinlock_release(&inst->lock);
|
|
|
|
session->state = SESSION_STATE_READY;
|
|
|
|
dcb_printf(session->client_dcb, "Welcome to the MariaDB Corporation MaxScale Debug Interface.\n");
|
|
dcb_printf(session->client_dcb, "Type help for a list of available commands.\n\n");
|
|
|
|
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;
|
|
|
|
|
|
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);
|
|
/**
|
|
* Router session is freed in session.c:session_close, when session who
|
|
* owns it, is freed.
|
|
*/
|
|
}
|
|
|
|
/**
|
|
* Free a debugcli session
|
|
*
|
|
* @param router_instance The router session
|
|
* @param router_client_session The router session as returned from newSession
|
|
*/
|
|
static void freeSession(
|
|
ROUTER* router_instance,
|
|
void* router_client_session)
|
|
{
|
|
MXS_FREE(router_client_session);
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
|
|
|
|
char *cmdbuf = session->cmdbuf;
|
|
int cmdlen = 0;
|
|
|
|
*cmdbuf = 0;
|
|
|
|
/* Extract the characters */
|
|
while (queue && (cmdlen < CMDBUFLEN - 1))
|
|
{
|
|
const char* data = (char*)GWBUF_DATA(queue);
|
|
int len = GWBUF_LENGTH(queue);
|
|
int n = MXS_MIN(len, CMDBUFLEN - cmdlen - 1);
|
|
|
|
if (n != len)
|
|
{
|
|
MXS_WARNING("Too long user command truncated.");
|
|
}
|
|
|
|
strncat(cmdbuf, data, n);
|
|
|
|
cmdlen += n;
|
|
cmdbuf += n;
|
|
|
|
queue = gwbuf_consume(queue, GWBUF_LENGTH(queue));
|
|
}
|
|
|
|
if (strrchr(session->cmdbuf, '\n'))
|
|
{
|
|
if (execute_cmd(session))
|
|
{
|
|
dcb_printf(session->session->client_dcb, "MaxScale> ");
|
|
}
|
|
else
|
|
{
|
|
dcb_close(session->session->client_dcb);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Display router diagnostics
|
|
*
|
|
* @param instance Instance of the router
|
|
* @param dcb DCB to send diagnostics to
|
|
*/
|
|
static void
|
|
diagnostics(ROUTER *instance, DCB *dcb)
|
|
{
|
|
return; /* Nothing to do currently */
|
|
}
|
|
|
|
static uint64_t getCapabilities(void)
|
|
{
|
|
return 0;
|
|
}
|