From 9e164b83f08badfa3b0bd12a1ac09c143c38f45b Mon Sep 17 00:00:00 2001 From: Mark Riddoch Date: Sat, 7 Jun 2014 20:41:58 +0100 Subject: [PATCH 1/6] Updates to debug CLI Fix for argument passign to show filter Addition of list dcbs commands --- server/core/dcb.c | 76 ++++++++++++++++++++++++------- server/include/dcb.h | 1 + server/modules/routing/debugcmd.c | 6 ++- 3 files changed, 65 insertions(+), 18 deletions(-) diff --git a/server/core/dcb.c b/server/core/dcb.c index 16ca964ac..517b697cd 100644 --- a/server/core/dcb.c +++ b/server/core/dcb.c @@ -1089,12 +1089,18 @@ printDCB(DCB *dcb) if (dcb->writeq) printf("\tQueued write data: %d\n",gwbuf_length(dcb->writeq)); printf("\tStatistics:\n"); - printf("\t\tNo. of Reads: %d\n", dcb->stats.n_reads); - printf("\t\tNo. of Writes: %d\n", dcb->stats.n_writes); - printf("\t\tNo. of Buffered Writes: %d\n", dcb->stats.n_buffered); - printf("\t\tNo. of Accepts: %d\n", dcb->stats.n_accepts); - 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); + printf("\t\tNo. of Reads: %d\n", + dcb->stats.n_reads); + printf("\t\tNo. of Writes: %d\n", + dcb->stats.n_writes); + printf("\t\tNo. of Buffered Writes: %d\n", + dcb->stats.n_buffered); + printf("\t\tNo. of Accepts: %d\n", + dcb->stats.n_accepts); + 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); } /** @@ -1129,13 +1135,17 @@ DCB *dcb; while (dcb) { dcb_printf(pdcb, "DCB: %p\n", (void *)dcb); - dcb_printf(pdcb, "\tDCB state: %s\n", gw_dcb_state2string(dcb->state)); + dcb_printf(pdcb, "\tDCB state: %s\n", + gw_dcb_state2string(dcb->state)); if (dcb->session && dcb->session->service) - dcb_printf(pdcb, "\tService: %s\n", dcb->session->service->name); + dcb_printf(pdcb, "\tService: %s\n", + dcb->session->service->name); if (dcb->remote) - dcb_printf(pdcb, "\tConnected to: %s\n", dcb->remote); + dcb_printf(pdcb, "\tConnected to: %s\n", + dcb->remote); if (dcb->writeq) - dcb_printf(pdcb, "\tQueued write data: %d\n", gwbuf_length(dcb->writeq)); + 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); @@ -1148,6 +1158,32 @@ DCB *dcb; spinlock_release(&dcbspin); } +/** + * Diagnotic routine to print DCB data in a tabular form. + * + * @param pdcb DCB to print results to + */ +void +dListDCBs(DCB *pdcb) +{ +DCB *dcb; + + spinlock_acquire(&dcbspin); + dcb = allDCBs; + dcb_printf(pdcb, " %-10s | %-26s | %-20s | %s\n", + "DCB", "State", "Service", "Remote"); + dcb_printf(pdcb, "---------------------------------------------------------------------------\n"); + while (dcb) + { + dcb_printf(pdcb, " %10p | %-26s | %-20s | %s\n", + dcb, gw_dcb_state2string(dcb->state), + (dcb->service ? dcb->service->name : ""), + (dcb->remote ? dcb->remote : "")); + dcb = dcb->next; + } + spinlock_release(&dcbspin); +} + /** * Diagnostic to print a DCB to another DCB * @@ -1161,16 +1197,22 @@ dprintDCB(DCB *pdcb, DCB *dcb) dcb_printf(pdcb, "\tDCB state: %s\n", gw_dcb_state2string(dcb->state)); if (dcb->remote) dcb_printf(pdcb, "\tConnected to: %s\n", dcb->remote); - dcb_printf(pdcb, "\tOwning Session: %d\n", dcb->session); + dcb_printf(pdcb, "\tOwning Session: %p\n", dcb->session); if (dcb->writeq) 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_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_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_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); } /** diff --git a/server/include/dcb.h b/server/include/dcb.h index 49a262f73..e7d2ec716 100644 --- a/server/include/dcb.h +++ b/server/include/dcb.h @@ -273,6 +273,7 @@ void printAllDCBs(); /* Debug to print all DCB in the system */ void printDCB(DCB *); /* Debug print routine */ void dprintAllDCBs(DCB *); /* Debug to print all DCB in the system */ void dprintDCB(DCB *, DCB *); /* Debug to print a DCB in the system */ +void dListDCBs(DCB *); /* List all DCBs in the system */ const char *gw_dcb_state2string(int); /* DCB state to string */ void dcb_printf(DCB *, const char *, ...); /* DCB version of printf */ int dcb_isclient(DCB *); /* the DCB is the client of the session */ diff --git a/server/modules/routing/debugcmd.c b/server/modules/routing/debugcmd.c index eb0fc2832..4bd19e957 100644 --- a/server/modules/routing/debugcmd.c +++ b/server/modules/routing/debugcmd.c @@ -116,7 +116,7 @@ struct subcommand showoptions[] = { "Show the poll statistics", "Show the poll statistics", {0, 0, 0} }, - { "filter", 0, dprintFilter, + { "filter", 1, dprintFilter, "Show details of a filter, called with a filter name", "Show details of a filter, called with the address of a filter", {ARG_TYPE_FILTER, 0, 0} }, @@ -168,6 +168,10 @@ struct subcommand showoptions[] = { * The subcommands of the list command */ struct subcommand listoptions[] = { + { "dcbs", 0, dListDCBs, + "List all the DCBs active within MaxScale", + "List all the DCBs active within MaxScale", + {0, 0, 0} }, { "filters", 0, dListFilters, "List all the filters defined within MaxScale", "List all the filters defined within MaxScale", From 02330093cc12c1d3808a0a44702bd3226ff8e7aa Mon Sep 17 00:00:00 2001 From: VilhoRaatikka Date: Wed, 11 Jun 2014 15:33:42 +0300 Subject: [PATCH 2/6] Added test for session commands. --- .../routing/readwritesplit/test/rwsplit.sh | 39 +++++++++++++++++++ .../readwritesplit/test/test_sescmd.sql | 4 ++ 2 files changed, 43 insertions(+) create mode 100644 server/modules/routing/readwritesplit/test/test_sescmd.sql diff --git a/server/modules/routing/readwritesplit/test/rwsplit.sh b/server/modules/routing/readwritesplit/test/rwsplit.sh index 6c5268d46..36199e384 100755 --- a/server/modules/routing/readwritesplit/test/rwsplit.sh +++ b/server/modules/routing/readwritesplit/test/rwsplit.sh @@ -191,3 +191,42 @@ else echo "$TINPUT PASSED">>$TLOG ; fi + +TINPUT=test_sescmd.sql +TRETVAL=2 +a=`$RUNCMD < ./$TINPUT` +if [ "$a" != "$TRETVAL" ]; then + echo "$TINPUT FAILED, return value $a when $TRETVAL was expected">>$TLOG; +else + echo "$TINPUT PASSED">>$TLOG ; +fi +a=`$RUNCMD < ./$TINPUT` +if [ "$a" != "$TRETVAL" ]; then + echo "$TINPUT FAILED, return value $a when $TRETVAL was expected">>$TLOG; +else + echo "$TINPUT PASSED">>$TLOG ; +fi +a=`$RUNCMD < ./$TINPUT` +if [ "$a" != "$TRETVAL" ]; then + echo "$TINPUT FAILED, return value $a when $TRETVAL was expected">>$TLOG; +else + echo "$TINPUT PASSED">>$TLOG ; +fi +a=`$RUNCMD < ./$TINPUT` +if [ "$a" != "$TRETVAL" ]; then + echo "$TINPUT FAILED, return value $a when $TRETVAL was expected">>$TLOG; +else + echo "$TINPUT PASSED">>$TLOG ; +fi +a=`$RUNCMD < ./$TINPUT` +if [ "$a" != "$TRETVAL" ]; then + echo "$TINPUT FAILED, return value $a when $TRETVAL was expected">>$TLOG; +else + echo "$TINPUT PASSED">>$TLOG ; +fi +a=`$RUNCMD < ./$TINPUT` +if [ "$a" != "$TRETVAL" ]; then + echo "$TINPUT FAILED, return value $a when $TRETVAL was expected">>$TLOG; +else + echo "$TINPUT PASSED">>$TLOG ; +fi diff --git a/server/modules/routing/readwritesplit/test/test_sescmd.sql b/server/modules/routing/readwritesplit/test/test_sescmd.sql new file mode 100644 index 000000000..7bc6edcf9 --- /dev/null +++ b/server/modules/routing/readwritesplit/test/test_sescmd.sql @@ -0,0 +1,4 @@ +use test; +set autocommit=1; +use mysql; +select count(*) from user where user='maxuser' From 719503e471c5301d7621f303df012c589f12cc08 Mon Sep 17 00:00:00 2001 From: Mark Riddoch Date: Fri, 13 Jun 2014 23:40:07 +0100 Subject: [PATCH 3/6] Addition of new client utility, maxadmin. Supporting protocol for the admin interface New routing module, cli, which shares source with debugcli Tidyup output of lsit commands --- Makefile | 4 + client/.maxadmin.c.swp | Bin 0 -> 20480 bytes client/Makefile | 71 ++++++ client/depend.mk | 0 client/maxadmin.c | 373 +++++++++++++++++++++++++++ server/core/dcb.c | 8 +- server/core/filter.c | 4 +- server/core/load_utils.c | 3 +- server/core/server.c | 4 +- server/core/service.c | 8 +- server/core/session.c | 4 +- server/modules/include/maxscaled.h | 46 ++++ server/modules/protocol/Makefile | 8 +- server/modules/protocol/maxscaled.c | 383 ++++++++++++++++++++++++++++ server/modules/routing/Makefile | 9 +- server/modules/routing/cli.c | 297 +++++++++++++++++++++ server/modules/routing/debugcmd.c | 2 + 17 files changed, 1212 insertions(+), 12 deletions(-) create mode 100644 client/.maxadmin.c.swp create mode 100644 client/Makefile create mode 100644 client/depend.mk create mode 100644 client/maxadmin.c create mode 100644 server/modules/include/maxscaled.h create mode 100644 server/modules/protocol/maxscaled.c create mode 100644 server/modules/routing/cli.c diff --git a/Makefile b/Makefile index 67eb0d159..07a385b61 100644 --- a/Makefile +++ b/Makefile @@ -39,21 +39,25 @@ all: (cd log_manager; make) (cd query_classifier; make) (cd server; make) + (cd client; make) clean: (cd log_manager; make clean) (cd query_classifier; make clean) (cd server; make clean) + (cd client; make clean) depend: (cd log_manager; make depend) (cd query_classifier; make depend) (cd server; make depend) + (cd client; make depend) install: (cd server; make DEST=$(DEST) install) (cd log_manager; make DEST=$(DEST) install) (cd query_classifier; make DEST=$(DEST) install) + (cd client; make DEST=$(DEST) install) cleantests: $(MAKE) -C test cleantests diff --git a/client/.maxadmin.c.swp b/client/.maxadmin.c.swp new file mode 100644 index 0000000000000000000000000000000000000000..a864922abaa67d4cffcffed3281a0d4ade6de26b GIT binary patch literal 20480 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 depend.mk + +install: maxadmin + @mkdir -p $(DEST)/bin + install -D maxadmin $(DEST)/bin + +include depend.mk diff --git a/client/depend.mk b/client/depend.mk new file mode 100644 index 000000000..e69de29bb diff --git a/client/maxadmin.c b/client/maxadmin.c new file mode 100644 index 000000000..4065a971d --- /dev/null +++ b/client/maxadmin.c @@ -0,0 +1,373 @@ +/* + * This file is distributed as part of MaxScale. 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 2014 + */ + +/** + * @file maxadmin.c - The MaxScale administration client + * + * @verbatim + * Revision History + * + * Date Who Description + * 13/06/14 Mark Riddoch Initial implementation + * + * @endverbatim + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static int connectMaxScale(char *hostname, char *port); +static int setipaddress(struct in_addr *a, char *p); +static int authMaxScale(int so, char *user, char *password); +static int sendCommand(int so, char *cmd); + +static char * +prompt(EditLine *el __attribute__((__unused__))) +{ + static char prompt[] = "MaxScale> "; + + return prompt; +} + +int +main(int argc, char **argv) +{ +EditLine *el = NULL; +int i, num, rv, fatal = 0; +char *buf; +Tokenizer *tok; +History *hist; +HistEvent ev; +const LineInfo *li; +char *hostname = "localhost"; +char *port = "6603"; +char *user = "admin"; +char *passwd = NULL; +int so, cmdlen; +char *cmd; + + cmd = malloc(1); + *cmd = 0; + cmdlen = 1; + + for (i = 1; i < argc; i++) + { + if (argv[i][0] == '-') + { + switch (argv[i][1]) + { + case 'u': /* User */ + if (argv[i][2]) + user = &(argv[i][2]); + else if (i + 1 < argc) + user = argv[++i]; + else + { + fprintf(stderr, "Missing username" + "in -u option.\n"); + fatal = 1; + } + break; + case 'p': /* Password */ + if (argv[i][2]) + passwd = &(argv[i][2]); + else if (i + 1 < argc) + passwd = argv[++i]; + else + { + fprintf(stderr, "Missing password " + "in -p option.\n"); + fatal = 1; + } + break; + case 'h': /* hostname */ + if (argv[i][2]) + hostname = &(argv[i][2]); + else if (i + 1 < argc) + hostname = argv[++i]; + else + { + fprintf(stderr, "Missing hostname value " + "in -h option.\n"); + fatal = 1; + } + break; + case 'P': /* Port */ + if (argv[i][2]) + port = &(argv[i][2]); + else if (i + 1 < argc) + port = argv[++i]; + else + { + fprintf(stderr, "Missing Port value " + "in -P option.\n"); + fatal = 1; + } + break; + } + } + else + { + cmdlen += strlen(argv[i]) + 1; + cmd = realloc(cmd, cmdlen); + strcat(cmd, argv[i]); + strcat(cmd, " "); + } + } + + if (fatal) + exit(1); + + if (passwd == NULL) + { + struct termios tty_attr; + tcflag_t c_lflag; + + if (tcgetattr(STDIN_FILENO, &tty_attr) < 0) + return -1; + + c_lflag = tty_attr.c_lflag; + tty_attr.c_lflag &= ~ICANON; + tty_attr.c_lflag &= ~ECHO; + + if (tcsetattr(STDIN_FILENO, 0, &tty_attr) < 0) + return -1; + + printf("Password: "); + passwd = malloc(80); + fgets(passwd, 80, stdin); + + tty_attr.c_lflag = c_lflag; + if (tcsetattr(STDIN_FILENO, 0, &tty_attr) < 0) + return -1; + i = strlen(passwd); + if (i > 1) + passwd[i - 1] = '\0'; + printf("\n"); + } + + if ((so = connectMaxScale(hostname, port)) == -1) + exit(1); + if (!authMaxScale(so, user, passwd)) + { + fprintf(stderr, "Failed to connect to MaxScale. " + "Incorrect username or password.\n"); + exit(1); + } + + if (cmdlen > 1) + { + cmd[cmdlen - 2] = '\0'; + sendCommand(so, cmd); + exit(0); + } + + (void) setlocale(LC_CTYPE, ""); + + hist = history_init(); /* Init the builtin history */ + /* Remember 100 events */ + history(hist, &ev, H_SETSIZE, 100); + + tok = tok_init(NULL); /* Initialize the tokenizer */ + + /* Initialize editline */ + el = el_init(*argv, stdin, stdout, stderr); + + el_set(el, EL_EDITOR, "vi"); /* Default editor is vi */ + el_set(el, EL_SIGNAL, 1); /* Handle signals gracefully */ + el_set(el, EL_PROMPT, prompt);/* Set the prompt function */ + + /* Tell editline to use this history interface */ + el_set(el, EL_HIST, history, hist); + + /* + * Bind j, k in vi command mode to previous and next line, instead + * of previous and next history. + */ + el_set(el, EL_BIND, "-a", "k", "ed-prev-line", NULL); + el_set(el, EL_BIND, "-a", "j", "ed-next-line", NULL); + + /* + * Source the user's defaults file. + */ + el_source(el, NULL); + + while ((buf = el_gets(el, &num)) != NULL && num != 0) + { + /* Strip trailing \n\r */ + for (i = num - 1; buf[i] == '\r' || buf[i] == '\n'; i--) + buf[i] = 0; + + li = el_line(el); + history(hist, &ev, H_ENTER, buf); + + if (!strcasecmp(buf, "quit")) + { + break; + } + else if (!strcasecmp(buf, "history")) + { + for (rv = history(hist, &ev, H_LAST); rv != -1; + rv = history(hist, &ev, H_PREV)) + fprintf(stdout, "%4d %s\n", + ev.num, ev.str); + } + else if (*buf) + { + sendCommand(so, buf); + } + } + + el_end(el); + tok_end(tok); + history_end(hist); + close(so); + return 0; +} + +static int +connectMaxScale(char *hostname, char *port) +{ +struct sockaddr_in addr; +int so; + + if ((so = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + fprintf(stderr, "Unable to create socket: %s\n", + strerror(errno)); + return -1; + } + memset(&addr, 0, sizeof addr); + addr.sin_family = AF_INET; + setipaddress(&addr.sin_addr, hostname); + addr.sin_port = htons(atoi(port)); + if (connect(so, (struct sockaddr *)&addr, sizeof(addr)) < 0) + { + fprintf(stderr, "Unable to connect to MaxScale at %s, %s: %s\n", + hostname, port, strerror(errno)); + return -1; + } + + return so; +} + + +/* + * Set IP address in socket structure in_addr + * + * @param a Pointer to a struct in_addr into which the address is written + * @param p The hostname to lookup + * @return 1 on success, 0 on failure + */ +static int +setipaddress(struct in_addr *a, char *p) +{ +#ifdef __USE_POSIX + struct addrinfo *ai = NULL, hint; + int rc; + struct sockaddr_in * res_addr; + memset(&hint, 0, sizeof (hint)); + + hint.ai_socktype = SOCK_STREAM; + hint.ai_flags = AI_CANONNAME; + hint.ai_family = AF_INET; + + if ((rc = getaddrinfo(p, NULL, &hint, &ai)) != 0) { + return 0; + } + + /* take the first one */ + if (ai != NULL) { + res_addr = (struct sockaddr_in *)(ai->ai_addr); + memcpy(a, &res_addr->sin_addr, sizeof(struct in_addr)); + + freeaddrinfo(ai); + + return 1; + } +#else + struct hostent *h; + + spinlock_acquire(&tmplock); + h = gethostbyname(p); + spinlock_release(&tmplock); + + if (h == NULL) { + if ((a->s_addr = inet_addr(p)) == -1) { + return 0; + } + } else { + /* take the first one */ + memcpy(a, h->h_addr, h->h_length); + + return 1; + } +#endif + return 0; +} + +static int +authMaxScale(int so, char *user, char *password) +{ +char buf[20]; + + read(so, buf, 4); + write(so, user, strlen(user)); + read(so, buf, 8); + write(so, password, strlen(password)); + read(so, buf, 6); + + return strncmp(buf, "FAILED", 6); +} + +static int +sendCommand(int so, char *cmd) +{ +char buf[80]; +int i; + + write(so, cmd, strlen(cmd)); + while (1) + { + if ((i = read(so, buf, 80)) == -1) + return 0; + if (i > 1 && buf[i-1] == 'K' && buf[i-2] == 'O') + { + write(1, buf, i - 2); + return 1; + } + write(1, buf, i); + } + return 1; +} diff --git a/server/core/dcb.c b/server/core/dcb.c index 517b697cd..5417abe80 100644 --- a/server/core/dcb.c +++ b/server/core/dcb.c @@ -1172,15 +1172,17 @@ DCB *dcb; dcb = allDCBs; dcb_printf(pdcb, " %-10s | %-26s | %-20s | %s\n", "DCB", "State", "Service", "Remote"); - dcb_printf(pdcb, "---------------------------------------------------------------------------\n"); + dcb_printf(pdcb, "------------+----------------------------+----------------------+----------\n"); while (dcb) { dcb_printf(pdcb, " %10p | %-26s | %-20s | %s\n", dcb, gw_dcb_state2string(dcb->state), - (dcb->service ? dcb->service->name : ""), + (dcb->session->service ? + dcb->session->service->name : ""), (dcb->remote ? dcb->remote : "")); - dcb = dcb->next; + dcb = dcb->next; } + dcb_printf(pdcb, "------------+----------------------------+----------------------+----------\n"); spinlock_release(&dcbspin); } diff --git a/server/core/filter.c b/server/core/filter.c index a3db72e3b..bf9eb4228 100644 --- a/server/core/filter.c +++ b/server/core/filter.c @@ -209,7 +209,7 @@ int i; { dcb_printf(dcb, "%-18s | %-15s | Options\n", "Filter", "Module"); - dcb_printf(dcb, "-------------------------------------------------------------------------------\n"); + dcb_printf(dcb, "--------------------+-----------------+----------------------------------------\n"); } while (ptr) { @@ -220,6 +220,8 @@ int i; dcb_printf(dcb, "\n"); ptr = ptr->next; } + if (allFilters) + dcb_printf(dcb, "--------------------+-----------------+----------------------------------------\n"); spinlock_release(&filter_spin); } diff --git a/server/core/load_utils.c b/server/core/load_utils.c index 3ace0f91f..188535375 100644 --- a/server/core/load_utils.c +++ b/server/core/load_utils.c @@ -360,7 +360,7 @@ dprintAllModules(DCB *dcb) MODULES *ptr = registered; dcb_printf(dcb, "%-15s | %-11s | Version | API | Status\n", "Module Name", "Module Type"); - dcb_printf(dcb, "--------------------------------------------------------------------------\n"); + dcb_printf(dcb, "----------------+-------------+---------+-------+-------------------------\n"); while (ptr) { dcb_printf(dcb, "%-15s | %-11s | %-7s ", ptr->module, ptr->type, ptr->version); @@ -380,4 +380,5 @@ MODULES *ptr = registered; dcb_printf(dcb, "\n"); ptr = ptr->next; } + dcb_printf(dcb, "----------------+-------------+---------+-------+-------------------------\n"); } diff --git a/server/core/server.c b/server/core/server.c index 42a60caea..0a13b7751 100644 --- a/server/core/server.c +++ b/server/core/server.c @@ -314,7 +314,7 @@ char *stat; { dcb_printf(dcb, "%-18s | %-15s | Port | %-18s | Connections\n", "Server", "Address", "Status"); - dcb_printf(dcb, "-------------------------------------------------------------------------------\n"); + dcb_printf(dcb, "-------------------+-----------------+-------+--------------------+------------\n"); } while (ptr) { @@ -326,6 +326,8 @@ char *stat; free(stat); ptr = ptr->next; } + if (allServers) + dcb_printf(dcb, "-------------------+-----------------+-------+--------------------+------------\n"); spinlock_release(&server_spin); } diff --git a/server/core/service.c b/server/core/service.c index d963987d5..f7c626a34 100644 --- a/server/core/service.c +++ b/server/core/service.c @@ -828,7 +828,7 @@ SERVICE *ptr; { dcb_printf(dcb, "%-25s | %-20s | #Users | Total Sessions\n", "Service Name", "Router Module"); - dcb_printf(dcb, "--------------------------------------------------------------------------\n"); + dcb_printf(dcb, "--------------------------+----------------------+--------+---------------\n"); } while (ptr) { @@ -837,6 +837,8 @@ SERVICE *ptr; ptr->stats.n_current, ptr->stats.n_sessions); ptr = ptr->next; } + if (allServices) + dcb_printf(dcb, "--------------------------+----------------------+--------+---------------\n"); spinlock_release(&service_spin); } @@ -857,7 +859,7 @@ SERV_PROTOCOL *lptr; { dcb_printf(dcb, "%-20s | %-18s | %-15s | Port | State\n", "Service Name", "Protocol Module", "Address"); - dcb_printf(dcb, "---------------------------------------------------------------------------\n"); + dcb_printf(dcb, "---------------------+--------------------+-----------------+-------+------\n"); } while (ptr) { @@ -875,6 +877,8 @@ SERV_PROTOCOL *lptr; } ptr = ptr->next; } + if (allServices) + dcb_printf(dcb, "---------------------+--------------------+-----------------+-------+------\n"); spinlock_release(&service_spin); } diff --git a/server/core/session.c b/server/core/session.c index cb392258c..bd24cde9a 100644 --- a/server/core/session.c +++ b/server/core/session.c @@ -538,7 +538,7 @@ SESSION *ptr; if (ptr) { dcb_printf(dcb, "Session | Client | State\n"); - dcb_printf(dcb, "------------------------------------------\n"); + dcb_printf(dcb, "-----------------+-----------------+----------------\n"); } while (ptr) { @@ -548,6 +548,8 @@ SESSION *ptr; session_state(ptr->state)); ptr = ptr->next; } + if (allSessions) + dcb_printf(dcb, "-----------------+-----------------+----------------\n"); spinlock_release(&session_spin); } diff --git a/server/modules/include/maxscaled.h b/server/modules/include/maxscaled.h new file mode 100644 index 000000000..3733772d8 --- /dev/null +++ b/server/modules/include/maxscaled.h @@ -0,0 +1,46 @@ +#ifndef _MAXSCALED_H +#define _MAXSCALED_H +/* + * This file is distributed as part of MaxScale. 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 2014 + */ + +/** + * @file maxscaled.h The maxscaled protocol module header file + * + * @verbatim + * Revision History + * + * Date Who Description + * 13/06/14 Mark Riddoch Initial implementation + * + * @endverbatim + */ +#include + +/** + * The telnetd specific protocol structure to put in the DCB. + */ +typedef struct maxscaled { + int state; /**< The connection state */ + char *username; /**< The login name of the user */ +} MAXSCALED; + +#define MAXSCALED_STATE_LOGIN 1 /**< Issued login prompt */ +#define MAXSCALED_STATE_PASSWD 2 /**< Issued password prompt */ +#define MAXSCALED_STATE_DATA 3 /**< User logged in */ + +#endif diff --git a/server/modules/protocol/Makefile b/server/modules/protocol/Makefile index 1d98f76db..789cd9b78 100644 --- a/server/modules/protocol/Makefile +++ b/server/modules/protocol/Makefile @@ -22,6 +22,7 @@ # headers so that liblog_manager.so can # be linked in. # 09/07/2013 Massimiliano Pinto Added the HTTPD protocol module +# 13/06/2014 Mark Riddoch Added thr MaxScale protocol module # include ../../../build_gateway.inc @@ -45,10 +46,12 @@ TELNETDSRCS=telnetd.c TELNETDOBJ=$(TELNETDSRCS:.c=.o) HTTPDSRCS=httpd.c HTTPDOBJ=$(HTTPDSRCS:.c=.o) +MAXSCALEDSRCS=maxscaled.c +MAXSCALEDOBJ=$(MAXSCALEDSRCS:.c=.o) SRCS=$(MYSQLCLIENTSRCS) $(MYSQLBACKENDSRCS) $(TELNETDSRCS) $(HTTPDSRCS) OBJ=$(SRCS:.c=.o) LIBS=$(UTILSPATH)/skygw_utils.o -MODULES=libMySQLClient.so libMySQLBackend.so libtelnetd.so libHTTPD.so +MODULES=libMySQLClient.so libMySQLBackend.so libtelnetd.so libHTTPD.so libmaxscaled.so all: $(MODULES) @@ -64,6 +67,9 @@ libtelnetd.so: $(TELNETDOBJ) libHTTPD.so: $(HTTPDOBJ) $(CC) $(LDFLAGS) $(HTTPDOBJ) $(LIBS) -o $@ +libmaxscaled.so: $(MAXSCALEDOBJ) + $(CC) $(LDFLAGS) $(MAXSCALEDOBJ) $(LIBS) -lcrypt -o $@ + .c.o: $(CC) $(CFLAGS) $< -o $@ diff --git a/server/modules/protocol/maxscaled.c b/server/modules/protocol/maxscaled.c new file mode 100644 index 000000000..f26a3d17a --- /dev/null +++ b/server/modules/protocol/maxscaled.c @@ -0,0 +1,383 @@ +/* + * This file is distributed as part of MaxScale. 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 2014 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_INFO info = { + MODULE_API_PROTOCOL, + MODULE_ALPHA_RELEASE, + GWPROTOCOL_VERSION, + "A maxscale protocol for the administration interface" +}; + +extern int lm_enabled_logfiles_bitmask; + +/** + * @file maxscaled.c - MaxScale administration protocol + * + * + * @verbatim + * Revision History + * Date Who Description + * 13/06/2014 Mark Riddoch Initial implementation + * + * @endverbatim + */ + +static char *version_str = "V1.0.0"; + +static int maxscaled_read_event(DCB* dcb); +static int maxscaled_write_event(DCB *dcb); +static int maxscaled_write(DCB *dcb, GWBUF *queue); +static int maxscaled_error(DCB *dcb); +static int maxscaled_hangup(DCB *dcb); +static int maxscaled_accept(DCB *dcb); +static int maxscaled_close(DCB *dcb); +static int maxscaled_listen(DCB *dcb, char *config); + +/** + * The "module object" for the maxscaled protocol module. + */ +static GWPROTOCOL MyObject = { + maxscaled_read_event, /**< Read - EPOLLIN handler */ + maxscaled_write, /**< Write - data from gateway */ + maxscaled_write_event, /**< WriteReady - EPOLLOUT handler */ + maxscaled_error, /**< Error - EPOLLERR handler */ + maxscaled_hangup, /**< HangUp - EPOLLHUP handler */ + maxscaled_accept, /**< Accept */ + NULL, /**< Connect */ + maxscaled_close, /**< Close */ + maxscaled_listen, /**< Create a listener */ + NULL, /**< Authentication */ + NULL /**< Session */ + }; + +static void maxscaled_command(DCB *, unsigned char *cmd); + +/** + * 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() +{ + LOGIF(LT, (skygw_log_write( + LOGFILE_TRACE, + "Initialise MaxScaled Protocol module.\n"))); +} + +/** + * 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 + */ +GWPROTOCOL * +GetModuleObject() +{ + return &MyObject; +} + +/** + * Read event for EPOLLIN on the maxscaled protocol module. + * + * @param dcb The descriptor control block + * @return + */ +static int +maxscaled_read_event(DCB* dcb) +{ +int n; +GWBUF *head = NULL; +SESSION *session = dcb->session; +MAXSCALED *maxscaled = (MAXSCALED *)dcb->protocol; +char *password; + + if ((n = dcb_read(dcb, &head)) != -1) + { + if (head) + { + unsigned char *ptr = GWBUF_DATA(head); + ptr = GWBUF_DATA(head); + if (GWBUF_LENGTH(head)) + { + switch (maxscaled->state) + { + case MAXSCALED_STATE_LOGIN: + maxscaled->username = strndup(GWBUF_DATA(head), GWBUF_LENGTH(head)); + maxscaled->state = MAXSCALED_STATE_PASSWD; + dcb_printf(dcb, "PASSWORD"); + gwbuf_consume(head, GWBUF_LENGTH(head)); + break; + case MAXSCALED_STATE_PASSWD: + password = strndup(GWBUF_DATA(head), GWBUF_LENGTH(head)); + if (admin_verify(maxscaled->username, password)) + { + dcb_printf(dcb, "OK----"); + maxscaled->state = MAXSCALED_STATE_DATA; + } + else + { + dcb_printf(dcb, "FAILED"); + maxscaled->state = MAXSCALED_STATE_LOGIN; + free(maxscaled->username); + } + gwbuf_consume(head, GWBUF_LENGTH(head)); + free(password); + break; + case MAXSCALED_STATE_DATA: + SESSION_ROUTE_QUERY(session, head); + dcb_printf(dcb, "OK"); + break; + } + } + else + { + // Force the free of the buffer header + gwbuf_consume(head, 0); + } + } + } + return n; +} + +/** + * EPOLLOUT handler for the maxscaled protocol module. + * + * @param dcb The descriptor control block + * @return + */ +static int +maxscaled_write_event(DCB *dcb) +{ + return dcb_drain_writeq(dcb); +} + +/** + * Write routine for the maxscaled protocol module. + * + * Writes the content of the buffer queue to the socket + * observing the non-blocking principles of MaxScale. + * + * @param dcb Descriptor Control Block for the socket + * @param queue Linked list of buffes to write + */ +static int +maxscaled_write(DCB *dcb, GWBUF *queue) +{ + int rc; + rc = dcb_write(dcb, queue); + return rc; +} + +/** + * Handler for the EPOLLERR event. + * + * @param dcb The descriptor control block + */ +static int +maxscaled_error(DCB *dcb) +{ + return 0; +} + +/** + * Handler for the EPOLLHUP event. + * + * @param dcb The descriptor control block + */ +static int +maxscaled_hangup(DCB *dcb) +{ + return 0; +} + +/** + * Handler for the EPOLLIN event when the DCB refers to the listening + * socket for the protocol. + * + * @param dcb The descriptor control block + * @return The number of new connections created + */ +static int +maxscaled_accept(DCB *dcb) +{ +int n_connect = 0; + + while (1) + { + int so; + struct sockaddr_in addr; + socklen_t addrlen = sizeof(struct sockaddr); + DCB *client_dcb; + MAXSCALED *maxscaled_pr = NULL; + + so = accept(dcb->fd, (struct sockaddr *)&addr, &addrlen); + + if (so == -1) + return n_connect; + else + { + atomic_add(&dcb->stats.n_accepts, 1); + client_dcb = dcb_alloc(DCB_ROLE_REQUEST_HANDLER); + + if (client_dcb == NULL) + + { + return n_connect; + } + client_dcb->fd = so; + client_dcb->remote = strdup(inet_ntoa(addr.sin_addr)); + memcpy(&client_dcb->func, &MyObject, sizeof(GWPROTOCOL)); + client_dcb->session = + session_alloc(dcb->session->service, client_dcb); + maxscaled_pr = (MAXSCALED *)malloc(sizeof(MAXSCALED)); + client_dcb->protocol = (void *)maxscaled_pr; + + if (maxscaled_pr == NULL) + { + dcb_add_to_zombieslist(client_dcb); + return n_connect; + } + + if (poll_add_dcb(client_dcb) == -1) + { + dcb_add_to_zombieslist(dcb); + return n_connect; + } + n_connect++; + maxscaled_pr->state = MAXSCALED_STATE_LOGIN; + maxscaled_pr->username = NULL; + dcb_printf(client_dcb, "USER"); + } + } + return n_connect; +} + +/** + * The close handler for the descriptor. Called by the gateway to + * explicitly close a connection. + * + * @param dcb The descriptor control block + */ + +static int +maxscaled_close(DCB *dcb) +{ +MAXSCALED *maxscaled = dcb->protocol; + + if (maxscaled && maxscaled->username) + free(maxscaled->username); + + dcb_close(dcb); + return 0; +} + +/** + * Maxscale daemon listener entry point + * + * @param listener The Listener DCB + * @param config Configuration (ip:port) + */ +static int +maxscaled_listen(DCB *listener, char *config) +{ +struct sockaddr_in addr; +int one = 1; +int rc; + + memcpy(&listener->func, &MyObject, sizeof(GWPROTOCOL)); + + if (!parse_bindconfig(config, 6033, &addr)) + return 0; + + + if ((listener->fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + return 0; + } + + // socket options + setsockopt(listener->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)); + // set NONBLOCKING mode + setnonblocking(listener->fd); + // bind address and port + if (bind(listener->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) + { + return 0; + } + + rc = listen(listener->fd, SOMAXCONN); + + if (rc == 0) { + LOGIF(LD, (skygw_log_write( + LOGFILE_DEBUG, + "Listening maxscale connections at %s\n", + config))); + } else { + int eno = errno; + errno = 0; + LOGIF(LE, (skygw_log_write( + LOGFILE_ERROR, + "Failed to start listening for maxscale admin connections " + "due error %d, %s\n\n", + eno, + strerror(eno)))); + return 0; + } + + + if (poll_add_dcb(listener) == -1) + { + return 0; + } + return 1; +} diff --git a/server/modules/routing/Makefile b/server/modules/routing/Makefile index 1e50f3455..8019513c7 100644 --- a/server/modules/routing/Makefile +++ b/server/modules/routing/Makefile @@ -42,10 +42,12 @@ READCONSRCS=readconnroute.c READCONOBJ=$(READCONSRCS:.c=.o) DEBUGCLISRCS=debugcli.c debugcmd.c DEBUGCLIOBJ=$(DEBUGCLISRCS:.c=.o) -SRCS=$(TESTSRCS) $(READCONSRCS) $(DEBUGCLISRCS) +CLISRCS=cli.c debugcmd.c +CLIOBJ=$(CLISRCS:.c=.o) +SRCS=$(TESTSRCS) $(READCONSRCS) $(DEBUGCLISRCS) cli.c OBJ=$(SRCS:.c=.o) LIBS=$(UTILSPATH)/skygw_utils.o -lssl -llog_manager -MODULES= libdebugcli.so libreadconnroute.so libtestroute.so +MODULES= libdebugcli.so libreadconnroute.so libtestroute.so libcli.so all: $(MODULES) @@ -59,6 +61,9 @@ libreadconnroute.so: $(READCONOBJ) libdebugcli.so: $(DEBUGCLIOBJ) $(CC) $(LDFLAGS) $(DEBUGCLIOBJ) $(LIBS) -o $@ +libcli.so: $(CLIOBJ) + $(CC) $(LDFLAGS) $(CLIOBJ) $(LIBS) -o $@ + libreadwritesplit.so: # (cd readwritesplit; touch depend.mk ; make; cp $@ ..) diff --git a/server/modules/routing/cli.c b/server/modules/routing/cli.c new file mode 100644 index 000000000..9abfa5377 --- /dev/null +++ b/server/modules/routing/cli.c @@ -0,0 +1,297 @@ +/* + * This file is distributed as part of MaxScale. 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 2014 + */ + +/** + * @file cli.c - A "routing module" that in fact merely gives access + * to a command line interface + * + * @verbatim + * Revision History + * + * Date Who Description + * 18/06/13 Mark Riddoch Initial implementation + * 13/06/14 Mark Riddoch Creted from the debugcli + * + * @endverbatim + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +MODULE_INFO info = { + MODULE_API_ROUTER, + MODULE_ALPHA_RELEASE, + ROUTER_VERSION, + "The admin user interface" +}; + +extern int lm_enabled_logfiles_bitmask; + +static char *version_str = "V1.0.0"; + +/* 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 uint8_t getCapabilities (ROUTER* inst, void* router_session); + +/** The module object definition */ +static ROUTER_OBJECT MyObject = { + createInstance, + newSession, + closeSession, + freeSession, + execute, + diagnostics, + NULL, + NULL, + getCapabilities +}; + +extern int 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() +{ + LOGIF(LM, (skygw_log_write( + LOGFILE_MESSAGE, + "Initialise CLI router module %s.\n", + version_str))); + 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() +{ + 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 + * @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 = malloc(sizeof(CLI_INSTANCE))) == NULL) + return NULL; + + inst->service = service; + spinlock_init(&inst->lock); + inst->sessions = NULL; + inst->mode = CLIM_USER; + + if (options) + { + for (i = 0; options[i]; i++) + { + { + 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 + * 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, 0, 80); + + spinlock_acquire(&inst->lock); + client->next = inst->sessions; + inst->sessions = client; + spinlock_release(&inst->lock); + + session->state = SESSION_STATE_READY; + client->mode = inst->mode; + + 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) +{ + 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; + + /* Extract the characters */ + while (queue) + { + strncat(session->cmdbuf, GWBUF_DATA(queue), GWBUF_LENGTH(queue)); + queue = gwbuf_consume(queue, GWBUF_LENGTH(queue)); + } + + execute_cmd(session); + 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 uint8_t getCapabilities( + ROUTER* inst, + void* router_session) +{ + return 0; +} diff --git a/server/modules/routing/debugcmd.c b/server/modules/routing/debugcmd.c index 4bd19e957..fb638d541 100644 --- a/server/modules/routing/debugcmd.c +++ b/server/modules/routing/debugcmd.c @@ -601,6 +601,8 @@ char *ptr, *lptr; if (args[0] == NULL || *args[0] == 0) return 1; + for (i = 0; args[i] && *args[i]; i++) + ; argc = i - 2; /* The number of extra arguments to commands */ From c2fa112407cfeb86947856d2f9167ac39e3b78c4 Mon Sep 17 00:00:00 2001 From: Mark Riddoch Date: Fri, 13 Jun 2014 23:42:21 +0100 Subject: [PATCH 4/6] Remove .swp file which was added by mistake --- client/.maxadmin.c.swp | Bin 20480 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 client/.maxadmin.c.swp diff --git a/client/.maxadmin.c.swp b/client/.maxadmin.c.swp deleted file mode 100644 index a864922abaa67d4cffcffed3281a0d4ade6de26b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20480 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 Date: Mon, 16 Jun 2014 07:57:12 +0100 Subject: [PATCH 5/6] Improvements to CLI commands and client --- client/maxadmin.c | 47 ++++++++++++++++++++++++++++++++++++++++ server/core/dcb.c | 4 +++- server/core/filter.c | 4 +++- server/core/load_utils.c | 4 +++- server/core/server.c | 10 +++++---- server/core/service.c | 12 ++++++---- server/core/session.c | 12 ++++++---- 7 files changed, 78 insertions(+), 15 deletions(-) diff --git a/client/maxadmin.c b/client/maxadmin.c index 4065a971d..00a75a872 100644 --- a/client/maxadmin.c +++ b/client/maxadmin.c @@ -24,6 +24,7 @@ * * Date Who Description * 13/06/14 Mark Riddoch Initial implementation + * 15/06/14 Mark Riddoch Addition of source command * * @endverbatim */ @@ -51,6 +52,7 @@ static int connectMaxScale(char *hostname, char *port); static int setipaddress(struct in_addr *a, char *p); static int authMaxScale(int so, char *user, char *password); static int sendCommand(int so, char *cmd); +static void DoSource(int so, char *cmd); static char * prompt(EditLine *el __attribute__((__unused__))) @@ -243,6 +245,10 @@ char *cmd; fprintf(stdout, "%4d %s\n", ev.num, ev.str); } + else if (!strncasecmp(buf, "source", 6)) + { + DoSource(so, buf); + } else if (*buf) { sendCommand(so, buf); @@ -371,3 +377,44 @@ int i; } return 1; } + +static void +DoSource(int so, char *buf) +{ +char *ptr, *pe; +char line[132]; +FILE *fp; + + /* Find the filename */ + ptr = &buf[strlen("source")]; + while (*ptr && isspace(*ptr)) + ptr++; + + if ((fp = fopen(ptr, "r")) == NULL) + { + fprintf(stderr, "Unable to open command file '%s'.\n", + ptr); + return; + } + + while ((ptr = fgets(line, 132, fp)) != NULL) + { + /* Strip tailing newlines */ + pe = &ptr[strlen(ptr)-1]; + while (pe >= ptr && (*pe == '\r' || *pe == '\n')) + { + *pe = '\0'; + pe--; + } + + if (*ptr != '#') /* Comment */ + { + if (! sendCommand(so, ptr)) + { + break; + } + } + } + fclose(fp); + return; +} diff --git a/server/core/dcb.c b/server/core/dcb.c index 5417abe80..89a7cd8ba 100644 --- a/server/core/dcb.c +++ b/server/core/dcb.c @@ -1170,6 +1170,8 @@ DCB *dcb; spinlock_acquire(&dcbspin); dcb = allDCBs; + dcb_printf(pdcb, "Descriptor Control Blocks\n"); + dcb_printf(pdcb, "------------+----------------------------+----------------------+----------\n"); dcb_printf(pdcb, " %-10s | %-26s | %-20s | %s\n", "DCB", "State", "Service", "Remote"); dcb_printf(pdcb, "------------+----------------------------+----------------------+----------\n"); @@ -1182,7 +1184,7 @@ DCB *dcb; (dcb->remote ? dcb->remote : "")); dcb = dcb->next; } - dcb_printf(pdcb, "------------+----------------------------+----------------------+----------\n"); + dcb_printf(pdcb, "------------+----------------------------+----------------------+----------\n\n"); spinlock_release(&dcbspin); } diff --git a/server/core/filter.c b/server/core/filter.c index bf9eb4228..ad7974678 100644 --- a/server/core/filter.c +++ b/server/core/filter.c @@ -207,6 +207,8 @@ int i; ptr = allFilters; if (ptr) { + dcb_printf(dcb, "Filters\n"); + dcb_printf(dcb, "--------------------+-----------------+----------------------------------------\n"); dcb_printf(dcb, "%-18s | %-15s | Options\n", "Filter", "Module"); dcb_printf(dcb, "--------------------+-----------------+----------------------------------------\n"); @@ -221,7 +223,7 @@ int i; ptr = ptr->next; } if (allFilters) - dcb_printf(dcb, "--------------------+-----------------+----------------------------------------\n"); + dcb_printf(dcb, "--------------------+-----------------+----------------------------------------\n\n"); spinlock_release(&filter_spin); } diff --git a/server/core/load_utils.c b/server/core/load_utils.c index 188535375..50efc5c89 100644 --- a/server/core/load_utils.c +++ b/server/core/load_utils.c @@ -359,6 +359,8 @@ dprintAllModules(DCB *dcb) { MODULES *ptr = registered; + dcb_printf(dcb, "Modules.\n"); + dcb_printf(dcb, "----------------+-------------+---------+-------+-------------------------\n"); dcb_printf(dcb, "%-15s | %-11s | Version | API | Status\n", "Module Name", "Module Type"); dcb_printf(dcb, "----------------+-------------+---------+-------+-------------------------\n"); while (ptr) @@ -380,5 +382,5 @@ MODULES *ptr = registered; dcb_printf(dcb, "\n"); ptr = ptr->next; } - dcb_printf(dcb, "----------------+-------------+---------+-------+-------------------------\n"); + dcb_printf(dcb, "----------------+-------------+---------+-------+-------------------------\n\n"); } diff --git a/server/core/server.c b/server/core/server.c index 0a13b7751..c1bec6189 100644 --- a/server/core/server.c +++ b/server/core/server.c @@ -312,14 +312,16 @@ char *stat; ptr = allServers; if (ptr) { - dcb_printf(dcb, "%-18s | %-15s | Port | %-18s | Connections\n", + dcb_printf(dcb, "Servers.\n"); + dcb_printf(dcb, "-------------------+-----------------+-------+----------------------+------------\n"); + dcb_printf(dcb, "%-18s | %-15s | Port | %-20s | Connections\n", "Server", "Address", "Status"); - dcb_printf(dcb, "-------------------+-----------------+-------+--------------------+------------\n"); + dcb_printf(dcb, "-------------------+-----------------+-------+----------------------+------------\n"); } while (ptr) { stat = server_status(ptr); - dcb_printf(dcb, "%-18s | %-15s | %5d | %-18s | %4d\n", + dcb_printf(dcb, "%-18s | %-15s | %5d | %-20s | %4d\n", ptr->unique_name, ptr->name, ptr->port, stat, ptr->stats.n_current); @@ -327,7 +329,7 @@ char *stat; ptr = ptr->next; } if (allServers) - dcb_printf(dcb, "-------------------+-----------------+-------+--------------------+------------\n"); + dcb_printf(dcb, "-------------------+-----------------+-------+----------------------+------------\n\n"); spinlock_release(&server_spin); } diff --git a/server/core/service.c b/server/core/service.c index f7c626a34..966b9f684 100644 --- a/server/core/service.c +++ b/server/core/service.c @@ -826,6 +826,8 @@ SERVICE *ptr; ptr = allServices; if (ptr) { + dcb_printf(dcb, "Services.\n"); + dcb_printf(dcb, "--------------------------+----------------------+--------+---------------\n"); dcb_printf(dcb, "%-25s | %-20s | #Users | Total Sessions\n", "Service Name", "Router Module"); dcb_printf(dcb, "--------------------------+----------------------+--------+---------------\n"); @@ -838,7 +840,7 @@ SERVICE *ptr; ptr = ptr->next; } if (allServices) - dcb_printf(dcb, "--------------------------+----------------------+--------+---------------\n"); + dcb_printf(dcb, "--------------------------+----------------------+--------+---------------\n\n"); spinlock_release(&service_spin); } @@ -857,9 +859,11 @@ SERV_PROTOCOL *lptr; ptr = allServices; if (ptr) { + dcb_printf(dcb, "Listeners.\n"); + dcb_printf(dcb, "---------------------+--------------------+-----------------+-------+--------\n"); dcb_printf(dcb, "%-20s | %-18s | %-15s | Port | State\n", "Service Name", "Protocol Module", "Address"); - dcb_printf(dcb, "---------------------+--------------------+-----------------+-------+------\n"); + dcb_printf(dcb, "---------------------+--------------------+-----------------+-------+--------\n"); } while (ptr) { @@ -868,7 +872,7 @@ SERV_PROTOCOL *lptr; { dcb_printf(dcb, "%-20s | %-18s | %-15s | %5d | %s\n", ptr->name, lptr->protocol, - (lptr != NULL) ? lptr->address : "*", + (lptr && lptr->address) ? lptr->address : "*", lptr->port, (lptr->listener->session->state == SESSION_STATE_LISTENER_STOPPED) ? "Stopped" : "Running" ); @@ -878,7 +882,7 @@ SERV_PROTOCOL *lptr; ptr = ptr->next; } if (allServices) - dcb_printf(dcb, "---------------------+--------------------+-----------------+-------+------\n"); + dcb_printf(dcb, "---------------------+--------------------+-----------------+-------+--------\n\n"); spinlock_release(&service_spin); } diff --git a/server/core/session.c b/server/core/session.c index bd24cde9a..ae40b7369 100644 --- a/server/core/session.c +++ b/server/core/session.c @@ -537,19 +537,23 @@ SESSION *ptr; ptr = allSessions; if (ptr) { - dcb_printf(dcb, "Session | Client | State\n"); - dcb_printf(dcb, "-----------------+-----------------+----------------\n"); + dcb_printf(dcb, "Sessions.\n"); + dcb_printf(dcb, "-----------------+-----------------+----------------+--------------------------\n"); + dcb_printf(dcb, "Session | Client | Service | State\n"); + dcb_printf(dcb, "-----------------+-----------------+----------------+--------------------------\n"); } while (ptr) { - dcb_printf(dcb, "%-16p | %-15s | %s\n", ptr, + dcb_printf(dcb, "%-16p | %-15s | %-14s | %s\n", ptr, ((ptr->client && ptr->client->remote) ? ptr->client->remote : ""), + (ptr->service && ptr->service->name ? ptr->service->name + : ""), session_state(ptr->state)); ptr = ptr->next; } if (allSessions) - dcb_printf(dcb, "-----------------+-----------------+----------------\n"); + dcb_printf(dcb, "-----------------+-----------------+----------------+--------------------------\n\n"); spinlock_release(&session_spin); } From 189793f9920ef1c912e82b8bb40346980132313f Mon Sep 17 00:00:00 2001 From: Mark Riddoch Date: Mon, 16 Jun 2014 08:40:04 +0100 Subject: [PATCH 6/6] Clean up some compiler warnings --- server/core/filter.c | 2 +- server/core/gateway.c | 1 + server/core/gw_utils.c | 1 + server/core/service.c | 15 +++++++++++++-- server/core/session.c | 2 +- server/include/dcb.h | 2 +- server/include/service.h | 1 + 7 files changed, 19 insertions(+), 5 deletions(-) diff --git a/server/core/filter.c b/server/core/filter.c index ad7974678..87049461a 100644 --- a/server/core/filter.c +++ b/server/core/filter.c @@ -311,7 +311,7 @@ DOWNSTREAM *me; return NULL; } me->instance = filter->filter; - me->routeQuery = filter->obj->routeQuery; + me->routeQuery = (void *)(filter->obj->routeQuery); me->session = filter->obj->newSession(me->instance, session); filter->obj->setDownstream(me->instance, me->session, downstream); diff --git a/server/core/gateway.c b/server/core/gateway.c index 2bd592fe7..25c01e9b2 100644 --- a/server/core/gateway.c +++ b/server/core/gateway.c @@ -52,6 +52,7 @@ #include #include +#include #include #include #include diff --git a/server/core/gw_utils.c b/server/core/gw_utils.c index 0507e3d1c..40fca700c 100644 --- a/server/core/gw_utils.c +++ b/server/core/gw_utils.c @@ -130,6 +130,7 @@ setipaddress(struct in_addr *a, char *p) { return 1; } #endif + return 0; } /** diff --git a/server/core/service.c b/server/core/service.c index 966b9f684..aa04db972 100644 --- a/server/core/service.c +++ b/server/core/service.c @@ -650,12 +650,23 @@ FILTER_DEF **flist; char *ptr, *brkt; int n = 0; - flist = (FILTER_DEF *)malloc(sizeof(FILTER_DEF *)); + if ((flist = (FILTER_DEF **)malloc(sizeof(FILTER_DEF *))) == NULL) + { + LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR, + "Out of memory adding filters to service.\n"))); + return; + } ptr = strtok_r(filters, "|", &brkt); while (ptr) { n++; - flist = (FILTER_DEF *)realloc(flist, (n + 1) * sizeof(FILTER_DEF *)); + if ((flist = (FILTER_DEF **)realloc(flist, + (n + 1) * sizeof(FILTER_DEF *))) == NULL) + { + LOGIF(LE, (skygw_log_write_flush(LOGFILE_ERROR, + "Out of memory adding filters to service.\n"))); + return; + } if ((flist[n-1] = filter_find(trim(ptr))) == NULL) { LOGIF(LE, (skygw_log_write_flush( diff --git a/server/core/session.c b/server/core/session.c index ae40b7369..f98a2903a 100644 --- a/server/core/session.c +++ b/server/core/session.c @@ -165,7 +165,7 @@ session_alloc(SERVICE *service, DCB *client_dcb) session->head.instance = service->router_instance; session->head.session = session->router_session; - session->head.routeQuery = service->router->routeQuery; + session->head.routeQuery = (void *)(service->router->routeQuery); if (service->n_filters > 0) { diff --git a/server/include/dcb.h b/server/include/dcb.h index e7d2ec716..e6beafb79 100644 --- a/server/include/dcb.h +++ b/server/include/dcb.h @@ -209,7 +209,7 @@ typedef struct dcb { struct session *session; /**< The owning session */ GWPROTOCOL func; /**< The functions for this descriptor */ - unsigned int writeqlen; /**< Current number of byes in the write queue */ + int writeqlen; /**< Current number of byes in the write queue */ SPINLOCK writeqlock; /**< Write Queue spinlock */ GWBUF *writeq; /**< Write Data Queue */ SPINLOCK delayqlock; /**< Delay Backend Write Queue spinlock */ diff --git a/server/include/service.h b/server/include/service.h index 40023332b..5b3f675b0 100644 --- a/server/include/service.h +++ b/server/include/service.h @@ -155,6 +155,7 @@ extern int serviceStop(SERVICE *); extern int serviceRestart(SERVICE *); extern int serviceSetUser(SERVICE *, char *, char *); extern int serviceGetUser(SERVICE *, char **, char **); +extern void serviceSetFilters(SERVICE *, char *); extern int serviceEnableRootUser(SERVICE *, int ); extern void service_update(SERVICE *, char *, char *, char *); extern int service_refresh_users(SERVICE *);