merge from branch 'cenh'
merge from branch ‘cenh’
This commit is contained in:
43
README
43
README
@ -174,4 +174,47 @@ home directory.
|
|||||||
|
|
||||||
The -f flag can be used to set the name and the location of the configuration
|
The -f flag can be used to set the name and the location of the configuration
|
||||||
file. Without path expression the file is read from $MAXSCALE_HOME/etc directory.
|
file. Without path expression the file is read from $MAXSCALE_HOME/etc directory.
|
||||||
|
|
||||||
|
\section Testing Running MaxScale testsuite
|
||||||
|
|
||||||
|
To run "make testall" you need to have three mysqld servers running
|
||||||
|
on localhost:
|
||||||
|
|
||||||
|
* a master on port 3000, with server_id=2
|
||||||
|
* a slave on port 3001, server_id doesn't matter
|
||||||
|
* a slave on port 2002, server_id doesn't matter
|
||||||
|
|
||||||
|
On the master full privileges on the databases "test" and "FOO"
|
||||||
|
are needed, on the saves SELECT permissions on test.* should
|
||||||
|
be sufficient.
|
||||||
|
|
||||||
|
You can use different port numbers but you'll have to change
|
||||||
|
the server settings at the end of server/test/MaxScale_test.cnf then.
|
||||||
|
|
||||||
|
You also always need to edit the top level test.inc file,
|
||||||
|
this file contains appropriate default values for the
|
||||||
|
test setup as described above, these are only given as
|
||||||
|
comments though ...
|
||||||
|
|
||||||
|
You can then run the full testsuite using
|
||||||
|
|
||||||
|
make testall
|
||||||
|
|
||||||
|
in the top level directory. After testing has finished you
|
||||||
|
can find a full testlog in test/test_maxscale.log
|
||||||
|
|
||||||
|
You may also find additional information in the following
|
||||||
|
component specific logs:
|
||||||
|
|
||||||
|
utils/test/testutils.log
|
||||||
|
query_classifier/test/testqclass.log
|
||||||
|
server/test/MaxScale/log/skygw_msg1.log
|
||||||
|
server/test/MaxScale/log/skygw_err1.log
|
||||||
|
server/test/MaxScale/log/skygw_trace1.log
|
||||||
|
server/test/MaxScale/log/skygw_debug1.log
|
||||||
|
server/test/testserver.log
|
||||||
|
server/core/test/testhash.log
|
||||||
|
test/test_maxscale.log
|
||||||
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
@ -25,10 +25,10 @@ MaxScale
|
|||||||
|
|
||||||
%build
|
%build
|
||||||
ln -s /lib64/libaio.so.1 /lib64/libaio.so
|
ln -s /lib64/libaio.so.1 /lib64/libaio.so
|
||||||
make ROOT_PATH=`pwd` HOME="" clean
|
make ROOT_PATH=`pwd` HOME="" $DEBUG_FLAG1 $DEBUG_FLAG2 clean
|
||||||
make ROOT_PATH=`pwd` HOME="" depend
|
make ROOT_PATH=`pwd` HOME="" $DEBUG_FLAG1 $DEBUG_FLAG2 depend
|
||||||
make ROOT_PATH=`pwd` HOME=""
|
make ROOT_PATH=`pwd` HOME="" $DEBUG_FLAG1 $DEBUG_FLAG2
|
||||||
make DEST=`pwd`/binaries ROOT_PATH=`pwd` HOME="" ERRMSG="/usr/share/mysql/english" install
|
make DEST=`pwd`/binaries ROOT_PATH=`pwd` HOME="" ERRMSG="/usr/share/mysql/english" $DEBUG_FLAG1 $DEBUG_FLAG2 install
|
||||||
|
|
||||||
%post
|
%post
|
||||||
ln -s /lib64/libaio.so.1 /lib64/libaio.so
|
ln -s /lib64/libaio.so.1 /lib64/libaio.so
|
||||||
|
@ -29,7 +29,8 @@
|
|||||||
* 06/02/14 Massimiliano Pinto Added support for enable/disable root user in services
|
* 06/02/14 Massimiliano Pinto Added support for enable/disable root user in services
|
||||||
* 14/02/14 Massimiliano Pinto Added enable_root_user in the service_params list
|
* 14/02/14 Massimiliano Pinto Added enable_root_user in the service_params list
|
||||||
* 11/03/14 Massimiliano Pinto Added Unix socket support
|
* 11/03/14 Massimiliano Pinto Added Unix socket support
|
||||||
* 11/05/14 Massimiliano Pinto Added version_string support to service
|
* 11/05/14 Massimiliano Pinto Added version_string support to service
|
||||||
|
* 19/05/14 Mark Riddoch Added unique names from section headers
|
||||||
*
|
*
|
||||||
* @endverbatim
|
* @endverbatim
|
||||||
*/
|
*/
|
||||||
@ -129,7 +130,6 @@ int rval;
|
|||||||
if (ptr) {
|
if (ptr) {
|
||||||
*ptr = '\0';
|
*ptr = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
mysql_close(conn);
|
mysql_close(conn);
|
||||||
}
|
}
|
||||||
@ -226,7 +226,7 @@ int error_count = 0;
|
|||||||
config_get_value(obj->parameters, "passwd");
|
config_get_value(obj->parameters, "passwd");
|
||||||
char *enable_root_user =
|
char *enable_root_user =
|
||||||
config_get_value(obj->parameters, "enable_root_user");
|
config_get_value(obj->parameters, "enable_root_user");
|
||||||
|
|
||||||
char *version_string = config_get_value(obj->parameters, "version_string");
|
char *version_string = config_get_value(obj->parameters, "version_string");
|
||||||
|
|
||||||
if (obj->element == NULL) /*< if module load failed */
|
if (obj->element == NULL) /*< if module load failed */
|
||||||
@ -241,7 +241,7 @@ int error_count = 0;
|
|||||||
obj = obj->next;
|
obj = obj->next;
|
||||||
continue; /*< process next obj */
|
continue; /*< process next obj */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version_string) {
|
if (version_string) {
|
||||||
((SERVICE *)(obj->element))->version_string = strdup(version_string);
|
((SERVICE *)(obj->element))->version_string = strdup(version_string);
|
||||||
} else {
|
} else {
|
||||||
@ -333,6 +333,7 @@ int error_count = 0;
|
|||||||
obj->element = server_alloc(address,
|
obj->element = server_alloc(address,
|
||||||
protocol,
|
protocol,
|
||||||
atoi(port));
|
atoi(port));
|
||||||
|
server_set_unique_name(obj->element, obj->object);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -183,6 +183,8 @@ getUsers(SERVICE *service, struct users *users)
|
|||||||
}
|
}
|
||||||
|
|
||||||
serviceGetUser(service, &service_user, &service_passwd);
|
serviceGetUser(service, &service_user, &service_passwd);
|
||||||
|
if (service_user == NULL || service_passwd == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
/** multi-thread environment requires that thread init succeeds. */
|
/** multi-thread environment requires that thread init succeeds. */
|
||||||
if (mysql_thread_init()) {
|
if (mysql_thread_init()) {
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
* error and 0 bytes to read.
|
* error and 0 bytes to read.
|
||||||
* This fixes a bug with many reads from
|
* This fixes a bug with many reads from
|
||||||
* backend
|
* backend
|
||||||
|
* 07/05/2014 Mark Riddoch Addition of callback mechanism
|
||||||
*
|
*
|
||||||
* @endverbatim
|
* @endverbatim
|
||||||
*/
|
*/
|
||||||
@ -80,6 +81,7 @@ static bool dcb_set_state_nomutex(
|
|||||||
DCB* dcb,
|
DCB* dcb,
|
||||||
const dcb_state_t new_state,
|
const dcb_state_t new_state,
|
||||||
dcb_state_t* old_state);
|
dcb_state_t* old_state);
|
||||||
|
static void dcb_call_callback(DCB *dcb, DCB_REASON reason);
|
||||||
|
|
||||||
DCB* dcb_get_zombies(void)
|
DCB* dcb_get_zombies(void)
|
||||||
{
|
{
|
||||||
@ -94,8 +96,8 @@ DCB* dcb_get_zombies(void)
|
|||||||
*
|
*
|
||||||
* @return A newly allocated DCB or NULL if non could be allocated.
|
* @return A newly allocated DCB or NULL if non could be allocated.
|
||||||
*/
|
*/
|
||||||
DCB * dcb_alloc(
|
DCB *
|
||||||
dcb_role_t role)
|
dcb_alloc(dcb_role_t role)
|
||||||
{
|
{
|
||||||
DCB *rval;
|
DCB *rval;
|
||||||
|
|
||||||
@ -118,11 +120,16 @@ DCB *rval;
|
|||||||
spinlock_init(&rval->writeqlock);
|
spinlock_init(&rval->writeqlock);
|
||||||
spinlock_init(&rval->delayqlock);
|
spinlock_init(&rval->delayqlock);
|
||||||
spinlock_init(&rval->authlock);
|
spinlock_init(&rval->authlock);
|
||||||
|
spinlock_init(&rval->cb_lock);
|
||||||
rval->fd = -1;
|
rval->fd = -1;
|
||||||
memset(&rval->stats, 0, sizeof(DCBSTATS)); // Zero the statistics
|
memset(&rval->stats, 0, sizeof(DCBSTATS)); // Zero the statistics
|
||||||
rval->state = DCB_STATE_ALLOC;
|
rval->state = DCB_STATE_ALLOC;
|
||||||
bitmask_init(&rval->memdata.bitmask);
|
bitmask_init(&rval->memdata.bitmask);
|
||||||
|
rval->writeqlen = 0;
|
||||||
|
rval->high_water = 0;
|
||||||
|
rval->low_water = 0;
|
||||||
rval->next = NULL;
|
rval->next = NULL;
|
||||||
|
rval->callbacks = NULL;
|
||||||
|
|
||||||
spinlock_acquire(&dcbspin);
|
spinlock_acquire(&dcbspin);
|
||||||
if (allDCBs == NULL)
|
if (allDCBs == NULL)
|
||||||
@ -248,6 +255,8 @@ dcb_add_to_zombieslist(DCB *dcb)
|
|||||||
static void
|
static void
|
||||||
dcb_final_free(DCB *dcb)
|
dcb_final_free(DCB *dcb)
|
||||||
{
|
{
|
||||||
|
DCB_CALLBACK *cb;
|
||||||
|
|
||||||
CHK_DCB(dcb);
|
CHK_DCB(dcb);
|
||||||
ss_info_dassert(dcb->state == DCB_STATE_DISCONNECTED,
|
ss_info_dassert(dcb->state == DCB_STATE_DISCONNECTED,
|
||||||
"dcb not in DCB_STATE_DISCONNECTED state.");
|
"dcb not in DCB_STATE_DISCONNECTED state.");
|
||||||
@ -307,6 +316,19 @@ dcb_final_free(DCB *dcb)
|
|||||||
GWBUF *queue = dcb->delayq;
|
GWBUF *queue = dcb->delayq;
|
||||||
while ((queue = gwbuf_consume(queue, GWBUF_LENGTH(queue))) != NULL);
|
while ((queue = gwbuf_consume(queue, GWBUF_LENGTH(queue))) != NULL);
|
||||||
}
|
}
|
||||||
|
if (dcb->dcb_readqueue)
|
||||||
|
{
|
||||||
|
GWBUF* queue = dcb->dcb_readqueue;
|
||||||
|
while ((queue = gwbuf_consume(queue, GWBUF_LENGTH(queue))) != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
spinlock_acquire(&dcb->cb_lock);
|
||||||
|
while ((cb = dcb->callbacks) != NULL)
|
||||||
|
{
|
||||||
|
dcb->callbacks = cb->next;
|
||||||
|
free(cb);
|
||||||
|
}
|
||||||
|
spinlock_release(&dcb->cb_lock);
|
||||||
|
|
||||||
if (dcb->dcb_readqueue)
|
if (dcb->dcb_readqueue)
|
||||||
{
|
{
|
||||||
@ -688,9 +710,11 @@ return_n:
|
|||||||
int
|
int
|
||||||
dcb_write(DCB *dcb, GWBUF *queue)
|
dcb_write(DCB *dcb, GWBUF *queue)
|
||||||
{
|
{
|
||||||
int w;
|
int w, qlen;
|
||||||
int saved_errno = 0;
|
int saved_errno = 0;
|
||||||
|
int below_water;
|
||||||
|
|
||||||
|
below_water = (dcb->high_water && dcb->writeqlen < dcb->high_water) ? 1 : 0;
|
||||||
ss_dassert(queue != NULL);
|
ss_dassert(queue != NULL);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -734,6 +758,8 @@ dcb_write(DCB *dcb, GWBUF *queue)
|
|||||||
* the routine that drains the queue data, so we should
|
* the routine that drains the queue data, so we should
|
||||||
* not have a race condition on the event.
|
* not have a race condition on the event.
|
||||||
*/
|
*/
|
||||||
|
qlen = gwbuf_length(queue);
|
||||||
|
atomic_add(&dcb->writeqlen, qlen);
|
||||||
dcb->writeq = gwbuf_append(dcb->writeq, queue);
|
dcb->writeq = gwbuf_append(dcb->writeq, queue);
|
||||||
dcb->stats.n_buffered++;
|
dcb->stats.n_buffered++;
|
||||||
LOGIF(LD, (skygw_log_write(
|
LOGIF(LD, (skygw_log_write(
|
||||||
@ -846,6 +872,8 @@ dcb_write(DCB *dcb, GWBUF *queue)
|
|||||||
* for suspended write.
|
* for suspended write.
|
||||||
*/
|
*/
|
||||||
dcb->writeq = queue;
|
dcb->writeq = queue;
|
||||||
|
qlen = gwbuf_length(queue);
|
||||||
|
atomic_add(&dcb->writeqlen, qlen);
|
||||||
|
|
||||||
if (queue != NULL)
|
if (queue != NULL)
|
||||||
{
|
{
|
||||||
@ -869,6 +897,13 @@ dcb_write(DCB *dcb, GWBUF *queue)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
spinlock_release(&dcb->writeqlock);
|
spinlock_release(&dcb->writeqlock);
|
||||||
|
|
||||||
|
if (dcb->high_water && dcb->writeqlen > dcb->high_water && below_water)
|
||||||
|
{
|
||||||
|
atomic_add(&dcb->stats.n_high_water, 1);
|
||||||
|
dcb_call_callback(dcb, DCB_REASON_HIGH_WATER);
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -883,9 +918,12 @@ dcb_write(DCB *dcb, GWBUF *queue)
|
|||||||
int
|
int
|
||||||
dcb_drain_writeq(DCB *dcb)
|
dcb_drain_writeq(DCB *dcb)
|
||||||
{
|
{
|
||||||
int n = 0;
|
int n = 0;
|
||||||
int w;
|
int w;
|
||||||
int saved_errno = 0;
|
int saved_errno = 0;
|
||||||
|
int above_water;
|
||||||
|
|
||||||
|
above_water = (dcb->low_water && dcb->writeqlen > dcb->low_water) ? 1 : 0;
|
||||||
|
|
||||||
spinlock_acquire(&dcb->writeqlock);
|
spinlock_acquire(&dcb->writeqlock);
|
||||||
if (dcb->writeq)
|
if (dcb->writeq)
|
||||||
@ -946,6 +984,17 @@ int saved_errno = 0;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
spinlock_release(&dcb->writeqlock);
|
spinlock_release(&dcb->writeqlock);
|
||||||
|
atomic_add(&dcb->writeqlen, -n);
|
||||||
|
/* The write queue has drained, potentially need to call a callback function */
|
||||||
|
if (dcb->writeq == NULL)
|
||||||
|
dcb_call_callback(dcb, DCB_REASON_DRAINED);
|
||||||
|
if (above_water && dcb->writeqlen < dcb->low_water)
|
||||||
|
{
|
||||||
|
atomic_add(&dcb->stats.n_low_water, 1);
|
||||||
|
dcb_call_callback(dcb, DCB_REASON_LOW_WATER);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -988,6 +1037,8 @@ dcb_close(DCB *dcb)
|
|||||||
ss_dassert(dcb->state == DCB_STATE_NOPOLLING ||
|
ss_dassert(dcb->state == DCB_STATE_NOPOLLING ||
|
||||||
dcb->state == DCB_STATE_ZOMBIE);
|
dcb->state == DCB_STATE_ZOMBIE);
|
||||||
|
|
||||||
|
dcb_call_callback(dcb, DCB_REASON_CLOSE);
|
||||||
|
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
LOGIF(LD, (skygw_log_write(
|
LOGIF(LD, (skygw_log_write(
|
||||||
LOGFILE_DEBUG,
|
LOGFILE_DEBUG,
|
||||||
@ -1030,6 +1081,8 @@ printDCB(DCB *dcb)
|
|||||||
printf("\t\tNo. of Writes: %d\n", dcb->stats.n_writes);
|
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 Buffered Writes: %d\n", dcb->stats.n_buffered);
|
||||||
printf("\t\tNo. of Accepts: %d\n", dcb->stats.n_accepts);
|
printf("\t\tNo. of Accepts: %d\n", dcb->stats.n_accepts);
|
||||||
|
printf("\t\tNo. of High Water Events: %d\n", dcb->stats.n_high_water);
|
||||||
|
printf("\t\tNo. of Low Water Events: %d\n", dcb->stats.n_low_water);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1076,6 +1129,8 @@ DCB *dcb;
|
|||||||
dcb_printf(pdcb, "\t\tNo. of Writes: %d\n", dcb->stats.n_writes);
|
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 Buffered Writes: %d\n", dcb->stats.n_buffered);
|
||||||
dcb_printf(pdcb, "\t\tNo. of Accepts: %d\n", dcb->stats.n_accepts);
|
dcb_printf(pdcb, "\t\tNo. of Accepts: %d\n", dcb->stats.n_accepts);
|
||||||
|
dcb_printf(pdcb, "\t\tNo. of High Water Events: %d\n", dcb->stats.n_high_water);
|
||||||
|
dcb_printf(pdcb, "\t\tNo. of Low Water Events: %d\n", dcb->stats.n_low_water);
|
||||||
dcb = dcb->next;
|
dcb = dcb->next;
|
||||||
}
|
}
|
||||||
spinlock_release(&dcbspin);
|
spinlock_release(&dcbspin);
|
||||||
@ -1101,6 +1156,8 @@ dprintDCB(DCB *pdcb, DCB *dcb)
|
|||||||
dcb_printf(pdcb, "\t\tNo. of Writes: %d\n", dcb->stats.n_writes);
|
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 Buffered Writes: %d\n", dcb->stats.n_buffered);
|
||||||
dcb_printf(pdcb, "\t\tNo. of Accepts: %d\n", dcb->stats.n_accepts);
|
dcb_printf(pdcb, "\t\tNo. of Accepts: %d\n", dcb->stats.n_accepts);
|
||||||
|
dcb_printf(pdcb, "\t\tNo. of High Water Events: %d\n", dcb->stats.n_high_water);
|
||||||
|
dcb_printf(pdcb, "\t\tNo. of Low Water Events: %d\n", dcb->stats.n_low_water);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1437,4 +1494,163 @@ int gw_write(
|
|||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a callback
|
||||||
|
*
|
||||||
|
* Duplicate registrations are not allowed, therefore an error will be returned if
|
||||||
|
* the specific function, reason and userdata triple are already registered.
|
||||||
|
* An error will also be returned if the is insufficient memeory available to
|
||||||
|
* create the registration.
|
||||||
|
*
|
||||||
|
* @param dcb The DCB to add the callback to
|
||||||
|
* @param reason The callback reason
|
||||||
|
* @param cb The callback function to call
|
||||||
|
* @param userdata User data to send in the call
|
||||||
|
* @return Non-zero (true) if the callback was added
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
dcb_add_callback(DCB *dcb, DCB_REASON reason, int (*callback)(struct dcb *, DCB_REASON, void *), void *userdata)
|
||||||
|
{
|
||||||
|
DCB_CALLBACK *cb, *ptr;
|
||||||
|
int rval = 1;
|
||||||
|
|
||||||
|
if ((ptr = (DCB_CALLBACK *)malloc(sizeof(DCB_CALLBACK))) == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ptr->reason = reason;
|
||||||
|
ptr->cb = callback;
|
||||||
|
ptr->userdata = userdata;
|
||||||
|
ptr->next = NULL;
|
||||||
|
spinlock_acquire(&dcb->cb_lock);
|
||||||
|
cb = dcb->callbacks;
|
||||||
|
if (cb == NULL)
|
||||||
|
{
|
||||||
|
dcb->callbacks = ptr;
|
||||||
|
spinlock_release(&dcb->cb_lock);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (cb)
|
||||||
|
{
|
||||||
|
if (cb->reason == reason && cb->cb == callback &&
|
||||||
|
cb->userdata == userdata)
|
||||||
|
{
|
||||||
|
free(ptr);
|
||||||
|
spinlock_release(&dcb->cb_lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (cb->next == NULL)
|
||||||
|
cb->next = ptr;
|
||||||
|
cb = cb->next;
|
||||||
|
}
|
||||||
|
spinlock_release(&dcb->cb_lock);
|
||||||
|
}
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a callback from the callback list for the DCB
|
||||||
|
*
|
||||||
|
* Searches down the linked list to find he callback with a matching reason, function
|
||||||
|
* and userdata.
|
||||||
|
*
|
||||||
|
* @param dcb The DCB to add the callback to
|
||||||
|
* @param reason The callback reason
|
||||||
|
* @param cb The callback function to call
|
||||||
|
* @param userdata User data to send in the call
|
||||||
|
* @return Non-zero (true) if the callback was removed
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
dcb_remove_callback(DCB *dcb, DCB_REASON reason, int (*callback)(struct dcb *, DCB_REASON), void *userdata)
|
||||||
|
{
|
||||||
|
DCB_CALLBACK *cb, *pcb = NULL;
|
||||||
|
int rval = 0;
|
||||||
|
|
||||||
|
spinlock_acquire(&dcb->cb_lock);
|
||||||
|
cb = dcb->callbacks;
|
||||||
|
if (cb == NULL)
|
||||||
|
{
|
||||||
|
rval = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (cb)
|
||||||
|
{
|
||||||
|
if (cb->reason == reason && cb->cb == callback
|
||||||
|
&& cb->userdata == userdata)
|
||||||
|
{
|
||||||
|
if (pcb == NULL)
|
||||||
|
pcb->next = cb->next;
|
||||||
|
else
|
||||||
|
dcb->callbacks = cb->next;
|
||||||
|
spinlock_release(&dcb->cb_lock);
|
||||||
|
free(cb);
|
||||||
|
rval = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pcb = cb;
|
||||||
|
cb = cb->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!rval)
|
||||||
|
spinlock_release(&dcb->cb_lock);
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call the set of callbacks registered for a particular reason.
|
||||||
|
*
|
||||||
|
* @param dcb The DCB to call the callbacks regarding
|
||||||
|
* @param reason The reason that has triggered the call
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
dcb_call_callback(DCB *dcb, DCB_REASON reason)
|
||||||
|
{
|
||||||
|
DCB_CALLBACK *cb, *nextcb;
|
||||||
|
|
||||||
|
spinlock_acquire(&dcb->cb_lock);
|
||||||
|
cb = dcb->callbacks;
|
||||||
|
while (cb)
|
||||||
|
{
|
||||||
|
if (cb->reason == reason)
|
||||||
|
{
|
||||||
|
nextcb = cb->next;
|
||||||
|
spinlock_release(&dcb->cb_lock);
|
||||||
|
cb->cb(dcb, reason, cb->userdata);
|
||||||
|
spinlock_acquire(&dcb->cb_lock);
|
||||||
|
cb = nextcb;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cb = cb->next;
|
||||||
|
}
|
||||||
|
spinlock_release(&dcb->cb_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the passed DCB to ensure it is in the list of allDCBS
|
||||||
|
*
|
||||||
|
* @param DCB The DCB to check
|
||||||
|
* @return 1 if the DCB is in the list, otherwise 0
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
dcb_isvalid(DCB *dcb)
|
||||||
|
{
|
||||||
|
DCB *ptr;
|
||||||
|
int rval = 0;
|
||||||
|
|
||||||
|
spinlock_acquire(&dcbspin);
|
||||||
|
ptr = allDCBs;
|
||||||
|
while (ptr)
|
||||||
|
{
|
||||||
|
if (ptr == dcb)
|
||||||
|
{
|
||||||
|
rval = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ptr = ptr->next;
|
||||||
|
}
|
||||||
|
spinlock_release(&dcbspin);
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
@ -106,6 +106,7 @@ MODULES *mod;
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((dlhandle = dlopen(fname, RTLD_NOW|RTLD_LOCAL)) == NULL)
|
if ((dlhandle = dlopen(fname, RTLD_NOW|RTLD_LOCAL)) == NULL)
|
||||||
{
|
{
|
||||||
LOGIF(LE, (skygw_log_write_flush(
|
LOGIF(LE, (skygw_log_write_flush(
|
||||||
@ -156,9 +157,10 @@ MODULES *mod;
|
|||||||
|
|
||||||
LOGIF(LM, (skygw_log_write_flush(
|
LOGIF(LM, (skygw_log_write_flush(
|
||||||
LOGFILE_MESSAGE,
|
LOGFILE_MESSAGE,
|
||||||
"Loaded module %s: %s.",
|
"Loaded module %s: %s from %s",
|
||||||
module,
|
module,
|
||||||
version)));
|
version,
|
||||||
|
fname)));
|
||||||
register_module(module, type, dlhandle, version, modobj);
|
register_module(module, type, dlhandle, version, modobj);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -197,3 +197,26 @@ MONITOR *ptr;
|
|||||||
}
|
}
|
||||||
spinlock_release(&monLock);
|
spinlock_release(&monLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a monitor by name
|
||||||
|
*
|
||||||
|
* @param name The name of the monitor
|
||||||
|
* @return Pointer to the monitor or NULL
|
||||||
|
*/
|
||||||
|
MONITOR *
|
||||||
|
monitor_find(char *name)
|
||||||
|
{
|
||||||
|
MONITOR *ptr;
|
||||||
|
|
||||||
|
spinlock_acquire(&monLock);
|
||||||
|
ptr = allMonitors;
|
||||||
|
while (ptr)
|
||||||
|
{
|
||||||
|
if (!strcmp(ptr->name, name))
|
||||||
|
break;
|
||||||
|
ptr = ptr->next;
|
||||||
|
}
|
||||||
|
spinlock_release(&monLock);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
@ -67,6 +67,7 @@ SERVER *server;
|
|||||||
server->nextdb = NULL;
|
server->nextdb = NULL;
|
||||||
server->monuser = NULL;
|
server->monuser = NULL;
|
||||||
server->monpw = NULL;
|
server->monpw = NULL;
|
||||||
|
server->unique_name = NULL;
|
||||||
|
|
||||||
spinlock_acquire(&server_spin);
|
spinlock_acquire(&server_spin);
|
||||||
server->next = allServers;
|
server->next = allServers;
|
||||||
@ -109,10 +110,49 @@ SERVER *ptr;
|
|||||||
/* Clean up session and free the memory */
|
/* Clean up session and free the memory */
|
||||||
free(server->name);
|
free(server->name);
|
||||||
free(server->protocol);
|
free(server->protocol);
|
||||||
|
if (server->unique_name)
|
||||||
|
free(server->unique_name);
|
||||||
free(server);
|
free(server);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a unique name for the server
|
||||||
|
*
|
||||||
|
* @param server The server to ste the name on
|
||||||
|
* @param name The unique name for the server
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
server_set_unique_name(SERVER *server, char *name)
|
||||||
|
{
|
||||||
|
server->unique_name = strdup(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find an existing server using the unique section name in
|
||||||
|
* configuration file
|
||||||
|
*
|
||||||
|
* @param servname The Server name or address
|
||||||
|
* @param port The server port
|
||||||
|
* @return The server or NULL if not found
|
||||||
|
*/
|
||||||
|
SERVER *
|
||||||
|
server_find_by_unique_name(char *name)
|
||||||
|
{
|
||||||
|
SERVER *server;
|
||||||
|
|
||||||
|
spinlock_acquire(&server_spin);
|
||||||
|
server = allServers;
|
||||||
|
while (server)
|
||||||
|
{
|
||||||
|
if (strcmp(server->unique_name, name) == 0)
|
||||||
|
break;
|
||||||
|
server = server->next;
|
||||||
|
}
|
||||||
|
spinlock_release(&server_spin);
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find an existing server
|
* Find an existing server
|
||||||
*
|
*
|
||||||
@ -190,7 +230,7 @@ char *stat;
|
|||||||
ptr = allServers;
|
ptr = allServers;
|
||||||
while (ptr)
|
while (ptr)
|
||||||
{
|
{
|
||||||
dcb_printf(dcb, "Server %p\n", ptr);
|
dcb_printf(dcb, "Server %p (%s)\n", ptr, ptr->unique_name);
|
||||||
dcb_printf(dcb, "\tServer: %s\n", ptr->name);
|
dcb_printf(dcb, "\tServer: %s\n", ptr->name);
|
||||||
stat = server_status(ptr);
|
stat = server_status(ptr);
|
||||||
dcb_printf(dcb, "\tStatus: %s\n", stat);
|
dcb_printf(dcb, "\tStatus: %s\n", stat);
|
||||||
@ -215,7 +255,7 @@ dprintServer(DCB *dcb, SERVER *server)
|
|||||||
{
|
{
|
||||||
char *stat;
|
char *stat;
|
||||||
|
|
||||||
dcb_printf(dcb, "Server %p\n", server);
|
dcb_printf(dcb, "Server %p (%s)\n", server, server->unique_name);
|
||||||
dcb_printf(dcb, "\tServer: %s\n", server->name);
|
dcb_printf(dcb, "\tServer: %s\n", server->name);
|
||||||
stat = server_status(server);
|
stat = server_status(server);
|
||||||
dcb_printf(dcb, "\tStatus: %s\n", stat);
|
dcb_printf(dcb, "\tStatus: %s\n", stat);
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
* 25/02/14 Massimiliano Pinto Added: service refresh limit feature
|
* 25/02/14 Massimiliano Pinto Added: service refresh limit feature
|
||||||
* 28/02/14 Massimiliano Pinto users_alloc moved from service_alloc to serviceStartPort (generic hashable for services)
|
* 28/02/14 Massimiliano Pinto users_alloc moved from service_alloc to serviceStartPort (generic hashable for services)
|
||||||
* 07/05/14 Massimiliano Pinto Added: version_string initialized to NULL
|
* 07/05/14 Massimiliano Pinto Added: version_string initialized to NULL
|
||||||
|
* 23/05/14 Mark Riddoch Addition of service validation call
|
||||||
*
|
*
|
||||||
* @endverbatim
|
* @endverbatim
|
||||||
*/
|
*/
|
||||||
@ -121,6 +122,33 @@ SERVICE *service;
|
|||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check to see if a service pointer is valid
|
||||||
|
*
|
||||||
|
* @param service The poitner to check
|
||||||
|
* @return 1 if the service is in the list of all services
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
service_isvalid(SERVICE *service)
|
||||||
|
{
|
||||||
|
SERVICE *ptr;
|
||||||
|
int rval = 0;
|
||||||
|
|
||||||
|
spinlock_acquire(&service_spin);
|
||||||
|
ptr = allServices;
|
||||||
|
while (ptr)
|
||||||
|
{
|
||||||
|
if (ptr == service)
|
||||||
|
{
|
||||||
|
rval = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ptr = ptr->next;
|
||||||
|
}
|
||||||
|
spinlock_release(&service_spin);
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start an individual port/protocol pair
|
* Start an individual port/protocol pair
|
||||||
*
|
*
|
||||||
@ -184,7 +212,7 @@ GWPROTOCOL *funcs;
|
|||||||
|
|
||||||
if (port->listener->func.listen(port->listener, config_bind)) {
|
if (port->listener->func.listen(port->listener, config_bind)) {
|
||||||
port->listener->session = session_alloc(service, port->listener);
|
port->listener->session = session_alloc(service, port->listener);
|
||||||
|
|
||||||
if (port->listener->session != NULL) {
|
if (port->listener->session != NULL) {
|
||||||
port->listener->session->state = SESSION_STATE_LISTENER;
|
port->listener->session->state = SESSION_STATE_LISTENER;
|
||||||
listeners += 1;
|
listeners += 1;
|
||||||
@ -650,7 +678,7 @@ SERVICE *ptr;
|
|||||||
/**
|
/**
|
||||||
* Print all services to a DCB
|
* Print all services to a DCB
|
||||||
*
|
*
|
||||||
* Designed to be called within a debugger session in order
|
* Designed to be called within a CLI command in order
|
||||||
* to display all active services within the gateway
|
* to display all active services within the gateway
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
@ -662,30 +690,42 @@ SERVICE *ptr;
|
|||||||
ptr = allServices;
|
ptr = allServices;
|
||||||
while (ptr)
|
while (ptr)
|
||||||
{
|
{
|
||||||
SERVER *server = ptr->databases;
|
dprintService(dcb, ptr);
|
||||||
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;
|
ptr = ptr->next;
|
||||||
}
|
}
|
||||||
spinlock_release(&service_spin);
|
spinlock_release(&service_spin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print details of a single service.
|
||||||
|
*
|
||||||
|
* @param dcb DCB to print data to
|
||||||
|
* @param service The service to print
|
||||||
|
*/
|
||||||
|
dprintService(DCB *dcb, SERVICE *service)
|
||||||
|
{
|
||||||
|
SERVER *server = service->databases;
|
||||||
|
|
||||||
|
dcb_printf(dcb, "Service %p\n", service);
|
||||||
|
dcb_printf(dcb, "\tService: %s\n", service->name);
|
||||||
|
dcb_printf(dcb, "\tRouter: %s (%p)\n", service->routerModule,
|
||||||
|
service->router);
|
||||||
|
if (service->router)
|
||||||
|
service->router->diagnostics(service->router_instance, dcb);
|
||||||
|
dcb_printf(dcb, "\tStarted: %s",
|
||||||
|
asctime(localtime(&service->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", service->users);
|
||||||
|
dcb_printf(dcb, "\tTotal connections: %d\n", service->stats.n_sessions);
|
||||||
|
dcb_printf(dcb, "\tCurrently connected: %d\n", service->stats.n_current);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the definition of a service
|
* Update the definition of a service
|
||||||
*
|
*
|
||||||
|
@ -114,7 +114,7 @@ session_alloc(SERVICE *service, DCB *client_dcb)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Only create a router session if we are not the listening
|
* Only create a router session if we are not the listening
|
||||||
* DCB. Creating a router session may create a connection to a
|
* DCB or an internal DCB. Creating a router session may create a connection to a
|
||||||
* backend server, depending upon the router module implementation
|
* backend server, depending upon the router module implementation
|
||||||
* and should be avoided for the listener session
|
* and should be avoided for the listener session
|
||||||
*
|
*
|
||||||
@ -122,7 +122,7 @@ session_alloc(SERVICE *service, DCB *client_dcb)
|
|||||||
* session, therefore it is important that the session lock is
|
* session, therefore it is important that the session lock is
|
||||||
* relinquished beforethe router call.
|
* relinquished beforethe router call.
|
||||||
*/
|
*/
|
||||||
if (client_dcb->state != DCB_STATE_LISTENING)
|
if (client_dcb->state != DCB_STATE_LISTENING && client_dcb->dcb_role != DCB_ROLE_INTERNAL)
|
||||||
{
|
{
|
||||||
session->router_session =
|
session->router_session =
|
||||||
service->router->newSession(service->router_instance,
|
service->router->newSession(service->router_instance,
|
||||||
@ -273,6 +273,34 @@ return_succp :
|
|||||||
return succp;
|
return succp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check to see if a session is valid, i.e. in the list of all sessions
|
||||||
|
*
|
||||||
|
* @param session Session to check
|
||||||
|
* @return 1 if the session is valid otherwise 0
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
session_isvalid(SESSION *session)
|
||||||
|
{
|
||||||
|
SESSION *ptr;
|
||||||
|
int rval = 0;
|
||||||
|
|
||||||
|
spinlock_acquire(&session_spin);
|
||||||
|
ptr = allSessions;
|
||||||
|
while (ptr)
|
||||||
|
{
|
||||||
|
if (ptr == session)
|
||||||
|
{
|
||||||
|
rval = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ptr = ptr->next;
|
||||||
|
}
|
||||||
|
spinlock_release(&session_spin);
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print details of an individual session
|
* Print details of an individual session
|
||||||
*
|
*
|
||||||
|
@ -48,6 +48,8 @@ struct service;
|
|||||||
* 15/07/2013 Massimiliano Pinto Added session entry point
|
* 15/07/2013 Massimiliano Pinto Added session entry point
|
||||||
* 16/07/2013 Massimiliano Pinto Added command type for dcb
|
* 16/07/2013 Massimiliano Pinto Added command type for dcb
|
||||||
* 07/02/2014 Massimiliano Pinto Added ipv4 data struct into for dcb
|
* 07/02/2014 Massimiliano Pinto Added ipv4 data struct into for dcb
|
||||||
|
* 07/05/2014 Mark Riddoch Addition of callback mechanism
|
||||||
|
* 08/05/2014 Mark Riddoch Addition of writeq high and low watermarks
|
||||||
*
|
*
|
||||||
* @endverbatim
|
* @endverbatim
|
||||||
*/
|
*/
|
||||||
@ -99,6 +101,8 @@ typedef struct dcbstats {
|
|||||||
int n_writes; /*< Number of writes on this descriptor */
|
int n_writes; /*< Number of writes on this descriptor */
|
||||||
int n_accepts; /*< Number of accepts on this descriptor */
|
int n_accepts; /*< Number of accepts on this descriptor */
|
||||||
int n_buffered; /*< Number of buffered writes */
|
int n_buffered; /*< Number of buffered writes */
|
||||||
|
int n_high_water; /*< Number of crosses of high water mark */
|
||||||
|
int n_low_water; /*< Number of crosses of low water mark */
|
||||||
} DCBSTATS;
|
} DCBSTATS;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -137,10 +141,35 @@ typedef enum {
|
|||||||
} dcb_state_t;
|
} dcb_state_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
DCB_ROLE_SERVICE_LISTENER, /*< Receives initial connect requests from clients */
|
DCB_ROLE_SERVICE_LISTENER, /*< Receives initial connect requests from clients */
|
||||||
DCB_ROLE_REQUEST_HANDLER /*< Serves dedicated client */
|
DCB_ROLE_REQUEST_HANDLER, /*< Serves dedicated client */
|
||||||
|
DCB_ROLE_INTERNAL /*< Internal DCB not connected to the outside */
|
||||||
} dcb_role_t;
|
} dcb_role_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback reasons for the DCB callback mechanism.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
DCB_REASON_CLOSE, /*< The DCB is closing */
|
||||||
|
DCB_REASON_DRAINED, /*< The write delay queue has drained */
|
||||||
|
DCB_REASON_HIGH_WATER, /*< Cross high water mark */
|
||||||
|
DCB_REASON_LOW_WATER, /*< Cross low water mark */
|
||||||
|
DCB_REASON_ERROR, /*< An error was flagged on the connection */
|
||||||
|
DCB_REASON_HUP /*< A hangup was detected */
|
||||||
|
} DCB_REASON;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback structure - used to track callbacks registered on a DCB
|
||||||
|
*/
|
||||||
|
typedef struct dcb_callback {
|
||||||
|
DCB_REASON reason; /*< The reason for the callback */
|
||||||
|
int (*cb)(struct dcb *dcb, DCB_REASON reason, void *userdata);
|
||||||
|
void *userdata; /*< User data to be sent in the callback */
|
||||||
|
struct dcb_callback
|
||||||
|
*next; /*< Next callback for this DCB */
|
||||||
|
} DCB_CALLBACK;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Descriptor Control Block
|
* Descriptor Control Block
|
||||||
*
|
*
|
||||||
@ -172,6 +201,7 @@ typedef struct dcb {
|
|||||||
struct session *session; /**< The owning session */
|
struct session *session; /**< The owning session */
|
||||||
GWPROTOCOL func; /**< The functions for this descriptor */
|
GWPROTOCOL func; /**< The functions for this descriptor */
|
||||||
|
|
||||||
|
unsigned int writeqlen; /**< Current number of byes in the write queue */
|
||||||
SPINLOCK writeqlock; /**< Write Queue spinlock */
|
SPINLOCK writeqlock; /**< Write Queue spinlock */
|
||||||
GWBUF *writeq; /**< Write Data Queue */
|
GWBUF *writeq; /**< Write Data Queue */
|
||||||
SPINLOCK delayqlock; /**< Delay Backend Write Queue spinlock */
|
SPINLOCK delayqlock; /**< Delay Backend Write Queue spinlock */
|
||||||
@ -186,6 +216,11 @@ typedef struct dcb {
|
|||||||
void *data; /**< Specific client data */
|
void *data; /**< Specific client data */
|
||||||
DCBMM memdata; /**< The data related to DCB memory management */
|
DCBMM memdata; /**< The data related to DCB memory management */
|
||||||
int command; /**< Specific client command type */
|
int command; /**< Specific client command type */
|
||||||
|
SPINLOCK cb_lock; /**< The lock for the callbacks linked list */
|
||||||
|
DCB_CALLBACK *callbacks; /**< The list of callbacks for the DCB */
|
||||||
|
|
||||||
|
unsigned int high_water; /**< High water mark */
|
||||||
|
unsigned int low_water; /**< Low water mark */
|
||||||
#if defined(SS_DEBUG)
|
#if defined(SS_DEBUG)
|
||||||
skygw_chk_t dcb_chk_tail;
|
skygw_chk_t dcb_chk_tail;
|
||||||
#endif
|
#endif
|
||||||
@ -204,6 +239,11 @@ int fail_accept_errno;
|
|||||||
#define DCB_SESSION(x) (x)->session
|
#define DCB_SESSION(x) (x)->session
|
||||||
#define DCB_PROTOCOL(x, type) (type *)((x)->protocol)
|
#define DCB_PROTOCOL(x, type) (type *)((x)->protocol)
|
||||||
#define DCB_ISZOMBIE(x) ((x)->state == DCB_STATE_ZOMBIE)
|
#define DCB_ISZOMBIE(x) ((x)->state == DCB_STATE_ZOMBIE)
|
||||||
|
#define DCB_WRITEQLEN(x) (x)->writeqlen
|
||||||
|
#define DCB_SET_LOW_WATER(x, lo) (x)->low_water = (lo);
|
||||||
|
#define DCB_SET_HIGH_WATER(x, hi) (x)->low_water = (hi);
|
||||||
|
#define DCB_BELOW_LOW_WATER(x) ((x)->low_water && (x)->writeqlen < (x)->low_water)
|
||||||
|
#define DCB_ABOVE_HIGH_WATER(x) ((x)->high_water && (x)->writeqlen > (x)->high_water)
|
||||||
|
|
||||||
DCB *dcb_get_zombies(void);
|
DCB *dcb_get_zombies(void);
|
||||||
int gw_write(
|
int gw_write(
|
||||||
@ -230,6 +270,11 @@ void dcb_printf(DCB *, const char *, ...); /* DCB version of printf */
|
|||||||
int dcb_isclient(DCB *); /* the DCB is the client of the session */
|
int dcb_isclient(DCB *); /* the DCB is the client of the session */
|
||||||
void dcb_hashtable_stats(DCB *, void *); /**< Print statisitics */
|
void dcb_hashtable_stats(DCB *, void *); /**< Print statisitics */
|
||||||
void dcb_add_to_zombieslist(DCB* dcb);
|
void dcb_add_to_zombieslist(DCB* dcb);
|
||||||
|
int dcb_add_callback(DCB *, DCB_REASON, int (*)(struct dcb *, DCB_REASON, void *),
|
||||||
|
void *);
|
||||||
|
int dcb_remove_callback(DCB *, DCB_REASON, int (*)(struct dcb *, DCB_REASON),
|
||||||
|
void *);
|
||||||
|
int dcb_isvalid(DCB *); /* Check the DCB is in the linked list */
|
||||||
|
|
||||||
bool dcb_set_state(
|
bool dcb_set_state(
|
||||||
DCB* dcb,
|
DCB* dcb,
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
* Date Who Description
|
* Date Who Description
|
||||||
* 07/07/13 Mark Riddoch Initial implementation
|
* 07/07/13 Mark Riddoch Initial implementation
|
||||||
* 25/07/13 Mark Riddoch Addition of diagnotics
|
* 25/07/13 Mark Riddoch Addition of diagnotics
|
||||||
|
* 23/05/14 Mark Riddoch Addition of routine to find monitors by name
|
||||||
*
|
*
|
||||||
* @endverbatim
|
* @endverbatim
|
||||||
*/
|
*/
|
||||||
@ -79,6 +80,7 @@ typedef struct monitor {
|
|||||||
|
|
||||||
extern MONITOR *monitor_alloc(char *, char *);
|
extern MONITOR *monitor_alloc(char *, char *);
|
||||||
extern void monitor_free(MONITOR *);
|
extern void monitor_free(MONITOR *);
|
||||||
|
extern MONITOR *monitor_find(char *);
|
||||||
extern void monitorAddServer(MONITOR *, SERVER *);
|
extern void monitorAddServer(MONITOR *, SERVER *);
|
||||||
extern void monitorAddUser(MONITOR *, char *, char *);
|
extern void monitorAddUser(MONITOR *, char *, char *);
|
||||||
extern void monitorStop(MONITOR *);
|
extern void monitorStop(MONITOR *);
|
||||||
|
@ -51,6 +51,7 @@ typedef struct {
|
|||||||
* between the gateway and the server.
|
* between the gateway and the server.
|
||||||
*/
|
*/
|
||||||
typedef struct server {
|
typedef struct server {
|
||||||
|
char *unique_name; /**< Unique name for the server */
|
||||||
char *name; /**< Server name/IP address*/
|
char *name; /**< Server name/IP address*/
|
||||||
unsigned short port; /**< Port to listen on */
|
unsigned short port; /**< Port to listen on */
|
||||||
char *protocol; /**< Protocol module to use */
|
char *protocol; /**< Protocol module to use */
|
||||||
@ -103,6 +104,7 @@ typedef struct server {
|
|||||||
|
|
||||||
extern SERVER *server_alloc(char *, char *, unsigned short);
|
extern SERVER *server_alloc(char *, char *, unsigned short);
|
||||||
extern int server_free(SERVER *);
|
extern int server_free(SERVER *);
|
||||||
|
extern SERVER *server_find_by_unique_name(char *);
|
||||||
extern SERVER *server_find(char *, unsigned short);
|
extern SERVER *server_find(char *, unsigned short);
|
||||||
extern void printServer(SERVER *);
|
extern void printServer(SERVER *);
|
||||||
extern void printAllServers();
|
extern void printAllServers();
|
||||||
|
@ -110,6 +110,7 @@ typedef struct service {
|
|||||||
*router; /**< The router we are using */
|
*router; /**< The router we are using */
|
||||||
void *router_instance;
|
void *router_instance;
|
||||||
/**< The router instance for this service */
|
/**< The router instance for this service */
|
||||||
|
char *version_string; /** version string for this service listeners */
|
||||||
struct server *databases; /**< The set of servers in the backend */
|
struct server *databases; /**< The set of servers in the backend */
|
||||||
char *version_string; /** version string for this service listeners */
|
char *version_string; /** version string for this service listeners */
|
||||||
SERVICE_USER credentials; /**< The cedentials of the service user */
|
SERVICE_USER credentials; /**< The cedentials of the service user */
|
||||||
@ -134,6 +135,7 @@ typedef enum count_spec_t {COUNT_ATLEAST=0, COUNT_EXACT, COUNT_ATMOST} count_spe
|
|||||||
extern SERVICE *service_alloc(char *, char *);
|
extern SERVICE *service_alloc(char *, char *);
|
||||||
extern int service_free(SERVICE *);
|
extern int service_free(SERVICE *);
|
||||||
extern SERVICE *service_find(char *);
|
extern SERVICE *service_find(char *);
|
||||||
|
extern int service_isvalid(SERVICE *);
|
||||||
extern int serviceAddProtocol(SERVICE *, char *, char *, unsigned short);
|
extern int serviceAddProtocol(SERVICE *, char *, char *, unsigned short);
|
||||||
extern int serviceHasProtocol(SERVICE *, char *, unsigned short);
|
extern int serviceHasProtocol(SERVICE *, char *, unsigned short);
|
||||||
extern void serviceAddBackend(SERVICE *, SERVER *);
|
extern void serviceAddBackend(SERVICE *, SERVER *);
|
||||||
@ -153,11 +155,10 @@ extern int service_refresh_users(SERVICE *);
|
|||||||
extern void printService(SERVICE *);
|
extern void printService(SERVICE *);
|
||||||
extern void printAllServices();
|
extern void printAllServices();
|
||||||
extern void dprintAllServices(DCB *);
|
extern void dprintAllServices(DCB *);
|
||||||
|
|
||||||
bool service_set_slave_conn_limit (
|
bool service_set_slave_conn_limit (
|
||||||
SERVICE* service,
|
SERVICE* service,
|
||||||
CONFIG_PARAMETER* param,
|
CONFIG_PARAMETER* param,
|
||||||
char* valstr,
|
char* valstr,
|
||||||
count_spec_t count_spec);
|
count_spec_t count_spec);
|
||||||
|
extern void dprintService(DCB *, SERVICE *);
|
||||||
#endif
|
#endif
|
||||||
|
@ -88,6 +88,7 @@ typedef struct session {
|
|||||||
|
|
||||||
SESSION *session_alloc(struct service *, struct dcb *);
|
SESSION *session_alloc(struct service *, struct dcb *);
|
||||||
bool session_free(SESSION *);
|
bool session_free(SESSION *);
|
||||||
|
int session_isvalid(SESSION *);
|
||||||
void printAllSessions();
|
void printAllSessions();
|
||||||
void printSession(SESSION *);
|
void printSession(SESSION *);
|
||||||
void dprintAllSessions(struct dcb *);
|
void dprintAllSessions(struct dcb *);
|
||||||
@ -95,4 +96,4 @@ void dprintSession(struct dcb *, SESSION *);
|
|||||||
char *session_state(int);
|
char *session_state(int);
|
||||||
bool session_link_dcb(SESSION *, struct dcb *);
|
bool session_link_dcb(SESSION *, struct dcb *);
|
||||||
SESSION* get_session_by_router_ses(void* rses);
|
SESSION* get_session_by_router_ses(void* rses);
|
||||||
#endif
|
#endif
|
||||||
|
@ -41,6 +41,7 @@ struct cli_session;
|
|||||||
typedef struct cli_instance {
|
typedef struct cli_instance {
|
||||||
SPINLOCK lock; /*< The instance spinlock */
|
SPINLOCK lock; /*< The instance spinlock */
|
||||||
SERVICE *service; /*< The debug cli service */
|
SERVICE *service; /*< The debug cli service */
|
||||||
|
int mode; /*< CLI interface mode */
|
||||||
struct cli_session
|
struct cli_session
|
||||||
*sessions; /*< Linked list of sessions within this instance */
|
*sessions; /*< Linked list of sessions within this instance */
|
||||||
struct cli_instance
|
struct cli_instance
|
||||||
@ -53,8 +54,13 @@ typedef struct cli_instance {
|
|||||||
*/
|
*/
|
||||||
typedef struct cli_session {
|
typedef struct cli_session {
|
||||||
char cmdbuf[80]; /*< The command buffer used to build up user commands */
|
char cmdbuf[80]; /*< The command buffer used to build up user commands */
|
||||||
|
int mode; /*< The CLI Mode for this session */
|
||||||
SESSION *session; /*< The gateway session */
|
SESSION *session; /*< The gateway session */
|
||||||
struct cli_session
|
struct cli_session
|
||||||
*next; /*< The next pointer for the list of sessions */
|
*next; /*< The next pointer for the list of sessions */
|
||||||
} CLI_SESSION;
|
} CLI_SESSION;
|
||||||
|
|
||||||
|
/* Command line interface modes */
|
||||||
|
#define CLIM_USER 1
|
||||||
|
#define CLIM_DEVELOPER 2
|
||||||
#endif
|
#endif
|
||||||
|
@ -424,21 +424,23 @@ static int gw_read_backend_event(DCB *dcb) {
|
|||||||
if (dcb->session->client != NULL) {
|
if (dcb->session->client != NULL) {
|
||||||
client_protocol = SESSION_PROTOCOL(dcb->session,
|
client_protocol = SESSION_PROTOCOL(dcb->session,
|
||||||
MySQLProtocol);
|
MySQLProtocol);
|
||||||
}
|
if (client_protocol != NULL) {
|
||||||
|
CHK_PROTOCOL(client_protocol);
|
||||||
if (client_protocol != NULL) {
|
|
||||||
CHK_PROTOCOL(client_protocol);
|
|
||||||
|
|
||||||
if (client_protocol->state == MYSQL_IDLE)
|
if (client_protocol->state == MYSQL_IDLE)
|
||||||
{
|
{
|
||||||
router->clientReply(router_instance,
|
router->clientReply(router_instance,
|
||||||
rsession,
|
rsession,
|
||||||
writebuf,
|
writebuf,
|
||||||
dcb);
|
dcb);
|
||||||
rc = 1;
|
rc = 1;
|
||||||
}
|
}
|
||||||
goto return_rc;
|
goto return_rc;
|
||||||
}
|
} else if (dcb->session->client->dcb_role == DCB_ROLE_INTERNAL) {
|
||||||
|
router->clientReply(router_instance, rsession, writebuf, dcb);
|
||||||
|
rc = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return_rc:
|
return_rc:
|
||||||
|
@ -1323,9 +1323,8 @@ GWBUF* gw_MySQL_get_next_packet(
|
|||||||
size_t packetlen;
|
size_t packetlen;
|
||||||
size_t totalbuflen;
|
size_t totalbuflen;
|
||||||
uint8_t* data;
|
uint8_t* data;
|
||||||
|
|
||||||
readbuf = *p_readbuf;
|
readbuf = *p_readbuf;
|
||||||
|
|
||||||
if (readbuf == NULL)
|
if (readbuf == NULL)
|
||||||
{
|
{
|
||||||
packetbuf = NULL;
|
packetbuf = NULL;
|
||||||
|
@ -49,6 +49,8 @@ MODULES= libdebugcli.so libreadconnroute.so libtestroute.so
|
|||||||
|
|
||||||
|
|
||||||
all: $(MODULES)
|
all: $(MODULES)
|
||||||
|
(cd readwritesplit; make )
|
||||||
|
(cd binlog; make )
|
||||||
|
|
||||||
libtestroute.so: $(TESTOBJ)
|
libtestroute.so: $(TESTOBJ)
|
||||||
$(CC) $(LDFLAGS) $(TESTOBJ) $(LIBS) -o $@
|
$(CC) $(LDFLAGS) $(TESTOBJ) $(LIBS) -o $@
|
||||||
@ -68,20 +70,24 @@ libreadwritesplit.so:
|
|||||||
clean:
|
clean:
|
||||||
rm -f $(OBJ) $(MODULES)
|
rm -f $(OBJ) $(MODULES)
|
||||||
(cd readwritesplit; touch depend.mk; make clean)
|
(cd readwritesplit; touch depend.mk; make clean)
|
||||||
|
(cd binlog; touch depend.mk; make clean)
|
||||||
|
|
||||||
tags:
|
tags:
|
||||||
ctags $(SRCS) $(HDRS)
|
ctags $(SRCS) $(HDRS)
|
||||||
(cd readwritesplit; make tags)
|
(cd readwritesplit; make tags)
|
||||||
|
(cd binlog; make tags)
|
||||||
|
|
||||||
depend:
|
depend:
|
||||||
@rm -f depend.mk
|
@rm -f depend.mk
|
||||||
cc -M $(CFLAGS) $(SRCS) > depend.mk
|
cc -M $(CFLAGS) $(SRCS) > depend.mk
|
||||||
(cd readwritesplit; touch depend.mk ; make depend)
|
(cd readwritesplit; touch depend.mk ; make depend)
|
||||||
|
(cd binlog; touch depend.mk ; make depend)
|
||||||
|
|
||||||
install: $(MODULES)
|
install: $(MODULES)
|
||||||
install -D $(MODULES) $(DEST)/MaxScale/modules
|
install -D $(MODULES) $(DEST)/MaxScale/modules
|
||||||
(cd readwritesplit; make DEST=$(DEST) install)
|
(cd readwritesplit; make DEST=$(DEST) install)
|
||||||
|
|
||||||
|
|
||||||
cleantests:
|
cleantests:
|
||||||
$(MAKE) -C readwritesplit/test cleantests
|
$(MAKE) -C readwritesplit/test cleantests
|
||||||
$(MAKE) -C test cleantests
|
$(MAKE) -C test cleantests
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
|
|
||||||
extern int lm_enabled_logfiles_bitmask;
|
extern int lm_enabled_logfiles_bitmask;
|
||||||
|
|
||||||
static char *version_str = "V1.0.1";
|
static char *version_str = "V1.1.0";
|
||||||
|
|
||||||
/* The router entry points */
|
/* The router entry points */
|
||||||
static ROUTER *createInstance(SERVICE *service, char **options);
|
static ROUTER *createInstance(SERVICE *service, char **options);
|
||||||
@ -127,6 +127,7 @@ static ROUTER *
|
|||||||
createInstance(SERVICE *service, char **options)
|
createInstance(SERVICE *service, char **options)
|
||||||
{
|
{
|
||||||
CLI_INSTANCE *inst;
|
CLI_INSTANCE *inst;
|
||||||
|
int i;
|
||||||
|
|
||||||
if ((inst = malloc(sizeof(CLI_INSTANCE))) == NULL)
|
if ((inst = malloc(sizeof(CLI_INSTANCE))) == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -134,7 +135,29 @@ CLI_INSTANCE *inst;
|
|||||||
inst->service = service;
|
inst->service = service;
|
||||||
spinlock_init(&inst->lock);
|
spinlock_init(&inst->lock);
|
||||||
inst->sessions = NULL;
|
inst->sessions = NULL;
|
||||||
|
inst->mode = CLIM_USER;
|
||||||
|
|
||||||
|
if (options)
|
||||||
|
{
|
||||||
|
for (i = 0; options[i]; i++)
|
||||||
|
{
|
||||||
|
if (!strcasecmp(options[i], "developer"))
|
||||||
|
{
|
||||||
|
inst->mode = CLIM_DEVELOPER;
|
||||||
|
}
|
||||||
|
else if (!strcasecmp(options[i], "user"))
|
||||||
|
{
|
||||||
|
inst->mode = CLIM_USER;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOGIF(LE, (skygw_log_write(
|
||||||
|
LOGFILE_ERROR,
|
||||||
|
"Unknown option for CLI '%s'\n",
|
||||||
|
options[i])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have completed the creation of the instance data, so now
|
* We have completed the creation of the instance data, so now
|
||||||
@ -176,11 +199,15 @@ CLI_SESSION *client;
|
|||||||
spinlock_release(&inst->lock);
|
spinlock_release(&inst->lock);
|
||||||
|
|
||||||
session->state = SESSION_STATE_READY;
|
session->state = SESSION_STATE_READY;
|
||||||
|
client->mode = inst->mode;
|
||||||
|
|
||||||
dcb_printf(session->client, "Welcome the SkySQL MaxScale Debug Interface (%s).\n",
|
dcb_printf(session->client, "Welcome the SkySQL MaxScale Debug Interface (%s).\n",
|
||||||
version_str);
|
version_str);
|
||||||
dcb_printf(session->client, "WARNING: This interface is meant for developer usage,\n");
|
if (client->mode == CLIM_DEVELOPER)
|
||||||
dcb_printf(session->client, "passing incorrect addresses to commands can endanger your MaxScale server.\n\n");
|
{
|
||||||
|
dcb_printf(session->client, "WARNING: This interface is meant for developer usage,\n");
|
||||||
|
dcb_printf(session->client, "passing incorrect addresses to commands can endanger your MaxScale server.\n\n");
|
||||||
|
}
|
||||||
dcb_printf(session->client, "Type help for a list of available commands.\n\n");
|
dcb_printf(session->client, "Type help for a list of available commands.\n\n");
|
||||||
|
|
||||||
return (void *)client;
|
return (void *)client;
|
||||||
@ -281,4 +308,4 @@ static uint8_t getCapabilities(
|
|||||||
void* router_session)
|
void* router_session)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,10 @@
|
|||||||
* Date Who Description
|
* Date Who Description
|
||||||
* 20/06/13 Mark Riddoch Initial implementation
|
* 20/06/13 Mark Riddoch Initial implementation
|
||||||
* 17/07/13 Mark Riddoch Additional commands
|
* 17/07/13 Mark Riddoch Additional commands
|
||||||
* 09/08/2013 Massimiliano Pinto Addes enable/disable commands (now only for log)
|
* 09/08/2013 Massimiliano Pinto Added enable/disable commands (now only for log)
|
||||||
|
* 20/05/14 Mark Riddoch Added ability to give server and service names rather
|
||||||
|
* than simply addresses
|
||||||
|
* 23/05/14 Mark Riddoch Added support for developer and user modes
|
||||||
*
|
*
|
||||||
* @endverbatim
|
* @endverbatim
|
||||||
*/
|
*/
|
||||||
@ -68,6 +71,13 @@
|
|||||||
|
|
||||||
#define ARG_TYPE_ADDRESS 1
|
#define ARG_TYPE_ADDRESS 1
|
||||||
#define ARG_TYPE_STRING 2
|
#define ARG_TYPE_STRING 2
|
||||||
|
#define ARG_TYPE_SERVICE 3
|
||||||
|
#define ARG_TYPE_SERVER 4
|
||||||
|
#define ARG_TYPE_DBUSERS 5
|
||||||
|
#define ARG_TYPE_SESSION 6
|
||||||
|
#define ARG_TYPE_DCB 7
|
||||||
|
#define ARG_TYPE_MONITOR 8
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The subcommand structure
|
* The subcommand structure
|
||||||
*
|
*
|
||||||
@ -78,6 +88,7 @@ struct subcommand {
|
|||||||
int n_args;
|
int n_args;
|
||||||
void (*fn)();
|
void (*fn)();
|
||||||
char *help;
|
char *help;
|
||||||
|
char *devhelp;
|
||||||
int arg_types[3];
|
int arg_types[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -86,31 +97,59 @@ static void telnetdShowUsers(DCB *);
|
|||||||
* The subcommands of the show command
|
* The subcommands of the show command
|
||||||
*/
|
*/
|
||||||
struct subcommand showoptions[] = {
|
struct subcommand showoptions[] = {
|
||||||
{ "dcbs", 0, dprintAllDCBs, "Show all descriptor control blocks (network connections)",
|
{ "dcbs", 0, dprintAllDCBs,
|
||||||
|
"Show all descriptor control blocks (network connections)",
|
||||||
|
"Show all descriptor control blocks (network connections)",
|
||||||
{0, 0, 0} },
|
{0, 0, 0} },
|
||||||
{ "dcb", 1, dprintDCB, "Show a single descriptor control block e.g. show dcb 0x493340",
|
{ "dcb", 1, dprintDCB,
|
||||||
{ARG_TYPE_ADDRESS, 0, 0} },
|
"Show a single descriptor control block e.g. show dcb 0x493340",
|
||||||
{ "dbusers", 1, dcb_usersPrint, "Show statistics and user names for a service's user table.\n\t\tExample : show dbusers <ptr of 'User's data' from services list>",
|
"Show a single descriptor control block e.g. show dcb 0x493340",
|
||||||
{ARG_TYPE_ADDRESS, 0, 0} },
|
{ARG_TYPE_DCB, 0, 0} },
|
||||||
{ "epoll", 0, dprintPollStats, "Show the poll statistics",
|
{ "dbusers", 1, dcb_usersPrint,
|
||||||
|
"Show statistics and user names for a service's user table.\n\t\tExample : show dbusers <service name>",
|
||||||
|
"Show statistics and user names for a service's user table.\n\t\tExample : show dbusers <ptr of 'User's data' from services list>|<service name>",
|
||||||
|
{ARG_TYPE_DBUSERS, 0, 0} },
|
||||||
|
{ "epoll", 0, dprintPollStats,
|
||||||
|
"Show the poll statistics",
|
||||||
|
"Show the poll statistics",
|
||||||
{0, 0, 0} },
|
{0, 0, 0} },
|
||||||
{ "modules", 0, dprintAllModules, "Show all currently loaded modules",
|
{ "modules", 0, dprintAllModules,
|
||||||
|
"Show all currently loaded modules",
|
||||||
|
"Show all currently loaded modules",
|
||||||
{0, 0, 0} },
|
{0, 0, 0} },
|
||||||
{ "monitors", 0, monitorShowAll, "Show the monitors that are configured",
|
{ "monitors", 0, monitorShowAll,
|
||||||
|
"Show the monitors that are configured",
|
||||||
|
"Show the monitors that are configured",
|
||||||
{0, 0, 0} },
|
{0, 0, 0} },
|
||||||
{ "server", 1, dprintServer, "Show details for a server, e.g. show server 0x485390",
|
{ "server", 1, dprintServer,
|
||||||
{ARG_TYPE_ADDRESS, 0, 0} },
|
"Show details for a named server, e.g. show server dbnode1",
|
||||||
{ "servers", 0, dprintAllServers, "Show all configured servers",
|
"Show details for a server, e.g. show server 0x485390. The address may also be repalced with the server name from the configuration file",
|
||||||
|
{ARG_TYPE_SERVER, 0, 0} },
|
||||||
|
{ "servers", 0, dprintAllServers,
|
||||||
|
"Show all configured servers",
|
||||||
|
"Show all configured servers",
|
||||||
{0, 0, 0} },
|
{0, 0, 0} },
|
||||||
{ "services", 0, dprintAllServices, "Show all configured services in MaxScale",
|
{ "services", 0, dprintAllServices,
|
||||||
|
"Show all configured services in MaxScale",
|
||||||
|
"Show all configured services in MaxScale",
|
||||||
{0, 0, 0} },
|
{0, 0, 0} },
|
||||||
{ "session", 1, dprintSession, "Show a single session in MaxScale, e.g. show session 0x284830",
|
{ "service", 1, dprintService,
|
||||||
{ARG_TYPE_ADDRESS, 0, 0} },
|
"Show a single service in MaxScale, may be passed a service name",
|
||||||
{ "sessions", 0, dprintAllSessions, "Show all active sessions in MaxScale",
|
"Show a single service in MaxScale, may be passed a service name or address of a service object",
|
||||||
|
{ARG_TYPE_SERVICE, 0, 0} },
|
||||||
|
{ "session", 1, dprintSession,
|
||||||
|
"Show a single session in MaxScale, e.g. show session 0x284830",
|
||||||
|
"Show a single session in MaxScale, e.g. show session 0x284830",
|
||||||
|
{ARG_TYPE_SESSION, 0, 0} },
|
||||||
|
{ "sessions", 0, dprintAllSessions,
|
||||||
|
"Show all active sessions in MaxScale",
|
||||||
|
"Show all active sessions in MaxScale",
|
||||||
{0, 0, 0} },
|
{0, 0, 0} },
|
||||||
{ "users", 0, telnetdShowUsers, "Show statistics and user names for the debug interface",
|
{ "users", 0, telnetdShowUsers,
|
||||||
{ARG_TYPE_ADDRESS, 0, 0} },
|
"Show statistics and user names for the debug interface",
|
||||||
{ NULL, 0, NULL, NULL,
|
"Show statistics and user names for the debug interface",
|
||||||
|
{0, 0, 0} },
|
||||||
|
{ NULL, 0, NULL, NULL, NULL,
|
||||||
{0, 0, 0} }
|
{0, 0, 0} }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -126,7 +165,7 @@ struct subcommand shutdownoptions[] = {
|
|||||||
0,
|
0,
|
||||||
shutdown_server,
|
shutdown_server,
|
||||||
"Shutdown MaxScale",
|
"Shutdown MaxScale",
|
||||||
|
"Shutdown MaxScale",
|
||||||
{0, 0, 0}
|
{0, 0, 0}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -134,20 +173,23 @@ struct subcommand shutdownoptions[] = {
|
|||||||
1,
|
1,
|
||||||
shutdown_monitor,
|
shutdown_monitor,
|
||||||
"Shutdown a monitor, e.g. shutdown monitor 0x48381e0",
|
"Shutdown a monitor, e.g. shutdown monitor 0x48381e0",
|
||||||
{ARG_TYPE_ADDRESS, 0, 0}
|
"Shutdown a monitor, e.g. shutdown monitor 0x48381e0",
|
||||||
|
{ARG_TYPE_MONITOR, 0, 0}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"service",
|
"service",
|
||||||
1,
|
1,
|
||||||
shutdown_service,
|
shutdown_service,
|
||||||
"Shutdown a service, e.g. shutdown service 0x4838320",
|
"Shutdown a service, e.g. shutdown service \"Sales Database\"",
|
||||||
{ARG_TYPE_ADDRESS, 0, 0}
|
"Shutdown a service, e.g. shutdown service 0x4838320 or shutdown service \"Sales Database\"",
|
||||||
|
{ARG_TYPE_SERVICE, 0, 0}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
NULL,
|
NULL,
|
||||||
0,
|
0,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
|
NULL,
|
||||||
{0, 0, 0}
|
{0, 0, 0}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -159,11 +201,15 @@ static void restart_monitor(DCB *dcb, MONITOR *monitor);
|
|||||||
* The subcommands of the restart command
|
* The subcommands of the restart command
|
||||||
*/
|
*/
|
||||||
struct subcommand restartoptions[] = {
|
struct subcommand restartoptions[] = {
|
||||||
{ "monitor", 1, restart_monitor, "Restart a monitor, e.g. restart monitor 0x48181e0",
|
{ "monitor", 1, restart_monitor,
|
||||||
{ARG_TYPE_ADDRESS, 0, 0} },
|
"Restart a monitor, e.g. restart monitor 0x48181e0",
|
||||||
{ "service", 1, restart_service, "Restart a service, e.g. restart service 0x4838320",
|
"Restart a monitor, e.g. restart monitor 0x48181e0",
|
||||||
{ARG_TYPE_ADDRESS, 0, 0} },
|
{ARG_TYPE_MONITOR, 0, 0} },
|
||||||
{ NULL, 0, NULL, NULL,
|
{ "service", 1, restart_service,
|
||||||
|
"Restart a service, e.g. restart service \"Test Service\"",
|
||||||
|
"Restart a service, e.g. restart service 0x4838320",
|
||||||
|
{ARG_TYPE_SERVICE, 0, 0} },
|
||||||
|
{ NULL, 0, NULL, NULL, NULL,
|
||||||
{0, 0, 0} }
|
{0, 0, 0} }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -172,9 +218,11 @@ static void set_server(DCB *dcb, SERVER *server, char *bit);
|
|||||||
* The subcommands of the set command
|
* The subcommands of the set command
|
||||||
*/
|
*/
|
||||||
struct subcommand setoptions[] = {
|
struct subcommand setoptions[] = {
|
||||||
{ "server", 2, set_server, "Set the status of a server. E.g. set server 0x4838320 master",
|
{ "server", 2, set_server,
|
||||||
{ARG_TYPE_ADDRESS, ARG_TYPE_STRING, 0} },
|
"Set the status of a server. E.g. set server dbnode4 master",
|
||||||
{ NULL, 0, NULL, NULL,
|
"Set the status of a server. E.g. set server 0x4838320 master",
|
||||||
|
{ARG_TYPE_SERVER, ARG_TYPE_STRING, 0} },
|
||||||
|
{ NULL, 0, NULL, NULL, NULL,
|
||||||
{0, 0, 0} }
|
{0, 0, 0} }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -183,9 +231,11 @@ static void clear_server(DCB *dcb, SERVER *server, char *bit);
|
|||||||
* The subcommands of the clear command
|
* The subcommands of the clear command
|
||||||
*/
|
*/
|
||||||
struct subcommand clearoptions[] = {
|
struct subcommand clearoptions[] = {
|
||||||
{ "server", 2, clear_server, "Clear the status of a server. E.g. clear server 0x4838320 master",
|
{ "server", 2, clear_server,
|
||||||
{ARG_TYPE_ADDRESS, ARG_TYPE_STRING, 0} },
|
"Clear the status of a server. E.g. clear server dbnode2 master",
|
||||||
{ NULL, 0, NULL, NULL,
|
"Clear the status of a server. E.g. clear server 0x4838320 master",
|
||||||
|
{ARG_TYPE_SERVER, ARG_TYPE_STRING, 0} },
|
||||||
|
{ NULL, 0, NULL, NULL, NULL,
|
||||||
{0, 0, 0} }
|
{0, 0, 0} }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -196,11 +246,15 @@ static void reload_config(DCB *dcb);
|
|||||||
* The subcommands of the reload command
|
* The subcommands of the reload command
|
||||||
*/
|
*/
|
||||||
struct subcommand reloadoptions[] = {
|
struct subcommand reloadoptions[] = {
|
||||||
{ "config", 0, reload_config, "Reload the configuration data for MaxScale.",
|
{ "config", 0, reload_config,
|
||||||
{ARG_TYPE_ADDRESS, 0, 0} },
|
"Reload the configuration data for MaxScale.",
|
||||||
{ "dbusers", 1, reload_dbusers, "Reload the dbuser data for a service. E.g. reload dbusers 0x849420",
|
"Reload the configuration data for MaxScale.",
|
||||||
{ARG_TYPE_ADDRESS, 0, 0} },
|
{0, 0, 0} },
|
||||||
{ NULL, 0, NULL, NULL,
|
{ "dbusers", 1, reload_dbusers,
|
||||||
|
"Reload the dbuser data for a service. E.g. reload dbusers \"splitter service\"",
|
||||||
|
"Reload the dbuser data for a service. E.g. reload dbusers 0x849420",
|
||||||
|
{ARG_TYPE_DBUSERS, 0, 0} },
|
||||||
|
{ NULL, 0, NULL, NULL, NULL,
|
||||||
{0, 0, 0} }
|
{0, 0, 0} }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -217,6 +271,8 @@ struct subcommand enableoptions[] = {
|
|||||||
enable_log_action,
|
enable_log_action,
|
||||||
"Enable Log options for MaxScale, options trace | error | "
|
"Enable Log options for MaxScale, options trace | error | "
|
||||||
"message E.g. enable log message.",
|
"message E.g. enable log message.",
|
||||||
|
"Enable Log options for MaxScale, options trace | error | "
|
||||||
|
"message E.g. enable log message.",
|
||||||
{ARG_TYPE_STRING, 0, 0}
|
{ARG_TYPE_STRING, 0, 0}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -224,6 +280,7 @@ struct subcommand enableoptions[] = {
|
|||||||
0,
|
0,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
|
NULL,
|
||||||
{0, 0, 0}
|
{0, 0, 0}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -239,6 +296,8 @@ struct subcommand disableoptions[] = {
|
|||||||
disable_log_action,
|
disable_log_action,
|
||||||
"Disable Log for MaxScale, Options: debug | trace | error | message "
|
"Disable Log for MaxScale, Options: debug | trace | error | message "
|
||||||
"E.g. disable log debug",
|
"E.g. disable log debug",
|
||||||
|
"Disable Log for MaxScale, Options: debug | trace | error | message "
|
||||||
|
"E.g. disable log debug",
|
||||||
{ARG_TYPE_STRING, 0, 0}
|
{ARG_TYPE_STRING, 0, 0}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -246,6 +305,7 @@ struct subcommand disableoptions[] = {
|
|||||||
0,
|
0,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
|
NULL,
|
||||||
{0, 0, 0}
|
{0, 0, 0}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -264,6 +324,7 @@ struct subcommand failoptions[] = {
|
|||||||
0,
|
0,
|
||||||
fail_backendfd,
|
fail_backendfd,
|
||||||
"Fail backend socket for next operation.",
|
"Fail backend socket for next operation.",
|
||||||
|
"Fail backend socket for next operation.",
|
||||||
{ARG_TYPE_STRING, 0, 0}
|
{ARG_TYPE_STRING, 0, 0}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -271,6 +332,7 @@ struct subcommand failoptions[] = {
|
|||||||
0,
|
0,
|
||||||
fail_clientfd,
|
fail_clientfd,
|
||||||
"Fail client socket for next operation.",
|
"Fail client socket for next operation.",
|
||||||
|
"Fail client socket for next operation.",
|
||||||
{ARG_TYPE_STRING, 0, 0}
|
{ARG_TYPE_STRING, 0, 0}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -278,6 +340,7 @@ struct subcommand failoptions[] = {
|
|||||||
2,
|
2,
|
||||||
fail_accept,
|
fail_accept,
|
||||||
"Fail to accept next client connection.",
|
"Fail to accept next client connection.",
|
||||||
|
"Fail to accept next client connection.",
|
||||||
{ARG_TYPE_STRING, ARG_TYPE_STRING, 0}
|
{ARG_TYPE_STRING, ARG_TYPE_STRING, 0}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -285,6 +348,7 @@ struct subcommand failoptions[] = {
|
|||||||
0,
|
0,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
|
NULL,
|
||||||
{0, 0, 0}
|
{0, 0, 0}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -295,9 +359,11 @@ static void telnetdAddUser(DCB *, char *, char *);
|
|||||||
* The subcommands of the add command
|
* The subcommands of the add command
|
||||||
*/
|
*/
|
||||||
struct subcommand addoptions[] = {
|
struct subcommand addoptions[] = {
|
||||||
{ "user", 2, telnetdAddUser, "Add a new user for the debug interface. E.g. add user john today",
|
{ "user", 2, telnetdAddUser,
|
||||||
|
"Add a new user for the debug interface. E.g. add user john today",
|
||||||
|
"Add a new user for the debug interface. E.g. add user john today",
|
||||||
{ARG_TYPE_STRING, ARG_TYPE_STRING, 0} },
|
{ARG_TYPE_STRING, ARG_TYPE_STRING, 0} },
|
||||||
{ NULL, 0, NULL, NULL,
|
{ NULL, 0, NULL, NULL, NULL,
|
||||||
{0, 0, 0} }
|
{0, 0, 0} }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -312,10 +378,11 @@ struct subcommand removeoptions[] = {
|
|||||||
2,
|
2,
|
||||||
telnetdRemoveUser,
|
telnetdRemoveUser,
|
||||||
"Remove existing maxscale user. Example : remove user john johnpwd",
|
"Remove existing maxscale user. Example : remove user john johnpwd",
|
||||||
|
"Remove existing maxscale user. Example : remove user john johnpwd",
|
||||||
{ARG_TYPE_STRING, ARG_TYPE_STRING, 0}
|
{ARG_TYPE_STRING, ARG_TYPE_STRING, 0}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
NULL, 0, NULL, NULL, {0, 0, 0}
|
NULL, 0, NULL, NULL, NULL, {0, 0, 0}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -348,19 +415,59 @@ static struct {
|
|||||||
* Convert a string argument to a numeric, observing prefixes
|
* Convert a string argument to a numeric, observing prefixes
|
||||||
* for number bases, e.g. 0x for hex, 0 for octal
|
* for number bases, e.g. 0x for hex, 0 for octal
|
||||||
*
|
*
|
||||||
|
* @param mode The CLI mode
|
||||||
* @param arg The string representation of the argument
|
* @param arg The string representation of the argument
|
||||||
* @param arg_type The target type for the argument
|
* @param arg_type The target type for the argument
|
||||||
* @return The argument as a long integer
|
* @return The argument as a long integer
|
||||||
*/
|
*/
|
||||||
static unsigned long
|
static unsigned long
|
||||||
convert_arg(char *arg, int arg_type)
|
convert_arg(int mode, char *arg, int arg_type)
|
||||||
{
|
{
|
||||||
|
unsigned long rval;
|
||||||
|
SERVICE *service;
|
||||||
|
|
||||||
switch (arg_type)
|
switch (arg_type)
|
||||||
{
|
{
|
||||||
|
case ARG_TYPE_SERVICE:
|
||||||
|
if ((rval = (unsigned long)strtol(arg, NULL, 0)) == 0)
|
||||||
|
rval = (unsigned long)service_find(arg);
|
||||||
|
return rval;
|
||||||
case ARG_TYPE_ADDRESS:
|
case ARG_TYPE_ADDRESS:
|
||||||
return (unsigned long)strtol(arg, NULL, 0);
|
return (unsigned long)strtol(arg, NULL, 0);
|
||||||
case ARG_TYPE_STRING:
|
case ARG_TYPE_STRING:
|
||||||
return (unsigned long)arg;
|
return (unsigned long)arg;
|
||||||
|
case ARG_TYPE_SERVICE:
|
||||||
|
if (mode == CLIM_USER || (rval = (unsigned long)strtol(arg, NULL, 0)) == 0)
|
||||||
|
rval = (unsigned long)service_find(arg);
|
||||||
|
return rval;
|
||||||
|
case ARG_TYPE_SERVER:
|
||||||
|
if (mode == CLIM_USER || (rval = (unsigned long)strtol(arg, NULL, 0)) == 0)
|
||||||
|
rval = (unsigned long)server_find_by_unique_name(arg);
|
||||||
|
return rval;
|
||||||
|
case ARG_TYPE_DBUSERS:
|
||||||
|
if (mode == CLIM_USER || (rval = (unsigned long)strtol(arg, NULL, 0)) == 0)
|
||||||
|
{
|
||||||
|
service = service_find(arg);
|
||||||
|
if (service)
|
||||||
|
return (unsigned long)(service->users);
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return rval;
|
||||||
|
case ARG_TYPE_DCB:
|
||||||
|
rval = (unsigned long)strtol(arg, NULL, 0);
|
||||||
|
if (mode == CLIM_USER && dcb_isvalid((DCB *)rval) == 0)
|
||||||
|
rval = 0;
|
||||||
|
return rval;
|
||||||
|
case ARG_TYPE_SESSION:
|
||||||
|
rval = (unsigned long)strtol(arg, NULL, 0);
|
||||||
|
if (mode == CLIM_USER && session_isvalid((SESSION *)rval) == 0)
|
||||||
|
rval = 0;
|
||||||
|
return rval;
|
||||||
|
case ARG_TYPE_MONITOR:
|
||||||
|
if (mode == CLIM_USER || (rval = (unsigned long)strtol(arg, NULL, 0)) == 0)
|
||||||
|
rval = (unsigned long)monitor_find(arg);
|
||||||
|
return rval;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -387,33 +494,94 @@ int argc, i, j, found = 0;
|
|||||||
char *args[MAXARGS];
|
char *args[MAXARGS];
|
||||||
char *saveptr, *delim = " \t\r\n";
|
char *saveptr, *delim = " \t\r\n";
|
||||||
unsigned long arg1, arg2, arg3;
|
unsigned long arg1, arg2, arg3;
|
||||||
|
int in_quotes = 0, escape_next = 0;
|
||||||
|
char *ptr, *lptr;
|
||||||
|
|
||||||
/* Tokenize the input string */
|
args[0] = cli->cmdbuf;
|
||||||
args[0] = strtok_r(cli->cmdbuf, delim, &saveptr);
|
ptr = args[0];
|
||||||
|
lptr = ptr;
|
||||||
i = 0;
|
i = 0;
|
||||||
do {
|
/*
|
||||||
i++;
|
* Break the command line into a number of words. Whitespace is used
|
||||||
args[i] = strtok_r(NULL, delim, &saveptr);
|
* to delimit words and may be escaped by use of the \ character or
|
||||||
} while (args[i] != NULL && i < MAXARGS);
|
* the use of double quotes.
|
||||||
|
* The array args contains the broken down words, one per index.
|
||||||
|
*/
|
||||||
|
while (*ptr)
|
||||||
|
{
|
||||||
|
if (escape_next)
|
||||||
|
{
|
||||||
|
*lptr++ = *ptr++;
|
||||||
|
escape_next = 0;
|
||||||
|
}
|
||||||
|
else if (*ptr == '\\')
|
||||||
|
{
|
||||||
|
escape_next = 1;
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
else if (in_quotes == 0 && (*ptr == ' ' || *ptr == '\t' || *ptr == '\r' || *ptr == '\n'))
|
||||||
|
{
|
||||||
|
*lptr = 0;
|
||||||
|
if (args[i] == ptr)
|
||||||
|
args[i] = ptr + 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
if (i >= MAXARGS)
|
||||||
|
break;
|
||||||
|
args[i] = ptr + 1;
|
||||||
|
}
|
||||||
|
ptr++;
|
||||||
|
lptr++;
|
||||||
|
}
|
||||||
|
else if (*ptr == '\"' && in_quotes == 0)
|
||||||
|
{
|
||||||
|
in_quotes = 1;
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
else if (*ptr == '\"' && in_quotes == 1)
|
||||||
|
{
|
||||||
|
in_quotes = 0;
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*lptr++ = *ptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*lptr = 0;
|
||||||
|
args[i+1] = NULL;
|
||||||
|
|
||||||
if (args[0] == NULL)
|
if (args[0] == NULL || *args[0] == 0)
|
||||||
return 1;
|
return 1;
|
||||||
argc = i - 2; /* The number of extra arguments to commands */
|
argc = i - 2; /* The number of extra arguments to commands */
|
||||||
|
|
||||||
|
|
||||||
if (!strcasecmp(args[0], "help"))
|
if (!strcasecmp(args[0], "help"))
|
||||||
{
|
{
|
||||||
if (args[1] == NULL)
|
if (args[1] == NULL || *args[1] == 0)
|
||||||
{
|
{
|
||||||
found = 1;
|
found = 1;
|
||||||
dcb_printf(dcb, "Available commands:\n");
|
dcb_printf(dcb, "Available commands:\n");
|
||||||
for (i = 0; cmds[i].cmd; i++)
|
for (i = 0; cmds[i].cmd; i++)
|
||||||
{
|
{
|
||||||
for (j = 0; cmds[i].options[j].arg1; j++)
|
if (cmds[i].options[1].arg1 == NULL)
|
||||||
|
dcb_printf(dcb, " %s %s\n", cmds[i].cmd, cmds[i].options[0].arg1);
|
||||||
|
else
|
||||||
{
|
{
|
||||||
dcb_printf(dcb, " %s %s\n", cmds[i].cmd, cmds[i].options[j].arg1);
|
dcb_printf(dcb, " %s [", cmds[i].cmd);
|
||||||
|
for (j = 0; cmds[i].options[j].arg1; j++)
|
||||||
|
{
|
||||||
|
dcb_printf(dcb, "%s%s", cmds[i].options[j].arg1,
|
||||||
|
cmds[i].options[j+1].arg1 ? "|" : "");
|
||||||
|
}
|
||||||
|
dcb_printf(dcb, "]\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
dcb_printf(dcb, "\nType help command to see details of each command.\n");
|
||||||
|
dcb_printf(dcb, "Where commands require names as arguments and these names contain\n");
|
||||||
|
dcb_printf(dcb, "whitespace either the \\ character may be used to escape the whitespace\n");
|
||||||
|
dcb_printf(dcb, "or the name may be enclosed in double quotes \".\n\n");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -449,9 +617,9 @@ unsigned long arg1, arg2, arg3;
|
|||||||
{
|
{
|
||||||
for (j = 0; cmds[i].options[j].arg1; j++)
|
for (j = 0; cmds[i].options[j].arg1; j++)
|
||||||
{
|
{
|
||||||
found = 1; /**< command and sub-command match */
|
|
||||||
if (strcasecmp(args[1], cmds[i].options[j].arg1) == 0)
|
if (strcasecmp(args[1], cmds[i].options[j].arg1) == 0)
|
||||||
{
|
{
|
||||||
|
found = 1; /**< command and sub-command match */
|
||||||
if (argc != cmds[i].options[j].n_args)
|
if (argc != cmds[i].options[j].n_args)
|
||||||
{
|
{
|
||||||
dcb_printf(dcb, "Incorrect number of arguments: %s %s expects %d arguments\n",
|
dcb_printf(dcb, "Incorrect number of arguments: %s %s expects %d arguments\n",
|
||||||
@ -467,7 +635,7 @@ unsigned long arg1, arg2, arg3;
|
|||||||
cmds[i].options[j].fn(dcb);
|
cmds[i].options[j].fn(dcb);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
arg1 = convert_arg(args[2],cmds[i].options[j].arg_types[0]);
|
arg1 = convert_arg(cli->mode, args[2],cmds[i].options[j].arg_types[0]);
|
||||||
if (arg1)
|
if (arg1)
|
||||||
cmds[i].options[j].fn(dcb, arg1);
|
cmds[i].options[j].fn(dcb, arg1);
|
||||||
else
|
else
|
||||||
@ -475,8 +643,8 @@ unsigned long arg1, arg2, arg3;
|
|||||||
args[2]);
|
args[2]);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
arg1 = convert_arg(args[2],cmds[i].options[j].arg_types[0]);
|
arg1 = convert_arg(cli->mode, args[2],cmds[i].options[j].arg_types[0]);
|
||||||
arg2 = convert_arg(args[3],cmds[i].options[j].arg_types[1]);
|
arg2 = convert_arg(cli->mode, args[3],cmds[i].options[j].arg_types[1]);
|
||||||
if (arg1 && arg2)
|
if (arg1 && arg2)
|
||||||
cmds[i].options[j].fn(dcb, arg1, arg2);
|
cmds[i].options[j].fn(dcb, arg1, arg2);
|
||||||
else if (arg1 == 0)
|
else if (arg1 == 0)
|
||||||
@ -487,9 +655,9 @@ unsigned long arg1, arg2, arg3;
|
|||||||
args[3]);
|
args[3]);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
arg1 = convert_arg(args[2],cmds[i].options[j].arg_types[0]);
|
arg1 = convert_arg(cli->mode, args[2],cmds[i].options[j].arg_types[0]);
|
||||||
arg2 = convert_arg(args[3],cmds[i].options[j].arg_types[1]);
|
arg2 = convert_arg(cli->mode, args[3],cmds[i].options[j].arg_types[1]);
|
||||||
arg3 = convert_arg(args[4],cmds[i].options[j].arg_types[2]);
|
arg3 = convert_arg(cli->mode, args[4],cmds[i].options[j].arg_types[2]);
|
||||||
if (arg1 && arg2 && arg3)
|
if (arg1 && arg2 && arg3)
|
||||||
cmds[i].options[j].fn(dcb, arg1, arg2, arg3);
|
cmds[i].options[j].fn(dcb, arg1, arg2, arg3);
|
||||||
else if (arg1 == 0)
|
else if (arg1 == 0)
|
||||||
|
Reference in New Issue
Block a user