[master] 597b3fb Collapse the VCLI .c and .h files, leaving only two: The bare protocol and the VCLI core serve code.

Poul-Henning Kamp phk at FreeBSD.org
Sun May 22 01:06:05 CEST 2016


commit 597b3fbc6755bbfc17f2d6dbc0ba8ef93a56ba77
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Sat May 21 23:03:57 2016 +0000

    Collapse the VCLI .c and .h files, leaving only two: The bare protocol
    and the VCLI core serve code.

diff --git a/include/vcli_common.h b/include/vcli_common.h
deleted file mode 100644
index 8d0a623..0000000
--- a/include/vcli_common.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2011 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- */
-
-struct vlu;
-struct VCLS;
-
-struct cli {
-	unsigned		magic;
-#define CLI_MAGIC		0x4038d570
-	struct vsb		*sb;
-	enum VCLI_status_e	result;
-	char			*cmd;
-	unsigned		auth;
-	char			challenge[34];
-	char			*ident;
-	struct vlu		*vlu;
-	struct VCLS		*cls;
-	volatile unsigned	*limit;
-};
diff --git a/include/vcli_serve.h b/include/vcli_serve.h
deleted file mode 100644
index 1c5ac88..0000000
--- a/include/vcli_serve.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*-
- * Copyright (c) 2010-2011 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- */
-
-struct VCLS;
-typedef void cls_cb_f(void *priv);
-typedef void cls_cbc_f(const struct cli*);
-struct VCLS *VCLS_New(cls_cbc_f *before, cls_cbc_f *after,
-    volatile unsigned *maxlen, volatile unsigned *limit);
-struct cli *VCLS_AddFd(struct VCLS *cs, int fdi, int fdo, cls_cb_f *closefunc,
-    void *priv);
-void VCLS_AddFunc(struct VCLS *cs, unsigned auth, struct cli_proto *clp);
-int VCLS_Poll(struct VCLS *cs, int timeout);
-int VCLS_PollFd(struct VCLS *cs, int fd, int timeout);
-void VCLS_Destroy(struct VCLS **);
-void VCLS_Clone(struct VCLS *cs, struct VCLS *cso);
-
-/* From libvarnish/cli.c */
-cli_func_t	VCLS_func_close;
-cli_func_t	VCLS_func_help;
-cli_func_t	VCLS_func_help_json;
-cli_func_t	VCLS_func_ping;
diff --git a/lib/libvarnish/cli_auth.c b/lib/libvarnish/cli_auth.c
deleted file mode 100644
index d7b7bf2..0000000
--- a/lib/libvarnish/cli_auth.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*-
- * Copyright (c) 2010-2011 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#include <sys/types.h>
-
-#include <stdint.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#include "vas.h"
-#include "vcli.h"
-#include "vsha256.h"
-
-void
-VCLI_AuthResponse(int S_fd, const char *challenge,
-    char response[CLI_AUTH_RESPONSE_LEN + 1])
-{
-	SHA256_CTX ctx;
-	uint8_t buf[SHA256_LEN];
-	int i;
-
-	assert(CLI_AUTH_RESPONSE_LEN == (SHA256_LEN * 2));
-
-	SHA256_Init(&ctx);
-	SHA256_Update(&ctx, challenge, 32);
-	SHA256_Update(&ctx, "\n", 1);
-	do {
-		i = read(S_fd, buf, 1);
-		if (i == 1)
-			SHA256_Update(&ctx, buf, i);
-	} while (i > 0);
-	SHA256_Update(&ctx, challenge, 32);
-	SHA256_Update(&ctx, "\n", 1);
-	SHA256_Final(buf, &ctx);
-	for(i = 0; i < SHA256_LEN; i++)
-		sprintf(response + 2 * i, "%02x", buf[i]);
-}
diff --git a/lib/libvarnish/cli_common.c b/lib/libvarnish/cli_common.c
deleted file mode 100644
index a2dd4f6..0000000
--- a/lib/libvarnish/cli_common.c
+++ /dev/null
@@ -1,258 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2011 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#include <sys/types.h>
-#include <sys/uio.h>
-
-#include <errno.h>
-#include <poll.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "vdef.h"
-#include "vas.h"
-#include "miniobj.h"
-#include "vqueue.h"
-
-#include "vcli.h"
-#include "vcli_common.h"
-#include "vcli_priv.h"
-#include "vsb.h"
-
-/*lint -e{818} cli could be const */
-void
-VCLI_Out(struct cli *cli, const char *fmt, ...)
-{
-	va_list ap;
-
-	va_start(ap, fmt);
-	if (cli != NULL) {
-		CHECK_OBJ_NOTNULL(cli, CLI_MAGIC);
-		if (VSB_len(cli->sb) < *cli->limit)
-			(void)VSB_vprintf(cli->sb, fmt, ap);
-		else if (cli->result == CLIS_OK)
-			cli->result = CLIS_TRUNCATED;
-	} else {
-		(void)vfprintf(stdout, fmt, ap);
-	}
-	va_end(ap);
-}
-
-/*lint -e{818} cli could be const */
-int
-VCLI_Overflow(struct cli *cli)
-{
-	CHECK_OBJ_NOTNULL(cli, CLI_MAGIC);
-	if (cli->result == CLIS_TRUNCATED ||
-	    VSB_len(cli->sb) >= *cli->limit)
-		return (1);
-	return (0);
-}
-
-/*lint -e{818} cli could be const */
-void
-VCLI_JSON_str(struct cli *cli, const char *s)
-{
-
-	CHECK_OBJ_NOTNULL(cli, CLI_MAGIC);
-	VSB_quote(cli->sb, s, -1, VSB_QUOTE_JSON);
-}
-
-/*lint -e{818} cli could be const */
-void
-VCLI_JSON_ver(struct cli *cli, unsigned ver, const char * const * av)
-{
-	int i;
-
-	CHECK_OBJ_NOTNULL(cli, CLI_MAGIC);
-	VCLI_Out(cli, "[ %u, [", ver);
-	for (i = 1; av[i] != NULL; i++) {
-		VCLI_JSON_str(cli, av[i]);
-		if (av[i + 1] != NULL)
-			VCLI_Out(cli, ", ");
-	}
-	VCLI_Out(cli, "]");
-}
-
-/*lint -e{818} cli could be const */
-void
-VCLI_Quote(struct cli *cli, const char *s)
-{
-
-	CHECK_OBJ_NOTNULL(cli, CLI_MAGIC);
-	VSB_quote(cli->sb, s, -1, 0);
-}
-
-void
-VCLI_SetResult(struct cli *cli, unsigned res)
-{
-
-	if (cli != NULL) {
-		CHECK_OBJ_NOTNULL(cli, CLI_MAGIC);
-		if (cli->result != CLIS_TRUNCATED || res != CLIS_OK)
-			cli->result = res;	/*lint !e64 type mismatch */
-	} else {
-		printf("CLI result = %u\n", res);
-	}
-}
-
-int
-VCLI_WriteResult(int fd, unsigned status, const char *result)
-{
-	int i, l;
-	struct iovec iov[3];
-	char nl[2] = "\n";
-	size_t len;
-	char res[CLI_LINE0_LEN + 2];	/*
-					 * NUL + one more so we can catch
-					 * any misformats by snprintf
-					 */
-
-	assert(status >= 100);
-	assert(status <= 999);		/*lint !e650 const out of range */
-
-	len = strlen(result);
-
-	i = snprintf(res, sizeof res,
-	    "%-3d %-8zd\n", status, len);
-	assert(i == CLI_LINE0_LEN);
-	assert(strtoul(res + 3, NULL, 10) == len);
-
-	iov[0].iov_base = res;
-	iov[0].iov_len = CLI_LINE0_LEN;
-
-	iov[1].iov_base = (void*)(uintptr_t)result;	/* TRUST ME */
-	iov[1].iov_len = len;
-
-	iov[2].iov_base = nl;
-	iov[2].iov_len = 1;
-
-	for (l = i = 0; i < 3; i++)
-		l += iov[i].iov_len;
-	i = writev(fd, iov, 3);
-	return (i != l);
-}
-
-static int
-read_tmo(int fd, char *ptr, unsigned len, double tmo)
-{
-	int i, j, to;
-	struct pollfd pfd;
-
-	if (tmo > 0)
-		to = (int)(tmo * 1e3);
-	else
-		to = -1;
-	pfd.fd = fd;
-	pfd.events = POLLIN;
-	for (j = 0; len > 0; ) {
-		i = poll(&pfd, 1, to);
-		if (i == 0) {
-			errno = ETIMEDOUT;
-			return (-1);
-		}
-		i = read(fd, ptr, len);
-		if (i < 0)
-			return (i);
-		if (i == 0)
-			break;
-		len -= i;
-		ptr += i;
-		j += i;
-	}
-	return (j);
-}
-
-int
-VCLI_ReadResult(int fd, unsigned *status, char **ptr, double tmo)
-{
-	char res[CLI_LINE0_LEN];	/* For NUL */
-	int i, j;
-	unsigned u, v, s;
-	char *p = NULL;
-	const char *err = "CLI communication error (hdr)";
-
-	if (status == NULL)
-		status = &s;
-	if (ptr != NULL)
-		*ptr = NULL;
-	do {
-		i = read_tmo(fd, res, CLI_LINE0_LEN, tmo);
-		if (i != CLI_LINE0_LEN)
-			break;
-
-		if (res[3] != ' ')
-			break;
-
-		if (res[CLI_LINE0_LEN - 1] != '\n')
-			break;
-
-		res[CLI_LINE0_LEN - 1] = '\0';
-		j = sscanf(res, "%u %u\n", &u, &v);
-		if (j != 2)
-			break;
-
-		err = "CLI communication error (body)";
-
-		*status = u;
-		p = malloc(v + 1L);
-		if (p == NULL)
-			break;
-
-		i = read_tmo(fd, p, v + 1, tmo);
-		if (i < 0)
-			break;
-		if (i != v + 1)
-			break;
-		if (p[v] != '\n')
-			break;
-
-		p[v] = '\0';
-		if (ptr == NULL)
-			free(p);
-		else
-			*ptr = p;
-		return (0);
-	} while(0);
-
-	if (p != NULL)
-		free(p);
-	*status = CLIS_COMMS;
-	if (ptr != NULL)
-		*ptr = strdup(err);
-	return (*status);
-}
diff --git a/lib/libvarnish/cli_serve.c b/lib/libvarnish/cli_serve.c
deleted file mode 100644
index 4e88bdc..0000000
--- a/lib/libvarnish/cli_serve.c
+++ /dev/null
@@ -1,616 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2011 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * Stuff for handling the CLI protocol
- */
-
-#include "config.h"
-
-#include <ctype.h>
-#include <errno.h>
-#include <poll.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "vdef.h"
-#include "vas.h"
-#include "vqueue.h"
-#include "miniobj.h"
-
-#include "vav.h"
-#include "vcli.h"
-#include "vcli_common.h"
-#include "vcli_priv.h"
-#include "vcli_serve.h"
-#include "vlu.h"
-#include "vsb.h"
-
-struct VCLS_fd {
-	unsigned			magic;
-#define VCLS_FD_MAGIC			0x010dbd1e
-	VTAILQ_ENTRY(VCLS_fd)		list;
-	int				fdi, fdo;
-	struct VCLS			*cls;
-	struct cli			*cli, clis;
-	cls_cb_f			*closefunc;
-	void				*priv;
-	struct vsb			*last_arg;
-	int				last_idx;
-	char				**argv;
-};
-
-struct VCLS {
-	unsigned			magic;
-#define VCLS_MAGIC			0x60f044a3
-	VTAILQ_HEAD(,VCLS_fd)		fds;
-	unsigned			nfd;
-	VTAILQ_HEAD(,cli_proto)		funcs;
-	cls_cbc_f			*before, *after;
-	volatile unsigned		*maxlen;
-	volatile unsigned		*limit;
-	struct cli_proto		*wildcard;
-};
-
-/*--------------------------------------------------------------------*/
-
-void __match_proto__(cli_func_t)
-VCLS_func_close(struct cli *cli, const char *const *av, void *priv)
-{
-
-	(void)av;
-	(void)priv;
-	VCLI_Out(cli, "Closing CLI connection");
-	VCLI_SetResult(cli, CLIS_CLOSE);
-}
-
-/*--------------------------------------------------------------------*/
-
-void __match_proto__(cli_func_t)
-VCLS_func_ping(struct cli *cli, const char * const *av, void *priv)
-{
-	time_t t;
-
-	(void)av;
-	(void)priv;
-	t = time(NULL);
-	VCLI_Out(cli, "PONG %jd 1.0", (intmax_t)t);
-}
-
-/*--------------------------------------------------------------------*/
-
-void __match_proto__(cli_func_t)
-VCLS_func_help(struct cli *cli, const char * const *av, void *priv)
-{
-	struct cli_proto *clp;
-	unsigned all, debug, d;
-	struct VCLS *cs;
-
-	(void)priv;
-	cs = cli->cls;
-	CHECK_OBJ_NOTNULL(cs, VCLS_MAGIC);
-
-	if (av[2] == NULL) {
-		all = debug = 0;
-	} else if (!strcmp(av[2], "-a")) {
-		all = 1;
-		debug = 0;
-	} else if (!strcmp(av[2], "-d")) {
-		all = 0;
-		debug = 1;
-	} else {
-		VTAILQ_FOREACH(clp, &cs->funcs, list) {
-			if (clp->auth <= cli->auth &&
-			    !strcmp(clp->desc->request, av[2])) {
-				VCLI_Out(cli, "%s\n%s\n",
-				    clp->desc->syntax, clp->desc->help);
-				return;
-			}
-		}
-		VCLI_Out(cli, "Unknown request.\nType 'help' for more info.\n");
-		VCLI_SetResult(cli, CLIS_UNKNOWN);
-		return;
-	}
-	VTAILQ_FOREACH(clp, &cs->funcs, list) {
-		if (clp->auth > cli->auth)
-			continue;
-		d =  strchr(clp->flags, 'd') != NULL ? 1 : 0;
-		if (d && (!all && !debug))
-			continue;
-		if (debug && !d)
-			continue;
-		if (clp->desc->syntax != NULL)
-			VCLI_Out(cli, "%s\n", clp->desc->syntax);
-	}
-}
-
-void __match_proto__(cli_func_t)
-VCLS_func_help_json(struct cli *cli, const char * const *av, void *priv)
-{
-	struct cli_proto *clp;
-	struct VCLS *cs;
-
-	(void)priv;
-	cs = cli->cls;
-	CHECK_OBJ_NOTNULL(cs, VCLS_MAGIC);
-
-	VCLI_JSON_ver(cli, 1, av);
-	VTAILQ_FOREACH(clp, &cs->funcs, list) {
-		if (clp->auth > cli->auth)
-			continue;
-		VCLI_Out(cli, ",\n  {");
-		VCLI_Out(cli, "\n  \"request\": ");
-		VCLI_JSON_str(cli, clp->desc->request);
-		VCLI_Out(cli, ",\n  \"syntax\": ");
-		VCLI_JSON_str(cli, clp->desc->syntax);
-		VCLI_Out(cli, ",\n  \"help\": ");
-		VCLI_JSON_str(cli, clp->desc->help);
-		VCLI_Out(cli, ",\n  \"minarg\": %d", clp->desc->minarg);
-		VCLI_Out(cli, ", \"maxarg\": %d", clp->desc->maxarg);
-		VCLI_Out(cli, ", \"flags\": ");
-		VCLI_JSON_str(cli, clp->flags);
-		VCLI_Out(cli, ", \"json\": %s",
-		    clp->jsonfunc == NULL ? "false" : "true");
-		VCLI_Out(cli, "\n  }");
-	}
-	VCLI_Out(cli, "\n]\n");
-}
-
-/*--------------------------------------------------------------------
- * Look for a CLI command to execute
- */
-
-static void
-cls_dispatch(struct cli *cli, const struct cli_proto *cp,
-    char * const * av, unsigned ac)
-{
-	int json = 0;
-
-	AN(av);
-
-	if (ac > 1 && !strcmp(av[2], "-j"))
-		json = 1;
-
-	if (cp->func == NULL && !json) {
-		VCLI_Out(cli, "Unimplemented\n");
-		VCLI_SetResult(cli, CLIS_UNIMPL);
-		return;
-	}
-	if (cp->jsonfunc == NULL && json) {
-		VCLI_Out(cli, "JSON unimplemented\n");
-		VCLI_SetResult(cli, CLIS_UNIMPL);
-		return;
-	}
-
-	if (ac - 1 < cp->desc->minarg + json) {
-		VCLI_Out(cli, "Too few parameters\n");
-		VCLI_SetResult(cli, CLIS_TOOFEW);
-		return;
-	}
-
-	if (ac - 1> cp->desc->maxarg + json) {
-		VCLI_Out(cli, "Too many parameters\n");
-		VCLI_SetResult(cli, CLIS_TOOMANY);
-		return;
-	}
-
-	cli->result = CLIS_OK;
-	VSB_clear(cli->sb);
-	if (json)
-		cp->jsonfunc(cli, (const char * const *)av, cp->priv);
-	else
-		cp->func(cli, (const char * const *)av, cp->priv);
-}
-
-/*--------------------------------------------------------------------
- * We have collected a full cli line, parse it and execute, if possible.
- */
-
-static int
-cls_vlu2(void *priv, char * const *av)
-{
-	struct VCLS_fd *cfd;
-	struct VCLS *cs;
-	struct cli_proto *clp;
-	struct cli *cli;
-	unsigned na;
-	ssize_t len;
-	char *s;
-	unsigned lim;
-	const char *trunc = "!\n[response was truncated]\n";
-
-	CAST_OBJ_NOTNULL(cfd, priv, VCLS_FD_MAGIC);
-	cs = cfd->cls;
-	CHECK_OBJ_NOTNULL(cs, VCLS_MAGIC);
-
-	cli = cfd->cli;
-	CHECK_OBJ_NOTNULL(cli, CLI_MAGIC);
-	AN(cli->cmd);
-
-	cli->cls = cs;
-
-	cli->result = CLIS_UNKNOWN;
-	VSB_clear(cli->sb);
-	VCLI_Out(cli, "Unknown request.\nType 'help' for more info.\n");
-
-	if (cs->before != NULL)
-		cs->before(cli);
-
-	do {
-		if (av[0] != NULL) {
-			VCLI_Out(cli, "Syntax Error: %s\n", av[0]);
-			VCLI_SetResult(cli, CLIS_SYNTAX);
-			break;
-		}
-
-		if (isupper(av[1][0])) {
-			VCLI_Out(cli, "all commands are in lower-case.\n");
-			VCLI_SetResult(cli, CLIS_UNKNOWN);
-			break;
-		}
-
-		if (!islower(av[1][0]))
-			break;
-
-		for (na = 0; av[na + 1] != NULL; na++)
-			continue;
-
-		VTAILQ_FOREACH(clp, &cs->funcs, list) {
-			if (clp->auth > cli->auth)
-				continue;
-			if (!strcmp(clp->desc->request, av[1])) {
-				cls_dispatch(cli, clp, av, na);
-				break;
-			}
-		}
-		if (clp == NULL &&
-		    cs->wildcard && cs->wildcard->auth <= cli->auth)
-			cls_dispatch(cli, cs->wildcard, av, na);
-
-	} while (0);
-
-	AZ(VSB_finish(cli->sb));
-
-	if (cs->after != NULL)
-		cs->after(cli);
-
-	cli->cls = NULL;
-
-	s = VSB_data(cli->sb);
-	len = VSB_len(cli->sb);
-	lim = *cs->limit;
-	if (len > lim) {
-		if (cli->result == CLIS_OK)
-			cli->result = CLIS_TRUNCATED;
-		strcpy(s + (lim - strlen(trunc)), trunc);
-		assert(strlen(s) <= lim);
-	}
-	if (VCLI_WriteResult(cfd->fdo, cli->result, s) ||
-	    cli->result == CLIS_CLOSE)
-		return (1);
-
-	return (0);
-}
-
-static int
-cls_vlu(void *priv, const char *p)
-{
-	struct VCLS_fd *cfd;
-	struct cli *cli;
-	int i;
-	char **av;
-
-	CAST_OBJ_NOTNULL(cfd, priv, VCLS_FD_MAGIC);
-	AN(p);
-
-	cli = cfd->cli;
-	CHECK_OBJ_NOTNULL(cli, CLI_MAGIC);
-
-	if (cfd->argv == NULL) {
-		/*
-		 * Lines with only whitespace are simply ignored, in order
-		 * to not complicate CLI-client side scripts and TELNET users
-		 */
-		for (; isspace(*p); p++)
-			continue;
-		if (*p == '\0')
-			return (0);
-		REPLACE(cli->cmd, p);
-
-		av = VAV_Parse(p, NULL, 0);
-		AN(av);
-		if (av[0] != NULL) {
-			i = cls_vlu2(priv, av);
-			VAV_Free(av);
-			free(cli->cmd);
-			cli->cmd = NULL;
-			return (i);
-		}
-		for (i = 1; av[i] != NULL; i++)
-			continue;
-		if (i < 3 || cli->auth == 0 || strcmp(av[i - 2], "<<")) {
-			i = cls_vlu2(priv, av);
-			VAV_Free(av);
-			free(cli->cmd);
-			cli->cmd = NULL;
-			return (i);
-		}
-		cfd->argv = av;
-		cfd->last_idx = i - 2;
-		cfd->last_arg = VSB_new_auto();
-		AN(cfd->last_arg);
-		return (0);
-	} else {
-		AN(cfd->argv[cfd->last_idx]);
-		AZ(strcmp(cfd->argv[cfd->last_idx], "<<"));
-		AN(cfd->argv[cfd->last_idx + 1]);
-		if (strcmp(p, cfd->argv[cfd->last_idx + 1])) {
-			VSB_cat(cfd->last_arg, p);
-			VSB_cat(cfd->last_arg, "\n");
-			return (0);
-		}
-		AZ(VSB_finish(cfd->last_arg));
-		free(cfd->argv[cfd->last_idx]);
-		cfd->argv[cfd->last_idx] = NULL;
-		free(cfd->argv[cfd->last_idx + 1]);
-		cfd->argv[cfd->last_idx + 1] = NULL;
-		cfd->argv[cfd->last_idx] = VSB_data(cfd->last_arg);
-		i = cls_vlu2(priv, cfd->argv);
-		cfd->argv[cfd->last_idx] = NULL;
-		VAV_Free(cfd->argv);
-		cfd->argv = NULL;
-		free(cli->cmd);
-		cli->cmd = NULL;
-		VSB_destroy(&cfd->last_arg);
-		cfd->last_idx = 0;
-		return (i);
-	}
-}
-
-struct VCLS *
-VCLS_New(cls_cbc_f *before, cls_cbc_f *after, volatile unsigned *maxlen,
-    volatile unsigned *limit)
-{
-	struct VCLS *cs;
-
-	ALLOC_OBJ(cs, VCLS_MAGIC);
-	AN(cs);
-	VTAILQ_INIT(&cs->fds);
-	VTAILQ_INIT(&cs->funcs);
-	cs->before = before;
-	cs->after = after;
-	cs->maxlen = maxlen;
-	cs->limit = limit;
-	return (cs);
-}
-
-struct cli *
-VCLS_AddFd(struct VCLS *cs, int fdi, int fdo, cls_cb_f *closefunc, void *priv)
-{
-	struct VCLS_fd *cfd;
-
-	CHECK_OBJ_NOTNULL(cs, VCLS_MAGIC);
-	assert(fdi >= 0);
-	assert(fdo >= 0);
-	ALLOC_OBJ(cfd, VCLS_FD_MAGIC);
-	AN(cfd);
-	cfd->cls = cs;
-	cfd->fdi = fdi;
-	cfd->fdo = fdo;
-	cfd->cli = &cfd->clis;
-	cfd->cli->magic = CLI_MAGIC;
-	cfd->cli->vlu = VLU_New(cfd, cls_vlu, *cs->maxlen);
-	cfd->cli->sb = VSB_new_auto();
-	cfd->cli->limit = cs->limit;
-	cfd->closefunc = closefunc;
-	cfd->priv = priv;
-	AN(cfd->cli->sb);
-	VTAILQ_INSERT_TAIL(&cs->fds, cfd, list);
-	cs->nfd++;
-	return (cfd->cli);
-}
-
-static void
-cls_close_fd(struct VCLS *cs, struct VCLS_fd *cfd)
-{
-
-	CHECK_OBJ_NOTNULL(cs, VCLS_MAGIC);
-	CHECK_OBJ_NOTNULL(cfd, VCLS_FD_MAGIC);
-
-	VTAILQ_REMOVE(&cs->fds, cfd, list);
-	cs->nfd--;
-	VLU_Destroy(cfd->cli->vlu);
-	VSB_destroy(&cfd->cli->sb);
-	if (cfd->closefunc == NULL) {
-		(void)close(cfd->fdi);
-		if (cfd->fdo != cfd->fdi)
-			(void)close(cfd->fdo);
-	} else {
-		cfd->closefunc(cfd->priv);
-	}
-	if (cfd->cli->ident != NULL)
-		free(cfd->cli->ident);
-	FREE_OBJ(cfd);
-}
-
-void
-VCLS_AddFunc(struct VCLS *cs, unsigned auth, struct cli_proto *clp)
-{
-	struct cli_proto *clp2;
-	int i;
-
-	CHECK_OBJ_NOTNULL(cs, VCLS_MAGIC);
-	AN(clp);
-
-	for (;clp->desc != NULL; clp++) {
-		clp->auth = auth;
-		if (!strcmp(clp->desc->request, "*")) {
-			cs->wildcard = clp;
-		} else {
-			i = 0;
-			VTAILQ_FOREACH(clp2, &cs->funcs, list) {
-				i = strcmp(clp->desc->request,
-				    clp2->desc->request);
-				if (i <= 0)
-					break;
-			}
-			if (clp2 != NULL && i == 0) {
-				VTAILQ_INSERT_BEFORE(clp2, clp, list);
-				VTAILQ_REMOVE(&cs->funcs, clp2, list);
-			} else if (clp2 != NULL)
-				VTAILQ_INSERT_BEFORE(clp2, clp, list);
-			else
-				VTAILQ_INSERT_TAIL(&cs->funcs, clp, list);
-		}
-	}
-}
-
-/*
- * This function has *very* special semantics, related to the mgt/worker
- * process Copy-On-Write memory relationship.
- */
-
-void
-VCLS_Clone(struct VCLS *cs, struct VCLS *cso)
-{
-	struct cli_proto *clp, *clp2;
-
-	CHECK_OBJ_NOTNULL(cs, VCLS_MAGIC);
-	CHECK_OBJ_NOTNULL(cso, VCLS_MAGIC);
-	VTAILQ_FOREACH_SAFE(clp, &cso->funcs, list, clp2) {
-		VTAILQ_REMOVE(&cso->funcs, clp, list);
-		VTAILQ_INSERT_TAIL(&cs->funcs, clp, list);
-		clp->auth = 0;
-		clp->func = NULL;
-	}
-}
-
-int
-VCLS_PollFd(struct VCLS *cs, int fd, int timeout)
-{
-	struct VCLS_fd *cfd;
-	struct pollfd pfd[1];
-	int i, j, k;
-
-	CHECK_OBJ_NOTNULL(cs, VCLS_MAGIC);
-	if (cs->nfd == 0) {
-		errno = 0;
-		return (-1);
-	}
-	assert(cs->nfd > 0);
-
-	i = 0;
-	VTAILQ_FOREACH(cfd, &cs->fds, list) {
-		if (cfd->fdi != fd)
-			continue;
-		pfd[i].fd = cfd->fdi;
-		pfd[i].events = POLLIN;
-		pfd[i].revents = 0;
-		i++;
-		break;
-	}
-	assert(i == 1);
-	CHECK_OBJ_NOTNULL(cfd, VCLS_FD_MAGIC);
-
-	j = poll(pfd, 1, timeout);
-	if (j <= 0)
-		return (j);
-	if (pfd[0].revents & POLLHUP)
-		k = 1;
-	else
-		k = VLU_Fd(cfd->fdi, cfd->cli->vlu);
-	if (k)
-		cls_close_fd(cs, cfd);
-	return (k);
-}
-
-int
-VCLS_Poll(struct VCLS *cs, int timeout)
-{
-	struct VCLS_fd *cfd, *cfd2;
-	int i, j, k;
-
-	CHECK_OBJ_NOTNULL(cs, VCLS_MAGIC);
-	if (cs->nfd == 0) {
-		errno = 0;
-		return (-1);
-	}
-	assert(cs->nfd > 0);
-	{
-		struct pollfd pfd[cs->nfd];
-
-		i = 0;
-		VTAILQ_FOREACH(cfd, &cs->fds, list) {
-			pfd[i].fd = cfd->fdi;
-			pfd[i].events = POLLIN;
-			pfd[i].revents = 0;
-			i++;
-		}
-		assert(i == cs->nfd);
-
-		j = poll(pfd, cs->nfd, timeout);
-		if (j <= 0)
-			return (j);
-		i = 0;
-		VTAILQ_FOREACH_SAFE(cfd, &cs->fds, list, cfd2) {
-			assert(pfd[i].fd == cfd->fdi);
-			if (pfd[i].revents & POLLHUP)
-				k = 1;
-			else
-				k = VLU_Fd(cfd->fdi, cfd->cli->vlu);
-			if (k)
-				cls_close_fd(cs, cfd);
-			i++;
-		}
-		assert(i == j);
-	}
-	return (j);
-}
-
-void
-VCLS_Destroy(struct VCLS **csp)
-{
-	struct VCLS *cs;
-	struct VCLS_fd *cfd, *cfd2;
-	struct cli_proto *clp;
-
-	cs = *csp;
-	*csp = NULL;
-	CHECK_OBJ_NOTNULL(cs, VCLS_MAGIC);
-	VTAILQ_FOREACH_SAFE(cfd, &cs->fds, list, cfd2)
-		cls_close_fd(cs, cfd);
-
-	while (!VTAILQ_EMPTY(&cs->funcs)) {
-		clp = VTAILQ_FIRST(&cs->funcs);
-		VTAILQ_REMOVE(&cs->funcs, clp, list);
-	}
-	FREE_OBJ(cs);
-}
diff --git a/lib/libvarnish/vcli_proto.c b/lib/libvarnish/vcli_proto.c
new file mode 100644
index 0000000..d7b7bf2
--- /dev/null
+++ b/lib/libvarnish/vcli_proto.c
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 2010-2011 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "vas.h"
+#include "vcli.h"
+#include "vsha256.h"
+
+void
+VCLI_AuthResponse(int S_fd, const char *challenge,
+    char response[CLI_AUTH_RESPONSE_LEN + 1])
+{
+	SHA256_CTX ctx;
+	uint8_t buf[SHA256_LEN];
+	int i;
+
+	assert(CLI_AUTH_RESPONSE_LEN == (SHA256_LEN * 2));
+
+	SHA256_Init(&ctx);
+	SHA256_Update(&ctx, challenge, 32);
+	SHA256_Update(&ctx, "\n", 1);
+	do {
+		i = read(S_fd, buf, 1);
+		if (i == 1)
+			SHA256_Update(&ctx, buf, i);
+	} while (i > 0);
+	SHA256_Update(&ctx, challenge, 32);
+	SHA256_Update(&ctx, "\n", 1);
+	SHA256_Final(buf, &ctx);
+	for(i = 0; i < SHA256_LEN; i++)
+		sprintf(response + 2 * i, "%02x", buf[i]);
+}
diff --git a/lib/libvarnish/vcli_serve.c b/lib/libvarnish/vcli_serve.c
new file mode 100644
index 0000000..4e88bdc
--- /dev/null
+++ b/lib/libvarnish/vcli_serve.c
@@ -0,0 +1,616 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2011 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Stuff for handling the CLI protocol
+ */
+
+#include "config.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <poll.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "vdef.h"
+#include "vas.h"
+#include "vqueue.h"
+#include "miniobj.h"
+
+#include "vav.h"
+#include "vcli.h"
+#include "vcli_common.h"
+#include "vcli_priv.h"
+#include "vcli_serve.h"
+#include "vlu.h"
+#include "vsb.h"
+
+struct VCLS_fd {
+	unsigned			magic;
+#define VCLS_FD_MAGIC			0x010dbd1e
+	VTAILQ_ENTRY(VCLS_fd)		list;
+	int				fdi, fdo;
+	struct VCLS			*cls;
+	struct cli			*cli, clis;
+	cls_cb_f			*closefunc;
+	void				*priv;
+	struct vsb			*last_arg;
+	int				last_idx;
+	char				**argv;
+};
+
+struct VCLS {
+	unsigned			magic;
+#define VCLS_MAGIC			0x60f044a3
+	VTAILQ_HEAD(,VCLS_fd)		fds;
+	unsigned			nfd;
+	VTAILQ_HEAD(,cli_proto)		funcs;
+	cls_cbc_f			*before, *after;
+	volatile unsigned		*maxlen;
+	volatile unsigned		*limit;
+	struct cli_proto		*wildcard;
+};
+
+/*--------------------------------------------------------------------*/
+
+void __match_proto__(cli_func_t)
+VCLS_func_close(struct cli *cli, const char *const *av, void *priv)
+{
+
+	(void)av;
+	(void)priv;
+	VCLI_Out(cli, "Closing CLI connection");
+	VCLI_SetResult(cli, CLIS_CLOSE);
+}
+
+/*--------------------------------------------------------------------*/
+
+void __match_proto__(cli_func_t)
+VCLS_func_ping(struct cli *cli, const char * const *av, void *priv)
+{
+	time_t t;
+
+	(void)av;
+	(void)priv;
+	t = time(NULL);
+	VCLI_Out(cli, "PONG %jd 1.0", (intmax_t)t);
+}
+
+/*--------------------------------------------------------------------*/
+
+void __match_proto__(cli_func_t)
+VCLS_func_help(struct cli *cli, const char * const *av, void *priv)
+{
+	struct cli_proto *clp;
+	unsigned all, debug, d;
+	struct VCLS *cs;
+
+	(void)priv;
+	cs = cli->cls;
+	CHECK_OBJ_NOTNULL(cs, VCLS_MAGIC);
+
+	if (av[2] == NULL) {
+		all = debug = 0;
+	} else if (!strcmp(av[2], "-a")) {
+		all = 1;
+		debug = 0;
+	} else if (!strcmp(av[2], "-d")) {
+		all = 0;
+		debug = 1;
+	} else {
+		VTAILQ_FOREACH(clp, &cs->funcs, list) {
+			if (clp->auth <= cli->auth &&
+			    !strcmp(clp->desc->request, av[2])) {
+				VCLI_Out(cli, "%s\n%s\n",
+				    clp->desc->syntax, clp->desc->help);
+				return;
+			}
+		}
+		VCLI_Out(cli, "Unknown request.\nType 'help' for more info.\n");
+		VCLI_SetResult(cli, CLIS_UNKNOWN);
+		return;
+	}
+	VTAILQ_FOREACH(clp, &cs->funcs, list) {
+		if (clp->auth > cli->auth)
+			continue;
+		d =  strchr(clp->flags, 'd') != NULL ? 1 : 0;
+		if (d && (!all && !debug))
+			continue;
+		if (debug && !d)
+			continue;
+		if (clp->desc->syntax != NULL)
+			VCLI_Out(cli, "%s\n", clp->desc->syntax);
+	}
+}
+
+void __match_proto__(cli_func_t)
+VCLS_func_help_json(struct cli *cli, const char * const *av, void *priv)
+{
+	struct cli_proto *clp;
+	struct VCLS *cs;
+
+	(void)priv;
+	cs = cli->cls;
+	CHECK_OBJ_NOTNULL(cs, VCLS_MAGIC);
+
+	VCLI_JSON_ver(cli, 1, av);
+	VTAILQ_FOREACH(clp, &cs->funcs, list) {
+		if (clp->auth > cli->auth)
+			continue;
+		VCLI_Out(cli, ",\n  {");
+		VCLI_Out(cli, "\n  \"request\": ");
+		VCLI_JSON_str(cli, clp->desc->request);
+		VCLI_Out(cli, ",\n  \"syntax\": ");
+		VCLI_JSON_str(cli, clp->desc->syntax);
+		VCLI_Out(cli, ",\n  \"help\": ");
+		VCLI_JSON_str(cli, clp->desc->help);
+		VCLI_Out(cli, ",\n  \"minarg\": %d", clp->desc->minarg);
+		VCLI_Out(cli, ", \"maxarg\": %d", clp->desc->maxarg);
+		VCLI_Out(cli, ", \"flags\": ");
+		VCLI_JSON_str(cli, clp->flags);
+		VCLI_Out(cli, ", \"json\": %s",
+		    clp->jsonfunc == NULL ? "false" : "true");
+		VCLI_Out(cli, "\n  }");
+	}
+	VCLI_Out(cli, "\n]\n");
+}
+
+/*--------------------------------------------------------------------
+ * Look for a CLI command to execute
+ */
+
+static void
+cls_dispatch(struct cli *cli, const struct cli_proto *cp,
+    char * const * av, unsigned ac)
+{
+	int json = 0;
+
+	AN(av);
+
+	if (ac > 1 && !strcmp(av[2], "-j"))
+		json = 1;
+
+	if (cp->func == NULL && !json) {
+		VCLI_Out(cli, "Unimplemented\n");
+		VCLI_SetResult(cli, CLIS_UNIMPL);
+		return;
+	}
+	if (cp->jsonfunc == NULL && json) {
+		VCLI_Out(cli, "JSON unimplemented\n");
+		VCLI_SetResult(cli, CLIS_UNIMPL);
+		return;
+	}
+
+	if (ac - 1 < cp->desc->minarg + json) {
+		VCLI_Out(cli, "Too few parameters\n");
+		VCLI_SetResult(cli, CLIS_TOOFEW);
+		return;
+	}
+
+	if (ac - 1> cp->desc->maxarg + json) {
+		VCLI_Out(cli, "Too many parameters\n");
+		VCLI_SetResult(cli, CLIS_TOOMANY);
+		return;
+	}
+
+	cli->result = CLIS_OK;
+	VSB_clear(cli->sb);
+	if (json)
+		cp->jsonfunc(cli, (const char * const *)av, cp->priv);
+	else
+		cp->func(cli, (const char * const *)av, cp->priv);
+}
+
+/*--------------------------------------------------------------------
+ * We have collected a full cli line, parse it and execute, if possible.
+ */
+
+static int
+cls_vlu2(void *priv, char * const *av)
+{
+	struct VCLS_fd *cfd;
+	struct VCLS *cs;
+	struct cli_proto *clp;
+	struct cli *cli;
+	unsigned na;
+	ssize_t len;
+	char *s;
+	unsigned lim;
+	const char *trunc = "!\n[response was truncated]\n";
+
+	CAST_OBJ_NOTNULL(cfd, priv, VCLS_FD_MAGIC);
+	cs = cfd->cls;
+	CHECK_OBJ_NOTNULL(cs, VCLS_MAGIC);
+
+	cli = cfd->cli;
+	CHECK_OBJ_NOTNULL(cli, CLI_MAGIC);
+	AN(cli->cmd);
+
+	cli->cls = cs;
+
+	cli->result = CLIS_UNKNOWN;
+	VSB_clear(cli->sb);
+	VCLI_Out(cli, "Unknown request.\nType 'help' for more info.\n");
+
+	if (cs->before != NULL)
+		cs->before(cli);
+
+	do {
+		if (av[0] != NULL) {
+			VCLI_Out(cli, "Syntax Error: %s\n", av[0]);
+			VCLI_SetResult(cli, CLIS_SYNTAX);
+			break;
+		}
+
+		if (isupper(av[1][0])) {
+			VCLI_Out(cli, "all commands are in lower-case.\n");
+			VCLI_SetResult(cli, CLIS_UNKNOWN);
+			break;
+		}
+
+		if (!islower(av[1][0]))
+			break;
+
+		for (na = 0; av[na + 1] != NULL; na++)
+			continue;
+
+		VTAILQ_FOREACH(clp, &cs->funcs, list) {
+			if (clp->auth > cli->auth)
+				continue;
+			if (!strcmp(clp->desc->request, av[1])) {
+				cls_dispatch(cli, clp, av, na);
+				break;
+			}
+		}
+		if (clp == NULL &&
+		    cs->wildcard && cs->wildcard->auth <= cli->auth)
+			cls_dispatch(cli, cs->wildcard, av, na);
+
+	} while (0);
+
+	AZ(VSB_finish(cli->sb));
+
+	if (cs->after != NULL)
+		cs->after(cli);
+
+	cli->cls = NULL;
+
+	s = VSB_data(cli->sb);
+	len = VSB_len(cli->sb);
+	lim = *cs->limit;
+	if (len > lim) {
+		if (cli->result == CLIS_OK)
+			cli->result = CLIS_TRUNCATED;
+		strcpy(s + (lim - strlen(trunc)), trunc);
+		assert(strlen(s) <= lim);
+	}
+	if (VCLI_WriteResult(cfd->fdo, cli->result, s) ||
+	    cli->result == CLIS_CLOSE)
+		return (1);
+
+	return (0);
+}
+
+static int
+cls_vlu(void *priv, const char *p)
+{
+	struct VCLS_fd *cfd;
+	struct cli *cli;
+	int i;
+	char **av;
+
+	CAST_OBJ_NOTNULL(cfd, priv, VCLS_FD_MAGIC);
+	AN(p);
+
+	cli = cfd->cli;
+	CHECK_OBJ_NOTNULL(cli, CLI_MAGIC);
+
+	if (cfd->argv == NULL) {
+		/*
+		 * Lines with only whitespace are simply ignored, in order
+		 * to not complicate CLI-client side scripts and TELNET users
+		 */
+		for (; isspace(*p); p++)
+			continue;
+		if (*p == '\0')
+			return (0);
+		REPLACE(cli->cmd, p);
+
+		av = VAV_Parse(p, NULL, 0);
+		AN(av);
+		if (av[0] != NULL) {
+			i = cls_vlu2(priv, av);
+			VAV_Free(av);
+			free(cli->cmd);
+			cli->cmd = NULL;
+			return (i);
+		}
+		for (i = 1; av[i] != NULL; i++)
+			continue;
+		if (i < 3 || cli->auth == 0 || strcmp(av[i - 2], "<<")) {
+			i = cls_vlu2(priv, av);
+			VAV_Free(av);
+			free(cli->cmd);
+			cli->cmd = NULL;
+			return (i);
+		}
+		cfd->argv = av;
+		cfd->last_idx = i - 2;
+		cfd->last_arg = VSB_new_auto();
+		AN(cfd->last_arg);
+		return (0);
+	} else {
+		AN(cfd->argv[cfd->last_idx]);
+		AZ(strcmp(cfd->argv[cfd->last_idx], "<<"));
+		AN(cfd->argv[cfd->last_idx + 1]);
+		if (strcmp(p, cfd->argv[cfd->last_idx + 1])) {
+			VSB_cat(cfd->last_arg, p);
+			VSB_cat(cfd->last_arg, "\n");
+			return (0);
+		}
+		AZ(VSB_finish(cfd->last_arg));
+		free(cfd->argv[cfd->last_idx]);
+		cfd->argv[cfd->last_idx] = NULL;
+		free(cfd->argv[cfd->last_idx + 1]);
+		cfd->argv[cfd->last_idx + 1] = NULL;
+		cfd->argv[cfd->last_idx] = VSB_data(cfd->last_arg);
+		i = cls_vlu2(priv, cfd->argv);
+		cfd->argv[cfd->last_idx] = NULL;
+		VAV_Free(cfd->argv);
+		cfd->argv = NULL;
+		free(cli->cmd);
+		cli->cmd = NULL;
+		VSB_destroy(&cfd->last_arg);
+		cfd->last_idx = 0;
+		return (i);
+	}
+}
+
+struct VCLS *
+VCLS_New(cls_cbc_f *before, cls_cbc_f *after, volatile unsigned *maxlen,
+    volatile unsigned *limit)
+{
+	struct VCLS *cs;
+
+	ALLOC_OBJ(cs, VCLS_MAGIC);
+	AN(cs);
+	VTAILQ_INIT(&cs->fds);
+	VTAILQ_INIT(&cs->funcs);
+	cs->before = before;
+	cs->after = after;
+	cs->maxlen = maxlen;
+	cs->limit = limit;
+	return (cs);
+}
+
+struct cli *
+VCLS_AddFd(struct VCLS *cs, int fdi, int fdo, cls_cb_f *closefunc, void *priv)
+{
+	struct VCLS_fd *cfd;
+
+	CHECK_OBJ_NOTNULL(cs, VCLS_MAGIC);
+	assert(fdi >= 0);
+	assert(fdo >= 0);
+	ALLOC_OBJ(cfd, VCLS_FD_MAGIC);
+	AN(cfd);
+	cfd->cls = cs;
+	cfd->fdi = fdi;
+	cfd->fdo = fdo;
+	cfd->cli = &cfd->clis;
+	cfd->cli->magic = CLI_MAGIC;
+	cfd->cli->vlu = VLU_New(cfd, cls_vlu, *cs->maxlen);
+	cfd->cli->sb = VSB_new_auto();
+	cfd->cli->limit = cs->limit;
+	cfd->closefunc = closefunc;
+	cfd->priv = priv;
+	AN(cfd->cli->sb);
+	VTAILQ_INSERT_TAIL(&cs->fds, cfd, list);
+	cs->nfd++;
+	return (cfd->cli);
+}
+
+static void
+cls_close_fd(struct VCLS *cs, struct VCLS_fd *cfd)
+{
+
+	CHECK_OBJ_NOTNULL(cs, VCLS_MAGIC);
+	CHECK_OBJ_NOTNULL(cfd, VCLS_FD_MAGIC);
+
+	VTAILQ_REMOVE(&cs->fds, cfd, list);
+	cs->nfd--;
+	VLU_Destroy(cfd->cli->vlu);
+	VSB_destroy(&cfd->cli->sb);
+	if (cfd->closefunc == NULL) {
+		(void)close(cfd->fdi);
+		if (cfd->fdo != cfd->fdi)
+			(void)close(cfd->fdo);
+	} else {
+		cfd->closefunc(cfd->priv);
+	}
+	if (cfd->cli->ident != NULL)
+		free(cfd->cli->ident);
+	FREE_OBJ(cfd);
+}
+
+void
+VCLS_AddFunc(struct VCLS *cs, unsigned auth, struct cli_proto *clp)
+{
+	struct cli_proto *clp2;
+	int i;
+
+	CHECK_OBJ_NOTNULL(cs, VCLS_MAGIC);
+	AN(clp);
+
+	for (;clp->desc != NULL; clp++) {
+		clp->auth = auth;
+		if (!strcmp(clp->desc->request, "*")) {
+			cs->wildcard = clp;
+		} else {
+			i = 0;
+			VTAILQ_FOREACH(clp2, &cs->funcs, list) {
+				i = strcmp(clp->desc->request,
+				    clp2->desc->request);
+				if (i <= 0)
+					break;
+			}
+			if (clp2 != NULL && i == 0) {
+				VTAILQ_INSERT_BEFORE(clp2, clp, list);
+				VTAILQ_REMOVE(&cs->funcs, clp2, list);
+			} else if (clp2 != NULL)
+				VTAILQ_INSERT_BEFORE(clp2, clp, list);
+			else
+				VTAILQ_INSERT_TAIL(&cs->funcs, clp, list);
+		}
+	}
+}
+
+/*
+ * This function has *very* special semantics, related to the mgt/worker
+ * process Copy-On-Write memory relationship.
+ */
+
+void
+VCLS_Clone(struct VCLS *cs, struct VCLS *cso)
+{
+	struct cli_proto *clp, *clp2;
+
+	CHECK_OBJ_NOTNULL(cs, VCLS_MAGIC);
+	CHECK_OBJ_NOTNULL(cso, VCLS_MAGIC);
+	VTAILQ_FOREACH_SAFE(clp, &cso->funcs, list, clp2) {
+		VTAILQ_REMOVE(&cso->funcs, clp, list);
+		VTAILQ_INSERT_TAIL(&cs->funcs, clp, list);
+		clp->auth = 0;
+		clp->func = NULL;
+	}
+}
+
+int
+VCLS_PollFd(struct VCLS *cs, int fd, int timeout)
+{
+	struct VCLS_fd *cfd;
+	struct pollfd pfd[1];
+	int i, j, k;
+
+	CHECK_OBJ_NOTNULL(cs, VCLS_MAGIC);
+	if (cs->nfd == 0) {
+		errno = 0;
+		return (-1);
+	}
+	assert(cs->nfd > 0);
+
+	i = 0;
+	VTAILQ_FOREACH(cfd, &cs->fds, list) {
+		if (cfd->fdi != fd)
+			continue;
+		pfd[i].fd = cfd->fdi;
+		pfd[i].events = POLLIN;
+		pfd[i].revents = 0;
+		i++;
+		break;
+	}
+	assert(i == 1);
+	CHECK_OBJ_NOTNULL(cfd, VCLS_FD_MAGIC);
+
+	j = poll(pfd, 1, timeout);
+	if (j <= 0)
+		return (j);
+	if (pfd[0].revents & POLLHUP)
+		k = 1;
+	else
+		k = VLU_Fd(cfd->fdi, cfd->cli->vlu);
+	if (k)
+		cls_close_fd(cs, cfd);
+	return (k);
+}
+
+int
+VCLS_Poll(struct VCLS *cs, int timeout)
+{
+	struct VCLS_fd *cfd, *cfd2;
+	int i, j, k;
+
+	CHECK_OBJ_NOTNULL(cs, VCLS_MAGIC);
+	if (cs->nfd == 0) {
+		errno = 0;
+		return (-1);
+	}
+	assert(cs->nfd > 0);
+	{
+		struct pollfd pfd[cs->nfd];
+
+		i = 0;
+		VTAILQ_FOREACH(cfd, &cs->fds, list) {
+			pfd[i].fd = cfd->fdi;
+			pfd[i].events = POLLIN;
+			pfd[i].revents = 0;
+			i++;
+		}
+		assert(i == cs->nfd);
+
+		j = poll(pfd, cs->nfd, timeout);
+		if (j <= 0)
+			return (j);
+		i = 0;
+		VTAILQ_FOREACH_SAFE(cfd, &cs->fds, list, cfd2) {
+			assert(pfd[i].fd == cfd->fdi);
+			if (pfd[i].revents & POLLHUP)
+				k = 1;
+			else
+				k = VLU_Fd(cfd->fdi, cfd->cli->vlu);
+			if (k)
+				cls_close_fd(cs, cfd);
+			i++;
+		}
+		assert(i == j);
+	}
+	return (j);
+}
+
+void
+VCLS_Destroy(struct VCLS **csp)
+{
+	struct VCLS *cs;
+	struct VCLS_fd *cfd, *cfd2;
+	struct cli_proto *clp;
+
+	cs = *csp;
+	*csp = NULL;
+	CHECK_OBJ_NOTNULL(cs, VCLS_MAGIC);
+	VTAILQ_FOREACH_SAFE(cfd, &cs->fds, list, cfd2)
+		cls_close_fd(cs, cfd);
+
+	while (!VTAILQ_EMPTY(&cs->funcs)) {
+		clp = VTAILQ_FIRST(&cs->funcs);
+		VTAILQ_REMOVE(&cs->funcs, clp, list);
+	}
+	FREE_OBJ(cs);
+}



More information about the varnish-commit mailing list