summaryrefslogtreecommitdiff
path: root/contrib/bind9/lib/bind/isc/ctl_clnt.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bind9/lib/bind/isc/ctl_clnt.c')
-rw-r--r--contrib/bind9/lib/bind/isc/ctl_clnt.c602
1 files changed, 0 insertions, 602 deletions
diff --git a/contrib/bind9/lib/bind/isc/ctl_clnt.c b/contrib/bind9/lib/bind/isc/ctl_clnt.c
deleted file mode 100644
index e1fa7e798072..000000000000
--- a/contrib/bind9/lib/bind/isc/ctl_clnt.c
+++ /dev/null
@@ -1,602 +0,0 @@
-#if !defined(lint) && !defined(SABER)
-static const char rcsid[] = "$Id: ctl_clnt.c,v 1.4.2.1.4.3 2004/03/17 01:13:35 marka Exp $";
-#endif /* not lint */
-
-/*
- * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
- * 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 ISC DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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 <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 <isc/assertions.h>
-#include <isc/ctl.h>
-#include <isc/eventlib.h>
-#include <isc/list.h>
-#include <isc/memcluster.h>
-
-#include "ctl_p.h"
-
-#include "port_after.h"
-
-/* Constants. */
-
-
-/* Macros. */
-
-#define donefunc_p(ctx) ((ctx).donefunc != NULL)
-#define arpacode_p(line) (isdigit((unsigned char)(line[0])) && \
- isdigit((unsigned char)(line[1])) && \
- isdigit((unsigned char)(line[2])))
-#define arpacont_p(line) (line[3] == '-')
-#define arpadone_p(line) (line[3] == ' ' || line[3] == '\t' || \
- line[3] == '\r' || line[3] == '\0')
-
-/* Types. */
-
-enum state {
- initializing = 0, connecting, connected, destroyed
-};
-
-struct ctl_tran {
- LINK(struct ctl_tran) link;
- LINK(struct ctl_tran) wlink;
- struct ctl_cctx * ctx;
- struct ctl_buf outbuf;
- ctl_clntdone donefunc;
- void * uap;
-};
-
-struct ctl_cctx {
- enum state state;
- evContext ev;
- int sock;
- ctl_logfunc logger;
- ctl_clntdone donefunc;
- void * uap;
- evConnID coID;
- evTimerID tiID;
- evFileID rdID;
- evStreamID wrID;
- struct ctl_buf inbuf;
- struct timespec timeout;
- LIST(struct ctl_tran) tran;
- LIST(struct ctl_tran) wtran;
-};
-
-/* Forward. */
-
-static struct ctl_tran *new_tran(struct ctl_cctx *, ctl_clntdone, void *, int);
-static void start_write(struct ctl_cctx *);
-static void destroy(struct ctl_cctx *, int);
-static void error(struct ctl_cctx *);
-static void new_state(struct ctl_cctx *, enum state);
-static void conn_done(evContext, void *, int,
- const void *, int,
- const void *, int);
-static void write_done(evContext, void *, int, int);
-static void start_read(struct ctl_cctx *);
-static void stop_read(struct ctl_cctx *);
-static void readable(evContext, void *, int, int);
-static void start_timer(struct ctl_cctx *);
-static void stop_timer(struct ctl_cctx *);
-static void touch_timer(struct ctl_cctx *);
-static void timer(evContext, void *,
- struct timespec, struct timespec);
-
-/* Private data. */
-
-static const char * const state_names[] = {
- "initializing", "connecting", "connected", "destroyed"
-};
-
-/* Public. */
-
-/*
- * void
- * ctl_client()
- * create, condition, and connect to a listener on the control port.
- */
-struct ctl_cctx *
-ctl_client(evContext lev, const struct sockaddr *cap, size_t cap_len,
- const struct sockaddr *sap, size_t sap_len,
- ctl_clntdone donefunc, void *uap,
- u_int timeout, ctl_logfunc logger)
-{
- static const char me[] = "ctl_client";
- static const int on = 1;
- struct ctl_cctx *ctx;
- struct sockaddr *captmp;
-
- if (logger == NULL)
- logger = ctl_logger;
- ctx = memget(sizeof *ctx);
- if (ctx == NULL) {
- (*logger)(ctl_error, "%s: getmem: %s", me, strerror(errno));
- goto fatal;
- }
- ctx->state = initializing;
- ctx->ev = lev;
- ctx->logger = logger;
- ctx->timeout = evConsTime(timeout, 0);
- ctx->donefunc = donefunc;
- ctx->uap = uap;
- ctx->coID.opaque = NULL;
- ctx->tiID.opaque = NULL;
- ctx->rdID.opaque = NULL;
- ctx->wrID.opaque = NULL;
- buffer_init(ctx->inbuf);
- INIT_LIST(ctx->tran);
- INIT_LIST(ctx->wtran);
- 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) {
- (*ctx->logger)(ctl_error, "%s: socket: %s",
- me, strerror(errno));
- goto fatal;
- }
- if (cap != NULL) {
- if (setsockopt(ctx->sock, SOL_SOCKET, SO_REUSEADDR,
- (const char *)&on, sizeof on) != 0) {
- (*ctx->logger)(ctl_warning,
- "%s: setsockopt(REUSEADDR): %s",
- me, strerror(errno));
- }
- DE_CONST(cap, captmp);
- if (bind(ctx->sock, captmp, cap_len) < 0) {
- (*ctx->logger)(ctl_error, "%s: bind: %s", me,
- strerror(errno));
- goto fatal;
- }
- }
- if (evConnect(lev, ctx->sock, (const struct sockaddr *)sap, sap_len,
- conn_done, ctx, &ctx->coID) < 0) {
- (*ctx->logger)(ctl_error, "%s: evConnect(fd %d): %s",
- me, ctx->sock, strerror(errno));
- fatal:
- if (ctx != NULL) {
- if (ctx->sock >= 0)
- close(ctx->sock);
- memput(ctx, sizeof *ctx);
- }
- return (NULL);
- }
- new_state(ctx, connecting);
- return (ctx);
-}
-
-/*
- * void
- * ctl_endclient(ctx)
- * close a client and release all of its resources.
- */
-void
-ctl_endclient(struct ctl_cctx *ctx) {
- if (ctx->state != destroyed)
- destroy(ctx, 0);
- memput(ctx, sizeof *ctx);
-}
-
-/*
- * int
- * ctl_command(ctx, cmd, len, donefunc, uap)
- * Queue a transaction, which will begin with sending cmd
- * and complete by calling donefunc with the answer.
- */
-int
-ctl_command(struct ctl_cctx *ctx, const char *cmd, size_t len,
- ctl_clntdone donefunc, void *uap)
-{
- struct ctl_tran *tran;
- char *pc;
- unsigned int n;
-
- switch (ctx->state) {
- case destroyed:
- errno = ENOTCONN;
- return (-1);
- case connecting:
- case connected:
- break;
- default:
- abort();
- }
- if (len >= (size_t)MAX_LINELEN) {
- errno = EMSGSIZE;
- return (-1);
- }
- tran = new_tran(ctx, donefunc, uap, 1);
- if (tran == NULL)
- return (-1);
- if (ctl_bufget(&tran->outbuf, ctx->logger) < 0)
- return (-1);
- memcpy(tran->outbuf.text, cmd, len);
- tran->outbuf.used = len;
- for (pc = tran->outbuf.text, n = 0; n < tran->outbuf.used; pc++, n++)
- if (!isascii((unsigned char)*pc) ||
- !isprint((unsigned char)*pc))
- *pc = '\040';
- start_write(ctx);
- return (0);
-}
-
-/* Private. */
-
-static struct ctl_tran *
-new_tran(struct ctl_cctx *ctx, ctl_clntdone donefunc, void *uap, int w) {
- struct ctl_tran *new = memget(sizeof *new);
-
- if (new == NULL)
- return (NULL);
- new->ctx = ctx;
- buffer_init(new->outbuf);
- new->donefunc = donefunc;
- new->uap = uap;
- INIT_LINK(new, link);
- INIT_LINK(new, wlink);
- APPEND(ctx->tran, new, link);
- if (w)
- APPEND(ctx->wtran, new, wlink);
- return (new);
-}
-
-static void
-start_write(struct ctl_cctx *ctx) {
- static const char me[] = "isc/ctl_clnt::start_write";
- struct ctl_tran *tran;
- struct iovec iov[2], *iovp = iov;
- char * tmp;
-
- REQUIRE(ctx->state == connecting || ctx->state == connected);
- /* If there is a write in progress, don't try to write more yet. */
- if (ctx->wrID.opaque != NULL)
- return;
- /* If there are no trans, make sure timer is off, and we're done. */
- if (EMPTY(ctx->wtran)) {
- if (ctx->tiID.opaque != NULL)
- stop_timer(ctx);
- return;
- }
- /* Pull it off the head of the write queue. */
- tran = HEAD(ctx->wtran);
- UNLINK(ctx->wtran, tran, wlink);
- /* Since there are some trans, make sure timer is successfully "on". */
- if (ctx->tiID.opaque != NULL)
- touch_timer(ctx);
- else
- start_timer(ctx);
- if (ctx->state == destroyed)
- return;
- /* Marshall a newline-terminated message and clock it out. */
- *iovp++ = evConsIovec(tran->outbuf.text, tran->outbuf.used);
- DE_CONST("\r\n", tmp);
- *iovp++ = evConsIovec(tmp, 2);
- if (evWrite(ctx->ev, ctx->sock, iov, iovp - iov,
- write_done, tran, &ctx->wrID) < 0) {
- (*ctx->logger)(ctl_error, "%s: evWrite: %s", me,
- strerror(errno));
- error(ctx);
- return;
- }
- if (evTimeRW(ctx->ev, ctx->wrID, ctx->tiID) < 0) {
- (*ctx->logger)(ctl_error, "%s: evTimeRW: %s", me,
- strerror(errno));
- error(ctx);
- return;
- }
-}
-
-static void
-destroy(struct ctl_cctx *ctx, int notify) {
- struct ctl_tran *this, *next;
-
- if (ctx->sock != -1) {
- (void) close(ctx->sock);
- ctx->sock = -1;
- }
- switch (ctx->state) {
- case connecting:
- REQUIRE(ctx->wrID.opaque == NULL);
- REQUIRE(EMPTY(ctx->tran));
- /*
- * This test is nec'y since destroy() can be called from
- * start_read() while the state is still "connecting".
- */
- if (ctx->coID.opaque != NULL) {
- (void)evCancelConn(ctx->ev, ctx->coID);
- ctx->coID.opaque = NULL;
- }
- break;
- case connected:
- REQUIRE(ctx->coID.opaque == NULL);
- if (ctx->wrID.opaque != NULL) {
- (void)evCancelRW(ctx->ev, ctx->wrID);
- ctx->wrID.opaque = NULL;
- }
- if (ctx->rdID.opaque != NULL)
- stop_read(ctx);
- break;
- case destroyed:
- break;
- default:
- abort();
- }
- if (allocated_p(ctx->inbuf))
- ctl_bufput(&ctx->inbuf);
- for (this = HEAD(ctx->tran); this != NULL; this = next) {
- next = NEXT(this, link);
- if (allocated_p(this->outbuf))
- ctl_bufput(&this->outbuf);
- if (notify && this->donefunc != NULL)
- (*this->donefunc)(ctx, this->uap, NULL, 0);
- memput(this, sizeof *this);
- }
- if (ctx->tiID.opaque != NULL)
- stop_timer(ctx);
- new_state(ctx, destroyed);
-}
-
-static void
-error(struct ctl_cctx *ctx) {
- REQUIRE(ctx->state != destroyed);
- destroy(ctx, 1);
-}
-
-static void
-new_state(struct ctl_cctx *ctx, enum state new_state) {
- static const char me[] = "isc/ctl_clnt::new_state";
-
- (*ctx->logger)(ctl_debug, "%s: %s -> %s", me,
- state_names[ctx->state], state_names[new_state]);
- ctx->state = new_state;
-}
-
-static void
-conn_done(evContext ev, void *uap, int fd,
- const void *la, int lalen,
- const void *ra, int ralen)
-{
- static const char me[] = "isc/ctl_clnt::conn_done";
- struct ctl_cctx *ctx = uap;
- struct ctl_tran *tran;
-
- UNUSED(ev);
- UNUSED(la);
- UNUSED(lalen);
- UNUSED(ra);
- UNUSED(ralen);
-
- ctx->coID.opaque = NULL;
- if (fd < 0) {
- (*ctx->logger)(ctl_error, "%s: evConnect: %s", me,
- strerror(errno));
- error(ctx);
- return;
- }
- new_state(ctx, connected);
- tran = new_tran(ctx, ctx->donefunc, ctx->uap, 0);
- if (tran == NULL) {
- (*ctx->logger)(ctl_error, "%s: new_tran failed: %s", me,
- strerror(errno));
- error(ctx);
- return;
- }
- start_read(ctx);
- if (ctx->state == destroyed) {
- (*ctx->logger)(ctl_error, "%s: start_read failed: %s",
- me, strerror(errno));
- error(ctx);
- return;
- }
-}
-
-static void
-write_done(evContext lev, void *uap, int fd, int bytes) {
- struct ctl_tran *tran = (struct ctl_tran *)uap;
- struct ctl_cctx *ctx = tran->ctx;
-
- UNUSED(lev);
- UNUSED(fd);
-
- ctx->wrID.opaque = NULL;
- if (ctx->tiID.opaque != NULL)
- touch_timer(ctx);
- ctl_bufput(&tran->outbuf);
- start_write(ctx);
- if (bytes < 0)
- destroy(ctx, 1);
- else
- start_read(ctx);
-}
-
-static void
-start_read(struct ctl_cctx *ctx) {
- static const char me[] = "isc/ctl_clnt::start_read";
-
- REQUIRE(ctx->state == connecting || ctx->state == connected);
- REQUIRE(ctx->rdID.opaque == NULL);
- if (evSelectFD(ctx->ev, ctx->sock, EV_READ, readable, ctx,
- &ctx->rdID) < 0)
- {
- (*ctx->logger)(ctl_error, "%s: evSelect(fd %d): %s", me,
- ctx->sock, strerror(errno));
- error(ctx);
- return;
- }
-}
-
-static void
-stop_read(struct ctl_cctx *ctx) {
- REQUIRE(ctx->coID.opaque == NULL);
- REQUIRE(ctx->rdID.opaque != NULL);
- (void)evDeselectFD(ctx->ev, ctx->rdID);
- ctx->rdID.opaque = NULL;
-}
-
-static void
-readable(evContext ev, void *uap, int fd, int evmask) {
- static const char me[] = "isc/ctl_clnt::readable";
- struct ctl_cctx *ctx = uap;
- struct ctl_tran *tran;
- ssize_t n;
- char *eos;
-
- UNUSED(ev);
-
- REQUIRE(ctx != NULL);
- REQUIRE(fd >= 0);
- REQUIRE(evmask == EV_READ);
- REQUIRE(ctx->state == connected);
- REQUIRE(!EMPTY(ctx->tran));
- tran = HEAD(ctx->tran);
- if (!allocated_p(ctx->inbuf) &&
- ctl_bufget(&ctx->inbuf, ctx->logger) < 0) {
- (*ctx->logger)(ctl_error, "%s: can't get an input buffer", me);
- error(ctx);
- return;
- }
- n = read(ctx->sock, ctx->inbuf.text + ctx->inbuf.used,
- MAX_LINELEN - ctx->inbuf.used);
- if (n <= 0) {
- (*ctx->logger)(ctl_warning, "%s: read: %s", me,
- (n == 0) ? "Unexpected EOF" : strerror(errno));
- error(ctx);
- return;
- }
- if (ctx->tiID.opaque != NULL)
- touch_timer(ctx);
- ctx->inbuf.used += n;
- (*ctx->logger)(ctl_debug, "%s: read %d, used %d", me,
- n, ctx->inbuf.used);
- again:
- eos = memchr(ctx->inbuf.text, '\n', ctx->inbuf.used);
- if (eos != NULL && eos != ctx->inbuf.text && eos[-1] == '\r') {
- int done = 0;
-
- eos[-1] = '\0';
- if (!arpacode_p(ctx->inbuf.text)) {
- /* XXX Doesn't FTP do this sometimes? Is it legal? */
- (*ctx->logger)(ctl_error, "%s: no arpa code (%s)", me,
- ctx->inbuf.text);
- error(ctx);
- return;
- }
- if (arpadone_p(ctx->inbuf.text))
- done = 1;
- else if (arpacont_p(ctx->inbuf.text))
- done = 0;
- else {
- /* XXX Doesn't FTP do this sometimes? Is it legal? */
- (*ctx->logger)(ctl_error, "%s: no arpa flag (%s)", me,
- ctx->inbuf.text);
- error(ctx);
- return;
- }
- (*tran->donefunc)(ctx, tran->uap, ctx->inbuf.text,
- (done ? 0 : CTL_MORE));
- ctx->inbuf.used -= ((eos - ctx->inbuf.text) + 1);
- if (ctx->inbuf.used == 0U)
- ctl_bufput(&ctx->inbuf);
- else
- memmove(ctx->inbuf.text, eos + 1, ctx->inbuf.used);
- if (done) {
- UNLINK(ctx->tran, tran, link);
- memput(tran, sizeof *tran);
- stop_read(ctx);
- start_write(ctx);
- return;
- }
- if (allocated_p(ctx->inbuf))
- goto again;
- return;
- }
- if (ctx->inbuf.used == (size_t)MAX_LINELEN) {
- (*ctx->logger)(ctl_error, "%s: line too long (%-10s...)", me,
- ctx->inbuf.text);
- error(ctx);
- }
-}
-
-/* Timer related stuff. */
-
-static void
-start_timer(struct ctl_cctx *ctx) {
- static const char me[] = "isc/ctl_clnt::start_timer";
-
- REQUIRE(ctx->tiID.opaque == NULL);
- if (evSetIdleTimer(ctx->ev, timer, ctx, ctx->timeout, &ctx->tiID) < 0){
- (*ctx->logger)(ctl_error, "%s: evSetIdleTimer: %s", me,
- strerror(errno));
- error(ctx);
- return;
- }
-}
-
-static void
-stop_timer(struct ctl_cctx *ctx) {
- static const char me[] = "isc/ctl_clnt::stop_timer";
-
- REQUIRE(ctx->tiID.opaque != NULL);
- if (evClearIdleTimer(ctx->ev, ctx->tiID) < 0) {
- (*ctx->logger)(ctl_error, "%s: evClearIdleTimer: %s", me,
- strerror(errno));
- error(ctx);
- return;
- }
- ctx->tiID.opaque = NULL;
-}
-
-static void
-touch_timer(struct ctl_cctx *ctx) {
- REQUIRE(ctx->tiID.opaque != NULL);
-
- evTouchIdleTimer(ctx->ev, ctx->tiID);
-}
-
-static void
-timer(evContext ev, void *uap, struct timespec due, struct timespec itv) {
- static const char me[] = "isc/ctl_clnt::timer";
- struct ctl_cctx *ctx = uap;
-
- UNUSED(ev);
- UNUSED(due);
- UNUSED(itv);
-
- ctx->tiID.opaque = NULL;
- (*ctx->logger)(ctl_error, "%s: timeout after %u seconds while %s", me,
- ctx->timeout.tv_sec, state_names[ctx->state]);
- error(ctx);
-}