# $Id$
-INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/contrib/libevent
+INCLUDES = -I$(top_srcdir)/include
bin_PROGRAMS = varnishd
varnishd_SOURCES = \
cache.h \
- cli_event.h \
+ common_cli.h \
hash_slinger.h \
heritage.h \
mgt.h \
cache_vrt.c \
cache_vrt_acl.c \
cache_vrt_re.c \
- cli_event.c \
+ common_cli.c \
hash_simple_list.c \
hash_classic.c \
mgt_child.c \
+ mgt_cli.c \
rfc2616.c \
shmlog.c \
storage_file.c \
$(top_builddir)/lib/libsbuf/libsbuf.a \
$(top_builddir)/lib/libvarnish/libvarnish.la \
$(top_builddir)/lib/libvcl/libvcl.la \
- $(top_builddir)/contrib/libevent/libevent.la \
-lpthread \
-lmd
#include <poll.h>
#include <pthread.h>
-#include "event.h" /* XXX only as long as it takes */
-
#include "libvarnish.h"
#include "shmlog.h"
#include "cli.h"
#include "cli_priv.h"
-#include "cli_event.h"
+#include "common_cli.h"
#include "cache.h"
#include "sbuf.h"
#include "heritage.h"
{ NULL }
};
-static int
-cli_writes(const char *s, const char *r, const char *t)
-{
- int i, l;
- struct iovec iov[3];
-
- iov[0].iov_base = (void*)(uintptr_t)s;
- iov[1].iov_base = (void*)(uintptr_t)r;
- iov[2].iov_base = (void*)(uintptr_t)t;
- for (l = i = 0; i < 3; i++) {
- iov[i].iov_len = strlen(iov[i].iov_base);
- l += iov[i].iov_len;
- }
- i = writev(heritage.fds[1], iov, 3);
- VSL(SLT_CLI, 0, "Wr %d %s %s", i != l, s, r);
- return (i != l);
-}
-
void
CLI_Init(void)
{
unsigned nbuf, lbuf;
struct cli *cli, clis;
int i;
- char res[30];
cli = &clis;
memset(cli, 0, sizeof *cli);
sbuf_clear(cli->sb);
cli_dispatch(cli, CLI_cmds, buf);
sbuf_finish(cli->sb);
- sprintf(res, "%d ", cli->result);
- if (cli_writes(res, sbuf_data(cli->sb), "\n")) {
+ i = cli_writeres(heritage.fds[2], cli);
+ if (i) {
VSL(SLT_Error, 0, "CLI write failed (errno=%d)", errno);
return;
}
+ VSL(SLT_CLI, 0, "Wr %d %d %s",
+ i, cli->result, sbuf_data(cli->sb));
i = ++p - buf;
assert(i <= nbuf);
if (i < nbuf)
#include "heritage.h"
#include "shmlog.h"
#include "cache.h"
-#include "event.h"
struct stevedore *stevedore;
--- /dev/null
+/*
+ * $Id$
+ */
+
+#include <errno.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <sys/wait.h>
+
+#include "sbuf.h"
+
+#include <cli.h>
+#include <cli_common.h>
+#include <libvarnish.h>
+
+void
+cli_out(struct cli *cli, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ sbuf_vprintf(cli->sb, fmt, ap);
+ va_end(ap);
+}
+
+void
+cli_param(struct cli *cli)
+{
+
+ cli->result = CLIS_PARAM;
+ cli_out(cli, "Parameter error, use \"help [command]\" for more info.\n");
+}
+
+void
+cli_result(struct cli *cli, unsigned res)
+{
+
+ cli->result = res;
+}
+
+++ /dev/null
-/*
- * $Id$
- */
-
-#include <errno.h>
-#include <assert.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <signal.h>
-
-#include <sys/wait.h>
-
-#include <event.h>
-#include <sbuf.h>
-
-#include <cli.h>
-#include <cli_priv.h>
-#include <libvarnish.h>
-
-#include "heritage.h"
-#include "cli_event.h"
-
-void
-cli_encode_string(struct evbuffer *buf, char *b)
-{
- char *p, *q;
-
- evbuffer_add_printf(buf, "\"");
- for (p = q = b; *p != '\0'; p++) {
- if ((*p != '"' && *p != '\\' && isgraph(*p)) || *p == ' ')
- continue;
- if (p != q)
- evbuffer_add(buf, q, p - q);
- if (*p == '\n')
- evbuffer_add_printf(buf, "\\n");
- else
- evbuffer_add_printf(buf, "\\x%02x", *p);
- q = p + 1;
- }
- if (p != q)
- evbuffer_add(buf, q, p - q);
- evbuffer_add_printf(buf, "\"");
-}
-
-
-void
-cli_out(struct cli *cli, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- sbuf_vprintf(cli->sb, fmt, ap);
- va_end(ap);
-}
-
-void
-cli_param(struct cli *cli)
-{
-
- cli->result = CLIS_PARAM;
- cli_out(cli, "Parameter error, use \"help [command]\" for more info.\n");
-}
-
-void
-cli_result(struct cli *cli, unsigned res)
-{
-
- cli->result = res;
-}
-
-static void
-encode_output(struct cli *cli)
-{
-
- if (cli->verbose) {
- if (cli->result != CLIS_OK)
- evbuffer_add_printf(cli->bev1->output, "ERROR %d ",
- cli->result);
- evbuffer_add(cli->bev1->output,
- sbuf_data(cli->sb), sbuf_len(cli->sb));
- if (cli->result == CLIS_OK)
- evbuffer_add_printf(cli->bev1->output, "OK\n");
- return;
- }
- evbuffer_add_printf(cli->bev1->output, "%d ", cli->result);
- cli_encode_string(cli->bev1->output, sbuf_data(cli->sb));
- evbuffer_add_printf(cli->bev1->output, "\n");
-}
-
-static void
-rdcb(struct bufferevent *bev, void *arg)
-{
- const char *p;
- struct cli *cli = arg;
-
- p = evbuffer_readline(bev->input);
- if (p == NULL)
- return;
- sbuf_clear(cli->sb);
- cli_dispatch(cli, cli->cli_proto, p);
- if (!cli->suspend) {
- sbuf_finish(cli->sb);
- /* XXX: syslog results ? */
- encode_output(cli);
- AZ(bufferevent_enable(cli->bev1, EV_WRITE));
- }
-}
-
-static void
-wrcb(struct bufferevent *bev, void *arg)
-{
- struct cli *cli = arg;
-
- (void)bev;
- AZ(bufferevent_disable(cli->bev1, EV_WRITE));
-}
-
-static void
-excb(struct bufferevent *bev, short what, void *arg)
-{
- printf("%s(%p, %d, %p)\n", __func__, (void*)bev, (int)what, arg);
-}
-
-struct cli *
-cli_setup(struct event_base *eb, int fdr, int fdw, int ver, struct cli_proto *cli_proto)
-{
- struct cli *cli;
-
- cli = calloc(sizeof *cli, 1);
- assert(cli != NULL);
-
- cli->bev0 = bufferevent_new(fdr, rdcb, wrcb, excb, cli);
- assert(cli->bev0 != NULL);
- AZ(bufferevent_base_set(eb, cli->bev0));
- if (fdr == fdw)
- cli->bev1 = cli->bev0;
- else
- cli->bev1 = bufferevent_new(fdw, rdcb, wrcb, excb, cli);
- assert(cli->bev1 != NULL);
- AZ(bufferevent_base_set(eb, cli->bev1));
- cli->sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
- assert(cli->sb != NULL);
-
- cli->verbose = ver;
- cli->cli_proto = cli_proto;
-
- AZ(bufferevent_enable(cli->bev0, EV_READ));
- return (cli);
-}
-
-void
-cli_suspend(struct cli *cli)
-{
-
- cli->suspend = 1;
- AZ(bufferevent_disable(cli->bev0, EV_READ));
-}
-
-void
-cli_resume(struct cli *cli)
-{
- sbuf_finish(cli->sb);
- /* XXX: syslog results ? */
- encode_output(cli);
- AZ(bufferevent_enable(cli->bev1, EV_WRITE));
- cli->suspend = 0;
- AZ(bufferevent_enable(cli->bev0, EV_READ));
-}
-
--- /dev/null
+/*
+ * $Id: cli_event.c 466 2006-07-12 23:30:49Z phk $
+ */
+
+#include <errno.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/uio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <sys/wait.h>
+
+#include "sbuf.h"
+
+#include "cli.h"
+#include "cli_priv.h"
+#include "common_cli.h"
+#include "libvarnish.h"
+
+void
+cli_out(struct cli *cli, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ sbuf_vprintf(cli->sb, fmt, ap);
+ va_end(ap);
+}
+
+void
+cli_param(struct cli *cli)
+{
+
+ cli->result = CLIS_PARAM;
+ cli_out(cli, "Parameter error, use \"help [command]\" for more info.\n");
+}
+
+void
+cli_result(struct cli *cli, unsigned res)
+{
+
+ cli->result = res;
+}
+
+int
+cli_writeres(int fd, struct cli *cli)
+{
+ int i, l;
+ struct iovec iov[3];
+ char res[32];
+
+ sprintf(res, "%d %d\n", cli->result, sbuf_len(cli->sb));
+ iov[0].iov_base = (void*)(uintptr_t)res;
+ iov[1].iov_base = (void*)(uintptr_t)sbuf_data(cli->sb);
+ iov[2].iov_base = (void*)(uintptr_t)"\n";
+ for (l = i = 0; i < 3; i++) {
+ iov[i].iov_len = strlen(iov[i].iov_base);
+ l += iov[i].iov_len;
+ }
+ i = writev(fd, iov, 3);
+ return (i != l);
+}
*/
struct cli {
- struct bufferevent *bev0, *bev1;
struct sbuf *sb;
unsigned verbose;
unsigned suspend;
struct cli_proto *cli_proto;
};
-struct cli *cli_setup(struct event_base *eb, int fdr, int fdw, int ver, struct cli_proto *cli_proto);
void cli_suspend(struct cli *cli);
void cli_resume(struct cli *cli);
-void cli_encode_string(struct evbuffer *buf, char *b);
+int cli_writeres(int fd, struct cli *cli);
extern struct cli_proto CLI_cmds[];
#include "common.h"
-extern struct event_base *mgt_eb;
+/* mgt_child.c */
+void mgt_run(int dflag);
+void mgt_start_child(void);
+void mgt_stop_child(void);
-void mgt_child_start(void);
-void mgt_child_stop(void);
-void mgt_child_kill(void);
-void mgt_sigchld(int, short, void *);
+/* mgt_cli.c */
-typedef void mgt_ccb_f(unsigned, const char *, void *);
-void mgt_child_request(mgt_ccb_f *, void *, char **argv, const char *fmt, ...);
+void mgt_cli_init(void);
+void mgt_cli_setup(int fdi, int fdo, int verbose);
+void mgt_cli_start_child(int fdi, int fdo);
+void mgt_cli_stop_child(void);
/* tcp.c */
int open_tcp(const char *port);
* The mechanics of handling the child process
*/
-#include <assert.h>
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <stdarg.h>
+#include <unistd.h>
#include <stdio.h>
+#include <fcntl.h>
#include <stdlib.h>
-#include <time.h>
-#include <unistd.h>
-
+#include <signal.h>
+#include <assert.h>
+#include <errno.h>
+#include <poll.h>
+#include <pthread.h>
+#include <sys/types.h>
#include <sys/wait.h>
-#include "queue.h"
-
-#include <event.h>
-#include <sbuf.h>
-#include <libvarnish.h>
-#include <cli.h>
+#include <err.h> /* XXX */
-#include "cli_event.h" /* for cli_encode_string */
+#include "libvarnish.h"
#include "heritage.h"
#include "mgt.h"
-/*--------------------------------------------------------------------*/
-
-static enum {
- H_STOP = 0,
- H_START
-} desired;
-
-static pid_t child_pid;
-static int child_fds[2];
-
-static struct bufferevent *child_std;
-static struct bufferevent *child_cli0, *child_cli1;
-
-static struct event ev_child_pingpong;
+static pid_t child_pid = -1;
+static int child_fds[2];
+static unsigned child_should_run;
+static pthread_t child_listen_thread;
+static pthread_t child_poker_thread;
+static pthread_mutex_t child_mtx;
+static pthread_cond_t child_cv;
+static unsigned child_ticker;
-struct creq {
- TAILQ_ENTRY(creq) list;
- char *req;
- char **argv;
- mgt_ccb_f *func;
- void *priv;
-};
-
-static TAILQ_HEAD(,creq) creqhead = TAILQ_HEAD_INITIALIZER(creqhead);
-
-/*--------------------------------------------------------------------
- * Handle stdout+stderr from the child.
- */
+/*--------------------------------------------------------------------*/
-static void
-std_rdcb(struct bufferevent *bev, void *arg)
+static void *
+child_listener(void *arg)
{
- const char *p;
+ FILE *f;
+ char buf[BUFSIZ];
(void)arg;
- while (1) {
- p = evbuffer_readline(bev->input);
- if (p == NULL)
- return;
- printf("Child said <%s>\n", p);
- }
-}
-
-static void
-std_wrcb(struct bufferevent *bev, void *arg)
-{
-
- printf("%s(%p, %p)\n",
- (const char *)__func__, (void*)bev, arg);
- exit (2);
-}
-
-static void
-std_excb(struct bufferevent *bev, short what, void *arg)
-{
-
- printf("%s(%p, %d, %p)\n",
- (const char *)__func__, (void*)bev, what, arg);
- exit (2);
-}
-
-/*--------------------------------------------------------------------
- * Multiplex requests/answers to the child
- */
-
-static void
-send_req(void)
-{
- struct creq *cr;
- int u;
-
- cr = TAILQ_FIRST(&creqhead);
- if (cr == NULL)
- return;
- if (0)
- printf("Send Request <%s>\n", cr->req);
- evbuffer_add_printf(child_cli1->output, "%s", cr->req);
- for (u = 0; cr->argv != NULL && cr->argv[u] != NULL; u++) {
- evbuffer_add_printf(child_cli1->output, " ");
- cli_encode_string(child_cli1->output, cr->argv[u]);
+ f = fdopen(child_fds[0], "r");
+ assert(f != NULL);
+ while (fgets(buf, sizeof buf, f)) {
+ printf("Child said: %s", buf);
}
- evbuffer_add_printf(child_cli1->output, "\n");
- AZ(bufferevent_enable(child_cli1, EV_WRITE));
-}
-
-void
-mgt_child_request(mgt_ccb_f *func, void *priv, char **argv, const char *fmt, ...)
-{
- struct creq *cr;
- va_list ap;
- int i;
-
- cr = calloc(sizeof *cr, 1);
- assert(cr != NULL);
- cr->func = func;
- cr->priv = priv;
- cr->argv = argv;
- va_start(ap, fmt);
- vasprintf(&cr->req, fmt, ap);
- va_end(ap);
- i = TAILQ_EMPTY(&creqhead);
- TAILQ_INSERT_TAIL(&creqhead, cr, list);
- if (i)
- send_req();
-}
-
-static void
-cli_rdcb(struct bufferevent *bev, void *arg)
-{
- const char *p;
- char **av;
- struct creq *cr;
-
- (void)arg;
-
- p = evbuffer_readline(bev->input);
- if (p == NULL)
- return;
- cr = TAILQ_FIRST(&creqhead);
- assert(cr != NULL);
- av = ParseArgv(p, 0);
- if (av[0] != NULL)
- cr->func(CLIS_SYNTAX, av[0], cr->priv);
- else
- cr->func(strtoul(av[1], NULL, 0), av[2], cr->priv);
- FreeArgv(av);
- TAILQ_REMOVE(&creqhead, cr, list);
- free(cr->req);
- free(cr);
- send_req();
-}
-
-static void
-cli_wrcb(struct bufferevent *bev, void *arg)
-{
-
- (void)bev;
- (void)arg;
-}
-
-static void
-cli_excb(struct bufferevent *bev, short what, void *arg)
-{
-
- printf("%s(%p, %d, %p)\n",
- (const char *)__func__, (void*)bev, what, arg);
- exit (2);
+ return (NULL);
}
/*--------------------------------------------------------------------*/
-static void
-child_pingpong_ccb(unsigned u, const char *r, void *priv)
+static void *
+child_poker(void *arg)
{
- (void)u;
- (void)r;
- (void)priv;
-
- /* XXX: reset keepalive timer */
-}
-
-static void
-child_pingpong(int a, short b, void *c)
-{
- time_t t;
- struct timeval tv;
-
- (void)a;
- (void)b;
- (void)c;
-
- t = time(NULL);
- mgt_child_request(child_pingpong_ccb, NULL, NULL, "ping %ld", t);
- if (1) {
- tv.tv_sec = 10;
- tv.tv_usec = 0;
- AZ(evtimer_del(&ev_child_pingpong));
- AZ(evtimer_add(&ev_child_pingpong, &tv));
+ (void)arg;
+ while (1) {
+ sleep (1);
+ /* CLI: ping/pong */
+ child_ticker = 0;
}
}
-
/*--------------------------------------------------------------------*/
static void
{
int i;
- assert(pipe(&heritage.fds[0]) == 0);
- assert(pipe(&heritage.fds[2]) == 0);
- assert(pipe(child_fds) == 0);
+ AZ(pipe(&heritage.fds[0]));
+ AZ(pipe(&heritage.fds[2]));
+ AZ(pipe(child_fds));
i = fork();
if (i < 0)
errx(1, "Could not fork child");
if (i == 0) {
+ AZ(pthread_single_np());
/* Redirect stdin/out/err */
AZ(close(0));
i = open("/dev/null", O_RDONLY);
exit (1);
}
- child_pid = i;
printf("start child pid %d\n", i);
AZ(close(child_fds[1]));
AZ(close(heritage.fds[1]));
AZ(close(heritage.fds[2]));
-
- child_std = bufferevent_new(child_fds[0],
- std_rdcb, std_wrcb, std_excb, NULL);
- assert(child_std != NULL);
- AZ(bufferevent_base_set(mgt_eb, child_std));
- bufferevent_enable(child_std, EV_READ);
-
- child_cli0 = bufferevent_new(heritage.fds[0],
- cli_rdcb, cli_wrcb, cli_excb, NULL);
- assert(child_cli0 != NULL);
- AZ(bufferevent_base_set(mgt_eb, child_cli0));
- bufferevent_enable(child_cli0, EV_READ);
-
- child_cli1 = bufferevent_new(heritage.fds[3],
- cli_rdcb, cli_wrcb, cli_excb, NULL);
- assert(child_cli1 != NULL);
- AZ(bufferevent_base_set(mgt_eb, child_cli1));
-
- evtimer_set(&ev_child_pingpong, child_pingpong, NULL);
- AZ(event_base_set(mgt_eb, &ev_child_pingpong));
- child_pingpong(0, 0, NULL);
+ mgt_cli_start_child(heritage.fds[0], heritage.fds[3]);
+ child_pid = i;
+ AZ(pthread_create(&child_listen_thread, NULL, child_listener, NULL));
+ AZ(pthread_create(&child_poker_thread, NULL, child_poker, NULL));
}
-
/*--------------------------------------------------------------------*/
-void
-mgt_child_start(void)
+static void
+stop_child(void)
{
- if (desired == H_START)
- return;
- desired = H_START;
- start_child();
+ exit(2);
+ /* kill child, if relevant */
+ /* join child_listen_thread */
+ /* join child_poker_thread */
+ /* close heritage.fds */
+ /* close child_fds */
}
/*--------------------------------------------------------------------*/
-void
-mgt_child_stop(void)
+static void
+mgt_sigchld(int arg)
{
+ int status;
+ pid_t r;
- if (desired == H_STOP)
- return;
- desired = H_STOP;
+ (void)arg;
+ r = wait4(-1, &status, WNOHANG, NULL);
+ if (r == child_pid) {
+ printf("Cache child died pid=%d status=0x%x\n",
+ r, status);
+ child_pid = -1;
+ } else {
+ printf("Unknown child died pid=%d status=0x%x\n",
+ r, status);
+ }
}
-/*--------------------------------------------------------------------*/
+/*--------------------------------------------------------------------
+ * This thread is the master thread in the management process.
+ * The relatively simple task is to start and stop the child process
+ * and to reincarnate it in case of trouble.
+ */
void
-mgt_child_kill(void)
+mgt_run(int dflag)
{
+ struct timespec to;
+ struct sigaction sac;
+ int i, dstarts = 0;
+
+#if 1
+ if (dflag)
+ mgt_cli_setup(0, 1, 1);
+#else
+ dflag = 0;
+#endif
+
+ sac.sa_handler = mgt_sigchld;
+ sac.sa_flags = SA_NOCLDSTOP;
+ AZ(sigaction(SIGCHLD, &sac, NULL));
+ child_should_run = !dflag;
- desired = H_STOP;
- kill(child_pid, 9);
+ AZ(pthread_cond_init(&child_cv, NULL));
+ AZ(pthread_mutex_init(&child_mtx, NULL));
+
+ while (1) {
+ if (!child_should_run && child_pid != -1)
+ stop_child();
+ else if (child_should_run && child_pid == -1) {
+ if (dflag && dstarts)
+ exit(2);
+ start_child();
+ dstarts = 1;
+ }
+
+ /* XXX POSIXBRAINDAMAGE */
+ AZ(clock_gettime(CLOCK_REALTIME, &to));
+ to.tv_sec += 1;
+
+ AZ(pthread_mutex_lock(&child_mtx));
+ i = pthread_cond_timedwait(&child_cv, &child_mtx, &to);
+ AZ(pthread_mutex_unlock(&child_mtx));
+ if (i == ETIMEDOUT && ++child_ticker > 5 && child_pid != -1) {
+ stop_child();
+ if (dflag)
+ exit (2);
+ }
+ }
}
/*--------------------------------------------------------------------*/
void
-mgt_sigchld(int a, short b, void *c)
+mgt_start_child(void)
{
- pid_t p;
- int status;
-
- printf("sig_chld(%d, %d, %p)\n", a, b, c);
-
- p = wait4(-1, &status, WNOHANG, NULL);
- if (p == 0)
- return;
- printf("pid = %d status = 0x%x\n", p, status);
- assert(p == child_pid);
-
- printf("Child died :-(\n");
- exit (0);
- bufferevent_free(child_std); /* XXX: is this enough ? */
- child_std = NULL;
+ child_should_run = 1;
+ AZ(pthread_cond_signal(&child_cv));
+}
- AZ(close(heritage.fds[0]));
- AZ(close(heritage.fds[1]));
- AZ(close(heritage.fds[2]));
- AZ(close(heritage.fds[3]));
- AZ(close(child_fds[0]));
- AZ(close(child_fds[1]));
+void
+mgt_stop_child(void)
+{
- if (desired == H_START)
- start_child();
+ child_should_run = 0;
+ AZ(pthread_cond_signal(&child_cv));
}
--- /dev/null
+/*
+ * $Id$
+ *
+ * The management process' CLI handling
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <sys/types.h>
+
+#include "libvarnish.h"
+#include "cli_priv.h"
+#include "cli.h"
+#include "sbuf.h"
+#include "common_cli.h"
+#include "mgt.h"
+
+static int cli_i = -1, cli_o = -1;
+
+/*--------------------------------------------------------------------*/
+
+static void
+mcf_server_start(struct cli *cli)
+{
+
+ (void)cli;
+ mgt_start_child();
+}
+
+
+/*--------------------------------------------------------------------*/
+
+static struct cli_proto *cli_proto;
+
+static struct cli_proto mgt_cli_proto[] = {
+ { CLI_HELP, cli_func_help, NULL }, /* must be first */
+ { CLI_SERVER_START, mcf_server_start, NULL },
+ { CLI_CONFIG_LOAD },
+#if 0
+ { CLI_CONFIG_LOAD, m_cli_func_config_load, NULL },
+ { CLI_CONFIG_INLINE, m_cli_func_config_inline, NULL },
+ { CLI_SERVER_STOP, m_cli_func_server_stop, NULL },
+ { CLI_SERVER_RESTART },
+ { CLI_PING, m_cli_func_ping, NULL },
+ { CLI_STATS, m_cli_func_stats, NULL },
+ { CLI_ZERO },
+ { CLI_VERBOSE, m_cli_func_verbose, NULL },
+ { CLI_EXIT, m_cli_func_exit, NULL},
+#endif
+ { CLI_QUIT },
+ { CLI_BYE },
+ { NULL }
+};
+
+
+/*--------------------------------------------------------------------*/
+
+void
+mgt_cli_init(void)
+{
+ struct cli_proto *cp;
+ unsigned u, v;
+
+
+ /*
+ * Build the joint cli_proto by combining the manager process
+ * entries with with the cache process entries. The latter
+ * get a "passthough" function in the joint list
+ */
+ u = 0;
+ for (cp = mgt_cli_proto; cp->request != NULL; cp++)
+ u++;
+ for (cp = CLI_cmds; cp->request != NULL; cp++)
+ u++;
+ cli_proto = calloc(sizeof *cli_proto, u + 1);
+ assert(cli_proto != NULL);
+ u = 0;
+ for (cp = mgt_cli_proto; cp->request != NULL; cp++)
+ cli_proto[u++] = *cp;
+ for (cp = CLI_cmds; cp->request != NULL; cp++) {
+ /* Skip any cache commands we already have in the manager */
+ for (v = 0; v < u; v++)
+ if (!strcmp(cli_proto[v].request, cp->request))
+ break;
+ if (v < u)
+ continue;
+ cli_proto[u] = *cp;
+ cli_proto[u].func = NULL; /* XXX: pass */
+ u++;
+ }
+
+ /* Fixup the entry for 'help' entry */
+ assert(!strcmp(cli_proto[0].request, "help"));
+ cli_proto[0].priv = cli_proto;
+
+ /* XXX: open listening sockets, contact cluster server etc */
+}
+
+/*--------------------------------------------------------------------*/
+
+void
+mgt_cli_start_child(int fdi, int fdo)
+{
+
+ cli_i = fdi;
+ cli_o = fdo;
+}
+
+/*--------------------------------------------------------------------*/
+
+void
+mgt_cli_stop_child(void)
+{
+
+ cli_i = -1;
+ cli_o = -1;
+ /* XXX: kick any users */
+}
+
+/*--------------------------------------------------------------------*/
+
+struct cli_port {
+ int fdi;
+ int fdo;
+ int verbose;
+ char *buf;
+ unsigned nbuf;
+ unsigned lbuf;
+ struct cli cli[1];
+};
+
+static void *
+mgt_cli_main(void *arg)
+{
+ struct cli_port *cp;
+ char *p;
+ int i;
+
+ assert(arg != NULL);
+ cp = arg;
+
+ cp->lbuf = 4096;
+ cp->buf = malloc(cp->lbuf);
+ assert(cp->buf != NULL);
+ cp->cli->sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
+ assert(cp->cli->sb != NULL);
+ while (1) {
+ if (cp->nbuf == cp->lbuf) {
+ cp->lbuf += cp->lbuf;
+ cp->buf = realloc(cp->buf, cp->lbuf);
+ assert(cp->buf != NULL);
+ }
+ i = read(cp->fdi, cp->buf + cp->nbuf, cp->lbuf - cp->nbuf);
+ if (i <= 0)
+ break;
+ cp->nbuf += i;
+ p = strchr(cp->buf, '\n');
+ if (p == NULL)
+ continue;
+ *p = '\0';
+ sbuf_clear(cp->cli->sb);
+ cli_dispatch(cp->cli, cli_proto, cp->buf);
+ sbuf_finish(cp->cli->sb);
+ /* XXX: cp->verbose */
+ if (cli_writeres(cp->fdo, cp->cli))
+ break;
+ i = ++p - cp->buf;
+ assert(i <= cp->nbuf);
+ if (i < cp->nbuf)
+ memcpy(cp->buf, p, cp->nbuf - i);
+ cp->nbuf -= i;
+ }
+ sbuf_delete(cp->cli->sb);
+ free(cp->buf);
+ close(cp->fdi);
+ close(cp->fdo);
+ free(cp);
+ return (NULL);
+}
+
+void
+mgt_cli_setup(int fdi, int fdo, int verbose)
+{
+ struct cli_port *cp;
+ pthread_t tp;
+
+ cp = calloc(sizeof *cp, 1);
+ assert(cp != NULL);
+
+ cp->fdi = fdi;
+ cp->fdo = fdo;
+ cp->verbose = verbose;
+ AZ(pthread_create(&tp, NULL, mgt_cli_main, cp));
+ AZ(pthread_detach(tp));
+}
+
+#if 0
+
+/*--------------------------------------------------------------------
+ * Generic passthrough for CLI functions
+ */
+
+static void
+cli_passthrough_cb(unsigned u, const char *r, void *priv)
+{
+ struct cli *cli = priv;
+
+ cli_out(cli, "%s\n", r);
+ cli_result(cli, u);
+ cli_resume(cli);
+}
+
+static void
+m_cli_func_passthrough(struct cli *cli, char **av, void *priv)
+{
+
+ (void)av;
+ (void)priv;
+
+ cli_suspend(cli);
+ mgt_child_request(cli_passthrough_cb, cli, &av[2], av[1]);
+}
+
+static void
+m_cli_func_config_inline(struct cli *cli, char **av, void *priv)
+{
+ char *vf;
+ struct sbuf *sb;
+
+ (void)priv;
+
+ sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
+ assert(sb != NULL);
+ vf = VCC_Compile(sb, av[3], NULL);
+ sbuf_finish(sb);
+ if (sbuf_len(sb) > 0) {
+ cli_out(cli, "%s", sbuf_data(sb));
+ sbuf_delete(sb);
+ return;
+ }
+ sbuf_delete(sb);
+ cli_suspend(cli);
+ mgt_child_request(cli_passthrough_cb, cli, NULL,
+ "config.load %s %s", av[2], vf);
+}
+
+/* XXX: m prefix to avoid name clash */
+static void
+m_cli_func_config_load(struct cli *cli, char **av, void *priv)
+{
+ char *vf;
+ struct sbuf *sb;
+
+ (void)priv;
+
+ sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
+ assert(sb != NULL);
+ vf = VCC_CompileFile(sb, av[3]);
+ sbuf_finish(sb);
+ if (sbuf_len(sb) > 0) {
+ cli_out(cli, "%s", sbuf_data(sb));
+ sbuf_delete(sb);
+ return;
+ }
+ sbuf_delete(sb);
+ cli_suspend(cli);
+ mgt_child_request(cli_passthrough_cb, cli, NULL,
+ "config.load %s %s", av[2], vf);
+}
+
+static char *
+vcl_file(const char *fflag)
+{
+ char *vf;
+ struct sbuf *sb;
+
+ sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
+ assert(sb != NULL);
+ vf = VCC_CompileFile(sb, fflag);
+ sbuf_finish(sb);
+ if (sbuf_len(sb) > 0) {
+ fprintf(stderr, "%s", sbuf_data(sb));
+ sbuf_delete(sb);
+ return (NULL);
+ }
+ sbuf_delete(sb);
+ return (vf);
+}
+
+
+/*--------------------------------------------------------------------*/
+
+static void
+m_cli_func_server_start(struct cli *cli, char **av, void *priv)
+{
+
+ (void)cli;
+ (void)av;
+ (void)priv;
+
+ mgt_child_start();
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+m_cli_func_server_stop(struct cli *cli, char **av, void *priv)
+{
+
+ (void)cli;
+ (void)av;
+ (void)priv;
+
+ mgt_child_stop();
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+m_cli_func_exit(struct cli *cli, char **av, void *priv)
+{
+
+ (void)cli;
+ (void)av;
+ (void)priv;
+ mgt_child_kill();
+ exit (0);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+m_cli_func_verbose(struct cli *cli, char **av, void *priv)
+{
+
+ (void)av;
+ (void)priv;
+
+ cli->verbose = !cli->verbose;
+}
+
+
+static void
+m_cli_func_ping(struct cli *cli, char **av, void *priv)
+{
+ time_t t;
+
+ (void)priv;
+
+ if (av[2] != NULL) {
+ cli_out(cli, "Got your %s\n", av[2]);
+ }
+ t = time(NULL);
+ cli_out(cli, "PONG %ld\n", t);
+}
+
+/*--------------------------------------------------------------------*/
+
+static void
+m_cli_func_stats(struct cli *cli, char **av, void *priv)
+{
+
+ (void)av;
+ (void)priv;
+
+ assert (VSL_stats != NULL);
+#define MAC_STAT(n,t,f,d) \
+ cli_out(cli, "%12ju " d "\n", (VSL_stats->n));
+#include "stat_field.h"
+#undef MAC_STAT
+}
+
+/*--------------------------------------------------------------------*/
+
+
+/*--------------------------------------------------------------------*/
+
+/* for development purposes */
+#include <printf.h>
+
+int
+main(int argc, char *argv[])
+{
+ int o;
+ const char *portnumber = "8080";
+ unsigned dflag = 0;
+ const char *bflag = NULL;
+ const char *fflag = NULL;
+ const char *sflag = "file";
+ const char *hflag = "classic";
+
+ (void)register_printf_render_std((const unsigned char *)"HVQ");
+
+ setbuf(stdout, NULL);
+ setbuf(stderr, NULL);
+
+ VCC_InitCompile(default_vcl);
+
+ heritage.default_ttl = 120;
+ heritage.wthread_min = 1;
+ heritage.wthread_max = UINT_MAX;
+ heritage.wthread_timeout = 10;
+ heritage.mem_workspace = 4096;
+
+ while ((o = getopt(argc, argv, "b:df:h:p:s:t:w:")) != -1)
+ switch (o) {
+ case 'b':
+ bflag = optarg;
+ break;
+ case 'd':
+ dflag++;
+ break;
+ case 'f':
+ fflag = optarg;
+ break;
+ case 'h':
+ hflag = optarg;
+ break;
+ case 'p':
+ portnumber = optarg;
+ break;
+ case 's':
+ sflag = optarg;
+ break;
+ case 't':
+ heritage.default_ttl = strtoul(optarg, NULL, 0);
+ break;
+ case 'w':
+ tackle_warg(optarg);
+ break;
+ default:
+ usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 0) {
+ fprintf(stderr, "Too many arguments\n");
+ usage();
+ }
+
+ if (bflag != NULL && fflag != NULL) {
+ fprintf(stderr, "Only one of -b or -f can be specified\n");
+ usage();
+ }
+ if (bflag == NULL && fflag == NULL) {
+ fprintf(stderr, "One of -b or -f must be specified\n");
+ usage();
+ }
+
+ if (bflag != NULL)
+ heritage.vcl_file = vcl_default(bflag);
+ else
+ heritage.vcl_file = vcl_file(fflag);
+ if (heritage.vcl_file == NULL)
+ exit (1);
+
+ setup_storage(sflag);
+ setup_hash(hflag);
+
+ /*
+ * XXX: Lacking the suspend/resume facility (due to the socket API
+ * missing an unlisten(2) facility) we may want to push this into
+ * the child to limit the amount of time where the socket(s) exists
+ * but do not answer. That, on the other hand, would eliminate the
+ * possibility of doing a "no-glitch" restart of the child process.
+ */
+ open_tcp(portnumber);
+
+ VSL_MgtInit(SHMLOG_FILENAME, 8*1024*1024);
+
+ if (dflag)
+ DebugStunt();
+ daemon(dflag, dflag);
+ if (dflag)
+ printf("%d\n%d\n%d\n", getpid(), getsid(0), getpgrp());
+
+ {
+ struct event e_sigchld;
+ struct cli *cli;
+ int i;
+
+ mgt_eb = event_init();
+ assert(mgt_eb != NULL);
+
+ if (dflag)
+ cli = cli_setup(mgt_eb, 0, 1, 1, cli_proto);
+
+ signal_set(&e_sigchld, SIGCHLD, mgt_sigchld, NULL);
+ AZ(event_base_set(mgt_eb, &e_sigchld));
+ AZ(signal_add(&e_sigchld, NULL));
+
+ mgt_child_start();
+
+ i = event_base_loop(mgt_eb, 0);
+ if (i != 0)
+ printf("event_dispatch() = %d\n", i);
+
+ }
+
+ exit(0);
+}
+#endif
#include <time.h>
#include <unistd.h>
-#include <sys/wait.h>
-
-#include "event.h"
#include "sbuf.h"
-#include <cli.h>
-#include <cli_priv.h>
-#include <libvarnish.h>
-#include <libvcl.h>
+#include "libvarnish.h"
+#include "libvcl.h"
+#include "cli.h"
+#include "cli_priv.h"
+#include "common_cli.h"
#include "mgt.h"
#include "heritage.h"
#include "shmlog.h"
-#include "cli_event.h"
/*--------------------------------------------------------------------*/
/*--------------------------------------------------------------------*/
struct heritage heritage;
-struct event_base *mgt_eb;
+#if 0
/*--------------------------------------------------------------------
* Generic passthrough for CLI functions
*/
cli_suspend(cli);
mgt_child_request(cli_passthrough_cb, cli, &av[2], av[1]);
}
+#endif
/*--------------------------------------------------------------------*/
free(buf);
return (vf);
}
-
+#if 0
static void
m_cli_func_config_inline(struct cli *cli, char **av, void *priv)
{
mgt_child_request(cli_passthrough_cb, cli, NULL,
"config.load %s %s", av[2], vf);
}
+#endif
static char *
vcl_file(const char *fflag)
return (vf);
}
+#if 0
/*--------------------------------------------------------------------*/
{ NULL }
};
+#endif
/*--------------------------------------------------------------------*/
/*--------------------------------------------------------------------*/
+
/* for development purposes */
#include <printf.h>
if (dflag)
printf("%d\n%d\n%d\n", getpid(), getsid(0), getpgrp());
- {
- struct event e_sigchld;
- struct cli *cli;
- int i;
-
- mgt_eb = event_init();
- assert(mgt_eb != NULL);
-
- if (dflag)
- cli = cli_setup(mgt_eb, 0, 1, 1, cli_proto);
-
- signal_set(&e_sigchld, SIGCHLD, mgt_sigchld, NULL);
- AZ(event_base_set(mgt_eb, &e_sigchld));
- AZ(signal_add(&e_sigchld, NULL));
+ mgt_cli_init();
- mgt_child_start();
-
- i = event_base_loop(mgt_eb, 0);
- if (i != 0)
- printf("event_dispatch() = %d\n", i);
-
- }
+ mgt_run(dflag);
exit(0);
}