summaryrefslogtreecommitdiff
path: root/contrib/bind/lib/isc
diff options
context:
space:
mode:
authorPeter Wemm <peter@FreeBSD.org>1999-11-30 02:43:11 +0000
committerPeter Wemm <peter@FreeBSD.org>1999-11-30 02:43:11 +0000
commit44856387160435985b3d0972db19a60e74ca56cb (patch)
tree229e9e7b96508abdb1746797aa00dea2ba694063 /contrib/bind/lib/isc
parentfe6d3fe571a4dd5637c70923fde9268eccde1731 (diff)
parent6b6ac9438f352903fe405daefaf6a3c9a2b63093 (diff)
Notes
Diffstat (limited to 'contrib/bind/lib/isc')
-rw-r--r--contrib/bind/lib/isc/Makefile28
-rw-r--r--contrib/bind/lib/isc/assertions.c4
-rw-r--r--contrib/bind/lib/isc/assertions.mdoc4
-rw-r--r--contrib/bind/lib/isc/base64.c4
-rw-r--r--contrib/bind/lib/isc/bitncmp.c4
-rw-r--r--contrib/bind/lib/isc/bitncmp.mdoc4
-rw-r--r--contrib/bind/lib/isc/ctl_clnt.c581
-rw-r--r--contrib/bind/lib/isc/ctl_p.c156
-rw-r--r--contrib/bind/lib/isc/ctl_p.h22
-rw-r--r--contrib/bind/lib/isc/ctl_srvr.c744
-rw-r--r--contrib/bind/lib/isc/ev_connects.c41
-rw-r--r--contrib/bind/lib/isc/ev_files.c15
-rw-r--r--contrib/bind/lib/isc/ev_streams.c9
-rw-r--r--contrib/bind/lib/isc/ev_timers.c6
-rw-r--r--contrib/bind/lib/isc/ev_waits.c9
-rw-r--r--contrib/bind/lib/isc/eventlib.c35
-rw-r--r--contrib/bind/lib/isc/eventlib.mdoc31
-rw-r--r--contrib/bind/lib/isc/eventlib_p.h6
-rw-r--r--contrib/bind/lib/isc/heap.c4
-rw-r--r--contrib/bind/lib/isc/heap.mdoc4
-rw-r--r--contrib/bind/lib/isc/logging.c28
-rw-r--r--contrib/bind/lib/isc/logging.mdoc4
-rw-r--r--contrib/bind/lib/isc/logging_p.h2
-rw-r--r--contrib/bind/lib/isc/memcluster.c213
-rw-r--r--contrib/bind/lib/isc/memcluster.mdoc4
-rw-r--r--contrib/bind/lib/isc/tree.c6
-rw-r--r--contrib/bind/lib/isc/tree.mdoc4
27 files changed, 1880 insertions, 92 deletions
diff --git a/contrib/bind/lib/isc/Makefile b/contrib/bind/lib/isc/Makefile
index cdcac69f61b3..87e20f2a50c2 100644
--- a/contrib/bind/lib/isc/Makefile
+++ b/contrib/bind/lib/isc/Makefile
@@ -1,4 +1,4 @@
-# Copyright (c) 1996 by Internet Software Consortium
+# Copyright (c) 1996,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
@@ -13,7 +13,7 @@
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
# SOFTWARE.
-# $Id: Makefile,v 8.15 1997/12/03 22:36:08 halley Exp $
+# $Id: Makefile,v 8.22 1999/02/22 02:47:58 vixie Exp $
# these are only appropriate for BSD 4.4 or derivatives, and are used in
# development. normal builds will be done in the top level directory and
@@ -31,37 +31,55 @@ TOP= ../..
INCL = ${TOP}/include
PORTINCL = ${TOP}/port/${SYSTYPE}/include
LIBBIND = ${TOP}/lib/libbind.${A}
+LIBBINDR = ../${TOP}/lib/libbind_r.${A}
CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL}
+# -Wimplicit
LD_LIBFLAGS= -x -r
-AR= ar cruv
+AR= ar cru
RANLIB= ranlib
INSTALL= install
+INSTALL_EXEC=
+INSTALL_LIB=-o bin -g bin
+THREADED= threaded
SRCS= tree.c base64.c bitncmp.c assertions.c \
memcluster.c logging.c heap.c \
+ ctl_p.c ctl_srvr.c ctl_clnt.c \
eventlib.c ev_connects.c ev_files.c \
ev_timers.c ev_streams.c ev_waits.c
OBJS= tree.${O} base64.${O} bitncmp.${O} assertions.${O} \
memcluster.${O} logging.${O} heap.${O} \
+ ctl_p.${O} ctl_srvr.${O} ctl_clnt.${O} \
eventlib.${O} ev_connects.${O} ev_files.${O} \
ev_timers.${O} ev_streams.${O} ev_waits.${O}
all: ${LIBBIND}
${LIBBIND}: ${OBJS}
+ ( cd ${THREADED} ; \
+ ${AR} ${LIBBINDR} ${ARPREF} ${OBJS} ${ARSUFF} ; \
+ ${RANLIB} ${LIBBINDR} )
${AR} ${LIBBIND} ${ARPREF} ${OBJS} ${ARSUFF}
${RANLIB} ${LIBBIND}
.c.${O}:
- ${CC} ${CPPFLAGS} ${CFLAGS} -c $*.c
- -${LDS} ${LD} ${LD_LIBFLAGS} $*.${O} && ${LDS} mv a.out $*.${O}
+ if test ! -d ${THREADED} ; then mkdir ${THREADED} ; fi
+ ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} ${REENTRANT} -c $*.c \
+ -o ${THREADED}/$*.${O}
+ -${LDS} ${LD} ${LD_LIBFLAGS} ${THREADED}/$*.${O} -o a.out && \
+ ${LDS} mv a.out ${THREADED}/$*.${O}
+ ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} -c $*.c
+ -${LDS} ${LD} ${LD_LIBFLAGS} $*.${O} -o a.out && \
+ ${LDS} mv a.out $*.${O}
distclean: clean
clean: FRC
rm -f .depend a.out core ${LIB} tags
rm -f *.${O} *.BAK *.CKP *~
+ rm -f ${THREADED}/*.${O}
+ -rmdir ${THREADED}
depend: FRC
mkdep -I${INCL} -I${PORTINCL} ${CPPFLAGS} ${SRCS}
diff --git a/contrib/bind/lib/isc/assertions.c b/contrib/bind/lib/isc/assertions.c
index 949d4d2e60d1..b53cc0ab69c6 100644
--- a/contrib/bind/lib/isc/assertions.c
+++ b/contrib/bind/lib/isc/assertions.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997 by Internet Software Consortium.
+ * Copyright (c) 1997,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
@@ -16,7 +16,7 @@
*/
#if !defined(LINT) && !defined(CODECENTER)
-static const char rcsid[] = "$Id: assertions.c,v 8.2 1997/12/08 21:29:05 halley Exp $";
+static const char rcsid[] = "$Id: assertions.c,v 8.3 1999/01/08 19:25:14 vixie Exp $";
#endif
#include "port_before.h"
diff --git a/contrib/bind/lib/isc/assertions.mdoc b/contrib/bind/lib/isc/assertions.mdoc
index e82d9f9fce56..3d8d103e727c 100644
--- a/contrib/bind/lib/isc/assertions.mdoc
+++ b/contrib/bind/lib/isc/assertions.mdoc
@@ -1,6 +1,6 @@
-.\" $Id: assertions.mdoc,v 8.1 1997/12/03 22:33:30 halley Exp $
+.\" $Id: assertions.mdoc,v 8.2 1999/01/08 19:25:15 vixie Exp $
.\"
-.\"Copyright (c) 1997 by Internet Software Consortium.
+.\"Copyright (c) 1997,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
diff --git a/contrib/bind/lib/isc/base64.c b/contrib/bind/lib/isc/base64.c
index 58e700ea13c2..c1eebe672d42 100644
--- a/contrib/bind/lib/isc/base64.c
+++ b/contrib/bind/lib/isc/base64.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 1998 by Internet Software Consortium.
+ * Copyright (c) 1996-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
@@ -41,7 +41,7 @@
*/
#if !defined(LINT) && !defined(CODECENTER)
-static char rcsid[] = "$Id: base64.c,v 8.5 1998/03/27 00:17:46 halley Exp $";
+static const char rcsid[] = "$Id: base64.c,v 8.7 1999/10/13 16:39:33 vixie Exp $";
#endif /* not lint */
#include "port_before.h"
diff --git a/contrib/bind/lib/isc/bitncmp.c b/contrib/bind/lib/isc/bitncmp.c
index 473f4f77b9fb..8dadca067c92 100644
--- a/contrib/bind/lib/isc/bitncmp.c
+++ b/contrib/bind/lib/isc/bitncmp.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996 by Internet Software Consortium.
+ * Copyright (c) 1996,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
@@ -16,7 +16,7 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static const char rcsid[] = "$Id: bitncmp.c,v 1.5 1996/11/18 09:09:48 vixie Exp $";
+static const char rcsid[] = "$Id: bitncmp.c,v 1.6 1999/01/08 19:25:20 vixie Exp $";
#endif
#include "port_before.h"
diff --git a/contrib/bind/lib/isc/bitncmp.mdoc b/contrib/bind/lib/isc/bitncmp.mdoc
index 99c6c25be40f..4fa12e8c95f4 100644
--- a/contrib/bind/lib/isc/bitncmp.mdoc
+++ b/contrib/bind/lib/isc/bitncmp.mdoc
@@ -1,6 +1,6 @@
-.\" $Id: bitncmp.mdoc,v 8.1 1997/01/30 20:27:23 vixie Exp $
+.\" $Id: bitncmp.mdoc,v 8.2 1999/01/08 19:25:21 vixie Exp $
.\"
-.\"Copyright (c) 1996 by Internet Software Consortium.
+.\"Copyright (c) 1996,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
diff --git a/contrib/bind/lib/isc/ctl_clnt.c b/contrib/bind/lib/isc/ctl_clnt.c
new file mode 100644
index 000000000000..66f32f8a2521
--- /dev/null
+++ b/contrib/bind/lib/isc/ctl_clnt.c
@@ -0,0 +1,581 @@
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: ctl_clnt.c,v 8.14 1999/10/13 16:39: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 <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(line[0]) && isdigit(line[1]) && \
+ isdigit(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;
+
+ 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,
+ (char *)&on, sizeof on) != 0) {
+ (*ctx->logger)(ctl_warning,
+ "%s: setsockopt(REUSEADDR): %s",
+ me, strerror(errno));
+ }
+ if (bind(ctx->sock, cap, cap_len) < 0) {
+ (*ctx->logger)(ctl_error, "%s: bind: %s", me,
+ strerror(errno));
+ goto fatal;
+ }
+ }
+ if (evConnect(lev, ctx->sock, (struct sockaddr *)sap, sap_len,
+ conn_done, ctx, &ctx->coID) < 0) {
+ (*ctx->logger)(ctl_error, "%s: evConnect(fd %d): %s",
+ me, (void *)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;
+ int n;
+
+ switch (ctx->state) {
+ case destroyed:
+ errno = ENOTCONN;
+ return (-1);
+ case connecting:
+ case connected:
+ break;
+ default:
+ abort();
+ }
+ if (len >= 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(*pc) || !isprint(*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;
+ APPEND(ctx->tran, new, link);
+ if (w)
+ APPEND(ctx->wtran, new, wlink);
+ else
+ INIT_LINK(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;
+
+ 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);
+ *iovp++ = evConsIovec("\r\n", 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;
+
+ 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;
+
+ 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;
+
+ 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 == 0)
+ 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 == 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;
+
+ 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);
+}
diff --git a/contrib/bind/lib/isc/ctl_p.c b/contrib/bind/lib/isc/ctl_p.c
new file mode 100644
index 000000000000..d70a05fe7ea0
--- /dev/null
+++ b/contrib/bind/lib/isc/ctl_p.c
@@ -0,0 +1,156 @@
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: ctl_p.c,v 8.6 1999/10/13 16:39:34 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <isc/assertions.h>
+#include <isc/eventlib.h>
+#include <isc/logging.h>
+#include <isc/memcluster.h>
+#include <isc/ctl.h>
+
+#include "ctl_p.h"
+
+#include "port_after.h"
+
+/* Constants. */
+
+const char * const ctl_sevnames[] = {
+ "debug", "warning", "error"
+};
+
+/* Public. */
+
+/*
+ * ctl_logger()
+ * if ctl_startup()'s caller didn't specify a logger, this one
+ * is used. this pollutes stderr with all kinds of trash so it will
+ * probably never be used in real applications.
+ */
+void
+ctl_logger(enum ctl_severity severity, const char *format, ...) {
+ va_list ap;
+ static const char me[] = "ctl_logger";
+
+ fprintf(stderr, "%s(%s): ", me, ctl_sevnames[severity]);
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+ fputc('\n', stderr);
+}
+
+int
+ctl_bufget(struct ctl_buf *buf, ctl_logfunc logger) {
+ static const char me[] = "ctl_bufget";
+
+ REQUIRE(!allocated_p(*buf) && buf->used == 0);
+ buf->text = memget(MAX_LINELEN);
+ if (!allocated_p(*buf)) {
+ (*logger)(ctl_error, "%s: getmem: %s", me, strerror(errno));
+ return (-1);
+ }
+ buf->used = 0;
+ return (0);
+}
+
+void
+ctl_bufput(struct ctl_buf *buf) {
+
+ REQUIRE(allocated_p(*buf));
+ memput(buf->text, MAX_LINELEN);
+ buf->text = NULL;
+ buf->used = 0;
+}
+
+const char *
+ctl_sa_ntop(const struct sockaddr *sa,
+ char *buf, size_t size,
+ ctl_logfunc logger)
+{
+ static const char me[] = "ctl_sa_ntop";
+ static const char punt[] = "[0].-1";
+ char tmp[sizeof "255.255.255.255"];
+
+ switch (sa->sa_family) {
+ case AF_INET: {
+ const struct sockaddr_in *in = (struct sockaddr_in *) sa;
+
+ if (inet_ntop(in->sin_family, &in->sin_addr, tmp, sizeof tmp)
+ == NULL) {
+ (*logger)(ctl_error, "%s: inet_ntop(%u %04x %08x): %s",
+ me, in->sin_family,
+ in->sin_port, in->sin_addr.s_addr,
+ strerror(errno));
+ return (punt);
+ }
+ if (strlen(tmp) + sizeof "[].65535" > size) {
+ (*logger)(ctl_error, "%s: buffer overflow", me);
+ return (punt);
+ }
+ (void) sprintf(buf, "[%s].%u", tmp, ntohs(in->sin_port));
+ return (buf);
+ }
+ case AF_UNIX: {
+ const struct sockaddr_un *un = (struct sockaddr_un *) sa;
+ int x = sizeof un->sun_path;
+
+ if (x > size)
+ x = size;
+ strncpy(buf, un->sun_path, x - 1);
+ buf[x - 1] = '\0';
+ return (buf);
+ }
+ default:
+ return (punt);
+ }
+}
+
+void
+ctl_sa_copy(const struct sockaddr *src, struct sockaddr *dst) {
+ switch (src->sa_family) {
+ case AF_INET:
+ *((struct sockaddr_in *)dst) = *((struct sockaddr_in *)src);
+ break;
+ case AF_UNIX:
+ *((struct sockaddr_un *)dst) = *((struct sockaddr_un *)src);
+ break;
+ default:
+ *dst = *src;
+ break;
+ }
+}
diff --git a/contrib/bind/lib/isc/ctl_p.h b/contrib/bind/lib/isc/ctl_p.h
new file mode 100644
index 000000000000..1ebb2542367a
--- /dev/null
+++ b/contrib/bind/lib/isc/ctl_p.h
@@ -0,0 +1,22 @@
+struct ctl_buf {
+ char * text;
+ size_t used;
+};
+
+#define MAX_LINELEN 990 /* Like SMTP. */
+#define MAX_NTOP (sizeof "[255.255.255.255].65535")
+
+#define allocated_p(Buf) ((Buf).text != NULL)
+#define buffer_init(Buf) ((Buf).text = 0, (Buf.used) = 0)
+
+#define ctl_bufget __ctl_bufget
+#define ctl_bufput __ctl_bufput
+#define ctl_sa_ntop __ctl_sa_ntop
+#define ctl_sa_copy __ctl_sa_copy
+
+int ctl_bufget(struct ctl_buf *, ctl_logfunc);
+void ctl_bufput(struct ctl_buf *);
+const char * ctl_sa_ntop(const struct sockaddr *, char *, size_t,
+ ctl_logfunc);
+void ctl_sa_copy(const struct sockaddr *,
+ struct sockaddr *);
diff --git a/contrib/bind/lib/isc/ctl_srvr.c b/contrib/bind/lib/isc/ctl_srvr.c
new file mode 100644
index 000000000000..0bdc8c834410
--- /dev/null
+++ b/contrib/bind/lib/isc/ctl_srvr.c
@@ -0,0 +1,744 @@
+#if !defined(lint) && !defined(SABER)
+static const char rcsid[] = "$Id: ctl_srvr.c,v 8.21 1999/10/17 08:41:57 cyarnell 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;
+ struct sockaddr_un un;
+};
+
+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) {
+ save_errno = errno;
+ (*ctx->logger)(ctl_error, "%s: bind: %s", me, strerror(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, 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;
+ }
+}
diff --git a/contrib/bind/lib/isc/ev_connects.c b/contrib/bind/lib/isc/ev_connects.c
index 1cf729153b11..237bcb1e01d3 100644
--- a/contrib/bind/lib/isc/ev_connects.c
+++ b/contrib/bind/lib/isc/ev_connects.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 1996, 1997, 1998 by Internet Software Consortium
+ * Copyright (c) 1995-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
@@ -20,7 +20,7 @@
*/
#if !defined(LINT) && !defined(CODECENTER)
-static const char rcsid[] = "$Id: ev_connects.c,v 8.19 1998/03/20 23:26:22 halley Exp $";
+static const char rcsid[] = "$Id: ev_connects.c,v 8.25 1999/10/07 20:44:04 vixie Exp $";
#endif
/* Import. */
@@ -39,6 +39,18 @@ static const char rcsid[] = "$Id: ev_connects.c,v 8.19 1998/03/20 23:26:22 halle
#include "port_after.h"
+/* Macros. */
+
+#define GETXXXNAME(f, s, sa, len) ( \
+ (f((s), (&sa), (&len)) >= 0) ? 0 : \
+ (errno != EAFNOSUPPORT && errno != EOPNOTSUPP) ? -1 : ( \
+ memset(&(sa), 0, sizeof (sa)), \
+ (len) = sizeof (sa), \
+ (sa).sa_family = AF_UNIX, \
+ 0 \
+ ) \
+ )
+
/* Forward. */
static void listener(evContext ctx, void *uap, int fd, int evmask);
@@ -64,8 +76,8 @@ evListen(evContext opaqueCtx, int fd, int maxconn,
* are not met, then we might restore the old nonblocking status
* incorrectly.
*/
- if ((mode & O_NONBLOCK) == 0) {
- OK(fcntl(fd, F_SETFL, mode | O_NONBLOCK));
+ if ((mode & PORT_NONBLOCK) == 0) {
+ OK(fcntl(fd, F_SETFL, mode | PORT_NONBLOCK));
new->flags |= EV_CONN_BLOCK;
}
OK(listen(fd, maxconn));
@@ -149,7 +161,7 @@ evCancelConn(evContext opaqueCtx, evConnID id) {
if (errno != EBADF)
return (-1);
} else
- OK(fcntl(this->fd, F_SETFL, mode | O_NONBLOCK));
+ OK(fcntl(this->fd, F_SETFL, mode | PORT_NONBLOCK));
}
/* Unlink from ctx->conns. */
@@ -224,9 +236,14 @@ evTryAccept(evContext opaqueCtx, evConnID id, int *sys_errno) {
new->conn = conn;
new->ralen = sizeof new->ra;
new->fd = accept(conn->fd, &new->ra, &new->ralen);
+ if (new->fd > ctx->highestFD) {
+ close(new->fd);
+ new->fd = -1;
+ new->ioErrno = ENOTSOCK;
+ }
if (new->fd >= 0) {
new->lalen = sizeof new->la;
- if (getsockname(new->fd, &new->la, &new->lalen) < 0) {
+ if (GETXXXNAME(getsockname, new->fd, new->la, new->lalen) < 0) {
new->ioErrno = errno;
(void) close(new->fd);
new->fd = -1;
@@ -256,9 +273,14 @@ listener(evContext opaqueCtx, void *uap, int fd, int evmask) {
REQUIRE((evmask & EV_READ) != 0);
ralen = sizeof ra;
new = accept(fd, &ra, &ralen);
+ if (new > ctx->highestFD) {
+ close(new);
+ new = -1;
+ errno = ENOTSOCK;
+ }
if (new >= 0) {
lalen = sizeof la;
- if (getsockname(new, &la, &lalen) < 0) {
+ if (GETXXXNAME(getsockname, new, la, lalen) < 0) {
int save = errno;
(void) close(new);
@@ -272,7 +294,6 @@ listener(evContext opaqueCtx, void *uap, int fd, int evmask) {
static void
connector(evContext opaqueCtx, void *uap, int fd, int evmask) {
- evContext_p *ctx = opaqueCtx.opaque;
evConn *conn = uap;
struct sockaddr la, ra;
int lalen, ralen;
@@ -304,8 +325,8 @@ connector(evContext opaqueCtx, void *uap, int fd, int evmask) {
#else
read(fd, buf, 0) < 0 ||
#endif
- getsockname(fd, &la, &lalen) < 0 ||
- getpeername(fd, &ra, &ralen) < 0) {
+ GETXXXNAME(getsockname, fd, la, lalen) < 0 ||
+ GETXXXNAME(getpeername, fd, ra, ralen) < 0) {
int save = errno;
(void) close(fd); /* XXX closing caller's fd */
diff --git a/contrib/bind/lib/isc/ev_files.c b/contrib/bind/lib/isc/ev_files.c
index 6cd1d41abdc2..434385c17008 100644
--- a/contrib/bind/lib/isc/ev_files.c
+++ b/contrib/bind/lib/isc/ev_files.c
@@ -1,4 +1,5 @@
-/* Copyright (c) 1995, 1996, 1997, 1998 by Internet Software Consortium
+/*
+ * Copyright (c) 1995-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
@@ -19,7 +20,7 @@
*/
#if !defined(LINT) && !defined(CODECENTER)
-static const char rcsid[] = "$Id: ev_files.c,v 1.15 1998/02/06 01:53:52 halley Exp $";
+static const char rcsid[] = "$Id: ev_files.c,v 1.19 1999/10/07 20:44:04 vixie Exp $";
#endif
#include "port_before.h"
@@ -56,7 +57,7 @@ evSelectFD(evContext opaqueCtx,
ctx, fd, eventmask, func, uap);
if (eventmask == 0 || (eventmask & ~EV_MASK_ALL) != 0)
ERR(EINVAL);
- if (fd >= FD_SETSIZE)
+ if (fd > ctx->highestFD)
ERR(EINVAL);
OK(mode = fcntl(fd, F_GETFL, NULL)); /* side effect: validate fd. */
@@ -68,10 +69,10 @@ evSelectFD(evContext opaqueCtx,
*/
id = FindFD(ctx, fd, EV_MASK_ALL);
if (id == NULL) {
- if (mode & O_NONBLOCK)
+ if (mode & PORT_NONBLOCK)
FD_SET(fd, &ctx->nonblockBefore);
else {
- OK(fcntl(fd, F_SETFL, mode | O_NONBLOCK));
+ OK(fcntl(fd, F_SETFL, mode | PORT_NONBLOCK));
FD_CLR(fd, &ctx->nonblockBefore);
}
}
@@ -150,7 +151,7 @@ int
evDeselectFD(evContext opaqueCtx, evFileID opaqueID) {
evContext_p *ctx = opaqueCtx.opaque;
evFile *del = opaqueID.opaque;
- evFile *old, *cur;
+ evFile *cur;
int mode, eventmask;
if (!del) {
@@ -196,7 +197,7 @@ evDeselectFD(evContext opaqueCtx, evFileID opaqueID) {
* this fcntl() fails since (a) we've already done the work
* and (b) the caller didn't ask us anything about O_NONBLOCK.
*/
- (void) fcntl(del->fd, F_SETFL, mode & ~O_NONBLOCK);
+ (void) fcntl(del->fd, F_SETFL, mode & ~PORT_NONBLOCK);
}
/*
diff --git a/contrib/bind/lib/isc/ev_streams.c b/contrib/bind/lib/isc/ev_streams.c
index aa4270b60a43..b25a666c355a 100644
--- a/contrib/bind/lib/isc/ev_streams.c
+++ b/contrib/bind/lib/isc/ev_streams.c
@@ -1,4 +1,5 @@
-/* Copyright (c) 1996, 1997, 1998 by Internet Software Consortium
+/*
+ * Copyright (c) 1996-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
@@ -19,7 +20,7 @@
*/
#if !defined(LINT) && !defined(CODECENTER)
-static const char rcsid[] = "$Id: ev_streams.c,v 8.18 1998/03/20 23:26:22 halley Exp $";
+static const char rcsid[] = "$Id: ev_streams.c,v 8.21 1999/10/07 20:44:04 vixie Exp $";
#endif
#include "port_before.h"
@@ -83,7 +84,6 @@ evWrite(evContext opaqueCtx, int fd, const struct iovec *iov, int iocnt,
save = errno;
FREE(new);
errno = save;
- err:
return (-1);
}
@@ -118,13 +118,11 @@ evRead(evContext opaqueCtx, int fd, const struct iovec *iov, int iocnt,
save = errno;
FREE(new);
errno = save;
- err:
return (-1);
}
int
evTimeRW(evContext opaqueCtx, evStreamID id, evTimerID timer) /*ARGSUSED*/ {
- evContext_p *ctx = opaqueCtx.opaque;
evStream *str = id.opaque;
str->timer = timer;
@@ -134,7 +132,6 @@ evTimeRW(evContext opaqueCtx, evStreamID id, evTimerID timer) /*ARGSUSED*/ {
int
evUntimeRW(evContext opaqueCtx, evStreamID id) /*ARGSUSED*/ {
- evContext_p *ctx = opaqueCtx.opaque;
evStream *str = id.opaque;
str->flags &= ~EV_STR_TIMEROK;
diff --git a/contrib/bind/lib/isc/ev_timers.c b/contrib/bind/lib/isc/ev_timers.c
index 198f27c585ad..0db770c4daa0 100644
--- a/contrib/bind/lib/isc/ev_timers.c
+++ b/contrib/bind/lib/isc/ev_timers.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 1996, 1997, 1998 by Internet Software Consortium
+ * Copyright (c) 1995-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
@@ -20,7 +20,7 @@
*/
#if !defined(LINT) && !defined(CODECENTER)
-static const char rcsid[] = "$Id: ev_timers.c,v 1.23 1998/03/20 23:26:23 halley Exp $";
+static const char rcsid[] = "$Id: ev_timers.c,v 1.25 1999/10/07 20:44:04 vixie Exp $";
#endif
/* Import. */
@@ -107,7 +107,6 @@ evCmpTime(struct timespec a, struct timespec b) {
struct timespec
evNowTime() {
struct timeval now;
- struct timespec ret;
if (gettimeofday(&now, NULL) < 0)
return (evConsTime(0, 0));
@@ -288,7 +287,6 @@ evSetIdleTimer(evContext opaqueCtx,
int
evClearIdleTimer(evContext opaqueCtx, evTimerID id) {
- evContext_p *ctx = opaqueCtx.opaque;
evTimer *del = id.opaque;
idle_timer *tt = del->uap;
diff --git a/contrib/bind/lib/isc/ev_waits.c b/contrib/bind/lib/isc/ev_waits.c
index a45adf107afd..c336dcb63ab2 100644
--- a/contrib/bind/lib/isc/ev_waits.c
+++ b/contrib/bind/lib/isc/ev_waits.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 1997, 1998 by Internet Software Consortium
+ * Copyright (c) 1996-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
@@ -20,7 +20,7 @@
*/
#if !defined(LINT) && !defined(CODECENTER)
-static const char rcsid[] = "$Id: ev_waits.c,v 8.6 1998/03/20 23:26:23 halley Exp $";
+static const char rcsid[] = "$Id: ev_waits.c,v 8.9 1999/10/13 17:11:20 vixie Exp $";
#endif
#include "port_before.h"
@@ -117,7 +117,7 @@ evUnwait(evContext opaqueCtx, evWaitID id) {
for (prev = NULL, this = wl->first;
this != NULL;
prev = this, this = this->next)
- if (this == id.opaque) {
+ if (this == (evWait *)id.opaque) {
found = 1;
if (prev != NULL)
prev->next = this->next;
@@ -136,7 +136,7 @@ evUnwait(evContext opaqueCtx, evWaitID id) {
for (prev = NULL, this = ctx->waitDone.first;
this != NULL;
prev = this, this = this->next)
- if (this == id.opaque) {
+ if (this == (evWait *)id.opaque) {
found = 1;
if (prev != NULL)
prev->next = this->next;
@@ -218,7 +218,6 @@ evNewWaitList(evContext_p *ctx) {
static void
evFreeWaitList(evContext_p *ctx, evWaitList *this) {
- evWaitList *prev;
INSIST(this != NULL);
diff --git a/contrib/bind/lib/isc/eventlib.c b/contrib/bind/lib/isc/eventlib.c
index afb9d9dd6b1c..6cb227b0f3fa 100644
--- a/contrib/bind/lib/isc/eventlib.c
+++ b/contrib/bind/lib/isc/eventlib.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 1996, 1997, 1998 by Internet Software Consortium
+ * Copyright (c) 1995-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
@@ -20,7 +20,7 @@
*/
#if !defined(LINT) && !defined(CODECENTER)
-static const char rcsid[] = "$Id: eventlib.c,v 1.38 1998/03/20 23:26:24 halley Exp $";
+static const char rcsid[] = "$Id: eventlib.c,v 1.44 1999/10/13 17:11:20 vixie Exp $";
#endif
#include "port_before.h"
@@ -31,6 +31,7 @@ static const char rcsid[] = "$Id: eventlib.c,v 1.38 1998/03/20 23:26:24 halley E
#include <sys/stat.h>
#include <errno.h>
+#include <signal.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
@@ -44,7 +45,9 @@ static const char rcsid[] = "$Id: eventlib.c,v 1.38 1998/03/20 23:26:24 halley E
/* Forward. */
#ifdef NEED_PSELECT
-static int pselect(int, void *, void *, void *, struct timespec*);
+static int pselect(int, void *, void *, void *,
+ struct timespec *,
+ const sigset_t *);
#endif
/* Public. */
@@ -52,7 +55,6 @@ static int pselect(int, void *, void *, void *, struct timespec*);
int
evCreate(evContext *opaqueCtx) {
evContext_p *ctx;
- int i;
/* Make sure the memory heap is initialized. */
if (meminit(0, 0) < 0 && errno != EEXIST)
@@ -76,14 +78,15 @@ evCreate(evContext *opaqueCtx) {
FD_ZERO(&ctx->rdNext);
FD_ZERO(&ctx->wrNext);
FD_ZERO(&ctx->exNext);
+ FD_ZERO(&ctx->nonblockBefore);
ctx->fdMax = -1;
ctx->fdNext = NULL;
ctx->fdCount = 0; /* Invalidate {rd,wr,ex}Last. */
+ ctx->highestFD = FD_SETSIZE - 1;
#ifdef EVENTLIB_TIME_CHECKS
ctx->lastFdCount = 0;
#endif
- for (i = 0; i < FD_SETSIZE; i++)
- ctx->fdTable[i] = NULL;
+ memset(ctx->fdTable, 0, sizeof ctx->fdTable);
/* Streams. */
ctx->streams = NULL;
@@ -299,7 +302,7 @@ evGetNext(evContext opaqueCtx, evEvent *opaqueEv, int options) {
/* XXX should predict system's earliness and adjust. */
x = pselect(ctx->fdMax+1,
&ctx->rdLast, &ctx->wrLast, &ctx->exLast,
- tp);
+ tp, NULL);
pselect_errno = errno;
evPrintf(ctx, 4, "select() returns %d (err: %s)\n",
@@ -625,6 +628,13 @@ evMainLoop(evContext opaqueCtx) {
return (x);
}
+int
+evHighestFD(evContext opaqueCtx) {
+ evContext_p *ctx = opaqueCtx.opaque;
+
+ return (ctx->highestFD);
+}
+
void
evPrintf(const evContext_p *ctx, int level, const char *fmt, ...) {
va_list ap;
@@ -638,9 +648,14 @@ evPrintf(const evContext_p *ctx, int level, const char *fmt, ...) {
}
#ifdef NEED_PSELECT
+/* XXX needs to move to the porting library. */
static int
-pselect(int nfds, void *rfds, void *wfds, void *efds, struct timespec *tsp) {
+pselect(int nfds, void *rfds, void *wfds, void *efds,
+ struct timespec *tsp,
+ const sigset_t *sigmask)
+{
struct timeval tv, *tvp;
+ sigset_t sigs;
int n;
if (tsp) {
@@ -648,7 +663,11 @@ pselect(int nfds, void *rfds, void *wfds, void *efds, struct timespec *tsp) {
tv = evTimeVal(*tsp);
} else
tvp = NULL;
+ if (sigmask)
+ sigprocmask(SIG_SETMASK, sigmask, &sigs);
n = select(nfds, rfds, wfds, efds, tvp);
+ if (sigmask)
+ sigprocmask(SIG_SETMASK, &sigs, NULL);
if (tsp)
*tsp = evTimeSpec(tv);
return (n);
diff --git a/contrib/bind/lib/isc/eventlib.mdoc b/contrib/bind/lib/isc/eventlib.mdoc
index f0e31e16ddec..202b1cb405e2 100644
--- a/contrib/bind/lib/isc/eventlib.mdoc
+++ b/contrib/bind/lib/isc/eventlib.mdoc
@@ -1,6 +1,6 @@
-.\" $Id: eventlib.mdoc,v 1.18 1998/01/26 23:00:56 halley Exp $
+.\" $Id: eventlib.mdoc,v 1.20 1999/08/18 22:09:04 vixie Exp $
.\"
-.\"Copyright (c) 1995, 1996, 1997 by Internet Software Consortium
+.\"Copyright (c) 1995-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
@@ -63,7 +63,9 @@
.Nm evTryAccept ,
.Nm evConsIovec ,
.Nm evSetDebug ,
-.Nm evPrintf
+.Nm evPrintf ,
+.Nm evInitID ,
+.Nm evTestID
.Nd event handling library
.Sh SYNOPSIS
.Fd #include <isc/eventlib.h>
@@ -171,6 +173,10 @@
.Fn evSetDebug "evContext ctx" "int level" "FILE *output"
.Ft void
.Fn evPrintf "const evContext_p *ctx" "int level" "const char *fmt" "..."
+.Ft void
+.Fn evInitID "*\s-1ID\s+1"
+.Ft int
+.Fn evTestID "\s-1ID\s+1"
.Sh DESCRIPTION
This library provides multiple outstanding asynchronous timers and I/O
to a cooperating application. The model is similar to that of the X
@@ -769,6 +775,25 @@ with the event context pointed to by
The message is output if the event context's debug level is greater than
or equal to the indicated
.Fa level .
+.Pp
+The function
+.Fn evInitID
+will initialize an opaque
+.Dq evConn \s-1ID\s+1 ,
+.Dq evFile \s-1ID\s+1 ,
+.Dq evStream \s-1ID\s+1 ,
+.Dq evTimer \s-1ID\s+1 ,
+.Dq evWait \s-1ID\s+1 ,
+.Dq evContext ,
+or
+.Dq evEvent ,
+which is passed by reference.
+.Pp
+The function
+.Fn evTestID
+will examine an opaque \s-1ID\s+1 and return
+.Dq TRUE
+only if it is not in its initialized state.
.Sh RETURN VALUES
All the functions whose return type is
.Dq Fa int
diff --git a/contrib/bind/lib/isc/eventlib_p.h b/contrib/bind/lib/isc/eventlib_p.h
index 2606333fcae3..80dc16028290 100644
--- a/contrib/bind/lib/isc/eventlib_p.h
+++ b/contrib/bind/lib/isc/eventlib_p.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 1996, 1997, 1998 by Internet Software Consortium
+ * Copyright (c) 1995-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
@@ -18,7 +18,7 @@
/* eventlib_p.h - private interfaces for eventlib
* vix 09sep95 [initial]
*
- * $Id: eventlib_p.h,v 1.25 1998/02/06 01:53:54 halley Exp $
+ * $Id: eventlib_p.h,v 1.27 1999/06/03 20:36:05 vixie Exp $
*/
#ifndef _EVENTLIB_P_H
@@ -165,7 +165,7 @@ typedef struct {
fd_set wrLast, wrNext;
fd_set exLast, exNext;
fd_set nonblockBefore;
- int fdMax, fdCount;
+ int fdMax, fdCount, highestFD;
evFile *fdTable[FD_SETSIZE];
#ifdef EVENTLIB_TIME_CHECKS
struct timespec lastSelectTime;
diff --git a/contrib/bind/lib/isc/heap.c b/contrib/bind/lib/isc/heap.c
index 821d3232906e..ba9c5036c77a 100644
--- a/contrib/bind/lib/isc/heap.c
+++ b/contrib/bind/lib/isc/heap.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997 by Internet Software Consortium.
+ * Copyright (c) 1997,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
@@ -26,7 +26,7 @@
*/
#if !defined(LINT) && !defined(CODECENTER)
-static char rcsid[] = "$Id: heap.c,v 8.5 1998/03/27 00:17:47 halley Exp $";
+static const char rcsid[] = "$Id: heap.c,v 8.7 1999/10/13 16:39:34 vixie Exp $";
#endif /* not lint */
#include "port_before.h"
diff --git a/contrib/bind/lib/isc/heap.mdoc b/contrib/bind/lib/isc/heap.mdoc
index 2c22bc28745b..516490b22ba9 100644
--- a/contrib/bind/lib/isc/heap.mdoc
+++ b/contrib/bind/lib/isc/heap.mdoc
@@ -1,6 +1,6 @@
-.\" $Id: heap.mdoc,v 8.4 1997/04/26 04:00:55 vixie Exp $
+.\" $Id: heap.mdoc,v 8.5 1999/01/08 19:25:38 vixie Exp $
.\"
-.\"Copyright (c) 1997 by Internet Software Consortium.
+.\"Copyright (c) 1997,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
diff --git a/contrib/bind/lib/isc/logging.c b/contrib/bind/lib/isc/logging.c
index e5264fffe9e7..a3988e45037b 100644
--- a/contrib/bind/lib/isc/logging.c
+++ b/contrib/bind/lib/isc/logging.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 1997, 1998 by Internet Software Consortium.
+ * Copyright (c) 1996-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
@@ -16,7 +16,7 @@
*/
#if !defined(LINT) && !defined(CODECENTER)
-static char rcsid[] = "$Id: logging.c,v 8.18 1998/03/27 00:17:47 halley Exp $";
+static const char rcsid[] = "$Id: logging.c,v 8.24 1999/10/13 16:39:34 vixie Exp $";
#endif /* not lint */
#include "port_before.h"
@@ -115,9 +115,7 @@ log_open_stream(log_channel chan) {
regular = (sb.st_mode & S_IFREG);
if (chan->out.file.versions) {
- if (regular)
- version_rename(chan);
- else {
+ if (!regular) {
syslog(LOG_ERR,
"log_open_stream: want versions but %s isn't a regular file",
chan->out.file.name);
@@ -265,7 +263,6 @@ log_vwrite(log_context lc, int category, int level, const char *format,
int pri, debugging, did_vsprintf = 0;
int original_category;
FILE *stream;
- int chan_level;
log_channel chan;
struct timeval tv;
struct tm *local_tm;
@@ -300,7 +297,11 @@ log_vwrite(log_context lc, int category, int level, const char *format,
if (gettimeofday(&tv, NULL) < 0) {
syslog(LOG_INFO, "gettimeofday failed in log_vwrite()");
} else {
+#ifdef HAVE_TIME_R
+ localtime_r((time_t *)&tv.tv_sec, &local_tm);
+#else
local_tm = localtime((time_t *)&tv.tv_sec);
+#endif
if (local_tm != NULL) {
sprintf(time_buf, "%02d-%s-%4d %02d:%02d:%02d.%03ld ",
local_tm->tm_mday, months[local_tm->tm_mon],
@@ -378,8 +379,19 @@ log_vwrite(log_context lc, int category, int level, const char *format,
pos = ftell(stream);
if (pos >= 0 &&
(unsigned long)pos >
- chan->out.file.max_size)
- break;
+ chan->out.file.max_size) {
+ /*
+ * try to roll over the log files,
+ * ignoring all all return codes
+ * except the open (we don't want
+ * to write any more anyway)
+ */
+ log_close_stream(chan);
+ version_rename(chan);
+ stream = log_open_stream(chan);
+ if (stream == NULL)
+ break;
+ }
}
fprintf(stream, "%s%s%s%s\n",
(chan->flags & LOG_TIMESTAMP) ? time_buf : "",
diff --git a/contrib/bind/lib/isc/logging.mdoc b/contrib/bind/lib/isc/logging.mdoc
index 6fdb618b5263..6b48943e06af 100644
--- a/contrib/bind/lib/isc/logging.mdoc
+++ b/contrib/bind/lib/isc/logging.mdoc
@@ -1,6 +1,6 @@
-.\" $Id: logging.mdoc,v 8.2 1998/02/06 01:54:34 halley Exp $
+.\" $Id: logging.mdoc,v 8.3 1999/01/08 19:25:41 vixie Exp $
.\"
-.\"Copyright (c) 1995, 1996, 1997, 1998 by Internet Software Consortium
+.\"Copyright (c) 1995-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
diff --git a/contrib/bind/lib/isc/logging_p.h b/contrib/bind/lib/isc/logging_p.h
index 317582da8160..e94102ef4cf3 100644
--- a/contrib/bind/lib/isc/logging_p.h
+++ b/contrib/bind/lib/isc/logging_p.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 1997 by Internet Software Consortium.
+ * Copyright (c) 1996-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
diff --git a/contrib/bind/lib/isc/memcluster.c b/contrib/bind/lib/isc/memcluster.c
index 761fe98f82ff..b775fa7aa84c 100644
--- a/contrib/bind/lib/isc/memcluster.c
+++ b/contrib/bind/lib/isc/memcluster.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997 by Internet Software Consortium.
+ * Copyright (c) 1997,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
@@ -15,8 +15,15 @@
* SOFTWARE.
*/
+
+/* When this symbol is defined allocations via memget are made slightly
+ bigger and some debugging info stuck before and after the region given
+ back to the caller. */
+/* #define DEBUGGING_MEMCLUSTER */
+
+
#if !defined(LINT) && !defined(CODECENTER)
-static char rcsid[] = "$Id: memcluster.c,v 8.10 1998/05/05 19:00:52 halley Exp $";
+static const char rcsid[] = "$Id: memcluster.c,v 8.19 1999/10/13 17:11:22 vixie Exp $";
#endif /* not lint */
#include "port_before.h"
@@ -41,15 +48,34 @@ static char rcsid[] = "$Id: memcluster.c,v 8.10 1998/05/05 19:00:52 halley Exp $
#include "port_after.h"
+#ifdef MEMCLUSTER_RECORD
+#ifndef DEBUGGING_MEMCLUSTER
+#define DEBUGGING_MEMCLUSTER
+#endif
+#endif
+
#define DEF_MAX_SIZE 1100
#define DEF_MEM_TARGET 4096
+typedef u_int32_t fence_t;
+
typedef struct {
void * next;
+#if defined(DEBUGGING_MEMCLUSTER)
+#if defined(MEMCLUSTER_RECORD)
+ const char * file;
+ int line;
+#endif
+ int size;
+ fence_t fencepost;
+#endif
} memcluster_element;
#define SMALL_SIZE_LIMIT sizeof(memcluster_element)
#define P_SIZE sizeof(void *)
+#define FRONT_FENCEPOST 0xfebafeba
+#define BACK_FENCEPOST 0xabefabef
+#define FENCEPOST_SIZE 4
#ifndef MEMCLUSTER_LITTLE_MALLOC
#define MEMCLUSTER_BIG_MALLOC 1
@@ -70,6 +96,9 @@ static size_t mem_target;
static size_t mem_target_half;
static size_t mem_target_fudge;
static memcluster_element ** freelists;
+#ifdef MEMCLUSTER_RECORD
+static memcluster_element ** activelists;
+#endif
#ifdef MEMCLUSTER_BIG_MALLOC
static memcluster_element * basic_blocks;
#endif
@@ -78,13 +107,18 @@ static struct stats * stats;
/* Forward. */
static size_t quantize(size_t);
+#if defined(DEBUGGING_MEMCLUSTER)
+static void check(unsigned char *, int, size_t);
+#endif
/* Public. */
int
meminit(size_t init_max_size, size_t target_size) {
- int i;
+#if defined(DEBUGGING_MEMCLUSTER)
+ INSIST(sizeof(fence_t) == FENCEPOST_SIZE);
+#endif
if (freelists != NULL) {
errno = EEXIST;
return (-1);
@@ -108,6 +142,15 @@ meminit(size_t init_max_size, size_t target_size) {
memset(freelists, 0,
max_size * sizeof (memcluster_element *));
memset(stats, 0, (max_size + 1) * sizeof (struct stats));
+#ifdef MEMCLUSTER_RECORD
+ activelists = malloc((max_size + 1) * sizeof (memcluster_element *));
+ if (activelists == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ memset(activelists, 0,
+ (max_size + 1) * sizeof (memcluster_element *));
+#endif
#ifdef MEMCLUSTER_BIG_MALLOC
basic_blocks = NULL;
#endif
@@ -116,7 +159,17 @@ meminit(size_t init_max_size, size_t target_size) {
void *
__memget(size_t size) {
+ return (__memget_record(size, NULL, 0));
+}
+
+void *
+__memget_record(size_t size, const char *file, int line) {
size_t new_size = quantize(size);
+#if defined(DEBUGGING_MEMCLUSTER)
+ memcluster_element *e;
+ char *p;
+ fence_t fp = BACK_FENCEPOST;
+#endif
void *ret;
if (freelists == NULL)
@@ -130,7 +183,27 @@ __memget(size_t size) {
/* memget() was called on something beyond our upper limit. */
stats[max_size].gets++;
stats[max_size].totalgets++;
+#if defined(DEBUGGING_MEMCLUSTER)
+ e = malloc(new_size);
+ if (e == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ e->next = NULL;
+ e->size = size;
+#ifdef MEMCLUSTER_RECORD
+ e->file = file;
+ e->line = line;
+ e->next = activelists[max_size];
+ activelists[max_size] = e;
+#endif
+ e->fencepost = FRONT_FENCEPOST;
+ p = (char *)e + sizeof *e + size;
+ memcpy(p, &fp, sizeof fp);
+ return ((char *)e + sizeof *e);
+#else
return (malloc(size));
+#endif
}
/*
@@ -186,18 +259,50 @@ __memget(size_t size) {
curr = new;
next = curr + new_size;
for (i = 0; i < (frags - 1); i++) {
+#if defined (DEBUGGING_MEMCLUSTER)
+ memset(curr, 0xa5, new_size);
+#endif
((memcluster_element *)curr)->next = next;
curr = next;
next += new_size;
}
/* curr is now pointing at the last block in the array. */
+#if defined (DEBUGGING_MEMCLUSTER)
+ memset(curr, 0xa5, new_size);
+#endif
((memcluster_element *)curr)->next = freelists[new_size];
freelists[new_size] = new;
}
- /* The free list uses the "rounded-up" size "new_size": */
+ /* The free list uses the "rounded-up" size "new_size". */
+#if defined (DEBUGGING_MEMCLUSTER)
+ e = freelists[new_size];
+ ret = (char *)e + sizeof *e;
+ /*
+ * Check to see if this buffer has been written to while on free list.
+ */
+ check(ret, 0xa5, new_size - sizeof *e);
+ /*
+ * Mark memory we are returning.
+ */
+ memset(ret, 0xe5, size);
+#else
ret = freelists[new_size];
+#endif
freelists[new_size] = freelists[new_size]->next;
+#if defined(DEBUGGING_MEMCLUSTER)
+ e->next = NULL;
+ e->size = size;
+ e->fencepost = FRONT_FENCEPOST;
+#ifdef MEMCLUSTER_RECORD
+ e->file = file;
+ e->line = line;
+ e->next = activelists[size];
+ activelists[size] = e;
+#endif
+ p = (char *)e + sizeof *e + size;
+ memcpy(p, &fp, sizeof fp);
+#endif
/*
* The stats[] uses the _actual_ "size" requested by the
@@ -208,7 +313,11 @@ __memget(size_t size) {
stats[size].gets++;
stats[size].totalgets++;
stats[new_size].freefrags--;
+#if defined(DEBUGGING_MEMCLUSTER)
+ return ((char *)e + sizeof *e);
+#else
return (ret);
+#endif
}
/*
@@ -217,25 +326,83 @@ __memget(size_t size) {
*/
void
__memput(void *mem, size_t size) {
- size_t new_size = quantize(size);
+ __memput_record(mem, size, NULL, 0);
+}
+void
+__memput_record(void *mem, size_t size, const char *file, int line) {
+ size_t new_size = quantize(size);
+#if defined (DEBUGGING_MEMCLUSTER)
+ memcluster_element *e;
+#ifdef MEMCLUSTER_RECORD
+ memcluster_element *prev, *el;
+#endif
+ int fp;
+ char *p;
+#endif
REQUIRE(freelists != NULL);
if (size == 0) {
errno = EINVAL;
return;
}
+
+#if defined (DEBUGGING_MEMCLUSTER)
+ e = (memcluster_element *) ((char *)mem - sizeof *e);
+ INSIST(e->fencepost == FRONT_FENCEPOST);
+ INSIST(e->size == size);
+ p = (char *)e + sizeof *e + size;
+ memcpy(&fp, p, sizeof fp);
+ INSIST(fp == BACK_FENCEPOST);
+ INSIST(((int)mem % 4) == 0);
+#ifdef MEMCLUSTER_RECORD
+ prev = NULL;
+ if (size == max_size || new_size >= max_size)
+ el = activelists[max_size];
+ else
+ el = activelists[size];
+ while (el != NULL && el != e) {
+ prev = el;
+ el = el->next;
+ }
+ INSIST(el != NULL); /* double free */
+ if (prev == NULL) {
+ if (size == max_size || new_size >= max_size)
+ activelists[max_size] = el->next;
+ else
+ activelists[size] = el->next;
+ } else
+ prev->next = el->next;
+#endif
+#endif
+
if (size == max_size || new_size >= max_size) {
/* memput() called on something beyond our upper limit */
+#if defined(DEBUGGING_MEMCLUSTER)
+ free(e);
+#else
free(mem);
+#endif
+
INSIST(stats[max_size].gets != 0);
stats[max_size].gets--;
return;
}
/* The free list uses the "rounded-up" size "new_size": */
+#if defined(DEBUGGING_MEMCLUSTER)
+ memset(mem, 0xa5, new_size - sizeof *e); /* catch write after free */
+ e->size = 0; /* catch double memput() */
+#ifdef MEMCLUSTER_RECORD
+ e->file = file;
+ e->line = line;
+#endif
+ e->next = freelists[new_size];
+ freelists[new_size] = (void *)e;
+#else
((memcluster_element *)mem)->next = freelists[new_size];
freelists[new_size] = (memcluster_element *)mem;
+#endif
/*
* The stats[] uses the _actual_ "size" requested by the
@@ -251,7 +418,7 @@ __memput(void *mem, size_t size) {
void *
__memget_debug(size_t size, const char *file, int line) {
void *ptr;
- ptr = __memget(size);
+ ptr = __memget_record(size, file, line);
fprintf(stderr, "%s:%d: memget(%lu) -> %p\n", file, line,
(u_long)size, ptr);
return (ptr);
@@ -261,7 +428,7 @@ void
__memput_debug(void *ptr, size_t size, const char *file, int line) {
fprintf(stderr, "%s:%d: memput(%p, %lu)\n", file, line, ptr,
(u_long)size);
- __memput(ptr, size);
+ __memput_record(ptr, size, file, line);
}
/*
@@ -270,6 +437,9 @@ __memput_debug(void *ptr, size_t size, const char *file, int line) {
void
memstats(FILE *out) {
size_t i;
+#ifdef MEMCLUSTER_RECORD
+ memcluster_element *e;
+#endif
if (freelists == NULL)
return;
@@ -286,6 +456,19 @@ memstats(FILE *out) {
s->blocks, s->freefrags);
fputc('\n', out);
}
+#ifdef MEMCLUSTER_RECORD
+ fprintf(out, "Active Memory:\n");
+ for (i = 1; i <= max_size; i++) {
+ if ((e = activelists[i]) != NULL)
+ while (e != NULL) {
+ fprintf(out, "%s:%d %#p:%d\n",
+ e->file != NULL ? e->file :
+ "<UNKNOWN>", e->line,
+ (char *)e + sizeof *e, e->size);
+ e = e->next;
+ }
+ }
+#endif
}
/* Private. */
@@ -295,7 +478,7 @@ memstats(FILE *out) {
* block is at least sizeof void *, and that we won't violate alignment
* restrictions, both of which are needed to make lists of blocks.
*/
-static size_t
+static size_t
quantize(size_t size) {
int remainder;
/*
@@ -309,7 +492,19 @@ quantize(size_t size) {
*/
remainder = size % P_SIZE;
if (remainder != 0)
- size += P_SIZE - remainder;
+ size += P_SIZE - remainder;
+#if defined(DEBUGGING_MEMCLUSTER)
+ return (size + SMALL_SIZE_LIMIT + sizeof (int));
+#else
return (size);
+#endif
}
+#if defined(DEBUGGING_MEMCLUSTER)
+static void
+check(unsigned char *a, int value, size_t len) {
+ int i;
+ for (i = 0; i < len; i++)
+ INSIST(a[i] == value);
+}
+#endif
diff --git a/contrib/bind/lib/isc/memcluster.mdoc b/contrib/bind/lib/isc/memcluster.mdoc
index c076972f9d7e..82bfd71a852b 100644
--- a/contrib/bind/lib/isc/memcluster.mdoc
+++ b/contrib/bind/lib/isc/memcluster.mdoc
@@ -1,6 +1,6 @@
-.\" $Id: memcluster.mdoc,v 8.1 1997/09/26 17:56:10 halley Exp $
+.\" $Id: memcluster.mdoc,v 8.2 1999/01/08 19:25:46 vixie Exp $
.\"
-.\"Copyright (c) 1995, 1996 by Internet Software Consortium
+.\"Copyright (c) 1995-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
diff --git a/contrib/bind/lib/isc/tree.c b/contrib/bind/lib/isc/tree.c
index ce500ec7b41c..90ba146670aa 100644
--- a/contrib/bind/lib/isc/tree.c
+++ b/contrib/bind/lib/isc/tree.c
@@ -1,5 +1,5 @@
#ifndef LINT
-static char RCSid[] = "$Id: tree.c,v 8.6 1997/09/26 17:56:11 halley Exp $";
+static const char rcsid[] = "$Id: tree.c,v 8.9 1999/01/08 19:25:47 vixie Exp $";
#endif
/*
@@ -22,7 +22,7 @@ static char RCSid[] = "$Id: tree.c,v 8.6 1997/09/26 17:56:11 halley Exp $";
*/
/*
- * Portions Copyright (c) 1996,1997 by Internet Software Consortium.
+ * Portions Copyright (c) 1996-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
@@ -56,7 +56,7 @@ static char *debugFuncs[256];
# define ENTER(proc) { \
debugFuncs[debugDepth] = proc; \
fprintf(stderr, "ENTER(%d:%s.%s)\n", \
- debugDepth, DEBUG,
+ debugDepth, DEBUG, \
debugFuncs[debugDepth]); \
debugDepth++; \
}
diff --git a/contrib/bind/lib/isc/tree.mdoc b/contrib/bind/lib/isc/tree.mdoc
index 2406219b2da1..422344ebae32 100644
--- a/contrib/bind/lib/isc/tree.mdoc
+++ b/contrib/bind/lib/isc/tree.mdoc
@@ -1,6 +1,6 @@
-.\" $Id: tree.mdoc,v 8.1 1997/01/30 20:27:25 vixie Exp $
+.\" $Id: tree.mdoc,v 8.2 1999/01/08 19:25:48 vixie Exp $
.\"
-.\"Copyright (c) 1995, 1996 by Internet Software Consortium
+.\"Copyright (c) 1995-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