aboutsummaryrefslogtreecommitdiff
path: root/contrib/bind/lib/isc/ctl_srvr.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bind/lib/isc/ctl_srvr.c')
-rw-r--r--contrib/bind/lib/isc/ctl_srvr.c751
1 files changed, 0 insertions, 751 deletions
diff --git a/contrib/bind/lib/isc/ctl_srvr.c b/contrib/bind/lib/isc/ctl_srvr.c
deleted file mode 100644
index ff1fc829aad1..000000000000
--- a/contrib/bind/lib/isc/ctl_srvr.c
+++ /dev/null
@@ -1,751 +0,0 @@
-#if !defined(lint) && !defined(SABER)
-static const char rcsid[] = "$Id: ctl_srvr.c,v 8.23 2000/02/04 08:28:33 vixie Exp $";
-#endif /* not lint */
-
-/*
- * Copyright (c) 1998,1999 by Internet Software Consortium.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
- * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
- * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- * SOFTWARE.
- */
-
-/* Extern. */
-
-#include "port_before.h"
-
-#include <sys/param.h>
-#include <sys/file.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-
-#include <netinet/in.h>
-#include <arpa/nameser.h>
-#include <arpa/inet.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include <isc/assertions.h>
-#include <isc/ctl.h>
-#include <isc/eventlib.h>
-#include <isc/list.h>
-#include <isc/logging.h>
-#include <isc/memcluster.h>
-
-#include "ctl_p.h"
-
-#include "port_after.h"
-
-#ifdef SPRINTF_CHAR
-# define SPRINTF(x) strlen(sprintf/**/x)
-#else
-# define SPRINTF(x) ((size_t)sprintf x)
-#endif
-
-/* Macros. */
-
-#define lastverb_p(verb) (verb->name == NULL || verb->func == NULL)
-#define address_expr ctl_sa_ntop((struct sockaddr *)&sess->sa, \
- tmp, sizeof tmp, ctx->logger)
-
-/* Types. */
-
-enum state {
- available = 0, initializing, writing, reading, reading_data,
- processing, idling, quitting, closing
-};
-
-union sa_un {
- struct sockaddr_in in;
-#ifndef NO_SOCKADDR_UN
- struct sockaddr_un un;
-#endif
-};
-
-struct ctl_sess {
- LINK(struct ctl_sess) link;
- struct ctl_sctx * ctx;
- enum state state;
- int sock;
- union sa_un sa;
- evFileID rdID;
- evStreamID wrID;
- evTimerID rdtiID;
- evTimerID wrtiID;
- struct ctl_buf inbuf;
- struct ctl_buf outbuf;
- const struct ctl_verb * verb;
- u_int helpcode;
- void * respctx;
- u_int respflags;
- ctl_srvrdone donefunc;
- void * uap;
- void * csctx;
-};
-
-struct ctl_sctx {
- evContext ev;
- void * uctx;
- u_int unkncode;
- u_int timeoutcode;
- const struct ctl_verb * verbs;
- const struct ctl_verb * connverb;
- int sock;
- int max_sess;
- int cur_sess;
- struct timespec timeout;
- ctl_logfunc logger;
- evConnID acID;
- LIST(struct ctl_sess) sess;
-};
-
-/* Forward. */
-
-static void ctl_accept(evContext, void *, int,
- const void *, int,
- const void *, int);
-static void ctl_close(struct ctl_sess *);
-static void ctl_new_state(struct ctl_sess *,
- enum state,
- const char *);
-static void ctl_start_read(struct ctl_sess *);
-static void ctl_stop_read(struct ctl_sess *);
-static void ctl_readable(evContext, void *, int, int);
-static void ctl_rdtimeout(evContext, void *,
- struct timespec,
- struct timespec);
-static void ctl_wrtimeout(evContext, void *,
- struct timespec,
- struct timespec);
-static void ctl_docommand(struct ctl_sess *);
-static void ctl_writedone(evContext, void *, int, int);
-static void ctl_morehelp(struct ctl_sctx *,
- struct ctl_sess *,
- const struct ctl_verb *,
- const char *,
- u_int, void *, void *);
-static void ctl_signal_done(struct ctl_sctx *,
- struct ctl_sess *);
-
-/* Private data. */
-
-static const char * state_names[] = {
- "available", "initializing", "writing", "reading",
- "reading_data", "processing", "idling", "quitting", "closing"
-};
-
-static const char space[] = " ";
-
-static const struct ctl_verb fakehelpverb = { "fakehelp", ctl_morehelp };
-
-/* Public. */
-
-/*
- * void
- * ctl_server()
- * create, condition, and start a listener on the control port.
- */
-struct ctl_sctx *
-ctl_server(evContext lev, const struct sockaddr *sap, size_t sap_len,
- const struct ctl_verb *verbs,
- u_int unkncode, u_int timeoutcode,
- u_int timeout, int backlog, int max_sess,
- ctl_logfunc logger, void *uctx)
-{
- static const char me[] = "ctl_server";
- static const int on = 1;
- const struct ctl_verb *connverb;
- struct ctl_sctx *ctx;
- int save_errno;
-
- if (logger == NULL)
- logger = ctl_logger;
- for (connverb = verbs;
- connverb->name != NULL && connverb->func != NULL;
- connverb++)
- if (connverb->name[0] == '\0')
- break;
- if (connverb->func == NULL) {
- (*logger)(ctl_error, "%s: no connection verb found", me);
- return (NULL);
- }
- ctx = memget(sizeof *ctx);
- if (ctx == NULL) {
- (*logger)(ctl_error, "%s: getmem: %s", me, strerror(errno));
- return (NULL);
- }
- ctx->ev = lev;
- ctx->uctx = uctx;
- ctx->unkncode = unkncode;
- ctx->timeoutcode = timeoutcode;
- ctx->verbs = verbs;
- ctx->timeout = evConsTime(timeout, 0);
- ctx->logger = logger;
- ctx->connverb = connverb;
- ctx->max_sess = max_sess;
- ctx->cur_sess = 0;
- INIT_LIST(ctx->sess);
- ctx->sock = socket(sap->sa_family, SOCK_STREAM, PF_UNSPEC);
- if (ctx->sock > evHighestFD(ctx->ev)) {
- ctx->sock = -1;
- errno = ENOTSOCK;
- }
- if (ctx->sock < 0) {
- save_errno = errno;
- (*ctx->logger)(ctl_error, "%s: socket: %s",
- me, strerror(errno));
- memput(ctx, sizeof *ctx);
- errno = save_errno;
- return (NULL);
- }
- if (ctx->sock > evHighestFD(lev)) {
- close(ctx->sock);
- (*ctx->logger)(ctl_error, "%s: file descriptor > evHighestFD");
- errno = ENFILE;
- memput(ctx, sizeof *ctx);
- return (NULL);
- }
-#ifdef NO_UNIX_REUSEADDR
- if (sap->sa_family != AF_UNIX)
-#endif
- if (setsockopt(ctx->sock, SOL_SOCKET, SO_REUSEADDR,
- (char *)&on, sizeof on) != 0) {
- (*ctx->logger)(ctl_warning,
- "%s: setsockopt(REUSEADDR): %s",
- me, strerror(errno));
- }
- if (bind(ctx->sock, sap, sap_len) < 0) {
- char tmp[MAX_NTOP];
- save_errno = errno;
- (*ctx->logger)(ctl_error, "%s: bind: %s: %s",
- me, ctl_sa_ntop((struct sockaddr *)sap,
- tmp, sizeof tmp, ctx->logger),
- strerror(save_errno));
- close(ctx->sock);
- memput(ctx, sizeof *ctx);
- errno = save_errno;
- return (NULL);
- }
- if (fcntl(ctx->sock, F_SETFD, 1) < 0) {
- (*ctx->logger)(ctl_warning, "%s: fcntl: %s", me,
- strerror(errno));
- }
- if (evListen(lev, ctx->sock, backlog, ctl_accept, ctx,
- &ctx->acID) < 0) {
- save_errno = errno;
- (*ctx->logger)(ctl_error, "%s: evListen(fd %d): %s",
- me, (void *)ctx->sock, strerror(errno));
- close(ctx->sock);
- memput(ctx, sizeof *ctx);
- errno = save_errno;
- return (NULL);
- }
- (*ctx->logger)(ctl_debug, "%s: new ctx %p, sock %d",
- me, ctx, ctx->sock);
- return (ctx);
-}
-
-/*
- * void
- * ctl_endserver(ctx)
- * if the control listener is open, close it. clean out all eventlib
- * stuff. close all active sessions.
- */
-void
-ctl_endserver(struct ctl_sctx *ctx) {
- static const char me[] = "ctl_endserver";
- struct ctl_sess *this, *next;
-
- (*ctx->logger)(ctl_debug, "%s: ctx %p, sock %d, acID %p, sess %p",
- me, ctx, ctx->sock, ctx->acID.opaque, ctx->sess);
- if (ctx->acID.opaque != NULL) {
- (void)evCancelConn(ctx->ev, ctx->acID);
- ctx->acID.opaque = NULL;
- }
- if (ctx->sock != -1) {
- (void) close(ctx->sock);
- ctx->sock = -1;
- }
- for (this = HEAD(ctx->sess); this != NULL; this = next) {
- next = NEXT(this, link);
- ctl_close(this);
- }
- memput(ctx, sizeof *ctx);
-}
-
-/*
- * If body is non-NULL then it we add a "." line after it.
- * Caller must have escaped lines with leading ".".
- */
-void
-ctl_response(struct ctl_sess *sess, u_int code, const char *text,
- u_int flags, void *respctx, ctl_srvrdone donefunc, void *uap,
- const char *body, size_t bodylen)
-{
- static const char me[] = "ctl_response";
- struct iovec iov[3], *iovp = iov;
- struct ctl_sctx *ctx = sess->ctx;
- char tmp[MAX_NTOP], *pc;
- int n;
-
- REQUIRE(sess->state == initializing ||
- sess->state == processing ||
- sess->state == reading_data ||
- sess->state == writing);
- REQUIRE(sess->wrtiID.opaque == NULL);
- REQUIRE(sess->wrID.opaque == NULL);
- ctl_new_state(sess, writing, me);
- sess->donefunc = donefunc;
- sess->uap = uap;
- if (!allocated_p(sess->outbuf) &&
- ctl_bufget(&sess->outbuf, ctx->logger) < 0) {
- (*ctx->logger)(ctl_error, "%s: %s: cant get an output buffer",
- me, address_expr);
- goto untimely;
- }
- if (sizeof "000-\r\n" + strlen(text) > MAX_LINELEN) {
- (*ctx->logger)(ctl_error, "%s: %s: output buffer ovf, closing",
- me, address_expr);
- goto untimely;
- }
- sess->outbuf.used = SPRINTF((sess->outbuf.text, "%03d%c%s\r\n",
- code, (flags & CTL_MORE) != 0 ? '-' : ' ',
- text));
- for (pc = sess->outbuf.text, n = 0; n < sess->outbuf.used-2; pc++, n++)
- if (!isascii(*pc) || !isprint(*pc))
- *pc = '\040';
- *iovp++ = evConsIovec(sess->outbuf.text, sess->outbuf.used);
- if (body != NULL) {
- *iovp++ = evConsIovec((char *)body, bodylen);
- *iovp++ = evConsIovec(".\r\n", 3);
- }
- (*ctx->logger)(ctl_debug, "%s: [%d] %s", me,
- sess->outbuf.used, sess->outbuf.text);
- if (evWrite(ctx->ev, sess->sock, iov, iovp - iov,
- ctl_writedone, sess, &sess->wrID) < 0) {
- (*ctx->logger)(ctl_error, "%s: %s: evWrite: %s", me,
- address_expr, strerror(errno));
- goto untimely;
- }
- if (evSetIdleTimer(ctx->ev, ctl_wrtimeout, sess, ctx->timeout,
- &sess->wrtiID) < 0)
- {
- (*ctx->logger)(ctl_error, "%s: %s: evSetIdleTimer: %s", me,
- address_expr, strerror(errno));
- goto untimely;
- }
- if (evTimeRW(ctx->ev, sess->wrID, sess->wrtiID) < 0) {
- (*ctx->logger)(ctl_error, "%s: %s: evTimeRW: %s", me,
- address_expr, strerror(errno));
- untimely:
- ctl_signal_done(ctx, sess);
- ctl_close(sess);
- return;
- }
- sess->respctx = respctx;
- sess->respflags = flags;
-}
-
-void
-ctl_sendhelp(struct ctl_sess *sess, u_int code) {
- static const char me[] = "ctl_sendhelp";
- struct ctl_sctx *ctx = sess->ctx;
-
- sess->helpcode = code;
- sess->verb = &fakehelpverb;
- ctl_morehelp(ctx, sess, NULL, me, CTL_MORE, (void *)ctx->verbs, NULL);
-}
-
-void *
-ctl_getcsctx(struct ctl_sess *sess) {
- return (sess->csctx);
-}
-
-void *
-ctl_setcsctx(struct ctl_sess *sess, void *csctx) {
- void *old = sess->csctx;
-
- sess->csctx = csctx;
- return (old);
-}
-
-/* Private functions. */
-
-static void
-ctl_accept(evContext lev, void *uap, int fd,
- const void *lav, int lalen,
- const void *rav, int ralen)
-{
- static const char me[] = "ctl_accept";
- struct ctl_sctx *ctx = uap;
- struct ctl_sess *sess = NULL;
- char tmp[MAX_NTOP];
-
- if (fd < 0) {
- (*ctx->logger)(ctl_error, "%s: accept: %s",
- me, strerror(errno));
- return;
- }
- if (ctx->cur_sess == ctx->max_sess) {
- (*ctx->logger)(ctl_error, "%s: %s: too many control sessions",
- me, ctl_sa_ntop((struct sockaddr *)rav,
- tmp, sizeof tmp,
- ctx->logger));
- (void) close(fd);
- return;
- }
- sess = memget(sizeof *sess);
- if (sess == NULL) {
- (*ctx->logger)(ctl_error, "%s: memget: %s", me,
- strerror(errno));
- (void) close(fd);
- return;
- }
- if (fcntl(fd, F_SETFD, 1) < 0) {
- (*ctx->logger)(ctl_warning, "%s: fcntl: %s", me,
- strerror(errno));
- }
- ctx->cur_sess++;
- APPEND(ctx->sess, sess, link);
- sess->ctx = ctx;
- sess->sock = fd;
- sess->wrID.opaque = NULL;
- sess->rdID.opaque = NULL;
- sess->wrtiID.opaque = NULL;
- sess->rdtiID.opaque = NULL;
- sess->respctx = NULL;
- sess->csctx = NULL;
- if (((struct sockaddr *)rav)->sa_family == AF_UNIX)
- ctl_sa_copy((struct sockaddr *)lav,
- (struct sockaddr *)&sess->sa);
- else
- ctl_sa_copy((struct sockaddr *)rav,
- (struct sockaddr *)&sess->sa);
- sess->donefunc = NULL;
- buffer_init(sess->inbuf);
- buffer_init(sess->outbuf);
- sess->state = available;
- ctl_new_state(sess, initializing, me);
- sess->verb = ctx->connverb;
- (*ctx->logger)(ctl_debug, "%s: %s: accepting (fd %d)",
- me, address_expr, sess->sock);
- (*ctx->connverb->func)(ctx, sess, ctx->connverb, "", 0,
- (struct sockaddr *)rav, ctx->uctx);
-}
-
-static void
-ctl_new_state(struct ctl_sess *sess, enum state new_state, const char *reason)
-{
- static const char me[] = "ctl_new_state";
- struct ctl_sctx *ctx = sess->ctx;
- char tmp[MAX_NTOP];
-
- (*ctx->logger)(ctl_debug, "%s: %s: %s -> %s (%s)",
- me, address_expr,
- state_names[sess->state],
- state_names[new_state], reason);
- sess->state = new_state;
-}
-
-static void
-ctl_close(struct ctl_sess *sess) {
- static const char me[] = "ctl_close";
- struct ctl_sctx *ctx = sess->ctx;
- char tmp[MAX_NTOP];
-
- REQUIRE(sess->state == initializing ||
- sess->state == writing ||
- sess->state == reading ||
- sess->state == processing ||
- sess->state == reading_data ||
- sess->state == idling);
- REQUIRE(sess->sock != -1);
- if (sess->state == reading || sess->state == reading_data)
- ctl_stop_read(sess);
- else if (sess->state == writing) {
- if (sess->wrID.opaque != NULL) {
- (void) evCancelRW(ctx->ev, sess->wrID);
- sess->wrID.opaque = NULL;
- }
- if (sess->wrtiID.opaque != NULL) {
- (void) evClearIdleTimer(ctx->ev, sess->wrtiID);
- sess->wrtiID.opaque = NULL;
- }
- }
- ctl_new_state(sess, closing, me);
- (void) close(sess->sock);
- if (allocated_p(sess->inbuf))
- ctl_bufput(&sess->inbuf);
- if (allocated_p(sess->outbuf))
- ctl_bufput(&sess->outbuf);
- (*ctx->logger)(ctl_debug, "%s: %s: closed (fd %d)",
- me, address_expr, sess->sock);
- UNLINK(ctx->sess, sess, link);
- memput(sess, sizeof *sess);
- ctx->cur_sess--;
-}
-
-static void
-ctl_start_read(struct ctl_sess *sess) {
- static const char me[] = "ctl_start_read";
- struct ctl_sctx *ctx = sess->ctx;
- char tmp[MAX_NTOP];
-
- REQUIRE(sess->state == initializing ||
- sess->state == writing ||
- sess->state == processing ||
- sess->state == idling);
- REQUIRE(sess->rdtiID.opaque == NULL);
- REQUIRE(sess->rdID.opaque == NULL);
- sess->inbuf.used = 0;
- if (evSetIdleTimer(ctx->ev, ctl_rdtimeout, sess, ctx->timeout,
- &sess->rdtiID) < 0)
- {
- (*ctx->logger)(ctl_error, "%s: %s: evSetIdleTimer: %s", me,
- address_expr, strerror(errno));
- ctl_close(sess);
- return;
- }
- if (evSelectFD(ctx->ev, sess->sock, EV_READ,
- ctl_readable, sess, &sess->rdID) < 0) {
- (*ctx->logger)(ctl_error, "%s: %s: evSelectFD: %s", me,
- address_expr, strerror(errno));
- return;
- }
- ctl_new_state(sess, reading, me);
-}
-
-static void
-ctl_stop_read(struct ctl_sess *sess) {
- static const char me[] = "ctl_stop_read";
- struct ctl_sctx *ctx = sess->ctx;
-
- REQUIRE(sess->state == reading || sess->state == reading_data);
- REQUIRE(sess->rdID.opaque != NULL);
- (void) evDeselectFD(ctx->ev, sess->rdID);
- sess->rdID.opaque = NULL;
- if (sess->rdtiID.opaque != NULL) {
- (void) evClearIdleTimer(ctx->ev, sess->rdtiID);
- sess->rdtiID.opaque = NULL;
- }
- ctl_new_state(sess, idling, me);
-}
-
-static void
-ctl_readable(evContext lev, void *uap, int fd, int evmask) {
- static const char me[] = "ctl_readable";
- struct ctl_sess *sess = uap;
- struct ctl_sctx *ctx = sess->ctx;
- char *eos, tmp[MAX_NTOP];
- ssize_t n;
-
- REQUIRE(sess != NULL);
- REQUIRE(fd >= 0);
- REQUIRE(evmask == EV_READ);
- REQUIRE(sess->state == reading || sess->state == reading_data);
- evTouchIdleTimer(lev, sess->rdtiID);
- if (!allocated_p(sess->inbuf) &&
- ctl_bufget(&sess->inbuf, ctx->logger) < 0) {
- (*ctx->logger)(ctl_error, "%s: %s: cant get an input buffer",
- me, address_expr);
- ctl_close(sess);
- return;
- }
- n = read(sess->sock, sess->inbuf.text + sess->inbuf.used,
- MAX_LINELEN - sess->inbuf.used);
- if (n <= 0) {
- (*ctx->logger)(ctl_debug, "%s: %s: read: %s",
- me, address_expr,
- (n == 0) ? "Unexpected EOF" : strerror(errno));
- ctl_close(sess);
- return;
- }
- sess->inbuf.used += n;
- eos = memchr(sess->inbuf.text, '\n', sess->inbuf.used);
- if (eos != NULL && eos != sess->inbuf.text && eos[-1] == '\r') {
- eos[-1] = '\0';
- if ((sess->respflags & CTL_DATA) != 0) {
- INSIST(sess->verb != NULL);
- (*sess->verb->func)(sess->ctx, sess, sess->verb,
- sess->inbuf.text,
- CTL_DATA, sess->respctx,
- sess->ctx->uctx);
- } else {
- ctl_stop_read(sess);
- ctl_docommand(sess);
- }
- sess->inbuf.used -= ((eos - sess->inbuf.text) + 1);
- if (sess->inbuf.used == 0)
- ctl_bufput(&sess->inbuf);
- else
- memmove(sess->inbuf.text, eos + 1, sess->inbuf.used);
- return;
- }
- if (sess->inbuf.used == MAX_LINELEN) {
- (*ctx->logger)(ctl_error, "%s: %s: line too long, closing",
- me, address_expr);
- ctl_close(sess);
- }
-}
-
-static void
-ctl_wrtimeout(evContext lev, void *uap,
- struct timespec due,
- struct timespec itv)
-{
- static const char me[] = "ctl_wrtimeout";
- struct ctl_sess *sess = uap;
- struct ctl_sctx *ctx = sess->ctx;
- char tmp[MAX_NTOP];
-
- REQUIRE(sess->state == writing);
- sess->wrtiID.opaque = NULL;
- (*ctx->logger)(ctl_warning, "%s: %s: write timeout, closing",
- me, address_expr);
- if (sess->wrID.opaque != NULL) {
- (void) evCancelRW(ctx->ev, sess->wrID);
- sess->wrID.opaque = NULL;
- }
- ctl_signal_done(ctx, sess);
- ctl_new_state(sess, processing, me);
- ctl_close(sess);
-}
-
-static void
-ctl_rdtimeout(evContext lev, void *uap,
- struct timespec due,
- struct timespec itv)
-{
- static const char me[] = "ctl_rdtimeout";
- struct ctl_sess *sess = uap;
- struct ctl_sctx *ctx = sess->ctx;
- char tmp[MAX_NTOP];
-
- REQUIRE(sess->state == reading);
- sess->rdtiID.opaque = NULL;
- (*ctx->logger)(ctl_warning, "%s: %s: timeout, closing",
- me, address_expr);
- if (sess->state == reading || sess->state == reading_data)
- ctl_stop_read(sess);
- ctl_signal_done(ctx, sess);
- ctl_new_state(sess, processing, me);
- ctl_response(sess, ctx->timeoutcode, "Timeout.", CTL_EXIT, NULL,
- NULL, NULL, NULL, 0);
-}
-
-static void
-ctl_docommand(struct ctl_sess *sess) {
- static const char me[] = "ctl_docommand";
- char *name, *rest, tmp[MAX_NTOP];
- struct ctl_sctx *ctx = sess->ctx;
- const struct ctl_verb *verb;
-
- REQUIRE(allocated_p(sess->inbuf));
- (*ctx->logger)(ctl_debug, "%s: %s: \"%s\" [%u]",
- me, address_expr,
- sess->inbuf.text, (u_int)sess->inbuf.used);
- ctl_new_state(sess, processing, me);
- name = sess->inbuf.text + strspn(sess->inbuf.text, space);
- rest = name + strcspn(name, space);
- if (*rest != '\0') {
- *rest++ = '\0';
- rest += strspn(rest, space);
- }
- for (verb = ctx->verbs;
- verb != NULL && verb->name != NULL && verb->func != NULL;
- verb++)
- if (verb->name[0] != '\0' && strcasecmp(name, verb->name) == 0)
- break;
- if (verb != NULL && verb->name != NULL && verb->func != NULL) {
- sess->verb = verb;
- (*verb->func)(ctx, sess, verb, rest, 0, NULL, ctx->uctx);
- } else {
- char buf[1100];
-
- if (sizeof "Unrecognized command \"\" (args \"\")" +
- strlen(name) + strlen(rest) > sizeof buf)
- strcpy(buf, "Unrecognized command (buf ovf)");
- else
- sprintf(buf,
- "Unrecognized command \"%s\" (args \"%s\")",
- name, rest);
- ctl_response(sess, ctx->unkncode, buf, 0, NULL, NULL, NULL,
- NULL, 0);
- }
-}
-
-static void
-ctl_writedone(evContext lev, void *uap, int fd, int bytes) {
- static const char me[] = "ctl_writedone";
- struct ctl_sess *sess = uap;
- struct ctl_sctx *ctx = sess->ctx;
- char tmp[MAX_NTOP];
- int save_errno = errno;
-
- REQUIRE(sess->state == writing);
- REQUIRE(fd == sess->sock);
- REQUIRE(sess->wrtiID.opaque != NULL);
- sess->wrID.opaque = NULL;
- (void) evClearIdleTimer(ctx->ev, sess->wrtiID);
- sess->wrtiID.opaque = NULL;
- if (bytes < 0) {
- (*ctx->logger)(ctl_error, "%s: %s: %s",
- me, address_expr, strerror(save_errno));
- ctl_close(sess);
- return;
- }
-
- INSIST(allocated_p(sess->outbuf));
- ctl_bufput(&sess->outbuf);
- if ((sess->respflags & CTL_EXIT) != 0) {
- ctl_signal_done(ctx, sess);
- ctl_close(sess);
- return;
- } else if ((sess->respflags & CTL_MORE) != 0) {
- INSIST(sess->verb != NULL);
- (*sess->verb->func)(sess->ctx, sess, sess->verb, "",
- CTL_MORE, sess->respctx, sess->ctx->uctx);
- } else {
- ctl_signal_done(ctx, sess);
- ctl_start_read(sess);
- }
-}
-
-static void
-ctl_morehelp(struct ctl_sctx *ctx, struct ctl_sess *sess,
- const struct ctl_verb *verb, const char *text,
- u_int respflags, void *respctx, void *uctx)
-{
- struct ctl_verb *this = respctx, *next = this + 1;
-
- REQUIRE(!lastverb_p(this));
- REQUIRE((respflags & CTL_MORE) != 0);
- if (lastverb_p(next))
- respflags &= ~CTL_MORE;
- ctl_response(sess, sess->helpcode, this->help, respflags, next,
- NULL, NULL, NULL, 0);
-}
-
-static void
-ctl_signal_done(struct ctl_sctx *ctx, struct ctl_sess *sess) {
- if (sess->donefunc != NULL) {
- (*sess->donefunc)(ctx, sess, sess->uap);
- sess->donefunc = NULL;
- }
-}