diff options
Diffstat (limited to 'contrib/ntp/lib')
265 files changed, 72324 insertions, 0 deletions
diff --git a/contrib/ntp/lib/isc/Atffile b/contrib/ntp/lib/isc/Atffile new file mode 100644 index 0000000..1edb838 --- /dev/null +++ b/contrib/ntp/lib/isc/Atffile @@ -0,0 +1,5 @@ +Content-Type: application/X-atf-atffile; version="1" + +prop: test-suite = bind9 + +tp: tests diff --git a/contrib/ntp/lib/isc/alpha/include/isc/atomic.h b/contrib/ntp/lib/isc/alpha/include/isc/atomic.h new file mode 100644 index 0000000..ab3de5d --- /dev/null +++ b/contrib/ntp/lib/isc/alpha/include/isc/atomic.h @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: atomic.h,v 1.7 2009/04/08 06:48:23 tbox Exp $ */ + +/* + * This code was written based on FreeBSD's kernel source whose copyright + * follows: + */ + +/*- + * Copyright (c) 1998 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: 258945 2013-12-04 21:33:17Z roberto $ + */ + +#ifndef ISC_ATOMIC_H +#define ISC_ATOMIC_H 1 + +#include <isc/platform.h> +#include <isc/types.h> + +#ifdef ISC_PLATFORM_USEOSFASM +#include <c_asm.h> + +#pragma intrinsic(asm) + +/* + * This routine atomically increments the value stored in 'p' by 'val', and + * returns the previous value. Memory access ordering around this function + * can be critical, so we add explicit memory block instructions at the + * beginning and the end of it (same for other functions). + */ +static inline isc_int32_t +isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) { + return (asm("mb;" + "1:" + "ldl_l %t0, 0(%a0);" /* load old value */ + "mov %t0, %v0;" /* copy the old value */ + "addl %t0, %a1, %t0;" /* calculate new value */ + "stl_c %t0, 0(%a0);" /* attempt to store */ + "beq %t0, 1b;" /* spin if failed */ + "mb;", + p, val)); +} + +/* + * This routine atomically stores the value 'val' in 'p'. + */ +static inline void +isc_atomic_store(isc_int32_t *p, isc_int32_t val) { + (void)asm("mb;" + "1:" + "ldl_l %t0, 0(%a0);" /* load old value */ + "mov %a1, %t0;" /* value to store */ + "stl_c %t0, 0(%a0);" /* attempt to store */ + "beq %t0, 1b;" /* spin if failed */ + "mb;", + p, val); +} + +/* + * This routine atomically replaces the value in 'p' with 'val', if the + * original value is equal to 'cmpval'. The original value is returned in any + * case. + */ +static inline isc_int32_t +isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) { + + return(asm("mb;" + "1:" + "ldl_l %t0, 0(%a0);" /* load old value */ + "mov %t0, %v0;" /* copy the old value */ + "cmpeq %t0, %a1, %t0;" /* compare */ + "beq %t0, 2f;" /* exit if not equal */ + "mov %a2, %t0;" /* value to store */ + "stl_c %t0, 0(%a0);" /* attempt to store */ + "beq %t0, 1b;" /* if it failed, spin */ + "2:" + "mb;", + p, cmpval, val)); +} +#elif defined (ISC_PLATFORM_USEGCCASM) +static inline isc_int32_t +isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) { + isc_int32_t temp, prev; + + __asm__ volatile( + "mb;" + "1:" + "ldl_l %0, %1;" /* load old value */ + "mov %0, %2;" /* copy the old value */ + "addl %0, %3, %0;" /* calculate new value */ + "stl_c %0, %1;" /* attempt to store */ + "beq %0, 1b;" /* spin if failed */ + "mb;" + : "=&r"(temp), "+m"(*p), "=&r"(prev) + : "r"(val) + : "memory"); + + return (prev); +} + +static inline void +isc_atomic_store(isc_int32_t *p, isc_int32_t val) { + isc_int32_t temp; + + __asm__ volatile( + "mb;" + "1:" + "ldl_l %0, %1;" /* load old value */ + "mov %2, %0;" /* value to store */ + "stl_c %0, %1;" /* attempt to store */ + "beq %0, 1b;" /* if it failed, spin */ + "mb;" + : "=&r"(temp), "+m"(*p) + : "r"(val) + : "memory"); +} + +static inline isc_int32_t +isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) { + isc_int32_t temp, prev; + + __asm__ volatile( + "mb;" + "1:" + "ldl_l %0, %1;" /* load old value */ + "mov %0, %2;" /* copy the old value */ + "cmpeq %0, %3, %0;" /* compare */ + "beq %0, 2f;" /* exit if not equal */ + "mov %4, %0;" /* value to store */ + "stl_c %0, %1;" /* attempt to store */ + "beq %0, 1b;" /* if it failed, spin */ + "2:" + "mb;" + : "=&r"(temp), "+m"(*p), "=&r"(prev) + : "r"(cmpval), "r"(val) + : "memory"); + + return (prev); +} +#else + +#error "unsupported compiler. disable atomic ops by --disable-atomic" + +#endif + +#endif /* ISC_ATOMIC_H */ diff --git a/contrib/ntp/lib/isc/api b/contrib/ntp/lib/isc/api new file mode 100644 index 0000000..ed4b69f --- /dev/null +++ b/contrib/ntp/lib/isc/api @@ -0,0 +1,8 @@ +# LIBINTERFACE ranges +# 9.6: 50-59, 110-119 +# 9.7: 60-79 +# 9.8: 80-89 +# 9.9: 90-109 +LIBINTERFACE = 91 +LIBREVISION = 1 +LIBAGE = 1 diff --git a/contrib/ntp/lib/isc/app_api.c b/contrib/ntp/lib/isc/app_api.c new file mode 100644 index 0000000..ce767d1 --- /dev/null +++ b/contrib/ntp/lib/isc/app_api.c @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: app_api.c,v 1.5 2009/09/02 23:48:02 tbox Exp $ */ + +#include <config.h> + +#include <unistd.h> + +#include <isc/app.h> +#include <isc/magic.h> +#include <isc/mutex.h> +#include <isc/once.h> +#include <isc/util.h> + +static isc_mutex_t createlock; +static isc_once_t once = ISC_ONCE_INIT; +static isc_appctxcreatefunc_t appctx_createfunc = NULL; + +#define ISCAPI_APPMETHODS_VALID(m) ISC_MAGIC_VALID(m, ISCAPI_APPMETHODS_MAGIC) + +static void +initialize(void) { + RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS); +} + +isc_result_t +isc_app_register(isc_appctxcreatefunc_t createfunc) { + isc_result_t result = ISC_R_SUCCESS; + + RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS); + + LOCK(&createlock); + if (appctx_createfunc == NULL) + appctx_createfunc = createfunc; + else + result = ISC_R_EXISTS; + UNLOCK(&createlock); + + return (result); +} + +isc_result_t +isc_appctx_create(isc_mem_t *mctx, isc_appctx_t **ctxp) { + isc_result_t result; + + LOCK(&createlock); + + REQUIRE(appctx_createfunc != NULL); + result = (*appctx_createfunc)(mctx, ctxp); + + UNLOCK(&createlock); + + return (result); +} + +void +isc_appctx_destroy(isc_appctx_t **ctxp) { + REQUIRE(ctxp != NULL && ISCAPI_APPCTX_VALID(*ctxp)); + + (*ctxp)->methods->ctxdestroy(ctxp); + + ENSURE(*ctxp == NULL); +} + +isc_result_t +isc_app_ctxstart(isc_appctx_t *ctx) { + REQUIRE(ISCAPI_APPCTX_VALID(ctx)); + + return (ctx->methods->ctxstart(ctx)); +} + +isc_result_t +isc_app_ctxrun(isc_appctx_t *ctx) { + REQUIRE(ISCAPI_APPCTX_VALID(ctx)); + + return (ctx->methods->ctxrun(ctx)); +} + +isc_result_t +isc_app_ctxsuspend(isc_appctx_t *ctx) { + REQUIRE(ISCAPI_APPCTX_VALID(ctx)); + + return (ctx->methods->ctxsuspend(ctx)); +} + +isc_result_t +isc_app_ctxshutdown(isc_appctx_t *ctx) { + REQUIRE(ISCAPI_APPCTX_VALID(ctx)); + + return (ctx->methods->ctxshutdown(ctx)); +} + +void +isc_app_ctxfinish(isc_appctx_t *ctx) { + REQUIRE(ISCAPI_APPCTX_VALID(ctx)); + + ctx->methods->ctxfinish(ctx); +} + +void +isc_appctx_settaskmgr(isc_appctx_t *ctx, isc_taskmgr_t *taskmgr) { + REQUIRE(ISCAPI_APPCTX_VALID(ctx)); + REQUIRE(taskmgr != NULL); + + ctx->methods->settaskmgr(ctx, taskmgr); +} + +void +isc_appctx_setsocketmgr(isc_appctx_t *ctx, isc_socketmgr_t *socketmgr) { + REQUIRE(ISCAPI_APPCTX_VALID(ctx)); + REQUIRE(socketmgr != NULL); + + ctx->methods->setsocketmgr(ctx, socketmgr); +} + +void +isc_appctx_settimermgr(isc_appctx_t *ctx, isc_timermgr_t *timermgr) { + REQUIRE(ISCAPI_APPCTX_VALID(ctx)); + REQUIRE(timermgr != NULL); + + ctx->methods->settimermgr(ctx, timermgr); +} diff --git a/contrib/ntp/lib/isc/assertions.c b/contrib/ntp/lib/isc/assertions.c new file mode 100644 index 0000000..31c4fe7 --- /dev/null +++ b/contrib/ntp/lib/isc/assertions.c @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1997-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: assertions.c,v 1.26 2009/09/29 15:06:07 fdupont Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> + +#include <isc/assertions.h> +#include <isc/backtrace.h> +#include <isc/msgs.h> +#include <isc/result.h> + +/* + * The maximum number of stack frames to dump on assertion failure. + */ +#ifndef BACKTRACE_MAXFRAME +#define BACKTRACE_MAXFRAME 128 +#endif + +/*% + * Forward. + */ +static void +default_callback(const char *, int, isc_assertiontype_t, const char *); + +static isc_assertioncallback_t isc_assertion_failed_cb = default_callback; + +/*% + * Public. + */ + +/*% assertion failed handler */ +/* coverity[+kill] */ +void +isc_assertion_failed(const char *file, int line, isc_assertiontype_t type, + const char *cond) +{ + isc_assertion_failed_cb(file, line, type, cond); + abort(); + /* NOTREACHED */ +} + +/*% Set callback. */ +void +isc_assertion_setcallback(isc_assertioncallback_t cb) { + if (cb == NULL) + isc_assertion_failed_cb = default_callback; + else + isc_assertion_failed_cb = cb; +} + +/*% Type to Text */ +const char * +isc_assertion_typetotext(isc_assertiontype_t type) { + const char *result; + + /* + * These strings have purposefully not been internationalized + * because they are considered to essentially be keywords of + * the ISC development environment. + */ + switch (type) { + case isc_assertiontype_require: + result = "REQUIRE"; + break; + case isc_assertiontype_ensure: + result = "ENSURE"; + break; + case isc_assertiontype_insist: + result = "INSIST"; + break; + case isc_assertiontype_invariant: + result = "INVARIANT"; + break; + default: + result = NULL; + } + return (result); +} + +/* + * Private. + */ + +static void +default_callback(const char *file, int line, isc_assertiontype_t type, + const char *cond) +{ + void *tracebuf[BACKTRACE_MAXFRAME]; + int i, nframes; + const char *logsuffix = "."; + const char *fname; + isc_result_t result; + + result = isc_backtrace_gettrace(tracebuf, BACKTRACE_MAXFRAME, &nframes); + if (result == ISC_R_SUCCESS && nframes > 0) + logsuffix = ", back trace"; + + fprintf(stderr, "%s:%d: %s(%s) %s%s\n", + file, line, isc_assertion_typetotext(type), cond, + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed"), logsuffix); + if (result == ISC_R_SUCCESS) { + for (i = 0; i < nframes; i++) { + unsigned long offset; + + fname = NULL; + result = isc_backtrace_getsymbol(tracebuf[i], &fname, + &offset); + if (result == ISC_R_SUCCESS) { + fprintf(stderr, "#%d %p in %s()+0x%lx\n", i, + tracebuf[i], fname, offset); + } else { + fprintf(stderr, "#%d %p in ??\n", i, + tracebuf[i]); + } + } + } + fflush(stderr); +} diff --git a/contrib/ntp/lib/isc/backtrace-emptytbl.c b/contrib/ntp/lib/isc/backtrace-emptytbl.c new file mode 100644 index 0000000..bd534d6 --- /dev/null +++ b/contrib/ntp/lib/isc/backtrace-emptytbl.c @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: backtrace-emptytbl.c,v 1.3 2009/09/01 20:13:44 each Exp $ */ + +/*! \file */ + +/* + * This file defines an empty (default) symbol table used in backtrace.c + * If the application wants to have a complete symbol table, it should redefine + * isc__backtrace_symtable with the complete table in some way, and link the + * version of the library not including this definition + * (e.g. libisc-nosymbol.a). + */ + +#include <config.h> + +#include <isc/backtrace.h> + +const int isc__backtrace_nsymbols = 0; +const isc_backtrace_symmap_t isc__backtrace_symtable[] = { { NULL, "" } }; diff --git a/contrib/ntp/lib/isc/backtrace.c b/contrib/ntp/lib/isc/backtrace.c new file mode 100644 index 0000000..4274da3 --- /dev/null +++ b/contrib/ntp/lib/isc/backtrace.c @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: backtrace.c,v 1.3 2009/09/02 23:48:02 tbox Exp $ */ + +/*! \file */ + +#include "config.h" + +#include <string.h> +#include <stdlib.h> +#ifdef HAVE_LIBCTRACE +#include <execinfo.h> +#endif + +#include <isc/backtrace.h> +#include <isc/result.h> +#include <isc/util.h> + +#ifdef ISC_PLATFORM_USEBACKTRACE +/* + * Getting a back trace of a running process is tricky and highly platform + * dependent. Our current approach is as follows: + * 1. If the system library supports the "backtrace()" function, use it. + * 2. Otherwise, if the compiler is gcc and the architecture is x86_64 or IA64, + * then use gcc's (hidden) Unwind_Backtrace() function. Note that this + * function doesn't work for C programs on many other architectures. + * 3. Otherwise, if the architecture x86 or x86_64, try to unwind the stack + * frame following frame pointers. This assumes the executable binary + * compiled with frame pointers; this is not always true for x86_64 (rather, + * compiler optimizations often disable frame pointers). The validation + * checks in getnextframeptr() hopefully rejects bogus values stored in + * the RBP register in such a case. If the backtrace function itself crashes + * due to this problem, the whole package should be rebuilt with + * --disable-backtrace. + */ +#ifdef HAVE_LIBCTRACE +#define BACKTRACE_LIBC +#elif defined(__GNUC__) && (defined(__x86_64__) || defined(__ia64__)) +#define BACKTRACE_GCC +#elif defined(__x86_64__) || defined(__i386__) +#define BACKTRACE_X86STACK +#else +#define BACKTRACE_DISABLED +#endif /* HAVE_LIBCTRACE */ +#else /* !ISC_PLATFORM_USEBACKTRACE */ +#define BACKTRACE_DISABLED +#endif /* ISC_PLATFORM_USEBACKTRACE */ + +#ifdef BACKTRACE_LIBC +isc_result_t +isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) { + int n; + + /* + * Validate the arguments: intentionally avoid using REQUIRE(). + * See notes in backtrace.h. + */ + if (addrs == NULL || nframes == NULL) + return (ISC_R_FAILURE); + + /* + * backtrace(3) includes this function itself in the address array, + * which should be eliminated from the returned sequence. + */ + n = backtrace(addrs, maxaddrs); + if (n < 2) + return (ISC_R_NOTFOUND); + n--; + memmove(addrs, &addrs[1], sizeof(void *) * n); + *nframes = n; + return (ISC_R_SUCCESS); +} +#elif defined(BACKTRACE_GCC) +extern int _Unwind_Backtrace(void* fn, void* a); +extern void* _Unwind_GetIP(void* ctx); + +typedef struct { + void **result; + int max_depth; + int skip_count; + int count; +} trace_arg_t; + +static int +btcallback(void *uc, void *opq) { + trace_arg_t *arg = (trace_arg_t *)opq; + + if (arg->skip_count > 0) + arg->skip_count--; + else + arg->result[arg->count++] = (void *)_Unwind_GetIP(uc); + if (arg->count == arg->max_depth) + return (5); /* _URC_END_OF_STACK */ + + return (0); /* _URC_NO_REASON */ +} + +isc_result_t +isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) { + trace_arg_t arg; + + /* Argument validation: see above. */ + if (addrs == NULL || nframes == NULL) + return (ISC_R_FAILURE); + + arg.skip_count = 1; + arg.result = addrs; + arg.max_depth = maxaddrs; + arg.count = 0; + _Unwind_Backtrace(btcallback, &arg); + + *nframes = arg.count; + + return (ISC_R_SUCCESS); +} +#elif defined(BACKTRACE_X86STACK) +#ifdef __x86_64__ +static unsigned long +getrbp() { + __asm("movq %rbp, %rax\n"); +} +#endif + +static void ** +getnextframeptr(void **sp) { + void **newsp = (void **)*sp; + + /* + * Perform sanity check for the new frame pointer, derived from + * google glog. This can actually be bogus depending on compiler. + */ + + /* prohibit the stack frames from growing downwards */ + if (newsp <= sp) + return (NULL); + + /* A heuristics to reject "too large" frame: this actually happened. */ + if ((char *)newsp - (char *)sp > 100000) + return (NULL); + + /* + * Not sure if other checks used in glog are needed at this moment. + * For our purposes we don't have to consider non-contiguous frames, + * for example. + */ + + return (newsp); +} + +isc_result_t +isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) { + int i = 0; + void **sp; + + /* Argument validation: see above. */ + if (addrs == NULL || nframes == NULL) + return (ISC_R_FAILURE); + +#ifdef __x86_64__ + sp = (void **)getrbp(); + if (sp == NULL) + return (ISC_R_NOTFOUND); + /* + * sp is the frame ptr of this function itself due to the call to + * getrbp(), so need to unwind one frame for consistency. + */ + sp = getnextframeptr(sp); +#else + /* + * i386: the frame pointer is stored 2 words below the address for the + * first argument. Note that the body of this function cannot be + * inlined since it depends on the address of the function argument. + */ + sp = (void **)&addrs - 2; +#endif + + while (sp != NULL && i < maxaddrs) { + addrs[i++] = *(sp + 1); + sp = getnextframeptr(sp); + } + + *nframes = i; + + return (ISC_R_SUCCESS); +} +#elif defined(BACKTRACE_DISABLED) +isc_result_t +isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes) { + /* Argument validation: see above. */ + if (addrs == NULL || nframes == NULL) + return (ISC_R_FAILURE); + + UNUSED(maxaddrs); + + return (ISC_R_NOTIMPLEMENTED); +} +#endif + +isc_result_t +isc_backtrace_getsymbolfromindex(int idx, const void **addrp, + const char **symbolp) +{ + REQUIRE(addrp != NULL && *addrp == NULL); + REQUIRE(symbolp != NULL && *symbolp == NULL); + + if (idx < 0 || idx >= isc__backtrace_nsymbols) + return (ISC_R_RANGE); + + *addrp = isc__backtrace_symtable[idx].addr; + *symbolp = isc__backtrace_symtable[idx].symbol; + return (ISC_R_SUCCESS); +} + +static int +symtbl_compare(const void *addr, const void *entryarg) { + const isc_backtrace_symmap_t *entry = entryarg; + const isc_backtrace_symmap_t *end = + &isc__backtrace_symtable[isc__backtrace_nsymbols - 1]; + + if (isc__backtrace_nsymbols == 1 || entry == end) { + if (addr >= entry->addr) { + /* + * If addr is equal to or larger than that of the last + * entry of the table, we cannot be sure if this is + * within a valid range so we consider it valid. + */ + return (0); + } + return (-1); + } + + /* entry + 1 is a valid entry from now on. */ + if (addr < entry->addr) + return (-1); + else if (addr >= (entry + 1)->addr) + return (1); + return (0); +} + +isc_result_t +isc_backtrace_getsymbol(const void *addr, const char **symbolp, + unsigned long *offsetp) +{ + isc_result_t result = ISC_R_SUCCESS; + isc_backtrace_symmap_t *found; + + /* + * Validate the arguments: intentionally avoid using REQUIRE(). + * See notes in backtrace.h. + */ + if (symbolp == NULL || *symbolp != NULL || offsetp == NULL) + return (ISC_R_FAILURE); + + if (isc__backtrace_nsymbols < 1) + return (ISC_R_NOTFOUND); + + /* + * Search the table for the entry that meets: + * entry.addr <= addr < next_entry.addr. + */ + found = bsearch(addr, isc__backtrace_symtable, isc__backtrace_nsymbols, + sizeof(isc__backtrace_symtable[0]), symtbl_compare); + if (found == NULL) + result = ISC_R_NOTFOUND; + else { + *symbolp = found->symbol; + *offsetp = (const char *)addr - (char *)found->addr; + } + + return (result); +} diff --git a/contrib/ntp/lib/isc/base32.c b/contrib/ntp/lib/isc/base32.c new file mode 100644 index 0000000..d25e3c4 --- /dev/null +++ b/contrib/ntp/lib/isc/base32.c @@ -0,0 +1,373 @@ +/* + * Copyright (C) 2008, 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: base32.c,v 1.6 2009/10/21 01:22:29 each Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <isc/base32.h> +#include <isc/buffer.h> +#include <isc/lex.h> +#include <isc/region.h> +#include <isc/string.h> +#include <isc/util.h> + +#define RETERR(x) do { \ + isc_result_t _r = (x); \ + if (_r != ISC_R_SUCCESS) \ + return (_r); \ + } while (0) + + +/*@{*/ +/*! + * These static functions are also present in lib/dns/rdata.c. I'm not + * sure where they should go. -- bwelling + */ +static isc_result_t +str_totext(const char *source, isc_buffer_t *target); + +static isc_result_t +mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length); + +/*@}*/ + +static const char base32[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=abcdefghijklmnopqrstuvwxyz234567"; +static const char base32hex[] = + "0123456789ABCDEFGHIJKLMNOPQRSTUV=0123456789abcdefghijklmnopqrstuv"; + +static isc_result_t +base32_totext(isc_region_t *source, int wordlength, const char *wordbreak, + isc_buffer_t *target, const char base[]) +{ + char buf[9]; + unsigned int loops = 0; + + if (wordlength >= 0 && wordlength < 8) + wordlength = 8; + + memset(buf, 0, sizeof(buf)); + while (source->length > 0) { + buf[0] = base[((source->base[0]>>3)&0x1f)]; /* 5 + */ + if (source->length == 1) { + buf[1] = base[(source->base[0]<<2)&0x1c]; + buf[2] = buf[3] = buf[4] = '='; + buf[5] = buf[6] = buf[7] = '='; + RETERR(str_totext(buf, target)); + break; + } + buf[1] = base[((source->base[0]<<2)&0x1c)| /* 3 = 8 */ + ((source->base[1]>>6)&0x03)]; /* 2 + */ + buf[2] = base[((source->base[1]>>1)&0x1f)]; /* 5 + */ + if (source->length == 2) { + buf[3] = base[(source->base[1]<<4)&0x10]; + buf[4] = buf[5] = buf[6] = buf[7] = '='; + RETERR(str_totext(buf, target)); + break; + } + buf[3] = base[((source->base[1]<<4)&0x10)| /* 1 = 8 */ + ((source->base[2]>>4)&0x0f)]; /* 4 + */ + if (source->length == 3) { + buf[4] = base[(source->base[2]<<1)&0x1e]; + buf[5] = buf[6] = buf[7] = '='; + RETERR(str_totext(buf, target)); + break; + } + buf[4] = base[((source->base[2]<<1)&0x1e)| /* 4 = 8 */ + ((source->base[3]>>7)&0x01)]; /* 1 + */ + buf[5] = base[((source->base[3]>>2)&0x1f)]; /* 5 + */ + if (source->length == 4) { + buf[6] = base[(source->base[3]<<3)&0x18]; + buf[7] = '='; + RETERR(str_totext(buf, target)); + break; + } + buf[6] = base[((source->base[3]<<3)&0x18)| /* 2 = 8 */ + ((source->base[4]>>5)&0x07)]; /* 3 + */ + buf[7] = base[source->base[4]&0x1f]; /* 5 = 8 */ + RETERR(str_totext(buf, target)); + isc_region_consume(source, 5); + + loops++; + if (source->length != 0 && wordlength >= 0 && + (int)((loops + 1) * 8) >= wordlength) + { + loops = 0; + RETERR(str_totext(wordbreak, target)); + } + } + if (source->length > 0) + isc_region_consume(source, source->length); + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_base32_totext(isc_region_t *source, int wordlength, + const char *wordbreak, isc_buffer_t *target) +{ + return (base32_totext(source, wordlength, wordbreak, target, base32)); +} + +isc_result_t +isc_base32hex_totext(isc_region_t *source, int wordlength, + const char *wordbreak, isc_buffer_t *target) +{ + return (base32_totext(source, wordlength, wordbreak, target, + base32hex)); +} + +/*% + * State of a base32 decoding process in progress. + */ +typedef struct { + int length; /*%< Desired length of binary data or -1 */ + isc_buffer_t *target; /*%< Buffer for resulting binary data */ + int digits; /*%< Number of buffered base32 digits */ + isc_boolean_t seen_end; /*%< True if "=" end marker seen */ + int val[8]; + const char *base; /*%< Which encoding we are using */ + int seen_32; /*%< Number of significant bytes if non zero */ +} base32_decode_ctx_t; + +static inline void +base32_decode_init(base32_decode_ctx_t *ctx, int length, + const char base[], isc_buffer_t *target) +{ + ctx->digits = 0; + ctx->seen_end = ISC_FALSE; + ctx->seen_32 = 0; + ctx->length = length; + ctx->target = target; + ctx->base = base; +} + +static inline isc_result_t +base32_decode_char(base32_decode_ctx_t *ctx, int c) { + char *s; + unsigned int last; + + if (ctx->seen_end) + return (ISC_R_BADBASE32); + if ((s = strchr(ctx->base, c)) == NULL) + return (ISC_R_BADBASE32); + last = s - ctx->base; + /* + * Handle lower case. + */ + if (last > 32) + last -= 33; + /* + * Check that padding is contiguous. + */ + if (last != 32 && ctx->seen_32 != 0) + return (ISC_R_BADBASE32); + /* + * Check that padding starts at the right place and that + * bits that should be zero are. + * Record how many significant bytes in answer (seen_32). + */ + if (last == 32 && ctx->seen_32 == 0) + switch (ctx->digits) { + case 0: + case 1: + return (ISC_R_BADBASE32); + case 2: + if ((ctx->val[1]&0x03) != 0) + return (ISC_R_BADBASE32); + ctx->seen_32 = 1; + break; + case 3: + return (ISC_R_BADBASE32); + case 4: + if ((ctx->val[3]&0x0f) != 0) + return (ISC_R_BADBASE32); + ctx->seen_32 = 3; + break; + case 5: + if ((ctx->val[4]&0x01) != 0) + return (ISC_R_BADBASE32); + ctx->seen_32 = 3; + break; + case 6: + return (ISC_R_BADBASE32); + case 7: + if ((ctx->val[6]&0x07) != 0) + return (ISC_R_BADBASE32); + ctx->seen_32 = 4; + break; + } + /* + * Zero fill pad values. + */ + ctx->val[ctx->digits++] = (last == 32) ? 0 : last; + + if (ctx->digits == 8) { + int n = 5; + unsigned char buf[5]; + + if (ctx->seen_32 != 0) { + ctx->seen_end = ISC_TRUE; + n = ctx->seen_32; + } + buf[0] = (ctx->val[0]<<3)|(ctx->val[1]>>2); + buf[1] = (ctx->val[1]<<6)|(ctx->val[2]<<1)|(ctx->val[3]>>4); + buf[2] = (ctx->val[3]<<4)|(ctx->val[4]>>1); + buf[3] = (ctx->val[4]<<7)|(ctx->val[5]<<2)|(ctx->val[6]>>3); + buf[4] = (ctx->val[6]<<5)|(ctx->val[7]); + RETERR(mem_tobuffer(ctx->target, buf, n)); + if (ctx->length >= 0) { + if (n > ctx->length) + return (ISC_R_BADBASE32); + else + ctx->length -= n; + } + ctx->digits = 0; + } + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +base32_decode_finish(base32_decode_ctx_t *ctx) { + if (ctx->length > 0) + return (ISC_R_UNEXPECTEDEND); + if (ctx->digits != 0) + return (ISC_R_BADBASE32); + return (ISC_R_SUCCESS); +} + +static isc_result_t +base32_tobuffer(isc_lex_t *lexer, const char base[], isc_buffer_t *target, + int length) +{ + base32_decode_ctx_t ctx; + isc_textregion_t *tr; + isc_token_t token; + isc_boolean_t eol; + + base32_decode_init(&ctx, length, base, target); + + while (!ctx.seen_end && (ctx.length != 0)) { + unsigned int i; + + if (length > 0) + eol = ISC_FALSE; + else + eol = ISC_TRUE; + RETERR(isc_lex_getmastertoken(lexer, &token, + isc_tokentype_string, eol)); + if (token.type != isc_tokentype_string) + break; + tr = &token.value.as_textregion; + for (i = 0; i < tr->length; i++) + RETERR(base32_decode_char(&ctx, tr->base[i])); + } + if (ctx.length < 0 && !ctx.seen_end) + isc_lex_ungettoken(lexer, &token); + RETERR(base32_decode_finish(&ctx)); + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_base32_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) { + return (base32_tobuffer(lexer, base32, target, length)); +} + +isc_result_t +isc_base32hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) { + return (base32_tobuffer(lexer, base32hex, target, length)); +} + +static isc_result_t +base32_decodestring(const char *cstr, const char base[], isc_buffer_t *target) { + base32_decode_ctx_t ctx; + + base32_decode_init(&ctx, -1, base, target); + for (;;) { + int c = *cstr++; + if (c == '\0') + break; + if (c == ' ' || c == '\t' || c == '\n' || c== '\r') + continue; + RETERR(base32_decode_char(&ctx, c)); + } + RETERR(base32_decode_finish(&ctx)); + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_base32_decodestring(const char *cstr, isc_buffer_t *target) { + return (base32_decodestring(cstr, base32, target)); +} + +isc_result_t +isc_base32hex_decodestring(const char *cstr, isc_buffer_t *target) { + return (base32_decodestring(cstr, base32hex, target)); +} + +static isc_result_t +base32_decoderegion(isc_region_t *source, const char base[], isc_buffer_t *target) { + base32_decode_ctx_t ctx; + + base32_decode_init(&ctx, -1, base, target); + while (source->length != 0) { + int c = *source->base; + RETERR(base32_decode_char(&ctx, c)); + isc_region_consume(source, 1); + } + RETERR(base32_decode_finish(&ctx)); + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_base32_decoderegion(isc_region_t *source, isc_buffer_t *target) { + return (base32_decoderegion(source, base32, target)); +} + +isc_result_t +isc_base32hex_decoderegion(isc_region_t *source, isc_buffer_t *target) { + return (base32_decoderegion(source, base32hex, target)); +} + +static isc_result_t +str_totext(const char *source, isc_buffer_t *target) { + unsigned int l; + isc_region_t region; + + isc_buffer_availableregion(target, ®ion); + l = strlen(source); + + if (l > region.length) + return (ISC_R_NOSPACE); + + memcpy(region.base, source, l); + isc_buffer_add(target, l); + return (ISC_R_SUCCESS); +} + +static isc_result_t +mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) { + isc_region_t tr; + + isc_buffer_availableregion(target, &tr); + if (length > tr.length) + return (ISC_R_NOSPACE); + memcpy(tr.base, base, length); + isc_buffer_add(target, length); + return (ISC_R_SUCCESS); +} diff --git a/contrib/ntp/lib/isc/base64.c b/contrib/ntp/lib/isc/base64.c new file mode 100644 index 0000000..bad1565 --- /dev/null +++ b/contrib/ntp/lib/isc/base64.c @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2001, 2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: base64.c,v 1.34 2009/10/21 23:48:05 tbox Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <isc/base64.h> +#include <isc/buffer.h> +#include <isc/lex.h> +#include <isc/string.h> +#include <isc/util.h> + +#define RETERR(x) do { \ + isc_result_t _r = (x); \ + if (_r != ISC_R_SUCCESS) \ + return (_r); \ + } while (0) + + +/*@{*/ +/*! + * These static functions are also present in lib/dns/rdata.c. I'm not + * sure where they should go. -- bwelling + */ +static isc_result_t +str_totext(const char *source, isc_buffer_t *target); + +static isc_result_t +mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length); + +static const char base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; +/*@}*/ + +isc_result_t +isc_base64_totext(isc_region_t *source, int wordlength, + const char *wordbreak, isc_buffer_t *target) +{ + char buf[5]; + unsigned int loops = 0; + + if (wordlength < 4) + wordlength = 4; + + memset(buf, 0, sizeof(buf)); + while (source->length > 2) { + buf[0] = base64[(source->base[0]>>2)&0x3f]; + buf[1] = base64[((source->base[0]<<4)&0x30)| + ((source->base[1]>>4)&0x0f)]; + buf[2] = base64[((source->base[1]<<2)&0x3c)| + ((source->base[2]>>6)&0x03)]; + buf[3] = base64[source->base[2]&0x3f]; + RETERR(str_totext(buf, target)); + isc_region_consume(source, 3); + + loops++; + if (source->length != 0 && + (int)((loops + 1) * 4) >= wordlength) + { + loops = 0; + RETERR(str_totext(wordbreak, target)); + } + } + if (source->length == 2) { + buf[0] = base64[(source->base[0]>>2)&0x3f]; + buf[1] = base64[((source->base[0]<<4)&0x30)| + ((source->base[1]>>4)&0x0f)]; + buf[2] = base64[((source->base[1]<<2)&0x3c)]; + buf[3] = '='; + RETERR(str_totext(buf, target)); + isc_region_consume(source, 2); + } else if (source->length == 1) { + buf[0] = base64[(source->base[0]>>2)&0x3f]; + buf[1] = base64[((source->base[0]<<4)&0x30)]; + buf[2] = buf[3] = '='; + RETERR(str_totext(buf, target)); + isc_region_consume(source, 1); + } + return (ISC_R_SUCCESS); +} + +/*% + * State of a base64 decoding process in progress. + */ +typedef struct { + int length; /*%< Desired length of binary data or -1 */ + isc_buffer_t *target; /*%< Buffer for resulting binary data */ + int digits; /*%< Number of buffered base64 digits */ + isc_boolean_t seen_end; /*%< True if "=" end marker seen */ + int val[4]; +} base64_decode_ctx_t; + +static inline void +base64_decode_init(base64_decode_ctx_t *ctx, int length, isc_buffer_t *target) +{ + ctx->digits = 0; + ctx->seen_end = ISC_FALSE; + ctx->length = length; + ctx->target = target; +} + +static inline isc_result_t +base64_decode_char(base64_decode_ctx_t *ctx, int c) { + char *s; + + if (ctx->seen_end) + return (ISC_R_BADBASE64); + if ((s = strchr(base64, c)) == NULL) + return (ISC_R_BADBASE64); + ctx->val[ctx->digits++] = s - base64; + if (ctx->digits == 4) { + int n; + unsigned char buf[3]; + if (ctx->val[0] == 64 || ctx->val[1] == 64) + return (ISC_R_BADBASE64); + if (ctx->val[2] == 64 && ctx->val[3] != 64) + return (ISC_R_BADBASE64); + /* + * Check that bits that should be zero are. + */ + if (ctx->val[2] == 64 && (ctx->val[1] & 0xf) != 0) + return (ISC_R_BADBASE64); + /* + * We don't need to test for ctx->val[2] != 64 as + * the bottom two bits of 64 are zero. + */ + if (ctx->val[3] == 64 && (ctx->val[2] & 0x3) != 0) + return (ISC_R_BADBASE64); + n = (ctx->val[2] == 64) ? 1 : + (ctx->val[3] == 64) ? 2 : 3; + if (n != 3) { + ctx->seen_end = ISC_TRUE; + if (ctx->val[2] == 64) + ctx->val[2] = 0; + if (ctx->val[3] == 64) + ctx->val[3] = 0; + } + buf[0] = (ctx->val[0]<<2)|(ctx->val[1]>>4); + buf[1] = (ctx->val[1]<<4)|(ctx->val[2]>>2); + buf[2] = (ctx->val[2]<<6)|(ctx->val[3]); + RETERR(mem_tobuffer(ctx->target, buf, n)); + if (ctx->length >= 0) { + if (n > ctx->length) + return (ISC_R_BADBASE64); + else + ctx->length -= n; + } + ctx->digits = 0; + } + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +base64_decode_finish(base64_decode_ctx_t *ctx) { + if (ctx->length > 0) + return (ISC_R_UNEXPECTEDEND); + if (ctx->digits != 0) + return (ISC_R_BADBASE64); + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_base64_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) { + base64_decode_ctx_t ctx; + isc_textregion_t *tr; + isc_token_t token; + isc_boolean_t eol; + + base64_decode_init(&ctx, length, target); + + while (!ctx.seen_end && (ctx.length != 0)) { + unsigned int i; + + if (length > 0) + eol = ISC_FALSE; + else + eol = ISC_TRUE; + RETERR(isc_lex_getmastertoken(lexer, &token, + isc_tokentype_string, eol)); + if (token.type != isc_tokentype_string) + break; + tr = &token.value.as_textregion; + for (i = 0; i < tr->length; i++) + RETERR(base64_decode_char(&ctx, tr->base[i])); + } + if (ctx.length < 0 && !ctx.seen_end) + isc_lex_ungettoken(lexer, &token); + RETERR(base64_decode_finish(&ctx)); + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_base64_decodestring(const char *cstr, isc_buffer_t *target) { + base64_decode_ctx_t ctx; + + base64_decode_init(&ctx, -1, target); + for (;;) { + int c = *cstr++; + if (c == '\0') + break; + if (c == ' ' || c == '\t' || c == '\n' || c== '\r') + continue; + RETERR(base64_decode_char(&ctx, c)); + } + RETERR(base64_decode_finish(&ctx)); + return (ISC_R_SUCCESS); +} + +static isc_result_t +str_totext(const char *source, isc_buffer_t *target) { + unsigned int l; + isc_region_t region; + + isc_buffer_availableregion(target, ®ion); + l = strlen(source); + + if (l > region.length) + return (ISC_R_NOSPACE); + + memcpy(region.base, source, l); + isc_buffer_add(target, l); + return (ISC_R_SUCCESS); +} + +static isc_result_t +mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) { + isc_region_t tr; + + isc_buffer_availableregion(target, &tr); + if (length > tr.length) + return (ISC_R_NOSPACE); + memcpy(tr.base, base, length); + isc_buffer_add(target, length); + return (ISC_R_SUCCESS); +} diff --git a/contrib/ntp/lib/isc/bitstring.c b/contrib/ntp/lib/isc/bitstring.c new file mode 100644 index 0000000..33c7c1f --- /dev/null +++ b/contrib/ntp/lib/isc/bitstring.c @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: bitstring.c,v 1.17 2007/06/19 23:47:17 tbox Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <stddef.h> + +#include <isc/magic.h> +#include <isc/bitstring.h> +#include <isc/util.h> + +#define DIV8(x) ((x) >> 3) +#define MOD8(x) ((x) & 0x00000007U) +#define OCTETS(n) (((n) + 7) >> 3) +#define PADDED(n) ((((n) + 7) >> 3) << 3) +#define BITSET(bs, n) (((bs)->data[DIV8(n)] & \ + (1 << (7 - MOD8(n)))) != 0) +#define SETBIT(bs, n) (bs)->data[DIV8(n)] |= (1 << (7 - MOD8(n))) +#define CLEARBIT(bs, n) (bs)->data[DIV8(n)] &= ~(1 << (7 - MOD8(n))) + +#define BITSTRING_MAGIC ISC_MAGIC('B', 'S', 't', 'r') +#define VALID_BITSTRING(b) ISC_MAGIC_VALID(b, BITSTRING_MAGIC) + +void +isc_bitstring_init(isc_bitstring_t *bitstring, unsigned char *data, + unsigned int length, unsigned int size, isc_boolean_t lsb0) +{ + /* + * Make 'bitstring' refer to the bitstring of 'size' bits starting + * at 'data'. 'length' bits of the bitstring are valid. If 'lsb0' + * is set then, bit 0 refers to the least significant bit of the + * bitstring. Otherwise bit 0 is the most significant bit. + */ + + REQUIRE(bitstring != NULL); + REQUIRE(data != NULL); + REQUIRE(length <= size); + + bitstring->magic = BITSTRING_MAGIC; + bitstring->data = data; + bitstring->length = length; + bitstring->size = size; + bitstring->lsb0 = lsb0; +} + +void +isc_bitstring_invalidate(isc_bitstring_t *bitstring) { + + /* + * Invalidate 'bitstring'. + */ + + REQUIRE(VALID_BITSTRING(bitstring)); + + bitstring->magic = 0; + bitstring->data = NULL; + bitstring->length = 0; + bitstring->size = 0; + bitstring->lsb0 = ISC_FALSE; +} + +void +isc_bitstring_copy(isc_bitstring_t *source, unsigned int sbitpos, + isc_bitstring_t *target, unsigned int tbitpos, + unsigned int n) +{ + unsigned int tlast; + + /* + * Starting at bit 'sbitpos', copy 'n' bits from 'source' to + * the 'n' bits of 'target' starting at 'tbitpos'. + */ + + REQUIRE(VALID_BITSTRING(source)); + REQUIRE(VALID_BITSTRING(target)); + REQUIRE(source->lsb0 == target->lsb0); + if (source->lsb0) { + REQUIRE(sbitpos <= source->length); + sbitpos = PADDED(source->size) - sbitpos; + REQUIRE(sbitpos >= n); + sbitpos -= n; + } else + REQUIRE(sbitpos + n <= source->length); + tlast = tbitpos + n; + if (target->lsb0) { + REQUIRE(tbitpos <= target->length); + tbitpos = PADDED(target->size) - tbitpos; + REQUIRE(tbitpos >= n); + tbitpos -= n; + } else + REQUIRE(tlast <= target->size); + + if (tlast > target->length) + target->length = tlast; + + /* + * This is far from optimal... + */ + + while (n > 0) { + if (BITSET(source, sbitpos)) + SETBIT(target, tbitpos); + else + CLEARBIT(target, tbitpos); + sbitpos++; + tbitpos++; + n--; + } +} diff --git a/contrib/ntp/lib/isc/buffer.c b/contrib/ntp/lib/isc/buffer.c new file mode 100644 index 0000000..1b59e65 --- /dev/null +++ b/contrib/ntp/lib/isc/buffer.c @@ -0,0 +1,489 @@ +/* + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: buffer.c,v 1.49 2008/09/25 04:02:39 tbox Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <isc/buffer.h> +#include <isc/mem.h> +#include <isc/region.h> +#include <isc/string.h> +#include <isc/util.h> + +void +isc__buffer_init(isc_buffer_t *b, const void *base, unsigned int length) { + /* + * Make 'b' refer to the 'length'-byte region starting at 'base'. + * XXXDCL see the comment in buffer.h about base being const. + */ + + REQUIRE(b != NULL); + + ISC__BUFFER_INIT(b, base, length); +} + +void +isc__buffer_initnull(isc_buffer_t *b) { + /* + * Initialize a new buffer which has no backing store. This can + * later be grown as needed and swapped in place. + */ + + ISC__BUFFER_INIT(b, NULL, 0); +} + +void +isc_buffer_reinit(isc_buffer_t *b, void *base, unsigned int length) { + /* + * Re-initialize the buffer enough to reconfigure the base of the + * buffer. We will swap in the new buffer, after copying any + * data we contain into the new buffer and adjusting all of our + * internal pointers. + * + * The buffer must not be smaller than the length of the original + * buffer. + */ + REQUIRE(b->length <= length); + REQUIRE(base != NULL); + + (void)memmove(base, b->base, b->length); + b->base = base; + b->length = length; +} + +void +isc__buffer_invalidate(isc_buffer_t *b) { + /* + * Make 'b' an invalid buffer. + */ + + REQUIRE(ISC_BUFFER_VALID(b)); + REQUIRE(!ISC_LINK_LINKED(b, link)); + REQUIRE(b->mctx == NULL); + + ISC__BUFFER_INVALIDATE(b); +} + +void +isc__buffer_region(isc_buffer_t *b, isc_region_t *r) { + /* + * Make 'r' refer to the region of 'b'. + */ + + REQUIRE(ISC_BUFFER_VALID(b)); + REQUIRE(r != NULL); + + ISC__BUFFER_REGION(b, r); +} + +void +isc__buffer_usedregion(isc_buffer_t *b, isc_region_t *r) { + /* + * Make 'r' refer to the used region of 'b'. + */ + + REQUIRE(ISC_BUFFER_VALID(b)); + REQUIRE(r != NULL); + + ISC__BUFFER_USEDREGION(b, r); +} + +void +isc__buffer_availableregion(isc_buffer_t *b, isc_region_t *r) { + /* + * Make 'r' refer to the available region of 'b'. + */ + + REQUIRE(ISC_BUFFER_VALID(b)); + REQUIRE(r != NULL); + + ISC__BUFFER_AVAILABLEREGION(b, r); +} + +void +isc__buffer_add(isc_buffer_t *b, unsigned int n) { + /* + * Increase the 'used' region of 'b' by 'n' bytes. + */ + + REQUIRE(ISC_BUFFER_VALID(b)); + REQUIRE(b->used + n <= b->length); + + ISC__BUFFER_ADD(b, n); +} + +void +isc__buffer_subtract(isc_buffer_t *b, unsigned int n) { + /* + * Decrease the 'used' region of 'b' by 'n' bytes. + */ + + REQUIRE(ISC_BUFFER_VALID(b)); + REQUIRE(b->used >= n); + + ISC__BUFFER_SUBTRACT(b, n); +} + +void +isc__buffer_clear(isc_buffer_t *b) { + /* + * Make the used region empty. + */ + + REQUIRE(ISC_BUFFER_VALID(b)); + + ISC__BUFFER_CLEAR(b); +} + +void +isc__buffer_consumedregion(isc_buffer_t *b, isc_region_t *r) { + /* + * Make 'r' refer to the consumed region of 'b'. + */ + + REQUIRE(ISC_BUFFER_VALID(b)); + REQUIRE(r != NULL); + + ISC__BUFFER_CONSUMEDREGION(b, r); +} + +void +isc__buffer_remainingregion(isc_buffer_t *b, isc_region_t *r) { + /* + * Make 'r' refer to the remaining region of 'b'. + */ + + REQUIRE(ISC_BUFFER_VALID(b)); + REQUIRE(r != NULL); + + ISC__BUFFER_REMAININGREGION(b, r); +} + +void +isc__buffer_activeregion(isc_buffer_t *b, isc_region_t *r) { + /* + * Make 'r' refer to the active region of 'b'. + */ + + REQUIRE(ISC_BUFFER_VALID(b)); + REQUIRE(r != NULL); + + ISC__BUFFER_ACTIVEREGION(b, r); +} + +void +isc__buffer_setactive(isc_buffer_t *b, unsigned int n) { + /* + * Sets the end of the active region 'n' bytes after current. + */ + + REQUIRE(ISC_BUFFER_VALID(b)); + REQUIRE(b->current + n <= b->used); + + ISC__BUFFER_SETACTIVE(b, n); +} + +void +isc__buffer_first(isc_buffer_t *b) { + /* + * Make the consumed region empty. + */ + + REQUIRE(ISC_BUFFER_VALID(b)); + + ISC__BUFFER_FIRST(b); +} + +void +isc__buffer_forward(isc_buffer_t *b, unsigned int n) { + /* + * Increase the 'consumed' region of 'b' by 'n' bytes. + */ + + REQUIRE(ISC_BUFFER_VALID(b)); + REQUIRE(b->current + n <= b->used); + + ISC__BUFFER_FORWARD(b, n); +} + +void +isc__buffer_back(isc_buffer_t *b, unsigned int n) { + /* + * Decrease the 'consumed' region of 'b' by 'n' bytes. + */ + + REQUIRE(ISC_BUFFER_VALID(b)); + REQUIRE(n <= b->current); + + ISC__BUFFER_BACK(b, n); +} + +void +isc_buffer_compact(isc_buffer_t *b) { + unsigned int length; + void *src; + + /* + * Compact the used region by moving the remaining region so it occurs + * at the start of the buffer. The used region is shrunk by the size + * of the consumed region, and the consumed region is then made empty. + */ + + REQUIRE(ISC_BUFFER_VALID(b)); + + src = isc_buffer_current(b); + length = isc_buffer_remaininglength(b); + (void)memmove(b->base, src, (size_t)length); + + if (b->active > b->current) + b->active -= b->current; + else + b->active = 0; + b->current = 0; + b->used = length; +} + +isc_uint8_t +isc_buffer_getuint8(isc_buffer_t *b) { + unsigned char *cp; + isc_uint8_t result; + + /* + * Read an unsigned 8-bit integer from 'b' and return it. + */ + + REQUIRE(ISC_BUFFER_VALID(b)); + REQUIRE(b->used - b->current >= 1); + + cp = isc_buffer_current(b); + b->current += 1; + result = ((isc_uint8_t)(cp[0])); + + return (result); +} + +void +isc__buffer_putuint8(isc_buffer_t *b, isc_uint8_t val) { + REQUIRE(ISC_BUFFER_VALID(b)); + REQUIRE(b->used + 1 <= b->length); + + ISC__BUFFER_PUTUINT8(b, val); +} + +isc_uint16_t +isc_buffer_getuint16(isc_buffer_t *b) { + unsigned char *cp; + isc_uint16_t result; + + /* + * Read an unsigned 16-bit integer in network byte order from 'b', + * convert it to host byte order, and return it. + */ + + REQUIRE(ISC_BUFFER_VALID(b)); + REQUIRE(b->used - b->current >= 2); + + cp = isc_buffer_current(b); + b->current += 2; + result = ((unsigned int)(cp[0])) << 8; + result |= ((unsigned int)(cp[1])); + + return (result); +} + +void +isc__buffer_putuint16(isc_buffer_t *b, isc_uint16_t val) { + REQUIRE(ISC_BUFFER_VALID(b)); + REQUIRE(b->used + 2 <= b->length); + + ISC__BUFFER_PUTUINT16(b, val); +} + +void +isc__buffer_putuint24(isc_buffer_t *b, isc_uint32_t val) { + REQUIRE(ISC_BUFFER_VALID(b)); + REQUIRE(b->used + 3 <= b->length); + + ISC__BUFFER_PUTUINT24(b, val); +} + +isc_uint32_t +isc_buffer_getuint32(isc_buffer_t *b) { + unsigned char *cp; + isc_uint32_t result; + + /* + * Read an unsigned 32-bit integer in network byte order from 'b', + * convert it to host byte order, and return it. + */ + + REQUIRE(ISC_BUFFER_VALID(b)); + REQUIRE(b->used - b->current >= 4); + + cp = isc_buffer_current(b); + b->current += 4; + result = ((unsigned int)(cp[0])) << 24; + result |= ((unsigned int)(cp[1])) << 16; + result |= ((unsigned int)(cp[2])) << 8; + result |= ((unsigned int)(cp[3])); + + return (result); +} + +void +isc__buffer_putuint32(isc_buffer_t *b, isc_uint32_t val) { + REQUIRE(ISC_BUFFER_VALID(b)); + REQUIRE(b->used + 4 <= b->length); + + ISC__BUFFER_PUTUINT32(b, val); +} + +isc_uint64_t +isc_buffer_getuint48(isc_buffer_t *b) { + unsigned char *cp; + isc_uint64_t result; + + /* + * Read an unsigned 48-bit integer in network byte order from 'b', + * convert it to host byte order, and return it. + */ + + REQUIRE(ISC_BUFFER_VALID(b)); + REQUIRE(b->used - b->current >= 6); + + cp = isc_buffer_current(b); + b->current += 6; + result = ((isc_int64_t)(cp[0])) << 40; + result |= ((isc_int64_t)(cp[1])) << 32; + result |= ((isc_int64_t)(cp[2])) << 24; + result |= ((isc_int64_t)(cp[3])) << 16; + result |= ((isc_int64_t)(cp[4])) << 8; + result |= ((isc_int64_t)(cp[5])); + + return (result); +} + +void +isc__buffer_putuint48(isc_buffer_t *b, isc_uint64_t val) { + isc_uint16_t valhi; + isc_uint32_t vallo; + + REQUIRE(ISC_BUFFER_VALID(b)); + REQUIRE(b->used + 6 <= b->length); + + valhi = (isc_uint16_t)(val >> 32); + vallo = (isc_uint32_t)(val & 0xFFFFFFFF); + ISC__BUFFER_PUTUINT16(b, valhi); + ISC__BUFFER_PUTUINT32(b, vallo); +} + +void +isc__buffer_putmem(isc_buffer_t *b, const unsigned char *base, + unsigned int length) +{ + REQUIRE(ISC_BUFFER_VALID(b)); + REQUIRE(b->used + length <= b->length); + + ISC__BUFFER_PUTMEM(b, base, length); +} + +void +isc__buffer_putstr(isc_buffer_t *b, const char *source) { + unsigned int l; + unsigned char *cp; + + REQUIRE(ISC_BUFFER_VALID(b)); + REQUIRE(source != NULL); + + /* + * Do not use ISC__BUFFER_PUTSTR(), so strlen is only done once. + */ + l = strlen(source); + + REQUIRE(l <= isc_buffer_availablelength(b)); + + cp = isc_buffer_used(b); + memcpy(cp, source, l); + b->used += l; +} + +isc_result_t +isc_buffer_copyregion(isc_buffer_t *b, const isc_region_t *r) { + unsigned char *base; + unsigned int available; + + REQUIRE(ISC_BUFFER_VALID(b)); + REQUIRE(r != NULL); + + /* + * XXXDCL + */ + base = isc_buffer_used(b); + available = isc_buffer_availablelength(b); + if (r->length > available) + return (ISC_R_NOSPACE); + memcpy(base, r->base, r->length); + b->used += r->length; + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_buffer_allocate(isc_mem_t *mctx, isc_buffer_t **dynbuffer, + unsigned int length) +{ + isc_buffer_t *dbuf; + + REQUIRE(dynbuffer != NULL); + REQUIRE(*dynbuffer == NULL); + + dbuf = isc_mem_get(mctx, length + sizeof(isc_buffer_t)); + if (dbuf == NULL) + return (ISC_R_NOMEMORY); + + isc_buffer_init(dbuf, ((unsigned char *)dbuf) + sizeof(isc_buffer_t), + length); + dbuf->mctx = mctx; + + *dynbuffer = dbuf; + + return (ISC_R_SUCCESS); +} + +void +isc_buffer_free(isc_buffer_t **dynbuffer) { + unsigned int real_length; + isc_buffer_t *dbuf; + isc_mem_t *mctx; + + REQUIRE(dynbuffer != NULL); + REQUIRE(ISC_BUFFER_VALID(*dynbuffer)); + REQUIRE((*dynbuffer)->mctx != NULL); + + dbuf = *dynbuffer; + *dynbuffer = NULL; /* destroy external reference */ + + real_length = dbuf->length + sizeof(isc_buffer_t); + mctx = dbuf->mctx; + dbuf->mctx = NULL; + isc_buffer_invalidate(dbuf); + + isc_mem_put(mctx, dbuf, real_length); +} diff --git a/contrib/ntp/lib/isc/bufferlist.c b/contrib/ntp/lib/isc/bufferlist.c new file mode 100644 index 0000000..0e5c125 --- /dev/null +++ b/contrib/ntp/lib/isc/bufferlist.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: bufferlist.c,v 1.17 2007/06/19 23:47:17 tbox Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <stddef.h> + +#include <isc/buffer.h> +#include <isc/bufferlist.h> +#include <isc/util.h> + +unsigned int +isc_bufferlist_usedcount(isc_bufferlist_t *bl) { + isc_buffer_t *buffer; + unsigned int length; + + REQUIRE(bl != NULL); + + length = 0; + buffer = ISC_LIST_HEAD(*bl); + while (buffer != NULL) { + REQUIRE(ISC_BUFFER_VALID(buffer)); + length += isc_buffer_usedlength(buffer); + buffer = ISC_LIST_NEXT(buffer, link); + } + + return (length); +} + +unsigned int +isc_bufferlist_availablecount(isc_bufferlist_t *bl) { + isc_buffer_t *buffer; + unsigned int length; + + REQUIRE(bl != NULL); + + length = 0; + buffer = ISC_LIST_HEAD(*bl); + while (buffer != NULL) { + REQUIRE(ISC_BUFFER_VALID(buffer)); + length += isc_buffer_availablelength(buffer); + buffer = ISC_LIST_NEXT(buffer, link); + } + + return (length); +} diff --git a/contrib/ntp/lib/isc/commandline.c b/contrib/ntp/lib/isc/commandline.c new file mode 100644 index 0000000..aca1203 --- /dev/null +++ b/contrib/ntp/lib/isc/commandline.c @@ -0,0 +1,225 @@ +/* + * Portions Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id: commandline.c,v 1.22 2008/09/25 04:02:39 tbox Exp $ */ + +/*! \file + * This file was adapted from the NetBSD project's source tree, RCS ID: + * NetBSD: getopt.c,v 1.15 1999/09/20 04:39:37 lukem Exp + * + * The primary change has been to rename items to the ISC namespace + * and format in the ISC coding style. + */ + +/* + * \author Principal Authors: Computer Systems Research Group at UC Berkeley + * \author Principal ISC caretaker: DCL + */ + +#include <config.h> + +#include <stdio.h> + +#include <isc/commandline.h> +#include <isc/msgs.h> +#include <isc/string.h> +#include <isc/util.h> + +/*% Index into parent argv vector. */ +LIBISC_EXTERNAL_DATA int isc_commandline_index = 1; +/*% Character checked for validity. */ +LIBISC_EXTERNAL_DATA int isc_commandline_option; +/*% Argument associated with option. */ +LIBISC_EXTERNAL_DATA char *isc_commandline_argument; +/*% For printing error messages. */ +LIBISC_EXTERNAL_DATA char *isc_commandline_progname; +/*% Print error messages. */ +LIBISC_EXTERNAL_DATA isc_boolean_t isc_commandline_errprint = ISC_TRUE; +/*% Reset processing. */ +LIBISC_EXTERNAL_DATA isc_boolean_t isc_commandline_reset = ISC_TRUE; + +static char endopt = '\0'; + +#define BADOPT '?' +#define BADARG ':' +#define ENDOPT &endopt + +/*! + * getopt -- + * Parse argc/argv argument vector. + */ +int +isc_commandline_parse(int argc, char * const *argv, const char *options) { + static char *place = ENDOPT; + char *option; /* Index into *options of option. */ + + REQUIRE(argc >= 0 && argv != NULL && options != NULL); + + /* + * Update scanning pointer, either because a reset was requested or + * the previous argv was finished. + */ + if (isc_commandline_reset || *place == '\0') { + if (isc_commandline_reset) { + isc_commandline_index = 1; + isc_commandline_reset = ISC_FALSE; + } + + if (isc_commandline_progname == NULL) + isc_commandline_progname = argv[0]; + + if (isc_commandline_index >= argc || + *(place = argv[isc_commandline_index]) != '-') { + /* + * Index out of range or points to non-option. + */ + place = ENDOPT; + return (-1); + } + + if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { + /* + * Found '--' to signal end of options. Advance + * index to next argv, the first non-option. + */ + isc_commandline_index++; + place = ENDOPT; + return (-1); + } + } + + isc_commandline_option = *place++; + option = strchr(options, isc_commandline_option); + + /* + * Ensure valid option has been passed as specified by options string. + * '-:' is never a valid command line option because it could not + * distinguish ':' from the argument specifier in the options string. + */ + if (isc_commandline_option == ':' || option == NULL) { + if (*place == '\0') + isc_commandline_index++; + + if (isc_commandline_errprint && *options != ':') + fprintf(stderr, "%s: %s -- %c\n", + isc_commandline_progname, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_COMMANDLINE, + ISC_MSG_ILLEGALOPT, + "illegal option"), + isc_commandline_option); + + return (BADOPT); + } + + if (*++option != ':') { + /* + * Option does not take an argument. + */ + isc_commandline_argument = NULL; + + /* + * Skip to next argv if at the end of the current argv. + */ + if (*place == '\0') + ++isc_commandline_index; + + } else { + /* + * Option needs an argument. + */ + if (*place != '\0') + /* + * Option is in this argv, -D1 style. + */ + isc_commandline_argument = place; + + else if (argc > ++isc_commandline_index) + /* + * Option is next argv, -D 1 style. + */ + isc_commandline_argument = argv[isc_commandline_index]; + + else { + /* + * Argument needed, but no more argv. + */ + place = ENDOPT; + + /* + * Silent failure with "missing argument" return + * when ':' starts options string, per historical spec. + */ + if (*options == ':') + return (BADARG); + + if (isc_commandline_errprint) + fprintf(stderr, "%s: %s -- %c\n", + isc_commandline_progname, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_COMMANDLINE, + ISC_MSG_OPTNEEDARG, + "option requires " + "an argument"), + isc_commandline_option); + + return (BADOPT); + } + + place = ENDOPT; + + /* + * Point to argv that follows argument. + */ + isc_commandline_index++; + } + + return (isc_commandline_option); +} diff --git a/contrib/ntp/lib/isc/entropy.c b/contrib/ntp/lib/isc/entropy.c new file mode 100644 index 0000000..da9e81f --- /dev/null +++ b/contrib/ntp/lib/isc/entropy.c @@ -0,0 +1,1277 @@ +/* + * Copyright (C) 2004-2007, 2009, 2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000-2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: entropy.c,v 1.22 2010/08/10 23:48:19 tbox Exp $ */ + +/*! \file + * \brief + * This is the system independent part of the entropy module. It is + * compiled via inclusion from the relevant OS source file, ie, + * \link unix/entropy.c unix/entropy.c \endlink or win32/entropy.c. + * + * \author Much of this code is modeled after the NetBSD /dev/random implementation, + * written by Michael Graff <explorer@netbsd.org>. + */ + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> + +#include <isc/buffer.h> +#include <isc/entropy.h> +#include <isc/keyboard.h> +#include <isc/list.h> +#include <isc/magic.h> +#include <isc/mem.h> +#include <isc/msgs.h> +#include <isc/mutex.h> +#include <isc/platform.h> +#include <isc/region.h> +#include <isc/sha1.h> +#include <isc/string.h> +#include <isc/time.h> +#include <isc/util.h> + + +#define ENTROPY_MAGIC ISC_MAGIC('E', 'n', 't', 'e') +#define SOURCE_MAGIC ISC_MAGIC('E', 'n', 't', 's') + +#define VALID_ENTROPY(e) ISC_MAGIC_VALID(e, ENTROPY_MAGIC) +#define VALID_SOURCE(s) ISC_MAGIC_VALID(s, SOURCE_MAGIC) + +/*** + *** "constants." Do not change these unless you _really_ know what + *** you are doing. + ***/ + +/*% + * Size of entropy pool in 32-bit words. This _MUST_ be a power of 2. + */ +#define RND_POOLWORDS 128 +/*% Pool in bytes. */ +#define RND_POOLBYTES (RND_POOLWORDS * 4) +/*% Pool in bits. */ +#define RND_POOLBITS (RND_POOLWORDS * 32) + +/*% + * Number of bytes returned per hash. This must be true: + * threshold * 2 <= digest_size_in_bytes + */ +#define RND_ENTROPY_THRESHOLD 10 +#define THRESHOLD_BITS (RND_ENTROPY_THRESHOLD * 8) + +/*% + * Size of the input event queue in samples. + */ +#define RND_EVENTQSIZE 32 + +/*% + * The number of times we'll "reseed" for pseudorandom seeds. This is an + * extremely weak pseudorandom seed. If the caller is using lots of + * pseudorandom data and they cannot provide a stronger random source, + * there is little we can do other than hope they're smart enough to + * call _adddata() with something better than we can come up with. + */ +#define RND_INITIALIZE 128 + +/*% Entropy Pool */ +typedef struct { + isc_uint32_t cursor; /*%< current add point in the pool */ + isc_uint32_t entropy; /*%< current entropy estimate in bits */ + isc_uint32_t pseudo; /*%< bits extracted in pseudorandom */ + isc_uint32_t rotate; /*%< how many bits to rotate by */ + isc_uint32_t pool[RND_POOLWORDS]; /*%< random pool data */ +} isc_entropypool_t; + +struct isc_entropy { + unsigned int magic; + isc_mem_t *mctx; + isc_mutex_t lock; + unsigned int refcnt; + isc_uint32_t initialized; + isc_uint32_t initcount; + isc_entropypool_t pool; + unsigned int nsources; + isc_entropysource_t *nextsource; + ISC_LIST(isc_entropysource_t) sources; +}; + +/*% Sample Queue */ +typedef struct { + isc_uint32_t last_time; /*%< last time recorded */ + isc_uint32_t last_delta; /*%< last delta value */ + isc_uint32_t last_delta2; /*%< last delta2 value */ + isc_uint32_t nsamples; /*%< number of samples filled in */ + isc_uint32_t *samples; /*%< the samples */ + isc_uint32_t *extra; /*%< extra samples added in */ +} sample_queue_t; + +typedef struct { + sample_queue_t samplequeue; +} isc_entropysamplesource_t; + +typedef struct { + isc_boolean_t start_called; + isc_entropystart_t startfunc; + isc_entropyget_t getfunc; + isc_entropystop_t stopfunc; + void *arg; + sample_queue_t samplequeue; +} isc_cbsource_t; + +typedef struct { + FILESOURCE_HANDLE_TYPE handle; +} isc_entropyfilesource_t; + +struct isc_entropysource { + unsigned int magic; + unsigned int type; + isc_entropy_t *ent; + isc_uint32_t total; /*%< entropy from this source */ + ISC_LINK(isc_entropysource_t) link; + char name[32]; + isc_boolean_t bad; + isc_boolean_t warn_keyboard; + isc_keyboard_t kbd; + union { + isc_entropysamplesource_t sample; + isc_entropyfilesource_t file; + isc_cbsource_t callback; + isc_entropyusocketsource_t usocket; + } sources; +}; + +#define ENTROPY_SOURCETYPE_SAMPLE 1 /*%< Type is a sample source */ +#define ENTROPY_SOURCETYPE_FILE 2 /*%< Type is a file source */ +#define ENTROPY_SOURCETYPE_CALLBACK 3 /*%< Type is a callback source */ +#define ENTROPY_SOURCETYPE_USOCKET 4 /*%< Type is a Unix socket source */ + +/*@{*/ +/*% + * The random pool "taps" + */ +#define TAP1 99 +#define TAP2 59 +#define TAP3 31 +#define TAP4 9 +#define TAP5 7 +/*@}*/ + +/*@{*/ +/*% + * Declarations for function provided by the system dependent sources that + * include this file. + */ +static void +fillpool(isc_entropy_t *, unsigned int, isc_boolean_t); + +static int +wait_for_sources(isc_entropy_t *); + +static void +destroyfilesource(isc_entropyfilesource_t *source); + +static void +destroyusocketsource(isc_entropyusocketsource_t *source); + +/*@}*/ + +static void +samplequeue_release(isc_entropy_t *ent, sample_queue_t *sq) { + REQUIRE(sq->samples != NULL); + REQUIRE(sq->extra != NULL); + + isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4); + isc_mem_put(ent->mctx, sq->extra, RND_EVENTQSIZE * 4); + sq->samples = NULL; + sq->extra = NULL; +} + +static isc_result_t +samplesource_allocate(isc_entropy_t *ent, sample_queue_t *sq) { + sq->samples = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4); + if (sq->samples == NULL) + return (ISC_R_NOMEMORY); + + sq->extra = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4); + if (sq->extra == NULL) { + isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4); + sq->samples = NULL; + return (ISC_R_NOMEMORY); + } + + sq->nsamples = 0; + + return (ISC_R_SUCCESS); +} + +/*% + * Add in entropy, even when the value we're adding in could be + * very large. + */ +static inline void +add_entropy(isc_entropy_t *ent, isc_uint32_t entropy) { + /* clamp input. Yes, this must be done. */ + entropy = ISC_MIN(entropy, RND_POOLBITS); + /* Add in the entropy we already have. */ + entropy += ent->pool.entropy; + /* Clamp. */ + ent->pool.entropy = ISC_MIN(entropy, RND_POOLBITS); +} + +/*% + * Decrement the amount of entropy the pool has. + */ +static inline void +subtract_entropy(isc_entropy_t *ent, isc_uint32_t entropy) { + entropy = ISC_MIN(entropy, ent->pool.entropy); + ent->pool.entropy -= entropy; +} + +/*! + * Add in entropy, even when the value we're adding in could be + * very large. + */ +static inline void +add_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) { + /* clamp input. Yes, this must be done. */ + pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8); + /* Add in the pseudo we already have. */ + pseudo += ent->pool.pseudo; + /* Clamp. */ + ent->pool.pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8); +} + +/*! + * Decrement the amount of pseudo the pool has. + */ +static inline void +subtract_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) { + pseudo = ISC_MIN(pseudo, ent->pool.pseudo); + ent->pool.pseudo -= pseudo; +} + +/*! + * Add one word to the pool, rotating the input as needed. + */ +static inline void +entropypool_add_word(isc_entropypool_t *rp, isc_uint32_t val) { + /* + * Steal some values out of the pool, and xor them into the + * word we were given. + * + * Mix the new value into the pool using xor. This will + * prevent the actual values from being known to the caller + * since the previous values are assumed to be unknown as well. + */ + val ^= rp->pool[(rp->cursor + TAP1) & (RND_POOLWORDS - 1)]; + val ^= rp->pool[(rp->cursor + TAP2) & (RND_POOLWORDS - 1)]; + val ^= rp->pool[(rp->cursor + TAP3) & (RND_POOLWORDS - 1)]; + val ^= rp->pool[(rp->cursor + TAP4) & (RND_POOLWORDS - 1)]; + val ^= rp->pool[(rp->cursor + TAP5) & (RND_POOLWORDS - 1)]; + if (rp->rotate == 0) + rp->pool[rp->cursor++] ^= val; + else + rp->pool[rp->cursor++] ^= + ((val << rp->rotate) | (val >> (32 - rp->rotate))); + + /* + * If we have looped around the pool, increment the rotate + * variable so the next value will get xored in rotated to + * a different position. + * Increment by a value that is relatively prime to the word size + * to try to spread the bits throughout the pool quickly when the + * pool is empty. + */ + if (rp->cursor == RND_POOLWORDS) { + rp->cursor = 0; + rp->rotate = (rp->rotate + 7) & 31; + } +} + +/*! + * Add a buffer's worth of data to the pool. + * + * Requires that the lock is held on the entropy pool. + */ +static void +entropypool_adddata(isc_entropy_t *ent, void *p, unsigned int len, + isc_uint32_t entropy) +{ + isc_uint32_t val; + unsigned long addr; + isc_uint8_t *buf; + + addr = (unsigned long)p; + buf = p; + + if ((addr & 0x03U) != 0U) { + val = 0; + switch (len) { + case 3: + val = *buf++; + len--; + case 2: + val = val << 8 | *buf++; + len--; + case 1: + val = val << 8 | *buf++; + len--; + } + + entropypool_add_word(&ent->pool, val); + } + + for (; len > 3; len -= 4) { + val = *((isc_uint32_t *)buf); + + entropypool_add_word(&ent->pool, val); + buf += 4; + } + + if (len != 0) { + val = 0; + switch (len) { + case 3: + val = *buf++; + case 2: + val = val << 8 | *buf++; + case 1: + val = val << 8 | *buf++; + } + + entropypool_add_word(&ent->pool, val); + } + + add_entropy(ent, entropy); + subtract_pseudo(ent, entropy); +} + +static inline void +reseed(isc_entropy_t *ent) { + isc_time_t t; + pid_t pid; + + if (ent->initcount == 0) { + pid = getpid(); + entropypool_adddata(ent, &pid, sizeof(pid), 0); + pid = getppid(); + entropypool_adddata(ent, &pid, sizeof(pid), 0); + } + + /*! + * After we've reseeded 100 times, only add new timing info every + * 50 requests. This will keep us from using lots and lots of + * CPU just to return bad pseudorandom data anyway. + */ + if (ent->initcount > 100) + if ((ent->initcount % 50) != 0) + return; + + TIME_NOW(&t); + entropypool_adddata(ent, &t, sizeof(t), 0); + ent->initcount++; +} + +static inline unsigned int +estimate_entropy(sample_queue_t *sq, isc_uint32_t t) { + isc_int32_t delta; + isc_int32_t delta2; + isc_int32_t delta3; + + /*! + * If the time counter has overflowed, calculate the real difference. + * If it has not, it is simpler. + */ + if (t < sq->last_time) + delta = UINT_MAX - sq->last_time + t; + else + delta = sq->last_time - t; + + if (delta < 0) + delta = -delta; + + /* + * Calculate the second and third order differentials + */ + delta2 = sq->last_delta - delta; + if (delta2 < 0) + delta2 = -delta2; + + delta3 = sq->last_delta2 - delta2; + if (delta3 < 0) + delta3 = -delta3; + + sq->last_time = t; + sq->last_delta = delta; + sq->last_delta2 = delta2; + + /* + * If any delta is 0, we got no entropy. If all are non-zero, we + * might have something. + */ + if (delta == 0 || delta2 == 0 || delta3 == 0) + return 0; + + /* + * We could find the smallest delta and claim we got log2(delta) + * bits, but for now return that we found 1 bit. + */ + return 1; +} + +static unsigned int +crunchsamples(isc_entropy_t *ent, sample_queue_t *sq) { + unsigned int ns; + unsigned int added; + + if (sq->nsamples < 6) + return (0); + + added = 0; + sq->last_time = sq->samples[0]; + sq->last_delta = 0; + sq->last_delta2 = 0; + + /* + * Prime the values by adding in the first 4 samples in. This + * should completely initialize the delta calculations. + */ + for (ns = 0; ns < 4; ns++) + (void)estimate_entropy(sq, sq->samples[ns]); + + for (ns = 4; ns < sq->nsamples; ns++) + added += estimate_entropy(sq, sq->samples[ns]); + + entropypool_adddata(ent, sq->samples, sq->nsamples * 4, added); + entropypool_adddata(ent, sq->extra, sq->nsamples * 4, 0); + + /* + * Move the last 4 samples into the first 4 positions, and start + * adding new samples from that point. + */ + for (ns = 0; ns < 4; ns++) { + sq->samples[ns] = sq->samples[sq->nsamples - 4 + ns]; + sq->extra[ns] = sq->extra[sq->nsamples - 4 + ns]; + } + + sq->nsamples = 4; + + return (added); +} + +static unsigned int +get_from_callback(isc_entropysource_t *source, unsigned int desired, + isc_boolean_t blocking) +{ + isc_entropy_t *ent = source->ent; + isc_cbsource_t *cbs = &source->sources.callback; + unsigned int added; + unsigned int got; + isc_result_t result; + + if (desired == 0) + return (0); + + if (source->bad) + return (0); + + if (!cbs->start_called && cbs->startfunc != NULL) { + result = cbs->startfunc(source, cbs->arg, blocking); + if (result != ISC_R_SUCCESS) + return (0); + cbs->start_called = ISC_TRUE; + } + + added = 0; + result = ISC_R_SUCCESS; + while (desired > 0 && result == ISC_R_SUCCESS) { + result = cbs->getfunc(source, cbs->arg, blocking); + if (result == ISC_R_QUEUEFULL) { + got = crunchsamples(ent, &cbs->samplequeue); + added += got; + desired -= ISC_MIN(got, desired); + result = ISC_R_SUCCESS; + } else if (result != ISC_R_SUCCESS && + result != ISC_R_NOTBLOCKING) + source->bad = ISC_TRUE; + + } + + return (added); +} + +/* + * Extract some number of bytes from the random pool, decreasing the + * estimate of randomness as each byte is extracted. + * + * Do this by stiring the pool and returning a part of hash as randomness. + * Note that no secrets are given away here since parts of the hash are + * xored together before returned. + * + * Honor the request from the caller to only return good data, any data, + * etc. + */ +isc_result_t +isc_entropy_getdata(isc_entropy_t *ent, void *data, unsigned int length, + unsigned int *returned, unsigned int flags) +{ + unsigned int i; + isc_sha1_t hash; + unsigned char digest[ISC_SHA1_DIGESTLENGTH]; + isc_uint32_t remain, deltae, count, total; + isc_uint8_t *buf; + isc_boolean_t goodonly, partial, blocking; + + REQUIRE(VALID_ENTROPY(ent)); + REQUIRE(data != NULL); + REQUIRE(length > 0); + + goodonly = ISC_TF((flags & ISC_ENTROPY_GOODONLY) != 0); + partial = ISC_TF((flags & ISC_ENTROPY_PARTIAL) != 0); + blocking = ISC_TF((flags & ISC_ENTROPY_BLOCKING) != 0); + + REQUIRE(!partial || returned != NULL); + + LOCK(&ent->lock); + + remain = length; + buf = data; + total = 0; + while (remain != 0) { + count = ISC_MIN(remain, RND_ENTROPY_THRESHOLD); + + /* + * If we are extracting good data only, make certain we + * have enough data in our pool for this pass. If we don't, + * get some, and fail if we can't, and partial returns + * are not ok. + */ + if (goodonly) { + unsigned int fillcount; + + fillcount = ISC_MAX(remain * 8, count * 8); + + /* + * If, however, we have at least THRESHOLD_BITS + * of entropy in the pool, don't block here. It is + * better to drain the pool once in a while and + * then refill it than it is to constantly keep the + * pool full. + */ + if (ent->pool.entropy >= THRESHOLD_BITS) + fillpool(ent, fillcount, ISC_FALSE); + else + fillpool(ent, fillcount, blocking); + + /* + * Verify that we got enough entropy to do one + * extraction. If we didn't, bail. + */ + if (ent->pool.entropy < THRESHOLD_BITS) { + if (!partial) + goto zeroize; + else + goto partial_output; + } + } else { + /* + * If we've extracted half our pool size in bits + * since the last refresh, try to refresh here. + */ + if (ent->initialized < THRESHOLD_BITS) + fillpool(ent, THRESHOLD_BITS, blocking); + else + fillpool(ent, 0, ISC_FALSE); + + /* + * If we've not initialized with enough good random + * data, seed with our crappy code. + */ + if (ent->initialized < THRESHOLD_BITS) + reseed(ent); + } + + isc_sha1_init(&hash); + isc_sha1_update(&hash, (void *)(ent->pool.pool), + RND_POOLBYTES); + isc_sha1_final(&hash, digest); + + /* + * Stir the extracted data (all of it) back into the pool. + */ + entropypool_adddata(ent, digest, ISC_SHA1_DIGESTLENGTH, 0); + + for (i = 0; i < count; i++) + buf[i] = digest[i] ^ digest[i + RND_ENTROPY_THRESHOLD]; + + buf += count; + remain -= count; + + deltae = count * 8; + deltae = ISC_MIN(deltae, ent->pool.entropy); + total += deltae; + subtract_entropy(ent, deltae); + add_pseudo(ent, count * 8); + } + + partial_output: + memset(digest, 0, sizeof(digest)); + + if (returned != NULL) + *returned = (length - remain); + + UNLOCK(&ent->lock); + + return (ISC_R_SUCCESS); + + zeroize: + /* put the entropy we almost extracted back */ + add_entropy(ent, total); + memset(data, 0, length); + memset(digest, 0, sizeof(digest)); + if (returned != NULL) + *returned = 0; + + UNLOCK(&ent->lock); + + return (ISC_R_NOENTROPY); +} + +static void +isc_entropypool_init(isc_entropypool_t *pool) { + pool->cursor = RND_POOLWORDS - 1; + pool->entropy = 0; + pool->pseudo = 0; + pool->rotate = 0; + memset(pool->pool, 0, RND_POOLBYTES); +} + +static void +isc_entropypool_invalidate(isc_entropypool_t *pool) { + pool->cursor = 0; + pool->entropy = 0; + pool->pseudo = 0; + pool->rotate = 0; + memset(pool->pool, 0, RND_POOLBYTES); +} + +isc_result_t +isc_entropy_create(isc_mem_t *mctx, isc_entropy_t **entp) { + isc_result_t result; + isc_entropy_t *ent; + + REQUIRE(mctx != NULL); + REQUIRE(entp != NULL && *entp == NULL); + + ent = isc_mem_get(mctx, sizeof(isc_entropy_t)); + if (ent == NULL) + return (ISC_R_NOMEMORY); + + /* + * We need a lock. + */ + result = isc_mutex_init(&ent->lock); + if (result != ISC_R_SUCCESS) + goto errout; + + /* + * From here down, no failures will/can occur. + */ + ISC_LIST_INIT(ent->sources); + ent->nextsource = NULL; + ent->nsources = 0; + ent->mctx = NULL; + isc_mem_attach(mctx, &ent->mctx); + ent->refcnt = 1; + ent->initialized = 0; + ent->initcount = 0; + ent->magic = ENTROPY_MAGIC; + + isc_entropypool_init(&ent->pool); + + *entp = ent; + return (ISC_R_SUCCESS); + + errout: + isc_mem_put(mctx, ent, sizeof(isc_entropy_t)); + + return (result); +} + +/*! + * Requires "ent" be locked. + */ +static void +destroysource(isc_entropysource_t **sourcep) { + isc_entropysource_t *source; + isc_entropy_t *ent; + isc_cbsource_t *cbs; + + source = *sourcep; + *sourcep = NULL; + ent = source->ent; + + ISC_LIST_UNLINK(ent->sources, source, link); + ent->nextsource = NULL; + REQUIRE(ent->nsources > 0); + ent->nsources--; + + switch (source->type) { + case ENTROPY_SOURCETYPE_FILE: + if (! source->bad) + destroyfilesource(&source->sources.file); + break; + case ENTROPY_SOURCETYPE_USOCKET: + if (! source->bad) + destroyusocketsource(&source->sources.usocket); + break; + case ENTROPY_SOURCETYPE_SAMPLE: + samplequeue_release(ent, &source->sources.sample.samplequeue); + break; + case ENTROPY_SOURCETYPE_CALLBACK: + cbs = &source->sources.callback; + if (cbs->start_called && cbs->stopfunc != NULL) { + cbs->stopfunc(source, cbs->arg); + cbs->start_called = ISC_FALSE; + } + samplequeue_release(ent, &cbs->samplequeue); + break; + } + + memset(source, 0, sizeof(isc_entropysource_t)); + + isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t)); +} + +static inline isc_boolean_t +destroy_check(isc_entropy_t *ent) { + isc_entropysource_t *source; + + if (ent->refcnt > 0) + return (ISC_FALSE); + + source = ISC_LIST_HEAD(ent->sources); + while (source != NULL) { + switch (source->type) { + case ENTROPY_SOURCETYPE_FILE: + case ENTROPY_SOURCETYPE_USOCKET: + break; + default: + return (ISC_FALSE); + } + source = ISC_LIST_NEXT(source, link); + } + + return (ISC_TRUE); +} + +static void +destroy(isc_entropy_t **entp) { + isc_entropy_t *ent; + isc_entropysource_t *source; + isc_mem_t *mctx; + + REQUIRE(entp != NULL && *entp != NULL); + ent = *entp; + *entp = NULL; + + LOCK(&ent->lock); + + REQUIRE(ent->refcnt == 0); + + /* + * Here, detach non-sample sources. + */ + source = ISC_LIST_HEAD(ent->sources); + while (source != NULL) { + switch(source->type) { + case ENTROPY_SOURCETYPE_FILE: + case ENTROPY_SOURCETYPE_USOCKET: + destroysource(&source); + break; + } + source = ISC_LIST_HEAD(ent->sources); + } + + /* + * If there are other types of sources, we've found a bug. + */ + REQUIRE(ISC_LIST_EMPTY(ent->sources)); + + mctx = ent->mctx; + + isc_entropypool_invalidate(&ent->pool); + + UNLOCK(&ent->lock); + + DESTROYLOCK(&ent->lock); + + memset(ent, 0, sizeof(isc_entropy_t)); + isc_mem_put(mctx, ent, sizeof(isc_entropy_t)); + isc_mem_detach(&mctx); +} + +void +isc_entropy_destroysource(isc_entropysource_t **sourcep) { + isc_entropysource_t *source; + isc_entropy_t *ent; + isc_boolean_t killit; + + REQUIRE(sourcep != NULL); + REQUIRE(VALID_SOURCE(*sourcep)); + + source = *sourcep; + *sourcep = NULL; + + ent = source->ent; + REQUIRE(VALID_ENTROPY(ent)); + + LOCK(&ent->lock); + + destroysource(&source); + + killit = destroy_check(ent); + + UNLOCK(&ent->lock); + + if (killit) + destroy(&ent); +} + +isc_result_t +isc_entropy_createcallbacksource(isc_entropy_t *ent, + isc_entropystart_t start, + isc_entropyget_t get, + isc_entropystop_t stop, + void *arg, + isc_entropysource_t **sourcep) +{ + isc_result_t result; + isc_entropysource_t *source; + isc_cbsource_t *cbs; + + REQUIRE(VALID_ENTROPY(ent)); + REQUIRE(get != NULL); + REQUIRE(sourcep != NULL && *sourcep == NULL); + + LOCK(&ent->lock); + + source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t)); + if (source == NULL) { + result = ISC_R_NOMEMORY; + goto errout; + } + source->bad = ISC_FALSE; + + cbs = &source->sources.callback; + + result = samplesource_allocate(ent, &cbs->samplequeue); + if (result != ISC_R_SUCCESS) + goto errout; + + cbs->start_called = ISC_FALSE; + cbs->startfunc = start; + cbs->getfunc = get; + cbs->stopfunc = stop; + cbs->arg = arg; + + /* + * From here down, no failures can occur. + */ + source->magic = SOURCE_MAGIC; + source->type = ENTROPY_SOURCETYPE_CALLBACK; + source->ent = ent; + source->total = 0; + memset(source->name, 0, sizeof(source->name)); + ISC_LINK_INIT(source, link); + + /* + * Hook it into the entropy system. + */ + ISC_LIST_APPEND(ent->sources, source, link); + ent->nsources++; + + *sourcep = source; + + UNLOCK(&ent->lock); + return (ISC_R_SUCCESS); + + errout: + if (source != NULL) + isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t)); + + UNLOCK(&ent->lock); + + return (result); +} + +void +isc_entropy_stopcallbacksources(isc_entropy_t *ent) { + isc_entropysource_t *source; + isc_cbsource_t *cbs; + + REQUIRE(VALID_ENTROPY(ent)); + + LOCK(&ent->lock); + + source = ISC_LIST_HEAD(ent->sources); + while (source != NULL) { + if (source->type == ENTROPY_SOURCETYPE_CALLBACK) { + cbs = &source->sources.callback; + if (cbs->start_called && cbs->stopfunc != NULL) { + cbs->stopfunc(source, cbs->arg); + cbs->start_called = ISC_FALSE; + } + } + + source = ISC_LIST_NEXT(source, link); + } + + UNLOCK(&ent->lock); +} + +isc_result_t +isc_entropy_createsamplesource(isc_entropy_t *ent, + isc_entropysource_t **sourcep) +{ + isc_result_t result; + isc_entropysource_t *source; + sample_queue_t *sq; + + REQUIRE(VALID_ENTROPY(ent)); + REQUIRE(sourcep != NULL && *sourcep == NULL); + + LOCK(&ent->lock); + + source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t)); + if (source == NULL) { + result = ISC_R_NOMEMORY; + goto errout; + } + + sq = &source->sources.sample.samplequeue; + result = samplesource_allocate(ent, sq); + if (result != ISC_R_SUCCESS) + goto errout; + + /* + * From here down, no failures can occur. + */ + source->magic = SOURCE_MAGIC; + source->type = ENTROPY_SOURCETYPE_SAMPLE; + source->ent = ent; + source->total = 0; + memset(source->name, 0, sizeof(source->name)); + ISC_LINK_INIT(source, link); + + /* + * Hook it into the entropy system. + */ + ISC_LIST_APPEND(ent->sources, source, link); + ent->nsources++; + + *sourcep = source; + + UNLOCK(&ent->lock); + return (ISC_R_SUCCESS); + + errout: + if (source != NULL) + isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t)); + + UNLOCK(&ent->lock); + + return (result); +} + +/*! + * Add a sample, and return ISC_R_SUCCESS if the queue has become full, + * ISC_R_NOENTROPY if it has space remaining, and ISC_R_NOMORE if the + * queue was full when this function was called. + */ +static isc_result_t +addsample(sample_queue_t *sq, isc_uint32_t sample, isc_uint32_t extra) { + if (sq->nsamples >= RND_EVENTQSIZE) + return (ISC_R_NOMORE); + + sq->samples[sq->nsamples] = sample; + sq->extra[sq->nsamples] = extra; + sq->nsamples++; + + if (sq->nsamples >= RND_EVENTQSIZE) + return (ISC_R_QUEUEFULL); + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_entropy_addsample(isc_entropysource_t *source, isc_uint32_t sample, + isc_uint32_t extra) +{ + isc_entropy_t *ent; + sample_queue_t *sq; + unsigned int entropy; + isc_result_t result; + + REQUIRE(VALID_SOURCE(source)); + + ent = source->ent; + + LOCK(&ent->lock); + + sq = &source->sources.sample.samplequeue; + result = addsample(sq, sample, extra); + if (result == ISC_R_QUEUEFULL) { + entropy = crunchsamples(ent, sq); + add_entropy(ent, entropy); + } + + UNLOCK(&ent->lock); + + return (result); +} + +isc_result_t +isc_entropy_addcallbacksample(isc_entropysource_t *source, isc_uint32_t sample, + isc_uint32_t extra) +{ + sample_queue_t *sq; + isc_result_t result; + + REQUIRE(VALID_SOURCE(source)); + REQUIRE(source->type == ENTROPY_SOURCETYPE_CALLBACK); + + sq = &source->sources.callback.samplequeue; + result = addsample(sq, sample, extra); + + return (result); +} + +void +isc_entropy_putdata(isc_entropy_t *ent, void *data, unsigned int length, + isc_uint32_t entropy) +{ + REQUIRE(VALID_ENTROPY(ent)); + + LOCK(&ent->lock); + + entropypool_adddata(ent, data, length, entropy); + + if (ent->initialized < THRESHOLD_BITS) + ent->initialized = THRESHOLD_BITS; + + UNLOCK(&ent->lock); +} + +static void +dumpstats(isc_entropy_t *ent, FILE *out) { + fprintf(out, + isc_msgcat_get(isc_msgcat, ISC_MSGSET_ENTROPY, + ISC_MSG_ENTROPYSTATS, + "Entropy pool %p: refcnt %u cursor %u," + " rotate %u entropy %u pseudo %u nsources %u" + " nextsource %p initialized %u initcount %u\n"), + ent, ent->refcnt, + ent->pool.cursor, ent->pool.rotate, + ent->pool.entropy, ent->pool.pseudo, + ent->nsources, ent->nextsource, ent->initialized, + ent->initcount); +} + +/* + * This function ignores locking. Use at your own risk. + */ +void +isc_entropy_stats(isc_entropy_t *ent, FILE *out) { + REQUIRE(VALID_ENTROPY(ent)); + + LOCK(&ent->lock); + dumpstats(ent, out); + UNLOCK(&ent->lock); +} + +unsigned int +isc_entropy_status(isc_entropy_t *ent) { + unsigned int estimate; + + LOCK(&ent->lock); + estimate = ent->pool.entropy; + UNLOCK(&ent->lock); + + return estimate; +} + +void +isc_entropy_attach(isc_entropy_t *ent, isc_entropy_t **entp) { + REQUIRE(VALID_ENTROPY(ent)); + REQUIRE(entp != NULL && *entp == NULL); + + LOCK(&ent->lock); + + ent->refcnt++; + *entp = ent; + + UNLOCK(&ent->lock); +} + +void +isc_entropy_detach(isc_entropy_t **entp) { + isc_entropy_t *ent; + isc_boolean_t killit; + + REQUIRE(entp != NULL && VALID_ENTROPY(*entp)); + ent = *entp; + *entp = NULL; + + LOCK(&ent->lock); + + REQUIRE(ent->refcnt > 0); + ent->refcnt--; + + killit = destroy_check(ent); + + UNLOCK(&ent->lock); + + if (killit) + destroy(&ent); +} + +static isc_result_t +kbdstart(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) { + /* + * The intent of "first" is to provide a warning message only once + * during the run of a program that might try to gather keyboard + * entropy multiple times. + */ + static isc_boolean_t first = ISC_TRUE; + + UNUSED(arg); + + if (! blocking) + return (ISC_R_NOENTROPY); + + if (first) { + if (source->warn_keyboard) + fprintf(stderr, "You must use the keyboard to create " + "entropy, since your system is lacking\n" + "/dev/random (or equivalent)\n\n"); + first = ISC_FALSE; + } + fprintf(stderr, "start typing:\n"); + + return (isc_keyboard_open(&source->kbd)); +} + +static void +kbdstop(isc_entropysource_t *source, void *arg) { + + UNUSED(arg); + + if (! isc_keyboard_canceled(&source->kbd)) + fprintf(stderr, "stop typing.\r\n"); + + (void)isc_keyboard_close(&source->kbd, 3); +} + +static isc_result_t +kbdget(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) { + isc_result_t result; + isc_time_t t; + isc_uint32_t sample; + isc_uint32_t extra; + unsigned char c; + + UNUSED(arg); + + if (!blocking) + return (ISC_R_NOTBLOCKING); + + result = isc_keyboard_getchar(&source->kbd, &c); + if (result != ISC_R_SUCCESS) + return (result); + + TIME_NOW(&t); + + sample = isc_time_nanoseconds(&t); + extra = c; + + result = isc_entropy_addcallbacksample(source, sample, extra); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "\r\n"); + return (result); + } + + fprintf(stderr, "."); + fflush(stderr); + + return (result); +} + +isc_result_t +isc_entropy_usebestsource(isc_entropy_t *ectx, isc_entropysource_t **source, + const char *randomfile, int use_keyboard) +{ + isc_result_t result; + isc_result_t final_result = ISC_R_NOENTROPY; + isc_boolean_t userfile = ISC_TRUE; + + REQUIRE(VALID_ENTROPY(ectx)); + REQUIRE(source != NULL && *source == NULL); + REQUIRE(use_keyboard == ISC_ENTROPY_KEYBOARDYES || + use_keyboard == ISC_ENTROPY_KEYBOARDNO || + use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE); + +#ifdef PATH_RANDOMDEV + if (randomfile == NULL) { + randomfile = PATH_RANDOMDEV; + userfile = ISC_FALSE; + } +#endif + + if (randomfile != NULL && use_keyboard != ISC_ENTROPY_KEYBOARDYES) { + result = isc_entropy_createfilesource(ectx, randomfile); + if (result == ISC_R_SUCCESS && + use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE) + use_keyboard = ISC_ENTROPY_KEYBOARDNO; + if (result != ISC_R_SUCCESS && userfile) + return (result); + + final_result = result; + } + + if (use_keyboard != ISC_ENTROPY_KEYBOARDNO) { + result = isc_entropy_createcallbacksource(ectx, kbdstart, + kbdget, kbdstop, + NULL, source); + if (result == ISC_R_SUCCESS) + (*source)->warn_keyboard = + ISC_TF(use_keyboard == + ISC_ENTROPY_KEYBOARDMAYBE); + + if (final_result != ISC_R_SUCCESS) + final_result = result; + } + + /* + * final_result is ISC_R_SUCCESS if at least one source of entropy + * could be started, otherwise it is the error from the most recently + * failed operation (or ISC_R_NOENTROPY if PATH_RANDOMDEV is not + * defined and use_keyboard is ISC_ENTROPY_KEYBOARDNO). + */ + return (final_result); +} diff --git a/contrib/ntp/lib/isc/error.c b/contrib/ntp/lib/isc/error.c new file mode 100644 index 0000000..095100a --- /dev/null +++ b/contrib/ntp/lib/isc/error.c @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: error.c,v 1.21 2007/06/19 23:47:17 tbox Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> + +#include <isc/error.h> +#include <isc/msgs.h> + +/*% Default unexpected callback. */ +static void +default_unexpected_callback(const char *, int, const char *, va_list) + ISC_FORMAT_PRINTF(3, 0); + +/*% Default fatal callback. */ +static void +default_fatal_callback(const char *, int, const char *, va_list) + ISC_FORMAT_PRINTF(3, 0); + +/*% unexpected_callback */ +static isc_errorcallback_t unexpected_callback = default_unexpected_callback; +static isc_errorcallback_t fatal_callback = default_fatal_callback; + +void +isc_error_setunexpected(isc_errorcallback_t cb) { + if (cb == NULL) + unexpected_callback = default_unexpected_callback; + else + unexpected_callback = cb; +} + +void +isc_error_setfatal(isc_errorcallback_t cb) { + if (cb == NULL) + fatal_callback = default_fatal_callback; + else + fatal_callback = cb; +} + +void +isc_error_unexpected(const char *file, int line, const char *format, ...) { + va_list args; + + va_start(args, format); + (unexpected_callback)(file, line, format, args); + va_end(args); +} + +void +isc_error_fatal(const char *file, int line, const char *format, ...) { + va_list args; + + va_start(args, format); + (fatal_callback)(file, line, format, args); + va_end(args); + abort(); +} + +void +isc_error_runtimecheck(const char *file, int line, const char *expression) { + isc_error_fatal(file, line, "RUNTIME_CHECK(%s) %s", expression, + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed")); +} + +static void +default_unexpected_callback(const char *file, int line, const char *format, + va_list args) +{ + fprintf(stderr, "%s:%d: ", file, line); + vfprintf(stderr, format, args); + fprintf(stderr, "\n"); + fflush(stderr); +} + +static void +default_fatal_callback(const char *file, int line, const char *format, + va_list args) +{ + fprintf(stderr, "%s:%d: %s: ", file, line, + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FATALERROR, "fatal error")); + vfprintf(stderr, format, args); + fprintf(stderr, "\n"); + fflush(stderr); +} diff --git a/contrib/ntp/lib/isc/event.c b/contrib/ntp/lib/isc/event.c new file mode 100644 index 0000000..e979616 --- /dev/null +++ b/contrib/ntp/lib/isc/event.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: event.c,v 1.21 2007/06/19 23:47:17 tbox Exp $ */ + +/*! + * \file + * \author Principal Author: Bob Halley + */ + +#include <config.h> + +#include <isc/event.h> +#include <isc/mem.h> +#include <isc/util.h> + +/*** + *** Events. + ***/ + +static void +destroy(isc_event_t *event) { + isc_mem_put(event->ev_destroy_arg, event, event->ev_size); +} + +isc_event_t * +isc_event_allocate(isc_mem_t *mctx, void *sender, isc_eventtype_t type, + isc_taskaction_t action, const void *arg, size_t size) +{ + isc_event_t *event; + void *deconst_arg; + + REQUIRE(size >= sizeof(struct isc_event)); + REQUIRE(action != NULL); + + event = isc_mem_get(mctx, size); + if (event == NULL) + return (NULL); + + /* + * Removing the const attribute from "arg" is the best of two + * evils here. If the event->ev_arg member is made const, then + * it affects a great many users of the task/event subsystem + * which are not passing in an "arg" which starts its life as + * const. Changing isc_event_allocate() and isc_task_onshutdown() + * to not have "arg" prototyped as const (which is quite legitimate, + * because neither of those functions modify arg) can cause + * compiler whining anytime someone does want to use a const + * arg that they themselves never modify, such as with + * gcc -Wwrite-strings and using a string "arg". + */ + DE_CONST(arg, deconst_arg); + + ISC_EVENT_INIT(event, size, 0, NULL, type, action, deconst_arg, + sender, destroy, mctx); + + return (event); +} + +void +isc_event_free(isc_event_t **eventp) { + isc_event_t *event; + + REQUIRE(eventp != NULL); + event = *eventp; + REQUIRE(event != NULL); + + if (event->ev_destroy != NULL) + (event->ev_destroy)(event); + + *eventp = NULL; +} diff --git a/contrib/ntp/lib/isc/fsaccess.c b/contrib/ntp/lib/isc/fsaccess.c new file mode 100644 index 0000000..5c97183 --- /dev/null +++ b/contrib/ntp/lib/isc/fsaccess.c @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: fsaccess.c,v 1.10 2007/06/19 23:47:17 tbox Exp $ */ + +/*! \file + * \brief + * This file contains the OS-independent functionality of the API. + */ +#include <isc/fsaccess.h> +#include <isc/result.h> +#include <isc/util.h> + +/*! + * Shorthand. Maybe ISC__FSACCESS_PERMISSIONBITS should not even be in + * <isc/fsaccess.h>. Could check consistency with sizeof(isc_fsaccess_t) + * and the number of bits in each function. + */ +#define STEP (ISC__FSACCESS_PERMISSIONBITS) +#define GROUP (STEP) +#define OTHER (STEP * 2) + +void +isc_fsaccess_add(int trustee, int permission, isc_fsaccess_t *access) { + REQUIRE(trustee <= 0x7); + REQUIRE(permission <= 0xFF); + + if ((trustee & ISC_FSACCESS_OWNER) != 0) + *access |= permission; + + if ((trustee & ISC_FSACCESS_GROUP) != 0) + *access |= (permission << GROUP); + + if ((trustee & ISC_FSACCESS_OTHER) != 0) + *access |= (permission << OTHER); +} + +void +isc_fsaccess_remove(int trustee, int permission, isc_fsaccess_t *access) { + REQUIRE(trustee <= 0x7); + REQUIRE(permission <= 0xFF); + + + if ((trustee & ISC_FSACCESS_OWNER) != 0) + *access &= ~permission; + + if ((trustee & ISC_FSACCESS_GROUP) != 0) + *access &= ~(permission << GROUP); + + if ((trustee & ISC_FSACCESS_OTHER) != 0) + *access &= ~(permission << OTHER); +} + +static isc_result_t +check_bad_bits(isc_fsaccess_t access, isc_boolean_t is_dir) { + isc_fsaccess_t bits; + + /* + * Check for disallowed user bits. + */ + if (is_dir) + bits = ISC_FSACCESS_READ | + ISC_FSACCESS_WRITE | + ISC_FSACCESS_EXECUTE; + else + bits = ISC_FSACCESS_CREATECHILD | + ISC_FSACCESS_ACCESSCHILD | + ISC_FSACCESS_DELETECHILD | + ISC_FSACCESS_LISTDIRECTORY; + + /* + * Set group bad bits. + */ + bits |= bits << STEP; + /* + * Set other bad bits. + */ + bits |= bits << STEP; + + if ((access & bits) != 0) { + if (is_dir) + return (ISC_R_NOTFILE); + else + return (ISC_R_NOTDIRECTORY); + } + + return (ISC_R_SUCCESS); +} diff --git a/contrib/ntp/lib/isc/hash.c b/contrib/ntp/lib/isc/hash.c new file mode 100644 index 0000000..f1d68c7 --- /dev/null +++ b/contrib/ntp/lib/isc/hash.c @@ -0,0 +1,404 @@ +/* + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: hash.c,v 1.16 2009/09/01 00:22:28 jinmei Exp $ */ + +/*! \file + * Some portion of this code was derived from universal hash function + * libraries of Rice University. +\section license UH Universal Hashing Library + +Copyright ((c)) 2002, Rice University +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of Rice University (RICE) nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + +This software is provided by RICE and the contributors on an "as is" +basis, without any representations or warranties of any kind, express +or implied including, but not limited to, representations or +warranties of non-infringement, merchantability or fitness for a +particular purpose. In no event shall RICE or contributors be liable +for any direct, indirect, incidental, special, exemplary, or +consequential damages (including, but not limited to, procurement of +substitute goods or services; loss of use, data, or profits; or +business interruption) however caused and on any theory of liability, +whether in contract, strict liability, or tort (including negligence +or otherwise) arising in any way out of the use of this software, even +if advised of the possibility of such damage. +*/ + +#include <config.h> + +#include <isc/entropy.h> +#include <isc/hash.h> +#include <isc/mem.h> +#include <isc/magic.h> +#include <isc/mutex.h> +#include <isc/once.h> +#include <isc/random.h> +#include <isc/refcount.h> +#include <isc/string.h> +#include <isc/util.h> + +#define HASH_MAGIC ISC_MAGIC('H', 'a', 's', 'h') +#define VALID_HASH(h) ISC_MAGIC_VALID((h), HASH_MAGIC) + +/*% + * A large 32-bit prime number that specifies the range of the hash output. + */ +#define PRIME32 0xFFFFFFFB /* 2^32 - 5 */ + +/*@{*/ +/*% + * Types of random seed and hash accumulator. Perhaps they can be system + * dependent. + */ +typedef isc_uint32_t hash_accum_t; +typedef isc_uint16_t hash_random_t; +/*@}*/ + +/*% isc hash structure */ +struct isc_hash { + unsigned int magic; + isc_mem_t *mctx; + isc_mutex_t lock; + isc_boolean_t initialized; + isc_refcount_t refcnt; + isc_entropy_t *entropy; /*%< entropy source */ + unsigned int limit; /*%< upper limit of key length */ + size_t vectorlen; /*%< size of the vector below */ + hash_random_t *rndvector; /*%< random vector for universal hashing */ +}; + +static isc_mutex_t createlock; +static isc_once_t once = ISC_ONCE_INIT; +static isc_hash_t *hash = NULL; + +static unsigned char maptolower[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +isc_result_t +isc_hash_ctxcreate(isc_mem_t *mctx, isc_entropy_t *entropy, + unsigned int limit, isc_hash_t **hctxp) +{ + isc_result_t result; + isc_hash_t *hctx; + size_t vlen; + hash_random_t *rv; + hash_accum_t overflow_limit; + + REQUIRE(mctx != NULL); + REQUIRE(hctxp != NULL && *hctxp == NULL); + + /* + * Overflow check. Since our implementation only does a modulo + * operation at the last stage of hash calculation, the accumulator + * must not overflow. + */ + overflow_limit = + 1 << (((sizeof(hash_accum_t) - sizeof(hash_random_t))) * 8); + if (overflow_limit < (limit + 1) * 0xff) + return (ISC_R_RANGE); + + hctx = isc_mem_get(mctx, sizeof(isc_hash_t)); + if (hctx == NULL) + return (ISC_R_NOMEMORY); + + vlen = sizeof(hash_random_t) * (limit + 1); + rv = isc_mem_get(mctx, vlen); + if (rv == NULL) { + result = ISC_R_NOMEMORY; + goto errout; + } + + /* + * We need a lock. + */ + result = isc_mutex_init(&hctx->lock); + if (result != ISC_R_SUCCESS) + goto errout; + + /* + * From here down, no failures will/can occur. + */ + hctx->magic = HASH_MAGIC; + hctx->mctx = NULL; + isc_mem_attach(mctx, &hctx->mctx); + hctx->initialized = ISC_FALSE; + result = isc_refcount_init(&hctx->refcnt, 1); + if (result != ISC_R_SUCCESS) + goto cleanup_lock; + hctx->entropy = NULL; + hctx->limit = limit; + hctx->vectorlen = vlen; + hctx->rndvector = rv; + +#ifdef BIND9 + if (entropy != NULL) + isc_entropy_attach(entropy, &hctx->entropy); +#else + UNUSED(entropy); +#endif + + *hctxp = hctx; + return (ISC_R_SUCCESS); + + cleanup_lock: + DESTROYLOCK(&hctx->lock); + errout: + isc_mem_put(mctx, hctx, sizeof(isc_hash_t)); + if (rv != NULL) + isc_mem_put(mctx, rv, vlen); + + return (result); +} + +static void +initialize_lock(void) { + RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS); +} + +isc_result_t +isc_hash_create(isc_mem_t *mctx, isc_entropy_t *entropy, size_t limit) { + isc_result_t result = ISC_R_SUCCESS; + + REQUIRE(mctx != NULL); + INSIST(hash == NULL); + + RUNTIME_CHECK(isc_once_do(&once, initialize_lock) == ISC_R_SUCCESS); + + LOCK(&createlock); + + if (hash == NULL) + result = isc_hash_ctxcreate(mctx, entropy, limit, &hash); + + UNLOCK(&createlock); + + return (result); +} + +void +isc_hash_ctxinit(isc_hash_t *hctx) { + LOCK(&hctx->lock); + + if (hctx->initialized == ISC_TRUE) + goto out; + + if (hctx->entropy) { +#ifdef BIND9 + isc_result_t result; + + result = isc_entropy_getdata(hctx->entropy, + hctx->rndvector, hctx->vectorlen, + NULL, 0); + INSIST(result == ISC_R_SUCCESS); +#else + INSIST(0); +#endif + } else { + isc_uint32_t pr; + unsigned int i, copylen; + unsigned char *p; + + p = (unsigned char *)hctx->rndvector; + for (i = 0; i < hctx->vectorlen; i += copylen, p += copylen) { + isc_random_get(&pr); + if (i + sizeof(pr) <= hctx->vectorlen) + copylen = sizeof(pr); + else + copylen = hctx->vectorlen - i; + + memcpy(p, &pr, copylen); + } + INSIST(p == (unsigned char *)hctx->rndvector + + hctx->vectorlen); + } + + hctx->initialized = ISC_TRUE; + + out: + UNLOCK(&hctx->lock); +} + +void +isc_hash_init() { + INSIST(hash != NULL && VALID_HASH(hash)); + + isc_hash_ctxinit(hash); +} + +void +isc_hash_ctxattach(isc_hash_t *hctx, isc_hash_t **hctxp) { + REQUIRE(VALID_HASH(hctx)); + REQUIRE(hctxp != NULL && *hctxp == NULL); + + isc_refcount_increment(&hctx->refcnt, NULL); + *hctxp = hctx; +} + +static void +destroy(isc_hash_t **hctxp) { + isc_hash_t *hctx; + isc_mem_t *mctx; + unsigned char canary0[4], canary1[4]; + + REQUIRE(hctxp != NULL && *hctxp != NULL); + hctx = *hctxp; + *hctxp = NULL; + + LOCK(&hctx->lock); + + isc_refcount_destroy(&hctx->refcnt); + + mctx = hctx->mctx; +#ifdef BIND9 + if (hctx->entropy != NULL) + isc_entropy_detach(&hctx->entropy); +#endif + if (hctx->rndvector != NULL) + isc_mem_put(mctx, hctx->rndvector, hctx->vectorlen); + + UNLOCK(&hctx->lock); + + DESTROYLOCK(&hctx->lock); + + memcpy(canary0, hctx + 1, sizeof(canary0)); + memset(hctx, 0, sizeof(isc_hash_t)); + memcpy(canary1, hctx + 1, sizeof(canary1)); + INSIST(memcmp(canary0, canary1, sizeof(canary0)) == 0); + isc_mem_put(mctx, hctx, sizeof(isc_hash_t)); + isc_mem_detach(&mctx); +} + +void +isc_hash_ctxdetach(isc_hash_t **hctxp) { + isc_hash_t *hctx; + unsigned int refs; + + REQUIRE(hctxp != NULL && VALID_HASH(*hctxp)); + hctx = *hctxp; + + isc_refcount_decrement(&hctx->refcnt, &refs); + if (refs == 0) + destroy(&hctx); + + *hctxp = NULL; +} + +void +isc_hash_destroy() { + unsigned int refs; + + INSIST(hash != NULL && VALID_HASH(hash)); + + isc_refcount_decrement(&hash->refcnt, &refs); + INSIST(refs == 0); + + destroy(&hash); +} + +static inline unsigned int +hash_calc(isc_hash_t *hctx, const unsigned char *key, unsigned int keylen, + isc_boolean_t case_sensitive) +{ + hash_accum_t partial_sum = 0; + hash_random_t *p = hctx->rndvector; + unsigned int i = 0; + + /* Make it sure that the hash context is initialized. */ + if (hctx->initialized == ISC_FALSE) + isc_hash_ctxinit(hctx); + + if (case_sensitive) { + for (i = 0; i < keylen; i++) + partial_sum += key[i] * (hash_accum_t)p[i]; + } else { + for (i = 0; i < keylen; i++) + partial_sum += maptolower[key[i]] * (hash_accum_t)p[i]; + } + + partial_sum += p[i]; + + return ((unsigned int)(partial_sum % PRIME32)); +} + +unsigned int +isc_hash_ctxcalc(isc_hash_t *hctx, const unsigned char *key, + unsigned int keylen, isc_boolean_t case_sensitive) +{ + REQUIRE(hctx != NULL && VALID_HASH(hctx)); + REQUIRE(keylen <= hctx->limit); + + return (hash_calc(hctx, key, keylen, case_sensitive)); +} + +unsigned int +isc_hash_calc(const unsigned char *key, unsigned int keylen, + isc_boolean_t case_sensitive) +{ + INSIST(hash != NULL && VALID_HASH(hash)); + REQUIRE(keylen <= hash->limit); + + return (hash_calc(hash, key, keylen, case_sensitive)); +} diff --git a/contrib/ntp/lib/isc/heap.c b/contrib/ntp/lib/isc/heap.c new file mode 100644 index 0000000..ebadd2f --- /dev/null +++ b/contrib/ntp/lib/isc/heap.c @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2004-2007, 2010-2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1997-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/*! \file + * Heap implementation of priority queues adapted from the following: + * + * \li "Introduction to Algorithms," Cormen, Leiserson, and Rivest, + * MIT Press / McGraw Hill, 1990, ISBN 0-262-03141-8, chapter 7. + * + * \li "Algorithms," Second Edition, Sedgewick, Addison-Wesley, 1988, + * ISBN 0-201-06673-4, chapter 11. + */ + +#include <config.h> + +#include <isc/heap.h> +#include <isc/magic.h> +#include <isc/mem.h> +#include <isc/string.h> /* Required for memcpy. */ +#include <isc/util.h> + +/*@{*/ +/*% + * Note: to make heap_parent and heap_left easy to compute, the first + * element of the heap array is not used; i.e. heap subscripts are 1-based, + * not 0-based. The parent is index/2, and the left-child is index*2. + * The right child is index*2+1. + */ +#define heap_parent(i) ((i) >> 1) +#define heap_left(i) ((i) << 1) +/*@}*/ + +#define SIZE_INCREMENT 1024 + +#define HEAP_MAGIC ISC_MAGIC('H', 'E', 'A', 'P') +#define VALID_HEAP(h) ISC_MAGIC_VALID(h, HEAP_MAGIC) + +/*% + * When the heap is in a consistent state, the following invariant + * holds true: for every element i > 1, heap_parent(i) has a priority + * higher than or equal to that of i. + */ +#define HEAPCONDITION(i) ((i) == 1 || \ + ! heap->compare(heap->array[(i)], \ + heap->array[heap_parent(i)])) + +/*% ISC heap structure. */ +struct isc_heap { + unsigned int magic; + isc_mem_t * mctx; + unsigned int size; + unsigned int size_increment; + unsigned int last; + void **array; + isc_heapcompare_t compare; + isc_heapindex_t index; +}; + +isc_result_t +isc_heap_create(isc_mem_t *mctx, isc_heapcompare_t compare, + isc_heapindex_t index, unsigned int size_increment, + isc_heap_t **heapp) +{ + isc_heap_t *heap; + + REQUIRE(heapp != NULL && *heapp == NULL); + REQUIRE(compare != NULL); + + heap = isc_mem_get(mctx, sizeof(*heap)); + if (heap == NULL) + return (ISC_R_NOMEMORY); + heap->magic = HEAP_MAGIC; + heap->size = 0; + heap->mctx = NULL; + isc_mem_attach(mctx, &heap->mctx); + if (size_increment == 0) + heap->size_increment = SIZE_INCREMENT; + else + heap->size_increment = size_increment; + heap->last = 0; + heap->array = NULL; + heap->compare = compare; + heap->index = index; + + *heapp = heap; + + return (ISC_R_SUCCESS); +} + +void +isc_heap_destroy(isc_heap_t **heapp) { + isc_heap_t *heap; + + REQUIRE(heapp != NULL); + heap = *heapp; + REQUIRE(VALID_HEAP(heap)); + + if (heap->array != NULL) + isc_mem_put(heap->mctx, heap->array, + heap->size * sizeof(void *)); + heap->magic = 0; + isc_mem_putanddetach(&heap->mctx, heap, sizeof(*heap)); + + *heapp = NULL; +} + +static isc_boolean_t +resize(isc_heap_t *heap) { + void **new_array; + size_t new_size; + + REQUIRE(VALID_HEAP(heap)); + + new_size = heap->size + heap->size_increment; + new_array = isc_mem_get(heap->mctx, new_size * sizeof(void *)); + if (new_array == NULL) + return (ISC_FALSE); + if (heap->array != NULL) { + memcpy(new_array, heap->array, heap->size * sizeof(void *)); + isc_mem_put(heap->mctx, heap->array, + heap->size * sizeof(void *)); + } + heap->size = new_size; + heap->array = new_array; + + return (ISC_TRUE); +} + +static void +float_up(isc_heap_t *heap, unsigned int i, void *elt) { + unsigned int p; + + for (p = heap_parent(i) ; + i > 1 && heap->compare(elt, heap->array[p]) ; + i = p, p = heap_parent(i)) { + heap->array[i] = heap->array[p]; + if (heap->index != NULL) + (heap->index)(heap->array[i], i); + } + heap->array[i] = elt; + if (heap->index != NULL) + (heap->index)(heap->array[i], i); + + INSIST(HEAPCONDITION(i)); +} + +static void +sink_down(isc_heap_t *heap, unsigned int i, void *elt) { + unsigned int j, size, half_size; + size = heap->last; + half_size = size / 2; + while (i <= half_size) { + /* Find the smallest of the (at most) two children. */ + j = heap_left(i); + if (j < size && heap->compare(heap->array[j+1], + heap->array[j])) + j++; + if (heap->compare(elt, heap->array[j])) + break; + heap->array[i] = heap->array[j]; + if (heap->index != NULL) + (heap->index)(heap->array[i], i); + i = j; + } + heap->array[i] = elt; + if (heap->index != NULL) + (heap->index)(heap->array[i], i); + + INSIST(HEAPCONDITION(i)); +} + +isc_result_t +isc_heap_insert(isc_heap_t *heap, void *elt) { + unsigned int new_last; + + REQUIRE(VALID_HEAP(heap)); + + new_last = heap->last + 1; + RUNTIME_CHECK(new_last > 0); /* overflow check */ + if (new_last >= heap->size && !resize(heap)) + return (ISC_R_NOMEMORY); + heap->last = new_last; + + float_up(heap, new_last, elt); + + return (ISC_R_SUCCESS); +} + +void +isc_heap_delete(isc_heap_t *heap, unsigned int index) { + void *elt; + isc_boolean_t less; + + REQUIRE(VALID_HEAP(heap)); + REQUIRE(index >= 1 && index <= heap->last); + + if (index == heap->last) { + heap->array[heap->last] = NULL; + heap->last--; + } else { + elt = heap->array[heap->last]; + heap->array[heap->last] = NULL; + heap->last--; + + less = heap->compare(elt, heap->array[index]); + heap->array[index] = elt; + if (less) + float_up(heap, index, heap->array[index]); + else + sink_down(heap, index, heap->array[index]); + } +} + +void +isc_heap_increased(isc_heap_t *heap, unsigned int index) { + REQUIRE(VALID_HEAP(heap)); + REQUIRE(index >= 1 && index <= heap->last); + + float_up(heap, index, heap->array[index]); +} + +void +isc_heap_decreased(isc_heap_t *heap, unsigned int index) { + REQUIRE(VALID_HEAP(heap)); + REQUIRE(index >= 1 && index <= heap->last); + + sink_down(heap, index, heap->array[index]); +} + +void * +isc_heap_element(isc_heap_t *heap, unsigned int index) { + REQUIRE(VALID_HEAP(heap)); + REQUIRE(index >= 1); + + if (index <= heap->last) + return (heap->array[index]); + return (NULL); +} + +void +isc_heap_foreach(isc_heap_t *heap, isc_heapaction_t action, void *uap) { + unsigned int i; + + REQUIRE(VALID_HEAP(heap)); + REQUIRE(action != NULL); + + for (i = 1 ; i <= heap->last ; i++) + (action)(heap->array[i], uap); +} diff --git a/contrib/ntp/lib/isc/hex.c b/contrib/ntp/lib/isc/hex.c new file mode 100644 index 0000000..3fa0e69 --- /dev/null +++ b/contrib/ntp/lib/isc/hex.c @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000-2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: hex.c,v 1.20 2008/09/25 04:02:39 tbox Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <ctype.h> + +#include <isc/buffer.h> +#include <isc/hex.h> +#include <isc/lex.h> +#include <isc/string.h> +#include <isc/util.h> + +#define RETERR(x) do { \ + isc_result_t _r = (x); \ + if (_r != ISC_R_SUCCESS) \ + return (_r); \ + } while (0) + + +/* + * BEW: These static functions are copied from lib/dns/rdata.c. + */ +static isc_result_t +str_totext(const char *source, isc_buffer_t *target); + +static isc_result_t +mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length); + +static const char hex[] = "0123456789ABCDEF"; + +isc_result_t +isc_hex_totext(isc_region_t *source, int wordlength, + const char *wordbreak, isc_buffer_t *target) +{ + char buf[3]; + unsigned int loops = 0; + + if (wordlength < 2) + wordlength = 2; + + memset(buf, 0, sizeof(buf)); + while (source->length > 0) { + buf[0] = hex[(source->base[0] >> 4) & 0xf]; + buf[1] = hex[(source->base[0]) & 0xf]; + RETERR(str_totext(buf, target)); + isc_region_consume(source, 1); + + loops++; + if (source->length != 0 && + (int)((loops + 1) * 2) >= wordlength) + { + loops = 0; + RETERR(str_totext(wordbreak, target)); + } + } + return (ISC_R_SUCCESS); +} + +/*% + * State of a hex decoding process in progress. + */ +typedef struct { + int length; /*%< Desired length of binary data or -1 */ + isc_buffer_t *target; /*%< Buffer for resulting binary data */ + int digits; /*%< Number of buffered hex digits */ + int val[2]; +} hex_decode_ctx_t; + +static inline void +hex_decode_init(hex_decode_ctx_t *ctx, int length, isc_buffer_t *target) +{ + ctx->digits = 0; + ctx->length = length; + ctx->target = target; +} + +static inline isc_result_t +hex_decode_char(hex_decode_ctx_t *ctx, int c) { + char *s; + + if ((s = strchr(hex, toupper(c))) == NULL) + return (ISC_R_BADHEX); + ctx->val[ctx->digits++] = s - hex; + if (ctx->digits == 2) { + unsigned char num; + + num = (ctx->val[0] << 4) + (ctx->val[1]); + RETERR(mem_tobuffer(ctx->target, &num, 1)); + if (ctx->length >= 0) { + if (ctx->length == 0) + return (ISC_R_BADHEX); + else + ctx->length -= 1; + } + ctx->digits = 0; + } + return (ISC_R_SUCCESS); +} + +static inline isc_result_t +hex_decode_finish(hex_decode_ctx_t *ctx) { + if (ctx->length > 0) + return (ISC_R_UNEXPECTEDEND); + if (ctx->digits != 0) + return (ISC_R_BADHEX); + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length) { + hex_decode_ctx_t ctx; + isc_textregion_t *tr; + isc_token_t token; + isc_boolean_t eol; + + hex_decode_init(&ctx, length, target); + + while (ctx.length != 0) { + unsigned int i; + + if (length > 0) + eol = ISC_FALSE; + else + eol = ISC_TRUE; + RETERR(isc_lex_getmastertoken(lexer, &token, + isc_tokentype_string, eol)); + if (token.type != isc_tokentype_string) + break; + tr = &token.value.as_textregion; + for (i = 0; i < tr->length; i++) + RETERR(hex_decode_char(&ctx, tr->base[i])); + } + if (ctx.length < 0) + isc_lex_ungettoken(lexer, &token); + RETERR(hex_decode_finish(&ctx)); + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_hex_decodestring(const char *cstr, isc_buffer_t *target) { + hex_decode_ctx_t ctx; + + hex_decode_init(&ctx, -1, target); + for (;;) { + int c = *cstr++; + if (c == '\0') + break; + if (c == ' ' || c == '\t' || c == '\n' || c== '\r') + continue; + RETERR(hex_decode_char(&ctx, c)); + } + RETERR(hex_decode_finish(&ctx)); + return (ISC_R_SUCCESS); +} + +static isc_result_t +str_totext(const char *source, isc_buffer_t *target) { + unsigned int l; + isc_region_t region; + + isc_buffer_availableregion(target, ®ion); + l = strlen(source); + + if (l > region.length) + return (ISC_R_NOSPACE); + + memcpy(region.base, source, l); + isc_buffer_add(target, l); + return (ISC_R_SUCCESS); +} + +static isc_result_t +mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) { + isc_region_t tr; + + isc_buffer_availableregion(target, &tr); + if (length > tr.length) + return (ISC_R_NOSPACE); + memcpy(tr.base, base, length); + isc_buffer_add(target, length); + return (ISC_R_SUCCESS); +} diff --git a/contrib/ntp/lib/isc/hmacmd5.c b/contrib/ntp/lib/isc/hmacmd5.c new file mode 100644 index 0000000..6abe6e2 --- /dev/null +++ b/contrib/ntp/lib/isc/hmacmd5.c @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: hmacmd5.c,v 1.16 2009/02/06 23:47:42 tbox Exp $ */ + +/*! \file + * This code implements the HMAC-MD5 keyed hash algorithm + * described in RFC2104. + */ + +#include "config.h" + +#include <isc/assertions.h> +#include <isc/hmacmd5.h> +#include <isc/md5.h> +#include <isc/platform.h> +#include <isc/string.h> +#include <isc/types.h> +#include <isc/util.h> + +#ifdef ISC_PLATFORM_OPENSSLHASH + +void +isc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key, + unsigned int len) +{ + HMAC_Init(ctx, (const void *) key, (int) len, EVP_md5()); +} + +void +isc_hmacmd5_invalidate(isc_hmacmd5_t *ctx) { + HMAC_CTX_cleanup(ctx); +} + +void +isc_hmacmd5_update(isc_hmacmd5_t *ctx, const unsigned char *buf, + unsigned int len) +{ + HMAC_Update(ctx, buf, (int) len); +} + +void +isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest) { + HMAC_Final(ctx, digest, NULL); + HMAC_CTX_cleanup(ctx); +} + +#else + +#define PADLEN 64 +#define IPAD 0x36 +#define OPAD 0x5C + +/*! + * Start HMAC-MD5 process. Initialize an md5 context and digest the key. + */ +void +isc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key, + unsigned int len) +{ + unsigned char ipad[PADLEN]; + int i; + + memset(ctx->key, 0, sizeof(ctx->key)); + if (len > sizeof(ctx->key)) { + isc_md5_t md5ctx; + isc_md5_init(&md5ctx); + isc_md5_update(&md5ctx, key, len); + isc_md5_final(&md5ctx, ctx->key); + } else + memcpy(ctx->key, key, len); + + isc_md5_init(&ctx->md5ctx); + memset(ipad, IPAD, sizeof(ipad)); + for (i = 0; i < PADLEN; i++) + ipad[i] ^= ctx->key[i]; + isc_md5_update(&ctx->md5ctx, ipad, sizeof(ipad)); +} + +void +isc_hmacmd5_invalidate(isc_hmacmd5_t *ctx) { + isc_md5_invalidate(&ctx->md5ctx); + memset(ctx->key, 0, sizeof(ctx->key)); +} + +/*! + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +isc_hmacmd5_update(isc_hmacmd5_t *ctx, const unsigned char *buf, + unsigned int len) +{ + isc_md5_update(&ctx->md5ctx, buf, len); +} + +/*! + * Compute signature - finalize MD5 operation and reapply MD5. + */ +void +isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest) { + unsigned char opad[PADLEN]; + int i; + + isc_md5_final(&ctx->md5ctx, digest); + + memset(opad, OPAD, sizeof(opad)); + for (i = 0; i < PADLEN; i++) + opad[i] ^= ctx->key[i]; + + isc_md5_init(&ctx->md5ctx); + isc_md5_update(&ctx->md5ctx, opad, sizeof(opad)); + isc_md5_update(&ctx->md5ctx, digest, ISC_MD5_DIGESTLENGTH); + isc_md5_final(&ctx->md5ctx, digest); + isc_hmacmd5_invalidate(ctx); +} +#endif /* !ISC_PLATFORM_OPENSSLHASH */ + +/*! + * Verify signature - finalize MD5 operation and reapply MD5, then + * compare to the supplied digest. + */ +isc_boolean_t +isc_hmacmd5_verify(isc_hmacmd5_t *ctx, unsigned char *digest) { + return (isc_hmacmd5_verify2(ctx, digest, ISC_MD5_DIGESTLENGTH)); +} + +isc_boolean_t +isc_hmacmd5_verify2(isc_hmacmd5_t *ctx, unsigned char *digest, size_t len) { + unsigned char newdigest[ISC_MD5_DIGESTLENGTH]; + + REQUIRE(len <= ISC_MD5_DIGESTLENGTH); + isc_hmacmd5_sign(ctx, newdigest); + return (ISC_TF(memcmp(digest, newdigest, len) == 0)); +} diff --git a/contrib/ntp/lib/isc/hmacsha.c b/contrib/ntp/lib/isc/hmacsha.c new file mode 100644 index 0000000..d7b9f18 --- /dev/null +++ b/contrib/ntp/lib/isc/hmacsha.c @@ -0,0 +1,594 @@ +/* + * Copyright (C) 2005-2007, 2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/* + * This code implements the HMAC-SHA1, HMAC-SHA224, HMAC-SHA256, HMAC-SHA384 + * and HMAC-SHA512 keyed hash algorithm described in RFC 2104 and + * draft-ietf-dnsext-tsig-sha-01.txt. + */ + +#include "config.h" + +#include <isc/assertions.h> +#include <isc/hmacsha.h> +#include <isc/platform.h> +#include <isc/sha1.h> +#include <isc/sha2.h> +#include <isc/string.h> +#include <isc/types.h> +#include <isc/util.h> + +#ifdef ISC_PLATFORM_OPENSSLHASH + +void +isc_hmacsha1_init(isc_hmacsha1_t *ctx, const unsigned char *key, + unsigned int len) +{ + HMAC_Init(ctx, (const void *) key, (int) len, EVP_sha1()); +} + +void +isc_hmacsha1_invalidate(isc_hmacsha1_t *ctx) { + HMAC_CTX_cleanup(ctx); +} + +void +isc_hmacsha1_update(isc_hmacsha1_t *ctx, const unsigned char *buf, + unsigned int len) +{ + HMAC_Update(ctx, buf, (int) len); +} + +void +isc_hmacsha1_sign(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len) { + unsigned char newdigest[ISC_SHA1_DIGESTLENGTH]; + + REQUIRE(len <= ISC_SHA1_DIGESTLENGTH); + + HMAC_Final(ctx, newdigest, NULL); + HMAC_CTX_cleanup(ctx); + memcpy(digest, newdigest, len); + memset(newdigest, 0, sizeof(newdigest)); +} + +void +isc_hmacsha224_init(isc_hmacsha224_t *ctx, const unsigned char *key, + unsigned int len) +{ + HMAC_Init(ctx, (const void *) key, (int) len, EVP_sha224()); +} + +void +isc_hmacsha224_invalidate(isc_hmacsha224_t *ctx) { + HMAC_CTX_cleanup(ctx); +} + +void +isc_hmacsha224_update(isc_hmacsha224_t *ctx, const unsigned char *buf, + unsigned int len) +{ + HMAC_Update(ctx, buf, (int) len); +} + +void +isc_hmacsha224_sign(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len) { + unsigned char newdigest[ISC_SHA224_DIGESTLENGTH]; + + REQUIRE(len <= ISC_SHA224_DIGESTLENGTH); + + HMAC_Final(ctx, newdigest, NULL); + HMAC_CTX_cleanup(ctx); + memcpy(digest, newdigest, len); + memset(newdigest, 0, sizeof(newdigest)); +} + +void +isc_hmacsha256_init(isc_hmacsha256_t *ctx, const unsigned char *key, + unsigned int len) +{ + HMAC_Init(ctx, (const void *) key, (int) len, EVP_sha256()); +} + +void +isc_hmacsha256_invalidate(isc_hmacsha256_t *ctx) { + HMAC_CTX_cleanup(ctx); +} + +void +isc_hmacsha256_update(isc_hmacsha256_t *ctx, const unsigned char *buf, + unsigned int len) +{ + HMAC_Update(ctx, buf, (int) len); +} + +void +isc_hmacsha256_sign(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len) { + unsigned char newdigest[ISC_SHA256_DIGESTLENGTH]; + + REQUIRE(len <= ISC_SHA256_DIGESTLENGTH); + + HMAC_Final(ctx, newdigest, NULL); + HMAC_CTX_cleanup(ctx); + memcpy(digest, newdigest, len); + memset(newdigest, 0, sizeof(newdigest)); +} + +void +isc_hmacsha384_init(isc_hmacsha384_t *ctx, const unsigned char *key, + unsigned int len) +{ + HMAC_Init(ctx, (const void *) key, (int) len, EVP_sha384()); +} + +void +isc_hmacsha384_invalidate(isc_hmacsha384_t *ctx) { + HMAC_CTX_cleanup(ctx); +} + +void +isc_hmacsha384_update(isc_hmacsha384_t *ctx, const unsigned char *buf, + unsigned int len) +{ + HMAC_Update(ctx, buf, (int) len); +} + +void +isc_hmacsha384_sign(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len) { + unsigned char newdigest[ISC_SHA384_DIGESTLENGTH]; + + REQUIRE(len <= ISC_SHA384_DIGESTLENGTH); + + HMAC_Final(ctx, newdigest, NULL); + HMAC_CTX_cleanup(ctx); + memcpy(digest, newdigest, len); + memset(newdigest, 0, sizeof(newdigest)); +} + +void +isc_hmacsha512_init(isc_hmacsha512_t *ctx, const unsigned char *key, + unsigned int len) +{ + HMAC_Init(ctx, (const void *) key, (int) len, EVP_sha512()); +} + +void +isc_hmacsha512_invalidate(isc_hmacsha512_t *ctx) { + HMAC_CTX_cleanup(ctx); +} + +void +isc_hmacsha512_update(isc_hmacsha512_t *ctx, const unsigned char *buf, + unsigned int len) +{ + HMAC_Update(ctx, buf, (int) len); +} + +void +isc_hmacsha512_sign(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len) { + unsigned char newdigest[ISC_SHA512_DIGESTLENGTH]; + + REQUIRE(len <= ISC_SHA512_DIGESTLENGTH); + + HMAC_Final(ctx, newdigest, NULL); + HMAC_CTX_cleanup(ctx); + memcpy(digest, newdigest, len); + memset(newdigest, 0, sizeof(newdigest)); +} + +#else + +#define IPAD 0x36 +#define OPAD 0x5C + +/* + * Start HMAC-SHA1 process. Initialize an sha1 context and digest the key. + */ +void +isc_hmacsha1_init(isc_hmacsha1_t *ctx, const unsigned char *key, + unsigned int len) +{ + unsigned char ipad[ISC_SHA1_BLOCK_LENGTH]; + unsigned int i; + + memset(ctx->key, 0, sizeof(ctx->key)); + if (len > sizeof(ctx->key)) { + isc_sha1_t sha1ctx; + isc_sha1_init(&sha1ctx); + isc_sha1_update(&sha1ctx, key, len); + isc_sha1_final(&sha1ctx, ctx->key); + } else + memcpy(ctx->key, key, len); + + isc_sha1_init(&ctx->sha1ctx); + memset(ipad, IPAD, sizeof(ipad)); + for (i = 0; i < ISC_SHA1_BLOCK_LENGTH; i++) + ipad[i] ^= ctx->key[i]; + isc_sha1_update(&ctx->sha1ctx, ipad, sizeof(ipad)); +} + +void +isc_hmacsha1_invalidate(isc_hmacsha1_t *ctx) { + isc_sha1_invalidate(&ctx->sha1ctx); + memset(ctx, 0, sizeof(*ctx)); +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +isc_hmacsha1_update(isc_hmacsha1_t *ctx, const unsigned char *buf, + unsigned int len) +{ + isc_sha1_update(&ctx->sha1ctx, buf, len); +} + +/* + * Compute signature - finalize SHA1 operation and reapply SHA1. + */ +void +isc_hmacsha1_sign(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len) { + unsigned char opad[ISC_SHA1_BLOCK_LENGTH]; + unsigned char newdigest[ISC_SHA1_DIGESTLENGTH]; + unsigned int i; + + REQUIRE(len <= ISC_SHA1_DIGESTLENGTH); + isc_sha1_final(&ctx->sha1ctx, newdigest); + + memset(opad, OPAD, sizeof(opad)); + for (i = 0; i < ISC_SHA1_BLOCK_LENGTH; i++) + opad[i] ^= ctx->key[i]; + + isc_sha1_init(&ctx->sha1ctx); + isc_sha1_update(&ctx->sha1ctx, opad, sizeof(opad)); + isc_sha1_update(&ctx->sha1ctx, newdigest, ISC_SHA1_DIGESTLENGTH); + isc_sha1_final(&ctx->sha1ctx, newdigest); + isc_hmacsha1_invalidate(ctx); + memcpy(digest, newdigest, len); + memset(newdigest, 0, sizeof(newdigest)); +} + +/* + * Start HMAC-SHA224 process. Initialize an sha224 context and digest the key. + */ +void +isc_hmacsha224_init(isc_hmacsha224_t *ctx, const unsigned char *key, + unsigned int len) +{ + unsigned char ipad[ISC_SHA224_BLOCK_LENGTH]; + unsigned int i; + + memset(ctx->key, 0, sizeof(ctx->key)); + if (len > sizeof(ctx->key)) { + isc_sha224_t sha224ctx; + isc_sha224_init(&sha224ctx); + isc_sha224_update(&sha224ctx, key, len); + isc_sha224_final(ctx->key, &sha224ctx); + } else + memcpy(ctx->key, key, len); + + isc_sha224_init(&ctx->sha224ctx); + memset(ipad, IPAD, sizeof(ipad)); + for (i = 0; i < ISC_SHA224_BLOCK_LENGTH; i++) + ipad[i] ^= ctx->key[i]; + isc_sha224_update(&ctx->sha224ctx, ipad, sizeof(ipad)); +} + +void +isc_hmacsha224_invalidate(isc_hmacsha224_t *ctx) { + memset(ctx, 0, sizeof(*ctx)); +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +isc_hmacsha224_update(isc_hmacsha224_t *ctx, const unsigned char *buf, + unsigned int len) +{ + isc_sha224_update(&ctx->sha224ctx, buf, len); +} + +/* + * Compute signature - finalize SHA224 operation and reapply SHA224. + */ +void +isc_hmacsha224_sign(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len) { + unsigned char opad[ISC_SHA224_BLOCK_LENGTH]; + unsigned char newdigest[ISC_SHA224_DIGESTLENGTH]; + unsigned int i; + + REQUIRE(len <= ISC_SHA224_DIGESTLENGTH); + isc_sha224_final(newdigest, &ctx->sha224ctx); + + memset(opad, OPAD, sizeof(opad)); + for (i = 0; i < ISC_SHA224_BLOCK_LENGTH; i++) + opad[i] ^= ctx->key[i]; + + isc_sha224_init(&ctx->sha224ctx); + isc_sha224_update(&ctx->sha224ctx, opad, sizeof(opad)); + isc_sha224_update(&ctx->sha224ctx, newdigest, ISC_SHA224_DIGESTLENGTH); + isc_sha224_final(newdigest, &ctx->sha224ctx); + memcpy(digest, newdigest, len); + memset(newdigest, 0, sizeof(newdigest)); +} + +/* + * Start HMAC-SHA256 process. Initialize an sha256 context and digest the key. + */ +void +isc_hmacsha256_init(isc_hmacsha256_t *ctx, const unsigned char *key, + unsigned int len) +{ + unsigned char ipad[ISC_SHA256_BLOCK_LENGTH]; + unsigned int i; + + memset(ctx->key, 0, sizeof(ctx->key)); + if (len > sizeof(ctx->key)) { + isc_sha256_t sha256ctx; + isc_sha256_init(&sha256ctx); + isc_sha256_update(&sha256ctx, key, len); + isc_sha256_final(ctx->key, &sha256ctx); + } else + memcpy(ctx->key, key, len); + + isc_sha256_init(&ctx->sha256ctx); + memset(ipad, IPAD, sizeof(ipad)); + for (i = 0; i < ISC_SHA256_BLOCK_LENGTH; i++) + ipad[i] ^= ctx->key[i]; + isc_sha256_update(&ctx->sha256ctx, ipad, sizeof(ipad)); +} + +void +isc_hmacsha256_invalidate(isc_hmacsha256_t *ctx) { + memset(ctx, 0, sizeof(*ctx)); +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +isc_hmacsha256_update(isc_hmacsha256_t *ctx, const unsigned char *buf, + unsigned int len) +{ + isc_sha256_update(&ctx->sha256ctx, buf, len); +} + +/* + * Compute signature - finalize SHA256 operation and reapply SHA256. + */ +void +isc_hmacsha256_sign(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len) { + unsigned char opad[ISC_SHA256_BLOCK_LENGTH]; + unsigned char newdigest[ISC_SHA256_DIGESTLENGTH]; + unsigned int i; + + REQUIRE(len <= ISC_SHA256_DIGESTLENGTH); + isc_sha256_final(newdigest, &ctx->sha256ctx); + + memset(opad, OPAD, sizeof(opad)); + for (i = 0; i < ISC_SHA256_BLOCK_LENGTH; i++) + opad[i] ^= ctx->key[i]; + + isc_sha256_init(&ctx->sha256ctx); + isc_sha256_update(&ctx->sha256ctx, opad, sizeof(opad)); + isc_sha256_update(&ctx->sha256ctx, newdigest, ISC_SHA256_DIGESTLENGTH); + isc_sha256_final(newdigest, &ctx->sha256ctx); + memcpy(digest, newdigest, len); + memset(newdigest, 0, sizeof(newdigest)); +} + +/* + * Start HMAC-SHA384 process. Initialize an sha384 context and digest the key. + */ +void +isc_hmacsha384_init(isc_hmacsha384_t *ctx, const unsigned char *key, + unsigned int len) +{ + unsigned char ipad[ISC_SHA384_BLOCK_LENGTH]; + unsigned int i; + + memset(ctx->key, 0, sizeof(ctx->key)); + if (len > sizeof(ctx->key)) { + isc_sha384_t sha384ctx; + isc_sha384_init(&sha384ctx); + isc_sha384_update(&sha384ctx, key, len); + isc_sha384_final(ctx->key, &sha384ctx); + } else + memcpy(ctx->key, key, len); + + isc_sha384_init(&ctx->sha384ctx); + memset(ipad, IPAD, sizeof(ipad)); + for (i = 0; i < ISC_SHA384_BLOCK_LENGTH; i++) + ipad[i] ^= ctx->key[i]; + isc_sha384_update(&ctx->sha384ctx, ipad, sizeof(ipad)); +} + +void +isc_hmacsha384_invalidate(isc_hmacsha384_t *ctx) { + memset(ctx, 0, sizeof(*ctx)); +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +isc_hmacsha384_update(isc_hmacsha384_t *ctx, const unsigned char *buf, + unsigned int len) +{ + isc_sha384_update(&ctx->sha384ctx, buf, len); +} + +/* + * Compute signature - finalize SHA384 operation and reapply SHA384. + */ +void +isc_hmacsha384_sign(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len) { + unsigned char opad[ISC_SHA384_BLOCK_LENGTH]; + unsigned char newdigest[ISC_SHA384_DIGESTLENGTH]; + unsigned int i; + + REQUIRE(len <= ISC_SHA384_DIGESTLENGTH); + isc_sha384_final(newdigest, &ctx->sha384ctx); + + memset(opad, OPAD, sizeof(opad)); + for (i = 0; i < ISC_SHA384_BLOCK_LENGTH; i++) + opad[i] ^= ctx->key[i]; + + isc_sha384_init(&ctx->sha384ctx); + isc_sha384_update(&ctx->sha384ctx, opad, sizeof(opad)); + isc_sha384_update(&ctx->sha384ctx, newdigest, ISC_SHA384_DIGESTLENGTH); + isc_sha384_final(newdigest, &ctx->sha384ctx); + memcpy(digest, newdigest, len); + memset(newdigest, 0, sizeof(newdigest)); +} + +/* + * Start HMAC-SHA512 process. Initialize an sha512 context and digest the key. + */ +void +isc_hmacsha512_init(isc_hmacsha512_t *ctx, const unsigned char *key, + unsigned int len) +{ + unsigned char ipad[ISC_SHA512_BLOCK_LENGTH]; + unsigned int i; + + memset(ctx->key, 0, sizeof(ctx->key)); + if (len > sizeof(ctx->key)) { + isc_sha512_t sha512ctx; + isc_sha512_init(&sha512ctx); + isc_sha512_update(&sha512ctx, key, len); + isc_sha512_final(ctx->key, &sha512ctx); + } else + memcpy(ctx->key, key, len); + + isc_sha512_init(&ctx->sha512ctx); + memset(ipad, IPAD, sizeof(ipad)); + for (i = 0; i < ISC_SHA512_BLOCK_LENGTH; i++) + ipad[i] ^= ctx->key[i]; + isc_sha512_update(&ctx->sha512ctx, ipad, sizeof(ipad)); +} + +void +isc_hmacsha512_invalidate(isc_hmacsha512_t *ctx) { + memset(ctx, 0, sizeof(*ctx)); +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +isc_hmacsha512_update(isc_hmacsha512_t *ctx, const unsigned char *buf, + unsigned int len) +{ + isc_sha512_update(&ctx->sha512ctx, buf, len); +} + +/* + * Compute signature - finalize SHA512 operation and reapply SHA512. + */ +void +isc_hmacsha512_sign(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len) { + unsigned char opad[ISC_SHA512_BLOCK_LENGTH]; + unsigned char newdigest[ISC_SHA512_DIGESTLENGTH]; + unsigned int i; + + REQUIRE(len <= ISC_SHA512_DIGESTLENGTH); + isc_sha512_final(newdigest, &ctx->sha512ctx); + + memset(opad, OPAD, sizeof(opad)); + for (i = 0; i < ISC_SHA512_BLOCK_LENGTH; i++) + opad[i] ^= ctx->key[i]; + + isc_sha512_init(&ctx->sha512ctx); + isc_sha512_update(&ctx->sha512ctx, opad, sizeof(opad)); + isc_sha512_update(&ctx->sha512ctx, newdigest, ISC_SHA512_DIGESTLENGTH); + isc_sha512_final(newdigest, &ctx->sha512ctx); + memcpy(digest, newdigest, len); + memset(newdigest, 0, sizeof(newdigest)); +} +#endif /* !ISC_PLATFORM_OPENSSLHASH */ + +/* + * Verify signature - finalize SHA1 operation and reapply SHA1, then + * compare to the supplied digest. + */ +isc_boolean_t +isc_hmacsha1_verify(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len) { + unsigned char newdigest[ISC_SHA1_DIGESTLENGTH]; + + REQUIRE(len <= ISC_SHA1_DIGESTLENGTH); + isc_hmacsha1_sign(ctx, newdigest, ISC_SHA1_DIGESTLENGTH); + return (ISC_TF(memcmp(digest, newdigest, len) == 0)); +} + +/* + * Verify signature - finalize SHA224 operation and reapply SHA224, then + * compare to the supplied digest. + */ +isc_boolean_t +isc_hmacsha224_verify(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len) { + unsigned char newdigest[ISC_SHA224_DIGESTLENGTH]; + + REQUIRE(len <= ISC_SHA224_DIGESTLENGTH); + isc_hmacsha224_sign(ctx, newdigest, ISC_SHA224_DIGESTLENGTH); + return (ISC_TF(memcmp(digest, newdigest, len) == 0)); +} + +/* + * Verify signature - finalize SHA256 operation and reapply SHA256, then + * compare to the supplied digest. + */ +isc_boolean_t +isc_hmacsha256_verify(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len) { + unsigned char newdigest[ISC_SHA256_DIGESTLENGTH]; + + REQUIRE(len <= ISC_SHA256_DIGESTLENGTH); + isc_hmacsha256_sign(ctx, newdigest, ISC_SHA256_DIGESTLENGTH); + return (ISC_TF(memcmp(digest, newdigest, len) == 0)); +} + +/* + * Verify signature - finalize SHA384 operation and reapply SHA384, then + * compare to the supplied digest. + */ +isc_boolean_t +isc_hmacsha384_verify(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len) { + unsigned char newdigest[ISC_SHA384_DIGESTLENGTH]; + + REQUIRE(len <= ISC_SHA384_DIGESTLENGTH); + isc_hmacsha384_sign(ctx, newdigest, ISC_SHA384_DIGESTLENGTH); + return (ISC_TF(memcmp(digest, newdigest, len) == 0)); +} + +/* + * Verify signature - finalize SHA512 operation and reapply SHA512, then + * compare to the supplied digest. + */ +isc_boolean_t +isc_hmacsha512_verify(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len) { + unsigned char newdigest[ISC_SHA512_DIGESTLENGTH]; + + REQUIRE(len <= ISC_SHA512_DIGESTLENGTH); + isc_hmacsha512_sign(ctx, newdigest, ISC_SHA512_DIGESTLENGTH); + return (ISC_TF(memcmp(digest, newdigest, len) == 0)); +} diff --git a/contrib/ntp/lib/isc/httpd.c b/contrib/ntp/lib/isc/httpd.c new file mode 100644 index 0000000..16a8c9f --- /dev/null +++ b/contrib/ntp/lib/isc/httpd.c @@ -0,0 +1,1028 @@ +/* + * Copyright (C) 2006-2008, 2010-2012 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/*! \file */ + +#include <config.h> + +#include <isc/buffer.h> +#include <isc/httpd.h> +#include <isc/mem.h> +#include <isc/socket.h> +#include <isc/string.h> +#include <isc/task.h> +#include <isc/util.h> + +#include <string.h> + +/*% + * TODO: + * + * o Put in better checks to make certain things are passed in correctly. + * This includes a magic number for externally-visible structures, + * checking for NULL-ness before dereferencing, etc. + * o Make the URL processing external functions which will fill-in a buffer + * structure we provide, or return an error and we will render a generic + * page and close the client. + */ + +#define MSHUTTINGDOWN(cm) ((cm->flags & ISC_HTTPDMGR_FLAGSHUTTINGDOWN) != 0) +#define MSETSHUTTINGDOWN(cm) (cm->flags |= ISC_HTTPDMGR_FLAGSHUTTINGDOWN) + +#ifdef DEBUG_HTTPD +#define ENTER(x) do { fprintf(stderr, "ENTER %s\n", (x)); } while (0) +#define EXIT(x) do { fprintf(stderr, "EXIT %s\n", (x)); } while (0) +#define NOTICE(x) do { fprintf(stderr, "NOTICE %s\n", (x)); } while (0) +#else +#define ENTER(x) do { } while(0) +#define EXIT(x) do { } while(0) +#define NOTICE(x) do { } while(0) +#endif + +#define HTTP_RECVLEN 1024 +#define HTTP_SENDGROW 1024 +#define HTTP_SEND_MAXLEN 10240 + +/*% + * HTTP urls. These are the URLs we manage, and the function to call to + * provide the data for it. We pass in the base url (so the same function + * can handle multiple requests), and a structure to fill in to return a + * result to the client. We also pass in a pointer to be filled in for + * the data cleanup function. + */ +struct isc_httpdurl { + char *url; + isc_httpdaction_t *action; + void *action_arg; + ISC_LINK(isc_httpdurl_t) link; +}; + +#define HTTPD_CLOSE 0x0001 /* Got a Connection: close header */ +#define HTTPD_FOUNDHOST 0x0002 /* Got a Host: header */ + +/*% http client */ +struct isc_httpd { + isc_httpdmgr_t *mgr; /*%< our parent */ + ISC_LINK(isc_httpd_t) link; + unsigned int state; + isc_socket_t *sock; + + /*% + * Received data state. + */ + char recvbuf[HTTP_RECVLEN]; /*%< receive buffer */ + isc_uint32_t recvlen; /*%< length recv'd */ + unsigned int method; + char *url; + char *querystring; + char *protocol; + + /* + * Flags on the httpd client. + */ + int flags; + + /*% + * Transmit data state. + * + * This is the data buffer we will transmit. + * + * This free function pointer is filled in by the rendering function + * we call. The free function is called after the data is transmitted + * to the client. + * + * The bufflist is the list of buffers we are currently transmitting. + * The headerdata is where we render our headers to. If we run out of + * space when rendering a header, we will change the size of our + * buffer. We will not free it until we are finished, and will + * allocate an additional HTTP_SENDGROW bytes per header space grow. + * + * We currently use two buffers total, one for the headers (which + * we manage) and another for the client to fill in (which it manages, + * it provides the space for it, etc) -- we will pass that buffer + * structure back to the caller, who is responsible for managing the + * space it may have allocated as backing store for it. This second + * buffer is bodybuffer, and we only allocate the buffer itself, not + * the backing store. + */ + isc_bufferlist_t bufflist; + char *headerdata; /*%< send header buf */ + unsigned int headerlen; /*%< current header buffer size */ + isc_buffer_t headerbuffer; + + const char *mimetype; + unsigned int retcode; + const char *retmsg; + isc_buffer_t bodybuffer; + isc_httpdfree_t *freecb; + void *freecb_arg; +}; + +/*% lightweight socket manager for httpd output */ +struct isc_httpdmgr { + isc_mem_t *mctx; + isc_socket_t *sock; /*%< listening socket */ + isc_task_t *task; /*%< owning task */ + isc_timermgr_t *timermgr; + + isc_httpdclientok_t *client_ok; /*%< client validator */ + isc_httpdondestroy_t *ondestroy; /*%< cleanup callback */ + void *cb_arg; /*%< argument for the above */ + + unsigned int flags; + ISC_LIST(isc_httpd_t) running; /*%< running clients */ + + isc_mutex_t lock; + + ISC_LIST(isc_httpdurl_t) urls; /*%< urls we manage */ + isc_httpdaction_t *render_404; + isc_httpdaction_t *render_500; +}; + +/*% + * HTTP methods. + */ +#define ISC_HTTPD_METHODUNKNOWN 0 +#define ISC_HTTPD_METHODGET 1 +#define ISC_HTTPD_METHODPOST 2 + +/*% + * Client states. + * + * _IDLE The client is not doing anything at all. This state should + * only occur just after creation, and just before being + * destroyed. + * + * _RECV The client is waiting for data after issuing a socket recv(). + * + * _RECVDONE Data has been received, and is being processed. + * + * _SEND All data for a response has completed, and a reply was + * sent via a socket send() call. + * + * _SENDDONE Send is completed. + * + * Badly formatted state table: + * + * IDLE -> RECV when client has a recv() queued. + * + * RECV -> RECVDONE when recvdone event received. + * + * RECVDONE -> SEND if the data for a reply is at hand. + * + * SEND -> RECV when a senddone event was received. + * + * At any time -> RECV on error. If RECV fails, the client will + * self-destroy, closing the socket and freeing memory. + */ +#define ISC_HTTPD_STATEIDLE 0 +#define ISC_HTTPD_STATERECV 1 +#define ISC_HTTPD_STATERECVDONE 2 +#define ISC_HTTPD_STATESEND 3 +#define ISC_HTTPD_STATESENDDONE 4 + +#define ISC_HTTPD_ISRECV(c) ((c)->state == ISC_HTTPD_STATERECV) +#define ISC_HTTPD_ISRECVDONE(c) ((c)->state == ISC_HTTPD_STATERECVDONE) +#define ISC_HTTPD_ISSEND(c) ((c)->state == ISC_HTTPD_STATESEND) +#define ISC_HTTPD_ISSENDDONE(c) ((c)->state == ISC_HTTPD_STATESENDDONE) + +/*% + * Overall magic test that means we're not idle. + */ +#define ISC_HTTPD_SETRECV(c) ((c)->state = ISC_HTTPD_STATERECV) +#define ISC_HTTPD_SETRECVDONE(c) ((c)->state = ISC_HTTPD_STATERECVDONE) +#define ISC_HTTPD_SETSEND(c) ((c)->state = ISC_HTTPD_STATESEND) +#define ISC_HTTPD_SETSENDDONE(c) ((c)->state = ISC_HTTPD_STATESENDDONE) + +static void isc_httpd_accept(isc_task_t *, isc_event_t *); +static void isc_httpd_recvdone(isc_task_t *, isc_event_t *); +static void isc_httpd_senddone(isc_task_t *, isc_event_t *); +static void destroy_client(isc_httpd_t **); +static isc_result_t process_request(isc_httpd_t *, int); +static void httpdmgr_destroy(isc_httpdmgr_t *); +static isc_result_t grow_headerspace(isc_httpd_t *); +static void reset_client(isc_httpd_t *httpd); +static isc_result_t render_404(const char *, const char *, + void *, + unsigned int *, const char **, + const char **, isc_buffer_t *, + isc_httpdfree_t **, void **); +static isc_result_t render_500(const char *, const char *, + void *, + unsigned int *, const char **, + const char **, isc_buffer_t *, + isc_httpdfree_t **, void **); + +static void +destroy_client(isc_httpd_t **httpdp) +{ + isc_httpd_t *httpd = *httpdp; + isc_httpdmgr_t *httpdmgr = httpd->mgr; + + *httpdp = NULL; + + LOCK(&httpdmgr->lock); + + isc_socket_detach(&httpd->sock); + ISC_LIST_UNLINK(httpdmgr->running, httpd, link); + + if (httpd->headerlen > 0) + isc_mem_put(httpdmgr->mctx, httpd->headerdata, + httpd->headerlen); + + isc_mem_put(httpdmgr->mctx, httpd, sizeof(isc_httpd_t)); + + UNLOCK(&httpdmgr->lock); + + httpdmgr_destroy(httpdmgr); +} + +isc_result_t +isc_httpdmgr_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task, + isc_httpdclientok_t *client_ok, + isc_httpdondestroy_t *ondestroy, void *cb_arg, + isc_timermgr_t *tmgr, isc_httpdmgr_t **httpdp) +{ + isc_result_t result; + isc_httpdmgr_t *httpd; + + REQUIRE(mctx != NULL); + REQUIRE(sock != NULL); + REQUIRE(task != NULL); + REQUIRE(tmgr != NULL); + REQUIRE(httpdp != NULL && *httpdp == NULL); + + httpd = isc_mem_get(mctx, sizeof(isc_httpdmgr_t)); + if (httpd == NULL) + return (ISC_R_NOMEMORY); + + result = isc_mutex_init(&httpd->lock); + if (result != ISC_R_SUCCESS) { + isc_mem_put(mctx, httpd, sizeof(isc_httpdmgr_t)); + return (result); + } + httpd->mctx = NULL; + isc_mem_attach(mctx, &httpd->mctx); + httpd->sock = NULL; + isc_socket_attach(sock, &httpd->sock); + httpd->task = NULL; + isc_task_attach(task, &httpd->task); + httpd->timermgr = tmgr; /* XXXMLG no attach function? */ + httpd->client_ok = client_ok; + httpd->ondestroy = ondestroy; + httpd->cb_arg = cb_arg; + + ISC_LIST_INIT(httpd->running); + ISC_LIST_INIT(httpd->urls); + + /* XXXMLG ignore errors on isc_socket_listen() */ + result = isc_socket_listen(sock, SOMAXCONN); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_socket_listen() failed: %s", + isc_result_totext(result)); + goto cleanup; + } + + (void)isc_socket_filter(sock, "httpready"); + + result = isc_socket_accept(sock, task, isc_httpd_accept, httpd); + if (result != ISC_R_SUCCESS) + goto cleanup; + + httpd->render_404 = render_404; + httpd->render_500 = render_500; + + *httpdp = httpd; + return (ISC_R_SUCCESS); + + cleanup: + isc_task_detach(&httpd->task); + isc_socket_detach(&httpd->sock); + isc_mem_detach(&httpd->mctx); + (void)isc_mutex_destroy(&httpd->lock); + isc_mem_put(mctx, httpd, sizeof(isc_httpdmgr_t)); + return (result); +} + +static void +httpdmgr_destroy(isc_httpdmgr_t *httpdmgr) +{ + isc_mem_t *mctx; + isc_httpdurl_t *url; + + ENTER("httpdmgr_destroy"); + + LOCK(&httpdmgr->lock); + + if (!MSHUTTINGDOWN(httpdmgr)) { + NOTICE("httpdmgr_destroy not shutting down yet"); + UNLOCK(&httpdmgr->lock); + return; + } + + /* + * If all clients are not shut down, don't do anything yet. + */ + if (!ISC_LIST_EMPTY(httpdmgr->running)) { + NOTICE("httpdmgr_destroy clients still active"); + UNLOCK(&httpdmgr->lock); + return; + } + + NOTICE("httpdmgr_destroy detaching socket, task, and timermgr"); + + isc_socket_detach(&httpdmgr->sock); + isc_task_detach(&httpdmgr->task); + httpdmgr->timermgr = NULL; + + /* + * Clear out the list of all actions we know about. Just free the + * memory. + */ + url = ISC_LIST_HEAD(httpdmgr->urls); + while (url != NULL) { + isc_mem_free(httpdmgr->mctx, url->url); + ISC_LIST_UNLINK(httpdmgr->urls, url, link); + isc_mem_put(httpdmgr->mctx, url, sizeof(isc_httpdurl_t)); + url = ISC_LIST_HEAD(httpdmgr->urls); + } + + UNLOCK(&httpdmgr->lock); + (void)isc_mutex_destroy(&httpdmgr->lock); + + if (httpdmgr->ondestroy != NULL) + (httpdmgr->ondestroy)(httpdmgr->cb_arg); + + mctx = httpdmgr->mctx; + isc_mem_putanddetach(&mctx, httpdmgr, sizeof(isc_httpdmgr_t)); + + EXIT("httpdmgr_destroy"); +} + +#define LENGTHOK(s) (httpd->recvbuf - (s) < (int)httpd->recvlen) +#define BUFLENOK(s) (httpd->recvbuf - (s) < HTTP_RECVLEN) + +static isc_result_t +process_request(isc_httpd_t *httpd, int length) +{ + char *s; + char *p; + int delim; + + ENTER("request"); + + httpd->recvlen += length; + + httpd->recvbuf[httpd->recvlen] = 0; + + /* + * If we don't find a blank line in our buffer, return that we need + * more data. + */ + s = strstr(httpd->recvbuf, "\r\n\r\n"); + delim = 1; + if (s == NULL) { + s = strstr(httpd->recvbuf, "\n\n"); + delim = 2; + } + if (s == NULL) + return (ISC_R_NOTFOUND); + + /* + * Determine if this is a POST or GET method. Any other values will + * cause an error to be returned. + */ + if (strncmp(httpd->recvbuf, "GET ", 4) == 0) { + httpd->method = ISC_HTTPD_METHODGET; + p = httpd->recvbuf + 4; + } else if (strncmp(httpd->recvbuf, "POST ", 5) == 0) { + httpd->method = ISC_HTTPD_METHODPOST; + p = httpd->recvbuf + 5; + } else { + return (ISC_R_RANGE); + } + + /* + * From now on, p is the start of our buffer. + */ + + /* + * Extract the URL. + */ + s = p; + while (LENGTHOK(s) && BUFLENOK(s) && + (*s != '\n' && *s != '\r' && *s != '\0' && *s != ' ')) + s++; + if (!LENGTHOK(s)) + return (ISC_R_NOTFOUND); + if (!BUFLENOK(s)) + return (ISC_R_NOMEMORY); + *s = 0; + + /* + * Make the URL relative. + */ + if ((strncmp(p, "http:/", 6) == 0) + || (strncmp(p, "https:/", 7) == 0)) { + /* Skip first / */ + while (*p != '/' && *p != 0) + p++; + if (*p == 0) + return (ISC_R_RANGE); + p++; + /* Skip second / */ + while (*p != '/' && *p != 0) + p++; + if (*p == 0) + return (ISC_R_RANGE); + p++; + /* Find third / */ + while (*p != '/' && *p != 0) + p++; + if (*p == 0) { + p--; + *p = '/'; + } + } + + httpd->url = p; + p = s + delim; + s = p; + + /* + * Now, see if there is a ? mark in the URL. If so, this is + * part of the query string, and we will split it from the URL. + */ + httpd->querystring = strchr(httpd->url, '?'); + if (httpd->querystring != NULL) { + *(httpd->querystring) = 0; + httpd->querystring++; + } + + /* + * Extract the HTTP/1.X protocol. We will bounce on anything but + * HTTP/1.1 for now. + */ + while (LENGTHOK(s) && BUFLENOK(s) && + (*s != '\n' && *s != '\r' && *s != '\0')) + s++; + if (!LENGTHOK(s)) + return (ISC_R_NOTFOUND); + if (!BUFLENOK(s)) + return (ISC_R_NOMEMORY); + *s = 0; + if ((strncmp(p, "HTTP/1.0", 8) != 0) + && (strncmp(p, "HTTP/1.1", 8) != 0)) + return (ISC_R_RANGE); + httpd->protocol = p; + p = s + 1; + s = p; + + if (strstr(s, "Connection: close") != NULL) + httpd->flags |= HTTPD_CLOSE; + + if (strstr(s, "Host: ") != NULL) + httpd->flags |= HTTPD_FOUNDHOST; + + /* + * Standards compliance hooks here. + */ + if (strcmp(httpd->protocol, "HTTP/1.1") == 0 + && ((httpd->flags & HTTPD_FOUNDHOST) == 0)) + return (ISC_R_RANGE); + + EXIT("request"); + + return (ISC_R_SUCCESS); +} + +static void +isc_httpd_accept(isc_task_t *task, isc_event_t *ev) +{ + isc_result_t result; + isc_httpdmgr_t *httpdmgr = ev->ev_arg; + isc_httpd_t *httpd; + isc_region_t r; + isc_socket_newconnev_t *nev = (isc_socket_newconnev_t *)ev; + isc_sockaddr_t peeraddr; + + ENTER("accept"); + + LOCK(&httpdmgr->lock); + if (MSHUTTINGDOWN(httpdmgr)) { + NOTICE("accept shutting down, goto out"); + goto out; + } + + if (nev->result == ISC_R_CANCELED) { + NOTICE("accept canceled, goto out"); + goto out; + } + + if (nev->result != ISC_R_SUCCESS) { + /* XXXMLG log failure */ + NOTICE("accept returned failure, goto requeue"); + goto requeue; + } + + (void)isc_socket_getpeername(nev->newsocket, &peeraddr); + if (httpdmgr->client_ok != NULL && + !(httpdmgr->client_ok)(&peeraddr, httpdmgr->cb_arg)) { + isc_socket_detach(&nev->newsocket); + goto requeue; + } + + httpd = isc_mem_get(httpdmgr->mctx, sizeof(isc_httpd_t)); + if (httpd == NULL) { + /* XXXMLG log failure */ + NOTICE("accept failed to allocate memory, goto requeue"); + isc_socket_detach(&nev->newsocket); + goto requeue; + } + + httpd->mgr = httpdmgr; + ISC_LINK_INIT(httpd, link); + ISC_LIST_APPEND(httpdmgr->running, httpd, link); + ISC_HTTPD_SETRECV(httpd); + httpd->sock = nev->newsocket; + isc_socket_setname(httpd->sock, "httpd", NULL); + httpd->flags = 0; + + /* + * Initialize the buffer for our headers. + */ + httpd->headerdata = isc_mem_get(httpdmgr->mctx, HTTP_SENDGROW); + if (httpd->headerdata == NULL) { + isc_mem_put(httpdmgr->mctx, httpd, sizeof(isc_httpd_t)); + isc_socket_detach(&nev->newsocket); + goto requeue; + } + httpd->headerlen = HTTP_SENDGROW; + isc_buffer_init(&httpd->headerbuffer, httpd->headerdata, + httpd->headerlen); + + ISC_LIST_INIT(httpd->bufflist); + + isc_buffer_initnull(&httpd->bodybuffer); + reset_client(httpd); + + r.base = (unsigned char *)httpd->recvbuf; + r.length = HTTP_RECVLEN - 1; + result = isc_socket_recv(httpd->sock, &r, 1, task, isc_httpd_recvdone, + httpd); + /* FIXME!!! */ + POST(result); + NOTICE("accept queued recv on socket"); + + requeue: + result = isc_socket_accept(httpdmgr->sock, task, isc_httpd_accept, + httpdmgr); + if (result != ISC_R_SUCCESS) { + /* XXXMLG what to do? Log failure... */ + NOTICE("accept could not reaccept due to failure"); + } + + out: + UNLOCK(&httpdmgr->lock); + + httpdmgr_destroy(httpdmgr); + + isc_event_free(&ev); + + EXIT("accept"); +} + +static isc_result_t +render_404(const char *url, const char *querystring, + void *arg, + unsigned int *retcode, const char **retmsg, + const char **mimetype, isc_buffer_t *b, + isc_httpdfree_t **freecb, void **freecb_args) +{ + static char msg[] = "No such URL."; + + UNUSED(url); + UNUSED(querystring); + UNUSED(arg); + + *retcode = 404; + *retmsg = "No such URL"; + *mimetype = "text/plain"; + isc_buffer_reinit(b, msg, strlen(msg)); + isc_buffer_add(b, strlen(msg)); + *freecb = NULL; + *freecb_args = NULL; + + return (ISC_R_SUCCESS); +} + +static isc_result_t +render_500(const char *url, const char *querystring, + void *arg, + unsigned int *retcode, const char **retmsg, + const char **mimetype, isc_buffer_t *b, + isc_httpdfree_t **freecb, void **freecb_args) +{ + static char msg[] = "Internal server failure."; + + UNUSED(url); + UNUSED(querystring); + UNUSED(arg); + + *retcode = 500; + *retmsg = "Internal server failure"; + *mimetype = "text/plain"; + isc_buffer_reinit(b, msg, strlen(msg)); + isc_buffer_add(b, strlen(msg)); + *freecb = NULL; + *freecb_args = NULL; + + return (ISC_R_SUCCESS); +} + +static void +isc_httpd_recvdone(isc_task_t *task, isc_event_t *ev) +{ + isc_region_t r; + isc_result_t result; + isc_httpd_t *httpd = ev->ev_arg; + isc_socketevent_t *sev = (isc_socketevent_t *)ev; + isc_httpdurl_t *url; + isc_time_t now; + char datebuf[32]; /* Only need 30, but safety first */ + + ENTER("recv"); + + INSIST(ISC_HTTPD_ISRECV(httpd)); + + if (sev->result != ISC_R_SUCCESS) { + NOTICE("recv destroying client"); + destroy_client(&httpd); + goto out; + } + + result = process_request(httpd, sev->n); + if (result == ISC_R_NOTFOUND) { + if (httpd->recvlen >= HTTP_RECVLEN - 1) { + destroy_client(&httpd); + goto out; + } + r.base = (unsigned char *)httpd->recvbuf + httpd->recvlen; + r.length = HTTP_RECVLEN - httpd->recvlen - 1; + /* check return code? */ + (void)isc_socket_recv(httpd->sock, &r, 1, task, + isc_httpd_recvdone, httpd); + goto out; + } else if (result != ISC_R_SUCCESS) { + destroy_client(&httpd); + goto out; + } + + ISC_HTTPD_SETSEND(httpd); + + /* + * XXXMLG Call function here. Provide an add-header function + * which will append the common headers to a response we generate. + */ + isc_buffer_initnull(&httpd->bodybuffer); + isc_time_now(&now); + isc_time_formathttptimestamp(&now, datebuf, sizeof(datebuf)); + url = ISC_LIST_HEAD(httpd->mgr->urls); + while (url != NULL) { + if (strcmp(httpd->url, url->url) == 0) + break; + url = ISC_LIST_NEXT(url, link); + } + if (url == NULL) + result = httpd->mgr->render_404(httpd->url, httpd->querystring, + NULL, + &httpd->retcode, + &httpd->retmsg, + &httpd->mimetype, + &httpd->bodybuffer, + &httpd->freecb, + &httpd->freecb_arg); + else + result = url->action(httpd->url, httpd->querystring, + url->action_arg, + &httpd->retcode, &httpd->retmsg, + &httpd->mimetype, &httpd->bodybuffer, + &httpd->freecb, &httpd->freecb_arg); + if (result != ISC_R_SUCCESS) { + result = httpd->mgr->render_500(httpd->url, httpd->querystring, + NULL, &httpd->retcode, + &httpd->retmsg, + &httpd->mimetype, + &httpd->bodybuffer, + &httpd->freecb, + &httpd->freecb_arg); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + } + + isc_httpd_response(httpd); + isc_httpd_addheader(httpd, "Content-Type", httpd->mimetype); + isc_httpd_addheader(httpd, "Date", datebuf); + isc_httpd_addheader(httpd, "Expires", datebuf); + isc_httpd_addheader(httpd, "Last-Modified", datebuf); + isc_httpd_addheader(httpd, "Pragma: no-cache", NULL); + isc_httpd_addheader(httpd, "Cache-Control: no-cache", NULL); + isc_httpd_addheader(httpd, "Server: libisc", NULL); + isc_httpd_addheaderuint(httpd, "Content-Length", + isc_buffer_usedlength(&httpd->bodybuffer)); + isc_httpd_endheaders(httpd); /* done */ + + ISC_LIST_APPEND(httpd->bufflist, &httpd->headerbuffer, link); + /* + * Link the data buffer into our send queue, should we have any data + * rendered into it. If no data is present, we won't do anything + * with the buffer. + */ + if (isc_buffer_length(&httpd->bodybuffer) > 0) + ISC_LIST_APPEND(httpd->bufflist, &httpd->bodybuffer, link); + + /* check return code? */ + (void)isc_socket_sendv(httpd->sock, &httpd->bufflist, task, + isc_httpd_senddone, httpd); + + out: + isc_event_free(&ev); + EXIT("recv"); +} + +void +isc_httpdmgr_shutdown(isc_httpdmgr_t **httpdmgrp) +{ + isc_httpdmgr_t *httpdmgr; + isc_httpd_t *httpd; + httpdmgr = *httpdmgrp; + *httpdmgrp = NULL; + + ENTER("isc_httpdmgr_shutdown"); + + LOCK(&httpdmgr->lock); + + MSETSHUTTINGDOWN(httpdmgr); + + isc_socket_cancel(httpdmgr->sock, httpdmgr->task, ISC_SOCKCANCEL_ALL); + + httpd = ISC_LIST_HEAD(httpdmgr->running); + while (httpd != NULL) { + isc_socket_cancel(httpd->sock, httpdmgr->task, + ISC_SOCKCANCEL_ALL); + httpd = ISC_LIST_NEXT(httpd, link); + } + + UNLOCK(&httpdmgr->lock); + + EXIT("isc_httpdmgr_shutdown"); +} + +static isc_result_t +grow_headerspace(isc_httpd_t *httpd) +{ + char *newspace; + unsigned int newlen; + isc_region_t r; + + newlen = httpd->headerlen + HTTP_SENDGROW; + if (newlen > HTTP_SEND_MAXLEN) + return (ISC_R_NOSPACE); + + newspace = isc_mem_get(httpd->mgr->mctx, newlen); + if (newspace == NULL) + return (ISC_R_NOMEMORY); + isc_buffer_region(&httpd->headerbuffer, &r); + isc_buffer_reinit(&httpd->headerbuffer, newspace, newlen); + + isc_mem_put(httpd->mgr->mctx, r.base, r.length); + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_httpd_response(isc_httpd_t *httpd) +{ + isc_result_t result; + unsigned int needlen; + + needlen = strlen(httpd->protocol) + 1; /* protocol + space */ + needlen += 3 + 1; /* room for response code, always 3 bytes */ + needlen += strlen(httpd->retmsg) + 2; /* return msg + CRLF */ + + while (isc_buffer_availablelength(&httpd->headerbuffer) < needlen) { + result = grow_headerspace(httpd); + if (result != ISC_R_SUCCESS) + return (result); + } + + sprintf(isc_buffer_used(&httpd->headerbuffer), "%s %03d %s\r\n", + httpd->protocol, httpd->retcode, httpd->retmsg); + isc_buffer_add(&httpd->headerbuffer, needlen); + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_httpd_addheader(isc_httpd_t *httpd, const char *name, + const char *val) +{ + isc_result_t result; + unsigned int needlen; + + needlen = strlen(name); /* name itself */ + if (val != NULL) + needlen += 2 + strlen(val); /* :<space> and val */ + needlen += 2; /* CRLF */ + + while (isc_buffer_availablelength(&httpd->headerbuffer) < needlen) { + result = grow_headerspace(httpd); + if (result != ISC_R_SUCCESS) + return (result); + } + + if (val != NULL) + sprintf(isc_buffer_used(&httpd->headerbuffer), + "%s: %s\r\n", name, val); + else + sprintf(isc_buffer_used(&httpd->headerbuffer), + "%s\r\n", name); + + isc_buffer_add(&httpd->headerbuffer, needlen); + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_httpd_endheaders(isc_httpd_t *httpd) +{ + isc_result_t result; + + while (isc_buffer_availablelength(&httpd->headerbuffer) < 2) { + result = grow_headerspace(httpd); + if (result != ISC_R_SUCCESS) + return (result); + } + + sprintf(isc_buffer_used(&httpd->headerbuffer), "\r\n"); + isc_buffer_add(&httpd->headerbuffer, 2); + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_httpd_addheaderuint(isc_httpd_t *httpd, const char *name, int val) { + isc_result_t result; + unsigned int needlen; + char buf[sizeof "18446744073709551616"]; + + sprintf(buf, "%d", val); + + needlen = strlen(name); /* name itself */ + needlen += 2 + strlen(buf); /* :<space> and val */ + needlen += 2; /* CRLF */ + + while (isc_buffer_availablelength(&httpd->headerbuffer) < needlen) { + result = grow_headerspace(httpd); + if (result != ISC_R_SUCCESS) + return (result); + } + + sprintf(isc_buffer_used(&httpd->headerbuffer), + "%s: %s\r\n", name, buf); + + isc_buffer_add(&httpd->headerbuffer, needlen); + + return (ISC_R_SUCCESS); +} + +static void +isc_httpd_senddone(isc_task_t *task, isc_event_t *ev) +{ + isc_httpd_t *httpd = ev->ev_arg; + isc_region_t r; + isc_socketevent_t *sev = (isc_socketevent_t *)ev; + + ENTER("senddone"); + INSIST(ISC_HTTPD_ISSEND(httpd)); + + /* + * First, unlink our header buffer from the socket's bufflist. This + * is sort of an evil hack, since we know our buffer will be there, + * and we know it's address, so we can just remove it directly. + */ + NOTICE("senddone unlinked header"); + ISC_LIST_UNLINK(sev->bufferlist, &httpd->headerbuffer, link); + + /* + * We will always want to clean up our receive buffer, even if we + * got an error on send or we are shutting down. + * + * We will pass in the buffer only if there is data in it. If + * there is no data, we will pass in a NULL. + */ + if (httpd->freecb != NULL) { + isc_buffer_t *b = NULL; + if (isc_buffer_length(&httpd->bodybuffer) > 0) + b = &httpd->bodybuffer; + httpd->freecb(b, httpd->freecb_arg); + NOTICE("senddone free callback performed"); + } + if (ISC_LINK_LINKED(&httpd->bodybuffer, link)) { + ISC_LIST_UNLINK(sev->bufferlist, &httpd->bodybuffer, link); + NOTICE("senddone body buffer unlinked"); + } + + if (sev->result != ISC_R_SUCCESS) { + destroy_client(&httpd); + goto out; + } + + if ((httpd->flags & HTTPD_CLOSE) != 0) { + destroy_client(&httpd); + goto out; + } + + ISC_HTTPD_SETRECV(httpd); + + NOTICE("senddone restarting recv on socket"); + + reset_client(httpd); + + r.base = (unsigned char *)httpd->recvbuf; + r.length = HTTP_RECVLEN - 1; + /* check return code? */ + (void)isc_socket_recv(httpd->sock, &r, 1, task, + isc_httpd_recvdone, httpd); + +out: + isc_event_free(&ev); + EXIT("senddone"); +} + +static void +reset_client(isc_httpd_t *httpd) +{ + /* + * Catch errors here. We MUST be in RECV mode, and we MUST NOT have + * any outstanding buffers. If we have buffers, we have a leak. + */ + INSIST(ISC_HTTPD_ISRECV(httpd)); + INSIST(!ISC_LINK_LINKED(&httpd->headerbuffer, link)); + INSIST(!ISC_LINK_LINKED(&httpd->bodybuffer, link)); + + httpd->recvbuf[0] = 0; + httpd->recvlen = 0; + httpd->method = ISC_HTTPD_METHODUNKNOWN; + httpd->url = NULL; + httpd->querystring = NULL; + httpd->protocol = NULL; + httpd->flags = 0; + + isc_buffer_clear(&httpd->headerbuffer); + isc_buffer_invalidate(&httpd->bodybuffer); +} + +isc_result_t +isc_httpdmgr_addurl(isc_httpdmgr_t *httpdmgr, const char *url, + isc_httpdaction_t *func, void *arg) +{ + isc_httpdurl_t *item; + + if (url == NULL) { + httpdmgr->render_404 = func; + return (ISC_R_SUCCESS); + } + + item = isc_mem_get(httpdmgr->mctx, sizeof(isc_httpdurl_t)); + if (item == NULL) + return (ISC_R_NOMEMORY); + + item->url = isc_mem_strdup(httpdmgr->mctx, url); + if (item->url == NULL) { + isc_mem_put(httpdmgr->mctx, item, sizeof(isc_httpdurl_t)); + return (ISC_R_NOMEMORY); + } + + item->action = func; + item->action_arg = arg; + ISC_LINK_INIT(item, link); + ISC_LIST_APPEND(httpdmgr->urls, item, link); + + return (ISC_R_SUCCESS); +} diff --git a/contrib/ntp/lib/isc/ia64/include/isc/atomic.h b/contrib/ntp/lib/isc/ia64/include/isc/atomic.h new file mode 100644 index 0000000..6c22f2a --- /dev/null +++ b/contrib/ntp/lib/isc/ia64/include/isc/atomic.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2006, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: atomic.h,v 1.7 2009/06/24 02:22:50 marka Exp $ */ + +#ifndef ISC_ATOMIC_H +#define ISC_ATOMIC_H 1 + +#include <isc/platform.h> +#include <isc/types.h> + +#ifdef ISC_PLATFORM_USEGCCASM +/* + * This routine atomically increments the value stored in 'p' by 'val', and + * returns the previous value. + * + * Open issue: can 'fetchadd' make the code faster for some particular values + * (e.g., 1 and -1)? + */ +static inline isc_int32_t +#ifdef __GNUC__ +__attribute__ ((unused)) +#endif +isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) +{ + isc_int32_t prev, swapped; + + for (prev = *(volatile isc_int32_t *)p; ; prev = swapped) { + swapped = prev + val; + __asm__ volatile( + "mov ar.ccv=%2;" + "cmpxchg4.acq %0=%4,%3,ar.ccv" + : "=r" (swapped), "=m" (*p) + : "r" (prev), "r" (swapped), "m" (*p) + : "memory"); + if (swapped == prev) + break; + } + + return (prev); +} + +/* + * This routine atomically stores the value 'val' in 'p'. + */ +static inline void +#ifdef __GNUC__ +__attribute__ ((unused)) +#endif +isc_atomic_store(isc_int32_t *p, isc_int32_t val) +{ + __asm__ volatile( + "st4.rel %0=%1" + : "=m" (*p) + : "r" (val) + : "memory" + ); +} + +/* + * This routine atomically replaces the value in 'p' with 'val', if the + * original value is equal to 'cmpval'. The original value is returned in any + * case. + */ +static inline isc_int32_t +#ifdef __GNUC__ +__attribute__ ((unused)) +#endif +isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) +{ + isc_int32_t ret; + + __asm__ volatile( + "mov ar.ccv=%2;" + "cmpxchg4.acq %0=%4,%3,ar.ccv" + : "=r" (ret), "=m" (*p) + : "r" (cmpval), "r" (val), "m" (*p) + : "memory"); + + return (ret); +} +#else /* !ISC_PLATFORM_USEGCCASM */ + +#error "unsupported compiler. disable atomic ops by --disable-atomic" + +#endif +#endif /* ISC_ATOMIC_H */ diff --git a/contrib/ntp/lib/isc/include/isc/app.h b/contrib/ntp/lib/isc/include/isc/app.h new file mode 100644 index 0000000..e0be790 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/app.h @@ -0,0 +1,375 @@ +/* + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: app.h,v 1.11 2009/09/02 23:48:03 tbox Exp $ */ + +#ifndef ISC_APP_H +#define ISC_APP_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file isc/app.h + * \brief ISC Application Support + * + * Dealing with program termination can be difficult, especially in a + * multithreaded program. The routines in this module help coordinate + * the shutdown process. They are used as follows by the initial (main) + * thread of the application: + * + *\li isc_app_start(); Call very early in main(), before + * any other threads have been created. + * + *\li isc_app_run(); This will post any on-run events, + * and then block until application + * shutdown is requested. A shutdown + * request is made by calling + * isc_app_shutdown(), or by sending + * SIGINT or SIGTERM to the process. + * After isc_app_run() returns, the + * application should shutdown itself. + * + *\li isc_app_finish(); Call very late in main(). + * + * Applications that want to use SIGHUP/isc_app_reload() to trigger reloading + * should check the result of isc_app_run() and call the reload routine if + * the result is ISC_R_RELOAD. They should then call isc_app_run() again + * to resume waiting for reload or termination. + * + * Use of this module is not required. In particular, isc_app_start() is + * NOT an ISC library initialization routine. + * + * This module also supports per-thread 'application contexts'. With this + * mode, a thread-based application will have a separate context, in which + * it uses other ISC library services such as tasks or timers. Signals are + * not caught in this mode, so that the application can handle the signals + * in its preferred way. + * + * \li MP: + * Clients must ensure that isc_app_start(), isc_app_run(), and + * isc_app_finish() are called at most once. isc_app_shutdown() + * is safe to use by any thread (provided isc_app_start() has been + * called previously). + * + * The same note applies to isc_app_ctxXXX() functions, but in this case + * it's a per-thread restriction. For example, a thread with an + * application context must ensure that isc_app_ctxstart() with the + * context is called at most once. + * + * \li Reliability: + * No anticipated impact. + * + * \li Resources: + * None. + * + * \li Security: + * No anticipated impact. + * + * \li Standards: + * None. + */ + +#include <isc/eventclass.h> +#include <isc/lang.h> +#include <isc/magic.h> +#include <isc/result.h> + +/*** + *** Types + ***/ + +typedef isc_event_t isc_appevent_t; + +#define ISC_APPEVENT_FIRSTEVENT (ISC_EVENTCLASS_APP + 0) +#define ISC_APPEVENT_SHUTDOWN (ISC_EVENTCLASS_APP + 1) +#define ISC_APPEVENT_LASTEVENT (ISC_EVENTCLASS_APP + 65535) + +/*% + * app module methods. Only app driver implementations use this structure. + * Other clients should use the top-level interfaces (i.e., isc_app_xxx + * functions). magic must be ISCAPI_APPMETHODS_MAGIC. + */ +typedef struct isc_appmethods { + void (*ctxdestroy)(isc_appctx_t **ctxp); + isc_result_t (*ctxstart)(isc_appctx_t *ctx); + isc_result_t (*ctxrun)(isc_appctx_t *ctx); + isc_result_t (*ctxsuspend)(isc_appctx_t *ctx); + isc_result_t (*ctxshutdown)(isc_appctx_t *ctx); + void (*ctxfinish)(isc_appctx_t *ctx); + void (*settaskmgr)(isc_appctx_t *ctx, + isc_taskmgr_t *timermgr); + void (*setsocketmgr)(isc_appctx_t *ctx, + isc_socketmgr_t *timermgr); + void (*settimermgr)(isc_appctx_t *ctx, + isc_timermgr_t *timermgr); +} isc_appmethods_t; + +/*% + * This structure is actually just the common prefix of an application context + * implementation's version of an isc_appctx_t. + * \brief + * Direct use of this structure by clients is forbidden. app implementations + * may change the structure. 'magic' must be ISCAPI_APPCTX_MAGIC for any + * of the isc_app_ routines to work. app implementations must maintain + * all app context invariants. + */ +struct isc_appctx { + unsigned int impmagic; + unsigned int magic; + isc_appmethods_t *methods; +}; + +#define ISCAPI_APPCTX_MAGIC ISC_MAGIC('A','a','p','c') +#define ISCAPI_APPCTX_VALID(c) ((c) != NULL && \ + (c)->magic == ISCAPI_APPCTX_MAGIC) + +ISC_LANG_BEGINDECLS + +isc_result_t +isc_app_ctxstart(isc_appctx_t *ctx); + +isc_result_t +isc_app_start(void); +/*!< + * \brief Start an ISC library application. + * + * Notes: + * This call should be made before any other ISC library call, and as + * close to the beginning of the application as possible. + * + * Requires: + * 'ctx' is a valid application context (for app_ctxstart()). + */ + +isc_result_t +isc_app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action, + void *arg); +/*!< + * \brief Request delivery of an event when the application is run. + * + * Requires: + *\li isc_app_start() has been called. + * + * Returns: + * ISC_R_SUCCESS + * ISC_R_NOMEMORY + */ + +isc_result_t +isc_app_ctxrun(isc_appctx_t *ctx); + +isc_result_t +isc_app_run(void); +/*!< + * \brief Run an ISC library application. + * + * Notes: + *\li The caller (typically the initial thread of an application) will + * block until shutdown is requested. When the call returns, the + * caller should start shutting down the application. + * + * Requires: + *\li isc_app_[ctx]start() has been called. + * + * Ensures: + *\li Any events requested via isc_app_onrun() will have been posted (in + * FIFO order) before isc_app_run() blocks. + *\li 'ctx' is a valid application context (for app_ctxrun()). + * + * Returns: + *\li ISC_R_SUCCESS Shutdown has been requested. + *\li ISC_R_RELOAD Reload has been requested. + */ + +isc_result_t +isc_app_ctxshutdown(isc_appctx_t *ctx); + +isc_result_t +isc_app_shutdown(void); +/*!< + * \brief Request application shutdown. + * + * Notes: + *\li It is safe to call isc_app_shutdown() multiple times. Shutdown will + * only be triggered once. + * + * Requires: + *\li isc_app_[ctx]run() has been called. + *\li 'ctx' is a valid application context (for app_ctxshutdown()). + * + * Returns: + *\li ISC_R_SUCCESS + *\li ISC_R_UNEXPECTED + */ + +isc_result_t +isc_app_ctxsuspend(isc_appctx_t *ctx); +/*!< + * \brief This has the same behavior as isc_app_ctxsuspend(). + */ + +isc_result_t +isc_app_reload(void); +/*!< + * \brief Request application reload. + * + * Requires: + *\li isc_app_run() has been called. + * + * Returns: + *\li ISC_R_SUCCESS + *\li ISC_R_UNEXPECTED + */ + +void +isc_app_ctxfinish(isc_appctx_t *ctx); + +void +isc_app_finish(void); +/*!< + * \brief Finish an ISC library application. + * + * Notes: + *\li This call should be made at or near the end of main(). + * + * Requires: + *\li isc_app_start() has been called. + *\li 'ctx' is a valid application context (for app_ctxfinish()). + * + * Ensures: + *\li Any resources allocated by isc_app_start() have been released. + */ + +void +isc_app_block(void); +/*!< + * \brief Indicate that a blocking operation will be performed. + * + * Notes: + *\li If a blocking operation is in process, a call to isc_app_shutdown() + * or an external signal will abort the program, rather than allowing + * clean shutdown. This is primarily useful for reading user input. + * + * Requires: + * \li isc_app_start() has been called. + * \li No other blocking operations are in progress. + */ + +void +isc_app_unblock(void); +/*!< + * \brief Indicate that a blocking operation is complete. + * + * Notes: + * \li When a blocking operation has completed, return the program to a + * state where a call to isc_app_shutdown() or an external signal will + * shutdown normally. + * + * Requires: + * \li isc_app_start() has been called. + * \li isc_app_block() has been called by the same thread. + */ + +isc_result_t +isc_appctx_create(isc_mem_t *mctx, isc_appctx_t **ctxp); +/*!< + * \brief Create an application context. + * + * Requires: + *\li 'mctx' is a valid memory context. + *\li 'ctxp' != NULL && *ctxp == NULL. + */ + +void +isc_appctx_destroy(isc_appctx_t **ctxp); +/*!< + * \brief Destroy an application context. + * + * Requires: + *\li '*ctxp' is a valid application context. + * + * Ensures: + *\li *ctxp == NULL. + */ + +void +isc_appctx_settaskmgr(isc_appctx_t *ctx, isc_taskmgr_t *taskmgr); +/*!< + * \brief Associate a task manager with an application context. + * + * This must be done before running tasks within the application context. + * + * Requires: + *\li 'ctx' is a valid application context. + *\li 'taskmgr' is a valid task manager. + */ + +void +isc_appctx_setsocketmgr(isc_appctx_t *ctx, isc_socketmgr_t *socketmgr); +/*!< + * \brief Associate a socket manager with an application context. + * + * This must be done before handling socket events within the application + * context. + * + * Requires: + *\li 'ctx' is a valid application context. + *\li 'socketmgr' is a valid socket manager. + */ + +void +isc_appctx_settimermgr(isc_appctx_t *ctx, isc_timermgr_t *timermgr); +/*!< + * \brief Associate a socket timer with an application context. + * + * This must be done before handling timer events within the application + * context. + * + * Requires: + *\li 'ctx' is a valid application context. + *\li 'timermgr' is a valid timer manager. + */ + +#ifdef USE_APPIMPREGISTER +/*%< + * See isc_appctx_create() above. + */ +typedef isc_result_t +(*isc_appctxcreatefunc_t)(isc_mem_t *mctx, isc_appctx_t **ctxp); + +isc_result_t +isc_app_register(isc_appctxcreatefunc_t createfunc); +/*%< + * Register a new application implementation and add it to the list of + * supported implementations. This function must be called when a different + * event library is used than the one contained in the ISC library. + */ + +isc_result_t +isc__app_register(void); +/*%< + * A short cut function that specifies the application module in the ISC + * library for isc_app_register(). An application that uses the ISC library + * usually do not have to care about this function: it would call + * isc_lib_register(), which internally calls this function. + */ +#endif /* USE_APPIMPREGISTER */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_APP_H */ diff --git a/contrib/ntp/lib/isc/include/isc/assertions.h b/contrib/ntp/lib/isc/include/isc/assertions.h new file mode 100644 index 0000000..2c81b1a --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/assertions.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1997-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* + * $Id: assertions.h,v 1.28 2009/09/29 23:48:04 tbox Exp $ + */ +/*! \file isc/assertions.h + */ + +#ifndef ISC_ASSERTIONS_H +#define ISC_ASSERTIONS_H 1 + +#include <isc/lang.h> +#include <isc/platform.h> + +ISC_LANG_BEGINDECLS + +/*% isc assertion type */ +typedef enum { + isc_assertiontype_require, + isc_assertiontype_ensure, + isc_assertiontype_insist, + isc_assertiontype_invariant +} isc_assertiontype_t; + +typedef void (*isc_assertioncallback_t)(const char *, int, isc_assertiontype_t, + const char *); + +/* coverity[+kill] */ +ISC_PLATFORM_NORETURN_PRE +void isc_assertion_failed(const char *, int, isc_assertiontype_t, + const char *) ISC_PLATFORM_NORETURN_POST; + +void +isc_assertion_setcallback(isc_assertioncallback_t); + +const char * +isc_assertion_typetotext(isc_assertiontype_t type); + +#if defined(ISC_CHECK_ALL) || defined(__COVERITY__) +#define ISC_CHECK_REQUIRE 1 +#define ISC_CHECK_ENSURE 1 +#define ISC_CHECK_INSIST 1 +#define ISC_CHECK_INVARIANT 1 +#endif + +#if defined(ISC_CHECK_NONE) && !defined(__COVERITY__) +#define ISC_CHECK_REQUIRE 0 +#define ISC_CHECK_ENSURE 0 +#define ISC_CHECK_INSIST 0 +#define ISC_CHECK_INVARIANT 0 +#endif + +#ifndef ISC_CHECK_REQUIRE +#define ISC_CHECK_REQUIRE 1 +#endif + +#ifndef ISC_CHECK_ENSURE +#define ISC_CHECK_ENSURE 1 +#endif + +#ifndef ISC_CHECK_INSIST +#define ISC_CHECK_INSIST 1 +#endif + +#ifndef ISC_CHECK_INVARIANT +#define ISC_CHECK_INVARIANT 1 +#endif + +#if ISC_CHECK_REQUIRE != 0 +#define ISC_REQUIRE(cond) \ + ((void) ((cond) || \ + ((isc_assertion_failed)(__FILE__, __LINE__, \ + isc_assertiontype_require, \ + #cond), 0))) +#else +#define ISC_REQUIRE(cond) ((void) 0) +#endif /* ISC_CHECK_REQUIRE */ + +#if ISC_CHECK_ENSURE != 0 +#define ISC_ENSURE(cond) \ + ((void) ((cond) || \ + ((isc_assertion_failed)(__FILE__, __LINE__, \ + isc_assertiontype_ensure, \ + #cond), 0))) +#else +#define ISC_ENSURE(cond) ((void) 0) +#endif /* ISC_CHECK_ENSURE */ + +#if ISC_CHECK_INSIST != 0 +#define ISC_INSIST(cond) \ + ((void) ((cond) || \ + ((isc_assertion_failed)(__FILE__, __LINE__, \ + isc_assertiontype_insist, \ + #cond), 0))) +#else +#define ISC_INSIST(cond) ((void) 0) +#endif /* ISC_CHECK_INSIST */ + +#if ISC_CHECK_INVARIANT != 0 +#define ISC_INVARIANT(cond) \ + ((void) ((cond) || \ + ((isc_assertion_failed)(__FILE__, __LINE__, \ + isc_assertiontype_invariant, \ + #cond), 0))) +#else +#define ISC_INVARIANT(cond) ((void) 0) +#endif /* ISC_CHECK_INVARIANT */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_ASSERTIONS_H */ diff --git a/contrib/ntp/lib/isc/include/isc/backtrace.h b/contrib/ntp/lib/isc/include/isc/backtrace.h new file mode 100644 index 0000000..7d7fc32 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/backtrace.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: backtrace.h,v 1.2 2009/09/01 18:40:25 jinmei Exp $ */ + +/*! \file isc/backtrace.h + * \brief provide a back trace of the running process to help debug problems. + * + * This module tries to get a back trace of the process using some platform + * dependent way when available. It also manages an internal symbol table + * that maps function addresses used in the process to their textual symbols. + * This module is expected to be used to help debug when some fatal error + * happens. + * + * IMPORTANT NOTE: since the (major) intended use case of this module is + * dumping a back trace on a fatal error, normally followed by self termination, + * functions defined in this module generally doesn't employ assertion checks + * (if it did, a program bug could cause infinite recursive calls to a + * backtrace function). These functions still perform minimal checks and return + * ISC_R_FAILURE if they detect an error, but the caller should therefore be + * very careful about the use of these functions, and generally discouraged to + * use them except in an exit path. The exception is + * isc_backtrace_getsymbolfromindex(), which is expected to be used in a + * non-error-handling context and validates arguments with assertion checks. + */ + +#ifndef ISC_BACKTRACE_H +#define ISC_BACKTRACE_H 1 + +/*** + *** Imports + ***/ + +#include <isc/types.h> + +/*** + *** Types + ***/ +struct isc_backtrace_symmap { + void *addr; + const char *symbol; +}; + +extern const int isc__backtrace_nsymbols; +extern const isc_backtrace_symmap_t isc__backtrace_symtable[]; + +/*** + *** Functions + ***/ + +ISC_LANG_BEGINDECLS +isc_result_t +isc_backtrace_gettrace(void **addrs, int maxaddrs, int *nframes); +/*%< + * Get a back trace of the running process above this function itself. On + * success, addrs[i] will store the address of the call point of the i-th + * stack frame (addrs[0] is the caller of this function). *nframes will store + * the total number of frames. + * + * Requires (note that these are not ensured by assertion checks, see above): + * + *\li 'addrs' is a valid array containing at least 'maxaddrs' void * entries. + * + *\li 'nframes' must be non NULL. + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_FAILURE + *\li #ISC_R_NOTFOUND + *\li #ISC_R_NOTIMPLEMENTED + */ + +isc_result_t +isc_backtrace_getsymbolfromindex(int idx, const void **addrp, + const char **symbolp); +/*%< + * Returns the content of the internal symbol table of the given index. + * On success, *addrsp and *symbolp point to the address and the symbol of + * the 'index'th entry of the table, respectively. If 'idx' is not in the + * range of the symbol table, ISC_R_RANGE will be returned. + * + * Requires + * + *\li 'addrp' must be non NULL && '*addrp' == NULL. + * + *\li 'symbolp' must be non NULL && '*symbolp' == NULL. + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_RANGE + */ + +isc_result_t +isc_backtrace_getsymbol(const void *addr, const char **symbolp, + unsigned long *offsetp); +/*%< + * Searches the internal symbol table for the symbol that most matches the + * given 'addr'. On success, '*symbolp' will point to the name of function + * to which the address 'addr' belong, and '*offsetp' will store the offset + * from the function's entry address to 'addr'. + * + * Requires (note that these are not ensured by assertion checks, see above): + * + *\li 'symbolp' must be non NULL && '*symbolp' == NULL. + * + *\li 'offsetp' must be non NULL. + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_FAILURE + *\li #ISC_R_NOTFOUND + */ +ISC_LANG_ENDDECLS + +#endif /* ISC_BACKTRACE_H */ diff --git a/contrib/ntp/lib/isc/include/isc/base32.h b/contrib/ntp/lib/isc/include/isc/base32.h new file mode 100644 index 0000000..978a8db --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/base32.h @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2008 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: base32.h,v 1.3 2008/09/25 04:02:39 tbox Exp $ */ + +#ifndef ISC_BASE32_H +#define ISC_BASE32_H 1 + +/*! \file */ + +/* + * Routines for manipulating base 32 and base 32 hex encoded data. + * Based on RFC 4648. + * + * Base 32 hex preserves the sort order of data when it is encoded / + * decoded. + */ + +#include <isc/lang.h> +#include <isc/types.h> + +ISC_LANG_BEGINDECLS + +/*** + *** Functions + ***/ + +isc_result_t +isc_base32_totext(isc_region_t *source, int wordlength, + const char *wordbreak, isc_buffer_t *target); +isc_result_t +isc_base32hex_totext(isc_region_t *source, int wordlength, + const char *wordbreak, isc_buffer_t *target); +/*!< + * \brief Convert data into base32 encoded text. + * + * Notes: + *\li The base32 encoded text in 'target' will be divided into + * words of at most 'wordlength' characters, separated by + * the 'wordbreak' string. No parentheses will surround + * the text. + * + * Requires: + *\li 'source' is a region containing binary data + *\li 'target' is a text buffer containing available space + *\li 'wordbreak' points to a null-terminated string of + * zero or more whitespace characters + * + * Ensures: + *\li target will contain the base32 encoded version of the data + * in source. The 'used' pointer in target will be advanced as + * necessary. + */ + +isc_result_t +isc_base32_decodestring(const char *cstr, isc_buffer_t *target); +isc_result_t +isc_base32hex_decodestring(const char *cstr, isc_buffer_t *target); +/*!< + * \brief Decode a null-terminated base32 string. + * + * Requires: + *\li 'cstr' is non-null. + *\li 'target' is a valid buffer. + * + * Returns: + *\li #ISC_R_SUCCESS -- the entire decoded representation of 'cstring' + * fit in 'target'. + *\li #ISC_R_BADBASE32 -- 'cstr' is not a valid base32 encoding. + * + * Other error returns are any possible error code from: + *\li isc_lex_create(), + *\li isc_lex_openbuffer(), + *\li isc_base32_tobuffer(). + */ + +isc_result_t +isc_base32_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length); +isc_result_t +isc_base32hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length); +/*!< + * \brief Convert base32 encoded text from a lexer context into data. + * + * Requires: + *\li 'lex' is a valid lexer context + *\li 'target' is a buffer containing binary data + *\li 'length' is an integer + * + * Ensures: + *\li target will contain the data represented by the base32 encoded + * string parsed by the lexer. No more than length bytes will be read, + * if length is positive. The 'used' pointer in target will be + * advanced as necessary. + */ + +isc_result_t +isc_base32_decoderegion(isc_region_t *source, isc_buffer_t *target); +isc_result_t +isc_base32hex_decoderegion(isc_region_t *source, isc_buffer_t *target); +/*!< + * \brief Decode a packed (no white space permitted) base32 region. + * + * Requires: + *\li 'source' is a valid region. + *\li 'target' is a valid buffer. + * + * Returns: + *\li #ISC_R_SUCCESS -- the entire decoded representation of 'cstring' + * fit in 'target'. + *\li #ISC_R_BADBASE32 -- 'source' is not a valid base32 encoding. + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_BASE32_H */ diff --git a/contrib/ntp/lib/isc/include/isc/base64.h b/contrib/ntp/lib/isc/include/isc/base64.h new file mode 100644 index 0000000..e48ef2a --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/base64.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: base64.h,v 1.22 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_BASE64_H +#define ISC_BASE64_H 1 + +/*! \file isc/base64.h */ + +#include <isc/lang.h> +#include <isc/types.h> + +ISC_LANG_BEGINDECLS + +/*** + *** Functions + ***/ + +isc_result_t +isc_base64_totext(isc_region_t *source, int wordlength, + const char *wordbreak, isc_buffer_t *target); +/*!< + * \brief Convert data into base64 encoded text. + * + * Notes: + *\li The base64 encoded text in 'target' will be divided into + * words of at most 'wordlength' characters, separated by + * the 'wordbreak' string. No parentheses will surround + * the text. + * + * Requires: + *\li 'source' is a region containing binary data + *\li 'target' is a text buffer containing available space + *\li 'wordbreak' points to a null-terminated string of + * zero or more whitespace characters + * + * Ensures: + *\li target will contain the base64 encoded version of the data + * in source. The 'used' pointer in target will be advanced as + * necessary. + */ + +isc_result_t +isc_base64_decodestring(const char *cstr, isc_buffer_t *target); +/*!< + * \brief Decode a null-terminated base64 string. + * + * Requires: + *\li 'cstr' is non-null. + *\li 'target' is a valid buffer. + * + * Returns: + *\li #ISC_R_SUCCESS -- the entire decoded representation of 'cstring' + * fit in 'target'. + *\li #ISC_R_BADBASE64 -- 'cstr' is not a valid base64 encoding. + * + * Other error returns are any possible error code from: + *\li isc_lex_create(), + *\li isc_lex_openbuffer(), + *\li isc_base64_tobuffer(). + */ + +isc_result_t +isc_base64_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length); +/*!< + * \brief Convert base64 encoded text from a lexer context into data. + * + * Requires: + *\li 'lex' is a valid lexer context + *\li 'target' is a buffer containing binary data + *\li 'length' is an integer + * + * Ensures: + *\li target will contain the data represented by the base64 encoded + * string parsed by the lexer. No more than length bytes will be read, + * if length is positive. The 'used' pointer in target will be + * advanced as necessary. + */ + + + +ISC_LANG_ENDDECLS + +#endif /* ISC_BASE64_H */ diff --git a/contrib/ntp/lib/isc/include/isc/bind9.h b/contrib/ntp/lib/isc/include/isc/bind9.h new file mode 100644 index 0000000..00bcb24 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/bind9.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: bind9.h,v 1.2 2009/12/05 23:31:41 each Exp $ */ + +#ifndef ISC_BIND9_H +#define ISC_BIND9_H 1 + +/* + * This determines whether we are building BIND9 or using the exported + * libisc/libdns libraries. The version of this file included in the + * standard BIND9 build defines BIND9; the version included with the + * exportable libraries does not. + */ +#define BIND9 1 + +#endif /* ISC_BIND9_H */ diff --git a/contrib/ntp/lib/isc/include/isc/bitstring.h b/contrib/ntp/lib/isc/include/isc/bitstring.h new file mode 100644 index 0000000..252d111 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/bitstring.h @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: bitstring.h,v 1.14 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_BITSTRING_H +#define ISC_BITSTRING_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file isc/bitstring.h + * + * \brief Bitstring manipulation functions. + * + * A bitstring is a packed array of bits, stored in a contiguous + * sequence of octets. The "most significant bit" (msb) of a bitstring + * is the high bit of the first octet. The "least significant bit" of a + * bitstring is the low bit of the last octet. + * + * Two bit numbering schemes are supported, "msb0" and "lsb0". + * + * In the "msb0" scheme, bit number 0 designates the most significant bit, + * and any padding bits required to make the bitstring a multiple of 8 bits + * long are added to the least significant end of the last octet. + * + * In the "lsb0" scheme, bit number 0 designates the least significant bit, + * and any padding bits required to make the bitstring a multiple of 8 bits + * long are added to the most significant end of the first octet. + * + * E.g., consider the bitstring "11010001111". This bitstring is 11 bits + * long and will take two octets. Let "p" denote a pad bit. In the msb0 + * encoding, it would be + * + * \verbatim + * Octet 0 Octet 1 + * | + * 1 1 0 1 0 0 0 1 | 1 1 1 p p p p p + * ^ | ^ + * | | + * bit 0 bit 15 + * \endverbatim + * + * In the lsb0 encoding, it would be + * + * \verbatim + * Octet 0 Octet 1 + * | + * p p p p p 1 1 0 | 1 0 0 0 1 1 1 1 + * ^ | ^ + * | | + * bit 15 bit 0 + * \endverbatim + */ + +/*** + *** Imports + ***/ + +#include <isc/lang.h> +#include <isc/types.h> + +ISC_LANG_BEGINDECLS + +/*** + *** Types + ***/ + +struct isc_bitstring { + unsigned int magic; + unsigned char * data; + unsigned int length; + unsigned int size; + isc_boolean_t lsb0; +}; + +/*** + *** Functions + ***/ + +void +isc_bitstring_init(isc_bitstring_t *bitstring, unsigned char *data, + unsigned int length, unsigned int size, isc_boolean_t lsb0); +/*!< + * \brief Make 'bitstring' refer to the bitstring of 'size' bits starting + * at 'data'. 'length' bits of the bitstring are valid. If 'lsb0' + * is set then, bit 0 refers to the least significant bit of the + * bitstring. Otherwise bit 0 is the most significant bit. + * + * Requires: + * + *\li 'bitstring' points to a isc_bitstring_t. + * + *\li 'data' points to an array of unsigned char large enough to hold + * 'size' bits. + * + *\li 'length' <= 'size'. + * + * Ensures: + * + *\li 'bitstring' is a valid bitstring. + */ + +void +isc_bitstring_invalidate(isc_bitstring_t *bitstring); +/*!< + * \brief Invalidate 'bitstring'. + * + * Requires: + * + *\li 'bitstring' is a valid bitstring. + * + * Ensures: + * + *\li 'bitstring' is not a valid bitstring. + */ + +void +isc_bitstring_copy(isc_bitstring_t *source, unsigned int sbitpos, + isc_bitstring_t *target, unsigned int tbitpos, + unsigned int n); +/*!< + * \brief Starting at bit 'sbitpos', copy 'n' bits from 'source' to + * the 'n' bits of 'target' starting at 'tbitpos'. + * + * Requires: + * + *\li 'source' and target are valid bitstrings with the same lsb0 setting. + * + *\li 'sbitpos' + 'n' is less than or equal to the length of 'source'. + * + *\li 'tbitpos' + 'n' is less than or equal to the size of 'target'. + * + * Ensures: + * + *\li The specified bits have been copied, and the length of 'target' + * adjusted (if required). + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_BITSTRING_H */ diff --git a/contrib/ntp/lib/isc/include/isc/boolean.h b/contrib/ntp/lib/isc/include/isc/boolean.h new file mode 100644 index 0000000..348b096 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/boolean.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: boolean.h,v 1.19 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_BOOLEAN_H +#define ISC_BOOLEAN_H 1 + +/*! \file isc/boolean.h */ + +typedef enum { isc_boolean_false = 0, isc_boolean_true = 1 } isc_boolean_t; + +#define ISC_FALSE isc_boolean_false +#define ISC_TRUE isc_boolean_true +#define ISC_TF(x) ((x) ? ISC_TRUE : ISC_FALSE) + +#endif /* ISC_BOOLEAN_H */ diff --git a/contrib/ntp/lib/isc/include/isc/buffer.h b/contrib/ntp/lib/isc/include/isc/buffer.h new file mode 100644 index 0000000..ae7e4c3 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/buffer.h @@ -0,0 +1,904 @@ +/* + * Copyright (C) 2004-2008, 2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: buffer.h,v 1.55 2010/12/20 23:47:21 tbox Exp $ */ + +#ifndef ISC_BUFFER_H +#define ISC_BUFFER_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file isc/buffer.h + * + * \brief A buffer is a region of memory, together with a set of related subregions. + * Buffers are used for parsing and I/O operations. + * + * The 'used region' and the 'available' region are disjoint, and their + * union is the buffer's region. The used region extends from the beginning + * of the buffer region to the last used byte. The available region + * extends from one byte greater than the last used byte to the end of the + * buffer's region. The size of the used region can be changed using various + * buffer commands. Initially, the used region is empty. + * + * The used region is further subdivided into two disjoint regions: the + * 'consumed region' and the 'remaining region'. The union of these two + * regions is the used region. The consumed region extends from the beginning + * of the used region to the byte before the 'current' offset (if any). The + * 'remaining' region the current pointer to the end of the used + * region. The size of the consumed region can be changed using various + * buffer commands. Initially, the consumed region is empty. + * + * The 'active region' is an (optional) subregion of the remaining region. + * It extends from the current offset to an offset in the remaining region + * that is selected with isc_buffer_setactive(). Initially, the active region + * is empty. If the current offset advances beyond the chosen offset, the + * active region will also be empty. + * + * \verbatim + * /------------entire length---------------\ + * /----- used region -----\/-- available --\ + * +----------------------------------------+ + * | consumed | remaining | | + * +----------------------------------------+ + * a b c d e + * + * a == base of buffer. + * b == current pointer. Can be anywhere between a and d. + * c == active pointer. Meaningful between b and d. + * d == used pointer. + * e == length of buffer. + * + * a-e == entire length of buffer. + * a-d == used region. + * a-b == consumed region. + * b-d == remaining region. + * b-c == optional active region. + *\endverbatim + * + * The following invariants are maintained by all routines: + * + *\code + * length > 0 + * + * base is a valid pointer to length bytes of memory + * + * 0 <= used <= length + * + * 0 <= current <= used + * + * 0 <= active <= used + * (although active < current implies empty active region) + *\endcode + * + * \li MP: + * Buffers have no synchronization. Clients must ensure exclusive + * access. + * + * \li Reliability: + * No anticipated impact. + * + * \li Resources: + * Memory: 1 pointer + 6 unsigned integers per buffer. + * + * \li Security: + * No anticipated impact. + * + * \li Standards: + * None. + */ + +/*** + *** Imports + ***/ + +#include <isc/lang.h> +#include <isc/magic.h> +#include <isc/types.h> + +/*! + * To make many functions be inline macros (via \#define) define this. + * If it is undefined, a function will be used. + */ +/* #define ISC_BUFFER_USEINLINE */ + +ISC_LANG_BEGINDECLS + +/*@{*/ +/*! + *** Magic numbers + ***/ +#define ISC_BUFFER_MAGIC 0x42756621U /* Buf!. */ +#define ISC_BUFFER_VALID(b) ISC_MAGIC_VALID(b, ISC_BUFFER_MAGIC) +/*@}*/ + +/* + * The following macros MUST be used only on valid buffers. It is the + * caller's responsibility to ensure this by using the ISC_BUFFER_VALID + * check above, or by calling another isc_buffer_*() function (rather than + * another macro.) + */ + +/*@{*/ +/*! + * Fundamental buffer elements. (A through E in the introductory comment.) + */ +#define isc_buffer_base(b) ((void *)(b)->base) /*a*/ +#define isc_buffer_current(b) \ + ((void *)((unsigned char *)(b)->base + (b)->current)) /*b*/ +#define isc_buffer_active(b) \ + ((void *)((unsigned char *)(b)->base + (b)->active)) /*c*/ +#define isc_buffer_used(b) \ + ((void *)((unsigned char *)(b)->base + (b)->used)) /*d*/ +#define isc_buffer_length(b) ((b)->length) /*e*/ +/*@}*/ + +/*@{*/ +/*! + * Derived lengths. (Described in the introductory comment.) + */ +#define isc_buffer_usedlength(b) ((b)->used) /* d-a */ +#define isc_buffer_consumedlength(b) ((b)->current) /* b-a */ +#define isc_buffer_remaininglength(b) ((b)->used - (b)->current) /* d-b */ +#define isc_buffer_activelength(b) ((b)->active - (b)->current) /* c-b */ +#define isc_buffer_availablelength(b) ((b)->length - (b)->used) /* e-d */ +/*@}*/ + +/*! + * Note that the buffer structure is public. This is principally so buffer + * operations can be implemented using macros. Applications are strongly + * discouraged from directly manipulating the structure. + */ + +struct isc_buffer { + unsigned int magic; + void *base; + /*@{*/ + /*! The following integers are byte offsets from 'base'. */ + unsigned int length; + unsigned int used; + unsigned int current; + unsigned int active; + /*@}*/ + /*! linkable */ + ISC_LINK(isc_buffer_t) link; + /*! private internal elements */ + isc_mem_t *mctx; +}; + +/*** + *** Functions + ***/ + +isc_result_t +isc_buffer_allocate(isc_mem_t *mctx, isc_buffer_t **dynbuffer, + unsigned int length); +/*!< + * \brief Allocate a dynamic linkable buffer which has "length" bytes in the + * data region. + * + * Requires: + *\li "mctx" is valid. + * + *\li "dynbuffer" is non-NULL, and "*dynbuffer" is NULL. + * + * Returns: + *\li ISC_R_SUCCESS - success + *\li ISC_R_NOMEMORY - no memory available + * + * Note: + *\li Changing the buffer's length field is not permitted. + */ + +void +isc_buffer_free(isc_buffer_t **dynbuffer); +/*!< + * \brief Release resources allocated for a dynamic buffer. + * + * Requires: + *\li "dynbuffer" is not NULL. + * + *\li "*dynbuffer" is a valid dynamic buffer. + * + * Ensures: + *\li "*dynbuffer" will be NULL on return, and all memory associated with + * the dynamic buffer is returned to the memory context used in + * isc_buffer_allocate(). + */ + +void +isc__buffer_init(isc_buffer_t *b, const void *base, unsigned int length); +/*!< + * \brief Make 'b' refer to the 'length'-byte region starting at base. + * + * Requires: + * + *\li 'length' > 0 + * + *\li 'base' is a pointer to a sequence of 'length' bytes. + * + */ + +void +isc__buffer_initnull(isc_buffer_t *b); +/*!< + *\brief Initialize a buffer 'b' with a null data and zero length/ + */ + +void +isc_buffer_reinit(isc_buffer_t *b, void *base, unsigned int length); +/*!< + * \brief Make 'b' refer to the 'length'-byte region starting at base. + * Any existing data will be copied. + * + * Requires: + * + *\li 'length' > 0 AND length >= previous length + * + *\li 'base' is a pointer to a sequence of 'length' bytes. + * + */ + +void +isc__buffer_invalidate(isc_buffer_t *b); +/*!< + * \brief Make 'b' an invalid buffer. + * + * Requires: + *\li 'b' is a valid buffer. + * + * Ensures: + *\li If assertion checking is enabled, future attempts to use 'b' without + * calling isc_buffer_init() on it will cause an assertion failure. + */ + +void +isc__buffer_region(isc_buffer_t *b, isc_region_t *r); +/*!< + * \brief Make 'r' refer to the region of 'b'. + * + * Requires: + * + *\li 'b' is a valid buffer. + * + *\li 'r' points to a region structure. + */ + +void +isc__buffer_usedregion(isc_buffer_t *b, isc_region_t *r); +/*!< + * \brief Make 'r' refer to the used region of 'b'. + * + * Requires: + * + *\li 'b' is a valid buffer. + * + *\li 'r' points to a region structure. + */ + +void +isc__buffer_availableregion(isc_buffer_t *b, isc_region_t *r); +/*!< + * \brief Make 'r' refer to the available region of 'b'. + * + * Requires: + * + *\li 'b' is a valid buffer. + * + *\li 'r' points to a region structure. + */ + +void +isc__buffer_add(isc_buffer_t *b, unsigned int n); +/*!< + * \brief Increase the 'used' region of 'b' by 'n' bytes. + * + * Requires: + * + *\li 'b' is a valid buffer + * + *\li used + n <= length + * + */ + +void +isc__buffer_subtract(isc_buffer_t *b, unsigned int n); +/*!< + * \brief Decrease the 'used' region of 'b' by 'n' bytes. + * + * Requires: + * + *\li 'b' is a valid buffer + * + *\li used >= n + * + */ + +void +isc__buffer_clear(isc_buffer_t *b); +/*!< + * \brief Make the used region empty. + * + * Requires: + * + *\li 'b' is a valid buffer + * + * Ensures: + * + *\li used = 0 + * + */ + +void +isc__buffer_consumedregion(isc_buffer_t *b, isc_region_t *r); +/*!< + * \brief Make 'r' refer to the consumed region of 'b'. + * + * Requires: + * + *\li 'b' is a valid buffer. + * + *\li 'r' points to a region structure. + */ + +void +isc__buffer_remainingregion(isc_buffer_t *b, isc_region_t *r); +/*!< + * \brief Make 'r' refer to the remaining region of 'b'. + * + * Requires: + * + *\li 'b' is a valid buffer. + * + *\li 'r' points to a region structure. + */ + +void +isc__buffer_activeregion(isc_buffer_t *b, isc_region_t *r); +/*!< + * \brief Make 'r' refer to the active region of 'b'. + * + * Requires: + * + *\li 'b' is a valid buffer. + * + *\li 'r' points to a region structure. + */ + +void +isc__buffer_setactive(isc_buffer_t *b, unsigned int n); +/*!< + * \brief Sets the end of the active region 'n' bytes after current. + * + * Requires: + * + *\li 'b' is a valid buffer. + * + *\li current + n <= used + */ + +void +isc__buffer_first(isc_buffer_t *b); +/*!< + * \brief Make the consumed region empty. + * + * Requires: + * + *\li 'b' is a valid buffer + * + * Ensures: + * + *\li current == 0 + * + */ + +void +isc__buffer_forward(isc_buffer_t *b, unsigned int n); +/*!< + * \brief Increase the 'consumed' region of 'b' by 'n' bytes. + * + * Requires: + * + *\li 'b' is a valid buffer + * + *\li current + n <= used + * + */ + +void +isc__buffer_back(isc_buffer_t *b, unsigned int n); +/*!< + * \brief Decrease the 'consumed' region of 'b' by 'n' bytes. + * + * Requires: + * + *\li 'b' is a valid buffer + * + *\li n <= current + * + */ + +void +isc_buffer_compact(isc_buffer_t *b); +/*!< + * \brief Compact the used region by moving the remaining region so it occurs + * at the start of the buffer. The used region is shrunk by the size of + * the consumed region, and the consumed region is then made empty. + * + * Requires: + * + *\li 'b' is a valid buffer + * + * Ensures: + * + *\li current == 0 + * + *\li The size of the used region is now equal to the size of the remaining + * region (as it was before the call). The contents of the used region + * are those of the remaining region (as it was before the call). + */ + +isc_uint8_t +isc_buffer_getuint8(isc_buffer_t *b); +/*!< + * \brief Read an unsigned 8-bit integer from 'b' and return it. + * + * Requires: + * + *\li 'b' is a valid buffer. + * + *\li The length of the available region of 'b' is at least 1. + * + * Ensures: + * + *\li The current pointer in 'b' is advanced by 1. + * + * Returns: + * + *\li A 8-bit unsigned integer. + */ + +void +isc__buffer_putuint8(isc_buffer_t *b, isc_uint8_t val); +/*!< + * \brief Store an unsigned 8-bit integer from 'val' into 'b'. + * + * Requires: + *\li 'b' is a valid buffer. + * + *\li The length of the unused region of 'b' is at least 1. + * + * Ensures: + *\li The used pointer in 'b' is advanced by 1. + */ + +isc_uint16_t +isc_buffer_getuint16(isc_buffer_t *b); +/*!< + * \brief Read an unsigned 16-bit integer in network byte order from 'b', convert + * it to host byte order, and return it. + * + * Requires: + * + *\li 'b' is a valid buffer. + * + *\li The length of the available region of 'b' is at least 2. + * + * Ensures: + * + *\li The current pointer in 'b' is advanced by 2. + * + * Returns: + * + *\li A 16-bit unsigned integer. + */ + +void +isc__buffer_putuint16(isc_buffer_t *b, isc_uint16_t val); +/*!< + * \brief Store an unsigned 16-bit integer in host byte order from 'val' + * into 'b' in network byte order. + * + * Requires: + *\li 'b' is a valid buffer. + * + *\li The length of the unused region of 'b' is at least 2. + * + * Ensures: + *\li The used pointer in 'b' is advanced by 2. + */ + +isc_uint32_t +isc_buffer_getuint32(isc_buffer_t *b); +/*!< + * \brief Read an unsigned 32-bit integer in network byte order from 'b', convert + * it to host byte order, and return it. + * + * Requires: + * + *\li 'b' is a valid buffer. + * + *\li The length of the available region of 'b' is at least 4. + * + * Ensures: + * + *\li The current pointer in 'b' is advanced by 4. + * + * Returns: + * + *\li A 32-bit unsigned integer. + */ + +void +isc__buffer_putuint32(isc_buffer_t *b, isc_uint32_t val); +/*!< + * \brief Store an unsigned 32-bit integer in host byte order from 'val' + * into 'b' in network byte order. + * + * Requires: + *\li 'b' is a valid buffer. + * + *\li The length of the unused region of 'b' is at least 4. + * + * Ensures: + *\li The used pointer in 'b' is advanced by 4. + */ + +isc_uint64_t +isc_buffer_getuint48(isc_buffer_t *b); +/*!< + * \brief Read an unsigned 48-bit integer in network byte order from 'b', + * convert it to host byte order, and return it. + * + * Requires: + * + *\li 'b' is a valid buffer. + * + *\li The length of the available region of 'b' is at least 6. + * + * Ensures: + * + *\li The current pointer in 'b' is advanced by 6. + * + * Returns: + * + *\li A 48-bit unsigned integer (stored in a 64-bit integer). + */ + +void +isc__buffer_putuint48(isc_buffer_t *b, isc_uint64_t val); +/*!< + * \brief Store an unsigned 48-bit integer in host byte order from 'val' + * into 'b' in network byte order. + * + * Requires: + *\li 'b' is a valid buffer. + * + *\li The length of the unused region of 'b' is at least 6. + * + * Ensures: + *\li The used pointer in 'b' is advanced by 6. + */ + +void +isc__buffer_putuint24(isc_buffer_t *b, isc_uint32_t val); +/*!< + * Store an unsigned 24-bit integer in host byte order from 'val' + * into 'b' in network byte order. + * + * Requires: + *\li 'b' is a valid buffer. + * + * The length of the unused region of 'b' is at least 3. + * + * Ensures: + *\li The used pointer in 'b' is advanced by 3. + */ + +void +isc__buffer_putmem(isc_buffer_t *b, const unsigned char *base, + unsigned int length); +/*!< + * \brief Copy 'length' bytes of memory at 'base' into 'b'. + * + * Requires: + *\li 'b' is a valid buffer. + * + *\li 'base' points to 'length' bytes of valid memory. + * + */ + +void +isc__buffer_putstr(isc_buffer_t *b, const char *source); +/*!< + * \brief Copy 'source' into 'b', not including terminating NUL. + * + * Requires: + *\li 'b' is a valid buffer. + * + *\li 'source' to be a valid NULL terminated string. + * + *\li strlen(source) <= isc_buffer_available(b) + */ + +isc_result_t +isc_buffer_copyregion(isc_buffer_t *b, const isc_region_t *r); +/*!< + * \brief Copy the contents of 'r' into 'b'. + * + * Requires: + *\li 'b' is a valid buffer. + * + *\li 'r' is a valid region. + * + * Returns: + * + *\li ISC_R_SUCCESS + *\li ISC_R_NOSPACE The available region of 'b' is not + * big enough. + */ + +ISC_LANG_ENDDECLS + +/* + * Inline macro versions of the functions. These should never be called + * directly by an application, but will be used by the functions within + * buffer.c. The callers should always use "isc_buffer_*()" names, never + * ones beginning with "isc__" + */ + +/*! \note + * XXXDCL Something more could be done with initializing buffers that + * point to const data. For example, a new function, isc_buffer_initconst, + * could be used, and a new boolean flag in the buffer structure could + * indicate whether the buffer was initialized with that function. + * (isc_bufer_init itself would be reprototyped to *not* have its "base" + * parameter be const.) Then if the boolean were true, the isc_buffer_put* + * functions could assert a contractual requirement for a non-const buffer. + * One drawback is that the isc_buffer_* functions (macros) that return + * pointers would still need to return non-const pointers to avoid compiler + * warnings, so it would be up to code that uses them to have to deal + * with the possibility that the buffer was initialized as const -- + * a problem that they *already* have to deal with but have absolutely + * no ability to. With a new isc_buffer_isconst() function returning + * true/false, they could at least assert a contractual requirement for + * non-const buffers when needed. + */ +#define ISC__BUFFER_INIT(_b, _base, _length) \ + do { \ + union { \ + const void * konst; \ + void * var; \ + } _u; \ + _u.konst = (_base); \ + (_b)->base = _u.var; \ + (_b)->length = (_length); \ + (_b)->used = 0; \ + (_b)->current = 0; \ + (_b)->active = 0; \ + (_b)->mctx = NULL; \ + ISC_LINK_INIT(_b, link); \ + (_b)->magic = ISC_BUFFER_MAGIC; \ + } while (0) + +#define ISC__BUFFER_INITNULL(_b) ISC__BUFFER_INIT(_b, NULL, 0) + +#define ISC__BUFFER_INVALIDATE(_b) \ + do { \ + (_b)->magic = 0; \ + (_b)->base = NULL; \ + (_b)->length = 0; \ + (_b)->used = 0; \ + (_b)->current = 0; \ + (_b)->active = 0; \ + } while (0) + +#define ISC__BUFFER_REGION(_b, _r) \ + do { \ + (_r)->base = (_b)->base; \ + (_r)->length = (_b)->length; \ + } while (0) + +#define ISC__BUFFER_USEDREGION(_b, _r) \ + do { \ + (_r)->base = (_b)->base; \ + (_r)->length = (_b)->used; \ + } while (0) + +#define ISC__BUFFER_AVAILABLEREGION(_b, _r) \ + do { \ + (_r)->base = isc_buffer_used(_b); \ + (_r)->length = isc_buffer_availablelength(_b); \ + } while (0) + +#define ISC__BUFFER_ADD(_b, _n) \ + do { \ + (_b)->used += (_n); \ + } while (0) + +#define ISC__BUFFER_SUBTRACT(_b, _n) \ + do { \ + (_b)->used -= (_n); \ + if ((_b)->current > (_b)->used) \ + (_b)->current = (_b)->used; \ + if ((_b)->active > (_b)->used) \ + (_b)->active = (_b)->used; \ + } while (0) + +#define ISC__BUFFER_CLEAR(_b) \ + do { \ + (_b)->used = 0; \ + (_b)->current = 0; \ + (_b)->active = 0; \ + } while (0) + +#define ISC__BUFFER_CONSUMEDREGION(_b, _r) \ + do { \ + (_r)->base = (_b)->base; \ + (_r)->length = (_b)->current; \ + } while (0) + +#define ISC__BUFFER_REMAININGREGION(_b, _r) \ + do { \ + (_r)->base = isc_buffer_current(_b); \ + (_r)->length = isc_buffer_remaininglength(_b); \ + } while (0) + +#define ISC__BUFFER_ACTIVEREGION(_b, _r) \ + do { \ + if ((_b)->current < (_b)->active) { \ + (_r)->base = isc_buffer_current(_b); \ + (_r)->length = isc_buffer_activelength(_b); \ + } else { \ + (_r)->base = NULL; \ + (_r)->length = 0; \ + } \ + } while (0) + +#define ISC__BUFFER_SETACTIVE(_b, _n) \ + do { \ + (_b)->active = (_b)->current + (_n); \ + } while (0) + +#define ISC__BUFFER_FIRST(_b) \ + do { \ + (_b)->current = 0; \ + } while (0) + +#define ISC__BUFFER_FORWARD(_b, _n) \ + do { \ + (_b)->current += (_n); \ + } while (0) + +#define ISC__BUFFER_BACK(_b, _n) \ + do { \ + (_b)->current -= (_n); \ + } while (0) + +#define ISC__BUFFER_PUTMEM(_b, _base, _length) \ + do { \ + memcpy(isc_buffer_used(_b), (_base), (_length)); \ + (_b)->used += (_length); \ + } while (0) + +#define ISC__BUFFER_PUTSTR(_b, _source) \ + do { \ + unsigned int _length; \ + unsigned char *_cp; \ + _length = strlen(_source); \ + _cp = isc_buffer_used(_b); \ + memcpy(_cp, (_source), _length); \ + (_b)->used += (_length); \ + } while (0) + +#define ISC__BUFFER_PUTUINT8(_b, _val) \ + do { \ + unsigned char *_cp; \ + isc_uint8_t _val2 = (_val); \ + _cp = isc_buffer_used(_b); \ + (_b)->used++; \ + _cp[0] = _val2 & 0x00ff; \ + } while (0) + +#define ISC__BUFFER_PUTUINT16(_b, _val) \ + do { \ + unsigned char *_cp; \ + isc_uint16_t _val2 = (_val); \ + _cp = isc_buffer_used(_b); \ + (_b)->used += 2; \ + _cp[0] = (unsigned char)((_val2 & 0xff00U) >> 8); \ + _cp[1] = (unsigned char)(_val2 & 0x00ffU); \ + } while (0) + +#define ISC__BUFFER_PUTUINT24(_b, _val) \ + do { \ + unsigned char *_cp; \ + isc_uint32_t _val2 = (_val); \ + _cp = isc_buffer_used(_b); \ + (_b)->used += 3; \ + _cp[0] = (unsigned char)((_val2 & 0xff0000U) >> 16); \ + _cp[1] = (unsigned char)((_val2 & 0xff00U) >> 8); \ + _cp[2] = (unsigned char)(_val2 & 0x00ffU); \ + } while (0) + +#define ISC__BUFFER_PUTUINT32(_b, _val) \ + do { \ + unsigned char *_cp; \ + isc_uint32_t _val2 = (_val); \ + _cp = isc_buffer_used(_b); \ + (_b)->used += 4; \ + _cp[0] = (unsigned char)((_val2 & 0xff000000) >> 24); \ + _cp[1] = (unsigned char)((_val2 & 0x00ff0000) >> 16); \ + _cp[2] = (unsigned char)((_val2 & 0x0000ff00) >> 8); \ + _cp[3] = (unsigned char)((_val2 & 0x000000ff)); \ + } while (0) + +#if defined(ISC_BUFFER_USEINLINE) +#define isc_buffer_init ISC__BUFFER_INIT +#define isc_buffer_initnull ISC__BUFFER_INITNULL +#define isc_buffer_invalidate ISC__BUFFER_INVALIDATE +#define isc_buffer_region ISC__BUFFER_REGION +#define isc_buffer_usedregion ISC__BUFFER_USEDREGION +#define isc_buffer_availableregion ISC__BUFFER_AVAILABLEREGION +#define isc_buffer_add ISC__BUFFER_ADD +#define isc_buffer_subtract ISC__BUFFER_SUBTRACT +#define isc_buffer_clear ISC__BUFFER_CLEAR +#define isc_buffer_consumedregion ISC__BUFFER_CONSUMEDREGION +#define isc_buffer_remainingregion ISC__BUFFER_REMAININGREGION +#define isc_buffer_activeregion ISC__BUFFER_ACTIVEREGION +#define isc_buffer_setactive ISC__BUFFER_SETACTIVE +#define isc_buffer_first ISC__BUFFER_FIRST +#define isc_buffer_forward ISC__BUFFER_FORWARD +#define isc_buffer_back ISC__BUFFER_BACK +#define isc_buffer_putmem ISC__BUFFER_PUTMEM +#define isc_buffer_putstr ISC__BUFFER_PUTSTR +#define isc_buffer_putuint8 ISC__BUFFER_PUTUINT8 +#define isc_buffer_putuint16 ISC__BUFFER_PUTUINT16 +#define isc_buffer_putuint24 ISC__BUFFER_PUTUINT24 +#define isc_buffer_putuint32 ISC__BUFFER_PUTUINT32 +#else +#define isc_buffer_init isc__buffer_init +#define isc_buffer_initnull isc__buffer_initnull +#define isc_buffer_invalidate isc__buffer_invalidate +#define isc_buffer_region isc__buffer_region +#define isc_buffer_usedregion isc__buffer_usedregion +#define isc_buffer_availableregion isc__buffer_availableregion +#define isc_buffer_add isc__buffer_add +#define isc_buffer_subtract isc__buffer_subtract +#define isc_buffer_clear isc__buffer_clear +#define isc_buffer_consumedregion isc__buffer_consumedregion +#define isc_buffer_remainingregion isc__buffer_remainingregion +#define isc_buffer_activeregion isc__buffer_activeregion +#define isc_buffer_setactive isc__buffer_setactive +#define isc_buffer_first isc__buffer_first +#define isc_buffer_forward isc__buffer_forward +#define isc_buffer_back isc__buffer_back +#define isc_buffer_putmem isc__buffer_putmem +#define isc_buffer_putstr isc__buffer_putstr +#define isc_buffer_putuint8 isc__buffer_putuint8 +#define isc_buffer_putuint16 isc__buffer_putuint16 +#define isc_buffer_putuint24 isc__buffer_putuint24 +#define isc_buffer_putuint32 isc__buffer_putuint32 +#endif + +/* + * No inline method for this one (yet). + */ +#define isc_buffer_putuint48 isc__buffer_putuint48 + +#endif /* ISC_BUFFER_H */ diff --git a/contrib/ntp/lib/isc/include/isc/bufferlist.h b/contrib/ntp/lib/isc/include/isc/bufferlist.h new file mode 100644 index 0000000..54e00c7 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/bufferlist.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: bufferlist.h,v 1.17 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_BUFFERLIST_H +#define ISC_BUFFERLIST_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file isc/bufferlist.h + * + * + *\brief Buffer lists have no synchronization. Clients must ensure exclusive + * access. + * + * \li Reliability: + * No anticipated impact. + + * \li Security: + * No anticipated impact. + * + * \li Standards: + * None. + */ + +/*** + *** Imports + ***/ + +#include <isc/lang.h> +#include <isc/types.h> + +ISC_LANG_BEGINDECLS + +/*** + *** Functions + ***/ + +unsigned int +isc_bufferlist_usedcount(isc_bufferlist_t *bl); +/*!< + * \brief Return the length of the sum of all used regions of all buffers in + * the buffer list 'bl' + * + * Requires: + * + *\li 'bl' is not NULL. + * + * Returns: + *\li sum of all used regions' lengths. + */ + +unsigned int +isc_bufferlist_availablecount(isc_bufferlist_t *bl); +/*!< + * \brief Return the length of the sum of all available regions of all buffers in + * the buffer list 'bl' + * + * Requires: + * + *\li 'bl' is not NULL. + * + * Returns: + *\li sum of all available regions' lengths. + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_BUFFERLIST_H */ diff --git a/contrib/ntp/lib/isc/include/isc/commandline.h b/contrib/ntp/lib/isc/include/isc/commandline.h new file mode 100644 index 0000000..384640a --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/commandline.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: commandline.h,v 1.16 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_COMMANDLINE_H +#define ISC_COMMANDLINE_H 1 + +/*! \file isc/commandline.h */ + +#include <isc/boolean.h> +#include <isc/lang.h> +#include <isc/platform.h> + +/*% Index into parent argv vector. */ +LIBISC_EXTERNAL_DATA extern int isc_commandline_index; +/*% Character checked for validity. */ +LIBISC_EXTERNAL_DATA extern int isc_commandline_option; +/*% Argument associated with option. */ +LIBISC_EXTERNAL_DATA extern char *isc_commandline_argument; +/*% For printing error messages. */ +LIBISC_EXTERNAL_DATA extern char *isc_commandline_progname; +/*% Print error message. */ +LIBISC_EXTERNAL_DATA extern isc_boolean_t isc_commandline_errprint; +/*% Reset getopt. */ +LIBISC_EXTERNAL_DATA extern isc_boolean_t isc_commandline_reset; + +ISC_LANG_BEGINDECLS + +/*% parse command line */ +int +isc_commandline_parse(int argc, char * const *argv, const char *options); + +ISC_LANG_ENDDECLS + +#endif /* ISC_COMMANDLINE_H */ diff --git a/contrib/ntp/lib/isc/include/isc/entropy.h b/contrib/ntp/lib/isc/include/isc/entropy.h new file mode 100644 index 0000000..d28f29a --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/entropy.h @@ -0,0 +1,314 @@ +/* + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: entropy.h,v 1.35 2009/10/19 02:37:08 marka Exp $ */ + +#ifndef ISC_ENTROPY_H +#define ISC_ENTROPY_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file isc/entropy.h + * \brief The entropy API + * + * \li MP: + * The entropy object is locked internally. All callbacks into + * application-provided functions (for setup, gathering, and + * shutdown of sources) are guaranteed to be called with the + * entropy API lock held. This means these functions are + * not permitted to call back into the entropy API. + * + * \li Reliability: + * No anticipated impact. + * + * \li Resources: + * A buffer, used as an entropy pool. + * + * \li Security: + * While this code is believed to implement good entropy gathering + * and distribution, it has not been reviewed by a cryptographic + * expert. + * Since the added entropy is only as good as the sources used, + * this module could hand out bad data and never know it. + * + * \li Standards: + * None. + */ + +/*** + *** Imports + ***/ + +#include <stdio.h> + +#include <isc/lang.h> +#include <isc/types.h> + +/*@{*/ +/*% Entropy callback function. */ +typedef isc_result_t (*isc_entropystart_t)(isc_entropysource_t *source, + void *arg, isc_boolean_t blocking); +typedef isc_result_t (*isc_entropyget_t)(isc_entropysource_t *source, + void *arg, isc_boolean_t blocking); +typedef void (*isc_entropystop_t)(isc_entropysource_t *source, void *arg); +/*@}*/ + +/*** + *** Flags. + ***/ + +/*! + * \brief + * Extract only "good" data; return failure if there is not enough + * data available and there are no sources which we can poll to get + * data, or those sources are empty. + * + * + */ +#define ISC_ENTROPY_GOODONLY 0x00000001U +/*! + * \brief + * Extract as much good data as possible, but if there isn't enough + * at hand, return what is available. This flag only makes sense + * when used with _GOODONLY. + */ +#define ISC_ENTROPY_PARTIAL 0x00000002U +/*! + * \brief + * Block the task until data is available. This is contrary to the + * ISC task system, where tasks should never block. However, if + * this is a special purpose application where blocking a task is + * acceptable (say, an offline zone signer) this flag may be set. + * This flag only makes sense when used with _GOODONLY, and will + * block regardless of the setting for _PARTIAL. + */ +#define ISC_ENTROPY_BLOCKING 0x00000004U + +/*! + * \brief + * Estimate the amount of entropy contained in the sample pool. + * If this is not set, the source will be gathered and periodically + * mixed into the entropy pool, but no increment in contained entropy + * will be assumed. This flag only makes sense on sample sources. + */ +#define ISC_ENTROPYSOURCE_ESTIMATE 0x00000001U + +/* + * For use with isc_entropy_usebestsource(). + */ +/*! + * \brief + * Use the keyboard as the only entropy source. + */ +#define ISC_ENTROPY_KEYBOARDYES 1 +/*! + * \brief + * Never use the keyboard as an entropy source. + */ +#define ISC_ENTROPY_KEYBOARDNO 2 +/*! + * \brief + * Use the keyboard as an entropy source only if opening the + * random device fails. + */ +#define ISC_ENTROPY_KEYBOARDMAYBE 3 + +ISC_LANG_BEGINDECLS + +/*** + *** Functions + ***/ + +isc_result_t +isc_entropy_create(isc_mem_t *mctx, isc_entropy_t **entp); +/*!< + * \brief Create a new entropy object. + */ + +void +isc_entropy_attach(isc_entropy_t *ent, isc_entropy_t **entp); +/*!< + * Attaches to an entropy object. + */ + +void +isc_entropy_detach(isc_entropy_t **entp); +/*!< + * \brief Detaches from an entropy object. + */ + +isc_result_t +isc_entropy_createfilesource(isc_entropy_t *ent, const char *fname); +/*!< + * \brief Create a new entropy source from a file. + * + * The file is assumed to contain good randomness, and will be mixed directly + * into the pool with every byte adding 8 bits of entropy. + * + * The file will be put into non-blocking mode, so it may be a device file, + * such as /dev/random. /dev/urandom should not be used here if it can + * be avoided, since it will always provide data even if it isn't good. + * We will make as much pseudorandom data as we need internally if our + * caller asks for it. + * + * If we hit end-of-file, we will stop reading from this source. Callers + * who require strong random data will get failure when our pool drains. + * The file will never be opened/read again once EOF is reached. + */ + +void +isc_entropy_destroysource(isc_entropysource_t **sourcep); +/*!< + * \brief Removes an entropy source from the entropy system. + */ + +isc_result_t +isc_entropy_createsamplesource(isc_entropy_t *ent, + isc_entropysource_t **sourcep); +/*!< + * \brief Create an entropy source that consists of samples. Each sample is + * added to the source via isc_entropy_addsamples(), below. + */ + +isc_result_t +isc_entropy_createcallbacksource(isc_entropy_t *ent, + isc_entropystart_t start, + isc_entropyget_t get, + isc_entropystop_t stop, + void *arg, + isc_entropysource_t **sourcep); +/*!< + * \brief Create an entropy source that is polled via a callback. + * + * This would + * be used when keyboard input is used, or a GUI input method. It can + * also be used to hook in any external entropy source. + * + * Samples are added via isc_entropy_addcallbacksample(), below. + * _addcallbacksample() is the only function which may be called from + * within an entropy API callback function. + */ + +void +isc_entropy_stopcallbacksources(isc_entropy_t *ent); +/*!< + * \brief Call the stop functions for callback sources that have had their + * start functions called. + */ + +/*@{*/ +isc_result_t +isc_entropy_addcallbacksample(isc_entropysource_t *source, isc_uint32_t sample, + isc_uint32_t extra); +isc_result_t +isc_entropy_addsample(isc_entropysource_t *source, isc_uint32_t sample, + isc_uint32_t extra); +/*!< + * \brief Add a sample to the sample source. + * + * The sample MUST be a timestamp + * that increases over time, with the exception of wrap-around for + * extremely high resolution timers which will quickly wrap-around + * a 32-bit integer. + * + * The "extra" parameter is used only to add a bit more unpredictable + * data. It is not used other than included in the hash of samples. + * + * When in an entropy API callback function, _addcallbacksource() must be + * used. At all other times, _addsample() must be used. + */ +/*@}*/ + +isc_result_t +isc_entropy_getdata(isc_entropy_t *ent, void *data, unsigned int length, + unsigned int *returned, unsigned int flags); +/*!< + * \brief Extract data from the entropy pool. This may load the pool from various + * sources. + * + * Do this by stiring the pool and returning a part of hash as randomness. + * Note that no secrets are given away here since parts of the hash are + * xored together before returned. + * + * Honor the request from the caller to only return good data, any data, + * etc. + */ + +void +isc_entropy_putdata(isc_entropy_t *ent, void *data, unsigned int length, + isc_uint32_t entropy); +/*!< + * \brief Add "length" bytes in "data" to the entropy pool, incrementing the + * pool's entropy count by "entropy." + * + * These bytes will prime the pseudorandom portion even if no entropy is + * actually added. + */ + +void +isc_entropy_stats(isc_entropy_t *ent, FILE *out); +/*!< + * \brief Dump some (trivial) stats to the stdio stream "out". + */ + +unsigned int +isc_entropy_status(isc_entropy_t *end); +/* + * Returns the number of bits the pool currently contains. This is just + * an estimate. + */ + +isc_result_t +isc_entropy_usebestsource(isc_entropy_t *ectx, isc_entropysource_t **source, + const char *randomfile, int use_keyboard); +/*!< + * \brief Use whatever source of entropy is best. + * + * Notes: + *\li If "randomfile" is not NULL, open it with + * isc_entropy_createfilesource(). + * + *\li If "randomfile" is NULL and the system's random device was detected + * when the program was configured and built, open that device with + * isc_entropy_createfilesource(). + * + *\li If "use_keyboard" is #ISC_ENTROPY_KEYBOARDYES, then always open + * the keyboard as an entropy source (possibly in addition to + * "randomfile" or the random device). + * + *\li If "use_keyboard" is #ISC_ENTROPY_KEYBOARDMAYBE, open the keyboard only + * if opening the random file/device fails. A message will be + * printed describing the need for keyboard input. + * + *\li If "use_keyboard" is #ISC_ENTROPY_KEYBOARDNO, the keyboard will + * never be opened. + * + * Returns: + *\li #ISC_R_SUCCESS if at least one source of entropy could be started. + * + *\li #ISC_R_NOENTROPY if use_keyboard is #ISC_ENTROPY_KEYBOARDNO and + * there is no random device pathname compiled into the program. + * + *\li A return code from isc_entropy_createfilesource() or + * isc_entropy_createcallbacksource(). + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_ENTROPY_H */ diff --git a/contrib/ntp/lib/isc/include/isc/error.h b/contrib/ntp/lib/isc/include/isc/error.h new file mode 100644 index 0000000..e0cdfa8 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/error.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: error.h,v 1.22 2009/09/29 23:48:04 tbox Exp $ */ + +#ifndef ISC_ERROR_H +#define ISC_ERROR_H 1 + +/*! \file isc/error.h */ + +#include <stdarg.h> + +#include <isc/formatcheck.h> +#include <isc/lang.h> +#include <isc/platform.h> + +ISC_LANG_BEGINDECLS + +typedef void (*isc_errorcallback_t)(const char *, int, const char *, va_list); + +/*% set unexpected error */ +void +isc_error_setunexpected(isc_errorcallback_t); + +/*% set fatal error */ +void +isc_error_setfatal(isc_errorcallback_t); + +/*% unexpected error */ +void +isc_error_unexpected(const char *, int, const char *, ...) + ISC_FORMAT_PRINTF(3, 4); + +/*% fatal error */ +ISC_PLATFORM_NORETURN_PRE void +isc_error_fatal(const char *, int, const char *, ...) +ISC_FORMAT_PRINTF(3, 4) ISC_PLATFORM_NORETURN_POST; + +/*% runtimecheck error */ +void +isc_error_runtimecheck(const char *, int, const char *); + +#define ISC_ERROR_RUNTIMECHECK(cond) \ + ((void) ((cond) || \ + ((isc_error_runtimecheck)(__FILE__, __LINE__, #cond), 0))) + +ISC_LANG_ENDDECLS + +#endif /* ISC_ERROR_H */ diff --git a/contrib/ntp/lib/isc/include/isc/event.h b/contrib/ntp/lib/isc/include/isc/event.h new file mode 100644 index 0000000..68fabb2 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/event.h @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: event.h,v 1.34 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_EVENT_H +#define ISC_EVENT_H 1 + +/*! \file isc/event.h */ + +#include <isc/lang.h> +#include <isc/types.h> + +/***** + ***** Events. + *****/ + +typedef void (*isc_eventdestructor_t)(isc_event_t *); + +#define ISC_EVENT_COMMON(ltype) \ + size_t ev_size; \ + unsigned int ev_attributes; \ + void * ev_tag; \ + isc_eventtype_t ev_type; \ + isc_taskaction_t ev_action; \ + void * ev_arg; \ + void * ev_sender; \ + isc_eventdestructor_t ev_destroy; \ + void * ev_destroy_arg; \ + ISC_LINK(ltype) ev_link + +/*% + * Attributes matching a mask of 0x000000ff are reserved for the task library's + * definition. Attributes of 0xffffff00 may be used by the application + * or non-ISC libraries. + */ +#define ISC_EVENTATTR_NOPURGE 0x00000001 + +/*% + * The ISC_EVENTATTR_CANCELED attribute is intended to indicate + * that an event is delivered as a result of a canceled operation + * rather than successful completion, by mutual agreement + * between the sender and receiver. It is not set or used by + * the task system. + */ +#define ISC_EVENTATTR_CANCELED 0x00000002 + +#define ISC_EVENT_INIT(event, sz, at, ta, ty, ac, ar, sn, df, da) \ +do { \ + (event)->ev_size = (sz); \ + (event)->ev_attributes = (at); \ + (event)->ev_tag = (ta); \ + (event)->ev_type = (ty); \ + (event)->ev_action = (ac); \ + (event)->ev_arg = (ar); \ + (event)->ev_sender = (sn); \ + (event)->ev_destroy = (df); \ + (event)->ev_destroy_arg = (da); \ + ISC_LINK_INIT((event), ev_link); \ +} while (0) + +/*% + * This structure is public because "subclassing" it may be useful when + * defining new event types. + */ +struct isc_event { + ISC_EVENT_COMMON(struct isc_event); +}; + +#define ISC_EVENTTYPE_FIRSTEVENT 0x00000000 +#define ISC_EVENTTYPE_LASTEVENT 0xffffffff + +#define ISC_EVENT_PTR(p) ((isc_event_t **)(void *)(p)) + +ISC_LANG_BEGINDECLS + +isc_event_t * +isc_event_allocate(isc_mem_t *mctx, void *sender, isc_eventtype_t type, + isc_taskaction_t action, const void *arg, size_t size); +/*%< + * Allocate an event structure. + * + * Allocate and initialize in a structure with initial elements + * defined by: + * + * \code + * struct { + * ISC_EVENT_COMMON(struct isc_event); + * ... + * }; + * \endcode + * + * Requires: + *\li 'size' >= sizeof(struct isc_event) + *\li 'action' to be non NULL + * + * Returns: + *\li a pointer to a initialized structure of the requested size. + *\li NULL if unable to allocate memory. + */ + +void +isc_event_free(isc_event_t **); + +ISC_LANG_ENDDECLS + +#endif /* ISC_EVENT_H */ diff --git a/contrib/ntp/lib/isc/include/isc/eventclass.h b/contrib/ntp/lib/isc/include/isc/eventclass.h new file mode 100644 index 0000000..9e6c145 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/eventclass.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: eventclass.h,v 1.18 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_EVENTCLASS_H +#define ISC_EVENTCLASS_H 1 + +/*! \file isc/eventclass.h + ***** Registry of Predefined Event Type Classes + *****/ + +/*% + * An event class is an unsigned 16 bit number. Each class may contain up + * to 65536 events. An event type is formed by adding the event number + * within the class to the class number. + * + */ + +#define ISC_EVENTCLASS(eclass) ((eclass) << 16) + +/*@{*/ +/*! + * Classes < 1024 are reserved for ISC use. + * Event classes >= 1024 and <= 65535 are reserved for application use. + */ + +#define ISC_EVENTCLASS_TASK ISC_EVENTCLASS(0) +#define ISC_EVENTCLASS_TIMER ISC_EVENTCLASS(1) +#define ISC_EVENTCLASS_SOCKET ISC_EVENTCLASS(2) +#define ISC_EVENTCLASS_FILE ISC_EVENTCLASS(3) +#define ISC_EVENTCLASS_DNS ISC_EVENTCLASS(4) +#define ISC_EVENTCLASS_APP ISC_EVENTCLASS(5) +#define ISC_EVENTCLASS_OMAPI ISC_EVENTCLASS(6) +#define ISC_EVENTCLASS_RATELIMITER ISC_EVENTCLASS(7) +#define ISC_EVENTCLASS_ISCCC ISC_EVENTCLASS(8) +/*@}*/ + +#endif /* ISC_EVENTCLASS_H */ diff --git a/contrib/ntp/lib/isc/include/isc/file.h b/contrib/ntp/lib/isc/include/isc/file.h new file mode 100644 index 0000000..5db506a --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/file.h @@ -0,0 +1,304 @@ +/* + * Copyright (C) 2004-2007, 2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +#ifndef ISC_FILE_H +#define ISC_FILE_H 1 + +/*! \file isc/file.h */ + +#include <stdio.h> + +#include <isc/lang.h> +#include <isc/types.h> + +ISC_LANG_BEGINDECLS + +isc_result_t +isc_file_settime(const char *file, isc_time_t *itime); + +isc_result_t +isc_file_getmodtime(const char *file, isc_time_t *itime); +/*!< + * \brief Get the time of last modification of a file. + * + * Notes: + *\li The time that is set is relative to the (OS-specific) epoch, as are + * all isc_time_t structures. + * + * Requires: + *\li file != NULL. + *\li time != NULL. + * + * Ensures: + *\li If the file could not be accessed, 'time' is unchanged. + * + * Returns: + *\li #ISC_R_SUCCESS + * Success. + *\li #ISC_R_NOTFOUND + * No such file exists. + *\li #ISC_R_INVALIDFILE + * The path specified was not usable by the operating system. + *\li #ISC_R_NOPERM + * The file's metainformation could not be retrieved because + * permission was denied to some part of the file's path. + *\li #ISC_R_EIO + * Hardware error interacting with the filesystem. + *\li #ISC_R_UNEXPECTED + * Something totally unexpected happened. + * + */ + +isc_result_t +isc_file_mktemplate(const char *path, char *buf, size_t buflen); +/*!< + * \brief Generate a template string suitable for use with isc_file_openunique(). + * + * Notes: + *\li This function is intended to make creating temporary files + * portable between different operating systems. + * + *\li The path is prepended to an implementation-defined string and + * placed into buf. The string has no path characters in it, + * and its maximum length is 14 characters plus a NUL. Thus + * buflen should be at least strlen(path) + 15 characters or + * an error will be returned. + * + * Requires: + *\li buf != NULL. + * + * Ensures: + *\li If result == #ISC_R_SUCCESS: + * buf contains a string suitable for use as the template argument + * to isc_file_openunique(). + * + *\li If result != #ISC_R_SUCCESS: + * buf is unchanged. + * + * Returns: + *\li #ISC_R_SUCCESS Success. + *\li #ISC_R_NOSPACE buflen indicates buf is too small for the catenation + * of the path with the internal template string. + */ + + +isc_result_t +isc_file_openunique(char *templet, FILE **fp); +isc_result_t +isc_file_openuniqueprivate(char *templet, FILE **fp); +isc_result_t +isc_file_openuniquemode(char *templet, int mode, FILE **fp); +/*!< + * \brief Create and open a file with a unique name based on 'templet'. + * + * Notes: + *\li 'template' is a reserved work in C++. If you want to complain + * about the spelling of 'templet', first look it up in the + * Merriam-Webster English dictionary. (http://www.m-w.com/) + * + *\li This function works by using the template to generate file names. + * The template must be a writable string, as it is modified in place. + * Trailing X characters in the file name (full file name on Unix, + * basename on Win32 -- eg, tmp-XXXXXX vs XXXXXX.tmp, respectively) + * are replaced with ASCII characters until a non-existent filename + * is found. If the template does not include pathname information, + * the files in the working directory of the program are searched. + * + *\li isc_file_mktemplate is a good, portable way to get a template. + * + * Requires: + *\li 'fp' is non-NULL and '*fp' is NULL. + * + *\li 'template' is non-NULL, and of a form suitable for use by + * the system as described above. + * + * Ensures: + *\li If result is #ISC_R_SUCCESS: + * *fp points to an stream opening in stdio's "w+" mode. + * + *\li If result is not #ISC_R_SUCCESS: + * *fp is NULL. + * + * No file is open. Even if one was created (but unable + * to be reopened as a stdio FILE pointer) then it has been + * removed. + * + *\li This function does *not* ensure that the template string has not been + * modified, even if the operation was unsuccessful. + * + * Returns: + *\li #ISC_R_SUCCESS + * Success. + *\li #ISC_R_EXISTS + * No file with a unique name could be created based on the + * template. + *\li #ISC_R_INVALIDFILE + * The path specified was not usable by the operating system. + *\li #ISC_R_NOPERM + * The file could not be created because permission was denied + * to some part of the file's path. + *\li #ISC_R_IOERROR + * Hardware error interacting with the filesystem. + *\li #ISC_R_UNEXPECTED + * Something totally unexpected happened. + */ + +isc_result_t +isc_file_remove(const char *filename); +/*!< + * \brief Remove the file named by 'filename'. + */ + +isc_result_t +isc_file_rename(const char *oldname, const char *newname); +/*!< + * \brief Rename the file 'oldname' to 'newname'. + */ + +isc_boolean_t +isc_file_exists(const char *pathname); +/*!< + * \brief Return #ISC_TRUE if the calling process can tell that the given file exists. + * Will not return true if the calling process has insufficient privileges + * to search the entire path. + */ + +isc_boolean_t +isc_file_isabsolute(const char *filename); +/*!< + * \brief Return #ISC_TRUE if the given file name is absolute. + */ + +isc_result_t +isc_file_isplainfile(const char *name); +/*!< + * \brief Check that the file is a plain file + * + * Returns: + *\li #ISC_R_SUCCESS + * Success. The file is a plain file. + *\li #ISC_R_INVALIDFILE + * The path specified was not usable by the operating system. + *\li #ISC_R_FILENOTFOUND + * The file does not exist. This return code comes from + * errno=ENOENT when stat returns -1. This code is mentioned + * here, because in logconf.c, it is the one rcode that is + * permitted in addition to ISC_R_SUCCESS. This is done since + * the next call in logconf.c is to isc_stdio_open(), which + * will create the file if it can. + *\li #other ISC_R_* errors translated from errno + * These occur when stat returns -1 and an errno. + */ + +isc_boolean_t +isc_file_iscurrentdir(const char *filename); +/*!< + * \brief Return #ISC_TRUE if the given file name is the current directory ("."). + */ + +isc_boolean_t +isc_file_ischdiridempotent(const char *filename); +/*%< + * Return #ISC_TRUE if calling chdir(filename) multiple times will give + * the same result as calling it once. + */ + +const char * +isc_file_basename(const char *filename); +/*%< + * Return the final component of the path in the file name. + */ + +isc_result_t +isc_file_progname(const char *filename, char *buf, size_t buflen); +/*!< + * \brief Given an operating system specific file name "filename" + * referring to a program, return the canonical program name. + * + * + * Any directory prefix or executable file name extension (if + * used on the OS in case) is stripped. On systems where program + * names are case insensitive, the name is canonicalized to all + * lower case. The name is written to 'buf', an array of 'buflen' + * chars, and null terminated. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOSPACE The name did not fit in 'buf'. + */ + +isc_result_t +isc_file_template(const char *path, const char *templet, char *buf, + size_t buflen); +/*%< + * Create an OS specific template using 'path' to define the directory + * 'templet' to describe the filename and store the result in 'buf' + * such that path can be renamed to buf atomically. + */ + +isc_result_t +isc_file_renameunique(const char *file, char *templet); +/*%< + * Rename 'file' using 'templet' as a template for the new file name. + */ + +isc_result_t +isc_file_absolutepath(const char *filename, char *path, size_t pathlen); +/*%< + * Given a file name, return the fully qualified path to the file. + */ + +/* + * XXX We should also have a isc_file_writeeopen() function + * for safely open a file in a publicly writable directory + * (see write_open() in BIND 8's ns_config.c). + */ + +isc_result_t +isc_file_truncate(const char *filename, isc_offset_t size); +/*%< + * Truncate/extend the file specified to 'size' bytes. + */ + +isc_result_t +isc_file_safecreate(const char *filename, FILE **fp); +/*%< + * Open 'filename' for writing, truncating if necessary. Ensure that + * if it existed it was a normal file. If creating the file, ensure + * that only the owner can read/write it. + */ + +isc_result_t +isc_file_splitpath(isc_mem_t *mctx, char *path, + char **dirname, char **basename); +/*%< + * Split a path into dirname and basename. If 'path' contains no slash + * (or, on windows, backslash), then '*dirname' is set to ".". + * + * Allocates memory for '*dirname', which can be freed with isc_mem_free(). + * + * Returns: + * - ISC_R_SUCCESS on success + * - ISC_R_INVALIDFILE if 'path' is empty or ends with '/' + * - ISC_R_NOMEMORY if unable to allocate memory + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_FILE_H */ diff --git a/contrib/ntp/lib/isc/include/isc/formatcheck.h b/contrib/ntp/lib/isc/include/isc/formatcheck.h new file mode 100644 index 0000000..51ce3ca --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/formatcheck.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: formatcheck.h,v 1.13 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_FORMATCHECK_H +#define ISC_FORMATCHECK_H 1 + +/*! \file isc/formatcheck.h */ + +/*% + * ISC_FORMAT_PRINTF(). + * + * \li fmt is the location of the format string parameter. + * \li args is the location of the first argument (or 0 for no argument checking). + * + * Note: + * \li The first parameter is 1, not 0. + */ +#ifdef __GNUC__ +#define ISC_FORMAT_PRINTF(fmt, args) __attribute__((__format__(__printf__, fmt, args))) +#else +#define ISC_FORMAT_PRINTF(fmt, args) +#endif + +#endif /* ISC_FORMATCHECK_H */ diff --git a/contrib/ntp/lib/isc/include/isc/fsaccess.h b/contrib/ntp/lib/isc/include/isc/fsaccess.h new file mode 100644 index 0000000..7962bbe --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/fsaccess.h @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: fsaccess.h,v 1.16 2009/01/17 23:47:43 tbox Exp $ */ + +#ifndef ISC_FSACCESS_H +#define ISC_FSACCESS_H 1 + +/*! \file isc/fsaccess.h + * \brief The ISC filesystem access module encapsulates the setting of file + * and directory access permissions into one API that is meant to be + * portable to multiple operating systems. + * + * The two primary operating system flavors that are initially accommodated + * are POSIX and Windows NT 4.0 and later. The Windows NT access model is + * considerable more flexible than POSIX's model (as much as I am loathe to + * admit it), and so the ISC API has a higher degree of complexity than would + * be needed to simply address POSIX's needs. + * + * The full breadth of NT's flexibility is not available either, for the + * present time. Much of it is to provide compatibility with what Unix + * programmers are expecting. This is also due to not yet really needing all + * of the functionality of an NT system (or, for that matter, a POSIX system) + * in BIND9, and so resolving how to handle the various incompatibilities has + * been a purely theoretical exercise with no operational experience to + * indicate how flawed the thinking may be. + * + * Some of the more notable dumbing down of NT for this API includes: + * + *\li Each of FILE_READ_DATA and FILE_READ_EA are set with #ISC_FSACCESS_READ. + * + * \li All of FILE_WRITE_DATA, FILE_WRITE_EA and FILE_APPEND_DATA are + * set with #ISC_FSACCESS_WRITE. FILE_WRITE_ATTRIBUTES is not set + * so as to be consistent with Unix, where only the owner of the file + * or the superuser can change the attributes/mode of a file. + * + * \li Both of FILE_ADD_FILE and FILE_ADD_SUBDIRECTORY are set with + * #ISC_FSACCESS_CREATECHILD. This is similar to setting the WRITE + * permission on a Unix directory. + * + * \li SYNCHRONIZE is always set for files and directories, unless someone + * can give me a reason why this is a bad idea. + * + * \li READ_CONTROL and FILE_READ_ATTRIBUTES are always set; this is + * consistent with Unix, where any file or directory can be stat()'d + * unless the directory path disallows complete access somewhere along + * the way. + * + * \li WRITE_DAC is only set for the owner. This too is consistent with + * Unix, and is tighter security than allowing anyone else to be + * able to set permissions. + * + * \li DELETE is only set for the owner. On Unix the ability to delete + * a file is controlled by the directory permissions, but it isn't + * currently clear to me what happens on NT if the directory has + * FILE_DELETE_CHILD set but a file within it does not have DELETE + * set. Always setting DELETE on the file/directory for the owner + * gives maximum flexibility to the owner without exposing the + * file to deletion by others. + * + * \li WRITE_OWNER is never set. This too is consistent with Unix, + * and is also tighter security than allowing anyone to change the + * ownership of the file apart from the superu..ahem, Administrator. + * + * \li Inheritance is set to NO_INHERITANCE. + * + * Unix's dumbing down includes: + * + * \li The sticky bit cannot be set. + * + * \li setuid and setgid cannot be set. + * + * \li Only regular files and directories can be set. + * + * The rest of this comment discusses a few of the incompatibilities + * between the two systems that need more thought if this API is to + * be extended to accommodate them. + * + * The Windows standard access right "DELETE" doesn't have a direct + * equivalent in the Unix world, so it isn't clear what should be done + * with it. + * + * The Unix sticky bit is not supported. While NT does have a concept + * of allowing users to create files in a directory but not delete or + * rename them, it does not have a concept of allowing them to be deleted + * if they are owned by the user trying to delete/rename. While it is + * probable that something could be cobbled together in NT 5 with inheritance, + * it can't really be done in NT 4 as a single property that you could + * set on a directory. You'd need to coordinate something with file creation + * so that every file created had DELETE set for the owner but noone else. + * + * On Unix systems, setting #ISC_FSACCESS_LISTDIRECTORY sets READ. + * ... setting either #ISC_FSACCESS_CREATECHILD or #ISC_FSACCESS_DELETECHILD + * sets WRITE. + * ... setting #ISC_FSACCESS_ACCESSCHILD sets EXECUTE. + * + * On NT systems, setting #ISC_FSACCESS_LISTDIRECTORY sets FILE_LIST_DIRECTORY. + * ... setting #ISC_FSACCESS_CREATECHILD sets FILE_CREATE_CHILD independently. + * ... setting #ISC_FSACCESS_DELETECHILD sets FILE_DELETE_CHILD independently. + * ... setting #ISC_FSACCESS_ACCESSCHILD sets FILE_TRAVERSE. + * + * Unresolved: XXXDCL + * \li What NT access right controls the ability to rename a file? + * \li How does DELETE work? If a directory has FILE_DELETE_CHILD but a + * file or directory within it does not have DELETE, is that file + * or directory deletable? + * \li To implement isc_fsaccess_get(), mapping an existing Unix permission + * mode_t back to an isc_fsaccess_t is pretty trivial; however, mapping + * an NT DACL could be impossible to do in a responsible way. + * \li Similarly, trying to implement the functionality of being able to + * say "add group writability to whatever permissions already exist" + * could be tricky on NT because of the order-of-entry issue combined + * with possibly having one or more matching ACEs already explicitly + * granting or denying access. Because this functionality is + * not yet needed by the ISC, no code has been written to try to + * solve this problem. + */ + +#include <isc/lang.h> +#include <isc/types.h> + +/* + * Trustees. + */ +#define ISC_FSACCESS_OWNER 0x1 /*%< User account. */ +#define ISC_FSACCESS_GROUP 0x2 /*%< Primary group owner. */ +#define ISC_FSACCESS_OTHER 0x4 /*%< Not the owner or the group owner. */ +#define ISC_FSACCESS_WORLD 0x7 /*%< User, Group, Other. */ + +/* + * Types of permission. + */ +#define ISC_FSACCESS_READ 0x00000001 /*%< File only. */ +#define ISC_FSACCESS_WRITE 0x00000002 /*%< File only. */ +#define ISC_FSACCESS_EXECUTE 0x00000004 /*%< File only. */ +#define ISC_FSACCESS_CREATECHILD 0x00000008 /*%< Dir only. */ +#define ISC_FSACCESS_DELETECHILD 0x00000010 /*%< Dir only. */ +#define ISC_FSACCESS_LISTDIRECTORY 0x00000020 /*%< Dir only. */ +#define ISC_FSACCESS_ACCESSCHILD 0x00000040 /*%< Dir only. */ + +/*% + * Adding any permission bits beyond 0x200 would mean typedef'ing + * isc_fsaccess_t as isc_uint64_t, and redefining this value to + * reflect the new range of permission types, Probably to 21 for + * maximum flexibility. The number of bits has to accommodate all of + * the permission types, and three full sets of them have to fit + * within an isc_fsaccess_t. + */ +#define ISC__FSACCESS_PERMISSIONBITS 10 + +ISC_LANG_BEGINDECLS + +void +isc_fsaccess_add(int trustee, int permission, isc_fsaccess_t *access); + +void +isc_fsaccess_remove(int trustee, int permission, isc_fsaccess_t *access); + +isc_result_t +isc_fsaccess_set(const char *path, isc_fsaccess_t access); + +ISC_LANG_ENDDECLS + +#endif /* ISC_FSACCESS_H */ diff --git a/contrib/ntp/lib/isc/include/isc/hash.h b/contrib/ntp/lib/isc/include/isc/hash.h new file mode 100644 index 0000000..ca04b4e --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/hash.h @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: hash.h,v 1.12 2009/01/17 23:47:43 tbox Exp $ */ + +#ifndef ISC_HASH_H +#define ISC_HASH_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file isc/hash.h + * + * \brief The hash API + * provides an unpredictable hash value for variable length data. + * A hash object contains a random vector (which is hidden from clients + * of this API) to make the actual hash value unpredictable. + * + * The algorithm used in the API guarantees the probability of hash + * collision; in the current implementation, as long as the values stored + * in the random vector are unpredictable, the probability of hash + * collision between arbitrary two different values is at most 1/2^16. + * + * Although the API is generic about the hash keys, it mainly expects + * DNS names (and sometimes IPv4/v6 addresses) as inputs. It has an + * upper limit of the input length, and may run slow to calculate the + * hash values for large inputs. + * + * This API is designed to be general so that it can provide multiple + * different hash contexts that have different random vectors. However, + * it should be typical to have a single context for an entire system. + * To support such cases, the API also provides a single-context mode. + * + * \li MP: + * The hash object is almost read-only. Once the internal random vector + * is initialized, no write operation will occur, and there will be no + * need to lock the object to calculate actual hash values. + * + * \li Reliability: + * In some cases this module uses low-level data copy to initialize the + * random vector. Errors in this part are likely to crash the server or + * corrupt memory. + * + * \li Resources: + * A buffer, used as a random vector for calculating hash values. + * + * \li Security: + * This module intends to provide unpredictable hash values in + * adversarial environments in order to avoid denial of service attacks + * to hash buckets. + * Its unpredictability relies on the quality of entropy to build the + * random vector. + * + * \li Standards: + * None. + */ + +/*** + *** Imports + ***/ + +#include <isc/types.h> + +/*** + *** Functions + ***/ +ISC_LANG_BEGINDECLS + +isc_result_t +isc_hash_ctxcreate(isc_mem_t *mctx, isc_entropy_t *entropy, unsigned int limit, + isc_hash_t **hctx); +isc_result_t +isc_hash_create(isc_mem_t *mctx, isc_entropy_t *entropy, size_t limit); +/*!< + * \brief Create a new hash object. + * + * isc_hash_ctxcreate() creates a different object. + * + * isc_hash_create() creates a module-internal object to support the + * single-context mode. It should be called only once. + * + * 'entropy' must be NULL or a valid entropy object. If 'entropy' is NULL, + * pseudo random values will be used to build the random vector, which may + * weaken security. + * + * 'limit' specifies the maximum number of hash keys. If it is too large, + * these functions may fail. + */ + +void +isc_hash_ctxattach(isc_hash_t *hctx, isc_hash_t **hctxp); +/*!< + * \brief Attach to a hash object. + * + * This function is only necessary for the multiple-context mode. + */ + +void +isc_hash_ctxdetach(isc_hash_t **hctxp); +/*!< + * \brief Detach from a hash object. + * + * This function is for the multiple-context mode, and takes a valid + * hash object as an argument. + */ + +void +isc_hash_destroy(void); +/*!< + * \brief This function is for the single-context mode, and is expected to be used + * as a counterpart of isc_hash_create(). + * + * A valid module-internal hash object must have been created, and this + * function should be called only once. + */ + +/*@{*/ +void +isc_hash_ctxinit(isc_hash_t *hctx); +void +isc_hash_init(void); +/*!< + * \brief Initialize a hash object. + * + * It fills in the random vector with a proper + * source of entropy, which is typically from the entropy object specified + * at the creation. Thus, it is desirable to call these functions after + * initializing the entropy object with some good entropy sources. + * + * These functions should be called before the first hash calculation. + * + * isc_hash_ctxinit() is for the multiple-context mode, and takes a valid hash + * object as an argument. + * + * isc_hash_init() is for the single-context mode. A valid module-internal + * hash object must have been created, and this function should be called only + * once. + */ +/*@}*/ + +/*@{*/ +unsigned int +isc_hash_ctxcalc(isc_hash_t *hctx, const unsigned char *key, + unsigned int keylen, isc_boolean_t case_sensitive); +unsigned int +isc_hash_calc(const unsigned char *key, unsigned int keylen, + isc_boolean_t case_sensitive); +/*!< + * \brief Calculate a hash value. + * + * isc_hash_ctxinit() is for the multiple-context mode, and takes a valid hash + * object as an argument. + * + * isc_hash_init() is for the single-context mode. A valid module-internal + * hash object must have been created. + * + * 'key' is the hash key, which is a variable length buffer. + * + * 'keylen' specifies the key length, which must not be larger than the limit + * specified for the corresponding hash object. + * + * 'case_sensitive' specifies whether the hash key should be treated as + * case_sensitive values. It should typically be ISC_FALSE if the hash key + * is a DNS name. + */ +/*@}*/ + +ISC_LANG_ENDDECLS + +#endif /* ISC_HASH_H */ diff --git a/contrib/ntp/lib/isc/include/isc/heap.h b/contrib/ntp/lib/isc/include/isc/heap.h new file mode 100644 index 0000000..77bf07c --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/heap.h @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1997-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: heap.h,v 1.26 2009/01/17 23:47:43 tbox Exp $ */ + +#ifndef ISC_HEAP_H +#define ISC_HEAP_H 1 + +/*! \file isc/heap.h */ + +#include <isc/lang.h> +#include <isc/types.h> + +ISC_LANG_BEGINDECLS + +/*% + * The comparison function returns ISC_TRUE if the first argument has + * higher priority than the second argument, and ISC_FALSE otherwise. + */ +typedef isc_boolean_t (*isc_heapcompare_t)(void *, void *); + +/*% + * The index function allows the client of the heap to receive a callback + * when an item's index number changes. This allows it to maintain + * sync with its external state, but still delete itself, since deletions + * from the heap require the index be provided. + */ +typedef void (*isc_heapindex_t)(void *, unsigned int); + +/*% + * The heapaction function is used when iterating over the heap. + * + * NOTE: The heap structure CANNOT BE MODIFIED during the call to + * isc_heap_foreach(). + */ +typedef void (*isc_heapaction_t)(void *, void *); + +typedef struct isc_heap isc_heap_t; + +isc_result_t +isc_heap_create(isc_mem_t *mctx, isc_heapcompare_t compare, + isc_heapindex_t index, unsigned int size_increment, + isc_heap_t **heapp); +/*!< + * \brief Create a new heap. The heap is implemented using a space-efficient + * storage method. When the heap elements are deleted space is not freed + * but will be reused when new elements are inserted. + * + * Requires: + *\li "mctx" is valid. + *\li "compare" is a function which takes two void * arguments and + * returns ISC_TRUE if the first argument has a higher priority than + * the second, and ISC_FALSE otherwise. + *\li "index" is a function which takes a void *, and an unsigned int + * argument. This function will be called whenever an element's + * index value changes, so it may continue to delete itself from the + * heap. This option may be NULL if this functionality is unneeded. + *\li "size_increment" is a hint about how large the heap should grow + * when resizing is needed. If this is 0, a default size will be + * used, which is currently 1024, allowing space for an additional 1024 + * heap elements to be inserted before adding more space. + *\li "heapp" is not NULL, and "*heap" is NULL. + * + * Returns: + *\li ISC_R_SUCCESS - success + *\li ISC_R_NOMEMORY - insufficient memory + */ + +void +isc_heap_destroy(isc_heap_t **heapp); +/*!< + * \brief Destroys a heap. + * + * Requires: + *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t. + */ + +isc_result_t +isc_heap_insert(isc_heap_t *heap, void *elt); +/*!< + * \brief Inserts a new element into a heap. + * + * Requires: + *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t. + */ + +void +isc_heap_delete(isc_heap_t *heap, unsigned int index); +/*!< + * \brief Deletes an element from a heap, by element index. + * + * Requires: + *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t. + *\li "index" is a valid element index, as provided by the "index" callback + * provided during heap creation. + */ + +void +isc_heap_increased(isc_heap_t *heap, unsigned int index); +/*!< + * \brief Indicates to the heap that an element's priority has increased. + * This function MUST be called whenever an element has increased in priority. + * + * Requires: + *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t. + *\li "index" is a valid element index, as provided by the "index" callback + * provided during heap creation. + */ + +void +isc_heap_decreased(isc_heap_t *heap, unsigned int index); +/*!< + * \brief Indicates to the heap that an element's priority has decreased. + * This function MUST be called whenever an element has decreased in priority. + * + * Requires: + *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t. + *\li "index" is a valid element index, as provided by the "index" callback + * provided during heap creation. + */ + +void * +isc_heap_element(isc_heap_t *heap, unsigned int index); +/*!< + * \brief Returns the element for a specific element index. + * + * Requires: + *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t. + *\li "index" is a valid element index, as provided by the "index" callback + * provided during heap creation. + * + * Returns: + *\li A pointer to the element for the element index. + */ + +void +isc_heap_foreach(isc_heap_t *heap, isc_heapaction_t action, void *uap); +/*!< + * \brief Iterate over the heap, calling an action for each element. The + * order of iteration is not sorted. + * + * Requires: + *\li "heapp" is not NULL and "*heap" points to a valid isc_heap_t. + *\li "action" is not NULL, and is a function which takes two arguments. + * The first is a void *, representing the element, and the second is + * "uap" as provided to isc_heap_foreach. + *\li "uap" is a caller-provided argument, and may be NULL. + * + * Note: + *\li The heap structure CANNOT be modified during this iteration. The only + * safe function to call while iterating the heap is isc_heap_element(). + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_HEAP_H */ diff --git a/contrib/ntp/lib/isc/include/isc/hex.h b/contrib/ntp/lib/isc/include/isc/hex.h new file mode 100644 index 0000000..a5e2f53 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/hex.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: hex.h,v 1.13 2008/09/25 04:02:39 tbox Exp $ */ + +#ifndef ISC_HEX_H +#define ISC_HEX_H 1 + +/*! \file isc/hex.h */ + +#include <isc/lang.h> +#include <isc/types.h> + +ISC_LANG_BEGINDECLS + +/*** + *** Functions + ***/ + +isc_result_t +isc_hex_totext(isc_region_t *source, int wordlength, + const char *wordbreak, isc_buffer_t *target); +/*!< + * \brief Convert data into hex encoded text. + * + * Notes: + *\li The hex encoded text in 'target' will be divided into + * words of at most 'wordlength' characters, separated by + * the 'wordbreak' string. No parentheses will surround + * the text. + * + * Requires: + *\li 'source' is a region containing binary data + *\li 'target' is a text buffer containing available space + *\li 'wordbreak' points to a null-terminated string of + * zero or more whitespace characters + * + * Ensures: + *\li target will contain the hex encoded version of the data + * in source. The 'used' pointer in target will be advanced as + * necessary. + */ + +isc_result_t +isc_hex_decodestring(const char *cstr, isc_buffer_t *target); +/*!< + * \brief Decode a null-terminated hex string. + * + * Requires: + *\li 'cstr' is non-null. + *\li 'target' is a valid buffer. + * + * Returns: + *\li #ISC_R_SUCCESS -- the entire decoded representation of 'cstring' + * fit in 'target'. + *\li #ISC_R_BADHEX -- 'cstr' is not a valid hex encoding. + * + * Other error returns are any possible error code from: + * isc_lex_create(), + * isc_lex_openbuffer(), + * isc_hex_tobuffer(). + */ + +isc_result_t +isc_hex_tobuffer(isc_lex_t *lexer, isc_buffer_t *target, int length); +/*!< + * \brief Convert hex encoded text from a lexer context into data. + * + * Requires: + *\li 'lex' is a valid lexer context + *\li 'target' is a buffer containing binary data + *\li 'length' is an integer + * + * Ensures: + *\li target will contain the data represented by the hex encoded + * string parsed by the lexer. No more than length bytes will be read, + * if length is positive. The 'used' pointer in target will be + * advanced as necessary. + */ + + +ISC_LANG_ENDDECLS + +#endif /* ISC_HEX_H */ diff --git a/contrib/ntp/lib/isc/include/isc/hmacmd5.h b/contrib/ntp/lib/isc/include/isc/hmacmd5.h new file mode 100644 index 0000000..9ecad453 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/hmacmd5.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: hmacmd5.h,v 1.14 2009/02/06 23:47:42 tbox Exp $ */ + +/*! \file isc/hmacmd5.h + * \brief This is the header file for the HMAC-MD5 keyed hash algorithm + * described in RFC2104. + */ + +#ifndef ISC_HMACMD5_H +#define ISC_HMACMD5_H 1 + +#include <isc/lang.h> +#include <isc/md5.h> +#include <isc/platform.h> +#include <isc/types.h> + +#define ISC_HMACMD5_KEYLENGTH 64 + +#ifdef ISC_PLATFORM_OPENSSLHASH +#include <openssl/hmac.h> + +typedef HMAC_CTX isc_hmacmd5_t; + +#else + +typedef struct { + isc_md5_t md5ctx; + unsigned char key[ISC_HMACMD5_KEYLENGTH]; +} isc_hmacmd5_t; +#endif + +ISC_LANG_BEGINDECLS + +void +isc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key, + unsigned int len); + +void +isc_hmacmd5_invalidate(isc_hmacmd5_t *ctx); + +void +isc_hmacmd5_update(isc_hmacmd5_t *ctx, const unsigned char *buf, + unsigned int len); + +void +isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest); + +isc_boolean_t +isc_hmacmd5_verify(isc_hmacmd5_t *ctx, unsigned char *digest); + +isc_boolean_t +isc_hmacmd5_verify2(isc_hmacmd5_t *ctx, unsigned char *digest, size_t len); + +ISC_LANG_ENDDECLS + +#endif /* ISC_HMACMD5_H */ diff --git a/contrib/ntp/lib/isc/include/isc/hmacsha.h b/contrib/ntp/lib/isc/include/isc/hmacsha.h new file mode 100644 index 0000000..1d0e184 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/hmacsha.h @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2005-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: hmacsha.h,v 1.9 2009/02/06 23:47:42 tbox Exp $ */ + +/*! \file isc/hmacsha.h + * This is the header file for the HMAC-SHA1, HMAC-SHA224, HMAC-SHA256, + * HMAC-SHA334 and HMAC-SHA512 hash algorithm described in RFC 2104. + */ + +#ifndef ISC_HMACSHA_H +#define ISC_HMACSHA_H 1 + +#include <isc/lang.h> +#include <isc/platform.h> +#include <isc/sha1.h> +#include <isc/sha2.h> +#include <isc/types.h> + +#define ISC_HMACSHA1_KEYLENGTH ISC_SHA1_BLOCK_LENGTH +#define ISC_HMACSHA224_KEYLENGTH ISC_SHA224_BLOCK_LENGTH +#define ISC_HMACSHA256_KEYLENGTH ISC_SHA256_BLOCK_LENGTH +#define ISC_HMACSHA384_KEYLENGTH ISC_SHA384_BLOCK_LENGTH +#define ISC_HMACSHA512_KEYLENGTH ISC_SHA512_BLOCK_LENGTH + +#ifdef ISC_PLATFORM_OPENSSLHASH +#include <openssl/hmac.h> + +typedef HMAC_CTX isc_hmacsha1_t; +typedef HMAC_CTX isc_hmacsha224_t; +typedef HMAC_CTX isc_hmacsha256_t; +typedef HMAC_CTX isc_hmacsha384_t; +typedef HMAC_CTX isc_hmacsha512_t; + +#else + +typedef struct { + isc_sha1_t sha1ctx; + unsigned char key[ISC_HMACSHA1_KEYLENGTH]; +} isc_hmacsha1_t; + +typedef struct { + isc_sha224_t sha224ctx; + unsigned char key[ISC_HMACSHA224_KEYLENGTH]; +} isc_hmacsha224_t; + +typedef struct { + isc_sha256_t sha256ctx; + unsigned char key[ISC_HMACSHA256_KEYLENGTH]; +} isc_hmacsha256_t; + +typedef struct { + isc_sha384_t sha384ctx; + unsigned char key[ISC_HMACSHA384_KEYLENGTH]; +} isc_hmacsha384_t; + +typedef struct { + isc_sha512_t sha512ctx; + unsigned char key[ISC_HMACSHA512_KEYLENGTH]; +} isc_hmacsha512_t; +#endif + +ISC_LANG_BEGINDECLS + +void +isc_hmacsha1_init(isc_hmacsha1_t *ctx, const unsigned char *key, + unsigned int len); + +void +isc_hmacsha1_invalidate(isc_hmacsha1_t *ctx); + +void +isc_hmacsha1_update(isc_hmacsha1_t *ctx, const unsigned char *buf, + unsigned int len); + +void +isc_hmacsha1_sign(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len); + +isc_boolean_t +isc_hmacsha1_verify(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len); + + +void +isc_hmacsha224_init(isc_hmacsha224_t *ctx, const unsigned char *key, + unsigned int len); + +void +isc_hmacsha224_invalidate(isc_hmacsha224_t *ctx); + +void +isc_hmacsha224_update(isc_hmacsha224_t *ctx, const unsigned char *buf, + unsigned int len); + +void +isc_hmacsha224_sign(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len); + +isc_boolean_t +isc_hmacsha224_verify(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len); + + +void +isc_hmacsha256_init(isc_hmacsha256_t *ctx, const unsigned char *key, + unsigned int len); + +void +isc_hmacsha256_invalidate(isc_hmacsha256_t *ctx); + +void +isc_hmacsha256_update(isc_hmacsha256_t *ctx, const unsigned char *buf, + unsigned int len); + +void +isc_hmacsha256_sign(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len); + +isc_boolean_t +isc_hmacsha256_verify(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len); + + +void +isc_hmacsha384_init(isc_hmacsha384_t *ctx, const unsigned char *key, + unsigned int len); + +void +isc_hmacsha384_invalidate(isc_hmacsha384_t *ctx); + +void +isc_hmacsha384_update(isc_hmacsha384_t *ctx, const unsigned char *buf, + unsigned int len); + +void +isc_hmacsha384_sign(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len); + +isc_boolean_t +isc_hmacsha384_verify(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len); + + +void +isc_hmacsha512_init(isc_hmacsha512_t *ctx, const unsigned char *key, + unsigned int len); + +void +isc_hmacsha512_invalidate(isc_hmacsha512_t *ctx); + +void +isc_hmacsha512_update(isc_hmacsha512_t *ctx, const unsigned char *buf, + unsigned int len); + +void +isc_hmacsha512_sign(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len); + +isc_boolean_t +isc_hmacsha512_verify(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len); + +ISC_LANG_ENDDECLS + +#endif /* ISC_HMACSHA_H */ diff --git a/contrib/ntp/lib/isc/include/isc/httpd.h b/contrib/ntp/lib/isc/include/isc/httpd.h new file mode 100644 index 0000000..ba7f900 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/httpd.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2006-2008 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: httpd.h,v 1.9 2008/08/08 05:06:49 marka Exp $ */ + +#ifndef ISC_HTTPD_H +#define ISC_HTTPD_H 1 + +/*! \file */ + +#include <isc/event.h> +#include <isc/eventclass.h> +#include <isc/types.h> +#include <isc/mutex.h> +#include <isc/task.h> + +#define HTTPD_EVENTCLASS ISC_EVENTCLASS(4300) +#define HTTPD_SHUTDOWN (HTTPD_EVENTCLASS + 0x0001) + +#define ISC_HTTPDMGR_FLAGSHUTTINGDOWN 0x00000001 + +/* + * Create a new http daemon which will send, once every time period, + * a http-like header followed by HTTP data. + */ +isc_result_t +isc_httpdmgr_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task, + isc_httpdclientok_t *client_ok, + isc_httpdondestroy_t *ondestory, void *cb_arg, + isc_timermgr_t *tmgr, isc_httpdmgr_t **httpdp); + +void +isc_httpdmgr_shutdown(isc_httpdmgr_t **httpdp); + +isc_result_t +isc_httpdmgr_addurl(isc_httpdmgr_t *httpdmgr, const char *url, + isc_httpdaction_t *func, void *arg); + +isc_result_t +isc_httpd_response(isc_httpd_t *httpd); + +isc_result_t +isc_httpd_addheader(isc_httpd_t *httpd, const char *name, + const char *val); + +isc_result_t +isc_httpd_addheaderuint(isc_httpd_t *httpd, const char *name, int val); + +isc_result_t isc_httpd_endheaders(isc_httpd_t *httpd); + +#endif /* ISC_HTTPD_H */ diff --git a/contrib/ntp/lib/isc/include/isc/interfaceiter.h b/contrib/ntp/lib/isc/include/isc/interfaceiter.h new file mode 100644 index 0000000..544f54b --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/interfaceiter.h @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: interfaceiter.h,v 1.17 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_INTERFACEITER_H +#define ISC_INTERFACEITER_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file isc/interfaceiter.h + * \brief Iterates over the list of network interfaces. + * + * Interfaces whose address family is not supported are ignored and never + * returned by the iterator. Interfaces whose netmask, interface flags, + * or similar cannot be obtained are also ignored, and the failure is logged. + * + * Standards: + * The API for scanning varies greatly among operating systems. + * This module attempts to hide the differences. + */ + +/*** + *** Imports + ***/ + +#include <isc/lang.h> +#include <isc/netaddr.h> +#include <isc/types.h> + +/*! + * \brief Public structure describing a network interface. + */ + +struct isc_interface { + char name[32]; /*%< Interface name, null-terminated. */ + unsigned int af; /*%< Address family. */ + isc_netaddr_t address; /*%< Local address. */ + isc_netaddr_t netmask; /*%< Network mask. */ + isc_netaddr_t broadcast; /*&< Broadcast address. */ + isc_netaddr_t dstaddress; /*%< Destination address (point-to-point only). */ + isc_uint32_t flags; /*%< Flags; see INTERFACE flags. */ + unsigned int ifindex; /*%< Interface index for IP(V6)_MULTICAST_IF. */ +}; + +/*@{*/ +/*! Interface flags. */ + +#define INTERFACE_F_UP 0x00000001U +#define INTERFACE_F_POINTTOPOINT 0x00000002U +#define INTERFACE_F_LOOPBACK 0x00000004U +#define INTERFACE_F_BROADCAST 0x00000008U +#define INTERFACE_F_MULTICAST 0x00000010U +#define INTERFACE_F_PRIVACY 0x00000020U /* RFC 4941 */ +/*@}*/ + +/*** + *** Functions + ***/ + +ISC_LANG_BEGINDECLS + +isc_result_t +isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp); +/*!< + * \brief Create an iterator for traversing the operating system's list + * of network interfaces. + * + * Returns: + *\li #ISC_R_SUCCESS + * \li #ISC_R_NOMEMORY + *\li Various network-related errors + */ + +isc_result_t +isc_interfaceiter_first(isc_interfaceiter_t *iter); +/*!< + * \brief Position the iterator on the first interface. + * + * Returns: + *\li #ISC_R_SUCCESS Success. + *\li #ISC_R_NOMORE There are no interfaces. + */ + +isc_result_t +isc_interfaceiter_current(isc_interfaceiter_t *iter, + isc_interface_t *ifdata); +/*!< + * \brief Get information about the interface the iterator is currently + * positioned at and store it at *ifdata. + * + * Requires: + *\li The iterator has been successfully positioned using + * isc_interface_iter_first() / isc_interface_iter_next(). + * + * Returns: + *\li #ISC_R_SUCCESS Success. + */ + +isc_result_t +isc_interfaceiter_next(isc_interfaceiter_t *iter); +/*!< + * \brief Position the iterator on the next interface. + * + * Requires: + * \li The iterator has been successfully positioned using + * isc_interface_iter_first() / isc_interface_iter_next(). + * + * Returns: + *\li #ISC_R_SUCCESS Success. + *\li #ISC_R_NOMORE There are no more interfaces. + */ + +void +isc_interfaceiter_destroy(isc_interfaceiter_t **iterp); +/*!< + * \brief Destroy the iterator. + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_INTERFACEITER_H */ diff --git a/contrib/ntp/lib/isc/include/isc/ipv6.h b/contrib/ntp/lib/isc/include/isc/ipv6.h new file mode 100644 index 0000000..8054c9e --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/ipv6.h @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: ipv6.h,v 1.24 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_IPV6_H +#define ISC_IPV6_H 1 + +/*! + * Also define LWRES_IPV6_H to keep it from being included if liblwres is + * being used, or redefinition errors will occur. + */ +#define LWRES_IPV6_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file isc/ipv6.h + * \brief IPv6 definitions for systems which do not support IPv6. + * + * \li MP: + * No impact. + * + * \li Reliability: + * No anticipated impact. + * + * \li Resources: + * N/A. + * + * \li Security: + * No anticipated impact. + * + * \li Standards: + * RFC2553. + */ + +/*** + *** Imports. + ***/ + +#include <isc/int.h> +#include <isc/platform.h> + +/*** + *** Types. + ***/ + +struct in6_addr { + union { + isc_uint8_t _S6_u8[16]; + isc_uint16_t _S6_u16[8]; + isc_uint32_t _S6_u32[4]; + } _S6_un; +}; +#define s6_addr _S6_un._S6_u8 +#define s6_addr8 _S6_un._S6_u8 +#define s6_addr16 _S6_un._S6_u16 +#define s6_addr32 _S6_un._S6_u32 + +#define IN6ADDR_ANY_INIT {{{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }}} +#define IN6ADDR_LOOPBACK_INIT {{{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }}} + +LIBISC_EXTERNAL_DATA extern const struct in6_addr in6addr_any; +LIBISC_EXTERNAL_DATA extern const struct in6_addr in6addr_loopback; + +struct sockaddr_in6 { +#ifdef ISC_PLATFORM_HAVESALEN + isc_uint8_t sin6_len; + isc_uint8_t sin6_family; +#else + isc_uint16_t sin6_family; +#endif + isc_uint16_t sin6_port; + isc_uint32_t sin6_flowinfo; + struct in6_addr sin6_addr; + isc_uint32_t sin6_scope_id; +}; + +#ifdef ISC_PLATFORM_HAVESALEN +#define SIN6_LEN 1 +#endif + +/*% + * Unspecified + */ +#define IN6_IS_ADDR_UNSPECIFIED(a) \ + (((a)->s6_addr32[0] == 0) && \ + ((a)->s6_addr32[1] == 0) && \ + ((a)->s6_addr32[2] == 0) && \ + ((a)->s6_addr32[3] == 0)) + +/*% + * Loopback + */ +#define IN6_IS_ADDR_LOOPBACK(a) \ + (((a)->s6_addr32[0] == 0) && \ + ((a)->s6_addr32[1] == 0) && \ + ((a)->s6_addr32[2] == 0) && \ + ((a)->s6_addr32[3] == htonl(1))) + +/*% + * IPv4 compatible + */ +#define IN6_IS_ADDR_V4COMPAT(a) \ + (((a)->s6_addr32[0] == 0) && \ + ((a)->s6_addr32[1] == 0) && \ + ((a)->s6_addr32[2] == 0) && \ + ((a)->s6_addr32[3] != 0) && \ + ((a)->s6_addr32[3] != htonl(1))) + +/*% + * Mapped + */ +#define IN6_IS_ADDR_V4MAPPED(a) \ + (((a)->s6_addr32[0] == 0) && \ + ((a)->s6_addr32[1] == 0) && \ + ((a)->s6_addr32[2] == htonl(0x0000ffff))) + +/*% + * Multicast + */ +#define IN6_IS_ADDR_MULTICAST(a) \ + ((a)->s6_addr8[0] == 0xffU) + +/*% + * Unicast link / site local. + */ +#define IN6_IS_ADDR_LINKLOCAL(a) \ + (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0x80)) +#define IN6_IS_ADDR_SITELOCAL(a) \ + (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0xc0)) + +#endif /* ISC_IPV6_H */ diff --git a/contrib/ntp/lib/isc/include/isc/iterated_hash.h b/contrib/ntp/lib/isc/include/isc/iterated_hash.h new file mode 100644 index 0000000..a8173f0 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/iterated_hash.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: iterated_hash.h,v 1.3 2008/09/25 04:02:39 tbox Exp $ */ + +#ifndef ISC_ITERATED_HASH_H +#define ISC_ITERATED_HASH_H 1 + +#include <isc/lang.h> +#include <isc/sha1.h> + +/* + * The maximal hash length that can be encoded it a name + * using base32hex. floor(255/8)*5 + */ +#define NSEC3_MAX_HASH_LENGTH 155 + +/* + * The maximum has that can be encoded in a single label using + * base32hex. floor(63/8)*5 + */ +#define NSEC3_MAX_LABEL_HASH 35 + +ISC_LANG_BEGINDECLS + +int isc_iterated_hash(unsigned char out[NSEC3_MAX_HASH_LENGTH], + unsigned int hashalg, int iterations, + const unsigned char *salt, int saltlength, + const unsigned char *in, int inlength); + + +ISC_LANG_ENDDECLS + +#endif /* ISC_ITERATED_HASH_H */ diff --git a/contrib/ntp/lib/isc/include/isc/lang.h b/contrib/ntp/lib/isc/include/isc/lang.h new file mode 100644 index 0000000..8c60866 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/lang.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: lang.h,v 1.13 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_LANG_H +#define ISC_LANG_H 1 + +/*! \file isc/lang.h */ + +#ifdef __cplusplus +#define ISC_LANG_BEGINDECLS extern "C" { +#define ISC_LANG_ENDDECLS } +#else +#define ISC_LANG_BEGINDECLS +#define ISC_LANG_ENDDECLS +#endif + +#endif /* ISC_LANG_H */ diff --git a/contrib/ntp/lib/isc/include/isc/lex.h b/contrib/ntp/lib/isc/include/isc/lex.h new file mode 100644 index 0000000..8612150 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/lex.h @@ -0,0 +1,431 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: lex.h,v 1.37 2008/05/30 23:47:01 tbox Exp $ */ + +#ifndef ISC_LEX_H +#define ISC_LEX_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file isc/lex.h + * \brief The "lex" module provides a lightweight tokenizer. It can operate + * on files or buffers, and can handle "include". It is designed for + * parsing of DNS master files and the BIND configuration file, but + * should be general enough to tokenize other things, e.g. HTTP. + * + * \li MP: + * No synchronization is provided. Clients must ensure exclusive + * access. + * + * \li Reliability: + * No anticipated impact. + * + * \li Resources: + * TBS + * + * \li Security: + * No anticipated impact. + * + * \li Standards: + * None. + */ + +/*** + *** Imports + ***/ + +#include <stdio.h> + +#include <isc/lang.h> +#include <isc/region.h> +#include <isc/types.h> + +ISC_LANG_BEGINDECLS + +/*** + *** Options + ***/ + +/*@{*/ +/*! + * Various options for isc_lex_gettoken(). + */ + +#define ISC_LEXOPT_EOL 0x01 /*%< Want end-of-line token. */ +#define ISC_LEXOPT_EOF 0x02 /*%< Want end-of-file token. */ +#define ISC_LEXOPT_INITIALWS 0x04 /*%< Want initial whitespace. */ +#define ISC_LEXOPT_NUMBER 0x08 /*%< Recognize numbers. */ +#define ISC_LEXOPT_QSTRING 0x10 /*%< Recognize qstrings. */ +/*@}*/ + +/*@{*/ +/*! + * The ISC_LEXOPT_DNSMULTILINE option handles the processing of '(' and ')' in + * the DNS master file format. If this option is set, then the + * ISC_LEXOPT_INITIALWS and ISC_LEXOPT_EOL options will be ignored when + * the paren count is > 0. To use this option, '(' and ')' must be special + * characters. + */ +#define ISC_LEXOPT_DNSMULTILINE 0x20 /*%< Handle '(' and ')'. */ +#define ISC_LEXOPT_NOMORE 0x40 /*%< Want "no more" token. */ + +#define ISC_LEXOPT_CNUMBER 0x80 /*%< Recognize octal and hex. */ +#define ISC_LEXOPT_ESCAPE 0x100 /*%< Recognize escapes. */ +#define ISC_LEXOPT_QSTRINGMULTILINE 0x200 /*%< Allow multiline "" strings */ +#define ISC_LEXOPT_OCTAL 0x400 /*%< Expect a octal number. */ +/*@}*/ +/*@{*/ +/*! + * Various commenting styles, which may be changed at any time with + * isc_lex_setcomments(). + */ + +#define ISC_LEXCOMMENT_C 0x01 +#define ISC_LEXCOMMENT_CPLUSPLUS 0x02 +#define ISC_LEXCOMMENT_SHELL 0x04 +#define ISC_LEXCOMMENT_DNSMASTERFILE 0x08 +/*@}*/ + +/*** + *** Types + ***/ + +/*! Lex */ + +typedef char isc_lexspecials_t[256]; + +/* Tokens */ + +typedef enum { + isc_tokentype_unknown = 0, + isc_tokentype_string = 1, + isc_tokentype_number = 2, + isc_tokentype_qstring = 3, + isc_tokentype_eol = 4, + isc_tokentype_eof = 5, + isc_tokentype_initialws = 6, + isc_tokentype_special = 7, + isc_tokentype_nomore = 8 +} isc_tokentype_t; + +typedef union { + char as_char; + unsigned long as_ulong; + isc_region_t as_region; + isc_textregion_t as_textregion; + void * as_pointer; +} isc_tokenvalue_t; + +typedef struct isc_token { + isc_tokentype_t type; + isc_tokenvalue_t value; +} isc_token_t; + +/*** + *** Functions + ***/ + +isc_result_t +isc_lex_create(isc_mem_t *mctx, size_t max_token, isc_lex_t **lexp); +/*%< + * Create a lexer. + * + * 'max_token' is a hint of the number of bytes in the largest token. + * + * Requires: + *\li '*lexp' is a valid lexer. + * + *\li max_token > 0. + * + * Ensures: + *\li On success, *lexp is attached to the newly created lexer. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + */ + +void +isc_lex_destroy(isc_lex_t **lexp); +/*%< + * Destroy the lexer. + * + * Requires: + *\li '*lexp' is a valid lexer. + * + * Ensures: + *\li *lexp == NULL + */ + +unsigned int +isc_lex_getcomments(isc_lex_t *lex); +/*%< + * Return the current lexer commenting styles. + * + * Requires: + *\li 'lex' is a valid lexer. + * + * Returns: + *\li The commenting sytles which are currently allowed. + */ + +void +isc_lex_setcomments(isc_lex_t *lex, unsigned int comments); +/*%< + * Set allowed lexer commenting styles. + * + * Requires: + *\li 'lex' is a valid lexer. + * + *\li 'comments' has meaningful values. + */ + +void +isc_lex_getspecials(isc_lex_t *lex, isc_lexspecials_t specials); +/*%< + * Put the current list of specials into 'specials'. + * + * Requires: + *\li 'lex' is a valid lexer. + */ + +void +isc_lex_setspecials(isc_lex_t *lex, isc_lexspecials_t specials); +/*!< + * The characters in 'specials' are returned as tokens. Along with + * whitespace, they delimit strings and numbers. + * + * Note: + *\li Comment processing takes precedence over special character + * recognition. + * + * Requires: + *\li 'lex' is a valid lexer. + */ + +isc_result_t +isc_lex_openfile(isc_lex_t *lex, const char *filename); +/*%< + * Open 'filename' and make it the current input source for 'lex'. + * + * Requires: + *\li 'lex' is a valid lexer. + * + *\li filename is a valid C string. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY Out of memory + *\li #ISC_R_NOTFOUND File not found + *\li #ISC_R_NOPERM No permission to open file + *\li #ISC_R_FAILURE Couldn't open file, not sure why + *\li #ISC_R_UNEXPECTED + */ + +isc_result_t +isc_lex_openstream(isc_lex_t *lex, FILE *stream); +/*%< + * Make 'stream' the current input source for 'lex'. + * + * Requires: + *\li 'lex' is a valid lexer. + * + *\li 'stream' is a valid C stream. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY Out of memory + */ + +isc_result_t +isc_lex_openbuffer(isc_lex_t *lex, isc_buffer_t *buffer); +/*%< + * Make 'buffer' the current input source for 'lex'. + * + * Requires: + *\li 'lex' is a valid lexer. + * + *\li 'buffer' is a valid buffer. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY Out of memory + */ + +isc_result_t +isc_lex_close(isc_lex_t *lex); +/*%< + * Close the most recently opened object (i.e. file or buffer). + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMORE No more input sources + */ + +isc_result_t +isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp); +/*%< + * Get the next token. + * + * Requires: + *\li 'lex' is a valid lexer. + * + *\li 'lex' has an input source. + * + *\li 'options' contains valid options. + * + *\li '*tokenp' is a valid pointer. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_UNEXPECTEDEND + *\li #ISC_R_NOMEMORY + * + * These two results are returned only if their corresponding lexer + * options are not set. + * + *\li #ISC_R_EOF End of input source + *\li #ISC_R_NOMORE No more input sources + */ + +isc_result_t +isc_lex_getmastertoken(isc_lex_t *lex, isc_token_t *token, + isc_tokentype_t expect, isc_boolean_t eol); +/*%< + * Get the next token from a DNS master file type stream. This is a + * convenience function that sets appropriate options and handles quoted + * strings and end of line correctly for master files. It also ungets + * unexpected tokens. + * + * Requires: + *\li 'lex' is a valid lexer. + * + *\li 'token' is a valid pointer + * + * Returns: + * + * \li any return code from isc_lex_gettoken(). + */ + +isc_result_t +isc_lex_getoctaltoken(isc_lex_t *lex, isc_token_t *token, isc_boolean_t eol); +/*%< + * Get the next token from a DNS master file type stream. This is a + * convenience function that sets appropriate options and handles end + * of line correctly for master files. It also ungets unexpected tokens. + * + * Requires: + *\li 'lex' is a valid lexer. + * + *\li 'token' is a valid pointer + * + * Returns: + * + * \li any return code from isc_lex_gettoken(). + */ + +void +isc_lex_ungettoken(isc_lex_t *lex, isc_token_t *tokenp); +/*%< + * Unget the current token. + * + * Requires: + *\li 'lex' is a valid lexer. + * + *\li 'lex' has an input source. + * + *\li 'tokenp' points to a valid token. + * + *\li There is no ungotten token already. + */ + +void +isc_lex_getlasttokentext(isc_lex_t *lex, isc_token_t *tokenp, isc_region_t *r); +/*%< + * Returns a region containing the text of the last token returned. + * + * Requires: + *\li 'lex' is a valid lexer. + * + *\li 'lex' has an input source. + * + *\li 'tokenp' points to a valid token. + * + *\li A token has been gotten and not ungotten. + */ + +char * +isc_lex_getsourcename(isc_lex_t *lex); +/*%< + * Return the input source name. + * + * Requires: + *\li 'lex' is a valid lexer. + * + * Returns: + * \li source name or NULL if no current source. + *\li result valid while current input source exists. + */ + + +unsigned long +isc_lex_getsourceline(isc_lex_t *lex); +/*%< + * Return the input source line number. + * + * Requires: + *\li 'lex' is a valid lexer. + * + * Returns: + *\li Current line number or 0 if no current source. + */ + +isc_result_t +isc_lex_setsourcename(isc_lex_t *lex, const char *name); +/*%< + * Assigns a new name to the input source. + * + * Requires: + * + * \li 'lex' is a valid lexer. + * + * Returns: + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOMEMORY + * \li #ISC_R_NOTFOUND - there are no sources. + */ + +isc_boolean_t +isc_lex_isfile(isc_lex_t *lex); +/*%< + * Return whether the current input source is a file. + * + * Requires: + *\li 'lex' is a valid lexer. + * + * Returns: + * \li #ISC_TRUE if the current input is a file, + *\li #ISC_FALSE otherwise. + */ + + +ISC_LANG_ENDDECLS + +#endif /* ISC_LEX_H */ diff --git a/contrib/ntp/lib/isc/include/isc/lfsr.h b/contrib/ntp/lib/isc/include/isc/lfsr.h new file mode 100644 index 0000000..d4d9707 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/lfsr.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: lfsr.h,v 1.17 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_LFSR_H +#define ISC_LFSR_H 1 + +/*! \file isc/lfsr.h */ + +#include <isc/lang.h> +#include <isc/types.h> + +typedef struct isc_lfsr isc_lfsr_t; + +/*% + * This function is called when reseeding is needed. It is allowed to + * modify any state in the LFSR in any way it sees fit OTHER THAN "bits". + * + * It MUST set "count" to a new value or the lfsr will never reseed again. + * + * Also, a reseed will never occur in the middle of an extraction. This + * is purely an optimization, and is probably what one would want. + */ +typedef void (*isc_lfsrreseed_t)(isc_lfsr_t *, void *); + +/*% + * The members of this structure can be used by the application, but care + * needs to be taken to not change state once the lfsr is in operation. + */ +struct isc_lfsr { + isc_uint32_t state; /*%< previous state */ + unsigned int bits; /*%< length */ + isc_uint32_t tap; /*%< bit taps */ + unsigned int count; /*%< reseed count (in BITS!) */ + isc_lfsrreseed_t reseed; /*%< reseed function */ + void *arg; /*%< reseed function argument */ +}; + +ISC_LANG_BEGINDECLS + + +void +isc_lfsr_init(isc_lfsr_t *lfsr, isc_uint32_t state, unsigned int bits, + isc_uint32_t tap, unsigned int count, + isc_lfsrreseed_t reseed, void *arg); +/*%< + * Initialize an LFSR. + * + * Note: + * + *\li Putting untrusted values into this function will cause the LFSR to + * generate (perhaps) non-maximal length sequences. + * + * Requires: + * + *\li lfsr != NULL + * + *\li 8 <= bits <= 32 + * + *\li tap != 0 + */ + +void +isc_lfsr_generate(isc_lfsr_t *lfsr, void *data, unsigned int count); +/*%< + * Returns "count" bytes of data from the LFSR. + * + * Requires: + * + *\li lfsr be valid. + * + *\li data != NULL. + * + *\li count > 0. + */ + +void +isc_lfsr_skip(isc_lfsr_t *lfsr, unsigned int skip); +/*%< + * Skip "skip" states. + * + * Requires: + * + *\li lfsr be valid. + */ + +isc_uint32_t +isc_lfsr_generate32(isc_lfsr_t *lfsr1, isc_lfsr_t *lfsr2); +/*%< + * Given two LFSRs, use the current state from each to skip entries in the + * other. The next states are then xor'd together and returned. + * + * WARNING: + * + *\li This function is used only for very, very low security data, such + * as DNS message IDs where it is desired to have an unpredictable + * stream of bytes that are harder to predict than a simple flooding + * attack. + * + * Notes: + * + *\li Since the current state from each of the LFSRs is used to skip + * state in the other, it is important that no state be leaked + * from either LFSR. + * + * Requires: + * + *\li lfsr1 and lfsr2 be valid. + * + *\li 1 <= skipbits <= 31 + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_LFSR_H */ diff --git a/contrib/ntp/lib/isc/include/isc/lib.h b/contrib/ntp/lib/isc/include/isc/lib.h new file mode 100644 index 0000000..f24fef8 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/lib.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: lib.h,v 1.16 2009/09/02 23:48:03 tbox Exp $ */ + +#ifndef ISC_LIB_H +#define ISC_LIB_H 1 + +/*! \file isc/lib.h */ + +#include <isc/types.h> +#include <isc/lang.h> + +ISC_LANG_BEGINDECLS + +LIBISC_EXTERNAL_DATA extern isc_msgcat_t *isc_msgcat; + +void +isc_lib_initmsgcat(void); +/*!< + * \brief Initialize the ISC library's message catalog, isc_msgcat, if it + * has not already been initialized. + */ + +void +isc_lib_register(void); +/*!< + * \brief Register the ISC library implementations for some base services + * such as memory or event management and handling socket or timer events. + * An external application that wants to use the ISC library must call this + * function very early in main(). + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_LIB_H */ diff --git a/contrib/ntp/lib/isc/include/isc/list.h b/contrib/ntp/lib/isc/include/isc/list.h new file mode 100644 index 0000000..c9bdfc7 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/list.h @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2004, 2006, 2007, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1997-2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +#ifndef ISC_LIST_H +#define ISC_LIST_H 1 +#include <isc/boolean.h> +#include <isc/assertions.h> + +#ifdef ISC_LIST_CHECKINIT +#define ISC_LINK_INSIST(x) ISC_INSIST(x) +#else +#define ISC_LINK_INSIST(x) +#endif + +#define ISC_LIST(type) struct { type *head, *tail; } +#define ISC_LIST_INIT(list) \ + do { (list).head = NULL; (list).tail = NULL; } while (0) + +#define ISC_LINK(type) struct { type *prev, *next; } +#define ISC_LINK_INIT_TYPE(elt, link, type) \ + do { \ + (elt)->link.prev = (type *)(-1); \ + (elt)->link.next = (type *)(-1); \ + } while (0) +#define ISC_LINK_INIT(elt, link) \ + ISC_LINK_INIT_TYPE(elt, link, void) +#define ISC_LINK_LINKED(elt, link) ((void *)((elt)->link.prev) != (void *)(-1)) + +#define ISC_LIST_HEAD(list) ((list).head) +#define ISC_LIST_TAIL(list) ((list).tail) +#define ISC_LIST_EMPTY(list) ISC_TF((list).head == NULL) + +#define __ISC_LIST_PREPENDUNSAFE(list, elt, link) \ + do { \ + if ((list).head != NULL) \ + (list).head->link.prev = (elt); \ + else \ + (list).tail = (elt); \ + (elt)->link.prev = NULL; \ + (elt)->link.next = (list).head; \ + (list).head = (elt); \ + } while (0) + +#define ISC_LIST_PREPEND(list, elt, link) \ + do { \ + ISC_LINK_INSIST(!ISC_LINK_LINKED(elt, link)); \ + __ISC_LIST_PREPENDUNSAFE(list, elt, link); \ + } while (0) + +#define ISC_LIST_INITANDPREPEND(list, elt, link) \ + __ISC_LIST_PREPENDUNSAFE(list, elt, link) + +#define __ISC_LIST_APPENDUNSAFE(list, elt, link) \ + do { \ + if ((list).tail != NULL) \ + (list).tail->link.next = (elt); \ + else \ + (list).head = (elt); \ + (elt)->link.prev = (list).tail; \ + (elt)->link.next = NULL; \ + (list).tail = (elt); \ + } while (0) + +#define ISC_LIST_APPEND(list, elt, link) \ + do { \ + ISC_LINK_INSIST(!ISC_LINK_LINKED(elt, link)); \ + __ISC_LIST_APPENDUNSAFE(list, elt, link); \ + } while (0) + +#define ISC_LIST_INITANDAPPEND(list, elt, link) \ + __ISC_LIST_APPENDUNSAFE(list, elt, link) + +#define __ISC_LIST_UNLINKUNSAFE_TYPE(list, elt, link, type) \ + do { \ + if ((elt)->link.next != NULL) \ + (elt)->link.next->link.prev = (elt)->link.prev; \ + else { \ + ISC_INSIST((list).tail == (elt)); \ + (list).tail = (elt)->link.prev; \ + } \ + if ((elt)->link.prev != NULL) \ + (elt)->link.prev->link.next = (elt)->link.next; \ + else { \ + ISC_INSIST((list).head == (elt)); \ + (list).head = (elt)->link.next; \ + } \ + (elt)->link.prev = (type *)(-1); \ + (elt)->link.next = (type *)(-1); \ + } while (0) + +#define __ISC_LIST_UNLINKUNSAFE(list, elt, link) \ + __ISC_LIST_UNLINKUNSAFE_TYPE(list, elt, link, void) + +#define ISC_LIST_UNLINK_TYPE(list, elt, link, type) \ + do { \ + ISC_LINK_INSIST(ISC_LINK_LINKED(elt, link)); \ + __ISC_LIST_UNLINKUNSAFE_TYPE(list, elt, link, type); \ + } while (0) +#define ISC_LIST_UNLINK(list, elt, link) \ + ISC_LIST_UNLINK_TYPE(list, elt, link, void) + +#define ISC_LIST_PREV(elt, link) ((elt)->link.prev) +#define ISC_LIST_NEXT(elt, link) ((elt)->link.next) + +#define __ISC_LIST_INSERTBEFOREUNSAFE(list, before, elt, link) \ + do { \ + if ((before)->link.prev == NULL) \ + ISC_LIST_PREPEND(list, elt, link); \ + else { \ + (elt)->link.prev = (before)->link.prev; \ + (before)->link.prev = (elt); \ + (elt)->link.prev->link.next = (elt); \ + (elt)->link.next = (before); \ + } \ + } while (0) + +#define ISC_LIST_INSERTBEFORE(list, before, elt, link) \ + do { \ + ISC_LINK_INSIST(ISC_LINK_LINKED(before, link)); \ + ISC_LINK_INSIST(!ISC_LINK_LINKED(elt, link)); \ + __ISC_LIST_INSERTBEFOREUNSAFE(list, before, elt, link); \ + } while (0) + +#define __ISC_LIST_INSERTAFTERUNSAFE(list, after, elt, link) \ + do { \ + if ((after)->link.next == NULL) \ + ISC_LIST_APPEND(list, elt, link); \ + else { \ + (elt)->link.next = (after)->link.next; \ + (after)->link.next = (elt); \ + (elt)->link.next->link.prev = (elt); \ + (elt)->link.prev = (after); \ + } \ + } while (0) + +#define ISC_LIST_INSERTAFTER(list, after, elt, link) \ + do { \ + ISC_LINK_INSIST(ISC_LINK_LINKED(after, link)); \ + ISC_LINK_INSIST(!ISC_LINK_LINKED(elt, link)); \ + __ISC_LIST_INSERTAFTERUNSAFE(list, after, elt, link); \ + } while (0) + +#define ISC_LIST_APPENDLIST(list1, list2, link) \ + do { \ + if (ISC_LIST_EMPTY(list1)) \ + (list1) = (list2); \ + else if (!ISC_LIST_EMPTY(list2)) { \ + (list1).tail->link.next = (list2).head; \ + (list2).head->link.prev = (list1).tail; \ + (list1).tail = (list2).tail; \ + } \ + (list2).head = NULL; \ + (list2).tail = NULL; \ + } while (0) + +#define ISC_LIST_PREPENDLIST(list1, list2, link) \ + do { \ + if (ISC_LIST_EMPTY(list1)) \ + (list1) = (list2); \ + else if (!ISC_LIST_EMPTY(list2)) { \ + (list2).tail->link.next = (list1).head; \ + (list1).head->link.prev = (list2).tail; \ + (list1).head = (list2).head; \ + } \ + (list2).head = NULL; \ + (list2).tail = NULL; \ + } while (0) + +#define ISC_LIST_ENQUEUE(list, elt, link) ISC_LIST_APPEND(list, elt, link) +#define __ISC_LIST_ENQUEUEUNSAFE(list, elt, link) \ + __ISC_LIST_APPENDUNSAFE(list, elt, link) +#define ISC_LIST_DEQUEUE(list, elt, link) \ + ISC_LIST_UNLINK_TYPE(list, elt, link, void) +#define ISC_LIST_DEQUEUE_TYPE(list, elt, link, type) \ + ISC_LIST_UNLINK_TYPE(list, elt, link, type) +#define __ISC_LIST_DEQUEUEUNSAFE(list, elt, link) \ + __ISC_LIST_UNLINKUNSAFE_TYPE(list, elt, link, void) +#define __ISC_LIST_DEQUEUEUNSAFE_TYPE(list, elt, link, type) \ + __ISC_LIST_UNLINKUNSAFE_TYPE(list, elt, link, type) + +#endif /* ISC_LIST_H */ diff --git a/contrib/ntp/lib/isc/include/isc/log.h b/contrib/ntp/lib/isc/include/isc/log.h new file mode 100644 index 0000000..741c532 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/log.h @@ -0,0 +1,914 @@ +/* + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: log.h,v 1.59 2009/02/16 02:01:16 marka Exp $ */ + +#ifndef ISC_LOG_H +#define ISC_LOG_H 1 + +/*! \file isc/log.h */ + +#include <stdio.h> +#include <stdarg.h> +#include <syslog.h> /* XXXDCL NT */ + +#include <isc/formatcheck.h> +#include <isc/lang.h> +#include <isc/platform.h> +#include <isc/types.h> + +/*@{*/ +/*! + * \brief Severity levels, patterned after Unix's syslog levels. + * + */ +#define ISC_LOG_DEBUG(level) (level) +/*! + * #ISC_LOG_DYNAMIC can only be used for defining channels with + * isc_log_createchannel(), not to specify a level in isc_log_write(). + */ +#define ISC_LOG_DYNAMIC 0 +#define ISC_LOG_INFO (-1) +#define ISC_LOG_NOTICE (-2) +#define ISC_LOG_WARNING (-3) +#define ISC_LOG_ERROR (-4) +#define ISC_LOG_CRITICAL (-5) +/*@}*/ + +/*@{*/ +/*! + * \brief Destinations. + */ +#define ISC_LOG_TONULL 1 +#define ISC_LOG_TOSYSLOG 2 +#define ISC_LOG_TOFILE 3 +#define ISC_LOG_TOFILEDESC 4 +/*@}*/ + +/*@{*/ +/*% + * Channel flags. + */ +#define ISC_LOG_PRINTTIME 0x0001 +#define ISC_LOG_PRINTLEVEL 0x0002 +#define ISC_LOG_PRINTCATEGORY 0x0004 +#define ISC_LOG_PRINTMODULE 0x0008 +#define ISC_LOG_PRINTTAG 0x0010 +#define ISC_LOG_PRINTALL 0x001F +#define ISC_LOG_DEBUGONLY 0x1000 +#define ISC_LOG_OPENERR 0x8000 /* internal */ +/*@}*/ + +/*@{*/ +/*! + * \brief Other options. + * + * XXXDCL INFINITE doesn't yet work. Arguably it isn't needed, but + * since I am intend to make large number of versions work efficiently, + * INFINITE is going to be trivial to add to that. + */ +#define ISC_LOG_ROLLINFINITE (-1) +#define ISC_LOG_ROLLNEVER (-2) +/*@}*/ + +/*! + * \brief Used to name the categories used by a library. + * + * An array of isc_logcategory + * structures names each category, and the id value is initialized by calling + * isc_log_registercategories. + */ +struct isc_logcategory { + const char *name; + unsigned int id; +}; + +/*% + * Similar to isc_logcategory, but for all the modules a library defines. + */ +struct isc_logmodule { + const char *name; + unsigned int id; +}; + +/*% + * The isc_logfile structure is initialized as part of an isc_logdestination + * before calling isc_log_createchannel(). + * + * When defining an #ISC_LOG_TOFILE + * channel the name, versions and maximum_size should be set before calling + * isc_log_createchannel(). To define an #ISC_LOG_TOFILEDESC channel set only + * the stream before the call. + * + * Setting maximum_size to zero implies no maximum. + */ +typedef struct isc_logfile { + FILE *stream; /*%< Initialized to NULL for #ISC_LOG_TOFILE. */ + const char *name; /*%< NULL for #ISC_LOG_TOFILEDESC. */ + int versions; /* >= 0, #ISC_LOG_ROLLNEVER, #ISC_LOG_ROLLINFINITE. */ + /*% + * stdio's ftell is standardized to return a long, which may well not + * be big enough for the largest file supportable by the operating + * system (though it is _probably_ big enough for the largest log + * anyone would want). st_size returned by fstat should be typedef'd + * to a size large enough for the largest possible file on a system. + */ + isc_offset_t maximum_size; + isc_boolean_t maximum_reached; /*%< Private. */ +} isc_logfile_t; + +/*% + * Passed to isc_log_createchannel to define the attributes of either + * a stdio or a syslog log. + */ +typedef union isc_logdestination { + isc_logfile_t file; + int facility; /* XXXDCL NT */ +} isc_logdestination_t; + +/*@{*/ +/*% + * The built-in categories of libisc. + * + * Each library registering categories should provide library_LOGCATEGORY_name + * definitions with indexes into its isc_logcategory structure corresponding to + * the order of the names. + */ +LIBISC_EXTERNAL_DATA extern isc_logcategory_t isc_categories[]; +LIBISC_EXTERNAL_DATA extern isc_log_t *isc_lctx; +LIBISC_EXTERNAL_DATA extern isc_logmodule_t isc_modules[]; +/*@}*/ + +/*@{*/ +/*% + * Do not log directly to DEFAULT. Use another category. When in doubt, + * use GENERAL. + */ +#define ISC_LOGCATEGORY_DEFAULT (&isc_categories[0]) +#define ISC_LOGCATEGORY_GENERAL (&isc_categories[1]) +/*@}*/ + +#define ISC_LOGMODULE_SOCKET (&isc_modules[0]) +#define ISC_LOGMODULE_TIME (&isc_modules[1]) +#define ISC_LOGMODULE_INTERFACE (&isc_modules[2]) +#define ISC_LOGMODULE_TIMER (&isc_modules[3]) +#define ISC_LOGMODULE_FILE (&isc_modules[4]) + +ISC_LANG_BEGINDECLS + +isc_result_t +isc_log_create(isc_mem_t *mctx, isc_log_t **lctxp, isc_logconfig_t **lcfgp); +/*%< + * Establish a new logging context, with default channels. + * + * Notes: + *\li isc_log_create() calls isc_logconfig_create(), so see its comment + * below for more information. + * + * Requires: + *\li mctx is a valid memory context. + *\li lctxp is not null and *lctxp is null. + *\li lcfgp is null or lcfgp is not null and *lcfgp is null. + * + * Ensures: + *\li *lctxp will point to a valid logging context if all of the necessary + * memory was allocated, or NULL otherwise. + *\li *lcfgp will point to a valid logging configuration if all of the + * necessary memory was allocated, or NULL otherwise. + *\li On failure, no additional memory is allocated. + * + * Returns: + *\li #ISC_R_SUCCESS Success + *\li #ISC_R_NOMEMORY Resource limit: Out of memory + */ + +isc_result_t +isc_logconfig_create(isc_log_t *lctx, isc_logconfig_t **lcfgp); +/*%< + * Create the data structure that holds all of the configurable information + * about where messages are actually supposed to be sent -- the information + * that could changed based on some configuration file, as opposed to the + * the category/module specification of isc_log_[v]write[1] that is compiled + * into a program, or the debug_level which is dynamic state information. + * + * Notes: + *\li It is necessary to specify the logging context the configuration + * will be used with because the number of categories and modules + * needs to be known in order to set the configuration. However, + * the configuration is not used by the logging context until the + * isc_logconfig_use function is called. + * + *\li The memory context used for operations that allocate memory for + * the configuration is that of the logging context, as specified + * in the isc_log_create call. + * + *\li Four default channels are established: + *\verbatim + * default_syslog + * - log to syslog's daemon facility #ISC_LOG_INFO or higher + * default_stderr + * - log to stderr #ISC_LOG_INFO or higher + * default_debug + * - log to stderr #ISC_LOG_DEBUG dynamically + * null + * - log nothing + *\endverbatim + * + * Requires: + *\li lctx is a valid logging context. + *\li lcftp is not null and *lcfgp is null. + * + * Ensures: + *\li *lcfgp will point to a valid logging context if all of the necessary + * memory was allocated, or NULL otherwise. + *\li On failure, no additional memory is allocated. + * + * Returns: + *\li #ISC_R_SUCCESS Success + *\li #ISC_R_NOMEMORY Resource limit: Out of memory + */ + +isc_logconfig_t * +isc_logconfig_get(isc_log_t *lctx); +/*%< + * Returns a pointer to the configuration currently in use by the log context. + * + * Requires: + *\li lctx is a valid context. + * + * Ensures: + *\li The configuration pointer is non-null. + * + * Returns: + *\li The configuration pointer. + */ + +isc_result_t +isc_logconfig_use(isc_log_t *lctx, isc_logconfig_t *lcfg); +/*%< + * Associate a new configuration with a logging context. + * + * Notes: + *\li This is thread safe. The logging context will lock a mutex + * before attempting to swap in the new configuration, and isc_log_doit + * (the internal function used by all of isc_log_[v]write[1]) locks + * the same lock for the duration of its use of the configuration. + * + * Requires: + *\li lctx is a valid logging context. + *\li lcfg is a valid logging configuration. + *\li lctx is the same configuration given to isc_logconfig_create + * when the configuration was created. + * + * Ensures: + *\li Future calls to isc_log_write will use the new configuration. + * + * Returns: + *\li #ISC_R_SUCCESS Success + *\li #ISC_R_NOMEMORY Resource limit: Out of memory + */ + +void +isc_log_destroy(isc_log_t **lctxp); +/*%< + * Deallocate the memory associated with a logging context. + * + * Requires: + *\li *lctx is a valid logging context. + * + * Ensures: + *\li All of the memory associated with the logging context is returned + * to the free memory pool. + * + *\li Any open files are closed. + * + *\li The logging context is marked as invalid. + */ + +void +isc_logconfig_destroy(isc_logconfig_t **lcfgp); +/*%< + * Destroy a logging configuration. + * + * Notes: + *\li This function cannot be used directly with the return value of + * isc_logconfig_get, because a logging context must always have + * a valid configuration associated with it. + * + * Requires: + *\li lcfgp is not null and *lcfgp is a valid logging configuration. + *\li The logging configuration is not in use by an existing logging context. + * + * Ensures: + *\li All memory allocated for the configuration is freed. + * + *\li The configuration is marked as invalid. + */ + +void +isc_log_registercategories(isc_log_t *lctx, isc_logcategory_t categories[]); +/*%< + * Identify logging categories a library will use. + * + * Notes: + *\li A category should only be registered once, but no mechanism enforces + * this rule. + * + *\li The end of the categories array is identified by a NULL name. + * + *\li Because the name is used by #ISC_LOG_PRINTCATEGORY, it should not + * be altered or destroyed after isc_log_registercategories(). + * + *\li Because each element of the categories array is used by + * isc_log_categorybyname, it should not be altered or destroyed + * after registration. + * + *\li The value of the id integer in each structure is overwritten + * by this function, and so id need not be initialized to any particular + * value prior to the function call. + * + *\li A subsequent call to isc_log_registercategories with the same + * logging context (but new categories) will cause the last + * element of the categories array from the prior call to have + * its "name" member changed from NULL to point to the new + * categories array, and its "id" member set to UINT_MAX. + * + * Requires: + *\li lctx is a valid logging context. + *\li categories != NULL. + *\li categories[0].name != NULL. + * + * Ensures: + * \li There are references to each category in the logging context, + * so they can be used with isc_log_usechannel() and isc_log_write(). + */ + +void +isc_log_registermodules(isc_log_t *lctx, isc_logmodule_t modules[]); +/*%< + * Identify logging categories a library will use. + * + * Notes: + *\li A module should only be registered once, but no mechanism enforces + * this rule. + * + *\li The end of the modules array is identified by a NULL name. + * + *\li Because the name is used by #ISC_LOG_PRINTMODULE, it should not + * be altered or destroyed after isc_log_registermodules(). + * + *\li Because each element of the modules array is used by + * isc_log_modulebyname, it should not be altered or destroyed + * after registration. + * + *\li The value of the id integer in each structure is overwritten + * by this function, and so id need not be initialized to any particular + * value prior to the function call. + * + *\li A subsequent call to isc_log_registermodules with the same + * logging context (but new modules) will cause the last + * element of the modules array from the prior call to have + * its "name" member changed from NULL to point to the new + * modules array, and its "id" member set to UINT_MAX. + * + * Requires: + *\li lctx is a valid logging context. + *\li modules != NULL. + *\li modules[0].name != NULL; + * + * Ensures: + *\li Each module has a reference in the logging context, so they can be + * used with isc_log_usechannel() and isc_log_write(). + */ + +isc_result_t +isc_log_createchannel(isc_logconfig_t *lcfg, const char *name, + unsigned int type, int level, + const isc_logdestination_t *destination, + unsigned int flags); +/*%< + * Specify the parameters of a logging channel. + * + * Notes: + *\li The name argument is copied to memory in the logging context, so + * it can be altered or destroyed after isc_log_createchannel(). + * + *\li Defining a very large number of channels will have a performance + * impact on isc_log_usechannel(), since the names are searched + * linearly until a match is made. This same issue does not affect + * isc_log_write, however. + * + *\li Channel names can be redefined; this is primarily useful for programs + * that want their own definition of default_syslog, default_debug + * and default_stderr. + * + *\li Any channel that is redefined will not affect logging that was + * already directed to its original definition, _except_ for the + * default_stderr channel. This case is handled specially so that + * the default logging category can be changed by redefining + * default_stderr. (XXXDCL Though now that I think of it, the default + * logging category can be changed with only one additional function + * call by defining a new channel and then calling isc_log_usechannel() + * for #ISC_LOGCATEGORY_DEFAULT.) + * + *\li Specifying #ISC_LOG_PRINTTIME or #ISC_LOG_PRINTTAG for syslog is allowed, + * but probably not what you wanted to do. + * + * #ISC_LOG_DEBUGONLY will mark the channel as usable only when the + * debug level of the logging context (see isc_log_setdebuglevel) + * is non-zero. + * + * Requires: + *\li lcfg is a valid logging configuration. + * + *\li name is not NULL. + * + *\li type is #ISC_LOG_TOSYSLOG, #ISC_LOG_TOFILE, #ISC_LOG_TOFILEDESC or + * #ISC_LOG_TONULL. + * + *\li destination is not NULL unless type is #ISC_LOG_TONULL. + * + *\li level is >= #ISC_LOG_CRITICAL (the most negative logging level). + * + *\li flags does not include any bits aside from the ISC_LOG_PRINT* bits + * or #ISC_LOG_DEBUGONLY. + * + * Ensures: + *\li #ISC_R_SUCCESS + * A channel with the given name is usable with + * isc_log_usechannel(). + * + *\li #ISC_R_NOMEMORY or #ISC_R_UNEXPECTED + * No additional memory is being used by the logging context. + * Any channel that previously existed with the given name + * is not redefined. + * + * Returns: + *\li #ISC_R_SUCCESS Success + *\li #ISC_R_NOMEMORY Resource limit: Out of memory + *\li #ISC_R_UNEXPECTED type was out of range and REQUIRE() + * was disabled. + */ + +isc_result_t +isc_log_usechannel(isc_logconfig_t *lcfg, const char *name, + const isc_logcategory_t *category, + const isc_logmodule_t *module); +/*%< + * Associate a named logging channel with a category and module that + * will use it. + * + * Notes: + *\li The name is searched for linearly in the set of known channel names + * until a match is found. (Note the performance impact of a very large + * number of named channels.) When multiple channels of the same + * name are defined, the most recent definition is found. + * + *\li Specifying a very large number of channels for a category will have + * a moderate impact on performance in isc_log_write(), as each + * call looks up the category for the start of a linked list, which + * it follows all the way to the end to find matching modules. The + * test for matching modules is integral, though. + * + *\li If category is NULL, then the channel is associated with the indicated + * module for all known categories (including the "default" category). + * + *\li If module is NULL, then the channel is associated with every module + * that uses that category. + * + *\li Passing both category and module as NULL would make every log message + * use the indicated channel. + * + * \li Specifying a channel that is #ISC_LOG_TONULL for a category/module pair + * has no effect on any other channels associated with that pair, + * regardless of ordering. Thus you cannot use it to "mask out" one + * category/module pair when you have specified some other channel that + * is also used by that category/module pair. + * + * Requires: + *\li lcfg is a valid logging configuration. + * + *\li category is NULL or has an id that is in the range of known ids. + * + * module is NULL or has an id that is in the range of known ids. + * + * Ensures: + *\li #ISC_R_SUCCESS + * The channel will be used by the indicated category/module + * arguments. + * + *\li #ISC_R_NOMEMORY + * If assignment for a specific category has been requested, + * the channel has not been associated with the indicated + * category/module arguments and no additional memory is + * used by the logging context. + * If assignment for all categories has been requested + * then _some_ may have succeeded (starting with category + * "default" and progressing through the order of categories + * passed to isc_log_registercategories()) and additional memory + * is being used by whatever assignments succeeded. + * + * Returns: + *\li #ISC_R_SUCCESS Success + *\li #ISC_R_NOMEMORY Resource limit: Out of memory + */ + +/* Attention: next four comments PRECEED code */ +/*! + * \brief + * Write a message to the log channels. + * + * Notes: + *\li Log messages containing natural language text should be logged with + * isc_log_iwrite() to allow for localization. + * + *\li lctx can be NULL; this is allowed so that programs which use + * libraries that use the ISC logging system are not required to + * also use it. + * + *\li The format argument is a printf(3) string, with additional arguments + * as necessary. + * + * Requires: + *\li lctx is a valid logging context. + * + *\li The category and module arguments must have ids that are in the + * range of known ids, as established by isc_log_registercategories() + * and isc_log_registermodules(). + * + *\li level != #ISC_LOG_DYNAMIC. ISC_LOG_DYNAMIC is used only to define + * channels, and explicit debugging level must be identified for + * isc_log_write() via ISC_LOG_DEBUG(level). + * + *\li format != NULL. + * + * Ensures: + *\li The log message is written to every channel associated with the + * indicated category/module pair. + * + * Returns: + *\li Nothing. Failure to log a message is not construed as a + * meaningful error. + */ +void +isc_log_write(isc_log_t *lctx, isc_logcategory_t *category, + isc_logmodule_t *module, int level, + const char *format, ...) + +ISC_FORMAT_PRINTF(5, 6); + +/*% + * Write a message to the log channels. + * + * Notes: + *\li lctx can be NULL; this is allowed so that programs which use + * libraries that use the ISC logging system are not required to + * also use it. + * + *\li The format argument is a printf(3) string, with additional arguments + * as necessary. + * + * Requires: + *\li lctx is a valid logging context. + * + *\li The category and module arguments must have ids that are in the + * range of known ids, as established by isc_log_registercategories() + * and isc_log_registermodules(). + * + *\li level != #ISC_LOG_DYNAMIC. ISC_LOG_DYNAMIC is used only to define + * channels, and explicit debugging level must be identified for + * isc_log_write() via ISC_LOG_DEBUG(level). + * + *\li format != NULL. + * + * Ensures: + *\li The log message is written to every channel associated with the + * indicated category/module pair. + * + * Returns: + *\li Nothing. Failure to log a message is not construed as a + * meaningful error. + */ +void +isc_log_vwrite(isc_log_t *lctx, isc_logcategory_t *category, + isc_logmodule_t *module, int level, + const char *format, va_list args) + +ISC_FORMAT_PRINTF(5, 0); + +/*% + * Write a message to the log channels, pruning duplicates that occur within + * a configurable amount of seconds (see isc_log_[sg]etduplicateinterval). + * This function is otherwise identical to isc_log_write(). + */ +void +isc_log_write1(isc_log_t *lctx, isc_logcategory_t *category, + isc_logmodule_t *module, int level, const char *format, ...) + +ISC_FORMAT_PRINTF(5, 6); + +/*% + * Write a message to the log channels, pruning duplicates that occur within + * a configurable amount of seconds (see isc_log_[sg]etduplicateinterval). + * This function is otherwise identical to isc_log_vwrite(). + */ +void +isc_log_vwrite1(isc_log_t *lctx, isc_logcategory_t *category, + isc_logmodule_t *module, int level, const char *format, + va_list args) + +ISC_FORMAT_PRINTF(5, 0); + +/*% + * These are four internationalized versions of the isc_log_[v]write[1] + * functions. + * + * The only difference is that they take arguments for a message + * catalog, message set, and message number, all immediately preceding the + * format argument. The format argument becomes the default text, a la + * isc_msgcat_get. If the message catalog is NULL, no lookup is attempted + * for a message -- which makes the message set and message number irrelevant, + * and the non-internationalized call should have probably been used instead. + * + * Yes, that means there are now *eight* interfaces to logging a message. + * Sheesh. Make the madness stop! + */ +/*@{*/ +void +isc_log_iwrite(isc_log_t *lctx, isc_logcategory_t *category, + isc_logmodule_t *module, int level, + isc_msgcat_t *msgcat, int msgset, int message, + const char *format, ...) +ISC_FORMAT_PRINTF(8, 9); + +void +isc_log_ivwrite(isc_log_t *lctx, isc_logcategory_t *category, + isc_logmodule_t *module, int level, + isc_msgcat_t *msgcat, int msgset, int message, + const char *format, va_list args) +ISC_FORMAT_PRINTF(8, 0); + +void +isc_log_iwrite1(isc_log_t *lctx, isc_logcategory_t *category, + isc_logmodule_t *module, int level, + isc_msgcat_t *msgcat, int msgset, int message, + const char *format, ...) +ISC_FORMAT_PRINTF(8, 9); + +void +isc_log_ivwrite1(isc_log_t *lctx, isc_logcategory_t *category, + isc_logmodule_t *module, int level, + isc_msgcat_t *msgcat, int msgset, int message, + const char *format, va_list args) +ISC_FORMAT_PRINTF(8, 0); +/*@}*/ + +void +isc_log_setdebuglevel(isc_log_t *lctx, unsigned int level); +/*%< + * Set the debugging level used for logging. + * + * Notes: + *\li Setting the debugging level to 0 disables debugging log messages. + * + * Requires: + *\li lctx is a valid logging context. + * + * Ensures: + *\li The debugging level is set to the requested value. + */ + +unsigned int +isc_log_getdebuglevel(isc_log_t *lctx); +/*%< + * Get the current debugging level. + * + * Notes: + *\li This is provided so that a program can have a notion of + * "increment debugging level" or "decrement debugging level" + * without needing to keep track of what the current level is. + * + *\li A return value of 0 indicates that debugging messages are disabled. + * + * Requires: + *\li lctx is a valid logging context. + * + * Ensures: + *\li The current logging debugging level is returned. + */ + +isc_boolean_t +isc_log_wouldlog(isc_log_t *lctx, int level); +/*%< + * Determine whether logging something to 'lctx' at 'level' would + * actually cause something to be logged somewhere. + * + * If #ISC_FALSE is returned, it is guaranteed that nothing would + * be logged, allowing the caller to omit unnecessary + * isc_log_write() calls and possible message preformatting. + */ + +void +isc_log_setduplicateinterval(isc_logconfig_t *lcfg, unsigned int interval); +/*%< + * Set the interval over which duplicate log messages will be ignored + * by isc_log_[v]write1(), in seconds. + * + * Notes: + *\li Increasing the duplicate interval from X to Y will not necessarily + * filter out duplicates of messages logged in Y - X seconds since the + * increase. (Example: Message1 is logged at midnight. Message2 + * is logged at 00:01:00, when the interval is only 30 seconds, causing + * Message1 to be expired from the log message history. Then the interval + * is increased to 3000 (five minutes) and at 00:04:00 Message1 is logged + * again. It will appear the second time even though less than five + * passed since the first occurrence. + * + * Requires: + *\li lctx is a valid logging context. + */ + +unsigned int +isc_log_getduplicateinterval(isc_logconfig_t *lcfg); +/*%< + * Get the current duplicate filtering interval. + * + * Requires: + *\li lctx is a valid logging context. + * + * Returns: + *\li The current duplicate filtering interval. + */ + +isc_result_t +isc_log_settag(isc_logconfig_t *lcfg, const char *tag); +/*%< + * Set the program name or other identifier for #ISC_LOG_PRINTTAG. + * + * Requires: + *\li lcfg is a valid logging configuration. + * + * Notes: + *\li If this function has not set the tag to a non-NULL, non-empty value, + * then the #ISC_LOG_PRINTTAG channel flag will not print anything. + * Unlike some implementations of syslog on Unix systems, you *must* set + * the tag in order to get it logged. It is not implicitly derived from + * the program name (which is pretty impossible to infer portably). + * + *\li Setting the tag to NULL or the empty string will also cause the + * #ISC_LOG_PRINTTAG channel flag to not print anything. If tag equals the + * empty string, calls to isc_log_gettag will return NULL. + * + * Returns: + *\li #ISC_R_SUCCESS Success + *\li #ISC_R_NOMEMORY Resource Limit: Out of memory + * + * XXXDCL when creating a new isc_logconfig_t, it might be nice if the tag + * of the currently active isc_logconfig_t was inherited. this does not + * currently happen. + */ + +char * +isc_log_gettag(isc_logconfig_t *lcfg); +/*%< + * Get the current identifier printed with #ISC_LOG_PRINTTAG. + * + * Requires: + *\li lcfg is a valid logging configuration. + * + * Notes: + *\li Since isc_log_settag() will not associate a zero-length string + * with the logging configuration, attempts to do so will cause + * this function to return NULL. However, a determined programmer + * will observe that (currently) a tag of length greater than zero + * could be set, and then modified to be zero length. + * + * Returns: + *\li A pointer to the current identifier, or NULL if none has been set. + */ + +void +isc_log_opensyslog(const char *tag, int options, int facility); +/*%< + * Initialize syslog logging. + * + * Notes: + *\li XXXDCL NT + * This is currently equivalent to openlog(), but is not going to remain + * that way. In the meantime, the arguments are all identical to + * those used by openlog(3), as follows: + * + * \code + * tag: The string to use in the position of the program + * name in syslog messages. Most (all?) syslogs + * will use basename(argv[0]) if tag is NULL. + * + * options: LOG_CONS, LOG_PID, LOG_NDELAY ... whatever your + * syslog supports. + * + * facility: The default syslog facility. This is irrelevant + * since isc_log_write will ALWAYS use the channel's + * declared facility. + * \endcode + * + *\li Zero effort has been made (yet) to accommodate systems with openlog() + * that only takes two arguments, or to identify valid syslog + * facilities or options for any given architecture. + * + *\li It is necessary to call isc_log_opensyslog() to initialize + * syslogging on machines which do not support network connections to + * syslogd because they require a Unix domain socket to be used. Since + * this is a chore to determine at run-time, it is suggested that it + * always be called by programs using the ISC logging system. + * + * Requires: + *\li Nothing. + * + * Ensures: + *\li openlog() is called to initialize the syslog system. + */ + +void +isc_log_closefilelogs(isc_log_t *lctx); +/*%< + * Close all open files used by #ISC_LOG_TOFILE channels. + * + * Notes: + *\li This function is provided for programs that want to use their own + * log rolling mechanism rather than the one provided internally. + * For example, a program that wanted to keep daily logs would define + * a channel which used #ISC_LOG_ROLLNEVER, then once a day would + * rename the log file and call isc_log_closefilelogs(). + * + *\li #ISC_LOG_TOFILEDESC channels are unaffected. + * + * Requires: + *\li lctx is a valid context. + * + * Ensures: + *\li The open files are closed and will be reopened when they are + * next needed. + */ + +isc_logcategory_t * +isc_log_categorybyname(isc_log_t *lctx, const char *name); +/*%< + * Find a category by its name. + * + * Notes: + *\li The string name of a category is not required to be unique. + * + * Requires: + *\li lctx is a valid context. + *\li name is not NULL. + * + * Returns: + *\li A pointer to the _first_ isc_logcategory_t structure used by "name". + * + *\li NULL if no category exists by that name. + */ + +isc_logmodule_t * +isc_log_modulebyname(isc_log_t *lctx, const char *name); +/*%< + * Find a module by its name. + * + * Notes: + *\li The string name of a module is not required to be unique. + * + * Requires: + *\li lctx is a valid context. + *\li name is not NULL. + * + * Returns: + *\li A pointer to the _first_ isc_logmodule_t structure used by "name". + * + *\li NULL if no module exists by that name. + */ + +void +isc_log_setcontext(isc_log_t *lctx); +/*%< + * Sets the context used by the libisc for logging. + * + * Requires: + *\li lctx be a valid context. + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_LOG_H */ diff --git a/contrib/ntp/lib/isc/include/isc/magic.h b/contrib/ntp/lib/isc/include/isc/magic.h new file mode 100644 index 0000000..073de90 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/magic.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: magic.h,v 1.18 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_MAGIC_H +#define ISC_MAGIC_H 1 + +/*! \file isc/magic.h */ + +typedef struct { + unsigned int magic; +} isc__magic_t; + + +/*% + * To use this macro the magic number MUST be the first thing in the + * structure, and MUST be of type "unsigned int". + * The intent of this is to allow magic numbers to be checked even though + * the object is otherwise opaque. + */ +#define ISC_MAGIC_VALID(a,b) (((a) != NULL) && \ + (((const isc__magic_t *)(a))->magic == (b))) + +#define ISC_MAGIC(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d)) + +#endif /* ISC_MAGIC_H */ diff --git a/contrib/ntp/lib/isc/include/isc/md5.h b/contrib/ntp/lib/isc/include/isc/md5.h new file mode 100644 index 0000000..dfa586d --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/md5.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2004-2007, 2009, 2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: md5.h,v 1.20 2010/01/07 23:48:54 tbox Exp $ */ + +/*! \file isc/md5.h + * \brief This is the header file for the MD5 message-digest algorithm. + * + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' + * header definitions; now uses stuff from dpkg's config.h + * - Ian Jackson <ijackson@nyx.cs.du.edu>. + * Still in the public domain. + */ + +#ifndef ISC_MD5_H +#define ISC_MD5_H 1 + +#include <isc/lang.h> +#include <isc/platform.h> +#include <isc/types.h> + +#define ISC_MD5_DIGESTLENGTH 16U +#define ISC_MD5_BLOCK_LENGTH 64U + +#ifdef ISC_PLATFORM_OPENSSLHASH +#include <openssl/evp.h> + +typedef EVP_MD_CTX isc_md5_t; + +#else + +typedef struct { + isc_uint32_t buf[4]; + isc_uint32_t bytes[2]; + isc_uint32_t in[16]; +} isc_md5_t; +#endif + +ISC_LANG_BEGINDECLS + +void +isc_md5_init(isc_md5_t *ctx); + +void +isc_md5_invalidate(isc_md5_t *ctx); + +void +isc_md5_update(isc_md5_t *ctx, const unsigned char *buf, unsigned int len); + +void +isc_md5_final(isc_md5_t *ctx, unsigned char *digest); + +ISC_LANG_ENDDECLS + +#endif /* ISC_MD5_H */ diff --git a/contrib/ntp/lib/isc/include/isc/mem.h b/contrib/ntp/lib/isc/include/isc/mem.h new file mode 100644 index 0000000..5101ea3 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/mem.h @@ -0,0 +1,750 @@ +/* + * Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1997-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +#ifndef ISC_MEM_H +#define ISC_MEM_H 1 + +/*! \file isc/mem.h */ + +#include <stdio.h> + +#include <isc/lang.h> +#include <isc/mutex.h> +#include <isc/platform.h> +#include <isc/types.h> +#include <isc/xml.h> + +ISC_LANG_BEGINDECLS + +#define ISC_MEM_LOWATER 0 +#define ISC_MEM_HIWATER 1 +typedef void (*isc_mem_water_t)(void *, int); + +typedef void * (*isc_memalloc_t)(void *, size_t); +typedef void (*isc_memfree_t)(void *, void *); + +/*% + * Define ISC_MEM_DEBUG=1 to make all functions that free memory + * set the pointer being freed to NULL after being freed. + * This is the default; set ISC_MEM_DEBUG=0 to disable it. + */ +#ifndef ISC_MEM_DEBUG +#define ISC_MEM_DEBUG 1 +#endif + +/*% + * Define ISC_MEM_TRACKLINES=1 to turn on detailed tracing of memory + * allocation and freeing by file and line number. + */ +#ifndef ISC_MEM_TRACKLINES +#define ISC_MEM_TRACKLINES 1 +#endif + +/*% + * Define ISC_MEM_CHECKOVERRUN=1 to turn on checks for using memory outside + * the requested space. This will increase the size of each allocation. + */ +#ifndef ISC_MEM_CHECKOVERRUN +#define ISC_MEM_CHECKOVERRUN 1 +#endif + +/*% + * Define ISC_MEM_FILL=1 to fill each block of memory returned to the system + * with the byte string '0xbe'. This helps track down uninitialized pointers + * and the like. On freeing memory, the space is filled with '0xde' for + * the same reasons. + */ +#ifndef ISC_MEM_FILL +#define ISC_MEM_FILL 1 +#endif + +/*% + * Define ISC_MEMPOOL_NAMES=1 to make memory pools store a symbolic + * name so that the leaking pool can be more readily identified in + * case of a memory leak. + */ +#ifndef ISC_MEMPOOL_NAMES +#define ISC_MEMPOOL_NAMES 1 +#endif + +LIBISC_EXTERNAL_DATA extern unsigned int isc_mem_debugging; +/*@{*/ +#define ISC_MEM_DEBUGTRACE 0x00000001U +#define ISC_MEM_DEBUGRECORD 0x00000002U +#define ISC_MEM_DEBUGUSAGE 0x00000004U +#define ISC_MEM_DEBUGSIZE 0x00000008U +#define ISC_MEM_DEBUGCTX 0x00000010U +#define ISC_MEM_DEBUGALL 0x0000001FU +/*!< + * The variable isc_mem_debugging holds a set of flags for + * turning certain memory debugging options on or off at + * runtime. It is initialized to the value ISC_MEM_DEGBUGGING, + * which is 0 by default but may be overridden at compile time. + * The following flags can be specified: + * + * \li #ISC_MEM_DEBUGTRACE + * Log each allocation and free to isc_lctx. + * + * \li #ISC_MEM_DEBUGRECORD + * Remember each allocation, and match them up on free. + * Crash if a free doesn't match an allocation. + * + * \li #ISC_MEM_DEBUGUSAGE + * If a hi_water mark is set, print the maximum inuse memory + * every time it is raised once it exceeds the hi_water mark. + * + * \li #ISC_MEM_DEBUGSIZE + * Check the size argument being passed to isc_mem_put() matches + * that passed to isc_mem_get(). + * + * \li #ISC_MEM_DEBUGCTX + * Check the mctx argument being passed to isc_mem_put() matches + * that passed to isc_mem_get(). + */ +/*@}*/ + +#if ISC_MEM_TRACKLINES +#define _ISC_MEM_FILELINE , __FILE__, __LINE__ +#define _ISC_MEM_FLARG , const char *, unsigned int +#else +#define _ISC_MEM_FILELINE +#define _ISC_MEM_FLARG +#endif + +/*! + * Define ISC_MEM_USE_INTERNAL_MALLOC=1 to use the internal malloc() + * implementation in preference to the system one. The internal malloc() + * is very space-efficient, and quite fast on uniprocessor systems. It + * performs poorly on multiprocessor machines. + * JT: we can overcome the performance issue on multiprocessor machines + * by carefully separating memory contexts. + */ + +#ifndef ISC_MEM_USE_INTERNAL_MALLOC +#define ISC_MEM_USE_INTERNAL_MALLOC 1 +#endif + +/* + * Flags for isc_mem_create2()calls. + */ +#define ISC_MEMFLAG_NOLOCK 0x00000001 /* no lock is necessary */ +#define ISC_MEMFLAG_INTERNAL 0x00000002 /* use internal malloc */ +#if ISC_MEM_USE_INTERNAL_MALLOC +#define ISC_MEMFLAG_DEFAULT ISC_MEMFLAG_INTERNAL +#else +#define ISC_MEMFLAG_DEFAULT 0 +#endif + + +/*%< + * We use either isc___mem (three underscores) or isc__mem (two) depending on + * whether it's for BIND9's internal purpose (with -DBIND9) or generic export + * library. This condition is generally handled in isc/namespace.h, but for + * Windows it doesn't work if it involves multiple times of macro expansion + * (such as isc_mem to isc__mem then to isc___mem). The following definitions + * are used to work around this portability issue. Right now, we don't support + * the export library for Windows, so we always use the three-underscore + * version. + */ +#ifdef WIN32 +#define ISCMEMFUNC(sfx) isc___mem_ ## sfx +#define ISCMEMPOOLFUNC(sfx) isc___mempool_ ## sfx +#else +#define ISCMEMFUNC(sfx) isc__mem_ ## sfx +#define ISCMEMPOOLFUNC(sfx) isc__mempool_ ## sfx +#endif + +#define isc_mem_get(c, s) ISCMEMFUNC(get)((c), (s) _ISC_MEM_FILELINE) +#define isc_mem_allocate(c, s) ISCMEMFUNC(allocate)((c), (s) _ISC_MEM_FILELINE) +#define isc_mem_reallocate(c, p, s) ISCMEMFUNC(reallocate)((c), (p), (s) _ISC_MEM_FILELINE) +#define isc_mem_strdup(c, p) ISCMEMFUNC(strdup)((c), (p) _ISC_MEM_FILELINE) +#define isc_mempool_get(c) ISCMEMPOOLFUNC(get)((c) _ISC_MEM_FILELINE) + +/*% + * isc_mem_putanddetach() is a convenience function for use where you + * have a structure with an attached memory context. + * + * Given: + * + * \code + * struct { + * ... + * isc_mem_t *mctx; + * ... + * } *ptr; + * + * isc_mem_t *mctx; + * + * isc_mem_putanddetach(&ptr->mctx, ptr, sizeof(*ptr)); + * \endcode + * + * is the equivalent of: + * + * \code + * mctx = NULL; + * isc_mem_attach(ptr->mctx, &mctx); + * isc_mem_detach(&ptr->mctx); + * isc_mem_put(mctx, ptr, sizeof(*ptr)); + * isc_mem_detach(&mctx); + * \endcode + */ + +/*% memory and memory pool methods */ +typedef struct isc_memmethods { + void (*attach)(isc_mem_t *source, isc_mem_t **targetp); + void (*detach)(isc_mem_t **mctxp); + void (*destroy)(isc_mem_t **mctxp); + void *(*memget)(isc_mem_t *mctx, size_t size _ISC_MEM_FLARG); + void (*memput)(isc_mem_t *mctx, void *ptr, size_t size _ISC_MEM_FLARG); + void (*memputanddetach)(isc_mem_t **mctxp, void *ptr, + size_t size _ISC_MEM_FLARG); + void *(*memallocate)(isc_mem_t *mctx, size_t size _ISC_MEM_FLARG); + void *(*memreallocate)(isc_mem_t *mctx, void *ptr, + size_t size _ISC_MEM_FLARG); + char *(*memstrdup)(isc_mem_t *mctx, const char *s _ISC_MEM_FLARG); + void (*memfree)(isc_mem_t *mctx, void *ptr _ISC_MEM_FLARG); + void (*setdestroycheck)(isc_mem_t *mctx, isc_boolean_t flag); + void (*setwater)(isc_mem_t *ctx, isc_mem_water_t water, + void *water_arg, size_t hiwater, size_t lowater); + void (*waterack)(isc_mem_t *ctx, int flag); + size_t (*inuse)(isc_mem_t *mctx); + isc_boolean_t (*isovermem)(isc_mem_t *mctx); + isc_result_t (*mpcreate)(isc_mem_t *mctx, size_t size, + isc_mempool_t **mpctxp); +} isc_memmethods_t; + +typedef struct isc_mempoolmethods { + void (*destroy)(isc_mempool_t **mpctxp); + void *(*get)(isc_mempool_t *mpctx _ISC_MEM_FLARG); + void (*put)(isc_mempool_t *mpctx, void *mem _ISC_MEM_FLARG); + unsigned int (*getallocated)(isc_mempool_t *mpctx); + void (*setmaxalloc)(isc_mempool_t *mpctx, unsigned int limit); + void (*setfreemax)(isc_mempool_t *mpctx, unsigned int limit); + void (*setname)(isc_mempool_t *mpctx, const char *name); + void (*associatelock)(isc_mempool_t *mpctx, isc_mutex_t *lock); + void (*setfillcount)(isc_mempool_t *mpctx, unsigned int limit); +} isc_mempoolmethods_t; + +/*% + * This structure is actually just the common prefix of a memory context + * implementation's version of an isc_mem_t. + * \brief + * Direct use of this structure by clients is forbidden. mctx implementations + * may change the structure. 'magic' must be ISCAPI_MCTX_MAGIC for any of the + * isc_mem_ routines to work. mctx implementations must maintain all mctx + * invariants. + */ +struct isc_mem { + unsigned int impmagic; + unsigned int magic; + isc_memmethods_t *methods; +}; + +#define ISCAPI_MCTX_MAGIC ISC_MAGIC('A','m','c','x') +#define ISCAPI_MCTX_VALID(m) ((m) != NULL && \ + (m)->magic == ISCAPI_MCTX_MAGIC) + +/*% + * This is the common prefix of a memory pool context. The same note as + * that for the mem structure applies. + */ +struct isc_mempool { + unsigned int impmagic; + unsigned int magic; + isc_mempoolmethods_t *methods; +}; + +#define ISCAPI_MPOOL_MAGIC ISC_MAGIC('A','m','p','l') +#define ISCAPI_MPOOL_VALID(mp) ((mp) != NULL && \ + (mp)->magic == ISCAPI_MPOOL_MAGIC) + +#if ISC_MEM_DEBUG +#define isc_mem_put(c, p, s) \ + do { \ + ISCMEMFUNC(put)((c), (p), (s) _ISC_MEM_FILELINE); \ + (p) = NULL; \ + } while (0) +#define isc_mem_putanddetach(c, p, s) \ + do { \ + ISCMEMFUNC(putanddetach)((c), (p), (s) _ISC_MEM_FILELINE); \ + (p) = NULL; \ + } while (0) +#define isc_mem_free(c, p) \ + do { \ + ISCMEMFUNC(free)((c), (p) _ISC_MEM_FILELINE); \ + (p) = NULL; \ + } while (0) +#define isc_mempool_put(c, p) \ + do { \ + ISCMEMPOOLFUNC(put)((c), (p) _ISC_MEM_FILELINE); \ + (p) = NULL; \ + } while (0) +#else +#define isc_mem_put(c, p, s) ISCMEMFUNC(put)((c), (p), (s) _ISC_MEM_FILELINE) +#define isc_mem_putanddetach(c, p, s) \ + ISCMEMFUNC(putanddetach)((c), (p), (s) _ISC_MEM_FILELINE) +#define isc_mem_free(c, p) ISCMEMFUNC(free)((c), (p) _ISC_MEM_FILELINE) +#define isc_mempool_put(c, p) ISCMEMPOOLFUNC(put)((c), (p) _ISC_MEM_FILELINE) +#endif + +/*@{*/ +isc_result_t +isc_mem_create(size_t max_size, size_t target_size, + isc_mem_t **mctxp); + +isc_result_t +isc_mem_create2(size_t max_size, size_t target_size, + isc_mem_t **mctxp, unsigned int flags); + +isc_result_t +isc_mem_createx(size_t max_size, size_t target_size, + isc_memalloc_t memalloc, isc_memfree_t memfree, + void *arg, isc_mem_t **mctxp); + +isc_result_t +isc_mem_createx2(size_t max_size, size_t target_size, + isc_memalloc_t memalloc, isc_memfree_t memfree, + void *arg, isc_mem_t **mctxp, unsigned int flags); + +/*!< + * \brief Create a memory context. + * + * 'max_size' and 'target_size' are tuning parameters. When + * ISC_MEMFLAG_INTERNAL is set, allocations smaller than 'max_size' + * will be satisfied by getting blocks of size 'target_size' from the + * system allocator and breaking them up into pieces; larger allocations + * will use the system allocator directly. If 'max_size' and/or + * 'target_size' are zero, default values will be * used. When + * ISC_MEMFLAG_INTERNAL is not set, 'target_size' is ignored. + * + * 'max_size' is also used to size the statistics arrays and the array + * used to record active memory when ISC_MEM_DEBUGRECORD is set. Setting + * 'max_size' too low can have detrimental effects on performance. + * + * A memory context created using isc_mem_createx() will obtain + * memory from the system by calling 'memalloc' and 'memfree', + * passing them the argument 'arg'. A memory context created + * using isc_mem_create() will use the standard library malloc() + * and free(). + * + * If ISC_MEMFLAG_NOLOCK is set in 'flags', the corresponding memory context + * will be accessed without locking. The user who creates the context must + * ensure there be no race. Since this can be a source of bug, it is generally + * inadvisable to use this flag unless the user is very sure about the race + * condition and the access to the object is highly performance sensitive. + * + * Requires: + * mctxp != NULL && *mctxp == NULL */ +/*@}*/ + +/*@{*/ +void +isc_mem_attach(isc_mem_t *, isc_mem_t **); +void +isc_mem_detach(isc_mem_t **); +/*!< + * \brief Attach to / detach from a memory context. + * + * This is intended for applications that use multiple memory contexts + * in such a way that it is not obvious when the last allocations from + * a given context has been freed and destroying the context is safe. + * + * Most applications do not need to call these functions as they can + * simply create a single memory context at the beginning of main() + * and destroy it at the end of main(), thereby guaranteeing that it + * is not destroyed while there are outstanding allocations. + */ +/*@}*/ + +void +isc_mem_destroy(isc_mem_t **); +/*%< + * Destroy a memory context. + */ + +isc_result_t +isc_mem_ondestroy(isc_mem_t *ctx, + isc_task_t *task, + isc_event_t **event); +/*%< + * Request to be notified with an event when a memory context has + * been successfully destroyed. + */ + +void +isc_mem_stats(isc_mem_t *mctx, FILE *out); +/*%< + * Print memory usage statistics for 'mctx' on the stream 'out'. + */ + +void +isc_mem_setdestroycheck(isc_mem_t *mctx, + isc_boolean_t on); +/*%< + * If 'on' is ISC_TRUE, 'mctx' will check for memory leaks when + * destroyed and abort the program if any are present. + */ + +/*@{*/ +void +isc_mem_setquota(isc_mem_t *, size_t); +size_t +isc_mem_getquota(isc_mem_t *); +/*%< + * Set/get the memory quota of 'mctx'. This is a hard limit + * on the amount of memory that may be allocated from mctx; + * if it is exceeded, allocations will fail. + */ +/*@}*/ + +size_t +isc_mem_inuse(isc_mem_t *mctx); +/*%< + * Get an estimate of the number of memory in use in 'mctx', in bytes. + * This includes quantization overhead, but does not include memory + * allocated from the system but not yet used. + */ + +isc_boolean_t +isc_mem_isovermem(isc_mem_t *mctx); +/*%< + * Return true iff the memory context is in "over memory" state, i.e., + * a hiwater mark has been set and the used amount of memory has exceeds + * the mark. + */ + +void +isc_mem_setwater(isc_mem_t *mctx, isc_mem_water_t water, void *water_arg, + size_t hiwater, size_t lowater); +/*%< + * Set high and low water marks for this memory context. + * + * When the memory usage of 'mctx' exceeds 'hiwater', + * '(water)(water_arg, #ISC_MEM_HIWATER)' will be called. 'water' needs to + * call isc_mem_waterack() with #ISC_MEM_HIWATER to acknowledge the state + * change. 'water' may be called multiple times. + * + * When the usage drops below 'lowater', 'water' will again be called, this + * time with #ISC_MEM_LOWATER. 'water' need to calls isc_mem_waterack() with + * #ISC_MEM_LOWATER to acknowledge the change. + * + * static void + * water(void *arg, int mark) { + * struct foo *foo = arg; + * + * LOCK(&foo->marklock); + * if (foo->mark != mark) { + * foo->mark = mark; + * .... + * isc_mem_waterack(foo->mctx, mark); + * } + * UNLOCK(&foo->marklock); + * } + * + * If 'water' is NULL then 'water_arg', 'hi_water' and 'lo_water' are + * ignored and the state is reset. + * + * Requires: + * + * 'water' is not NULL. + * hi_water >= lo_water + */ + +void +isc_mem_waterack(isc_mem_t *ctx, int mark); +/*%< + * Called to acknowledge changes in signaled by calls to 'water'. + */ + +void +isc_mem_printactive(isc_mem_t *mctx, FILE *file); +/*%< + * Print to 'file' all active memory in 'mctx'. + * + * Requires ISC_MEM_DEBUGRECORD to have been set. + */ + +void +isc_mem_printallactive(FILE *file); +/*%< + * Print to 'file' all active memory in all contexts. + * + * Requires ISC_MEM_DEBUGRECORD to have been set. + */ + +void +isc_mem_checkdestroyed(FILE *file); +/*%< + * Check that all memory contexts have been destroyed. + * Prints out those that have not been. + * Fatally fails if there are still active contexts. + */ + +unsigned int +isc_mem_references(isc_mem_t *ctx); +/*%< + * Return the current reference count. + */ + +void +isc_mem_setname(isc_mem_t *ctx, const char *name, void *tag); +/*%< + * Name 'ctx'. + * + * Notes: + * + *\li Only the first 15 characters of 'name' will be copied. + * + *\li 'tag' is for debugging purposes only. + * + * Requires: + * + *\li 'ctx' is a valid ctx. + */ + +const char * +isc_mem_getname(isc_mem_t *ctx); +/*%< + * Get the name of 'ctx', as previously set using isc_mem_setname(). + * + * Requires: + *\li 'ctx' is a valid ctx. + * + * Returns: + *\li A non-NULL pointer to a null-terminated string. + * If the ctx has not been named, the string is + * empty. + */ + +void * +isc_mem_gettag(isc_mem_t *ctx); +/*%< + * Get the tag value for 'task', as previously set using isc_mem_setname(). + * + * Requires: + *\li 'ctx' is a valid ctx. + * + * Notes: + *\li This function is for debugging purposes only. + * + * Requires: + *\li 'ctx' is a valid task. + */ + +#ifdef HAVE_LIBXML2 +void +isc_mem_renderxml(xmlTextWriterPtr writer); +/*%< + * Render all contexts' statistics and status in XML for writer. + */ +#endif /* HAVE_LIBXML2 */ + +/* + * Memory pools + */ + +isc_result_t +isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp); +/*%< + * Create a memory pool. + * + * Requires: + *\li mctx is a valid memory context. + *\li size > 0 + *\li mpctxp != NULL and *mpctxp == NULL + * + * Defaults: + *\li maxalloc = UINT_MAX + *\li freemax = 1 + *\li fillcount = 1 + * + * Returns: + *\li #ISC_R_NOMEMORY -- not enough memory to create pool + *\li #ISC_R_SUCCESS -- all is well. + */ + +void +isc_mempool_destroy(isc_mempool_t **mpctxp); +/*%< + * Destroy a memory pool. + * + * Requires: + *\li mpctxp != NULL && *mpctxp is a valid pool. + *\li The pool has no un"put" allocations outstanding + */ + +void +isc_mempool_setname(isc_mempool_t *mpctx, const char *name); +/*%< + * Associate a name with a memory pool. At most 15 characters may be used. + * + * Requires: + *\li mpctx is a valid pool. + *\li name != NULL; + */ + +void +isc_mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock); +/*%< + * Associate a lock with this memory pool. + * + * This lock is used when getting or putting items using this memory pool, + * and it is also used to set or get internal state via the isc_mempool_get*() + * and isc_mempool_set*() set of functions. + * + * Multiple pools can each share a single lock. For instance, if "manager" + * type object contained pools for various sizes of events, and each of + * these pools used a common lock. Note that this lock must NEVER be used + * by other than mempool routines once it is given to a pool, since that can + * easily cause double locking. + * + * Requires: + * + *\li mpctpx is a valid pool. + * + *\li lock != NULL. + * + *\li No previous lock is assigned to this pool. + * + *\li The lock is initialized before calling this function via the normal + * means of doing that. + */ + +/* + * The following functions get/set various parameters. Note that due to + * the unlocked nature of pools these are potentially random values unless + * the imposed externally provided locking protocols are followed. + * + * Also note that the quota limits will not always take immediate effect. + * For instance, setting "maxalloc" to a number smaller than the currently + * allocated count is permitted. New allocations will be refused until + * the count drops below this threshold. + * + * All functions require (in addition to other requirements): + * mpctx is a valid memory pool + */ + +unsigned int +isc_mempool_getfreemax(isc_mempool_t *mpctx); +/*%< + * Returns the maximum allowed size of the free list. + */ + +void +isc_mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit); +/*%< + * Sets the maximum allowed size of the free list. + */ + +unsigned int +isc_mempool_getfreecount(isc_mempool_t *mpctx); +/*%< + * Returns current size of the free list. + */ + +unsigned int +isc_mempool_getmaxalloc(isc_mempool_t *mpctx); +/*!< + * Returns the maximum allowed number of allocations. + */ + +void +isc_mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit); +/*%< + * Sets the maximum allowed number of allocations. + * + * Additional requirements: + *\li limit > 0 + */ + +unsigned int +isc_mempool_getallocated(isc_mempool_t *mpctx); +/*%< + * Returns the number of items allocated from this pool. + */ + +unsigned int +isc_mempool_getfillcount(isc_mempool_t *mpctx); +/*%< + * Returns the number of items allocated as a block from the parent memory + * context when the free list is empty. + */ + +void +isc_mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit); +/*%< + * Sets the fillcount. + * + * Additional requirements: + *\li limit > 0 + */ + + +/* + * Pseudo-private functions for use via macros. Do not call directly. + */ +void * +ISCMEMFUNC(get)(isc_mem_t *, size_t _ISC_MEM_FLARG); +void +ISCMEMFUNC(putanddetach)(isc_mem_t **, void *, size_t _ISC_MEM_FLARG); +void +ISCMEMFUNC(put)(isc_mem_t *, void *, size_t _ISC_MEM_FLARG); +void * +ISCMEMFUNC(allocate)(isc_mem_t *, size_t _ISC_MEM_FLARG); +void * +ISCMEMFUNC(reallocate)(isc_mem_t *, void *, size_t _ISC_MEM_FLARG); +void +ISCMEMFUNC(free)(isc_mem_t *, void * _ISC_MEM_FLARG); +char * +ISCMEMFUNC(strdup)(isc_mem_t *, const char *_ISC_MEM_FLARG); +void * +ISCMEMPOOLFUNC(get)(isc_mempool_t * _ISC_MEM_FLARG); +void +ISCMEMPOOLFUNC(put)(isc_mempool_t *, void * _ISC_MEM_FLARG); + +#ifdef USE_MEMIMPREGISTER + +/*%< + * See isc_mem_create2() above. + */ +typedef isc_result_t +(*isc_memcreatefunc_t)(size_t init_max_size, size_t target_size, + isc_mem_t **ctxp, unsigned int flags); + +isc_result_t +isc_mem_register(isc_memcreatefunc_t createfunc); +/*%< + * Register a new memory management implementation and add it to the list of + * supported implementations. This function must be called when a different + * memory management library is used than the one contained in the ISC library. + */ + +isc_result_t +isc__mem_register(void); +/*%< + * A short cut function that specifies the memory management module in the ISC + * library for isc_mem_register(). An application that uses the ISC library + * usually do not have to care about this function: it would call + * isc_lib_register(), which internally calls this function. + */ +#endif /* USE_MEMIMPREGISTER */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_MEM_H */ diff --git a/contrib/ntp/lib/isc/include/isc/msgcat.h b/contrib/ntp/lib/isc/include/isc/msgcat.h new file mode 100644 index 0000000..fe3d336 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/msgcat.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: msgcat.h,v 1.13 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_MSGCAT_H +#define ISC_MSGCAT_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file isc/msgcat.h + * \brief The ISC Message Catalog + * aids internationalization of applications by allowing + * messages to be retrieved from locale-specific files instead of + * hardwiring them into the application. This allows translations of + * messages appropriate to the locale to be supplied without recompiling + * the application. + * + * Notes: + *\li It's very important that message catalogs work, even if only the + * default_text can be used. + * + * MP: + *\li The caller must ensure appropriate synchronization of + * isc_msgcat_open() and isc_msgcat_close(). isc_msgcat_get() + * ensures appropriate synchronization. + * + * Reliability: + *\li No anticipated impact. + * + * Resources: + *\li TBS + * + * \li Security: + * No anticipated impact. + * + * \li Standards: + * None. + */ + +/***** + ***** Imports + *****/ + +#include <isc/lang.h> +#include <isc/types.h> + +ISC_LANG_BEGINDECLS + +/***** + ***** Methods + *****/ + +void +isc_msgcat_open(const char *name, isc_msgcat_t **msgcatp); +/*%< + * Open a message catalog. + * + * Notes: + * + *\li If memory cannot be allocated or other failures occur, *msgcatp + * will be set to NULL. If a NULL msgcat is given to isc_msgcat_get(), + * the default_text will be returned, ensuring that some message text + * will be available, no matter what's going wrong. + * + * Requires: + * + *\li 'name' is a valid string. + * + *\li msgcatp != NULL && *msgcatp == NULL + */ + +void +isc_msgcat_close(isc_msgcat_t **msgcatp); +/*%< + * Close a message catalog. + * + * Notes: + * + *\li Any string pointers returned by prior calls to isc_msgcat_get() are + * invalid after isc_msgcat_close() has been called and must not be + * used. + * + * Requires: + * + *\li *msgcatp is a valid message catalog or is NULL. + * + * Ensures: + * + *\li All resources associated with the message catalog are released. + * + *\li *msgcatp == NULL + */ + +const char * +isc_msgcat_get(isc_msgcat_t *msgcat, int set, int message, + const char *default_text); +/*%< + * Get message 'message' from message set 'set' in 'msgcat'. If it + * is not available, use 'default_text'. + * + * Requires: + * + *\li 'msgcat' is a valid message catalog or is NULL. + * + *\li set > 0 + * + *\li message > 0 + * + *\li 'default_text' is a valid string. + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_MSGCAT_H */ diff --git a/contrib/ntp/lib/isc/include/isc/msgs.h b/contrib/ntp/lib/isc/include/isc/msgs.h new file mode 100644 index 0000000..60c5c7c --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/msgs.h @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000-2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: msgs.h,v 1.19 2009/10/01 23:48:08 tbox Exp $ */ + +#ifndef ISC_MSGS_H +#define ISC_MSGS_H 1 + +/*! \file isc/msgs.h */ + +#include <isc/lib.h> /* Provide isc_msgcat global variable. */ +#include <isc/msgcat.h> /* Provide isc_msgcat_*() functions. */ + +/*@{*/ +/*! + * \brief Message sets, named per source file, excepting "GENERAL". + * + * IMPORTANT: The original list is alphabetical, but any new sets must + * be added to the end. + */ +#define ISC_MSGSET_GENERAL 1 +/* ISC_RESULT_RESULTSET 2 */ /* XXX */ +/* ISC_RESULT_UNAVAILABLESET 3 */ /* XXX */ +#define ISC_MSGSET_APP 4 +#define ISC_MSGSET_COMMANDLINE 5 +#define ISC_MSGSET_ENTROPY 6 +#define ISC_MSGSET_IFITERIOCTL 7 +#define ISC_MSGSET_IFITERSYSCTL 8 +#define ISC_MSGSET_LEX 9 +#define ISC_MSGSET_LOG 10 +#define ISC_MSGSET_MEM 11 +#define ISC_MSGSET_NETADDR 12 +#define ISC_MSGSET_PRINT 13 +#define ISC_MSGSET_RESULT 14 +#define ISC_MSGSET_RWLOCK 15 +#define ISC_MSGSET_SOCKADDR 16 +#define ISC_MSGSET_SOCKET 17 +#define ISC_MSGSET_TASK 18 +#define ISC_MSGSET_TIMER 19 +#define ISC_MSGSET_UTIL 20 +#define ISC_MSGSET_IFITERGETIFADDRS 21 +/*@}*/ + +/*@{*/ +/*! + * Message numbers + * are only required to be unique per message set, + * but are unique throughout the entire catalog to not be as confusing when + * debugging. + * + * The initial numbering was done by multiply by 100 the set number the + * message appears in then adding the incremental message number. + */ +#define ISC_MSG_FAILED 101 /*%< "failed" */ +#define ISC_MSG_SUCCEEDED 102 /*%< Compatible with "failed" */ +#define ISC_MSG_SUCCESS 103 /*%< More usual way to say "success" */ +#define ISC_MSG_STARTING 104 /*%< As in "daemon: starting" */ +#define ISC_MSG_STOPING 105 /*%< As in "daemon: stopping" */ +#define ISC_MSG_ENTERING 106 /*%< As in "some_subr: entering" */ +#define ISC_MSG_EXITING 107 /*%< As in "some_subr: exiting" */ +#define ISC_MSG_CALLING 108 /*%< As in "calling some_subr()" */ +#define ISC_MSG_RETURNED 109 /*%< As in "some_subr: returned <foo>" */ +#define ISC_MSG_FATALERROR 110 /*%< "fatal error" */ +#define ISC_MSG_SHUTTINGDOWN 111 /*%< "shutting down" */ +#define ISC_MSG_RUNNING 112 /*%< "running" */ +#define ISC_MSG_WAIT 113 /*%< "wait" */ +#define ISC_MSG_WAITUNTIL 114 /*%< "waituntil" */ + +#define ISC_MSG_SIGNALSETUP 201 /*%< "handle_signal() %d setup: %s" */ + +#define ISC_MSG_ILLEGALOPT 301 /*%< "illegal option" */ +#define ISC_MSG_OPTNEEDARG 302 /*%< "option requires an argument" */ + +#define ISC_MSG_ENTROPYSTATS 401 /*%< "Entropy pool %p: refcnt %u ..." */ + +#define ISC_MSG_MAKESCANSOCKET 501 /*%< "making interface scan socket: %s" */ +#define ISC_MSG_GETIFCONFIG 502 /*%< "get interface configuration: %s" */ +#define ISC_MSG_BUFFERMAX 503 /*%< "... maximum buffer size exceeded" */ +#define ISC_MSG_GETDESTADDR 504 /*%< "%s: getting destination address: %s" */ +#define ISC_MSG_GETNETMASK 505 /*%< "%s: getting netmask: %s" */ +#define ISC_MSG_GETBCSTADDR 506 /*%< "%s: getting broadcast address: %s" */ + +#define ISC_MSG_GETIFLISTSIZE 601 /*%< "getting interface list size: ..." */ +#define ISC_MSG_GETIFLIST 602 /*%< "getting interface list: ..." */ +#define ISC_MSG_UNEXPECTEDTYPE 603 /*%< "... unexpected ... message type" */ + +#define ISC_MSG_UNEXPECTEDSTATE 701 /*%< "Unexpected state %d" */ + +#define ISC_MSG_BADTIME 801 /*%< "Bad 00 99:99:99.999 " */ +#define ISC_MSG_LEVEL 802 /*%< "level %d: " */ + +#define ISC_MSG_ADDTRACE 901 /*%< "add %p size %u " */ +#define ISC_MSG_DELTRACE 902 /*%< "del %p size %u " */ +#define ISC_MSG_POOLSTATS 903 /*%< "[Pool statistics]\n" */ +#define ISC_MSG_POOLNAME 904 /*%< "name" */ +#define ISC_MSG_POOLSIZE 905 /*%< "size" */ +#define ISC_MSG_POOLMAXALLOC 906 /*%< "maxalloc" */ +#define ISC_MSG_POOLALLOCATED 907 /*%< "allocated" */ +#define ISC_MSG_POOLFREECOUNT 908 /*%< "freecount" */ +#define ISC_MSG_POOLFREEMAX 909 /*%< "freemax" */ +#define ISC_MSG_POOLFILLCOUNT 910 /*%< "fillcount" */ +#define ISC_MSG_POOLGETS 911 /*%< "gets" */ +#define ISC_MSG_DUMPALLOC 912 /*%< "DUMP OF ALL OUTSTANDING MEMORY ..." */ +#define ISC_MSG_NONE 913 /*%< "\tNone.\n" */ +#define ISC_MSG_PTRFILELINE 914 /*%< "\tptr %p file %s line %u\n" */ + +#define ISC_MSG_UNKNOWNADDR 1001 /*%< "<unknown address, family %u>" */ + +#define ISC_MSG_NOLONGDBL 1104 /*%< "long doubles are not supported" */ + +#define ISC_MSG_PRINTLOCK 1201 /*%< "rwlock %p thread %lu ..." */ +#define ISC_MSG_READ 1202 /*%< "read" */ +#define ISC_MSG_WRITE 1203 /*%< "write" */ +#define ISC_MSG_READING 1204 /*%< "reading" */ +#define ISC_MSG_WRITING 1205 /*%< "writing" */ +#define ISC_MSG_PRELOCK 1206 /*%< "prelock" */ +#define ISC_MSG_POSTLOCK 1207 /*%< "postlock" */ +#define ISC_MSG_PREUNLOCK 1208 /*%< "preunlock" */ +#define ISC_MSG_POSTUNLOCK 1209 /*%< "postunlock" */ + +#define ISC_MSG_UNKNOWNFAMILY 1301 /*%< "unknown address family: %d" */ + +#define ISC_MSG_WRITEFAILED 1401 /*%< "write() failed during watcher ..." */ +#define ISC_MSG_READFAILED 1402 /*%< "read() failed during watcher ... " */ +#define ISC_MSG_PROCESSCMSG 1403 /*%< "processing cmsg %p" */ +#define ISC_MSG_IFRECEIVED 1404 /*%< "interface received on ifindex %u" */ +#define ISC_MSG_SENDTODATA 1405 /*%< "sendto pktinfo data, ifindex %u" */ +#define ISC_MSG_DOIORECV 1406 /*%< "doio_recv: recvmsg(%d) %d bytes ..." */ +#define ISC_MSG_PKTRECV 1407 /*%< "packet received correctly" */ +#define ISC_MSG_DESTROYING 1408 /*%< "destroying" */ +#define ISC_MSG_CREATED 1409 /*%< "created" */ +#define ISC_MSG_ACCEPTLOCK 1410 /*%< "internal_accept called, locked ..." */ +#define ISC_MSG_ACCEPTEDCXN 1411 /*%< "accepted connection, new socket %p" */ +#define ISC_MSG_INTERNALRECV 1412 /*%< "internal_recv: task %p got event %p" */ +#define ISC_MSG_INTERNALSEND 1413 /*%< "internal_send: task %p got event %p" */ +#define ISC_MSG_WATCHERMSG 1414 /*%< "watcher got message %d" */ +#define ISC_MSG_SOCKETSREMAIN 1415 /*%< "sockets exist" */ +#define ISC_MSG_PKTINFOPROVIDED 1416 /*%< "pktinfo structure provided, ..." */ +#define ISC_MSG_BOUND 1417 /*%< "bound" */ +#define ISC_MSG_ACCEPTRETURNED 1418 /*%< accept() returned %d/%s */ +#define ISC_MSG_TOOMANYFDS 1419 /*%< %s: too many open file descriptors */ +#define ISC_MSG_ZEROPORT 1420 /*%< dropping source port zero packet */ +#define ISC_MSG_FILTER 1421 /*%< setsockopt(SO_ACCEPTFILTER): %s */ + +#define ISC_MSG_TOOMANYHANDLES 1422 /*%< %s: too many open WSA event handles: %s */ +#define ISC_MSG_POKED 1423 /*%< "poked flags: %d" */ + +#define ISC_MSG_AWAKE 1502 /*%< "awake" */ +#define ISC_MSG_WORKING 1503 /*%< "working" */ +#define ISC_MSG_EXECUTE 1504 /*%< "execute action" */ +#define ISC_MSG_EMPTY 1505 /*%< "empty" */ +#define ISC_MSG_DONE 1506 /*%< "done" */ +#define ISC_MSG_QUANTUM 1507 /*%< "quantum" */ + +#define ISC_MSG_SCHEDULE 1601 /*%< "schedule" */ +#define ISC_MSG_SIGNALSCHED 1602 /*%< "signal (schedule)" */ +#define ISC_MSG_SIGNALDESCHED 1603 /*%< "signal (deschedule)" */ +#define ISC_MSG_SIGNALDESTROY 1604 /*%< "signal (destroy)" */ +#define ISC_MSG_IDLERESCHED 1605 /*%< "idle reschedule" */ +#define ISC_MSG_EVENTNOTALLOC 1606 /*%< "couldn't allocate event" */ +#define ISC_MSG_SCHEDFAIL 1607 /*%< "couldn't schedule timer: %u" */ +#define ISC_MSG_POSTING 1608 /*%< "posting" */ +#define ISC_MSG_WAKEUP 1609 /*%< "wakeup" */ + +#define ISC_MSG_LOCK 1701 /*%< "LOCK" */ +#define ISC_MSG_LOCKING 1702 /*%< "LOCKING" */ +#define ISC_MSG_LOCKED 1703 /*%< "LOCKED" */ +#define ISC_MSG_UNLOCKED 1704 /*%< "UNLOCKED" */ +#define ISC_MSG_RWLOCK 1705 /*%< "RWLOCK" */ +#define ISC_MSG_RWLOCKED 1706 /*%< "RWLOCKED" */ +#define ISC_MSG_RWUNLOCK 1707 /*%< "RWUNLOCK" */ +#define ISC_MSG_BROADCAST 1708 /*%< "BROADCAST" */ +#define ISC_MSG_SIGNAL 1709 /*%< "SIGNAL" */ +#define ISC_MSG_UTILWAIT 1710 /*%< "WAIT" */ +#define ISC_MSG_WAITED 1711 /*%< "WAITED" */ + +#define ISC_MSG_GETIFADDRS 1801 /*%< "getting interface addresses: ..." */ + +/*@}*/ + +#endif /* ISC_MSGS_H */ diff --git a/contrib/ntp/lib/isc/include/isc/mutexblock.h b/contrib/ntp/lib/isc/include/isc/mutexblock.h new file mode 100644 index 0000000..65bf2bf --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/mutexblock.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: mutexblock.h,v 1.17 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_MUTEXBLOCK_H +#define ISC_MUTEXBLOCK_H 1 + +/*! \file isc/mutexblock.h */ + +#include <isc/lang.h> +#include <isc/mutex.h> +#include <isc/types.h> + +ISC_LANG_BEGINDECLS + +isc_result_t +isc_mutexblock_init(isc_mutex_t *block, unsigned int count); +/*%< + * Initialize a block of locks. If an error occurs all initialized locks + * will be destroyed, if possible. + * + * Requires: + * + *\li block != NULL + * + *\li count > 0 + * + * Returns: + * + *\li Any code isc_mutex_init() can return is a valid return for this + * function. + */ + +isc_result_t +isc_mutexblock_destroy(isc_mutex_t *block, unsigned int count); +/*%< + * Destroy a block of locks. + * + * Requires: + * + *\li block != NULL + * + *\li count > 0 + * + *\li Each lock in the block be initialized via isc_mutex_init() or + * the whole block was initialized via isc_mutex_initblock(). + * + * Returns: + * + *\li Any code isc_mutex_init() can return is a valid return for this + * function. + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_MUTEXBLOCK_H */ diff --git a/contrib/ntp/lib/isc/include/isc/namespace.h b/contrib/ntp/lib/isc/include/isc/namespace.h new file mode 100644 index 0000000..cd4ec9a --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/namespace.h @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2009-2012 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +#ifndef ISCAPI_NAMESPACE_H +#define ISCAPI_NAMESPACE_H 1 + +/*% + * name space conversions + */ + +#ifdef BIND9 + +#define isc_app_start isc__app_start +#define isc_app_ctxstart isc__app_ctxstart +#define isc_app_onrun isc__app_onrun +#define isc_app_run isc__app_run +#define isc_app_ctxrun isc__app_ctxrun +#define isc_app_shutdown isc__app_shutdown +#define isc_app_ctxfinish isc__app_ctxfinish +#define isc_app_ctxshutdown isc__app_ctxshutdown +#define isc_app_ctxsuspend isc__app_ctxsuspend +#define isc_app_reload isc__app_reload +#define isc_app_finish isc__app_finish +#define isc_app_block isc__app_block +#define isc_app_unblock isc__app_unblock +#define isc_appctx_create isc__appctx_create +#define isc_appctx_destroy isc__appctx_destroy +#define isc_appctx_settaskmgr isc__appctx_settaskmgr +#define isc_appctx_setsocketmgr isc__appctx_setsocketmgr +#define isc_appctx_settimermgr isc__appctx_settimermgr + +#define isc_mem_checkdestroyed isc__mem_checkdestroyed +#define isc_mem_createx isc__mem_createx +#define isc_mem_createx2 isc__mem_createx2 +#define isc_mem_create isc__mem_create +#define isc_mem_create2 isc__mem_create2 +#define isc_mem_attach isc__mem_attach +#define isc_mem_detach isc__mem_detach +#define isc__mem_putanddetach isc___mem_putanddetach +#define isc_mem_destroy isc__mem_destroy +#define isc_mem_ondestroy isc__mem_ondestroy +#define isc__mem_get isc___mem_get +#define isc__mem_put isc___mem_put +#define isc_mem_stats isc__mem_stats +#define isc__mem_allocate isc___mem_allocate +#define isc__mem_free isc___mem_free +#define isc__mem_strdup isc___mem_strdup +#define isc__mem_reallocate isc___mem_reallocate +#define isc_mem_references isc__mem_references +#define isc_mem_setdestroycheck isc__mem_setdestroycheck +#define isc_mem_setquota isc__mem_setquota +#define isc_mem_getname isc__mem_getname +#define isc_mem_getquota isc__mem_getquota +#define isc_mem_gettag isc__mem_gettag +#define isc_mem_inuse isc__mem_inuse +#define isc_mem_isovermem isc__mem_isovermem +#define isc_mem_setname isc__mem_setname +#define isc_mem_setwater isc__mem_setwater +#define isc_mem_printallactive isc__mem_printallactive +#define isc_mem_waterack isc__mem_waterack +#define isc_mempool_create isc__mempool_create +#define isc_mempool_setname isc__mempool_setname +#define isc_mempool_destroy isc__mempool_destroy +#define isc_mempool_associatelock isc__mempool_associatelock +#define isc__mempool_get isc___mempool_get +#define isc__mempool_put isc___mempool_put +#define isc_mempool_setfreemax isc__mempool_setfreemax +#define isc_mempool_getfreemax isc__mempool_getfreemax +#define isc_mempool_getfreecount isc__mempool_getfreecount +#define isc_mempool_setmaxalloc isc__mempool_setmaxalloc +#define isc_mempool_getmaxalloc isc__mempool_getmaxalloc +#define isc_mempool_getallocated isc__mempool_getallocated +#define isc_mempool_setfillcount isc__mempool_setfillcount +#define isc_mempool_getfillcount isc__mempool_getfillcount + +#define isc_socket_create isc__socket_create +#define isc_socket_dup isc__socket_dup +#define isc_socket_attach isc__socket_attach +#define isc_socket_detach isc__socket_detach +#define isc_socketmgr_create isc__socketmgr_create +#define isc_socketmgr_create2 isc__socketmgr_create2 +#define isc_socketmgr_destroy isc__socketmgr_destroy +#define isc_socket_open isc__socket_open +#define isc_socket_close isc__socket_close +#define isc_socket_recvv isc__socket_recvv +#define isc_socket_recv isc__socket_recv +#define isc_socket_recv2 isc__socket_recv2 +#define isc_socket_send isc__socket_send +#define isc_socket_sendto isc__socket_sendto +#define isc_socket_sendv isc__socket_sendv +#define isc_socket_sendtov isc__socket_sendtov +#define isc_socket_sendto2 isc__socket_sendto2 +#define isc_socket_cleanunix isc__socket_cleanunix +#define isc_socket_permunix isc__socket_permunix +#define isc_socket_bind isc__socket_bind +#define isc_socket_filter isc__socket_filter +#define isc_socket_listen isc__socket_listen +#define isc_socket_accept isc__socket_accept +#define isc_socket_connect isc__socket_connect +#define isc_socket_getfd isc__socket_getfd +#define isc_socket_getname isc__socket_getname +#define isc_socket_gettag isc__socket_gettag +#define isc_socket_getpeername isc__socket_getpeername +#define isc_socket_getsockname isc__socket_getsockname +#define isc_socket_cancel isc__socket_cancel +#define isc_socket_gettype isc__socket_gettype +#define isc_socket_isbound isc__socket_isbound +#define isc_socket_ipv6only isc__socket_ipv6only +#define isc_socket_setname isc__socket_setname +#define isc_socketmgr_getmaxsockets isc__socketmgr_getmaxsockets +#define isc_socketmgr_setstats isc__socketmgr_setstats +#define isc_socketmgr_setreserved isc__socketmgr_setreserved +#define isc__socketmgr_maxudp isc___socketmgr_maxudp +#define isc_socket_fdwatchcreate isc__socket_fdwatchcreate +#define isc_socket_fdwatchpoke isc__socket_fdwatchpoke + +#define isc_task_create isc__task_create +#define isc_task_attach isc__task_attach +#define isc_task_detach isc__task_detach +/* #define isc_task_exiting isc__task_exiting XXXMPA */ +#define isc_task_send isc__task_send +#define isc_task_sendanddetach isc__task_sendanddetach +#define isc_task_purgerange isc__task_purgerange +#define isc_task_purge isc__task_purge +#define isc_task_purgeevent isc__task_purgeevent +#define isc_task_unsendrange isc__task_unsendrange +#define isc_task_unsend isc__task_unsend +#define isc_task_onshutdown isc__task_onshutdown +#define isc_task_shutdown isc__task_shutdown +#define isc_task_destroy isc__task_destroy +#define isc_task_setname isc__task_setname +#define isc_task_getname isc__task_getname +#define isc_task_gettag isc__task_gettag +#define isc_task_getcurrenttime isc__task_getcurrenttime +#define isc_taskmgr_create isc__taskmgr_create +#define isc_taskmgr_setmode isc__taskmgr_setmode +#define isc_taskmgr_mode isc__taskmgr_mode +#define isc_taskmgr_destroy isc__taskmgr_destroy +#define isc_task_beginexclusive isc__task_beginexclusive +#define isc_task_endexclusive isc__task_endexclusive +#define isc_task_setprivilege isc__task_setprivilege +#define isc_task_privilege isc__task_privilege + +#define isc_timer_create isc__timer_create +#define isc_timer_reset isc__timer_reset +#define isc_timer_gettype isc__timer_gettype +#define isc_timer_touch isc__timer_touch +#define isc_timer_attach isc__timer_attach +#define isc_timer_detach isc__timer_detach +#define isc_timermgr_create isc__timermgr_create +#define isc_timermgr_poke isc__timermgr_poke +#define isc_timermgr_destroy isc__timermgr_destroy + +#endif /* BIND9 */ + +#endif /* ISCAPI_NAMESPACE_H */ diff --git a/contrib/ntp/lib/isc/include/isc/netaddr.h b/contrib/ntp/lib/isc/include/isc/netaddr.h new file mode 100644 index 0000000..954d770 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/netaddr.h @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: netaddr.h,v 1.37 2009/01/17 23:47:43 tbox Exp $ */ + +#ifndef ISC_NETADDR_H +#define ISC_NETADDR_H 1 + +/*! \file isc/netaddr.h */ + +#include <isc/lang.h> +#include <isc/net.h> +#include <isc/types.h> + +#ifdef ISC_PLATFORM_HAVESYSUNH +#include <sys/types.h> +#include <sys/un.h> +#endif + +ISC_LANG_BEGINDECLS + +struct isc_netaddr { + unsigned int family; + union { + struct in_addr in; + struct in6_addr in6; +#ifdef ISC_PLATFORM_HAVESYSUNH + char un[sizeof(((struct sockaddr_un *)0)->sun_path)]; +#endif + } type; + isc_uint32_t zone; +}; + +isc_boolean_t +isc_netaddr_equal(const isc_netaddr_t *a, const isc_netaddr_t *b); + +/*%< + * Compare network addresses 'a' and 'b'. Return #ISC_TRUE if + * they are equal, #ISC_FALSE if not. + */ + +isc_boolean_t +isc_netaddr_eqprefix(const isc_netaddr_t *a, const isc_netaddr_t *b, + unsigned int prefixlen); +/*%< + * Compare the 'prefixlen' most significant bits of the network + * addresses 'a' and 'b'. If 'b''s scope is zero then 'a''s scope is + * ignored. Return #ISC_TRUE if they are equal, #ISC_FALSE if not. + */ + +isc_result_t +isc_netaddr_masktoprefixlen(const isc_netaddr_t *s, unsigned int *lenp); +/*%< + * Convert a netmask in 's' into a prefix length in '*lenp'. + * The mask should consist of zero or more '1' bits in the most + * most significant part of the address, followed by '0' bits. + * If this is not the case, #ISC_R_MASKNONCONTIG is returned. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_MASKNONCONTIG + */ + +isc_result_t +isc_netaddr_totext(const isc_netaddr_t *netaddr, isc_buffer_t *target); +/*%< + * Append a text representation of 'sockaddr' to the buffer 'target'. + * The text is NOT null terminated. Handles IPv4 and IPv6 addresses. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOSPACE The text or the null termination did not fit. + *\li #ISC_R_FAILURE Unspecified failure + */ + +void +isc_netaddr_format(const isc_netaddr_t *na, char *array, unsigned int size); +/*%< + * Format a human-readable representation of the network address '*na' + * into the character array 'array', which is of size 'size'. + * The resulting string is guaranteed to be null-terminated. + */ + +#define ISC_NETADDR_FORMATSIZE \ + sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:XXX.XXX.XXX.XXX%SSSSSSSSSS") +/*%< + * Minimum size of array to pass to isc_netaddr_format(). + */ + +void +isc_netaddr_fromsockaddr(isc_netaddr_t *netaddr, const isc_sockaddr_t *source); + +void +isc_netaddr_fromin(isc_netaddr_t *netaddr, const struct in_addr *ina); + +void +isc_netaddr_fromin6(isc_netaddr_t *netaddr, const struct in6_addr *ina6); + +isc_result_t +isc_netaddr_frompath(isc_netaddr_t *netaddr, const char *path); + +void +isc_netaddr_setzone(isc_netaddr_t *netaddr, isc_uint32_t zone); + +isc_uint32_t +isc_netaddr_getzone(const isc_netaddr_t *netaddr); + +void +isc_netaddr_any(isc_netaddr_t *netaddr); +/*%< + * Return the IPv4 wildcard address. + */ + +void +isc_netaddr_any6(isc_netaddr_t *netaddr); +/*%< + * Return the IPv6 wildcard address. + */ + +isc_boolean_t +isc_netaddr_ismulticast(isc_netaddr_t *na); +/*%< + * Returns ISC_TRUE if the address is a multicast address. + */ + +isc_boolean_t +isc_netaddr_isexperimental(isc_netaddr_t *na); +/*%< + * Returns ISC_TRUE if the address is a experimental (CLASS E) address. + */ + +isc_boolean_t +isc_netaddr_islinklocal(isc_netaddr_t *na); +/*%< + * Returns #ISC_TRUE if the address is a link local address. + */ + +isc_boolean_t +isc_netaddr_issitelocal(isc_netaddr_t *na); +/*%< + * Returns #ISC_TRUE if the address is a site local address. + */ + +void +isc_netaddr_fromv4mapped(isc_netaddr_t *t, const isc_netaddr_t *s); +/*%< + * Convert an IPv6 v4mapped address into an IPv4 address. + */ + +isc_result_t +isc_netaddr_prefixok(const isc_netaddr_t *na, unsigned int prefixlen); +/* + * Test whether the netaddr 'na' and 'prefixlen' are consistant. + * e.g. prefixlen within range. + * na does not have bits set which are not covered by the prefixlen. + * + * Returns: + * ISC_R_SUCCESS + * ISC_R_RANGE prefixlen out of range + * ISC_R_NOTIMPLEMENTED unsupported family + * ISC_R_FAILURE extra bits. + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_NETADDR_H */ diff --git a/contrib/ntp/lib/isc/include/isc/netscope.h b/contrib/ntp/lib/isc/include/isc/netscope.h new file mode 100644 index 0000000..163a08c --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/netscope.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: netscope.h,v 1.13 2009/06/25 23:48:02 tbox Exp $ */ + +#ifndef ISC_NETSCOPE_H +#define ISC_NETSCOPE_H 1 + +/*! \file isc/netscope.h */ + +ISC_LANG_BEGINDECLS + +/*% + * Convert a string of an IPv6 scope zone to zone index. If the conversion + * succeeds, 'zoneid' will store the index value. + * + * XXXJT: when a standard interface for this purpose is defined, + * we should use it. + * + * Returns: + * \li ISC_R_SUCCESS: conversion succeeds + * \li ISC_R_FAILURE: conversion fails + */ +isc_result_t +isc_netscope_pton(int af, char *scopename, void *addr, isc_uint32_t *zoneid); + +ISC_LANG_ENDDECLS + +#endif /* ISC_NETSCOPE_H */ diff --git a/contrib/ntp/lib/isc/include/isc/ondestroy.h b/contrib/ntp/lib/isc/include/isc/ondestroy.h new file mode 100644 index 0000000..64bd643 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/ondestroy.h @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: ondestroy.h,v 1.14 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_ONDESTROY_H +#define ISC_ONDESTROY_H 1 + +#include <isc/lang.h> +#include <isc/types.h> + +ISC_LANG_BEGINDECLS + +/*! \file isc/ondestroy.h + * ondestroy handling. + * + * Any class ``X'' of objects that wants to send out notifications + * on its destruction should declare a field of type isc_ondestroy_t + * (call it 'ondest'). + * + * \code + * typedef struct { + * ... + * isc_ondestroy_t ondest; + * ... + * } X; + * \endcode + * + * When an object ``A'' of type X is created + * it must initialize the field ondest with a call to + * + * \code + * isc_ondestroy_init(&A->ondest). + * \endcode + * + * X should also provide a registration function for third-party + * objects to call to register their interest in being told about + * the destruction of a particular instance of X. + * + * \code + * isc_result_t + * X_ondestroy(X *instance, isc_task_t *task, + * isc_event_t **eventp) { + * return(isc_ondestroy_register(&instance->ondest, task,eventp)); + * } + * \endcode + * + * Note: locking of the ondestory structure embedded inside of X, is + * X's responsibility. + * + * When an instance of X is destroyed, a call to isc_ondestroy_notify() + * sends the notifications: + * + * \code + * X *instance; + * isc_ondestroy_t ondest = instance->ondest; + * + * ... completely cleanup 'instance' here... + * + * isc_ondestroy_notify(&ondest, instance); + * \endcode + * + * + * see lib/dns/zone.c for an ifdef'd-out example. + */ + +struct isc_ondestroy { + unsigned int magic; + isc_eventlist_t events; +}; + +void +isc_ondestroy_init(isc_ondestroy_t *ondest); +/*%< + * Initialize the on ondest structure. *must* be called before first call + * to isc_ondestroy_register(). + */ + +isc_result_t +isc_ondestroy_register(isc_ondestroy_t *ondest, isc_task_t *task, + isc_event_t **eventp); + +/*%< + * Stores task and *eventp away inside *ondest. Ownership of **event is + * taken from the caller (and *eventp is set to NULL). The task is attached + * to. + */ + +void +isc_ondestroy_notify(isc_ondestroy_t *ondest, void *sender); +/*%< + * Dispatches the event(s) to the task(s) that were given in + * isc_ondestroy_register call(s) (done via calls to + * isc_task_sendanddetach()). Before dispatch, the sender value of each + * event structure is set to the value of the sender paramater. The + * internal structures of the ondest parameter are cleaned out, so no other + * cleanup is needed. + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_ONDESTROY_H */ diff --git a/contrib/ntp/lib/isc/include/isc/os.h b/contrib/ntp/lib/isc/include/isc/os.h new file mode 100644 index 0000000..3cf59e2 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/os.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: os.h,v 1.12 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_OS_H +#define ISC_OS_H 1 + +/*! \file isc/os.h */ + +#include <isc/lang.h> + +ISC_LANG_BEGINDECLS + +unsigned int +isc_os_ncpus(void); +/*%< + * Return the number of CPUs available on the system, or 1 if this cannot + * be determined. + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_OS_H */ diff --git a/contrib/ntp/lib/isc/include/isc/parseint.h b/contrib/ntp/lib/isc/include/isc/parseint.h new file mode 100644 index 0000000..5047676 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/parseint.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001, 2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: parseint.h,v 1.9 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_PARSEINT_H +#define ISC_PARSEINT_H 1 + +#include <isc/lang.h> +#include <isc/types.h> + +/*! \file isc/parseint.h + * \brief Parse integers, in a saner way than atoi() or strtoul() do. + */ + +/*** + *** Functions + ***/ + +ISC_LANG_BEGINDECLS + +isc_result_t +isc_parse_uint32(isc_uint32_t *uip, const char *string, int base); + +isc_result_t +isc_parse_uint16(isc_uint16_t *uip, const char *string, int base); + +isc_result_t +isc_parse_uint8(isc_uint8_t *uip, const char *string, int base); +/*%< + * Parse the null-terminated string 'string' containing a base 'base' + * integer, storing the result in '*uip'. + * The base is interpreted + * as in strtoul(). Unlike strtoul(), leading whitespace, minus or + * plus signs are not accepted, and all errors (including overflow) + * are reported uniformly through the return value. + * + * Requires: + *\li 'string' points to a null-terminated string + *\li 0 <= 'base' <= 36 + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_BADNUMBER The string is not numeric (in the given base) + *\li #ISC_R_RANGE The number is not representable as the requested type. + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_PARSEINT_H */ diff --git a/contrib/ntp/lib/isc/include/isc/platform.h b/contrib/ntp/lib/isc/include/isc/platform.h new file mode 100644 index 0000000..bd11a25 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/platform.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 1999-2001 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. + */ + +/* $Id: platform.h.in,v 1.28 2001/11/19 03:08:26 mayer Exp $ */ + +#ifndef ISC_PLATFORM_H +#define ISC_PLATFORM_H 1 + + +#ifndef ISC_PLATFORM_USEDECLSPEC +#define LIBISC_EXTERNAL_DATA +#define LIBDNS_EXTERNAL_DATA +#define LIBISCCC_EXTERNAL_DATA +#define LIBISCCFG_EXTERNAL_DATA +#define LIBBIND9_EXTERNAL_DATA +#endif /* ISC_PLATFORM_USEDECLSPEC */ + +/* + * Tell emacs to use C mode for this file. + * + * Local Variables: + * mode: c + * End: + */ + +#endif /* ISC_PLATFORM_H */ diff --git a/contrib/ntp/lib/isc/include/isc/platform.h.in b/contrib/ntp/lib/isc/include/isc/platform.h.in new file mode 100644 index 0000000..03c2710 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/platform.h.in @@ -0,0 +1,367 @@ +/* + * Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: platform.h.in,v 1.56 2010/12/18 01:56:23 each Exp $ */ + +#ifndef ISC_PLATFORM_H +#define ISC_PLATFORM_H 1 + +/*! \file */ + +/***** + ***** Platform-dependent defines. + *****/ + +/*** + *** Network. + ***/ + +/*! \brief + * Define if this system needs the <netinet/in6.h> header file included + * for full IPv6 support (pretty much only UnixWare). + */ +@ISC_PLATFORM_NEEDNETINETIN6H@ + +/*! \brief + * Define if this system needs the <netinet6/in6.h> header file included + * to support in6_pkinfo (pretty much only BSD/OS). + */ +@ISC_PLATFORM_NEEDNETINET6IN6H@ + +/*! \brief + * If sockaddrs on this system have an sa_len field, ISC_PLATFORM_HAVESALEN + * will be defined. + */ +@ISC_PLATFORM_HAVESALEN@ + +/*! \brief + * If this system has the IPv6 structure definitions, ISC_PLATFORM_HAVEIPV6 + * will be defined. + */ +@ISC_PLATFORM_HAVEIPV6@ + +/*! \brief + * If this system is missing in6addr_any, ISC_PLATFORM_NEEDIN6ADDRANY will + * be defined. + */ +@ISC_PLATFORM_NEEDIN6ADDRANY@ + +/*! \brief + * If this system is missing in6addr_loopback, ISC_PLATFORM_NEEDIN6ADDRLOOPBACK + * will be defined. + */ +@ISC_PLATFORM_NEEDIN6ADDRLOOPBACK@ + +/*! \brief + * If this system has in6_pktinfo, ISC_PLATFORM_HAVEIN6PKTINFO will be + * defined. + */ +@ISC_PLATFORM_HAVEIN6PKTINFO@ + +/*! \brief + * If this system has in_addr6, rather than in6_addr, ISC_PLATFORM_HAVEINADDR6 + * will be defined. + */ +@ISC_PLATFORM_HAVEINADDR6@ + +/*! \brief + * If this system has sin6_scope_id, ISC_PLATFORM_HAVESCOPEID will be defined. + */ +@ISC_PLATFORM_HAVESCOPEID@ + +/*! \brief + * If this system needs inet_ntop(), ISC_PLATFORM_NEEDNTOP will be defined. + */ +@ISC_PLATFORM_NEEDNTOP@ + +/*! \brief + * If this system needs inet_pton(), ISC_PLATFORM_NEEDPTON will be defined. + */ +@ISC_PLATFORM_NEEDPTON@ + +/*! \brief + * If this system needs in_port_t, ISC_PLATFORM_NEEDPORTT will be defined. + */ +@ISC_PLATFORM_NEEDPORTT@ + +/*! \brief + * Define if the system has struct lifconf which is a extended struct ifconf + * for IPv6. + */ +@ISC_PLATFORM_HAVELIFCONF@ + +/*! \brief + * Define if the system has struct if_laddrconf which is a extended struct + * ifconf for IPv6. + */ +@ISC_PLATFORM_HAVEIF_LADDRCONF@ + +/*! \brief + * Define if the system has struct if_laddrreq. + */ +@ISC_PLATFORM_HAVEIF_LADDRREQ@ + +/*! \brief + * Define either ISC_PLATFORM_BSD44MSGHDR or ISC_PLATFORM_BSD43MSGHDR. + */ +@ISC_PLATFORM_MSGHDRFLAVOR@ + +/*! \brief + * Define if the system supports if_nametoindex. + */ +@ISC_PLATFORM_HAVEIFNAMETOINDEX@ + +/*! \brief + * Define on some UnixWare systems to fix erroneous definitions of various + * IN6_IS_ADDR_* macros. + */ +@ISC_PLATFORM_FIXIN6ISADDR@ + +/*! \brief + * Define if the system supports kqueue multiplexing + */ +@ISC_PLATFORM_HAVEKQUEUE@ + +/*! \brief + * Define if the system supports epoll multiplexing + */ +@ISC_PLATFORM_HAVEEPOLL@ + +/*! \brief + * Define if the system supports /dev/poll multiplexing + */ +@ISC_PLATFORM_HAVEDEVPOLL@ + +/*! \brief + * Define if we want to log backtrace + */ +@ISC_PLATFORM_USEBACKTRACE@ + +/* + *** Printing. + ***/ + +/*! \brief + * If this system needs vsnprintf() and snprintf(), ISC_PLATFORM_NEEDVSNPRINTF + * will be defined. + */ +@ISC_PLATFORM_NEEDVSNPRINTF@ + +/*! \brief + * If this system need a modern sprintf() that returns (int) not (char*). + */ +@ISC_PLATFORM_NEEDSPRINTF@ + +/*! \brief + * The printf format string modifier to use with isc_uint64_t values. + */ +@ISC_PLATFORM_QUADFORMAT@ + +/*** + *** String functions. + ***/ +/* + * If the system needs strsep(), ISC_PLATFORM_NEEDSTRSEP will be defined. + */ +@ISC_PLATFORM_NEEDSTRSEP@ + +/* + * If the system needs strlcpy(), ISC_PLATFORM_NEEDSTRLCPY will be defined. + */ +@ISC_PLATFORM_NEEDSTRLCPY@ + +/* + * If the system needs strlcat(), ISC_PLATFORM_NEEDSTRLCAT will be defined. + */ +@ISC_PLATFORM_NEEDSTRLCAT@ + +/* + * Define if this system needs strtoul. + */ +@ISC_PLATFORM_NEEDSTRTOUL@ + +/* + * Define if this system needs memmove. + */ +@ISC_PLATFORM_NEEDMEMMOVE@ + +/*** + *** Miscellaneous. + ***/ + +/* + * Defined if we are using threads. + */ +@ISC_PLATFORM_USETHREADS@ + +/* + * Defined if unistd.h does not cause fd_set to be delared. + */ +@ISC_PLATFORM_NEEDSYSSELECTH@ + +/* + * Defined to <gssapi.h> or <gssapi/gssapi.h> for how to include + * the GSSAPI header. + */ +@ISC_PLATFORM_GSSAPIHEADER@ + +/* + * Defined to <gssapi_krb5.h> or <gssapi/gssapi_krb5.h> for how to + * include the GSSAPI KRB5 header. + */ +@ISC_PLATFORM_GSSAPI_KRB5_HEADER@ + +/* + * Defined to <krb5.h> or <krb5/krb5.h> for how to include + * the KRB5 header. + */ +@ISC_PLATFORM_KRB5HEADER@ + +/* + * Type used for resource limits. + */ +@ISC_PLATFORM_RLIMITTYPE@ + +/* + * Define if your compiler supports "long long int". + */ +@ISC_PLATFORM_HAVELONGLONG@ + +/* + * Define if PTHREAD_ONCE_INIT should be surrounded by braces to + * prevent compiler warnings (such as with gcc on Solaris 2.8). + */ +@ISC_PLATFORM_BRACEPTHREADONCEINIT@ + +/* + * Used to control how extern data is linked; needed for Win32 platforms. + */ +@ISC_PLATFORM_USEDECLSPEC@ + +/* + * Define if the platform has <sys/un.h>. + */ +@ISC_PLATFORM_HAVESYSUNH@ + +/* + * If the "xadd" operation is available on this architecture, + * ISC_PLATFORM_HAVEXADD will be defined. + */ +@ISC_PLATFORM_HAVEXADD@ + +/* + * If the "xaddq" operation (64bit xadd) is available on this architecture, + * ISC_PLATFORM_HAVEXADDQ will be defined. + */ +@ISC_PLATFORM_HAVEXADDQ@ + +/* + * If the "atomic swap" operation is available on this architecture, + * ISC_PLATFORM_HAVEATOMICSTORE" will be defined. + */ +@ISC_PLATFORM_HAVEATOMICSTORE@ + +/* + * If the "compare-and-exchange" operation is available on this architecture, + * ISC_PLATFORM_HAVECMPXCHG will be defined. + */ +@ISC_PLATFORM_HAVECMPXCHG@ + +/* + * Define if gcc ASM extension is available + */ +@ISC_PLATFORM_USEGCCASM@ + +/* + * Define if Tru64 style ASM syntax must be used. + */ +@ISC_PLATFORM_USEOSFASM@ + +/* + * Define if the standard __asm function must be used. + */ +@ISC_PLATFORM_USESTDASM@ + +/* + * Define if the platform has <strings.h>. + */ +@ISC_PLATFORM_HAVESTRINGSH@ + +/* + * Define if the hash functions must be provided by OpenSSL. + */ +@ISC_PLATFORM_OPENSSLHASH@ + +/* + * Defines for the noreturn attribute. + */ +@ISC_PLATFORM_NORETURN_PRE@ +@ISC_PLATFORM_NORETURN_POST@ + +/*** + *** Windows dll support. + ***/ + +/* + * Define if MacOS style of PPC assembly must be used. + * e.g. "r6", not "6", for register six. + */ +@ISC_PLATFORM_USEMACASM@ + +#ifndef ISC_PLATFORM_USEDECLSPEC +#define LIBISC_EXTERNAL_DATA +#define LIBDNS_EXTERNAL_DATA +#define LIBISCCC_EXTERNAL_DATA +#define LIBISCCFG_EXTERNAL_DATA +#define LIBBIND9_EXTERNAL_DATA +#else /*! \brief ISC_PLATFORM_USEDECLSPEC */ +#ifdef LIBISC_EXPORTS +#define LIBISC_EXTERNAL_DATA __declspec(dllexport) +#else +#define LIBISC_EXTERNAL_DATA __declspec(dllimport) +#endif +#ifdef LIBDNS_EXPORTS +#define LIBDNS_EXTERNAL_DATA __declspec(dllexport) +#else +#define LIBDNS_EXTERNAL_DATA __declspec(dllimport) +#endif +#ifdef LIBISCCC_EXPORTS +#define LIBISCCC_EXTERNAL_DATA __declspec(dllexport) +#else +#define LIBISCCC_EXTERNAL_DATA __declspec(dllimport) +#endif +#ifdef LIBISCCFG_EXPORTS +#define LIBISCCFG_EXTERNAL_DATA __declspec(dllexport) +#else +#define LIBISCCFG_EXTERNAL_DATA __declspec(dllimport) +#endif +#ifdef LIBBIND9_EXPORTS +#define LIBBIND9_EXTERNAL_DATA __declspec(dllexport) +#else +#define LIBBIND9_EXTERNAL_DATA __declspec(dllimport) +#endif +#endif /*! \brief ISC_PLATFORM_USEDECLSPEC */ + +/* + * Tell emacs to use C mode for this file. + * + * Local Variables: + * mode: c + * End: + */ + +#endif /* ISC_PLATFORM_H */ diff --git a/contrib/ntp/lib/isc/include/isc/portset.h b/contrib/ntp/lib/isc/include/isc/portset.h new file mode 100644 index 0000000..774d6bb --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/portset.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2008, 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: portset.h,v 1.6 2009/06/25 05:28:34 marka Exp $ */ + +/*! \file isc/portset.h + * \brief Transport Protocol Port Manipulation Module + * + * This module provides simple utilities to handle a set of transport protocol + * (UDP or TCP) port numbers, e.g., for creating an ACL list. An isc_portset_t + * object is an opaque instance of a port set, for which the user can add or + * remove a specific port or a range of consecutive ports. This object is + * expected to be used as a temporary work space only, and does not protect + * simultaneous access from multiple threads. Therefore it must not be stored + * in a place that can be accessed from multiple threads. + */ + +#ifndef ISC_PORTSET_H +#define ISC_PORTSET_H 1 + +/*** + *** Imports + ***/ + +#include <isc/net.h> + +/*** + *** Functions + ***/ + +ISC_LANG_BEGINDECLS + +isc_result_t +isc_portset_create(isc_mem_t *mctx, isc_portset_t **portsetp); +/*%< + * Create a port set and initialize it as an empty set. + * + * Requires: + *\li 'mctx' to be valid. + *\li 'portsetp' to be non NULL and '*portsetp' to be NULL; + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + */ + +void +isc_portset_destroy(isc_mem_t *mctx, isc_portset_t **portsetp); +/*%< + * Destroy a port set. + * + * Requires: + *\li 'mctx' to be valid and must be the same context given when the port set + * was created. + *\li '*portsetp' to be a valid set. + */ + +isc_boolean_t +isc_portset_isset(isc_portset_t *portset, in_port_t port); +/*%< + * Test whether the given port is stored in the portset. + * + * Requires: + *\li 'portset' to be a valid set. + * + * Returns + * \li #ISC_TRUE if the port is found, ISC_FALSE otherwise. + */ + +unsigned int +isc_portset_nports(isc_portset_t *portset); +/*%< + * Provides the number of ports stored in the given portset. + * + * Requires: + *\li 'portset' to be a valid set. + * + * Returns + * \li the number of ports stored in portset. + */ + +void +isc_portset_add(isc_portset_t *portset, in_port_t port); +/*%< + * Add the given port to the portset. The port may or may not be stored in + * the portset. + * + * Requires: + *\li 'portlist' to be valid. + */ + +void +isc_portset_remove(isc_portset_t *portset, in_port_t port); +/*%< + * Remove the given port to the portset. The port may or may not be stored in + * the portset. + * + * Requires: + *\li 'portlist' to be valid. + */ + +void +isc_portset_addrange(isc_portset_t *portset, in_port_t port_lo, + in_port_t port_hi); +/*%< + * Add a subset of [port_lo, port_hi] (inclusive) to the portset. Ports in the + * subset may or may not be stored in portset. + * + * Requires: + *\li 'portlist' to be valid. + *\li port_lo <= port_hi + */ + +void +isc_portset_removerange(isc_portset_t *portset, in_port_t port_lo, + in_port_t port_hi); +/*%< + * Subtract a subset of [port_lo, port_hi] (inclusive) from the portset. Ports + * in the subset may or may not be stored in portset. + * + * Requires: + *\li 'portlist' to be valid. + *\li port_lo <= port_hi + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_PORTSET_H */ diff --git a/contrib/ntp/lib/isc/include/isc/print.h b/contrib/ntp/lib/isc/include/isc/print.h new file mode 100644 index 0000000..cd1e38e --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/print.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001, 2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: print.h,v 1.26 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_PRINT_H +#define ISC_PRINT_H 1 + +/*! \file isc/print.h */ + +/*** + *** Imports + ***/ + +#include <isc/formatcheck.h> /* Required for ISC_FORMAT_PRINTF() macro. */ +#include <isc/lang.h> +#include <isc/platform.h> + +/*! + * This block allows lib/isc/print.c to be cleanly compiled even if + * the platform does not need it. The standard Makefile will still + * not compile print.c or archive print.o, so this is just to make test + * compilation ("make print.o") easier. + */ +#if !defined(ISC_PLATFORM_NEEDVSNPRINTF) && defined(ISC__PRINT_SOURCE) +#define ISC_PLATFORM_NEEDVSNPRINTF +#endif + +#if !defined(ISC_PLATFORM_NEEDSPRINTF) && defined(ISC__PRINT_SOURCE) +#define ISC_PLATFORM_NEEDSPRINTF +#endif + +/*** + *** Macros + ***/ +#define ISC_PRINT_QUADFORMAT ISC_PLATFORM_QUADFORMAT + +/*** + *** Functions + ***/ + +#ifdef ISC_PLATFORM_NEEDVSNPRINTF +#include <stdarg.h> +#include <stddef.h> +#endif +#ifdef ISC_PLATFORM_NEEDSPRINTF +#include <stdio.h> +#endif + + +ISC_LANG_BEGINDECLS + +#ifdef ISC_PLATFORM_NEEDVSNPRINTF +int +isc_print_vsnprintf(char *str, size_t size, const char *format, va_list ap) + ISC_FORMAT_PRINTF(3, 0); +#define vsnprintf isc_print_vsnprintf + +int +isc_print_snprintf(char *str, size_t size, const char *format, ...) + ISC_FORMAT_PRINTF(3, 4); +#define snprintf isc_print_snprintf +#endif /* ISC_PLATFORM_NEEDVSNPRINTF */ + +#ifdef ISC_PLATFORM_NEEDSPRINTF +int +isc_print_sprintf(char *str, const char *format, ...) ISC_FORMAT_PRINTF(2, 3); +#define sprintf isc_print_sprintf +#endif + +ISC_LANG_ENDDECLS + +#endif /* ISC_PRINT_H */ diff --git a/contrib/ntp/lib/isc/include/isc/queue.h b/contrib/ntp/lib/isc/include/isc/queue.h new file mode 100644 index 0000000..5bf84c5 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/queue.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/* + * This is a generic implementation of a two-lock concurrent queue. + * There are built-in mutex locks for the head and tail of the queue, + * allowing elements to be safely added and removed at the same time. + */ + +#ifndef ISC_QUEUE_H +#define ISC_QUEUE_H 1 +#include <isc/assertions.h> +#include <isc/boolean.h> +#include <isc/mutex.h> + +#ifdef ISC_QUEUE_CHECKINIT +#define ISC_QLINK_INSIST(x) ISC_INSIST(x) +#else +#define ISC_QLINK_INSIST(x) (void)0 +#endif + +#define ISC_QLINK(type) struct { void *next; isc_boolean_t linked; } +#define ISC_QLINK_INIT(elt, link) \ + do { \ + (elt)->link.next = (void *)(-1); \ + (elt)->link.linked = ISC_FALSE; \ + } while (0) +#define ISC_QLINK_LINKED(elt, link) ((elt)->link.linked) + +#define ISC_QUEUE(type) struct { \ + type headnode; \ + type *head, *tail; \ + isc_mutex_t headlock, taillock; \ +} + +#define ISC_QUEUE_INIT(queue, link) \ + do { \ + isc_mutex_init(&(queue).headlock); \ + isc_mutex_init(&(queue).taillock); \ + (queue).head = (void *) &((queue).headnode); \ + (queue).tail = (void *) &((queue).headnode); \ + ISC_QLINK_INIT((queue).head, link); \ + } while (0) + +#define ISC_QUEUE_EMPTY(queue) ISC_TF((queue).head == (queue).tail) + +#define ISC_QUEUE_DESTROY(queue) \ + do { \ + ISC_QLINK_INSIST(ISC_QUEUE_EMPTY(queue)); \ + isc_mutex_destroy(&(queue).headlock); \ + isc_mutex_destroy(&(queue).taillock); \ + } while (0) + +#define ISC_QUEUE_PUSH(queue, elt, link) \ + do { \ + ISC_QLINK_INSIST(!ISC_QLINK_LINKED(elt, link)); \ + (elt)->link.next = (void *)(-1); \ + LOCK(&(queue).taillock); \ + (queue).tail->link.next = elt; \ + (queue).tail = elt; \ + UNLOCK(&(queue).taillock); \ + (elt)->link.linked = ISC_TRUE; \ + } while (0) + +#define ISC_QUEUE_POP(queue, link, ret) \ + do { \ + LOCK(&(queue).headlock); \ + ret = (queue).head->link.next; \ + if (ret == (void *)(-1)) { \ + UNLOCK(&(queue).headlock); \ + ret = NULL; \ + } else { \ + (queue).head->link.next = ret->link.next; \ + if (ret->link.next == (void *)(-1)) { \ + LOCK(&(queue).taillock); \ + (queue).tail = (queue).head; \ + UNLOCK(&(queue).taillock); \ + } \ + UNLOCK(&(queue).headlock); \ + ret->link.next = (void *)(-1); \ + ret->link.linked = ISC_FALSE; \ + } \ + } while (0) + +#endif /* ISC_QUEUE_H */ diff --git a/contrib/ntp/lib/isc/include/isc/quota.h b/contrib/ntp/lib/isc/include/isc/quota.h new file mode 100644 index 0000000..7b0d0d9 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/quota.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: quota.h,v 1.16 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_QUOTA_H +#define ISC_QUOTA_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file isc/quota.h + * + * \brief The isc_quota_t object is a simple helper object for implementing + * quotas on things like the number of simultaneous connections to + * a server. It keeps track of the amount of quota in use, and + * encapsulates the locking necessary to allow multiple tasks to + * share a quota. + */ + +/*** + *** Imports. + ***/ + +#include <isc/lang.h> +#include <isc/mutex.h> +#include <isc/types.h> + +/***** + ***** Types. + *****/ + +ISC_LANG_BEGINDECLS + +/*% isc_quota structure */ +struct isc_quota { + isc_mutex_t lock; /*%< Locked by lock. */ + int max; + int used; + int soft; +}; + +isc_result_t +isc_quota_init(isc_quota_t *quota, int max); +/*%< + * Initialize a quota object. + * + * Returns: + * ISC_R_SUCCESS + * Other error Lock creation failed. + */ + +void +isc_quota_destroy(isc_quota_t *quota); +/*%< + * Destroy a quota object. + */ + +void +isc_quota_soft(isc_quota_t *quota, int soft); +/*%< + * Set a soft quota. + */ + +void +isc_quota_max(isc_quota_t *quota, int max); +/*%< + * Re-set a maximum quota. + */ + +isc_result_t +isc_quota_reserve(isc_quota_t *quota); +/*%< + * Attempt to reserve one unit of 'quota'. + * + * Returns: + * \li #ISC_R_SUCCESS Success + * \li #ISC_R_SOFTQUOTA Success soft quota reached + * \li #ISC_R_QUOTA Quota is full + */ + +void +isc_quota_release(isc_quota_t *quota); +/*%< + * Release one unit of quota. + */ + +isc_result_t +isc_quota_attach(isc_quota_t *quota, isc_quota_t **p); +/*%< + * Like isc_quota_reserve, and also attaches '*p' to the + * quota if successful (ISC_R_SUCCESS or ISC_R_SOFTQUOTA). + */ + +void +isc_quota_detach(isc_quota_t **p); +/*%< + * Like isc_quota_release, and also detaches '*p' from the + * quota. + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_QUOTA_H */ diff --git a/contrib/ntp/lib/isc/include/isc/radix.h b/contrib/ntp/lib/isc/include/isc/radix.h new file mode 100644 index 0000000..6b413a2 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/radix.h @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2007, 2008 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: radix.h,v 1.13 2008/12/01 23:47:45 tbox Exp $ */ + +/* + * This source was adapted from MRT's RCS Ids: + * Id: radix.h,v 1.6 1999/08/03 03:32:53 masaki Exp + * Id: mrt.h,v 1.57.2.6 1999/12/28 23:41:27 labovit Exp + * Id: defs.h,v 1.5.2.2 2000/01/15 14:19:16 masaki Exp + */ + +#include <isc/magic.h> +#include <isc/types.h> +#include <isc/mutex.h> +#include <isc/net.h> +#include <isc/refcount.h> + +#include <string.h> + +#ifndef _RADIX_H +#define _RADIX_H + +#define NETADDR_TO_PREFIX_T(na,pt,bits) \ + do { \ + memset(&(pt), 0, sizeof(pt)); \ + if((na) != NULL) { \ + (pt).family = (na)->family; \ + (pt).bitlen = (bits); \ + if ((pt).family == AF_INET6) { \ + memcpy(&(pt).add.sin6, &(na)->type.in6, \ + ((bits)+7)/8); \ + } else \ + memcpy(&(pt).add.sin, &(na)->type.in, \ + ((bits)+7)/8); \ + } else { \ + (pt).family = AF_UNSPEC; \ + (pt).bitlen = 0; \ + } \ + isc_refcount_init(&(pt).refcount, 0); \ + } while(0) + +typedef struct isc_prefix { + unsigned int family; /* AF_INET | AF_INET6, or AF_UNSPEC for "any" */ + unsigned int bitlen; /* 0 for "any" */ + isc_refcount_t refcount; + union { + struct in_addr sin; + struct in6_addr sin6; + } add; +} isc_prefix_t; + +typedef void (*isc_radix_destroyfunc_t)(void *); +typedef void (*isc_radix_processfunc_t)(isc_prefix_t *, void **); + +#define isc_prefix_tochar(prefix) ((char *)&(prefix)->add.sin) +#define isc_prefix_touchar(prefix) ((u_char *)&(prefix)->add.sin) + +#define BIT_TEST(f, b) ((f) & (b)) + +/* + * We need "first match" when we search the radix tree to preserve + * compatibility with the existing ACL implementation. Radix trees + * naturally lend themselves to "best match". In order to get "first match" + * behavior, we keep track of the order in which entries are added to the + * tree--and when a search is made, we find all matching entries, and + * return the one that was added first. + * + * An IPv4 prefix and an IPv6 prefix may share a radix tree node if they + * have the same length and bit pattern (e.g., 127/8 and 7f::/8). To + * disambiguate between them, node_num and data are two-element arrays; + * node_num[0] and data[0] are used for IPv4 addresses, node_num[1] + * and data[1] for IPv6 addresses. The only exception is a prefix of + * 0/0 (aka "any" or "none"), which is always stored as IPv4 but matches + * IPv6 addresses too. + */ + +#define ISC_IS6(family) ((family) == AF_INET6 ? 1 : 0) +typedef struct isc_radix_node { + isc_uint32_t bit; /* bit length of the prefix */ + isc_prefix_t *prefix; /* who we are in radix tree */ + struct isc_radix_node *l, *r; /* left and right children */ + struct isc_radix_node *parent; /* may be used */ + void *data[2]; /* pointers to IPv4 and IPV6 data */ + int node_num[2]; /* which node this was in the tree, + or -1 for glue nodes */ +} isc_radix_node_t; + +#define RADIX_TREE_MAGIC ISC_MAGIC('R','d','x','T'); +#define RADIX_TREE_VALID(a) ISC_MAGIC_VALID(a, RADIX_TREE_MAGIC); + +typedef struct isc_radix_tree { + unsigned int magic; + isc_mem_t *mctx; + isc_radix_node_t *head; + isc_uint32_t maxbits; /* for IP, 32 bit addresses */ + int num_active_node; /* for debugging purposes */ + int num_added_node; /* total number of nodes */ +} isc_radix_tree_t; + +isc_result_t +isc_radix_search(isc_radix_tree_t *radix, isc_radix_node_t **target, + isc_prefix_t *prefix); +/*%< + * Search 'radix' for the best match to 'prefix'. + * Return the node found in '*target'. + * + * Requires: + * \li 'radix' to be valid. + * \li 'target' is not NULL and "*target" is NULL. + * \li 'prefix' to be valid. + * + * Returns: + * \li ISC_R_NOTFOUND + * \li ISC_R_SUCCESS + */ + +isc_result_t +isc_radix_insert(isc_radix_tree_t *radix, isc_radix_node_t **target, + isc_radix_node_t *source, isc_prefix_t *prefix); +/*%< + * Insert 'source' or 'prefix' into the radix tree 'radix'. + * Return the node added in 'target'. + * + * Requires: + * \li 'radix' to be valid. + * \li 'target' is not NULL and "*target" is NULL. + * \li 'prefix' to be valid or 'source' to be non NULL and contain + * a valid prefix. + * + * Returns: + * \li ISC_R_NOMEMORY + * \li ISC_R_SUCCESS + */ + +void +isc_radix_remove(isc_radix_tree_t *radix, isc_radix_node_t *node); +/*%< + * Remove the node 'node' from the radix tree 'radix'. + * + * Requires: + * \li 'radix' to be valid. + * \li 'node' to be valid. + */ + +isc_result_t +isc_radix_create(isc_mem_t *mctx, isc_radix_tree_t **target, int maxbits); +/*%< + * Create a radix tree with a maximum depth of 'maxbits'; + * + * Requires: + * \li 'mctx' to be valid. + * \li 'target' to be non NULL and '*target' to be NULL. + * \li 'maxbits' to be less than or equal to RADIX_MAXBITS. + * + * Returns: + * \li ISC_R_NOMEMORY + * \li ISC_R_SUCCESS + */ + +void +isc_radix_destroy(isc_radix_tree_t *radix, isc_radix_destroyfunc_t func); +/*%< + * Destroy a radix tree optionally calling 'func' to clean up node data. + * + * Requires: + * \li 'radix' to be valid. + */ + +void +isc_radix_process(isc_radix_tree_t *radix, isc_radix_processfunc_t func); +/*%< + * Walk a radix tree calling 'func' to process node data. + * + * Requires: + * \li 'radix' to be valid. + * \li 'func' to point to a function. + */ + +#define RADIX_MAXBITS 128 +#define RADIX_NBIT(x) (0x80 >> ((x) & 0x7f)) +#define RADIX_NBYTE(x) ((x) >> 3) + +#define RADIX_DATA_GET(node, type) (type *)((node)->data) +#define RADIX_DATA_SET(node, value) ((node)->data = (void *)(value)) + +#define RADIX_WALK(Xhead, Xnode) \ + do { \ + isc_radix_node_t *Xstack[RADIX_MAXBITS+1]; \ + isc_radix_node_t **Xsp = Xstack; \ + isc_radix_node_t *Xrn = (Xhead); \ + while ((Xnode = Xrn)) { \ + if (Xnode->prefix) + +#define RADIX_WALK_ALL(Xhead, Xnode) \ +do { \ + isc_radix_node_t *Xstack[RADIX_MAXBITS+1]; \ + isc_radix_node_t **Xsp = Xstack; \ + isc_radix_node_t *Xrn = (Xhead); \ + while ((Xnode = Xrn)) { \ + if (1) + +#define RADIX_WALK_BREAK { \ + if (Xsp != Xstack) { \ + Xrn = *(--Xsp); \ + } else { \ + Xrn = (radix_node_t *) 0; \ + } \ + continue; } + +#define RADIX_WALK_END \ + if (Xrn->l) { \ + if (Xrn->r) { \ + *Xsp++ = Xrn->r; \ + } \ + Xrn = Xrn->l; \ + } else if (Xrn->r) { \ + Xrn = Xrn->r; \ + } else if (Xsp != Xstack) { \ + Xrn = *(--Xsp); \ + } else { \ + Xrn = (isc_radix_node_t *) 0; \ + } \ + } \ + } while (0) + +#endif /* _RADIX_H */ diff --git a/contrib/ntp/lib/isc/include/isc/random.h b/contrib/ntp/lib/isc/include/isc/random.h new file mode 100644 index 0000000..1f9572d --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/random.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: random.h,v 1.20 2009/01/17 23:47:43 tbox Exp $ */ + +#ifndef ISC_RANDOM_H +#define ISC_RANDOM_H 1 + +#include <isc/lang.h> +#include <isc/types.h> + +/*! \file isc/random.h + * \brief Implements a random state pool which will let the caller return a + * series of possibly non-reproducible random values. + * + * Note that the + * strength of these numbers is not all that high, and should not be + * used in cryptography functions. It is useful for jittering values + * a bit here and there, such as timeouts, etc. + */ + +ISC_LANG_BEGINDECLS + +void +isc_random_seed(isc_uint32_t seed); +/*%< + * Set the initial seed of the random state. + */ + +void +isc_random_get(isc_uint32_t *val); +/*%< + * Get a random value. + * + * Requires: + * val != NULL. + */ + +isc_uint32_t +isc_random_jitter(isc_uint32_t max, isc_uint32_t jitter); +/*%< + * Get a random value between (max - jitter) and (max). + * This is useful for jittering timer values. + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_RANDOM_H */ diff --git a/contrib/ntp/lib/isc/include/isc/ratelimiter.h b/contrib/ntp/lib/isc/include/isc/ratelimiter.h new file mode 100644 index 0000000..00a7209 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/ratelimiter.h @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: ratelimiter.h,v 1.23 2009/01/18 23:48:14 tbox Exp $ */ + +#ifndef ISC_RATELIMITER_H +#define ISC_RATELIMITER_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file isc/ratelimiter.h + * \brief A rate limiter is a mechanism for dispatching events at a limited + * rate. This is intended to be used when sending zone maintenance + * SOA queries, NOTIFY messages, etc. + */ + +/*** + *** Imports. + ***/ + +#include <isc/lang.h> +#include <isc/types.h> + +ISC_LANG_BEGINDECLS + +/***** + ***** Functions. + *****/ + +isc_result_t +isc_ratelimiter_create(isc_mem_t *mctx, isc_timermgr_t *timermgr, + isc_task_t *task, isc_ratelimiter_t **ratelimiterp); +/*%< + * Create a rate limiter. The execution interval is initially undefined. + */ + +isc_result_t +isc_ratelimiter_setinterval(isc_ratelimiter_t *rl, isc_interval_t *interval); +/*!< + * Set the minimum interval between event executions. + * The interval value is copied, so the caller need not preserve it. + * + * Requires: + * '*interval' is a nonzero interval. + */ + +void +isc_ratelimiter_setpertic(isc_ratelimiter_t *rl, isc_uint32_t perint); +/*%< + * Set the number of events processed per interval timer tick. + * If 'perint' is zero it is treated as 1. + */ + +isc_result_t +isc_ratelimiter_enqueue(isc_ratelimiter_t *rl, isc_task_t *task, + isc_event_t **eventp); +/*%< + * Queue an event for rate-limited execution. + * + * This is similar + * to doing an isc_task_send() to the 'task', except that the + * execution may be delayed to achieve the desired rate of + * execution. + * + * '(*eventp)->ev_sender' is used to hold the task. The caller + * must ensure that the task exists until the event is delivered. + * + * Requires: + *\li An interval has been set by calling + * isc_ratelimiter_setinterval(). + * + *\li 'task' to be non NULL. + *\li '(*eventp)->ev_sender' to be NULL. + */ + +void +isc_ratelimiter_shutdown(isc_ratelimiter_t *ratelimiter); +/*%< + * Shut down a rate limiter. + * + * Ensures: + *\li All events that have not yet been + * dispatched to the task are dispatched immediately with + * the #ISC_EVENTATTR_CANCELED bit set in ev_attributes. + * + *\li Further attempts to enqueue events will fail with + * #ISC_R_SHUTTINGDOWN. + * + *\li The rate limiter is no longer attached to its task. + */ + +void +isc_ratelimiter_attach(isc_ratelimiter_t *source, isc_ratelimiter_t **target); +/*%< + * Attach to a rate limiter. + */ + +void +isc_ratelimiter_detach(isc_ratelimiter_t **ratelimiterp); +/*%< + * Detach from a rate limiter. + */ + +isc_result_t +isc_ratelimiter_stall(isc_ratelimiter_t *rl); +/*%< + * Stall event processing. + */ + +isc_result_t +isc_ratelimiter_release(isc_ratelimiter_t *rl); +/*%< + * Release a stalled rate limiter. + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_RATELIMITER_H */ diff --git a/contrib/ntp/lib/isc/include/isc/refcount.h b/contrib/ntp/lib/isc/include/isc/refcount.h new file mode 100644 index 0000000..b72b158 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/refcount.h @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001, 2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: refcount.h,v 1.17 2009/09/29 23:48:04 tbox Exp $ */ + +#ifndef ISC_REFCOUNT_H +#define ISC_REFCOUNT_H 1 + +#include <isc/atomic.h> +#include <isc/lang.h> +#include <isc/mutex.h> +#include <isc/platform.h> +#include <isc/types.h> +#include <isc/util.h> + +/*! \file isc/refcount.h + * \brief Implements a locked reference counter. + * + * These functions may actually be + * implemented using macros, and implementations of these macros are below. + * The isc_refcount_t type should not be accessed directly, as its contents + * depend on the implementation. + */ + +ISC_LANG_BEGINDECLS + +/* + * Function prototypes + */ + +/* + * isc_result_t + * isc_refcount_init(isc_refcount_t *ref, unsigned int n); + * + * Initialize the reference counter. There will be 'n' initial references. + * + * Requires: + * ref != NULL + */ + +/* + * void + * isc_refcount_destroy(isc_refcount_t *ref); + * + * Destroys a reference counter. + * + * Requires: + * ref != NULL + * The number of references is 0. + */ + +/* + * void + * isc_refcount_increment(isc_refcount_t *ref, unsigned int *targetp); + * isc_refcount_increment0(isc_refcount_t *ref, unsigned int *targetp); + * + * Increments the reference count, returning the new value in targetp if it's + * not NULL. The reference counter typically begins with the initial counter + * of 1, and will be destroyed once the counter reaches 0. Thus, + * isc_refcount_increment() additionally requires the previous counter be + * larger than 0 so that an error which violates the usage can be easily + * caught. isc_refcount_increment0() does not have this restriction. + * + * Requires: + * ref != NULL. + */ + +/* + * void + * isc_refcount_decrement(isc_refcount_t *ref, unsigned int *targetp); + * + * Decrements the reference count, returning the new value in targetp if it's + * not NULL. + * + * Requires: + * ref != NULL. + */ + + +/* + * Sample implementations + */ +#ifdef ISC_PLATFORM_USETHREADS +#ifdef ISC_PLATFORM_HAVEXADD + +#define ISC_REFCOUNT_HAVEATOMIC 1 + +typedef struct isc_refcount { + isc_int32_t refs; +} isc_refcount_t; + +#define isc_refcount_destroy(rp) REQUIRE((rp)->refs == 0) +#define isc_refcount_current(rp) ((unsigned int)((rp)->refs)) + +#define isc_refcount_increment0(rp, tp) \ + do { \ + unsigned int *_tmp = (unsigned int *)(tp); \ + isc_int32_t prev; \ + prev = isc_atomic_xadd(&(rp)->refs, 1); \ + if (_tmp != NULL) \ + *_tmp = prev + 1; \ + } while (0) + +#define isc_refcount_increment(rp, tp) \ + do { \ + unsigned int *_tmp = (unsigned int *)(tp); \ + isc_int32_t prev; \ + prev = isc_atomic_xadd(&(rp)->refs, 1); \ + REQUIRE(prev > 0); \ + if (_tmp != NULL) \ + *_tmp = prev + 1; \ + } while (0) + +#define isc_refcount_decrement(rp, tp) \ + do { \ + unsigned int *_tmp = (unsigned int *)(tp); \ + isc_int32_t prev; \ + prev = isc_atomic_xadd(&(rp)->refs, -1); \ + REQUIRE(prev > 0); \ + if (_tmp != NULL) \ + *_tmp = prev - 1; \ + } while (0) + +#else /* ISC_PLATFORM_HAVEXADD */ + +typedef struct isc_refcount { + int refs; + isc_mutex_t lock; +} isc_refcount_t; + +/*% Destroys a reference counter. */ +#define isc_refcount_destroy(rp) \ + do { \ + REQUIRE((rp)->refs == 0); \ + DESTROYLOCK(&(rp)->lock); \ + } while (0) + +#define isc_refcount_current(rp) ((unsigned int)((rp)->refs)) + +/*% Increments the reference count, returning the new value in targetp if it's not NULL. */ +#define isc_refcount_increment0(rp, tp) \ + do { \ + unsigned int *_tmp = (unsigned int *)(tp); \ + LOCK(&(rp)->lock); \ + ++((rp)->refs); \ + if (_tmp != NULL) \ + *_tmp = ((rp)->refs); \ + UNLOCK(&(rp)->lock); \ + } while (0) + +#define isc_refcount_increment(rp, tp) \ + do { \ + unsigned int *_tmp = (unsigned int *)(tp); \ + LOCK(&(rp)->lock); \ + REQUIRE((rp)->refs > 0); \ + ++((rp)->refs); \ + if (_tmp != NULL) \ + *_tmp = ((rp)->refs); \ + UNLOCK(&(rp)->lock); \ + } while (0) + +/*% Decrements the reference count, returning the new value in targetp if it's not NULL. */ +#define isc_refcount_decrement(rp, tp) \ + do { \ + unsigned int *_tmp = (unsigned int *)(tp); \ + LOCK(&(rp)->lock); \ + REQUIRE((rp)->refs > 0); \ + --((rp)->refs); \ + if (_tmp != NULL) \ + *_tmp = ((rp)->refs); \ + UNLOCK(&(rp)->lock); \ + } while (0) + +#endif /* ISC_PLATFORM_HAVEXADD */ +#else /* ISC_PLATFORM_USETHREADS */ + +typedef struct isc_refcount { + int refs; +} isc_refcount_t; + +#define isc_refcount_destroy(rp) REQUIRE((rp)->refs == 0) +#define isc_refcount_current(rp) ((unsigned int)((rp)->refs)) + +#define isc_refcount_increment0(rp, tp) \ + do { \ + unsigned int *_tmp = (unsigned int *)(tp); \ + int _n = ++(rp)->refs; \ + if (_tmp != NULL) \ + *_tmp = _n; \ + } while (0) + +#define isc_refcount_increment(rp, tp) \ + do { \ + unsigned int *_tmp = (unsigned int *)(tp); \ + int _n; \ + REQUIRE((rp)->refs > 0); \ + _n = ++(rp)->refs; \ + if (_tmp != NULL) \ + *_tmp = _n; \ + } while (0) + +#define isc_refcount_decrement(rp, tp) \ + do { \ + unsigned int *_tmp = (unsigned int *)(tp); \ + int _n; \ + REQUIRE((rp)->refs > 0); \ + _n = --(rp)->refs; \ + if (_tmp != NULL) \ + *_tmp = _n; \ + } while (0) + +#endif /* ISC_PLATFORM_USETHREADS */ + +isc_result_t +isc_refcount_init(isc_refcount_t *ref, unsigned int n); + +ISC_LANG_ENDDECLS + +#endif /* ISC_REFCOUNT_H */ diff --git a/contrib/ntp/lib/isc/include/isc/region.h b/contrib/ntp/lib/isc/include/isc/region.h new file mode 100644 index 0000000..43d8f8f --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/region.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: region.h,v 1.25 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_REGION_H +#define ISC_REGION_H 1 + +/*! \file isc/region.h */ + +#include <isc/types.h> + +struct isc_region { + unsigned char * base; + unsigned int length; +}; + +struct isc_textregion { + char * base; + unsigned int length; +}; + +/* XXXDCL questionable ... bears discussion. we have been putting off + * discussing the region api. + */ +struct isc_constregion { + const void * base; + unsigned int length; +}; + +struct isc_consttextregion { + const char * base; + unsigned int length; +}; + +/*@{*/ +/*! + * The region structure is not opaque, and is usually directly manipulated. + * Some macros are defined below for convenience. + */ + +#define isc_region_consume(r,l) \ + do { \ + isc_region_t *_r = (r); \ + unsigned int _l = (l); \ + INSIST(_r->length >= _l); \ + _r->base += _l; \ + _r->length -= _l; \ + } while (0) + +#define isc_textregion_consume(r,l) \ + do { \ + isc_textregion_t *_r = (r); \ + unsigned int _l = (l); \ + INSIST(_r->length >= _l); \ + _r->base += _l; \ + _r->length -= _l; \ + } while (0) + +#define isc_constregion_consume(r,l) \ + do { \ + isc_constregion_t *_r = (r); \ + unsigned int _l = (l); \ + INSIST(_r->length >= _l); \ + _r->base += _l; \ + _r->length -= _l; \ + } while (0) +/*@}*/ + +int +isc_region_compare(isc_region_t *r1, isc_region_t *r2); +/*%< + * Compares the contents of two regions + * + * Requires: + *\li 'r1' is a valid region + *\li 'r2' is a valid region + * + * Returns: + *\li < 0 if r1 is lexicographically less than r2 + *\li = 0 if r1 is lexicographically identical to r2 + *\li > 0 if r1 is lexicographically greater than r2 + */ + +#endif /* ISC_REGION_H */ diff --git a/contrib/ntp/lib/isc/include/isc/resource.h b/contrib/ntp/lib/isc/include/isc/resource.h new file mode 100644 index 0000000..747c9fd --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/resource.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: resource.h,v 1.13 2008/07/11 23:47:09 tbox Exp $ */ + +#ifndef ISC_RESOURCE_H +#define ISC_RESOURCE_H 1 + +/*! \file isc/resource.h */ + +#include <isc/lang.h> +#include <isc/types.h> + +#define ISC_RESOURCE_UNLIMITED ((isc_resourcevalue_t)ISC_UINT64_MAX) + +ISC_LANG_BEGINDECLS + +isc_result_t +isc_resource_setlimit(isc_resource_t resource, isc_resourcevalue_t value); +/*%< + * Set the maximum limit for a system resource. + * + * Notes: + *\li If 'value' exceeds the maximum possible on the operating system, + * it is silently limited to that maximum -- or to "infinity", if + * the operating system has that concept. #ISC_RESOURCE_UNLIMITED + * can be used to explicitly ask for the maximum. + * + * Requires: + *\li 'resource' is a valid member of the isc_resource_t enumeration. + * + * Returns: + *\li #ISC_R_SUCCESS Success. + *\li #ISC_R_NOTIMPLEMENTED 'resource' is not a type known by the OS. + *\li #ISC_R_NOPERM The calling process did not have adequate permission + * to change the resource limit. + */ + +isc_result_t +isc_resource_getlimit(isc_resource_t resource, isc_resourcevalue_t *value); +/*%< + * Get the maximum limit for a system resource. + * + * Notes: + *\li 'value' is set to the maximum limit. + * + *\li #ISC_RESOURCE_UNLIMITED is the maximum value of isc_resourcevalue_t. + * + *\li On many (all?) Unix systems, RLIM_INFINITY is a valid value that is + * significantly less than #ISC_RESOURCE_UNLIMITED, but which in practice + * behaves the same. + * + *\li The current ISC libdns configuration file parser assigns a value + * of ISC_UINT32_MAX for a size_spec of "unlimited" and ISC_UNIT32_MAX - 1 + * for "default", the latter of which is supposed to represent "the + * limit that was in force when the server started". Since these are + * valid values in the middle of the range of isc_resourcevalue_t, + * there is the possibility for confusion over what exactly those + * particular values are supposed to represent in a particular context -- + * discrete integral values or generalized concepts. + * + * Requires: + *\li 'resource' is a valid member of the isc_resource_t enumeration. + * + * Returns: + *\li #ISC_R_SUCCESS Success. + *\li #ISC_R_NOTIMPLEMENTED 'resource' is not a type known by the OS. + */ + +isc_result_t +isc_resource_getcurlimit(isc_resource_t resource, isc_resourcevalue_t *value); +/*%< + * Same as isc_resource_getlimit(), but returns the current (soft) limit. + * + * Returns: + *\li #ISC_R_SUCCESS Success. + *\li #ISC_R_NOTIMPLEMENTED 'resource' is not a type known by the OS. + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_RESOURCE_H */ + diff --git a/contrib/ntp/lib/isc/include/isc/result.h b/contrib/ntp/lib/isc/include/isc/result.h new file mode 100644 index 0000000..dcd457b --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/result.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2004-2009, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2001, 2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +#ifndef ISC_RESULT_H +#define ISC_RESULT_H 1 + +/*! \file isc/result.h */ + +#include <isc/lang.h> +#include <isc/types.h> + +#define ISC_R_SUCCESS 0 /*%< success */ +#define ISC_R_NOMEMORY 1 /*%< out of memory */ +#define ISC_R_TIMEDOUT 2 /*%< timed out */ +#define ISC_R_NOTHREADS 3 /*%< no available threads */ +#define ISC_R_ADDRNOTAVAIL 4 /*%< address not available */ +#define ISC_R_ADDRINUSE 5 /*%< address in use */ +#define ISC_R_NOPERM 6 /*%< permission denied */ +#define ISC_R_NOCONN 7 /*%< no pending connections */ +#define ISC_R_NETUNREACH 8 /*%< network unreachable */ +#define ISC_R_HOSTUNREACH 9 /*%< host unreachable */ +#define ISC_R_NETDOWN 10 /*%< network down */ +#define ISC_R_HOSTDOWN 11 /*%< host down */ +#define ISC_R_CONNREFUSED 12 /*%< connection refused */ +#define ISC_R_NORESOURCES 13 /*%< not enough free resources */ +#define ISC_R_EOF 14 /*%< end of file */ +#define ISC_R_BOUND 15 /*%< socket already bound */ +#define ISC_R_RELOAD 16 /*%< reload */ +#define ISC_R_SUSPEND ISC_R_RELOAD /*%< alias of 'reload' */ +#define ISC_R_LOCKBUSY 17 /*%< lock busy */ +#define ISC_R_EXISTS 18 /*%< already exists */ +#define ISC_R_NOSPACE 19 /*%< ran out of space */ +#define ISC_R_CANCELED 20 /*%< operation canceled */ +#define ISC_R_NOTBOUND 21 /*%< socket is not bound */ +#define ISC_R_SHUTTINGDOWN 22 /*%< shutting down */ +#define ISC_R_NOTFOUND 23 /*%< not found */ +#define ISC_R_UNEXPECTEDEND 24 /*%< unexpected end of input */ +#define ISC_R_FAILURE 25 /*%< generic failure */ +#define ISC_R_IOERROR 26 /*%< I/O error */ +#define ISC_R_NOTIMPLEMENTED 27 /*%< not implemented */ +#define ISC_R_UNBALANCED 28 /*%< unbalanced parentheses */ +#define ISC_R_NOMORE 29 /*%< no more */ +#define ISC_R_INVALIDFILE 30 /*%< invalid file */ +#define ISC_R_BADBASE64 31 /*%< bad base64 encoding */ +#define ISC_R_UNEXPECTEDTOKEN 32 /*%< unexpected token */ +#define ISC_R_QUOTA 33 /*%< quota reached */ +#define ISC_R_UNEXPECTED 34 /*%< unexpected error */ +#define ISC_R_ALREADYRUNNING 35 /*%< already running */ +#define ISC_R_IGNORE 36 /*%< ignore */ +#define ISC_R_MASKNONCONTIG 37 /*%< addr mask not contiguous */ +#define ISC_R_FILENOTFOUND 38 /*%< file not found */ +#define ISC_R_FILEEXISTS 39 /*%< file already exists */ +#define ISC_R_NOTCONNECTED 40 /*%< socket is not connected */ +#define ISC_R_RANGE 41 /*%< out of range */ +#define ISC_R_NOENTROPY 42 /*%< out of entropy */ +#define ISC_R_MULTICAST 43 /*%< invalid use of multicast */ +#define ISC_R_NOTFILE 44 /*%< not a file */ +#define ISC_R_NOTDIRECTORY 45 /*%< not a directory */ +#define ISC_R_QUEUEFULL 46 /*%< queue is full */ +#define ISC_R_FAMILYMISMATCH 47 /*%< address family mismatch */ +#define ISC_R_FAMILYNOSUPPORT 48 /*%< AF not supported */ +#define ISC_R_BADHEX 49 /*%< bad hex encoding */ +#define ISC_R_TOOMANYOPENFILES 50 /*%< too many open files */ +#define ISC_R_NOTBLOCKING 51 /*%< not blocking */ +#define ISC_R_UNBALANCEDQUOTES 52 /*%< unbalanced quotes */ +#define ISC_R_INPROGRESS 53 /*%< operation in progress */ +#define ISC_R_CONNECTIONRESET 54 /*%< connection reset */ +#define ISC_R_SOFTQUOTA 55 /*%< soft quota reached */ +#define ISC_R_BADNUMBER 56 /*%< not a valid number */ +#define ISC_R_DISABLED 57 /*%< disabled */ +#define ISC_R_MAXSIZE 58 /*%< max size */ +#define ISC_R_BADADDRESSFORM 59 /*%< invalid address format */ +#define ISC_R_BADBASE32 60 /*%< bad base32 encoding */ +#define ISC_R_UNSET 61 /*%< unset */ + +/*% Not a result code: the number of results. */ +#define ISC_R_NRESULTS 62 + +ISC_LANG_BEGINDECLS + +const char * +isc_result_totext(isc_result_t); +/*%< + * Convert an isc_result_t into a string message describing the result. + */ + +isc_result_t +isc_result_register(unsigned int base, unsigned int nresults, + const char **text, isc_msgcat_t *msgcat, int set); + +ISC_LANG_ENDDECLS + +#endif /* ISC_RESULT_H */ diff --git a/contrib/ntp/lib/isc/include/isc/resultclass.h b/contrib/ntp/lib/isc/include/isc/resultclass.h new file mode 100644 index 0000000..d91e800 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/resultclass.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: resultclass.h,v 1.20 2009/09/02 23:48:03 tbox Exp $ */ + +#ifndef ISC_RESULTCLASS_H +#define ISC_RESULTCLASS_H 1 + + +/*! \file isc/resultclass.h + * \brief Registry of Predefined Result Type Classes + * + * A result class number is an unsigned 16 bit number. Each class may + * contain up to 65536 results. A result code is formed by adding the + * result number within the class to the class number multiplied by 65536. + * + * Classes < 1024 are reserved for ISC use. + * Result classes >= 1024 and <= 65535 are reserved for application use. + */ + +#define ISC_RESULTCLASS_FROMNUM(num) ((num) << 16) +#define ISC_RESULTCLASS_TONUM(rclass) ((rclass) >> 16) +#define ISC_RESULTCLASS_SIZE 65536 +#define ISC_RESULTCLASS_INCLASS(rclass, result) \ + ((rclass) == ((result) & 0xFFFF0000)) + + +#define ISC_RESULTCLASS_ISC ISC_RESULTCLASS_FROMNUM(0) +#define ISC_RESULTCLASS_DNS ISC_RESULTCLASS_FROMNUM(1) +#define ISC_RESULTCLASS_DST ISC_RESULTCLASS_FROMNUM(2) +#define ISC_RESULTCLASS_DNSRCODE ISC_RESULTCLASS_FROMNUM(3) +#define ISC_RESULTCLASS_OMAPI ISC_RESULTCLASS_FROMNUM(4) +#define ISC_RESULTCLASS_ISCCC ISC_RESULTCLASS_FROMNUM(5) +#define ISC_RESULTCLASS_DHCP ISC_RESULTCLASS_FROMNUM(6) + + +#endif /* ISC_RESULTCLASS_H */ diff --git a/contrib/ntp/lib/isc/include/isc/rwlock.h b/contrib/ntp/lib/isc/include/isc/rwlock.h new file mode 100644 index 0000000..28052cd --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/rwlock.h @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2001, 2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: rwlock.h,v 1.28 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_RWLOCK_H +#define ISC_RWLOCK_H 1 + +/*! \file isc/rwlock.h */ + +#include <isc/condition.h> +#include <isc/lang.h> +#include <isc/platform.h> +#include <isc/types.h> + +ISC_LANG_BEGINDECLS + +typedef enum { + isc_rwlocktype_none = 0, + isc_rwlocktype_read, + isc_rwlocktype_write +} isc_rwlocktype_t; + +#ifdef ISC_PLATFORM_USETHREADS +#if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG) +#define ISC_RWLOCK_USEATOMIC 1 +#endif + +struct isc_rwlock { + /* Unlocked. */ + unsigned int magic; + isc_mutex_t lock; + +#if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG) + /* + * When some atomic instructions with hardware assistance are + * available, rwlock will use those so that concurrent readers do not + * interfere with each other through mutex as long as no writers + * appear, massively reducing the lock overhead in the typical case. + * + * The basic algorithm of this approach is the "simple + * writer-preference lock" shown in the following URL: + * http://www.cs.rochester.edu/u/scott/synchronization/pseudocode/rw.html + * but our implementation does not rely on the spin lock unlike the + * original algorithm to be more portable as a user space application. + */ + + /* Read or modified atomically. */ + isc_int32_t write_requests; + isc_int32_t write_completions; + isc_int32_t cnt_and_flag; + + /* Locked by lock. */ + isc_condition_t readable; + isc_condition_t writeable; + unsigned int readers_waiting; + + /* Locked by rwlock itself. */ + unsigned int write_granted; + + /* Unlocked. */ + unsigned int write_quota; + +#else /* ISC_PLATFORM_HAVEXADD && ISC_PLATFORM_HAVECMPXCHG */ + + /*%< Locked by lock. */ + isc_condition_t readable; + isc_condition_t writeable; + isc_rwlocktype_t type; + + /*% The number of threads that have the lock. */ + unsigned int active; + + /*% + * The number of lock grants made since the lock was last switched + * from reading to writing or vice versa; used in determining + * when the quota is reached and it is time to switch. + */ + unsigned int granted; + + unsigned int readers_waiting; + unsigned int writers_waiting; + unsigned int read_quota; + unsigned int write_quota; + isc_rwlocktype_t original; +#endif /* ISC_PLATFORM_HAVEXADD && ISC_PLATFORM_HAVECMPXCHG */ +}; +#else /* ISC_PLATFORM_USETHREADS */ +struct isc_rwlock { + unsigned int magic; + isc_rwlocktype_t type; + unsigned int active; +}; +#endif /* ISC_PLATFORM_USETHREADS */ + + +isc_result_t +isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota, + unsigned int write_quota); + +isc_result_t +isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type); + +isc_result_t +isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type); + +isc_result_t +isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type); + +isc_result_t +isc_rwlock_tryupgrade(isc_rwlock_t *rwl); + +void +isc_rwlock_downgrade(isc_rwlock_t *rwl); + +void +isc_rwlock_destroy(isc_rwlock_t *rwl); + +ISC_LANG_ENDDECLS + +#endif /* ISC_RWLOCK_H */ diff --git a/contrib/ntp/lib/isc/include/isc/serial.h b/contrib/ntp/lib/isc/include/isc/serial.h new file mode 100644 index 0000000..a5e0397 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/serial.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: serial.h,v 1.18 2009/01/18 23:48:14 tbox Exp $ */ + +#ifndef ISC_SERIAL_H +#define ISC_SERIAL_H 1 + +#include <isc/lang.h> +#include <isc/types.h> + +/*! \file isc/serial.h + * \brief Implement 32 bit serial space arithmetic comparison functions. + * Note: Undefined results are returned as ISC_FALSE. + */ + +/*** + *** Functions + ***/ + +ISC_LANG_BEGINDECLS + +isc_boolean_t +isc_serial_lt(isc_uint32_t a, isc_uint32_t b); +/*%< + * Return true if 'a' < 'b' otherwise false. + */ + +isc_boolean_t +isc_serial_gt(isc_uint32_t a, isc_uint32_t b); +/*%< + * Return true if 'a' > 'b' otherwise false. + */ + +isc_boolean_t +isc_serial_le(isc_uint32_t a, isc_uint32_t b); +/*%< + * Return true if 'a' <= 'b' otherwise false. + */ + +isc_boolean_t +isc_serial_ge(isc_uint32_t a, isc_uint32_t b); +/*%< + * Return true if 'a' >= 'b' otherwise false. + */ + +isc_boolean_t +isc_serial_eq(isc_uint32_t a, isc_uint32_t b); +/*%< + * Return true if 'a' == 'b' otherwise false. + */ + +isc_boolean_t +isc_serial_ne(isc_uint32_t a, isc_uint32_t b); +/*%< + * Return true if 'a' != 'b' otherwise false. + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_SERIAL_H */ diff --git a/contrib/ntp/lib/isc/include/isc/sha1.h b/contrib/ntp/lib/isc/include/isc/sha1.h new file mode 100644 index 0000000..313ff96 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/sha1.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +#ifndef ISC_SHA1_H +#define ISC_SHA1_H 1 + +/* $Id: sha1.h,v 1.19 2009/02/06 23:47:42 tbox Exp $ */ + +/* $NetBSD: sha1.h,v 1.2 1998/05/29 22:55:44 thorpej Exp $ */ + +/*! \file isc/sha1.h + * \brief SHA-1 in C + * \author By Steve Reid <steve@edmweb.com> + * \note 100% Public Domain + */ + +#include <isc/lang.h> +#include <isc/platform.h> +#include <isc/types.h> + +#define ISC_SHA1_DIGESTLENGTH 20U +#define ISC_SHA1_BLOCK_LENGTH 64U + +#ifdef ISC_PLATFORM_OPENSSLHASH +#include <openssl/evp.h> + +typedef EVP_MD_CTX isc_sha1_t; + +#else + +typedef struct { + isc_uint32_t state[5]; + isc_uint32_t count[2]; + unsigned char buffer[ISC_SHA1_BLOCK_LENGTH]; +} isc_sha1_t; +#endif + +ISC_LANG_BEGINDECLS + +void +isc_sha1_init(isc_sha1_t *ctx); + +void +isc_sha1_invalidate(isc_sha1_t *ctx); + +void +isc_sha1_update(isc_sha1_t *ctx, const unsigned char *data, unsigned int len); + +void +isc_sha1_final(isc_sha1_t *ctx, unsigned char *digest); + +ISC_LANG_ENDDECLS + +#endif /* ISC_SHA1_H */ diff --git a/contrib/ntp/lib/isc/include/isc/sha2.h b/contrib/ntp/lib/isc/include/isc/sha2.h new file mode 100644 index 0000000..0c9dea8 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/sha2.h @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2005-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: sha2.h,v 1.12 2009/10/22 02:21:31 each Exp $ */ + +/* $FreeBSD: 258945 2013-12-04 21:33:17Z roberto $ */ +/* $KAME: sha2.h,v 1.3 2001/03/12 08:27:48 itojun Exp $ */ + +/* + * sha2.h + * + * Version 1.0.0beta1 + * + * Written by Aaron D. Gifford <me@aarongifford.com> + * + * Copyright 2000 Aaron D. Gifford. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTOR(S) ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef ISC_SHA2_H +#define ISC_SHA2_H + +#include <isc/lang.h> +#include <isc/platform.h> +#include <isc/types.h> + +/*** SHA-224/256/384/512 Various Length Definitions ***********************/ + +#define ISC_SHA224_BLOCK_LENGTH 64U +#define ISC_SHA224_DIGESTLENGTH 28U +#define ISC_SHA224_DIGESTSTRINGLENGTH (ISC_SHA224_DIGESTLENGTH * 2 + 1) +#define ISC_SHA256_BLOCK_LENGTH 64U +#define ISC_SHA256_DIGESTLENGTH 32U +#define ISC_SHA256_DIGESTSTRINGLENGTH (ISC_SHA256_DIGESTLENGTH * 2 + 1) +#define ISC_SHA384_BLOCK_LENGTH 128 +#define ISC_SHA384_DIGESTLENGTH 48U +#define ISC_SHA384_DIGESTSTRINGLENGTH (ISC_SHA384_DIGESTLENGTH * 2 + 1) +#define ISC_SHA512_BLOCK_LENGTH 128U +#define ISC_SHA512_DIGESTLENGTH 64U +#define ISC_SHA512_DIGESTSTRINGLENGTH (ISC_SHA512_DIGESTLENGTH * 2 + 1) + +/*** SHA-256/384/512 Context Structures *******************************/ + +#ifdef ISC_PLATFORM_OPENSSLHASH +#include <openssl/evp.h> + +typedef EVP_MD_CTX isc_sha256_t; +typedef EVP_MD_CTX isc_sha512_t; + +#else + +/* + * Keep buffer immediately after bitcount to preserve alignment. + */ +typedef struct { + isc_uint32_t state[8]; + isc_uint64_t bitcount; + isc_uint8_t buffer[ISC_SHA256_BLOCK_LENGTH]; +} isc_sha256_t; + +/* + * Keep buffer immediately after bitcount to preserve alignment. + */ +typedef struct { + isc_uint64_t state[8]; + isc_uint64_t bitcount[2]; + isc_uint8_t buffer[ISC_SHA512_BLOCK_LENGTH]; +} isc_sha512_t; +#endif + +typedef isc_sha256_t isc_sha224_t; +typedef isc_sha512_t isc_sha384_t; + +ISC_LANG_BEGINDECLS + +/*** SHA-224/256/384/512 Function Prototypes ******************************/ + +void isc_sha224_init (isc_sha224_t *); +void isc_sha224_invalidate (isc_sha224_t *); +void isc_sha224_update (isc_sha224_t *, const isc_uint8_t *, size_t); +void isc_sha224_final (isc_uint8_t[ISC_SHA224_DIGESTLENGTH], isc_sha224_t *); +char *isc_sha224_end (isc_sha224_t *, char[ISC_SHA224_DIGESTSTRINGLENGTH]); +char *isc_sha224_data (const isc_uint8_t *, size_t, char[ISC_SHA224_DIGESTSTRINGLENGTH]); + +void isc_sha256_init (isc_sha256_t *); +void isc_sha256_invalidate (isc_sha256_t *); +void isc_sha256_update (isc_sha256_t *, const isc_uint8_t *, size_t); +void isc_sha256_final (isc_uint8_t[ISC_SHA256_DIGESTLENGTH], isc_sha256_t *); +char *isc_sha256_end (isc_sha256_t *, char[ISC_SHA256_DIGESTSTRINGLENGTH]); +char *isc_sha256_data (const isc_uint8_t *, size_t, char[ISC_SHA256_DIGESTSTRINGLENGTH]); + +void isc_sha384_init (isc_sha384_t *); +void isc_sha384_invalidate (isc_sha384_t *); +void isc_sha384_update (isc_sha384_t *, const isc_uint8_t *, size_t); +void isc_sha384_final (isc_uint8_t[ISC_SHA384_DIGESTLENGTH], isc_sha384_t *); +char *isc_sha384_end (isc_sha384_t *, char[ISC_SHA384_DIGESTSTRINGLENGTH]); +char *isc_sha384_data (const isc_uint8_t *, size_t, char[ISC_SHA384_DIGESTSTRINGLENGTH]); + +void isc_sha512_init (isc_sha512_t *); +void isc_sha512_invalidate (isc_sha512_t *); +void isc_sha512_update (isc_sha512_t *, const isc_uint8_t *, size_t); +void isc_sha512_final (isc_uint8_t[ISC_SHA512_DIGESTLENGTH], isc_sha512_t *); +char *isc_sha512_end (isc_sha512_t *, char[ISC_SHA512_DIGESTSTRINGLENGTH]); +char *isc_sha512_data (const isc_uint8_t *, size_t, char[ISC_SHA512_DIGESTSTRINGLENGTH]); + +ISC_LANG_ENDDECLS + +#endif /* ISC_SHA2_H */ diff --git a/contrib/ntp/lib/isc/include/isc/sockaddr.h b/contrib/ntp/lib/isc/include/isc/sockaddr.h new file mode 100644 index 0000000..1e69142 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/sockaddr.h @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: sockaddr.h,v 1.57 2009/01/18 23:48:14 tbox Exp $ */ + +#ifndef ISC_SOCKADDR_H +#define ISC_SOCKADDR_H 1 + +/*! \file isc/sockaddr.h */ + +#include <isc/lang.h> +#include <isc/net.h> +#include <isc/types.h> +#ifdef ISC_PLATFORM_HAVESYSUNH +#include <sys/un.h> +#endif + +struct isc_sockaddr { + union { + struct sockaddr sa; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; +#ifdef ISC_PLATFORM_HAVESYSUNH + struct sockaddr_un sunix; +#endif + } type; + unsigned int length; /* XXXRTH beginning? */ + ISC_LINK(struct isc_sockaddr) link; +}; + +typedef ISC_LIST(struct isc_sockaddr) isc_sockaddrlist_t; + +#define ISC_SOCKADDR_CMPADDR 0x0001 /*%< compare the address + * sin_addr/sin6_addr */ +#define ISC_SOCKADDR_CMPPORT 0x0002 /*%< compare the port + * sin_port/sin6_port */ +#define ISC_SOCKADDR_CMPSCOPE 0x0004 /*%< compare the scope + * sin6_scope */ +#define ISC_SOCKADDR_CMPSCOPEZERO 0x0008 /*%< when comparing scopes + * zero scopes always match */ + +ISC_LANG_BEGINDECLS + +isc_boolean_t +isc_sockaddr_compare(const isc_sockaddr_t *a, const isc_sockaddr_t *b, + unsigned int flags); +/*%< + * Compare the elements of the two address ('a' and 'b') as specified + * by 'flags' and report if they are equal or not. + * + * 'flags' is set from ISC_SOCKADDR_CMP*. + */ + +isc_boolean_t +isc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b); +/*%< + * Return ISC_TRUE iff the socket addresses 'a' and 'b' are equal. + */ + +isc_boolean_t +isc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b); +/*%< + * Return ISC_TRUE iff the address parts of the socket addresses + * 'a' and 'b' are equal, ignoring the ports. + */ + +isc_boolean_t +isc_sockaddr_eqaddrprefix(const isc_sockaddr_t *a, const isc_sockaddr_t *b, + unsigned int prefixlen); +/*%< + * Return ISC_TRUE iff the most significant 'prefixlen' bits of the + * socket addresses 'a' and 'b' are equal, ignoring the ports. + * If 'b''s scope is zero then 'a''s scope will be ignored. + */ + +unsigned int +isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, isc_boolean_t address_only); +/*%< + * Return a hash value for the socket address 'sockaddr'. If 'address_only' + * is ISC_TRUE, the hash value will not depend on the port. + * + * IPv6 addresses containing mapped IPv4 addresses generate the same hash + * value as the equivalent IPv4 address. + */ + +void +isc_sockaddr_any(isc_sockaddr_t *sockaddr); +/*%< + * Return the IPv4 wildcard address. + */ + +void +isc_sockaddr_any6(isc_sockaddr_t *sockaddr); +/*%< + * Return the IPv6 wildcard address. + */ + +void +isc_sockaddr_anyofpf(isc_sockaddr_t *sockaddr, int family); +/*%< + * Set '*sockaddr' to the wildcard address of protocol family + * 'family'. + * + * Requires: + * \li 'family' is AF_INET or AF_INET6. + */ + +void +isc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina, + in_port_t port); +/*%< + * Construct an isc_sockaddr_t from an IPv4 address and port. + */ + +void +isc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6, + in_port_t port); +/*%< + * Construct an isc_sockaddr_t from an IPv6 address and port. + */ + +void +isc_sockaddr_v6fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina, + in_port_t port); +/*%< + * Construct an IPv6 isc_sockaddr_t representing a mapped IPv4 address. + */ + +void +isc_sockaddr_fromnetaddr(isc_sockaddr_t *sockaddr, const isc_netaddr_t *na, + in_port_t port); +/*%< + * Construct an isc_sockaddr_t from an isc_netaddr_t and port. + */ + +int +isc_sockaddr_pf(const isc_sockaddr_t *sockaddr); +/*%< + * Get the protocol family of 'sockaddr'. + * + * Requires: + * + *\li 'sockaddr' is a valid sockaddr with an address family of AF_INET + * or AF_INET6. + * + * Returns: + * + *\li The protocol family of 'sockaddr', e.g. PF_INET or PF_INET6. + */ + +void +isc_sockaddr_setport(isc_sockaddr_t *sockaddr, in_port_t port); +/*%< + * Set the port of 'sockaddr' to 'port'. + */ + +in_port_t +isc_sockaddr_getport(const isc_sockaddr_t *sockaddr); +/*%< + * Get the port stored in 'sockaddr'. + */ + +isc_result_t +isc_sockaddr_totext(const isc_sockaddr_t *sockaddr, isc_buffer_t *target); +/*%< + * Append a text representation of 'sockaddr' to the buffer 'target'. + * The text will include both the IP address (v4 or v6) and the port. + * The text is null terminated, but the terminating null is not + * part of the buffer's used region. + * + * Returns: + * \li ISC_R_SUCCESS + * \li ISC_R_NOSPACE The text or the null termination did not fit. + */ + +void +isc_sockaddr_format(const isc_sockaddr_t *sa, char *array, unsigned int size); +/*%< + * Format a human-readable representation of the socket address '*sa' + * into the character array 'array', which is of size 'size'. + * The resulting string is guaranteed to be null-terminated. + */ + +isc_boolean_t +isc_sockaddr_ismulticast(const isc_sockaddr_t *sa); +/*%< + * Returns #ISC_TRUE if the address is a multicast address. + */ + +isc_boolean_t +isc_sockaddr_isexperimental(const isc_sockaddr_t *sa); +/* + * Returns ISC_TRUE if the address is a experimental (CLASS E) address. + */ + +isc_boolean_t +isc_sockaddr_islinklocal(const isc_sockaddr_t *sa); +/*%< + * Returns ISC_TRUE if the address is a link local address. + */ + +isc_boolean_t +isc_sockaddr_issitelocal(const isc_sockaddr_t *sa); +/*%< + * Returns ISC_TRUE if the address is a sitelocal address. + */ + +isc_result_t +isc_sockaddr_frompath(isc_sockaddr_t *sockaddr, const char *path); +/* + * Create a UNIX domain sockaddr that refers to path. + * + * Returns: + * \li ISC_R_NOSPACE + * \li ISC_R_NOTIMPLEMENTED + * \li ISC_R_SUCCESS + */ + +#define ISC_SOCKADDR_FORMATSIZE \ + sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:XXX.XXX.XXX.XXX%SSSSSSSSSS#YYYYY") +/*%< + * Minimum size of array to pass to isc_sockaddr_format(). + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_SOCKADDR_H */ diff --git a/contrib/ntp/lib/isc/include/isc/socket.h b/contrib/ntp/lib/isc/include/isc/socket.h new file mode 100644 index 0000000..46e05a0 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/socket.h @@ -0,0 +1,1168 @@ +/* + * Copyright (C) 2004-2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +#ifndef ISC_SOCKET_H +#define ISC_SOCKET_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file isc/socket.h + * \brief Provides TCP and UDP sockets for network I/O. The sockets are event + * sources in the task system. + * + * When I/O completes, a completion event for the socket is posted to the + * event queue of the task which requested the I/O. + * + * \li MP: + * The module ensures appropriate synchronization of data structures it + * creates and manipulates. + * Clients of this module must not be holding a socket's task's lock when + * making a call that affects that socket. Failure to follow this rule + * can result in deadlock. + * The caller must ensure that isc_socketmgr_destroy() is called only + * once for a given manager. + * + * \li Reliability: + * No anticipated impact. + * + * \li Resources: + * TBS + * + * \li Security: + * No anticipated impact. + * + * \li Standards: + * None. + */ + +/*** + *** Imports + ***/ + +#include <isc/lang.h> +#include <isc/types.h> +#include <isc/event.h> +#include <isc/eventclass.h> +#include <isc/time.h> +#include <isc/region.h> +#include <isc/sockaddr.h> +#include <isc/xml.h> + +ISC_LANG_BEGINDECLS + +/*** + *** Constants + ***/ + +/*% + * Maximum number of buffers in a scatter/gather read/write. The operating + * system in use must support at least this number (plus one on some.) + */ +#define ISC_SOCKET_MAXSCATTERGATHER 8 + +/*% + * In isc_socket_bind() set socket option SO_REUSEADDR prior to calling + * bind() if a non zero port is specified (AF_INET and AF_INET6). + */ +#define ISC_SOCKET_REUSEADDRESS 0x01U + +/*% + * Statistics counters. Used as isc_statscounter_t values. + */ +enum { + isc_sockstatscounter_udp4open = 0, + isc_sockstatscounter_udp6open = 1, + isc_sockstatscounter_tcp4open = 2, + isc_sockstatscounter_tcp6open = 3, + isc_sockstatscounter_unixopen = 4, + + isc_sockstatscounter_udp4openfail = 5, + isc_sockstatscounter_udp6openfail = 6, + isc_sockstatscounter_tcp4openfail = 7, + isc_sockstatscounter_tcp6openfail = 8, + isc_sockstatscounter_unixopenfail = 9, + + isc_sockstatscounter_udp4close = 10, + isc_sockstatscounter_udp6close = 11, + isc_sockstatscounter_tcp4close = 12, + isc_sockstatscounter_tcp6close = 13, + isc_sockstatscounter_unixclose = 14, + isc_sockstatscounter_fdwatchclose = 15, + + isc_sockstatscounter_udp4bindfail = 16, + isc_sockstatscounter_udp6bindfail = 17, + isc_sockstatscounter_tcp4bindfail = 18, + isc_sockstatscounter_tcp6bindfail = 19, + isc_sockstatscounter_unixbindfail = 20, + isc_sockstatscounter_fdwatchbindfail = 21, + + isc_sockstatscounter_udp4connect = 22, + isc_sockstatscounter_udp6connect = 23, + isc_sockstatscounter_tcp4connect = 24, + isc_sockstatscounter_tcp6connect = 25, + isc_sockstatscounter_unixconnect = 26, + isc_sockstatscounter_fdwatchconnect = 27, + + isc_sockstatscounter_udp4connectfail = 28, + isc_sockstatscounter_udp6connectfail = 29, + isc_sockstatscounter_tcp4connectfail = 30, + isc_sockstatscounter_tcp6connectfail = 31, + isc_sockstatscounter_unixconnectfail = 32, + isc_sockstatscounter_fdwatchconnectfail = 33, + + isc_sockstatscounter_tcp4accept = 34, + isc_sockstatscounter_tcp6accept = 35, + isc_sockstatscounter_unixaccept = 36, + + isc_sockstatscounter_tcp4acceptfail = 37, + isc_sockstatscounter_tcp6acceptfail = 38, + isc_sockstatscounter_unixacceptfail = 39, + + isc_sockstatscounter_udp4sendfail = 40, + isc_sockstatscounter_udp6sendfail = 41, + isc_sockstatscounter_tcp4sendfail = 42, + isc_sockstatscounter_tcp6sendfail = 43, + isc_sockstatscounter_unixsendfail = 44, + isc_sockstatscounter_fdwatchsendfail = 45, + + isc_sockstatscounter_udp4recvfail = 46, + isc_sockstatscounter_udp6recvfail = 47, + isc_sockstatscounter_tcp4recvfail = 48, + isc_sockstatscounter_tcp6recvfail = 49, + isc_sockstatscounter_unixrecvfail = 50, + isc_sockstatscounter_fdwatchrecvfail = 51, + + isc_sockstatscounter_max = 52 +}; + +/*** + *** Types + ***/ + +struct isc_socketevent { + ISC_EVENT_COMMON(isc_socketevent_t); + isc_result_t result; /*%< OK, EOF, whatever else */ + unsigned int minimum; /*%< minimum i/o for event */ + unsigned int n; /*%< bytes read or written */ + unsigned int offset; /*%< offset into buffer list */ + isc_region_t region; /*%< for single-buffer i/o */ + isc_bufferlist_t bufferlist; /*%< list of buffers */ + isc_sockaddr_t address; /*%< source address */ + isc_time_t timestamp; /*%< timestamp of packet recv */ + struct in6_pktinfo pktinfo; /*%< ipv6 pktinfo */ + isc_uint32_t attributes; /*%< see below */ + isc_eventdestructor_t destroy; /*%< original destructor */ +}; + +typedef struct isc_socket_newconnev isc_socket_newconnev_t; +struct isc_socket_newconnev { + ISC_EVENT_COMMON(isc_socket_newconnev_t); + isc_socket_t * newsocket; + isc_result_t result; /*%< OK, EOF, whatever else */ + isc_sockaddr_t address; /*%< source address */ +}; + +typedef struct isc_socket_connev isc_socket_connev_t; +struct isc_socket_connev { + ISC_EVENT_COMMON(isc_socket_connev_t); + isc_result_t result; /*%< OK, EOF, whatever else */ +}; + +/*@{*/ +/*! + * _ATTACHED: Internal use only. + * _TRUNC: Packet was truncated on receive. + * _CTRUNC: Packet control information was truncated. This can + * indicate that the packet is not complete, even though + * all the data is valid. + * _TIMESTAMP: The timestamp member is valid. + * _PKTINFO: The pktinfo member is valid. + * _MULTICAST: The UDP packet was received via a multicast transmission. + */ +#define ISC_SOCKEVENTATTR_ATTACHED 0x80000000U /* internal */ +#define ISC_SOCKEVENTATTR_TRUNC 0x00800000U /* public */ +#define ISC_SOCKEVENTATTR_CTRUNC 0x00400000U /* public */ +#define ISC_SOCKEVENTATTR_TIMESTAMP 0x00200000U /* public */ +#define ISC_SOCKEVENTATTR_PKTINFO 0x00100000U /* public */ +#define ISC_SOCKEVENTATTR_MULTICAST 0x00080000U /* public */ +/*@}*/ + +#define ISC_SOCKEVENT_ANYEVENT (0) +#define ISC_SOCKEVENT_RECVDONE (ISC_EVENTCLASS_SOCKET + 1) +#define ISC_SOCKEVENT_SENDDONE (ISC_EVENTCLASS_SOCKET + 2) +#define ISC_SOCKEVENT_NEWCONN (ISC_EVENTCLASS_SOCKET + 3) +#define ISC_SOCKEVENT_CONNECT (ISC_EVENTCLASS_SOCKET + 4) + +/* + * Internal events. + */ +#define ISC_SOCKEVENT_INTR (ISC_EVENTCLASS_SOCKET + 256) +#define ISC_SOCKEVENT_INTW (ISC_EVENTCLASS_SOCKET + 257) + +typedef enum { + isc_sockettype_udp = 1, + isc_sockettype_tcp = 2, + isc_sockettype_unix = 3, + isc_sockettype_fdwatch = 4 +} isc_sockettype_t; + +/*@{*/ +/*! + * How a socket should be shutdown in isc_socket_shutdown() calls. + */ +#define ISC_SOCKSHUT_RECV 0x00000001 /*%< close read side */ +#define ISC_SOCKSHUT_SEND 0x00000002 /*%< close write side */ +#define ISC_SOCKSHUT_ALL 0x00000003 /*%< close them all */ +/*@}*/ + +/*@{*/ +/*! + * What I/O events to cancel in isc_socket_cancel() calls. + */ +#define ISC_SOCKCANCEL_RECV 0x00000001 /*%< cancel recv */ +#define ISC_SOCKCANCEL_SEND 0x00000002 /*%< cancel send */ +#define ISC_SOCKCANCEL_ACCEPT 0x00000004 /*%< cancel accept */ +#define ISC_SOCKCANCEL_CONNECT 0x00000008 /*%< cancel connect */ +#define ISC_SOCKCANCEL_ALL 0x0000000f /*%< cancel everything */ +/*@}*/ + +/*@{*/ +/*! + * Flags for isc_socket_send() and isc_socket_recv() calls. + */ +#define ISC_SOCKFLAG_IMMEDIATE 0x00000001 /*%< send event only if needed */ +#define ISC_SOCKFLAG_NORETRY 0x00000002 /*%< drop failed UDP sends */ +/*@}*/ + +/*@{*/ +/*! + * Flags for fdwatchcreate. + */ +#define ISC_SOCKFDWATCH_READ 0x00000001 /*%< watch for readable */ +#define ISC_SOCKFDWATCH_WRITE 0x00000002 /*%< watch for writable */ +/*@}*/ + +/*% Socket and socket manager methods */ +typedef struct isc_socketmgrmethods { + void (*destroy)(isc_socketmgr_t **managerp); + isc_result_t (*socketcreate)(isc_socketmgr_t *manager, int pf, + isc_sockettype_t type, + isc_socket_t **socketp); + isc_result_t (*fdwatchcreate)(isc_socketmgr_t *manager, int fd, + int flags, + isc_sockfdwatch_t callback, + void *cbarg, isc_task_t *task, + isc_socket_t **socketp); +} isc_socketmgrmethods_t; + +typedef struct isc_socketmethods { + void (*attach)(isc_socket_t *sock, + isc_socket_t **socketp); + void (*detach)(isc_socket_t **socketp); + isc_result_t (*bind)(isc_socket_t *sock, isc_sockaddr_t *sockaddr, + unsigned int options); + isc_result_t (*sendto)(isc_socket_t *sock, isc_region_t *region, + isc_task_t *task, isc_taskaction_t action, + const void *arg, isc_sockaddr_t *address, + struct in6_pktinfo *pktinfo); + isc_result_t (*connect)(isc_socket_t *sock, isc_sockaddr_t *addr, + isc_task_t *task, isc_taskaction_t action, + const void *arg); + isc_result_t (*recv)(isc_socket_t *sock, isc_region_t *region, + unsigned int minimum, isc_task_t *task, + isc_taskaction_t action, const void *arg); + void (*cancel)(isc_socket_t *sock, isc_task_t *task, + unsigned int how); + isc_result_t (*getsockname)(isc_socket_t *sock, + isc_sockaddr_t *addressp); + isc_sockettype_t (*gettype)(isc_socket_t *sock); + void (*ipv6only)(isc_socket_t *sock, isc_boolean_t yes); + isc_result_t (*fdwatchpoke)(isc_socket_t *sock, int flags); + isc_result_t (*dup)(isc_socket_t *sock, + isc_socket_t **socketp); + int (*getfd)(isc_socket_t *sock); +} isc_socketmethods_t; + +/*% + * This structure is actually just the common prefix of a socket manager + * object implementation's version of an isc_socketmgr_t. + * \brief + * Direct use of this structure by clients is forbidden. socket implementations + * may change the structure. 'magic' must be ISCAPI_SOCKETMGR_MAGIC for any + * of the isc_socket_ routines to work. socket implementations must maintain + * all socket invariants. + * In effect, this definition is used only for non-BIND9 version ("export") + * of the library, and the export version does not work for win32. So, to avoid + * the definition conflict with win32/socket.c, we enable this definition only + * for non-Win32 (i.e. Unix) platforms. + */ +#ifndef WIN32 +struct isc_socketmgr { + unsigned int impmagic; + unsigned int magic; + isc_socketmgrmethods_t *methods; +}; +#endif + +#define ISCAPI_SOCKETMGR_MAGIC ISC_MAGIC('A','s','m','g') +#define ISCAPI_SOCKETMGR_VALID(m) ((m) != NULL && \ + (m)->magic == ISCAPI_SOCKETMGR_MAGIC) + +/*% + * This is the common prefix of a socket object. The same note as + * that for the socketmgr structure applies. + */ +#ifndef WIN32 +struct isc_socket { + unsigned int impmagic; + unsigned int magic; + isc_socketmethods_t *methods; +}; +#endif + +#define ISCAPI_SOCKET_MAGIC ISC_MAGIC('A','s','c','t') +#define ISCAPI_SOCKET_VALID(s) ((s) != NULL && \ + (s)->magic == ISCAPI_SOCKET_MAGIC) + +/*** + *** Socket and Socket Manager Functions + *** + *** Note: all Ensures conditions apply only if the result is success for + *** those functions which return an isc_result. + ***/ + +isc_result_t +isc_socket_fdwatchcreate(isc_socketmgr_t *manager, + int fd, + int flags, + isc_sockfdwatch_t callback, + void *cbarg, + isc_task_t *task, + isc_socket_t **socketp); +/*%< + * Create a new file descriptor watch socket managed by 'manager'. + * + * Note: + * + *\li 'fd' is the already-opened file descriptor. + *\li This function is not available on Windows. + *\li The callback function is called "in-line" - this means the function + * needs to return as fast as possible, as all other I/O will be suspended + * until the callback completes. + * + * Requires: + * + *\li 'manager' is a valid manager + * + *\li 'socketp' is a valid pointer, and *socketp == NULL + * + *\li 'fd' be opened. + * + * Ensures: + * + * '*socketp' is attached to the newly created fdwatch socket + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li #ISC_R_NORESOURCES + *\li #ISC_R_UNEXPECTED + */ + +isc_result_t +isc_socket_fdwatchpoke(isc_socket_t *sock, + int flags); +/*%< + * Poke a file descriptor watch socket informing the manager that it + * should restart watching the socket + * + * Note: + * + *\li 'sock' is the socket returned by isc_socket_fdwatchcreate + * + *\li 'flags' indicates what the manager should watch for on the socket + * in addition to what it may already be watching. It can be one or + * both of ISC_SOCKFDWATCH_READ and ISC_SOCKFDWATCH_WRITE. To + * temporarily disable watching on a socket the value indicating + * no more data should be returned from the call back routine. + * + *\li This function is not available on Windows. + * + * Requires: + * + *\li 'sock' is a valid isc socket + * + * + * Returns: + * + *\li #ISC_R_SUCCESS + */ + +isc_result_t +isc_socket_create(isc_socketmgr_t *manager, + int pf, + isc_sockettype_t type, + isc_socket_t **socketp); +/*%< + * Create a new 'type' socket managed by 'manager'. + * + * For isc_sockettype_fdwatch sockets you should use isc_socket_fdwatchcreate() + * rather than isc_socket_create(). + * + * Note: + * + *\li 'pf' is the desired protocol family, e.g. PF_INET or PF_INET6. + * + * Requires: + * + *\li 'manager' is a valid manager + * + *\li 'socketp' is a valid pointer, and *socketp == NULL + * + *\li 'type' is not isc_sockettype_fdwatch + * + * Ensures: + * + * '*socketp' is attached to the newly created socket + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li #ISC_R_NORESOURCES + *\li #ISC_R_UNEXPECTED + */ + +isc_result_t +isc_socket_dup(isc_socket_t *sock0, isc_socket_t **socketp); +/*%< + * Duplicate an existing socket, reusing its file descriptor. + */ + +void +isc_socket_cancel(isc_socket_t *sock, isc_task_t *task, + unsigned int how); +/*%< + * Cancel pending I/O of the type specified by "how". + * + * Note: if "task" is NULL, then the cancel applies to all tasks using the + * socket. + * + * Requires: + * + * \li "socket" is a valid socket + * + * \li "task" is NULL or a valid task + * + * "how" is a bitmask describing the type of cancelation to perform. + * The type ISC_SOCKCANCEL_ALL will cancel all pending I/O on this + * socket. + * + * \li ISC_SOCKCANCEL_RECV: + * Cancel pending isc_socket_recv() calls. + * + * \li ISC_SOCKCANCEL_SEND: + * Cancel pending isc_socket_send() and isc_socket_sendto() calls. + * + * \li ISC_SOCKCANCEL_ACCEPT: + * Cancel pending isc_socket_accept() calls. + * + * \li ISC_SOCKCANCEL_CONNECT: + * Cancel pending isc_socket_connect() call. + */ + +void +isc_socket_shutdown(isc_socket_t *sock, unsigned int how); +/*%< + * Shutdown 'socket' according to 'how'. + * + * Requires: + * + * \li 'socket' is a valid socket. + * + * \li 'task' is NULL or is a valid task. + * + * \li If 'how' is 'ISC_SOCKSHUT_RECV' or 'ISC_SOCKSHUT_ALL' then + * + * The read queue must be empty. + * + * No further read requests may be made. + * + * \li If 'how' is 'ISC_SOCKSHUT_SEND' or 'ISC_SOCKSHUT_ALL' then + * + * The write queue must be empty. + * + * No further write requests may be made. + */ + +void +isc_socket_attach(isc_socket_t *sock, isc_socket_t **socketp); +/*%< + * Attach *socketp to socket. + * + * Requires: + * + * \li 'socket' is a valid socket. + * + * \li 'socketp' points to a NULL socket. + * + * Ensures: + * + * \li *socketp is attached to socket. + */ + +void +isc_socket_detach(isc_socket_t **socketp); +/*%< + * Detach *socketp from its socket. + * + * Requires: + * + * \li 'socketp' points to a valid socket. + * + * \li If '*socketp' is the last reference to the socket, + * then: + * + * There must be no pending I/O requests. + * + * Ensures: + * + * \li *socketp is NULL. + * + * \li If '*socketp' is the last reference to the socket, + * then: + * + * The socket will be shutdown (both reading and writing) + * for all tasks. + * + * All resources used by the socket have been freed + */ + +isc_result_t +isc_socket_open(isc_socket_t *sock); +/*%< + * Open a new socket file descriptor of the given socket structure. It simply + * opens a new descriptor; all of the other parameters including the socket + * type are inherited from the existing socket. This function is provided to + * avoid overhead of destroying and creating sockets when many short-lived + * sockets are frequently opened and closed. When the efficiency is not an + * issue, it should be safer to detach the unused socket and re-create a new + * one. This optimization may not be available for some systems, in which + * case this function will return ISC_R_NOTIMPLEMENTED and must not be used. + * + * isc_socket_open() should not be called on sockets created by + * isc_socket_fdwatchcreate(). + * + * Requires: + * + * \li there must be no other reference to this socket. + * + * \li 'socket' is a valid and previously closed by isc_socket_close() + * + * \li 'sock->type' is not isc_sockettype_fdwatch + * + * Returns: + * Same as isc_socket_create(). + * \li ISC_R_NOTIMPLEMENTED + */ + +isc_result_t +isc_socket_close(isc_socket_t *sock); +/*%< + * Close a socket file descriptor of the given socket structure. This function + * is provided as an alternative to destroying an unused socket when overhead + * destroying/re-creating sockets can be significant, and is expected to be + * used with isc_socket_open(). This optimization may not be available for some + * systems, in which case this function will return ISC_R_NOTIMPLEMENTED and + * must not be used. + * + * isc_socket_close() should not be called on sockets created by + * isc_socket_fdwatchcreate(). + * + * Requires: + * + * \li The socket must have a valid descriptor. + * + * \li There must be no other reference to this socket. + * + * \li There must be no pending I/O requests. + * + * \li 'sock->type' is not isc_sockettype_fdwatch + * + * Returns: + * \li #ISC_R_NOTIMPLEMENTED + */ + +isc_result_t +isc_socket_bind(isc_socket_t *sock, isc_sockaddr_t *addressp, + unsigned int options); +/*%< + * Bind 'socket' to '*addressp'. + * + * Requires: + * + * \li 'socket' is a valid socket + * + * \li 'addressp' points to a valid isc_sockaddr. + * + * Returns: + * + * \li ISC_R_SUCCESS + * \li ISC_R_NOPERM + * \li ISC_R_ADDRNOTAVAIL + * \li ISC_R_ADDRINUSE + * \li ISC_R_BOUND + * \li ISC_R_UNEXPECTED + */ + +isc_result_t +isc_socket_filter(isc_socket_t *sock, const char *filter); +/*%< + * Inform the kernel that it should perform accept filtering. + * If filter is NULL the current filter will be removed.:w + */ + +isc_result_t +isc_socket_listen(isc_socket_t *sock, unsigned int backlog); +/*%< + * Set listen mode on the socket. After this call, the only function that + * can be used (other than attach and detach) is isc_socket_accept(). + * + * Notes: + * + * \li 'backlog' is as in the UNIX system call listen() and may be + * ignored by non-UNIX implementations. + * + * \li If 'backlog' is zero, a reasonable system default is used, usually + * SOMAXCONN. + * + * Requires: + * + * \li 'socket' is a valid, bound TCP socket or a valid, bound UNIX socket. + * + * Returns: + * + * \li ISC_R_SUCCESS + * \li ISC_R_UNEXPECTED + */ + +isc_result_t +isc_socket_accept(isc_socket_t *sock, + isc_task_t *task, isc_taskaction_t action, const void *arg); +/*%< + * Queue accept event. When a new connection is received, the task will + * get an ISC_SOCKEVENT_NEWCONN event with the sender set to the listen + * socket. The new socket structure is sent inside the isc_socket_newconnev_t + * event type, and is attached to the task 'task'. + * + * REQUIRES: + * \li 'socket' is a valid TCP socket that isc_socket_listen() was called + * on. + * + * \li 'task' is a valid task + * + * \li 'action' is a valid action + * + * RETURNS: + * \li ISC_R_SUCCESS + * \li ISC_R_NOMEMORY + * \li ISC_R_UNEXPECTED + */ + +isc_result_t +isc_socket_connect(isc_socket_t *sock, isc_sockaddr_t *addressp, + isc_task_t *task, isc_taskaction_t action, + const void *arg); +/*%< + * Connect 'socket' to peer with address *saddr. When the connection + * succeeds, or when an error occurs, a CONNECT event with action 'action' + * and arg 'arg' will be posted to the event queue for 'task'. + * + * Requires: + * + * \li 'socket' is a valid TCP socket + * + * \li 'addressp' points to a valid isc_sockaddr + * + * \li 'task' is a valid task + * + * \li 'action' is a valid action + * + * Returns: + * + * \li ISC_R_SUCCESS + * \li ISC_R_NOMEMORY + * \li ISC_R_UNEXPECTED + * + * Posted event's result code: + * + * \li ISC_R_SUCCESS + * \li ISC_R_TIMEDOUT + * \li ISC_R_CONNREFUSED + * \li ISC_R_NETUNREACH + * \li ISC_R_UNEXPECTED + */ + +isc_result_t +isc_socket_getpeername(isc_socket_t *sock, isc_sockaddr_t *addressp); +/*%< + * Get the name of the peer connected to 'socket'. + * + * Requires: + * + * \li 'socket' is a valid TCP socket. + * + * Returns: + * + * \li ISC_R_SUCCESS + * \li ISC_R_TOOSMALL + * \li ISC_R_UNEXPECTED + */ + +isc_result_t +isc_socket_getsockname(isc_socket_t *sock, isc_sockaddr_t *addressp); +/*%< + * Get the name of 'socket'. + * + * Requires: + * + * \li 'socket' is a valid socket. + * + * Returns: + * + * \li ISC_R_SUCCESS + * \li ISC_R_TOOSMALL + * \li ISC_R_UNEXPECTED + */ + +/*@{*/ +isc_result_t +isc_socket_recv(isc_socket_t *sock, isc_region_t *region, + unsigned int minimum, + isc_task_t *task, isc_taskaction_t action, const void *arg); +isc_result_t +isc_socket_recvv(isc_socket_t *sock, isc_bufferlist_t *buflist, + unsigned int minimum, + isc_task_t *task, isc_taskaction_t action, const void *arg); + +isc_result_t +isc_socket_recv2(isc_socket_t *sock, isc_region_t *region, + unsigned int minimum, isc_task_t *task, + isc_socketevent_t *event, unsigned int flags); + +/*! + * Receive from 'socket', storing the results in region. + * + * Notes: + * + *\li Let 'length' refer to the length of 'region' or to the sum of all + * available regions in the list of buffers '*buflist'. + * + *\li If 'minimum' is non-zero and at least that many bytes are read, + * the completion event will be posted to the task 'task.' If minimum + * is zero, the exact number of bytes requested in the region must + * be read for an event to be posted. This only makes sense for TCP + * connections, and is always set to 1 byte for UDP. + * + *\li The read will complete when the desired number of bytes have been + * read, if end-of-input occurs, or if an error occurs. A read done + * event with the given 'action' and 'arg' will be posted to the + * event queue of 'task'. + * + *\li The caller may not modify 'region', the buffers which are passed + * into this function, or any data they refer to until the completion + * event is received. + * + *\li For isc_socket_recvv(): + * On successful completion, '*buflist' will be empty, and the list of + * all buffers will be returned in the done event's 'bufferlist' + * member. On error return, '*buflist' will be unchanged. + * + *\li For isc_socket_recv2(): + * 'event' is not NULL, and the non-socket specific fields are + * expected to be initialized. + * + *\li For isc_socket_recv2(): + * The only defined value for 'flags' is ISC_SOCKFLAG_IMMEDIATE. If + * set and the operation completes, the return value will be + * ISC_R_SUCCESS and the event will be filled in and not sent. If the + * operation does not complete, the return value will be + * ISC_R_INPROGRESS and the event will be sent when the operation + * completes. + * + * Requires: + * + *\li 'socket' is a valid, bound socket. + * + *\li For isc_socket_recv(): + * 'region' is a valid region + * + *\li For isc_socket_recvv(): + * 'buflist' is non-NULL, and '*buflist' contain at least one buffer. + * + *\li 'task' is a valid task + * + *\li For isc_socket_recv() and isc_socket_recvv(): + * action != NULL and is a valid action + * + *\li For isc_socket_recv2(): + * event != NULL + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_INPROGRESS + *\li #ISC_R_NOMEMORY + *\li #ISC_R_UNEXPECTED + * + * Event results: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_UNEXPECTED + *\li XXX needs other net-type errors + */ +/*@}*/ + +/*@{*/ +isc_result_t +isc_socket_send(isc_socket_t *sock, isc_region_t *region, + isc_task_t *task, isc_taskaction_t action, const void *arg); +isc_result_t +isc_socket_sendto(isc_socket_t *sock, isc_region_t *region, + isc_task_t *task, isc_taskaction_t action, const void *arg, + isc_sockaddr_t *address, struct in6_pktinfo *pktinfo); +isc_result_t +isc_socket_sendv(isc_socket_t *sock, isc_bufferlist_t *buflist, + isc_task_t *task, isc_taskaction_t action, const void *arg); +isc_result_t +isc_socket_sendtov(isc_socket_t *sock, isc_bufferlist_t *buflist, + isc_task_t *task, isc_taskaction_t action, const void *arg, + isc_sockaddr_t *address, struct in6_pktinfo *pktinfo); +isc_result_t +isc_socket_sendto2(isc_socket_t *sock, isc_region_t *region, + isc_task_t *task, + isc_sockaddr_t *address, struct in6_pktinfo *pktinfo, + isc_socketevent_t *event, unsigned int flags); + +/*! + * Send the contents of 'region' to the socket's peer. + * + * Notes: + * + *\li Shutting down the requestor's task *may* result in any + * still pending writes being dropped or completed, depending on the + * underlying OS implementation. + * + *\li If 'action' is NULL, then no completion event will be posted. + * + *\li The caller may not modify 'region', the buffers which are passed + * into this function, or any data they refer to until the completion + * event is received. + * + *\li For isc_socket_sendv() and isc_socket_sendtov(): + * On successful completion, '*buflist' will be empty, and the list of + * all buffers will be returned in the done event's 'bufferlist' + * member. On error return, '*buflist' will be unchanged. + * + *\li For isc_socket_sendto2(): + * 'event' is not NULL, and the non-socket specific fields are + * expected to be initialized. + * + *\li For isc_socket_sendto2(): + * The only defined values for 'flags' are ISC_SOCKFLAG_IMMEDIATE + * and ISC_SOCKFLAG_NORETRY. + * + *\li If ISC_SOCKFLAG_IMMEDIATE is set and the operation completes, the + * return value will be ISC_R_SUCCESS and the event will be filled + * in and not sent. If the operation does not complete, the return + * value will be ISC_R_INPROGRESS and the event will be sent when + * the operation completes. + * + *\li ISC_SOCKFLAG_NORETRY can only be set for UDP sockets. If set + * and the send operation fails due to a transient error, the send + * will not be retried and the error will be indicated in the event. + * Using this option along with ISC_SOCKFLAG_IMMEDIATE allows the caller + * to specify a region that is allocated on the stack. + * + * Requires: + * + *\li 'socket' is a valid, bound socket. + * + *\li For isc_socket_send(): + * 'region' is a valid region + * + *\li For isc_socket_sendv() and isc_socket_sendtov(): + * 'buflist' is non-NULL, and '*buflist' contain at least one buffer. + * + *\li 'task' is a valid task + * + *\li For isc_socket_sendv(), isc_socket_sendtov(), isc_socket_send(), and + * isc_socket_sendto(): + * action == NULL or is a valid action + * + *\li For isc_socket_sendto2(): + * event != NULL + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_INPROGRESS + *\li #ISC_R_NOMEMORY + *\li #ISC_R_UNEXPECTED + * + * Event results: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_UNEXPECTED + *\li XXX needs other net-type errors + */ +/*@}*/ + +isc_result_t +isc_socketmgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx, + isc_socketmgr_t **managerp); + +isc_result_t +isc_socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp); + +isc_result_t +isc_socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp, + unsigned int maxsocks); +/*%< + * Create a socket manager. If "maxsocks" is non-zero, it specifies the + * maximum number of sockets that the created manager should handle. + * isc_socketmgr_create() is equivalent of isc_socketmgr_create2() with + * "maxsocks" being zero. + * isc_socketmgr_createinctx() also associates the new manager with the + * specified application context. + * + * Notes: + * + *\li All memory will be allocated in memory context 'mctx'. + * + * Requires: + * + *\li 'mctx' is a valid memory context. + * + *\li 'managerp' points to a NULL isc_socketmgr_t. + * + *\li 'actx' is a valid application context (for createinctx()). + * + * Ensures: + * + *\li '*managerp' is a valid isc_socketmgr_t. + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li #ISC_R_UNEXPECTED + *\li #ISC_R_NOTIMPLEMENTED + */ + +isc_result_t +isc_socketmgr_getmaxsockets(isc_socketmgr_t *manager, unsigned int *nsockp); +/*%< + * Returns in "*nsockp" the maximum number of sockets this manager may open. + * + * Requires: + * + *\li '*manager' is a valid isc_socketmgr_t. + *\li 'nsockp' is not NULL. + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOTIMPLEMENTED + */ + +void +isc_socketmgr_setstats(isc_socketmgr_t *manager, isc_stats_t *stats); +/*%< + * Set a general socket statistics counter set 'stats' for 'manager'. + * + * Requires: + * \li 'manager' is valid, hasn't opened any socket, and doesn't have + * stats already set. + * + *\li stats is a valid statistics supporting socket statistics counters + * (see above). + */ + +void +isc_socketmgr_destroy(isc_socketmgr_t **managerp); +/*%< + * Destroy a socket manager. + * + * Notes: + * + *\li This routine blocks until there are no sockets left in the manager, + * so if the caller holds any socket references using the manager, it + * must detach them before calling isc_socketmgr_destroy() or it will + * block forever. + * + * Requires: + * + *\li '*managerp' is a valid isc_socketmgr_t. + * + *\li All sockets managed by this manager are fully detached. + * + * Ensures: + * + *\li *managerp == NULL + * + *\li All resources used by the manager have been freed. + */ + +isc_sockettype_t +isc_socket_gettype(isc_socket_t *sock); +/*%< + * Returns the socket type for "sock." + * + * Requires: + * + *\li "sock" is a valid socket. + */ + +/*@{*/ +isc_boolean_t +isc_socket_isbound(isc_socket_t *sock); + +void +isc_socket_ipv6only(isc_socket_t *sock, isc_boolean_t yes); +/*%< + * If the socket is an IPv6 socket set/clear the IPV6_IPV6ONLY socket + * option if the host OS supports this option. + * + * Requires: + *\li 'sock' is a valid socket. + */ +/*@}*/ + +void +isc_socket_cleanunix(isc_sockaddr_t *addr, isc_boolean_t active); + +/*%< + * Cleanup UNIX domain sockets in the file-system. If 'active' is true + * then just unlink the socket. If 'active' is false try to determine + * if there is a listener of the socket or not. If no listener is found + * then unlink socket. + * + * Prior to unlinking the path is tested to see if it a socket. + * + * Note: there are a number of race conditions which cannot be avoided + * both in the filesystem and any application using UNIX domain + * sockets (e.g. socket is tested between bind() and listen(), + * the socket is deleted and replaced in the file-system between + * stat() and unlink()). + */ + +isc_result_t +isc_socket_permunix(isc_sockaddr_t *sockaddr, isc_uint32_t perm, + isc_uint32_t owner, isc_uint32_t group); +/*%< + * Set ownership and file permissions on the UNIX domain socket. + * + * Note: On Solaris and SunOS this secures the directory containing + * the socket as Solaris and SunOS do not honour the filesystem + * permissions on the socket. + * + * Requires: + * \li 'sockaddr' to be a valid UNIX domain sockaddr. + * + * Returns: + * \li #ISC_R_SUCCESS + * \li #ISC_R_FAILURE + */ + +void isc_socket_setname(isc_socket_t *sock, const char *name, void *tag); +/*%< + * Set the name and optional tag for a socket. This allows tracking of the + * owner or purpose for this socket, and is useful for tracing and statistics + * reporting. + */ + +const char *isc_socket_getname(isc_socket_t *sock); +/*%< + * Get the name associated with a socket, if any. + */ + +void *isc_socket_gettag(isc_socket_t *sock); +/*%< + * Get the tag associated with a socket, if any. + */ + +int isc_socket_getfd(isc_socket_t *sock); +/*%< + * Get the file descriptor associated with a socket + */ + +void +isc__socketmgr_setreserved(isc_socketmgr_t *mgr, isc_uint32_t); +/*%< + * Temporary. For use by named only. + */ + +void +isc__socketmgr_maxudp(isc_socketmgr_t *mgr, int maxudp); +/*%< + * Test interface. Drop UDP packet > 'maxudp'. + */ + +#ifdef HAVE_LIBXML2 + +void +isc_socketmgr_renderxml(isc_socketmgr_t *mgr, xmlTextWriterPtr writer); +/*%< + * Render internal statistics and other state into the XML document. + */ + +#endif /* HAVE_LIBXML2 */ + +#ifdef USE_SOCKETIMPREGISTER +/*%< + * See isc_socketmgr_create() above. + */ +typedef isc_result_t +(*isc_socketmgrcreatefunc_t)(isc_mem_t *mctx, isc_socketmgr_t **managerp); + +isc_result_t +isc_socket_register(isc_socketmgrcreatefunc_t createfunc); +/*%< + * Register a new socket I/O implementation and add it to the list of + * supported implementations. This function must be called when a different + * event library is used than the one contained in the ISC library. + */ + +isc_result_t +isc__socket_register(void); +/*%< + * A short cut function that specifies the socket I/O module in the ISC + * library for isc_socket_register(). An application that uses the ISC library + * usually do not have to care about this function: it would call + * isc_lib_register(), which internally calls this function. + */ +#endif /* USE_SOCKETIMPREGISTER */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_SOCKET_H */ diff --git a/contrib/ntp/lib/isc/include/isc/stats.h b/contrib/ntp/lib/isc/include/isc/stats.h new file mode 100644 index 0000000..682eefd --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/stats.h @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2009, 2012 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +#ifndef ISC_STATS_H +#define ISC_STATS_H 1 + +/*! \file isc/stats.h */ + +#include <isc/types.h> + +ISC_LANG_BEGINDECLS + +/*%< + * Flag(s) for isc_stats_dump(). + */ +#define ISC_STATSDUMP_VERBOSE 0x00000001 /*%< dump 0-value counters */ + +/*%< + * Dump callback type. + */ +typedef void (*isc_stats_dumper_t)(isc_statscounter_t, isc_uint64_t, void *); + +isc_result_t +isc_stats_create(isc_mem_t *mctx, isc_stats_t **statsp, int ncounters); +/*%< + * Create a statistics counter structure of general type. It counts a general + * set of counters indexed by an ID between 0 and ncounters -1. + * + * Requires: + *\li 'mctx' must be a valid memory context. + * + *\li 'statsp' != NULL && '*statsp' == NULL. + * + * Returns: + *\li ISC_R_SUCCESS -- all ok + * + *\li anything else -- failure + */ + +void +isc_stats_attach(isc_stats_t *stats, isc_stats_t **statsp); +/*%< + * Attach to a statistics set. + * + * Requires: + *\li 'stats' is a valid isc_stats_t. + * + *\li 'statsp' != NULL && '*statsp' == NULL + */ + +void +isc_stats_detach(isc_stats_t **statsp); +/*%< + * Detaches from the statistics set. + * + * Requires: + *\li 'statsp' != NULL and '*statsp' is a valid isc_stats_t. + */ + +int +isc_stats_ncounters(isc_stats_t *stats); +/*%< + * Returns the number of counters contained in stats. + * + * Requires: + *\li 'stats' is a valid isc_stats_t. + * + */ + +void +isc_stats_increment(isc_stats_t *stats, isc_statscounter_t counter); +/*%< + * Increment the counter-th counter of stats. + * + * Requires: + *\li 'stats' is a valid isc_stats_t. + * + *\li counter is less than the maximum available ID for the stats specified + * on creation. + */ + +void +isc_stats_decrement(isc_stats_t *stats, isc_statscounter_t counter); +/*%< + * Decrement the counter-th counter of stats. + * + * Requires: + *\li 'stats' is a valid isc_stats_t. + */ + +void +isc_stats_dump(isc_stats_t *stats, isc_stats_dumper_t dump_fn, void *arg, + unsigned int options); +/*%< + * Dump the current statistics counters in a specified way. For each counter + * in stats, dump_fn is called with its current value and the given argument + * arg. By default counters that have a value of 0 is skipped; if options has + * the ISC_STATSDUMP_VERBOSE flag, even such counters are dumped. + * + * Requires: + *\li 'stats' is a valid isc_stats_t. + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_STATS_H */ diff --git a/contrib/ntp/lib/isc/include/isc/stdio.h b/contrib/ntp/lib/isc/include/isc/stdio.h new file mode 100644 index 0000000..1a7ae64 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/stdio.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: stdio.h,v 1.13 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_STDIO_H +#define ISC_STDIO_H 1 + +/*! \file isc/stdio.h */ + +/*% + * These functions are wrappers around the corresponding stdio functions. + * + * They return a detailed error code in the form of an an isc_result_t. ANSI C + * does not guarantee that stdio functions set errno, hence these functions + * must use platform dependent methods (e.g., the POSIX errno) to construct the + * error code. + */ + +#include <stdio.h> + +#include <isc/lang.h> +#include <isc/result.h> + +ISC_LANG_BEGINDECLS + +/*% Open */ +isc_result_t +isc_stdio_open(const char *filename, const char *mode, FILE **fp); + +/*% Close */ +isc_result_t +isc_stdio_close(FILE *f); + +/*% Seek */ +isc_result_t +isc_stdio_seek(FILE *f, long offset, int whence); + +/*% Read */ +isc_result_t +isc_stdio_read(void *ptr, size_t size, size_t nmemb, FILE *f, + size_t *nret); + +/*% Write */ +isc_result_t +isc_stdio_write(const void *ptr, size_t size, size_t nmemb, FILE *f, + size_t *nret); + +/*% Flush */ +isc_result_t +isc_stdio_flush(FILE *f); + +isc_result_t +isc_stdio_sync(FILE *f); +/*%< + * Invoke fsync() on the file descriptor underlying an stdio stream, or an + * equivalent system-dependent operation. Note that this function has no + * direct counterpart in the stdio library. + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_STDIO_H */ diff --git a/contrib/ntp/lib/isc/include/isc/stdlib.h b/contrib/ntp/lib/isc/include/isc/stdlib.h new file mode 100644 index 0000000..02243f0 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/stdlib.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: stdlib.h,v 1.8 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_STDLIB_H +#define ISC_STDLIB_H 1 + +/*! \file isc/stdlib.h */ + +#include <stdlib.h> + +#include <isc/lang.h> +#include <isc/platform.h> + +#ifdef ISC_PLATFORM_NEEDSTRTOUL +#define strtoul isc_strtoul +#endif + +ISC_LANG_BEGINDECLS + +unsigned long isc_strtoul(const char *, char **, int); + +ISC_LANG_ENDDECLS + +#endif diff --git a/contrib/ntp/lib/isc/include/isc/string.h b/contrib/ntp/lib/isc/include/isc/string.h new file mode 100644 index 0000000..b49fdbc --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/string.h @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001, 2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: string.h,v 1.23 2007/09/13 04:48:16 each Exp $ */ + +#ifndef ISC_STRING_H +#define ISC_STRING_H 1 + +/*! \file isc/string.h */ + +#include <isc/formatcheck.h> +#include <isc/int.h> +#include <isc/lang.h> +#include <isc/platform.h> +#include <isc/types.h> + +#include <string.h> + +#ifdef ISC_PLATFORM_HAVESTRINGSH +#include <strings.h> +#endif + +#define ISC_STRING_MAGIC 0x5e + +ISC_LANG_BEGINDECLS + +isc_uint64_t +isc_string_touint64(char *source, char **endp, int base); +/*%< + * Convert the string pointed to by 'source' to isc_uint64_t. + * + * On successful conversion 'endp' points to the first character + * after conversion is complete. + * + * 'base': 0 or 2..36 + * + * If base is 0 the base is computed from the string type. + * + * On error 'endp' points to 'source'. + */ + +isc_result_t +isc_string_copy(char *target, size_t size, const char *source); +/* + * Copy the string pointed to by 'source' to 'target' which is a + * pointer to a string of at least 'size' bytes. + * + * Requires: + * 'target' is a pointer to a char[] of at least 'size' bytes. + * 'size' an integer > 0. + * 'source' == NULL or points to a NUL terminated string. + * + * Ensures: + * If result == ISC_R_SUCCESS + * 'target' will be a NUL terminated string of no more + * than 'size' bytes (including NUL). + * + * If result == ISC_R_NOSPACE + * 'target' is undefined. + * + * Returns: + * ISC_R_SUCCESS -- 'source' was successfully copied to 'target'. + * ISC_R_NOSPACE -- 'source' could not be copied since 'target' + * is too small. + */ + +void +isc_string_copy_truncate(char *target, size_t size, const char *source); +/* + * Copy the string pointed to by 'source' to 'target' which is a + * pointer to a string of at least 'size' bytes. + * + * Requires: + * 'target' is a pointer to a char[] of at least 'size' bytes. + * 'size' an integer > 0. + * 'source' == NULL or points to a NUL terminated string. + * + * Ensures: + * 'target' will be a NUL terminated string of no more + * than 'size' bytes (including NUL). + */ + +isc_result_t +isc_string_append(char *target, size_t size, const char *source); +/* + * Append the string pointed to by 'source' to 'target' which is a + * pointer to a NUL terminated string of at least 'size' bytes. + * + * Requires: + * 'target' is a pointer to a NUL terminated char[] of at + * least 'size' bytes. + * 'size' an integer > 0. + * 'source' == NULL or points to a NUL terminated string. + * + * Ensures: + * If result == ISC_R_SUCCESS + * 'target' will be a NUL terminated string of no more + * than 'size' bytes (including NUL). + * + * If result == ISC_R_NOSPACE + * 'target' is undefined. + * + * Returns: + * ISC_R_SUCCESS -- 'source' was successfully appended to 'target'. + * ISC_R_NOSPACE -- 'source' could not be appended since 'target' + * is too small. + */ + +void +isc_string_append_truncate(char *target, size_t size, const char *source); +/* + * Append the string pointed to by 'source' to 'target' which is a + * pointer to a NUL terminated string of at least 'size' bytes. + * + * Requires: + * 'target' is a pointer to a NUL terminated char[] of at + * least 'size' bytes. + * 'size' an integer > 0. + * 'source' == NULL or points to a NUL terminated string. + * + * Ensures: + * 'target' will be a NUL terminated string of no more + * than 'size' bytes (including NUL). + */ + +isc_result_t +isc_string_printf(char *target, size_t size, const char *format, ...) + ISC_FORMAT_PRINTF(3, 4); +/* + * Print 'format' to 'target' which is a pointer to a string of at least + * 'size' bytes. + * + * Requires: + * 'target' is a pointer to a char[] of at least 'size' bytes. + * 'size' an integer > 0. + * 'format' == NULL or points to a NUL terminated string. + * + * Ensures: + * If result == ISC_R_SUCCESS + * 'target' will be a NUL terminated string of no more + * than 'size' bytes (including NUL). + * + * If result == ISC_R_NOSPACE + * 'target' is undefined. + * + * Returns: + * ISC_R_SUCCESS -- 'format' was successfully printed to 'target'. + * ISC_R_NOSPACE -- 'format' could not be printed to 'target' since it + * is too small. + */ + +void +isc_string_printf_truncate(char *target, size_t size, const char *format, ...) + ISC_FORMAT_PRINTF(3, 4); +/* + * Print 'format' to 'target' which is a pointer to a string of at least + * 'size' bytes. + * + * Requires: + * 'target' is a pointer to a char[] of at least 'size' bytes. + * 'size' an integer > 0. + * 'format' == NULL or points to a NUL terminated string. + * + * Ensures: + * 'target' will be a NUL terminated string of no more + * than 'size' bytes (including NUL). + */ + + +char * +isc_string_regiondup(isc_mem_t *mctx, const isc_region_t *source); +/* + * Copy the region pointed to by r to a NUL terminated string + * allocated from the memory context pointed to by mctx. + * + * The result should be deallocated using isc_mem_free() + * + * Requires: + * 'mctx' is a point to a valid memory context. + * 'source' is a pointer to a valid region. + * + * Returns: + * a pointer to a NUL terminated string or + * NULL if memory for the copy could not be allocated + * + */ + +char * +isc_string_separate(char **stringp, const char *delim); + +#ifdef ISC_PLATFORM_NEEDSTRSEP +#define strsep isc_string_separate +#endif + +#ifdef ISC_PLATFORM_NEEDMEMMOVE +#define memmove(a,b,c) bcopy(b,a,c) +#endif + +size_t +isc_string_strlcpy(char *dst, const char *src, size_t size); + + +#ifdef ISC_PLATFORM_NEEDSTRLCPY +#define strlcpy isc_string_strlcpy +#endif + + +size_t +isc_string_strlcat(char *dst, const char *src, size_t size); + +#ifdef ISC_PLATFORM_NEEDSTRLCAT +#define strlcat isc_string_strlcat +#endif + +ISC_LANG_ENDDECLS + +#endif /* ISC_STRING_H */ diff --git a/contrib/ntp/lib/isc/include/isc/symtab.h b/contrib/ntp/lib/isc/include/isc/symtab.h new file mode 100644 index 0000000..9d0e5e2f --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/symtab.h @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2004-2007, 2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1996-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +#ifndef ISC_SYMTAB_H +#define ISC_SYMTAB_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file isc/symtab.h + * \brief Provides a simple memory-based symbol table. + * + * Keys are C strings, and key comparisons are case-insensitive. A type may + * be specified when looking up, defining, or undefining. A type value of + * 0 means "match any type"; any other value will only match the given + * type. + * + * It's possible that a client will attempt to define a <key, type, value> + * tuple when a tuple with the given key and type already exists in the table. + * What to do in this case is specified by the client. Possible policies are: + * + *\li #isc_symexists_reject Disallow the define, returning #ISC_R_EXISTS + *\li #isc_symexists_replace Replace the old value with the new. The + * undefine action (if provided) will be called + * with the old <key, type, value> tuple. + *\li #isc_symexists_add Add the new tuple, leaving the old tuple in + * the table. Subsequent lookups will retrieve + * the most-recently-defined tuple. + * + * A lookup of a key using type 0 will return the most-recently defined + * symbol with that key. An undefine of a key using type 0 will undefine the + * most-recently defined symbol with that key. Trying to define a key with + * type 0 is illegal. + * + * The symbol table library does not make a copy the key field, so the + * caller must ensure that any key it passes to isc_symtab_define() will not + * change until it calls isc_symtab_undefine() or isc_symtab_destroy(). + * + * A user-specified action will be called (if provided) when a symbol is + * undefined. It can be used to free memory associated with keys and/or + * values. + * + * A symbol table is implemented as a hash table of lists; the size of the + * hash table is set by the 'size' parameter to isc_symtbl_create(). When + * the number of entries in the symbol table reaches three quarters of this + * value, the hash table is reallocated with size doubled, in order to + * optimize lookup performance. This has a negative effect on insertion + * performance, which can be mitigated by sizing the table appropriately + * when creating it. + * + * \li MP: + * The callers of this module must ensure any required synchronization. + * + * \li Reliability: + * No anticipated impact. + * + * \li Resources: + * TBS + * + * \li Security: + * No anticipated impact. + * + * \li Standards: + * None. + */ + +/*** + *** Imports. + ***/ + +#include <isc/lang.h> +#include <isc/types.h> + +/* + *** Symbol Tables. + ***/ +/*% Symbol table value. */ +typedef union isc_symvalue { + void * as_pointer; + const void * as_cpointer; + int as_integer; + unsigned int as_uinteger; +} isc_symvalue_t; + +typedef void (*isc_symtabaction_t)(char *key, unsigned int type, + isc_symvalue_t value, void *userarg); +/*% Symbol table exists. */ +typedef enum { + isc_symexists_reject = 0, /*%< Disallow the define */ + isc_symexists_replace = 1, /*%< Replace the old value with the new */ + isc_symexists_add = 2 /*%< Add the new tuple */ +} isc_symexists_t; + +ISC_LANG_BEGINDECLS + +/*% Create a symbol table. */ +isc_result_t +isc_symtab_create(isc_mem_t *mctx, unsigned int size, + isc_symtabaction_t undefine_action, void *undefine_arg, + isc_boolean_t case_sensitive, isc_symtab_t **symtabp); + +/*% Destroy a symbol table. */ +void +isc_symtab_destroy(isc_symtab_t **symtabp); + +/*% Lookup a symbol table. */ +isc_result_t +isc_symtab_lookup(isc_symtab_t *symtab, const char *key, unsigned int type, + isc_symvalue_t *value); + +/*% Define a symbol table. */ +isc_result_t +isc_symtab_define(isc_symtab_t *symtab, const char *key, unsigned int type, + isc_symvalue_t value, isc_symexists_t exists_policy); + +/*% Undefine a symbol table. */ +isc_result_t +isc_symtab_undefine(isc_symtab_t *symtab, const char *key, unsigned int type); + +ISC_LANG_ENDDECLS + +#endif /* ISC_SYMTAB_H */ diff --git a/contrib/ntp/lib/isc/include/isc/task.h b/contrib/ntp/lib/isc/include/isc/task.h new file mode 100644 index 0000000..594d80f --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/task.h @@ -0,0 +1,796 @@ +/* + * Copyright (C) 2004-2007, 2009-2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2001, 2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +#ifndef ISC_TASK_H +#define ISC_TASK_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file isc/task.h + * \brief The task system provides a lightweight execution context, which is + * basically an event queue. + + * When a task's event queue is non-empty, the + * task is runnable. A small work crew of threads, typically one per CPU, + * execute runnable tasks by dispatching the events on the tasks' event + * queues. Context switching between tasks is fast. + * + * \li MP: + * The module ensures appropriate synchronization of data structures it + * creates and manipulates. + * The caller must ensure that isc_taskmgr_destroy() is called only + * once for a given manager. + * + * \li Reliability: + * No anticipated impact. + * + * \li Resources: + * TBS + * + * \li Security: + * No anticipated impact. + * + * \li Standards: + * None. + * + * \section purge Purging and Unsending + * + * Events which have been queued for a task but not delivered may be removed + * from the task's event queue by purging or unsending. + * + * With both types, the caller specifies a matching pattern that selects + * events based upon their sender, type, and tag. + * + * Purging calls isc_event_free() on the matching events. + * + * Unsending returns a list of events that matched the pattern. + * The caller is then responsible for them. + * + * Consumers of events should purge, not unsend. + * + * Producers of events often want to remove events when the caller indicates + * it is no longer interested in the object, e.g. by canceling a timer. + * Sometimes this can be done by purging, but for some event types, the + * calls to isc_event_free() cause deadlock because the event free routine + * wants to acquire a lock the caller is already holding. Unsending instead + * of purging solves this problem. As a general rule, producers should only + * unsend events which they have sent. + */ + + +/*** + *** Imports. + ***/ + +#include <isc/eventclass.h> +#include <isc/lang.h> +#include <isc/stdtime.h> +#include <isc/types.h> +#include <isc/xml.h> + +#define ISC_TASKEVENT_FIRSTEVENT (ISC_EVENTCLASS_TASK + 0) +#define ISC_TASKEVENT_SHUTDOWN (ISC_EVENTCLASS_TASK + 1) +#define ISC_TASKEVENT_TEST (ISC_EVENTCLASS_TASK + 1) +#define ISC_TASKEVENT_LASTEVENT (ISC_EVENTCLASS_TASK + 65535) + +/***** + ***** Tasks. + *****/ + +ISC_LANG_BEGINDECLS + +/*** + *** Types + ***/ + +typedef enum { + isc_taskmgrmode_normal = 0, + isc_taskmgrmode_privileged +} isc_taskmgrmode_t; + +/*% Task and task manager methods */ +typedef struct isc_taskmgrmethods { + void (*destroy)(isc_taskmgr_t **managerp); + void (*setmode)(isc_taskmgr_t *manager, + isc_taskmgrmode_t mode); + isc_taskmgrmode_t (*mode)(isc_taskmgr_t *manager); + isc_result_t (*taskcreate)(isc_taskmgr_t *manager, + unsigned int quantum, + isc_task_t **taskp); +} isc_taskmgrmethods_t; + +typedef struct isc_taskmethods { + void (*attach)(isc_task_t *source, isc_task_t **targetp); + void (*detach)(isc_task_t **taskp); + void (*destroy)(isc_task_t **taskp); + void (*send)(isc_task_t *task, isc_event_t **eventp); + void (*sendanddetach)(isc_task_t **taskp, isc_event_t **eventp); + unsigned int (*unsend)(isc_task_t *task, void *sender, isc_eventtype_t type, + void *tag, isc_eventlist_t *events); + isc_result_t (*onshutdown)(isc_task_t *task, isc_taskaction_t action, + const void *arg); + void (*shutdown)(isc_task_t *task); + void (*setname)(isc_task_t *task, const char *name, void *tag); + unsigned int (*purgeevents)(isc_task_t *task, void *sender, + isc_eventtype_t type, void *tag); + unsigned int (*purgerange)(isc_task_t *task, void *sender, + isc_eventtype_t first, isc_eventtype_t last, + void *tag); + isc_result_t (*beginexclusive)(isc_task_t *task); + void (*endexclusive)(isc_task_t *task); + void (*setprivilege)(isc_task_t *task, isc_boolean_t priv); + isc_boolean_t (*privilege)(isc_task_t *task); +} isc_taskmethods_t; + +/*% + * This structure is actually just the common prefix of a task manager + * object implementation's version of an isc_taskmgr_t. + * \brief + * Direct use of this structure by clients is forbidden. task implementations + * may change the structure. 'magic' must be ISCAPI_TASKMGR_MAGIC for any + * of the isc_task_ routines to work. task implementations must maintain + * all task invariants. + */ +struct isc_taskmgr { + unsigned int impmagic; + unsigned int magic; + isc_taskmgrmethods_t *methods; +}; + +#define ISCAPI_TASKMGR_MAGIC ISC_MAGIC('A','t','m','g') +#define ISCAPI_TASKMGR_VALID(m) ((m) != NULL && \ + (m)->magic == ISCAPI_TASKMGR_MAGIC) + +/*% + * This is the common prefix of a task object. The same note as + * that for the taskmgr structure applies. + */ +struct isc_task { + unsigned int impmagic; + unsigned int magic; + isc_taskmethods_t *methods; +}; + +#define ISCAPI_TASK_MAGIC ISC_MAGIC('A','t','s','t') +#define ISCAPI_TASK_VALID(s) ((s) != NULL && \ + (s)->magic == ISCAPI_TASK_MAGIC) + +isc_result_t +isc_task_create(isc_taskmgr_t *manager, unsigned int quantum, + isc_task_t **taskp); +/*%< + * Create a task. + * + * Notes: + * + *\li If 'quantum' is non-zero, then only that many events can be dispatched + * before the task must yield to other tasks waiting to execute. If + * quantum is zero, then the default quantum of the task manager will + * be used. + * + *\li The 'quantum' option may be removed from isc_task_create() in the + * future. If this happens, isc_task_getquantum() and + * isc_task_setquantum() will be provided. + * + * Requires: + * + *\li 'manager' is a valid task manager. + * + *\li taskp != NULL && *taskp == NULL + * + * Ensures: + * + *\li On success, '*taskp' is bound to the new task. + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li #ISC_R_UNEXPECTED + *\li #ISC_R_SHUTTINGDOWN + */ + +void +isc_task_attach(isc_task_t *source, isc_task_t **targetp); +/*%< + * Attach *targetp to source. + * + * Requires: + * + *\li 'source' is a valid task. + * + *\li 'targetp' points to a NULL isc_task_t *. + * + * Ensures: + * + *\li *targetp is attached to source. + */ + +void +isc_task_detach(isc_task_t **taskp); +/*%< + * Detach *taskp from its task. + * + * Requires: + * + *\li '*taskp' is a valid task. + * + * Ensures: + * + *\li *taskp is NULL. + * + *\li If '*taskp' is the last reference to the task, the task is idle (has + * an empty event queue), and has not been shutdown, the task will be + * shutdown. + * + *\li If '*taskp' is the last reference to the task and + * the task has been shutdown, + * all resources used by the task will be freed. + */ + +void +isc_task_send(isc_task_t *task, isc_event_t **eventp); +/*%< + * Send '*event' to 'task'. + * + * Requires: + * + *\li 'task' is a valid task. + *\li eventp != NULL && *eventp != NULL. + * + * Ensures: + * + *\li *eventp == NULL. + */ + +void +isc_task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp); +/*%< + * Send '*event' to '*taskp' and then detach '*taskp' from its + * task. + * + * Requires: + * + *\li '*taskp' is a valid task. + *\li eventp != NULL && *eventp != NULL. + * + * Ensures: + * + *\li *eventp == NULL. + * + *\li *taskp == NULL. + * + *\li If '*taskp' is the last reference to the task, the task is + * idle (has an empty event queue), and has not been shutdown, + * the task will be shutdown. + * + *\li If '*taskp' is the last reference to the task and + * the task has been shutdown, + * all resources used by the task will be freed. + */ + + +unsigned int +isc_task_purgerange(isc_task_t *task, void *sender, isc_eventtype_t first, + isc_eventtype_t last, void *tag); +/*%< + * Purge events from a task's event queue. + * + * Requires: + * + *\li 'task' is a valid task. + * + *\li last >= first + * + * Ensures: + * + *\li Events in the event queue of 'task' whose sender is 'sender', whose + * type is >= first and <= last, and whose tag is 'tag' will be purged, + * unless they are marked as unpurgable. + * + *\li A sender of NULL will match any sender. A NULL tag matches any + * tag. + * + * Returns: + * + *\li The number of events purged. + */ + +unsigned int +isc_task_purge(isc_task_t *task, void *sender, isc_eventtype_t type, + void *tag); +/*%< + * Purge events from a task's event queue. + * + * Notes: + * + *\li This function is equivalent to + * + *\code + * isc_task_purgerange(task, sender, type, type, tag); + *\endcode + * + * Requires: + * + *\li 'task' is a valid task. + * + * Ensures: + * + *\li Events in the event queue of 'task' whose sender is 'sender', whose + * type is 'type', and whose tag is 'tag' will be purged, unless they + * are marked as unpurgable. + * + *\li A sender of NULL will match any sender. A NULL tag matches any + * tag. + * + * Returns: + * + *\li The number of events purged. + */ + +isc_boolean_t +isc_task_purgeevent(isc_task_t *task, isc_event_t *event); +/*%< + * Purge 'event' from a task's event queue. + * + * XXXRTH: WARNING: This method may be removed before beta. + * + * Notes: + * + *\li If 'event' is on the task's event queue, it will be purged, + * unless it is marked as unpurgeable. 'event' does not have to be + * on the task's event queue; in fact, it can even be an invalid + * pointer. Purging only occurs if the event is actually on the task's + * event queue. + * + * \li Purging never changes the state of the task. + * + * Requires: + * + *\li 'task' is a valid task. + * + * Ensures: + * + *\li 'event' is not in the event queue for 'task'. + * + * Returns: + * + *\li #ISC_TRUE The event was purged. + *\li #ISC_FALSE The event was not in the event queue, + * or was marked unpurgeable. + */ + +unsigned int +isc_task_unsendrange(isc_task_t *task, void *sender, isc_eventtype_t first, + isc_eventtype_t last, void *tag, isc_eventlist_t *events); +/*%< + * Remove events from a task's event queue. + * + * Requires: + * + *\li 'task' is a valid task. + * + *\li last >= first. + * + *\li *events is a valid list. + * + * Ensures: + * + *\li Events in the event queue of 'task' whose sender is 'sender', whose + * type is >= first and <= last, and whose tag is 'tag' will be dequeued + * and appended to *events. + * + *\li A sender of NULL will match any sender. A NULL tag matches any + * tag. + * + * Returns: + * + *\li The number of events unsent. + */ + +unsigned int +isc_task_unsend(isc_task_t *task, void *sender, isc_eventtype_t type, + void *tag, isc_eventlist_t *events); +/*%< + * Remove events from a task's event queue. + * + * Notes: + * + *\li This function is equivalent to + * + *\code + * isc_task_unsendrange(task, sender, type, type, tag, events); + *\endcode + * + * Requires: + * + *\li 'task' is a valid task. + * + *\li *events is a valid list. + * + * Ensures: + * + *\li Events in the event queue of 'task' whose sender is 'sender', whose + * type is 'type', and whose tag is 'tag' will be dequeued and appended + * to *events. + * + * Returns: + * + *\li The number of events unsent. + */ + +isc_result_t +isc_task_onshutdown(isc_task_t *task, isc_taskaction_t action, + const void *arg); +/*%< + * Send a shutdown event with action 'action' and argument 'arg' when + * 'task' is shutdown. + * + * Notes: + * + *\li Shutdown events are posted in LIFO order. + * + * Requires: + * + *\li 'task' is a valid task. + * + *\li 'action' is a valid task action. + * + * Ensures: + * + *\li When the task is shutdown, shutdown events requested with + * isc_task_onshutdown() will be appended to the task's event queue. + * + + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li #ISC_R_TASKSHUTTINGDOWN Task is shutting down. + */ + +void +isc_task_shutdown(isc_task_t *task); +/*%< + * Shutdown 'task'. + * + * Notes: + * + *\li Shutting down a task causes any shutdown events requested with + * isc_task_onshutdown() to be posted (in LIFO order). The task + * moves into a "shutting down" mode which prevents further calls + * to isc_task_onshutdown(). + * + *\li Trying to shutdown a task that has already been shutdown has no + * effect. + * + * Requires: + * + *\li 'task' is a valid task. + * + * Ensures: + * + *\li Any shutdown events requested with isc_task_onshutdown() have been + * posted (in LIFO order). + */ + +void +isc_task_destroy(isc_task_t **taskp); +/*%< + * Destroy '*taskp'. + * + * Notes: + * + *\li This call is equivalent to: + * + *\code + * isc_task_shutdown(*taskp); + * isc_task_detach(taskp); + *\endcode + * + * Requires: + * + * '*taskp' is a valid task. + * + * Ensures: + * + *\li Any shutdown events requested with isc_task_onshutdown() have been + * posted (in LIFO order). + * + *\li *taskp == NULL + * + *\li If '*taskp' is the last reference to the task, + * all resources used by the task will be freed. + */ + +void +isc_task_setname(isc_task_t *task, const char *name, void *tag); +/*%< + * Name 'task'. + * + * Notes: + * + *\li Only the first 15 characters of 'name' will be copied. + * + *\li Naming a task is currently only useful for debugging purposes. + * + * Requires: + * + *\li 'task' is a valid task. + */ + +const char * +isc_task_getname(isc_task_t *task); +/*%< + * Get the name of 'task', as previously set using isc_task_setname(). + * + * Notes: + *\li This function is for debugging purposes only. + * + * Requires: + *\li 'task' is a valid task. + * + * Returns: + *\li A non-NULL pointer to a null-terminated string. + * If the task has not been named, the string is + * empty. + * + */ + +void * +isc_task_gettag(isc_task_t *task); +/*%< + * Get the tag value for 'task', as previously set using isc_task_settag(). + * + * Notes: + *\li This function is for debugging purposes only. + * + * Requires: + *\li 'task' is a valid task. + */ + +isc_result_t +isc_task_beginexclusive(isc_task_t *task); +/*%< + * Request exclusive access for 'task', which must be the calling + * task. Waits for any other concurrently executing tasks to finish their + * current event, and prevents any new events from executing in any of the + * tasks sharing a task manager with 'task'. + * + * The exclusive access must be relinquished by calling + * isc_task_endexclusive() before returning from the current event handler. + * + * Requires: + *\li 'task' is the calling task. + * + * Returns: + *\li #ISC_R_SUCCESS The current task now has exclusive access. + *\li #ISC_R_LOCKBUSY Another task has already requested exclusive + * access. + */ + +void +isc_task_endexclusive(isc_task_t *task); +/*%< + * Relinquish the exclusive access obtained by isc_task_beginexclusive(), + * allowing other tasks to execute. + * + * Requires: + *\li 'task' is the calling task, and has obtained + * exclusive access by calling isc_task_spl(). + */ + +void +isc_task_getcurrenttime(isc_task_t *task, isc_stdtime_t *t); +/*%< + * Provide the most recent timestamp on the task. The timestamp is considered + * as the "current time" in the second-order granularity. + * + * Requires: + *\li 'task' is a valid task. + *\li 't' is a valid non NULL pointer. + * + * Ensures: + *\li '*t' has the "current time". + */ + +isc_boolean_t +isc_task_exiting(isc_task_t *t); +/*%< + * Returns ISC_TRUE if the task is in the process of shutting down, + * ISC_FALSE otherwise. + * + * Requires: + *\li 'task' is a valid task. + */ + +void +isc_task_setprivilege(isc_task_t *task, isc_boolean_t priv); +/*%< + * Set or unset the task's "privileged" flag depending on the value of + * 'priv'. + * + * Under normal circumstances this flag has no effect on the task behavior, + * but when the task manager has been set to privileged exeuction mode via + * isc_taskmgr_setmode(), only tasks with the flag set will be executed, + * and all other tasks will wait until they're done. Once all privileged + * tasks have finished executing, the task manager will automatically + * return to normal execution mode and nonprivileged task can resume. + * + * Requires: + *\li 'task' is a valid task. + */ + +isc_boolean_t +isc_task_privilege(isc_task_t *task); +/*%< + * Returns the current value of the task's privilege flag. + * + * Requires: + *\li 'task' is a valid task. + */ + +/***** + ***** Task Manager. + *****/ + +isc_result_t +isc_taskmgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx, + unsigned int workers, unsigned int default_quantum, + isc_taskmgr_t **managerp); +isc_result_t +isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers, + unsigned int default_quantum, isc_taskmgr_t **managerp); +/*%< + * Create a new task manager. isc_taskmgr_createinctx() also associates + * the new manager with the specified application context. + * + * Notes: + * + *\li 'workers' in the number of worker threads to create. In general, + * the value should be close to the number of processors in the system. + * The 'workers' value is advisory only. An attempt will be made to + * create 'workers' threads, but if at least one thread creation + * succeeds, isc_taskmgr_create() may return ISC_R_SUCCESS. + * + *\li If 'default_quantum' is non-zero, then it will be used as the default + * quantum value when tasks are created. If zero, then an implementation + * defined default quantum will be used. + * + * Requires: + * + *\li 'mctx' is a valid memory context. + * + *\li workers > 0 + * + *\li managerp != NULL && *managerp == NULL + * + *\li 'actx' is a valid application context (for createinctx()). + * + * Ensures: + * + *\li On success, '*managerp' will be attached to the newly created task + * manager. + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li #ISC_R_NOTHREADS No threads could be created. + *\li #ISC_R_UNEXPECTED An unexpected error occurred. + *\li #ISC_R_SHUTTINGDOWN The non-threaded, shared, task + * manager shutting down. + */ + +void +isc_taskmgr_setmode(isc_taskmgr_t *manager, isc_taskmgrmode_t mode); + +isc_taskmgrmode_t +isc_taskmgr_mode(isc_taskmgr_t *manager); +/*%< + * Set/get the current operating mode of the task manager. Valid modes are: + * + *\li isc_taskmgrmode_normal + *\li isc_taskmgrmode_privileged + * + * In privileged execution mode, only tasks that have had the "privilege" + * flag set via isc_task_setprivilege() can be executed. When all such + * tasks are complete, the manager automatically returns to normal mode + * and proceeds with running non-privileged ready tasks. This means it is + * necessary to have at least one privileged task waiting on the ready + * queue *before* setting the manager into privileged execution mode, + * which in turn means the task which calls this function should be in + * task-exclusive mode when it does so. + * + * Requires: + * + *\li 'manager' is a valid task manager. + */ + +void +isc_taskmgr_destroy(isc_taskmgr_t **managerp); +/*%< + * Destroy '*managerp'. + * + * Notes: + * + *\li Calling isc_taskmgr_destroy() will shutdown all tasks managed by + * *managerp that haven't already been shutdown. The call will block + * until all tasks have entered the done state. + * + *\li isc_taskmgr_destroy() must not be called by a task event action, + * because it would block forever waiting for the event action to + * complete. An event action that wants to cause task manager shutdown + * should request some non-event action thread of execution to do the + * shutdown, e.g. by signaling a condition variable or using + * isc_app_shutdown(). + * + *\li Task manager references are not reference counted, so the caller + * must ensure that no attempt will be made to use the manager after + * isc_taskmgr_destroy() returns. + * + * Requires: + * + *\li '*managerp' is a valid task manager. + * + *\li isc_taskmgr_destroy() has not be called previously on '*managerp'. + * + * Ensures: + * + *\li All resources used by the task manager, and any tasks it managed, + * have been freed. + */ + +#ifdef HAVE_LIBXML2 + +void +isc_taskmgr_renderxml(isc_taskmgr_t *mgr, xmlTextWriterPtr writer); + +#endif + +/*%< + * See isc_taskmgr_create() above. + */ +typedef isc_result_t +(*isc_taskmgrcreatefunc_t)(isc_mem_t *mctx, unsigned int workers, + unsigned int default_quantum, + isc_taskmgr_t **managerp); + +isc_result_t +isc_task_register(isc_taskmgrcreatefunc_t createfunc); +/*%< + * Register a new task management implementation and add it to the list of + * supported implementations. This function must be called when a different + * event library is used than the one contained in the ISC library. + */ + +isc_result_t +isc__task_register(void); +/*%< + * A short cut function that specifies the task management module in the ISC + * library for isc_task_register(). An application that uses the ISC library + * usually do not have to care about this function: it would call + * isc_lib_register(), which internally calls this function. + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_TASK_H */ diff --git a/contrib/ntp/lib/isc/include/isc/taskpool.h b/contrib/ntp/lib/isc/include/isc/taskpool.h new file mode 100644 index 0000000..46f395e --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/taskpool.h @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2004-2007, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +#ifndef ISC_TASKPOOL_H +#define ISC_TASKPOOL_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file isc/taskpool.h + * \brief A task pool is a mechanism for sharing a small number of tasks + * among a large number of objects such that each object is + * assigned a unique task, but each task may be shared by several + * objects. + * + * Task pools are used to let objects that can exist in large + * numbers (e.g., zones) use tasks for synchronization without + * the memory overhead and unfair scheduling competition that + * could result from creating a separate task for each object. + */ + + +/*** + *** Imports. + ***/ + +#include <isc/lang.h> +#include <isc/task.h> + +ISC_LANG_BEGINDECLS + +/***** + ***** Types. + *****/ + +typedef struct isc_taskpool isc_taskpool_t; + +/***** + ***** Functions. + *****/ + +isc_result_t +isc_taskpool_create(isc_taskmgr_t *tmgr, isc_mem_t *mctx, + unsigned int ntasks, unsigned int quantum, + isc_taskpool_t **poolp); +/*%< + * Create a task pool of "ntasks" tasks, each with quantum + * "quantum". + * + * Requires: + * + *\li 'tmgr' is a valid task manager. + * + *\li 'mctx' is a valid memory context. + * + *\li poolp != NULL && *poolp == NULL + * + * Ensures: + * + *\li On success, '*taskp' points to the new task pool. + * + * Returns: + * + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li #ISC_R_UNEXPECTED + */ + +void +isc_taskpool_gettask(isc_taskpool_t *pool, isc_task_t **targetp); +/*%< + * Attach to a task from the pool. Currently the next task is chosen + * from the pool at random. (This may be changed in the future to + * something that guaratees balance.) + */ + +int +isc_taskpool_size(isc_taskpool_t *pool); +/*%< + * Returns the number of tasks in the task pool 'pool'. + */ + +isc_result_t +isc_taskpool_expand(isc_taskpool_t **sourcep, unsigned int size, + isc_taskpool_t **targetp); + +/*%< + * If 'size' is larger than the number of tasks in the pool pointed to by + * 'sourcep', then a new taskpool of size 'size' is allocated, the existing + * tasks from are moved into it, additional tasks are created to bring the + * total number up to 'size', and the resulting pool is attached to + * 'targetp'. + * + * If 'size' is less than or equal to the tasks in pool 'source', then + * 'sourcep' is attached to 'targetp' without any other action being taken. + * + * In either case, 'sourcep' is detached. + * + * Requires: + * + * \li 'sourcep' is not NULL and '*source' is not NULL + * \li 'targetp' is not NULL and '*source' is NULL + * + * Ensures: + * + * \li On success, '*targetp' points to a valid task pool. + * \li On success, '*sourcep' points to NULL. + * + * Returns: + * + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOMEMORY + */ + +void +isc_taskpool_destroy(isc_taskpool_t **poolp); +/*%< + * Destroy a task pool. The tasks in the pool are detached but not + * shut down. + * + * Requires: + * \li '*poolp' is a valid task pool. + */ + +void +isc_taskpool_setprivilege(isc_taskpool_t *pool, isc_boolean_t priv); +/*%< + * Set the privilege flag on all tasks in 'pool' to 'priv'. If 'priv' is + * true, then when the task manager is set into privileged mode, only + * tasks wihin this pool will be able to execute. (Note: It is important + * to turn the pool tasks' privilege back off before the last task finishes + * executing.) + * + * Requires: + * \li 'pool' is a valid task pool. + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_TASKPOOL_H */ diff --git a/contrib/ntp/lib/isc/include/isc/timer.h b/contrib/ntp/lib/isc/include/isc/timer.h new file mode 100644 index 0000000..fa9abb1 --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/timer.h @@ -0,0 +1,431 @@ +/* + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: timer.h,v 1.43 2009/09/02 23:48:03 tbox Exp $ */ + +#ifndef ISC_TIMER_H +#define ISC_TIMER_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file isc/timer.h + * \brief Provides timers which are event sources in the task system. + * + * Three types of timers are supported: + * + *\li 'ticker' timers generate a periodic tick event. + * + *\li 'once' timers generate an idle timeout event if they are idle for too + * long, and generate a life timeout event if their lifetime expires. + * They are used to implement both (possibly expiring) idle timers and + * 'one-shot' timers. + * + *\li 'limited' timers generate a periodic tick event until they reach + * their lifetime when they generate a life timeout event. + * + *\li 'inactive' timers generate no events. + * + * Timers can change type. It is typical to create a timer as + * an 'inactive' timer and then change it into a 'ticker' or + * 'once' timer. + * + *\li MP: + * The module ensures appropriate synchronization of data structures it + * creates and manipulates. + * Clients of this module must not be holding a timer's task's lock when + * making a call that affects that timer. Failure to follow this rule + * can result in deadlock. + * The caller must ensure that isc_timermgr_destroy() is called only + * once for a given manager. + * + * \li Reliability: + * No anticipated impact. + * + * \li Resources: + * TBS + * + * \li Security: + * No anticipated impact. + * + * \li Standards: + * None. + */ + + +/*** + *** Imports + ***/ + +#include <isc/types.h> +#include <isc/event.h> +#include <isc/eventclass.h> +#include <isc/lang.h> +#include <isc/time.h> + +ISC_LANG_BEGINDECLS + +/*** + *** Types + ***/ + +/*% Timer Type */ +typedef enum { + isc_timertype_ticker = 0, /*%< Ticker */ + isc_timertype_once = 1, /*%< Once */ + isc_timertype_limited = 2, /*%< Limited */ + isc_timertype_inactive = 3 /*%< Inactive */ +} isc_timertype_t; + +typedef struct isc_timerevent { + struct isc_event common; + isc_time_t due; +} isc_timerevent_t; + +#define ISC_TIMEREVENT_FIRSTEVENT (ISC_EVENTCLASS_TIMER + 0) +#define ISC_TIMEREVENT_TICK (ISC_EVENTCLASS_TIMER + 1) +#define ISC_TIMEREVENT_IDLE (ISC_EVENTCLASS_TIMER + 2) +#define ISC_TIMEREVENT_LIFE (ISC_EVENTCLASS_TIMER + 3) +#define ISC_TIMEREVENT_LASTEVENT (ISC_EVENTCLASS_TIMER + 65535) + +/*% Timer and timer manager methods */ +typedef struct { + void (*destroy)(isc_timermgr_t **managerp); + isc_result_t (*timercreate)(isc_timermgr_t *manager, + isc_timertype_t type, + isc_time_t *expires, + isc_interval_t *interval, + isc_task_t *task, + isc_taskaction_t action, + const void *arg, + isc_timer_t **timerp); +} isc_timermgrmethods_t; + +typedef struct { + void (*attach)(isc_timer_t *timer, isc_timer_t **timerp); + void (*detach)(isc_timer_t **timerp); + isc_result_t (*reset)(isc_timer_t *timer, isc_timertype_t type, + isc_time_t *expires, isc_interval_t *interval, + isc_boolean_t purge); + isc_result_t (*touch)(isc_timer_t *timer); +} isc_timermethods_t; + +/*% + * This structure is actually just the common prefix of a timer manager + * object implementation's version of an isc_timermgr_t. + * \brief + * Direct use of this structure by clients is forbidden. timer implementations + * may change the structure. 'magic' must be ISCAPI_TIMERMGR_MAGIC for any + * of the isc_timer_ routines to work. timer implementations must maintain + * all timer invariants. + */ +struct isc_timermgr { + unsigned int impmagic; + unsigned int magic; + isc_timermgrmethods_t *methods; +}; + +#define ISCAPI_TIMERMGR_MAGIC ISC_MAGIC('A','t','m','g') +#define ISCAPI_TIMERMGR_VALID(m) ((m) != NULL && \ + (m)->magic == ISCAPI_TIMERMGR_MAGIC) + +/*% + * This is the common prefix of a timer object. The same note as + * that for the timermgr structure applies. + */ +struct isc_timer { + unsigned int impmagic; + unsigned int magic; + isc_timermethods_t *methods; +}; + +#define ISCAPI_TIMER_MAGIC ISC_MAGIC('A','t','m','r') +#define ISCAPI_TIMER_VALID(s) ((s) != NULL && \ + (s)->magic == ISCAPI_TIMER_MAGIC) + +/*** + *** Timer and Timer Manager Functions + *** + *** Note: all Ensures conditions apply only if the result is success for + *** those functions which return an isc_result_t. + ***/ + +isc_result_t +isc_timer_create(isc_timermgr_t *manager, + isc_timertype_t type, + isc_time_t *expires, + isc_interval_t *interval, + isc_task_t *task, + isc_taskaction_t action, + const void *arg, + isc_timer_t **timerp); +/*%< + * Create a new 'type' timer managed by 'manager'. The timers parameters + * are specified by 'expires' and 'interval'. Events will be posted to + * 'task' and when dispatched 'action' will be called with 'arg' as the + * arg value. The new timer is returned in 'timerp'. + * + * Notes: + * + *\li For ticker timers, the timer will generate a 'tick' event every + * 'interval' seconds. The value of 'expires' is ignored. + * + *\li For once timers, 'expires' specifies the time when a life timeout + * event should be generated. If 'expires' is 0 (the epoch), then no life + * timeout will be generated. 'interval' specifies how long the timer + * can be idle before it generates an idle timeout. If 0, then no + * idle timeout will be generated. + * + *\li If 'expires' is NULL, the epoch will be used. + * + * If 'interval' is NULL, the zero interval will be used. + * + * Requires: + * + *\li 'manager' is a valid manager + * + *\li 'task' is a valid task + * + *\li 'action' is a valid action + * + *\li 'expires' points to a valid time, or is NULL. + * + *\li 'interval' points to a valid interval, or is NULL. + * + *\li type == isc_timertype_inactive || + * ('expires' and 'interval' are not both 0) + * + *\li 'timerp' is a valid pointer, and *timerp == NULL + * + * Ensures: + * + *\li '*timerp' is attached to the newly created timer + * + *\li The timer is attached to the task + * + *\li An idle timeout will not be generated until at least Now + the + * timer's interval if 'timer' is a once timer with a non-zero + * interval. + * + * Returns: + * + *\li Success + *\li No memory + *\li Unexpected error + */ + +isc_result_t +isc_timer_reset(isc_timer_t *timer, + isc_timertype_t type, + isc_time_t *expires, + isc_interval_t *interval, + isc_boolean_t purge); +/*%< + * Change the timer's type, expires, and interval values to the given + * values. If 'purge' is TRUE, any pending events from this timer + * are purged from its task's event queue. + * + * Notes: + * + *\li If 'expires' is NULL, the epoch will be used. + * + *\li If 'interval' is NULL, the zero interval will be used. + * + * Requires: + * + *\li 'timer' is a valid timer + * + *\li The same requirements that isc_timer_create() imposes on 'type', + * 'expires' and 'interval' apply. + * + * Ensures: + * + *\li An idle timeout will not be generated until at least Now + the + * timer's interval if 'timer' is a once timer with a non-zero + * interval. + * + * Returns: + * + *\li Success + *\li No memory + *\li Unexpected error + */ + +isc_result_t +isc_timer_touch(isc_timer_t *timer); +/*%< + * Set the last-touched time of 'timer' to the current time. + * + * Requires: + * + *\li 'timer' is a valid once timer. + * + * Ensures: + * + *\li An idle timeout will not be generated until at least Now + the + * timer's interval if 'timer' is a once timer with a non-zero + * interval. + * + * Returns: + * + *\li Success + *\li Unexpected error + */ + +void +isc_timer_attach(isc_timer_t *timer, isc_timer_t **timerp); +/*%< + * Attach *timerp to timer. + * + * Requires: + * + *\li 'timer' is a valid timer. + * + *\li 'timerp' points to a NULL timer. + * + * Ensures: + * + *\li *timerp is attached to timer. + */ + +void +isc_timer_detach(isc_timer_t **timerp); +/*%< + * Detach *timerp from its timer. + * + * Requires: + * + *\li 'timerp' points to a valid timer. + * + * Ensures: + * + *\li *timerp is NULL. + * + *\li If '*timerp' is the last reference to the timer, + * then: + * + *\code + * The timer will be shutdown + * + * The timer will detach from its task + * + * All resources used by the timer have been freed + * + * Any events already posted by the timer will be purged. + * Therefore, if isc_timer_detach() is called in the context + * of the timer's task, it is guaranteed that no more + * timer event callbacks will run after the call. + *\endcode + */ + +isc_timertype_t +isc_timer_gettype(isc_timer_t *timer); +/*%< + * Return the timer type. + * + * Requires: + * + *\li 'timer' to be a valid timer. + */ + +isc_result_t +isc_timermgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx, + isc_timermgr_t **managerp); + +isc_result_t +isc_timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp); +/*%< + * Create a timer manager. isc_timermgr_createinctx() also associates + * the new manager with the specified application context. + * + * Notes: + * + *\li All memory will be allocated in memory context 'mctx'. + * + * Requires: + * + *\li 'mctx' is a valid memory context. + * + *\li 'managerp' points to a NULL isc_timermgr_t. + * + *\li 'actx' is a valid application context (for createinctx()). + * + * Ensures: + * + *\li '*managerp' is a valid isc_timermgr_t. + * + * Returns: + * + *\li Success + *\li No memory + *\li Unexpected error + */ + +void +isc_timermgr_destroy(isc_timermgr_t **managerp); +/*%< + * Destroy a timer manager. + * + * Notes: + * + *\li This routine blocks until there are no timers left in the manager, + * so if the caller holds any timer references using the manager, it + * must detach them before calling isc_timermgr_destroy() or it will + * block forever. + * + * Requires: + * + *\li '*managerp' is a valid isc_timermgr_t. + * + * Ensures: + * + *\li *managerp == NULL + * + *\li All resources used by the manager have been freed. + */ + +void isc_timermgr_poke(isc_timermgr_t *m); + +#ifdef USE_TIMERIMPREGISTER +/*%< + * See isc_timermgr_create() above. + */ +typedef isc_result_t +(*isc_timermgrcreatefunc_t)(isc_mem_t *mctx, isc_timermgr_t **managerp); + +isc_result_t +isc__timer_register(void); +/*%< + * Register a new timer management implementation and add it to the list of + * supported implementations. This function must be called when a different + * event library is used than the one contained in the ISC library. + */ + +isc_result_t +isc_timer_register(isc_timermgrcreatefunc_t createfunc); +/*%< + * A short cut function that specifies the timer management module in the ISC + * library for isc_timer_register(). An application that uses the ISC library + * usually do not have to care about this function: it would call + * isc_lib_register(), which internally calls this function. + */ +#endif /* USE_TIMERIMPREGISTER */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_TIMER_H */ diff --git a/contrib/ntp/lib/isc/include/isc/types.h b/contrib/ntp/lib/isc/include/isc/types.h new file mode 100644 index 0000000..8dbf67e --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/types.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2004-2009, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +#ifndef ISC_TYPES_H +#define ISC_TYPES_H 1 + +#include <isc/bind9.h> +#include <isc/namespace.h> + +/*! \file isc/types.h + * \brief + * OS-specific types, from the OS-specific include directories. + */ +#include <isc/int.h> +#include <isc/offset.h> + +/* + * XXXDCL should isc_boolean_t be moved here, requiring an explicit include + * of <isc/boolean.h> when ISC_TRUE/ISC_FALSE/ISC_TF() are desired? + */ +#include <isc/boolean.h> +/* + * XXXDCL This is just for ISC_LIST and ISC_LINK, but gets all of the other + * list macros too. + */ +#include <isc/list.h> + +/* Core Types. Alphabetized by defined type. */ + +typedef struct isc_appctx isc_appctx_t; /*%< Application context */ +typedef struct isc_backtrace_symmap isc_backtrace_symmap_t; /*%< Symbol Table Entry */ +typedef struct isc_bitstring isc_bitstring_t; /*%< Bitstring */ +typedef struct isc_buffer isc_buffer_t; /*%< Buffer */ +typedef ISC_LIST(isc_buffer_t) isc_bufferlist_t; /*%< Buffer List */ +typedef struct isc_constregion isc_constregion_t; /*%< Const region */ +typedef struct isc_consttextregion isc_consttextregion_t; /*%< Const Text Region */ +typedef struct isc_entropy isc_entropy_t; /*%< Entropy */ +typedef struct isc_entropysource isc_entropysource_t; /*%< Entropy Source */ +typedef struct isc_event isc_event_t; /*%< Event */ +typedef ISC_LIST(isc_event_t) isc_eventlist_t; /*%< Event List */ +typedef unsigned int isc_eventtype_t; /*%< Event Type */ +typedef isc_uint32_t isc_fsaccess_t; /*%< FS Access */ +typedef struct isc_hash isc_hash_t; /*%< Hash */ +typedef struct isc_httpd isc_httpd_t; /*%< HTTP client */ +typedef void (isc_httpdfree_t)(isc_buffer_t *, void *); /*%< HTTP free function */ +typedef struct isc_httpdmgr isc_httpdmgr_t; /*%< HTTP manager */ +typedef struct isc_httpdurl isc_httpdurl_t; /*%< HTTP URL */ +typedef void (isc_httpdondestroy_t)(void *); /*%< Callback on destroying httpd */ +typedef struct isc_interface isc_interface_t; /*%< Interface */ +typedef struct isc_interfaceiter isc_interfaceiter_t; /*%< Interface Iterator */ +typedef struct isc_interval isc_interval_t; /*%< Interval */ +typedef struct isc_lex isc_lex_t; /*%< Lex */ +typedef struct isc_log isc_log_t; /*%< Log */ +typedef struct isc_logcategory isc_logcategory_t; /*%< Log Category */ +typedef struct isc_logconfig isc_logconfig_t; /*%< Log Configuration */ +typedef struct isc_logmodule isc_logmodule_t; /*%< Log Module */ +typedef struct isc_mem isc_mem_t; /*%< Memory */ +typedef struct isc_mempool isc_mempool_t; /*%< Memory Pool */ +typedef struct isc_msgcat isc_msgcat_t; /*%< Message Catalog */ +typedef struct isc_ondestroy isc_ondestroy_t; /*%< On Destroy */ +typedef struct isc_netaddr isc_netaddr_t; /*%< Net Address */ +typedef struct isc_portset isc_portset_t; /*%< Port Set */ +typedef struct isc_quota isc_quota_t; /*%< Quota */ +typedef struct isc_random isc_random_t; /*%< Random */ +typedef struct isc_ratelimiter isc_ratelimiter_t; /*%< Rate Limiter */ +typedef struct isc_region isc_region_t; /*%< Region */ +typedef isc_uint64_t isc_resourcevalue_t; /*%< Resource Value */ +typedef unsigned int isc_result_t; /*%< Result */ +typedef struct isc_rwlock isc_rwlock_t; /*%< Read Write Lock */ +typedef struct isc_sockaddr isc_sockaddr_t; /*%< Socket Address */ +typedef struct isc_socket isc_socket_t; /*%< Socket */ +typedef struct isc_socketevent isc_socketevent_t; /*%< Socket Event */ +typedef struct isc_socketmgr isc_socketmgr_t; /*%< Socket Manager */ +typedef struct isc_stats isc_stats_t; /*%< Statistics */ +typedef int isc_statscounter_t; /*%< Statistics Counter */ +typedef struct isc_symtab isc_symtab_t; /*%< Symbol Table */ +typedef struct isc_task isc_task_t; /*%< Task */ +typedef ISC_LIST(isc_task_t) isc_tasklist_t; /*%< Task List */ +typedef struct isc_taskmgr isc_taskmgr_t; /*%< Task Manager */ +typedef struct isc_textregion isc_textregion_t; /*%< Text Region */ +typedef struct isc_time isc_time_t; /*%< Time */ +typedef struct isc_timer isc_timer_t; /*%< Timer */ +typedef struct isc_timermgr isc_timermgr_t; /*%< Timer Manager */ + +typedef void (*isc_taskaction_t)(isc_task_t *, isc_event_t *); +typedef int (*isc_sockfdwatch_t)(isc_task_t *, isc_socket_t *, void *, int); + +/* The following cannot be listed alphabetically due to forward reference */ +typedef isc_result_t (isc_httpdaction_t)(const char *url, + const char *querystring, + void *arg, + unsigned int *retcode, + const char **retmsg, + const char **mimetype, + isc_buffer_t *body, + isc_httpdfree_t **freecb, + void **freecb_args); +typedef isc_boolean_t (isc_httpdclientok_t)(const isc_sockaddr_t *, void *); + +/*% Resource */ +typedef enum { + isc_resource_coresize = 1, + isc_resource_cputime, + isc_resource_datasize, + isc_resource_filesize, + isc_resource_lockedmemory, + isc_resource_openfiles, + isc_resource_processes, + isc_resource_residentsize, + isc_resource_stacksize +} isc_resource_t; + +#endif /* ISC_TYPES_H */ diff --git a/contrib/ntp/lib/isc/include/isc/util.h b/contrib/ntp/lib/isc/include/isc/util.h new file mode 100644 index 0000000..670b28b --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/util.h @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2004-2007, 2010-2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +#ifndef ISC_UTIL_H +#define ISC_UTIL_H 1 + +/*! \file isc/util.h + * NOTE: + * + * This file is not to be included from any <isc/???.h> (or other) library + * files. + * + * \brief + * Including this file puts several macros in your name space that are + * not protected (as all the other ISC functions/macros do) by prepending + * ISC_ or isc_ to the name. + */ + +/*** + *** General Macros. + ***/ + +/*% + * Use this to hide unused function arguments. + * \code + * int + * foo(char *bar) + * { + * UNUSED(bar); + * } + * \endcode + */ +#define UNUSED(x) (void)(x) + +/*% + * The opposite: silent warnings about stored values which are never read. + */ +#define POST(x) (void)(x) + +#define ISC_MAX(a, b) ((a) > (b) ? (a) : (b)) +#define ISC_MIN(a, b) ((a) < (b) ? (a) : (b)) + +/*% + * Use this to remove the const qualifier of a variable to assign it to + * a non-const variable or pass it as a non-const function argument ... + * but only when you are sure it won't then be changed! + * This is necessary to sometimes shut up some compilers + * (as with gcc -Wcast-qual) when there is just no other good way to avoid the + * situation. + */ +#define DE_CONST(konst, var) \ + do { \ + union { const void *k; void *v; } _u; \ + _u.k = konst; \ + var = _u.v; \ + } while (0) + +/*% + * Use this in translation units that would otherwise be empty, to + * suppress compiler warnings. + */ +#define EMPTY_TRANSLATION_UNIT extern void exit(int); + +/*% + * We use macros instead of calling the routines directly because + * the capital letters make the locking stand out. + * We RUNTIME_CHECK for success since in general there's no way + * for us to continue if they fail. + */ + +#ifdef ISC_UTIL_TRACEON +#define ISC_UTIL_TRACE(a) a +#include <stdio.h> /* Required for fprintf/stderr when tracing. */ +#include <isc/msgs.h> /* Required for isc_msgcat when tracing. */ +#else +#define ISC_UTIL_TRACE(a) +#endif + +#include <isc/result.h> /* Contractual promise. */ + +#define LOCK(lp) do { \ + ISC_UTIL_TRACE(fprintf(stderr, "%s %p %s %d\n", \ + isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \ + ISC_MSG_LOCKING, "LOCKING"), \ + (lp), __FILE__, __LINE__)); \ + RUNTIME_CHECK(isc_mutex_lock((lp)) == ISC_R_SUCCESS); \ + ISC_UTIL_TRACE(fprintf(stderr, "%s %p %s %d\n", \ + isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \ + ISC_MSG_LOCKED, "LOCKED"), \ + (lp), __FILE__, __LINE__)); \ + } while (0) +#define UNLOCK(lp) do { \ + RUNTIME_CHECK(isc_mutex_unlock((lp)) == ISC_R_SUCCESS); \ + ISC_UTIL_TRACE(fprintf(stderr, "%s %p %s %d\n", \ + isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \ + ISC_MSG_UNLOCKED, "UNLOCKED"), \ + (lp), __FILE__, __LINE__)); \ + } while (0) +#define ISLOCKED(lp) (1) +#define DESTROYLOCK(lp) \ + RUNTIME_CHECK(isc_mutex_destroy((lp)) == ISC_R_SUCCESS) + + +#define BROADCAST(cvp) do { \ + ISC_UTIL_TRACE(fprintf(stderr, "%s %p %s %d\n", \ + isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \ + ISC_MSG_BROADCAST, "BROADCAST"),\ + (cvp), __FILE__, __LINE__)); \ + RUNTIME_CHECK(isc_condition_broadcast((cvp)) == ISC_R_SUCCESS); \ + } while (0) +#define SIGNAL(cvp) do { \ + ISC_UTIL_TRACE(fprintf(stderr, "%s %p %s %d\n", \ + isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \ + ISC_MSG_SIGNAL, "SIGNAL"), \ + (cvp), __FILE__, __LINE__)); \ + RUNTIME_CHECK(isc_condition_signal((cvp)) == ISC_R_SUCCESS); \ + } while (0) +#define WAIT(cvp, lp) do { \ + ISC_UTIL_TRACE(fprintf(stderr, "%s %p %s %p %s %d\n", \ + isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \ + ISC_MSG_UTILWAIT, "WAIT"), \ + (cvp), \ + isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \ + ISC_MSG_LOCK, "LOCK"), \ + (lp), __FILE__, __LINE__)); \ + RUNTIME_CHECK(isc_condition_wait((cvp), (lp)) == ISC_R_SUCCESS); \ + ISC_UTIL_TRACE(fprintf(stderr, "%s %p %s %p %s %d\n", \ + isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \ + ISC_MSG_WAITED, "WAITED"), \ + (cvp), \ + isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \ + ISC_MSG_LOCKED, "LOCKED"), \ + (lp), __FILE__, __LINE__)); \ + } while (0) + +/* + * isc_condition_waituntil can return ISC_R_TIMEDOUT, so we + * don't RUNTIME_CHECK the result. + * + * XXX Also, can't really debug this then... + */ + +#define WAITUNTIL(cvp, lp, tp) \ + isc_condition_waituntil((cvp), (lp), (tp)) + +#define RWLOCK(lp, t) do { \ + ISC_UTIL_TRACE(fprintf(stderr, "%s %p, %d %s %d\n", \ + isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \ + ISC_MSG_RWLOCK, "RWLOCK"), \ + (lp), (t), __FILE__, __LINE__)); \ + RUNTIME_CHECK(isc_rwlock_lock((lp), (t)) == ISC_R_SUCCESS); \ + ISC_UTIL_TRACE(fprintf(stderr, "%s %p, %d %s %d\n", \ + isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \ + ISC_MSG_RWLOCKED, "RWLOCKED"), \ + (lp), (t), __FILE__, __LINE__)); \ + } while (0) +#define RWUNLOCK(lp, t) do { \ + ISC_UTIL_TRACE(fprintf(stderr, "%s %p, %d %s %d\n", \ + isc_msgcat_get(isc_msgcat, ISC_MSGSET_UTIL, \ + ISC_MSG_RWUNLOCK, "RWUNLOCK"), \ + (lp), (t), __FILE__, __LINE__)); \ + RUNTIME_CHECK(isc_rwlock_unlock((lp), (t)) == ISC_R_SUCCESS); \ + } while (0) + +#define DESTROYMUTEXBLOCK(bp, n) \ + RUNTIME_CHECK(isc_mutexblock_destroy((bp), (n)) == ISC_R_SUCCESS) + +/* + * List Macros. + */ +#include <isc/list.h> /* Contractual promise. */ + +#define LIST(type) ISC_LIST(type) +#define INIT_LIST(type) ISC_LIST_INIT(type) +#define LINK(type) ISC_LINK(type) +#define INIT_LINK(elt, link) ISC_LINK_INIT(elt, link) +#define HEAD(list) ISC_LIST_HEAD(list) +#define TAIL(list) ISC_LIST_TAIL(list) +#define EMPTY(list) ISC_LIST_EMPTY(list) +#define PREV(elt, link) ISC_LIST_PREV(elt, link) +#define NEXT(elt, link) ISC_LIST_NEXT(elt, link) +#define APPEND(list, elt, link) ISC_LIST_APPEND(list, elt, link) +#define PREPEND(list, elt, link) ISC_LIST_PREPEND(list, elt, link) +#define UNLINK(list, elt, link) ISC_LIST_UNLINK(list, elt, link) +#define ENQUEUE(list, elt, link) ISC_LIST_APPEND(list, elt, link) +#define DEQUEUE(list, elt, link) ISC_LIST_UNLINK(list, elt, link) +#define INSERTBEFORE(li, b, e, ln) ISC_LIST_INSERTBEFORE(li, b, e, ln) +#define INSERTAFTER(li, a, e, ln) ISC_LIST_INSERTAFTER(li, a, e, ln) +#define APPENDLIST(list1, list2, link) ISC_LIST_APPENDLIST(list1, list2, link) + +/* + * Assertions + */ +#include <isc/assertions.h> /* Contractual promise. */ + +/*% Require Assertion */ +#define REQUIRE(e) ISC_REQUIRE(e) +/*% Ensure Assertion */ +#define ENSURE(e) ISC_ENSURE(e) +/*% Insist Assertion */ +#define INSIST(e) ISC_INSIST(e) +/*% Invariant Assertion */ +#define INVARIANT(e) ISC_INVARIANT(e) + +/* + * Errors + */ +#include <isc/error.h> /* Contractual promise. */ + +/*% Unexpected Error */ +#define UNEXPECTED_ERROR isc_error_unexpected +/*% Fatal Error */ +#define FATAL_ERROR isc_error_fatal +/*% Runtime Check */ +#define RUNTIME_CHECK(cond) ISC_ERROR_RUNTIMECHECK(cond) + +/*% + * Time + */ +#define TIME_NOW(tp) RUNTIME_CHECK(isc_time_now((tp)) == ISC_R_SUCCESS) + +#endif /* ISC_UTIL_H */ diff --git a/contrib/ntp/lib/isc/include/isc/version.h b/contrib/ntp/lib/isc/include/isc/version.h new file mode 100644 index 0000000..ec00bde --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/version.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: version.h,v 1.9 2007/06/19 23:47:18 tbox Exp $ */ + +/*! \file isc/version.h */ + +#include <isc/platform.h> + +LIBISC_EXTERNAL_DATA extern const char isc_version[]; + +LIBISC_EXTERNAL_DATA extern const unsigned int isc_libinterface; +LIBISC_EXTERNAL_DATA extern const unsigned int isc_librevision; +LIBISC_EXTERNAL_DATA extern const unsigned int isc_libage; diff --git a/contrib/ntp/lib/isc/include/isc/xml.h b/contrib/ntp/lib/isc/include/isc/xml.h new file mode 100644 index 0000000..d31a31a --- /dev/null +++ b/contrib/ntp/lib/isc/include/isc/xml.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2006, 2007 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: xml.h,v 1.4 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_XML_H +#define ISC_XML_H 1 + +/* + * This file is here mostly to make it easy to add additional libxml header + * files as needed across all the users of this file. Rather than place + * these libxml includes in each file, one include makes it easy to handle + * the ifdef as well as adding the ability to add additional functions + * which may be useful. + */ + +#ifdef HAVE_LIBXML2 +#include <libxml/encoding.h> +#include <libxml/xmlwriter.h> +#endif + +#define ISC_XMLCHAR (const xmlChar *) + +#define ISC_XML_RENDERCONFIG 0x00000001 /* render config data */ +#define ISC_XML_RENDERSTATS 0x00000002 /* render stats */ +#define ISC_XML_RENDERALL 0x000000ff /* render everything */ + +#endif /* ISC_XML_H */ diff --git a/contrib/ntp/lib/isc/inet_aton.c b/contrib/ntp/lib/isc/inet_aton.c new file mode 100644 index 0000000..14b4887 --- /dev/null +++ b/contrib/ntp/lib/isc/inet_aton.c @@ -0,0 +1,196 @@ +/* + * Portions Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 1996-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* + * Copyright (c) 1983, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * 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, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION 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. + */ +/*! \file */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93"; +static char rcsid[] = "$Id: inet_aton.c,v 1.23 2008/12/01 23:47:45 tbox Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <config.h> + +#include <ctype.h> +#include <stddef.h> /* Required for NULL. */ + +#include <isc/types.h> +#include <isc/net.h> + +/*% + * Check whether "cp" is a valid ascii representation + * of an Internet address and convert to a binary address. + * Returns 1 if the address is valid, 0 if not. + * This replaces inet_addr, the return value from which + * cannot distinguish between failure and a local broadcast address. + */ +int +isc_net_aton(const char *cp, struct in_addr *addr) { + unsigned long val; + int base, n; + unsigned char c; + isc_uint8_t parts[4]; + isc_uint8_t *pp = parts; + int digit; + + c = *cp; + for (;;) { + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, isdigit=decimal. + */ + if (!isdigit(c & 0xff)) + return (0); + val = 0; base = 10; digit = 0; + if (c == '0') { + c = *++cp; + if (c == 'x' || c == 'X') + base = 16, c = *++cp; + else { + base = 8; + digit = 1; + } + } + for (;;) { + /* + * isascii() is valid for all integer values, and + * when it is true, c is known to be in scope + * for isdigit(). No cast necessary. Similar + * comment applies for later ctype uses. + */ + if (isascii(c) && isdigit(c)) { + if (base == 8 && (c == '8' || c == '9')) + return (0); + val = (val * base) + (c - '0'); + c = *++cp; + digit = 1; + } else if (base == 16 && isascii(c) && isxdigit(c)) { + val = (val << 4) | + (c + 10 - (islower(c) ? 'a' : 'A')); + c = *++cp; + digit = 1; + } else + break; + } + if (c == '.') { + /* + * Internet format: + * a.b.c.d + * a.b.c (with c treated as 16 bits) + * a.b (with b treated as 24 bits) + */ + if (pp >= parts + 3 || val > 0xffU) + return (0); + *pp++ = (isc_uint8_t)val; + c = *++cp; + } else + break; + } + /* + * Check for trailing characters. + */ + if (c != '\0' && (!isascii(c) || !isspace(c))) + return (0); + /* + * Did we get a valid digit? + */ + if (!digit) + return (0); + /* + * Concoct the address according to + * the number of parts specified. + */ + n = pp - parts + 1; + switch (n) { + case 1: /* a -- 32 bits */ + break; + + case 2: /* a.b -- 8.24 bits */ + if (val > 0xffffffU) + return (0); + val |= parts[0] << 24; + break; + + case 3: /* a.b.c -- 8.8.16 bits */ + if (val > 0xffffU) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16); + break; + + case 4: /* a.b.c.d -- 8.8.8.8 bits */ + if (val > 0xffU) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); + break; + } + if (addr != NULL) + addr->s_addr = htonl(val); + + return (1); +} diff --git a/contrib/ntp/lib/isc/inet_ntop.c b/contrib/ntp/lib/isc/inet_ntop.c new file mode 100644 index 0000000..26d5dca --- /dev/null +++ b/contrib/ntp/lib/isc/inet_ntop.c @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1996-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/*! \file */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char rcsid[] = + "$Id: inet_ntop.c,v 1.21 2009/07/17 23:47:41 tbox Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <config.h> + +#include <errno.h> +#include <stdio.h> +#include <string.h> + +#include <isc/net.h> +#include <isc/print.h> + +#define NS_INT16SZ 2 +#define NS_IN6ADDRSZ 16 + +/* + * WARNING: Don't even consider trying to compile this on a system where + * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. + */ + +static const char *inet_ntop4(const unsigned char *src, char *dst, + size_t size); + +#ifdef AF_INET6 +static const char *inet_ntop6(const unsigned char *src, char *dst, + size_t size); +#endif +const char *isc_net_ntop(int af, const void *src, char *dst, size_t size); + +/*! char * + * isc_net_ntop(af, src, dst, size) + * convert a network format address to presentation format. + * \return + * pointer to presentation format address (`dst'), or NULL (see errno). + * \author + * Paul Vixie, 1996. + */ +const char * +isc_net_ntop(int af, const void *src, char *dst, size_t size) +{ + switch (af) { + case AF_INET: + return (inet_ntop4(src, dst, size)); +#ifdef AF_INET6 + case AF_INET6: + return (inet_ntop6(src, dst, size)); +#endif + default: + errno = EAFNOSUPPORT; + return (NULL); + } + /* NOTREACHED */ +} + +/*! const char * + * inet_ntop4(src, dst, size) + * format an IPv4 address + * \return + * `dst' (as a const) + * \note + * (1) uses no statics + * \note + * (2) takes a unsigned char* not an in_addr as input + * \author + * Paul Vixie, 1996. + */ +static const char * +inet_ntop4(const unsigned char *src, char *dst, size_t size) +{ + static const char *fmt = "%u.%u.%u.%u"; + char tmp[sizeof("255.255.255.255")]; + int len; + + len = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]); + if (len < 0 || (size_t)len >= size) + { + errno = ENOSPC; + return (NULL); + } + memcpy(dst, tmp, 1 + len); + + return (dst); +} + +/*! const char * + * isc_inet_ntop6(src, dst, size) + * convert IPv6 binary address into presentation (printable) format + * \author + * Paul Vixie, 1996. + */ +#ifdef AF_INET6 +static const char * +inet_ntop6(const unsigned char *src, char *dst, size_t size) +{ + /* + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")], *tp; + struct { int base, len; } best, cur; + unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ]; + int i; + + /* + * Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + memset(words, '\0', sizeof(words)); + for (i = 0; i < NS_IN6ADDRSZ; i++) + words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); + best.base = -1; + cur.base = -1; + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { + if (words[i] == 0) { + if (cur.base == -1) + cur.base = i, cur.len = 1; + else + cur.len++; + } else { + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + } + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + } + if (best.base != -1 && best.len < 2) + best.base = -1; + + /* + * Format the result. + */ + tp = tmp; + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { + /* Are we inside the best run of 0x00's? */ + if (best.base != -1 && i >= best.base && + i < (best.base + best.len)) { + if (i == best.base) + *tp++ = ':'; + continue; + } + /* Are we following an initial run of 0x00s or any real hex? */ + if (i != 0) + *tp++ = ':'; + /* Is this address an encapsulated IPv4? */ + if (i == 6 && best.base == 0 && (best.len == 6 || + (best.len == 7 && words[7] != 0x0001) || + (best.len == 5 && words[5] == 0xffff))) { + if (!inet_ntop4(src+12, tp, + sizeof(tmp) - (tp - tmp))) + return (NULL); + tp += strlen(tp); + break; + } + tp += snprintf(tp, sizeof(tmp) - (tp - tmp), "%x", words[i]); + } + /* Was it a trailing run of 0x00's? */ + if (best.base != -1 && (best.base + best.len) == + (NS_IN6ADDRSZ / NS_INT16SZ)) + *tp++ = ':'; + *tp++ = '\0'; + + /* + * Check for overflow, copy, and we're done. + */ + if ((size_t)(tp - tmp) > size) { + errno = ENOSPC; + return (NULL); + } + memcpy(dst, tmp, (size_t)(tp - tmp)); + return (dst); +} +#endif /* AF_INET6 */ diff --git a/contrib/ntp/lib/isc/inet_pton.c b/contrib/ntp/lib/isc/inet_pton.c new file mode 100644 index 0000000..66b5de0 --- /dev/null +++ b/contrib/ntp/lib/isc/inet_pton.c @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1996-2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/*! \file */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char rcsid[] = + "$Id: inet_pton.c,v 1.19 2007/06/19 23:47:17 tbox Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <config.h> + +#include <errno.h> +#include <string.h> + +#include <isc/net.h> + +/*% INT16 Size */ +#define NS_INT16SZ 2 +/*% IPv4 Address Size */ +#define NS_INADDRSZ 4 +/*% IPv6 Address Size */ +#define NS_IN6ADDRSZ 16 + +/* + * WARNING: Don't even consider trying to compile this on a system where + * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. + */ + +static int inet_pton4(const char *src, unsigned char *dst); +static int inet_pton6(const char *src, unsigned char *dst); +int isc_net_pton(int af, const char *src, void *dst); + +/*% + * convert from presentation format (which usually means ASCII printable) + * to network format (which is usually some kind of binary format). + * \return + * 1 if the address was valid for the specified address family + * 0 if the address wasn't valid (`dst' is untouched in this case) + * -1 if some other error occurred (`dst' is untouched in this case, too) + * \author + * Paul Vixie, 1996. + */ +int +isc_net_pton(int af, const char *src, void *dst) { + switch (af) { + case AF_INET: + return (inet_pton4(src, dst)); + case AF_INET6: + return (inet_pton6(src, dst)); + default: + errno = EAFNOSUPPORT; + return (-1); + } + /* NOTREACHED */ +} + +/*!\fn static int inet_pton4(const char *src, unsigned char *dst) + * \brief + * like inet_aton() but without all the hexadecimal and shorthand. + * \return + * 1 if `src' is a valid dotted quad, else 0. + * \note + * does not touch `dst' unless it's returning 1. + * \author + * Paul Vixie, 1996. + */ +static int +inet_pton4(const char *src, unsigned char *dst) { + static const char digits[] = "0123456789"; + int saw_digit, octets, ch; + unsigned char tmp[NS_INADDRSZ], *tp; + + saw_digit = 0; + octets = 0; + *(tp = tmp) = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr(digits, ch)) != NULL) { + unsigned int newv = *tp * 10 + (pch - digits); + + if (saw_digit && *tp == 0) + return (0); + if (newv > 255) + return (0); + *tp = (unsigned char)newv; + if (!saw_digit) { + if (++octets > 4) + return (0); + saw_digit = 1; + } + } else if (ch == '.' && saw_digit) { + if (octets == 4) + return (0); + *++tp = 0; + saw_digit = 0; + } else + return (0); + } + if (octets < 4) + return (0); + memcpy(dst, tmp, NS_INADDRSZ); + return (1); +} + +/*% + * convert presentation level address to network order binary form. + * \return + * 1 if `src' is a valid [RFC1884 2.2] address, else 0. + * \note + * (1) does not touch `dst' unless it's returning 1. + * \note + * (2) :: in a full address is silently ignored. + * \author + * inspired by Mark Andrews. + * \author + * Paul Vixie, 1996. + */ +static int +inet_pton6(const char *src, unsigned char *dst) { + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, seen_xdigits; + unsigned int val; + + memset((tp = tmp), '\0', NS_IN6ADDRSZ); + endp = tp + NS_IN6ADDRSZ; + colonp = NULL; + /* Leading :: requires some special handling. */ + if (*src == ':') + if (*++src != ':') + return (0); + curtok = src; + seen_xdigits = 0; + val = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) + pch = strchr((xdigits = xdigits_u), ch); + if (pch != NULL) { + val <<= 4; + val |= (pch - xdigits); + if (++seen_xdigits > 4) + return (0); + continue; + } + if (ch == ':') { + curtok = src; + if (!seen_xdigits) { + if (colonp) + return (0); + colonp = tp; + continue; + } + if (tp + NS_INT16SZ > endp) + return (0); + *tp++ = (unsigned char) (val >> 8) & 0xff; + *tp++ = (unsigned char) val & 0xff; + seen_xdigits = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && + inet_pton4(curtok, tp) > 0) { + tp += NS_INADDRSZ; + seen_xdigits = 0; + break; /* '\0' was seen by inet_pton4(). */ + } + return (0); + } + if (seen_xdigits) { + if (tp + NS_INT16SZ > endp) + return (0); + *tp++ = (unsigned char) (val >> 8) & 0xff; + *tp++ = (unsigned char) val & 0xff; + } + if (colonp != NULL) { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = tp - colonp; + int i; + + if (tp == endp) + return (0); + for (i = 1; i <= n; i++) { + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if (tp != endp) + return (0); + memcpy(dst, tmp, NS_IN6ADDRSZ); + return (1); +} diff --git a/contrib/ntp/lib/isc/iterated_hash.c b/contrib/ntp/lib/isc/iterated_hash.c new file mode 100644 index 0000000..86dedde --- /dev/null +++ b/contrib/ntp/lib/isc/iterated_hash.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2006, 2008, 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: iterated_hash.c,v 1.6 2009/02/18 23:47:48 tbox Exp $ */ + +#include "config.h" + +#include <stdio.h> + +#include <isc/sha1.h> +#include <isc/iterated_hash.h> + +int +isc_iterated_hash(unsigned char out[ISC_SHA1_DIGESTLENGTH], + unsigned int hashalg, int iterations, + const unsigned char *salt, int saltlength, + const unsigned char *in, int inlength) +{ + isc_sha1_t ctx; + int n = 0; + + if (hashalg != 1) + return (0); + + do { + isc_sha1_init(&ctx); + isc_sha1_update(&ctx, in, inlength); + isc_sha1_update(&ctx, salt, saltlength); + isc_sha1_final(&ctx, out); + in = out; + inlength = ISC_SHA1_DIGESTLENGTH; + } while (n++ < iterations); + + return (ISC_SHA1_DIGESTLENGTH); +} diff --git a/contrib/ntp/lib/isc/lex.c b/contrib/ntp/lib/isc/lex.c new file mode 100644 index 0000000..8749ed0 --- /dev/null +++ b/contrib/ntp/lib/isc/lex.c @@ -0,0 +1,959 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: lex.c,v 1.86 2007/09/17 09:56:29 shane Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <ctype.h> +#include <errno.h> +#include <stdlib.h> + +#include <isc/buffer.h> +#include <isc/file.h> +#include <isc/lex.h> +#include <isc/mem.h> +#include <isc/msgs.h> +#include <isc/parseint.h> +#include <isc/print.h> +#include <isc/stdio.h> +#include <isc/string.h> +#include <isc/util.h> + +typedef struct inputsource { + isc_result_t result; + isc_boolean_t is_file; + isc_boolean_t need_close; + isc_boolean_t at_eof; + isc_buffer_t * pushback; + unsigned int ignored; + void * input; + char * name; + unsigned long line; + unsigned long saved_line; + ISC_LINK(struct inputsource) link; +} inputsource; + +#define LEX_MAGIC ISC_MAGIC('L', 'e', 'x', '!') +#define VALID_LEX(l) ISC_MAGIC_VALID(l, LEX_MAGIC) + +struct isc_lex { + /* Unlocked. */ + unsigned int magic; + isc_mem_t * mctx; + size_t max_token; + char * data; + unsigned int comments; + isc_boolean_t comment_ok; + isc_boolean_t last_was_eol; + unsigned int paren_count; + unsigned int saved_paren_count; + isc_lexspecials_t specials; + LIST(struct inputsource) sources; +}; + +static inline isc_result_t +grow_data(isc_lex_t *lex, size_t *remainingp, char **currp, char **prevp) { + char *new; + + new = isc_mem_get(lex->mctx, lex->max_token * 2 + 1); + if (new == NULL) + return (ISC_R_NOMEMORY); + memcpy(new, lex->data, lex->max_token + 1); + *currp = new + (*currp - lex->data); + if (*prevp != NULL) + *prevp = new + (*prevp - lex->data); + isc_mem_put(lex->mctx, lex->data, lex->max_token + 1); + lex->data = new; + *remainingp += lex->max_token; + lex->max_token *= 2; + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_lex_create(isc_mem_t *mctx, size_t max_token, isc_lex_t **lexp) { + isc_lex_t *lex; + + /* + * Create a lexer. + */ + + REQUIRE(lexp != NULL && *lexp == NULL); + REQUIRE(max_token > 0U); + + lex = isc_mem_get(mctx, sizeof(*lex)); + if (lex == NULL) + return (ISC_R_NOMEMORY); + lex->data = isc_mem_get(mctx, max_token + 1); + if (lex->data == NULL) { + isc_mem_put(mctx, lex, sizeof(*lex)); + return (ISC_R_NOMEMORY); + } + lex->mctx = mctx; + lex->max_token = max_token; + lex->comments = 0; + lex->comment_ok = ISC_TRUE; + lex->last_was_eol = ISC_TRUE; + lex->paren_count = 0; + lex->saved_paren_count = 0; + memset(lex->specials, 0, 256); + INIT_LIST(lex->sources); + lex->magic = LEX_MAGIC; + + *lexp = lex; + + return (ISC_R_SUCCESS); +} + +void +isc_lex_destroy(isc_lex_t **lexp) { + isc_lex_t *lex; + + /* + * Destroy the lexer. + */ + + REQUIRE(lexp != NULL); + lex = *lexp; + REQUIRE(VALID_LEX(lex)); + + while (!EMPTY(lex->sources)) + RUNTIME_CHECK(isc_lex_close(lex) == ISC_R_SUCCESS); + if (lex->data != NULL) + isc_mem_put(lex->mctx, lex->data, lex->max_token + 1); + lex->magic = 0; + isc_mem_put(lex->mctx, lex, sizeof(*lex)); + + *lexp = NULL; +} + +unsigned int +isc_lex_getcomments(isc_lex_t *lex) { + /* + * Return the current lexer commenting styles. + */ + + REQUIRE(VALID_LEX(lex)); + + return (lex->comments); +} + +void +isc_lex_setcomments(isc_lex_t *lex, unsigned int comments) { + /* + * Set allowed lexer commenting styles. + */ + + REQUIRE(VALID_LEX(lex)); + + lex->comments = comments; +} + +void +isc_lex_getspecials(isc_lex_t *lex, isc_lexspecials_t specials) { + /* + * Put the current list of specials into 'specials'. + */ + + REQUIRE(VALID_LEX(lex)); + + memcpy(specials, lex->specials, 256); +} + +void +isc_lex_setspecials(isc_lex_t *lex, isc_lexspecials_t specials) { + /* + * The characters in 'specials' are returned as tokens. Along with + * whitespace, they delimit strings and numbers. + */ + + REQUIRE(VALID_LEX(lex)); + + memcpy(lex->specials, specials, 256); +} + +static inline isc_result_t +new_source(isc_lex_t *lex, isc_boolean_t is_file, isc_boolean_t need_close, + void *input, const char *name) +{ + inputsource *source; + isc_result_t result; + + source = isc_mem_get(lex->mctx, sizeof(*source)); + if (source == NULL) + return (ISC_R_NOMEMORY); + source->result = ISC_R_SUCCESS; + source->is_file = is_file; + source->need_close = need_close; + source->at_eof = ISC_FALSE; + source->input = input; + source->name = isc_mem_strdup(lex->mctx, name); + if (source->name == NULL) { + isc_mem_put(lex->mctx, source, sizeof(*source)); + return (ISC_R_NOMEMORY); + } + source->pushback = NULL; + result = isc_buffer_allocate(lex->mctx, &source->pushback, + lex->max_token); + if (result != ISC_R_SUCCESS) { + isc_mem_free(lex->mctx, source->name); + isc_mem_put(lex->mctx, source, sizeof(*source)); + return (result); + } + source->ignored = 0; + source->line = 1; + ISC_LIST_INITANDPREPEND(lex->sources, source, link); + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_lex_openfile(isc_lex_t *lex, const char *filename) { + isc_result_t result; + FILE *stream = NULL; + + /* + * Open 'filename' and make it the current input source for 'lex'. + */ + + REQUIRE(VALID_LEX(lex)); + + result = isc_stdio_open(filename, "r", &stream); + if (result != ISC_R_SUCCESS) + return (result); + + result = new_source(lex, ISC_TRUE, ISC_TRUE, stream, filename); + if (result != ISC_R_SUCCESS) + (void)fclose(stream); + return (result); +} + +isc_result_t +isc_lex_openstream(isc_lex_t *lex, FILE *stream) { + char name[128]; + + /* + * Make 'stream' the current input source for 'lex'. + */ + + REQUIRE(VALID_LEX(lex)); + + snprintf(name, sizeof(name), "stream-%p", stream); + + return (new_source(lex, ISC_TRUE, ISC_FALSE, stream, name)); +} + +isc_result_t +isc_lex_openbuffer(isc_lex_t *lex, isc_buffer_t *buffer) { + char name[128]; + + /* + * Make 'buffer' the current input source for 'lex'. + */ + + REQUIRE(VALID_LEX(lex)); + + snprintf(name, sizeof(name), "buffer-%p", buffer); + + return (new_source(lex, ISC_FALSE, ISC_FALSE, buffer, name)); +} + +isc_result_t +isc_lex_close(isc_lex_t *lex) { + inputsource *source; + + /* + * Close the most recently opened object (i.e. file or buffer). + */ + + REQUIRE(VALID_LEX(lex)); + + source = HEAD(lex->sources); + if (source == NULL) + return (ISC_R_NOMORE); + + ISC_LIST_UNLINK(lex->sources, source, link); + if (source->is_file) { + if (source->need_close) + (void)fclose((FILE *)(source->input)); + } + isc_mem_free(lex->mctx, source->name); + isc_buffer_free(&source->pushback); + isc_mem_put(lex->mctx, source, sizeof(*source)); + + return (ISC_R_SUCCESS); +} + +typedef enum { + lexstate_start, + lexstate_crlf, + lexstate_string, + lexstate_number, + lexstate_maybecomment, + lexstate_ccomment, + lexstate_ccommentend, + lexstate_eatline, + lexstate_qstring +} lexstate; + +#define IWSEOL (ISC_LEXOPT_INITIALWS | ISC_LEXOPT_EOL) + +static void +pushback(inputsource *source, int c) { + REQUIRE(source->pushback->current > 0); + if (c == EOF) { + source->at_eof = ISC_FALSE; + return; + } + source->pushback->current--; + if (c == '\n') + source->line--; +} + +static isc_result_t +pushandgrow(isc_lex_t *lex, inputsource *source, int c) { + if (isc_buffer_availablelength(source->pushback) == 0) { + isc_buffer_t *tbuf = NULL; + unsigned int oldlen; + isc_region_t used; + isc_result_t result; + + oldlen = isc_buffer_length(source->pushback); + result = isc_buffer_allocate(lex->mctx, &tbuf, oldlen * 2); + if (result != ISC_R_SUCCESS) + return (result); + isc_buffer_usedregion(source->pushback, &used); + result = isc_buffer_copyregion(tbuf, &used); + INSIST(result == ISC_R_SUCCESS); + tbuf->current = source->pushback->current; + isc_buffer_free(&source->pushback); + source->pushback = tbuf; + } + isc_buffer_putuint8(source->pushback, (isc_uint8_t)c); + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp) { + inputsource *source; + int c; + isc_boolean_t done = ISC_FALSE; + isc_boolean_t no_comments = ISC_FALSE; + isc_boolean_t escaped = ISC_FALSE; + lexstate state = lexstate_start; + lexstate saved_state = lexstate_start; + isc_buffer_t *buffer; + FILE *stream; + char *curr, *prev; + size_t remaining; + isc_uint32_t as_ulong; + unsigned int saved_options; + isc_result_t result; + + /* + * Get the next token. + */ + + REQUIRE(VALID_LEX(lex)); + source = HEAD(lex->sources); + REQUIRE(tokenp != NULL); + + if (source == NULL) { + if ((options & ISC_LEXOPT_NOMORE) != 0) { + tokenp->type = isc_tokentype_nomore; + return (ISC_R_SUCCESS); + } + return (ISC_R_NOMORE); + } + + if (source->result != ISC_R_SUCCESS) + return (source->result); + + lex->saved_paren_count = lex->paren_count; + source->saved_line = source->line; + + if (isc_buffer_remaininglength(source->pushback) == 0 && + source->at_eof) + { + if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 && + lex->paren_count != 0) { + lex->paren_count = 0; + return (ISC_R_UNBALANCED); + } + if ((options & ISC_LEXOPT_EOF) != 0) { + tokenp->type = isc_tokentype_eof; + return (ISC_R_SUCCESS); + } + return (ISC_R_EOF); + } + + isc_buffer_compact(source->pushback); + + saved_options = options; + if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 && lex->paren_count > 0) + options &= ~IWSEOL; + + curr = lex->data; + *curr = '\0'; + + prev = NULL; + remaining = lex->max_token; + +#ifdef HAVE_FLOCKFILE + if (source->is_file) + flockfile(source->input); +#endif + + do { + if (isc_buffer_remaininglength(source->pushback) == 0) { + if (source->is_file) { + stream = source->input; + +#if defined(HAVE_FLOCKFILE) && defined(HAVE_GETCUNLOCKED) + c = getc_unlocked(stream); +#else + c = getc(stream); +#endif + if (c == EOF) { + if (ferror(stream)) { + source->result = ISC_R_IOERROR; + result = source->result; + goto done; + } + source->at_eof = ISC_TRUE; + } + } else { + buffer = source->input; + + if (buffer->current == buffer->used) { + c = EOF; + source->at_eof = ISC_TRUE; + } else { + c = *((char *)buffer->base + + buffer->current); + buffer->current++; + } + } + if (c != EOF) { + source->result = pushandgrow(lex, source, c); + if (source->result != ISC_R_SUCCESS) { + result = source->result; + goto done; + } + } + } + + if (!source->at_eof) { + if (state == lexstate_start) + /* Token has not started yet. */ + source->ignored = + isc_buffer_consumedlength(source->pushback); + c = isc_buffer_getuint8(source->pushback); + } else { + c = EOF; + } + + if (c == '\n') + source->line++; + + if (lex->comment_ok && !no_comments) { + if (!escaped && c == ';' && + ((lex->comments & ISC_LEXCOMMENT_DNSMASTERFILE) + != 0)) { + saved_state = state; + state = lexstate_eatline; + no_comments = ISC_TRUE; + continue; + } else if (c == '/' && + (lex->comments & + (ISC_LEXCOMMENT_C| + ISC_LEXCOMMENT_CPLUSPLUS)) != 0) { + saved_state = state; + state = lexstate_maybecomment; + no_comments = ISC_TRUE; + continue; + } else if (c == '#' && + ((lex->comments & ISC_LEXCOMMENT_SHELL) + != 0)) { + saved_state = state; + state = lexstate_eatline; + no_comments = ISC_TRUE; + continue; + } + } + + no_read: + /* INSIST(c == EOF || (c >= 0 && c <= 255)); */ + switch (state) { + case lexstate_start: + if (c == EOF) { + lex->last_was_eol = ISC_FALSE; + if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 && + lex->paren_count != 0) { + lex->paren_count = 0; + result = ISC_R_UNBALANCED; + goto done; + } + if ((options & ISC_LEXOPT_EOF) == 0) { + result = ISC_R_EOF; + goto done; + } + tokenp->type = isc_tokentype_eof; + done = ISC_TRUE; + } else if (c == ' ' || c == '\t') { + if (lex->last_was_eol && + (options & ISC_LEXOPT_INITIALWS) + != 0) { + lex->last_was_eol = ISC_FALSE; + tokenp->type = isc_tokentype_initialws; + tokenp->value.as_char = c; + done = ISC_TRUE; + } + } else if (c == '\n') { + if ((options & ISC_LEXOPT_EOL) != 0) { + tokenp->type = isc_tokentype_eol; + done = ISC_TRUE; + } + lex->last_was_eol = ISC_TRUE; + } else if (c == '\r') { + if ((options & ISC_LEXOPT_EOL) != 0) + state = lexstate_crlf; + } else if (c == '"' && + (options & ISC_LEXOPT_QSTRING) != 0) { + lex->last_was_eol = ISC_FALSE; + no_comments = ISC_TRUE; + state = lexstate_qstring; + } else if (lex->specials[c]) { + lex->last_was_eol = ISC_FALSE; + if ((c == '(' || c == ')') && + (options & ISC_LEXOPT_DNSMULTILINE) != 0) { + if (c == '(') { + if (lex->paren_count == 0) + options &= ~IWSEOL; + lex->paren_count++; + } else { + if (lex->paren_count == 0) { + result = ISC_R_UNBALANCED; + goto done; + } + lex->paren_count--; + if (lex->paren_count == 0) + options = + saved_options; + } + continue; + } + tokenp->type = isc_tokentype_special; + tokenp->value.as_char = c; + done = ISC_TRUE; + } else if (isdigit((unsigned char)c) && + (options & ISC_LEXOPT_NUMBER) != 0) { + lex->last_was_eol = ISC_FALSE; + if ((options & ISC_LEXOPT_OCTAL) != 0 && + (c == '8' || c == '9')) + state = lexstate_string; + else + state = lexstate_number; + goto no_read; + } else { + lex->last_was_eol = ISC_FALSE; + state = lexstate_string; + goto no_read; + } + break; + case lexstate_crlf: + if (c != '\n') + pushback(source, c); + tokenp->type = isc_tokentype_eol; + done = ISC_TRUE; + lex->last_was_eol = ISC_TRUE; + break; + case lexstate_number: + if (c == EOF || !isdigit((unsigned char)c)) { + if (c == ' ' || c == '\t' || c == '\r' || + c == '\n' || c == EOF || + lex->specials[c]) { + int base; + if ((options & ISC_LEXOPT_OCTAL) != 0) + base = 8; + else if ((options & ISC_LEXOPT_CNUMBER) != 0) + base = 0; + else + base = 10; + pushback(source, c); + + result = isc_parse_uint32(&as_ulong, + lex->data, + base); + if (result == ISC_R_SUCCESS) { + tokenp->type = + isc_tokentype_number; + tokenp->value.as_ulong = + as_ulong; + } else if (result == ISC_R_BADNUMBER) { + isc_tokenvalue_t *v; + + tokenp->type = + isc_tokentype_string; + v = &(tokenp->value); + v->as_textregion.base = + lex->data; + v->as_textregion.length = + lex->max_token - + remaining; + } else + goto done; + done = ISC_TRUE; + continue; + } else if (!(options & ISC_LEXOPT_CNUMBER) || + ((c != 'x' && c != 'X') || + (curr != &lex->data[1]) || + (lex->data[0] != '0'))) { + /* Above test supports hex numbers */ + state = lexstate_string; + } + } else if ((options & ISC_LEXOPT_OCTAL) != 0 && + (c == '8' || c == '9')) { + state = lexstate_string; + } + if (remaining == 0U) { + result = grow_data(lex, &remaining, + &curr, &prev); + if (result != ISC_R_SUCCESS) + goto done; + } + INSIST(remaining > 0U); + *curr++ = c; + *curr = '\0'; + remaining--; + break; + case lexstate_string: + /* + * EOF needs to be checked before lex->specials[c] + * as lex->specials[EOF] is not a good idea. + */ + if (c == '\r' || c == '\n' || c == EOF || + (!escaped && + (c == ' ' || c == '\t' || lex->specials[c]))) { + pushback(source, c); + if (source->result != ISC_R_SUCCESS) { + result = source->result; + goto done; + } + tokenp->type = isc_tokentype_string; + tokenp->value.as_textregion.base = lex->data; + tokenp->value.as_textregion.length = + lex->max_token - remaining; + done = ISC_TRUE; + continue; + } + if ((options & ISC_LEXOPT_ESCAPE) != 0) + escaped = (!escaped && c == '\\') ? + ISC_TRUE : ISC_FALSE; + if (remaining == 0U) { + result = grow_data(lex, &remaining, + &curr, &prev); + if (result != ISC_R_SUCCESS) + goto done; + } + INSIST(remaining > 0U); + *curr++ = c; + *curr = '\0'; + remaining--; + break; + case lexstate_maybecomment: + if (c == '*' && + (lex->comments & ISC_LEXCOMMENT_C) != 0) { + state = lexstate_ccomment; + continue; + } else if (c == '/' && + (lex->comments & ISC_LEXCOMMENT_CPLUSPLUS) != 0) { + state = lexstate_eatline; + continue; + } + pushback(source, c); + c = '/'; + no_comments = ISC_FALSE; + state = saved_state; + goto no_read; + case lexstate_ccomment: + if (c == EOF) { + result = ISC_R_UNEXPECTEDEND; + goto done; + } + if (c == '*') + state = lexstate_ccommentend; + break; + case lexstate_ccommentend: + if (c == EOF) { + result = ISC_R_UNEXPECTEDEND; + goto done; + } + if (c == '/') { + /* + * C-style comments become a single space. + * We do this to ensure that a comment will + * act as a delimiter for strings and + * numbers. + */ + c = ' '; + no_comments = ISC_FALSE; + state = saved_state; + goto no_read; + } else if (c != '*') + state = lexstate_ccomment; + break; + case lexstate_eatline: + if ((c == '\n') || (c == EOF)) { + no_comments = ISC_FALSE; + state = saved_state; + goto no_read; + } + break; + case lexstate_qstring: + if (c == EOF) { + result = ISC_R_UNEXPECTEDEND; + goto done; + } + if (c == '"') { + if (escaped) { + escaped = ISC_FALSE; + /* + * Overwrite the preceding backslash. + */ + INSIST(prev != NULL); + *prev = '"'; + } else { + tokenp->type = isc_tokentype_qstring; + tokenp->value.as_textregion.base = + lex->data; + tokenp->value.as_textregion.length = + lex->max_token - remaining; + no_comments = ISC_FALSE; + done = ISC_TRUE; + } + } else { + if (c == '\n' && !escaped && + (options & ISC_LEXOPT_QSTRINGMULTILINE) == 0) { + pushback(source, c); + result = ISC_R_UNBALANCEDQUOTES; + goto done; + } + if (c == '\\' && !escaped) + escaped = ISC_TRUE; + else + escaped = ISC_FALSE; + if (remaining == 0U) { + result = grow_data(lex, &remaining, + &curr, &prev); + if (result != ISC_R_SUCCESS) + goto done; + } + INSIST(remaining > 0U); + prev = curr; + *curr++ = c; + *curr = '\0'; + remaining--; + } + break; + default: + FATAL_ERROR(__FILE__, __LINE__, + isc_msgcat_get(isc_msgcat, ISC_MSGSET_LEX, + ISC_MSG_UNEXPECTEDSTATE, + "Unexpected state %d"), + state); + /* Does not return. */ + } + + } while (!done); + + result = ISC_R_SUCCESS; + done: +#ifdef HAVE_FLOCKFILE + if (source->is_file) + funlockfile(source->input); +#endif + return (result); +} + +isc_result_t +isc_lex_getmastertoken(isc_lex_t *lex, isc_token_t *token, + isc_tokentype_t expect, isc_boolean_t eol) +{ + unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF | + ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE; + isc_result_t result; + + if (expect == isc_tokentype_qstring) + options |= ISC_LEXOPT_QSTRING; + else if (expect == isc_tokentype_number) + options |= ISC_LEXOPT_NUMBER; + result = isc_lex_gettoken(lex, options, token); + if (result == ISC_R_RANGE) + isc_lex_ungettoken(lex, token); + if (result != ISC_R_SUCCESS) + return (result); + + if (eol && ((token->type == isc_tokentype_eol) || + (token->type == isc_tokentype_eof))) + return (ISC_R_SUCCESS); + if (token->type == isc_tokentype_string && + expect == isc_tokentype_qstring) + return (ISC_R_SUCCESS); + if (token->type != expect) { + isc_lex_ungettoken(lex, token); + if (token->type == isc_tokentype_eol || + token->type == isc_tokentype_eof) + return (ISC_R_UNEXPECTEDEND); + if (expect == isc_tokentype_number) + return (ISC_R_BADNUMBER); + return (ISC_R_UNEXPECTEDTOKEN); + } + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_lex_getoctaltoken(isc_lex_t *lex, isc_token_t *token, isc_boolean_t eol) +{ + unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF | + ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE| + ISC_LEXOPT_NUMBER | ISC_LEXOPT_OCTAL; + isc_result_t result; + + result = isc_lex_gettoken(lex, options, token); + if (result == ISC_R_RANGE) + isc_lex_ungettoken(lex, token); + if (result != ISC_R_SUCCESS) + return (result); + + if (eol && ((token->type == isc_tokentype_eol) || + (token->type == isc_tokentype_eof))) + return (ISC_R_SUCCESS); + if (token->type != isc_tokentype_number) { + isc_lex_ungettoken(lex, token); + if (token->type == isc_tokentype_eol || + token->type == isc_tokentype_eof) + return (ISC_R_UNEXPECTEDEND); + return (ISC_R_BADNUMBER); + } + return (ISC_R_SUCCESS); +} + +void +isc_lex_ungettoken(isc_lex_t *lex, isc_token_t *tokenp) { + inputsource *source; + /* + * Unget the current token. + */ + + REQUIRE(VALID_LEX(lex)); + source = HEAD(lex->sources); + REQUIRE(source != NULL); + REQUIRE(tokenp != NULL); + REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 || + tokenp->type == isc_tokentype_eof); + + UNUSED(tokenp); + + isc_buffer_first(source->pushback); + lex->paren_count = lex->saved_paren_count; + source->line = source->saved_line; + source->at_eof = ISC_FALSE; +} + +void +isc_lex_getlasttokentext(isc_lex_t *lex, isc_token_t *tokenp, isc_region_t *r) +{ + inputsource *source; + + REQUIRE(VALID_LEX(lex)); + source = HEAD(lex->sources); + REQUIRE(source != NULL); + REQUIRE(tokenp != NULL); + REQUIRE(isc_buffer_consumedlength(source->pushback) != 0 || + tokenp->type == isc_tokentype_eof); + + UNUSED(tokenp); + + INSIST(source->ignored <= isc_buffer_consumedlength(source->pushback)); + r->base = (unsigned char *)isc_buffer_base(source->pushback) + + source->ignored; + r->length = isc_buffer_consumedlength(source->pushback) - + source->ignored; +} + + +char * +isc_lex_getsourcename(isc_lex_t *lex) { + inputsource *source; + + REQUIRE(VALID_LEX(lex)); + source = HEAD(lex->sources); + + if (source == NULL) + return (NULL); + + return (source->name); +} + +unsigned long +isc_lex_getsourceline(isc_lex_t *lex) { + inputsource *source; + + REQUIRE(VALID_LEX(lex)); + source = HEAD(lex->sources); + + if (source == NULL) + return (0); + + return (source->line); +} + + +isc_result_t +isc_lex_setsourcename(isc_lex_t *lex, const char *name) { + inputsource *source; + char *newname; + + REQUIRE(VALID_LEX(lex)); + source = HEAD(lex->sources); + + if (source == NULL) + return(ISC_R_NOTFOUND); + newname = isc_mem_strdup(lex->mctx, name); + if (newname == NULL) + return (ISC_R_NOMEMORY); + isc_mem_free(lex->mctx, source->name); + source->name = newname; + return (ISC_R_SUCCESS); +} + +isc_boolean_t +isc_lex_isfile(isc_lex_t *lex) { + inputsource *source; + + REQUIRE(VALID_LEX(lex)); + + source = HEAD(lex->sources); + + if (source == NULL) + return (ISC_FALSE); + + return (source->is_file); +} diff --git a/contrib/ntp/lib/isc/lfsr.c b/contrib/ntp/lib/isc/lfsr.c new file mode 100644 index 0000000..0b8d782 --- /dev/null +++ b/contrib/ntp/lib/isc/lfsr.c @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: lfsr.c,v 1.20 2007/06/19 23:47:17 tbox Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <stddef.h> +#include <stdlib.h> + +#include <isc/assertions.h> +#include <isc/lfsr.h> +#include <isc/util.h> + +#define VALID_LFSR(x) (x != NULL) + +void +isc_lfsr_init(isc_lfsr_t *lfsr, isc_uint32_t state, unsigned int bits, + isc_uint32_t tap, unsigned int count, + isc_lfsrreseed_t reseed, void *arg) +{ + REQUIRE(VALID_LFSR(lfsr)); + REQUIRE(8 <= bits && bits <= 32); + REQUIRE(tap != 0); + + lfsr->state = state; + lfsr->bits = bits; + lfsr->tap = tap; + lfsr->count = count; + lfsr->reseed = reseed; + lfsr->arg = arg; + + if (count == 0 && reseed != NULL) + reseed(lfsr, arg); + if (lfsr->state == 0) + lfsr->state = 0xffffffffU >> (32 - lfsr->bits); +} + +/*! + * Return the next state of the lfsr. + */ +static inline isc_uint32_t +lfsr_generate(isc_lfsr_t *lfsr) +{ + + /* + * If the previous state is zero, we must fill it with something + * here, or we will begin to generate an extremely predictable output. + * + * First, give the reseed function a crack at it. If the state is + * still 0, set it to all ones. + */ + if (lfsr->state == 0) { + if (lfsr->reseed != NULL) + lfsr->reseed(lfsr, lfsr->arg); + if (lfsr->state == 0) + lfsr->state = 0xffffffffU >> (32 - lfsr->bits); + } + + if (lfsr->state & 0x01) { + lfsr->state = (lfsr->state >> 1) ^ lfsr->tap; + return (1); + } else { + lfsr->state >>= 1; + return (0); + } +} + +void +isc_lfsr_generate(isc_lfsr_t *lfsr, void *data, unsigned int count) +{ + unsigned char *p; + unsigned int bit; + unsigned int byte; + + REQUIRE(VALID_LFSR(lfsr)); + REQUIRE(data != NULL); + REQUIRE(count > 0); + + p = data; + byte = count; + + while (byte--) { + *p = 0; + for (bit = 0; bit < 7; bit++) { + *p |= lfsr_generate(lfsr); + *p <<= 1; + } + *p |= lfsr_generate(lfsr); + p++; + } + + if (lfsr->count != 0 && lfsr->reseed != NULL) { + if (lfsr->count <= count * 8) + lfsr->reseed(lfsr, lfsr->arg); + else + lfsr->count -= (count * 8); + } +} + +static inline isc_uint32_t +lfsr_skipgenerate(isc_lfsr_t *lfsr, unsigned int skip) +{ + while (skip--) + (void)lfsr_generate(lfsr); + + (void)lfsr_generate(lfsr); + + return (lfsr->state); +} + +/* + * Skip "skip" states in "lfsr". + */ +void +isc_lfsr_skip(isc_lfsr_t *lfsr, unsigned int skip) +{ + REQUIRE(VALID_LFSR(lfsr)); + + while (skip--) + (void)lfsr_generate(lfsr); +} + +/* + * Skip states in lfsr1 and lfsr2 using the other's current state. + * Return the final state of lfsr1 ^ lfsr2. + */ +isc_uint32_t +isc_lfsr_generate32(isc_lfsr_t *lfsr1, isc_lfsr_t *lfsr2) +{ + isc_uint32_t state1, state2; + isc_uint32_t skip1, skip2; + + REQUIRE(VALID_LFSR(lfsr1)); + REQUIRE(VALID_LFSR(lfsr2)); + + skip1 = lfsr1->state & 0x01; + skip2 = lfsr2->state & 0x01; + + /* cross-skip. */ + state1 = lfsr_skipgenerate(lfsr1, skip2); + state2 = lfsr_skipgenerate(lfsr2, skip1); + + return (state1 ^ state2); +} diff --git a/contrib/ntp/lib/isc/lib.c b/contrib/ntp/lib/isc/lib.c new file mode 100644 index 0000000..a505425 --- /dev/null +++ b/contrib/ntp/lib/isc/lib.c @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: lib.c,v 1.16 2009/09/02 23:48:02 tbox Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> + +#include <isc/app.h> +#include <isc/lib.h> +#include <isc/mem.h> +#include <isc/msgs.h> +#include <isc/once.h> +#include <isc/socket.h> +#include <isc/task.h> +#include <isc/timer.h> +#include <isc/util.h> + +/*** + *** Globals + ***/ + +LIBISC_EXTERNAL_DATA isc_msgcat_t * isc_msgcat = NULL; + + +/*** + *** Private + ***/ + +static isc_once_t msgcat_once = ISC_ONCE_INIT; + +/*** + *** Functions + ***/ + +static void +open_msgcat(void) { + isc_msgcat_open("libisc.cat", &isc_msgcat); +} + +void +isc_lib_initmsgcat(void) { + isc_result_t result; + + /*! + * Initialize the ISC library's message catalog, isc_msgcat, if it + * has not already been initialized. + */ + + result = isc_once_do(&msgcat_once, open_msgcat); + if (result != ISC_R_SUCCESS) { + /* + * Normally we'd use RUNTIME_CHECK() or FATAL_ERROR(), but + * we can't do that here, since they might call us! + * (Note that the catalog might be open anyway, so we might + * as well try to provide an internationalized message.) + */ + fprintf(stderr, "%s:%d: %s: isc_once_do() %s.\n", + __FILE__, __LINE__, + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FATALERROR, "fatal error"), + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed")); + abort(); + } +} + +#ifndef BIND9 +static isc_once_t register_once = ISC_ONCE_INIT; + +static void +do_register(void) { + RUNTIME_CHECK(isc__mem_register() == ISC_R_SUCCESS); + RUNTIME_CHECK(isc__app_register() == ISC_R_SUCCESS); + RUNTIME_CHECK(isc__task_register() == ISC_R_SUCCESS); + RUNTIME_CHECK(isc__socket_register() == ISC_R_SUCCESS); + RUNTIME_CHECK(isc__timer_register() == ISC_R_SUCCESS); +} + +void +isc_lib_register() { + RUNTIME_CHECK(isc_once_do(®ister_once, do_register) + == ISC_R_SUCCESS); +} +#endif diff --git a/contrib/ntp/lib/isc/log.c b/contrib/ntp/lib/isc/log.c new file mode 100644 index 0000000..ce98303 --- /dev/null +++ b/contrib/ntp/lib/isc/log.c @@ -0,0 +1,1767 @@ +/* + * Copyright (C) 2004-2007, 2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/*! \file + * \author Principal Authors: DCL */ + +#include <config.h> + +#include <errno.h> +#include <stdlib.h> +#include <limits.h> +#include <time.h> + +#include <sys/types.h> /* dev_t FreeBSD 2.1 */ + +#include <isc/dir.h> +#include <isc/file.h> +#include <isc/log.h> +#include <isc/magic.h> +#include <isc/mem.h> +#include <isc/msgs.h> +#include <isc/print.h> +#include <isc/stat.h> +#include <isc/stdio.h> +#include <isc/string.h> +#include <isc/time.h> +#include <isc/util.h> +#include "ntp_stdlib.h" /* NTP change for strlcpy, strlcat */ + +#define LCTX_MAGIC ISC_MAGIC('L', 'c', 't', 'x') +#define VALID_CONTEXT(lctx) ISC_MAGIC_VALID(lctx, LCTX_MAGIC) + +#define LCFG_MAGIC ISC_MAGIC('L', 'c', 'f', 'g') +#define VALID_CONFIG(lcfg) ISC_MAGIC_VALID(lcfg, LCFG_MAGIC) + +/* + * XXXDCL make dynamic? + */ +#define LOG_BUFFER_SIZE (8 * 1024) + +#ifndef PATH_MAX +#define PATH_MAX 1024 /* AIX and others don't define this. */ +#endif + +/*! + * This is the structure that holds each named channel. A simple linked + * list chains all of the channels together, so an individual channel is + * found by doing strcmp()s with the names down the list. Their should + * be no performance penalty from this as it is expected that the number + * of named channels will be no more than a dozen or so, and name lookups + * from the head of the list are only done when isc_log_usechannel() is + * called, which should also be very infrequent. + */ +typedef struct isc_logchannel isc_logchannel_t; + +struct isc_logchannel { + char * name; + unsigned int type; + int level; + unsigned int flags; + isc_logdestination_t destination; + ISC_LINK(isc_logchannel_t) link; +}; + +/*! + * The logchannellist structure associates categories and modules with + * channels. First the appropriate channellist is found based on the + * category, and then each structure in the linked list is checked for + * a matching module. It is expected that the number of channels + * associated with any given category will be very short, no more than + * three or four in the more unusual cases. + */ +typedef struct isc_logchannellist isc_logchannellist_t; + +struct isc_logchannellist { + const isc_logmodule_t * module; + isc_logchannel_t * channel; + ISC_LINK(isc_logchannellist_t) link; +}; + +/*! + * This structure is used to remember messages for pruning via + * isc_log_[v]write1(). + */ +typedef struct isc_logmessage isc_logmessage_t; + +struct isc_logmessage { + char * text; + isc_time_t time; + ISC_LINK(isc_logmessage_t) link; +}; + +/*! + * The isc_logconfig structure is used to store the configurable information + * about where messages are actually supposed to be sent -- the information + * that could changed based on some configuration file, as opposed to the + * the category/module specification of isc_log_[v]write[1] that is compiled + * into a program, or the debug_level which is dynamic state information. + */ +struct isc_logconfig { + unsigned int magic; + isc_log_t * lctx; + ISC_LIST(isc_logchannel_t) channels; + ISC_LIST(isc_logchannellist_t) *channellists; + unsigned int channellist_count; + unsigned int duplicate_interval; + int highest_level; + char * tag; + isc_boolean_t dynamic; +}; + +/*! + * This isc_log structure provides the context for the isc_log functions. + * The log context locks itself in isc_log_doit, the internal backend to + * isc_log_write. The locking is necessary both to provide exclusive access + * to the buffer into which the message is formatted and to guard against + * competing threads trying to write to the same syslog resource. (On + * some systems, such as BSD/OS, stdio is thread safe but syslog is not.) + * Unfortunately, the lock cannot guard against a _different_ logging + * context in the same program competing for syslog's attention. Thus + * There Can Be Only One, but this is not enforced. + * XXXDCL enforce it? + * + * Note that the category and module information is not locked. + * This is because in the usual case, only one isc_log_t is ever created + * in a program, and the category/module registration happens only once. + * XXXDCL it might be wise to add more locking overall. + */ +struct isc_log { + /* Not locked. */ + unsigned int magic; + isc_mem_t * mctx; + isc_logcategory_t * categories; + unsigned int category_count; + isc_logmodule_t * modules; + unsigned int module_count; + int debug_level; + isc_mutex_t lock; + /* Locked by isc_log lock. */ + isc_logconfig_t * logconfig; + char buffer[LOG_BUFFER_SIZE]; + ISC_LIST(isc_logmessage_t) messages; +}; + +/*! + * Used when ISC_LOG_PRINTLEVEL is enabled for a channel. + */ +static const char *log_level_strings[] = { + "debug", + "info", + "notice", + "warning", + "error", + "critical" +}; + +/*! + * Used to convert ISC_LOG_* priorities into syslog priorities. + * XXXDCL This will need modification for NT. + */ +static const int syslog_map[] = { + LOG_DEBUG, + LOG_INFO, + LOG_NOTICE, + LOG_WARNING, + LOG_ERR, + LOG_CRIT +}; + +/*! + * When adding new categories, a corresponding ISC_LOGCATEGORY_foo + * definition needs to be added to <isc/log.h>. + * + * The default category is provided so that the internal default can + * be overridden. Since the default is always looked up as the first + * channellist in the log context, it must come first in isc_categories[]. + */ +LIBISC_EXTERNAL_DATA isc_logcategory_t isc_categories[] = { + { "default", 0 }, /* "default" must come first. */ + { "general", 0 }, + { NULL, 0 } +}; + +/*! + * See above comment for categories on LIBISC_EXTERNAL_DATA, and apply it to modules. + */ +LIBISC_EXTERNAL_DATA isc_logmodule_t isc_modules[] = { + { "socket", 0 }, + { "time", 0 }, + { "interface", 0 }, + { "timer", 0 }, + { "file", 0 }, + { NULL, 0 } +}; + +/*! + * This essentially constant structure must be filled in at run time, + * because its channel member is pointed to a channel that is created + * dynamically with isc_log_createchannel. + */ +static isc_logchannellist_t default_channel; + +/*! + * libisc logs to this context. + */ +LIBISC_EXTERNAL_DATA isc_log_t *isc_lctx = NULL; + +/*! + * Forward declarations. + */ +static isc_result_t +assignchannel(isc_logconfig_t *lcfg, unsigned int category_id, + const isc_logmodule_t *module, isc_logchannel_t *channel); + +static isc_result_t +sync_channellist(isc_logconfig_t *lcfg); + +static isc_result_t +greatest_version(isc_logchannel_t *channel, int *greatest); + +static isc_result_t +roll_log(isc_logchannel_t *channel); + +static void +isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category, + isc_logmodule_t *module, int level, isc_boolean_t write_once, + isc_msgcat_t *msgcat, int msgset, int msg, + const char *format, va_list args) + ISC_FORMAT_PRINTF(9, 0); + +/*@{*/ +/*! + * Convenience macros. + */ + +#define FACILITY(channel) (channel->destination.facility) +#define FILE_NAME(channel) (channel->destination.file.name) +#define FILE_STREAM(channel) (channel->destination.file.stream) +#define FILE_VERSIONS(channel) (channel->destination.file.versions) +#define FILE_MAXSIZE(channel) (channel->destination.file.maximum_size) +#define FILE_MAXREACHED(channel) (channel->destination.file.maximum_reached) + +/*@}*/ +/**** + **** Public interfaces. + ****/ + +/* + * Establish a new logging context, with default channels. + */ +isc_result_t +isc_log_create(isc_mem_t *mctx, isc_log_t **lctxp, isc_logconfig_t **lcfgp) { + isc_log_t *lctx; + isc_logconfig_t *lcfg = NULL; + isc_result_t result; + + REQUIRE(mctx != NULL); + REQUIRE(lctxp != NULL && *lctxp == NULL); + REQUIRE(lcfgp == NULL || *lcfgp == NULL); + + lctx = isc_mem_get(mctx, sizeof(*lctx)); + if (lctx != NULL) { + lctx->mctx = mctx; + lctx->categories = NULL; + lctx->category_count = 0; + lctx->modules = NULL; + lctx->module_count = 0; + lctx->debug_level = 0; + + ISC_LIST_INIT(lctx->messages); + + result = isc_mutex_init(&lctx->lock); + if (result != ISC_R_SUCCESS) { + isc_mem_put(mctx, lctx, sizeof(*lctx)); + return (result); + } + + /* + * Normally setting the magic number is the last step done + * in a creation function, but a valid log context is needed + * by isc_log_registercategories and isc_logconfig_create. + * If either fails, the lctx is destroyed and not returned + * to the caller. + */ + lctx->magic = LCTX_MAGIC; + + isc_log_registercategories(lctx, isc_categories); + isc_log_registermodules(lctx, isc_modules); + result = isc_logconfig_create(lctx, &lcfg); + + } else + result = ISC_R_NOMEMORY; + + if (result == ISC_R_SUCCESS) + result = sync_channellist(lcfg); + + if (result == ISC_R_SUCCESS) { + lctx->logconfig = lcfg; + + *lctxp = lctx; + if (lcfgp != NULL) + *lcfgp = lcfg; + + } else { + if (lcfg != NULL) + isc_logconfig_destroy(&lcfg); + if (lctx != NULL) + isc_log_destroy(&lctx); + } + + return (result); +} + +isc_result_t +isc_logconfig_create(isc_log_t *lctx, isc_logconfig_t **lcfgp) { + isc_logconfig_t *lcfg; + isc_logdestination_t destination; + isc_result_t result = ISC_R_SUCCESS; + int level = ISC_LOG_INFO; + + REQUIRE(lcfgp != NULL && *lcfgp == NULL); + REQUIRE(VALID_CONTEXT(lctx)); + + lcfg = isc_mem_get(lctx->mctx, sizeof(*lcfg)); + + if (lcfg != NULL) { + lcfg->lctx = lctx; + lcfg->channellists = NULL; + lcfg->channellist_count = 0; + lcfg->duplicate_interval = 0; + lcfg->highest_level = level; + lcfg->tag = NULL; + lcfg->dynamic = ISC_FALSE; + + ISC_LIST_INIT(lcfg->channels); + + /* + * Normally the magic number is the last thing set in the + * structure, but isc_log_createchannel() needs a valid + * config. If the channel creation fails, the lcfg is not + * returned to the caller. + */ + lcfg->magic = LCFG_MAGIC; + + } else + result = ISC_R_NOMEMORY; + + /* + * Create the default channels: + * default_syslog, default_stderr, default_debug and null. + */ + if (result == ISC_R_SUCCESS) { + destination.facility = LOG_DAEMON; + result = isc_log_createchannel(lcfg, "default_syslog", + ISC_LOG_TOSYSLOG, level, + &destination, 0); + } + + if (result == ISC_R_SUCCESS) { + destination.file.stream = stderr; + destination.file.name = NULL; + destination.file.versions = ISC_LOG_ROLLNEVER; + destination.file.maximum_size = 0; + result = isc_log_createchannel(lcfg, "default_stderr", + ISC_LOG_TOFILEDESC, + level, + &destination, + ISC_LOG_PRINTTIME); + } + + if (result == ISC_R_SUCCESS) { + /* + * Set the default category's channel to default_stderr, + * which is at the head of the channels list because it was + * just created. + */ + default_channel.channel = ISC_LIST_HEAD(lcfg->channels); + + destination.file.stream = stderr; + destination.file.name = NULL; + destination.file.versions = ISC_LOG_ROLLNEVER; + destination.file.maximum_size = 0; + result = isc_log_createchannel(lcfg, "default_debug", + ISC_LOG_TOFILEDESC, + ISC_LOG_DYNAMIC, + &destination, + ISC_LOG_PRINTTIME); + } + + if (result == ISC_R_SUCCESS) + result = isc_log_createchannel(lcfg, "null", + ISC_LOG_TONULL, + ISC_LOG_DYNAMIC, + NULL, 0); + + if (result == ISC_R_SUCCESS) + *lcfgp = lcfg; + + else + if (lcfg != NULL) + isc_logconfig_destroy(&lcfg); + + return (result); +} + +isc_logconfig_t * +isc_logconfig_get(isc_log_t *lctx) { + REQUIRE(VALID_CONTEXT(lctx)); + + ENSURE(lctx->logconfig != NULL); + + return (lctx->logconfig); +} + +isc_result_t +isc_logconfig_use(isc_log_t *lctx, isc_logconfig_t *lcfg) { + isc_logconfig_t *old_cfg; + isc_result_t result; + + REQUIRE(VALID_CONTEXT(lctx)); + REQUIRE(VALID_CONFIG(lcfg)); + REQUIRE(lcfg->lctx == lctx); + + /* + * Ensure that lcfg->channellist_count == lctx->category_count. + * They won't be equal if isc_log_usechannel has not been called + * since any call to isc_log_registercategories. + */ + result = sync_channellist(lcfg); + if (result != ISC_R_SUCCESS) + return (result); + + LOCK(&lctx->lock); + + old_cfg = lctx->logconfig; + lctx->logconfig = lcfg; + + UNLOCK(&lctx->lock); + + isc_logconfig_destroy(&old_cfg); + + return (ISC_R_SUCCESS); +} + +void +isc_log_destroy(isc_log_t **lctxp) { + isc_log_t *lctx; + isc_logconfig_t *lcfg; + isc_mem_t *mctx; + isc_logmessage_t *message; + + REQUIRE(lctxp != NULL && VALID_CONTEXT(*lctxp)); + + lctx = *lctxp; + mctx = lctx->mctx; + + if (lctx->logconfig != NULL) { + lcfg = lctx->logconfig; + lctx->logconfig = NULL; + isc_logconfig_destroy(&lcfg); + } + + DESTROYLOCK(&lctx->lock); + + while ((message = ISC_LIST_HEAD(lctx->messages)) != NULL) { + ISC_LIST_UNLINK(lctx->messages, message, link); + + isc_mem_put(mctx, message, + sizeof(*message) + strlen(message->text) + 1); + } + + lctx->buffer[0] = '\0'; + lctx->debug_level = 0; + lctx->categories = NULL; + lctx->category_count = 0; + lctx->modules = NULL; + lctx->module_count = 0; + lctx->mctx = NULL; + lctx->magic = 0; + + isc_mem_put(mctx, lctx, sizeof(*lctx)); + + *lctxp = NULL; +} + +void +isc_logconfig_destroy(isc_logconfig_t **lcfgp) { + isc_logconfig_t *lcfg; + isc_mem_t *mctx; + isc_logchannel_t *channel; + isc_logchannellist_t *item; + char *filename; + unsigned int i; + + REQUIRE(lcfgp != NULL && VALID_CONFIG(*lcfgp)); + + lcfg = *lcfgp; + + /* + * This function cannot be called with a logconfig that is in + * use by a log context. + */ + REQUIRE(lcfg->lctx != NULL && lcfg->lctx->logconfig != lcfg); + + mctx = lcfg->lctx->mctx; + + while ((channel = ISC_LIST_HEAD(lcfg->channels)) != NULL) { + ISC_LIST_UNLINK(lcfg->channels, channel, link); + + if (channel->type == ISC_LOG_TOFILE) { + /* + * The filename for the channel may have ultimately + * started its life in user-land as a const string, + * but in isc_log_createchannel it gets copied + * into writable memory and is not longer truly const. + */ + DE_CONST(FILE_NAME(channel), filename); + isc_mem_free(mctx, filename); + + if (FILE_STREAM(channel) != NULL) + (void)fclose(FILE_STREAM(channel)); + } + + isc_mem_free(mctx, channel->name); + isc_mem_put(mctx, channel, sizeof(*channel)); + } + + for (i = 0; i < lcfg->channellist_count; i++) + while ((item = ISC_LIST_HEAD(lcfg->channellists[i])) != NULL) { + ISC_LIST_UNLINK(lcfg->channellists[i], item, link); + isc_mem_put(mctx, item, sizeof(*item)); + } + + if (lcfg->channellist_count > 0) + isc_mem_put(mctx, lcfg->channellists, + lcfg->channellist_count * + sizeof(ISC_LIST(isc_logchannellist_t))); + + lcfg->dynamic = ISC_FALSE; + if (lcfg->tag != NULL) + isc_mem_free(lcfg->lctx->mctx, lcfg->tag); + lcfg->tag = NULL; + lcfg->highest_level = 0; + lcfg->duplicate_interval = 0; + lcfg->magic = 0; + + isc_mem_put(mctx, lcfg, sizeof(*lcfg)); + + *lcfgp = NULL; +} + +void +isc_log_registercategories(isc_log_t *lctx, isc_logcategory_t categories[]) { + isc_logcategory_t *catp; + + REQUIRE(VALID_CONTEXT(lctx)); + REQUIRE(categories != NULL && categories[0].name != NULL); + + /* + * XXXDCL This somewhat sleazy situation of using the last pointer + * in one category array to point to the next array exists because + * this registration function returns void and I didn't want to have + * change everything that used it by making it return an isc_result_t. + * It would need to do that if it had to allocate memory to store + * pointers to each array passed in. + */ + if (lctx->categories == NULL) + lctx->categories = categories; + + else { + /* + * Adjust the last (NULL) pointer of the already registered + * categories to point to the incoming array. + */ + for (catp = lctx->categories; catp->name != NULL; ) + if (catp->id == UINT_MAX) + /* + * The name pointer points to the next array. + * Ick. + */ + DE_CONST(catp->name, catp); + else + catp++; + + catp->name = (void *)categories; + catp->id = UINT_MAX; + } + + /* + * Update the id number of the category with its new global id. + */ + for (catp = categories; catp->name != NULL; catp++) + catp->id = lctx->category_count++; +} + +isc_logcategory_t * +isc_log_categorybyname(isc_log_t *lctx, const char *name) { + isc_logcategory_t *catp; + + REQUIRE(VALID_CONTEXT(lctx)); + REQUIRE(name != NULL); + + for (catp = lctx->categories; catp->name != NULL; ) + if (catp->id == UINT_MAX) + /* + * catp is neither modified nor returned to the + * caller, so removing its const qualifier is ok. + */ + DE_CONST(catp->name, catp); + else { + if (strcmp(catp->name, name) == 0) + return (catp); + catp++; + } + + return (NULL); +} + +void +isc_log_registermodules(isc_log_t *lctx, isc_logmodule_t modules[]) { + isc_logmodule_t *modp; + + REQUIRE(VALID_CONTEXT(lctx)); + REQUIRE(modules != NULL && modules[0].name != NULL); + + /* + * XXXDCL This somewhat sleazy situation of using the last pointer + * in one category array to point to the next array exists because + * this registration function returns void and I didn't want to have + * change everything that used it by making it return an isc_result_t. + * It would need to do that if it had to allocate memory to store + * pointers to each array passed in. + */ + if (lctx->modules == NULL) + lctx->modules = modules; + + else { + /* + * Adjust the last (NULL) pointer of the already registered + * modules to point to the incoming array. + */ + for (modp = lctx->modules; modp->name != NULL; ) + if (modp->id == UINT_MAX) + /* + * The name pointer points to the next array. + * Ick. + */ + DE_CONST(modp->name, modp); + else + modp++; + + modp->name = (void *)modules; + modp->id = UINT_MAX; + } + + /* + * Update the id number of the module with its new global id. + */ + for (modp = modules; modp->name != NULL; modp++) + modp->id = lctx->module_count++; +} + +isc_logmodule_t * +isc_log_modulebyname(isc_log_t *lctx, const char *name) { + isc_logmodule_t *modp; + + REQUIRE(VALID_CONTEXT(lctx)); + REQUIRE(name != NULL); + + for (modp = lctx->modules; modp->name != NULL; ) + if (modp->id == UINT_MAX) + /* + * modp is neither modified nor returned to the + * caller, so removing its const qualifier is ok. + */ + DE_CONST(modp->name, modp); + else { + if (strcmp(modp->name, name) == 0) + return (modp); + modp++; + } + + return (NULL); +} + +isc_result_t +isc_log_createchannel(isc_logconfig_t *lcfg, const char *name, + unsigned int type, int level, + const isc_logdestination_t *destination, + unsigned int flags) +{ + isc_logchannel_t *channel; + isc_mem_t *mctx; + + REQUIRE(VALID_CONFIG(lcfg)); + REQUIRE(name != NULL); + REQUIRE(type == ISC_LOG_TOSYSLOG || type == ISC_LOG_TOFILE || + type == ISC_LOG_TOFILEDESC || type == ISC_LOG_TONULL); + REQUIRE(destination != NULL || type == ISC_LOG_TONULL); + REQUIRE(level >= ISC_LOG_CRITICAL); + REQUIRE((flags & + (unsigned int)~(ISC_LOG_PRINTALL | ISC_LOG_DEBUGONLY)) == 0); + + /* XXXDCL find duplicate names? */ + + mctx = lcfg->lctx->mctx; + + channel = isc_mem_get(mctx, sizeof(*channel)); + if (channel == NULL) + return (ISC_R_NOMEMORY); + + channel->name = isc_mem_strdup(mctx, name); + if (channel->name == NULL) { + isc_mem_put(mctx, channel, sizeof(*channel)); + return (ISC_R_NOMEMORY); + } + + channel->type = type; + channel->level = level; + channel->flags = flags; + ISC_LINK_INIT(channel, link); + + switch (type) { + case ISC_LOG_TOSYSLOG: + FACILITY(channel) = destination->facility; + break; + + case ISC_LOG_TOFILE: + /* + * The file name is copied because greatest_version wants + * to scribble on it, so it needs to be definitely in + * writable memory. + */ + FILE_NAME(channel) = + isc_mem_strdup(mctx, destination->file.name); + FILE_STREAM(channel) = NULL; + FILE_VERSIONS(channel) = destination->file.versions; + FILE_MAXSIZE(channel) = destination->file.maximum_size; + FILE_MAXREACHED(channel) = ISC_FALSE; + break; + + case ISC_LOG_TOFILEDESC: + FILE_NAME(channel) = NULL; + FILE_STREAM(channel) = destination->file.stream; + FILE_MAXSIZE(channel) = 0; + FILE_VERSIONS(channel) = ISC_LOG_ROLLNEVER; + break; + + case ISC_LOG_TONULL: + /* Nothing. */ + break; + + default: + isc_mem_put(mctx, channel->name, strlen(channel->name) + 1); + isc_mem_put(mctx, channel, sizeof(*channel)); + return (ISC_R_UNEXPECTED); + } + + ISC_LIST_PREPEND(lcfg->channels, channel, link); + + /* + * If default_stderr was redefined, make the default category + * point to the new default_stderr. + */ + if (strcmp(name, "default_stderr") == 0) + default_channel.channel = channel; + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_log_usechannel(isc_logconfig_t *lcfg, const char *name, + const isc_logcategory_t *category, + const isc_logmodule_t *module) +{ + isc_log_t *lctx; + isc_logchannel_t *channel; + isc_result_t result = ISC_R_SUCCESS; + unsigned int i; + + REQUIRE(VALID_CONFIG(lcfg)); + REQUIRE(name != NULL); + + lctx = lcfg->lctx; + + REQUIRE(category == NULL || category->id < lctx->category_count); + REQUIRE(module == NULL || module->id < lctx->module_count); + + for (channel = ISC_LIST_HEAD(lcfg->channels); channel != NULL; + channel = ISC_LIST_NEXT(channel, link)) + if (strcmp(name, channel->name) == 0) + break; + + if (channel == NULL) + return (ISC_R_NOTFOUND); + + if (category != NULL) + result = assignchannel(lcfg, category->id, module, channel); + + else + /* + * Assign to all categories. Note that this includes + * the default channel. + */ + for (i = 0; i < lctx->category_count; i++) { + result = assignchannel(lcfg, i, module, channel); + if (result != ISC_R_SUCCESS) + break; + } + + return (result); +} + +void +isc_log_write(isc_log_t *lctx, isc_logcategory_t *category, + isc_logmodule_t *module, int level, const char *format, ...) +{ + va_list args; + + /* + * Contract checking is done in isc_log_doit(). + */ + + va_start(args, format); + isc_log_doit(lctx, category, module, level, ISC_FALSE, + NULL, 0, 0, format, args); + va_end(args); +} + +void +isc_log_vwrite(isc_log_t *lctx, isc_logcategory_t *category, + isc_logmodule_t *module, int level, + const char *format, va_list args) +{ + /* + * Contract checking is done in isc_log_doit(). + */ + isc_log_doit(lctx, category, module, level, ISC_FALSE, + NULL, 0, 0, format, args); +} + +void +isc_log_write1(isc_log_t *lctx, isc_logcategory_t *category, + isc_logmodule_t *module, int level, const char *format, ...) +{ + va_list args; + + /* + * Contract checking is done in isc_log_doit(). + */ + + va_start(args, format); + isc_log_doit(lctx, category, module, level, ISC_TRUE, + NULL, 0, 0, format, args); + va_end(args); +} + +void +isc_log_vwrite1(isc_log_t *lctx, isc_logcategory_t *category, + isc_logmodule_t *module, int level, + const char *format, va_list args) +{ + /* + * Contract checking is done in isc_log_doit(). + */ + isc_log_doit(lctx, category, module, level, ISC_TRUE, + NULL, 0, 0, format, args); +} + +void +isc_log_iwrite(isc_log_t *lctx, isc_logcategory_t *category, + isc_logmodule_t *module, int level, + isc_msgcat_t *msgcat, int msgset, int msg, + const char *format, ...) +{ + va_list args; + + /* + * Contract checking is done in isc_log_doit(). + */ + + va_start(args, format); + isc_log_doit(lctx, category, module, level, ISC_FALSE, + msgcat, msgset, msg, format, args); + va_end(args); +} + +void +isc_log_ivwrite(isc_log_t *lctx, isc_logcategory_t *category, + isc_logmodule_t *module, int level, + isc_msgcat_t *msgcat, int msgset, int msg, + const char *format, va_list args) +{ + /* + * Contract checking is done in isc_log_doit(). + */ + isc_log_doit(lctx, category, module, level, ISC_FALSE, + msgcat, msgset, msg, format, args); +} + +void +isc_log_iwrite1(isc_log_t *lctx, isc_logcategory_t *category, + isc_logmodule_t *module, int level, + isc_msgcat_t *msgcat, int msgset, int msg, + const char *format, ...) +{ + va_list args; + + /* + * Contract checking is done in isc_log_doit(). + */ + + va_start(args, format); + isc_log_doit(lctx, category, module, level, ISC_TRUE, + msgcat, msgset, msg, format, args); + va_end(args); +} + +void +isc_log_ivwrite1(isc_log_t *lctx, isc_logcategory_t *category, + isc_logmodule_t *module, int level, + isc_msgcat_t *msgcat, int msgset, int msg, + const char *format, va_list args) +{ + /* + * Contract checking is done in isc_log_doit(). + */ + isc_log_doit(lctx, category, module, level, ISC_TRUE, + msgcat, msgset, msg, format, args); +} + +void +isc_log_setcontext(isc_log_t *lctx) { + isc_lctx = lctx; +} + +void +isc_log_setdebuglevel(isc_log_t *lctx, unsigned int level) { + isc_logchannel_t *channel; + + REQUIRE(VALID_CONTEXT(lctx)); + + LOCK(&lctx->lock); + + lctx->debug_level = level; + /* + * Close ISC_LOG_DEBUGONLY channels if level is zero. + */ + if (lctx->debug_level == 0) + for (channel = ISC_LIST_HEAD(lctx->logconfig->channels); + channel != NULL; + channel = ISC_LIST_NEXT(channel, link)) + if (channel->type == ISC_LOG_TOFILE && + (channel->flags & ISC_LOG_DEBUGONLY) != 0 && + FILE_STREAM(channel) != NULL) { + (void)fclose(FILE_STREAM(channel)); + FILE_STREAM(channel) = NULL; + } + UNLOCK(&lctx->lock); +} + +unsigned int +isc_log_getdebuglevel(isc_log_t *lctx) { + REQUIRE(VALID_CONTEXT(lctx)); + + return (lctx->debug_level); +} + +void +isc_log_setduplicateinterval(isc_logconfig_t *lcfg, unsigned int interval) { + REQUIRE(VALID_CONFIG(lcfg)); + + lcfg->duplicate_interval = interval; +} + +unsigned int +isc_log_getduplicateinterval(isc_logconfig_t *lcfg) { + REQUIRE(VALID_CONTEXT(lcfg)); + + return (lcfg->duplicate_interval); +} + +isc_result_t +isc_log_settag(isc_logconfig_t *lcfg, const char *tag) { + REQUIRE(VALID_CONFIG(lcfg)); + + if (tag != NULL && *tag != '\0') { + if (lcfg->tag != NULL) + isc_mem_free(lcfg->lctx->mctx, lcfg->tag); + lcfg->tag = isc_mem_strdup(lcfg->lctx->mctx, tag); + if (lcfg->tag == NULL) + return (ISC_R_NOMEMORY); + + } else { + if (lcfg->tag != NULL) + isc_mem_free(lcfg->lctx->mctx, lcfg->tag); + lcfg->tag = NULL; + } + + return (ISC_R_SUCCESS); +} + +char * +isc_log_gettag(isc_logconfig_t *lcfg) { + REQUIRE(VALID_CONFIG(lcfg)); + + return (lcfg->tag); +} + +/* XXXDCL NT -- This interface will assuredly be changing. */ +void +isc_log_opensyslog(const char *tag, int options, int facility) { + (void)openlog(tag, options, facility); +} + +void +isc_log_closefilelogs(isc_log_t *lctx) { + isc_logchannel_t *channel; + + REQUIRE(VALID_CONTEXT(lctx)); + + LOCK(&lctx->lock); + for (channel = ISC_LIST_HEAD(lctx->logconfig->channels); + channel != NULL; + channel = ISC_LIST_NEXT(channel, link)) + + if (channel->type == ISC_LOG_TOFILE && + FILE_STREAM(channel) != NULL) { + (void)fclose(FILE_STREAM(channel)); + FILE_STREAM(channel) = NULL; + } + UNLOCK(&lctx->lock); +} + +/**** + **** Internal functions + ****/ + +static isc_result_t +assignchannel(isc_logconfig_t *lcfg, unsigned int category_id, + const isc_logmodule_t *module, isc_logchannel_t *channel) +{ + isc_logchannellist_t *new_item; + isc_log_t *lctx; + isc_result_t result; + + REQUIRE(VALID_CONFIG(lcfg)); + + lctx = lcfg->lctx; + + REQUIRE(category_id < lctx->category_count); + REQUIRE(module == NULL || module->id < lctx->module_count); + REQUIRE(channel != NULL); + + /* + * Ensure lcfg->channellist_count == lctx->category_count. + */ + result = sync_channellist(lcfg); + if (result != ISC_R_SUCCESS) + return (result); + + new_item = isc_mem_get(lctx->mctx, sizeof(*new_item)); + if (new_item == NULL) + return (ISC_R_NOMEMORY); + + new_item->channel = channel; + new_item->module = module; + ISC_LIST_INITANDPREPEND(lcfg->channellists[category_id], + new_item, link); + + /* + * Remember the highest logging level set by any channel in the + * logging config, so isc_log_doit() can quickly return if the + * message is too high to be logged by any channel. + */ + if (channel->type != ISC_LOG_TONULL) { + if (lcfg->highest_level < channel->level) + lcfg->highest_level = channel->level; + if (channel->level == ISC_LOG_DYNAMIC) + lcfg->dynamic = ISC_TRUE; + } + + return (ISC_R_SUCCESS); +} + +/* + * This would ideally be part of isc_log_registercategories(), except then + * that function would have to return isc_result_t instead of void. + */ +static isc_result_t +sync_channellist(isc_logconfig_t *lcfg) { + unsigned int bytes; + isc_log_t *lctx; + void *lists; + + REQUIRE(VALID_CONFIG(lcfg)); + + lctx = lcfg->lctx; + + REQUIRE(lctx->category_count != 0); + + if (lctx->category_count == lcfg->channellist_count) + return (ISC_R_SUCCESS); + + bytes = lctx->category_count * sizeof(ISC_LIST(isc_logchannellist_t)); + + lists = isc_mem_get(lctx->mctx, bytes); + + if (lists == NULL) + return (ISC_R_NOMEMORY); + + memset(lists, 0, bytes); + + if (lcfg->channellist_count != 0) { + bytes = lcfg->channellist_count * + sizeof(ISC_LIST(isc_logchannellist_t)); + memcpy(lists, lcfg->channellists, bytes); + isc_mem_put(lctx->mctx, lcfg->channellists, bytes); + } + + lcfg->channellists = lists; + lcfg->channellist_count = lctx->category_count; + + return (ISC_R_SUCCESS); +} + +static isc_result_t +greatest_version(isc_logchannel_t *channel, int *greatestp) { + /* XXXDCL HIGHLY NT */ + char *basename, *digit_end; + const char *dirname; + int version, greatest = -1; + unsigned int basenamelen; + isc_dir_t dir; + isc_result_t result; + char sep = '/'; +#ifdef _WIN32 + char *basename2; +#endif + + REQUIRE(channel->type == ISC_LOG_TOFILE); + + /* + * It is safe to DE_CONST the file.name because it was copied + * with isc_mem_strdup in isc_log_createchannel. + */ + basename = strrchr(FILE_NAME(channel), sep); +#ifdef _WIN32 + basename2 = strrchr(FILE_NAME(channel), '\\'); + if ((basename != NULL && basename2 != NULL && basename2 > basename) || + (basename == NULL && basename2 != NULL)) { + basename = basename2; + sep = '\\'; + } +#endif + if (basename != NULL) { + *basename++ = '\0'; + dirname = FILE_NAME(channel); + } else { + DE_CONST(FILE_NAME(channel), basename); + dirname = "."; + } + basenamelen = strlen(basename); + + isc_dir_init(&dir); + result = isc_dir_open(&dir, dirname); + + /* + * Replace the file separator if it was taken out. + */ + if (basename != FILE_NAME(channel)) + *(basename - 1) = sep; + + /* + * Return if the directory open failed. + */ + if (result != ISC_R_SUCCESS) + return (result); + + while (isc_dir_read(&dir) == ISC_R_SUCCESS) { + if (dir.entry.length > basenamelen && + strncmp(dir.entry.name, basename, basenamelen) == 0 && + dir.entry.name[basenamelen] == '.') { + + version = strtol(&dir.entry.name[basenamelen + 1], + &digit_end, 10); + if (*digit_end == '\0' && version > greatest) + greatest = version; + } + } + isc_dir_close(&dir); + + *greatestp = ++greatest; + + return (ISC_R_SUCCESS); +} + +static isc_result_t +roll_log(isc_logchannel_t *channel) { + int i, n, greatest; + char current[PATH_MAX + 1]; + char new[PATH_MAX + 1]; + const char *path; + isc_result_t result; + + /* + * Do nothing (not even excess version trimming) if ISC_LOG_ROLLNEVER + * is specified. Apparently complete external control over the log + * files is desired. + */ + if (FILE_VERSIONS(channel) == ISC_LOG_ROLLNEVER) + return (ISC_R_SUCCESS); + + path = FILE_NAME(channel); + + /* + * Set greatest_version to the greatest existing version + * (not the maximum requested version). This is 1 based even + * though the file names are 0 based, so an oldest log of log.1 + * is a greatest_version of 2. + */ + result = greatest_version(channel, &greatest); + if (result != ISC_R_SUCCESS) + return (result); + + /* + * Now greatest should be set to the highest version number desired. + * Since the highest number is one less than FILE_VERSIONS(channel) + * when not doing infinite log rolling, greatest will need to be + * decremented when it is equal to -- or greater than -- + * FILE_VERSIONS(channel). When greatest is less than + * FILE_VERSIONS(channel), it is already suitable for use as + * the maximum version number. + */ + + if (FILE_VERSIONS(channel) == ISC_LOG_ROLLINFINITE || + FILE_VERSIONS(channel) > greatest) + ; /* Do nothing. */ + else + /* + * When greatest is >= FILE_VERSIONS(channel), it needs to + * be reduced until it is FILE_VERSIONS(channel) - 1. + * Remove any excess logs on the way to that value. + */ + while (--greatest >= FILE_VERSIONS(channel)) { + n = snprintf(current, sizeof(current), "%s.%d", + path, greatest); + if (n >= (int)sizeof(current) || n < 0) + result = ISC_R_NOSPACE; + else + result = isc_file_remove(current); + if (result != ISC_R_SUCCESS && + result != ISC_R_FILENOTFOUND) + syslog(LOG_ERR, + "unable to remove log file '%s.%d': %s", + path, greatest, + isc_result_totext(result)); + } + + for (i = greatest; i > 0; i--) { + result = ISC_R_SUCCESS; + n = snprintf(current, sizeof(current), "%s.%d", path, i - 1); + if (n >= (int)sizeof(current) || n < 0) + result = ISC_R_NOSPACE; + if (result == ISC_R_SUCCESS) { + n = snprintf(new, sizeof(new), "%s.%d", path, i); + if (n >= (int)sizeof(new) || n < 0) + result = ISC_R_NOSPACE; + } + if (result == ISC_R_SUCCESS) + result = isc_file_rename(current, new); + if (result != ISC_R_SUCCESS && + result != ISC_R_FILENOTFOUND) + syslog(LOG_ERR, + "unable to rename log file '%s.%d' to " + "'%s.%d': %s", path, i - 1, path, i, + isc_result_totext(result)); + } + + if (FILE_VERSIONS(channel) != 0) { + n = snprintf(new, sizeof(new), "%s.0", path); + if (n >= (int)sizeof(new) || n < 0) + result = ISC_R_NOSPACE; + else + result = isc_file_rename(path, new); + if (result != ISC_R_SUCCESS && + result != ISC_R_FILENOTFOUND) + syslog(LOG_ERR, + "unable to rename log file '%s' to '%s.0': %s", + path, path, isc_result_totext(result)); + } else { + result = isc_file_remove(path); + if (result != ISC_R_SUCCESS && + result != ISC_R_FILENOTFOUND) + syslog(LOG_ERR, "unable to remove log file '%s': %s", + path, isc_result_totext(result)); + } + + return (ISC_R_SUCCESS); +} + +static isc_result_t +isc_log_open(isc_logchannel_t *channel) { + struct stat statbuf; + isc_boolean_t regular_file; + isc_boolean_t roll = ISC_FALSE; + isc_result_t result = ISC_R_SUCCESS; + const char *path; + + REQUIRE(channel->type == ISC_LOG_TOFILE); + REQUIRE(FILE_STREAM(channel) == NULL); + + path = FILE_NAME(channel); + + REQUIRE(path != NULL && *path != '\0'); + + /* + * Determine type of file; only regular files will be + * version renamed, and only if the base file exists + * and either has no size limit or has reached its size limit. + */ + if (stat(path, &statbuf) == 0) { + regular_file = S_ISREG(statbuf.st_mode) ? ISC_TRUE : ISC_FALSE; + /* XXXDCL if not regular_file complain? */ + if ((FILE_MAXSIZE(channel) == 0 && + FILE_VERSIONS(channel) != ISC_LOG_ROLLNEVER) || + (FILE_MAXSIZE(channel) > 0 && + statbuf.st_size >= FILE_MAXSIZE(channel))) + roll = regular_file; + } else if (errno == ENOENT) { + regular_file = ISC_TRUE; + POST(regular_file); + } else + result = ISC_R_INVALIDFILE; + + /* + * Version control. + */ + if (result == ISC_R_SUCCESS && roll) { + if (FILE_VERSIONS(channel) == ISC_LOG_ROLLNEVER) + return (ISC_R_MAXSIZE); + result = roll_log(channel); + if (result != ISC_R_SUCCESS) { + if ((channel->flags & ISC_LOG_OPENERR) == 0) { + syslog(LOG_ERR, + "isc_log_open: roll_log '%s' " + "failed: %s", + FILE_NAME(channel), + isc_result_totext(result)); + channel->flags |= ISC_LOG_OPENERR; + } + return (result); + } + } + + result = isc_stdio_open(path, "a", &FILE_STREAM(channel)); + + return (result); +} + +isc_boolean_t +isc_log_wouldlog(isc_log_t *lctx, int level) { + /* + * Try to avoid locking the mutex for messages which can't + * possibly be logged to any channels -- primarily debugging + * messages that the debug level is not high enough to print. + * + * If the level is (mathematically) less than or equal to the + * highest_level, or if there is a dynamic channel and the level is + * less than or equal to the debug level, the main loop must be + * entered to see if the message should really be output. + * + * NOTE: this is UNLOCKED access to the logconfig. However, + * the worst thing that can happen is that a bad decision is made + * about returning without logging, and that's not a big concern, + * because that's a risk anyway if the logconfig is being + * dynamically changed. + */ + + if (lctx == NULL || lctx->logconfig == NULL) + return (ISC_FALSE); + + return (ISC_TF(level <= lctx->logconfig->highest_level || + (lctx->logconfig->dynamic && + level <= lctx->debug_level))); +} + +static void +isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category, + isc_logmodule_t *module, int level, isc_boolean_t write_once, + isc_msgcat_t *msgcat, int msgset, int msg, + const char *format, va_list args) +{ + int syslog_level; + char time_string[64]; + char level_string[24]; + size_t octets; + const char *iformat; + struct stat statbuf; + isc_boolean_t matched = ISC_FALSE; + isc_boolean_t printtime, printtag; + isc_boolean_t printcategory, printmodule, printlevel; + isc_logconfig_t *lcfg; + isc_logchannel_t *channel; + isc_logchannellist_t *category_channels; + isc_result_t result; + + REQUIRE(lctx == NULL || VALID_CONTEXT(lctx)); + REQUIRE(category != NULL); + REQUIRE(module != NULL); + REQUIRE(level != ISC_LOG_DYNAMIC); + REQUIRE(format != NULL); + + /* + * Programs can use libraries that use this logging code without + * wanting to do any logging, thus the log context is allowed to + * be non-existent. + */ + if (lctx == NULL) + return; + + REQUIRE(category->id < lctx->category_count); + REQUIRE(module->id < lctx->module_count); + + if (! isc_log_wouldlog(lctx, level)) + return; + + if (msgcat != NULL) + iformat = isc_msgcat_get(msgcat, msgset, msg, format); + else + iformat = format; + + time_string[0] = '\0'; + level_string[0] = '\0'; + + LOCK(&lctx->lock); + + lctx->buffer[0] = '\0'; + + lcfg = lctx->logconfig; + + category_channels = ISC_LIST_HEAD(lcfg->channellists[category->id]); + + /* + * XXXDCL add duplicate filtering? (To not write multiple times to + * the same source via various channels). + */ + do { + /* + * If the channel list end was reached and a match was made, + * everything is finished. + */ + if (category_channels == NULL && matched) + break; + + if (category_channels == NULL && ! matched && + category_channels != ISC_LIST_HEAD(lcfg->channellists[0])) + /* + * No category/module pair was explicitly configured. + * Try the category named "default". + */ + category_channels = + ISC_LIST_HEAD(lcfg->channellists[0]); + + if (category_channels == NULL && ! matched) + /* + * No matching module was explicitly configured + * for the category named "default". Use the internal + * default channel. + */ + category_channels = &default_channel; + + if (category_channels->module != NULL && + category_channels->module != module) { + category_channels = ISC_LIST_NEXT(category_channels, + link); + continue; + } + + matched = ISC_TRUE; + + channel = category_channels->channel; + category_channels = ISC_LIST_NEXT(category_channels, link); + + if (((channel->flags & ISC_LOG_DEBUGONLY) != 0) && + lctx->debug_level == 0) + continue; + + if (channel->level == ISC_LOG_DYNAMIC) { + if (lctx->debug_level < level) + continue; + } else if (channel->level < level) + continue; + + if ((channel->flags & ISC_LOG_PRINTTIME) != 0 && + time_string[0] == '\0') { + isc_time_t isctime; + + TIME_NOW(&isctime); + isc_time_formattimestamp(&isctime, time_string, + sizeof(time_string)); + } + + if ((channel->flags & ISC_LOG_PRINTLEVEL) != 0 && + level_string[0] == '\0') { + if (level < ISC_LOG_CRITICAL) + snprintf(level_string, sizeof(level_string), + "%s %d: ", + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_LOG, + ISC_MSG_LEVEL, + "level"), + level); + else if (level > ISC_LOG_DYNAMIC) + snprintf(level_string, sizeof(level_string), + "%s %d: ", log_level_strings[0], + level); + else + snprintf(level_string, sizeof(level_string), + "%s: ", log_level_strings[-level]); + } + + /* + * Only format the message once. + */ + if (lctx->buffer[0] == '\0') { + (void)vsnprintf(lctx->buffer, sizeof(lctx->buffer), + iformat, args); + + /* + * Check for duplicates. + */ + if (write_once) { + isc_logmessage_t *message, *new; + isc_time_t oldest; + isc_interval_t interval; + + isc_interval_set(&interval, + lcfg->duplicate_interval, 0); + + /* + * 'oldest' is the age of the oldest messages + * which fall within the duplicate_interval + * range. + */ + TIME_NOW(&oldest); + if (isc_time_subtract(&oldest, &interval, &oldest) + != ISC_R_SUCCESS) + /* + * Can't effectively do the checking + * without having a valid time. + */ + message = NULL; + else + message =ISC_LIST_HEAD(lctx->messages); + + while (message != NULL) { + if (isc_time_compare(&message->time, + &oldest) < 0) { + /* + * This message is older + * than the duplicate_interval, + * so it should be dropped from + * the history. + * + * Setting the interval to be + * to be longer will obviously + * not cause the expired + * message to spring back into + * existence. + */ + new = ISC_LIST_NEXT(message, + link); + + ISC_LIST_UNLINK(lctx->messages, + message, link); + + isc_mem_put(lctx->mctx, + message, + sizeof(*message) + 1 + + strlen(message->text)); + + message = new; + continue; + } + + /* + * This message is in the duplicate + * filtering interval ... + */ + if (strcmp(lctx->buffer, message->text) + == 0) { + /* + * ... and it is a duplicate. + * Unlock the mutex and + * get the hell out of Dodge. + */ + UNLOCK(&lctx->lock); + return; + } + + message = ISC_LIST_NEXT(message, link); + } + + /* + * It wasn't in the duplicate interval, + * so add it to the message list. + */ + octets = strlen(lctx->buffer) + 1; + new = isc_mem_get(lctx->mctx, + sizeof(isc_logmessage_t) + + octets); + if (new != NULL) { + /* + * Put the text immediately after + * the struct. The strcpy is safe. + */ + new->text = (char *)(new + 1); + strlcpy(new->text, lctx->buffer, octets); + + TIME_NOW(&new->time); + + ISC_LIST_APPEND(lctx->messages, + new, link); + } + } + } + + printtime = ISC_TF((channel->flags & ISC_LOG_PRINTTIME) + != 0); + printtag = ISC_TF((channel->flags & ISC_LOG_PRINTTAG) + != 0 && lcfg->tag != NULL); + printcategory = ISC_TF((channel->flags & ISC_LOG_PRINTCATEGORY) + != 0); + printmodule = ISC_TF((channel->flags & ISC_LOG_PRINTMODULE) + != 0); + printlevel = ISC_TF((channel->flags & ISC_LOG_PRINTLEVEL) + != 0); + + switch (channel->type) { + case ISC_LOG_TOFILE: + if (FILE_MAXREACHED(channel)) { + /* + * If the file can be rolled, OR + * If the file no longer exists, OR + * If the file is less than the maximum size, + * (such as if it had been renamed and + * a new one touched, or it was truncated + * in place) + * ... then close it to trigger reopening. + */ + if (FILE_VERSIONS(channel) != + ISC_LOG_ROLLNEVER || + (stat(FILE_NAME(channel), &statbuf) != 0 && + errno == ENOENT) || + statbuf.st_size < FILE_MAXSIZE(channel)) { + (void)fclose(FILE_STREAM(channel)); + FILE_STREAM(channel) = NULL; + FILE_MAXREACHED(channel) = ISC_FALSE; + } else + /* + * Eh, skip it. + */ + break; + } + + if (FILE_STREAM(channel) == NULL) { + result = isc_log_open(channel); + if (result != ISC_R_SUCCESS && + result != ISC_R_MAXSIZE && + (channel->flags & ISC_LOG_OPENERR) == 0) { + syslog(LOG_ERR, + "isc_log_open '%s' failed: %s", + FILE_NAME(channel), + isc_result_totext(result)); + channel->flags |= ISC_LOG_OPENERR; + } + if (result != ISC_R_SUCCESS) + break; + channel->flags &= ~ISC_LOG_OPENERR; + } + /* FALLTHROUGH */ + + case ISC_LOG_TOFILEDESC: + fprintf(FILE_STREAM(channel), "%s%s%s%s%s%s%s%s%s%s\n", + printtime ? time_string : "", + printtime ? " " : "", + printtag ? lcfg->tag : "", + printtag ? ": " : "", + printcategory ? category->name : "", + printcategory ? ": " : "", + printmodule ? (module != NULL ? module->name + : "no_module") + : "", + printmodule ? ": " : "", + printlevel ? level_string : "", + lctx->buffer); + + fflush(FILE_STREAM(channel)); + + /* + * If the file now exceeds its maximum size + * threshold, note it so that it will not be logged + * to any more. + */ + if (FILE_MAXSIZE(channel) > 0) { + INSIST(channel->type == ISC_LOG_TOFILE); + + /* XXXDCL NT fstat/fileno */ + /* XXXDCL complain if fstat fails? */ + if (fstat(fileno(FILE_STREAM(channel)), + &statbuf) >= 0 && + statbuf.st_size > FILE_MAXSIZE(channel)) + FILE_MAXREACHED(channel) = ISC_TRUE; + } + + break; + + case ISC_LOG_TOSYSLOG: + if (level > 0) + syslog_level = LOG_DEBUG; + else if (level < ISC_LOG_CRITICAL) + syslog_level = LOG_CRIT; + else + syslog_level = syslog_map[-level]; + + (void)syslog(FACILITY(channel) | syslog_level, + "%s%s%s%s%s%s%s%s%s%s", + printtime ? time_string : "", + printtime ? " " : "", + printtag ? lcfg->tag : "", + printtag ? ": " : "", + printcategory ? category->name : "", + printcategory ? ": " : "", + printmodule ? (module != NULL ? module->name + : "no_module") + : "", + printmodule ? ": " : "", + printlevel ? level_string : "", + lctx->buffer); + break; + + case ISC_LOG_TONULL: + break; + + } + + } while (1); + + UNLOCK(&lctx->lock); +} diff --git a/contrib/ntp/lib/isc/md5.c b/contrib/ntp/lib/isc/md5.c new file mode 100644 index 0000000..7c6419b --- /dev/null +++ b/contrib/ntp/lib/isc/md5.c @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: md5.c,v 1.16 2009/02/06 23:47:42 tbox Exp $ */ + +/*! \file + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + */ + +#include "config.h" + +#include <isc/assertions.h> +#include <isc/md5.h> +#include <isc/platform.h> +#include <isc/string.h> +#include <isc/types.h> +#include <isc/util.h> + +#ifdef ISC_PLATFORM_OPENSSLHASH + +void +isc_md5_init(isc_md5_t *ctx) { + EVP_DigestInit(ctx, EVP_md5()); +} + +void +isc_md5_invalidate(isc_md5_t *ctx) { + EVP_MD_CTX_cleanup(ctx); +} + +void +isc_md5_update(isc_md5_t *ctx, const unsigned char *buf, unsigned int len) { + EVP_DigestUpdate(ctx, (const void *) buf, (size_t) len); +} + +void +isc_md5_final(isc_md5_t *ctx, unsigned char *digest) { + EVP_DigestFinal(ctx, digest, NULL); +} + +#else + +static void +byteSwap(isc_uint32_t *buf, unsigned words) +{ + unsigned char *p = (unsigned char *)buf; + + do { + *buf++ = (isc_uint32_t)((unsigned)p[3] << 8 | p[2]) << 16 | + ((unsigned)p[1] << 8 | p[0]); + p += 4; + } while (--words); +} + +/*! + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void +isc_md5_init(isc_md5_t *ctx) { + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bytes[0] = 0; + ctx->bytes[1] = 0; +} + +void +isc_md5_invalidate(isc_md5_t *ctx) { + memset(ctx, 0, sizeof(isc_md5_t)); +} + +/*@{*/ +/*! The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) +/*@}*/ + +/*! This is the central step in the MD5 algorithm. */ +#define MD5STEP(f,w,x,y,z,in,s) \ + (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x) + +/*! + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void +transform(isc_uint32_t buf[4], isc_uint32_t const in[16]) { + register isc_uint32_t a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +/*! + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +isc_md5_update(isc_md5_t *ctx, const unsigned char *buf, unsigned int len) { + isc_uint32_t t; + + /* Update byte count */ + + t = ctx->bytes[0]; + if ((ctx->bytes[0] = t + len) < t) + ctx->bytes[1]++; /* Carry from low to high */ + + t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ + if (t > len) { + memcpy((unsigned char *)ctx->in + 64 - t, buf, len); + return; + } + /* First chunk is an odd size */ + memcpy((unsigned char *)ctx->in + 64 - t, buf, t); + byteSwap(ctx->in, 16); + transform(ctx->buf, ctx->in); + buf += t; + len -= t; + + /* Process data in 64-byte chunks */ + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteSwap(ctx->in, 16); + transform(ctx->buf, ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); +} + +/*! + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void +isc_md5_final(isc_md5_t *ctx, unsigned char *digest) { + int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ + unsigned char *p = (unsigned char *)ctx->in + count; + + /* Set the first char of padding to 0x80. There is always room. */ + *p++ = 0x80; + + /* Bytes of padding needed to make 56 bytes (-8..55) */ + count = 56 - 1 - count; + + if (count < 0) { /* Padding forces an extra block */ + memset(p, 0, count + 8); + byteSwap(ctx->in, 16); + transform(ctx->buf, ctx->in); + p = (unsigned char *)ctx->in; + count = 56; + } + memset(p, 0, count); + byteSwap(ctx->in, 14); + + /* Append length in bits and transform */ + ctx->in[14] = ctx->bytes[0] << 3; + ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; + transform(ctx->buf, ctx->in); + + byteSwap(ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(isc_md5_t)); /* In case it's sensitive */ +} +#endif diff --git a/contrib/ntp/lib/isc/mem.c b/contrib/ntp/lib/isc/mem.c new file mode 100644 index 0000000..5b4b16c --- /dev/null +++ b/contrib/ntp/lib/isc/mem.c @@ -0,0 +1,2477 @@ +/* + * Copyright (C) 2004-2010, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1997-2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/*! \file */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> + +#include <limits.h> + +#include <isc/magic.h> +#include <isc/mem.h> +#include <isc/msgs.h> +#include <isc/once.h> +#include <isc/ondestroy.h> +#include <isc/string.h> +#include <isc/mutex.h> +#include <isc/print.h> +#include <isc/util.h> +#include <isc/xml.h> + +#define MCTXLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) LOCK(l) +#define MCTXUNLOCK(m, l) if (((m)->flags & ISC_MEMFLAG_NOLOCK) == 0) UNLOCK(l) + +#ifndef ISC_MEM_DEBUGGING +#define ISC_MEM_DEBUGGING 0 +#endif +LIBISC_EXTERNAL_DATA unsigned int isc_mem_debugging = ISC_MEM_DEBUGGING; + +/* + * Constants. + */ + +#define DEF_MAX_SIZE 1100 +#define DEF_MEM_TARGET 4096 +#define ALIGNMENT_SIZE 8U /*%< must be a power of 2 */ +#define NUM_BASIC_BLOCKS 64 /*%< must be > 1 */ +#define TABLE_INCREMENT 1024 +#define DEBUGLIST_COUNT 1024 + +/* + * Types. + */ +typedef struct isc__mem isc__mem_t; +typedef struct isc__mempool isc__mempool_t; + +#if ISC_MEM_TRACKLINES +typedef struct debuglink debuglink_t; +struct debuglink { + ISC_LINK(debuglink_t) link; + const void *ptr[DEBUGLIST_COUNT]; + unsigned int size[DEBUGLIST_COUNT]; + const char *file[DEBUGLIST_COUNT]; + unsigned int line[DEBUGLIST_COUNT]; + unsigned int count; +}; + +#define FLARG_PASS , file, line +#define FLARG , const char *file, unsigned int line +#else +#define FLARG_PASS +#define FLARG +#endif + +typedef struct element element; +struct element { + element * next; +}; + +typedef struct { + /*! + * This structure must be ALIGNMENT_SIZE bytes. + */ + union { + size_t size; + isc__mem_t *ctx; + char bytes[ALIGNMENT_SIZE]; + } u; +} size_info; + +struct stats { + unsigned long gets; + unsigned long totalgets; + unsigned long blocks; + unsigned long freefrags; +}; + +#define MEM_MAGIC ISC_MAGIC('M', 'e', 'm', 'C') +#define VALID_CONTEXT(c) ISC_MAGIC_VALID(c, MEM_MAGIC) + +#if ISC_MEM_TRACKLINES +typedef ISC_LIST(debuglink_t) debuglist_t; +#endif + +/* List of all active memory contexts. */ + +static ISC_LIST(isc__mem_t) contexts; +static isc_once_t once = ISC_ONCE_INIT; +static isc_mutex_t lock; + +/*% + * Total size of lost memory due to a bug of external library. + * Locked by the global lock. + */ +static isc_uint64_t totallost; + +struct isc__mem { + isc_mem_t common; + isc_ondestroy_t ondestroy; + unsigned int flags; + isc_mutex_t lock; + isc_memalloc_t memalloc; + isc_memfree_t memfree; + void * arg; + size_t max_size; + isc_boolean_t checkfree; + struct stats * stats; + unsigned int references; + char name[16]; + void * tag; + size_t quota; + size_t total; + size_t inuse; + size_t maxinuse; + size_t hi_water; + size_t lo_water; + isc_boolean_t hi_called; + isc_boolean_t is_overmem; + isc_mem_water_t water; + void * water_arg; + ISC_LIST(isc__mempool_t) pools; + unsigned int poolcnt; + + /* ISC_MEMFLAG_INTERNAL */ + size_t mem_target; + element ** freelists; + element * basic_blocks; + unsigned char ** basic_table; + unsigned int basic_table_count; + unsigned int basic_table_size; + unsigned char * lowest; + unsigned char * highest; + +#if ISC_MEM_TRACKLINES + debuglist_t * debuglist; + unsigned int debuglistcnt; +#endif + + unsigned int memalloc_failures; + ISC_LINK(isc__mem_t) link; +}; + +#define MEMPOOL_MAGIC ISC_MAGIC('M', 'E', 'M', 'p') +#define VALID_MEMPOOL(c) ISC_MAGIC_VALID(c, MEMPOOL_MAGIC) + +struct isc__mempool { + /* always unlocked */ + isc_mempool_t common; /*%< common header of mempool's */ + isc_mutex_t *lock; /*%< optional lock */ + isc__mem_t *mctx; /*%< our memory context */ + /*%< locked via the memory context's lock */ + ISC_LINK(isc__mempool_t) link; /*%< next pool in this mem context */ + /*%< optionally locked from here down */ + element *items; /*%< low water item list */ + size_t size; /*%< size of each item on this pool */ + unsigned int maxalloc; /*%< max number of items allowed */ + unsigned int allocated; /*%< # of items currently given out */ + unsigned int freecount; /*%< # of items on reserved list */ + unsigned int freemax; /*%< # of items allowed on free list */ + unsigned int fillcount; /*%< # of items to fetch on each fill */ + /*%< Stats only. */ + unsigned int gets; /*%< # of requests to this pool */ + /*%< Debugging only. */ +#if ISC_MEMPOOL_NAMES + char name[16]; /*%< printed name in stats reports */ +#endif +}; + +/* + * Private Inline-able. + */ + +#if ! ISC_MEM_TRACKLINES +#define ADD_TRACE(a, b, c, d, e) +#define DELETE_TRACE(a, b, c, d, e) +#else +#define ADD_TRACE(a, b, c, d, e) \ + do { \ + if ((isc_mem_debugging & (ISC_MEM_DEBUGTRACE | \ + ISC_MEM_DEBUGRECORD)) != 0 && \ + b != NULL) \ + add_trace_entry(a, b, c, d, e); \ + } while (0) +#define DELETE_TRACE(a, b, c, d, e) delete_trace_entry(a, b, c, d, e) + +static void +print_active(isc__mem_t *ctx, FILE *out); + +/*% + * The following can be either static or public, depending on build environment. + */ + +#ifdef BIND9 +#define ISC_MEMFUNC_SCOPE +#else +#define ISC_MEMFUNC_SCOPE static +#endif + +ISC_MEMFUNC_SCOPE isc_result_t +isc__mem_createx(size_t init_max_size, size_t target_size, + isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, + isc_mem_t **ctxp); +ISC_MEMFUNC_SCOPE isc_result_t +isc__mem_createx2(size_t init_max_size, size_t target_size, + isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, + isc_mem_t **ctxp, unsigned int flags); +ISC_MEMFUNC_SCOPE isc_result_t +isc__mem_create(size_t init_max_size, size_t target_size, isc_mem_t **ctxp); +ISC_MEMFUNC_SCOPE isc_result_t +isc__mem_create2(size_t init_max_size, size_t target_size, + isc_mem_t **ctxp, unsigned int flags); +ISC_MEMFUNC_SCOPE void +isc__mem_attach(isc_mem_t *source, isc_mem_t **targetp); +ISC_MEMFUNC_SCOPE void +isc__mem_detach(isc_mem_t **ctxp); +ISC_MEMFUNC_SCOPE void +isc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG); +ISC_MEMFUNC_SCOPE void +isc__mem_destroy(isc_mem_t **ctxp); +ISC_MEMFUNC_SCOPE isc_result_t +isc__mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event); +ISC_MEMFUNC_SCOPE void * +isc___mem_get(isc_mem_t *ctx, size_t size FLARG); +ISC_MEMFUNC_SCOPE void +isc___mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG); +ISC_MEMFUNC_SCOPE void +isc__mem_stats(isc_mem_t *ctx, FILE *out); +ISC_MEMFUNC_SCOPE void * +isc___mem_allocate(isc_mem_t *ctx, size_t size FLARG); +ISC_MEMFUNC_SCOPE void * +isc___mem_reallocate(isc_mem_t *ctx, void *ptr, size_t size FLARG); +ISC_MEMFUNC_SCOPE void +isc___mem_free(isc_mem_t *ctx, void *ptr FLARG); +ISC_MEMFUNC_SCOPE char * +isc___mem_strdup(isc_mem_t *mctx, const char *s FLARG); +ISC_MEMFUNC_SCOPE void +isc__mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag); +ISC_MEMFUNC_SCOPE void +isc__mem_setquota(isc_mem_t *ctx, size_t quota); +ISC_MEMFUNC_SCOPE size_t +isc__mem_getquota(isc_mem_t *ctx); +ISC_MEMFUNC_SCOPE size_t +isc__mem_inuse(isc_mem_t *ctx); +ISC_MEMFUNC_SCOPE isc_boolean_t +isc__mem_isovermem(isc_mem_t *ctx); +ISC_MEMFUNC_SCOPE void +isc__mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg, + size_t hiwater, size_t lowater); +ISC_MEMFUNC_SCOPE void +isc__mem_waterack(isc_mem_t *ctx0, int flag); +ISC_MEMFUNC_SCOPE void +isc__mem_setname(isc_mem_t *ctx, const char *name, void *tag); +ISC_MEMFUNC_SCOPE const char * +isc__mem_getname(isc_mem_t *ctx); +ISC_MEMFUNC_SCOPE void * +isc__mem_gettag(isc_mem_t *ctx); +ISC_MEMFUNC_SCOPE isc_result_t +isc__mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp); +ISC_MEMFUNC_SCOPE void +isc__mempool_setname(isc_mempool_t *mpctx, const char *name); +ISC_MEMFUNC_SCOPE void +isc__mempool_destroy(isc_mempool_t **mpctxp); +ISC_MEMFUNC_SCOPE void +isc__mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock); +ISC_MEMFUNC_SCOPE void * +isc___mempool_get(isc_mempool_t *mpctx FLARG); +ISC_MEMFUNC_SCOPE void +isc___mempool_put(isc_mempool_t *mpctx, void *mem FLARG); +ISC_MEMFUNC_SCOPE void +isc__mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit); +ISC_MEMFUNC_SCOPE unsigned int +isc__mempool_getfreemax(isc_mempool_t *mpctx); +ISC_MEMFUNC_SCOPE unsigned int +isc__mempool_getfreecount(isc_mempool_t *mpctx); +ISC_MEMFUNC_SCOPE void +isc__mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit); +ISC_MEMFUNC_SCOPE unsigned int +isc__mempool_getmaxalloc(isc_mempool_t *mpctx); +ISC_MEMFUNC_SCOPE unsigned int +isc__mempool_getallocated(isc_mempool_t *mpctx); +ISC_MEMFUNC_SCOPE void +isc__mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit); +ISC_MEMFUNC_SCOPE unsigned int +isc__mempool_getfillcount(isc_mempool_t *mpctx); +#ifdef BIND9 +ISC_MEMFUNC_SCOPE void +isc__mem_printactive(isc_mem_t *ctx0, FILE *file); +ISC_MEMFUNC_SCOPE void +isc__mem_printallactive(FILE *file); +ISC_MEMFUNC_SCOPE void +isc__mem_checkdestroyed(FILE *file); +ISC_MEMFUNC_SCOPE unsigned int +isc__mem_references(isc_mem_t *ctx0); +#endif + +static struct isc__memmethods { + isc_memmethods_t methods; + + /*% + * The following are defined just for avoiding unused static functions. + */ +#ifndef BIND9 + void *createx, *create, *create2, *ondestroy, *stats, + *setquota, *getquota, *setname, *getname, *gettag; +#endif +} memmethods = { + { + isc__mem_attach, + isc__mem_detach, + isc__mem_destroy, + isc___mem_get, + isc___mem_put, + isc___mem_putanddetach, + isc___mem_allocate, + isc___mem_reallocate, + isc___mem_strdup, + isc___mem_free, + isc__mem_setdestroycheck, + isc__mem_setwater, + isc__mem_waterack, + isc__mem_inuse, + isc__mem_isovermem, + isc__mempool_create + } +#ifndef BIND9 + , + (void *)isc__mem_createx, (void *)isc__mem_create, + (void *)isc__mem_create2, (void *)isc__mem_ondestroy, + (void *)isc__mem_stats, (void *)isc__mem_setquota, + (void *)isc__mem_getquota, (void *)isc__mem_setname, + (void *)isc__mem_getname, (void *)isc__mem_gettag +#endif +}; + +static struct isc__mempoolmethods { + isc_mempoolmethods_t methods; + + /*% + * The following are defined just for avoiding unused static functions. + */ +#ifndef BIND9 + void *getfreemax, *getfreecount, *getmaxalloc, *getfillcount; +#endif +} mempoolmethods = { + { + isc__mempool_destroy, + isc___mempool_get, + isc___mempool_put, + isc__mempool_getallocated, + isc__mempool_setmaxalloc, + isc__mempool_setfreemax, + isc__mempool_setname, + isc__mempool_associatelock, + isc__mempool_setfillcount + } +#ifndef BIND9 + , + (void *)isc__mempool_getfreemax, (void *)isc__mempool_getfreecount, + (void *)isc__mempool_getmaxalloc, (void *)isc__mempool_getfillcount +#endif +}; + +/*! + * mctx must be locked. + */ +static inline void +add_trace_entry(isc__mem_t *mctx, const void *ptr, unsigned int size + FLARG) +{ + debuglink_t *dl; + unsigned int i; + unsigned int mysize = size; + + if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0) + fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, + ISC_MSG_ADDTRACE, + "add %p size %u " + "file %s line %u mctx %p\n"), + ptr, size, file, line, mctx); + + if (mctx->debuglist == NULL) + return; + + if (mysize > mctx->max_size) + mysize = mctx->max_size; + + dl = ISC_LIST_HEAD(mctx->debuglist[mysize]); + while (dl != NULL) { + if (dl->count == DEBUGLIST_COUNT) + goto next; + for (i = 0; i < DEBUGLIST_COUNT; i++) { + if (dl->ptr[i] == NULL) { + dl->ptr[i] = ptr; + dl->size[i] = size; + dl->file[i] = file; + dl->line[i] = line; + dl->count++; + return; + } + } + next: + dl = ISC_LIST_NEXT(dl, link); + } + + dl = malloc(sizeof(debuglink_t)); + INSIST(dl != NULL); + + ISC_LINK_INIT(dl, link); + for (i = 1; i < DEBUGLIST_COUNT; i++) { + dl->ptr[i] = NULL; + dl->size[i] = 0; + dl->file[i] = NULL; + dl->line[i] = 0; + } + + dl->ptr[0] = ptr; + dl->size[0] = size; + dl->file[0] = file; + dl->line[0] = line; + dl->count = 1; + + ISC_LIST_PREPEND(mctx->debuglist[mysize], dl, link); + mctx->debuglistcnt++; +} + +static inline void +delete_trace_entry(isc__mem_t *mctx, const void *ptr, unsigned int size, + const char *file, unsigned int line) +{ + debuglink_t *dl; + unsigned int i; + + if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0) + fprintf(stderr, isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, + ISC_MSG_DELTRACE, + "del %p size %u " + "file %s line %u mctx %p\n"), + ptr, size, file, line, mctx); + + if (mctx->debuglist == NULL) + return; + + if (size > mctx->max_size) + size = mctx->max_size; + + dl = ISC_LIST_HEAD(mctx->debuglist[size]); + while (dl != NULL) { + for (i = 0; i < DEBUGLIST_COUNT; i++) { + if (dl->ptr[i] == ptr) { + dl->ptr[i] = NULL; + dl->size[i] = 0; + dl->file[i] = NULL; + dl->line[i] = 0; + + INSIST(dl->count > 0); + dl->count--; + if (dl->count == 0) { + ISC_LIST_UNLINK(mctx->debuglist[size], + dl, link); + free(dl); + } + return; + } + } + dl = ISC_LIST_NEXT(dl, link); + } + + /* + * If we get here, we didn't find the item on the list. We're + * screwed. + */ + INSIST(dl != NULL); +} +#endif /* ISC_MEM_TRACKLINES */ + +static inline size_t +rmsize(size_t size) { + /* + * round down to ALIGNMENT_SIZE + */ + return (size & (~(ALIGNMENT_SIZE - 1))); +} + +static inline size_t +quantize(size_t size) { + /*! + * Round up the result in order to get a size big + * enough to satisfy the request and be aligned on ALIGNMENT_SIZE + * byte boundaries. + */ + + if (size == 0U) + return (ALIGNMENT_SIZE); + return ((size + ALIGNMENT_SIZE - 1) & (~(ALIGNMENT_SIZE - 1))); +} + +static inline isc_boolean_t +more_basic_blocks(isc__mem_t *ctx) { + void *new; + unsigned char *curr, *next; + unsigned char *first, *last; + unsigned char **table; + unsigned int table_size; + size_t increment; + int i; + + /* Require: we hold the context lock. */ + + /* + * Did we hit the quota for this context? + */ + increment = NUM_BASIC_BLOCKS * ctx->mem_target; + if (ctx->quota != 0U && ctx->total + increment > ctx->quota) + return (ISC_FALSE); + + INSIST(ctx->basic_table_count <= ctx->basic_table_size); + if (ctx->basic_table_count == ctx->basic_table_size) { + table_size = ctx->basic_table_size + TABLE_INCREMENT; + table = (ctx->memalloc)(ctx->arg, + table_size * sizeof(unsigned char *)); + if (table == NULL) { + ctx->memalloc_failures++; + return (ISC_FALSE); + } + if (ctx->basic_table_size != 0) { + memcpy(table, ctx->basic_table, + ctx->basic_table_size * + sizeof(unsigned char *)); + (ctx->memfree)(ctx->arg, ctx->basic_table); + } + ctx->basic_table = table; + ctx->basic_table_size = table_size; + } + + new = (ctx->memalloc)(ctx->arg, NUM_BASIC_BLOCKS * ctx->mem_target); + if (new == NULL) { + ctx->memalloc_failures++; + return (ISC_FALSE); + } + ctx->total += increment; + ctx->basic_table[ctx->basic_table_count] = new; + ctx->basic_table_count++; + + curr = new; + next = curr + ctx->mem_target; + for (i = 0; i < (NUM_BASIC_BLOCKS - 1); i++) { + ((element *)curr)->next = (element *)next; + curr = next; + next += ctx->mem_target; + } + /* + * curr is now pointing at the last block in the + * array. + */ + ((element *)curr)->next = NULL; + first = new; + last = first + NUM_BASIC_BLOCKS * ctx->mem_target - 1; + if (first < ctx->lowest || ctx->lowest == NULL) + ctx->lowest = first; + if (last > ctx->highest) + ctx->highest = last; + ctx->basic_blocks = new; + + return (ISC_TRUE); +} + +static inline isc_boolean_t +more_frags(isc__mem_t *ctx, size_t new_size) { + int i, frags; + size_t total_size; + void *new; + unsigned char *curr, *next; + + /*! + * Try to get more fragments by chopping up a basic block. + */ + + if (ctx->basic_blocks == NULL) { + if (!more_basic_blocks(ctx)) { + /* + * We can't get more memory from the OS, or we've + * hit the quota for this context. + */ + /* + * XXXRTH "At quota" notification here. + */ + return (ISC_FALSE); + } + } + + total_size = ctx->mem_target; + new = ctx->basic_blocks; + ctx->basic_blocks = ctx->basic_blocks->next; + frags = total_size / new_size; + ctx->stats[new_size].blocks++; + ctx->stats[new_size].freefrags += frags; + /* + * Set up a linked-list of blocks of size + * "new_size". + */ + curr = new; + next = curr + new_size; + total_size -= new_size; + for (i = 0; i < (frags - 1); i++) { + ((element *)curr)->next = (element *)next; + curr = next; + next += new_size; + total_size -= new_size; + } + /* + * Add the remaining fragment of the basic block to a free list. + */ + total_size = rmsize(total_size); + if (total_size > 0U) { + ((element *)next)->next = ctx->freelists[total_size]; + ctx->freelists[total_size] = (element *)next; + ctx->stats[total_size].freefrags++; + } + /* + * curr is now pointing at the last block in the + * array. + */ + ((element *)curr)->next = NULL; + ctx->freelists[new_size] = new; + + return (ISC_TRUE); +} + +static inline void * +mem_getunlocked(isc__mem_t *ctx, size_t size) { + size_t new_size = quantize(size); + void *ret; + + if (size >= ctx->max_size || new_size >= ctx->max_size) { + /* + * memget() was called on something beyond our upper limit. + */ + if (ctx->quota != 0U && ctx->total + size > ctx->quota) { + ret = NULL; + goto done; + } + ret = (ctx->memalloc)(ctx->arg, size); + if (ret == NULL) { + ctx->memalloc_failures++; + goto done; + } + ctx->total += size; + ctx->inuse += size; + ctx->stats[ctx->max_size].gets++; + ctx->stats[ctx->max_size].totalgets++; + /* + * If we don't set new_size to size, then the + * ISC_MEM_FILL code might write over bytes we + * don't own. + */ + new_size = size; + goto done; + } + + /* + * If there are no blocks in the free list for this size, get a chunk + * of memory and then break it up into "new_size"-sized blocks, adding + * them to the free list. + */ + if (ctx->freelists[new_size] == NULL && !more_frags(ctx, new_size)) + return (NULL); + + /* + * The free list uses the "rounded-up" size "new_size". + */ + ret = ctx->freelists[new_size]; + ctx->freelists[new_size] = ctx->freelists[new_size]->next; + + /* + * The stats[] uses the _actual_ "size" requested by the + * caller, with the caveat (in the code above) that "size" >= the + * max. size (max_size) ends up getting recorded as a call to + * max_size. + */ + ctx->stats[size].gets++; + ctx->stats[size].totalgets++; + ctx->stats[new_size].freefrags--; + ctx->inuse += new_size; + + done: + +#if ISC_MEM_FILL + if (ret != NULL) + memset(ret, 0xbe, new_size); /* Mnemonic for "beef". */ +#endif + + return (ret); +} + +#if ISC_MEM_FILL && ISC_MEM_CHECKOVERRUN +static inline void +check_overrun(void *mem, size_t size, size_t new_size) { + unsigned char *cp; + + cp = (unsigned char *)mem; + cp += size; + while (size < new_size) { + INSIST(*cp == 0xbe); + cp++; + size++; + } +} +#endif + +static inline void +mem_putunlocked(isc__mem_t *ctx, void *mem, size_t size) { + size_t new_size = quantize(size); + + if (size == ctx->max_size || new_size >= ctx->max_size) { + /* + * memput() called on something beyond our upper limit. + */ +#if ISC_MEM_FILL + memset(mem, 0xde, size); /* Mnemonic for "dead". */ +#endif + (ctx->memfree)(ctx->arg, mem); + INSIST(ctx->stats[ctx->max_size].gets != 0U); + ctx->stats[ctx->max_size].gets--; + INSIST(size <= ctx->total); + ctx->inuse -= size; + ctx->total -= size; + return; + } + +#if ISC_MEM_FILL +#if ISC_MEM_CHECKOVERRUN + check_overrun(mem, size, new_size); +#endif + memset(mem, 0xde, new_size); /* Mnemonic for "dead". */ +#endif + + /* + * The free list uses the "rounded-up" size "new_size". + */ + ((element *)mem)->next = ctx->freelists[new_size]; + ctx->freelists[new_size] = (element *)mem; + + /* + * The stats[] uses the _actual_ "size" requested by the + * caller, with the caveat (in the code above) that "size" >= the + * max. size (max_size) ends up getting recorded as a call to + * max_size. + */ + INSIST(ctx->stats[size].gets != 0U); + ctx->stats[size].gets--; + ctx->stats[new_size].freefrags++; + ctx->inuse -= new_size; +} + +/*! + * Perform a malloc, doing memory filling and overrun detection as necessary. + */ +static inline void * +mem_get(isc__mem_t *ctx, size_t size) { + char *ret; + +#if ISC_MEM_CHECKOVERRUN + size += 1; +#endif + + ret = (ctx->memalloc)(ctx->arg, size); + if (ret == NULL) + ctx->memalloc_failures++; + +#if ISC_MEM_FILL + if (ret != NULL) + memset(ret, 0xbe, size); /* Mnemonic for "beef". */ +#else +# if ISC_MEM_CHECKOVERRUN + if (ret != NULL) + ret[size-1] = 0xbe; +# endif +#endif + + return (ret); +} + +/*! + * Perform a free, doing memory filling and overrun detection as necessary. + */ +static inline void +mem_put(isc__mem_t *ctx, void *mem, size_t size) { +#if ISC_MEM_CHECKOVERRUN + INSIST(((unsigned char *)mem)[size] == 0xbe); +#endif +#if ISC_MEM_FILL + memset(mem, 0xde, size); /* Mnemonic for "dead". */ +#else + UNUSED(size); +#endif + (ctx->memfree)(ctx->arg, mem); +} + +/*! + * Update internal counters after a memory get. + */ +static inline void +mem_getstats(isc__mem_t *ctx, size_t size) { + ctx->total += size; + ctx->inuse += size; + + if (size > ctx->max_size) { + ctx->stats[ctx->max_size].gets++; + ctx->stats[ctx->max_size].totalgets++; + } else { + ctx->stats[size].gets++; + ctx->stats[size].totalgets++; + } +} + +/*! + * Update internal counters after a memory put. + */ +static inline void +mem_putstats(isc__mem_t *ctx, void *ptr, size_t size) { + UNUSED(ptr); + + INSIST(ctx->inuse >= size); + ctx->inuse -= size; + + if (size > ctx->max_size) { + INSIST(ctx->stats[ctx->max_size].gets > 0U); + ctx->stats[ctx->max_size].gets--; + } else { + INSIST(ctx->stats[size].gets > 0U); + ctx->stats[size].gets--; + } +} + +/* + * Private. + */ + +static void * +default_memalloc(void *arg, size_t size) { + UNUSED(arg); + if (size == 0U) + size = 1; + return (malloc(size)); +} + +static void +default_memfree(void *arg, void *ptr) { + UNUSED(arg); + free(ptr); +} + +static void +initialize_action(void) { + RUNTIME_CHECK(isc_mutex_init(&lock) == ISC_R_SUCCESS); + ISC_LIST_INIT(contexts); + totallost = 0; +} + +/* + * Public. + */ + +ISC_MEMFUNC_SCOPE isc_result_t +isc__mem_createx(size_t init_max_size, size_t target_size, + isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, + isc_mem_t **ctxp) +{ + return (isc__mem_createx2(init_max_size, target_size, memalloc, memfree, + arg, ctxp, ISC_MEMFLAG_DEFAULT)); + +} + +ISC_MEMFUNC_SCOPE isc_result_t +isc__mem_createx2(size_t init_max_size, size_t target_size, + isc_memalloc_t memalloc, isc_memfree_t memfree, void *arg, + isc_mem_t **ctxp, unsigned int flags) +{ + isc__mem_t *ctx; + isc_result_t result; + + REQUIRE(ctxp != NULL && *ctxp == NULL); + REQUIRE(memalloc != NULL); + REQUIRE(memfree != NULL); + + INSIST((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0); + + RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); + + ctx = (memalloc)(arg, sizeof(*ctx)); + if (ctx == NULL) + return (ISC_R_NOMEMORY); + + if ((flags & ISC_MEMFLAG_NOLOCK) == 0) { + result = isc_mutex_init(&ctx->lock); + if (result != ISC_R_SUCCESS) { + (memfree)(arg, ctx); + return (result); + } + } + + if (init_max_size == 0U) + ctx->max_size = DEF_MAX_SIZE; + else + ctx->max_size = init_max_size; + ctx->flags = flags; + ctx->references = 1; + memset(ctx->name, 0, sizeof(ctx->name)); + ctx->tag = NULL; + ctx->quota = 0; + ctx->total = 0; + ctx->inuse = 0; + ctx->maxinuse = 0; + ctx->hi_water = 0; + ctx->lo_water = 0; + ctx->hi_called = ISC_FALSE; + ctx->is_overmem = ISC_FALSE; + ctx->water = NULL; + ctx->water_arg = NULL; + ctx->common.impmagic = MEM_MAGIC; + ctx->common.magic = ISCAPI_MCTX_MAGIC; + ctx->common.methods = (isc_memmethods_t *)&memmethods; + isc_ondestroy_init(&ctx->ondestroy); + ctx->memalloc = memalloc; + ctx->memfree = memfree; + ctx->arg = arg; + ctx->stats = NULL; + ctx->checkfree = ISC_TRUE; +#if ISC_MEM_TRACKLINES + ctx->debuglist = NULL; + ctx->debuglistcnt = 0; +#endif + ISC_LIST_INIT(ctx->pools); + ctx->poolcnt = 0; + ctx->freelists = NULL; + ctx->basic_blocks = NULL; + ctx->basic_table = NULL; + ctx->basic_table_count = 0; + ctx->basic_table_size = 0; + ctx->lowest = NULL; + ctx->highest = NULL; + + ctx->stats = (memalloc)(arg, + (ctx->max_size+1) * sizeof(struct stats)); + if (ctx->stats == NULL) { + result = ISC_R_NOMEMORY; + goto error; + } + memset(ctx->stats, 0, (ctx->max_size + 1) * sizeof(struct stats)); + + if ((flags & ISC_MEMFLAG_INTERNAL) != 0) { + if (target_size == 0U) + ctx->mem_target = DEF_MEM_TARGET; + else + ctx->mem_target = target_size; + ctx->freelists = (memalloc)(arg, ctx->max_size * + sizeof(element *)); + if (ctx->freelists == NULL) { + result = ISC_R_NOMEMORY; + goto error; + } + memset(ctx->freelists, 0, + ctx->max_size * sizeof(element *)); + } + +#if ISC_MEM_TRACKLINES + if ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0) { + unsigned int i; + + ctx->debuglist = (memalloc)(arg, + (ctx->max_size+1) * sizeof(debuglist_t)); + if (ctx->debuglist == NULL) { + result = ISC_R_NOMEMORY; + goto error; + } + for (i = 0; i <= ctx->max_size; i++) + ISC_LIST_INIT(ctx->debuglist[i]); + } +#endif + + ctx->memalloc_failures = 0; + + LOCK(&lock); + ISC_LIST_INITANDAPPEND(contexts, ctx, link); + UNLOCK(&lock); + + *ctxp = (isc_mem_t *)ctx; + return (ISC_R_SUCCESS); + + error: + if (ctx != NULL) { + if (ctx->stats != NULL) + (memfree)(arg, ctx->stats); + if (ctx->freelists != NULL) + (memfree)(arg, ctx->freelists); +#if ISC_MEM_TRACKLINES + if (ctx->debuglist != NULL) + (ctx->memfree)(ctx->arg, ctx->debuglist); +#endif /* ISC_MEM_TRACKLINES */ + if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0) + DESTROYLOCK(&ctx->lock); + (memfree)(arg, ctx); + } + + return (result); +} + +ISC_MEMFUNC_SCOPE isc_result_t +isc__mem_create(size_t init_max_size, size_t target_size, isc_mem_t **ctxp) { + return (isc__mem_createx2(init_max_size, target_size, + default_memalloc, default_memfree, NULL, + ctxp, ISC_MEMFLAG_DEFAULT)); +} + +ISC_MEMFUNC_SCOPE isc_result_t +isc__mem_create2(size_t init_max_size, size_t target_size, + isc_mem_t **ctxp, unsigned int flags) +{ + return (isc__mem_createx2(init_max_size, target_size, + default_memalloc, default_memfree, NULL, + ctxp, flags)); +} + +static void +destroy(isc__mem_t *ctx) { + unsigned int i; + isc_ondestroy_t ondest; + + LOCK(&lock); + ISC_LIST_UNLINK(contexts, ctx, link); + totallost += ctx->inuse; + UNLOCK(&lock); + + ctx->common.impmagic = 0; + ctx->common.magic = 0; + + INSIST(ISC_LIST_EMPTY(ctx->pools)); + +#if ISC_MEM_TRACKLINES + if (ctx->debuglist != NULL) { + if (ctx->checkfree) { + for (i = 0; i <= ctx->max_size; i++) { + if (!ISC_LIST_EMPTY(ctx->debuglist[i])) + print_active(ctx, stderr); + INSIST(ISC_LIST_EMPTY(ctx->debuglist[i])); + } + } else { + debuglink_t *dl; + + for (i = 0; i <= ctx->max_size; i++) + for (dl = ISC_LIST_HEAD(ctx->debuglist[i]); + dl != NULL; + dl = ISC_LIST_HEAD(ctx->debuglist[i])) { + ISC_LIST_UNLINK(ctx->debuglist[i], + dl, link); + free(dl); + } + } + (ctx->memfree)(ctx->arg, ctx->debuglist); + } +#endif + INSIST(ctx->references == 0); + + if (ctx->checkfree) { + for (i = 0; i <= ctx->max_size; i++) { +#if ISC_MEM_TRACKLINES + if (ctx->stats[i].gets != 0U) + print_active(ctx, stderr); +#endif + INSIST(ctx->stats[i].gets == 0U); + } + } + + (ctx->memfree)(ctx->arg, ctx->stats); + + if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { + for (i = 0; i < ctx->basic_table_count; i++) + (ctx->memfree)(ctx->arg, ctx->basic_table[i]); + (ctx->memfree)(ctx->arg, ctx->freelists); + if (ctx->basic_table != NULL) + (ctx->memfree)(ctx->arg, ctx->basic_table); + } + + ondest = ctx->ondestroy; + + if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0) + DESTROYLOCK(&ctx->lock); + (ctx->memfree)(ctx->arg, ctx); + + isc_ondestroy_notify(&ondest, ctx); +} + +ISC_MEMFUNC_SCOPE void +isc__mem_attach(isc_mem_t *source0, isc_mem_t **targetp) { + isc__mem_t *source = (isc__mem_t *)source0; + + REQUIRE(VALID_CONTEXT(source)); + REQUIRE(targetp != NULL && *targetp == NULL); + + MCTXLOCK(source, &source->lock); + source->references++; + MCTXUNLOCK(source, &source->lock); + + *targetp = (isc_mem_t *)source; +} + +ISC_MEMFUNC_SCOPE void +isc__mem_detach(isc_mem_t **ctxp) { + isc__mem_t *ctx; + isc_boolean_t want_destroy = ISC_FALSE; + + REQUIRE(ctxp != NULL); + ctx = (isc__mem_t *)*ctxp; + REQUIRE(VALID_CONTEXT(ctx)); + + MCTXLOCK(ctx, &ctx->lock); + INSIST(ctx->references > 0); + ctx->references--; + if (ctx->references == 0) + want_destroy = ISC_TRUE; + MCTXUNLOCK(ctx, &ctx->lock); + + if (want_destroy) + destroy(ctx); + + *ctxp = NULL; +} + +/* + * isc_mem_putanddetach() is the equivalent of: + * + * mctx = NULL; + * isc_mem_attach(ptr->mctx, &mctx); + * isc_mem_detach(&ptr->mctx); + * isc_mem_put(mctx, ptr, sizeof(*ptr); + * isc_mem_detach(&mctx); + */ + +ISC_MEMFUNC_SCOPE void +isc___mem_putanddetach(isc_mem_t **ctxp, void *ptr, size_t size FLARG) { + isc__mem_t *ctx; + isc_boolean_t want_destroy = ISC_FALSE; + size_info *si; + size_t oldsize; + + REQUIRE(ctxp != NULL); + ctx = (isc__mem_t *)*ctxp; + REQUIRE(VALID_CONTEXT(ctx)); + REQUIRE(ptr != NULL); + + /* + * Must be before mem_putunlocked() as ctxp is usually within + * [ptr..ptr+size). + */ + *ctxp = NULL; + + if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) { + if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) { + si = &(((size_info *)ptr)[-1]); + oldsize = si->u.size - ALIGNMENT_SIZE; + if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) + oldsize -= ALIGNMENT_SIZE; + INSIST(oldsize == size); + } + isc_mem_free((isc_mem_t *)ctx, ptr); + + MCTXLOCK(ctx, &ctx->lock); + ctx->references--; + if (ctx->references == 0) + want_destroy = ISC_TRUE; + MCTXUNLOCK(ctx, &ctx->lock); + if (want_destroy) + destroy(ctx); + + return; + } + + if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { + MCTXLOCK(ctx, &ctx->lock); + mem_putunlocked(ctx, ptr, size); + } else { + mem_put(ctx, ptr, size); + MCTXLOCK(ctx, &ctx->lock); + mem_putstats(ctx, ptr, size); + } + + DELETE_TRACE(ctx, ptr, size, file, line); + INSIST(ctx->references > 0); + ctx->references--; + if (ctx->references == 0) + want_destroy = ISC_TRUE; + + MCTXUNLOCK(ctx, &ctx->lock); + + if (want_destroy) + destroy(ctx); +} + +ISC_MEMFUNC_SCOPE void +isc__mem_destroy(isc_mem_t **ctxp) { + isc__mem_t *ctx; + + /* + * This routine provides legacy support for callers who use mctxs + * without attaching/detaching. + */ + + REQUIRE(ctxp != NULL); + ctx = (isc__mem_t *)*ctxp; + REQUIRE(VALID_CONTEXT(ctx)); + + MCTXLOCK(ctx, &ctx->lock); +#if ISC_MEM_TRACKLINES + if (ctx->references != 1) + print_active(ctx, stderr); +#endif + REQUIRE(ctx->references == 1); + ctx->references--; + MCTXUNLOCK(ctx, &ctx->lock); + + destroy(ctx); + + *ctxp = NULL; +} + +ISC_MEMFUNC_SCOPE isc_result_t +isc__mem_ondestroy(isc_mem_t *ctx0, isc_task_t *task, isc_event_t **event) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; + isc_result_t res; + + MCTXLOCK(ctx, &ctx->lock); + res = isc_ondestroy_register(&ctx->ondestroy, task, event); + MCTXUNLOCK(ctx, &ctx->lock); + + return (res); +} + +ISC_MEMFUNC_SCOPE void * +isc___mem_get(isc_mem_t *ctx0, size_t size FLARG) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; + void *ptr; + isc_boolean_t call_water = ISC_FALSE; + + REQUIRE(VALID_CONTEXT(ctx)); + + if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) + return (isc__mem_allocate(ctx0, size FLARG_PASS)); + + if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { + MCTXLOCK(ctx, &ctx->lock); + ptr = mem_getunlocked(ctx, size); + } else { + ptr = mem_get(ctx, size); + MCTXLOCK(ctx, &ctx->lock); + if (ptr != NULL) + mem_getstats(ctx, size); + } + + ADD_TRACE(ctx, ptr, size, file, line); + if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water && + !ctx->is_overmem) { + ctx->is_overmem = ISC_TRUE; + } + if (ctx->hi_water != 0U && !ctx->hi_called && + ctx->inuse > ctx->hi_water) { + call_water = ISC_TRUE; + } + if (ctx->inuse > ctx->maxinuse) { + ctx->maxinuse = ctx->inuse; + if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water && + (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0) + fprintf(stderr, "maxinuse = %lu\n", + (unsigned long)ctx->inuse); + } + MCTXUNLOCK(ctx, &ctx->lock); + + if (call_water) + (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER); + + return (ptr); +} + +ISC_MEMFUNC_SCOPE void +isc___mem_put(isc_mem_t *ctx0, void *ptr, size_t size FLARG) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; + isc_boolean_t call_water = ISC_FALSE; + size_info *si; + size_t oldsize; + + REQUIRE(VALID_CONTEXT(ctx)); + REQUIRE(ptr != NULL); + + if ((isc_mem_debugging & (ISC_MEM_DEBUGSIZE|ISC_MEM_DEBUGCTX)) != 0) { + if ((isc_mem_debugging & ISC_MEM_DEBUGSIZE) != 0) { + si = &(((size_info *)ptr)[-1]); + oldsize = si->u.size - ALIGNMENT_SIZE; + if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) + oldsize -= ALIGNMENT_SIZE; + INSIST(oldsize == size); + } + isc_mem_free((isc_mem_t *)ctx, ptr); + return; + } + + if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { + MCTXLOCK(ctx, &ctx->lock); + mem_putunlocked(ctx, ptr, size); + } else { + mem_put(ctx, ptr, size); + MCTXLOCK(ctx, &ctx->lock); + mem_putstats(ctx, ptr, size); + } + + DELETE_TRACE(ctx, ptr, size, file, line); + + /* + * The check against ctx->lo_water == 0 is for the condition + * when the context was pushed over hi_water but then had + * isc_mem_setwater() called with 0 for hi_water and lo_water. + */ + if (ctx->is_overmem && + (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) { + ctx->is_overmem = ISC_FALSE; + } + if (ctx->hi_called && + (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) { + if (ctx->water != NULL) + call_water = ISC_TRUE; + } + MCTXUNLOCK(ctx, &ctx->lock); + + if (call_water) + (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER); +} + +ISC_MEMFUNC_SCOPE void +isc__mem_waterack(isc_mem_t *ctx0, int flag) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; + + REQUIRE(VALID_CONTEXT(ctx)); + + MCTXLOCK(ctx, &ctx->lock); + if (flag == ISC_MEM_LOWATER) + ctx->hi_called = ISC_FALSE; + else if (flag == ISC_MEM_HIWATER) + ctx->hi_called = ISC_TRUE; + MCTXUNLOCK(ctx, &ctx->lock); +} + +#if ISC_MEM_TRACKLINES +static void +print_active(isc__mem_t *mctx, FILE *out) { + if (mctx->debuglist != NULL) { + debuglink_t *dl; + unsigned int i, j; + const char *format; + isc_boolean_t found; + + fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, + ISC_MSG_DUMPALLOC, + "Dump of all outstanding " + "memory allocations:\n")); + found = ISC_FALSE; + format = isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, + ISC_MSG_PTRFILELINE, + "\tptr %p size %u file %s line %u\n"); + for (i = 0; i <= mctx->max_size; i++) { + dl = ISC_LIST_HEAD(mctx->debuglist[i]); + + if (dl != NULL) + found = ISC_TRUE; + + while (dl != NULL) { + for (j = 0; j < DEBUGLIST_COUNT; j++) + if (dl->ptr[j] != NULL) + fprintf(out, format, + dl->ptr[j], + dl->size[j], + dl->file[j], + dl->line[j]); + dl = ISC_LIST_NEXT(dl, link); + } + } + if (!found) + fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, + ISC_MSG_NONE, "\tNone.\n")); + } +} +#endif + +/* + * Print the stats[] on the stream "out" with suitable formatting. + */ +ISC_MEMFUNC_SCOPE void +isc__mem_stats(isc_mem_t *ctx0, FILE *out) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; + size_t i; + const struct stats *s; + const isc__mempool_t *pool; + + REQUIRE(VALID_CONTEXT(ctx)); + MCTXLOCK(ctx, &ctx->lock); + + for (i = 0; i <= ctx->max_size; i++) { + s = &ctx->stats[i]; + + if (s->totalgets == 0U && s->gets == 0U) + continue; + fprintf(out, "%s%5lu: %11lu gets, %11lu rem", + (i == ctx->max_size) ? ">=" : " ", + (unsigned long) i, s->totalgets, s->gets); + if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0 && + (s->blocks != 0U || s->freefrags != 0U)) + fprintf(out, " (%lu bl, %lu ff)", + s->blocks, s->freefrags); + fputc('\n', out); + } + + /* + * Note that since a pool can be locked now, these stats might be + * somewhat off if the pool is in active use at the time the stats + * are dumped. The link fields are protected by the isc_mem_t's + * lock, however, so walking this list and extracting integers from + * stats fields is always safe. + */ + pool = ISC_LIST_HEAD(ctx->pools); + if (pool != NULL) { + fprintf(out, "%s", isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, + ISC_MSG_POOLSTATS, + "[Pool statistics]\n")); + fprintf(out, "%15s %10s %10s %10s %10s %10s %10s %10s %1s\n", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, + ISC_MSG_POOLNAME, "name"), + isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, + ISC_MSG_POOLSIZE, "size"), + isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, + ISC_MSG_POOLMAXALLOC, "maxalloc"), + isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, + ISC_MSG_POOLALLOCATED, "allocated"), + isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, + ISC_MSG_POOLFREECOUNT, "freecount"), + isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, + ISC_MSG_POOLFREEMAX, "freemax"), + isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, + ISC_MSG_POOLFILLCOUNT, "fillcount"), + isc_msgcat_get(isc_msgcat, ISC_MSGSET_MEM, + ISC_MSG_POOLGETS, "gets"), + "L"); + } + while (pool != NULL) { + fprintf(out, "%15s %10lu %10u %10u %10u %10u %10u %10u %s\n", + pool->name, (unsigned long) pool->size, pool->maxalloc, + pool->allocated, pool->freecount, pool->freemax, + pool->fillcount, pool->gets, + (pool->lock == NULL ? "N" : "Y")); + pool = ISC_LIST_NEXT(pool, link); + } + +#if ISC_MEM_TRACKLINES + print_active(ctx, out); +#endif + + MCTXUNLOCK(ctx, &ctx->lock); +} + +/* + * Replacements for malloc() and free() -- they implicitly remember the + * size of the object allocated (with some additional overhead). + */ + +static void * +isc__mem_allocateunlocked(isc_mem_t *ctx0, size_t size) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; + size_info *si; + + size += ALIGNMENT_SIZE; + if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) + size += ALIGNMENT_SIZE; + + if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) + si = mem_getunlocked(ctx, size); + else + si = mem_get(ctx, size); + + if (si == NULL) + return (NULL); + if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) { + si->u.ctx = ctx; + si++; + } + si->u.size = size; + return (&si[1]); +} + +ISC_MEMFUNC_SCOPE void * +isc___mem_allocate(isc_mem_t *ctx0, size_t size FLARG) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; + size_info *si; + isc_boolean_t call_water = ISC_FALSE; + + REQUIRE(VALID_CONTEXT(ctx)); + + if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { + MCTXLOCK(ctx, &ctx->lock); + si = isc__mem_allocateunlocked((isc_mem_t *)ctx, size); + } else { + si = isc__mem_allocateunlocked((isc_mem_t *)ctx, size); + MCTXLOCK(ctx, &ctx->lock); + if (si != NULL) + mem_getstats(ctx, si[-1].u.size); + } + +#if ISC_MEM_TRACKLINES + ADD_TRACE(ctx, si, si[-1].u.size, file, line); +#endif + if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water && + !ctx->is_overmem) { + ctx->is_overmem = ISC_TRUE; + } + + if (ctx->hi_water != 0U && !ctx->hi_called && + ctx->inuse > ctx->hi_water) { + ctx->hi_called = ISC_TRUE; + call_water = ISC_TRUE; + } + if (ctx->inuse > ctx->maxinuse) { + ctx->maxinuse = ctx->inuse; + if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water && + (isc_mem_debugging & ISC_MEM_DEBUGUSAGE) != 0) + fprintf(stderr, "maxinuse = %lu\n", + (unsigned long)ctx->inuse); + } + MCTXUNLOCK(ctx, &ctx->lock); + + if (call_water) + (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER); + + return (si); +} + +ISC_MEMFUNC_SCOPE void * +isc___mem_reallocate(isc_mem_t *ctx0, void *ptr, size_t size FLARG) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; + void *new_ptr = NULL; + size_t oldsize, copysize; + + REQUIRE(VALID_CONTEXT(ctx)); + + /* + * This function emulates the realloc(3) standard library function: + * - if size > 0, allocate new memory; and if ptr is non NULL, copy + * as much of the old contents to the new buffer and free the old one. + * Note that when allocation fails the original pointer is intact; + * the caller must free it. + * - if size is 0 and ptr is non NULL, simply free the given ptr. + * - this function returns: + * pointer to the newly allocated memory, or + * NULL if allocation fails or doesn't happen. + */ + if (size > 0U) { + new_ptr = isc__mem_allocate(ctx0, size FLARG_PASS); + if (new_ptr != NULL && ptr != NULL) { + oldsize = (((size_info *)ptr)[-1]).u.size; + INSIST(oldsize >= ALIGNMENT_SIZE); + oldsize -= ALIGNMENT_SIZE; + copysize = oldsize > size ? size : oldsize; + memcpy(new_ptr, ptr, copysize); + isc__mem_free(ctx0, ptr FLARG_PASS); + } + } else if (ptr != NULL) + isc__mem_free(ctx0, ptr FLARG_PASS); + + return (new_ptr); +} + +ISC_MEMFUNC_SCOPE void +isc___mem_free(isc_mem_t *ctx0, void *ptr FLARG) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; + size_info *si; + size_t size; + isc_boolean_t call_water= ISC_FALSE; + + REQUIRE(VALID_CONTEXT(ctx)); + REQUIRE(ptr != NULL); + + if ((isc_mem_debugging & ISC_MEM_DEBUGCTX) != 0) { + si = &(((size_info *)ptr)[-2]); + REQUIRE(si->u.ctx == ctx); + size = si[1].u.size; + } else { + si = &(((size_info *)ptr)[-1]); + size = si->u.size; + } + + if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { + MCTXLOCK(ctx, &ctx->lock); + mem_putunlocked(ctx, si, size); + } else { + mem_put(ctx, si, size); + MCTXLOCK(ctx, &ctx->lock); + mem_putstats(ctx, si, size); + } + + DELETE_TRACE(ctx, ptr, size, file, line); + + /* + * The check against ctx->lo_water == 0 is for the condition + * when the context was pushed over hi_water but then had + * isc_mem_setwater() called with 0 for hi_water and lo_water. + */ + if (ctx->is_overmem && + (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) { + ctx->is_overmem = ISC_FALSE; + } + + if (ctx->hi_called && + (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) { + ctx->hi_called = ISC_FALSE; + + if (ctx->water != NULL) + call_water = ISC_TRUE; + } + MCTXUNLOCK(ctx, &ctx->lock); + + if (call_water) + (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER); +} + + +/* + * Other useful things. + */ + +ISC_MEMFUNC_SCOPE char * +isc___mem_strdup(isc_mem_t *mctx0, const char *s FLARG) { + isc__mem_t *mctx = (isc__mem_t *)mctx0; + size_t len; + char *ns; + + REQUIRE(VALID_CONTEXT(mctx)); + REQUIRE(s != NULL); + + len = strlen(s); + + ns = isc___mem_allocate((isc_mem_t *)mctx, len + 1 FLARG_PASS); + + if (ns != NULL) + strncpy(ns, s, len + 1); + + return (ns); +} + +ISC_MEMFUNC_SCOPE void +isc__mem_setdestroycheck(isc_mem_t *ctx0, isc_boolean_t flag) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; + + REQUIRE(VALID_CONTEXT(ctx)); + MCTXLOCK(ctx, &ctx->lock); + + ctx->checkfree = flag; + + MCTXUNLOCK(ctx, &ctx->lock); +} + +/* + * Quotas + */ + +ISC_MEMFUNC_SCOPE void +isc__mem_setquota(isc_mem_t *ctx0, size_t quota) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; + + REQUIRE(VALID_CONTEXT(ctx)); + MCTXLOCK(ctx, &ctx->lock); + + ctx->quota = quota; + + MCTXUNLOCK(ctx, &ctx->lock); +} + +ISC_MEMFUNC_SCOPE size_t +isc__mem_getquota(isc_mem_t *ctx0) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; + size_t quota; + + REQUIRE(VALID_CONTEXT(ctx)); + MCTXLOCK(ctx, &ctx->lock); + + quota = ctx->quota; + + MCTXUNLOCK(ctx, &ctx->lock); + + return (quota); +} + +ISC_MEMFUNC_SCOPE size_t +isc__mem_inuse(isc_mem_t *ctx0) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; + size_t inuse; + + REQUIRE(VALID_CONTEXT(ctx)); + MCTXLOCK(ctx, &ctx->lock); + + inuse = ctx->inuse; + + MCTXUNLOCK(ctx, &ctx->lock); + + return (inuse); +} + +ISC_MEMFUNC_SCOPE void +isc__mem_setwater(isc_mem_t *ctx0, isc_mem_water_t water, void *water_arg, + size_t hiwater, size_t lowater) +{ + isc__mem_t *ctx = (isc__mem_t *)ctx0; + isc_boolean_t callwater = ISC_FALSE; + isc_mem_water_t oldwater; + void *oldwater_arg; + + REQUIRE(VALID_CONTEXT(ctx)); + REQUIRE(hiwater >= lowater); + + MCTXLOCK(ctx, &ctx->lock); + oldwater = ctx->water; + oldwater_arg = ctx->water_arg; + if (water == NULL) { + callwater = ctx->hi_called; + ctx->water = NULL; + ctx->water_arg = NULL; + ctx->hi_water = 0; + ctx->lo_water = 0; + ctx->hi_called = ISC_FALSE; + } else { + if (ctx->hi_called && + (ctx->water != water || ctx->water_arg != water_arg || + ctx->inuse < lowater || lowater == 0U)) + callwater = ISC_TRUE; + ctx->water = water; + ctx->water_arg = water_arg; + ctx->hi_water = hiwater; + ctx->lo_water = lowater; + ctx->hi_called = ISC_FALSE; + } + MCTXUNLOCK(ctx, &ctx->lock); + + if (callwater && oldwater != NULL) + (oldwater)(oldwater_arg, ISC_MEM_LOWATER); +} + +ISC_MEMFUNC_SCOPE isc_boolean_t +isc__mem_isovermem(isc_mem_t *ctx0) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; + + REQUIRE(VALID_CONTEXT(ctx)); + + /* + * We don't bother to lock the context because 100% accuracy isn't + * necessary (and even if we locked the context the returned value + * could be different from the actual state when it's used anyway) + */ + return (ctx->is_overmem); +} + +ISC_MEMFUNC_SCOPE void +isc__mem_setname(isc_mem_t *ctx0, const char *name, void *tag) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; + + REQUIRE(VALID_CONTEXT(ctx)); + + LOCK(&ctx->lock); + memset(ctx->name, 0, sizeof(ctx->name)); + strncpy(ctx->name, name, sizeof(ctx->name) - 1); + ctx->tag = tag; + UNLOCK(&ctx->lock); +} + +ISC_MEMFUNC_SCOPE const char * +isc__mem_getname(isc_mem_t *ctx0) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; + + REQUIRE(VALID_CONTEXT(ctx)); + + return (ctx->name); +} + +ISC_MEMFUNC_SCOPE void * +isc__mem_gettag(isc_mem_t *ctx0) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; + + REQUIRE(VALID_CONTEXT(ctx)); + + return (ctx->tag); +} + +/* + * Memory pool stuff + */ + +ISC_MEMFUNC_SCOPE isc_result_t +isc__mempool_create(isc_mem_t *mctx0, size_t size, isc_mempool_t **mpctxp) { + isc__mem_t *mctx = (isc__mem_t *)mctx0; + isc__mempool_t *mpctx; + + REQUIRE(VALID_CONTEXT(mctx)); + REQUIRE(size > 0U); + REQUIRE(mpctxp != NULL && *mpctxp == NULL); + + /* + * Allocate space for this pool, initialize values, and if all works + * well, attach to the memory context. + */ + mpctx = isc_mem_get((isc_mem_t *)mctx, sizeof(isc__mempool_t)); + if (mpctx == NULL) + return (ISC_R_NOMEMORY); + + mpctx->common.methods = (isc_mempoolmethods_t *)&mempoolmethods; + mpctx->common.impmagic = MEMPOOL_MAGIC; + mpctx->common.magic = ISCAPI_MPOOL_MAGIC; + mpctx->lock = NULL; + mpctx->mctx = mctx; + mpctx->size = size; + mpctx->maxalloc = UINT_MAX; + mpctx->allocated = 0; + mpctx->freecount = 0; + mpctx->freemax = 1; + mpctx->fillcount = 1; + mpctx->gets = 0; +#if ISC_MEMPOOL_NAMES + mpctx->name[0] = 0; +#endif + mpctx->items = NULL; + + *mpctxp = (isc_mempool_t *)mpctx; + + MCTXLOCK(mctx, &mctx->lock); + ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link); + mctx->poolcnt++; + MCTXUNLOCK(mctx, &mctx->lock); + + return (ISC_R_SUCCESS); +} + +ISC_MEMFUNC_SCOPE void +isc__mempool_setname(isc_mempool_t *mpctx0, const char *name) { + isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; + + REQUIRE(name != NULL); + REQUIRE(VALID_MEMPOOL(mpctx)); + +#if ISC_MEMPOOL_NAMES + if (mpctx->lock != NULL) + LOCK(mpctx->lock); + + strncpy(mpctx->name, name, sizeof(mpctx->name) - 1); + mpctx->name[sizeof(mpctx->name) - 1] = '\0'; + + if (mpctx->lock != NULL) + UNLOCK(mpctx->lock); +#else + UNUSED(mpctx); + UNUSED(name); +#endif +} + +ISC_MEMFUNC_SCOPE void +isc__mempool_destroy(isc_mempool_t **mpctxp) { + isc__mempool_t *mpctx; + isc__mem_t *mctx; + isc_mutex_t *lock; + element *item; + + REQUIRE(mpctxp != NULL); + mpctx = (isc__mempool_t *)*mpctxp; + REQUIRE(VALID_MEMPOOL(mpctx)); +#if ISC_MEMPOOL_NAMES + if (mpctx->allocated > 0) + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc__mempool_destroy(): mempool %s " + "leaked memory", + mpctx->name); +#endif + REQUIRE(mpctx->allocated == 0); + + mctx = mpctx->mctx; + + lock = mpctx->lock; + + if (lock != NULL) + LOCK(lock); + + /* + * Return any items on the free list + */ + MCTXLOCK(mctx, &mctx->lock); + while (mpctx->items != NULL) { + INSIST(mpctx->freecount > 0); + mpctx->freecount--; + item = mpctx->items; + mpctx->items = item->next; + + if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { + mem_putunlocked(mctx, item, mpctx->size); + } else { + mem_put(mctx, item, mpctx->size); + mem_putstats(mctx, item, mpctx->size); + } + } + MCTXUNLOCK(mctx, &mctx->lock); + + /* + * Remove our linked list entry from the memory context. + */ + MCTXLOCK(mctx, &mctx->lock); + ISC_LIST_UNLINK(mctx->pools, mpctx, link); + mctx->poolcnt--; + MCTXUNLOCK(mctx, &mctx->lock); + + mpctx->common.impmagic = 0; + mpctx->common.magic = 0; + + isc_mem_put((isc_mem_t *)mpctx->mctx, mpctx, sizeof(isc__mempool_t)); + + if (lock != NULL) + UNLOCK(lock); + + *mpctxp = NULL; +} + +ISC_MEMFUNC_SCOPE void +isc__mempool_associatelock(isc_mempool_t *mpctx0, isc_mutex_t *lock) { + isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; + + REQUIRE(VALID_MEMPOOL(mpctx)); + REQUIRE(mpctx->lock == NULL); + REQUIRE(lock != NULL); + + mpctx->lock = lock; +} + +ISC_MEMFUNC_SCOPE void * +isc___mempool_get(isc_mempool_t *mpctx0 FLARG) { + isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; + element *item; + isc__mem_t *mctx; + unsigned int i; + + REQUIRE(VALID_MEMPOOL(mpctx)); + + mctx = mpctx->mctx; + + if (mpctx->lock != NULL) + LOCK(mpctx->lock); + + /* + * Don't let the caller go over quota + */ + if (mpctx->allocated >= mpctx->maxalloc) { + item = NULL; + goto out; + } + + /* + * if we have a free list item, return the first here + */ + item = mpctx->items; + if (item != NULL) { + mpctx->items = item->next; + INSIST(mpctx->freecount > 0); + mpctx->freecount--; + mpctx->gets++; + mpctx->allocated++; + goto out; + } + + /* + * We need to dip into the well. Lock the memory context here and + * fill up our free list. + */ + MCTXLOCK(mctx, &mctx->lock); + for (i = 0; i < mpctx->fillcount; i++) { + if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { + item = mem_getunlocked(mctx, mpctx->size); + } else { + item = mem_get(mctx, mpctx->size); + if (item != NULL) + mem_getstats(mctx, mpctx->size); + } + if (item == NULL) + break; + item->next = mpctx->items; + mpctx->items = item; + mpctx->freecount++; + } + MCTXUNLOCK(mctx, &mctx->lock); + + /* + * If we didn't get any items, return NULL. + */ + item = mpctx->items; + if (item == NULL) + goto out; + + mpctx->items = item->next; + mpctx->freecount--; + mpctx->gets++; + mpctx->allocated++; + + out: + if (mpctx->lock != NULL) + UNLOCK(mpctx->lock); + +#if ISC_MEM_TRACKLINES + if (item != NULL) { + MCTXLOCK(mctx, &mctx->lock); + ADD_TRACE(mctx, item, mpctx->size, file, line); + MCTXUNLOCK(mctx, &mctx->lock); + } +#endif /* ISC_MEM_TRACKLINES */ + + return (item); +} + +ISC_MEMFUNC_SCOPE void +isc___mempool_put(isc_mempool_t *mpctx0, void *mem FLARG) { + isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; + isc__mem_t *mctx; + element *item; + + REQUIRE(VALID_MEMPOOL(mpctx)); + REQUIRE(mem != NULL); + + mctx = mpctx->mctx; + + if (mpctx->lock != NULL) + LOCK(mpctx->lock); + + INSIST(mpctx->allocated > 0); + mpctx->allocated--; + +#if ISC_MEM_TRACKLINES + MCTXLOCK(mctx, &mctx->lock); + DELETE_TRACE(mctx, mem, mpctx->size, file, line); + MCTXUNLOCK(mctx, &mctx->lock); +#endif /* ISC_MEM_TRACKLINES */ + + /* + * If our free list is full, return this to the mctx directly. + */ + if (mpctx->freecount >= mpctx->freemax) { + if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { + MCTXLOCK(mctx, &mctx->lock); + mem_putunlocked(mctx, mem, mpctx->size); + MCTXUNLOCK(mctx, &mctx->lock); + } else { + mem_put(mctx, mem, mpctx->size); + MCTXLOCK(mctx, &mctx->lock); + mem_putstats(mctx, mem, mpctx->size); + MCTXUNLOCK(mctx, &mctx->lock); + } + if (mpctx->lock != NULL) + UNLOCK(mpctx->lock); + return; + } + + /* + * Otherwise, attach it to our free list and bump the counter. + */ + mpctx->freecount++; + item = (element *)mem; + item->next = mpctx->items; + mpctx->items = item; + + if (mpctx->lock != NULL) + UNLOCK(mpctx->lock); +} + +/* + * Quotas + */ + +ISC_MEMFUNC_SCOPE void +isc__mempool_setfreemax(isc_mempool_t *mpctx0, unsigned int limit) { + isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; + + REQUIRE(VALID_MEMPOOL(mpctx)); + + if (mpctx->lock != NULL) + LOCK(mpctx->lock); + + mpctx->freemax = limit; + + if (mpctx->lock != NULL) + UNLOCK(mpctx->lock); +} + +ISC_MEMFUNC_SCOPE unsigned int +isc__mempool_getfreemax(isc_mempool_t *mpctx0) { + isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; + unsigned int freemax; + + REQUIRE(VALID_MEMPOOL(mpctx)); + + if (mpctx->lock != NULL) + LOCK(mpctx->lock); + + freemax = mpctx->freemax; + + if (mpctx->lock != NULL) + UNLOCK(mpctx->lock); + + return (freemax); +} + +ISC_MEMFUNC_SCOPE unsigned int +isc__mempool_getfreecount(isc_mempool_t *mpctx0) { + isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; + unsigned int freecount; + + REQUIRE(VALID_MEMPOOL(mpctx)); + + if (mpctx->lock != NULL) + LOCK(mpctx->lock); + + freecount = mpctx->freecount; + + if (mpctx->lock != NULL) + UNLOCK(mpctx->lock); + + return (freecount); +} + +ISC_MEMFUNC_SCOPE void +isc__mempool_setmaxalloc(isc_mempool_t *mpctx0, unsigned int limit) { + isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; + + REQUIRE(limit > 0); + + REQUIRE(VALID_MEMPOOL(mpctx)); + + if (mpctx->lock != NULL) + LOCK(mpctx->lock); + + mpctx->maxalloc = limit; + + if (mpctx->lock != NULL) + UNLOCK(mpctx->lock); +} + +ISC_MEMFUNC_SCOPE unsigned int +isc__mempool_getmaxalloc(isc_mempool_t *mpctx0) { + isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; + unsigned int maxalloc; + + REQUIRE(VALID_MEMPOOL(mpctx)); + + if (mpctx->lock != NULL) + LOCK(mpctx->lock); + + maxalloc = mpctx->maxalloc; + + if (mpctx->lock != NULL) + UNLOCK(mpctx->lock); + + return (maxalloc); +} + +ISC_MEMFUNC_SCOPE unsigned int +isc__mempool_getallocated(isc_mempool_t *mpctx0) { + isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; + unsigned int allocated; + + REQUIRE(VALID_MEMPOOL(mpctx)); + + if (mpctx->lock != NULL) + LOCK(mpctx->lock); + + allocated = mpctx->allocated; + + if (mpctx->lock != NULL) + UNLOCK(mpctx->lock); + + return (allocated); +} + +ISC_MEMFUNC_SCOPE void +isc__mempool_setfillcount(isc_mempool_t *mpctx0, unsigned int limit) { + isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; + + REQUIRE(limit > 0); + REQUIRE(VALID_MEMPOOL(mpctx)); + + if (mpctx->lock != NULL) + LOCK(mpctx->lock); + + mpctx->fillcount = limit; + + if (mpctx->lock != NULL) + UNLOCK(mpctx->lock); +} + +ISC_MEMFUNC_SCOPE unsigned int +isc__mempool_getfillcount(isc_mempool_t *mpctx0) { + isc__mempool_t *mpctx = (isc__mempool_t *)mpctx0; + + unsigned int fillcount; + + REQUIRE(VALID_MEMPOOL(mpctx)); + + if (mpctx->lock != NULL) + LOCK(mpctx->lock); + + fillcount = mpctx->fillcount; + + if (mpctx->lock != NULL) + UNLOCK(mpctx->lock); + + return (fillcount); +} + +#ifdef USE_MEMIMPREGISTER +isc_result_t +isc__mem_register() { + return (isc_mem_register(isc__mem_create2)); +} +#endif + +#ifdef BIND9 +ISC_MEMFUNC_SCOPE void +isc__mem_printactive(isc_mem_t *ctx0, FILE *file) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; + + REQUIRE(VALID_CONTEXT(ctx)); + REQUIRE(file != NULL); + +#if !ISC_MEM_TRACKLINES + UNUSED(ctx); + UNUSED(file); +#else + print_active(ctx, file); +#endif +} + +ISC_MEMFUNC_SCOPE void +isc__mem_printallactive(FILE *file) { +#if !ISC_MEM_TRACKLINES + UNUSED(file); +#else + isc__mem_t *ctx; + + RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); + + LOCK(&lock); + for (ctx = ISC_LIST_HEAD(contexts); + ctx != NULL; + ctx = ISC_LIST_NEXT(ctx, link)) { + fprintf(file, "context: %p\n", ctx); + print_active(ctx, file); + } + UNLOCK(&lock); +#endif +} + +ISC_MEMFUNC_SCOPE void +isc__mem_checkdestroyed(FILE *file) { + + RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); + + LOCK(&lock); + if (!ISC_LIST_EMPTY(contexts)) { +#if ISC_MEM_TRACKLINES + isc__mem_t *ctx; + + for (ctx = ISC_LIST_HEAD(contexts); + ctx != NULL; + ctx = ISC_LIST_NEXT(ctx, link)) { + fprintf(file, "context: %p\n", ctx); + print_active(ctx, file); + } + fflush(file); +#endif + INSIST(0); + } + UNLOCK(&lock); +} + +ISC_MEMFUNC_SCOPE unsigned int +isc_mem_references(isc_mem_t *ctx0) { + isc__mem_t *ctx = (isc__mem_t *)ctx0; + unsigned int references; + + REQUIRE(VALID_CONTEXT(ctx)); + + MCTXLOCK(ctx, &ctx->lock); + references = ctx->references; + MCTXUNLOCK(ctx, &ctx->lock); + + return (references); +} + +#ifdef HAVE_LIBXML2 + +typedef struct summarystat { + isc_uint64_t total; + isc_uint64_t inuse; + isc_uint64_t blocksize; + isc_uint64_t contextsize; +} summarystat_t; + +static void +renderctx(isc__mem_t *ctx, summarystat_t *summary, xmlTextWriterPtr writer) { + REQUIRE(VALID_CONTEXT(ctx)); + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "context"); + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "id"); + xmlTextWriterWriteFormatString(writer, "%p", ctx); + xmlTextWriterEndElement(writer); /* id */ + + if (ctx->name[0] != 0) { + xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"); + xmlTextWriterWriteFormatString(writer, "%s", ctx->name); + xmlTextWriterEndElement(writer); /* name */ + } + + REQUIRE(VALID_CONTEXT(ctx)); + MCTXLOCK(ctx, &ctx->lock); + + summary->contextsize += sizeof(*ctx) + + (ctx->max_size + 1) * sizeof(struct stats) + + ctx->max_size * sizeof(element *) + + ctx->basic_table_count * sizeof(char *); +#if ISC_MEM_TRACKLINES + if (ctx->debuglist != NULL) { + summary->contextsize += + (ctx->max_size + 1) * sizeof(debuglist_t) + + ctx->debuglistcnt * sizeof(debuglink_t); + } +#endif + xmlTextWriterStartElement(writer, ISC_XMLCHAR "references"); + xmlTextWriterWriteFormatString(writer, "%d", ctx->references); + xmlTextWriterEndElement(writer); /* references */ + + summary->total += ctx->total; + xmlTextWriterStartElement(writer, ISC_XMLCHAR "total"); + xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", + (isc_uint64_t)ctx->total); + xmlTextWriterEndElement(writer); /* total */ + + summary->inuse += ctx->inuse; + xmlTextWriterStartElement(writer, ISC_XMLCHAR "inuse"); + xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", + (isc_uint64_t)ctx->inuse); + xmlTextWriterEndElement(writer); /* inuse */ + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "maxinuse"); + xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", + (isc_uint64_t)ctx->maxinuse); + xmlTextWriterEndElement(writer); /* maxinuse */ + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "blocksize"); + if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) { + summary->blocksize += ctx->basic_table_count * + NUM_BASIC_BLOCKS * ctx->mem_target; + xmlTextWriterWriteFormatString(writer, + "%" ISC_PRINT_QUADFORMAT "u", + (isc_uint64_t) + ctx->basic_table_count * + NUM_BASIC_BLOCKS * + ctx->mem_target); + } else + xmlTextWriterWriteFormatString(writer, "%s", "-"); + xmlTextWriterEndElement(writer); /* blocksize */ + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "pools"); + xmlTextWriterWriteFormatString(writer, "%u", ctx->poolcnt); + xmlTextWriterEndElement(writer); /* pools */ + summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t); + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "hiwater"); + xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", + (isc_uint64_t)ctx->hi_water); + xmlTextWriterEndElement(writer); /* hiwater */ + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "lowater"); + xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", + (isc_uint64_t)ctx->lo_water); + xmlTextWriterEndElement(writer); /* lowater */ + + MCTXUNLOCK(ctx, &ctx->lock); + + xmlTextWriterEndElement(writer); /* context */ +} + +void +isc_mem_renderxml(xmlTextWriterPtr writer) { + isc__mem_t *ctx; + summarystat_t summary; + isc_uint64_t lost; + + memset(&summary, 0, sizeof(summary)); + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "contexts"); + + RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); + + LOCK(&lock); + lost = totallost; + for (ctx = ISC_LIST_HEAD(contexts); + ctx != NULL; + ctx = ISC_LIST_NEXT(ctx, link)) { + renderctx(ctx, &summary, writer); + } + UNLOCK(&lock); + + xmlTextWriterEndElement(writer); /* contexts */ + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "summary"); + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "TotalUse"); + xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", + summary.total); + xmlTextWriterEndElement(writer); /* TotalUse */ + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "InUse"); + xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", + summary.inuse); + xmlTextWriterEndElement(writer); /* InUse */ + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "BlockSize"); + xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", + summary.blocksize); + xmlTextWriterEndElement(writer); /* BlockSize */ + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "ContextSize"); + xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", + summary.contextsize); + xmlTextWriterEndElement(writer); /* ContextSize */ + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "Lost"); + xmlTextWriterWriteFormatString(writer, "%" ISC_PRINT_QUADFORMAT "u", + lost); + xmlTextWriterEndElement(writer); /* Lost */ + + xmlTextWriterEndElement(writer); /* summary */ +} + +#endif /* HAVE_LIBXML2 */ +#endif /* BIND9 */ diff --git a/contrib/ntp/lib/isc/mem_api.c b/contrib/ntp/lib/isc/mem_api.c new file mode 100644 index 0000000..85abb9b --- /dev/null +++ b/contrib/ntp/lib/isc/mem_api.c @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2009, 2010 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: mem_api.c,v 1.8 2010/08/12 21:30:26 jinmei Exp $ */ + +#include <config.h> + +#include <isc/magic.h> +#include <isc/mem.h> +#include <isc/once.h> +#include <isc/util.h> + +#if ISC_MEM_TRACKLINES +#define FLARG_PASS , file, line +#define FLARG , const char *file, unsigned int line +#else +#define FLARG_PASS +#define FLARG +#endif + +static isc_mutex_t createlock; +static isc_once_t once = ISC_ONCE_INIT; +static isc_memcreatefunc_t mem_createfunc = NULL; + +static void +initialize(void) { + RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS); +} + +isc_result_t +isc_mem_register(isc_memcreatefunc_t createfunc) { + isc_result_t result = ISC_R_SUCCESS; + + RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS); + + LOCK(&createlock); + if (mem_createfunc == NULL) + mem_createfunc = createfunc; + else + result = ISC_R_EXISTS; + UNLOCK(&createlock); + + return (result); +} + +isc_result_t +isc_mem_create(size_t init_max_size, size_t target_size, isc_mem_t **mctxp) { + isc_result_t result; + + LOCK(&createlock); + + REQUIRE(mem_createfunc != NULL); + result = (*mem_createfunc)(init_max_size, target_size, mctxp, + ISC_MEMFLAG_DEFAULT); + + UNLOCK(&createlock); + + return (result); +} + +isc_result_t +isc_mem_create2(size_t init_max_size, size_t target_size, isc_mem_t **mctxp, + unsigned int flags) +{ + isc_result_t result; + + LOCK(&createlock); + + REQUIRE(mem_createfunc != NULL); + result = (*mem_createfunc)(init_max_size, target_size, mctxp, flags); + + UNLOCK(&createlock); + + return (result); +} + +void +isc_mem_attach(isc_mem_t *source, isc_mem_t **targetp) { + REQUIRE(ISCAPI_MCTX_VALID(source)); + REQUIRE(targetp != NULL && *targetp == NULL); + + source->methods->attach(source, targetp); + + ENSURE(*targetp == source); +} + +void +isc_mem_detach(isc_mem_t **mctxp) { + REQUIRE(mctxp != NULL && ISCAPI_MCTX_VALID(*mctxp)); + + (*mctxp)->methods->detach(mctxp); + + ENSURE(*mctxp == NULL); +} + +void +isc_mem_destroy(isc_mem_t **mctxp) { + REQUIRE(mctxp != NULL && ISCAPI_MCTX_VALID(*mctxp)); + + (*mctxp)->methods->destroy(mctxp); + + ENSURE(*mctxp == NULL); +} + +void * +isc__mem_get(isc_mem_t *mctx, size_t size FLARG) { + REQUIRE(ISCAPI_MCTX_VALID(mctx)); + + return (mctx->methods->memget(mctx, size FLARG_PASS)); +} + +void +isc__mem_put(isc_mem_t *mctx, void *ptr, size_t size FLARG) { + REQUIRE(ISCAPI_MCTX_VALID(mctx)); + + mctx->methods->memput(mctx, ptr, size FLARG_PASS); +} + +void +isc__mem_putanddetach(isc_mem_t **mctxp, void *ptr, size_t size FLARG) { + REQUIRE(mctxp != NULL && ISCAPI_MCTX_VALID(*mctxp)); + + (*mctxp)->methods->memputanddetach(mctxp, ptr, size FLARG_PASS); + + /* + * XXX: We cannot always ensure *mctxp == NULL here + * (see lib/isc/mem.c). + */ +} + +void * +isc__mem_allocate(isc_mem_t *mctx, size_t size FLARG) { + REQUIRE(ISCAPI_MCTX_VALID(mctx)); + + return (mctx->methods->memallocate(mctx, size FLARG_PASS)); +} + +void * +isc__mem_reallocate(isc_mem_t *mctx, void *ptr, size_t size FLARG) { + REQUIRE(ISCAPI_MCTX_VALID(mctx)); + + return (mctx->methods->memreallocate(mctx, ptr, size FLARG_PASS)); +} + +char * +isc__mem_strdup(isc_mem_t *mctx, const char *s FLARG) { + REQUIRE(ISCAPI_MCTX_VALID(mctx)); + + return (mctx->methods->memstrdup(mctx, s FLARG_PASS)); +} + +void +isc__mem_free(isc_mem_t *mctx, void *ptr FLARG) { + REQUIRE(ISCAPI_MCTX_VALID(mctx)); + + mctx->methods->memfree(mctx, ptr FLARG_PASS); +} + +void +isc_mem_setdestroycheck(isc_mem_t *mctx, isc_boolean_t flag) { + REQUIRE(ISCAPI_MCTX_VALID(mctx)); + + mctx->methods->setdestroycheck(mctx, flag); +} + +void +isc_mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg, + size_t hiwater, size_t lowater) +{ + REQUIRE(ISCAPI_MCTX_VALID(ctx)); + + ctx->methods->setwater(ctx, water, water_arg, hiwater, lowater); +} + +void +isc_mem_waterack(isc_mem_t *ctx, int flag) { + REQUIRE(ISCAPI_MCTX_VALID(ctx)); + + ctx->methods->waterack(ctx, flag); +} + +size_t +isc_mem_inuse(isc_mem_t *mctx) { + REQUIRE(ISCAPI_MCTX_VALID(mctx)); + + return (mctx->methods->inuse(mctx)); +} + +isc_boolean_t +isc_mem_isovermem(isc_mem_t *mctx) { + REQUIRE(ISCAPI_MCTX_VALID(mctx)); + + return (mctx->methods->isovermem(mctx)); +} + +void +isc_mem_setname(isc_mem_t *mctx, const char *name, void *tag) { + REQUIRE(ISCAPI_MCTX_VALID(mctx)); + + UNUSED(name); + UNUSED(tag); + + return; +} + +const char * +isc_mem_getname(isc_mem_t *mctx) { + REQUIRE(ISCAPI_MCTX_VALID(mctx)); + + return (""); +} + +void * +isc_mem_gettag(isc_mem_t *mctx) { + REQUIRE(ISCAPI_MCTX_VALID(mctx)); + + return (NULL); +} + +isc_result_t +isc_mempool_create(isc_mem_t *mctx, size_t size, isc_mempool_t **mpctxp) { + REQUIRE(ISCAPI_MCTX_VALID(mctx)); + + return (mctx->methods->mpcreate(mctx, size, mpctxp)); +} + +void +isc_mempool_destroy(isc_mempool_t **mpctxp) { + REQUIRE(mpctxp != NULL && ISCAPI_MPOOL_VALID(*mpctxp)); + + (*mpctxp)->methods->destroy(mpctxp); + + ENSURE(*mpctxp == NULL); +} + +void * +isc__mempool_get(isc_mempool_t *mpctx FLARG) { + REQUIRE(ISCAPI_MPOOL_VALID(mpctx)); + + return (mpctx->methods->get(mpctx FLARG_PASS)); +} + +void +isc__mempool_put(isc_mempool_t *mpctx, void *mem FLARG) { + REQUIRE(ISCAPI_MPOOL_VALID(mpctx)); + + mpctx->methods->put(mpctx, mem FLARG_PASS); +} + +unsigned int +isc_mempool_getallocated(isc_mempool_t *mpctx) { + REQUIRE(ISCAPI_MPOOL_VALID(mpctx)); + + return (mpctx->methods->getallocated(mpctx)); +} + +void +isc_mempool_setmaxalloc(isc_mempool_t *mpctx, unsigned int limit) { + REQUIRE(ISCAPI_MPOOL_VALID(mpctx)); + + mpctx->methods->setmaxalloc(mpctx, limit); +} + +void +isc_mempool_setfreemax(isc_mempool_t *mpctx, unsigned int limit) { + REQUIRE(ISCAPI_MPOOL_VALID(mpctx)); + + mpctx->methods->setfreemax(mpctx, limit); +} + +void +isc_mempool_setname(isc_mempool_t *mpctx, const char *name) { + REQUIRE(ISCAPI_MPOOL_VALID(mpctx)); + + mpctx->methods->setname(mpctx, name); +} + +void +isc_mempool_associatelock(isc_mempool_t *mpctx, isc_mutex_t *lock) { + REQUIRE(ISCAPI_MPOOL_VALID(mpctx)); + + mpctx->methods->associatelock(mpctx, lock); +} + +void +isc_mempool_setfillcount(isc_mempool_t *mpctx, unsigned int limit) { + REQUIRE(ISCAPI_MPOOL_VALID(mpctx)); + + mpctx->methods->setfillcount(mpctx, limit); +} diff --git a/contrib/ntp/lib/isc/mips/include/isc/atomic.h b/contrib/ntp/lib/isc/mips/include/isc/atomic.h new file mode 100644 index 0000000..bb739f7 --- /dev/null +++ b/contrib/ntp/lib/isc/mips/include/isc/atomic.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: atomic.h,v 1.3 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_ATOMIC_H +#define ISC_ATOMIC_H 1 + +#include <isc/platform.h> +#include <isc/types.h> + +#ifdef ISC_PLATFORM_USEGCCASM +/* + * This routine atomically increments the value stored in 'p' by 'val', and + * returns the previous value. + */ +static inline isc_int32_t +isc_atomic_xadd(isc_int32_t *p, int val) { + isc_int32_t orig; + + /* add is a cheat, since MIPS has no mov instruction */ + __asm__ volatile ( + "1:" + "ll $3, %1\n" + "add %0, $0, $3\n" + "add $3, $3, %2\n" + "sc $3, %1\n" + "beq $3, 0, 1b" + : "=&r"(orig) + : "m"(*p), "r"(val) + : "memory", "$3" + ); + + return (orig); +} + +/* + * This routine atomically stores the value 'val' in 'p'. + */ +static inline void +isc_atomic_store(isc_int32_t *p, isc_int32_t val) { + __asm__ volatile ( + "1:" + "ll $3, %0\n" + "add $3, $0, %1\n" + "sc $3, %0\n" + "beq $3, 0, 1b" + : + : "m"(*p), "r"(val) + : "memory", "$3" + ); +} + +/* + * This routine atomically replaces the value in 'p' with 'val', if the + * original value is equal to 'cmpval'. The original value is returned in any + * case. + */ +static inline isc_int32_t +isc_atomic_cmpxchg(isc_int32_t *p, int cmpval, int val) { + isc_int32_t orig; + + __asm__ volatile( + "1:" + "ll $3, %1\n" + "add %0, $0, $3\n" + "bne $3, %2, 2f\n" + "add $3, $0, %3\n" + "sc $3, %1\n" + "beq $3, 0, 1b\n" + "2:" + : "=&r"(orig) + : "m"(*p), "r"(cmpval), "r"(val) + : "memory", "$3" + ); + + return (orig); +} + +#else /* !ISC_PLATFORM_USEGCCASM */ + +#error "unsupported compiler. disable atomic ops by --disable-atomic" + +#endif +#endif /* ISC_ATOMIC_H */ diff --git a/contrib/ntp/lib/isc/mutexblock.c b/contrib/ntp/lib/isc/mutexblock.c new file mode 100644 index 0000000..d41e9d2 --- /dev/null +++ b/contrib/ntp/lib/isc/mutexblock.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/*! \file */ + +#include <config.h> + +#include <isc/mutexblock.h> +#include <isc/util.h> + +isc_result_t +isc_mutexblock_init(isc_mutex_t *block, unsigned int count) { + isc_result_t result; + unsigned int i; + + for (i = 0; i < count; i++) { + result = isc_mutex_init(&block[i]); + if (result != ISC_R_SUCCESS) { + while (i > 0U) { + i--; + DESTROYLOCK(&block[i]); + } + return (result); + } + } + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_mutexblock_destroy(isc_mutex_t *block, unsigned int count) { + isc_result_t result; + unsigned int i; + + for (i = 0; i < count; i++) { + result = isc_mutex_destroy(&block[i]); + if (result != ISC_R_SUCCESS) + return (result); + } + + return (ISC_R_SUCCESS); +} diff --git a/contrib/ntp/lib/isc/netaddr.c b/contrib/ntp/lib/isc/netaddr.c new file mode 100644 index 0000000..457576b --- /dev/null +++ b/contrib/ntp/lib/isc/netaddr.c @@ -0,0 +1,436 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2010-2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/*! \file */ + +#include <config.h> + +#include <stdio.h> + +#include <isc/buffer.h> +#include <isc/msgs.h> +#include <isc/net.h> +#include <isc/netaddr.h> +#include <isc/print.h> +#include <isc/sockaddr.h> +#include <isc/string.h> +#include <isc/util.h> +#include "ntp_stdlib.h" /* NTP change for strlcpy, strlcat */ + +isc_boolean_t +isc_netaddr_equal(const isc_netaddr_t *a, const isc_netaddr_t *b) { + REQUIRE(a != NULL && b != NULL); + + if (a->family != b->family) + return (ISC_FALSE); + + if (a->zone != b->zone) + return (ISC_FALSE); + + switch (a->family) { + case AF_INET: + if (a->type.in.s_addr != b->type.in.s_addr) + return (ISC_FALSE); + break; + case AF_INET6: + if (memcmp(&a->type.in6, &b->type.in6, + sizeof(a->type.in6)) != 0 || + a->zone != b->zone) + return (ISC_FALSE); + break; +#ifdef ISC_PLATFORM_HAVESYSUNH + case AF_UNIX: + if (strcmp(a->type.un, b->type.un) != 0) + return (ISC_FALSE); + break; +#endif + default: + return (ISC_FALSE); + } + return (ISC_TRUE); +} + +isc_boolean_t +isc_netaddr_eqprefix(const isc_netaddr_t *a, const isc_netaddr_t *b, + unsigned int prefixlen) +{ + const unsigned char *pa = NULL, *pb = NULL; + unsigned int ipabytes = 0; /* Length of whole IP address in bytes */ + unsigned int nbytes; /* Number of significant whole bytes */ + unsigned int nbits; /* Number of significant leftover bits */ + + REQUIRE(a != NULL && b != NULL); + + if (a->family != b->family) + return (ISC_FALSE); + + if (a->zone != b->zone && b->zone != 0) + return (ISC_FALSE); + + switch (a->family) { + case AF_INET: + pa = (const unsigned char *) &a->type.in; + pb = (const unsigned char *) &b->type.in; + ipabytes = 4; + break; + case AF_INET6: + pa = (const unsigned char *) &a->type.in6; + pb = (const unsigned char *) &b->type.in6; + ipabytes = 16; + break; + default: + return (ISC_FALSE); + } + + /* + * Don't crash if we get a pattern like 10.0.0.1/9999999. + */ + if (prefixlen > ipabytes * 8) + prefixlen = ipabytes * 8; + + nbytes = prefixlen / 8; + nbits = prefixlen % 8; + + if (nbytes > 0) { + if (memcmp(pa, pb, nbytes) != 0) + return (ISC_FALSE); + } + if (nbits > 0) { + unsigned int bytea, byteb, mask; + INSIST(nbytes < ipabytes); + INSIST(nbits < 8); + bytea = pa[nbytes]; + byteb = pb[nbytes]; + mask = (0xFF << (8-nbits)) & 0xFF; + if ((bytea & mask) != (byteb & mask)) + return (ISC_FALSE); + } + return (ISC_TRUE); +} + +isc_result_t +isc_netaddr_totext(const isc_netaddr_t *netaddr, isc_buffer_t *target) { + char abuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")]; + char zbuf[sizeof("%4294967295")]; + unsigned int alen; + int zlen; + const char *r; + const void *type; + + REQUIRE(netaddr != NULL); + + switch (netaddr->family) { + case AF_INET: + type = &netaddr->type.in; + break; + case AF_INET6: + type = &netaddr->type.in6; + break; +#ifdef ISC_PLATFORM_HAVESYSUNH + case AF_UNIX: + alen = strlen(netaddr->type.un); + if (alen > isc_buffer_availablelength(target)) + return (ISC_R_NOSPACE); + isc_buffer_putmem(target, + (const unsigned char *)(netaddr->type.un), + alen); + return (ISC_R_SUCCESS); +#endif + default: + return (ISC_R_FAILURE); + } + r = inet_ntop(netaddr->family, type, abuf, sizeof(abuf)); + if (r == NULL) + return (ISC_R_FAILURE); + + alen = strlen(abuf); + INSIST(alen < sizeof(abuf)); + + zlen = 0; + if (netaddr->family == AF_INET6 && netaddr->zone != 0) { + zlen = snprintf(zbuf, sizeof(zbuf), "%%%u", netaddr->zone); + if (zlen < 0) + return (ISC_R_FAILURE); + INSIST((unsigned int)zlen < sizeof(zbuf)); + } + + if (alen + zlen > isc_buffer_availablelength(target)) + return (ISC_R_NOSPACE); + + isc_buffer_putmem(target, (unsigned char *)abuf, alen); + isc_buffer_putmem(target, (unsigned char *)zbuf, zlen); + + return (ISC_R_SUCCESS); +} + +void +isc_netaddr_format(const isc_netaddr_t *na, char *array, unsigned int size) { + isc_result_t result; + isc_buffer_t buf; + + isc_buffer_init(&buf, array, size); + result = isc_netaddr_totext(na, &buf); + + if (size == 0) + return; + + /* + * Null terminate. + */ + if (result == ISC_R_SUCCESS) { + if (isc_buffer_availablelength(&buf) >= 1) + isc_buffer_putuint8(&buf, 0); + else + result = ISC_R_NOSPACE; + } + + if (result != ISC_R_SUCCESS) { + snprintf(array, size, + "<%s %u>", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR, + ISC_MSG_UNKNOWNADDR, + "unknown address, family"), + na->family); + array[size - 1] = '\0'; + } +} + + +isc_result_t +isc_netaddr_prefixok(const isc_netaddr_t *na, unsigned int prefixlen) { + static const unsigned char zeros[16] = { 0 }; + unsigned int nbits, nbytes, ipbytes = 0; + const unsigned char *p; + + switch (na->family) { + case AF_INET: + p = (const unsigned char *) &na->type.in; + ipbytes = 4; + if (prefixlen > 32) + return (ISC_R_RANGE); + break; + case AF_INET6: + p = (const unsigned char *) &na->type.in6; + ipbytes = 16; + if (prefixlen > 128) + return (ISC_R_RANGE); + break; + default: + return (ISC_R_NOTIMPLEMENTED); + } + nbytes = prefixlen / 8; + nbits = prefixlen % 8; + if (nbits != 0) { + if ((p[nbytes] & (0xff>>nbits)) != 0U) + return (ISC_R_FAILURE); + nbytes++; + } + if (memcmp(p + nbytes, zeros, ipbytes - nbytes) != 0) + return (ISC_R_FAILURE); + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_netaddr_masktoprefixlen(const isc_netaddr_t *s, unsigned int *lenp) { + unsigned int nbits = 0, nbytes = 0, ipbytes = 0, i; + const unsigned char *p; + + switch (s->family) { + case AF_INET: + p = (const unsigned char *) &s->type.in; + ipbytes = 4; + break; + case AF_INET6: + p = (const unsigned char *) &s->type.in6; + ipbytes = 16; + break; + default: + return (ISC_R_NOTIMPLEMENTED); + } + for (i = 0; i < ipbytes; i++) { + if (p[i] != 0xFF) + break; + } + nbytes = i; + if (i < ipbytes) { + unsigned int c = p[nbytes]; + while ((c & 0x80) != 0 && nbits < 8) { + c <<= 1; nbits++; + } + if ((c & 0xFF) != 0) + return (ISC_R_MASKNONCONTIG); + i++; + } + for (; i < ipbytes; i++) { + if (p[i] != 0) + return (ISC_R_MASKNONCONTIG); + i++; + } + *lenp = nbytes * 8 + nbits; + return (ISC_R_SUCCESS); +} + +void +isc_netaddr_fromin(isc_netaddr_t *netaddr, const struct in_addr *ina) { + memset(netaddr, 0, sizeof(*netaddr)); + netaddr->family = AF_INET; + netaddr->type.in = *ina; +} + +void +isc_netaddr_fromin6(isc_netaddr_t *netaddr, const struct in6_addr *ina6) { + memset(netaddr, 0, sizeof(*netaddr)); + netaddr->family = AF_INET6; + netaddr->type.in6 = *ina6; +} + +isc_result_t +isc_netaddr_frompath(isc_netaddr_t *netaddr, const char *path) { +#ifdef ISC_PLATFORM_HAVESYSUNH + if (strlen(path) > sizeof(netaddr->type.un) - 1) + return (ISC_R_NOSPACE); + + memset(netaddr, 0, sizeof(*netaddr)); + netaddr->family = AF_UNIX; + strlcpy(netaddr->type.un, path, sizeof(netaddr->type.un)); + netaddr->zone = 0; + return (ISC_R_SUCCESS); +#else + UNUSED(netaddr); + UNUSED(path); + return (ISC_R_NOTIMPLEMENTED); +#endif +} + + +void +isc_netaddr_setzone(isc_netaddr_t *netaddr, isc_uint32_t zone) { + /* we currently only support AF_INET6. */ + REQUIRE(netaddr->family == AF_INET6); + + netaddr->zone = zone; +} + +isc_uint32_t +isc_netaddr_getzone(const isc_netaddr_t *netaddr) { + return (netaddr->zone); +} + +void +isc_netaddr_fromsockaddr(isc_netaddr_t *t, const isc_sockaddr_t *s) { + int family = s->type.sa.sa_family; + t->family = family; + switch (family) { + case AF_INET: + t->type.in = s->type.sin.sin_addr; + t->zone = 0; + break; + case AF_INET6: + memcpy(&t->type.in6, &s->type.sin6.sin6_addr, 16); +#ifdef ISC_PLATFORM_HAVESCOPEID + t->zone = s->type.sin6.sin6_scope_id; +#else + t->zone = 0; +#endif + break; +#ifdef ISC_PLATFORM_HAVESYSUNH + case AF_UNIX: + memcpy(t->type.un, s->type.sunix.sun_path, sizeof(t->type.un)); + t->zone = 0; + break; +#endif + default: + INSIST(0); + } +} + +void +isc_netaddr_any(isc_netaddr_t *netaddr) { + memset(netaddr, 0, sizeof(*netaddr)); + netaddr->family = AF_INET; + netaddr->type.in.s_addr = INADDR_ANY; +} + +void +isc_netaddr_any6(isc_netaddr_t *netaddr) { + memset(netaddr, 0, sizeof(*netaddr)); + netaddr->family = AF_INET6; + netaddr->type.in6 = in6addr_any; +} + +isc_boolean_t +isc_netaddr_ismulticast(isc_netaddr_t *na) { + switch (na->family) { + case AF_INET: + return (ISC_TF(ISC_IPADDR_ISMULTICAST(na->type.in.s_addr))); + case AF_INET6: + return (ISC_TF(IN6_IS_ADDR_MULTICAST(&na->type.in6))); + default: + return (ISC_FALSE); /* XXXMLG ? */ + } +} + +isc_boolean_t +isc_netaddr_isexperimental(isc_netaddr_t *na) { + switch (na->family) { + case AF_INET: + return (ISC_TF(ISC_IPADDR_ISEXPERIMENTAL(na->type.in.s_addr))); + default: + return (ISC_FALSE); /* XXXMLG ? */ + } +} + +isc_boolean_t +isc_netaddr_islinklocal(isc_netaddr_t *na) { + switch (na->family) { + case AF_INET: + return (ISC_FALSE); + case AF_INET6: + return (ISC_TF(IN6_IS_ADDR_LINKLOCAL(&na->type.in6))); + default: + return (ISC_FALSE); + } +} + +isc_boolean_t +isc_netaddr_issitelocal(isc_netaddr_t *na) { + switch (na->family) { + case AF_INET: + return (ISC_FALSE); + case AF_INET6: + return (ISC_TF(IN6_IS_ADDR_SITELOCAL(&na->type.in6))); + default: + return (ISC_FALSE); + } +} + +void +isc_netaddr_fromv4mapped(isc_netaddr_t *t, const isc_netaddr_t *s) { + isc_netaddr_t *src; + + DE_CONST(s, src); /* Must come before IN6_IS_ADDR_V4MAPPED. */ + + REQUIRE(s->family == AF_INET6); + REQUIRE(IN6_IS_ADDR_V4MAPPED(&src->type.in6)); + + memset(t, 0, sizeof(*t)); + t->family = AF_INET; + memcpy(&t->type.in, (char *)&src->type.in6 + 12, 4); + return; +} diff --git a/contrib/ntp/lib/isc/netscope.c b/contrib/ntp/lib/isc/netscope.c new file mode 100644 index 0000000..9aa11db --- /dev/null +++ b/contrib/ntp/lib/isc/netscope.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/*! \file */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char rcsid[] = + "$Id: netscope.c,v 1.13 2007/06/19 23:47:17 tbox Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <config.h> + +#include <isc/string.h> +#include <isc/net.h> +#include <isc/netscope.h> +#include <isc/result.h> + +isc_result_t +isc_netscope_pton(int af, char *scopename, void *addr, isc_uint32_t *zoneid) { + char *ep; +#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX + unsigned int ifid; +#endif + struct in6_addr *in6; + isc_uint32_t zone; + isc_uint64_t llz; + + /* at this moment, we only support AF_INET6 */ + if (af != AF_INET6) + return (ISC_R_FAILURE); + + in6 = (struct in6_addr *)addr; + + /* + * Basically, "names" are more stable than numeric IDs in terms of + * renumbering, and are more preferred. However, since there is no + * standard naming convention and APIs to deal with the names. Thus, + * we only handle the case of link-local addresses, for which we use + * interface names as link names, assuming one to one mapping between + * interfaces and links. + */ +#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX + if (IN6_IS_ADDR_LINKLOCAL(in6) && + (ifid = if_nametoindex((const char *)scopename)) != 0) + zone = (isc_uint32_t)ifid; + else { +#endif + llz = isc_string_touint64(scopename, &ep, 10); + if (ep == scopename) + return (ISC_R_FAILURE); + + /* check overflow */ + zone = (isc_uint32_t)(llz & 0xffffffffUL); + if (zone != llz) + return (ISC_R_FAILURE); +#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX + } +#endif + + *zoneid = zone; + return (ISC_R_SUCCESS); +} diff --git a/contrib/ntp/lib/isc/nls/msgcat.c b/contrib/ntp/lib/isc/nls/msgcat.c new file mode 100644 index 0000000..3d6b676 --- /dev/null +++ b/contrib/ntp/lib/isc/nls/msgcat.c @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: msgcat.c,v 1.18 2007/06/19 23:47:18 tbox Exp $ */ + +/*! \file msgcat.c + * + * \author Principal Author: Bob Halley + */ + +#include <config.h> + +#include <stddef.h> +#include <stdlib.h> + +#include <isc/magic.h> +#include <isc/msgcat.h> +#include <isc/util.h> + +#ifdef HAVE_CATGETS +#include <nl_types.h> /* Required for nl_catd. */ +#endif + +/* + * Implementation Notes: + * + * We use malloc() and free() instead of isc_mem_get() and isc_mem_put() + * because we don't want to require a memory context to be specified + * in order to use a message catalog. + */ + +struct isc_msgcat { + unsigned int magic; +#ifdef HAVE_CATGETS + nl_catd catalog; +#endif +}; + +#define MSGCAT_MAGIC ISC_MAGIC('M', 'C', 'a', 't') +#define VALID_MSGCAT(m) ISC_MAGIC_VALID(m, MSGCAT_MAGIC) + +void +isc_msgcat_open(const char *name, isc_msgcat_t **msgcatp) { + isc_msgcat_t *msgcat; + + /* + * Open a message catalog. + */ + + REQUIRE(name != NULL); + REQUIRE(msgcatp != NULL && *msgcatp == NULL); + + msgcat = malloc(sizeof(*msgcat)); + if (msgcat == NULL) { + *msgcatp = NULL; + return; + } + +#ifdef HAVE_CATGETS + /* + * We don't check if catopen() fails because we don't care. + * If it does fail, then when we call catgets(), it will use + * the default string. + */ + msgcat->catalog = catopen(name, 0); +#endif + msgcat->magic = MSGCAT_MAGIC; + + *msgcatp = msgcat; +} + +void +isc_msgcat_close(isc_msgcat_t **msgcatp) { + isc_msgcat_t *msgcat; + + /* + * Close a message catalog. + */ + + REQUIRE(msgcatp != NULL); + msgcat = *msgcatp; + REQUIRE(VALID_MSGCAT(msgcat) || msgcat == NULL); + + if (msgcat != NULL) { +#ifdef HAVE_CATGETS + if (msgcat->catalog != (nl_catd)(-1)) + (void)catclose(msgcat->catalog); +#endif + msgcat->magic = 0; + free(msgcat); + } + + *msgcatp = NULL; +} + +const char * +isc_msgcat_get(isc_msgcat_t *msgcat, int set, int message, + const char *default_text) +{ + /* + * Get message 'message' from message set 'set' in 'msgcat'. If it + * is not available, use 'default'. + */ + + REQUIRE(VALID_MSGCAT(msgcat) || msgcat == NULL); + REQUIRE(set > 0); + REQUIRE(message > 0); + REQUIRE(default_text != NULL); + +#ifdef HAVE_CATGETS + if (msgcat == NULL) + return (default_text); + return (catgets(msgcat->catalog, set, message, default_text)); +#else + return (default_text); +#endif +} diff --git a/contrib/ntp/lib/isc/noatomic/include/isc/atomic.h b/contrib/ntp/lib/isc/noatomic/include/isc/atomic.h new file mode 100644 index 0000000..942ba03 --- /dev/null +++ b/contrib/ntp/lib/isc/noatomic/include/isc/atomic.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: atomic.h,v 1.4 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_ATOMIC_H +#define ISC_ATOMIC_H 1 + +/* This file is inherently empty. */ + +#endif /* ISC_ATOMIC_H */ diff --git a/contrib/ntp/lib/isc/nothreads/condition.c b/contrib/ntp/lib/isc/nothreads/condition.c new file mode 100644 index 0000000..9be8f83 --- /dev/null +++ b/contrib/ntp/lib/isc/nothreads/condition.c @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2004, 2006, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: condition.c,v 1.10 2007/06/19 23:47:18 tbox Exp $ */ + +#include <config.h> + +#include <isc/util.h> + +EMPTY_TRANSLATION_UNIT diff --git a/contrib/ntp/lib/isc/nothreads/include/isc/condition.h b/contrib/ntp/lib/isc/nothreads/include/isc/condition.h new file mode 100644 index 0000000..b269f82 --- /dev/null +++ b/contrib/ntp/lib/isc/nothreads/include/isc/condition.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: condition.h,v 1.6 2007/06/19 23:47:18 tbox Exp $ */ + +/* + * This provides a limited subset of the isc_condition_t + * functionality for use by single-threaded programs that + * need to block waiting for events. Only a single + * call to isc_condition_wait() may be blocked at any given + * time, and the _waituntil and _broadcast functions are not + * supported. This is intended primarily for use by the omapi + * library, and may go away once omapi goes away. Use for + * other purposes is strongly discouraged. + */ + +#ifndef ISC_CONDITION_H +#define ISC_CONDITION_H 1 + +#include <isc/mutex.h> + +typedef int isc_condition_t; + +isc_result_t isc__nothread_wait_hack(isc_condition_t *cp, isc_mutex_t *mp); +isc_result_t isc__nothread_signal_hack(isc_condition_t *cp); + +#define isc_condition_init(cp) \ + (*(cp) = 0, ISC_R_SUCCESS) + +#define isc_condition_wait(cp, mp) \ + isc__nothread_wait_hack(cp, mp) + +#define isc_condition_waituntil(cp, mp, tp) \ + ((void)(cp), (void)(mp), (void)(tp), ISC_R_NOTIMPLEMENTED) + +#define isc_condition_signal(cp) \ + isc__nothread_signal_hack(cp) + +#define isc_condition_broadcast(cp) \ + ((void)(cp), ISC_R_NOTIMPLEMENTED) + +#define isc_condition_destroy(cp) \ + (*(cp) == 0 ? (*(cp) = -1, ISC_R_SUCCESS) : ISC_R_UNEXPECTED) + +#endif /* ISC_CONDITION_H */ diff --git a/contrib/ntp/lib/isc/nothreads/include/isc/mutex.h b/contrib/ntp/lib/isc/nothreads/include/isc/mutex.h new file mode 100644 index 0000000..1f2187b --- /dev/null +++ b/contrib/ntp/lib/isc/nothreads/include/isc/mutex.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: mutex.h,v 1.6 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_MUTEX_H +#define ISC_MUTEX_H 1 + +#include <isc/result.h> /* for ISC_R_ codes */ + +typedef int isc_mutex_t; + +#define isc_mutex_init(mp) \ + (*(mp) = 0, ISC_R_SUCCESS) +#define isc_mutex_lock(mp) \ + ((*(mp))++ == 0 ? ISC_R_SUCCESS : ISC_R_UNEXPECTED) +#define isc_mutex_unlock(mp) \ + (--(*(mp)) == 0 ? ISC_R_SUCCESS : ISC_R_UNEXPECTED) +#define isc_mutex_trylock(mp) \ + (*(mp) == 0 ? ((*(mp))++, ISC_R_SUCCESS) : ISC_R_LOCKBUSY) +#define isc_mutex_destroy(mp) \ + (*(mp) == 0 ? (*(mp) = -1, ISC_R_SUCCESS) : ISC_R_UNEXPECTED) +#define isc_mutex_stats(fp) + +#endif /* ISC_MUTEX_H */ diff --git a/contrib/ntp/lib/isc/nothreads/include/isc/once.h b/contrib/ntp/lib/isc/nothreads/include/isc/once.h new file mode 100644 index 0000000..ab705a4 --- /dev/null +++ b/contrib/ntp/lib/isc/nothreads/include/isc/once.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: once.h,v 1.6 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_ONCE_H +#define ISC_ONCE_H 1 + +#include <isc/result.h> + +typedef isc_boolean_t isc_once_t; + +#define ISC_ONCE_INIT ISC_FALSE + +#define isc_once_do(op, f) \ + (!*(op) ? (f(), *(op) = ISC_TRUE, ISC_R_SUCCESS) : ISC_R_SUCCESS) + +#endif /* ISC_ONCE_H */ diff --git a/contrib/ntp/lib/isc/nothreads/include/isc/thread.h b/contrib/ntp/lib/isc/nothreads/include/isc/thread.h new file mode 100644 index 0000000..313bc5f --- /dev/null +++ b/contrib/ntp/lib/isc/nothreads/include/isc/thread.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: thread.h,v 1.6 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_THREAD_H +#define ISC_THREAD_H 1 + +#include <isc/lang.h> +#include <isc/result.h> + +ISC_LANG_BEGINDECLS + +void +isc_thread_setconcurrency(unsigned int level); + +#define isc_thread_self() ((unsigned long)0) + +ISC_LANG_ENDDECLS + +#endif /* ISC_THREAD_H */ diff --git a/contrib/ntp/lib/isc/nothreads/mutex.c b/contrib/ntp/lib/isc/nothreads/mutex.c new file mode 100644 index 0000000..50ba0f4 --- /dev/null +++ b/contrib/ntp/lib/isc/nothreads/mutex.c @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2004, 2006, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: mutex.c,v 1.10 2007/06/19 23:47:18 tbox Exp $ */ + +#include <config.h> + +#include <isc/util.h> + +EMPTY_TRANSLATION_UNIT + diff --git a/contrib/ntp/lib/isc/nothreads/thread.c b/contrib/ntp/lib/isc/nothreads/thread.c new file mode 100644 index 0000000..9075e25 --- /dev/null +++ b/contrib/ntp/lib/isc/nothreads/thread.c @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: thread.c,v 1.5 2007/06/19 23:47:18 tbox Exp $ */ + +#include <config.h> + +#include <isc/thread.h> +#include <isc/util.h> + +void +isc_thread_setconcurrency(unsigned int level) { + UNUSED(level); +} diff --git a/contrib/ntp/lib/isc/ondestroy.c b/contrib/ntp/lib/isc/ondestroy.c new file mode 100644 index 0000000..32a75e1 --- /dev/null +++ b/contrib/ntp/lib/isc/ondestroy.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: ondestroy.c,v 1.16 2007/06/19 23:47:17 tbox Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <stddef.h> + +#include <isc/event.h> +#include <isc/magic.h> +#include <isc/ondestroy.h> +#include <isc/task.h> +#include <isc/util.h> + +#define ONDESTROY_MAGIC ISC_MAGIC('D', 'e', 'S', 't') +#define VALID_ONDESTROY(s) ISC_MAGIC_VALID(s, ONDESTROY_MAGIC) + +void +isc_ondestroy_init(isc_ondestroy_t *ondest) { + ondest->magic = ONDESTROY_MAGIC; + ISC_LIST_INIT(ondest->events); +} + +isc_result_t +isc_ondestroy_register(isc_ondestroy_t *ondest, isc_task_t *task, + isc_event_t **eventp) +{ + isc_event_t *theevent; + isc_task_t *thetask = NULL; + + REQUIRE(VALID_ONDESTROY(ondest)); + REQUIRE(task != NULL); + REQUIRE(eventp != NULL); + + theevent = *eventp; + + REQUIRE(theevent != NULL); + + isc_task_attach(task, &thetask); + + theevent->ev_sender = thetask; + + ISC_LIST_APPEND(ondest->events, theevent, ev_link); + + return (ISC_R_SUCCESS); +} + +void +isc_ondestroy_notify(isc_ondestroy_t *ondest, void *sender) { + isc_event_t *eventp; + isc_task_t *task; + + REQUIRE(VALID_ONDESTROY(ondest)); + + eventp = ISC_LIST_HEAD(ondest->events); + while (eventp != NULL) { + ISC_LIST_UNLINK(ondest->events, eventp, ev_link); + + task = eventp->ev_sender; + eventp->ev_sender = sender; + + isc_task_sendanddetach(&task, &eventp); + + eventp = ISC_LIST_HEAD(ondest->events); + } +} + + diff --git a/contrib/ntp/lib/isc/parseint.c b/contrib/ntp/lib/isc/parseint.c new file mode 100644 index 0000000..266d44c --- /dev/null +++ b/contrib/ntp/lib/isc/parseint.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001-2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: parseint.c,v 1.8 2007/06/19 23:47:17 tbox Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <ctype.h> +#include <errno.h> +#include <limits.h> + +#include <isc/parseint.h> +#include <isc/result.h> +#include <isc/stdlib.h> + +isc_result_t +isc_parse_uint32(isc_uint32_t *uip, const char *string, int base) { + unsigned long n; + char *e; + if (! isalnum((unsigned char)(string[0]))) + return (ISC_R_BADNUMBER); + errno = 0; + n = strtoul(string, &e, base); + if (*e != '\0') + return (ISC_R_BADNUMBER); + if (n == ULONG_MAX && errno == ERANGE) + return (ISC_R_RANGE); + *uip = n; + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_parse_uint16(isc_uint16_t *uip, const char *string, int base) { + isc_uint32_t val; + isc_result_t result; + result = isc_parse_uint32(&val, string, base); + if (result != ISC_R_SUCCESS) + return (result); + if (val > 0xFFFF) + return (ISC_R_RANGE); + *uip = (isc_uint16_t) val; + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_parse_uint8(isc_uint8_t *uip, const char *string, int base) { + isc_uint32_t val; + isc_result_t result; + result = isc_parse_uint32(&val, string, base); + if (result != ISC_R_SUCCESS) + return (result); + if (val > 0xFF) + return (ISC_R_RANGE); + *uip = (isc_uint8_t) val; + return (ISC_R_SUCCESS); +} diff --git a/contrib/ntp/lib/isc/portset.c b/contrib/ntp/lib/isc/portset.c new file mode 100644 index 0000000..471ca8e --- /dev/null +++ b/contrib/ntp/lib/isc/portset.c @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2008 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: portset.c,v 1.4 2008/06/24 23:24:35 marka Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <isc/mem.h> +#include <isc/portset.h> +#include <isc/string.h> +#include <isc/types.h> +#include <isc/util.h> + +#define ISC_PORTSET_BUFSIZE (65536 / (sizeof(isc_uint32_t) * 8)) + +/*% + * Internal representation of portset. It's an array of 32-bit integers, each + * bit corresponding to a single port in the ascending order. For example, + * the second most significant bit of buf[0] corresponds to port 1. + */ +struct isc_portset { + unsigned int nports; /*%< number of ports in the set */ + isc_uint32_t buf[ISC_PORTSET_BUFSIZE]; +}; + +static inline isc_boolean_t +portset_isset(isc_portset_t *portset, in_port_t port) { + return (ISC_TF((portset->buf[port >> 5] & (1 << (port & 31))) != 0)); +} + +static inline void +portset_add(isc_portset_t *portset, in_port_t port) { + if (!portset_isset(portset, port)) { + portset->nports++; + portset->buf[port >> 5] |= (1 << (port & 31)); + } +} + +static inline void +portset_remove(isc_portset_t *portset, in_port_t port) { + if (portset_isset(portset, port)) { + portset->nports--; + portset->buf[port >> 5] &= ~(1 << (port & 31)); + } +} + +isc_result_t +isc_portset_create(isc_mem_t *mctx, isc_portset_t **portsetp) { + isc_portset_t *portset; + + REQUIRE(portsetp != NULL && *portsetp == NULL); + + portset = isc_mem_get(mctx, sizeof(*portset)); + if (portset == NULL) + return (ISC_R_NOMEMORY); + + /* Make the set 'empty' by default */ + memset(portset, 0, sizeof(*portset)); + *portsetp = portset; + + return (ISC_R_SUCCESS); +} + +void +isc_portset_destroy(isc_mem_t *mctx, isc_portset_t **portsetp) { + isc_portset_t *portset; + + REQUIRE(portsetp != NULL); + portset = *portsetp; + + isc_mem_put(mctx, portset, sizeof(*portset)); +} + +isc_boolean_t +isc_portset_isset(isc_portset_t *portset, in_port_t port) { + REQUIRE(portset != NULL); + + return (portset_isset(portset, port)); +} + +unsigned int +isc_portset_nports(isc_portset_t *portset) { + REQUIRE(portset != NULL); + + return (portset->nports); +} + +void +isc_portset_add(isc_portset_t *portset, in_port_t port) { + REQUIRE(portset != NULL); + + portset_add(portset, port); +} + +void +isc_portset_remove(isc_portset_t *portset, in_port_t port) { + portset_remove(portset, port); +} + +void +isc_portset_addrange(isc_portset_t *portset, in_port_t port_lo, + in_port_t port_hi) +{ + in_port_t p; + + REQUIRE(portset != NULL); + REQUIRE(port_lo <= port_hi); + + p = port_lo; + do { + portset_add(portset, p); + } while (p++ < port_hi); +} + +void +isc_portset_removerange(isc_portset_t *portset, in_port_t port_lo, + in_port_t port_hi) +{ + in_port_t p; + + REQUIRE(portset != NULL); + REQUIRE(port_lo <= port_hi); + + p = port_lo; + do { + portset_remove(portset, p); + } while (p++ < port_hi); +} diff --git a/contrib/ntp/lib/isc/powerpc/include/isc/atomic.h b/contrib/ntp/lib/isc/powerpc/include/isc/atomic.h new file mode 100644 index 0000000..030007f --- /dev/null +++ b/contrib/ntp/lib/isc/powerpc/include/isc/atomic.h @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2005, 2007, 2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +#ifndef ISC_ATOMIC_H +#define ISC_ATOMIC_H 1 + +#include <isc/platform.h> +#include <isc/types.h> + +/*!\file + * static inline isc_int32_t + * isc_atomic_xadd(isc_int32_t *p, isc_int32_t val); + * + * This routine atomically increments the value stored in 'p' by 'val', and + * returns the previous value. + * + * static inline void + * isc_atomic_store(void *p, isc_int32_t val); + * + * This routine atomically stores the value 'val' in 'p'. + * + * static inline isc_int32_t + * isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val); + * + * This routine atomically replaces the value in 'p' with 'val', if the + * original value is equal to 'cmpval'. The original value is returned in any + * case. + */ + +#if defined(_AIX) + +#include <sys/atomic_op.h> + +#define isc_atomic_store(p, v) _clear_lock(p, v) + +#ifdef __GNUC__ +static inline isc_int32_t +#else +static isc_int32_t +#endif +isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) { + int ret; + +#ifdef __GNUC__ + asm("ics"); +#else + __isync(); +#endif + + ret = fetch_and_add((atomic_p)p, (int)val); + +#ifdef __GNUC__ + asm("ics"); +#else + __isync(); +#endif + + return (ret); +} + +#ifdef __GNUC__ +static inline int +#else +static int +#endif +isc_atomic_cmpxchg(atomic_p p, int old, int new) { + int orig = old; + +#ifdef __GNUC__ + asm("ics"); +#else + __isync(); +#endif + if (compare_and_swap(p, &orig, new)) + orig = old; + +#ifdef __GNUC__ + asm("ics"); +#else + __isync(); +#endif + + return (orig); +} + +#elif defined(ISC_PLATFORM_USEGCCASM) || defined(ISC_PLATFORM_USEMACASM) +static inline isc_int32_t +isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) { + isc_int32_t orig; + + __asm__ volatile ( +#ifdef ISC_PLATFORM_USEMACASM + "1:" + "lwarx r6, 0, %1\n" + "mr %0, r6\n" + "add r6, r6, %2\n" + "stwcx. r6, 0, %1\n" + "bne- 1b\n" + "sync" +#else + "1:" + "lwarx 6, 0, %1\n" + "mr %0, 6\n" + "add 6, 6, %2\n" + "stwcx. 6, 0, %1\n" + "bne- 1b\n" + "sync" +#endif + : "=&r"(orig) + : "r"(p), "r"(val) + : "r6", "memory" + ); + + return (orig); +} + +static inline void +isc_atomic_store(void *p, isc_int32_t val) { + __asm__ volatile ( +#ifdef ISC_PLATFORM_USEMACASM + "1:" + "lwarx r6, 0, %0\n" + "lwz r6, %1\n" + "stwcx. r6, 0, %0\n" + "bne- 1b\n" + "sync" +#else + "1:" + "lwarx 6, 0, %0\n" + "lwz 6, %1\n" + "stwcx. 6, 0, %0\n" + "bne- 1b\n" + "sync" +#endif + : + : "r"(p), "m"(val) + : "r6", "memory" + ); +} + +static inline isc_int32_t +isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) { + isc_int32_t orig; + + __asm__ volatile ( +#ifdef ISC_PLATFORM_USEMACASM + "1:" + "lwarx r6, 0, %1\n" + "mr %0,r6\n" + "cmpw r6, %2\n" + "bne 2f\n" + "mr r6, %3\n" + "stwcx. r6, 0, %1\n" + "bne- 1b\n" + "2:\n" + "sync" +#else + "1:" + "lwarx 6, 0, %1\n" + "mr %0,6\n" + "cmpw 6, %2\n" + "bne 2f\n" + "mr 6, %3\n" + "stwcx. 6, 0, %1\n" + "bne- 1b\n" + "2:\n" + "sync" +#endif + : "=&r" (orig) + : "r"(p), "r"(cmpval), "r"(val) + : "r6", "memory" + ); + + return (orig); +} + +#else + +#error "unsupported compiler. disable atomic ops by --disable-atomic" + +#endif +#endif /* ISC_ATOMIC_H */ diff --git a/contrib/ntp/lib/isc/print.c b/contrib/ntp/lib/isc/print.c new file mode 100644 index 0000000..a5e5ba6 --- /dev/null +++ b/contrib/ntp/lib/isc/print.c @@ -0,0 +1,624 @@ +/* + * Copyright (C) 2004-2008, 2010 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001, 2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: print.c,v 1.37 2010/10/18 23:47:08 tbox Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <ctype.h> +#include <stdio.h> /* for sprintf() */ +#include <string.h> /* for strlen() */ + +#define ISC__PRINT_SOURCE /* Used to get the isc_print_* prototypes. */ + +#include <isc/assertions.h> +#include <isc/int.h> +#include <isc/msgs.h> +#include <isc/print.h> +#include <isc/stdlib.h> +#include <isc/util.h> + +int +isc_print_sprintf(char *str, const char *format, ...) { + va_list ap; + + va_start(ap, format); + vsprintf(str, format, ap); + va_end(ap); + return (strlen(str)); +} + +/*! + * Return length of string that would have been written if not truncated. + */ + +int +isc_print_snprintf(char *str, size_t size, const char *format, ...) { + va_list ap; + int ret; + + va_start(ap, format); + ret = vsnprintf(str, size, format, ap); + va_end(ap); + return (ret); + +} + +/*! + * Return length of string that would have been written if not truncated. + */ + +int +isc_print_vsnprintf(char *str, size_t size, const char *format, va_list ap) { + int h; + int l; + int q; + int alt; + int zero; + int left; + int plus; + int space; + int neg; + isc_int64_t tmpi; + isc_uint64_t tmpui; + unsigned long width; + unsigned long precision; + unsigned int length; + char buf[1024]; + char c; + void *v; + char *save = str; + const char *cp; + const char *head; + int count = 0; + int pad; + int zeropad; + int dot; + double dbl; +#ifdef HAVE_LONG_DOUBLE + long double ldbl; +#endif + char fmt[32]; + + INSIST(str != NULL); + INSIST(format != NULL); + + while (*format != '\0') { + if (*format != '%') { + if (size > 1) { + *str++ = *format; + size--; + } + count++; + format++; + continue; + } + format++; + + /* + * Reset flags. + */ + dot = neg = space = plus = left = zero = alt = h = l = q = 0; + width = precision = 0; + head = ""; + length = pad = zeropad = 0; + + do { + if (*format == '#') { + alt = 1; + format++; + } else if (*format == '-') { + left = 1; + zero = 0; + format++; + } else if (*format == ' ') { + if (!plus) + space = 1; + format++; + } else if (*format == '+') { + plus = 1; + space = 0; + format++; + } else if (*format == '0') { + if (!left) + zero = 1; + format++; + } else + break; + } while (1); + + /* + * Width. + */ + if (*format == '*') { + width = va_arg(ap, int); + format++; + } else if (isdigit((unsigned char)*format)) { + char *e; + width = strtoul(format, &e, 10); + format = e; + } + + /* + * Precision. + */ + if (*format == '.') { + format++; + dot = 1; + if (*format == '*') { + precision = va_arg(ap, int); + format++; + } else if (isdigit((unsigned char)*format)) { + char *e; + precision = strtoul(format, &e, 10); + format = e; + } + } + + switch (*format) { + case '\0': + continue; + case '%': + if (size > 1) { + *str++ = *format; + size--; + } + count++; + break; + case 'q': + q = 1; + format++; + goto doint; + case 'h': + h = 1; + format++; + goto doint; + case 'l': + l = 1; + format++; + if (*format == 'l') { + q = 1; + format++; + } + goto doint; + case 'n': + case 'i': + case 'd': + case 'o': + case 'u': + case 'x': + case 'X': + doint: + if (precision != 0) + zero = 0; + switch (*format) { + case 'n': + if (h) { + short int *p; + p = va_arg(ap, short *); + REQUIRE(p != NULL); + *p = str - save; + } else if (l) { + long int *p; + p = va_arg(ap, long *); + REQUIRE(p != NULL); + *p = str - save; + } else { + int *p; + p = va_arg(ap, int *); + REQUIRE(p != NULL); + *p = str - save; + } + break; + case 'i': + case 'd': + if (q) + tmpi = va_arg(ap, isc_int64_t); + else if (l) + tmpi = va_arg(ap, long int); + else + tmpi = va_arg(ap, int); + if (tmpi < 0) { + head = "-"; + tmpui = -tmpi; + } else { + if (plus) + head = "+"; + else if (space) + head = " "; + else + head = ""; + tmpui = tmpi; + } + if (tmpui <= 0xffffffffU) + sprintf(buf, "%lu", + (unsigned long)tmpui); + else { + unsigned long mid; + unsigned long lo; + unsigned long hi; + lo = tmpui % 1000000000; + tmpui /= 1000000000; + mid = tmpui % 1000000000; + hi = tmpui / 1000000000; + if (hi != 0) + sprintf(buf, "%lu", hi); + else + buf[0] = '\n'; + sprintf(buf + strlen(buf), "%lu", mid); + sprintf(buf + strlen(buf), "%lu", lo); + } + goto printint; + case 'o': + if (q) + tmpui = va_arg(ap, isc_uint64_t); + else if (l) + tmpui = va_arg(ap, long int); + else + tmpui = va_arg(ap, int); + if (tmpui <= 0xffffffffU) + sprintf(buf, alt ? "%#lo" : "%lo", + (unsigned long)tmpui); + else { + unsigned long mid; + unsigned long lo; + unsigned long hi; + lo = tmpui % 010000000000; + tmpui /= 010000000000; + mid = tmpui % 010000000000; + hi = tmpui / 010000000000; + if (hi != 0) { + sprintf(buf, + alt ? "%#lo" : "%lo", + hi); + sprintf(buf + strlen(buf), + "%lo", mid); + } else + sprintf(buf, + alt ? "%#lo" : "%lo", + mid); + sprintf(buf + strlen(buf), "%lo", lo); + } + goto printint; + case 'u': + if (q) + tmpui = va_arg(ap, isc_uint64_t); + else if (l) + tmpui = va_arg(ap, unsigned long int); + else + tmpui = va_arg(ap, unsigned int); + if (tmpui <= 0xffffffffU) + sprintf(buf, "%lu", + (unsigned long)tmpui); + else { + unsigned long mid; + unsigned long lo; + unsigned long hi; + lo = tmpui % 1000000000; + tmpui /= 1000000000; + mid = tmpui % 1000000000; + hi = tmpui / 1000000000; + if (hi != 0) + sprintf(buf, "%lu", hi); + else + buf[0] = '\n'; + sprintf(buf + strlen(buf), "%lu", mid); + sprintf(buf + strlen(buf), "%lu", lo); + } + goto printint; + case 'x': + if (q) + tmpui = va_arg(ap, isc_uint64_t); + else if (l) + tmpui = va_arg(ap, unsigned long int); + else + tmpui = va_arg(ap, unsigned int); + if (alt) { + head = "0x"; + if (precision > 2) + precision -= 2; + } + if (tmpui <= 0xffffffffU) + sprintf(buf, "%lx", + (unsigned long)tmpui); + else { + unsigned long hi = tmpui>>32; + unsigned long lo = tmpui & 0xffffffff; + sprintf(buf, "%lx", hi); + sprintf(buf + strlen(buf), "%lx", lo); + } + goto printint; + case 'X': + if (q) + tmpui = va_arg(ap, isc_uint64_t); + else if (l) + tmpui = va_arg(ap, unsigned long int); + else + tmpui = va_arg(ap, unsigned int); + if (alt) { + head = "0X"; + if (precision > 2) + precision -= 2; + } + if (tmpui <= 0xffffffffU) + sprintf(buf, "%lX", + (unsigned long)tmpui); + else { + unsigned long hi = tmpui>>32; + unsigned long lo = tmpui & 0xffffffff; + sprintf(buf, "%lX", hi); + sprintf(buf + strlen(buf), "%lX", lo); + } + goto printint; + printint: + if (precision != 0 || width != 0) { + length = strlen(buf); + if (length < precision) + zeropad = precision - length; + else if (length < width && zero) + zeropad = width - length; + if (width != 0) { + pad = width - length - + zeropad - strlen(head); + if (pad < 0) + pad = 0; + } + } + count += strlen(head) + strlen(buf) + pad + + zeropad; + if (!left) { + while (pad > 0 && size > 1) { + *str++ = ' '; + size--; + pad--; + } + } + cp = head; + while (*cp != '\0' && size > 1) { + *str++ = *cp++; + size--; + } + while (zeropad > 0 && size > 1) { + *str++ = '0'; + size--; + zeropad--; + } + cp = buf; + while (*cp != '\0' && size > 1) { + *str++ = *cp++; + size--; + } + while (pad > 0 && size > 1) { + *str++ = ' '; + size--; + pad--; + } + break; + default: + break; + } + break; + case 's': + cp = va_arg(ap, char *); + REQUIRE(cp != NULL); + + if (precision != 0) { + /* + * cp need not be NULL terminated. + */ + const char *tp; + unsigned long n; + + n = precision; + tp = cp; + while (n != 0 && *tp != '\0') + n--, tp++; + length = precision - n; + } else { + length = strlen(cp); + } + if (width != 0) { + pad = width - length; + if (pad < 0) + pad = 0; + } + count += pad + length; + if (!left) + while (pad > 0 && size > 1) { + *str++ = ' '; + size--; + pad--; + } + if (precision != 0) + while (precision > 0 && *cp != '\0' && + size > 1) { + *str++ = *cp++; + size--; + precision--; + } + else + while (*cp != '\0' && size > 1) { + *str++ = *cp++; + size--; + } + while (pad > 0 && size > 1) { + *str++ = ' '; + size--; + pad--; + } + break; + case 'c': + c = va_arg(ap, int); + if (width > 0) { + count += width; + width--; + if (left && size > 1) { + *str++ = c; + size--; + } + while (width-- > 0 && size > 1) { + *str++ = ' '; + size--; + } + if (!left && size > 1) { + *str++ = c; + size--; + } + } else { + count++; + if (size > 1) { + *str++ = c; + size--; + } + } + break; + case 'p': + v = va_arg(ap, void *); + sprintf(buf, "%p", v); + length = strlen(buf); + if (precision > length) + zeropad = precision - length; + if (width > 0) { + pad = width - length - zeropad; + if (pad < 0) + pad = 0; + } + count += length + pad + zeropad; + if (!left) + while (pad > 0 && size > 1) { + *str++ = ' '; + size--; + pad--; + } + cp = buf; + if (zeropad > 0 && buf[0] == '0' && + (buf[1] == 'x' || buf[1] == 'X')) { + if (size > 1) { + *str++ = *cp++; + size--; + } + if (size > 1) { + *str++ = *cp++; + size--; + } + while (zeropad > 0 && size > 1) { + *str++ = '0'; + size--; + zeropad--; + } + } + while (*cp != '\0' && size > 1) { + *str++ = *cp++; + size--; + } + while (pad > 0 && size > 1) { + *str++ = ' '; + size--; + pad--; + } + break; + case 'D': /*deprecated*/ + INSIST("use %ld instead of %D" == NULL); + case 'O': /*deprecated*/ + INSIST("use %lo instead of %O" == NULL); + case 'U': /*deprecated*/ + INSIST("use %lu instead of %U" == NULL); + + case 'L': +#ifdef HAVE_LONG_DOUBLE + l = 1; +#else + INSIST("long doubles are not supported" == NULL); +#endif + /*FALLTHROUGH*/ + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + if (!dot) + precision = 6; + /* + * IEEE floating point. + * MIN 2.2250738585072014E-308 + * MAX 1.7976931348623157E+308 + * VAX floating point has a smaller range than IEEE. + * + * precisions > 324 don't make much sense. + * if we cap the precision at 512 we will not + * overflow buf. + */ + if (precision > 512) + precision = 512; + sprintf(fmt, "%%%s%s.%lu%s%c", alt ? "#" : "", + plus ? "+" : space ? " " : "", + precision, l ? "L" : "", *format); + switch (*format) { + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': +#ifdef HAVE_LONG_DOUBLE + if (l) { + ldbl = va_arg(ap, long double); + sprintf(buf, fmt, ldbl); + } else +#endif + { + dbl = va_arg(ap, double); + sprintf(buf, fmt, dbl); + } + length = strlen(buf); + if (width > 0) { + pad = width - length; + if (pad < 0) + pad = 0; + } + count += length + pad; + if (!left) + while (pad > 0 && size > 1) { + *str++ = ' '; + size--; + pad--; + } + cp = buf; + while (*cp != ' ' && size > 1) { + *str++ = *cp++; + size--; + } + while (pad > 0 && size > 1) { + *str++ = ' '; + size--; + pad--; + } + break; + default: + continue; + } + break; + default: + continue; + } + format++; + } + if (size > 0) + *str = '\0'; + return (count); +} diff --git a/contrib/ntp/lib/isc/pthreads/condition.c b/contrib/ntp/lib/isc/pthreads/condition.c new file mode 100644 index 0000000..50281a2 --- /dev/null +++ b/contrib/ntp/lib/isc/pthreads/condition.c @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: condition.c,v 1.36 2007/06/19 23:47:18 tbox Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <errno.h> + +#include <isc/condition.h> +#include <isc/msgs.h> +#include <isc/strerror.h> +#include <isc/string.h> +#include <isc/time.h> +#include <isc/util.h> + +isc_result_t +isc_condition_waituntil(isc_condition_t *c, isc_mutex_t *m, isc_time_t *t) { + int presult; + isc_result_t result; + struct timespec ts; + char strbuf[ISC_STRERRORSIZE]; + + REQUIRE(c != NULL && m != NULL && t != NULL); + + /* + * POSIX defines a timespec's tv_sec as time_t. + */ + result = isc_time_secondsastimet(t, &ts.tv_sec); + if (result != ISC_R_SUCCESS) + return (result); + + /*! + * POSIX defines a timespec's tv_nsec as long. isc_time_nanoseconds + * ensures its return value is < 1 billion, which will fit in a long. + */ + ts.tv_nsec = (long)isc_time_nanoseconds(t); + + do { +#if ISC_MUTEX_PROFILE + presult = pthread_cond_timedwait(c, &m->mutex, &ts); +#else + presult = pthread_cond_timedwait(c, m, &ts); +#endif + if (presult == 0) + return (ISC_R_SUCCESS); + if (presult == ETIMEDOUT) + return (ISC_R_TIMEDOUT); + } while (presult == EINTR); + + isc__strerror(presult, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "pthread_cond_timedwait() %s %s", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_RETURNED, "returned"), + strbuf); + return (ISC_R_UNEXPECTED); +} diff --git a/contrib/ntp/lib/isc/pthreads/include/isc/condition.h b/contrib/ntp/lib/isc/pthreads/include/isc/condition.h new file mode 100644 index 0000000..04a6118 --- /dev/null +++ b/contrib/ntp/lib/isc/pthreads/include/isc/condition.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: condition.h,v 1.26 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_CONDITION_H +#define ISC_CONDITION_H 1 + +/*! \file */ + +#include <isc/lang.h> +#include <isc/mutex.h> +#include <isc/result.h> +#include <isc/types.h> + +typedef pthread_cond_t isc_condition_t; + +#define isc_condition_init(cp) \ + ((pthread_cond_init((cp), NULL) == 0) ? \ + ISC_R_SUCCESS : ISC_R_UNEXPECTED) + +#if ISC_MUTEX_PROFILE +#define isc_condition_wait(cp, mp) \ + ((pthread_cond_wait((cp), &((mp)->mutex)) == 0) ? \ + ISC_R_SUCCESS : ISC_R_UNEXPECTED) +#else +#define isc_condition_wait(cp, mp) \ + ((pthread_cond_wait((cp), (mp)) == 0) ? \ + ISC_R_SUCCESS : ISC_R_UNEXPECTED) +#endif + +#define isc_condition_signal(cp) \ + ((pthread_cond_signal((cp)) == 0) ? \ + ISC_R_SUCCESS : ISC_R_UNEXPECTED) + +#define isc_condition_broadcast(cp) \ + ((pthread_cond_broadcast((cp)) == 0) ? \ + ISC_R_SUCCESS : ISC_R_UNEXPECTED) + +#define isc_condition_destroy(cp) \ + ((pthread_cond_destroy((cp)) == 0) ? \ + ISC_R_SUCCESS : ISC_R_UNEXPECTED) + +ISC_LANG_BEGINDECLS + +isc_result_t +isc_condition_waituntil(isc_condition_t *, isc_mutex_t *, isc_time_t *); + +ISC_LANG_ENDDECLS + +#endif /* ISC_CONDITION_H */ diff --git a/contrib/ntp/lib/isc/pthreads/include/isc/mutex.h b/contrib/ntp/lib/isc/pthreads/include/isc/mutex.h new file mode 100644 index 0000000..dd7d326 --- /dev/null +++ b/contrib/ntp/lib/isc/pthreads/include/isc/mutex.h @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: mutex.h,v 1.30 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_MUTEX_H +#define ISC_MUTEX_H 1 + +/*! \file */ + +#include <pthread.h> +#include <stdio.h> + +#include <isc/lang.h> +#include <isc/result.h> /* for ISC_R_ codes */ + +ISC_LANG_BEGINDECLS + +/*! + * Supply mutex attributes that enable deadlock detection + * (helpful when debugging). This is system dependent and + * currently only supported on NetBSD. + */ +#if ISC_MUTEX_DEBUG && defined(__NetBSD__) && defined(PTHREAD_MUTEX_ERRORCHECK) +extern pthread_mutexattr_t isc__mutex_attrs; +#define ISC__MUTEX_ATTRS &isc__mutex_attrs +#else +#define ISC__MUTEX_ATTRS NULL +#endif + +/* XXX We could do fancier error handling... */ + +/*! + * Define ISC_MUTEX_PROFILE to turn on profiling of mutexes by line. When + * enabled, isc_mutex_stats() can be used to print a table showing the + * number of times each type of mutex was locked and the amount of time + * waiting to obtain the lock. + */ +#ifndef ISC_MUTEX_PROFILE +#define ISC_MUTEX_PROFILE 0 +#endif + +#if ISC_MUTEX_PROFILE +typedef struct isc_mutexstats isc_mutexstats_t; + +typedef struct { + pthread_mutex_t mutex; /*%< The actual mutex. */ + isc_mutexstats_t * stats; /*%< Mutex statistics. */ +} isc_mutex_t; +#else +typedef pthread_mutex_t isc_mutex_t; +#endif + + +#if ISC_MUTEX_PROFILE +#define isc_mutex_init(mp) \ + isc_mutex_init_profile((mp), __FILE__, __LINE__) +#else +#if ISC_MUTEX_DEBUG && defined(PTHREAD_MUTEX_ERRORCHECK) +#define isc_mutex_init(mp) \ + isc_mutex_init_errcheck((mp)) +#else +#define isc_mutex_init(mp) \ + isc__mutex_init((mp), __FILE__, __LINE__) +isc_result_t isc__mutex_init(isc_mutex_t *mp, const char *file, unsigned int line); +#endif +#endif + +#if ISC_MUTEX_PROFILE +#define isc_mutex_lock(mp) \ + isc_mutex_lock_profile((mp), __FILE__, __LINE__) +#else +#define isc_mutex_lock(mp) \ + ((pthread_mutex_lock((mp)) == 0) ? \ + ISC_R_SUCCESS : ISC_R_UNEXPECTED) +#endif + +#if ISC_MUTEX_PROFILE +#define isc_mutex_unlock(mp) \ + isc_mutex_unlock_profile((mp), __FILE__, __LINE__) +#else +#define isc_mutex_unlock(mp) \ + ((pthread_mutex_unlock((mp)) == 0) ? \ + ISC_R_SUCCESS : ISC_R_UNEXPECTED) +#endif + +#if ISC_MUTEX_PROFILE +#define isc_mutex_trylock(mp) \ + ((pthread_mutex_trylock((&(mp)->mutex)) == 0) ? \ + ISC_R_SUCCESS : ISC_R_LOCKBUSY) +#else +#define isc_mutex_trylock(mp) \ + ((pthread_mutex_trylock((mp)) == 0) ? \ + ISC_R_SUCCESS : ISC_R_LOCKBUSY) +#endif + +#if ISC_MUTEX_PROFILE +#define isc_mutex_destroy(mp) \ + ((pthread_mutex_destroy((&(mp)->mutex)) == 0) ? \ + ISC_R_SUCCESS : ISC_R_UNEXPECTED) +#else +#define isc_mutex_destroy(mp) \ + ((pthread_mutex_destroy((mp)) == 0) ? \ + ISC_R_SUCCESS : ISC_R_UNEXPECTED) +#endif + +#if ISC_MUTEX_PROFILE +#define isc_mutex_stats(fp) isc_mutex_statsprofile(fp); +#else +#define isc_mutex_stats(fp) +#endif + +#if ISC_MUTEX_PROFILE + +isc_result_t +isc_mutex_init_profile(isc_mutex_t *mp, const char * _file, int _line); +isc_result_t +isc_mutex_lock_profile(isc_mutex_t *mp, const char * _file, int _line); +isc_result_t +isc_mutex_unlock_profile(isc_mutex_t *mp, const char * _file, int _line); + +void +isc_mutex_statsprofile(FILE *fp); + +isc_result_t +isc_mutex_init_errcheck(isc_mutex_t *mp); + +#endif /* ISC_MUTEX_PROFILE */ + +ISC_LANG_ENDDECLS +#endif /* ISC_MUTEX_H */ diff --git a/contrib/ntp/lib/isc/pthreads/include/isc/once.h b/contrib/ntp/lib/isc/pthreads/include/isc/once.h new file mode 100644 index 0000000..31d76fb --- /dev/null +++ b/contrib/ntp/lib/isc/pthreads/include/isc/once.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: once.h,v 1.13 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_ONCE_H +#define ISC_ONCE_H 1 + +/*! \file */ + +#include <pthread.h> + +#include <isc/platform.h> +#include <isc/result.h> + +typedef pthread_once_t isc_once_t; + +#ifdef ISC_PLATFORM_BRACEPTHREADONCEINIT +/*! + * This accomodates systems that define PTHRAD_ONCE_INIT improperly. + */ +#define ISC_ONCE_INIT { PTHREAD_ONCE_INIT } +#else +/*! + * This is the usual case. + */ +#define ISC_ONCE_INIT PTHREAD_ONCE_INIT +#endif + +/* XXX We could do fancier error handling... */ + +#define isc_once_do(op, f) \ + ((pthread_once((op), (f)) == 0) ? \ + ISC_R_SUCCESS : ISC_R_UNEXPECTED) + +#endif /* ISC_ONCE_H */ diff --git a/contrib/ntp/lib/isc/pthreads/include/isc/thread.h b/contrib/ntp/lib/isc/pthreads/include/isc/thread.h new file mode 100644 index 0000000..7dcc952 --- /dev/null +++ b/contrib/ntp/lib/isc/pthreads/include/isc/thread.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: thread.h,v 1.26 2007/06/19 23:47:18 tbox Exp $ */ + +#ifndef ISC_THREAD_H +#define ISC_THREAD_H 1 + +/*! \file */ + +#include <pthread.h> + +#include <isc/lang.h> +#include <isc/result.h> + +ISC_LANG_BEGINDECLS + +typedef pthread_t isc_thread_t; +typedef void * isc_threadresult_t; +typedef void * isc_threadarg_t; +typedef isc_threadresult_t (*isc_threadfunc_t)(isc_threadarg_t); +typedef pthread_key_t isc_thread_key_t; + +isc_result_t +isc_thread_create(isc_threadfunc_t, isc_threadarg_t, isc_thread_t *); + +void +isc_thread_setconcurrency(unsigned int level); + +/* XXX We could do fancier error handling... */ + +#define isc_thread_join(t, rp) \ + ((pthread_join((t), (rp)) == 0) ? \ + ISC_R_SUCCESS : ISC_R_UNEXPECTED) + +#define isc_thread_self \ + (unsigned long)pthread_self + +#define isc_thread_key_create pthread_key_create +#define isc_thread_key_getspecific pthread_getspecific +#define isc_thread_key_setspecific pthread_setspecific +#define isc_thread_key_delete pthread_key_delete + +ISC_LANG_ENDDECLS + +#endif /* ISC_THREAD_H */ diff --git a/contrib/ntp/lib/isc/pthreads/mutex.c b/contrib/ntp/lib/isc/pthreads/mutex.c new file mode 100644 index 0000000..62ad540 --- /dev/null +++ b/contrib/ntp/lib/isc/pthreads/mutex.c @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2008, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000-2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: mutex.c,v 1.18 2011/01/04 23:47:14 tbox Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <stdio.h> +#include <time.h> +#include <sys/time.h> +#include <errno.h> + +#include <isc/mutex.h> +#include <isc/util.h> +#include <isc/strerror.h> + +#if HAVE_PTHREADS < 5 /* HP-UX 10.20 has 4, needs this */ +# define pthread_mutex_init(m, a) \ + pthread_mutex_init(m, (a) \ + ? *(const pthread_mutexattr_t *)(a) \ + : pthread_mutexattr_default) +# define PTHREAD_MUTEX_RECURSIVE MUTEX_RECURSIVE_NP +# define pthread_mutexattr_settype pthread_mutexattr_setkind_np +#endif + +#if ISC_MUTEX_PROFILE + +/*@{*/ +/*% Operations on timevals; adapted from FreeBSD's sys/time.h */ +#define timevalclear(tvp) ((tvp)->tv_sec = (tvp)->tv_usec = 0) +#define timevaladd(vvp, uvp) \ + do { \ + (vvp)->tv_sec += (uvp)->tv_sec; \ + (vvp)->tv_usec += (uvp)->tv_usec; \ + if ((vvp)->tv_usec >= 1000000) { \ + (vvp)->tv_sec++; \ + (vvp)->tv_usec -= 1000000; \ + } \ + } while (0) +#define timevalsub(vvp, uvp) \ + do { \ + (vvp)->tv_sec -= (uvp)->tv_sec; \ + (vvp)->tv_usec -= (uvp)->tv_usec; \ + if ((vvp)->tv_usec < 0) { \ + (vvp)->tv_sec--; \ + (vvp)->tv_usec += 1000000; \ + } \ + } while (0) + +/*@}*/ + +#define ISC_MUTEX_MAX_LOCKERS 32 + +typedef struct { + const char * file; + int line; + unsigned count; + struct timeval locked_total; + struct timeval wait_total; +} isc_mutexlocker_t; + +struct isc_mutexstats { + const char * file; /*%< File mutex was created in. */ + int line; /*%< Line mutex was created on. */ + unsigned count; + struct timeval lock_t; + struct timeval locked_total; + struct timeval wait_total; + isc_mutexlocker_t * cur_locker; + isc_mutexlocker_t lockers[ISC_MUTEX_MAX_LOCKERS]; +}; + +#ifndef ISC_MUTEX_PROFTABLESIZE +#define ISC_MUTEX_PROFTABLESIZE (1024 * 1024) +#endif +static isc_mutexstats_t stats[ISC_MUTEX_PROFTABLESIZE]; +static int stats_next = 0; +static isc_boolean_t stats_init = ISC_FALSE; +static pthread_mutex_t statslock = PTHREAD_MUTEX_INITIALIZER; + + +isc_result_t +isc_mutex_init_profile(isc_mutex_t *mp, const char *file, int line) { + int i, err; + + err = pthread_mutex_init(&mp->mutex, NULL); + if (err == ENOMEM) + return (ISC_R_NOMEMORY); + if (err != 0) + return (ISC_R_UNEXPECTED); + + RUNTIME_CHECK(pthread_mutex_lock(&statslock) == 0); + + if (stats_init == ISC_FALSE) + stats_init = ISC_TRUE; + + /* + * If all statistics entries have been used, give up and trigger an + * assertion failure. There would be no other way to deal with this + * because we'd like to keep record of all locks for the purpose of + * debugging and the number of necessary locks is unpredictable. + * If this failure is triggered while debugging, named should be + * rebuilt with an increased ISC_MUTEX_PROFTABLESIZE. + */ + RUNTIME_CHECK(stats_next < ISC_MUTEX_PROFTABLESIZE); + mp->stats = &stats[stats_next++]; + + RUNTIME_CHECK(pthread_mutex_unlock(&statslock) == 0); + + mp->stats->file = file; + mp->stats->line = line; + mp->stats->count = 0; + timevalclear(&mp->stats->locked_total); + timevalclear(&mp->stats->wait_total); + for (i = 0; i < ISC_MUTEX_MAX_LOCKERS; i++) { + mp->stats->lockers[i].file = NULL; + mp->stats->lockers[i].line = 0; + mp->stats->lockers[i].count = 0; + timevalclear(&mp->stats->lockers[i].locked_total); + timevalclear(&mp->stats->lockers[i].wait_total); + } + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_mutex_lock_profile(isc_mutex_t *mp, const char *file, int line) { + struct timeval prelock_t; + struct timeval postlock_t; + isc_mutexlocker_t *locker = NULL; + int i; + + gettimeofday(&prelock_t, NULL); + + if (pthread_mutex_lock(&mp->mutex) != 0) + return (ISC_R_UNEXPECTED); + + gettimeofday(&postlock_t, NULL); + mp->stats->lock_t = postlock_t; + + timevalsub(&postlock_t, &prelock_t); + + mp->stats->count++; + timevaladd(&mp->stats->wait_total, &postlock_t); + + for (i = 0; i < ISC_MUTEX_MAX_LOCKERS; i++) { + if (mp->stats->lockers[i].file == NULL) { + locker = &mp->stats->lockers[i]; + locker->file = file; + locker->line = line; + break; + } else if (mp->stats->lockers[i].file == file && + mp->stats->lockers[i].line == line) { + locker = &mp->stats->lockers[i]; + break; + } + } + + if (locker != NULL) { + locker->count++; + timevaladd(&locker->wait_total, &postlock_t); + } + + mp->stats->cur_locker = locker; + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_mutex_unlock_profile(isc_mutex_t *mp, const char *file, int line) { + struct timeval unlock_t; + + UNUSED(file); + UNUSED(line); + + if (mp->stats->cur_locker != NULL) { + gettimeofday(&unlock_t, NULL); + timevalsub(&unlock_t, &mp->stats->lock_t); + timevaladd(&mp->stats->locked_total, &unlock_t); + timevaladd(&mp->stats->cur_locker->locked_total, &unlock_t); + mp->stats->cur_locker = NULL; + } + + return ((pthread_mutex_unlock((&mp->mutex)) == 0) ? \ + ISC_R_SUCCESS : ISC_R_UNEXPECTED); +} + + +void +isc_mutex_statsprofile(FILE *fp) { + isc_mutexlocker_t *locker; + int i, j; + + fprintf(fp, "Mutex stats (in us)\n"); + for (i = 0; i < stats_next; i++) { + fprintf(fp, "%-12s %4d: %10u %lu.%06lu %lu.%06lu %5d\n", + stats[i].file, stats[i].line, stats[i].count, + stats[i].locked_total.tv_sec, + stats[i].locked_total.tv_usec, + stats[i].wait_total.tv_sec, + stats[i].wait_total.tv_usec, + i); + for (j = 0; j < ISC_MUTEX_MAX_LOCKERS; j++) { + locker = &stats[i].lockers[j]; + if (locker->file == NULL) + continue; + fprintf(fp, " %-11s %4d: %10u %lu.%06lu %lu.%06lu %5d\n", + locker->file, locker->line, locker->count, + locker->locked_total.tv_sec, + locker->locked_total.tv_usec, + locker->wait_total.tv_sec, + locker->wait_total.tv_usec, + i); + } + } +} + +#endif /* ISC_MUTEX_PROFILE */ + +#if ISC_MUTEX_DEBUG && defined(PTHREAD_MUTEX_ERRORCHECK) +isc_result_t +isc_mutex_init_errcheck(isc_mutex_t *mp) +{ + pthread_mutexattr_t attr; + int err; + + if (pthread_mutexattr_init(&attr) != 0) + return (ISC_R_UNEXPECTED); + + if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK) != 0) { + pthread_mutexattr_destroy(&attr); + return (ISC_R_UNEXPECTED); + } + + err = pthread_mutex_init(mp, &attr) != 0) + pthread_mutexattr_destroy(&attr); + if (err == ENOMEM) + return (ISC_R_NOMEMORY); + return ((err == 0) ? ISC_R_SUCCESS : ISC_R_UNEXPECTED); +} +#endif + +#if ISC_MUTEX_DEBUG && defined(__NetBSD__) && defined(PTHREAD_MUTEX_ERRORCHECK) +pthread_mutexattr_t isc__mutex_attrs = { + PTHREAD_MUTEX_ERRORCHECK, /* m_type */ + 0 /* m_flags, which appears to be unused. */ +}; +#endif + +#if !(ISC_MUTEX_DEBUG && defined(PTHREAD_MUTEX_ERRORCHECK)) && !ISC_MUTEX_PROFILE +isc_result_t +isc__mutex_init(isc_mutex_t *mp, const char *file, unsigned int line) { + char strbuf[ISC_STRERRORSIZE]; + isc_result_t result = ISC_R_SUCCESS; + int err; + + err = pthread_mutex_init(mp, ISC__MUTEX_ATTRS); + if (err == ENOMEM) + return (ISC_R_NOMEMORY); + if (err != 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(file, line, "isc_mutex_init() failed: %s", + strbuf); + result = ISC_R_UNEXPECTED; + } + return (result); +} +#endif diff --git a/contrib/ntp/lib/isc/pthreads/thread.c b/contrib/ntp/lib/isc/pthreads/thread.c new file mode 100644 index 0000000..4b5b491 --- /dev/null +++ b/contrib/ntp/lib/isc/pthreads/thread.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001, 2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: thread.c,v 1.17 2007/06/19 23:47:18 tbox Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <isc/thread.h> +#include <isc/util.h> + +#ifndef THREAD_MINSTACKSIZE +#define THREAD_MINSTACKSIZE (64U * 1024) +#endif + +isc_result_t +isc_thread_create(isc_threadfunc_t func, isc_threadarg_t arg, + isc_thread_t *thread) +{ + pthread_attr_t attr; + size_t stacksize; + int ret; + + pthread_attr_init(&attr); + +#if defined(HAVE_PTHREAD_ATTR_GETSTACKSIZE) && \ + defined(HAVE_PTHREAD_ATTR_SETSTACKSIZE) + ret = pthread_attr_getstacksize(&attr, &stacksize); + if (ret != 0) + return (ISC_R_UNEXPECTED); + + if (stacksize < THREAD_MINSTACKSIZE) { + ret = pthread_attr_setstacksize(&attr, THREAD_MINSTACKSIZE); + if (ret != 0) + return (ISC_R_UNEXPECTED); + } +#endif + +#if defined(PTHREAD_SCOPE_SYSTEM) && defined(NEED_PTHREAD_SCOPE_SYSTEM) + ret = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); + if (ret != 0) + return (ISC_R_UNEXPECTED); +#endif + + ret = pthread_create(thread, &attr, func, arg); + if (ret != 0) + return (ISC_R_UNEXPECTED); + + pthread_attr_destroy(&attr); + + return (ISC_R_SUCCESS); +} + +void +isc_thread_setconcurrency(unsigned int level) { +#if defined(CALL_PTHREAD_SETCONCURRENCY) + (void)pthread_setconcurrency(level); +#else + UNUSED(level); +#endif +} diff --git a/contrib/ntp/lib/isc/quota.c b/contrib/ntp/lib/isc/quota.c new file mode 100644 index 0000000..5e5c50c --- /dev/null +++ b/contrib/ntp/lib/isc/quota.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: quota.c,v 1.18 2007/06/19 23:47:17 tbox Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <stddef.h> + +#include <isc/quota.h> +#include <isc/util.h> + +isc_result_t +isc_quota_init(isc_quota_t *quota, int max) { + quota->max = max; + quota->used = 0; + quota->soft = 0; + return (isc_mutex_init("a->lock)); +} + +void +isc_quota_destroy(isc_quota_t *quota) { + INSIST(quota->used == 0); + quota->max = 0; + quota->used = 0; + quota->soft = 0; + DESTROYLOCK("a->lock); +} + +void +isc_quota_soft(isc_quota_t *quota, int soft) { + LOCK("a->lock); + quota->soft = soft; + UNLOCK("a->lock); +} + +void +isc_quota_max(isc_quota_t *quota, int max) { + LOCK("a->lock); + quota->max = max; + UNLOCK("a->lock); +} + +isc_result_t +isc_quota_reserve(isc_quota_t *quota) { + isc_result_t result; + LOCK("a->lock); + if (quota->max == 0 || quota->used < quota->max) { + if (quota->soft == 0 || quota->used < quota->soft) + result = ISC_R_SUCCESS; + else + result = ISC_R_SOFTQUOTA; + quota->used++; + } else + result = ISC_R_QUOTA; + UNLOCK("a->lock); + return (result); +} + +void +isc_quota_release(isc_quota_t *quota) { + LOCK("a->lock); + INSIST(quota->used > 0); + quota->used--; + UNLOCK("a->lock); +} + +isc_result_t +isc_quota_attach(isc_quota_t *quota, isc_quota_t **p) +{ + isc_result_t result; + INSIST(p != NULL && *p == NULL); + result = isc_quota_reserve(quota); + if (result == ISC_R_SUCCESS || result == ISC_R_SOFTQUOTA) + *p = quota; + return (result); +} + +void +isc_quota_detach(isc_quota_t **p) +{ + INSIST(p != NULL && *p != NULL); + isc_quota_release(*p); + *p = NULL; +} diff --git a/contrib/ntp/lib/isc/radix.c b/contrib/ntp/lib/isc/radix.c new file mode 100644 index 0000000..ac211ef --- /dev/null +++ b/contrib/ntp/lib/isc/radix.c @@ -0,0 +1,706 @@ +/* + * Copyright (C) 2007-2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/* + * This source was adapted from MRT's RCS Ids: + * Id: radix.c,v 1.10.2.1 1999/11/29 05:16:24 masaki Exp + * Id: prefix.c,v 1.37.2.9 2000/03/10 02:53:19 labovit Exp + */ + +#include <config.h> + +#include <isc/mem.h> +#include <isc/types.h> +#include <isc/util.h> +#include <isc/radix.h> + +static isc_result_t +_new_prefix(isc_mem_t *mctx, isc_prefix_t **target, int family, + void *dest, int bitlen); + +static void +_deref_prefix(isc_mem_t *mctx, isc_prefix_t *prefix); + +static isc_result_t +_ref_prefix(isc_mem_t *mctx, isc_prefix_t **target, isc_prefix_t *prefix); + +static int +_comp_with_mask(void *addr, void *dest, u_int mask); + +static void +_clear_radix(isc_radix_tree_t *radix, isc_radix_destroyfunc_t func); + +static isc_result_t +_new_prefix(isc_mem_t *mctx, isc_prefix_t **target, int family, void *dest, + int bitlen) +{ + isc_prefix_t *prefix; + + REQUIRE(target != NULL); + + if (family != AF_INET6 && family != AF_INET && family != AF_UNSPEC) + return (ISC_R_NOTIMPLEMENTED); + + prefix = isc_mem_get(mctx, sizeof(isc_prefix_t)); + if (prefix == NULL) + return (ISC_R_NOMEMORY); + + if (family == AF_INET6) { + prefix->bitlen = (bitlen >= 0) ? bitlen : 128; + memcpy(&prefix->add.sin6, dest, 16); + } else { + /* AF_UNSPEC is "any" or "none"--treat it as AF_INET */ + prefix->bitlen = (bitlen >= 0) ? bitlen : 32; + memcpy(&prefix->add.sin, dest, 4); + } + + prefix->family = family; + + isc_refcount_init(&prefix->refcount, 1); + + *target = prefix; + return (ISC_R_SUCCESS); +} + +static void +_deref_prefix(isc_mem_t *mctx, isc_prefix_t *prefix) { + int refs; + + if (prefix == NULL) + return; + + isc_refcount_decrement(&prefix->refcount, &refs); + + if (refs <= 0) { + isc_refcount_destroy(&prefix->refcount); + isc_mem_put(mctx, prefix, sizeof(isc_prefix_t)); + } +} + +static isc_result_t +_ref_prefix(isc_mem_t *mctx, isc_prefix_t **target, isc_prefix_t *prefix) { + INSIST(prefix != NULL); + INSIST((prefix->family == AF_INET && prefix->bitlen <= 32) || + (prefix->family == AF_INET6 && prefix->bitlen <= 128) || + (prefix->family == AF_UNSPEC && prefix->bitlen == 0)); + REQUIRE(target != NULL && *target == NULL); + + /* + * If this prefix is a static allocation, copy it into new memory. + * (Note, the refcount still has to be destroyed by the calling + * routine.) + */ + if (isc_refcount_current(&prefix->refcount) == 0) { + isc_result_t ret; + ret = _new_prefix(mctx, target, prefix->family, + &prefix->add, prefix->bitlen); + return ret; + } + + isc_refcount_increment(&prefix->refcount, NULL); + + *target = prefix; + return (ISC_R_SUCCESS); +} + +static int +_comp_with_mask(void *addr, void *dest, u_int mask) { + + /* Mask length of zero matches everything */ + if (mask == 0) + return (1); + + if (memcmp(addr, dest, mask / 8) == 0) { + int n = mask / 8; + int m = ((~0) << (8 - (mask % 8))); + + if ((mask % 8) == 0 || + (((u_char *)addr)[n] & m) == (((u_char *)dest)[n] & m)) + return (1); + } + return (0); +} + +isc_result_t +isc_radix_create(isc_mem_t *mctx, isc_radix_tree_t **target, int maxbits) { + isc_radix_tree_t *radix; + + REQUIRE(target != NULL && *target == NULL); + + radix = isc_mem_get(mctx, sizeof(isc_radix_tree_t)); + if (radix == NULL) + return (ISC_R_NOMEMORY); + + radix->mctx = mctx; + radix->maxbits = maxbits; + radix->head = NULL; + radix->num_active_node = 0; + radix->num_added_node = 0; + RUNTIME_CHECK(maxbits <= RADIX_MAXBITS); /* XXX */ + radix->magic = RADIX_TREE_MAGIC; + *target = radix; + return (ISC_R_SUCCESS); +} + +/* + * if func is supplied, it will be called as func(node->data) + * before deleting the node + */ + +static void +_clear_radix(isc_radix_tree_t *radix, isc_radix_destroyfunc_t func) { + + REQUIRE(radix != NULL); + + if (radix->head != NULL) { + + isc_radix_node_t *Xstack[RADIX_MAXBITS+1]; + isc_radix_node_t **Xsp = Xstack; + isc_radix_node_t *Xrn = radix->head; + + while (Xrn != NULL) { + isc_radix_node_t *l = Xrn->l; + isc_radix_node_t *r = Xrn->r; + + if (Xrn->prefix != NULL) { + _deref_prefix(radix->mctx, Xrn->prefix); + if (func != NULL && (Xrn->data[0] != NULL || + Xrn->data[1] != NULL)) + func(Xrn->data); + } else { + INSIST(Xrn->data[0] == NULL && + Xrn->data[1] == NULL); + } + + isc_mem_put(radix->mctx, Xrn, sizeof(*Xrn)); + radix->num_active_node--; + + if (l != NULL) { + if (r != NULL) { + *Xsp++ = r; + } + Xrn = l; + } else if (r != NULL) { + Xrn = r; + } else if (Xsp != Xstack) { + Xrn = *(--Xsp); + } else { + Xrn = NULL; + } + } + } + RUNTIME_CHECK(radix->num_active_node == 0); +} + + +void +isc_radix_destroy(isc_radix_tree_t *radix, isc_radix_destroyfunc_t func) +{ + REQUIRE(radix != NULL); + _clear_radix(radix, func); + isc_mem_put(radix->mctx, radix, sizeof(*radix)); +} + + +/* + * func will be called as func(node->prefix, node->data) + */ +void +isc_radix_process(isc_radix_tree_t *radix, isc_radix_processfunc_t func) +{ + isc_radix_node_t *node; + + REQUIRE(func != NULL); + + RADIX_WALK(radix->head, node) { + func(node->prefix, node->data); + } RADIX_WALK_END; +} + + +isc_result_t +isc_radix_search(isc_radix_tree_t *radix, isc_radix_node_t **target, + isc_prefix_t *prefix) +{ + isc_radix_node_t *node; + isc_radix_node_t *stack[RADIX_MAXBITS + 1]; + u_char *addr; + isc_uint32_t bitlen; + int tfamily = -1; + int cnt = 0; + + REQUIRE(radix != NULL); + REQUIRE(prefix != NULL); + REQUIRE(target != NULL && *target == NULL); + RUNTIME_CHECK(prefix->bitlen <= radix->maxbits); + + *target = NULL; + + if (radix->head == NULL) { + return (ISC_R_NOTFOUND); + } + + node = radix->head; + addr = isc_prefix_touchar(prefix); + bitlen = prefix->bitlen; + + while (node->bit < bitlen) { + if (node->prefix) + stack[cnt++] = node; + + if (BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) + node = node->r; + else + node = node->l; + + if (node == NULL) + break; + } + + if (node && node->prefix) + stack[cnt++] = node; + + while (cnt-- > 0) { + node = stack[cnt]; + + if (_comp_with_mask(isc_prefix_tochar(node->prefix), + isc_prefix_tochar(prefix), + node->prefix->bitlen)) { + if (node->node_num[ISC_IS6(prefix->family)] != -1 && + ((*target == NULL) || + (*target)->node_num[ISC_IS6(tfamily)] > + node->node_num[ISC_IS6(prefix->family)])) { + *target = node; + tfamily = prefix->family; + } + } + } + + if (*target == NULL) { + return (ISC_R_NOTFOUND); + } else { + return (ISC_R_SUCCESS); + } +} + +isc_result_t +isc_radix_insert(isc_radix_tree_t *radix, isc_radix_node_t **target, + isc_radix_node_t *source, isc_prefix_t *prefix) +{ + isc_radix_node_t *node, *new_node, *parent, *glue = NULL; + u_char *addr, *test_addr; + isc_uint32_t bitlen, fam, check_bit, differ_bit; + isc_uint32_t i, j, r; + isc_result_t result; + + REQUIRE(radix != NULL); + REQUIRE(target != NULL && *target == NULL); + REQUIRE(prefix != NULL || (source != NULL && source->prefix != NULL)); + RUNTIME_CHECK(prefix == NULL || prefix->bitlen <= radix->maxbits); + + if (prefix == NULL) + prefix = source->prefix; + + INSIST(prefix != NULL); + + bitlen = prefix->bitlen; + fam = prefix->family; + + if (radix->head == NULL) { + node = isc_mem_get(radix->mctx, sizeof(isc_radix_node_t)); + if (node == NULL) + return (ISC_R_NOMEMORY); + node->bit = bitlen; + node->node_num[0] = node->node_num[1] = -1; + node->prefix = NULL; + result = _ref_prefix(radix->mctx, &node->prefix, prefix); + if (result != ISC_R_SUCCESS) { + isc_mem_put(radix->mctx, node, + sizeof(isc_radix_node_t)); + return (result); + } + node->parent = NULL; + node->l = node->r = NULL; + if (source != NULL) { + /* + * If source is non-NULL, then we're merging in a + * node from an existing radix tree. To keep + * the node_num values consistent, the calling + * function will add the total number of nodes + * added to num_added_node at the end of + * the merge operation--we don't do it here. + */ + if (source->node_num[0] != -1) + node->node_num[0] = radix->num_added_node + + source->node_num[0]; + if (source->node_num[1] != -1) + node->node_num[1] = radix->num_added_node + + source->node_num[1]; + node->data[0] = source->data[0]; + node->data[1] = source->data[1]; + } else { + if (fam == AF_UNSPEC) { + /* "any" or "none" */ + node->node_num[0] = node->node_num[1] = + ++radix->num_added_node; + } else { + node->node_num[ISC_IS6(fam)] = + ++radix->num_added_node; + } + node->data[0] = NULL; + node->data[1] = NULL; + } + radix->head = node; + radix->num_active_node++; + *target = node; + return (ISC_R_SUCCESS); + } + + addr = isc_prefix_touchar(prefix); + node = radix->head; + + while (node->bit < bitlen || node->prefix == NULL) { + if (node->bit < radix->maxbits && + BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) + { + if (node->r == NULL) + break; + node = node->r; + } else { + if (node->l == NULL) + break; + node = node->l; + } + + INSIST(node != NULL); + } + + INSIST(node->prefix != NULL); + + test_addr = isc_prefix_touchar(node->prefix); + /* Find the first bit different. */ + check_bit = (node->bit < bitlen) ? node->bit : bitlen; + differ_bit = 0; + for (i = 0; i*8 < check_bit; i++) { + if ((r = (addr[i] ^ test_addr[i])) == 0) { + differ_bit = (i + 1) * 8; + continue; + } + /* I know the better way, but for now. */ + for (j = 0; j < 8; j++) { + if (BIT_TEST (r, (0x80 >> j))) + break; + } + /* Must be found. */ + INSIST(j < 8); + differ_bit = i * 8 + j; + break; + } + + if (differ_bit > check_bit) + differ_bit = check_bit; + + parent = node->parent; + while (parent != NULL && parent->bit >= differ_bit) { + node = parent; + parent = node->parent; + } + + if (differ_bit == bitlen && node->bit == bitlen) { + if (node->prefix != NULL) { + /* Set node_num only if it hasn't been set before */ + if (source != NULL) { + /* Merging node */ + if (node->node_num[0] == -1 && + source->node_num[0] != -1) { + node->node_num[0] = + radix->num_added_node + + source->node_num[0]; + node->data[0] = source->data[0]; + } + if (node->node_num[1] == -1 && + source->node_num[0] != -1) { + node->node_num[1] = + radix->num_added_node + + source->node_num[1]; + node->data[1] = source->data[1]; + } + } else { + if (fam == AF_UNSPEC) { + /* "any" or "none" */ + int next = radix->num_added_node + 1; + if (node->node_num[0] == -1) { + node->node_num[0] = next; + radix->num_added_node = next; + } + if (node->node_num[1] == -1) { + node->node_num[1] = next; + radix->num_added_node = next; + } + } else { + if (node->node_num[ISC_IS6(fam)] == -1) + node->node_num[ISC_IS6(fam)] + = ++radix->num_added_node; + } + } + *target = node; + return (ISC_R_SUCCESS); + } else { + result = + _ref_prefix(radix->mctx, &node->prefix, prefix); + if (result != ISC_R_SUCCESS) + return (result); + } + INSIST(node->data[0] == NULL && node->node_num[0] == -1 && + node->data[1] == NULL && node->node_num[1] == -1); + if (source != NULL) { + /* Merging node */ + if (source->node_num[0] != -1) { + node->node_num[0] = radix->num_added_node + + source->node_num[0]; + node->data[0] = source->data[0]; + } + if (source->node_num[1] != -1) { + node->node_num[1] = radix->num_added_node + + source->node_num[1]; + node->data[1] = source->data[1]; + } + } else { + if (fam == AF_UNSPEC) { + /* "any" or "none" */ + node->node_num[0] = node->node_num[1] = + ++radix->num_added_node; + } else { + node->node_num[ISC_IS6(fam)] = + ++radix->num_added_node; + } + } + *target = node; + return (ISC_R_SUCCESS); + } + + new_node = isc_mem_get(radix->mctx, sizeof(isc_radix_node_t)); + if (new_node == NULL) + return (ISC_R_NOMEMORY); + if (node->bit != differ_bit && bitlen != differ_bit) { + glue = isc_mem_get(radix->mctx, sizeof(isc_radix_node_t)); + if (glue == NULL) { + isc_mem_put(radix->mctx, new_node, + sizeof(isc_radix_node_t)); + return (ISC_R_NOMEMORY); + } + } + new_node->bit = bitlen; + new_node->prefix = NULL; + result = _ref_prefix(radix->mctx, &new_node->prefix, prefix); + if (result != ISC_R_SUCCESS) { + isc_mem_put(radix->mctx, new_node, sizeof(isc_radix_node_t)); + if (glue != NULL) + isc_mem_put(radix->mctx, glue, + sizeof(isc_radix_node_t)); + return (result); + } + new_node->parent = NULL; + new_node->l = new_node->r = NULL; + new_node->node_num[0] = new_node->node_num[1] = -1; + radix->num_active_node++; + + if (source != NULL) { + /* Merging node */ + if (source->node_num[0] != -1) + new_node->node_num[0] = radix->num_added_node + + source->node_num[0]; + if (source->node_num[1] != -1) + new_node->node_num[1] = radix->num_added_node + + source->node_num[1]; + new_node->data[0] = source->data[0]; + new_node->data[1] = source->data[1]; + } else { + if (fam == AF_UNSPEC) { + /* "any" or "none" */ + new_node->node_num[0] = new_node->node_num[1] = + ++radix->num_added_node; + } else { + new_node->node_num[ISC_IS6(fam)] = + ++radix->num_added_node; + } + new_node->data[0] = NULL; + new_node->data[1] = NULL; + } + + if (node->bit == differ_bit) { + INSIST(glue == NULL); + new_node->parent = node; + if (node->bit < radix->maxbits && + BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) + { + INSIST(node->r == NULL); + node->r = new_node; + } else { + INSIST(node->l == NULL); + node->l = new_node; + } + *target = new_node; + return (ISC_R_SUCCESS); + } + + if (bitlen == differ_bit) { + INSIST(glue == NULL); + if (bitlen < radix->maxbits && + BIT_TEST(test_addr[bitlen >> 3], 0x80 >> (bitlen & 0x07))) { + new_node->r = node; + } else { + new_node->l = node; + } + new_node->parent = node->parent; + if (node->parent == NULL) { + INSIST(radix->head == node); + radix->head = new_node; + } else if (node->parent->r == node) { + node->parent->r = new_node; + } else { + node->parent->l = new_node; + } + node->parent = new_node; + } else { + INSIST(glue != NULL); + glue->bit = differ_bit; + glue->prefix = NULL; + glue->parent = node->parent; + glue->data[0] = glue->data[1] = NULL; + glue->node_num[0] = glue->node_num[1] = -1; + radix->num_active_node++; + if (differ_bit < radix->maxbits && + BIT_TEST(addr[differ_bit>>3], 0x80 >> (differ_bit & 07))) { + glue->r = new_node; + glue->l = node; + } else { + glue->r = node; + glue->l = new_node; + } + new_node->parent = glue; + + if (node->parent == NULL) { + INSIST(radix->head == node); + radix->head = glue; + } else if (node->parent->r == node) { + node->parent->r = glue; + } else { + node->parent->l = glue; + } + node->parent = glue; + } + + *target = new_node; + return (ISC_R_SUCCESS); +} + +void +isc_radix_remove(isc_radix_tree_t *radix, isc_radix_node_t *node) { + isc_radix_node_t *parent, *child; + + REQUIRE(radix != NULL); + REQUIRE(node != NULL); + + if (node->r && node->l) { + /* + * This might be a placeholder node -- have to check and + * make sure there is a prefix associated with it! + */ + if (node->prefix != NULL) + _deref_prefix(radix->mctx, node->prefix); + + node->prefix = NULL; + node->data[0] = node->data[1] = NULL; + return; + } + + if (node->r == NULL && node->l == NULL) { + parent = node->parent; + _deref_prefix(radix->mctx, node->prefix); + isc_mem_put(radix->mctx, node, sizeof(*node)); + radix->num_active_node--; + + if (parent == NULL) { + INSIST(radix->head == node); + radix->head = NULL; + return; + } + + if (parent->r == node) { + parent->r = NULL; + child = parent->l; + } else { + INSIST(parent->l == node); + parent->l = NULL; + child = parent->r; + } + + if (parent->prefix) + return; + + /* We need to remove parent too. */ + + if (parent->parent == NULL) { + INSIST(radix->head == parent); + radix->head = child; + } else if (parent->parent->r == parent) { + parent->parent->r = child; + } else { + INSIST(parent->parent->l == parent); + parent->parent->l = child; + } + child->parent = parent->parent; + isc_mem_put(radix->mctx, parent, sizeof(*parent)); + radix->num_active_node--; + return; + } + + if (node->r) { + child = node->r; + } else { + INSIST(node->l != NULL); + child = node->l; + } + parent = node->parent; + child->parent = parent; + + _deref_prefix(radix->mctx, node->prefix); + isc_mem_put(radix->mctx, node, sizeof(*node)); + radix->num_active_node--; + + if (parent == NULL) { + INSIST(radix->head == node); + radix->head = child; + return; + } + + if (parent->r == node) { + parent->r = child; + } else { + INSIST(parent->l == node); + parent->l = child; + } +} + +/* +Local Variables: +c-basic-offset: 4 +indent-tabs-mode: t +End: +*/ diff --git a/contrib/ntp/lib/isc/random.c b/contrib/ntp/lib/isc/random.c new file mode 100644 index 0000000..8b73ed5 --- /dev/null +++ b/contrib/ntp/lib/isc/random.c @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: random.c,v 1.28 2009/07/16 05:52:46 marka Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <stdlib.h> +#include <time.h> /* Required for time(). */ +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include <isc/mutex.h> +#include <isc/once.h> +#include <isc/random.h> +#include <isc/string.h> +#include <isc/util.h> + +static isc_once_t once = ISC_ONCE_INIT; + +static void +initialize_rand(void) +{ +#ifndef HAVE_ARC4RANDOM + unsigned int pid = getpid(); + + /* + * The low bits of pid generally change faster. + * Xor them with the high bits of time which change slowly. + */ + pid = ((pid << 16) & 0xffff0000) | ((pid >> 16) & 0xffff); + + srand(time(NULL) ^ pid); +#endif +} + +static void +initialize(void) +{ + RUNTIME_CHECK(isc_once_do(&once, initialize_rand) == ISC_R_SUCCESS); +} + +void +isc_random_seed(isc_uint32_t seed) +{ + initialize(); + +#ifndef HAVE_ARC4RANDOM + srand(seed); +#else + arc4random_addrandom((u_char *) &seed, sizeof(isc_uint32_t)); +#endif +} + +void +isc_random_get(isc_uint32_t *val) +{ + REQUIRE(val != NULL); + + initialize(); + +#ifndef HAVE_ARC4RANDOM + /* + * rand()'s lower bits are not random. + * rand()'s upper bit is zero. + */ +#if RAND_MAX >= 0xfffff + /* We have at least 20 bits. Use lower 16 excluding lower most 4 */ + *val = ((rand() >> 4) & 0xffff) | ((rand() << 12) & 0xffff0000); +#elif RAND_MAX >= 0x7fff + /* We have at least 15 bits. Use lower 10/11 excluding lower most 4 */ + *val = ((rand() >> 4) & 0x000007ff) | ((rand() << 7) & 0x003ff800) | + ((rand() << 18) & 0xffc00000); +#else +#error RAND_MAX is too small +#endif +#else + *val = arc4random(); +#endif +} + +isc_uint32_t +isc_random_jitter(isc_uint32_t max, isc_uint32_t jitter) { + isc_uint32_t rnd; + + REQUIRE(jitter < max || (jitter == 0 && max == 0)); + + if (jitter == 0) + return (max); + + isc_random_get(&rnd); + return (max - rnd % jitter); +} diff --git a/contrib/ntp/lib/isc/ratelimiter.c b/contrib/ntp/lib/isc/ratelimiter.c new file mode 100644 index 0000000..07bcc7c --- /dev/null +++ b/contrib/ntp/lib/isc/ratelimiter.c @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: ratelimiter.c,v 1.25 2007/06/19 23:47:17 tbox Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <isc/mem.h> +#include <isc/ratelimiter.h> +#include <isc/task.h> +#include <isc/time.h> +#include <isc/timer.h> +#include <isc/util.h> + +typedef enum { + isc_ratelimiter_stalled = 0, + isc_ratelimiter_ratelimited = 1, + isc_ratelimiter_idle = 2, + isc_ratelimiter_shuttingdown = 3 +} isc_ratelimiter_state_t; + +struct isc_ratelimiter { + isc_mem_t * mctx; + isc_mutex_t lock; + int refs; + isc_task_t * task; + isc_timer_t * timer; + isc_interval_t interval; + isc_uint32_t pertic; + isc_ratelimiter_state_t state; + isc_event_t shutdownevent; + ISC_LIST(isc_event_t) pending; +}; + +#define ISC_RATELIMITEREVENT_SHUTDOWN (ISC_EVENTCLASS_RATELIMITER + 1) + +static void +ratelimiter_tick(isc_task_t *task, isc_event_t *event); + +static void +ratelimiter_shutdowncomplete(isc_task_t *task, isc_event_t *event); + +isc_result_t +isc_ratelimiter_create(isc_mem_t *mctx, isc_timermgr_t *timermgr, + isc_task_t *task, isc_ratelimiter_t **ratelimiterp) +{ + isc_result_t result; + isc_ratelimiter_t *rl; + INSIST(ratelimiterp != NULL && *ratelimiterp == NULL); + + rl = isc_mem_get(mctx, sizeof(*rl)); + if (rl == NULL) + return ISC_R_NOMEMORY; + rl->mctx = mctx; + rl->refs = 1; + rl->task = task; + isc_interval_set(&rl->interval, 0, 0); + rl->timer = NULL; + rl->pertic = 1; + rl->state = isc_ratelimiter_idle; + ISC_LIST_INIT(rl->pending); + + result = isc_mutex_init(&rl->lock); + if (result != ISC_R_SUCCESS) + goto free_mem; + result = isc_timer_create(timermgr, isc_timertype_inactive, + NULL, NULL, rl->task, ratelimiter_tick, + rl, &rl->timer); + if (result != ISC_R_SUCCESS) + goto free_mutex; + + /* + * Increment the reference count to indicate that we may + * (soon) have events outstanding. + */ + rl->refs++; + + ISC_EVENT_INIT(&rl->shutdownevent, + sizeof(isc_event_t), + 0, NULL, ISC_RATELIMITEREVENT_SHUTDOWN, + ratelimiter_shutdowncomplete, rl, rl, NULL, NULL); + + *ratelimiterp = rl; + return (ISC_R_SUCCESS); + +free_mutex: + DESTROYLOCK(&rl->lock); +free_mem: + isc_mem_put(mctx, rl, sizeof(*rl)); + return (result); +} + +isc_result_t +isc_ratelimiter_setinterval(isc_ratelimiter_t *rl, isc_interval_t *interval) { + isc_result_t result = ISC_R_SUCCESS; + LOCK(&rl->lock); + rl->interval = *interval; + /* + * If the timer is currently running, change its rate. + */ + if (rl->state == isc_ratelimiter_ratelimited) { + result = isc_timer_reset(rl->timer, isc_timertype_ticker, NULL, + &rl->interval, ISC_FALSE); + } + UNLOCK(&rl->lock); + return (result); +} + +void +isc_ratelimiter_setpertic(isc_ratelimiter_t *rl, isc_uint32_t pertic) { + if (pertic == 0) + pertic = 1; + rl->pertic = pertic; +} + +isc_result_t +isc_ratelimiter_enqueue(isc_ratelimiter_t *rl, isc_task_t *task, + isc_event_t **eventp) +{ + isc_result_t result = ISC_R_SUCCESS; + isc_event_t *ev; + + REQUIRE(eventp != NULL && *eventp != NULL); + REQUIRE(task != NULL); + ev = *eventp; + REQUIRE(ev->ev_sender == NULL); + + LOCK(&rl->lock); + if (rl->state == isc_ratelimiter_ratelimited || + rl->state == isc_ratelimiter_stalled) { + isc_event_t *ev = *eventp; + ev->ev_sender = task; + ISC_LIST_APPEND(rl->pending, ev, ev_link); + *eventp = NULL; + } else if (rl->state == isc_ratelimiter_idle) { + result = isc_timer_reset(rl->timer, isc_timertype_ticker, NULL, + &rl->interval, ISC_FALSE); + if (result == ISC_R_SUCCESS) { + ev->ev_sender = task; + rl->state = isc_ratelimiter_ratelimited; + } + } else { + INSIST(rl->state == isc_ratelimiter_shuttingdown); + result = ISC_R_SHUTTINGDOWN; + } + UNLOCK(&rl->lock); + if (*eventp != NULL && result == ISC_R_SUCCESS) + isc_task_send(task, eventp); + return (result); +} + +static void +ratelimiter_tick(isc_task_t *task, isc_event_t *event) { + isc_result_t result = ISC_R_SUCCESS; + isc_ratelimiter_t *rl = (isc_ratelimiter_t *)event->ev_arg; + isc_event_t *p; + isc_uint32_t pertic; + + UNUSED(task); + + isc_event_free(&event); + + pertic = rl->pertic; + while (pertic != 0) { + pertic--; + LOCK(&rl->lock); + p = ISC_LIST_HEAD(rl->pending); + if (p != NULL) { + /* + * There is work to do. Let's do it after unlocking. + */ + ISC_LIST_UNLINK(rl->pending, p, ev_link); + } else { + /* + * No work left to do. Stop the timer so that we don't + * waste resources by having it fire periodically. + */ + result = isc_timer_reset(rl->timer, + isc_timertype_inactive, + NULL, NULL, ISC_FALSE); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + rl->state = isc_ratelimiter_idle; + pertic = 0; /* Force the loop to exit. */ + } + UNLOCK(&rl->lock); + if (p != NULL) { + isc_task_t *evtask = p->ev_sender; + isc_task_send(evtask, &p); + } + INSIST(p == NULL); + } +} + +void +isc_ratelimiter_shutdown(isc_ratelimiter_t *rl) { + isc_event_t *ev; + isc_task_t *task; + LOCK(&rl->lock); + rl->state = isc_ratelimiter_shuttingdown; + (void)isc_timer_reset(rl->timer, isc_timertype_inactive, + NULL, NULL, ISC_FALSE); + while ((ev = ISC_LIST_HEAD(rl->pending)) != NULL) { + ISC_LIST_UNLINK(rl->pending, ev, ev_link); + ev->ev_attributes |= ISC_EVENTATTR_CANCELED; + task = ev->ev_sender; + isc_task_send(task, &ev); + } + isc_timer_detach(&rl->timer); + /* + * Send an event to our task. The delivery of this event + * indicates that no more timer events will be delivered. + */ + ev = &rl->shutdownevent; + isc_task_send(rl->task, &ev); + + UNLOCK(&rl->lock); +} + +static void +ratelimiter_shutdowncomplete(isc_task_t *task, isc_event_t *event) { + isc_ratelimiter_t *rl = (isc_ratelimiter_t *)event->ev_arg; + + UNUSED(task); + + isc_ratelimiter_detach(&rl); +} + +static void +ratelimiter_free(isc_ratelimiter_t *rl) { + DESTROYLOCK(&rl->lock); + isc_mem_put(rl->mctx, rl, sizeof(*rl)); +} + +void +isc_ratelimiter_attach(isc_ratelimiter_t *source, isc_ratelimiter_t **target) { + REQUIRE(source != NULL); + REQUIRE(target != NULL && *target == NULL); + + LOCK(&source->lock); + REQUIRE(source->refs > 0); + source->refs++; + INSIST(source->refs > 0); + UNLOCK(&source->lock); + *target = source; +} + +void +isc_ratelimiter_detach(isc_ratelimiter_t **rlp) { + isc_ratelimiter_t *rl = *rlp; + isc_boolean_t free_now = ISC_FALSE; + + LOCK(&rl->lock); + REQUIRE(rl->refs > 0); + rl->refs--; + if (rl->refs == 0) + free_now = ISC_TRUE; + UNLOCK(&rl->lock); + + if (free_now) + ratelimiter_free(rl); + + *rlp = NULL; +} + +isc_result_t +isc_ratelimiter_stall(isc_ratelimiter_t *rl) { + isc_result_t result = ISC_R_SUCCESS; + + LOCK(&rl->lock); + switch (rl->state) { + case isc_ratelimiter_shuttingdown: + result = ISC_R_SHUTTINGDOWN; + break; + case isc_ratelimiter_ratelimited: + result = isc_timer_reset(rl->timer, isc_timertype_inactive, + NULL, NULL, ISC_FALSE); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + case isc_ratelimiter_idle: + case isc_ratelimiter_stalled: + rl->state = isc_ratelimiter_stalled; + break; + } + UNLOCK(&rl->lock); + return (result); +} + +isc_result_t +isc_ratelimiter_release(isc_ratelimiter_t *rl) { + isc_result_t result = ISC_R_SUCCESS; + + LOCK(&rl->lock); + switch (rl->state) { + case isc_ratelimiter_shuttingdown: + result = ISC_R_SHUTTINGDOWN; + break; + case isc_ratelimiter_stalled: + if (!ISC_LIST_EMPTY(rl->pending)) { + result = isc_timer_reset(rl->timer, + isc_timertype_ticker, NULL, + &rl->interval, ISC_FALSE); + if (result == ISC_R_SUCCESS) + rl->state = isc_ratelimiter_ratelimited; + } else + rl->state = isc_ratelimiter_idle; + break; + case isc_ratelimiter_ratelimited: + case isc_ratelimiter_idle: + break; + } + UNLOCK(&rl->lock); + return (result); +} diff --git a/contrib/ntp/lib/isc/refcount.c b/contrib/ntp/lib/isc/refcount.c new file mode 100644 index 0000000..36dfff2 --- /dev/null +++ b/contrib/ntp/lib/isc/refcount.c @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: refcount.c,v 1.5 2007/06/19 23:47:17 tbox Exp $ */ + +#include <config.h> + +#include <stddef.h> + +#include <isc/mutex.h> +#include <isc/refcount.h> +#include <isc/result.h> + +isc_result_t +isc_refcount_init(isc_refcount_t *ref, unsigned int n) { + REQUIRE(ref != NULL); + + ref->refs = n; +#if defined(ISC_PLATFORM_USETHREADS) && !defined(ISC_PLATFORM_HAVEXADD) + return (isc_mutex_init(&ref->lock)); +#else + return (ISC_R_SUCCESS); +#endif +} diff --git a/contrib/ntp/lib/isc/region.c b/contrib/ntp/lib/isc/region.c new file mode 100644 index 0000000..cf64979 --- /dev/null +++ b/contrib/ntp/lib/isc/region.c @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: region.c,v 1.7 2007/06/19 23:47:17 tbox Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <stdlib.h> +#include <string.h> + +#include <isc/region.h> +#include <isc/util.h> + +int +isc_region_compare(isc_region_t *r1, isc_region_t *r2) { + unsigned int l; + int result; + + REQUIRE(r1 != NULL); + REQUIRE(r2 != NULL); + + l = (r1->length < r2->length) ? r1->length : r2->length; + + if ((result = memcmp(r1->base, r2->base, l)) != 0) + return ((result < 0) ? -1 : 1); + else + return ((r1->length == r2->length) ? 0 : + (r1->length < r2->length) ? -1 : 1); +} diff --git a/contrib/ntp/lib/isc/result.c b/contrib/ntp/lib/isc/result.c new file mode 100644 index 0000000..520f161 --- /dev/null +++ b/contrib/ntp/lib/isc/result.c @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2008, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2001, 2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/*! \file */ + +#include <config.h> + +#include <stddef.h> +#include <stdlib.h> + +#include <isc/lib.h> +#include <isc/msgs.h> +#include <isc/mutex.h> +#include <isc/once.h> +#include <isc/resultclass.h> +#include <isc/util.h> + +typedef struct resulttable { + unsigned int base; + unsigned int last; + const char ** text; + isc_msgcat_t * msgcat; + int set; + ISC_LINK(struct resulttable) link; +} resulttable; + +static const char *text[ISC_R_NRESULTS] = { + "success", /*%< 0 */ + "out of memory", /*%< 1 */ + "timed out", /*%< 2 */ + "no available threads", /*%< 3 */ + "address not available", /*%< 4 */ + "address in use", /*%< 5 */ + "permission denied", /*%< 6 */ + "no pending connections", /*%< 7 */ + "network unreachable", /*%< 8 */ + "host unreachable", /*%< 9 */ + "network down", /*%< 10 */ + "host down", /*%< 11 */ + "connection refused", /*%< 12 */ + "not enough free resources", /*%< 13 */ + "end of file", /*%< 14 */ + "socket already bound", /*%< 15 */ + "reload", /*%< 16 */ + "lock busy", /*%< 17 */ + "already exists", /*%< 18 */ + "ran out of space", /*%< 19 */ + "operation canceled", /*%< 20 */ + "socket is not bound", /*%< 21 */ + "shutting down", /*%< 22 */ + "not found", /*%< 23 */ + "unexpected end of input", /*%< 24 */ + "failure", /*%< 25 */ + "I/O error", /*%< 26 */ + "not implemented", /*%< 27 */ + "unbalanced parentheses", /*%< 28 */ + "no more", /*%< 29 */ + "invalid file", /*%< 30 */ + "bad base64 encoding", /*%< 31 */ + "unexpected token", /*%< 32 */ + "quota reached", /*%< 33 */ + "unexpected error", /*%< 34 */ + "already running", /*%< 35 */ + "ignore", /*%< 36 */ + "address mask not contiguous", /*%< 37 */ + "file not found", /*%< 38 */ + "file already exists", /*%< 39 */ + "socket is not connected", /*%< 40 */ + "out of range", /*%< 41 */ + "out of entropy", /*%< 42 */ + "invalid use of multicast address", /*%< 43 */ + "not a file", /*%< 44 */ + "not a directory", /*%< 45 */ + "queue is full", /*%< 46 */ + "address family mismatch", /*%< 47 */ + "address family not supported", /*%< 48 */ + "bad hex encoding", /*%< 49 */ + "too many open files", /*%< 50 */ + "not blocking", /*%< 51 */ + "unbalanced quotes", /*%< 52 */ + "operation in progress", /*%< 53 */ + "connection reset", /*%< 54 */ + "soft quota reached", /*%< 55 */ + "not a valid number", /*%< 56 */ + "disabled", /*%< 57 */ + "max size", /*%< 58 */ + "invalid address format", /*%< 59 */ + "bad base32 encoding", /*%< 60 */ + "unset", /*%< 61 */ +}; + +#define ISC_RESULT_RESULTSET 2 +#define ISC_RESULT_UNAVAILABLESET 3 + +static isc_once_t once = ISC_ONCE_INIT; +static ISC_LIST(resulttable) tables; +static isc_mutex_t lock; + +static isc_result_t +register_table(unsigned int base, unsigned int nresults, const char **txt, + isc_msgcat_t *msgcat, int set) +{ + resulttable *table; + + REQUIRE(base % ISC_RESULTCLASS_SIZE == 0); + REQUIRE(nresults <= ISC_RESULTCLASS_SIZE); + REQUIRE(txt != NULL); + + /* + * We use malloc() here because we we want to be able to use + * isc_result_totext() even if there is no memory context. + */ + table = malloc(sizeof(*table)); + if (table == NULL) + return (ISC_R_NOMEMORY); + table->base = base; + table->last = base + nresults - 1; + table->text = txt; + table->msgcat = msgcat; + table->set = set; + ISC_LINK_INIT(table, link); + + LOCK(&lock); + + ISC_LIST_APPEND(tables, table, link); + + UNLOCK(&lock); + + return (ISC_R_SUCCESS); +} + +static void +initialize_action(void) { + isc_result_t result; + + RUNTIME_CHECK(isc_mutex_init(&lock) == ISC_R_SUCCESS); + ISC_LIST_INIT(tables); + + result = register_table(ISC_RESULTCLASS_ISC, ISC_R_NRESULTS, text, + isc_msgcat, ISC_RESULT_RESULTSET); + if (result != ISC_R_SUCCESS) + UNEXPECTED_ERROR(__FILE__, __LINE__, + "register_table() %s: %u", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed"), + result); +} + +static void +initialize(void) { + isc_lib_initmsgcat(); + RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); +} + +const char * +isc_result_totext(isc_result_t result) { + resulttable *table; + const char *txt, *default_text; + int index; + + initialize(); + + LOCK(&lock); + + txt = NULL; + for (table = ISC_LIST_HEAD(tables); + table != NULL; + table = ISC_LIST_NEXT(table, link)) { + if (result >= table->base && result <= table->last) { + index = (int)(result - table->base); + default_text = table->text[index]; + /* + * Note: we use 'index + 1' as the message number + * instead of index because isc_msgcat_get() requires + * the message number to be > 0. + */ + txt = isc_msgcat_get(table->msgcat, table->set, + index + 1, default_text); + break; + } + } + if (txt == NULL) + txt = isc_msgcat_get(isc_msgcat, ISC_RESULT_UNAVAILABLESET, + 1, "(result code text not available)"); + + UNLOCK(&lock); + + return (txt); +} + +isc_result_t +isc_result_register(unsigned int base, unsigned int nresults, + const char **txt, isc_msgcat_t *msgcat, int set) +{ + initialize(); + + return (register_table(base, nresults, txt, msgcat, set)); +} diff --git a/contrib/ntp/lib/isc/rwlock.c b/contrib/ntp/lib/isc/rwlock.c new file mode 100644 index 0000000..9c84c25 --- /dev/null +++ b/contrib/ntp/lib/isc/rwlock.c @@ -0,0 +1,809 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2001, 2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/*! \file */ + +#include <config.h> + +#include <stddef.h> + +#include <isc/atomic.h> +#include <isc/magic.h> +#include <isc/msgs.h> +#include <isc/platform.h> +#include <isc/rwlock.h> +#include <isc/util.h> + +#define RWLOCK_MAGIC ISC_MAGIC('R', 'W', 'L', 'k') +#define VALID_RWLOCK(rwl) ISC_MAGIC_VALID(rwl, RWLOCK_MAGIC) + +#ifdef ISC_PLATFORM_USETHREADS + +#ifndef RWLOCK_DEFAULT_READ_QUOTA +#define RWLOCK_DEFAULT_READ_QUOTA 4 +#endif + +#ifndef RWLOCK_DEFAULT_WRITE_QUOTA +#define RWLOCK_DEFAULT_WRITE_QUOTA 4 +#endif + +#ifdef ISC_RWLOCK_TRACE +#include <stdio.h> /* Required for fprintf/stderr. */ +#include <isc/thread.h> /* Required for isc_thread_self(). */ + +static void +print_lock(const char *operation, isc_rwlock_t *rwl, isc_rwlocktype_t type) { + fprintf(stderr, + isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK, + ISC_MSG_PRINTLOCK, + "rwlock %p thread %lu %s(%s): %s, %u active, " + "%u granted, %u rwaiting, %u wwaiting\n"), + rwl, isc_thread_self(), operation, + (type == isc_rwlocktype_read ? + isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK, + ISC_MSG_READ, "read") : + isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK, + ISC_MSG_WRITE, "write")), + (rwl->type == isc_rwlocktype_read ? + isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK, + ISC_MSG_READING, "reading") : + isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK, + ISC_MSG_WRITING, "writing")), + rwl->active, rwl->granted, rwl->readers_waiting, + rwl->writers_waiting); +} +#endif + +isc_result_t +isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota, + unsigned int write_quota) +{ + isc_result_t result; + + REQUIRE(rwl != NULL); + + /* + * In case there's trouble initializing, we zero magic now. If all + * goes well, we'll set it to RWLOCK_MAGIC. + */ + rwl->magic = 0; + +#if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG) + rwl->write_requests = 0; + rwl->write_completions = 0; + rwl->cnt_and_flag = 0; + rwl->readers_waiting = 0; + rwl->write_granted = 0; + if (read_quota != 0) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "read quota is not supported"); + } + if (write_quota == 0) + write_quota = RWLOCK_DEFAULT_WRITE_QUOTA; + rwl->write_quota = write_quota; +#else + rwl->type = isc_rwlocktype_read; + rwl->original = isc_rwlocktype_none; + rwl->active = 0; + rwl->granted = 0; + rwl->readers_waiting = 0; + rwl->writers_waiting = 0; + if (read_quota == 0) + read_quota = RWLOCK_DEFAULT_READ_QUOTA; + rwl->read_quota = read_quota; + if (write_quota == 0) + write_quota = RWLOCK_DEFAULT_WRITE_QUOTA; + rwl->write_quota = write_quota; +#endif + + result = isc_mutex_init(&rwl->lock); + if (result != ISC_R_SUCCESS) + return (result); + + result = isc_condition_init(&rwl->readable); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_condition_init(readable) %s: %s", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed"), + isc_result_totext(result)); + result = ISC_R_UNEXPECTED; + goto destroy_lock; + } + result = isc_condition_init(&rwl->writeable); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_condition_init(writeable) %s: %s", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed"), + isc_result_totext(result)); + result = ISC_R_UNEXPECTED; + goto destroy_rcond; + } + + rwl->magic = RWLOCK_MAGIC; + + return (ISC_R_SUCCESS); + + destroy_rcond: + (void)isc_condition_destroy(&rwl->readable); + destroy_lock: + DESTROYLOCK(&rwl->lock); + + return (result); +} + +void +isc_rwlock_destroy(isc_rwlock_t *rwl) { + REQUIRE(VALID_RWLOCK(rwl)); + +#if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG) + REQUIRE(rwl->write_requests == rwl->write_completions && + rwl->cnt_and_flag == 0 && rwl->readers_waiting == 0); +#else + LOCK(&rwl->lock); + REQUIRE(rwl->active == 0 && + rwl->readers_waiting == 0 && + rwl->writers_waiting == 0); + UNLOCK(&rwl->lock); +#endif + + rwl->magic = 0; + (void)isc_condition_destroy(&rwl->readable); + (void)isc_condition_destroy(&rwl->writeable); + DESTROYLOCK(&rwl->lock); +} + +#if defined(ISC_PLATFORM_HAVEXADD) && defined(ISC_PLATFORM_HAVECMPXCHG) + +/* + * When some architecture-dependent atomic operations are available, + * rwlock can be more efficient than the generic algorithm defined below. + * The basic algorithm is described in the following URL: + * http://www.cs.rochester.edu/u/scott/synchronization/pseudocode/rw.html + * + * The key is to use the following integer variables modified atomically: + * write_requests, write_completions, and cnt_and_flag. + * + * write_requests and write_completions act as a waiting queue for writers + * in order to ensure the FIFO order. Both variables begin with the initial + * value of 0. When a new writer tries to get a write lock, it increments + * write_requests and gets the previous value of the variable as a "ticket". + * When write_completions reaches the ticket number, the new writer can start + * writing. When the writer completes its work, it increments + * write_completions so that another new writer can start working. If the + * write_requests is not equal to write_completions, it means a writer is now + * working or waiting. In this case, a new readers cannot start reading, or + * in other words, this algorithm basically prefers writers. + * + * cnt_and_flag is a "lock" shared by all readers and writers. This integer + * variable is a kind of structure with two members: writer_flag (1 bit) and + * reader_count (31 bits). The writer_flag shows whether a writer is working, + * and the reader_count shows the number of readers currently working or almost + * ready for working. A writer who has the current "ticket" tries to get the + * lock by exclusively setting the writer_flag to 1, provided that the whole + * 32-bit is 0 (meaning no readers or writers working). On the other hand, + * a new reader tries to increment the "reader_count" field provided that + * the writer_flag is 0 (meaning there is no writer working). + * + * If some of the above operations fail, the reader or the writer sleeps + * until the related condition changes. When a working reader or writer + * completes its work, some readers or writers are sleeping, and the condition + * that suspended the reader or writer has changed, it wakes up the sleeping + * readers or writers. + * + * As already noted, this algorithm basically prefers writers. In order to + * prevent readers from starving, however, the algorithm also introduces the + * "writer quota" (Q). When Q consecutive writers have completed their work, + * suspending readers, the last writer will wake up the readers, even if a new + * writer is waiting. + * + * Implementation specific note: due to the combination of atomic operations + * and a mutex lock, ordering between the atomic operation and locks can be + * very sensitive in some cases. In particular, it is generally very important + * to check the atomic variable that requires a reader or writer to sleep after + * locking the mutex and before actually sleeping; otherwise, it could be very + * likely to cause a deadlock. For example, assume "var" is a variable + * atomically modified, then the corresponding code would be: + * if (var == need_sleep) { + * LOCK(lock); + * if (var == need_sleep) + * WAIT(cond, lock); + * UNLOCK(lock); + * } + * The second check is important, since "var" is protected by the atomic + * operation, not by the mutex, and can be changed just before sleeping. + * (The first "if" could be omitted, but this is also important in order to + * make the code efficient by avoiding the use of the mutex unless it is + * really necessary.) + */ + +#define WRITER_ACTIVE 0x1 +#define READER_INCR 0x2 + +isc_result_t +isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) { + isc_int32_t cntflag; + + REQUIRE(VALID_RWLOCK(rwl)); + +#ifdef ISC_RWLOCK_TRACE + print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK, + ISC_MSG_PRELOCK, "prelock"), rwl, type); +#endif + + if (type == isc_rwlocktype_read) { + if (rwl->write_requests != rwl->write_completions) { + /* there is a waiting or active writer */ + LOCK(&rwl->lock); + if (rwl->write_requests != rwl->write_completions) { + rwl->readers_waiting++; + WAIT(&rwl->readable, &rwl->lock); + rwl->readers_waiting--; + } + UNLOCK(&rwl->lock); + } + + cntflag = isc_atomic_xadd(&rwl->cnt_and_flag, READER_INCR); + POST(cntflag); + while (1) { + if ((rwl->cnt_and_flag & WRITER_ACTIVE) == 0) + break; + + /* A writer is still working */ + LOCK(&rwl->lock); + rwl->readers_waiting++; + if ((rwl->cnt_and_flag & WRITER_ACTIVE) != 0) + WAIT(&rwl->readable, &rwl->lock); + rwl->readers_waiting--; + UNLOCK(&rwl->lock); + + /* + * Typically, the reader should be able to get a lock + * at this stage: + * (1) there should have been no pending writer when + * the reader was trying to increment the + * counter; otherwise, the writer should be in + * the waiting queue, preventing the reader from + * proceeding to this point. + * (2) once the reader increments the counter, no + * more writer can get a lock. + * Still, it is possible another writer can work at + * this point, e.g. in the following scenario: + * A previous writer unlocks the writer lock. + * This reader proceeds to point (1). + * A new writer appears, and gets a new lock before + * the reader increments the counter. + * The reader then increments the counter. + * The previous writer notices there is a waiting + * reader who is almost ready, and wakes it up. + * So, the reader needs to confirm whether it can now + * read explicitly (thus we loop). Note that this is + * not an infinite process, since the reader has + * incremented the counter at this point. + */ + } + + /* + * If we are temporarily preferred to writers due to the writer + * quota, reset the condition (race among readers doesn't + * matter). + */ + rwl->write_granted = 0; + } else { + isc_int32_t prev_writer; + + /* enter the waiting queue, and wait for our turn */ + prev_writer = isc_atomic_xadd(&rwl->write_requests, 1); + while (rwl->write_completions != prev_writer) { + LOCK(&rwl->lock); + if (rwl->write_completions != prev_writer) { + WAIT(&rwl->writeable, &rwl->lock); + UNLOCK(&rwl->lock); + continue; + } + UNLOCK(&rwl->lock); + break; + } + + while (1) { + cntflag = isc_atomic_cmpxchg(&rwl->cnt_and_flag, 0, + WRITER_ACTIVE); + if (cntflag == 0) + break; + + /* Another active reader or writer is working. */ + LOCK(&rwl->lock); + if (rwl->cnt_and_flag != 0) + WAIT(&rwl->writeable, &rwl->lock); + UNLOCK(&rwl->lock); + } + + INSIST((rwl->cnt_and_flag & WRITER_ACTIVE) != 0); + rwl->write_granted++; + } + +#ifdef ISC_RWLOCK_TRACE + print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK, + ISC_MSG_POSTLOCK, "postlock"), rwl, type); +#endif + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type) { + isc_int32_t cntflag; + + REQUIRE(VALID_RWLOCK(rwl)); + +#ifdef ISC_RWLOCK_TRACE + print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK, + ISC_MSG_PRELOCK, "prelock"), rwl, type); +#endif + + if (type == isc_rwlocktype_read) { + /* If a writer is waiting or working, we fail. */ + if (rwl->write_requests != rwl->write_completions) + return (ISC_R_LOCKBUSY); + + /* Otherwise, be ready for reading. */ + cntflag = isc_atomic_xadd(&rwl->cnt_and_flag, READER_INCR); + if ((cntflag & WRITER_ACTIVE) != 0) { + /* + * A writer is working. We lose, and cancel the read + * request. + */ + cntflag = isc_atomic_xadd(&rwl->cnt_and_flag, + -READER_INCR); + /* + * If no other readers are waiting and we've suspended + * new writers in this short period, wake them up. + */ + if (cntflag == READER_INCR && + rwl->write_completions != rwl->write_requests) { + LOCK(&rwl->lock); + BROADCAST(&rwl->writeable); + UNLOCK(&rwl->lock); + } + + return (ISC_R_LOCKBUSY); + } + } else { + /* Try locking without entering the waiting queue. */ + cntflag = isc_atomic_cmpxchg(&rwl->cnt_and_flag, 0, + WRITER_ACTIVE); + if (cntflag != 0) + return (ISC_R_LOCKBUSY); + + /* + * XXXJT: jump into the queue, possibly breaking the writer + * order. + */ + (void)isc_atomic_xadd(&rwl->write_completions, -1); + + rwl->write_granted++; + } + +#ifdef ISC_RWLOCK_TRACE + print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK, + ISC_MSG_POSTLOCK, "postlock"), rwl, type); +#endif + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_rwlock_tryupgrade(isc_rwlock_t *rwl) { + isc_int32_t prevcnt; + + REQUIRE(VALID_RWLOCK(rwl)); + + /* Try to acquire write access. */ + prevcnt = isc_atomic_cmpxchg(&rwl->cnt_and_flag, + READER_INCR, WRITER_ACTIVE); + /* + * There must have been no writer, and there must have been at least + * one reader. + */ + INSIST((prevcnt & WRITER_ACTIVE) == 0 && + (prevcnt & ~WRITER_ACTIVE) != 0); + + if (prevcnt == READER_INCR) { + /* + * We are the only reader and have been upgraded. + * Now jump into the head of the writer waiting queue. + */ + (void)isc_atomic_xadd(&rwl->write_completions, -1); + } else + return (ISC_R_LOCKBUSY); + + return (ISC_R_SUCCESS); + +} + +void +isc_rwlock_downgrade(isc_rwlock_t *rwl) { + isc_int32_t prev_readers; + + REQUIRE(VALID_RWLOCK(rwl)); + + /* Become an active reader. */ + prev_readers = isc_atomic_xadd(&rwl->cnt_and_flag, READER_INCR); + /* We must have been a writer. */ + INSIST((prev_readers & WRITER_ACTIVE) != 0); + + /* Complete write */ + (void)isc_atomic_xadd(&rwl->cnt_and_flag, -WRITER_ACTIVE); + (void)isc_atomic_xadd(&rwl->write_completions, 1); + + /* Resume other readers */ + LOCK(&rwl->lock); + if (rwl->readers_waiting > 0) + BROADCAST(&rwl->readable); + UNLOCK(&rwl->lock); +} + +isc_result_t +isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) { + isc_int32_t prev_cnt; + + REQUIRE(VALID_RWLOCK(rwl)); + +#ifdef ISC_RWLOCK_TRACE + print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK, + ISC_MSG_PREUNLOCK, "preunlock"), rwl, type); +#endif + + if (type == isc_rwlocktype_read) { + prev_cnt = isc_atomic_xadd(&rwl->cnt_and_flag, -READER_INCR); + + /* + * If we're the last reader and any writers are waiting, wake + * them up. We need to wake up all of them to ensure the + * FIFO order. + */ + if (prev_cnt == READER_INCR && + rwl->write_completions != rwl->write_requests) { + LOCK(&rwl->lock); + BROADCAST(&rwl->writeable); + UNLOCK(&rwl->lock); + } + } else { + isc_boolean_t wakeup_writers = ISC_TRUE; + + /* + * Reset the flag, and (implicitly) tell other writers + * we are done. + */ + (void)isc_atomic_xadd(&rwl->cnt_and_flag, -WRITER_ACTIVE); + (void)isc_atomic_xadd(&rwl->write_completions, 1); + + if (rwl->write_granted >= rwl->write_quota || + rwl->write_requests == rwl->write_completions || + (rwl->cnt_and_flag & ~WRITER_ACTIVE) != 0) { + /* + * We have passed the write quota, no writer is + * waiting, or some readers are almost ready, pending + * possible writers. Note that the last case can + * happen even if write_requests != write_completions + * (which means a new writer in the queue), so we need + * to catch the case explicitly. + */ + LOCK(&rwl->lock); + if (rwl->readers_waiting > 0) { + wakeup_writers = ISC_FALSE; + BROADCAST(&rwl->readable); + } + UNLOCK(&rwl->lock); + } + + if (rwl->write_requests != rwl->write_completions && + wakeup_writers) { + LOCK(&rwl->lock); + BROADCAST(&rwl->writeable); + UNLOCK(&rwl->lock); + } + } + +#ifdef ISC_RWLOCK_TRACE + print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK, + ISC_MSG_POSTUNLOCK, "postunlock"), + rwl, type); +#endif + + return (ISC_R_SUCCESS); +} + +#else /* ISC_PLATFORM_HAVEXADD && ISC_PLATFORM_HAVECMPXCHG */ + +static isc_result_t +doit(isc_rwlock_t *rwl, isc_rwlocktype_t type, isc_boolean_t nonblock) { + isc_boolean_t skip = ISC_FALSE; + isc_boolean_t done = ISC_FALSE; + isc_result_t result = ISC_R_SUCCESS; + + REQUIRE(VALID_RWLOCK(rwl)); + + LOCK(&rwl->lock); + +#ifdef ISC_RWLOCK_TRACE + print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK, + ISC_MSG_PRELOCK, "prelock"), rwl, type); +#endif + + if (type == isc_rwlocktype_read) { + if (rwl->readers_waiting != 0) + skip = ISC_TRUE; + while (!done) { + if (!skip && + ((rwl->active == 0 || + (rwl->type == isc_rwlocktype_read && + (rwl->writers_waiting == 0 || + rwl->granted < rwl->read_quota))))) + { + rwl->type = isc_rwlocktype_read; + rwl->active++; + rwl->granted++; + done = ISC_TRUE; + } else if (nonblock) { + result = ISC_R_LOCKBUSY; + done = ISC_TRUE; + } else { + skip = ISC_FALSE; + rwl->readers_waiting++; + WAIT(&rwl->readable, &rwl->lock); + rwl->readers_waiting--; + } + } + } else { + if (rwl->writers_waiting != 0) + skip = ISC_TRUE; + while (!done) { + if (!skip && rwl->active == 0) { + rwl->type = isc_rwlocktype_write; + rwl->active = 1; + rwl->granted++; + done = ISC_TRUE; + } else if (nonblock) { + result = ISC_R_LOCKBUSY; + done = ISC_TRUE; + } else { + skip = ISC_FALSE; + rwl->writers_waiting++; + WAIT(&rwl->writeable, &rwl->lock); + rwl->writers_waiting--; + } + } + } + +#ifdef ISC_RWLOCK_TRACE + print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK, + ISC_MSG_POSTLOCK, "postlock"), rwl, type); +#endif + + UNLOCK(&rwl->lock); + + return (result); +} + +isc_result_t +isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) { + return (doit(rwl, type, ISC_FALSE)); +} + +isc_result_t +isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type) { + return (doit(rwl, type, ISC_TRUE)); +} + +isc_result_t +isc_rwlock_tryupgrade(isc_rwlock_t *rwl) { + isc_result_t result = ISC_R_SUCCESS; + + REQUIRE(VALID_RWLOCK(rwl)); + LOCK(&rwl->lock); + REQUIRE(rwl->type == isc_rwlocktype_read); + REQUIRE(rwl->active != 0); + + /* If we are the only reader then succeed. */ + if (rwl->active == 1) { + rwl->original = (rwl->original == isc_rwlocktype_none) ? + isc_rwlocktype_read : isc_rwlocktype_none; + rwl->type = isc_rwlocktype_write; + } else + result = ISC_R_LOCKBUSY; + + UNLOCK(&rwl->lock); + return (result); +} + +void +isc_rwlock_downgrade(isc_rwlock_t *rwl) { + + REQUIRE(VALID_RWLOCK(rwl)); + LOCK(&rwl->lock); + REQUIRE(rwl->type == isc_rwlocktype_write); + REQUIRE(rwl->active == 1); + + rwl->type = isc_rwlocktype_read; + rwl->original = (rwl->original == isc_rwlocktype_none) ? + isc_rwlocktype_write : isc_rwlocktype_none; + /* + * Resume processing any read request that were blocked when + * we upgraded. + */ + if (rwl->original == isc_rwlocktype_none && + (rwl->writers_waiting == 0 || rwl->granted < rwl->read_quota) && + rwl->readers_waiting > 0) + BROADCAST(&rwl->readable); + + UNLOCK(&rwl->lock); +} + +isc_result_t +isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) { + + REQUIRE(VALID_RWLOCK(rwl)); + LOCK(&rwl->lock); + REQUIRE(rwl->type == type); + + UNUSED(type); + +#ifdef ISC_RWLOCK_TRACE + print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK, + ISC_MSG_PREUNLOCK, "preunlock"), rwl, type); +#endif + + INSIST(rwl->active > 0); + rwl->active--; + if (rwl->active == 0) { + if (rwl->original != isc_rwlocktype_none) { + rwl->type = rwl->original; + rwl->original = isc_rwlocktype_none; + } + if (rwl->type == isc_rwlocktype_read) { + rwl->granted = 0; + if (rwl->writers_waiting > 0) { + rwl->type = isc_rwlocktype_write; + SIGNAL(&rwl->writeable); + } else if (rwl->readers_waiting > 0) { + /* Does this case ever happen? */ + BROADCAST(&rwl->readable); + } + } else { + if (rwl->readers_waiting > 0) { + if (rwl->writers_waiting > 0 && + rwl->granted < rwl->write_quota) { + SIGNAL(&rwl->writeable); + } else { + rwl->granted = 0; + rwl->type = isc_rwlocktype_read; + BROADCAST(&rwl->readable); + } + } else if (rwl->writers_waiting > 0) { + rwl->granted = 0; + SIGNAL(&rwl->writeable); + } else { + rwl->granted = 0; + } + } + } + INSIST(rwl->original == isc_rwlocktype_none); + +#ifdef ISC_RWLOCK_TRACE + print_lock(isc_msgcat_get(isc_msgcat, ISC_MSGSET_RWLOCK, + ISC_MSG_POSTUNLOCK, "postunlock"), + rwl, type); +#endif + + UNLOCK(&rwl->lock); + + return (ISC_R_SUCCESS); +} + +#endif /* ISC_PLATFORM_HAVEXADD && ISC_PLATFORM_HAVECMPXCHG */ +#else /* ISC_PLATFORM_USETHREADS */ + +isc_result_t +isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota, + unsigned int write_quota) +{ + REQUIRE(rwl != NULL); + + UNUSED(read_quota); + UNUSED(write_quota); + + rwl->type = isc_rwlocktype_read; + rwl->active = 0; + rwl->magic = RWLOCK_MAGIC; + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) { + REQUIRE(VALID_RWLOCK(rwl)); + + if (type == isc_rwlocktype_read) { + if (rwl->type != isc_rwlocktype_read && rwl->active != 0) + return (ISC_R_LOCKBUSY); + rwl->type = isc_rwlocktype_read; + rwl->active++; + } else { + if (rwl->active != 0) + return (ISC_R_LOCKBUSY); + rwl->type = isc_rwlocktype_write; + rwl->active = 1; + } + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type) { + return (isc_rwlock_lock(rwl, type)); +} + +isc_result_t +isc_rwlock_tryupgrade(isc_rwlock_t *rwl) { + isc_result_t result = ISC_R_SUCCESS; + + REQUIRE(VALID_RWLOCK(rwl)); + REQUIRE(rwl->type == isc_rwlocktype_read); + REQUIRE(rwl->active != 0); + + /* If we are the only reader then succeed. */ + if (rwl->active == 1) + rwl->type = isc_rwlocktype_write; + else + result = ISC_R_LOCKBUSY; + return (result); +} + +void +isc_rwlock_downgrade(isc_rwlock_t *rwl) { + + REQUIRE(VALID_RWLOCK(rwl)); + REQUIRE(rwl->type == isc_rwlocktype_write); + REQUIRE(rwl->active == 1); + + rwl->type = isc_rwlocktype_read; +} + +isc_result_t +isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) { + REQUIRE(VALID_RWLOCK(rwl)); + REQUIRE(rwl->type == type); + + UNUSED(type); + + INSIST(rwl->active > 0); + rwl->active--; + + return (ISC_R_SUCCESS); +} + +void +isc_rwlock_destroy(isc_rwlock_t *rwl) { + REQUIRE(rwl != NULL); + REQUIRE(rwl->active == 0); + rwl->magic = 0; +} + +#endif /* ISC_PLATFORM_USETHREADS */ diff --git a/contrib/ntp/lib/isc/serial.c b/contrib/ntp/lib/isc/serial.c new file mode 100644 index 0000000..b43aac7 --- /dev/null +++ b/contrib/ntp/lib/isc/serial.c @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: serial.c,v 1.12 2007/06/19 23:47:17 tbox Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <isc/serial.h> + +isc_boolean_t +isc_serial_lt(isc_uint32_t a, isc_uint32_t b) { + /* + * Undefined => ISC_FALSE + */ + if (a == (b ^ 0x80000000U)) + return (ISC_FALSE); + return (((isc_int32_t)(a - b) < 0) ? ISC_TRUE : ISC_FALSE); +} + +isc_boolean_t +isc_serial_gt(isc_uint32_t a, isc_uint32_t b) { + return (((isc_int32_t)(a - b) > 0) ? ISC_TRUE : ISC_FALSE); +} + +isc_boolean_t +isc_serial_le(isc_uint32_t a, isc_uint32_t b) { + return ((a == b) ? ISC_TRUE : isc_serial_lt(a, b)); +} + +isc_boolean_t +isc_serial_ge(isc_uint32_t a, isc_uint32_t b) { + return ((a == b) ? ISC_TRUE : isc_serial_gt(a, b)); +} + +isc_boolean_t +isc_serial_eq(isc_uint32_t a, isc_uint32_t b) { + return ((a == b) ? ISC_TRUE : ISC_FALSE); +} + +isc_boolean_t +isc_serial_ne(isc_uint32_t a, isc_uint32_t b) { + return ((a != b) ? ISC_TRUE : ISC_FALSE); +} diff --git a/contrib/ntp/lib/isc/sha1.c b/contrib/ntp/lib/isc/sha1.c new file mode 100644 index 0000000..cce9603 --- /dev/null +++ b/contrib/ntp/lib/isc/sha1.c @@ -0,0 +1,354 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001, 2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/* $NetBSD: sha1.c,v 1.5 2000/01/22 22:19:14 mycroft Exp $ */ +/* $OpenBSD: sha1.c,v 1.9 1997/07/23 21:12:32 kstailey Exp $ */ + +/*! \file + * SHA-1 in C + * \author By Steve Reid <steve@edmweb.com> + * 100% Public Domain + * \verbatim + * Test Vectors (from FIPS PUB 180-1) + * "abc" + * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D + * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 + * A million repetitions of "a" + * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F + * \endverbatim + */ + +#include "config.h" + +#include <isc/assertions.h> +#include <isc/platform.h> +#include <isc/sha1.h> +#include <isc/string.h> +#include <isc/types.h> +#include <isc/util.h> + +#ifdef ISC_PLATFORM_OPENSSLHASH + +void +isc_sha1_init(isc_sha1_t *context) +{ + INSIST(context != NULL); + + EVP_DigestInit(context, EVP_sha1()); +} + +void +isc_sha1_invalidate(isc_sha1_t *context) { + EVP_MD_CTX_cleanup(context); +} + +void +isc_sha1_update(isc_sha1_t *context, const unsigned char *data, + unsigned int len) +{ + INSIST(context != 0); + INSIST(data != 0); + + EVP_DigestUpdate(context, (const void *) data, (size_t) len); +} + +void +isc_sha1_final(isc_sha1_t *context, unsigned char *digest) { + INSIST(digest != 0); + INSIST(context != 0); + + EVP_DigestFinal(context, digest, NULL); +} + +#else + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/*@{*/ +/*! + * blk0() and blk() perform the initial expand. + * I got the idea of expanding during the round function from SSLeay + */ +#if !defined(WORDS_BIGENDIAN) +# define blk0(i) \ + (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) \ + | (rol(block->l[i], 8) & 0x00FF00FF)) +#else +# define blk0(i) block->l[i] +#endif +#define blk(i) \ + (block->l[i & 15] = rol(block->l[(i + 13) & 15] \ + ^ block->l[(i + 8) & 15] \ + ^ block->l[(i + 2) & 15] \ + ^ block->l[i & 15], 1)) + +/*@}*/ +/*@{*/ +/*! + * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1 + */ +#define R0(v,w,x,y,z,i) \ + z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); +#define R1(v,w,x,y,z,i) \ + z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); +#define R2(v,w,x,y,z,i) \ + z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \ + w = rol(w, 30); +#define R3(v,w,x,y,z,i) \ + z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ + w = rol(w, 30); +#define R4(v,w,x,y,z,i) \ + z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ + w = rol(w, 30); + +/*@}*/ + +typedef union { + unsigned char c[64]; + unsigned int l[16]; +} CHAR64LONG16; + +#ifdef __sparc_v9__ +static void do_R01(isc_uint32_t *a, isc_uint32_t *b, isc_uint32_t *c, + isc_uint32_t *d, isc_uint32_t *e, CHAR64LONG16 *); +static void do_R2(isc_uint32_t *a, isc_uint32_t *b, isc_uint32_t *c, + isc_uint32_t *d, isc_uint32_t *e, CHAR64LONG16 *); +static void do_R3(isc_uint32_t *a, isc_uint32_t *b, isc_uint32_t *c, + isc_uint32_t *d, isc_uint32_t *e, CHAR64LONG16 *); +static void do_R4(isc_uint32_t *a, isc_uint32_t *b, isc_uint32_t *c, + isc_uint32_t *d, isc_uint32_t *e, CHAR64LONG16 *); + +#define nR0(v,w,x,y,z,i) R0(*v,*w,*x,*y,*z,i) +#define nR1(v,w,x,y,z,i) R1(*v,*w,*x,*y,*z,i) +#define nR2(v,w,x,y,z,i) R2(*v,*w,*x,*y,*z,i) +#define nR3(v,w,x,y,z,i) R3(*v,*w,*x,*y,*z,i) +#define nR4(v,w,x,y,z,i) R4(*v,*w,*x,*y,*z,i) + +static void +do_R01(isc_uint32_t *a, isc_uint32_t *b, isc_uint32_t *c, isc_uint32_t *d, + isc_uint32_t *e, CHAR64LONG16 *block) +{ + nR0(a,b,c,d,e, 0); nR0(e,a,b,c,d, 1); nR0(d,e,a,b,c, 2); + nR0(c,d,e,a,b, 3); nR0(b,c,d,e,a, 4); nR0(a,b,c,d,e, 5); + nR0(e,a,b,c,d, 6); nR0(d,e,a,b,c, 7); nR0(c,d,e,a,b, 8); + nR0(b,c,d,e,a, 9); nR0(a,b,c,d,e,10); nR0(e,a,b,c,d,11); + nR0(d,e,a,b,c,12); nR0(c,d,e,a,b,13); nR0(b,c,d,e,a,14); + nR0(a,b,c,d,e,15); nR1(e,a,b,c,d,16); nR1(d,e,a,b,c,17); + nR1(c,d,e,a,b,18); nR1(b,c,d,e,a,19); +} + +static void +do_R2(isc_uint32_t *a, isc_uint32_t *b, isc_uint32_t *c, isc_uint32_t *d, + isc_uint32_t *e, CHAR64LONG16 *block) +{ + nR2(a,b,c,d,e,20); nR2(e,a,b,c,d,21); nR2(d,e,a,b,c,22); + nR2(c,d,e,a,b,23); nR2(b,c,d,e,a,24); nR2(a,b,c,d,e,25); + nR2(e,a,b,c,d,26); nR2(d,e,a,b,c,27); nR2(c,d,e,a,b,28); + nR2(b,c,d,e,a,29); nR2(a,b,c,d,e,30); nR2(e,a,b,c,d,31); + nR2(d,e,a,b,c,32); nR2(c,d,e,a,b,33); nR2(b,c,d,e,a,34); + nR2(a,b,c,d,e,35); nR2(e,a,b,c,d,36); nR2(d,e,a,b,c,37); + nR2(c,d,e,a,b,38); nR2(b,c,d,e,a,39); +} + +static void +do_R3(isc_uint32_t *a, isc_uint32_t *b, isc_uint32_t *c, isc_uint32_t *d, + isc_uint32_t *e, CHAR64LONG16 *block) +{ + nR3(a,b,c,d,e,40); nR3(e,a,b,c,d,41); nR3(d,e,a,b,c,42); + nR3(c,d,e,a,b,43); nR3(b,c,d,e,a,44); nR3(a,b,c,d,e,45); + nR3(e,a,b,c,d,46); nR3(d,e,a,b,c,47); nR3(c,d,e,a,b,48); + nR3(b,c,d,e,a,49); nR3(a,b,c,d,e,50); nR3(e,a,b,c,d,51); + nR3(d,e,a,b,c,52); nR3(c,d,e,a,b,53); nR3(b,c,d,e,a,54); + nR3(a,b,c,d,e,55); nR3(e,a,b,c,d,56); nR3(d,e,a,b,c,57); + nR3(c,d,e,a,b,58); nR3(b,c,d,e,a,59); +} + +static void +do_R4(isc_uint32_t *a, isc_uint32_t *b, isc_uint32_t *c, isc_uint32_t *d, + isc_uint32_t *e, CHAR64LONG16 *block) +{ + nR4(a,b,c,d,e,60); nR4(e,a,b,c,d,61); nR4(d,e,a,b,c,62); + nR4(c,d,e,a,b,63); nR4(b,c,d,e,a,64); nR4(a,b,c,d,e,65); + nR4(e,a,b,c,d,66); nR4(d,e,a,b,c,67); nR4(c,d,e,a,b,68); + nR4(b,c,d,e,a,69); nR4(a,b,c,d,e,70); nR4(e,a,b,c,d,71); + nR4(d,e,a,b,c,72); nR4(c,d,e,a,b,73); nR4(b,c,d,e,a,74); + nR4(a,b,c,d,e,75); nR4(e,a,b,c,d,76); nR4(d,e,a,b,c,77); + nR4(c,d,e,a,b,78); nR4(b,c,d,e,a,79); +} +#endif + +/*! + * Hash a single 512-bit block. This is the core of the algorithm. + */ +static void +transform(isc_uint32_t state[5], const unsigned char buffer[64]) { + isc_uint32_t a, b, c, d, e; + CHAR64LONG16 *block; + CHAR64LONG16 workspace; + + INSIST(buffer != NULL); + INSIST(state != NULL); + + block = &workspace; + (void)memcpy(block, buffer, 64); + + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + +#ifdef __sparc_v9__ + do_R01(&a, &b, &c, &d, &e, block); + do_R2(&a, &b, &c, &d, &e, block); + do_R3(&a, &b, &c, &d, &e, block); + do_R4(&a, &b, &c, &d, &e, block); +#else + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); +#endif + + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + + /* Wipe variables */ + a = b = c = d = e = 0; + /* Avoid compiler warnings */ + POST(a); POST(b); POST(c); POST(d); POST(e); +} + + +/*! + * isc_sha1_init - Initialize new context + */ +void +isc_sha1_init(isc_sha1_t *context) +{ + INSIST(context != NULL); + + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = 0; + context->count[1] = 0; +} + +void +isc_sha1_invalidate(isc_sha1_t *context) { + memset(context, 0, sizeof(isc_sha1_t)); +} + +/*! + * Run your data through this. + */ +void +isc_sha1_update(isc_sha1_t *context, const unsigned char *data, + unsigned int len) +{ + unsigned int i, j; + + INSIST(context != 0); + INSIST(data != 0); + + j = context->count[0]; + if ((context->count[0] += len << 3) < j) + context->count[1] += (len >> 29) + 1; + j = (j >> 3) & 63; + if ((j + len) > 63) { + (void)memcpy(&context->buffer[j], data, (i = 64 - j)); + transform(context->state, context->buffer); + for (; i + 63 < len; i += 64) + transform(context->state, &data[i]); + j = 0; + } else { + i = 0; + } + + (void)memcpy(&context->buffer[j], &data[i], len - i); +} + + +/*! + * Add padding and return the message digest. + */ + +static const unsigned char final_200 = 128; +static const unsigned char final_0 = 0; + +void +isc_sha1_final(isc_sha1_t *context, unsigned char *digest) { + unsigned int i; + unsigned char finalcount[8]; + + INSIST(digest != 0); + INSIST(context != 0); + + for (i = 0; i < 8; i++) { + /* Endian independent */ + finalcount[i] = (unsigned char) + ((context->count[(i >= 4 ? 0 : 1)] + >> ((3 - (i & 3)) * 8)) & 255); + } + + isc_sha1_update(context, &final_200, 1); + while ((context->count[0] & 504) != 448) + isc_sha1_update(context, &final_0, 1); + /* The next Update should cause a transform() */ + isc_sha1_update(context, finalcount, 8); + + if (digest) { + for (i = 0; i < 20; i++) + digest[i] = (unsigned char) + ((context->state[i >> 2] + >> ((3 - (i & 3)) * 8)) & 255); + } + + memset(context, 0, sizeof(isc_sha1_t)); +} +#endif diff --git a/contrib/ntp/lib/isc/sha2.c b/contrib/ntp/lib/isc/sha2.c new file mode 100644 index 0000000..5a1d708 --- /dev/null +++ b/contrib/ntp/lib/isc/sha2.c @@ -0,0 +1,1449 @@ +/* + * Copyright (C) 2005-2007, 2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/* $FreeBSD: 258945 2013-12-04 21:33:17Z roberto $ */ +/* $KAME: sha2.c,v 1.8 2001/11/08 01:07:52 itojun Exp $ */ + +/* + * sha2.c + * + * Version 1.0.0beta1 + * + * Written by Aaron D. Gifford <me@aarongifford.com> + * + * Copyright 2000 Aaron D. Gifford. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTOR(S) ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + + +#include <config.h> + +#include <isc/assertions.h> +#include <isc/platform.h> +#include <isc/sha2.h> +#include <isc/string.h> +#include <isc/util.h> + +#ifdef ISC_PLATFORM_OPENSSLHASH + +void +isc_sha224_init(isc_sha224_t *context) { + if (context == (isc_sha224_t *)0) { + return; + } + EVP_DigestInit(context, EVP_sha224()); +} + +void +isc_sha224_invalidate(isc_sha224_t *context) { + EVP_MD_CTX_cleanup(context); +} + +void +isc_sha224_update(isc_sha224_t *context, const isc_uint8_t* data, size_t len) { + if (len == 0U) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + REQUIRE(context != (isc_sha224_t *)0 && data != (isc_uint8_t*)0); + + EVP_DigestUpdate(context, (const void *) data, len); +} + +void +isc_sha224_final(isc_uint8_t digest[], isc_sha224_t *context) { + /* Sanity check: */ + REQUIRE(context != (isc_sha224_t *)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (isc_uint8_t*)0) { + EVP_DigestFinal(context, digest, NULL); + } else { + EVP_MD_CTX_cleanup(context); + } +} + +void +isc_sha256_init(isc_sha256_t *context) { + if (context == (isc_sha256_t *)0) { + return; + } + EVP_DigestInit(context, EVP_sha256()); +} + +void +isc_sha256_invalidate(isc_sha256_t *context) { + EVP_MD_CTX_cleanup(context); +} + +void +isc_sha256_update(isc_sha256_t *context, const isc_uint8_t *data, size_t len) { + if (len == 0U) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + REQUIRE(context != (isc_sha256_t *)0 && data != (isc_uint8_t*)0); + + EVP_DigestUpdate(context, (const void *) data, len); +} + +void +isc_sha256_final(isc_uint8_t digest[], isc_sha256_t *context) { + /* Sanity check: */ + REQUIRE(context != (isc_sha256_t *)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (isc_uint8_t*)0) { + EVP_DigestFinal(context, digest, NULL); + } else { + EVP_MD_CTX_cleanup(context); + } +} + +void +isc_sha512_init(isc_sha512_t *context) { + if (context == (isc_sha512_t *)0) { + return; + } + EVP_DigestInit(context, EVP_sha512()); +} + +void +isc_sha512_invalidate(isc_sha512_t *context) { + EVP_MD_CTX_cleanup(context); +} + +void isc_sha512_update(isc_sha512_t *context, const isc_uint8_t *data, size_t len) { + if (len == 0U) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + REQUIRE(context != (isc_sha512_t *)0 && data != (isc_uint8_t*)0); + + EVP_DigestUpdate(context, (const void *) data, len); +} + +void isc_sha512_final(isc_uint8_t digest[], isc_sha512_t *context) { + /* Sanity check: */ + REQUIRE(context != (isc_sha512_t *)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (isc_uint8_t*)0) { + EVP_DigestFinal(context, digest, NULL); + } else { + EVP_MD_CTX_cleanup(context); + } +} + +void +isc_sha384_init(isc_sha384_t *context) { + if (context == (isc_sha384_t *)0) { + return; + } + EVP_DigestInit(context, EVP_sha384()); +} + +void +isc_sha384_invalidate(isc_sha384_t *context) { + EVP_MD_CTX_cleanup(context); +} + +void +isc_sha384_update(isc_sha384_t *context, const isc_uint8_t* data, size_t len) { + if (len == 0U) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + REQUIRE(context != (isc_sha512_t *)0 && data != (isc_uint8_t*)0); + + EVP_DigestUpdate(context, (const void *) data, len); +} + +void +isc_sha384_final(isc_uint8_t digest[], isc_sha384_t *context) { + /* Sanity check: */ + REQUIRE(context != (isc_sha384_t *)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (isc_uint8_t*)0) { + EVP_DigestFinal(context, digest, NULL); + } else { + EVP_MD_CTX_cleanup(context); + } +} + +#else + +/* + * UNROLLED TRANSFORM LOOP NOTE: + * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform + * loop version for the hash transform rounds (defined using macros + * later in this file). Either define on the command line, for example: + * + * cc -DISC_SHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c + * + * or define below: + * + * \#define ISC_SHA2_UNROLL_TRANSFORM + * + */ + +/*** SHA-256/384/512 Machine Architecture Definitions *****************/ +/* + * BYTE_ORDER NOTE: + * + * Please make sure that your system defines BYTE_ORDER. If your + * architecture is little-endian, make sure it also defines + * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are + * equivalent. + * + * If your system does not define the above, then you can do so by + * hand like this: + * + * \#define LITTLE_ENDIAN 1234 + * \#define BIG_ENDIAN 4321 + * + * And for little-endian machines, add: + * + * \#define BYTE_ORDER LITTLE_ENDIAN + * + * Or for big-endian machines: + * + * \#define BYTE_ORDER BIG_ENDIAN + * + * The FreeBSD machine this was written on defines BYTE_ORDER + * appropriately by including <sys/types.h> (which in turn includes + * <machine/endian.h> where the appropriate definitions are actually + * made). + */ +#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN) +#ifndef BYTE_ORDER +#ifndef BIG_ENDIAN +#define BIG_ENDIAN 4321 +#endif +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 1234 +#endif +#ifdef WORDS_BIGENDIAN +#define BYTE_ORDER BIG_ENDIAN +#else +#define BYTE_ORDER LITTLE_ENDIAN +#endif +#else +#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN +#endif +#endif + +/*** SHA-256/384/512 Various Length Definitions ***********************/ +/* NOTE: Most of these are in sha2.h */ +#define ISC_SHA256_SHORT_BLOCK_LENGTH (ISC_SHA256_BLOCK_LENGTH - 8) +#define ISC_SHA384_SHORT_BLOCK_LENGTH (ISC_SHA384_BLOCK_LENGTH - 16) +#define ISC_SHA512_SHORT_BLOCK_LENGTH (ISC_SHA512_BLOCK_LENGTH - 16) + + +/*** ENDIAN REVERSAL MACROS *******************************************/ +#if BYTE_ORDER == LITTLE_ENDIAN +#define REVERSE32(w,x) { \ + isc_uint32_t tmp = (w); \ + tmp = (tmp >> 16) | (tmp << 16); \ + (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ +} +#ifdef WIN32 +#define REVERSE64(w,x) { \ + isc_uint64_t tmp = (w); \ + tmp = (tmp >> 32) | (tmp << 32); \ + tmp = ((tmp & 0xff00ff00ff00ff00UL) >> 8) | \ + ((tmp & 0x00ff00ff00ff00ffUL) << 8); \ + (x) = ((tmp & 0xffff0000ffff0000UL) >> 16) | \ + ((tmp & 0x0000ffff0000ffffUL) << 16); \ +} +#else +#define REVERSE64(w,x) { \ + isc_uint64_t tmp = (w); \ + tmp = (tmp >> 32) | (tmp << 32); \ + tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \ + ((tmp & 0x00ff00ff00ff00ffULL) << 8); \ + (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \ + ((tmp & 0x0000ffff0000ffffULL) << 16); \ +} +#endif +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +/* + * Macro for incrementally adding the unsigned 64-bit integer n to the + * unsigned 128-bit integer (represented using a two-element array of + * 64-bit words): + */ +#define ADDINC128(w,n) { \ + (w)[0] += (isc_uint64_t)(n); \ + if ((w)[0] < (n)) { \ + (w)[1]++; \ + } \ +} + +/*** THE SIX LOGICAL FUNCTIONS ****************************************/ +/* + * Bit shifting and rotation (used by the six SHA-XYZ logical functions: + * + * NOTE: The naming of R and S appears backwards here (R is a SHIFT and + * S is a ROTATION) because the SHA-256/384/512 description document + * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this + * same "backwards" definition. + */ +/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */ +#define R(b,x) ((x) >> (b)) +/* 32-bit Rotate-right (used in SHA-256): */ +#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) +/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ +#define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) + +/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */ +#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) +#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + +/* Four of six logical functions used in SHA-256: */ +#define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x))) +#define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x))) +#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x))) +#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x))) + +/* Four of six logical functions used in SHA-384 and SHA-512: */ +#define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x))) +#define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x))) +#define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x))) +#define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x))) + +/*** INTERNAL FUNCTION PROTOTYPES *************************************/ +/* NOTE: These should not be accessed directly from outside this + * library -- they are intended for private internal visibility/use + * only. + */ +void isc_sha512_last(isc_sha512_t *); +void isc_sha256_transform(isc_sha256_t *, const isc_uint32_t*); +void isc_sha512_transform(isc_sha512_t *, const isc_uint64_t*); + + +/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ +/* Hash constant words K for SHA-224 and SHA-256: */ +static const isc_uint32_t K256[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, + 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, + 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, + 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, + 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, + 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, + 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL +}; + +/* Initial hash value H for SHA-224: */ +static const isc_uint32_t sha224_initial_hash_value[8] = { + 0xc1059ed8UL, + 0x367cd507UL, + 0x3070dd17UL, + 0xf70e5939UL, + 0xffc00b31UL, + 0x68581511UL, + 0x64f98fa7UL, + 0xbefa4fa4UL +}; + +/* Initial hash value H for SHA-256: */ +static const isc_uint32_t sha256_initial_hash_value[8] = { + 0x6a09e667UL, + 0xbb67ae85UL, + 0x3c6ef372UL, + 0xa54ff53aUL, + 0x510e527fUL, + 0x9b05688cUL, + 0x1f83d9abUL, + 0x5be0cd19UL +}; + +#ifdef WIN32 +/* Hash constant words K for SHA-384 and SHA-512: */ +static const isc_uint64_t K512[80] = { + 0x428a2f98d728ae22UL, 0x7137449123ef65cdUL, + 0xb5c0fbcfec4d3b2fUL, 0xe9b5dba58189dbbcUL, + 0x3956c25bf348b538UL, 0x59f111f1b605d019UL, + 0x923f82a4af194f9bUL, 0xab1c5ed5da6d8118UL, + 0xd807aa98a3030242UL, 0x12835b0145706fbeUL, + 0x243185be4ee4b28cUL, 0x550c7dc3d5ffb4e2UL, + 0x72be5d74f27b896fUL, 0x80deb1fe3b1696b1UL, + 0x9bdc06a725c71235UL, 0xc19bf174cf692694UL, + 0xe49b69c19ef14ad2UL, 0xefbe4786384f25e3UL, + 0x0fc19dc68b8cd5b5UL, 0x240ca1cc77ac9c65UL, + 0x2de92c6f592b0275UL, 0x4a7484aa6ea6e483UL, + 0x5cb0a9dcbd41fbd4UL, 0x76f988da831153b5UL, + 0x983e5152ee66dfabUL, 0xa831c66d2db43210UL, + 0xb00327c898fb213fUL, 0xbf597fc7beef0ee4UL, + 0xc6e00bf33da88fc2UL, 0xd5a79147930aa725UL, + 0x06ca6351e003826fUL, 0x142929670a0e6e70UL, + 0x27b70a8546d22ffcUL, 0x2e1b21385c26c926UL, + 0x4d2c6dfc5ac42aedUL, 0x53380d139d95b3dfUL, + 0x650a73548baf63deUL, 0x766a0abb3c77b2a8UL, + 0x81c2c92e47edaee6UL, 0x92722c851482353bUL, + 0xa2bfe8a14cf10364UL, 0xa81a664bbc423001UL, + 0xc24b8b70d0f89791UL, 0xc76c51a30654be30UL, + 0xd192e819d6ef5218UL, 0xd69906245565a910UL, + 0xf40e35855771202aUL, 0x106aa07032bbd1b8UL, + 0x19a4c116b8d2d0c8UL, 0x1e376c085141ab53UL, + 0x2748774cdf8eeb99UL, 0x34b0bcb5e19b48a8UL, + 0x391c0cb3c5c95a63UL, 0x4ed8aa4ae3418acbUL, + 0x5b9cca4f7763e373UL, 0x682e6ff3d6b2b8a3UL, + 0x748f82ee5defb2fcUL, 0x78a5636f43172f60UL, + 0x84c87814a1f0ab72UL, 0x8cc702081a6439ecUL, + 0x90befffa23631e28UL, 0xa4506cebde82bde9UL, + 0xbef9a3f7b2c67915UL, 0xc67178f2e372532bUL, + 0xca273eceea26619cUL, 0xd186b8c721c0c207UL, + 0xeada7dd6cde0eb1eUL, 0xf57d4f7fee6ed178UL, + 0x06f067aa72176fbaUL, 0x0a637dc5a2c898a6UL, + 0x113f9804bef90daeUL, 0x1b710b35131c471bUL, + 0x28db77f523047d84UL, 0x32caab7b40c72493UL, + 0x3c9ebe0a15c9bebcUL, 0x431d67c49c100d4cUL, + 0x4cc5d4becb3e42b6UL, 0x597f299cfc657e2aUL, + 0x5fcb6fab3ad6faecUL, 0x6c44198c4a475817UL +}; + +/* Initial hash value H for SHA-384: */ +static const isc_uint64_t sha384_initial_hash_value[8] = { + 0xcbbb9d5dc1059ed8UL, + 0x629a292a367cd507UL, + 0x9159015a3070dd17UL, + 0x152fecd8f70e5939UL, + 0x67332667ffc00b31UL, + 0x8eb44a8768581511UL, + 0xdb0c2e0d64f98fa7UL, + 0x47b5481dbefa4fa4UL +}; + +/* Initial hash value H for SHA-512: */ +static const isc_uint64_t sha512_initial_hash_value[8] = { + 0x6a09e667f3bcc908U, + 0xbb67ae8584caa73bUL, + 0x3c6ef372fe94f82bUL, + 0xa54ff53a5f1d36f1UL, + 0x510e527fade682d1UL, + 0x9b05688c2b3e6c1fUL, + 0x1f83d9abfb41bd6bUL, + 0x5be0cd19137e2179UL +}; +#else +/* Hash constant words K for SHA-384 and SHA-512: */ +static const isc_uint64_t K512[80] = { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, + 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, + 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, + 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, + 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, + 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, + 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, + 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, + 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, + 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, + 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, + 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, + 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, + 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, + 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, + 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, + 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, + 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, + 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, + 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, + 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, + 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, + 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, + 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, + 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL +}; + +/* Initial hash value H for SHA-384: */ +static const isc_uint64_t sha384_initial_hash_value[8] = { + 0xcbbb9d5dc1059ed8ULL, + 0x629a292a367cd507ULL, + 0x9159015a3070dd17ULL, + 0x152fecd8f70e5939ULL, + 0x67332667ffc00b31ULL, + 0x8eb44a8768581511ULL, + 0xdb0c2e0d64f98fa7ULL, + 0x47b5481dbefa4fa4ULL +}; + +/* Initial hash value H for SHA-512: */ +static const isc_uint64_t sha512_initial_hash_value[8] = { + 0x6a09e667f3bcc908ULL, + 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, + 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, + 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, + 0x5be0cd19137e2179ULL +}; +#endif + + +/*** SHA-224: *********************************************************/ +void +isc_sha224_init(isc_sha224_t *context) { + if (context == (isc_sha256_t *)0) { + return; + } + memcpy(context->state, sha224_initial_hash_value, + ISC_SHA256_DIGESTLENGTH); + memset(context->buffer, 0, ISC_SHA256_BLOCK_LENGTH); + context->bitcount = 0; +} + +void +isc_sha224_invalidate(isc_sha224_t *context) { + memset(context, 0, sizeof(isc_sha224_t)); +} + +void +isc_sha224_update(isc_sha224_t *context, const isc_uint8_t* data, size_t len) { + isc_sha256_update((isc_sha256_t *)context, data, len); +} + +void +isc_sha224_final(isc_uint8_t digest[], isc_sha224_t *context) { + isc_uint8_t sha256_digest[ISC_SHA256_DIGESTLENGTH]; + isc_sha256_final(sha256_digest, (isc_sha256_t *)context); + memcpy(digest, sha256_digest, ISC_SHA224_DIGESTLENGTH); + memset(sha256_digest, 0, ISC_SHA256_DIGESTLENGTH); +} + +/*** SHA-256: *********************************************************/ +void +isc_sha256_init(isc_sha256_t *context) { + if (context == (isc_sha256_t *)0) { + return; + } + memcpy(context->state, sha256_initial_hash_value, + ISC_SHA256_DIGESTLENGTH); + memset(context->buffer, 0, ISC_SHA256_BLOCK_LENGTH); + context->bitcount = 0; +} + +void +isc_sha256_invalidate(isc_sha256_t *context) { + memset(context, 0, sizeof(isc_sha256_t)); +} + +#ifdef ISC_SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-256 round macros: */ + +#if BYTE_ORDER == LITTLE_ENDIAN + +#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ + REVERSE32(*data++, W256[j]); \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ + K256[j] + W256[j]; \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + + +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ + K256[j] + (W256[j] = *data++); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND256(a,b,c,d,e,f,g,h) \ + s0 = W256[(j+1)&0x0f]; \ + s0 = sigma0_256(s0); \ + s1 = W256[(j+14)&0x0f]; \ + s1 = sigma1_256(s1); \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \ + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + +void isc_sha256_transform(isc_sha256_t *context, const isc_uint32_t* data) { + isc_uint32_t a, b, c, d, e, f, g, h, s0, s1; + isc_uint32_t T1, *W256; + int j; + + W256 = (isc_uint32_t*)context->buffer; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { + /* Rounds 0 to 15 (unrolled): */ + ROUND256_0_TO_15(a,b,c,d,e,f,g,h); + ROUND256_0_TO_15(h,a,b,c,d,e,f,g); + ROUND256_0_TO_15(g,h,a,b,c,d,e,f); + ROUND256_0_TO_15(f,g,h,a,b,c,d,e); + ROUND256_0_TO_15(e,f,g,h,a,b,c,d); + ROUND256_0_TO_15(d,e,f,g,h,a,b,c); + ROUND256_0_TO_15(c,d,e,f,g,h,a,b); + ROUND256_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds to 64: */ + do { + ROUND256(a,b,c,d,e,f,g,h); + ROUND256(h,a,b,c,d,e,f,g); + ROUND256(g,h,a,b,c,d,e,f); + ROUND256(f,g,h,a,b,c,d,e); + ROUND256(e,f,g,h,a,b,c,d); + ROUND256(d,e,f,g,h,a,b,c); + ROUND256(c,d,e,f,g,h,a,b); + ROUND256(b,c,d,e,f,g,h,a); + } while (j < 64); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; + /* Avoid compiler warnings */ + POST(a); POST(b); POST(c); POST(d); POST(e); POST(f); + POST(g); POST(h); POST(T1); +} + +#else /* ISC_SHA2_UNROLL_TRANSFORM */ + +void +isc_sha256_transform(isc_sha256_t *context, const isc_uint32_t* data) { + isc_uint32_t a, b, c, d, e, f, g, h, s0, s1; + isc_uint32_t T1, T2, *W256; + int j; + + W256 = (isc_uint32_t*)context->buffer; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { +#if BYTE_ORDER == LITTLE_ENDIAN + /* Copy data while converting to host byte order */ + REVERSE32(*data++,W256[j]); + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j]; +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + /* Apply the SHA-256 compression function to update a..h with copy */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++); +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W256[(j+1)&0x0f]; + s0 = sigma0_256(s0); + s1 = W256[(j+14)&0x0f]; + s1 = sigma1_256(s1); + + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 64); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; + /* Avoid compiler warnings */ + POST(a); POST(b); POST(c); POST(d); POST(e); POST(f); + POST(g); POST(h); POST(T1); POST(T2); +} + +#endif /* ISC_SHA2_UNROLL_TRANSFORM */ + +void +isc_sha256_update(isc_sha256_t *context, const isc_uint8_t *data, size_t len) { + unsigned int freespace, usedspace; + + if (len == 0U) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + REQUIRE(context != (isc_sha256_t *)0 && data != (isc_uint8_t*)0); + + usedspace = (unsigned int)((context->bitcount >> 3) % + ISC_SHA256_BLOCK_LENGTH); + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = ISC_SHA256_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + memcpy(&context->buffer[usedspace], data, freespace); + context->bitcount += freespace << 3; + len -= freespace; + data += freespace; + isc_sha256_transform(context, + (isc_uint32_t*)context->buffer); + } else { + /* The buffer is not yet full */ + memcpy(&context->buffer[usedspace], data, len); + context->bitcount += len << 3; + /* Clean up: */ + usedspace = freespace = 0; + /* Avoid compiler warnings: */ + POST(usedspace); POST(freespace); + return; + } + } + while (len >= ISC_SHA256_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + memcpy(context->buffer, data, ISC_SHA256_BLOCK_LENGTH); + isc_sha256_transform(context, (isc_uint32_t*)context->buffer); + context->bitcount += ISC_SHA256_BLOCK_LENGTH << 3; + len -= ISC_SHA256_BLOCK_LENGTH; + data += ISC_SHA256_BLOCK_LENGTH; + } + if (len > 0U) { + /* There's left-overs, so save 'em */ + memcpy(context->buffer, data, len); + context->bitcount += len << 3; + } + /* Clean up: */ + usedspace = freespace = 0; + /* Avoid compiler warnings: */ + POST(usedspace); POST(freespace); +} + +void +isc_sha256_final(isc_uint8_t digest[], isc_sha256_t *context) { + isc_uint32_t *d = (isc_uint32_t*)digest; + unsigned int usedspace; + + /* Sanity check: */ + REQUIRE(context != (isc_sha256_t *)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (isc_uint8_t*)0) { + usedspace = (unsigned int)((context->bitcount >> 3) % + ISC_SHA256_BLOCK_LENGTH); +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + REVERSE64(context->bitcount,context->bitcount); +#endif + if (usedspace > 0) { + /* Begin padding with a 1 bit: */ + context->buffer[usedspace++] = 0x80; + + if (usedspace <= ISC_SHA256_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + memset(&context->buffer[usedspace], 0, + ISC_SHA256_SHORT_BLOCK_LENGTH - usedspace); + } else { + if (usedspace < ISC_SHA256_BLOCK_LENGTH) { + memset(&context->buffer[usedspace], 0, + ISC_SHA256_BLOCK_LENGTH - + usedspace); + } + /* Do second-to-last transform: */ + isc_sha256_transform(context, + (isc_uint32_t*)context->buffer); + + /* And set-up for the last transform: */ + memset(context->buffer, 0, + ISC_SHA256_SHORT_BLOCK_LENGTH); + } + } else { + /* Set-up for the last transform: */ + memset(context->buffer, 0, ISC_SHA256_SHORT_BLOCK_LENGTH); + + /* Begin padding with a 1 bit: */ + *context->buffer = 0x80; + } + /* Set the bit count: */ + *(isc_uint64_t*)&context->buffer[ISC_SHA256_SHORT_BLOCK_LENGTH] = context->bitcount; + + /* Final transform: */ + isc_sha256_transform(context, (isc_uint32_t*)context->buffer); + +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 8; j++) { + REVERSE32(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + memcpy(d, context->state, ISC_SHA256_DIGESTLENGTH); +#endif + } + + /* Clean up state data: */ + memset(context, 0, sizeof(*context)); + usedspace = 0; + POST(usedspace); +} + +/*** SHA-512: *********************************************************/ +void +isc_sha512_init(isc_sha512_t *context) { + if (context == (isc_sha512_t *)0) { + return; + } + memcpy(context->state, sha512_initial_hash_value, + ISC_SHA512_DIGESTLENGTH); + memset(context->buffer, 0, ISC_SHA512_BLOCK_LENGTH); + context->bitcount[0] = context->bitcount[1] = 0; +} + +void +isc_sha512_invalidate(isc_sha512_t *context) { + memset(context, 0, sizeof(isc_sha512_t)); +} + +#ifdef ISC_SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-512 round macros: */ +#if BYTE_ORDER == LITTLE_ENDIAN + +#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ + REVERSE64(*data++, W512[j]); \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ + K512[j] + W512[j]; \ + (d) += T1, \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \ + j++ + + +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ + K512[j] + (W512[j] = *data++); \ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + j++ + +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND512(a,b,c,d,e,f,g,h) \ + s0 = W512[(j+1)&0x0f]; \ + s0 = sigma0_512(s0); \ + s1 = W512[(j+14)&0x0f]; \ + s1 = sigma1_512(s1); \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \ + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + j++ + +void isc_sha512_transform(isc_sha512_t *context, const isc_uint64_t* data) { + isc_uint64_t a, b, c, d, e, f, g, h, s0, s1; + isc_uint64_t T1, *W512 = (isc_uint64_t*)context->buffer; + int j; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { + ROUND512_0_TO_15(a,b,c,d,e,f,g,h); + ROUND512_0_TO_15(h,a,b,c,d,e,f,g); + ROUND512_0_TO_15(g,h,a,b,c,d,e,f); + ROUND512_0_TO_15(f,g,h,a,b,c,d,e); + ROUND512_0_TO_15(e,f,g,h,a,b,c,d); + ROUND512_0_TO_15(d,e,f,g,h,a,b,c); + ROUND512_0_TO_15(c,d,e,f,g,h,a,b); + ROUND512_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds up to 79: */ + do { + ROUND512(a,b,c,d,e,f,g,h); + ROUND512(h,a,b,c,d,e,f,g); + ROUND512(g,h,a,b,c,d,e,f); + ROUND512(f,g,h,a,b,c,d,e); + ROUND512(e,f,g,h,a,b,c,d); + ROUND512(d,e,f,g,h,a,b,c); + ROUND512(c,d,e,f,g,h,a,b); + ROUND512(b,c,d,e,f,g,h,a); + } while (j < 80); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; + /* Avoid compiler warnings */ + POST(a); POST(b); POST(c); POST(d); POST(e); POST(f); + POST(g); POST(h); POST(T1); +} + +#else /* ISC_SHA2_UNROLL_TRANSFORM */ + +void +isc_sha512_transform(isc_sha512_t *context, const isc_uint64_t* data) { + isc_uint64_t a, b, c, d, e, f, g, h, s0, s1; + isc_uint64_t T1, T2, *W512 = (isc_uint64_t*)context->buffer; + int j; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + REVERSE64(*data++, W512[j]); + /* Apply the SHA-512 compression function to update a..h */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j]; +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + /* Apply the SHA-512 compression function to update a..h with copy */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++); +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W512[(j+1)&0x0f]; + s0 = sigma0_512(s0); + s1 = W512[(j+14)&0x0f]; + s1 = sigma1_512(s1); + + /* Apply the SHA-512 compression function to update a..h */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 80); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; + /* Avoid compiler warnings */ + POST(a); POST(b); POST(c); POST(d); POST(e); POST(f); + POST(g); POST(h); POST(T1); POST(T2); +} + +#endif /* ISC_SHA2_UNROLL_TRANSFORM */ + +void isc_sha512_update(isc_sha512_t *context, const isc_uint8_t *data, size_t len) { + unsigned int freespace, usedspace; + + if (len == 0U) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + REQUIRE(context != (isc_sha512_t *)0 && data != (isc_uint8_t*)0); + + usedspace = (unsigned int)((context->bitcount[0] >> 3) % + ISC_SHA512_BLOCK_LENGTH); + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = ISC_SHA512_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + memcpy(&context->buffer[usedspace], data, freespace); + ADDINC128(context->bitcount, freespace << 3); + len -= freespace; + data += freespace; + isc_sha512_transform(context, + (isc_uint64_t*)context->buffer); + } else { + /* The buffer is not yet full */ + memcpy(&context->buffer[usedspace], data, len); + ADDINC128(context->bitcount, len << 3); + /* Clean up: */ + usedspace = freespace = 0; + /* Avoid compiler warnings: */ + POST(usedspace); POST(freespace); + return; + } + } + while (len >= ISC_SHA512_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + memcpy(context->buffer, data, ISC_SHA512_BLOCK_LENGTH); + isc_sha512_transform(context, (isc_uint64_t*)context->buffer); + ADDINC128(context->bitcount, ISC_SHA512_BLOCK_LENGTH << 3); + len -= ISC_SHA512_BLOCK_LENGTH; + data += ISC_SHA512_BLOCK_LENGTH; + } + if (len > 0U) { + /* There's left-overs, so save 'em */ + memcpy(context->buffer, data, len); + ADDINC128(context->bitcount, len << 3); + } + /* Clean up: */ + usedspace = freespace = 0; + /* Avoid compiler warnings: */ + POST(usedspace); POST(freespace); +} + +void isc_sha512_last(isc_sha512_t *context) { + unsigned int usedspace; + + usedspace = (unsigned int)((context->bitcount[0] >> 3) % + ISC_SHA512_BLOCK_LENGTH); +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + REVERSE64(context->bitcount[0],context->bitcount[0]); + REVERSE64(context->bitcount[1],context->bitcount[1]); +#endif + if (usedspace > 0) { + /* Begin padding with a 1 bit: */ + context->buffer[usedspace++] = 0x80; + + if (usedspace <= ISC_SHA512_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + memset(&context->buffer[usedspace], 0, + ISC_SHA512_SHORT_BLOCK_LENGTH - usedspace); + } else { + if (usedspace < ISC_SHA512_BLOCK_LENGTH) { + memset(&context->buffer[usedspace], 0, + ISC_SHA512_BLOCK_LENGTH - usedspace); + } + /* Do second-to-last transform: */ + isc_sha512_transform(context, + (isc_uint64_t*)context->buffer); + + /* And set-up for the last transform: */ + memset(context->buffer, 0, ISC_SHA512_BLOCK_LENGTH - 2); + } + } else { + /* Prepare for final transform: */ + memset(context->buffer, 0, ISC_SHA512_SHORT_BLOCK_LENGTH); + + /* Begin padding with a 1 bit: */ + *context->buffer = 0x80; + } + /* Store the length of input data (in bits): */ + *(isc_uint64_t*)&context->buffer[ISC_SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1]; + *(isc_uint64_t*)&context->buffer[ISC_SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0]; + + /* Final transform: */ + isc_sha512_transform(context, (isc_uint64_t*)context->buffer); +} + +void isc_sha512_final(isc_uint8_t digest[], isc_sha512_t *context) { + isc_uint64_t *d = (isc_uint64_t*)digest; + + /* Sanity check: */ + REQUIRE(context != (isc_sha512_t *)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (isc_uint8_t*)0) { + isc_sha512_last(context); + + /* Save the hash data for output: */ +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 8; j++) { + REVERSE64(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + memcpy(d, context->state, ISC_SHA512_DIGESTLENGTH); +#endif + } + + /* Zero out state data */ + memset(context, 0, sizeof(*context)); +} + + +/*** SHA-384: *********************************************************/ +void +isc_sha384_init(isc_sha384_t *context) { + if (context == (isc_sha384_t *)0) { + return; + } + memcpy(context->state, sha384_initial_hash_value, + ISC_SHA512_DIGESTLENGTH); + memset(context->buffer, 0, ISC_SHA384_BLOCK_LENGTH); + context->bitcount[0] = context->bitcount[1] = 0; +} + +void +isc_sha384_invalidate(isc_sha384_t *context) { + memset(context, 0, sizeof(isc_sha384_t)); +} + +void +isc_sha384_update(isc_sha384_t *context, const isc_uint8_t* data, size_t len) { + isc_sha512_update((isc_sha512_t *)context, data, len); +} + +void +isc_sha384_final(isc_uint8_t digest[], isc_sha384_t *context) { + isc_uint64_t *d = (isc_uint64_t*)digest; + + /* Sanity check: */ + REQUIRE(context != (isc_sha384_t *)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (isc_uint8_t*)0) { + isc_sha512_last((isc_sha512_t *)context); + + /* Save the hash data for output: */ +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 6; j++) { + REVERSE64(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + memcpy(d, context->state, ISC_SHA384_DIGESTLENGTH); +#endif + } + + /* Zero out state data */ + memset(context, 0, sizeof(*context)); +} +#endif /* !ISC_PLATFORM_OPENSSLHASH */ + +/* + * Constant used by SHA256/384/512_End() functions for converting the + * digest to a readable hexadecimal character string: + */ +static const char *sha2_hex_digits = "0123456789abcdef"; + +char * +isc_sha224_end(isc_sha224_t *context, char buffer[]) { + isc_uint8_t digest[ISC_SHA224_DIGESTLENGTH], *d = digest; + unsigned int i; + + /* Sanity check: */ + REQUIRE(context != (isc_sha224_t *)0); + + if (buffer != (char*)0) { + isc_sha224_final(digest, context); + + for (i = 0; i < ISC_SHA224_DIGESTLENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { +#ifdef ISC_PLATFORM_OPENSSLHASH + EVP_MD_CTX_cleanup(context); +#else + memset(context, 0, sizeof(*context)); +#endif + } + memset(digest, 0, ISC_SHA224_DIGESTLENGTH); + return buffer; +} + +char * +isc_sha224_data(const isc_uint8_t *data, size_t len, + char digest[ISC_SHA224_DIGESTSTRINGLENGTH]) +{ + isc_sha224_t context; + + isc_sha224_init(&context); + isc_sha224_update(&context, data, len); + return (isc_sha224_end(&context, digest)); +} + +char * +isc_sha256_end(isc_sha256_t *context, char buffer[]) { + isc_uint8_t digest[ISC_SHA256_DIGESTLENGTH], *d = digest; + unsigned int i; + + /* Sanity check: */ + REQUIRE(context != (isc_sha256_t *)0); + + if (buffer != (char*)0) { + isc_sha256_final(digest, context); + + for (i = 0; i < ISC_SHA256_DIGESTLENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { +#ifdef ISC_PLATFORM_OPENSSLHASH + EVP_MD_CTX_cleanup(context); +#else + memset(context, 0, sizeof(*context)); +#endif + } + memset(digest, 0, ISC_SHA256_DIGESTLENGTH); + return buffer; +} + +char * +isc_sha256_data(const isc_uint8_t* data, size_t len, + char digest[ISC_SHA256_DIGESTSTRINGLENGTH]) +{ + isc_sha256_t context; + + isc_sha256_init(&context); + isc_sha256_update(&context, data, len); + return (isc_sha256_end(&context, digest)); +} + +char * +isc_sha512_end(isc_sha512_t *context, char buffer[]) { + isc_uint8_t digest[ISC_SHA512_DIGESTLENGTH], *d = digest; + unsigned int i; + + /* Sanity check: */ + REQUIRE(context != (isc_sha512_t *)0); + + if (buffer != (char*)0) { + isc_sha512_final(digest, context); + + for (i = 0; i < ISC_SHA512_DIGESTLENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { +#ifdef ISC_PLATFORM_OPENSSLHASH + EVP_MD_CTX_cleanup(context); +#else + memset(context, 0, sizeof(*context)); +#endif + } + memset(digest, 0, ISC_SHA512_DIGESTLENGTH); + return buffer; +} + +char * +isc_sha512_data(const isc_uint8_t *data, size_t len, + char digest[ISC_SHA512_DIGESTSTRINGLENGTH]) +{ + isc_sha512_t context; + + isc_sha512_init(&context); + isc_sha512_update(&context, data, len); + return (isc_sha512_end(&context, digest)); +} + +char * +isc_sha384_end(isc_sha384_t *context, char buffer[]) { + isc_uint8_t digest[ISC_SHA384_DIGESTLENGTH], *d = digest; + unsigned int i; + + /* Sanity check: */ + REQUIRE(context != (isc_sha384_t *)0); + + if (buffer != (char*)0) { + isc_sha384_final(digest, context); + + for (i = 0; i < ISC_SHA384_DIGESTLENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { +#ifdef ISC_PLATFORM_OPENSSLHASH + EVP_MD_CTX_cleanup(context); +#else + memset(context, 0, sizeof(*context)); +#endif + } + memset(digest, 0, ISC_SHA384_DIGESTLENGTH); + return buffer; +} + +char * +isc_sha384_data(const isc_uint8_t *data, size_t len, + char digest[ISC_SHA384_DIGESTSTRINGLENGTH]) +{ + isc_sha384_t context; + + isc_sha384_init(&context); + isc_sha384_update(&context, data, len); + return (isc_sha384_end(&context, digest)); +} diff --git a/contrib/ntp/lib/isc/sockaddr.c b/contrib/ntp/lib/isc/sockaddr.c new file mode 100644 index 0000000..1ae5e7c --- /dev/null +++ b/contrib/ntp/lib/isc/sockaddr.c @@ -0,0 +1,510 @@ +/* + * Copyright (C) 2004-2007, 2010-2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/*! \file */ + +#include <config.h> + +#include <stdio.h> + +#include <isc/buffer.h> +#include <isc/hash.h> +#include <isc/msgs.h> +#include <isc/netaddr.h> +#include <isc/print.h> +#include <isc/region.h> +#include <isc/sockaddr.h> +#include <isc/string.h> +#include <isc/util.h> + +isc_boolean_t +isc_sockaddr_equal(const isc_sockaddr_t *a, const isc_sockaddr_t *b) { + return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR| + ISC_SOCKADDR_CMPPORT| + ISC_SOCKADDR_CMPSCOPE)); +} + +isc_boolean_t +isc_sockaddr_eqaddr(const isc_sockaddr_t *a, const isc_sockaddr_t *b) { + return (isc_sockaddr_compare(a, b, ISC_SOCKADDR_CMPADDR| + ISC_SOCKADDR_CMPSCOPE)); +} + +isc_boolean_t +isc_sockaddr_compare(const isc_sockaddr_t *a, const isc_sockaddr_t *b, + unsigned int flags) +{ + REQUIRE(a != NULL && b != NULL); + + if (a->length != b->length) + return (ISC_FALSE); + + /* + * We don't just memcmp because the sin_zero field isn't always + * zero. + */ + + if (a->type.sa.sa_family != b->type.sa.sa_family) + return (ISC_FALSE); + switch (a->type.sa.sa_family) { + case AF_INET: + if ((flags & ISC_SOCKADDR_CMPADDR) != 0 && + memcmp(&a->type.sin.sin_addr, &b->type.sin.sin_addr, + sizeof(a->type.sin.sin_addr)) != 0) + return (ISC_FALSE); + if ((flags & ISC_SOCKADDR_CMPPORT) != 0 && + a->type.sin.sin_port != b->type.sin.sin_port) + return (ISC_FALSE); + break; + case AF_INET6: + if ((flags & ISC_SOCKADDR_CMPADDR) != 0 && + memcmp(&a->type.sin6.sin6_addr, &b->type.sin6.sin6_addr, + sizeof(a->type.sin6.sin6_addr)) != 0) + return (ISC_FALSE); +#ifdef ISC_PLATFORM_HAVESCOPEID + /* + * If ISC_SOCKADDR_CMPSCOPEZERO is set then don't return + * ISC_FALSE if one of the scopes in zero. + */ + if ((flags & ISC_SOCKADDR_CMPSCOPE) != 0 && + a->type.sin6.sin6_scope_id != b->type.sin6.sin6_scope_id && + ((flags & ISC_SOCKADDR_CMPSCOPEZERO) == 0 || + (a->type.sin6.sin6_scope_id != 0 && + b->type.sin6.sin6_scope_id != 0))) + return (ISC_FALSE); +#endif + if ((flags & ISC_SOCKADDR_CMPPORT) != 0 && + a->type.sin6.sin6_port != b->type.sin6.sin6_port) + return (ISC_FALSE); + break; + default: + if (memcmp(&a->type, &b->type, a->length) != 0) + return (ISC_FALSE); + } + return (ISC_TRUE); +} + +isc_boolean_t +isc_sockaddr_eqaddrprefix(const isc_sockaddr_t *a, const isc_sockaddr_t *b, + unsigned int prefixlen) +{ + isc_netaddr_t na, nb; + isc_netaddr_fromsockaddr(&na, a); + isc_netaddr_fromsockaddr(&nb, b); + return (isc_netaddr_eqprefix(&na, &nb, prefixlen)); +} + +isc_result_t +isc_sockaddr_totext(const isc_sockaddr_t *sockaddr, isc_buffer_t *target) { + isc_result_t result; + isc_netaddr_t netaddr; + char pbuf[sizeof("65000")]; + unsigned int plen; + isc_region_t avail; + + REQUIRE(sockaddr != NULL); + + /* + * Do the port first, giving us the opportunity to check for + * unsupported address families before calling + * isc_netaddr_fromsockaddr(). + */ + switch (sockaddr->type.sa.sa_family) { + case AF_INET: + snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin.sin_port)); + break; + case AF_INET6: + snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin6.sin6_port)); + break; +#ifdef ISC_PLAFORM_HAVESYSUNH + case AF_UNIX: + plen = strlen(sockaddr->type.sunix.sun_path); + if (plen >= isc_buffer_availablelength(target)) + return (ISC_R_NOSPACE); + + isc_buffer_putmem(target, sockaddr->type.sunix.sun_path, plen); + + /* + * Null terminate after used region. + */ + isc_buffer_availableregion(target, &avail); + INSIST(avail.length >= 1); + avail.base[0] = '\0'; + + return (ISC_R_SUCCESS); +#endif + default: + return (ISC_R_FAILURE); + } + + plen = strlen(pbuf); + INSIST(plen < sizeof(pbuf)); + + isc_netaddr_fromsockaddr(&netaddr, sockaddr); + result = isc_netaddr_totext(&netaddr, target); + if (result != ISC_R_SUCCESS) + return (result); + + if (1 + plen + 1 > isc_buffer_availablelength(target)) + return (ISC_R_NOSPACE); + + isc_buffer_putmem(target, (const unsigned char *)"#", 1); + isc_buffer_putmem(target, (const unsigned char *)pbuf, plen); + + /* + * Null terminate after used region. + */ + isc_buffer_availableregion(target, &avail); + INSIST(avail.length >= 1); + avail.base[0] = '\0'; + + return (ISC_R_SUCCESS); +} + +void +isc_sockaddr_format(const isc_sockaddr_t *sa, char *array, unsigned int size) { + isc_result_t result; + isc_buffer_t buf; + + if (size == 0U) + return; + + isc_buffer_init(&buf, array, size); + result = isc_sockaddr_totext(sa, &buf); + if (result != ISC_R_SUCCESS) { + /* + * The message is the same as in netaddr.c. + */ + snprintf(array, size, + "<%s %u>", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_NETADDR, + ISC_MSG_UNKNOWNADDR, + "unknown address, family"), + sa->type.sa.sa_family); + array[size - 1] = '\0'; + } +} + +unsigned int +isc_sockaddr_hash(const isc_sockaddr_t *sockaddr, isc_boolean_t address_only) { + unsigned int length = 0; + const unsigned char *s = NULL; + unsigned int h = 0; + unsigned int g; + unsigned int p = 0; + const struct in6_addr *in6; + + REQUIRE(sockaddr != NULL); + + switch (sockaddr->type.sa.sa_family) { + case AF_INET: + s = (const unsigned char *)&sockaddr->type.sin.sin_addr; + p = ntohs(sockaddr->type.sin.sin_port); + length = sizeof(sockaddr->type.sin.sin_addr.s_addr); + break; + case AF_INET6: + in6 = &sockaddr->type.sin6.sin6_addr; + if (IN6_IS_ADDR_V4MAPPED(in6)) { + s = (const unsigned char *)&in6 + 12; + length = sizeof(sockaddr->type.sin.sin_addr.s_addr); + } else { + s = (const unsigned char *)in6; + length = sizeof(sockaddr->type.sin6.sin6_addr); + } + p = ntohs(sockaddr->type.sin6.sin6_port); + break; + default: + UNEXPECTED_ERROR(__FILE__, __LINE__, + "%s: %d", + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_SOCKADDR, + ISC_MSG_UNKNOWNFAMILY, + "unknown address family"), + (int)sockaddr->type.sa.sa_family); + s = (const unsigned char *)&sockaddr->type; + length = sockaddr->length; + p = 0; + } + + h = isc_hash_calc(s, length, ISC_TRUE); + if (!address_only) { + g = isc_hash_calc((const unsigned char *)&p, sizeof(p), + ISC_TRUE); + h = h ^ g; /* XXX: we should concatenate h and p first */ + } + + return (h); +} + +void +isc_sockaddr_any(isc_sockaddr_t *sockaddr) +{ + memset(sockaddr, 0, sizeof(*sockaddr)); + sockaddr->type.sin.sin_family = AF_INET; +#ifdef ISC_PLATFORM_HAVESALEN + sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin); +#endif + sockaddr->type.sin.sin_addr.s_addr = INADDR_ANY; + sockaddr->type.sin.sin_port = 0; + sockaddr->length = sizeof(sockaddr->type.sin); + ISC_LINK_INIT(sockaddr, link); +} + +void +isc_sockaddr_any6(isc_sockaddr_t *sockaddr) +{ + memset(sockaddr, 0, sizeof(*sockaddr)); + sockaddr->type.sin6.sin6_family = AF_INET6; +#ifdef ISC_PLATFORM_HAVESALEN + sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6); +#endif + sockaddr->type.sin6.sin6_addr = in6addr_any; + sockaddr->type.sin6.sin6_port = 0; + sockaddr->length = sizeof(sockaddr->type.sin6); + ISC_LINK_INIT(sockaddr, link); +} + +void +isc_sockaddr_fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina, + in_port_t port) +{ + memset(sockaddr, 0, sizeof(*sockaddr)); + sockaddr->type.sin.sin_family = AF_INET; +#ifdef ISC_PLATFORM_HAVESALEN + sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin); +#endif + sockaddr->type.sin.sin_addr = *ina; + sockaddr->type.sin.sin_port = htons(port); + sockaddr->length = sizeof(sockaddr->type.sin); + ISC_LINK_INIT(sockaddr, link); +} + +void +isc_sockaddr_anyofpf(isc_sockaddr_t *sockaddr, int pf) { + switch (pf) { + case AF_INET: + isc_sockaddr_any(sockaddr); + break; + case AF_INET6: + isc_sockaddr_any6(sockaddr); + break; + default: + INSIST(0); + } +} + +void +isc_sockaddr_fromin6(isc_sockaddr_t *sockaddr, const struct in6_addr *ina6, + in_port_t port) +{ + memset(sockaddr, 0, sizeof(*sockaddr)); + sockaddr->type.sin6.sin6_family = AF_INET6; +#ifdef ISC_PLATFORM_HAVESALEN + sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6); +#endif + sockaddr->type.sin6.sin6_addr = *ina6; + sockaddr->type.sin6.sin6_port = htons(port); + sockaddr->length = sizeof(sockaddr->type.sin6); + ISC_LINK_INIT(sockaddr, link); +} + +void +isc_sockaddr_v6fromin(isc_sockaddr_t *sockaddr, const struct in_addr *ina, + in_port_t port) +{ + memset(sockaddr, 0, sizeof(*sockaddr)); + sockaddr->type.sin6.sin6_family = AF_INET6; +#ifdef ISC_PLATFORM_HAVESALEN + sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6); +#endif + sockaddr->type.sin6.sin6_addr.s6_addr[10] = 0xff; + sockaddr->type.sin6.sin6_addr.s6_addr[11] = 0xff; + memcpy(&sockaddr->type.sin6.sin6_addr.s6_addr[12], ina, 4); + sockaddr->type.sin6.sin6_port = htons(port); + sockaddr->length = sizeof(sockaddr->type.sin6); + ISC_LINK_INIT(sockaddr, link); +} + +int +isc_sockaddr_pf(const isc_sockaddr_t *sockaddr) { + + /* + * Get the protocol family of 'sockaddr'. + */ + +#if (AF_INET == PF_INET && AF_INET6 == PF_INET6) + /* + * Assume that PF_xxx == AF_xxx for all AF and PF. + */ + return (sockaddr->type.sa.sa_family); +#else + switch (sockaddr->type.sa.sa_family) { + case AF_INET: + return (PF_INET); + case AF_INET6: + return (PF_INET6); + default: + FATAL_ERROR(__FILE__, __LINE__, + isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR, + ISC_MSG_UNKNOWNFAMILY, + "unknown address family: %d"), + (int)sockaddr->type.sa.sa_family); + } +#endif +} + +void +isc_sockaddr_fromnetaddr(isc_sockaddr_t *sockaddr, const isc_netaddr_t *na, + in_port_t port) +{ + memset(sockaddr, 0, sizeof(*sockaddr)); + sockaddr->type.sin.sin_family = (short)na->family; + switch (na->family) { + case AF_INET: + sockaddr->length = sizeof(sockaddr->type.sin); +#ifdef ISC_PLATFORM_HAVESALEN + sockaddr->type.sin.sin_len = sizeof(sockaddr->type.sin); +#endif + sockaddr->type.sin.sin_addr = na->type.in; + sockaddr->type.sin.sin_port = htons(port); + break; + case AF_INET6: + sockaddr->length = sizeof(sockaddr->type.sin6); +#ifdef ISC_PLATFORM_HAVESALEN + sockaddr->type.sin6.sin6_len = sizeof(sockaddr->type.sin6); +#endif + memcpy(&sockaddr->type.sin6.sin6_addr, &na->type.in6, 16); +#ifdef ISC_PLATFORM_HAVESCOPEID + sockaddr->type.sin6.sin6_scope_id = isc_netaddr_getzone(na); +#endif + sockaddr->type.sin6.sin6_port = htons(port); + break; + default: + INSIST(0); + } + ISC_LINK_INIT(sockaddr, link); +} + +void +isc_sockaddr_setport(isc_sockaddr_t *sockaddr, in_port_t port) { + switch (sockaddr->type.sa.sa_family) { + case AF_INET: + sockaddr->type.sin.sin_port = htons(port); + break; + case AF_INET6: + sockaddr->type.sin6.sin6_port = htons(port); + break; + default: + FATAL_ERROR(__FILE__, __LINE__, + "%s: %d", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR, + ISC_MSG_UNKNOWNFAMILY, + "unknown address family"), + (int)sockaddr->type.sa.sa_family); + } +} + +in_port_t +isc_sockaddr_getport(const isc_sockaddr_t *sockaddr) { + in_port_t port = 0; + + switch (sockaddr->type.sa.sa_family) { + case AF_INET: + port = ntohs(sockaddr->type.sin.sin_port); + break; + case AF_INET6: + port = ntohs(sockaddr->type.sin6.sin6_port); + break; + default: + FATAL_ERROR(__FILE__, __LINE__, + "%s: %d", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKADDR, + ISC_MSG_UNKNOWNFAMILY, + "unknown address family"), + (int)sockaddr->type.sa.sa_family); + } + + return (port); +} + +isc_boolean_t +isc_sockaddr_ismulticast(const isc_sockaddr_t *sockaddr) { + isc_netaddr_t netaddr; + + if (sockaddr->type.sa.sa_family == AF_INET || + sockaddr->type.sa.sa_family == AF_INET6) { + isc_netaddr_fromsockaddr(&netaddr, sockaddr); + return (isc_netaddr_ismulticast(&netaddr)); + } + return (ISC_FALSE); +} + +isc_boolean_t +isc_sockaddr_isexperimental(const isc_sockaddr_t *sockaddr) { + isc_netaddr_t netaddr; + + if (sockaddr->type.sa.sa_family == AF_INET) { + isc_netaddr_fromsockaddr(&netaddr, sockaddr); + return (isc_netaddr_isexperimental(&netaddr)); + } + return (ISC_FALSE); +} + +isc_boolean_t +isc_sockaddr_issitelocal(const isc_sockaddr_t *sockaddr) { + isc_netaddr_t netaddr; + + if (sockaddr->type.sa.sa_family == AF_INET6) { + isc_netaddr_fromsockaddr(&netaddr, sockaddr); + return (isc_netaddr_issitelocal(&netaddr)); + } + return (ISC_FALSE); +} + +isc_boolean_t +isc_sockaddr_islinklocal(const isc_sockaddr_t *sockaddr) { + isc_netaddr_t netaddr; + + if (sockaddr->type.sa.sa_family == AF_INET6) { + isc_netaddr_fromsockaddr(&netaddr, sockaddr); + return (isc_netaddr_islinklocal(&netaddr)); + } + return (ISC_FALSE); +} + +isc_result_t +isc_sockaddr_frompath(isc_sockaddr_t *sockaddr, const char *path) { +#ifdef ISC_PLATFORM_HAVESYSUNH + if (strlen(path) >= sizeof(sockaddr->type.sunix.sun_path)) + return (ISC_R_NOSPACE); + memset(sockaddr, 0, sizeof(*sockaddr)); + sockaddr->length = sizeof(sockaddr->type.sunix); + sockaddr->type.sunix.sun_family = AF_UNIX; +#ifdef ISC_PLATFORM_HAVESALEN + sockaddr->type.sunix.sun_len = + (unsigned char)sizeof(sockaddr->type.sunix); +#endif + strcpy(sockaddr->type.sunix.sun_path, path); + return (ISC_R_SUCCESS); +#else + UNUSED(sockaddr); + UNUSED(path); + return (ISC_R_NOTIMPLEMENTED); +#endif +} diff --git a/contrib/ntp/lib/isc/socket_api.c b/contrib/ntp/lib/isc/socket_api.c new file mode 100644 index 0000000..3394ce0 --- /dev/null +++ b/contrib/ntp/lib/isc/socket_api.c @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +#include <config.h> + +#include <isc/app.h> +#include <isc/magic.h> +#include <isc/mutex.h> +#include <isc/once.h> +#include <isc/socket.h> +#include <isc/util.h> + +static isc_mutex_t createlock; +static isc_once_t once = ISC_ONCE_INIT; +static isc_socketmgrcreatefunc_t socketmgr_createfunc = NULL; + +static void +initialize(void) { + RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS); +} + +isc_result_t +isc_socket_register(isc_socketmgrcreatefunc_t createfunc) { + isc_result_t result = ISC_R_SUCCESS; + + RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS); + + LOCK(&createlock); + if (socketmgr_createfunc == NULL) + socketmgr_createfunc = createfunc; + else + result = ISC_R_EXISTS; + UNLOCK(&createlock); + + return (result); +} + +isc_result_t +isc_socketmgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx, + isc_socketmgr_t **managerp) +{ + isc_result_t result; + + LOCK(&createlock); + + REQUIRE(socketmgr_createfunc != NULL); + result = (*socketmgr_createfunc)(mctx, managerp); + + UNLOCK(&createlock); + + if (result == ISC_R_SUCCESS) + isc_appctx_setsocketmgr(actx, *managerp); + + return (result); +} + +isc_result_t +isc_socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp) { + isc_result_t result; + + LOCK(&createlock); + + REQUIRE(socketmgr_createfunc != NULL); + result = (*socketmgr_createfunc)(mctx, managerp); + + UNLOCK(&createlock); + + return (result); +} + +void +isc_socketmgr_destroy(isc_socketmgr_t **managerp) { + REQUIRE(managerp != NULL && ISCAPI_SOCKETMGR_VALID(*managerp)); + + (*managerp)->methods->destroy(managerp); + + ENSURE(*managerp == NULL); +} + +isc_result_t +isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, + isc_socket_t **socketp) +{ + REQUIRE(ISCAPI_SOCKETMGR_VALID(manager)); + + return (manager->methods->socketcreate(manager, pf, type, socketp)); +} + +void +isc_socket_attach(isc_socket_t *sock, isc_socket_t **socketp) { + REQUIRE(ISCAPI_SOCKET_VALID(sock)); + REQUIRE(socketp != NULL && *socketp == NULL); + + sock->methods->attach(sock, socketp); + + ENSURE(*socketp == sock); +} + +void +isc_socket_detach(isc_socket_t **socketp) { + REQUIRE(socketp != NULL && ISCAPI_SOCKET_VALID(*socketp)); + + (*socketp)->methods->detach(socketp); + + ENSURE(*socketp == NULL); +} + +isc_result_t +isc_socket_bind(isc_socket_t *sock, isc_sockaddr_t *sockaddr, + unsigned int options) +{ + REQUIRE(ISCAPI_SOCKET_VALID(sock)); + + return (sock->methods->bind(sock, sockaddr, options)); +} + +isc_result_t +isc_socket_sendto(isc_socket_t *sock, isc_region_t *region, isc_task_t *task, + isc_taskaction_t action, const void *arg, + isc_sockaddr_t *address, struct in6_pktinfo *pktinfo) +{ + REQUIRE(ISCAPI_SOCKET_VALID(sock)); + + return (sock->methods->sendto(sock, region, task, action, arg, address, + pktinfo)); +} + +isc_result_t +isc_socket_connect(isc_socket_t *sock, isc_sockaddr_t *addr, isc_task_t *task, + isc_taskaction_t action, const void *arg) +{ + REQUIRE(ISCAPI_SOCKET_VALID(sock)); + + return (sock->methods->connect(sock, addr, task, action, arg)); +} + +isc_result_t +isc_socket_recv(isc_socket_t *sock, isc_region_t *region, unsigned int minimum, + isc_task_t *task, isc_taskaction_t action, const void *arg) +{ + REQUIRE(ISCAPI_SOCKET_VALID(sock)); + + return (sock->methods->recv(sock, region, minimum, task, action, arg)); +} + +void +isc_socket_cancel(isc_socket_t *sock, isc_task_t *task, unsigned int how) { + REQUIRE(ISCAPI_SOCKET_VALID(sock)); + + sock->methods->cancel(sock, task, how); +} + +isc_result_t +isc_socket_getsockname(isc_socket_t *sock, isc_sockaddr_t *addressp) { + REQUIRE(ISCAPI_SOCKET_VALID(sock)); + + return (sock->methods->getsockname(sock, addressp)); +} + +void +isc_socket_ipv6only(isc_socket_t *sock, isc_boolean_t yes) { + REQUIRE(ISCAPI_SOCKET_VALID(sock)); + + sock->methods->ipv6only(sock, yes); +} + +isc_sockettype_t +isc_socket_gettype(isc_socket_t *sock) { + REQUIRE(ISCAPI_SOCKET_VALID(sock)); + + return (sock->methods->gettype(sock)); +} + +void +isc_socket_setname(isc_socket_t *socket, const char *name, void *tag) { + REQUIRE(ISCAPI_SOCKET_VALID(socket)); + + UNUSED(socket); /* in case REQUIRE() is empty */ + UNUSED(name); + UNUSED(tag); +} + +isc_result_t +isc_socket_fdwatchcreate(isc_socketmgr_t *manager, int fd, int flags, + isc_sockfdwatch_t callback, void *cbarg, + isc_task_t *task, isc_socket_t **socketp) +{ + REQUIRE(ISCAPI_SOCKETMGR_VALID(manager)); + + return (manager->methods->fdwatchcreate(manager, fd, flags, + callback, cbarg, task, + socketp)); +} + +isc_result_t +isc_socket_fdwatchpoke(isc_socket_t *sock, int flags) +{ + REQUIRE(ISCAPI_SOCKET_VALID(sock)); + + return(sock->methods->fdwatchpoke(sock, flags)); +} + +isc_result_t +isc_socket_dup(isc_socket_t *sock, isc_socket_t **socketp) { + REQUIRE(ISCAPI_SOCKET_VALID(sock)); + REQUIRE(socketp != NULL && *socketp == NULL); + + return(sock->methods->dup(sock, socketp)); +} + +int +isc_socket_getfd(isc_socket_t *sock) { + REQUIRE(ISCAPI_SOCKET_VALID(sock)); + + return(sock->methods->getfd(sock)); +} diff --git a/contrib/ntp/lib/isc/sparc64/include/isc/atomic.h b/contrib/ntp/lib/isc/sparc64/include/isc/atomic.h new file mode 100644 index 0000000..ab17de1 --- /dev/null +++ b/contrib/ntp/lib/isc/sparc64/include/isc/atomic.h @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: atomic.h,v 1.5 2007/06/19 23:47:18 tbox Exp $ */ + +/* + * This code was written based on FreeBSD's kernel source whose copyright + * follows: + */ + +/*- + * Copyright (c) 1998 Doug Rabson. + * Copyright (c) 2001 Jake Burkholder. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: FreeBSD: src/sys/i386/include/atomic.h,v 1.20 2001/02/11 + * $FreeBSD: 258945 2013-12-04 21:33:17Z roberto $ + */ + +#ifndef ISC_ATOMIC_H +#define ISC_ATOMIC_H 1 + +#include <isc/platform.h> +#include <isc/types.h> + +#define ASI_P 0x80 /* Primary Address Space Identifier */ + +#ifdef ISC_PLATFORM_USEGCCASM + +/* + * This routine atomically increments the value stored in 'p' by 'val', and + * returns the previous value. + */ +static inline isc_int32_t +isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) { + isc_int32_t prev, swapped; + + for (prev = *(volatile isc_int32_t *)p; ; prev = swapped) { + swapped = prev + val; + __asm__ volatile( + "casa [%1] %2, %3, %0" + : "+r"(swapped) + : "r"(p), "n"(ASI_P), "r"(prev)); + if (swapped == prev) + break; + } + + return (prev); +} + +/* + * This routine atomically stores the value 'val' in 'p'. + */ +static inline void +isc_atomic_store(isc_int32_t *p, isc_int32_t val) { + isc_int32_t prev, swapped; + + for (prev = *(volatile isc_int32_t *)p; ; prev = swapped) { + swapped = val; + __asm__ volatile( + "casa [%1] %2, %3, %0" + : "+r"(swapped) + : "r"(p), "n"(ASI_P), "r"(prev) + : "memory"); + if (swapped == prev) + break; + } +} + +/* + * This routine atomically replaces the value in 'p' with 'val', if the + * original value is equal to 'cmpval'. The original value is returned in any + * case. + */ +static inline isc_int32_t +isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) { + isc_int32_t temp = val; + + __asm__ volatile( + "casa [%1] %2, %3, %0" + : "+r"(temp) + : "r"(p), "n"(ASI_P), "r"(cmpval)); + + return (temp); +} + +#else /* ISC_PLATFORM_USEGCCASM */ + +#error "unsupported compiler. disable atomic ops by --disable-atomic" + +#endif /* ISC_PLATFORM_USEGCCASM */ + +#endif /* ISC_ATOMIC_H */ diff --git a/contrib/ntp/lib/isc/stats.c b/contrib/ntp/lib/isc/stats.c new file mode 100644 index 0000000..8b624b2 --- /dev/null +++ b/contrib/ntp/lib/isc/stats.c @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2009, 2012 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/*! \file */ + +#include <config.h> + +#include <string.h> + +#include <isc/atomic.h> +#include <isc/buffer.h> +#include <isc/magic.h> +#include <isc/mem.h> +#include <isc/platform.h> +#include <isc/print.h> +#include <isc/rwlock.h> +#include <isc/stats.h> +#include <isc/util.h> + +#define ISC_STATS_MAGIC ISC_MAGIC('S', 't', 'a', 't') +#define ISC_STATS_VALID(x) ISC_MAGIC_VALID(x, ISC_STATS_MAGIC) + +#ifndef ISC_STATS_USEMULTIFIELDS +#if defined(ISC_RWLOCK_USEATOMIC) && defined(ISC_PLATFORM_HAVEXADD) && !defined(ISC_PLATFORM_HAVEXADDQ) +#define ISC_STATS_USEMULTIFIELDS 1 +#else +#define ISC_STATS_USEMULTIFIELDS 0 +#endif +#endif /* ISC_STATS_USEMULTIFIELDS */ + +#if ISC_STATS_USEMULTIFIELDS +typedef struct { + isc_uint32_t hi; + isc_uint32_t lo; +} isc_stat_t; +#else +typedef isc_uint64_t isc_stat_t; +#endif + +struct isc_stats { + /*% Unlocked */ + unsigned int magic; + isc_mem_t *mctx; + int ncounters; + + isc_mutex_t lock; + unsigned int references; /* locked by lock */ + + /*% + * Locked by counterlock or unlocked if efficient rwlock is not + * available. + */ +#ifdef ISC_RWLOCK_USEATOMIC + isc_rwlock_t counterlock; +#endif + isc_stat_t *counters; + + /*% + * We don't want to lock the counters while we are dumping, so we first + * copy the current counter values into a local array. This buffer + * will be used as the copy destination. It's allocated on creation + * of the stats structure so that the dump operation won't fail due + * to memory allocation failure. + * XXX: this approach is weird for non-threaded build because the + * additional memory and the copy overhead could be avoided. We prefer + * simplicity here, however, under the assumption that this function + * should be only rarely called. + */ + isc_uint64_t *copiedcounters; +}; + +static isc_result_t +create_stats(isc_mem_t *mctx, int ncounters, isc_stats_t **statsp) { + isc_stats_t *stats; + isc_result_t result = ISC_R_SUCCESS; + + REQUIRE(statsp != NULL && *statsp == NULL); + + stats = isc_mem_get(mctx, sizeof(*stats)); + if (stats == NULL) + return (ISC_R_NOMEMORY); + + result = isc_mutex_init(&stats->lock); + if (result != ISC_R_SUCCESS) + goto clean_stats; + + stats->counters = isc_mem_get(mctx, sizeof(isc_stat_t) * ncounters); + if (stats->counters == NULL) { + result = ISC_R_NOMEMORY; + goto clean_mutex; + } + stats->copiedcounters = isc_mem_get(mctx, + sizeof(isc_uint64_t) * ncounters); + if (stats->copiedcounters == NULL) { + result = ISC_R_NOMEMORY; + goto clean_counters; + } + +#ifdef ISC_RWLOCK_USEATOMIC + result = isc_rwlock_init(&stats->counterlock, 0, 0); + if (result != ISC_R_SUCCESS) + goto clean_copiedcounters; +#endif + + stats->references = 1; + memset(stats->counters, 0, sizeof(isc_stat_t) * ncounters); + stats->mctx = NULL; + isc_mem_attach(mctx, &stats->mctx); + stats->ncounters = ncounters; + stats->magic = ISC_STATS_MAGIC; + + *statsp = stats; + + return (result); + +clean_counters: + isc_mem_put(mctx, stats->counters, sizeof(isc_stat_t) * ncounters); + +#ifdef ISC_RWLOCK_USEATOMIC +clean_copiedcounters: + isc_mem_put(mctx, stats->copiedcounters, + sizeof(isc_stat_t) * ncounters); +#endif + +clean_mutex: + DESTROYLOCK(&stats->lock); + +clean_stats: + isc_mem_put(mctx, stats, sizeof(*stats)); + + return (result); +} + +void +isc_stats_attach(isc_stats_t *stats, isc_stats_t **statsp) { + REQUIRE(ISC_STATS_VALID(stats)); + REQUIRE(statsp != NULL && *statsp == NULL); + + LOCK(&stats->lock); + stats->references++; + UNLOCK(&stats->lock); + + *statsp = stats; +} + +void +isc_stats_detach(isc_stats_t **statsp) { + isc_stats_t *stats; + + REQUIRE(statsp != NULL && ISC_STATS_VALID(*statsp)); + + stats = *statsp; + *statsp = NULL; + + LOCK(&stats->lock); + stats->references--; + UNLOCK(&stats->lock); + + if (stats->references == 0) { + isc_mem_put(stats->mctx, stats->copiedcounters, + sizeof(isc_stat_t) * stats->ncounters); + isc_mem_put(stats->mctx, stats->counters, + sizeof(isc_stat_t) * stats->ncounters); + DESTROYLOCK(&stats->lock); +#ifdef ISC_RWLOCK_USEATOMIC + isc_rwlock_destroy(&stats->counterlock); +#endif + isc_mem_putanddetach(&stats->mctx, stats, sizeof(*stats)); + } +} + +int +isc_stats_ncounters(isc_stats_t *stats) { + REQUIRE(ISC_STATS_VALID(stats)); + + return (stats->ncounters); +} + +static inline void +incrementcounter(isc_stats_t *stats, int counter) { + isc_int32_t prev; + +#ifdef ISC_RWLOCK_USEATOMIC + /* + * We use a "read" lock to prevent other threads from reading the + * counter while we "writing" a counter field. The write access itself + * is protected by the atomic operation. + */ + isc_rwlock_lock(&stats->counterlock, isc_rwlocktype_read); +#endif + +#if ISC_STATS_USEMULTIFIELDS + prev = isc_atomic_xadd((isc_int32_t *)&stats->counters[counter].lo, 1); + /* + * If the lower 32-bit field overflows, increment the higher field. + * Note that it's *theoretically* possible that the lower field + * overlaps again before the higher field is incremented. It doesn't + * matter, however, because we don't read the value until + * isc_stats_copy() is called where the whole process is protected + * by the write (exclusive) lock. + */ + if (prev == (isc_int32_t)0xffffffff) + isc_atomic_xadd((isc_int32_t *)&stats->counters[counter].hi, 1); +#elif defined(ISC_PLATFORM_HAVEXADDQ) + UNUSED(prev); + isc_atomic_xaddq((isc_int64_t *)&stats->counters[counter], 1); +#else + UNUSED(prev); + stats->counters[counter]++; +#endif + +#ifdef ISC_RWLOCK_USEATOMIC + isc_rwlock_unlock(&stats->counterlock, isc_rwlocktype_read); +#endif +} + +static inline void +decrementcounter(isc_stats_t *stats, int counter) { + isc_int32_t prev; + +#ifdef ISC_RWLOCK_USEATOMIC + isc_rwlock_lock(&stats->counterlock, isc_rwlocktype_read); +#endif + +#if ISC_STATS_USEMULTIFIELDS + prev = isc_atomic_xadd((isc_int32_t *)&stats->counters[counter].lo, -1); + if (prev == 0) + isc_atomic_xadd((isc_int32_t *)&stats->counters[counter].hi, + -1); +#elif defined(ISC_PLATFORM_HAVEXADDQ) + UNUSED(prev); + isc_atomic_xaddq((isc_int64_t *)&stats->counters[counter], -1); +#else + UNUSED(prev); + stats->counters[counter]--; +#endif + +#ifdef ISC_RWLOCK_USEATOMIC + isc_rwlock_unlock(&stats->counterlock, isc_rwlocktype_read); +#endif +} + +static void +copy_counters(isc_stats_t *stats) { + int i; + +#ifdef ISC_RWLOCK_USEATOMIC + /* + * We use a "write" lock before "reading" the statistics counters as + * an exclusive lock. + */ + isc_rwlock_lock(&stats->counterlock, isc_rwlocktype_write); +#endif + +#if ISC_STATS_USEMULTIFIELDS + for (i = 0; i < stats->ncounters; i++) { + stats->copiedcounters[i] = + (isc_uint64_t)(stats->counters[i].hi) << 32 | + stats->counters[i].lo; + } +#else + UNUSED(i); + memcpy(stats->copiedcounters, stats->counters, + stats->ncounters * sizeof(isc_stat_t)); +#endif + +#ifdef ISC_RWLOCK_USEATOMIC + isc_rwlock_unlock(&stats->counterlock, isc_rwlocktype_write); +#endif +} + +isc_result_t +isc_stats_create(isc_mem_t *mctx, isc_stats_t **statsp, int ncounters) { + REQUIRE(statsp != NULL && *statsp == NULL); + + return (create_stats(mctx, ncounters, statsp)); +} + +void +isc_stats_increment(isc_stats_t *stats, isc_statscounter_t counter) { + REQUIRE(ISC_STATS_VALID(stats)); + REQUIRE(counter < stats->ncounters); + + incrementcounter(stats, (int)counter); +} + +void +isc_stats_decrement(isc_stats_t *stats, isc_statscounter_t counter) { + REQUIRE(ISC_STATS_VALID(stats)); + REQUIRE(counter < stats->ncounters); + + decrementcounter(stats, (int)counter); +} + +void +isc_stats_dump(isc_stats_t *stats, isc_stats_dumper_t dump_fn, + void *arg, unsigned int options) +{ + int i; + + REQUIRE(ISC_STATS_VALID(stats)); + + copy_counters(stats); + + for (i = 0; i < stats->ncounters; i++) { + if ((options & ISC_STATSDUMP_VERBOSE) == 0 && + stats->copiedcounters[i] == 0) + continue; + dump_fn((isc_statscounter_t)i, stats->copiedcounters[i], arg); + } +} diff --git a/contrib/ntp/lib/isc/string.c b/contrib/ntp/lib/isc/string.c new file mode 100644 index 0000000..cba517c --- /dev/null +++ b/contrib/ntp/lib/isc/string.c @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2004-2007, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001, 2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/*! \file */ + +#include <config.h> + +#include <ctype.h> + +#include <isc/mem.h> +#include <isc/print.h> +#include <isc/region.h> +#include <isc/string.h> +#include <isc/util.h> + +static char digits[] = "0123456789abcdefghijklmnoprstuvwxyz"; + +isc_uint64_t +isc_string_touint64(char *source, char **end, int base) { + isc_uint64_t tmp; + isc_uint64_t overflow; + char *s = source; + char *o; + char c; + + if ((base < 0) || (base == 1) || (base > 36)) { + *end = source; + return (0); + } + + while (*s != 0 && isascii(*s&0xff) && isspace(*s&0xff)) + s++; + if (*s == '+' /* || *s == '-' */) + s++; + if (base == 0) { + if (*s == '0' && (*(s+1) == 'X' || *(s+1) == 'x')) { + s += 2; + base = 16; + } else if (*s == '0') + base = 8; + else + base = 10; + } + if (*s == 0) { + *end = source; + return (0); + } + overflow = ~0; + overflow /= base; + tmp = 0; + + while ((c = *s) != 0) { + c = tolower(c&0xff); + /* end ? */ + if ((o = strchr(digits, c)) == NULL) { + *end = s; + return (tmp); + } + /* end ? */ + if ((o - digits) >= base) { + *end = s; + return (tmp); + } + /* overflow ? */ + if (tmp > overflow) { + *end = source; + return (0); + } + tmp *= base; + /* overflow ? */ + if ((tmp + (o - digits)) < tmp) { + *end = source; + return (0); + } + tmp += o - digits; + s++; + } + *end = s; + return (tmp); +} + +isc_result_t +isc_string_copy(char *target, size_t size, const char *source) { + REQUIRE(size > 0U); + + if (strlcpy(target, source, size) >= size) { + memset(target, ISC_STRING_MAGIC, size); + return (ISC_R_NOSPACE); + } + + ENSURE(strlen(target) < size); + + return (ISC_R_SUCCESS); +} + +void +isc_string_copy_truncate(char *target, size_t size, const char *source) { + REQUIRE(size > 0U); + + strlcpy(target, source, size); + + ENSURE(strlen(target) < size); +} + +isc_result_t +isc_string_append(char *target, size_t size, const char *source) { + REQUIRE(size > 0U); + REQUIRE(strlen(target) < size); + + if (strlcat(target, source, size) >= size) { + memset(target, ISC_STRING_MAGIC, size); + return (ISC_R_NOSPACE); + } + + ENSURE(strlen(target) < size); + + return (ISC_R_SUCCESS); +} + +void +isc_string_append_truncate(char *target, size_t size, const char *source) { + REQUIRE(size > 0U); + REQUIRE(strlen(target) < size); + + strlcat(target, source, size); + + ENSURE(strlen(target) < size); +} + +isc_result_t +isc_string_printf(char *target, size_t size, const char *format, ...) { + va_list args; + size_t n; + + REQUIRE(size > 0U); + + va_start(args, format); + n = vsnprintf(target, size, format, args); + va_end(args); + + if (n >= size) { + memset(target, ISC_STRING_MAGIC, size); + return (ISC_R_NOSPACE); + } + + ENSURE(strlen(target) < size); + + return (ISC_R_SUCCESS); +} + +void +isc_string_printf_truncate(char *target, size_t size, const char *format, ...) +{ + va_list args; + + REQUIRE(size > 0U); + + va_start(args, format); + /* check return code? */ + (void)vsnprintf(target, size, format, args); + va_end(args); + + ENSURE(strlen(target) < size); +} + +char * +isc_string_regiondup(isc_mem_t *mctx, const isc_region_t *source) { + char *target; + + REQUIRE(mctx != NULL); + REQUIRE(source != NULL); + + target = (char *) isc_mem_allocate(mctx, source->length + 1); + if (target != NULL) { + memcpy(source->base, target, source->length); + target[source->length] = '\0'; + } + + return (target); +} + +char * +isc_string_separate(char **stringp, const char *delim) { + char *string = *stringp; + char *s; + const char *d; + char sc, dc; + + if (string == NULL) + return (NULL); + + for (s = string; (sc = *s) != '\0'; s++) + for (d = delim; (dc = *d) != '\0'; d++) + if (sc == dc) { + *s++ = '\0'; + *stringp = s; + return (string); + } + *stringp = NULL; + return (string); +} + +size_t +isc_string_strlcpy(char *dst, const char *src, size_t size) +{ + char *d = dst; + const char *s = src; + size_t n = size; + + /* Copy as many bytes as will fit */ + if (n != 0U && --n != 0U) { + do { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0U); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0U) { + if (size != 0U) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} + +size_t +isc_string_strlcat(char *dst, const char *src, size_t size) +{ + char *d = dst; + const char *s = src; + size_t n = size; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0U && *d != '\0') + d++; + dlen = d - dst; + n = size - dlen; + + if (n == 0U) + return(dlen + strlen(s)); + while (*s != '\0') { + if (n != 1U) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return(dlen + (s - src)); /* count does not include NUL */ +} diff --git a/contrib/ntp/lib/isc/strtoul.c b/contrib/ntp/lib/isc/strtoul.c new file mode 100644 index 0000000..18d93e2 --- /dev/null +++ b/contrib/ntp/lib/isc/strtoul.c @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/*! \file */ +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strtoul.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ + +/* $Id: strtoul.c,v 1.7 2007/06/19 23:47:17 tbox Exp $ */ + +#include <config.h> + +#include <limits.h> +#include <ctype.h> +#include <errno.h> + +#include <isc/stdlib.h> +#include <isc/util.h> + +/*! + * Convert a string to an unsigned long integer. + * + * Ignores `locale' stuff. Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +unsigned long +isc_strtoul(const char *nptr, char **endptr, int base) { + const char *s = nptr; + unsigned long acc; + unsigned char c; + unsigned long cutoff; + int neg = 0, any, cutlim; + + /* + * See strtol for comments as to the logic used. + */ + do { + c = *s++; + } while (isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else if (c == '+') + c = *s++; + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + cutoff = (unsigned long)ULONG_MAX / (unsigned long)base; + cutlim = (unsigned long)ULONG_MAX % (unsigned long)base; + for (acc = 0, any = 0;; c = *s++) { + if (!isascii(c)) + break; + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = ULONG_MAX; + errno = ERANGE; + } else if (neg) + acc = -acc; + if (endptr != 0) + DE_CONST(any ? s - 1 : nptr, *endptr); + return (acc); +} diff --git a/contrib/ntp/lib/isc/symtab.c b/contrib/ntp/lib/isc/symtab.c new file mode 100644 index 0000000..d4c1dcc --- /dev/null +++ b/contrib/ntp/lib/isc/symtab.c @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1996-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/*! \file */ + +#include <config.h> + +#include <ctype.h> + +#include <isc/magic.h> +#include <isc/mem.h> +#include <isc/string.h> +#include <isc/symtab.h> +#include <isc/util.h> + +typedef struct elt { + char * key; + unsigned int type; + isc_symvalue_t value; + LINK(struct elt) link; +} elt_t; + +typedef LIST(elt_t) eltlist_t; + +#define SYMTAB_MAGIC ISC_MAGIC('S', 'y', 'm', 'T') +#define VALID_SYMTAB(st) ISC_MAGIC_VALID(st, SYMTAB_MAGIC) + +struct isc_symtab { + /* Unlocked. */ + unsigned int magic; + isc_mem_t * mctx; + unsigned int size; + unsigned int count; + unsigned int maxload; + eltlist_t * table; + isc_symtabaction_t undefine_action; + void * undefine_arg; + isc_boolean_t case_sensitive; +}; + +isc_result_t +isc_symtab_create(isc_mem_t *mctx, unsigned int size, + isc_symtabaction_t undefine_action, + void *undefine_arg, + isc_boolean_t case_sensitive, + isc_symtab_t **symtabp) +{ + isc_symtab_t *symtab; + unsigned int i; + + REQUIRE(mctx != NULL); + REQUIRE(symtabp != NULL && *symtabp == NULL); + REQUIRE(size > 0); /* Should be prime. */ + + symtab = (isc_symtab_t *)isc_mem_get(mctx, sizeof(*symtab)); + if (symtab == NULL) + return (ISC_R_NOMEMORY); + symtab->table = (eltlist_t *)isc_mem_get(mctx, + size * sizeof(eltlist_t)); + if (symtab->table == NULL) { + isc_mem_put(mctx, symtab, sizeof(*symtab)); + return (ISC_R_NOMEMORY); + } + for (i = 0; i < size; i++) + INIT_LIST(symtab->table[i]); + symtab->mctx = mctx; + symtab->size = size; + symtab->count = 0; + symtab->maxload = size * 3 / 4; + symtab->undefine_action = undefine_action; + symtab->undefine_arg = undefine_arg; + symtab->case_sensitive = case_sensitive; + symtab->magic = SYMTAB_MAGIC; + + *symtabp = symtab; + + return (ISC_R_SUCCESS); +} + +void +isc_symtab_destroy(isc_symtab_t **symtabp) { + isc_symtab_t *symtab; + unsigned int i; + elt_t *elt, *nelt; + + REQUIRE(symtabp != NULL); + symtab = *symtabp; + REQUIRE(VALID_SYMTAB(symtab)); + + for (i = 0; i < symtab->size; i++) { + for (elt = HEAD(symtab->table[i]); elt != NULL; elt = nelt) { + nelt = NEXT(elt, link); + if (symtab->undefine_action != NULL) + (symtab->undefine_action)(elt->key, + elt->type, + elt->value, + symtab->undefine_arg); + isc_mem_put(symtab->mctx, elt, sizeof(*elt)); + } + } + isc_mem_put(symtab->mctx, symtab->table, + symtab->size * sizeof(eltlist_t)); + symtab->magic = 0; + isc_mem_put(symtab->mctx, symtab, sizeof(*symtab)); + + *symtabp = NULL; +} + +static inline unsigned int +hash(const char *key, isc_boolean_t case_sensitive) { + const char *s; + unsigned int h = 0; + int c; + + /* + * This hash function is similar to the one Ousterhout + * uses in Tcl. + */ + + if (case_sensitive) { + for (s = key; *s != '\0'; s++) { + h += (h << 3) + *s; + } + } else { + for (s = key; *s != '\0'; s++) { + c = *s; + c = tolower((unsigned char)c); + h += (h << 3) + c; + } + } + + return (h); +} + +#define FIND(s, k, t, b, e) \ + b = hash((k), (s)->case_sensitive) % (s)->size; \ + if ((s)->case_sensitive) { \ + for (e = HEAD((s)->table[b]); e != NULL; e = NEXT(e, link)) { \ + if (((t) == 0 || e->type == (t)) && \ + strcmp(e->key, (k)) == 0) \ + break; \ + } \ + } else { \ + for (e = HEAD((s)->table[b]); e != NULL; e = NEXT(e, link)) { \ + if (((t) == 0 || e->type == (t)) && \ + strcasecmp(e->key, (k)) == 0) \ + break; \ + } \ + } + +isc_result_t +isc_symtab_lookup(isc_symtab_t *symtab, const char *key, unsigned int type, + isc_symvalue_t *value) +{ + unsigned int bucket; + elt_t *elt; + + REQUIRE(VALID_SYMTAB(symtab)); + REQUIRE(key != NULL); + + FIND(symtab, key, type, bucket, elt); + + if (elt == NULL) + return (ISC_R_NOTFOUND); + + if (value != NULL) + *value = elt->value; + + return (ISC_R_SUCCESS); +} + +static void +grow_table(isc_symtab_t *symtab) { + eltlist_t *newtable; + unsigned int i, newsize, newmax; + + REQUIRE(symtab != NULL); + + newsize = symtab->size * 2; + newmax = newsize * 3 / 4; + INSIST(newsize > 0U && newmax > 0U); + + newtable = isc_mem_get(symtab->mctx, newsize * sizeof(eltlist_t)); + if (newtable == NULL) + return; + + for (i = 0; i < newsize; i++) + INIT_LIST(newtable[i]); + + for (i = 0; i < symtab->size; i++) { + elt_t *elt, *nelt; + + for (elt = HEAD(symtab->table[i]); elt != NULL; elt = nelt) { + unsigned int hv; + + nelt = NEXT(elt, link); + + UNLINK(symtab->table[i], elt, link); + hv = hash(elt->key, symtab->case_sensitive); + APPEND(newtable[hv % newsize], elt, link); + } + } + + isc_mem_put(symtab->mctx, symtab->table, + symtab->size * sizeof(eltlist_t)); + + symtab->table = newtable; + symtab->size = newsize; + symtab->maxload = newmax; +} + +isc_result_t +isc_symtab_define(isc_symtab_t *symtab, const char *key, unsigned int type, + isc_symvalue_t value, isc_symexists_t exists_policy) +{ + unsigned int bucket; + elt_t *elt; + + REQUIRE(VALID_SYMTAB(symtab)); + REQUIRE(key != NULL); + REQUIRE(type != 0); + + FIND(symtab, key, type, bucket, elt); + + if (exists_policy != isc_symexists_add && elt != NULL) { + if (exists_policy == isc_symexists_reject) + return (ISC_R_EXISTS); + INSIST(exists_policy == isc_symexists_replace); + UNLINK(symtab->table[bucket], elt, link); + if (symtab->undefine_action != NULL) + (symtab->undefine_action)(elt->key, elt->type, + elt->value, + symtab->undefine_arg); + } else { + elt = (elt_t *)isc_mem_get(symtab->mctx, sizeof(*elt)); + if (elt == NULL) + return (ISC_R_NOMEMORY); + ISC_LINK_INIT(elt, link); + symtab->count++; + } + + /* + * Though the "key" can be const coming in, it is not stored as const + * so that the calling program can easily have writable access to + * it in its undefine_action function. In the event that it *was* + * truly const coming in and then the caller modified it anyway ... + * well, don't do that! + */ + DE_CONST(key, elt->key); + elt->type = type; + elt->value = value; + + /* + * We prepend so that the most recent definition will be found. + */ + PREPEND(symtab->table[bucket], elt, link); + + if (symtab->count > symtab->maxload) + grow_table(symtab); + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_symtab_undefine(isc_symtab_t *symtab, const char *key, unsigned int type) { + unsigned int bucket; + elt_t *elt; + + REQUIRE(VALID_SYMTAB(symtab)); + REQUIRE(key != NULL); + + FIND(symtab, key, type, bucket, elt); + + if (elt == NULL) + return (ISC_R_NOTFOUND); + + if (symtab->undefine_action != NULL) + (symtab->undefine_action)(elt->key, elt->type, + elt->value, symtab->undefine_arg); + UNLINK(symtab->table[bucket], elt, link); + isc_mem_put(symtab->mctx, elt, sizeof(*elt)); + symtab->count--; + + return (ISC_R_SUCCESS); +} diff --git a/contrib/ntp/lib/isc/task.c b/contrib/ntp/lib/isc/task.c new file mode 100644 index 0000000..cd19d2d --- /dev/null +++ b/contrib/ntp/lib/isc/task.c @@ -0,0 +1,1813 @@ +/* + * Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/*! \file + * \author Principal Author: Bob Halley + */ + +/* + * XXXRTH Need to document the states a task can be in, and the rules + * for changing states. + */ + +#include <config.h> + +#include <isc/condition.h> +#include <isc/event.h> +#include <isc/magic.h> +#include <isc/mem.h> +#include <isc/msgs.h> +#include <isc/platform.h> +#include <isc/string.h> +#include <isc/task.h> +#include <isc/thread.h> +#include <isc/util.h> +#include <isc/xml.h> + +#ifdef OPENSSL_LEAKS +#include <openssl/err.h> +#endif + +/*% + * For BIND9 internal applications: + * when built with threads we use multiple worker threads shared by the whole + * application. + * when built without threads we share a single global task manager and use + * an integrated event loop for socket, timer, and other generic task events. + * For generic library: + * we don't use either of them: an application can have multiple task managers + * whether or not it's threaded, and if the application is threaded each thread + * is expected to have a separate manager; no "worker threads" are shared by + * the application threads. + */ +#ifdef BIND9 +#ifdef ISC_PLATFORM_USETHREADS +#define USE_WORKER_THREADS +#else +#define USE_SHARED_MANAGER +#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* BIND9 */ + +#include "task_p.h" + +#ifdef ISC_TASK_TRACE +#define XTRACE(m) fprintf(stderr, "task %p thread %lu: %s\n", \ + task, isc_thread_self(), (m)) +#define XTTRACE(t, m) fprintf(stderr, "task %p thread %lu: %s\n", \ + (t), isc_thread_self(), (m)) +#define XTHREADTRACE(m) fprintf(stderr, "thread %lu: %s\n", \ + isc_thread_self(), (m)) +#else +#define XTRACE(m) +#define XTTRACE(t, m) +#define XTHREADTRACE(m) +#endif + +/*** + *** Types. + ***/ + +typedef enum { + task_state_idle, task_state_ready, task_state_running, + task_state_done +} task_state_t; + +#if defined(HAVE_LIBXML2) && defined(BIND9) +static const char *statenames[] = { + "idle", "ready", "running", "done", +}; +#endif + +#define TASK_MAGIC ISC_MAGIC('T', 'A', 'S', 'K') +#define VALID_TASK(t) ISC_MAGIC_VALID(t, TASK_MAGIC) + +typedef struct isc__task isc__task_t; +typedef struct isc__taskmgr isc__taskmgr_t; + +struct isc__task { + /* Not locked. */ + isc_task_t common; + isc__taskmgr_t * manager; + isc_mutex_t lock; + /* Locked by task lock. */ + task_state_t state; + unsigned int references; + isc_eventlist_t events; + isc_eventlist_t on_shutdown; + unsigned int quantum; + unsigned int flags; + isc_stdtime_t now; + char name[16]; + void * tag; + /* Locked by task manager lock. */ + LINK(isc__task_t) link; + LINK(isc__task_t) ready_link; + LINK(isc__task_t) ready_priority_link; +}; + +#define TASK_F_SHUTTINGDOWN 0x01 +#define TASK_F_PRIVILEGED 0x02 + +#define TASK_SHUTTINGDOWN(t) (((t)->flags & TASK_F_SHUTTINGDOWN) \ + != 0) + +#define TASK_MANAGER_MAGIC ISC_MAGIC('T', 'S', 'K', 'M') +#define VALID_MANAGER(m) ISC_MAGIC_VALID(m, TASK_MANAGER_MAGIC) + +typedef ISC_LIST(isc__task_t) isc__tasklist_t; + +struct isc__taskmgr { + /* Not locked. */ + isc_taskmgr_t common; + isc_mem_t * mctx; + isc_mutex_t lock; +#ifdef ISC_PLATFORM_USETHREADS + unsigned int workers; + isc_thread_t * threads; +#endif /* ISC_PLATFORM_USETHREADS */ + /* Locked by task manager lock. */ + unsigned int default_quantum; + LIST(isc__task_t) tasks; + isc__tasklist_t ready_tasks; + isc__tasklist_t ready_priority_tasks; + isc_taskmgrmode_t mode; +#ifdef ISC_PLATFORM_USETHREADS + isc_condition_t work_available; + isc_condition_t exclusive_granted; + isc_condition_t paused; +#endif /* ISC_PLATFORM_USETHREADS */ + unsigned int tasks_running; + isc_boolean_t pause_requested; + isc_boolean_t exclusive_requested; + isc_boolean_t exiting; +#ifdef USE_SHARED_MANAGER + unsigned int refs; +#endif /* ISC_PLATFORM_USETHREADS */ +}; + +#define DEFAULT_TASKMGR_QUANTUM 10 +#define DEFAULT_DEFAULT_QUANTUM 5 +#define FINISHED(m) ((m)->exiting && EMPTY((m)->tasks)) + +#ifdef USE_SHARED_MANAGER +static isc__taskmgr_t *taskmgr = NULL; +#endif /* USE_SHARED_MANAGER */ + +/*% + * The following can be either static or public, depending on build environment. + */ + +#ifdef BIND9 +#define ISC_TASKFUNC_SCOPE +#else +#define ISC_TASKFUNC_SCOPE static +#endif + +ISC_TASKFUNC_SCOPE isc_result_t +isc__task_create(isc_taskmgr_t *manager0, unsigned int quantum, + isc_task_t **taskp); +ISC_TASKFUNC_SCOPE void +isc__task_attach(isc_task_t *source0, isc_task_t **targetp); +ISC_TASKFUNC_SCOPE void +isc__task_detach(isc_task_t **taskp); +ISC_TASKFUNC_SCOPE void +isc__task_send(isc_task_t *task0, isc_event_t **eventp); +ISC_TASKFUNC_SCOPE void +isc__task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp); +ISC_TASKFUNC_SCOPE unsigned int +isc__task_purgerange(isc_task_t *task0, void *sender, isc_eventtype_t first, + isc_eventtype_t last, void *tag); +ISC_TASKFUNC_SCOPE unsigned int +isc__task_purge(isc_task_t *task, void *sender, isc_eventtype_t type, + void *tag); +ISC_TASKFUNC_SCOPE isc_boolean_t +isc__task_purgeevent(isc_task_t *task0, isc_event_t *event); +ISC_TASKFUNC_SCOPE unsigned int +isc__task_unsendrange(isc_task_t *task, void *sender, isc_eventtype_t first, + isc_eventtype_t last, void *tag, + isc_eventlist_t *events); +ISC_TASKFUNC_SCOPE unsigned int +isc__task_unsend(isc_task_t *task, void *sender, isc_eventtype_t type, + void *tag, isc_eventlist_t *events); +ISC_TASKFUNC_SCOPE isc_result_t +isc__task_onshutdown(isc_task_t *task0, isc_taskaction_t action, + const void *arg); +ISC_TASKFUNC_SCOPE void +isc__task_shutdown(isc_task_t *task0); +ISC_TASKFUNC_SCOPE void +isc__task_destroy(isc_task_t **taskp); +ISC_TASKFUNC_SCOPE void +isc__task_setname(isc_task_t *task0, const char *name, void *tag); +ISC_TASKFUNC_SCOPE const char * +isc__task_getname(isc_task_t *task0); +ISC_TASKFUNC_SCOPE void * +isc__task_gettag(isc_task_t *task0); +ISC_TASKFUNC_SCOPE void +isc__task_getcurrenttime(isc_task_t *task0, isc_stdtime_t *t); +ISC_TASKFUNC_SCOPE isc_result_t +isc__taskmgr_create(isc_mem_t *mctx, unsigned int workers, + unsigned int default_quantum, isc_taskmgr_t **managerp); +ISC_TASKFUNC_SCOPE void +isc__taskmgr_destroy(isc_taskmgr_t **managerp); +ISC_TASKFUNC_SCOPE isc_result_t +isc__task_beginexclusive(isc_task_t *task); +ISC_TASKFUNC_SCOPE void +isc__task_endexclusive(isc_task_t *task0); +ISC_TASKFUNC_SCOPE void +isc__task_setprivilege(isc_task_t *task0, isc_boolean_t priv); +ISC_TASKFUNC_SCOPE isc_boolean_t +isc__task_privilege(isc_task_t *task0); +ISC_TASKFUNC_SCOPE void +isc__taskmgr_setmode(isc_taskmgr_t *manager0, isc_taskmgrmode_t mode); +ISC_TASKFUNC_SCOPE isc_taskmgrmode_t +isc__taskmgr_mode(isc_taskmgr_t *manager0); + +static inline isc_boolean_t +empty_readyq(isc__taskmgr_t *manager); + +static inline isc__task_t * +pop_readyq(isc__taskmgr_t *manager); + +static inline void +push_readyq(isc__taskmgr_t *manager, isc__task_t *task); + +static struct isc__taskmethods { + isc_taskmethods_t methods; + + /*% + * The following are defined just for avoiding unused static functions. + */ +#ifndef BIND9 + void *purgeevent, *unsendrange, *getname, *gettag, *getcurrenttime; +#endif +} taskmethods = { + { + isc__task_attach, + isc__task_detach, + isc__task_destroy, + isc__task_send, + isc__task_sendanddetach, + isc__task_unsend, + isc__task_onshutdown, + isc__task_shutdown, + isc__task_setname, + isc__task_purge, + isc__task_purgerange, + isc__task_beginexclusive, + isc__task_endexclusive, + isc__task_setprivilege, + isc__task_privilege + } +#ifndef BIND9 + , + (void *)isc__task_purgeevent, (void *)isc__task_unsendrange, + (void *)isc__task_getname, (void *)isc__task_gettag, + (void *)isc__task_getcurrenttime +#endif +}; + +static isc_taskmgrmethods_t taskmgrmethods = { + isc__taskmgr_destroy, + isc__taskmgr_setmode, + isc__taskmgr_mode, + isc__task_create +}; + +/*** + *** Tasks. + ***/ + +static void +task_finished(isc__task_t *task) { + isc__taskmgr_t *manager = task->manager; + + REQUIRE(EMPTY(task->events)); + REQUIRE(EMPTY(task->on_shutdown)); + REQUIRE(task->references == 0); + REQUIRE(task->state == task_state_done); + + XTRACE("task_finished"); + + LOCK(&manager->lock); + UNLINK(manager->tasks, task, link); +#ifdef USE_WORKER_THREADS + if (FINISHED(manager)) { + /* + * All tasks have completed and the + * task manager is exiting. Wake up + * any idle worker threads so they + * can exit. + */ + BROADCAST(&manager->work_available); + } +#endif /* USE_WORKER_THREADS */ + UNLOCK(&manager->lock); + + DESTROYLOCK(&task->lock); + task->common.impmagic = 0; + task->common.magic = 0; + isc_mem_put(manager->mctx, task, sizeof(*task)); +} + +ISC_TASKFUNC_SCOPE isc_result_t +isc__task_create(isc_taskmgr_t *manager0, unsigned int quantum, + isc_task_t **taskp) +{ + isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0; + isc__task_t *task; + isc_boolean_t exiting; + isc_result_t result; + + REQUIRE(VALID_MANAGER(manager)); + REQUIRE(taskp != NULL && *taskp == NULL); + + task = isc_mem_get(manager->mctx, sizeof(*task)); + if (task == NULL) + return (ISC_R_NOMEMORY); + XTRACE("isc_task_create"); + result = isc_mutex_init(&task->lock); + if (result != ISC_R_SUCCESS) { + isc_mem_put(manager->mctx, task, sizeof(*task)); + return (result); + } + LOCK(&manager->lock); + LOCK(&task->lock); /* helps coverity analysis noise ratio */ + task->manager = manager; + task->state = task_state_idle; + task->references = 1; + INIT_LIST(task->events); + INIT_LIST(task->on_shutdown); + task->quantum = quantum; + task->flags = 0; + task->now = 0; + memset(task->name, 0, sizeof(task->name)); + task->tag = NULL; + INIT_LINK(task, link); + INIT_LINK(task, ready_link); + INIT_LINK(task, ready_priority_link); + UNLOCK(&task->lock); + UNLOCK(&manager->lock); + + exiting = ISC_FALSE; + LOCK(&manager->lock); + if (!manager->exiting) { + if (task->quantum == 0) + task->quantum = manager->default_quantum; + APPEND(manager->tasks, task, link); + } else + exiting = ISC_TRUE; + UNLOCK(&manager->lock); + + if (exiting) { + DESTROYLOCK(&task->lock); + isc_mem_put(manager->mctx, task, sizeof(*task)); + return (ISC_R_SHUTTINGDOWN); + } + + task->common.methods = (isc_taskmethods_t *)&taskmethods; + task->common.magic = ISCAPI_TASK_MAGIC; + task->common.impmagic = TASK_MAGIC; + *taskp = (isc_task_t *)task; + + return (ISC_R_SUCCESS); +} + +ISC_TASKFUNC_SCOPE void +isc__task_attach(isc_task_t *source0, isc_task_t **targetp) { + isc__task_t *source = (isc__task_t *)source0; + + /* + * Attach *targetp to source. + */ + + REQUIRE(VALID_TASK(source)); + REQUIRE(targetp != NULL && *targetp == NULL); + + XTTRACE(source, "isc_task_attach"); + + LOCK(&source->lock); + source->references++; + UNLOCK(&source->lock); + + *targetp = (isc_task_t *)source; +} + +static inline isc_boolean_t +task_shutdown(isc__task_t *task) { + isc_boolean_t was_idle = ISC_FALSE; + isc_event_t *event, *prev; + + /* + * Caller must be holding the task's lock. + */ + + XTRACE("task_shutdown"); + + if (! TASK_SHUTTINGDOWN(task)) { + XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_SHUTTINGDOWN, "shutting down")); + task->flags |= TASK_F_SHUTTINGDOWN; + if (task->state == task_state_idle) { + INSIST(EMPTY(task->events)); + task->state = task_state_ready; + was_idle = ISC_TRUE; + } + INSIST(task->state == task_state_ready || + task->state == task_state_running); + + /* + * Note that we post shutdown events LIFO. + */ + for (event = TAIL(task->on_shutdown); + event != NULL; + event = prev) { + prev = PREV(event, ev_link); + DEQUEUE(task->on_shutdown, event, ev_link); + ENQUEUE(task->events, event, ev_link); + } + } + + return (was_idle); +} + +/* + * Moves a task onto the appropriate run queue. + * + * Caller must NOT hold manager lock. + */ +static inline void +task_ready(isc__task_t *task) { + isc__taskmgr_t *manager = task->manager; +#ifdef USE_WORKER_THREADS + isc_boolean_t has_privilege = isc__task_privilege((isc_task_t *) task); +#endif /* USE_WORKER_THREADS */ + + REQUIRE(VALID_MANAGER(manager)); + REQUIRE(task->state == task_state_ready); + + XTRACE("task_ready"); + + LOCK(&manager->lock); + push_readyq(manager, task); +#ifdef USE_WORKER_THREADS + if (manager->mode == isc_taskmgrmode_normal || has_privilege) + SIGNAL(&manager->work_available); +#endif /* USE_WORKER_THREADS */ + UNLOCK(&manager->lock); +} + +static inline isc_boolean_t +task_detach(isc__task_t *task) { + + /* + * Caller must be holding the task lock. + */ + + REQUIRE(task->references > 0); + + XTRACE("detach"); + + task->references--; + if (task->references == 0 && task->state == task_state_idle) { + INSIST(EMPTY(task->events)); + /* + * There are no references to this task, and no + * pending events. We could try to optimize and + * either initiate shutdown or clean up the task, + * depending on its state, but it's easier to just + * make the task ready and allow run() or the event + * loop to deal with shutting down and termination. + */ + task->state = task_state_ready; + return (ISC_TRUE); + } + + return (ISC_FALSE); +} + +ISC_TASKFUNC_SCOPE void +isc__task_detach(isc_task_t **taskp) { + isc__task_t *task; + isc_boolean_t was_idle; + + /* + * Detach *taskp from its task. + */ + + REQUIRE(taskp != NULL); + task = (isc__task_t *)*taskp; + REQUIRE(VALID_TASK(task)); + + XTRACE("isc_task_detach"); + + LOCK(&task->lock); + was_idle = task_detach(task); + UNLOCK(&task->lock); + + if (was_idle) + task_ready(task); + + *taskp = NULL; +} + +static inline isc_boolean_t +task_send(isc__task_t *task, isc_event_t **eventp) { + isc_boolean_t was_idle = ISC_FALSE; + isc_event_t *event; + + /* + * Caller must be holding the task lock. + */ + + REQUIRE(eventp != NULL); + event = *eventp; + REQUIRE(event != NULL); + REQUIRE(event->ev_type > 0); + REQUIRE(task->state != task_state_done); + + XTRACE("task_send"); + + if (task->state == task_state_idle) { + was_idle = ISC_TRUE; + INSIST(EMPTY(task->events)); + task->state = task_state_ready; + } + INSIST(task->state == task_state_ready || + task->state == task_state_running); + ENQUEUE(task->events, event, ev_link); + *eventp = NULL; + + return (was_idle); +} + +ISC_TASKFUNC_SCOPE void +isc__task_send(isc_task_t *task0, isc_event_t **eventp) { + isc__task_t *task = (isc__task_t *)task0; + isc_boolean_t was_idle; + + /* + * Send '*event' to 'task'. + */ + + REQUIRE(VALID_TASK(task)); + + XTRACE("isc_task_send"); + + /* + * We're trying hard to hold locks for as short a time as possible. + * We're also trying to hold as few locks as possible. This is why + * some processing is deferred until after the lock is released. + */ + LOCK(&task->lock); + was_idle = task_send(task, eventp); + UNLOCK(&task->lock); + + if (was_idle) { + /* + * We need to add this task to the ready queue. + * + * We've waited until now to do it because making a task + * ready requires locking the manager. If we tried to do + * this while holding the task lock, we could deadlock. + * + * We've changed the state to ready, so no one else will + * be trying to add this task to the ready queue. The + * only way to leave the ready state is by executing the + * task. It thus doesn't matter if events are added, + * removed, or a shutdown is started in the interval + * between the time we released the task lock, and the time + * we add the task to the ready queue. + */ + task_ready(task); + } +} + +ISC_TASKFUNC_SCOPE void +isc__task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp) { + isc_boolean_t idle1, idle2; + isc__task_t *task; + + /* + * Send '*event' to '*taskp' and then detach '*taskp' from its + * task. + */ + + REQUIRE(taskp != NULL); + task = (isc__task_t *)*taskp; + REQUIRE(VALID_TASK(task)); + + XTRACE("isc_task_sendanddetach"); + + LOCK(&task->lock); + idle1 = task_send(task, eventp); + idle2 = task_detach(task); + UNLOCK(&task->lock); + + /* + * If idle1, then idle2 shouldn't be true as well since we're holding + * the task lock, and thus the task cannot switch from ready back to + * idle. + */ + INSIST(!(idle1 && idle2)); + + if (idle1 || idle2) + task_ready(task); + + *taskp = NULL; +} + +#define PURGE_OK(event) (((event)->ev_attributes & ISC_EVENTATTR_NOPURGE) == 0) + +static unsigned int +dequeue_events(isc__task_t *task, void *sender, isc_eventtype_t first, + isc_eventtype_t last, void *tag, + isc_eventlist_t *events, isc_boolean_t purging) +{ + isc_event_t *event, *next_event; + unsigned int count = 0; + + REQUIRE(VALID_TASK(task)); + REQUIRE(last >= first); + + XTRACE("dequeue_events"); + + /* + * Events matching 'sender', whose type is >= first and <= last, and + * whose tag is 'tag' will be dequeued. If 'purging', matching events + * which are marked as unpurgable will not be dequeued. + * + * sender == NULL means "any sender", and tag == NULL means "any tag". + */ + + LOCK(&task->lock); + + for (event = HEAD(task->events); event != NULL; event = next_event) { + next_event = NEXT(event, ev_link); + if (event->ev_type >= first && event->ev_type <= last && + (sender == NULL || event->ev_sender == sender) && + (tag == NULL || event->ev_tag == tag) && + (!purging || PURGE_OK(event))) { + DEQUEUE(task->events, event, ev_link); + ENQUEUE(*events, event, ev_link); + count++; + } + } + + UNLOCK(&task->lock); + + return (count); +} + +ISC_TASKFUNC_SCOPE unsigned int +isc__task_purgerange(isc_task_t *task0, void *sender, isc_eventtype_t first, + isc_eventtype_t last, void *tag) +{ + isc__task_t *task = (isc__task_t *)task0; + unsigned int count; + isc_eventlist_t events; + isc_event_t *event, *next_event; + + /* + * Purge events from a task's event queue. + */ + + XTRACE("isc_task_purgerange"); + + ISC_LIST_INIT(events); + + count = dequeue_events(task, sender, first, last, tag, &events, + ISC_TRUE); + + for (event = HEAD(events); event != NULL; event = next_event) { + next_event = NEXT(event, ev_link); + isc_event_free(&event); + } + + /* + * Note that purging never changes the state of the task. + */ + + return (count); +} + +ISC_TASKFUNC_SCOPE unsigned int +isc__task_purge(isc_task_t *task, void *sender, isc_eventtype_t type, + void *tag) +{ + /* + * Purge events from a task's event queue. + */ + + XTRACE("isc_task_purge"); + + return (isc__task_purgerange(task, sender, type, type, tag)); +} + +ISC_TASKFUNC_SCOPE isc_boolean_t +isc__task_purgeevent(isc_task_t *task0, isc_event_t *event) { + isc__task_t *task = (isc__task_t *)task0; + isc_event_t *curr_event, *next_event; + + /* + * Purge 'event' from a task's event queue. + * + * XXXRTH: WARNING: This method may be removed before beta. + */ + + REQUIRE(VALID_TASK(task)); + + /* + * If 'event' is on the task's event queue, it will be purged, + * unless it is marked as unpurgeable. 'event' does not have to be + * on the task's event queue; in fact, it can even be an invalid + * pointer. Purging only occurs if the event is actually on the task's + * event queue. + * + * Purging never changes the state of the task. + */ + + LOCK(&task->lock); + for (curr_event = HEAD(task->events); + curr_event != NULL; + curr_event = next_event) { + next_event = NEXT(curr_event, ev_link); + if (curr_event == event && PURGE_OK(event)) { + DEQUEUE(task->events, curr_event, ev_link); + break; + } + } + UNLOCK(&task->lock); + + if (curr_event == NULL) + return (ISC_FALSE); + + isc_event_free(&curr_event); + + return (ISC_TRUE); +} + +ISC_TASKFUNC_SCOPE unsigned int +isc__task_unsendrange(isc_task_t *task, void *sender, isc_eventtype_t first, + isc_eventtype_t last, void *tag, + isc_eventlist_t *events) +{ + /* + * Remove events from a task's event queue. + */ + + XTRACE("isc_task_unsendrange"); + + return (dequeue_events((isc__task_t *)task, sender, first, + last, tag, events, ISC_FALSE)); +} + +ISC_TASKFUNC_SCOPE unsigned int +isc__task_unsend(isc_task_t *task, void *sender, isc_eventtype_t type, + void *tag, isc_eventlist_t *events) +{ + /* + * Remove events from a task's event queue. + */ + + XTRACE("isc_task_unsend"); + + return (dequeue_events((isc__task_t *)task, sender, type, + type, tag, events, ISC_FALSE)); +} + +ISC_TASKFUNC_SCOPE isc_result_t +isc__task_onshutdown(isc_task_t *task0, isc_taskaction_t action, + const void *arg) +{ + isc__task_t *task = (isc__task_t *)task0; + isc_boolean_t disallowed = ISC_FALSE; + isc_result_t result = ISC_R_SUCCESS; + isc_event_t *event; + + /* + * Send a shutdown event with action 'action' and argument 'arg' when + * 'task' is shutdown. + */ + + REQUIRE(VALID_TASK(task)); + REQUIRE(action != NULL); + + event = isc_event_allocate(task->manager->mctx, + NULL, + ISC_TASKEVENT_SHUTDOWN, + action, + arg, + sizeof(*event)); + if (event == NULL) + return (ISC_R_NOMEMORY); + + LOCK(&task->lock); + if (TASK_SHUTTINGDOWN(task)) { + disallowed = ISC_TRUE; + result = ISC_R_SHUTTINGDOWN; + } else + ENQUEUE(task->on_shutdown, event, ev_link); + UNLOCK(&task->lock); + + if (disallowed) + isc_mem_put(task->manager->mctx, event, sizeof(*event)); + + return (result); +} + +ISC_TASKFUNC_SCOPE void +isc__task_shutdown(isc_task_t *task0) { + isc__task_t *task = (isc__task_t *)task0; + isc_boolean_t was_idle; + + /* + * Shutdown 'task'. + */ + + REQUIRE(VALID_TASK(task)); + + LOCK(&task->lock); + was_idle = task_shutdown(task); + UNLOCK(&task->lock); + + if (was_idle) + task_ready(task); +} + +ISC_TASKFUNC_SCOPE void +isc__task_destroy(isc_task_t **taskp) { + + /* + * Destroy '*taskp'. + */ + + REQUIRE(taskp != NULL); + + isc_task_shutdown(*taskp); + isc_task_detach(taskp); +} + +ISC_TASKFUNC_SCOPE void +isc__task_setname(isc_task_t *task0, const char *name, void *tag) { + isc__task_t *task = (isc__task_t *)task0; + + /* + * Name 'task'. + */ + + REQUIRE(VALID_TASK(task)); + + LOCK(&task->lock); + memset(task->name, 0, sizeof(task->name)); + strncpy(task->name, name, sizeof(task->name) - 1); + task->tag = tag; + UNLOCK(&task->lock); +} + +ISC_TASKFUNC_SCOPE const char * +isc__task_getname(isc_task_t *task0) { + isc__task_t *task = (isc__task_t *)task0; + + REQUIRE(VALID_TASK(task)); + + return (task->name); +} + +ISC_TASKFUNC_SCOPE void * +isc__task_gettag(isc_task_t *task0) { + isc__task_t *task = (isc__task_t *)task0; + + REQUIRE(VALID_TASK(task)); + + return (task->tag); +} + +ISC_TASKFUNC_SCOPE void +isc__task_getcurrenttime(isc_task_t *task0, isc_stdtime_t *t) { + isc__task_t *task = (isc__task_t *)task0; + + REQUIRE(VALID_TASK(task)); + REQUIRE(t != NULL); + + LOCK(&task->lock); + *t = task->now; + UNLOCK(&task->lock); +} + +/*** + *** Task Manager. + ***/ + +/* + * Return ISC_TRUE if the current ready list for the manager, which is + * either ready_tasks or the ready_priority_tasks, depending on whether + * the manager is currently in normal or privileged execution mode. + * + * Caller must hold the task manager lock. + */ +static inline isc_boolean_t +empty_readyq(isc__taskmgr_t *manager) { + isc__tasklist_t queue; + + if (manager->mode == isc_taskmgrmode_normal) + queue = manager->ready_tasks; + else + queue = manager->ready_priority_tasks; + + return (ISC_TF(EMPTY(queue))); +} + +/* + * Dequeue and return a pointer to the first task on the current ready + * list for the manager. + * If the task is privileged, dequeue it from the other ready list + * as well. + * + * Caller must hold the task manager lock. + */ +static inline isc__task_t * +pop_readyq(isc__taskmgr_t *manager) { + isc__task_t *task; + + if (manager->mode == isc_taskmgrmode_normal) + task = HEAD(manager->ready_tasks); + else + task = HEAD(manager->ready_priority_tasks); + + if (task != NULL) { + DEQUEUE(manager->ready_tasks, task, ready_link); + if (ISC_LINK_LINKED(task, ready_priority_link)) + DEQUEUE(manager->ready_priority_tasks, task, + ready_priority_link); + } + + return (task); +} + +/* + * Push 'task' onto the ready_tasks queue. If 'task' has the privilege + * flag set, then also push it onto the ready_priority_tasks queue. + * + * Caller must hold the task manager lock. + */ +static inline void +push_readyq(isc__taskmgr_t *manager, isc__task_t *task) { + ENQUEUE(manager->ready_tasks, task, ready_link); + if ((task->flags & TASK_F_PRIVILEGED) != 0) + ENQUEUE(manager->ready_priority_tasks, task, + ready_priority_link); +} + +static void +dispatch(isc__taskmgr_t *manager) { + isc__task_t *task; +#ifndef USE_WORKER_THREADS + unsigned int total_dispatch_count = 0; + isc__tasklist_t new_ready_tasks; + isc__tasklist_t new_priority_tasks; +#endif /* USE_WORKER_THREADS */ + + REQUIRE(VALID_MANAGER(manager)); + + /* + * Again we're trying to hold the lock for as short a time as possible + * and to do as little locking and unlocking as possible. + * + * In both while loops, the appropriate lock must be held before the + * while body starts. Code which acquired the lock at the top of + * the loop would be more readable, but would result in a lot of + * extra locking. Compare: + * + * Straightforward: + * + * LOCK(); + * ... + * UNLOCK(); + * while (expression) { + * LOCK(); + * ... + * UNLOCK(); + * + * Unlocked part here... + * + * LOCK(); + * ... + * UNLOCK(); + * } + * + * Note how if the loop continues we unlock and then immediately lock. + * For N iterations of the loop, this code does 2N+1 locks and 2N+1 + * unlocks. Also note that the lock is not held when the while + * condition is tested, which may or may not be important, depending + * on the expression. + * + * As written: + * + * LOCK(); + * while (expression) { + * ... + * UNLOCK(); + * + * Unlocked part here... + * + * LOCK(); + * ... + * } + * UNLOCK(); + * + * For N iterations of the loop, this code does N+1 locks and N+1 + * unlocks. The while expression is always protected by the lock. + */ + +#ifndef USE_WORKER_THREADS + ISC_LIST_INIT(new_ready_tasks); + ISC_LIST_INIT(new_priority_tasks); +#endif + LOCK(&manager->lock); + + while (!FINISHED(manager)) { +#ifdef USE_WORKER_THREADS + /* + * For reasons similar to those given in the comment in + * isc_task_send() above, it is safe for us to dequeue + * the task while only holding the manager lock, and then + * change the task to running state while only holding the + * task lock. + * + * If a pause has been requested, don't do any work + * until it's been released. + */ + while ((empty_readyq(manager) || manager->pause_requested || + manager->exclusive_requested) && !FINISHED(manager)) + { + XTHREADTRACE(isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_WAIT, "wait")); + WAIT(&manager->work_available, &manager->lock); + XTHREADTRACE(isc_msgcat_get(isc_msgcat, + ISC_MSGSET_TASK, + ISC_MSG_AWAKE, "awake")); + } +#else /* USE_WORKER_THREADS */ + if (total_dispatch_count >= DEFAULT_TASKMGR_QUANTUM || + empty_readyq(manager)) + break; +#endif /* USE_WORKER_THREADS */ + XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TASK, + ISC_MSG_WORKING, "working")); + + task = pop_readyq(manager); + if (task != NULL) { + unsigned int dispatch_count = 0; + isc_boolean_t done = ISC_FALSE; + isc_boolean_t requeue = ISC_FALSE; + isc_boolean_t finished = ISC_FALSE; + isc_event_t *event; + + INSIST(VALID_TASK(task)); + + /* + * Note we only unlock the manager lock if we actually + * have a task to do. We must reacquire the manager + * lock before exiting the 'if (task != NULL)' block. + */ + manager->tasks_running++; + UNLOCK(&manager->lock); + + LOCK(&task->lock); + INSIST(task->state == task_state_ready); + task->state = task_state_running; + XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_RUNNING, "running")); + isc_stdtime_get(&task->now); + do { + if (!EMPTY(task->events)) { + event = HEAD(task->events); + DEQUEUE(task->events, event, ev_link); + + /* + * Execute the event action. + */ + XTRACE(isc_msgcat_get(isc_msgcat, + ISC_MSGSET_TASK, + ISC_MSG_EXECUTE, + "execute action")); + if (event->ev_action != NULL) { + UNLOCK(&task->lock); + (event->ev_action)( + (isc_task_t *)task, + event); + LOCK(&task->lock); + } + dispatch_count++; +#ifndef USE_WORKER_THREADS + total_dispatch_count++; +#endif /* USE_WORKER_THREADS */ + } + + if (task->references == 0 && + EMPTY(task->events) && + !TASK_SHUTTINGDOWN(task)) { + isc_boolean_t was_idle; + + /* + * There are no references and no + * pending events for this task, + * which means it will not become + * runnable again via an external + * action (such as sending an event + * or detaching). + * + * We initiate shutdown to prevent + * it from becoming a zombie. + * + * We do this here instead of in + * the "if EMPTY(task->events)" block + * below because: + * + * If we post no shutdown events, + * we want the task to finish. + * + * If we did post shutdown events, + * will still want the task's + * quantum to be applied. + */ + was_idle = task_shutdown(task); + INSIST(!was_idle); + } + + if (EMPTY(task->events)) { + /* + * Nothing else to do for this task + * right now. + */ + XTRACE(isc_msgcat_get(isc_msgcat, + ISC_MSGSET_TASK, + ISC_MSG_EMPTY, + "empty")); + if (task->references == 0 && + TASK_SHUTTINGDOWN(task)) { + /* + * The task is done. + */ + XTRACE(isc_msgcat_get( + isc_msgcat, + ISC_MSGSET_TASK, + ISC_MSG_DONE, + "done")); + finished = ISC_TRUE; + task->state = task_state_done; + } else + task->state = task_state_idle; + done = ISC_TRUE; + } else if (dispatch_count >= task->quantum) { + /* + * Our quantum has expired, but + * there is more work to be done. + * We'll requeue it to the ready + * queue later. + * + * We don't check quantum until + * dispatching at least one event, + * so the minimum quantum is one. + */ + XTRACE(isc_msgcat_get(isc_msgcat, + ISC_MSGSET_TASK, + ISC_MSG_QUANTUM, + "quantum")); + task->state = task_state_ready; + requeue = ISC_TRUE; + done = ISC_TRUE; + } + } while (!done); + UNLOCK(&task->lock); + + if (finished) + task_finished(task); + + LOCK(&manager->lock); + manager->tasks_running--; +#ifdef USE_WORKER_THREADS + if (manager->exclusive_requested && + manager->tasks_running == 1) { + SIGNAL(&manager->exclusive_granted); + } else if (manager->pause_requested && + manager->tasks_running == 0) { + SIGNAL(&manager->paused); + } +#endif /* USE_WORKER_THREADS */ + if (requeue) { + /* + * We know we're awake, so we don't have + * to wakeup any sleeping threads if the + * ready queue is empty before we requeue. + * + * A possible optimization if the queue is + * empty is to 'goto' the 'if (task != NULL)' + * block, avoiding the ENQUEUE of the task + * and the subsequent immediate DEQUEUE + * (since it is the only executable task). + * We don't do this because then we'd be + * skipping the exit_requested check. The + * cost of ENQUEUE is low anyway, especially + * when you consider that we'd have to do + * an extra EMPTY check to see if we could + * do the optimization. If the ready queue + * were usually nonempty, the 'optimization' + * might even hurt rather than help. + */ +#ifdef USE_WORKER_THREADS + push_readyq(manager, task); +#else + ENQUEUE(new_ready_tasks, task, ready_link); + if ((task->flags & TASK_F_PRIVILEGED) != 0) + ENQUEUE(new_priority_tasks, task, + ready_priority_link); +#endif + } + } + +#ifdef USE_WORKER_THREADS + /* + * If we are in privileged execution mode and there are no + * tasks remaining on the current ready queue, then + * we're stuck. Automatically drop privileges at that + * point and continue with the regular ready queue. + */ + if (manager->tasks_running == 0 && empty_readyq(manager)) { + manager->mode = isc_taskmgrmode_normal; + if (!empty_readyq(manager)) + BROADCAST(&manager->work_available); + } +#endif + } + +#ifndef USE_WORKER_THREADS + ISC_LIST_APPENDLIST(manager->ready_tasks, new_ready_tasks, ready_link); + ISC_LIST_APPENDLIST(manager->ready_priority_tasks, new_priority_tasks, + ready_priority_link); + if (empty_readyq(manager)) + manager->mode = isc_taskmgrmode_normal; +#endif + + UNLOCK(&manager->lock); +} + +#ifdef USE_WORKER_THREADS +static isc_threadresult_t +#ifdef _WIN32 +WINAPI +#endif +run(void *uap) { + isc__taskmgr_t *manager = uap; + + XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_STARTING, "starting")); + + dispatch(manager); + + XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_EXITING, "exiting")); + +#ifdef OPENSSL_LEAKS + ERR_remove_state(0); +#endif + + return ((isc_threadresult_t)0); +} +#endif /* USE_WORKER_THREADS */ + +static void +manager_free(isc__taskmgr_t *manager) { + isc_mem_t *mctx; + + LOCK(&manager->lock); +#ifdef USE_WORKER_THREADS + (void)isc_condition_destroy(&manager->exclusive_granted); + (void)isc_condition_destroy(&manager->work_available); + (void)isc_condition_destroy(&manager->paused); + isc_mem_free(manager->mctx, manager->threads); +#endif /* USE_WORKER_THREADS */ + manager->common.impmagic = 0; + manager->common.magic = 0; + mctx = manager->mctx; + UNLOCK(&manager->lock); + DESTROYLOCK(&manager->lock); + isc_mem_put(mctx, manager, sizeof(*manager)); + isc_mem_detach(&mctx); + +#ifdef USE_SHARED_MANAGER + taskmgr = NULL; +#endif /* USE_SHARED_MANAGER */ +} + +ISC_TASKFUNC_SCOPE isc_result_t +isc__taskmgr_create(isc_mem_t *mctx, unsigned int workers, + unsigned int default_quantum, isc_taskmgr_t **managerp) +{ + isc_result_t result; + unsigned int i, started = 0; + isc__taskmgr_t *manager; + + /* + * Create a new task manager. + */ + + REQUIRE(workers > 0); + REQUIRE(managerp != NULL && *managerp == NULL); + +#ifndef USE_WORKER_THREADS + UNUSED(i); + UNUSED(started); +#endif + +#ifdef USE_SHARED_MANAGER + if (taskmgr != NULL) { + if (taskmgr->refs == 0) + return (ISC_R_SHUTTINGDOWN); + taskmgr->refs++; + *managerp = (isc_taskmgr_t *)taskmgr; + return (ISC_R_SUCCESS); + } +#endif /* USE_SHARED_MANAGER */ + + manager = isc_mem_get(mctx, sizeof(*manager)); + if (manager == NULL) + return (ISC_R_NOMEMORY); + manager->common.methods = &taskmgrmethods; + manager->common.impmagic = TASK_MANAGER_MAGIC; + manager->common.magic = ISCAPI_TASKMGR_MAGIC; + manager->mode = isc_taskmgrmode_normal; + manager->mctx = NULL; + result = isc_mutex_init(&manager->lock); + if (result != ISC_R_SUCCESS) + goto cleanup_mgr; + LOCK(&manager->lock); + +#ifdef USE_WORKER_THREADS + manager->workers = 0; + manager->threads = isc_mem_allocate(mctx, + workers * sizeof(isc_thread_t)); + if (manager->threads == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup_lock; + } + if (isc_condition_init(&manager->work_available) != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_condition_init() %s", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed")); + result = ISC_R_UNEXPECTED; + goto cleanup_threads; + } + if (isc_condition_init(&manager->exclusive_granted) != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_condition_init() %s", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed")); + result = ISC_R_UNEXPECTED; + goto cleanup_workavailable; + } + if (isc_condition_init(&manager->paused) != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_condition_init() %s", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed")); + result = ISC_R_UNEXPECTED; + goto cleanup_exclusivegranted; + } +#endif /* USE_WORKER_THREADS */ + if (default_quantum == 0) + default_quantum = DEFAULT_DEFAULT_QUANTUM; + manager->default_quantum = default_quantum; + INIT_LIST(manager->tasks); + INIT_LIST(manager->ready_tasks); + INIT_LIST(manager->ready_priority_tasks); + manager->tasks_running = 0; + manager->exclusive_requested = ISC_FALSE; + manager->pause_requested = ISC_FALSE; + manager->exiting = ISC_FALSE; + + isc_mem_attach(mctx, &manager->mctx); + +#ifdef USE_WORKER_THREADS + /* + * Start workers. + */ + for (i = 0; i < workers; i++) { + if (isc_thread_create(run, manager, + &manager->threads[manager->workers]) == + ISC_R_SUCCESS) { + manager->workers++; + started++; + } + } + UNLOCK(&manager->lock); + + if (started == 0) { + manager_free(manager); + return (ISC_R_NOTHREADS); + } + isc_thread_setconcurrency(workers); +#endif /* USE_WORKER_THREADS */ +#ifdef USE_SHARED_MANAGER + manager->refs = 1; + UNLOCK(&manager->lock); + taskmgr = manager; +#endif /* USE_SHARED_MANAGER */ + + *managerp = (isc_taskmgr_t *)manager; + + return (ISC_R_SUCCESS); + +#ifdef USE_WORKER_THREADS + cleanup_exclusivegranted: + (void)isc_condition_destroy(&manager->exclusive_granted); + cleanup_workavailable: + (void)isc_condition_destroy(&manager->work_available); + cleanup_threads: + isc_mem_free(mctx, manager->threads); + cleanup_lock: + UNLOCK(&manager->lock); + DESTROYLOCK(&manager->lock); +#endif + cleanup_mgr: + isc_mem_put(mctx, manager, sizeof(*manager)); + return (result); +} + +ISC_TASKFUNC_SCOPE void +isc__taskmgr_destroy(isc_taskmgr_t **managerp) { + isc__taskmgr_t *manager; + isc__task_t *task; + unsigned int i; + + /* + * Destroy '*managerp'. + */ + + REQUIRE(managerp != NULL); + manager = (isc__taskmgr_t *)*managerp; + REQUIRE(VALID_MANAGER(manager)); + +#ifndef USE_WORKER_THREADS + UNUSED(i); +#endif /* USE_WORKER_THREADS */ + +#ifdef USE_SHARED_MANAGER + manager->refs--; + if (manager->refs > 0) { + *managerp = NULL; + return; + } +#endif + + XTHREADTRACE("isc_taskmgr_destroy"); + /* + * Only one non-worker thread may ever call this routine. + * If a worker thread wants to initiate shutdown of the + * task manager, it should ask some non-worker thread to call + * isc_taskmgr_destroy(), e.g. by signalling a condition variable + * that the startup thread is sleeping on. + */ + + /* + * Unlike elsewhere, we're going to hold this lock a long time. + * We need to do so, because otherwise the list of tasks could + * change while we were traversing it. + * + * This is also the only function where we will hold both the + * task manager lock and a task lock at the same time. + */ + + LOCK(&manager->lock); + + /* + * Make sure we only get called once. + */ + INSIST(!manager->exiting); + manager->exiting = ISC_TRUE; + + /* + * If privileged mode was on, turn it off. + */ + manager->mode = isc_taskmgrmode_normal; + + /* + * Post shutdown event(s) to every task (if they haven't already been + * posted). + */ + for (task = HEAD(manager->tasks); + task != NULL; + task = NEXT(task, link)) { + LOCK(&task->lock); + if (task_shutdown(task)) + push_readyq(manager, task); + UNLOCK(&task->lock); + } +#ifdef USE_WORKER_THREADS + /* + * Wake up any sleeping workers. This ensures we get work done if + * there's work left to do, and if there are already no tasks left + * it will cause the workers to see manager->exiting. + */ + BROADCAST(&manager->work_available); + UNLOCK(&manager->lock); + + /* + * Wait for all the worker threads to exit. + */ + for (i = 0; i < manager->workers; i++) + (void)isc_thread_join(manager->threads[i], NULL); +#else /* USE_WORKER_THREADS */ + /* + * Dispatch the shutdown events. + */ + UNLOCK(&manager->lock); + while (isc__taskmgr_ready((isc_taskmgr_t *)manager)) + (void)isc__taskmgr_dispatch((isc_taskmgr_t *)manager); +#ifdef BIND9 + if (!ISC_LIST_EMPTY(manager->tasks)) + isc_mem_printallactive(stderr); +#endif + INSIST(ISC_LIST_EMPTY(manager->tasks)); +#ifdef USE_SHARED_MANAGER + taskmgr = NULL; +#endif +#endif /* USE_WORKER_THREADS */ + + manager_free(manager); + + *managerp = NULL; +} + +ISC_TASKFUNC_SCOPE void +isc__taskmgr_setmode(isc_taskmgr_t *manager0, isc_taskmgrmode_t mode) { + isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0; + + LOCK(&manager->lock); + manager->mode = mode; + UNLOCK(&manager->lock); +} + +ISC_TASKFUNC_SCOPE isc_taskmgrmode_t +isc__taskmgr_mode(isc_taskmgr_t *manager0) { + isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0; + isc_taskmgrmode_t mode; + LOCK(&manager->lock); + mode = manager->mode; + UNLOCK(&manager->lock); + return (mode); +} + +#ifndef USE_WORKER_THREADS +isc_boolean_t +isc__taskmgr_ready(isc_taskmgr_t *manager0) { + isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0; + isc_boolean_t is_ready; + +#ifdef USE_SHARED_MANAGER + if (manager == NULL) + manager = taskmgr; +#endif + if (manager == NULL) + return (ISC_FALSE); + + LOCK(&manager->lock); + is_ready = !empty_readyq(manager); + UNLOCK(&manager->lock); + + return (is_ready); +} + +isc_result_t +isc__taskmgr_dispatch(isc_taskmgr_t *manager0) { + isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0; + +#ifdef USE_SHARED_MANAGER + if (manager == NULL) + manager = taskmgr; +#endif + if (manager == NULL) + return (ISC_R_NOTFOUND); + + dispatch(manager); + + return (ISC_R_SUCCESS); +} + +#else +ISC_TASKFUNC_SCOPE void +isc__taskmgr_pause(isc_taskmgr_t *manager0) { + isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0; + LOCK(&manager->lock); + while (manager->tasks_running > 0) { + WAIT(&manager->paused, &manager->lock); + } + manager->pause_requested = ISC_TRUE; + UNLOCK(&manager->lock); +} + +ISC_TASKFUNC_SCOPE void +isc__taskmgr_resume(isc_taskmgr_t *manager0) { + isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0; + + LOCK(&manager->lock); + if (manager->pause_requested) { + manager->pause_requested = ISC_FALSE; + BROADCAST(&manager->work_available); + } + UNLOCK(&manager->lock); +} +#endif /* USE_WORKER_THREADS */ + +ISC_TASKFUNC_SCOPE isc_result_t +isc__task_beginexclusive(isc_task_t *task0) { +#ifdef USE_WORKER_THREADS + isc__task_t *task = (isc__task_t *)task0; + isc__taskmgr_t *manager = task->manager; + REQUIRE(task->state == task_state_running); + LOCK(&manager->lock); + if (manager->exclusive_requested) { + UNLOCK(&manager->lock); + return (ISC_R_LOCKBUSY); + } + manager->exclusive_requested = ISC_TRUE; + while (manager->tasks_running > 1) { + WAIT(&manager->exclusive_granted, &manager->lock); + } + UNLOCK(&manager->lock); +#else + UNUSED(task0); +#endif + return (ISC_R_SUCCESS); +} + +ISC_TASKFUNC_SCOPE void +isc__task_endexclusive(isc_task_t *task0) { +#ifdef USE_WORKER_THREADS + isc__task_t *task = (isc__task_t *)task0; + isc__taskmgr_t *manager = task->manager; + + REQUIRE(task->state == task_state_running); + LOCK(&manager->lock); + REQUIRE(manager->exclusive_requested); + manager->exclusive_requested = ISC_FALSE; + BROADCAST(&manager->work_available); + UNLOCK(&manager->lock); +#else + UNUSED(task0); +#endif +} + +ISC_TASKFUNC_SCOPE void +isc__task_setprivilege(isc_task_t *task0, isc_boolean_t priv) { + isc__task_t *task = (isc__task_t *)task0; + isc__taskmgr_t *manager = task->manager; + isc_boolean_t oldpriv; + + LOCK(&task->lock); + oldpriv = ISC_TF((task->flags & TASK_F_PRIVILEGED) != 0); + if (priv) + task->flags |= TASK_F_PRIVILEGED; + else + task->flags &= ~TASK_F_PRIVILEGED; + UNLOCK(&task->lock); + + if (priv == oldpriv) + return; + + LOCK(&manager->lock); + if (priv && ISC_LINK_LINKED(task, ready_link)) + ENQUEUE(manager->ready_priority_tasks, task, + ready_priority_link); + else if (!priv && ISC_LINK_LINKED(task, ready_priority_link)) + DEQUEUE(manager->ready_priority_tasks, task, + ready_priority_link); + UNLOCK(&manager->lock); +} + +ISC_TASKFUNC_SCOPE isc_boolean_t +isc__task_privilege(isc_task_t *task0) { + isc__task_t *task = (isc__task_t *)task0; + isc_boolean_t priv; + + LOCK(&task->lock); + priv = ISC_TF((task->flags & TASK_F_PRIVILEGED) != 0); + UNLOCK(&task->lock); + return (priv); +} + +#ifdef USE_SOCKETIMPREGISTER +isc_result_t +isc__task_register() { + return (isc_task_register(isc__taskmgr_create)); +} +#endif + +isc_boolean_t +isc_task_exiting(isc_task_t *t) { + isc__task_t *task = (isc__task_t *)t; + + REQUIRE(VALID_TASK(task)); + return (TASK_SHUTTINGDOWN(task)); +} + + +#if defined(HAVE_LIBXML2) && defined(BIND9) +void +isc_taskmgr_renderxml(isc_taskmgr_t *mgr0, xmlTextWriterPtr writer) { + isc__taskmgr_t *mgr = (isc__taskmgr_t *)mgr0; + isc__task_t *task; + + LOCK(&mgr->lock); + + /* + * Write out the thread-model, and some details about each depending + * on which type is enabled. + */ + xmlTextWriterStartElement(writer, ISC_XMLCHAR "thread-model"); +#ifdef ISC_PLATFORM_USETHREADS + xmlTextWriterStartElement(writer, ISC_XMLCHAR "type"); + xmlTextWriterWriteString(writer, ISC_XMLCHAR "threaded"); + xmlTextWriterEndElement(writer); /* type */ + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "worker-threads"); + xmlTextWriterWriteFormatString(writer, "%d", mgr->workers); + xmlTextWriterEndElement(writer); /* worker-threads */ +#else /* ISC_PLATFORM_USETHREADS */ + xmlTextWriterStartElement(writer, ISC_XMLCHAR "type"); + xmlTextWriterWriteString(writer, ISC_XMLCHAR "non-threaded"); + xmlTextWriterEndElement(writer); /* type */ + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "references"); + xmlTextWriterWriteFormatString(writer, "%d", mgr->refs); + xmlTextWriterEndElement(writer); /* references */ +#endif /* ISC_PLATFORM_USETHREADS */ + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "default-quantum"); + xmlTextWriterWriteFormatString(writer, "%d", mgr->default_quantum); + xmlTextWriterEndElement(writer); /* default-quantum */ + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "tasks-running"); + xmlTextWriterWriteFormatString(writer, "%d", mgr->tasks_running); + xmlTextWriterEndElement(writer); /* tasks-running */ + + xmlTextWriterEndElement(writer); /* thread-model */ + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "tasks"); + task = ISC_LIST_HEAD(mgr->tasks); + while (task != NULL) { + LOCK(&task->lock); + xmlTextWriterStartElement(writer, ISC_XMLCHAR "task"); + + if (task->name[0] != 0) { + xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"); + xmlTextWriterWriteFormatString(writer, "%s", + task->name); + xmlTextWriterEndElement(writer); /* name */ + } + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "references"); + xmlTextWriterWriteFormatString(writer, "%d", task->references); + xmlTextWriterEndElement(writer); /* references */ + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "id"); + xmlTextWriterWriteFormatString(writer, "%p", task); + xmlTextWriterEndElement(writer); /* id */ + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "state"); + xmlTextWriterWriteFormatString(writer, "%s", + statenames[task->state]); + xmlTextWriterEndElement(writer); /* state */ + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "quantum"); + xmlTextWriterWriteFormatString(writer, "%d", task->quantum); + xmlTextWriterEndElement(writer); /* quantum */ + + xmlTextWriterEndElement(writer); + + UNLOCK(&task->lock); + task = ISC_LIST_NEXT(task, link); + } + xmlTextWriterEndElement(writer); /* tasks */ + + UNLOCK(&mgr->lock); +} +#endif /* HAVE_LIBXML2 && BIND9 */ diff --git a/contrib/ntp/lib/isc/task_api.c b/contrib/ntp/lib/isc/task_api.c new file mode 100644 index 0000000..34510ff --- /dev/null +++ b/contrib/ntp/lib/isc/task_api.c @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2009-2012 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +#include <config.h> + +#include <unistd.h> + +#include <isc/app.h> +#include <isc/magic.h> +#include <isc/mutex.h> +#include <isc/once.h> +#include <isc/task.h> +#include <isc/util.h> + +static isc_mutex_t createlock; +static isc_once_t once = ISC_ONCE_INIT; +static isc_taskmgrcreatefunc_t taskmgr_createfunc = NULL; + +static void +initialize(void) { + RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS); +} + +isc_result_t +isc_task_register(isc_taskmgrcreatefunc_t createfunc) { + isc_result_t result = ISC_R_SUCCESS; + + RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS); + + LOCK(&createlock); + if (taskmgr_createfunc == NULL) + taskmgr_createfunc = createfunc; + else + result = ISC_R_EXISTS; + UNLOCK(&createlock); + + return (result); +} + +isc_result_t +isc_taskmgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx, + unsigned int workers, unsigned int default_quantum, + isc_taskmgr_t **managerp) +{ + isc_result_t result; + + LOCK(&createlock); + + REQUIRE(taskmgr_createfunc != NULL); + result = (*taskmgr_createfunc)(mctx, workers, default_quantum, + managerp); + + UNLOCK(&createlock); + + if (result == ISC_R_SUCCESS) + isc_appctx_settaskmgr(actx, *managerp); + + return (result); +} + +isc_result_t +isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers, + unsigned int default_quantum, isc_taskmgr_t **managerp) +{ + isc_result_t result; + + LOCK(&createlock); + + REQUIRE(taskmgr_createfunc != NULL); + result = (*taskmgr_createfunc)(mctx, workers, default_quantum, + managerp); + + UNLOCK(&createlock); + + return (result); +} + +void +isc_taskmgr_destroy(isc_taskmgr_t **managerp) { + REQUIRE(managerp != NULL && ISCAPI_TASKMGR_VALID(*managerp)); + + (*managerp)->methods->destroy(managerp); + + ENSURE(*managerp == NULL); +} + +void +isc_taskmgr_setmode(isc_taskmgr_t *manager, isc_taskmgrmode_t mode) { + REQUIRE(ISCAPI_TASKMGR_VALID(manager)); + + manager->methods->setmode(manager, mode); +} + +isc_taskmgrmode_t +isc_taskmgr_mode(isc_taskmgr_t *manager) { + REQUIRE(ISCAPI_TASKMGR_VALID(manager)); + + return (manager->methods->mode(manager)); +} + +isc_result_t +isc_task_create(isc_taskmgr_t *manager, unsigned int quantum, + isc_task_t **taskp) +{ + REQUIRE(ISCAPI_TASKMGR_VALID(manager)); + REQUIRE(taskp != NULL && *taskp == NULL); + + return (manager->methods->taskcreate(manager, quantum, taskp)); +} + +void +isc_task_attach(isc_task_t *source, isc_task_t **targetp) { + REQUIRE(ISCAPI_TASK_VALID(source)); + REQUIRE(targetp != NULL && *targetp == NULL); + + source->methods->attach(source, targetp); + + ENSURE(*targetp == source); +} + +void +isc_task_detach(isc_task_t **taskp) { + REQUIRE(taskp != NULL && ISCAPI_TASK_VALID(*taskp)); + + (*taskp)->methods->detach(taskp); + + ENSURE(*taskp == NULL); +} + +void +isc_task_send(isc_task_t *task, isc_event_t **eventp) { + REQUIRE(ISCAPI_TASK_VALID(task)); + REQUIRE(eventp != NULL && *eventp != NULL); + + task->methods->send(task, eventp); + + ENSURE(*eventp == NULL); +} + +void +isc_task_sendanddetach(isc_task_t **taskp, isc_event_t **eventp) { + REQUIRE(taskp != NULL && ISCAPI_TASK_VALID(*taskp)); + REQUIRE(eventp != NULL && *eventp != NULL); + + (*taskp)->methods->sendanddetach(taskp, eventp); + + ENSURE(*taskp == NULL && *eventp == NULL); +} + +unsigned int +isc_task_unsend(isc_task_t *task, void *sender, isc_eventtype_t type, + void *tag, isc_eventlist_t *events) +{ + REQUIRE(ISCAPI_TASK_VALID(task)); + + return (task->methods->unsend(task, sender, type, tag, events)); +} + +isc_result_t +isc_task_onshutdown(isc_task_t *task, isc_taskaction_t action, const void *arg) +{ + REQUIRE(ISCAPI_TASK_VALID(task)); + + return (task->methods->onshutdown(task, action, arg)); +} + +void +isc_task_shutdown(isc_task_t *task) { + REQUIRE(ISCAPI_TASK_VALID(task)); + + task->methods->shutdown(task); +} + +void +isc_task_setname(isc_task_t *task, const char *name, void *tag) { + REQUIRE(ISCAPI_TASK_VALID(task)); + + task->methods->setname(task, name, tag); +} + +unsigned int +isc_task_purge(isc_task_t *task, void *sender, isc_eventtype_t type, void *tag) +{ + REQUIRE(ISCAPI_TASK_VALID(task)); + + return (task->methods->purgeevents(task, sender, type, tag)); +} + +isc_result_t +isc_task_beginexclusive(isc_task_t *task) { + REQUIRE(ISCAPI_TASK_VALID(task)); + + return (task->methods->beginexclusive(task)); +} + +void +isc_task_endexclusive(isc_task_t *task) { + REQUIRE(ISCAPI_TASK_VALID(task)); + + task->methods->endexclusive(task); +} + +void +isc_task_setprivilege(isc_task_t *task, isc_boolean_t priv) { + REQUIRE(ISCAPI_TASK_VALID(task)); + + task->methods->setprivilege(task, priv); +} + +isc_boolean_t +isc_task_privilege(isc_task_t *task) { + REQUIRE(ISCAPI_TASK_VALID(task)); + + return (task->methods->privilege(task)); +} + + +/*% + * This is necessary for libisc's internal timer implementation. Other + * implementation might skip implementing this. + */ +unsigned int +isc_task_purgerange(isc_task_t *task, void *sender, isc_eventtype_t first, + isc_eventtype_t last, void *tag) +{ + REQUIRE(ISCAPI_TASK_VALID(task)); + + return (task->methods->purgerange(task, sender, first, last, tag)); +} diff --git a/contrib/ntp/lib/isc/task_p.h b/contrib/ntp/lib/isc/task_p.h new file mode 100644 index 0000000..8c1e4c5 --- /dev/null +++ b/contrib/ntp/lib/isc/task_p.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +#ifndef ISC_TASK_P_H +#define ISC_TASK_P_H + +/*! \file */ + +#if defined(BIND9) && defined(ISC_PLATFORM_USETHREADS) +void +isc__taskmgr_pause(isc_taskmgr_t *taskmgr); + +void +isc__taskmgr_resume(isc_taskmgr_t *taskmgr); +#else +isc_boolean_t +isc__taskmgr_ready(isc_taskmgr_t *taskmgr); + +isc_result_t +isc__taskmgr_dispatch(isc_taskmgr_t *taskmgr); +#endif /* !BIND9 || !ISC_PLATFORM_USETHREADS */ + +#endif /* ISC_TASK_P_H */ diff --git a/contrib/ntp/lib/isc/taskpool.c b/contrib/ntp/lib/isc/taskpool.c new file mode 100644 index 0000000..25d9516 --- /dev/null +++ b/contrib/ntp/lib/isc/taskpool.c @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/*! \file */ + +#include <config.h> + +#include <isc/mem.h> +#include <isc/random.h> +#include <isc/taskpool.h> +#include <isc/util.h> + +/*** + *** Types. + ***/ + +struct isc_taskpool { + isc_mem_t * mctx; + isc_taskmgr_t * tmgr; + unsigned int ntasks; + unsigned int quantum; + isc_task_t ** tasks; +}; + +/*** + *** Functions. + ***/ + +static isc_result_t +alloc_pool(isc_taskmgr_t *tmgr, isc_mem_t *mctx, unsigned int ntasks, + unsigned int quantum, isc_taskpool_t **poolp) +{ + isc_taskpool_t *pool; + unsigned int i; + + pool = isc_mem_get(mctx, sizeof(*pool)); + if (pool == NULL) + return (ISC_R_NOMEMORY); + pool->mctx = mctx; + pool->ntasks = ntasks; + pool->quantum = quantum; + pool->tmgr = tmgr; + pool->tasks = isc_mem_get(mctx, ntasks * sizeof(isc_task_t *)); + if (pool->tasks == NULL) { + isc_mem_put(mctx, pool, sizeof(*pool)); + return (ISC_R_NOMEMORY); + } + for (i = 0; i < ntasks; i++) + pool->tasks[i] = NULL; + + *poolp = pool; + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_taskpool_create(isc_taskmgr_t *tmgr, isc_mem_t *mctx, + unsigned int ntasks, unsigned int quantum, + isc_taskpool_t **poolp) +{ + unsigned int i; + isc_taskpool_t *pool = NULL; + isc_result_t result; + + INSIST(ntasks > 0); + + /* Allocate the pool structure */ + result = alloc_pool(tmgr, mctx, ntasks, quantum, &pool); + if (result != ISC_R_SUCCESS) + return (result); + + /* Create the tasks */ + for (i = 0; i < ntasks; i++) { + result = isc_task_create(tmgr, quantum, &pool->tasks[i]); + if (result != ISC_R_SUCCESS) { + isc_taskpool_destroy(&pool); + return (result); + } + isc_task_setname(pool->tasks[i], "taskpool", NULL); + } + + *poolp = pool; + return (ISC_R_SUCCESS); +} + +void +isc_taskpool_gettask(isc_taskpool_t *pool, isc_task_t **targetp) { + isc_uint32_t i; + isc_random_get(&i); + isc_task_attach(pool->tasks[i % pool->ntasks], targetp); +} + +int +isc_taskpool_size(isc_taskpool_t *pool) { + REQUIRE(pool != NULL); + return (pool->ntasks); +} + +isc_result_t +isc_taskpool_expand(isc_taskpool_t **sourcep, unsigned int size, + isc_taskpool_t **targetp) +{ + isc_result_t result; + isc_taskpool_t *pool; + + REQUIRE(sourcep != NULL && *sourcep != NULL); + REQUIRE(targetp != NULL && *targetp == NULL); + + pool = *sourcep; + if (size > pool->ntasks) { + isc_taskpool_t *newpool = NULL; + unsigned int i; + + /* Allocate a new pool structure */ + result = alloc_pool(pool->tmgr, pool->mctx, size, + pool->quantum, &newpool); + if (result != ISC_R_SUCCESS) + return (result); + + /* Copy over the tasks from the old pool */ + for (i = 0; i < pool->ntasks; i++) { + newpool->tasks[i] = pool->tasks[i]; + pool->tasks[i] = NULL; + } + + /* Create new tasks */ + for (i = pool->ntasks; i < size; i++) { + result = isc_task_create(pool->tmgr, pool->quantum, + &newpool->tasks[i]); + if (result != ISC_R_SUCCESS) { + isc_taskpool_destroy(&newpool); + return (result); + } + isc_task_setname(newpool->tasks[i], "taskpool", NULL); + } + + isc_taskpool_destroy(&pool); + pool = newpool; + } + + *sourcep = NULL; + *targetp = pool; + return (ISC_R_SUCCESS); +} + +void +isc_taskpool_destroy(isc_taskpool_t **poolp) { + unsigned int i; + isc_taskpool_t *pool = *poolp; + for (i = 0; i < pool->ntasks; i++) { + if (pool->tasks[i] != NULL) + isc_task_detach(&pool->tasks[i]); + } + isc_mem_put(pool->mctx, pool->tasks, + pool->ntasks * sizeof(isc_task_t *)); + isc_mem_put(pool->mctx, pool, sizeof(*pool)); + *poolp = NULL; +} + +void +isc_taskpool_setprivilege(isc_taskpool_t *pool, isc_boolean_t priv) { + unsigned int i; + + REQUIRE(pool != NULL); + + for (i = 0; i < pool->ntasks; i++) { + if (pool->tasks[i] != NULL) + isc_task_setprivilege(pool->tasks[i], priv); + } +} diff --git a/contrib/ntp/lib/isc/tests/Atffile b/contrib/ntp/lib/isc/tests/Atffile new file mode 100644 index 0000000..c3e044f --- /dev/null +++ b/contrib/ntp/lib/isc/tests/Atffile @@ -0,0 +1,5 @@ +Content-Type: application/X-atf-atffile; version="1" + +prop: test-suite = bind9 + +tp-glob: *_test diff --git a/contrib/ntp/lib/isc/tests/hash_test.c b/contrib/ntp/lib/isc/tests/hash_test.c new file mode 100644 index 0000000..836d7b6 --- /dev/null +++ b/contrib/ntp/lib/isc/tests/hash_test.c @@ -0,0 +1,1805 @@ +/* + * Copyright (C) 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/* ! \file */ + +#include <config.h> + +#include <atf-c.h> + +#include <stdio.h> +#include <string.h> + +#include <isc/hmacmd5.h> +#include <isc/hmacsha.h> +#include <isc/md5.h> +#include <isc/sha1.h> +#include <isc/util.h> +#include <isc/string.h> + +/* + * Test data from RFC6234 + */ + +unsigned char digest[ISC_SHA512_DIGESTLENGTH]; +unsigned char buffer[1024]; +const char *s; +char str[ISC_SHA512_DIGESTLENGTH]; +unsigned char key[20]; +int i = 0; + +isc_result_t +tohexstr(unsigned char *d, unsigned int len, char *out); +/* + * Precondition: a hexadecimal number in *d, the length of that number in len, + * and a pointer to a character array to put the output (*out). + * Postcondition: A String representation of the given hexadecimal number is + * placed into the array *out + * + * 'out' MUST point to an array of at least len / 2 + 1 + * + * Return values: ISC_R_SUCCESS if the operation is sucessful + */ + +isc_result_t +tohexstr(unsigned char *d, unsigned int len, char *out) { + + out[0]='\0'; + char c_ret[] = "AA"; + unsigned int i; + strcat(out, "0x"); + for (i = 0; i < len; i++) { + sprintf(c_ret, "%02X", d[i]); + strcat(out, c_ret); + } + strcat(out, "\0"); + return (ISC_R_SUCCESS); +} + + +#define TEST_INPUT(x) (x), sizeof(x)-1 + +typedef struct hash_testcase { + const char *input; + size_t input_len; + const char *result; + int repeats; +} hash_testcase_t; + +typedef struct hash_test_key { + const char *key; + const int len; +} hash_test_key_t; + +/* non-hmac tests */ + +ATF_TC(isc_sha1); +ATF_TC_HEAD(isc_sha1, tc) { + atf_tc_set_md_var(tc, "descr", "sha1 examples from RFC4634"); +} +ATF_TC_BODY(isc_sha1, tc) { + isc_sha1_t sha1; + + UNUSED(tc); + + /* + * These are the various test vectors. All of these are passed + * through the hash function and the results are compared to the + * result specified here. + */ + hash_testcase_t testcases[] = { + /* Test 1 */ + { + TEST_INPUT("abc"), + "0xA9993E364706816ABA3E25717850C26C9CD0D89D", + 1 + }, + /* Test 2 */ + { + TEST_INPUT("abcdbcdecdefdefgefghfghighijhijkijk" + "ljklmklmnlmnomnopnopq"), + "0x84983E441C3BD26EBAAE4AA1F95129E5E54670F1", + 1 + }, + /* Test 3 */ + { + TEST_INPUT("a") /* times 1000000 */, + "0x34AA973CD4C4DAA4F61EEB2BDBAD27316534016F", + 1000000 + }, + /* Test 4 -- exact multiple of 512 bits */ + { + TEST_INPUT("01234567012345670123456701234567"), + "0xDEA356A2CDDD90C7A7ECEDC5EBB563934F460452", + 20 /* 20 times */ + }, +#if 0 + /* Test 5 -- optional feature, not implemented */ + { + TEST_INPUT(""), + /* "extrabits": 0x98 , "numberextrabits": 5 */ + "0x29826B003B906E660EFF4027CE98AF3531AC75BA", + 1 + }, +#endif + /* Test 6 */ + { + TEST_INPUT("\x5e"), + "0x5E6F80A34A9798CAFC6A5DB96CC57BA4C4DB59C2", + 1 + }, +#if 0 + /* Test 7 -- optional feature, not implemented */ + { + TEST_INPUT("\x49\xb2\xae\xc2\x59\x4b\xbe\x3a" + "\x3b\x11\x75\x42\xd9\x4a\xc8"), + /* "extrabits": 0x80, "numberextrabits": 3 */ + "0x6239781E03729919C01955B3FFA8ACB60B988340", 1 }, +#endif + /* Test 8 */ + { + TEST_INPUT("\x9a\x7d\xfd\xf1\xec\xea\xd0\x6e\xd6\x46" + "\xaa\x55\xfe\x75\x71\x46"), + "0x82ABFF6605DBE1C17DEF12A394FA22A82B544A35", + 1 + }, +#if 0 + /* Test 9 -- optional feature, not implemented */ + { + TEST_INPUT("\x65\xf9\x32\x99\x5b\xa4\xce\x2c\xb1\xb4" + "\xa2\xe7\x1a\xe7\x02\x20\xaa\xce\xc8\x96" + "\x2d\xd4\x49\x9c\xbd\x7c\x88\x7a\x94\xea" + "\xaa\x10\x1e\xa5\xaa\xbc\x52\x9b\x4e\x7e" + "\x43\x66\x5a\x5a\xf2\xcd\x03\xfe\x67\x8e" + "\xa6\xa5\x00\x5b\xba\x3b\x08\x22\x04\xc2" + "\x8b\x91\x09\xf4\x69\xda\xc9\x2a\xaa\xb3" + "\xaa\x7c\x11\xa1\xb3\x2a"), + /* "extrabits": 0xE0 , "numberextrabits": 3 */ + "0x8C5B2A5DDAE5A97FC7F9D85661C672ADBF7933D4", + 1 + }, +#endif + /* Test 10 */ + { + TEST_INPUT("\xf7\x8f\x92\x14\x1b\xcd\x17\x0a\xe8\x9b" + "\x4f\xba\x15\xa1\xd5\x9f\x3f\xd8\x4d\x22" + "\x3c\x92\x51\xbd\xac\xbb\xae\x61\xd0\x5e" + "\xd1\x15\xa0\x6a\x7c\xe1\x17\xb7\xbe\xea" + "\xd2\x44\x21\xde\xd9\xc3\x25\x92\xbd\x57" + "\xed\xea\xe3\x9c\x39\xfa\x1f\xe8\x94\x6a" + "\x84\xd0\xcf\x1f\x7b\xee\xad\x17\x13\xe2" + "\xe0\x95\x98\x97\x34\x7f\x67\xc8\x0b\x04" + "\x00\xc2\x09\x81\x5d\x6b\x10\xa6\x83\x83" + "\x6f\xd5\x56\x2a\x56\xca\xb1\xa2\x8e\x81" + "\xb6\x57\x66\x54\x63\x1c\xf1\x65\x66\xb8" + "\x6e\x3b\x33\xa1\x08\xb0\x53\x07\xc0\x0a" + "\xff\x14\xa7\x68\xed\x73\x50\x60\x6a\x0f" + "\x85\xe6\xa9\x1d\x39\x6f\x5b\x5c\xbe\x57" + "\x7f\x9b\x38\x80\x7c\x7d\x52\x3d\x6d\x79" + "\x2f\x6e\xbc\x24\xa4\xec\xf2\xb3\xa4\x27" + "\xcd\xbb\xfb"), + "0xCB0082C8F197D260991BA6A460E76E202BAD27B3", + 1 + }, + { NULL, 0, NULL, 1 } + }; + + hash_testcase_t *testcase = testcases; + + while (testcase->input != NULL && testcase->result != NULL) { + isc_sha1_init(&sha1); + for(i = 0; i < testcase->repeats; i++) { + isc_sha1_update(&sha1, + (const isc_uint8_t *) testcase->input, + testcase->input_len); + } + isc_sha1_final(&sha1, digest); + tohexstr(digest, ISC_SHA1_DIGESTLENGTH, str); + ATF_CHECK_STREQ(str, testcase->result); + + testcase++; + } +} + + +ATF_TC(isc_sha224); +ATF_TC_HEAD(isc_sha224, tc) { + atf_tc_set_md_var(tc, "descr", "sha224 examples from RFC4634"); +} +ATF_TC_BODY(isc_sha224, tc) { + isc_sha224_t sha224; + + UNUSED(tc); + + /* + * These are the various test vectors. All of these are passed + * through the hash function and the results are compared to the + * result specified here. + */ + hash_testcase_t testcases[] = { + /* Test 1 */ + { + TEST_INPUT("abc"), + "0x23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7" + "E36C9DA7", + 1 + }, + /* Test 2 */ + { + TEST_INPUT("abcdbcdecdefdefgefghfghighijhijkijklj" + "klmklmnlmnomnopnopq"), + "0x75388B16512776CC5DBA5DA1FD890150B0C6455CB4F58B" + "1952522525", + 1 + }, + /* Test 3 */ + { + TEST_INPUT("a"), + "0x20794655980C91D8BBB4C1EA97618A4BF03F42581948B2" + "EE4EE7AD67", + 1000000 + }, + /* Test 4 */ + { + TEST_INPUT("01234567012345670123456701234567"), + "0x567F69F168CD7844E65259CE658FE7AADFA25216E68ECA" + "0EB7AB8262", + 20 + }, +#if 0 + /* Test 5 -- unimplemented optional functionality */ + { + TEST_INPUT(""), + "0xXXX", + 1 + }, +#endif + /* Test 6 */ + { + TEST_INPUT("\x07"), + "0x00ECD5F138422B8AD74C9799FD826C531BAD2FCABC7450" + "BEE2AA8C2A", + 1 + }, +#if 0 + /* Test 7 -- unimplemented optional functionality */ + { + TEST_INPUT(""), + "0xXXX", + 1 + }, +#endif + /* Test 8 */ + { + TEST_INPUT("\x18\x80\x40\x05\xdd\x4f\xbd\x15\x56\x29" + "\x9d\x6f\x9d\x93\xdf\x62"), + "0xDF90D78AA78821C99B40BA4C966921ACCD8FFB1E98AC38" + "8E56191DB1", + 1 + }, +#if 0 + /* Test 9 */ + { + TEST_INPUT(""), + "0xXXX", + 1 + }, +#endif + /* Test 10 */ + { + TEST_INPUT("\x55\xb2\x10\x07\x9c\x61\xb5\x3a\xdd\x52" + "\x06\x22\xd1\xac\x97\xd5\xcd\xbe\x8c\xb3" + "\x3a\xa0\xae\x34\x45\x17\xbe\xe4\xd7\xba" + "\x09\xab\xc8\x53\x3c\x52\x50\x88\x7a\x43" + "\xbe\xbb\xac\x90\x6c\x2e\x18\x37\xf2\x6b" + "\x36\xa5\x9a\xe3\xbe\x78\x14\xd5\x06\x89" + "\x6b\x71\x8b\x2a\x38\x3e\xcd\xac\x16\xb9" + "\x61\x25\x55\x3f\x41\x6f\xf3\x2c\x66\x74" + "\xc7\x45\x99\xa9\x00\x53\x86\xd9\xce\x11" + "\x12\x24\x5f\x48\xee\x47\x0d\x39\x6c\x1e" + "\xd6\x3b\x92\x67\x0c\xa5\x6e\xc8\x4d\xee" + "\xa8\x14\xb6\x13\x5e\xca\x54\x39\x2b\xde" + "\xdb\x94\x89\xbc\x9b\x87\x5a\x8b\xaf\x0d" + "\xc1\xae\x78\x57\x36\x91\x4a\xb7\xda\xa2" + "\x64\xbc\x07\x9d\x26\x9f\x2c\x0d\x7e\xdd" + "\xd8\x10\xa4\x26\x14\x5a\x07\x76\xf6\x7c" + "\x87\x82\x73"), + "0x0B31894EC8937AD9B91BDFBCBA294D9ADEFAA18E09305E" + "9F20D5C3A4", + 1 + }, + { NULL, 0, NULL, 1 } + }; + + hash_testcase_t *testcase = testcases; + + while (testcase->input != NULL && testcase->result != NULL) { + isc_sha224_init(&sha224); + for(i = 0; i < testcase->repeats; i++) { + isc_sha224_update(&sha224, + (const isc_uint8_t *) testcase->input, + testcase->input_len); + } + isc_sha224_final(digest, &sha224); + /* + *API inconsistency BUG HERE + * in order to be consistant with the other isc_hash_final + * functions the call should be + * isc_sha224_final(&sha224, digest); + */ + tohexstr(digest, ISC_SHA224_DIGESTLENGTH, str); + ATF_CHECK_STREQ(str, testcase->result); + + testcase++; + } + +} + +ATF_TC(isc_sha256); +ATF_TC_HEAD(isc_sha256, tc) { + atf_tc_set_md_var(tc, "descr", "sha224 examples from RFC4634"); +} +ATF_TC_BODY(isc_sha256, tc) { + isc_sha256_t sha256; + + UNUSED(tc); + + /* + * These are the various test vectors. All of these are passed + * through the hash function and the results are compared to the + * result specified here. + */ + hash_testcase_t testcases[] = { + /* Test 1 */ + { + TEST_INPUT("abc"), + "0xBA7816BF8F01CFEA414140DE5DAE2223B00361A396177A" + "9CB410FF61F20015AD", + 1 + }, + /* Test 2 */ + { + TEST_INPUT("abcdbcdecdefdefgefghfghighijhijkijkljk" + "lmklmnlmnomnopnopq"), + "0x248D6A61D20638B8E5C026930C3E6039A33CE45964FF21" + "67F6ECEDD419DB06C1", + 1 + }, + /* Test 3 */ + { + TEST_INPUT("a"), + "0xCDC76E5C9914FB9281A1C7E284D73E67F1809A48A49720" + "0E046D39CCC7112CD0", + 1000000 }, + /* Test 4 */ + { + TEST_INPUT("01234567012345670123456701234567"), + "0x594847328451BDFA85056225462CC1D867D877FB388DF0" + "CE35F25AB5562BFBB5", + 20 + }, +#if 0 + /* Test 5 -- unimplemented optional functionality */ + { + TEST_INPUT(""), + "0xXXX", + 1 + }, +#endif + /* Test 6 */ + { + TEST_INPUT("\x19"), + "0x68AA2E2EE5DFF96E3355E6C7EE373E3D6A4E17F75F9518" + "D843709C0C9BC3E3D4", + 1 + }, +#if 0 + /* Test 7 -- unimplemented optional functionality */ + { + TEST_INPUT(""), + "0xXXX", + 1 + }, +#endif + /* Test 8 */ + { + TEST_INPUT("\xe3\xd7\x25\x70\xdc\xdd\x78\x7c\xe3" + "\x88\x7a\xb2\xcd\x68\x46\x52"), + "0x175EE69B02BA9B58E2B0A5FD13819CEA573F3940A94F82" + "5128CF4209BEABB4E8", + 1 + }, +#if 0 + /* Test 9 -- unimplemented optional functionality */ + { + TEST_INPUT(""), + "0xXXX", + 1 + }, +#endif + /* Test 10 */ + { + TEST_INPUT("\x83\x26\x75\x4e\x22\x77\x37\x2f\x4f\xc1" + "\x2b\x20\x52\x7a\xfe\xf0\x4d\x8a\x05\x69" + "\x71\xb1\x1a\xd5\x71\x23\xa7\xc1\x37\x76" + "\x00\x00\xd7\xbe\xf6\xf3\xc1\xf7\xa9\x08" + "\x3a\xa3\x9d\x81\x0d\xb3\x10\x77\x7d\xab" + "\x8b\x1e\x7f\x02\xb8\x4a\x26\xc7\x73\x32" + "\x5f\x8b\x23\x74\xde\x7a\x4b\x5a\x58\xcb" + "\x5c\x5c\xf3\x5b\xce\xe6\xfb\x94\x6e\x5b" + "\xd6\x94\xfa\x59\x3a\x8b\xeb\x3f\x9d\x65" + "\x92\xec\xed\xaa\x66\xca\x82\xa2\x9d\x0c" + "\x51\xbc\xf9\x33\x62\x30\xe5\xd7\x84\xe4" + "\xc0\xa4\x3f\x8d\x79\xa3\x0a\x16\x5c\xba" + "\xbe\x45\x2b\x77\x4b\x9c\x71\x09\xa9\x7d" + "\x13\x8f\x12\x92\x28\x96\x6f\x6c\x0a\xdc" + "\x10\x6a\xad\x5a\x9f\xdd\x30\x82\x57\x69" + "\xb2\xc6\x71\xaf\x67\x59\xdf\x28\xeb\x39" + "\x3d\x54\xd6"), + "0x97DBCA7DF46D62C8A422C941DD7E835B8AD3361763F7E9" + "B2D95F4F0DA6E1CCBC", + 1 + }, + { NULL, 0, NULL, 1 } + }; + + hash_testcase_t *testcase = testcases; + + while (testcase->input != NULL && testcase->result != NULL) { + isc_sha256_init(&sha256); + for(i = 0; i < testcase->repeats; i++) { + isc_sha256_update(&sha256, + (const isc_uint8_t *) testcase->input, + testcase->input_len); + } + isc_sha256_final(digest, &sha256); + /* + *API inconsistency BUG HERE + * in order to be consistant with the other isc_hash_final + * functions the call should be + * isc_sha224_final(&sha224, digest); + */ + tohexstr(digest, ISC_SHA256_DIGESTLENGTH, str); + ATF_CHECK_STREQ(str, testcase->result); + + testcase++; + } + +} + +ATF_TC(isc_sha384); +ATF_TC_HEAD(isc_sha384, tc) { + atf_tc_set_md_var(tc, "descr", "sha224 examples from RFC4634"); +} +ATF_TC_BODY(isc_sha384, tc) { + isc_sha384_t sha384; + + UNUSED(tc); + + /* + * These are the various test vectors. All of these are passed + * through the hash function and the results are compared to the + * result specified here. + */ + hash_testcase_t testcases[] = { + /* Test 1 */ + { + TEST_INPUT("abc"), + "0xCB00753F45A35E8BB5A03D699AC65007272C32AB0EDED1" + "631A8B605A43FF5BED8086072BA1E7CC2358BAEC" + "A134C825A7", + 1 + }, + /* Test 2 */ + { + TEST_INPUT("abcdefghbcdefghicdefghijdefghijkefghijkl" + "fghijklmghijklmnhijklmnoijklmnopjklmnopq" + "klmnopqrlmnopqrsmnopqrstnopqrstu"), + "0x09330C33F71147E83D192FC782CD1B4753111B173B3B05" + "D22FA08086E3B0F712FCC7C71A557E2DB966C3E9" + "FA91746039", + 1 + }, + /* Test 3 */ + { + TEST_INPUT("a"), + "0x9D0E1809716474CB086E834E310A4A1CED149E9C00F248" + "527972CEC5704C2A5B07B8B3DC38ECC4EBAE97DD" + "D87F3D8985", + 1000000 + }, + /* Test 4 */ + { + TEST_INPUT("01234567012345670123456701234567"), + "0x2FC64A4F500DDB6828F6A3430B8DD72A368EB7F3A8322A" + "70BC84275B9C0B3AB00D27A5CC3C2D224AA6B61A" + "0D79FB4596", + 20 + }, +#if 0 + /* Test 5 -- unimplemented optional functionality */ + { + TEST_INPUT(""), + "0xXXX", + 1 + }, +#endif + /* Test 6 */ + { TEST_INPUT("\xb9"), + "0xBC8089A19007C0B14195F4ECC74094FEC64F01F9092928" + "2C2FB392881578208AD466828B1C6C283D2722CF" + "0AD1AB6938", + 1 + }, +#if 0 + /* Test 7 -- unimplemented optional functionality */ + { + TEST_INPUT(""), + "0xXXX", + 1 + }, +#endif + /* Test 8 */ + { + TEST_INPUT("\xa4\x1c\x49\x77\x79\xc0\x37\x5f\xf1" + "\x0a\x7f\x4e\x08\x59\x17\x39"), + "0xC9A68443A005812256B8EC76B00516F0DBB74FAB26D665" + "913F194B6FFB0E91EA9967566B58109CBC675CC2" + "08E4C823F7", + 1 + }, +#if 0 + /* Test 9 -- unimplemented optional functionality */ + { + TEST_INPUT(""), + "0xXXX", + 1 + }, +#endif + /* Test 10 */ + { + TEST_INPUT("\x39\x96\x69\xe2\x8f\x6b\x9c\x6d\xbc\xbb" + "\x69\x12\xec\x10\xff\xcf\x74\x79\x03\x49" + "\xb7\xdc\x8f\xbe\x4a\x8e\x7b\x3b\x56\x21" + "\xdb\x0f\x3e\x7d\xc8\x7f\x82\x32\x64\xbb" + "\xe4\x0d\x18\x11\xc9\xea\x20\x61\xe1\xc8" + "\x4a\xd1\x0a\x23\xfa\xc1\x72\x7e\x72\x02" + "\xfc\x3f\x50\x42\xe6\xbf\x58\xcb\xa8\xa2" + "\x74\x6e\x1f\x64\xf9\xb9\xea\x35\x2c\x71" + "\x15\x07\x05\x3c\xf4\xe5\x33\x9d\x52\x86" + "\x5f\x25\xcc\x22\xb5\xe8\x77\x84\xa1\x2f" + "\xc9\x61\xd6\x6c\xb6\xe8\x95\x73\x19\x9a" + "\x2c\xe6\x56\x5c\xbd\xf1\x3d\xca\x40\x38" + "\x32\xcf\xcb\x0e\x8b\x72\x11\xe8\x3a\xf3" + "\x2a\x11\xac\x17\x92\x9f\xf1\xc0\x73\xa5" + "\x1c\xc0\x27\xaa\xed\xef\xf8\x5a\xad\x7c" + "\x2b\x7c\x5a\x80\x3e\x24\x04\xd9\x6d\x2a" + "\x77\x35\x7b\xda\x1a\x6d\xae\xed\x17\x15" + "\x1c\xb9\xbc\x51\x25\xa4\x22\xe9\x41\xde" + "\x0c\xa0\xfc\x50\x11\xc2\x3e\xcf\xfe\xfd" + "\xd0\x96\x76\x71\x1c\xf3\xdb\x0a\x34\x40" + "\x72\x0e\x16\x15\xc1\xf2\x2f\xbc\x3c\x72" + "\x1d\xe5\x21\xe1\xb9\x9b\xa1\xbd\x55\x77" + "\x40\x86\x42\x14\x7e\xd0\x96"), + "0x4F440DB1E6EDD2899FA335F09515AA025EE177A79F4B4A" + "AF38E42B5C4DE660F5DE8FB2A5B2FBD2A3CBFFD2" + "0CFF1288C0", + 1 + }, + { NULL, 0, NULL, 1 } + }; + + hash_testcase_t *testcase = testcases; + + while (testcase->input != NULL && testcase->result != NULL) { + isc_sha384_init(&sha384); + for(i = 0; i < testcase->repeats; i++) { + isc_sha384_update(&sha384, + (const isc_uint8_t *) testcase->input, + testcase->input_len); + } + isc_sha384_final(digest, &sha384); + /* + *API inconsistency BUG HERE + * in order to be consistant with the other isc_hash_final + * functions the call should be + * isc_sha224_final(&sha224, digest); + */ + tohexstr(digest, ISC_SHA384_DIGESTLENGTH, str); + ATF_CHECK_STREQ(str, testcase->result); + + testcase++; + } + +} + +ATF_TC(isc_sha512); +ATF_TC_HEAD(isc_sha512, tc) { + atf_tc_set_md_var(tc, "descr", "sha224 examples from RFC4634"); +} +ATF_TC_BODY(isc_sha512, tc) { + isc_sha512_t sha512; + + UNUSED(tc); + + /* + * These are the various test vectors. All of these are passed + * through the hash function and the results are compared to the + * result specified here. + */ + hash_testcase_t testcases[] = { + /* Test 1 */ + { + TEST_INPUT("abc"), + "0xDDAF35A193617ABACC417349AE20413112E6FA4E89A97E" + "A20A9EEEE64B55D39A2192992A274FC1A836BA3C" + "23A3FEEBBD454D4423643CE80E2A9AC94FA54CA49F", + 1 + }, + /* Test 2 */ + { + TEST_INPUT("abcdefghbcdefghicdefghijdefghijkefghijkl" + "fghijklmghijklmnhijklmnoijklmnopjklmnopq" + "klmnopqrlmnopqrsmnopqrstnopqrstu"), + "0x8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7F" + "A17299AEADB6889018501D289E4900F7E4331B99" + "DEC4B5433AC7D329EEB6DD26545E96E55B874BE909", + 1 + }, + /* Test 3 */ + { + TEST_INPUT("a"), + "0xE718483D0CE769644E2E42C7BC15B4638E1F98B13B2044" + "285632A803AFA973EBDE0FF244877EA60A4CB043" + "2CE577C31BEB009C5C2C49AA2E4EADB217AD8CC09B", + 1000000 + }, + /* Test 4 */ + { + TEST_INPUT("01234567012345670123456701234567"), + "0x89D05BA632C699C31231DED4FFC127D5A894DAD412C0E0" + "24DB872D1ABD2BA8141A0F85072A9BE1E2AA04CF" + "33C765CB510813A39CD5A84C4ACAA64D3F3FB7BAE9", + 20 + }, +#if 0 + /* Test 5 -- unimplemented optional functionality */ + { + TEST_INPUT(""), + "0xXXX", + 1 + }, +#endif + /* Test 6 */ + { + TEST_INPUT("\xD0"), + "0x9992202938E882E73E20F6B69E68A0A7149090423D93C8" + "1BAB3F21678D4ACEEEE50E4E8CAFADA4C85A54EA" + "8306826C4AD6E74CECE9631BFA8A549B4AB3FBBA15", + 1 + }, +#if 0 + /* Test 7 -- unimplemented optional functionality */ + { + TEST_INPUT(""), + "0xXXX", + 1 + }, +#endif + /* Test 8 */ + { + TEST_INPUT("\x8d\x4e\x3c\x0e\x38\x89\x19\x14\x91\x81" + "\x6e\x9d\x98\xbf\xf0\xa0"), + "0xCB0B67A4B8712CD73C9AABC0B199E9269B20844AFB75AC" + "BDD1C153C9828924C3DDEDAAFE669C5FDD0BC66F" + "630F6773988213EB1B16F517AD0DE4B2F0C95C90F8", + 1 + }, +#if 0 + /* Test 9 -- unimplemented optional functionality */ + { + TEST_INPUT(""), + "0xXXX", + 1 + }, +#endif + /* Test 10 */ + { + TEST_INPUT("\xa5\x5f\x20\xc4\x11\xaa\xd1\x32\x80\x7a" + "\x50\x2d\x65\x82\x4e\x31\xa2\x30\x54\x32" + "\xaa\x3d\x06\xd3\xe2\x82\xa8\xd8\x4e\x0d" + "\xe1\xde\x69\x74\xbf\x49\x54\x69\xfc\x7f" + "\x33\x8f\x80\x54\xd5\x8c\x26\xc4\x93\x60" + "\xc3\xe8\x7a\xf5\x65\x23\xac\xf6\xd8\x9d" + "\x03\xe5\x6f\xf2\xf8\x68\x00\x2b\xc3\xe4" + "\x31\xed\xc4\x4d\xf2\xf0\x22\x3d\x4b\xb3" + "\xb2\x43\x58\x6e\x1a\x7d\x92\x49\x36\x69" + "\x4f\xcb\xba\xf8\x8d\x95\x19\xe4\xeb\x50" + "\xa6\x44\xf8\xe4\xf9\x5e\xb0\xea\x95\xbc" + "\x44\x65\xc8\x82\x1a\xac\xd2\xfe\x15\xab" + "\x49\x81\x16\x4b\xbb\x6d\xc3\x2f\x96\x90" + "\x87\xa1\x45\xb0\xd9\xcc\x9c\x67\xc2\x2b" + "\x76\x32\x99\x41\x9c\xc4\x12\x8b\xe9\xa0" + "\x77\xb3\xac\xe6\x34\x06\x4e\x6d\x99\x28" + "\x35\x13\xdc\x06\xe7\x51\x5d\x0d\x73\x13" + "\x2e\x9a\x0d\xc6\xd3\xb1\xf8\xb2\x46\xf1" + "\xa9\x8a\x3f\xc7\x29\x41\xb1\xe3\xbb\x20" + "\x98\xe8\xbf\x16\xf2\x68\xd6\x4f\x0b\x0f" + "\x47\x07\xfe\x1e\xa1\xa1\x79\x1b\xa2\xf3" + "\xc0\xc7\x58\xe5\xf5\x51\x86\x3a\x96\xc9" + "\x49\xad\x47\xd7\xfb\x40\xd2"), + "0xC665BEFB36DA189D78822D10528CBF3B12B3EEF7260399" + "09C1A16A270D48719377966B957A878E72058477" + "9A62825C18DA26415E49A7176A894E7510FD1451F5", + 1 + }, + { NULL, 0, NULL, 1 } + }; + + hash_testcase_t *testcase = testcases; + + while (testcase->input != NULL && testcase->result != NULL) { + isc_sha512_init(&sha512); + for(i = 0; i < testcase->repeats; i++) { + isc_sha512_update(&sha512, + (const isc_uint8_t *) testcase->input, + testcase->input_len); + } + isc_sha512_final(digest, &sha512); + /* + *API inconsistency BUG HERE + * in order to be consistant with the other isc_hash_final + * functions the call should be + * isc_sha224_final(&sha224, digest); + */ + tohexstr(digest, ISC_SHA512_DIGESTLENGTH, str); + ATF_CHECK_STREQ(str, testcase->result); + + testcase++; + } + +} + +ATF_TC(isc_md5); +ATF_TC_HEAD(isc_md5, tc) { + atf_tc_set_md_var(tc, "descr", "md5 example from RFC1321"); +} +ATF_TC_BODY(isc_md5, tc) { + isc_md5_t md5; + + UNUSED(tc); + + /* + * These are the various test vectors. All of these are passed + * through the hash function and the results are compared to the + * result specified here. + */ + hash_testcase_t testcases[] = { + { + TEST_INPUT(""), + "0xD41D8CD98F00B204E9800998ECF8427E", + 1 + }, + { + TEST_INPUT("a"), + "0x0CC175B9C0F1B6A831C399E269772661", + 1 + }, + { + TEST_INPUT("abc"), + "0x900150983CD24FB0D6963F7D28E17F72", + 1 + }, + { + TEST_INPUT("message digest"), + "0xF96B697D7CB7938D525A2F31AAF161D0", + 1 + }, + { + TEST_INPUT("abcdefghijklmnopqrstuvwxyz"), + "0xC3FCD3D76192E4007DFB496CCA67E13B", + 1 + }, + { + TEST_INPUT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklm" + "nopqrstuvwxyz0123456789"), + "0xD174AB98D277D9F5A5611C2C9F419D9F", + 1 + }, + { + TEST_INPUT("123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890"), + "0x57EDF4A22BE3C955AC49DA2E2107B67A", + 1 + }, + { NULL, 0, NULL, 1 } + }; + + hash_testcase_t *testcase = testcases; + + while (testcase->input != NULL && testcase->result != NULL) { + isc_md5_init(&md5); + for(i = 0; i < testcase->repeats; i++) { + isc_md5_update(&md5, + (const isc_uint8_t *) testcase->input, + testcase->input_len); + } + isc_md5_final(&md5, digest); + tohexstr(digest, ISC_MD5_DIGESTLENGTH, str); + ATF_CHECK_STREQ(str, testcase->result); + + testcase++; + } +} + +/* HMAC-SHA1 test */ +ATF_TC(isc_hmacsha1); +ATF_TC_HEAD(isc_hmacsha1, tc) { + atf_tc_set_md_var(tc, "descr", "HMAC-SHA1 examples from RFC2104"); +} +ATF_TC_BODY(isc_hmacsha1, tc) { + isc_hmacsha1_t hmacsha1; + + UNUSED(tc); + /* + * These are the various test vectors. All of these are passed + * through the hash function and the results are compared to the + * result specified here. + */ + hash_testcase_t testcases[] = { + /* Test 1 */ + { + TEST_INPUT("\x48\x69\x20\x54\x68\x65\x72\x65"), + "0xB617318655057264E28BC0B6FB378C8EF146BE00", + 1 + }, + /* Test 2 */ + { + TEST_INPUT("\x77\x68\x61\x74\x20\x64\x6f\x20\x79\x61" + "\x20\x77\x61\x6e\x74\x20\x66\x6f\x72\x20" + "\x6e\x6f\x74\x68\x69\x6e\x67\x3f"), + "0xEFFCDF6AE5EB2FA2D27416D5F184DF9C259A7C79", + 1 + }, + /* Test 3 */ + { + TEST_INPUT("\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"), + "0x125D7342B9AC11CD91A39AF48AA17B4F63F175D3", + 1 + }, + /* Test 4 */ + { + TEST_INPUT("\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"), + "0x4C9007F4026250C6BC8414F9BF50C86C2D7235DA", + 1 + }, +#if 0 + /* Test 5 -- unimplemented optional functionality */ + { + TEST_INPUT("Test With Truncation"), + "0x4C1A03424B55E07FE7F27BE1", + 1 + }, +#endif + /* Test 6 */ + { + TEST_INPUT("Test Using Larger Than Block-Size Key - " + "Hash Key First"), + "0xAA4AE5E15272D00E95705637CE8A3B55ED402112", 1 }, + /* Test 7 */ + { + TEST_INPUT("Test Using Larger Than Block-Size Key and " + "Larger Than One Block-Size Data"), + "0xE8E99D0F45237D786D6BBAA7965C7808BBFF1A91", + 1 + }, + { NULL, 0, NULL, 1 } + }; + + hash_testcase_t *testcase = testcases; + + hash_test_key_t test_keys[] = { + /* Key 1 */ + { "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", 20 }, + /* Key 2 */ + { "Jefe", 4 }, + /* Key 3 */ + { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 20 }, + /* Key 4 */ + { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a" + "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14" + "\x15\x16\x17\x18\x19", 25 }, +#if 0 + /* Key 5 */ + { "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c" + "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c", 20 }, +#endif + /* Key 6 */ + { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 80 }, + /* Key 7 */ + { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 80 }, + { "", 0 } + }; + + hash_test_key_t *test_key = test_keys; + + while (testcase->input != NULL && testcase->result != NULL) { + memcpy(buffer, test_key->key, test_key->len); + isc_hmacsha1_init(&hmacsha1, buffer, test_key->len); + isc_hmacsha1_update(&hmacsha1, + (const isc_uint8_t *) testcase->input, + testcase->input_len); + isc_hmacsha1_sign(&hmacsha1, digest, ISC_SHA1_DIGESTLENGTH); + tohexstr(digest, ISC_SHA1_DIGESTLENGTH, str); + ATF_CHECK_STREQ(str, testcase->result); + + testcase++; + test_key++; + } +} + +/* HMAC-SHA224 test */ +ATF_TC(isc_hmacsha224); +ATF_TC_HEAD(isc_hmacsha224, tc) { + atf_tc_set_md_var(tc, "descr", "HMAC-SHA224 examples from RFC4634"); +} +ATF_TC_BODY(isc_hmacsha224, tc) { + isc_hmacsha224_t hmacsha224; + + UNUSED(tc); + + /* + * These are the various test vectors. All of these are passed + * through the hash function and the results are compared to the + * result specified here. + */ + hash_testcase_t testcases[] = { + /* Test 1 */ + { + TEST_INPUT("\x48\x69\x20\x54\x68\x65\x72\x65"), + "0x896FB1128ABBDF196832107CD49DF33F47B4B1169912BA" + "4F53684B22", + 1 + }, + /* Test 2 */ + { + TEST_INPUT("\x77\x68\x61\x74\x20\x64\x6f\x20\x79\x61" + "\x20\x77\x61\x6e\x74\x20\x66\x6f\x72\x20" + "\x6e\x6f\x74\x68\x69\x6e\x67\x3f"), + "0xA30E01098BC6DBBF45690F3A7E9E6D0F8BBEA2A39E61480" + "08FD05E44", + 1 + }, + /* Test 3 */ + { + TEST_INPUT("\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"), + "0x7FB3CB3588C6C1F6FFA9694D7D6AD2649365B0C1F65D69" + "D1EC8333EA", + 1 + }, + /* Test 4 */ + { + TEST_INPUT("\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"), + "0x6C11506874013CAC6A2ABC1BB382627CEC6A90D86EFC01" + "2DE7AFEC5A", + 1 + }, +#if 0 + /* Test 5 -- unimplemented optional functionality */ + { + TEST_INPUT("Test With Truncation"), + "0x4C1A03424B55E07FE7F27BE1", + 1 + }, +#endif + /* Test 6 */ + { + TEST_INPUT("Test Using Larger Than Block-Size Key - " + "Hash Key First"), + "0x95E9A0DB962095ADAEBE9B2D6F0DBCE2D499F112F2D2B7" + "273FA6870E", + 1 + }, + /* Test 7 */ + { + TEST_INPUT("\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20" + "\x74\x65\x73\x74\x20\x75\x73\x69\x6e\x67" + "\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20" + "\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b" + "\x2d\x73\x69\x7a\x65\x20\x6b\x65\x79\x20" + "\x61\x6e\x64\x20\x61\x20\x6c\x61\x72\x67" + "\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c" + "\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x64" + "\x61\x74\x61\x2e\x20\x54\x68\x65\x20\x6b" + "\x65\x79\x20\x6e\x65\x65\x64\x73\x20\x74" + "\x6f\x20\x62\x65\x20\x68\x61\x73\x68\x65" + "\x64\x20\x62\x65\x66\x6f\x72\x65\x20\x62" + "\x65\x69\x6e\x67\x20\x75\x73\x65\x64\x20" + "\x62\x79\x20\x74\x68\x65\x20\x48\x4d\x41" + "\x43\x20\x61\x6c\x67\x6f\x72\x69\x74\x68" + "\x6d\x2e"), + "0x3A854166AC5D9F023F54D517D0B39DBD946770DB9C2B95" + "C9F6F565D1", + 1 + }, + { NULL, 0, NULL, 1 } + }; + + hash_testcase_t *testcase = testcases; + + hash_test_key_t test_keys[] = { + /* Key 1 */ + { "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", 20 }, + /* Key 2 */ + { "Jefe", 4 }, + /* Key 3 */ + { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 20 }, + /* Key 4 */ + { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a" + "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14" + "\x15\x16\x17\x18\x19", 25 }, +#if 0 + /* Key 5 */ + { "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c" + "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c", 20 }, +#endif + /* Key 6 */ + { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 131 }, + /* Key 7 */ + { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 131 }, + { "", 0 } + }; + + hash_test_key_t *test_key = test_keys; + + while (testcase->input != NULL && testcase->result != NULL) { + memcpy(buffer, test_key->key, test_key->len); + isc_hmacsha224_init(&hmacsha224, buffer, test_key->len); + isc_hmacsha224_update(&hmacsha224, + (const isc_uint8_t *) testcase->input, + testcase->input_len); + isc_hmacsha224_sign(&hmacsha224, digest, ISC_SHA224_DIGESTLENGTH); + tohexstr(digest, ISC_SHA224_DIGESTLENGTH, str); + ATF_CHECK_STREQ(str, testcase->result); + + testcase++; + test_key++; + } +} + +/* HMAC-SHA256 test */ +ATF_TC(isc_hmacsha256); +ATF_TC_HEAD(isc_hmacsha256, tc) { + atf_tc_set_md_var(tc, "descr", "HMAC-SHA256 examples from RFC4634"); +} +ATF_TC_BODY(isc_hmacsha256, tc) { + isc_hmacsha256_t hmacsha256; + + UNUSED(tc); + + /* + * These are the various test vectors. All of these are passed + * through the hash function and the results are compared to the + * result specified here. + */ + hash_testcase_t testcases[] = { + /* Test 1 */ + { + TEST_INPUT("\x48\x69\x20\x54\x68\x65\x72\x65"), + "0xB0344C61D8DB38535CA8AFCEAF0BF12B881DC200C9833D" + "A726E9376C2E32CFF7", + 1 + }, + /* Test 2 */ + { + TEST_INPUT("\x77\x68\x61\x74\x20\x64\x6f\x20\x79\x61" + "\x20\x77\x61\x6e\x74\x20\x66\x6f\x72\x20" + "\x6e\x6f\x74\x68\x69\x6e\x67\x3f"), + "0x5BDCC146BF60754E6A042426089575C75A003F089D2739" + "839DEC58B964EC3843", + 1 + }, + /* Test 3 */ + { + TEST_INPUT("\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"), + "0x773EA91E36800E46854DB8EBD09181A72959098B3EF8C1" + "22D9635514CED565FE", + 1 + }, + /* Test 4 */ + { + TEST_INPUT("\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"), + "0x82558A389A443C0EA4CC819899F2083A85F0FAA3E578F8" + "077A2E3FF46729665B", + 1 + }, +#if 0 + /* Test 5 -- unimplemented optional functionality */ + { + TEST_INPUT("Test With Truncation"), + "0x4C1A03424B55E07FE7F27BE1", + 1 + }, +#endif + /* Test 6 */ + { + TEST_INPUT("Test Using Larger Than Block-Size Key - " + "Hash Key First"), + "0x60E431591EE0B67F0D8A26AACBF5B77F8E0BC6213728C5" + "140546040F0EE37F54", + 1 + }, + /* Test 7 */ + { + TEST_INPUT("\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20" + "\x74\x65\x73\x74\x20\x75\x73\x69\x6e\x67" + "\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20" + "\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b" + "\x2d\x73\x69\x7a\x65\x20\x6b\x65\x79\x20" + "\x61\x6e\x64\x20\x61\x20\x6c\x61\x72\x67" + "\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c" + "\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x64" + "\x61\x74\x61\x2e\x20\x54\x68\x65\x20\x6b" + "\x65\x79\x20\x6e\x65\x65\x64\x73\x20\x74" + "\x6f\x20\x62\x65\x20\x68\x61\x73\x68\x65" + "\x64\x20\x62\x65\x66\x6f\x72\x65\x20\x62" + "\x65\x69\x6e\x67\x20\x75\x73\x65\x64\x20" + "\x62\x79\x20\x74\x68\x65\x20\x48\x4d\x41" + "\x43\x20\x61\x6c\x67\x6f\x72\x69\x74\x68" + "\x6d\x2e"), + "0x9B09FFA71B942FCB27635FBCD5B0E944BFDC63644F0713" + "938A7F51535C3A35E2", + 1 + }, + { NULL, 0, NULL, 1 } + }; + + hash_testcase_t *testcase = testcases; + + hash_test_key_t test_keys[] = { + /* Key 1 */ + { "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", 20 }, + /* Key 2 */ + { "Jefe", 4 }, + /* Key 3 */ + { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 20 }, + /* Key 4 */ + { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a" + "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14" + "\x15\x16\x17\x18\x19", 25 }, +#if 0 + /* Key 5 */ + { "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c" + "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c", 20 }, +#endif + /* Key 6 */ + { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 131 }, + /* Key 7 */ + { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 131 }, + { "", 0 } + }; + + hash_test_key_t *test_key = test_keys; + + while (testcase->input != NULL && testcase->result != NULL) { + memcpy(buffer, test_key->key, test_key->len); + isc_hmacsha256_init(&hmacsha256, buffer, test_key->len); + isc_hmacsha256_update(&hmacsha256, + (const isc_uint8_t *) testcase->input, + testcase->input_len); + isc_hmacsha256_sign(&hmacsha256, digest, ISC_SHA256_DIGESTLENGTH); + tohexstr(digest, ISC_SHA256_DIGESTLENGTH, str); + ATF_CHECK_STREQ(str, testcase->result); + + testcase++; + test_key++; + } +} + +/* HMAC-SHA384 test */ +ATF_TC(isc_hmacsha384); +ATF_TC_HEAD(isc_hmacsha384, tc) { + atf_tc_set_md_var(tc, "descr", "HMAC-SHA384 examples from RFC4634"); +} +ATF_TC_BODY(isc_hmacsha384, tc) { + isc_hmacsha384_t hmacsha384; + + UNUSED(tc); + + /* + * These are the various test vectors. All of these are passed + * through the hash function and the results are compared to the + * result specified here. + */ + hash_testcase_t testcases[] = { + /* Test 1 */ + { + TEST_INPUT("\x48\x69\x20\x54\x68\x65\x72\x65"), + "0xAFD03944D84895626B0825F4AB46907F15F9DADBE4101E" + "C682AA034C7CEBC59CFAEA9EA9076EDE7F4AF152" + "E8B2FA9CB6", + 1 + }, + /* Test 2 */ + { + TEST_INPUT("\x77\x68\x61\x74\x20\x64\x6f\x20\x79\x61" + "\x20\x77\x61\x6e\x74\x20\x66\x6f\x72\x20" + "\x6e\x6f\x74\x68\x69\x6e\x67\x3f"), + "0xAF45D2E376484031617F78D2B58A6B1B9C7EF464F5A01B" + "47E42EC3736322445E8E2240CA5E69E2C78B3239" + "ECFAB21649", + 1 + }, + /* Test 3 */ + { + TEST_INPUT("\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"), + "0x88062608D3E6AD8A0AA2ACE014C8A86F0AA635D947AC9F" + "EBE83EF4E55966144B2A5AB39DC13814B94E3AB6" + "E101A34F27", + 1 + }, + /* Test 4 */ + { + TEST_INPUT("\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"), + "0x3E8A69B7783C25851933AB6290AF6CA77A998148085000" + "9CC5577C6E1F573B4E6801DD23C4A7D679CCF8A3" + "86C674CFFB", + 1 + }, +#if 0 + /* Test 5 -- unimplemented optional functionality */ + { + TEST_INPUT("Test With Truncation"), + "0x4C1A03424B55E07FE7F27BE1", + 1 + }, +#endif + /* Test 6 */ + { + TEST_INPUT("Test Using Larger Than Block-Size Key - " + "Hash Key First"), + "0x4ECE084485813E9088D2C63A041BC5B44F9EF1012A2B58" + "8F3CD11F05033AC4C60C2EF6AB4030FE8296248D" + "F163F44952", + 1 + }, + /* Test 7 */ + { + TEST_INPUT("\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20" + "\x74\x65\x73\x74\x20\x75\x73\x69\x6e\x67" + "\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20" + "\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b" + "\x2d\x73\x69\x7a\x65\x20\x6b\x65\x79\x20" + "\x61\x6e\x64\x20\x61\x20\x6c\x61\x72\x67" + "\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c" + "\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x64" + "\x61\x74\x61\x2e\x20\x54\x68\x65\x20\x6b" + "\x65\x79\x20\x6e\x65\x65\x64\x73\x20\x74" + "\x6f\x20\x62\x65\x20\x68\x61\x73\x68\x65" + "\x64\x20\x62\x65\x66\x6f\x72\x65\x20\x62" + "\x65\x69\x6e\x67\x20\x75\x73\x65\x64\x20" + "\x62\x79\x20\x74\x68\x65\x20\x48\x4d\x41" + "\x43\x20\x61\x6c\x67\x6f\x72\x69\x74\x68" + "\x6d\x2e"), + "0x6617178E941F020D351E2F254E8FD32C602420FEB0B8FB" + "9ADCCEBB82461E99C5A678CC31E799176D3860E6" + "110C46523E", + 1 + }, + { NULL, 0, NULL, 1 } + }; + + hash_testcase_t *testcase = testcases; + + hash_test_key_t test_keys[] = { + /* Key 1 */ + { "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", 20 }, + /* Key 2 */ + { "Jefe", 4 }, + /* Key 3 */ + { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 20 }, + /* Key 4 */ + { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a" + "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14" + "\x15\x16\x17\x18\x19", 25 }, +#if 0 + /* Key 5 */ + { "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c" + "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c", 20 }, +#endif + /* Key 6 */ + { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 131 }, + /* Key 7 */ + { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 131 }, + { "", 0 } + }; + + hash_test_key_t *test_key = test_keys; + + while (testcase->input != NULL && testcase->result != NULL) { + memcpy(buffer, test_key->key, test_key->len); + isc_hmacsha384_init(&hmacsha384, buffer, test_key->len); + isc_hmacsha384_update(&hmacsha384, + (const isc_uint8_t *) testcase->input, + testcase->input_len); + isc_hmacsha384_sign(&hmacsha384, digest, ISC_SHA384_DIGESTLENGTH); + tohexstr(digest, ISC_SHA384_DIGESTLENGTH, str); + ATF_CHECK_STREQ(str, testcase->result); + + testcase++; + test_key++; + } +} + +/* HMAC-SHA512 test */ +ATF_TC(isc_hmacsha512); +ATF_TC_HEAD(isc_hmacsha512, tc) { + atf_tc_set_md_var(tc, "descr", "HMAC-SHA512 examples from RFC4634"); +} +ATF_TC_BODY(isc_hmacsha512, tc) { + isc_hmacsha512_t hmacsha512; + + UNUSED(tc); + + /* + * These are the various test vectors. All of these are passed + * through the hash function and the results are compared to the + * result specified here. + */ + hash_testcase_t testcases[] = { + /* Test 1 */ + { + TEST_INPUT("\x48\x69\x20\x54\x68\x65\x72\x65"), + "0x87AA7CDEA5EF619D4FF0B4241A1D6CB02379F4E2CE4EC2" + "787AD0B30545E17CDEDAA833B7D6B8A702038B27" + "4EAEA3F4E4BE9D914EEB61F1702E696C203A126854", + 1 + }, + /* Test 2 */ + { + TEST_INPUT("\x77\x68\x61\x74\x20\x64\x6f\x20\x79\x61" + "\x20\x77\x61\x6e\x74\x20\x66\x6f\x72\x20" + "\x6e\x6f\x74\x68\x69\x6e\x67\x3f"), + "0x164B7A7BFCF819E2E395FBE73B56E0A387BD64222E831F" + "D610270CD7EA2505549758BF75C05A994A6D034F" + "65F8F0E6FDCAEAB1A34D4A6B4B636E070A38BCE737", + 1 + }, + /* Test 3 */ + { + TEST_INPUT("\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"), + "0xFA73B0089D56A284EFB0F0756C890BE9B1B5DBDD8EE81A" + "3655F83E33B2279D39BF3E848279A722C806B485" + "A47E67C807B946A337BEE8942674278859E13292FB", + 1 + }, + /* Test 4 */ + { + TEST_INPUT("\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"), + "0xB0BA465637458C6990E5A8C5F61D4AF7E576D97FF94B87" + "2DE76F8050361EE3DBA91CA5C11AA25EB4D67927" + "5CC5788063A5F19741120C4F2DE2ADEBEB10A298DD", + 1 + }, +#if 0 + /* Test 5 -- unimplemented optional functionality */ + { + TEST_INPUT("Test With Truncation"), + "0x4C1A03424B55E07FE7F27BE1", + 1 + }, +#endif + /* Test 6 */ + { + TEST_INPUT("Test Using Larger Than Block-Size Key - " + "Hash Key First"), + "0x80B24263C7C1A3EBB71493C1DD7BE8B49B46D1F41B4AEE" + "C1121B013783F8F3526B56D037E05F2598BD0FD2" + "215D6A1E5295E64F73F63F0AEC8B915A985D786598", + 1 + }, + /* Test 7 */ + { + TEST_INPUT("\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20" + "\x74\x65\x73\x74\x20\x75\x73\x69\x6e\x67" + "\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20" + "\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b" + "\x2d\x73\x69\x7a\x65\x20\x6b\x65\x79\x20" + "\x61\x6e\x64\x20\x61\x20\x6c\x61\x72\x67" + "\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c" + "\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x64" + "\x61\x74\x61\x2e\x20\x54\x68\x65\x20\x6b" + "\x65\x79\x20\x6e\x65\x65\x64\x73\x20\x74" + "\x6f\x20\x62\x65\x20\x68\x61\x73\x68\x65" + "\x64\x20\x62\x65\x66\x6f\x72\x65\x20\x62" + "\x65\x69\x6e\x67\x20\x75\x73\x65\x64\x20" + "\x62\x79\x20\x74\x68\x65\x20\x48\x4d\x41" + "\x43\x20\x61\x6c\x67\x6f\x72\x69\x74\x68" + "\x6d\x2e"), + "0xE37B6A775DC87DBAA4DFA9F96E5E3FFDDEBD71F8867289" + "865DF5A32D20CDC944B6022CAC3C4982B10D5EEB" + "55C3E4DE15134676FB6DE0446065C97440FA8C6A58", + 1 + }, + { NULL, 0, NULL, 1 } + }; + + hash_testcase_t *testcase = testcases; + + hash_test_key_t test_keys[] = { + /* Key 1 */ + { "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", 20 }, + /* Key 2 */ + { "Jefe", 4 }, + /* Key 3 */ + { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 20 }, + /* Key 4 */ + { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a" + "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14" + "\x15\x16\x17\x18\x19", 25 }, +#if 0 + /* Key 5 */ + { "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c" + "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c", 20 }, +#endif + /* Key 6 */ + { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 131 }, + /* Key 7 */ + { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 131 }, + { "", 0 } + }; + + hash_test_key_t *test_key = test_keys; + + while (testcase->input != NULL && testcase->result != NULL) { + memcpy(buffer, test_key->key, test_key->len); + isc_hmacsha512_init(&hmacsha512, buffer, test_key->len); + isc_hmacsha512_update(&hmacsha512, + (const isc_uint8_t *) testcase->input, + testcase->input_len); + isc_hmacsha512_sign(&hmacsha512, digest, ISC_SHA512_DIGESTLENGTH); + tohexstr(digest, ISC_SHA512_DIGESTLENGTH, str); + ATF_CHECK_STREQ(str, testcase->result); + + testcase++; + test_key++; + } +} + + +/* HMAC-MD5 Test */ +ATF_TC(isc_hmacmd5); +ATF_TC_HEAD(isc_hmacmd5, tc) { + atf_tc_set_md_var(tc, "descr", "HMAC-MD5 examples from RFC2104"); +} +ATF_TC_BODY(isc_hmacmd5, tc) { + isc_hmacmd5_t hmacmd5; + + UNUSED(tc); + + /* + * These are the various test vectors. All of these are passed + * through the hash function and the results are compared to the + * result specified here. + */ + hash_testcase_t testcases[] = { + /* Test 1 */ + { + TEST_INPUT("\x48\x69\x20\x54\x68\x65\x72\x65"), + "0x9294727A3638BB1C13F48EF8158BFC9D", + 1 + }, + /* Test 2 */ + { + TEST_INPUT("\x77\x68\x61\x74\x20\x64\x6f\x20\x79" + "\x61\x20\x77\x61\x6e\x74\x20\x66\x6f" + "\x72\x20\x6e\x6f\x74\x68\x69\x6e\x67\x3f"), + "0x750C783E6AB0B503EAA86E310A5DB738", 1 + }, + /* Test 3 */ + { + TEST_INPUT("\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"), + "0x56BE34521D144C88DBB8C733F0E8B3F6", + 1 + }, + /* Test 4 */ + { + TEST_INPUT("\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd"), + "0x697EAF0ACA3A3AEA3A75164746FFAA79", + 1 + }, +#if 0 + /* Test 5 -- unimplemented optional functionality */ + { + TEST_INPUT("Test With Truncation"), + "0x4C1A03424B55E07FE7F27BE1", + 1 + }, + /* Test 6 -- unimplemented optional functionality */ + { + TEST_INPUT("Test Using Larger Than Block-Size Key - " + "Hash Key First"), + "0xAA4AE5E15272D00E95705637CE8A3B55ED402112", + 1 + }, + /* Test 7 -- unimplemented optional functionality */ + { + TEST_INPUT("Test Using Larger Than Block-Size Key and " + "Larger Than One Block-Size Data"), + "0xE8E99D0F45237D786D6BBAA7965C7808BBFF1A91", + 1 + }, +#endif + { NULL, 0, NULL, 1 } + }; + + hash_testcase_t *testcase = testcases; + + hash_test_key_t test_keys[] = { + /* Key 1 */ + { "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" + "\x0b\x0b\x0b\x0b\x0b\x0b", 16 }, + /* Key 2 */ + { "Jefe", 4 }, + /* Key 3 */ + { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa", 16 }, + /* Key 4 */ + { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a" + "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14" + "\x15\x16\x17\x18\x19", 25 }, +#if 0 + /* Key 5 */ + { "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c" + "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c", 20 }, + /* Key 6 */ + { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 131 }, + /* Key 7 */ + { "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 131 }, +#endif + { "", 0 } + }; + + hash_test_key_t *test_key = test_keys; + + while (testcase->input != NULL && testcase->result != NULL) { + memcpy(buffer, test_key->key, test_key->len); + isc_hmacmd5_init(&hmacmd5, buffer, test_key->len); + isc_hmacmd5_update(&hmacmd5, + (const isc_uint8_t *) testcase->input, + testcase->input_len); + isc_hmacmd5_sign(&hmacmd5, digest); + tohexstr(digest, ISC_MD5_DIGESTLENGTH, str); + ATF_CHECK_STREQ(str, testcase->result); + + testcase++; + test_key++; + } +} + +/* + * Main + */ +ATF_TP_ADD_TCS(tp) { + ATF_TP_ADD_TC(tp, isc_hmacmd5); + ATF_TP_ADD_TC(tp, isc_hmacsha1); + ATF_TP_ADD_TC(tp, isc_hmacsha224); + ATF_TP_ADD_TC(tp, isc_hmacsha256); + ATF_TP_ADD_TC(tp, isc_hmacsha384); + ATF_TP_ADD_TC(tp, isc_hmacsha512); + ATF_TP_ADD_TC(tp, isc_md5); + ATF_TP_ADD_TC(tp, isc_sha1); + ATF_TP_ADD_TC(tp, isc_sha224); + ATF_TP_ADD_TC(tp, isc_sha256); + ATF_TP_ADD_TC(tp, isc_sha384); + ATF_TP_ADD_TC(tp, isc_sha512); + return (atf_no_error()); +} + diff --git a/contrib/ntp/lib/isc/tests/isctest.c b/contrib/ntp/lib/isc/tests/isctest.c new file mode 100644 index 0000000..e118bbf --- /dev/null +++ b/contrib/ntp/lib/isc/tests/isctest.c @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/*! \file */ + +#include <config.h> + +#include <time.h> + +#include <isc/app.h> +#include <isc/buffer.h> +#include <isc/entropy.h> +#include <isc/hash.h> +#include <isc/mem.h> +#include <isc/os.h> +#include <isc/socket.h> +#include <isc/string.h> +#include <isc/task.h> +#include <isc/timer.h> +#include <isc/util.h> + +#include "isctest.h" + +isc_mem_t *mctx = NULL; +isc_entropy_t *ectx = NULL; +isc_log_t *lctx = NULL; +isc_taskmgr_t *taskmgr = NULL; +isc_timermgr_t *timermgr = NULL; +isc_socketmgr_t *socketmgr = NULL; +int ncpus; + +static isc_boolean_t hash_active = ISC_FALSE; + +/* + * Logging categories: this needs to match the list in bin/named/log.c. + */ +static isc_logcategory_t categories[] = { + { "", 0 }, + { "client", 0 }, + { "network", 0 }, + { "update", 0 }, + { "queries", 0 }, + { "unmatched", 0 }, + { "update-security", 0 }, + { "query-errors", 0 }, + { NULL, 0 } +}; + +static void +cleanup_managers() { + if (socketmgr != NULL) + isc_socketmgr_destroy(&socketmgr); + if (taskmgr != NULL) + isc_taskmgr_destroy(&taskmgr); + if (timermgr != NULL) + isc_timermgr_destroy(&timermgr); +} + +static isc_result_t +create_managers() { + isc_result_t result; +#ifdef ISC_PLATFORM_USETHREADS + ncpus = isc_os_ncpus(); +#else + ncpus = 1; +#endif + + CHECK(isc_taskmgr_create(mctx, ncpus, 0, &taskmgr)); + CHECK(isc_timermgr_create(mctx, &timermgr)); + CHECK(isc_socketmgr_create(mctx, &socketmgr)); + return (ISC_R_SUCCESS); + + cleanup: + cleanup_managers(); + return (result); +} + +isc_result_t +isc_test_begin(FILE *logfile, isc_boolean_t start_managers) { + isc_result_t result; + + isc_mem_debugging |= ISC_MEM_DEBUGRECORD; + CHECK(isc_mem_create(0, 0, &mctx)); + CHECK(isc_entropy_create(mctx, &ectx)); + + CHECK(isc_hash_create(mctx, ectx, 255)); + hash_active = ISC_TRUE; + + if (logfile != NULL) { + isc_logdestination_t destination; + isc_logconfig_t *logconfig = NULL; + + CHECK(isc_log_create(mctx, &lctx, &logconfig)); + isc_log_registercategories(lctx, categories); + isc_log_setcontext(lctx); + + destination.file.stream = logfile; + destination.file.name = NULL; + destination.file.versions = ISC_LOG_ROLLNEVER; + destination.file.maximum_size = 0; + CHECK(isc_log_createchannel(logconfig, "stderr", + ISC_LOG_TOFILEDESC, + ISC_LOG_DYNAMIC, + &destination, 0)); + CHECK(isc_log_usechannel(logconfig, "stderr", NULL, NULL)); + } + +#ifdef ISC_PLATFORM_USETHREADS + ncpus = isc_os_ncpus(); +#else + ncpus = 1; +#endif + + if (start_managers) + CHECK(create_managers()); + + return (ISC_R_SUCCESS); + + cleanup: + isc_test_end(); + return (result); +} + +void +isc_test_end() { + if (taskmgr != NULL) + isc_taskmgr_destroy(&taskmgr); + if (lctx != NULL) + isc_log_destroy(&lctx); + if (hash_active) { + isc_hash_destroy(); + hash_active = ISC_FALSE; + } + if (ectx != NULL) + isc_entropy_detach(&ectx); + + cleanup_managers(); + + if (mctx != NULL) + isc_mem_destroy(&mctx); +} + +/* + * Sleep for 'usec' microseconds. + */ +void +isc_test_nap(isc_uint32_t usec) { +#ifdef HAVE_NANOSLEEP + struct timespec ts; + + ts.tv_sec = usec / 1000000; + ts.tv_nsec = (usec % 1000000) * 1000; + nanosleep(&ts, NULL); +#elif HAVE_USLEEP + usleep(usec); +#else + /* + * No fractional-second sleep function is available, so we + * round up to the nearest second and sleep instead + */ + sleep((usec / 1000000) + 1); +#endif +} diff --git a/contrib/ntp/lib/isc/tests/isctest.h b/contrib/ntp/lib/isc/tests/isctest.h new file mode 100644 index 0000000..03423c8 --- /dev/null +++ b/contrib/ntp/lib/isc/tests/isctest.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/*! \file */ + +#include <config.h> + +#include <isc/buffer.h> +#include <isc/entropy.h> +#include <isc/hash.h> +#include <isc/log.h> +#include <isc/mem.h> +#include <isc/print.h> +#include <isc/result.h> +#include <isc/string.h> +#include <isc/task.h> +#include <isc/timer.h> +#include <isc/util.h> + +#define CHECK(r) \ + do { \ + result = (r); \ + if (result != ISC_R_SUCCESS) \ + goto cleanup; \ + } while (0) + +extern isc_mem_t *mctx; +extern isc_entropy_t *ectx; +extern isc_log_t *lctx; +extern isc_taskmgr_t *taskmgr; +isc_timermgr_t *timermgr; +isc_socketmgr_t *socketmgr; +extern int ncpus; + +isc_result_t +isc_test_begin(FILE *logfile, isc_boolean_t start_managers); + +void +isc_test_end(void); + +void +isc_test_nap(isc_uint32_t usec); diff --git a/contrib/ntp/lib/isc/tests/queue_test.c b/contrib/ntp/lib/isc/tests/queue_test.c new file mode 100644 index 0000000..74620fe --- /dev/null +++ b/contrib/ntp/lib/isc/tests/queue_test.c @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/*! \file */ + +#include <config.h> + +#include <atf-c.h> + +#include <unistd.h> +#include <time.h> + +#include <isc/queue.h> + +#include "isctest.h" + +typedef struct item { + int value; + ISC_QLINK(item_t) qlink; +} item_t; + +typedef ISC_QUEUE(item_t) item_queue_t; + +static void +item_init(item_t *item, int value) { + item->value = value; + ISC_QLINK_INIT(item, qlink); +} + +/* + * Individual unit tests + */ + +/* Test UDP sendto/recv (IPv4) */ +ATF_TC(queue_valid); +ATF_TC_HEAD(queue_valid, tc) { + atf_tc_set_md_var(tc, "descr", "Check queue validity"); +} +ATF_TC_BODY(queue_valid, tc) { + isc_result_t result; + item_queue_t queue; + item_t one, two, three, four, five; + item_t *p; + + UNUSED(tc); + + ISC_QUEUE_INIT(queue, qlink); + + item_init(&one, 1); + item_init(&two, 2); + item_init(&three, 3); + item_init(&four, 4); + item_init(&five, 5); + + result = isc_test_begin(NULL, ISC_TRUE); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + ATF_CHECK(ISC_QUEUE_EMPTY(queue)); + + ISC_QUEUE_POP(queue, qlink, p); + ATF_CHECK(p == NULL); + + ATF_CHECK(! ISC_QLINK_LINKED(&one, qlink)); + ISC_QUEUE_PUSH(queue, &one, qlink); + ATF_CHECK(ISC_QLINK_LINKED(&one, qlink)); + + ATF_CHECK(! ISC_QUEUE_EMPTY(queue)); + + ISC_QUEUE_POP(queue, qlink, p); + ATF_REQUIRE(p != NULL); + ATF_CHECK_EQ(p->value, 1); + ATF_CHECK(ISC_QUEUE_EMPTY(queue)); + ATF_CHECK(! ISC_QLINK_LINKED(p, qlink)); + + ISC_QUEUE_PUSH(queue, p, qlink); + ATF_CHECK(! ISC_QUEUE_EMPTY(queue)); + ATF_CHECK(ISC_QLINK_LINKED(p, qlink)); + + ATF_CHECK(! ISC_QLINK_LINKED(&two, qlink)); + ISC_QUEUE_PUSH(queue, &two, qlink); + ATF_CHECK(ISC_QLINK_LINKED(&two, qlink)); + + ATF_CHECK(! ISC_QLINK_LINKED(&three, qlink)); + ISC_QUEUE_PUSH(queue, &three, qlink); + ATF_CHECK(ISC_QLINK_LINKED(&three, qlink)); + + ATF_CHECK(! ISC_QLINK_LINKED(&four, qlink)); + ISC_QUEUE_PUSH(queue, &four, qlink); + ATF_CHECK(ISC_QLINK_LINKED(&four, qlink)); + + ATF_CHECK(! ISC_QLINK_LINKED(&five, qlink)); + ISC_QUEUE_PUSH(queue, &five, qlink); + ATF_CHECK(ISC_QLINK_LINKED(&five, qlink)); + + ISC_QUEUE_POP(queue, qlink, p); + ATF_REQUIRE(p != NULL); + ATF_CHECK_EQ(p->value, 1); + + ISC_QUEUE_POP(queue, qlink, p); + ATF_REQUIRE(p != NULL); + ATF_CHECK_EQ(p->value, 2); + + ISC_QUEUE_POP(queue, qlink, p); + ATF_REQUIRE(p != NULL); + ATF_CHECK_EQ(p->value, 3); + + ISC_QUEUE_POP(queue, qlink, p); + ATF_REQUIRE(p != NULL); + ATF_CHECK_EQ(p->value, 4); + + ISC_QUEUE_POP(queue, qlink, p); + ATF_REQUIRE(p != NULL); + ATF_CHECK_EQ(p->value, 5); + + ATF_CHECK(ISC_QUEUE_EMPTY(queue)); + + ISC_QUEUE_DESTROY(queue); + isc_test_end(); +} + +/* + * Main + */ +ATF_TP_ADD_TCS(tp) { + ATF_TP_ADD_TC(tp, queue_valid); + + return (atf_no_error()); +} + diff --git a/contrib/ntp/lib/isc/tests/socket_test.c b/contrib/ntp/lib/isc/tests/socket_test.c new file mode 100644 index 0000000..724d79d --- /dev/null +++ b/contrib/ntp/lib/isc/tests/socket_test.c @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/*! \file */ + +#include <config.h> + +#include <atf-c.h> + +#include <unistd.h> +#include <time.h> + +#include <isc/socket.h> + +#include "../task_p.h" +#include "isctest.h" + +/* + * Helper functions + */ +typedef struct { + isc_boolean_t done; + isc_result_t result; +} completion_t; + +static void +completion_init(completion_t *completion) { + completion->done = ISC_FALSE; +} + +static void +event_done(isc_task_t *task, isc_event_t *event) { + isc_socketevent_t *dev; + completion_t *completion = event->ev_arg; + + UNUSED(task); + + dev = (isc_socketevent_t *) event; + completion->result = dev->result; + completion->done = ISC_TRUE; + isc_event_free(&event); +} + +static isc_result_t +waitfor(completion_t *completion) { + int i = 0; + while (!completion->done && i++ < 5000) { +#ifndef ISC_PLATFORM_USETHREADS + while (isc__taskmgr_ready(taskmgr)) + isc__taskmgr_dispatch(taskmgr); +#endif + isc_test_nap(1000); + } + if (completion->done) + return (ISC_R_SUCCESS); + return (ISC_R_FAILURE); +} + +/* + * Individual unit tests + */ + +/* Test UDP sendto/recv (IPv4) */ +ATF_TC(udp_sendto); +ATF_TC_HEAD(udp_sendto, tc) { + atf_tc_set_md_var(tc, "descr", "UDP sendto/recv"); +} +ATF_TC_BODY(udp_sendto, tc) { + isc_result_t result; + isc_sockaddr_t addr1, addr2; + struct in_addr in; + isc_socket_t *s1 = NULL, *s2 = NULL; + isc_task_t *task = NULL; + char sendbuf[BUFSIZ], recvbuf[BUFSIZ]; + completion_t completion; + isc_region_t r; + + UNUSED(tc); + + result = isc_test_begin(NULL, ISC_TRUE); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + /* + * Create two sockets: 127.0.0.1/5444 and 127.0.0.1/5445, talking to + * each other. + */ + in.s_addr = inet_addr("127.0.0.1"); + isc_sockaddr_fromin(&addr1, &in, 5444); + isc_sockaddr_fromin(&addr2, &in, 5445); + + result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, &s1); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + result = isc_socket_bind(s1, &addr1, ISC_SOCKET_REUSEADDRESS); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, &s2); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + result = isc_socket_bind(s2, &addr2, ISC_SOCKET_REUSEADDRESS); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = isc_task_create(taskmgr, 0, &task); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + strcpy(sendbuf, "Hello"); + r.base = (void *) sendbuf; + r.length = strlen(sendbuf) + 1; + + completion_init(&completion); + result = isc_socket_sendto(s1, &r, task, event_done, &completion, + &addr2, NULL); + ATF_CHECK_EQ(result, ISC_R_SUCCESS); + waitfor(&completion); + ATF_CHECK(completion.done); + ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS); + + r.base = (void *) recvbuf; + r.length = BUFSIZ; + completion_init(&completion); + result = isc_socket_recv(s2, &r, 1, task, event_done, &completion); + ATF_CHECK_EQ(result, ISC_R_SUCCESS); + waitfor(&completion); + ATF_CHECK(completion.done); + ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS); + ATF_CHECK_STREQ(recvbuf, "Hello"); + + isc_task_detach(&task); + + isc_socket_detach(&s1); + isc_socket_detach(&s2); + + isc_test_end(); +} + +/* Test UDP sendto/recv with duplicated socket */ +ATF_TC(udp_dup); +ATF_TC_HEAD(udp_dup, tc) { + atf_tc_set_md_var(tc, "descr", "duplicated socket sendto/recv"); +} +ATF_TC_BODY(udp_dup, tc) { + isc_result_t result; + isc_sockaddr_t addr1, addr2; + struct in_addr in; + isc_socket_t *s1 = NULL, *s2 = NULL, *s3 = NULL; + isc_task_t *task = NULL; + char sendbuf[BUFSIZ], recvbuf[BUFSIZ]; + completion_t completion; + isc_region_t r; + + UNUSED(tc); + + result = isc_test_begin(NULL, ISC_TRUE); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + /* + * Create two sockets: 127.0.0.1/5444 and 127.0.0.1/5445, talking to + * each other. + */ + in.s_addr = inet_addr("127.0.0.1"); + isc_sockaddr_fromin(&addr1, &in, 5444); + isc_sockaddr_fromin(&addr2, &in, 5445); + + result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, &s1); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + result = isc_socket_bind(s1, &addr1, ISC_SOCKET_REUSEADDRESS); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, &s2); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + result = isc_socket_bind(s2, &addr2, ISC_SOCKET_REUSEADDRESS); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = isc_socket_dup(s2, &s3); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = isc_task_create(taskmgr, 0, &task); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + strcpy(sendbuf, "Hello"); + r.base = (void *) sendbuf; + r.length = strlen(sendbuf) + 1; + + completion_init(&completion); + result = isc_socket_sendto(s1, &r, task, event_done, &completion, + &addr2, NULL); + ATF_CHECK_EQ(result, ISC_R_SUCCESS); + waitfor(&completion); + ATF_CHECK(completion.done); + ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS); + + strcpy(sendbuf, "World"); + r.base = (void *) sendbuf; + r.length = strlen(sendbuf) + 1; + + completion_init(&completion); + result = isc_socket_sendto(s1, &r, task, event_done, &completion, + &addr2, NULL); + ATF_CHECK_EQ(result, ISC_R_SUCCESS); + waitfor(&completion); + ATF_CHECK(completion.done); + ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS); + + r.base = (void *) recvbuf; + r.length = BUFSIZ; + completion_init(&completion); + result = isc_socket_recv(s2, &r, 1, task, event_done, &completion); + ATF_CHECK_EQ(result, ISC_R_SUCCESS); + waitfor(&completion); + ATF_CHECK(completion.done); + ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS); + ATF_CHECK_STREQ(recvbuf, "Hello"); + + r.base = (void *) recvbuf; + r.length = BUFSIZ; + completion_init(&completion); + result = isc_socket_recv(s3, &r, 1, task, event_done, &completion); + ATF_CHECK_EQ(result, ISC_R_SUCCESS); + waitfor(&completion); + ATF_CHECK(completion.done); + ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS); + ATF_CHECK_STREQ(recvbuf, "World"); + + isc_task_detach(&task); + + isc_socket_detach(&s1); + isc_socket_detach(&s2); + isc_socket_detach(&s3); + + isc_test_end(); +} + +/* + * Main + */ +ATF_TP_ADD_TCS(tp) { + ATF_TP_ADD_TC(tp, udp_sendto); + ATF_TP_ADD_TC(tp, udp_dup); + + return (atf_no_error()); +} + diff --git a/contrib/ntp/lib/isc/tests/symtab_test.c b/contrib/ntp/lib/isc/tests/symtab_test.c new file mode 100644 index 0000000..21444b4 --- /dev/null +++ b/contrib/ntp/lib/isc/tests/symtab_test.c @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/*! \file */ + +#include <config.h> + +#include <atf-c.h> + +#include <unistd.h> + +#include <isc/symtab.h> +#include <isc/print.h> + +#include "isctest.h" + +static void +undefine(char *key, unsigned int type, isc_symvalue_t value, void *arg) { + UNUSED(arg); + + ATF_REQUIRE_EQ(type, 1); + isc_mem_free(mctx, key); + isc_mem_free(mctx, value.as_pointer); +} + +/* + * Individual unit tests + */ + +ATF_TC(symtab_grow); +ATF_TC_HEAD(symtab_grow, tc) { + atf_tc_set_md_var(tc, "descr", "symbol table growth"); +} +ATF_TC_BODY(symtab_grow, tc) { + isc_result_t result; + isc_symtab_t *st = NULL; + isc_symvalue_t value; + isc_symexists_t policy = isc_symexists_reject; + int i; + + UNUSED(tc); + + result = isc_test_begin(NULL, ISC_TRUE); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = isc_symtab_create(mctx, 3, undefine, NULL, ISC_FALSE, &st); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + ATF_REQUIRE(st != NULL); + + /* Nothing should be in the table yet */ + + /* + * Put 1024 entries in the table (this should necessate + * regrowing the hash table several times + */ + for (i = 0; i < 1024; i++) { + char str[16], *key; + + snprintf(str, sizeof(str), "%04x", i); + key = isc_mem_strdup(mctx, str); + ATF_REQUIRE(key != NULL); + value.as_pointer = isc_mem_strdup(mctx, str); + ATF_REQUIRE(value.as_pointer != NULL); + result = isc_symtab_define(st, key, 1, value, policy); + ATF_CHECK_EQ(result, ISC_R_SUCCESS); + if (result != ISC_R_SUCCESS) + undefine(key, 1, value, NULL); + } + + /* + * Try to put them in again; this should fail + */ + for (i = 0; i < 1024; i++) { + char str[16], *key; + + snprintf(str, sizeof(str), "%04x", i); + key = isc_mem_strdup(mctx, str); + ATF_REQUIRE(key != NULL); + value.as_pointer = isc_mem_strdup(mctx, str); + ATF_REQUIRE(value.as_pointer != NULL); + result = isc_symtab_define(st, key, 1, value, policy); + ATF_CHECK_EQ(result, ISC_R_EXISTS); + undefine(key, 1, value, NULL); + } + + /* + * Retrieve them; this should succeed + */ + for (i = 0; i < 1024; i++) { + char str[16]; + + snprintf(str, sizeof(str), "%04x", i); + result = isc_symtab_lookup(st, str, 0, &value); + ATF_CHECK_EQ(result, ISC_R_SUCCESS); + ATF_CHECK_STREQ(str, value.as_pointer); + } + + /* + * Undefine them + */ + for (i = 0; i < 1024; i++) { + char str[16]; + + snprintf(str, sizeof(str), "%04x", i); + result = isc_symtab_undefine(st, str, 1); + ATF_CHECK_EQ(result, ISC_R_SUCCESS); + } + + /* + * Retrieve them again; this should fail + */ + for (i = 0; i < 1024; i++) { + char str[16]; + + snprintf(str, sizeof(str), "%04x", i); + result = isc_symtab_lookup(st, str, 0, &value); + ATF_CHECK_EQ(result, ISC_R_NOTFOUND); + } + + isc_symtab_destroy(&st); + isc_test_end(); +} + +/* + * Main + */ +ATF_TP_ADD_TCS(tp) { + ATF_TP_ADD_TC(tp, symtab_grow); + + return (atf_no_error()); +} + diff --git a/contrib/ntp/lib/isc/tests/task_test.c b/contrib/ntp/lib/isc/tests/task_test.c new file mode 100644 index 0000000..7294d86 --- /dev/null +++ b/contrib/ntp/lib/isc/tests/task_test.c @@ -0,0 +1,416 @@ +/* + * Copyright (C) 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/*! \file */ + +#include <config.h> + +#include <atf-c.h> + +#include <unistd.h> + +#include <isc/task.h> +#include <isc/util.h> + +#include "../task_p.h" +#include "isctest.h" + +/* + * Helper functions + */ + +/* task event handler, sets a boolean to true */ +int counter = 0; +isc_mutex_t set_lock; + +static void +set(isc_task_t *task, isc_event_t *event) { + int *value = (int *) event->ev_arg; + + UNUSED(task); + + isc_event_free(&event); + LOCK(&set_lock); + *value = counter++; + UNLOCK(&set_lock); +} + +static void +set_and_drop(isc_task_t *task, isc_event_t *event) { + int *value = (int *) event->ev_arg; + + UNUSED(task); + + isc_event_free(&event); + LOCK(&set_lock); + *value = (int) isc_taskmgr_mode(taskmgr); + counter++; + UNLOCK(&set_lock); + isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_normal); +} + +/* + * Individual unit tests + */ + +/* Create a task */ +ATF_TC(create_task); +ATF_TC_HEAD(create_task, tc) { + atf_tc_set_md_var(tc, "descr", "create and destroy a task"); +} +ATF_TC_BODY(create_task, tc) { + isc_result_t result; + isc_task_t *task = NULL; + + UNUSED(tc); + + result = isc_test_begin(NULL, ISC_TRUE); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = isc_task_create(taskmgr, 0, &task); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + isc_task_destroy(&task); + ATF_REQUIRE_EQ(task, NULL); + + isc_test_end(); +} + +/* Process events */ +ATF_TC(all_events); +ATF_TC_HEAD(all_events, tc) { + atf_tc_set_md_var(tc, "descr", "process task events"); +} +ATF_TC_BODY(all_events, tc) { + isc_result_t result; + isc_task_t *task = NULL; + isc_event_t *event; + int a = 0, b = 0; + int i = 0; + + UNUSED(tc); + + counter = 1; + + result = isc_mutex_init(&set_lock); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = isc_test_begin(NULL, ISC_TRUE); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = isc_task_create(taskmgr, 0, &task); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + /* First event */ + event = isc_event_allocate(mctx, task, ISC_TASKEVENT_TEST, + set, &a, sizeof (isc_event_t)); + ATF_REQUIRE(event != NULL); + + ATF_CHECK_EQ(a, 0); + isc_task_send(task, &event); + + event = isc_event_allocate(mctx, task, ISC_TASKEVENT_TEST, + set, &b, sizeof (isc_event_t)); + ATF_REQUIRE(event != NULL); + + ATF_CHECK_EQ(b, 0); + isc_task_send(task, &event); + + while ((a == 0 || b == 0) && i++ < 5000) { +#ifndef ISC_PLATFORM_USETHREADS + while (isc__taskmgr_ready(taskmgr)) + isc__taskmgr_dispatch(taskmgr); +#endif + isc_test_nap(1000); + } + + ATF_CHECK(a != 0); + ATF_CHECK(b != 0); + + isc_task_destroy(&task); + ATF_REQUIRE_EQ(task, NULL); + + isc_test_end(); +} + +/* Privileged events */ +ATF_TC(privileged_events); +ATF_TC_HEAD(privileged_events, tc) { + atf_tc_set_md_var(tc, "descr", "process privileged events"); +} +ATF_TC_BODY(privileged_events, tc) { + isc_result_t result; + isc_task_t *task1 = NULL, *task2 = NULL; + isc_event_t *event; + int a = 0, b = 0, c = 0, d = 0, e = 0; + int i = 0; + + UNUSED(tc); + + counter = 1; + result = isc_mutex_init(&set_lock); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = isc_test_begin(NULL, ISC_TRUE); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + +#ifdef ISC_PLATFORM_USETHREADS + /* + * Pause the task manager so we can fill up the work queue + * without things happening while we do it. + */ + isc__taskmgr_pause(taskmgr); +#endif + + result = isc_task_create(taskmgr, 0, &task1); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + isc_task_setname(task1, "privileged", NULL); + ATF_CHECK(!isc_task_privilege(task1)); + isc_task_setprivilege(task1, ISC_TRUE); + ATF_CHECK(isc_task_privilege(task1)); + + result = isc_task_create(taskmgr, 0, &task2); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + isc_task_setname(task2, "normal", NULL); + ATF_CHECK(!isc_task_privilege(task2)); + + /* First event: privileged */ + event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST, + set, &a, sizeof (isc_event_t)); + ATF_REQUIRE(event != NULL); + + ATF_CHECK_EQ(a, 0); + isc_task_send(task1, &event); + + /* Second event: not privileged */ + event = isc_event_allocate(mctx, task2, ISC_TASKEVENT_TEST, + set, &b, sizeof (isc_event_t)); + ATF_REQUIRE(event != NULL); + + ATF_CHECK_EQ(b, 0); + isc_task_send(task2, &event); + + /* Third event: privileged */ + event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST, + set, &c, sizeof (isc_event_t)); + ATF_REQUIRE(event != NULL); + + ATF_CHECK_EQ(c, 0); + isc_task_send(task1, &event); + + /* Fourth event: privileged */ + event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST, + set, &d, sizeof (isc_event_t)); + ATF_REQUIRE(event != NULL); + + ATF_CHECK_EQ(d, 0); + isc_task_send(task1, &event); + + /* Fifth event: not privileged */ + event = isc_event_allocate(mctx, task2, ISC_TASKEVENT_TEST, + set, &e, sizeof (isc_event_t)); + ATF_REQUIRE(event != NULL); + + ATF_CHECK_EQ(e, 0); + isc_task_send(task2, &event); + + ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_normal); + isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_privileged); + ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_privileged); + +#ifdef ISC_PLATFORM_USETHREADS + isc__taskmgr_resume(taskmgr); +#endif + + /* We're waiting for *all* variables to be set */ + while ((a == 0 || b == 0 || c == 0 || d == 0 || e == 0) && i++ < 5000) { +#ifndef ISC_PLATFORM_USETHREADS + while (isc__taskmgr_ready(taskmgr)) + isc__taskmgr_dispatch(taskmgr); +#endif + isc_test_nap(1000); + } + + /* + * We can't guarantee what order the events fire, but + * we do know the privileged tasks that set a, c, and d + * would have fired first. + */ + ATF_CHECK(a <= 3); + ATF_CHECK(c <= 3); + ATF_CHECK(d <= 3); + + /* ...and the non-privileged tasks that set b and e, last */ + ATF_CHECK(b >= 4); + ATF_CHECK(e >= 4); + + ATF_CHECK_EQ(counter, 6); + + isc_task_setprivilege(task1, ISC_FALSE); + ATF_CHECK(!isc_task_privilege(task1)); + + ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_normal); + + isc_task_destroy(&task1); + ATF_REQUIRE_EQ(task1, NULL); + isc_task_destroy(&task2); + ATF_REQUIRE_EQ(task2, NULL); + + isc_test_end(); +} + +/* + * Edge case: this tests that the task manager behaves as expected when + * we explicitly set it into normal mode *while* running privileged. + */ +ATF_TC(privilege_drop); +ATF_TC_HEAD(privilege_drop, tc) { + atf_tc_set_md_var(tc, "descr", "process privileged events"); +} +ATF_TC_BODY(privilege_drop, tc) { + isc_result_t result; + isc_task_t *task1 = NULL, *task2 = NULL; + isc_event_t *event; + int a = -1, b = -1, c = -1, d = -1, e = -1; /* non valid states */ + int i = 0; + + UNUSED(tc); + + counter = 1; + result = isc_mutex_init(&set_lock); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = isc_test_begin(NULL, ISC_TRUE); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + +#ifdef ISC_PLATFORM_USETHREADS + /* + * Pause the task manager so we can fill up the work queue + * without things happening while we do it. + */ + isc__taskmgr_pause(taskmgr); +#endif + + result = isc_task_create(taskmgr, 0, &task1); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + isc_task_setname(task1, "privileged", NULL); + ATF_CHECK(!isc_task_privilege(task1)); + isc_task_setprivilege(task1, ISC_TRUE); + ATF_CHECK(isc_task_privilege(task1)); + + result = isc_task_create(taskmgr, 0, &task2); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + isc_task_setname(task2, "normal", NULL); + ATF_CHECK(!isc_task_privilege(task2)); + + /* First event: privileged */ + event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST, + set_and_drop, &a, sizeof (isc_event_t)); + ATF_REQUIRE(event != NULL); + + ATF_CHECK_EQ(a, -1); + isc_task_send(task1, &event); + + /* Second event: not privileged */ + event = isc_event_allocate(mctx, task2, ISC_TASKEVENT_TEST, + set_and_drop, &b, sizeof (isc_event_t)); + ATF_REQUIRE(event != NULL); + + ATF_CHECK_EQ(b, -1); + isc_task_send(task2, &event); + + /* Third event: privileged */ + event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST, + set_and_drop, &c, sizeof (isc_event_t)); + ATF_REQUIRE(event != NULL); + + ATF_CHECK_EQ(c, -1); + isc_task_send(task1, &event); + + /* Fourth event: privileged */ + event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST, + set_and_drop, &d, sizeof (isc_event_t)); + ATF_REQUIRE(event != NULL); + + ATF_CHECK_EQ(d, -1); + isc_task_send(task1, &event); + + /* Fifth event: not privileged */ + event = isc_event_allocate(mctx, task2, ISC_TASKEVENT_TEST, + set_and_drop, &e, sizeof (isc_event_t)); + ATF_REQUIRE(event != NULL); + + ATF_CHECK_EQ(e, -1); + isc_task_send(task2, &event); + + ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_normal); + isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_privileged); + ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_privileged); + +#ifdef ISC_PLATFORM_USETHREADS + isc__taskmgr_resume(taskmgr); +#endif + + /* We're waiting for all variables to be set. */ + while ((a == -1 || b == -1 || c == -1 || d == -1 || e == -1) && + i++ < 5000) { +#ifndef ISC_PLATFORM_USETHREADS + while (isc__taskmgr_ready(taskmgr)) + isc__taskmgr_dispatch(taskmgr); +#endif + isc_test_nap(1000); + } + + /* + * We can't guarantee what order the events fire, but + * we do know *exactly one* of the privileged tasks will + * have run in privileged mode... + */ + ATF_CHECK(a == isc_taskmgrmode_privileged || + c == isc_taskmgrmode_privileged || + d == isc_taskmgrmode_privileged); + ATF_CHECK(a + c + d == isc_taskmgrmode_privileged); + + /* ...and neither of the non-privileged tasks did... */ + ATF_CHECK(b == isc_taskmgrmode_normal || e == isc_taskmgrmode_normal); + + /* ...but all five of them did run. */ + ATF_CHECK_EQ(counter, 6); + + ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_normal); + + isc_task_destroy(&task1); + ATF_REQUIRE_EQ(task1, NULL); + isc_task_destroy(&task2); + ATF_REQUIRE_EQ(task2, NULL); + + isc_test_end(); +} + +/* + * Main + */ +ATF_TP_ADD_TCS(tp) { + ATF_TP_ADD_TC(tp, create_task); + ATF_TP_ADD_TC(tp, all_events); + ATF_TP_ADD_TC(tp, privileged_events); + ATF_TP_ADD_TC(tp, privilege_drop); + + return (atf_no_error()); +} + diff --git a/contrib/ntp/lib/isc/tests/taskpool_test.c b/contrib/ntp/lib/isc/tests/taskpool_test.c new file mode 100644 index 0000000..aecb694 --- /dev/null +++ b/contrib/ntp/lib/isc/tests/taskpool_test.c @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/*! \file */ + +#include <config.h> + +#include <atf-c.h> + +#include <unistd.h> + +#include <isc/task.h> +#include <isc/taskpool.h> + +#include "isctest.h" + +/* + * Individual unit tests + */ + +/* Create a taskpool */ +ATF_TC(create_pool); +ATF_TC_HEAD(create_pool, tc) { + atf_tc_set_md_var(tc, "descr", "create a taskpool"); +} +ATF_TC_BODY(create_pool, tc) { + isc_result_t result; + isc_taskpool_t *pool = NULL; + + UNUSED(tc); + + result = isc_test_begin(NULL, ISC_TRUE); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = isc_taskpool_create(taskmgr, mctx, 8, 2, &pool); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + ATF_REQUIRE_EQ(isc_taskpool_size(pool), 8); + + isc_taskpool_destroy(&pool); + ATF_REQUIRE_EQ(pool, NULL); + + isc_test_end(); +} + +/* Resize a taskpool */ +ATF_TC(expand_pool); +ATF_TC_HEAD(expand_pool, tc) { + atf_tc_set_md_var(tc, "descr", "expand a taskpool"); +} +ATF_TC_BODY(expand_pool, tc) { + isc_result_t result; + isc_taskpool_t *pool1 = NULL, *pool2 = NULL, *hold = NULL; + + UNUSED(tc); + + result = isc_test_begin(NULL, ISC_TRUE); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = isc_taskpool_create(taskmgr, mctx, 10, 2, &pool1); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + ATF_REQUIRE_EQ(isc_taskpool_size(pool1), 10); + + /* resizing to a smaller size should have no effect */ + hold = pool1; + result = isc_taskpool_expand(&pool1, 5, &pool2); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + ATF_REQUIRE_EQ(isc_taskpool_size(pool2), 10); + ATF_REQUIRE_EQ(pool2, hold); + ATF_REQUIRE_EQ(pool1, NULL); + pool1 = pool2; + pool2 = NULL; + + /* resizing to the same size should have no effect */ + hold = pool1; + result = isc_taskpool_expand(&pool1, 10, &pool2); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + ATF_REQUIRE_EQ(isc_taskpool_size(pool2), 10); + ATF_REQUIRE_EQ(pool2, hold); + ATF_REQUIRE_EQ(pool1, NULL); + pool1 = pool2; + pool2 = NULL; + + /* resizing to larger size should make a new pool */ + hold = pool1; + result = isc_taskpool_expand(&pool1, 20, &pool2); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + ATF_REQUIRE_EQ(isc_taskpool_size(pool2), 20); + ATF_REQUIRE(pool2 != hold); + ATF_REQUIRE_EQ(pool1, NULL); + + isc_taskpool_destroy(&pool2); + ATF_REQUIRE_EQ(pool2, NULL); + + isc_test_end(); +} + +/* Get tasks */ +ATF_TC(get_tasks); +ATF_TC_HEAD(get_tasks, tc) { + atf_tc_set_md_var(tc, "descr", "create a taskpool"); +} +ATF_TC_BODY(get_tasks, tc) { + isc_result_t result; + isc_taskpool_t *pool = NULL; + isc_task_t *task1 = NULL, *task2 = NULL, *task3 = NULL; + + UNUSED(tc); + + result = isc_test_begin(NULL, ISC_TRUE); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = isc_taskpool_create(taskmgr, mctx, 2, 2, &pool); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + ATF_REQUIRE_EQ(isc_taskpool_size(pool), 2); + + /* two tasks in pool; make sure we can access them more than twice */ + isc_taskpool_gettask(pool, &task1); + ATF_REQUIRE(ISCAPI_TASK_VALID(task1)); + + isc_taskpool_gettask(pool, &task2); + ATF_REQUIRE(ISCAPI_TASK_VALID(task2)); + + isc_taskpool_gettask(pool, &task3); + ATF_REQUIRE(ISCAPI_TASK_VALID(task3)); + + isc_task_destroy(&task1); + isc_task_destroy(&task2); + isc_task_destroy(&task3); + + isc_taskpool_destroy(&pool); + ATF_REQUIRE_EQ(pool, NULL); + + isc_test_end(); +} + +/* Get tasks */ +ATF_TC(set_privilege); +ATF_TC_HEAD(set_privilege, tc) { + atf_tc_set_md_var(tc, "descr", "create a taskpool"); +} +ATF_TC_BODY(set_privilege, tc) { + isc_result_t result; + isc_taskpool_t *pool = NULL; + isc_task_t *task1 = NULL, *task2 = NULL, *task3 = NULL; + + UNUSED(tc); + + result = isc_test_begin(NULL, ISC_TRUE); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + result = isc_taskpool_create(taskmgr, mctx, 2, 2, &pool); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + ATF_REQUIRE_EQ(isc_taskpool_size(pool), 2); + + isc_taskpool_setprivilege(pool, ISC_TRUE); + + isc_taskpool_gettask(pool, &task1); + isc_taskpool_gettask(pool, &task2); + isc_taskpool_gettask(pool, &task3); + + ATF_CHECK(ISCAPI_TASK_VALID(task1)); + ATF_CHECK(ISCAPI_TASK_VALID(task2)); + ATF_CHECK(ISCAPI_TASK_VALID(task3)); + + ATF_CHECK(isc_task_privilege(task1)); + ATF_CHECK(isc_task_privilege(task2)); + ATF_CHECK(isc_task_privilege(task3)); + + isc_taskpool_setprivilege(pool, ISC_FALSE); + + ATF_CHECK(!isc_task_privilege(task1)); + ATF_CHECK(!isc_task_privilege(task2)); + ATF_CHECK(!isc_task_privilege(task3)); + + isc_task_destroy(&task1); + isc_task_destroy(&task2); + isc_task_destroy(&task3); + + isc_taskpool_destroy(&pool); + ATF_REQUIRE_EQ(pool, NULL); + + isc_test_end(); +} + +/* + * Main + */ +ATF_TP_ADD_TCS(tp) { + ATF_TP_ADD_TC(tp, create_pool); + ATF_TP_ADD_TC(tp, expand_pool); + ATF_TP_ADD_TC(tp, get_tasks); + ATF_TP_ADD_TC(tp, set_privilege); + + return (atf_no_error()); +} + diff --git a/contrib/ntp/lib/isc/timer.c b/contrib/ntp/lib/isc/timer.c new file mode 100644 index 0000000..0da251f --- /dev/null +++ b/contrib/ntp/lib/isc/timer.c @@ -0,0 +1,1072 @@ +/* + * Copyright (C) 2004, 2005, 2007-2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/*! \file */ + +#include <config.h> + +#include <isc/condition.h> +#include <isc/heap.h> +#include <isc/log.h> +#include <isc/magic.h> +#include <isc/mem.h> +#include <isc/msgs.h> +#include <isc/platform.h> +#include <isc/task.h> +#include <isc/thread.h> +#include <isc/time.h> +#include <isc/timer.h> +#include <isc/util.h> + +#ifdef OPENSSL_LEAKS +#include <openssl/err.h> +#endif + +/* See task.c about the following definition: */ +#ifdef BIND9 +#ifdef ISC_PLATFORM_USETHREADS +#define USE_TIMER_THREAD +#else +#define USE_SHARED_MANAGER +#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* BIND9 */ + +#ifndef USE_TIMER_THREAD +#include "timer_p.h" +#endif /* USE_TIMER_THREAD */ + +#ifdef ISC_TIMER_TRACE +#define XTRACE(s) fprintf(stderr, "%s\n", (s)) +#define XTRACEID(s, t) fprintf(stderr, "%s %p\n", (s), (t)) +#define XTRACETIME(s, d) fprintf(stderr, "%s %u.%09u\n", (s), \ + (d).seconds, (d).nanoseconds) +#define XTRACETIME2(s, d, n) fprintf(stderr, "%s %u.%09u %u.%09u\n", (s), \ + (d).seconds, (d).nanoseconds, (n).seconds, (n).nanoseconds) +#define XTRACETIMER(s, t, d) fprintf(stderr, "%s %p %u.%09u\n", (s), (t), \ + (d).seconds, (d).nanoseconds) +#else +#define XTRACE(s) +#define XTRACEID(s, t) +#define XTRACETIME(s, d) +#define XTRACETIME2(s, d, n) +#define XTRACETIMER(s, t, d) +#endif /* ISC_TIMER_TRACE */ + +#define TIMER_MAGIC ISC_MAGIC('T', 'I', 'M', 'R') +#define VALID_TIMER(t) ISC_MAGIC_VALID(t, TIMER_MAGIC) + +typedef struct isc__timer isc__timer_t; +typedef struct isc__timermgr isc__timermgr_t; + +struct isc__timer { + /*! Not locked. */ + isc_timer_t common; + isc__timermgr_t * manager; + isc_mutex_t lock; + /*! Locked by timer lock. */ + unsigned int references; + isc_time_t idle; + /*! Locked by manager lock. */ + isc_timertype_t type; + isc_time_t expires; + isc_interval_t interval; + isc_task_t * task; + isc_taskaction_t action; + void * arg; + unsigned int index; + isc_time_t due; + LINK(isc__timer_t) link; +}; + +#define TIMER_MANAGER_MAGIC ISC_MAGIC('T', 'I', 'M', 'M') +#define VALID_MANAGER(m) ISC_MAGIC_VALID(m, TIMER_MANAGER_MAGIC) + +struct isc__timermgr { + /* Not locked. */ + isc_timermgr_t common; + isc_mem_t * mctx; + isc_mutex_t lock; + /* Locked by manager lock. */ + isc_boolean_t done; + LIST(isc__timer_t) timers; + unsigned int nscheduled; + isc_time_t due; +#ifdef USE_TIMER_THREAD + isc_condition_t wakeup; + isc_thread_t thread; +#endif /* USE_TIMER_THREAD */ +#ifdef USE_SHARED_MANAGER + unsigned int refs; +#endif /* USE_SHARED_MANAGER */ + isc_heap_t * heap; +}; + +/*% + * The followings can be either static or public, depending on build + * environment. + */ + +#ifdef BIND9 +#define ISC_TIMERFUNC_SCOPE +#else +#define ISC_TIMERFUNC_SCOPE static +#endif + +ISC_TIMERFUNC_SCOPE isc_result_t +isc__timer_create(isc_timermgr_t *manager, isc_timertype_t type, + isc_time_t *expires, isc_interval_t *interval, + isc_task_t *task, isc_taskaction_t action, const void *arg, + isc_timer_t **timerp); +ISC_TIMERFUNC_SCOPE isc_result_t +isc__timer_reset(isc_timer_t *timer, isc_timertype_t type, + isc_time_t *expires, isc_interval_t *interval, + isc_boolean_t purge); +ISC_TIMERFUNC_SCOPE isc_timertype_t +isc__timer_gettype(isc_timer_t *timer); +ISC_TIMERFUNC_SCOPE isc_result_t +isc__timer_touch(isc_timer_t *timer); +ISC_TIMERFUNC_SCOPE void +isc__timer_attach(isc_timer_t *timer0, isc_timer_t **timerp); +ISC_TIMERFUNC_SCOPE void +isc__timer_detach(isc_timer_t **timerp); +ISC_TIMERFUNC_SCOPE isc_result_t +isc__timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp); +ISC_TIMERFUNC_SCOPE void +isc__timermgr_poke(isc_timermgr_t *manager0); +ISC_TIMERFUNC_SCOPE void +isc__timermgr_destroy(isc_timermgr_t **managerp); + +static struct isc__timermethods { + isc_timermethods_t methods; + + /*% + * The following are defined just for avoiding unused static functions. + */ +#ifndef BIND9 + void *gettype; +#endif +} timermethods = { + { + isc__timer_attach, + isc__timer_detach, + isc__timer_reset, + isc__timer_touch + } +#ifndef BIND9 + , + (void *)isc__timer_gettype +#endif +}; + +static struct isc__timermgrmethods { + isc_timermgrmethods_t methods; +#ifndef BIND9 + void *poke; /* see above */ +#endif +} timermgrmethods = { + { + isc__timermgr_destroy, + isc__timer_create + } +#ifndef BIND9 + , + (void *)isc__timermgr_poke +#endif +}; + +#ifdef USE_SHARED_MANAGER +/*! + * If the manager is supposed to be shared, there can be only one. + */ +static isc__timermgr_t *timermgr = NULL; +#endif /* USE_SHARED_MANAGER */ + +static inline isc_result_t +schedule(isc__timer_t *timer, isc_time_t *now, isc_boolean_t signal_ok) { + isc_result_t result; + isc__timermgr_t *manager; + isc_time_t due; + int cmp; +#ifdef USE_TIMER_THREAD + isc_boolean_t timedwait; +#endif + + /*! + * Note: the caller must ensure locking. + */ + + REQUIRE(timer->type != isc_timertype_inactive); + +#ifndef USE_TIMER_THREAD + UNUSED(signal_ok); +#endif /* USE_TIMER_THREAD */ + + manager = timer->manager; + +#ifdef USE_TIMER_THREAD + /*! + * If the manager was timed wait, we may need to signal the + * manager to force a wakeup. + */ + timedwait = ISC_TF(manager->nscheduled > 0 && + isc_time_seconds(&manager->due) != 0); +#endif + + /* + * Compute the new due time. + */ + if (timer->type != isc_timertype_once) { + result = isc_time_add(now, &timer->interval, &due); + if (result != ISC_R_SUCCESS) + return (result); + if (timer->type == isc_timertype_limited && + isc_time_compare(&timer->expires, &due) < 0) + due = timer->expires; + } else { + if (isc_time_isepoch(&timer->idle)) + due = timer->expires; + else if (isc_time_isepoch(&timer->expires)) + due = timer->idle; + else if (isc_time_compare(&timer->idle, &timer->expires) < 0) + due = timer->idle; + else + due = timer->expires; + } + + /* + * Schedule the timer. + */ + + if (timer->index > 0) { + /* + * Already scheduled. + */ + cmp = isc_time_compare(&due, &timer->due); + timer->due = due; + switch (cmp) { + case -1: + isc_heap_increased(manager->heap, timer->index); + break; + case 1: + isc_heap_decreased(manager->heap, timer->index); + break; + case 0: + /* Nothing to do. */ + break; + } + } else { + timer->due = due; + result = isc_heap_insert(manager->heap, timer); + if (result != ISC_R_SUCCESS) { + INSIST(result == ISC_R_NOMEMORY); + return (ISC_R_NOMEMORY); + } + manager->nscheduled++; + } + + XTRACETIMER(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER, + ISC_MSG_SCHEDULE, "schedule"), timer, due); + + /* + * If this timer is at the head of the queue, we need to ensure + * that we won't miss it if it has a more recent due time than + * the current "next" timer. We do this either by waking up the + * run thread, or explicitly setting the value in the manager. + */ +#ifdef USE_TIMER_THREAD + + /* + * This is a temporary (probably) hack to fix a bug on tru64 5.1 + * and 5.1a. Sometimes, pthread_cond_timedwait() doesn't actually + * return when the time expires, so here, we check to see if + * we're 15 seconds or more behind, and if we are, we signal + * the dispatcher. This isn't such a bad idea as a general purpose + * watchdog, so perhaps we should just leave it in here. + */ + if (signal_ok && timedwait) { + isc_interval_t fifteen; + isc_time_t then; + + isc_interval_set(&fifteen, 15, 0); + result = isc_time_add(&manager->due, &fifteen, &then); + + if (result == ISC_R_SUCCESS && + isc_time_compare(&then, now) < 0) { + SIGNAL(&manager->wakeup); + signal_ok = ISC_FALSE; + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_TIMER, ISC_LOG_WARNING, + "*** POKED TIMER ***"); + } + } + + if (timer->index == 1 && signal_ok) { + XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER, + ISC_MSG_SIGNALSCHED, + "signal (schedule)")); + SIGNAL(&manager->wakeup); + } +#else /* USE_TIMER_THREAD */ + if (timer->index == 1 && + isc_time_compare(&timer->due, &manager->due) < 0) + manager->due = timer->due; +#endif /* USE_TIMER_THREAD */ + + return (ISC_R_SUCCESS); +} + +static inline void +deschedule(isc__timer_t *timer) { +#ifdef USE_TIMER_THREAD + isc_boolean_t need_wakeup = ISC_FALSE; +#endif + isc__timermgr_t *manager; + + /* + * The caller must ensure locking. + */ + + manager = timer->manager; + if (timer->index > 0) { +#ifdef USE_TIMER_THREAD + if (timer->index == 1) + need_wakeup = ISC_TRUE; +#endif + isc_heap_delete(manager->heap, timer->index); + timer->index = 0; + INSIST(manager->nscheduled > 0); + manager->nscheduled--; +#ifdef USE_TIMER_THREAD + if (need_wakeup) { + XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER, + ISC_MSG_SIGNALDESCHED, + "signal (deschedule)")); + SIGNAL(&manager->wakeup); + } +#endif /* USE_TIMER_THREAD */ + } +} + +static void +destroy(isc__timer_t *timer) { + isc__timermgr_t *manager = timer->manager; + + /* + * The caller must ensure it is safe to destroy the timer. + */ + + LOCK(&manager->lock); + + (void)isc_task_purgerange(timer->task, + timer, + ISC_TIMEREVENT_FIRSTEVENT, + ISC_TIMEREVENT_LASTEVENT, + NULL); + deschedule(timer); + UNLINK(manager->timers, timer, link); + + UNLOCK(&manager->lock); + + isc_task_detach(&timer->task); + DESTROYLOCK(&timer->lock); + timer->common.impmagic = 0; + timer->common.magic = 0; + isc_mem_put(manager->mctx, timer, sizeof(*timer)); +} + +ISC_TIMERFUNC_SCOPE isc_result_t +isc__timer_create(isc_timermgr_t *manager0, isc_timertype_t type, + isc_time_t *expires, isc_interval_t *interval, + isc_task_t *task, isc_taskaction_t action, const void *arg, + isc_timer_t **timerp) +{ + isc__timermgr_t *manager = (isc__timermgr_t *)manager0; + isc__timer_t *timer; + isc_result_t result; + isc_time_t now; + + /* + * Create a new 'type' timer managed by 'manager'. The timers + * parameters are specified by 'expires' and 'interval'. Events + * will be posted to 'task' and when dispatched 'action' will be + * called with 'arg' as the arg value. The new timer is returned + * in 'timerp'. + */ + + REQUIRE(VALID_MANAGER(manager)); + REQUIRE(task != NULL); + REQUIRE(action != NULL); + if (expires == NULL) + expires = isc_time_epoch; + if (interval == NULL) + interval = isc_interval_zero; + REQUIRE(type == isc_timertype_inactive || + !(isc_time_isepoch(expires) && isc_interval_iszero(interval))); + REQUIRE(timerp != NULL && *timerp == NULL); + REQUIRE(type != isc_timertype_limited || + !(isc_time_isepoch(expires) || isc_interval_iszero(interval))); + + /* + * Get current time. + */ + if (type != isc_timertype_inactive) { + TIME_NOW(&now); + } else { + /* + * We don't have to do this, but it keeps the compiler from + * complaining about "now" possibly being used without being + * set, even though it will never actually happen. + */ + isc_time_settoepoch(&now); + } + + + timer = isc_mem_get(manager->mctx, sizeof(*timer)); + if (timer == NULL) + return (ISC_R_NOMEMORY); + + timer->manager = manager; + timer->references = 1; + + if (type == isc_timertype_once && !isc_interval_iszero(interval)) { + result = isc_time_add(&now, interval, &timer->idle); + if (result != ISC_R_SUCCESS) { + isc_mem_put(manager->mctx, timer, sizeof(*timer)); + return (result); + } + } else + isc_time_settoepoch(&timer->idle); + + timer->type = type; + timer->expires = *expires; + timer->interval = *interval; + timer->task = NULL; + isc_task_attach(task, &timer->task); + timer->action = action; + /* + * Removing the const attribute from "arg" is the best of two + * evils here. If the timer->arg member is made const, then + * it affects a great many recipients of the timer event + * which did not pass in an "arg" that was truly const. + * Changing isc_timer_create() to not have "arg" prototyped as const, + * though, can cause compilers warnings for calls that *do* + * have a truly const arg. The caller will have to carefully + * keep track of whether arg started as a true const. + */ + DE_CONST(arg, timer->arg); + timer->index = 0; + result = isc_mutex_init(&timer->lock); + if (result != ISC_R_SUCCESS) { + isc_task_detach(&timer->task); + isc_mem_put(manager->mctx, timer, sizeof(*timer)); + return (result); + } + ISC_LINK_INIT(timer, link); + timer->common.impmagic = TIMER_MAGIC; + timer->common.magic = ISCAPI_TIMER_MAGIC; + timer->common.methods = (isc_timermethods_t *)&timermethods; + + LOCK(&manager->lock); + + /* + * Note we don't have to lock the timer like we normally would because + * there are no external references to it yet. + */ + + if (type != isc_timertype_inactive) + result = schedule(timer, &now, ISC_TRUE); + else + result = ISC_R_SUCCESS; + if (result == ISC_R_SUCCESS) + APPEND(manager->timers, timer, link); + + UNLOCK(&manager->lock); + + if (result != ISC_R_SUCCESS) { + timer->common.impmagic = 0; + timer->common.magic = 0; + DESTROYLOCK(&timer->lock); + isc_task_detach(&timer->task); + isc_mem_put(manager->mctx, timer, sizeof(*timer)); + return (result); + } + + *timerp = (isc_timer_t *)timer; + + return (ISC_R_SUCCESS); +} + +ISC_TIMERFUNC_SCOPE isc_result_t +isc__timer_reset(isc_timer_t *timer0, isc_timertype_t type, + isc_time_t *expires, isc_interval_t *interval, + isc_boolean_t purge) +{ + isc__timer_t *timer = (isc__timer_t *)timer0; + isc_time_t now; + isc__timermgr_t *manager; + isc_result_t result; + + /* + * Change the timer's type, expires, and interval values to the given + * values. If 'purge' is ISC_TRUE, any pending events from this timer + * are purged from its task's event queue. + */ + + REQUIRE(VALID_TIMER(timer)); + manager = timer->manager; + REQUIRE(VALID_MANAGER(manager)); + + if (expires == NULL) + expires = isc_time_epoch; + if (interval == NULL) + interval = isc_interval_zero; + REQUIRE(type == isc_timertype_inactive || + !(isc_time_isepoch(expires) && isc_interval_iszero(interval))); + REQUIRE(type != isc_timertype_limited || + !(isc_time_isepoch(expires) || isc_interval_iszero(interval))); + + /* + * Get current time. + */ + if (type != isc_timertype_inactive) { + TIME_NOW(&now); + } else { + /* + * We don't have to do this, but it keeps the compiler from + * complaining about "now" possibly being used without being + * set, even though it will never actually happen. + */ + isc_time_settoepoch(&now); + } + + LOCK(&manager->lock); + LOCK(&timer->lock); + + if (purge) + (void)isc_task_purgerange(timer->task, + timer, + ISC_TIMEREVENT_FIRSTEVENT, + ISC_TIMEREVENT_LASTEVENT, + NULL); + timer->type = type; + timer->expires = *expires; + timer->interval = *interval; + if (type == isc_timertype_once && !isc_interval_iszero(interval)) { + result = isc_time_add(&now, interval, &timer->idle); + } else { + isc_time_settoepoch(&timer->idle); + result = ISC_R_SUCCESS; + } + + if (result == ISC_R_SUCCESS) { + if (type == isc_timertype_inactive) { + deschedule(timer); + result = ISC_R_SUCCESS; + } else + result = schedule(timer, &now, ISC_TRUE); + } + + UNLOCK(&timer->lock); + UNLOCK(&manager->lock); + + return (result); +} + +ISC_TIMERFUNC_SCOPE isc_timertype_t +isc__timer_gettype(isc_timer_t *timer0) { + isc__timer_t *timer = (isc__timer_t *)timer0; + isc_timertype_t t; + + REQUIRE(VALID_TIMER(timer)); + + LOCK(&timer->lock); + t = timer->type; + UNLOCK(&timer->lock); + + return (t); +} + +ISC_TIMERFUNC_SCOPE isc_result_t +isc__timer_touch(isc_timer_t *timer0) { + isc__timer_t *timer = (isc__timer_t *)timer0; + isc_result_t result; + isc_time_t now; + + /* + * Set the last-touched time of 'timer' to the current time. + */ + + REQUIRE(VALID_TIMER(timer)); + + LOCK(&timer->lock); + + /* + * We'd like to + * + * REQUIRE(timer->type == isc_timertype_once); + * + * but we cannot without locking the manager lock too, which we + * don't want to do. + */ + + TIME_NOW(&now); + result = isc_time_add(&now, &timer->interval, &timer->idle); + + UNLOCK(&timer->lock); + + return (result); +} + +ISC_TIMERFUNC_SCOPE void +isc__timer_attach(isc_timer_t *timer0, isc_timer_t **timerp) { + isc__timer_t *timer = (isc__timer_t *)timer0; + + /* + * Attach *timerp to timer. + */ + + REQUIRE(VALID_TIMER(timer)); + REQUIRE(timerp != NULL && *timerp == NULL); + + LOCK(&timer->lock); + timer->references++; + UNLOCK(&timer->lock); + + *timerp = (isc_timer_t *)timer; +} + +ISC_TIMERFUNC_SCOPE void +isc__timer_detach(isc_timer_t **timerp) { + isc__timer_t *timer; + isc_boolean_t free_timer = ISC_FALSE; + + /* + * Detach *timerp from its timer. + */ + + REQUIRE(timerp != NULL); + timer = (isc__timer_t *)*timerp; + REQUIRE(VALID_TIMER(timer)); + + LOCK(&timer->lock); + REQUIRE(timer->references > 0); + timer->references--; + if (timer->references == 0) + free_timer = ISC_TRUE; + UNLOCK(&timer->lock); + + if (free_timer) + destroy(timer); + + *timerp = NULL; +} + +static void +dispatch(isc__timermgr_t *manager, isc_time_t *now) { + isc_boolean_t done = ISC_FALSE, post_event, need_schedule; + isc_timerevent_t *event; + isc_eventtype_t type = 0; + isc__timer_t *timer; + isc_result_t result; + isc_boolean_t idle; + + /*! + * The caller must be holding the manager lock. + */ + + while (manager->nscheduled > 0 && !done) { + timer = isc_heap_element(manager->heap, 1); + INSIST(timer->type != isc_timertype_inactive); + if (isc_time_compare(now, &timer->due) >= 0) { + if (timer->type == isc_timertype_ticker) { + type = ISC_TIMEREVENT_TICK; + post_event = ISC_TRUE; + need_schedule = ISC_TRUE; + } else if (timer->type == isc_timertype_limited) { + int cmp; + cmp = isc_time_compare(now, &timer->expires); + if (cmp >= 0) { + type = ISC_TIMEREVENT_LIFE; + post_event = ISC_TRUE; + need_schedule = ISC_FALSE; + } else { + type = ISC_TIMEREVENT_TICK; + post_event = ISC_TRUE; + need_schedule = ISC_TRUE; + } + } else if (!isc_time_isepoch(&timer->expires) && + isc_time_compare(now, + &timer->expires) >= 0) { + type = ISC_TIMEREVENT_LIFE; + post_event = ISC_TRUE; + need_schedule = ISC_FALSE; + } else { + idle = ISC_FALSE; + + LOCK(&timer->lock); + if (!isc_time_isepoch(&timer->idle) && + isc_time_compare(now, + &timer->idle) >= 0) { + idle = ISC_TRUE; + } + UNLOCK(&timer->lock); + if (idle) { + type = ISC_TIMEREVENT_IDLE; + post_event = ISC_TRUE; + need_schedule = ISC_FALSE; + } else { + /* + * Idle timer has been touched; + * reschedule. + */ + XTRACEID(isc_msgcat_get(isc_msgcat, + ISC_MSGSET_TIMER, + ISC_MSG_IDLERESCHED, + "idle reschedule"), + timer); + post_event = ISC_FALSE; + need_schedule = ISC_TRUE; + } + } + + if (post_event) { + XTRACEID(isc_msgcat_get(isc_msgcat, + ISC_MSGSET_TIMER, + ISC_MSG_POSTING, + "posting"), timer); + /* + * XXX We could preallocate this event. + */ + event = (isc_timerevent_t *)isc_event_allocate(manager->mctx, + timer, + type, + timer->action, + timer->arg, + sizeof(*event)); + + if (event != NULL) { + event->due = timer->due; + isc_task_send(timer->task, + ISC_EVENT_PTR(&event)); + } else + UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_TIMER, + ISC_MSG_EVENTNOTALLOC, + "couldn't " + "allocate event")); + } + + timer->index = 0; + isc_heap_delete(manager->heap, 1); + manager->nscheduled--; + + if (need_schedule) { + result = schedule(timer, now, ISC_FALSE); + if (result != ISC_R_SUCCESS) + UNEXPECTED_ERROR(__FILE__, __LINE__, + "%s: %u", + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_TIMER, + ISC_MSG_SCHEDFAIL, + "couldn't schedule " + "timer"), + result); + } + } else { + manager->due = timer->due; + done = ISC_TRUE; + } + } +} + +#ifdef USE_TIMER_THREAD +static isc_threadresult_t +#ifdef _WIN32 /* XXXDCL */ +WINAPI +#endif +run(void *uap) { + isc__timermgr_t *manager = uap; + isc_time_t now; + isc_result_t result; + + LOCK(&manager->lock); + while (!manager->done) { + TIME_NOW(&now); + + XTRACETIME(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_RUNNING, + "running"), now); + + dispatch(manager, &now); + + if (manager->nscheduled > 0) { + XTRACETIME2(isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_WAITUNTIL, + "waituntil"), + manager->due, now); + result = WAITUNTIL(&manager->wakeup, &manager->lock, &manager->due); + INSIST(result == ISC_R_SUCCESS || + result == ISC_R_TIMEDOUT); + } else { + XTRACETIME(isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_WAIT, "wait"), now); + WAIT(&manager->wakeup, &manager->lock); + } + XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER, + ISC_MSG_WAKEUP, "wakeup")); + } + UNLOCK(&manager->lock); + +#ifdef OPENSSL_LEAKS + ERR_remove_state(0); +#endif + + return ((isc_threadresult_t)0); +} +#endif /* USE_TIMER_THREAD */ + +static isc_boolean_t +sooner(void *v1, void *v2) { + isc__timer_t *t1, *t2; + + t1 = v1; + t2 = v2; + REQUIRE(VALID_TIMER(t1)); + REQUIRE(VALID_TIMER(t2)); + + if (isc_time_compare(&t1->due, &t2->due) < 0) + return (ISC_TRUE); + return (ISC_FALSE); +} + +static void +set_index(void *what, unsigned int index) { + isc__timer_t *timer; + + timer = what; + REQUIRE(VALID_TIMER(timer)); + + timer->index = index; +} + +ISC_TIMERFUNC_SCOPE isc_result_t +isc__timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp) { + isc__timermgr_t *manager; + isc_result_t result; + + /* + * Create a timer manager. + */ + + REQUIRE(managerp != NULL && *managerp == NULL); + +#ifdef USE_SHARED_MANAGER + if (timermgr != NULL) { + timermgr->refs++; + *managerp = (isc_timermgr_t *)timermgr; + return (ISC_R_SUCCESS); + } +#endif /* USE_SHARED_MANAGER */ + + manager = isc_mem_get(mctx, sizeof(*manager)); + if (manager == NULL) + return (ISC_R_NOMEMORY); + + manager->common.impmagic = TIMER_MANAGER_MAGIC; + manager->common.magic = ISCAPI_TIMERMGR_MAGIC; + manager->common.methods = (isc_timermgrmethods_t *)&timermgrmethods; + manager->mctx = NULL; + manager->done = ISC_FALSE; + INIT_LIST(manager->timers); + manager->nscheduled = 0; + isc_time_settoepoch(&manager->due); + manager->heap = NULL; + result = isc_heap_create(mctx, sooner, set_index, 0, &manager->heap); + if (result != ISC_R_SUCCESS) { + INSIST(result == ISC_R_NOMEMORY); + isc_mem_put(mctx, manager, sizeof(*manager)); + return (ISC_R_NOMEMORY); + } + result = isc_mutex_init(&manager->lock); + if (result != ISC_R_SUCCESS) { + isc_heap_destroy(&manager->heap); + isc_mem_put(mctx, manager, sizeof(*manager)); + return (result); + } + isc_mem_attach(mctx, &manager->mctx); +#ifdef USE_TIMER_THREAD + if (isc_condition_init(&manager->wakeup) != ISC_R_SUCCESS) { + isc_mem_detach(&manager->mctx); + DESTROYLOCK(&manager->lock); + isc_heap_destroy(&manager->heap); + isc_mem_put(mctx, manager, sizeof(*manager)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_condition_init() %s", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed")); + return (ISC_R_UNEXPECTED); + } + if (isc_thread_create(run, manager, &manager->thread) != + ISC_R_SUCCESS) { + isc_mem_detach(&manager->mctx); + (void)isc_condition_destroy(&manager->wakeup); + DESTROYLOCK(&manager->lock); + isc_heap_destroy(&manager->heap); + isc_mem_put(mctx, manager, sizeof(*manager)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_thread_create() %s", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed")); + return (ISC_R_UNEXPECTED); + } +#endif +#ifdef USE_SHARED_MANAGER + manager->refs = 1; + timermgr = manager; +#endif /* USE_SHARED_MANAGER */ + + *managerp = (isc_timermgr_t *)manager; + + return (ISC_R_SUCCESS); +} + +ISC_TIMERFUNC_SCOPE void +isc__timermgr_poke(isc_timermgr_t *manager0) { +#ifdef USE_TIMER_THREAD + isc__timermgr_t *manager = (isc__timermgr_t *)manager0; + + REQUIRE(VALID_MANAGER(manager)); + + SIGNAL(&manager->wakeup); +#else + UNUSED(manager0); +#endif +} + +ISC_TIMERFUNC_SCOPE void +isc__timermgr_destroy(isc_timermgr_t **managerp) { + isc__timermgr_t *manager; + isc_mem_t *mctx; + + /* + * Destroy a timer manager. + */ + + REQUIRE(managerp != NULL); + manager = (isc__timermgr_t *)*managerp; + REQUIRE(VALID_MANAGER(manager)); + + LOCK(&manager->lock); + +#ifdef USE_SHARED_MANAGER + manager->refs--; + if (manager->refs > 0) { + UNLOCK(&manager->lock); + *managerp = NULL; + return; + } + timermgr = NULL; +#endif /* USE_SHARED_MANAGER */ + +#ifndef USE_TIMER_THREAD + isc__timermgr_dispatch((isc_timermgr_t *)manager); +#endif + + REQUIRE(EMPTY(manager->timers)); + manager->done = ISC_TRUE; + +#ifdef USE_TIMER_THREAD + XTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TIMER, + ISC_MSG_SIGNALDESTROY, "signal (destroy)")); + SIGNAL(&manager->wakeup); +#endif /* USE_TIMER_THREAD */ + + UNLOCK(&manager->lock); + +#ifdef USE_TIMER_THREAD + /* + * Wait for thread to exit. + */ + if (isc_thread_join(manager->thread, NULL) != ISC_R_SUCCESS) + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_thread_join() %s", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed")); +#endif /* USE_TIMER_THREAD */ + + /* + * Clean up. + */ +#ifdef USE_TIMER_THREAD + (void)isc_condition_destroy(&manager->wakeup); +#endif /* USE_TIMER_THREAD */ + DESTROYLOCK(&manager->lock); + isc_heap_destroy(&manager->heap); + manager->common.impmagic = 0; + manager->common.magic = 0; + mctx = manager->mctx; + isc_mem_put(mctx, manager, sizeof(*manager)); + isc_mem_detach(&mctx); + + *managerp = NULL; + +#ifdef USE_SHARED_MANAGER + timermgr = NULL; +#endif +} + +#ifndef USE_TIMER_THREAD +isc_result_t +isc__timermgr_nextevent(isc_timermgr_t *manager0, isc_time_t *when) { + isc__timermgr_t *manager = (isc__timermgr_t *)manager0; + +#ifdef USE_SHARED_MANAGER + if (manager == NULL) + manager = timermgr; +#endif + if (manager == NULL || manager->nscheduled == 0) + return (ISC_R_NOTFOUND); + *when = manager->due; + return (ISC_R_SUCCESS); +} + +void +isc__timermgr_dispatch(isc_timermgr_t *manager0) { + isc__timermgr_t *manager = (isc__timermgr_t *)manager0; + isc_time_t now; + +#ifdef USE_SHARED_MANAGER + if (manager == NULL) + manager = timermgr; +#endif + if (manager == NULL) + return; + TIME_NOW(&now); + dispatch(manager, &now); +} +#endif /* USE_TIMER_THREAD */ + +#ifdef USE_TIMERIMPREGISTER +isc_result_t +isc__timer_register() { + return (isc_timer_register(isc__timermgr_create)); +} +#endif diff --git a/contrib/ntp/lib/isc/timer_api.c b/contrib/ntp/lib/isc/timer_api.c new file mode 100644 index 0000000..97e62b3 --- /dev/null +++ b/contrib/ntp/lib/isc/timer_api.c @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: timer_api.c,v 1.4 2009/09/02 23:48:02 tbox Exp $ */ + +#include <config.h> + +#include <unistd.h> + +#include <isc/app.h> +#include <isc/magic.h> +#include <isc/mutex.h> +#include <isc/once.h> +#include <isc/timer.h> +#include <isc/util.h> + +static isc_mutex_t createlock; +static isc_once_t once = ISC_ONCE_INIT; +static isc_timermgrcreatefunc_t timermgr_createfunc = NULL; + +static void +initialize(void) { + RUNTIME_CHECK(isc_mutex_init(&createlock) == ISC_R_SUCCESS); +} + +isc_result_t +isc_timer_register(isc_timermgrcreatefunc_t createfunc) { + isc_result_t result = ISC_R_SUCCESS; + + RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS); + + LOCK(&createlock); + if (timermgr_createfunc == NULL) + timermgr_createfunc = createfunc; + else + result = ISC_R_EXISTS; + UNLOCK(&createlock); + + return (result); +} + +isc_result_t +isc_timermgr_createinctx(isc_mem_t *mctx, isc_appctx_t *actx, + isc_timermgr_t **managerp) +{ + isc_result_t result; + + LOCK(&createlock); + + REQUIRE(timermgr_createfunc != NULL); + result = (*timermgr_createfunc)(mctx, managerp); + + UNLOCK(&createlock); + + if (result == ISC_R_SUCCESS) + isc_appctx_settimermgr(actx, *managerp); + + return (result); +} + +isc_result_t +isc_timermgr_create(isc_mem_t *mctx, isc_timermgr_t **managerp) { + isc_result_t result; + + LOCK(&createlock); + + REQUIRE(timermgr_createfunc != NULL); + result = (*timermgr_createfunc)(mctx, managerp); + + UNLOCK(&createlock); + + return (result); +} + +void +isc_timermgr_destroy(isc_timermgr_t **managerp) { + REQUIRE(*managerp != NULL && ISCAPI_TIMERMGR_VALID(*managerp)); + + (*managerp)->methods->destroy(managerp); + + ENSURE(*managerp == NULL); +} + +isc_result_t +isc_timer_create(isc_timermgr_t *manager, isc_timertype_t type, + isc_time_t *expires, isc_interval_t *interval, + isc_task_t *task, isc_taskaction_t action, const void *arg, + isc_timer_t **timerp) +{ + REQUIRE(ISCAPI_TIMERMGR_VALID(manager)); + + return (manager->methods->timercreate(manager, type, expires, + interval, task, action, arg, + timerp)); +} + +void +isc_timer_attach(isc_timer_t *timer, isc_timer_t **timerp) { + REQUIRE(ISCAPI_TIMER_VALID(timer)); + REQUIRE(timerp != NULL && *timerp == NULL); + + timer->methods->attach(timer, timerp); + + ENSURE(*timerp == timer); +} + +void +isc_timer_detach(isc_timer_t **timerp) { + REQUIRE(timerp != NULL && ISCAPI_TIMER_VALID(*timerp)); + + (*timerp)->methods->detach(timerp); + + ENSURE(*timerp == NULL); +} + +isc_result_t +isc_timer_reset(isc_timer_t *timer, isc_timertype_t type, + isc_time_t *expires, isc_interval_t *interval, + isc_boolean_t purge) +{ + REQUIRE(ISCAPI_TIMER_VALID(timer)); + + return (timer->methods->reset(timer, type, expires, interval, purge)); +} + +isc_result_t +isc_timer_touch(isc_timer_t *timer) { + REQUIRE(ISCAPI_TIMER_VALID(timer)); + + return (timer->methods->touch(timer)); +} diff --git a/contrib/ntp/lib/isc/timer_p.h b/contrib/ntp/lib/isc/timer_p.h new file mode 100644 index 0000000..d6f7c99 --- /dev/null +++ b/contrib/ntp/lib/isc/timer_p.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: timer_p.h,v 1.12 2009/09/02 23:48:02 tbox Exp $ */ + +#ifndef ISC_TIMER_P_H +#define ISC_TIMER_P_H + +/*! \file */ + +isc_result_t +isc__timermgr_nextevent(isc_timermgr_t *timermgr, isc_time_t *when); + +void +isc__timermgr_dispatch(isc_timermgr_t *timermgr); + +#endif /* ISC_TIMER_P_H */ diff --git a/contrib/ntp/lib/isc/unix/app.c b/contrib/ntp/lib/isc/unix/app.c new file mode 100644 index 0000000..5393be9 --- /dev/null +++ b/contrib/ntp/lib/isc/unix/app.c @@ -0,0 +1,946 @@ +/* + * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: app.c,v 1.64 2009/11/04 05:58:46 marka Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <sys/param.h> /* Openserver 5.0.6A and FD_SETSIZE */ +#include <sys/types.h> + +#include <stddef.h> +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <signal.h> +#include <sys/time.h> +#ifdef HAVE_EPOLL +#include <sys/epoll.h> +#endif + +#include <isc/app.h> +#include <isc/boolean.h> +#include <isc/condition.h> +#include <isc/mem.h> +#include <isc/msgs.h> +#include <isc/mutex.h> +#include <isc/event.h> +#include <isc/platform.h> +#include <isc/strerror.h> +#include <isc/string.h> +#include <isc/task.h> +#include <isc/time.h> +#include <isc/util.h> + +/*% + * For BIND9 internal applications built with threads, we use a single app + * context and let multiple worker, I/O, timer threads do actual jobs. + * For other cases (including BIND9 built without threads) an app context acts + * as an event loop dispatching various events. + */ +#if defined(ISC_PLATFORM_USETHREADS) && defined(BIND9) +#define USE_THREADS_SINGLECTX +#endif + +#ifdef ISC_PLATFORM_USETHREADS +#include <pthread.h> +#endif + +#ifndef USE_THREADS_SINGLECTX +#include "../timer_p.h" +#include "../task_p.h" +#include "socket_p.h" +#endif /* USE_THREADS_SINGLECTX */ + +#ifdef ISC_PLATFORM_USETHREADS +static pthread_t blockedthread; +#endif /* ISC_PLATFORM_USETHREADS */ + +/*% + * The following can be either static or public, depending on build environment. + */ + +#ifdef BIND9 +#define ISC_APPFUNC_SCOPE +#else +#define ISC_APPFUNC_SCOPE static +#endif + +ISC_APPFUNC_SCOPE isc_result_t isc__app_start(void); +ISC_APPFUNC_SCOPE isc_result_t isc__app_ctxstart(isc_appctx_t *ctx); +ISC_APPFUNC_SCOPE isc_result_t isc__app_onrun(isc_mem_t *mctx, + isc_task_t *task, + isc_taskaction_t action, + void *arg); +ISC_APPFUNC_SCOPE isc_result_t isc__app_ctxrun(isc_appctx_t *ctx); +ISC_APPFUNC_SCOPE isc_result_t isc__app_run(void); +ISC_APPFUNC_SCOPE isc_result_t isc__app_ctxshutdown(isc_appctx_t *ctx); +ISC_APPFUNC_SCOPE isc_result_t isc__app_shutdown(void); +ISC_APPFUNC_SCOPE isc_result_t isc__app_reload(void); +ISC_APPFUNC_SCOPE isc_result_t isc__app_ctxsuspend(isc_appctx_t *ctx); +ISC_APPFUNC_SCOPE void isc__app_ctxfinish(isc_appctx_t *ctx); +ISC_APPFUNC_SCOPE void isc__app_finish(void); +ISC_APPFUNC_SCOPE void isc__app_block(void); +ISC_APPFUNC_SCOPE void isc__app_unblock(void); +ISC_APPFUNC_SCOPE isc_result_t isc__appctx_create(isc_mem_t *mctx, + isc_appctx_t **ctxp); +ISC_APPFUNC_SCOPE void isc__appctx_destroy(isc_appctx_t **ctxp); +ISC_APPFUNC_SCOPE void isc__appctx_settaskmgr(isc_appctx_t *ctx, + isc_taskmgr_t *taskmgr); +ISC_APPFUNC_SCOPE void isc__appctx_setsocketmgr(isc_appctx_t *ctx, + isc_socketmgr_t *socketmgr); +ISC_APPFUNC_SCOPE void isc__appctx_settimermgr(isc_appctx_t *ctx, + isc_timermgr_t *timermgr); + +/* + * The application context of this module. This implementation actually + * doesn't use it. (This may change in the future). + */ +#define APPCTX_MAGIC ISC_MAGIC('A', 'p', 'c', 'x') +#define VALID_APPCTX(c) ISC_MAGIC_VALID(c, APPCTX_MAGIC) + +typedef struct isc__appctx { + isc_appctx_t common; + isc_mem_t *mctx; + isc_mutex_t lock; + isc_eventlist_t on_run; + isc_boolean_t shutdown_requested; + isc_boolean_t running; + + /*! + * We assume that 'want_shutdown' can be read and written atomically. + */ + isc_boolean_t want_shutdown; + /* + * We assume that 'want_reload' can be read and written atomically. + */ + isc_boolean_t want_reload; + + isc_boolean_t blocked; + + isc_taskmgr_t *taskmgr; + isc_socketmgr_t *socketmgr; + isc_timermgr_t *timermgr; +} isc__appctx_t; + +static isc__appctx_t isc_g_appctx; + +static struct { + isc_appmethods_t methods; + + /*% + * The following are defined just for avoiding unused static functions. + */ +#ifndef BIND9 + void *run, *shutdown, *start, *onrun, *reload, *finish, + *block, *unblock; +#endif +} appmethods = { + { + isc__appctx_destroy, + isc__app_ctxstart, + isc__app_ctxrun, + isc__app_ctxsuspend, + isc__app_ctxshutdown, + isc__app_ctxfinish, + isc__appctx_settaskmgr, + isc__appctx_setsocketmgr, + isc__appctx_settimermgr + } +#ifndef BIND9 + , + (void *)isc__app_run, (void *)isc__app_shutdown, + (void *)isc__app_start, (void *)isc__app_onrun, (void *)isc__app_reload, + (void *)isc__app_finish, (void *)isc__app_block, + (void *)isc__app_unblock +#endif +}; + +#ifdef HAVE_LINUXTHREADS +/*! + * Linux has sigwait(), but it appears to prevent signal handlers from + * running, even if they're not in the set being waited for. This makes + * it impossible to get the default actions for SIGILL, SIGSEGV, etc. + * Instead of messing with it, we just use sigsuspend() instead. + */ +#undef HAVE_SIGWAIT +/*! + * We need to remember which thread is the main thread... + */ +static pthread_t main_thread; +#endif + +#ifndef HAVE_SIGWAIT +static void +exit_action(int arg) { + UNUSED(arg); + isc_g_appctx.want_shutdown = ISC_TRUE; +} + +static void +reload_action(int arg) { + UNUSED(arg); + isc_g_appctx.want_reload = ISC_TRUE; +} +#endif + +static isc_result_t +handle_signal(int sig, void (*handler)(int)) { + struct sigaction sa; + char strbuf[ISC_STRERRORSIZE]; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = handler; + + if (sigfillset(&sa.sa_mask) != 0 || + sigaction(sig, &sa, NULL) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + isc_msgcat_get(isc_msgcat, ISC_MSGSET_APP, + ISC_MSG_SIGNALSETUP, + "handle_signal() %d setup: %s"), + sig, strbuf); + return (ISC_R_UNEXPECTED); + } + + return (ISC_R_SUCCESS); +} + +ISC_APPFUNC_SCOPE isc_result_t +isc__app_ctxstart(isc_appctx_t *ctx0) { + isc__appctx_t *ctx = (isc__appctx_t *)ctx0; + isc_result_t result; + + REQUIRE(VALID_APPCTX(ctx)); + + /* + * Start an ISC library application. + */ + +#ifdef NEED_PTHREAD_INIT + /* + * BSDI 3.1 seg faults in pthread_sigmask() if we don't do this. + */ + presult = pthread_init(); + if (presult != 0) { + isc__strerror(presult, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_app_start() pthread_init: %s", strbuf); + return (ISC_R_UNEXPECTED); + } +#endif + +#ifdef HAVE_LINUXTHREADS + main_thread = pthread_self(); +#endif + + result = isc_mutex_init(&ctx->lock); + if (result != ISC_R_SUCCESS) + return (result); + + ISC_LIST_INIT(ctx->on_run); + + ctx->shutdown_requested = ISC_FALSE; + ctx->running = ISC_FALSE; + ctx->want_shutdown = ISC_FALSE; + ctx->want_reload = ISC_FALSE; + ctx->blocked = ISC_FALSE; + + return (ISC_R_SUCCESS); +} + +ISC_APPFUNC_SCOPE isc_result_t +isc__app_start(void) { + isc_result_t result; + int presult; + sigset_t sset; + char strbuf[ISC_STRERRORSIZE]; + + isc_g_appctx.common.impmagic = APPCTX_MAGIC; + isc_g_appctx.common.magic = ISCAPI_APPCTX_MAGIC; + isc_g_appctx.common.methods = &appmethods.methods; + isc_g_appctx.mctx = NULL; + /* The remaining members will be initialized in ctxstart() */ + + result = isc__app_ctxstart((isc_appctx_t *)&isc_g_appctx); + if (result != ISC_R_SUCCESS) + return (result); + +#ifndef HAVE_SIGWAIT + /* + * Install do-nothing handlers for SIGINT and SIGTERM. + * + * We install them now because BSDI 3.1 won't block + * the default actions, regardless of what we do with + * pthread_sigmask(). + */ + result = handle_signal(SIGINT, exit_action); + if (result != ISC_R_SUCCESS) + return (result); + result = handle_signal(SIGTERM, exit_action); + if (result != ISC_R_SUCCESS) + return (result); +#endif + + /* + * Always ignore SIGPIPE. + */ + result = handle_signal(SIGPIPE, SIG_IGN); + if (result != ISC_R_SUCCESS) + return (result); + + /* + * On Solaris 2, delivery of a signal whose action is SIG_IGN + * will not cause sigwait() to return. We may have inherited + * unexpected actions for SIGHUP, SIGINT, and SIGTERM from our parent + * process (e.g, Solaris cron). Set an action of SIG_DFL to make + * sure sigwait() works as expected. Only do this for SIGTERM and + * SIGINT if we don't have sigwait(), since a different handler is + * installed above. + */ + result = handle_signal(SIGHUP, SIG_DFL); + if (result != ISC_R_SUCCESS) + return (result); + +#ifdef HAVE_SIGWAIT + result = handle_signal(SIGTERM, SIG_DFL); + if (result != ISC_R_SUCCESS) + return (result); + result = handle_signal(SIGINT, SIG_DFL); + if (result != ISC_R_SUCCESS) + return (result); +#endif + +#ifdef ISC_PLATFORM_USETHREADS + /* + * Block SIGHUP, SIGINT, SIGTERM. + * + * If isc_app_start() is called from the main thread before any other + * threads have been created, then the pthread_sigmask() call below + * will result in all threads having SIGHUP, SIGINT and SIGTERM + * blocked by default, ensuring that only the thread that calls + * sigwait() for them will get those signals. + */ + if (sigemptyset(&sset) != 0 || + sigaddset(&sset, SIGHUP) != 0 || + sigaddset(&sset, SIGINT) != 0 || + sigaddset(&sset, SIGTERM) != 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_app_start() sigsetops: %s", strbuf); + return (ISC_R_UNEXPECTED); + } + presult = pthread_sigmask(SIG_BLOCK, &sset, NULL); + if (presult != 0) { + isc__strerror(presult, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_app_start() pthread_sigmask: %s", + strbuf); + return (ISC_R_UNEXPECTED); + } +#else /* ISC_PLATFORM_USETHREADS */ + /* + * Unblock SIGHUP, SIGINT, SIGTERM. + * + * If we're not using threads, we need to make sure that SIGHUP, + * SIGINT and SIGTERM are not inherited as blocked from the parent + * process. + */ + if (sigemptyset(&sset) != 0 || + sigaddset(&sset, SIGHUP) != 0 || + sigaddset(&sset, SIGINT) != 0 || + sigaddset(&sset, SIGTERM) != 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_app_start() sigsetops: %s", strbuf); + return (ISC_R_UNEXPECTED); + } + presult = sigprocmask(SIG_UNBLOCK, &sset, NULL); + if (presult != 0) { + isc__strerror(presult, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_app_start() sigprocmask: %s", strbuf); + return (ISC_R_UNEXPECTED); + } +#endif /* ISC_PLATFORM_USETHREADS */ + + return (ISC_R_SUCCESS); +} + +ISC_APPFUNC_SCOPE isc_result_t +isc__app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action, + void *arg) +{ + isc_event_t *event; + isc_task_t *cloned_task = NULL; + isc_result_t result; + + LOCK(&isc_g_appctx.lock); + + if (isc_g_appctx.running) { + result = ISC_R_ALREADYRUNNING; + goto unlock; + } + + /* + * Note that we store the task to which we're going to send the event + * in the event's "sender" field. + */ + isc_task_attach(task, &cloned_task); + event = isc_event_allocate(mctx, cloned_task, ISC_APPEVENT_SHUTDOWN, + action, arg, sizeof(*event)); + if (event == NULL) { + result = ISC_R_NOMEMORY; + goto unlock; + } + + ISC_LIST_APPEND(isc_g_appctx.on_run, event, ev_link); + + result = ISC_R_SUCCESS; + + unlock: + UNLOCK(&isc_g_appctx.lock); + + return (result); +} + +#ifndef USE_THREADS_SINGLECTX +/*! + * Event loop for nonthreaded programs. + */ +static isc_result_t +evloop(isc__appctx_t *ctx) { + isc_result_t result; + + while (!ctx->want_shutdown) { + int n; + isc_time_t when, now; + struct timeval tv, *tvp; + isc_socketwait_t *swait; + isc_boolean_t readytasks; + isc_boolean_t call_timer_dispatch = ISC_FALSE; + + /* + * Check the reload (or suspend) case first for exiting the + * loop as fast as possible in case: + * - the direct call to isc__taskmgr_dispatch() in + * isc__app_ctxrun() completes all the tasks so far, + * - there is thus currently no active task, and + * - there is a timer event + */ + if (ctx->want_reload) { + ctx->want_reload = ISC_FALSE; + return (ISC_R_RELOAD); + } + + readytasks = isc__taskmgr_ready(ctx->taskmgr); + if (readytasks) { + tv.tv_sec = 0; + tv.tv_usec = 0; + tvp = &tv; + call_timer_dispatch = ISC_TRUE; + } else { + result = isc__timermgr_nextevent(ctx->timermgr, &when); + if (result != ISC_R_SUCCESS) + tvp = NULL; + else { + isc_uint64_t us; + + TIME_NOW(&now); + us = isc_time_microdiff(&when, &now); + if (us == 0) + call_timer_dispatch = ISC_TRUE; + tv.tv_sec = us / 1000000; + tv.tv_usec = us % 1000000; + tvp = &tv; + } + } + + swait = NULL; + n = isc__socketmgr_waitevents(ctx->socketmgr, tvp, &swait); + + if (n == 0 || call_timer_dispatch) { + /* + * We call isc__timermgr_dispatch() only when + * necessary, in order to reduce overhead. If the + * select() call indicates a timeout, we need the + * dispatch. Even if not, if we set the 0-timeout + * for the select() call, we need to check the timer + * events. In the 'readytasks' case, there may be no + * timeout event actually, but there is no other way + * to reduce the overhead. + * Note that we do not have to worry about the case + * where a new timer is inserted during the select() + * call, since this loop only runs in the non-thread + * mode. + */ + isc__timermgr_dispatch(ctx->timermgr); + } + if (n > 0) + (void)isc__socketmgr_dispatch(ctx->socketmgr, swait); + (void)isc__taskmgr_dispatch(ctx->taskmgr); + } + return (ISC_R_SUCCESS); +} +#endif /* USE_THREADS_SINGLECTX */ + +#ifndef ISC_PLATFORM_USETHREADS +/* + * This is a gross hack to support waiting for condition + * variables in nonthreaded programs in a limited way; + * see lib/isc/nothreads/include/isc/condition.h. + * We implement isc_condition_wait() by entering the + * event loop recursively until the want_shutdown flag + * is set by isc_condition_signal(). + */ + +/*! + * \brief True if we are currently executing in the recursive + * event loop. + */ +static isc_boolean_t in_recursive_evloop = ISC_FALSE; + +/*! + * \brief True if we are exiting the event loop as the result of + * a call to isc_condition_signal() rather than a shutdown + * or reload. + */ +static isc_boolean_t signalled = ISC_FALSE; + +isc_result_t +isc__nothread_wait_hack(isc_condition_t *cp, isc_mutex_t *mp) { + isc_result_t result; + + UNUSED(cp); + UNUSED(mp); + + INSIST(!in_recursive_evloop); + in_recursive_evloop = ISC_TRUE; + + INSIST(*mp == 1); /* Mutex must be locked on entry. */ + --*mp; + + result = evloop(&isc_g_appctx); + if (result == ISC_R_RELOAD) + isc_g_appctx.want_reload = ISC_TRUE; + if (signalled) { + isc_g_appctx.want_shutdown = ISC_FALSE; + signalled = ISC_FALSE; + } + + ++*mp; + in_recursive_evloop = ISC_FALSE; + return (ISC_R_SUCCESS); +} + +isc_result_t +isc__nothread_signal_hack(isc_condition_t *cp) { + + UNUSED(cp); + + INSIST(in_recursive_evloop); + + isc_g_appctx.want_shutdown = ISC_TRUE; + signalled = ISC_TRUE; + return (ISC_R_SUCCESS); +} + +#endif /* ISC_PLATFORM_USETHREADS */ + +ISC_APPFUNC_SCOPE isc_result_t +isc__app_ctxrun(isc_appctx_t *ctx0) { + isc__appctx_t *ctx = (isc__appctx_t *)ctx0; + int result; + isc_event_t *event, *next_event; + isc_task_t *task; +#ifdef USE_THREADS_SINGLECTX + sigset_t sset; + char strbuf[ISC_STRERRORSIZE]; +#ifdef HAVE_SIGWAIT + int sig; +#endif +#endif /* USE_THREADS_SINGLECTX */ + + REQUIRE(VALID_APPCTX(ctx)); + +#ifdef HAVE_LINUXTHREADS + REQUIRE(main_thread == pthread_self()); +#endif + + LOCK(&ctx->lock); + + if (!ctx->running) { + ctx->running = ISC_TRUE; + + /* + * Post any on-run events (in FIFO order). + */ + for (event = ISC_LIST_HEAD(ctx->on_run); + event != NULL; + event = next_event) { + next_event = ISC_LIST_NEXT(event, ev_link); + ISC_LIST_UNLINK(ctx->on_run, event, ev_link); + task = event->ev_sender; + event->ev_sender = NULL; + isc_task_sendanddetach(&task, &event); + } + + } + + UNLOCK(&ctx->lock); + +#ifndef HAVE_SIGWAIT + /* + * Catch SIGHUP. + * + * We do this here to ensure that the signal handler is installed + * (i.e. that it wasn't a "one-shot" handler). + */ + if (ctx == &isc_g_appctx) { + result = handle_signal(SIGHUP, reload_action); + if (result != ISC_R_SUCCESS) + return (ISC_R_SUCCESS); + } +#endif + +#ifdef USE_THREADS_SINGLECTX + /* + * When we are using multiple contexts, we don't rely on signals. + */ + if (ctx != &isc_g_appctx) + return (ISC_R_SUCCESS); + + /* + * There is no danger if isc_app_shutdown() is called before we wait + * for signals. Signals are blocked, so any such signal will simply + * be made pending and we will get it when we call sigwait(). + */ + + while (!ctx->want_shutdown) { +#ifdef HAVE_SIGWAIT + /* + * Wait for SIGHUP, SIGINT, or SIGTERM. + */ + if (sigemptyset(&sset) != 0 || + sigaddset(&sset, SIGHUP) != 0 || + sigaddset(&sset, SIGINT) != 0 || + sigaddset(&sset, SIGTERM) != 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_app_run() sigsetops: %s", strbuf); + return (ISC_R_UNEXPECTED); + } + +#ifndef HAVE_UNIXWARE_SIGWAIT + result = sigwait(&sset, &sig); + if (result == 0) { + if (sig == SIGINT || sig == SIGTERM) + ctx->want_shutdown = ISC_TRUE; + else if (sig == SIGHUP) + ctx->want_reload = ISC_TRUE; + } + +#else /* Using UnixWare sigwait semantics. */ + sig = sigwait(&sset); + if (sig >= 0) { + if (sig == SIGINT || sig == SIGTERM) + ctx->want_shutdown = ISC_TRUE; + else if (sig == SIGHUP) + ctx->want_reload = ISC_TRUE; + } + +#endif /* HAVE_UNIXWARE_SIGWAIT */ +#else /* Don't have sigwait(). */ + /* + * Listen for all signals. + */ + if (sigemptyset(&sset) != 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_app_run() sigsetops: %s", + strbuf); + return (ISC_R_UNEXPECTED); + } + result = sigsuspend(&sset); +#endif /* HAVE_SIGWAIT */ + + if (ctx->want_reload) { + ctx->want_reload = ISC_FALSE; + return (ISC_R_RELOAD); + } + + if (ctx->want_shutdown && ctx->blocked) + exit(1); + } + +#else /* USE_THREADS_SINGLECTX */ + + (void)isc__taskmgr_dispatch(ctx->taskmgr); + + result = evloop(ctx); + if (result != ISC_R_SUCCESS) + return (result); + +#endif /* USE_THREADS_SINGLECTX */ + + return (ISC_R_SUCCESS); +} + +ISC_APPFUNC_SCOPE isc_result_t +isc__app_run() { + return (isc__app_ctxrun((isc_appctx_t *)&isc_g_appctx)); +} + +ISC_APPFUNC_SCOPE isc_result_t +isc__app_ctxshutdown(isc_appctx_t *ctx0) { + isc__appctx_t *ctx = (isc__appctx_t *)ctx0; + isc_boolean_t want_kill = ISC_TRUE; + char strbuf[ISC_STRERRORSIZE]; + + REQUIRE(VALID_APPCTX(ctx)); + + LOCK(&ctx->lock); + + REQUIRE(ctx->running); + + if (ctx->shutdown_requested) + want_kill = ISC_FALSE; + else + ctx->shutdown_requested = ISC_TRUE; + + UNLOCK(&ctx->lock); + + if (want_kill) { + if (ctx != &isc_g_appctx) + ctx->want_shutdown = ISC_TRUE; + else { +#ifdef HAVE_LINUXTHREADS + int result; + + result = pthread_kill(main_thread, SIGTERM); + if (result != 0) { + isc__strerror(result, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_app_shutdown() " + "pthread_kill: %s", + strbuf); + return (ISC_R_UNEXPECTED); + } +#else + if (kill(getpid(), SIGTERM) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_app_shutdown() " + "kill: %s", strbuf); + return (ISC_R_UNEXPECTED); + } +#endif /* HAVE_LINUXTHREADS */ + } + } + + return (ISC_R_SUCCESS); +} + +ISC_APPFUNC_SCOPE isc_result_t +isc__app_shutdown() { + return (isc__app_ctxshutdown((isc_appctx_t *)&isc_g_appctx)); +} + +ISC_APPFUNC_SCOPE isc_result_t +isc__app_ctxsuspend(isc_appctx_t *ctx0) { + isc__appctx_t *ctx = (isc__appctx_t *)ctx0; + isc_boolean_t want_kill = ISC_TRUE; + char strbuf[ISC_STRERRORSIZE]; + + REQUIRE(VALID_APPCTX(ctx)); + + LOCK(&ctx->lock); + + REQUIRE(ctx->running); + + /* + * Don't send the reload signal if we're shutting down. + */ + if (ctx->shutdown_requested) + want_kill = ISC_FALSE; + + UNLOCK(&ctx->lock); + + if (want_kill) { + if (ctx != &isc_g_appctx) + ctx->want_reload = ISC_TRUE; + else { +#ifdef HAVE_LINUXTHREADS + int result; + + result = pthread_kill(main_thread, SIGHUP); + if (result != 0) { + isc__strerror(result, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_app_reload() " + "pthread_kill: %s", + strbuf); + return (ISC_R_UNEXPECTED); + } +#else + if (kill(getpid(), SIGHUP) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_app_reload() " + "kill: %s", strbuf); + return (ISC_R_UNEXPECTED); + } +#endif + } + } + + return (ISC_R_SUCCESS); +} + +ISC_APPFUNC_SCOPE isc_result_t +isc__app_reload(void) { + return (isc__app_ctxsuspend((isc_appctx_t *)&isc_g_appctx)); +} + +ISC_APPFUNC_SCOPE void +isc__app_ctxfinish(isc_appctx_t *ctx0) { + isc__appctx_t *ctx = (isc__appctx_t *)ctx0; + + REQUIRE(VALID_APPCTX(ctx)); + + DESTROYLOCK(&ctx->lock); +} + +ISC_APPFUNC_SCOPE void +isc__app_finish(void) { + isc__app_ctxfinish((isc_appctx_t *)&isc_g_appctx); +} + +ISC_APPFUNC_SCOPE void +isc__app_block(void) { +#ifdef ISC_PLATFORM_USETHREADS + sigset_t sset; +#endif /* ISC_PLATFORM_USETHREADS */ + REQUIRE(isc_g_appctx.running); + REQUIRE(!isc_g_appctx.blocked); + + isc_g_appctx.blocked = ISC_TRUE; +#ifdef ISC_PLATFORM_USETHREADS + blockedthread = pthread_self(); + RUNTIME_CHECK(sigemptyset(&sset) == 0 && + sigaddset(&sset, SIGINT) == 0 && + sigaddset(&sset, SIGTERM) == 0); + RUNTIME_CHECK(pthread_sigmask(SIG_UNBLOCK, &sset, NULL) == 0); +#endif /* ISC_PLATFORM_USETHREADS */ +} + +ISC_APPFUNC_SCOPE void +isc__app_unblock(void) { +#ifdef ISC_PLATFORM_USETHREADS + sigset_t sset; +#endif /* ISC_PLATFORM_USETHREADS */ + + REQUIRE(isc_g_appctx.running); + REQUIRE(isc_g_appctx.blocked); + + isc_g_appctx.blocked = ISC_FALSE; + +#ifdef ISC_PLATFORM_USETHREADS + REQUIRE(blockedthread == pthread_self()); + + RUNTIME_CHECK(sigemptyset(&sset) == 0 && + sigaddset(&sset, SIGINT) == 0 && + sigaddset(&sset, SIGTERM) == 0); + RUNTIME_CHECK(pthread_sigmask(SIG_BLOCK, &sset, NULL) == 0); +#endif /* ISC_PLATFORM_USETHREADS */ +} + +ISC_APPFUNC_SCOPE isc_result_t +isc__appctx_create(isc_mem_t *mctx, isc_appctx_t **ctxp) { + isc__appctx_t *ctx; + + REQUIRE(mctx != NULL); + REQUIRE(ctxp != NULL && *ctxp == NULL); + + ctx = isc_mem_get(mctx, sizeof(*ctx)); + if (ctx == NULL) + return (ISC_R_NOMEMORY); + + ctx->common.impmagic = APPCTX_MAGIC; + ctx->common.magic = ISCAPI_APPCTX_MAGIC; + ctx->common.methods = &appmethods.methods; + + ctx->mctx = NULL; + isc_mem_attach(mctx, &ctx->mctx); + + ctx->taskmgr = NULL; + ctx->socketmgr = NULL; + ctx->timermgr = NULL; + + *ctxp = (isc_appctx_t *)ctx; + + return (ISC_R_SUCCESS); +} + +ISC_APPFUNC_SCOPE void +isc__appctx_destroy(isc_appctx_t **ctxp) { + isc__appctx_t *ctx; + + REQUIRE(ctxp != NULL); + ctx = (isc__appctx_t *)*ctxp; + REQUIRE(VALID_APPCTX(ctx)); + + isc_mem_putanddetach(&ctx->mctx, ctx, sizeof(*ctx)); + + *ctxp = NULL; +} + +ISC_APPFUNC_SCOPE void +isc__appctx_settaskmgr(isc_appctx_t *ctx0, isc_taskmgr_t *taskmgr) { + isc__appctx_t *ctx = (isc__appctx_t *)ctx0; + + REQUIRE(VALID_APPCTX(ctx)); + + ctx->taskmgr = taskmgr; +} + +ISC_APPFUNC_SCOPE void +isc__appctx_setsocketmgr(isc_appctx_t *ctx0, isc_socketmgr_t *socketmgr) { + isc__appctx_t *ctx = (isc__appctx_t *)ctx0; + + REQUIRE(VALID_APPCTX(ctx)); + + ctx->socketmgr = socketmgr; +} + +ISC_APPFUNC_SCOPE void +isc__appctx_settimermgr(isc_appctx_t *ctx0, isc_timermgr_t *timermgr) { + isc__appctx_t *ctx = (isc__appctx_t *)ctx0; + + REQUIRE(VALID_APPCTX(ctx)); + + ctx->timermgr = timermgr; +} + +#ifdef USE_APPIMPREGISTER +isc_result_t +isc__app_register() { + return (isc_app_register(isc__appctx_create)); +} +#endif diff --git a/contrib/ntp/lib/isc/unix/dir.c b/contrib/ntp/lib/isc/unix/dir.c new file mode 100644 index 0000000..613ee56 --- /dev/null +++ b/contrib/ntp/lib/isc/unix/dir.c @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2004, 2005, 2007-2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/*! \file + * \author Principal Authors: DCL */ + +#include <config.h> + +#include <sys/types.h> +#include <sys/stat.h> + +#include <ctype.h> +#include <errno.h> +#include <unistd.h> + +#include <isc/dir.h> +#include <isc/magic.h> +#include <isc/string.h> +#include <isc/util.h> + +#include "errno2result.h" +#include "ntp_stdlib.h" /* NTP change for strlcpy, strlcat */ + +#define ISC_DIR_MAGIC ISC_MAGIC('D', 'I', 'R', '*') +#define VALID_DIR(dir) ISC_MAGIC_VALID(dir, ISC_DIR_MAGIC) + +void +isc_dir_init(isc_dir_t *dir) { + REQUIRE(dir != NULL); + + dir->entry.name[0] = '\0'; + dir->entry.length = 0; + + dir->handle = NULL; + + dir->magic = ISC_DIR_MAGIC; +} + +/*! + * \brief Allocate workspace and open directory stream. If either one fails, + * NULL will be returned. + */ +isc_result_t +isc_dir_open(isc_dir_t *dir, const char *dirname) { + char *p; + size_t octets; + isc_result_t result = ISC_R_SUCCESS; + + REQUIRE(VALID_DIR(dir)); + REQUIRE(dirname != NULL); + + /* + * Copy directory name. Need to have enough space for the name, + * a possible path separator, the wildcard, and the final NUL. + */ + octets = strlen(dirname) + 1; + if (octets + 2 > sizeof(dir->dirname)) + /* XXXDCL ? */ + return (ISC_R_NOSPACE); + strlcpy(dir->dirname, dirname, octets); + + /* + * Append path separator, if needed, and "*". + */ + p = dir->dirname + strlen(dir->dirname); + if (dir->dirname < p && *(p - 1) != '/') + *p++ = '/'; + *p++ = '*'; + *p = '\0'; + + /* + * Open stream. + */ + dir->handle = opendir(dirname); + + if (dir->handle == NULL) + return isc__errno2result(errno); + + return (result); +} + +/*! + * \brief Return previously retrieved file or get next one. + + * Unix's dirent has + * separate open and read functions, but the Win32 and DOS interfaces open + * the dir stream and reads the first file in one operation. + */ +isc_result_t +isc_dir_read(isc_dir_t *dir) { + struct dirent *entry; + size_t octets; + + REQUIRE(VALID_DIR(dir) && dir->handle != NULL); + + /* + * Fetch next file in directory. + */ + entry = readdir(dir->handle); + + if (entry == NULL) + return (ISC_R_NOMORE); + + /* + * Make sure that the space for the name is long enough. + */ + octets = strlen(entry->d_name) + 1; + if (sizeof(dir->entry.name) < octets) + return (ISC_R_UNEXPECTED); + + strlcpy(dir->entry.name, entry->d_name, octets); + + /* + * Some dirents have d_namlen, but it is not portable. + */ + dir->entry.length = strlen(entry->d_name); + + return (ISC_R_SUCCESS); +} + +/*! + * \brief Close directory stream. + */ +void +isc_dir_close(isc_dir_t *dir) { + REQUIRE(VALID_DIR(dir) && dir->handle != NULL); + + (void)closedir(dir->handle); + dir->handle = NULL; +} + +/*! + * \brief Reposition directory stream at start. + */ +isc_result_t +isc_dir_reset(isc_dir_t *dir) { + REQUIRE(VALID_DIR(dir) && dir->handle != NULL); + + rewinddir(dir->handle); + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_dir_chdir(const char *dirname) { + /*! + * \brief Change the current directory to 'dirname'. + */ + + REQUIRE(dirname != NULL); + + if (chdir(dirname) < 0) + return (isc__errno2result(errno)); + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_dir_chroot(const char *dirname) { + + REQUIRE(dirname != NULL); + +#ifdef HAVE_CHROOT + if (chroot(dirname) < 0 || chdir("/") < 0) + return (isc__errno2result(errno)); + + return (ISC_R_SUCCESS); +#else + return (ISC_R_NOTIMPLEMENTED); +#endif +} + +isc_result_t +isc_dir_createunique(char *templet) { + isc_result_t result; + char *x; + char *p; + int i; + int pid; + + REQUIRE(templet != NULL); + + /*! + * \brief mkdtemp is not portable, so this emulates it. + */ + + pid = getpid(); + + /* + * Replace trailing Xs with the process-id, zero-filled. + */ + for (x = templet + strlen(templet) - 1; *x == 'X' && x >= templet; + x--, pid /= 10) + *x = pid % 10 + '0'; + + x++; /* Set x to start of ex-Xs. */ + + do { + i = mkdir(templet, 0700); + if (i == 0 || errno != EEXIST) + break; + + /* + * The BSD algorithm. + */ + p = x; + while (*p != '\0') { + if (isdigit(*p & 0xff)) + *p = 'a'; + else if (*p != 'z') + ++*p; + else { + /* + * Reset character and move to next. + */ + *p++ = 'a'; + continue; + } + + break; + } + + if (*p == '\0') { + /* + * Tried all combinations. errno should already + * be EEXIST, but ensure it is anyway for + * isc__errno2result(). + */ + errno = EEXIST; + break; + } + } while (1); + + if (i == -1) + result = isc__errno2result(errno); + else + result = ISC_R_SUCCESS; + + return (result); +} diff --git a/contrib/ntp/lib/isc/unix/entropy.c b/contrib/ntp/lib/isc/unix/entropy.c new file mode 100644 index 0000000..ab53faf --- /dev/null +++ b/contrib/ntp/lib/isc/unix/entropy.c @@ -0,0 +1,605 @@ +/* + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000-2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: entropy.c,v 1.82 2008/12/01 23:47:45 tbox Exp $ */ + +/* \file unix/entropy.c + * \brief + * This is the system dependent part of the ISC entropy API. + */ + +#include <config.h> + +#include <sys/param.h> /* Openserver 5.0.6A and FD_SETSIZE */ +#include <sys/types.h> +#include <sys/time.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/un.h> + +#ifdef HAVE_NANOSLEEP +#include <time.h> +#endif +#include <unistd.h> + +#include <isc/platform.h> +#include <isc/strerror.h> + +#ifdef ISC_PLATFORM_NEEDSYSSELECTH +#include <sys/select.h> +#endif + +#include "errno2result.h" + +/*% + * There is only one variable in the entropy data structures that is not + * system independent, but pulling the structure that uses it into this file + * ultimately means pulling several other independent structures here also to + * resolve their interdependencies. Thus only the problem variable's type + * is defined here. + */ +#define FILESOURCE_HANDLE_TYPE int + +typedef struct { + int handle; + enum { + isc_usocketsource_disconnected, + isc_usocketsource_connecting, + isc_usocketsource_connected, + isc_usocketsource_ndesired, + isc_usocketsource_wrote, + isc_usocketsource_reading + } status; + size_t sz_to_recv; +} isc_entropyusocketsource_t; + +#include "../entropy.c" + +static unsigned int +get_from_filesource(isc_entropysource_t *source, isc_uint32_t desired) { + isc_entropy_t *ent = source->ent; + unsigned char buf[128]; + int fd = source->sources.file.handle; + ssize_t n, ndesired; + unsigned int added; + + if (source->bad) + return (0); + + desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0); + + added = 0; + while (desired > 0) { + ndesired = ISC_MIN(desired, sizeof(buf)); + n = read(fd, buf, ndesired); + if (n < 0) { + if (errno == EAGAIN || errno == EINTR) + goto out; + goto err; + } + if (n == 0) + goto err; + + entropypool_adddata(ent, buf, n, n * 8); + added += n * 8; + desired -= n; + } + goto out; + + err: + (void)close(fd); + source->sources.file.handle = -1; + source->bad = ISC_TRUE; + + out: + return (added); +} + +static unsigned int +get_from_usocketsource(isc_entropysource_t *source, isc_uint32_t desired) { + isc_entropy_t *ent = source->ent; + unsigned char buf[128]; + int fd = source->sources.usocket.handle; + ssize_t n = 0, ndesired; + unsigned int added; + size_t sz_to_recv = source->sources.usocket.sz_to_recv; + + if (source->bad) + return (0); + + desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0); + + added = 0; + while (desired > 0) { + ndesired = ISC_MIN(desired, sizeof(buf)); + eagain_loop: + + switch ( source->sources.usocket.status ) { + case isc_usocketsource_ndesired: + buf[0] = ndesired; + if ((n = sendto(fd, buf, 1, 0, NULL, 0)) < 0) { + if (errno == EWOULDBLOCK || errno == EINTR || + errno == ECONNRESET) + goto out; + goto err; + } + INSIST(n == 1); + source->sources.usocket.status = + isc_usocketsource_wrote; + goto eagain_loop; + + case isc_usocketsource_connecting: + case isc_usocketsource_connected: + buf[0] = 1; + buf[1] = ndesired; + if ((n = sendto(fd, buf, 2, 0, NULL, 0)) < 0) { + if (errno == EWOULDBLOCK || errno == EINTR || + errno == ECONNRESET) + goto out; + goto err; + } + if (n == 1) { + source->sources.usocket.status = + isc_usocketsource_ndesired; + goto eagain_loop; + } + INSIST(n == 2); + source->sources.usocket.status = + isc_usocketsource_wrote; + /*FALLTHROUGH*/ + + case isc_usocketsource_wrote: + if (recvfrom(fd, buf, 1, 0, NULL, NULL) != 1) { + if (errno == EAGAIN) { + /* + * The problem of EAGAIN (try again + * later) is a major issue on HP-UX. + * Solaris actually tries the recvfrom + * call again, while HP-UX just dies. + * This code is an attempt to let the + * entropy pool fill back up (at least + * that's what I think the problem is.) + * We go to eagain_loop because if we + * just "break", then the "desired" + * amount gets borked. + */ +#ifdef HAVE_NANOSLEEP + struct timespec ts; + + ts.tv_sec = 0; + ts.tv_nsec = 1000000; + nanosleep(&ts, NULL); +#else + usleep(1000); +#endif + goto eagain_loop; + } + if (errno == EWOULDBLOCK || errno == EINTR) + goto out; + goto err; + } + source->sources.usocket.status = + isc_usocketsource_reading; + sz_to_recv = buf[0]; + source->sources.usocket.sz_to_recv = sz_to_recv; + if (sz_to_recv > sizeof(buf)) + goto err; + /*FALLTHROUGH*/ + + case isc_usocketsource_reading: + if (sz_to_recv != 0U) { + n = recv(fd, buf, sz_to_recv, 0); + if (n < 0) { + if (errno == EWOULDBLOCK || + errno == EINTR) + goto out; + goto err; + } + } else + n = 0; + break; + + default: + goto err; + } + + if ((size_t)n != sz_to_recv) + source->sources.usocket.sz_to_recv -= n; + else + source->sources.usocket.status = + isc_usocketsource_connected; + + if (n == 0) + goto out; + + entropypool_adddata(ent, buf, n, n * 8); + added += n * 8; + desired -= n; + } + goto out; + + err: + close(fd); + source->bad = ISC_TRUE; + source->sources.usocket.status = isc_usocketsource_disconnected; + source->sources.usocket.handle = -1; + + out: + return (added); +} + +/* + * Poll each source, trying to get data from it to stuff into the entropy + * pool. + */ +static void +fillpool(isc_entropy_t *ent, unsigned int desired, isc_boolean_t blocking) { + unsigned int added; + unsigned int remaining; + unsigned int needed; + unsigned int nsource; + isc_entropysource_t *source; + + REQUIRE(VALID_ENTROPY(ent)); + + needed = desired; + + /* + * This logic is a little strange, so an explanation is in order. + * + * If needed is 0, it means we are being asked to "fill to whatever + * we think is best." This means that if we have at least a + * partially full pool (say, > 1/4th of the pool) we probably don't + * need to add anything. + * + * Also, we will check to see if the "pseudo" count is too high. + * If it is, try to mix in better data. Too high is currently + * defined as 1/4th of the pool. + * + * Next, if we are asked to add a specific bit of entropy, make + * certain that we will do so. Clamp how much we try to add to + * (DIGEST_SIZE * 8 < needed < POOLBITS - entropy). + * + * Note that if we are in a blocking mode, we will only try to + * get as much data as we need, not as much as we might want + * to build up. + */ + if (needed == 0) { + REQUIRE(!blocking); + + if ((ent->pool.entropy >= RND_POOLBITS / 4) + && (ent->pool.pseudo <= RND_POOLBITS / 4)) + return; + + needed = THRESHOLD_BITS * 4; + } else { + needed = ISC_MAX(needed, THRESHOLD_BITS); + needed = ISC_MIN(needed, RND_POOLBITS); + } + + /* + * In any case, clamp how much we need to how much we can add. + */ + needed = ISC_MIN(needed, RND_POOLBITS - ent->pool.entropy); + + /* + * But wait! If we're not yet initialized, we need at least + * THRESHOLD_BITS + * of randomness. + */ + if (ent->initialized < THRESHOLD_BITS) + needed = ISC_MAX(needed, THRESHOLD_BITS - ent->initialized); + + /* + * Poll each file source to see if we can read anything useful from + * it. XXXMLG When where are multiple sources, we should keep a + * record of which one we last used so we can start from it (or the + * next one) to avoid letting some sources build up entropy while + * others are always drained. + */ + + added = 0; + remaining = needed; + if (ent->nextsource == NULL) { + ent->nextsource = ISC_LIST_HEAD(ent->sources); + if (ent->nextsource == NULL) + return; + } + source = ent->nextsource; + again_file: + for (nsource = 0; nsource < ent->nsources; nsource++) { + unsigned int got; + + if (remaining == 0) + break; + + got = 0; + + switch ( source->type ) { + case ENTROPY_SOURCETYPE_FILE: + got = get_from_filesource(source, remaining); + break; + + case ENTROPY_SOURCETYPE_USOCKET: + got = get_from_usocketsource(source, remaining); + break; + } + + added += got; + + remaining -= ISC_MIN(remaining, got); + + source = ISC_LIST_NEXT(source, link); + if (source == NULL) + source = ISC_LIST_HEAD(ent->sources); + } + ent->nextsource = source; + + if (blocking && remaining != 0) { + int fds; + + fds = wait_for_sources(ent); + if (fds > 0) + goto again_file; + } + + /* + * Here, if there are bits remaining to be had and we can block, + * check to see if we have a callback source. If so, call them. + */ + source = ISC_LIST_HEAD(ent->sources); + while ((remaining != 0) && (source != NULL)) { + unsigned int got; + + got = 0; + + if (source->type == ENTROPY_SOURCETYPE_CALLBACK) + got = get_from_callback(source, remaining, blocking); + + added += got; + remaining -= ISC_MIN(remaining, got); + + if (added >= needed) + break; + + source = ISC_LIST_NEXT(source, link); + } + + /* + * Mark as initialized if we've added enough data. + */ + if (ent->initialized < THRESHOLD_BITS) + ent->initialized += added; +} + +static int +wait_for_sources(isc_entropy_t *ent) { + isc_entropysource_t *source; + int maxfd, fd; + int cc; + fd_set reads; + fd_set writes; + + maxfd = -1; + FD_ZERO(&reads); + FD_ZERO(&writes); + + source = ISC_LIST_HEAD(ent->sources); + while (source != NULL) { + if (source->type == ENTROPY_SOURCETYPE_FILE) { + fd = source->sources.file.handle; + if (fd >= 0) { + maxfd = ISC_MAX(maxfd, fd); + FD_SET(fd, &reads); + } + } + if (source->type == ENTROPY_SOURCETYPE_USOCKET) { + fd = source->sources.usocket.handle; + if (fd >= 0) { + switch (source->sources.usocket.status) { + case isc_usocketsource_disconnected: + break; + case isc_usocketsource_connecting: + case isc_usocketsource_connected: + case isc_usocketsource_ndesired: + maxfd = ISC_MAX(maxfd, fd); + FD_SET(fd, &writes); + break; + case isc_usocketsource_wrote: + case isc_usocketsource_reading: + maxfd = ISC_MAX(maxfd, fd); + FD_SET(fd, &reads); + break; + } + } + } + source = ISC_LIST_NEXT(source, link); + } + + if (maxfd < 0) + return (-1); + + cc = select(maxfd + 1, &reads, &writes, NULL, NULL); + if (cc < 0) + return (-1); + + return (cc); +} + +static void +destroyfilesource(isc_entropyfilesource_t *source) { + (void)close(source->handle); +} + +static void +destroyusocketsource(isc_entropyusocketsource_t *source) { + close(source->handle); +} + +/* + * Make a fd non-blocking + */ +static isc_result_t +make_nonblock(int fd) { + int ret; + int flags; + char strbuf[ISC_STRERRORSIZE]; +#ifdef USE_FIONBIO_IOCTL + int on = 1; + + ret = ioctl(fd, FIONBIO, (char *)&on); +#else + flags = fcntl(fd, F_GETFL, 0); + flags |= PORT_NONBLOCK; + ret = fcntl(fd, F_SETFL, flags); +#endif + + if (ret == -1) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, +#ifdef USE_FIONBIO_IOCTL + "ioctl(%d, FIONBIO, &on): %s", fd, +#else + "fcntl(%d, F_SETFL, %d): %s", fd, flags, +#endif + strbuf); + + return (ISC_R_UNEXPECTED); + } + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_entropy_createfilesource(isc_entropy_t *ent, const char *fname) { + int fd; + struct stat _stat; + isc_boolean_t is_usocket = ISC_FALSE; + isc_boolean_t is_connected = ISC_FALSE; + isc_result_t ret; + isc_entropysource_t *source; + + REQUIRE(VALID_ENTROPY(ent)); + REQUIRE(fname != NULL); + + LOCK(&ent->lock); + + if (stat(fname, &_stat) < 0) { + ret = isc__errno2result(errno); + goto errout; + } + /* + * Solaris 2.5.1 does not have support for sockets (S_IFSOCK), + * but it does return type S_IFIFO (the OS believes that + * the socket is a fifo). This may be an issue if we tell + * the program to look at an actual FIFO as its source of + * entropy. + */ +#if defined(S_ISSOCK) + if (S_ISSOCK(_stat.st_mode)) + is_usocket = ISC_TRUE; +#endif +#if defined(S_ISFIFO) && defined(sun) + if (S_ISFIFO(_stat.st_mode)) + is_usocket = ISC_TRUE; +#endif + if (is_usocket) + fd = socket(PF_UNIX, SOCK_STREAM, 0); + else + fd = open(fname, O_RDONLY | PORT_NONBLOCK, 0); + + if (fd < 0) { + ret = isc__errno2result(errno); + goto errout; + } + + ret = make_nonblock(fd); + if (ret != ISC_R_SUCCESS) + goto closefd; + + if (is_usocket) { + struct sockaddr_un sname; + + memset(&sname, 0, sizeof(sname)); + sname.sun_family = AF_UNIX; + strncpy(sname.sun_path, fname, sizeof(sname.sun_path)); + sname.sun_path[sizeof(sname.sun_path)-1] = '0'; +#ifdef ISC_PLATFORM_HAVESALEN +#if !defined(SUN_LEN) +#define SUN_LEN(su) \ + (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) +#endif + sname.sun_len = SUN_LEN(&sname); +#endif + + if (connect(fd, (struct sockaddr *) &sname, + sizeof(struct sockaddr_un)) < 0) { + if (errno != EINPROGRESS) { + ret = isc__errno2result(errno); + goto closefd; + } + } else + is_connected = ISC_TRUE; + } + + source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t)); + if (source == NULL) { + ret = ISC_R_NOMEMORY; + goto closefd; + } + + /* + * From here down, no failures can occur. + */ + source->magic = SOURCE_MAGIC; + source->ent = ent; + source->total = 0; + source->bad = ISC_FALSE; + memset(source->name, 0, sizeof(source->name)); + ISC_LINK_INIT(source, link); + if (is_usocket) { + source->sources.usocket.handle = fd; + if (is_connected) + source->sources.usocket.status = + isc_usocketsource_connected; + else + source->sources.usocket.status = + isc_usocketsource_connecting; + source->sources.usocket.sz_to_recv = 0; + source->type = ENTROPY_SOURCETYPE_USOCKET; + } else { + source->sources.file.handle = fd; + source->type = ENTROPY_SOURCETYPE_FILE; + } + + /* + * Hook it into the entropy system. + */ + ISC_LIST_APPEND(ent->sources, source, link); + ent->nsources++; + + UNLOCK(&ent->lock); + return (ISC_R_SUCCESS); + + closefd: + (void)close(fd); + + errout: + UNLOCK(&ent->lock); + + return (ret); +} diff --git a/contrib/ntp/lib/isc/unix/errno2result.c b/contrib/ntp/lib/isc/unix/errno2result.c new file mode 100644 index 0000000..f20aa29 --- /dev/null +++ b/contrib/ntp/lib/isc/unix/errno2result.c @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000-2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/*! \file */ + +#include <config.h> + +#include <isc/result.h> +#include <isc/strerror.h> +#include <isc/util.h> + +#include "errno2result.h" + +/*% + * Convert a POSIX errno value into an isc_result_t. The + * list of supported errno values is not complete; new users + * of this function should add any expected errors that are + * not already there. + */ +isc_result_t +isc___errno2result(int posixerrno, const char *file, unsigned int line) { + char strbuf[ISC_STRERRORSIZE]; + + switch (posixerrno) { + case ENOTDIR: + case ELOOP: + case EINVAL: /* XXX sometimes this is not for files */ + case ENAMETOOLONG: + case EBADF: + return (ISC_R_INVALIDFILE); + case ENOENT: + return (ISC_R_FILENOTFOUND); + case EACCES: + case EPERM: + return (ISC_R_NOPERM); + case EEXIST: + return (ISC_R_FILEEXISTS); + case EIO: + return (ISC_R_IOERROR); + case ENOMEM: + return (ISC_R_NOMEMORY); + case ENFILE: + case EMFILE: + return (ISC_R_TOOMANYOPENFILES); + case EPIPE: +#ifdef ECONNRESET + case ECONNRESET: +#endif +#ifdef ECONNABORTED + case ECONNABORTED: +#endif + return (ISC_R_CONNECTIONRESET); +#ifdef ENOTCONN + case ENOTCONN: + return (ISC_R_NOTCONNECTED); +#endif +#ifdef ETIMEDOUT + case ETIMEDOUT: + return (ISC_R_TIMEDOUT); +#endif +#ifdef ENOBUFS + case ENOBUFS: + return (ISC_R_NORESOURCES); +#endif +#ifdef EAFNOSUPPORT + case EAFNOSUPPORT: + return (ISC_R_FAMILYNOSUPPORT); +#endif +#ifdef ENETDOWN + case ENETDOWN: + return (ISC_R_NETDOWN); +#endif +#ifdef EHOSTDOWN + case EHOSTDOWN: + return (ISC_R_HOSTDOWN); +#endif +#ifdef ENETUNREACH + case ENETUNREACH: + return (ISC_R_NETUNREACH); +#endif +#ifdef EHOSTUNREACH + case EHOSTUNREACH: + return (ISC_R_HOSTUNREACH); +#endif +#ifdef EADDRINUSE + case EADDRINUSE: + return (ISC_R_ADDRINUSE); +#endif + case EADDRNOTAVAIL: + return (ISC_R_ADDRNOTAVAIL); + case ECONNREFUSED: + return (ISC_R_CONNREFUSED); + default: + isc__strerror(posixerrno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(file, line, "unable to convert errno " + "to isc_result: %d: %s", + posixerrno, strbuf); + /* + * XXXDCL would be nice if perhaps this function could + * return the system's error string, so the caller + * might have something more descriptive than "unexpected + * error" to log with. + */ + return (ISC_R_UNEXPECTED); + } +} diff --git a/contrib/ntp/lib/isc/unix/errno2result.h b/contrib/ntp/lib/isc/unix/errno2result.h new file mode 100644 index 0000000..1e49ed1 --- /dev/null +++ b/contrib/ntp/lib/isc/unix/errno2result.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +#ifndef UNIX_ERRNO2RESULT_H +#define UNIX_ERRNO2RESULT_H 1 + +/*! \file */ + +/* XXXDCL this should be moved to lib/isc/include/isc/errno2result.h. */ + +#include <errno.h> /* Provides errno. */ + +#include <isc/lang.h> +#include <isc/types.h> + +ISC_LANG_BEGINDECLS + +#define isc__errno2result(x) isc___errno2result(x, __FILE__, __LINE__) + +isc_result_t +isc___errno2result(int posixerrno, const char *file, unsigned int line); + +ISC_LANG_ENDDECLS + +#endif /* UNIX_ERRNO2RESULT_H */ diff --git a/contrib/ntp/lib/isc/unix/file.c b/contrib/ntp/lib/isc/unix/file.c new file mode 100644 index 0000000..3b59e86 --- /dev/null +++ b/contrib/ntp/lib/isc/unix/file.c @@ -0,0 +1,544 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000-2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* + * Portions Copyright (c) 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id$ */ + +/*! \file */ + +#include <config.h> + +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdlib.h> +#include <time.h> /* Required for utimes on some platforms. */ +#include <unistd.h> /* Required for mkstemp on NetBSD. */ + + +#include <sys/stat.h> +#include <sys/time.h> + +#include <isc/dir.h> +#include <isc/file.h> +#include <isc/log.h> +#include <isc/mem.h> +#include <isc/random.h> +#include <isc/string.h> +#include <isc/time.h> +#include <isc/util.h> + +#include "errno2result.h" +#include "ntp_stdlib.h" /* NTP change for strlcpy, strlcat */ + +/* + * XXXDCL As the API for accessing file statistics undoubtedly gets expanded, + * it might be good to provide a mechanism that allows for the results + * of a previous stat() to be used again without having to do another stat, + * such as perl's mechanism of using "_" in place of a file name to indicate + * that the results of the last stat should be used. But then you get into + * annoying MP issues. BTW, Win32 has stat(). + */ +static isc_result_t +file_stats(const char *file, struct stat *stats) { + isc_result_t result = ISC_R_SUCCESS; + + REQUIRE(file != NULL); + REQUIRE(stats != NULL); + + if (stat(file, stats) != 0) + result = isc__errno2result(errno); + + return (result); +} + +isc_result_t +isc_file_getmodtime(const char *file, isc_time_t *itime) { + isc_result_t result; + struct stat stats; + + REQUIRE(file != NULL); + REQUIRE(itime != NULL); + + result = file_stats(file, &stats); + + if (result == ISC_R_SUCCESS) + /* + * XXXDCL some operating systems provide nanoseconds, too, + * such as BSD/OS via st_mtimespec. + */ + isc_time_set(itime, stats.st_mtime, 0); + + return (result); +} + +isc_result_t +isc_file_settime(const char *file, isc_time_t *itime) { + struct timeval times[2]; + + REQUIRE(file != NULL && itime != NULL); + + /* + * tv_sec is at least a 32 bit quantity on all platforms we're + * dealing with, but it is signed on most (all?) of them, + * so we need to make sure the high bit isn't set. This unfortunately + * loses when either: + * * tv_sec becomes a signed 64 bit integer but long is 32 bits + * and isc_time_seconds > LONG_MAX, or + * * isc_time_seconds is changed to be > 32 bits but long is 32 bits + * and isc_time_seconds has at least 33 significant bits. + */ + times[0].tv_sec = times[1].tv_sec = (long)isc_time_seconds(itime); + + /* + * Here is the real check for the high bit being set. + */ + if ((times[0].tv_sec & + (1ULL << (sizeof(times[0].tv_sec) * CHAR_BIT - 1))) != 0) + return (ISC_R_RANGE); + + /* + * isc_time_nanoseconds guarantees a value that divided by 1000 will + * fit into the minimum possible size tv_usec field. Unfortunately, + * we don't know what that type is so can't cast directly ... but + * we can at least cast to signed so the IRIX compiler shuts up. + */ + times[0].tv_usec = times[1].tv_usec = + (isc_int32_t)(isc_time_nanoseconds(itime) / 1000); + + if (utimes(file, times) < 0) + return (isc__errno2result(errno)); + + return (ISC_R_SUCCESS); +} + +#undef TEMPLATE +#define TEMPLATE "tmp-XXXXXXXXXX" /*%< 14 characters. */ + +isc_result_t +isc_file_mktemplate(const char *path, char *buf, size_t buflen) { + return (isc_file_template(path, TEMPLATE, buf, buflen)); +} + +isc_result_t +isc_file_template(const char *path, const char *templet, char *buf, + size_t buflen) { + char *s; + + REQUIRE(path != NULL); + REQUIRE(templet != NULL); + REQUIRE(buf != NULL); + + s = strrchr(templet, '/'); + if (s != NULL) + templet = s + 1; + + s = strrchr(path, '/'); + + if (s != NULL) { + if ((s - path + 1 + strlen(templet) + 1) > buflen) + return (ISC_R_NOSPACE); + + strlcpy(buf, path, buflen); + buf[s - path + 1] = '\0'; + strlcat(buf, templet, buflen); + } else { + if ((strlen(templet) + 1) > buflen) + return (ISC_R_NOSPACE); + + strlcpy(buf, templet, buflen); + } + + return (ISC_R_SUCCESS); +} + +static char alphnum[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + +isc_result_t +isc_file_renameunique(const char *file, char *templet) { + char *x; + char *cp; + isc_uint32_t which; + + REQUIRE(file != NULL); + REQUIRE(templet != NULL); + + cp = templet; + while (*cp != '\0') + cp++; + if (cp == templet) + return (ISC_R_FAILURE); + + x = cp--; + while (cp >= templet && *cp == 'X') { + isc_random_get(&which); + *cp = alphnum[which % (sizeof(alphnum) - 1)]; + x = cp--; + } + while (link(file, templet) == -1) { + if (errno != EEXIST) + return (isc__errno2result(errno)); + for (cp = x;;) { + char *t; + if (*cp == '\0') + return (ISC_R_FAILURE); + t = strchr(alphnum, *cp); + if (t == NULL || *++t == '\0') + *cp++ = alphnum[0]; + else { + *cp = *t; + break; + } + } + } + if (unlink(file) < 0) + if (errno != ENOENT) + return (isc__errno2result(errno)); + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_file_openunique(char *templet, FILE **fp) { + int mode = S_IWUSR|S_IRUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; + return (isc_file_openuniquemode(templet, mode, fp)); +} + +isc_result_t +isc_file_openuniqueprivate(char *templet, FILE **fp) { + int mode = S_IWUSR|S_IRUSR; + return (isc_file_openuniquemode(templet, mode, fp)); +} + +isc_result_t +isc_file_openuniquemode(char *templet, int mode, FILE **fp) { + int fd; + FILE *f; + isc_result_t result = ISC_R_SUCCESS; + char *x; + char *cp; + isc_uint32_t which; + + REQUIRE(templet != NULL); + REQUIRE(fp != NULL && *fp == NULL); + + cp = templet; + while (*cp != '\0') + cp++; + if (cp == templet) + return (ISC_R_FAILURE); + + x = cp--; + while (cp >= templet && *cp == 'X') { + isc_random_get(&which); + *cp = alphnum[which % (sizeof(alphnum) - 1)]; + x = cp--; + } + + + while ((fd = open(templet, O_RDWR|O_CREAT|O_EXCL, mode)) == -1) { + if (errno != EEXIST) + return (isc__errno2result(errno)); + for (cp = x;;) { + char *t; + if (*cp == '\0') + return (ISC_R_FAILURE); + t = strchr(alphnum, *cp); + if (t == NULL || *++t == '\0') + *cp++ = alphnum[0]; + else { + *cp = *t; + break; + } + } + } + f = fdopen(fd, "w+"); + if (f == NULL) { + result = isc__errno2result(errno); + if (remove(templet) < 0) { + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_FILE, ISC_LOG_ERROR, + "remove '%s': failed", templet); + } + (void)close(fd); + } else + *fp = f; + + return (result); +} + +isc_result_t +isc_file_remove(const char *filename) { + int r; + + REQUIRE(filename != NULL); + + r = unlink(filename); + if (r == 0) + return (ISC_R_SUCCESS); + else + return (isc__errno2result(errno)); +} + +isc_result_t +isc_file_rename(const char *oldname, const char *newname) { + int r; + + REQUIRE(oldname != NULL); + REQUIRE(newname != NULL); + + r = rename(oldname, newname); + if (r == 0) + return (ISC_R_SUCCESS); + else + return (isc__errno2result(errno)); +} + +isc_boolean_t +isc_file_exists(const char *pathname) { + struct stat stats; + + REQUIRE(pathname != NULL); + + return (ISC_TF(file_stats(pathname, &stats) == ISC_R_SUCCESS)); +} + +isc_result_t +isc_file_isplainfile(const char *filename) { + /* + * This function returns success if filename is a plain file. + */ + struct stat filestat; + memset(&filestat,0,sizeof(struct stat)); + + if ((stat(filename, &filestat)) == -1) + return(isc__errno2result(errno)); + + if(! S_ISREG(filestat.st_mode)) + return(ISC_R_INVALIDFILE); + + return(ISC_R_SUCCESS); +} + +isc_boolean_t +isc_file_isabsolute(const char *filename) { + REQUIRE(filename != NULL); + return (ISC_TF(filename[0] == '/')); +} + +isc_boolean_t +isc_file_iscurrentdir(const char *filename) { + REQUIRE(filename != NULL); + return (ISC_TF(filename[0] == '.' && filename[1] == '\0')); +} + +isc_boolean_t +isc_file_ischdiridempotent(const char *filename) { + REQUIRE(filename != NULL); + if (isc_file_isabsolute(filename)) + return (ISC_TRUE); + if (isc_file_iscurrentdir(filename)) + return (ISC_TRUE); + return (ISC_FALSE); +} + +const char * +isc_file_basename(const char *filename) { + char *s; + + REQUIRE(filename != NULL); + + s = strrchr(filename, '/'); + if (s == NULL) + return (filename); + + return (s + 1); +} + +isc_result_t +isc_file_progname(const char *filename, char *buf, size_t buflen) { + const char *base; + size_t len; + + REQUIRE(filename != NULL); + REQUIRE(buf != NULL); + + base = isc_file_basename(filename); + len = strlen(base) + 1; + + if (len > buflen) + return (ISC_R_NOSPACE); + memcpy(buf, base, len); + + return (ISC_R_SUCCESS); +} + +/* + * Put the absolute name of the current directory into 'dirname', which is + * a buffer of at least 'length' characters. End the string with the + * appropriate path separator, such that the final product could be + * concatenated with a relative pathname to make a valid pathname string. + */ +static isc_result_t +dir_current(char *dirname, size_t length) { + char *cwd; + isc_result_t result = ISC_R_SUCCESS; + + REQUIRE(dirname != NULL); + REQUIRE(length > 0U); + + cwd = getcwd(dirname, length); + + if (cwd == NULL) { + if (errno == ERANGE) + result = ISC_R_NOSPACE; + else + result = isc__errno2result(errno); + } else { + if (strlen(dirname) + 1 == length) + result = ISC_R_NOSPACE; + else if (dirname[1] != '\0') + strlcat(dirname, "/", length); + } + + return (result); +} + +isc_result_t +isc_file_absolutepath(const char *filename, char *path, size_t pathlen) { + isc_result_t result; + result = dir_current(path, pathlen); + if (result != ISC_R_SUCCESS) + return (result); + if (strlen(path) + strlen(filename) + 1 > pathlen) + return (ISC_R_NOSPACE); + strlcat(path, filename, pathlen); + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_file_truncate(const char *filename, isc_offset_t size) { + isc_result_t result = ISC_R_SUCCESS; + + if (truncate(filename, size) < 0) + result = isc__errno2result(errno); + return (result); +} + +isc_result_t +isc_file_safecreate(const char *filename, FILE **fp) { + isc_result_t result; + int flags; + struct stat sb; + FILE *f; + int fd; + + REQUIRE(filename != NULL); + REQUIRE(fp != NULL && *fp == NULL); + + result = file_stats(filename, &sb); + if (result == ISC_R_SUCCESS) { + if ((sb.st_mode & S_IFREG) == 0) + return (ISC_R_INVALIDFILE); + flags = O_WRONLY | O_TRUNC; + } else if (result == ISC_R_FILENOTFOUND) { + flags = O_WRONLY | O_CREAT | O_EXCL; + } else + return (result); + + fd = open(filename, flags, S_IRUSR | S_IWUSR); + if (fd == -1) + return (isc__errno2result(errno)); + + f = fdopen(fd, "w"); + if (f == NULL) { + result = isc__errno2result(errno); + close(fd); + return (result); + } + + *fp = f; + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_file_splitpath(isc_mem_t *mctx, char *path, char **dirname, char **basename) +{ + char *dir, *file, *slash; + + REQUIRE(path != NULL); + + slash = strrchr(path, '/'); + + if (slash == path) { + file = ++slash; + dir = isc_mem_strdup(mctx, "/"); + } else if (slash != NULL) { + file = ++slash; + dir = isc_mem_allocate(mctx, slash - path); + if (dir != NULL) + strlcpy(dir, path, slash - path); + } else { + file = path; + dir = isc_mem_strdup(mctx, "."); + } + + if (dir == NULL) + return (ISC_R_NOMEMORY); + + if (*file == '\0') { + isc_mem_free(mctx, dir); + return (ISC_R_INVALIDFILE); + } + + *dirname = dir; + *basename = file; + + return (ISC_R_SUCCESS); +} diff --git a/contrib/ntp/lib/isc/unix/fsaccess.c b/contrib/ntp/lib/isc/unix/fsaccess.c new file mode 100644 index 0000000..a2bd89a --- /dev/null +++ b/contrib/ntp/lib/isc/unix/fsaccess.c @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: fsaccess.c,v 1.13 2007/06/19 23:47:18 tbox Exp $ */ + +#include <config.h> + +#include <sys/types.h> +#include <sys/stat.h> + +#include <errno.h> + +#include "errno2result.h" + +/*! \file + * \brief + * The OS-independent part of the API is in lib/isc. + */ +#include "../fsaccess.c" + +isc_result_t +isc_fsaccess_set(const char *path, isc_fsaccess_t access) { + struct stat statb; + mode_t mode; + isc_boolean_t is_dir = ISC_FALSE; + isc_fsaccess_t bits; + isc_result_t result; + + if (stat(path, &statb) != 0) + return (isc__errno2result(errno)); + + if ((statb.st_mode & S_IFDIR) != 0) + is_dir = ISC_TRUE; + else if ((statb.st_mode & S_IFREG) == 0) + return (ISC_R_INVALIDFILE); + + result = check_bad_bits(access, is_dir); + if (result != ISC_R_SUCCESS) + return (result); + + /* + * Done with checking bad bits. Set mode_t. + */ + mode = 0; + +#define SET_AND_CLEAR1(modebit) \ + if ((access & bits) != 0) { \ + mode |= modebit; \ + access &= ~bits; \ + } +#define SET_AND_CLEAR(user, group, other) \ + SET_AND_CLEAR1(user); \ + bits <<= STEP; \ + SET_AND_CLEAR1(group); \ + bits <<= STEP; \ + SET_AND_CLEAR1(other); + + bits = ISC_FSACCESS_READ | ISC_FSACCESS_LISTDIRECTORY; + + SET_AND_CLEAR(S_IRUSR, S_IRGRP, S_IROTH); + + bits = ISC_FSACCESS_WRITE | + ISC_FSACCESS_CREATECHILD | + ISC_FSACCESS_DELETECHILD; + + SET_AND_CLEAR(S_IWUSR, S_IWGRP, S_IWOTH); + + bits = ISC_FSACCESS_EXECUTE | + ISC_FSACCESS_ACCESSCHILD; + + SET_AND_CLEAR(S_IXUSR, S_IXGRP, S_IXOTH); + + INSIST(access == 0); + + if (chmod(path, mode) < 0) + return (isc__errno2result(errno)); + + return (ISC_R_SUCCESS); +} diff --git a/contrib/ntp/lib/isc/unix/ifiter_getifaddrs.c b/contrib/ntp/lib/isc/unix/ifiter_getifaddrs.c new file mode 100644 index 0000000..c2e4044 --- /dev/null +++ b/contrib/ntp/lib/isc/unix/ifiter_getifaddrs.c @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: ifiter_getifaddrs.c,v 1.13 2009/09/24 23:48:13 tbox Exp $ */ + +/*! \file + * \brief + * Obtain the list of network interfaces using the getifaddrs(3) library. + */ + +#include <ifaddrs.h> + +/*% Iterator Magic */ +#define IFITER_MAGIC ISC_MAGIC('I', 'F', 'I', 'G') +/*% Valid Iterator */ +#define VALID_IFITER(t) ISC_MAGIC_VALID(t, IFITER_MAGIC) + +#ifdef __linux +static isc_boolean_t seenv6 = ISC_FALSE; +#endif + +/*% Iterator structure */ +struct isc_interfaceiter { + unsigned int magic; /*%< Magic number. */ + isc_mem_t *mctx; + void *buf; /*%< (unused) */ + unsigned int bufsize; /*%< (always 0) */ + struct ifaddrs *ifaddrs; /*%< List of ifaddrs */ + struct ifaddrs *pos; /*%< Ptr to current ifaddr */ + isc_interface_t current; /*%< Current interface data. */ + isc_result_t result; /*%< Last result code. */ +#ifdef __linux + FILE * proc; + char entry[ISC_IF_INET6_SZ]; + isc_result_t valid; +#endif +}; + +isc_result_t +isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) { + isc_interfaceiter_t *iter; + isc_result_t result; + char strbuf[ISC_STRERRORSIZE]; + int trys, ret; + + REQUIRE(mctx != NULL); + REQUIRE(iterp != NULL); + REQUIRE(*iterp == NULL); + + iter = isc_mem_get(mctx, sizeof(*iter)); + if (iter == NULL) + return (ISC_R_NOMEMORY); + + iter->mctx = mctx; + iter->buf = NULL; + iter->bufsize = 0; + iter->ifaddrs = NULL; +#ifdef __linux + /* + * Only open "/proc/net/if_inet6" if we have never seen a IPv6 + * address returned by getifaddrs(). + */ + if (!seenv6) { + iter->proc = fopen("/proc/net/if_inet6", "r"); + if (iter->proc == NULL) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, ISC_LOG_WARNING, + "failed to open /proc/net/if_inet6"); + } + } else + iter->proc = NULL; + iter->valid = ISC_R_FAILURE; +#endif + + /* If interrupted, try again */ + for (trys = 0; trys < 3; trys++) { + if ((ret = getifaddrs(&iter->ifaddrs)) >= 0) + break; + if (errno != EINTR) + break; + } + if (ret < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "getting interface addresses: %s: %s", + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_IFITERGETIFADDRS, + ISC_MSG_GETIFADDRS, + "getifaddrs"), + strbuf); + result = ISC_R_UNEXPECTED; + goto failure; + } + + /* + * A newly created iterator has an undefined position + * until isc_interfaceiter_first() is called. + */ + iter->pos = NULL; + iter->result = ISC_R_FAILURE; + + iter->magic = IFITER_MAGIC; + *iterp = iter; + return (ISC_R_SUCCESS); + + failure: +#ifdef __linux + if (iter->proc != NULL) + fclose(iter->proc); +#endif + if (iter->ifaddrs != NULL) /* just in case */ + freeifaddrs(iter->ifaddrs); + isc_mem_put(mctx, iter, sizeof(*iter)); + return (result); +} + +/* + * Get information about the current interface to iter->current. + * If successful, return ISC_R_SUCCESS. + * If the interface has an unsupported address family, + * return ISC_R_IGNORE. + */ + +static isc_result_t +internal_current(isc_interfaceiter_t *iter) { + struct ifaddrs *ifa; + int family; + unsigned int namelen; + + REQUIRE(VALID_IFITER(iter)); + + ifa = iter->pos; + +#ifdef __linux + if (iter->pos == NULL) + return (linux_if_inet6_current(iter)); +#endif + + INSIST(ifa != NULL); + INSIST(ifa->ifa_name != NULL); + + if (ifa->ifa_addr == NULL) + return (ISC_R_IGNORE); + + family = ifa->ifa_addr->sa_family; + if (family != AF_INET && family != AF_INET6) + return (ISC_R_IGNORE); + +#ifdef __linux + if (family == AF_INET6) + seenv6 = ISC_TRUE; +#endif + + memset(&iter->current, 0, sizeof(iter->current)); + + namelen = strlen(ifa->ifa_name); + if (namelen > sizeof(iter->current.name) - 1) + namelen = sizeof(iter->current.name) - 1; + + memset(iter->current.name, 0, sizeof(iter->current.name)); + memcpy(iter->current.name, ifa->ifa_name, namelen); + + iter->current.flags = 0; + + if ((ifa->ifa_flags & IFF_UP) != 0) + iter->current.flags |= INTERFACE_F_UP; + + if ((ifa->ifa_flags & IFF_POINTOPOINT) != 0) + iter->current.flags |= INTERFACE_F_POINTTOPOINT; + + if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) + iter->current.flags |= INTERFACE_F_LOOPBACK; + + if ((ifa->ifa_flags & IFF_BROADCAST) != 0) + iter->current.flags |= INTERFACE_F_BROADCAST; + +#ifdef IFF_MULTICAST + if ((ifa->ifa_flags & IFF_MULTICAST) != 0) + iter->current.flags |= INTERFACE_F_MULTICAST; +#endif + + iter->current.af = family; + + get_addr(family, &iter->current.address, ifa->ifa_addr, ifa->ifa_name); + + if (ifa->ifa_netmask != NULL) + get_addr(family, &iter->current.netmask, ifa->ifa_netmask, + ifa->ifa_name); + + if (ifa->ifa_dstaddr != NULL && + (iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) + get_addr(family, &iter->current.dstaddress, ifa->ifa_dstaddr, + ifa->ifa_name); + + if (ifa->ifa_broadaddr != NULL && + (iter->current.flags & INTERFACE_F_BROADCAST) != 0) + get_addr(family, &iter->current.broadcast, ifa->ifa_broadaddr, + ifa->ifa_name); + + return (ISC_R_SUCCESS); +} + +/* + * Step the iterator to the next interface. Unlike + * isc_interfaceiter_next(), this may leave the iterator + * positioned on an interface that will ultimately + * be ignored. Return ISC_R_NOMORE if there are no more + * interfaces, otherwise ISC_R_SUCCESS. + */ +static isc_result_t +internal_next(isc_interfaceiter_t *iter) { + + if (iter->pos != NULL) + iter->pos = iter->pos->ifa_next; + if (iter->pos == NULL) { +#ifdef __linux + if (!seenv6) + return (linux_if_inet6_next(iter)); +#endif + return (ISC_R_NOMORE); + } + + return (ISC_R_SUCCESS); +} + +static void +internal_destroy(isc_interfaceiter_t *iter) { + +#ifdef __linux + if (iter->proc != NULL) + fclose(iter->proc); + iter->proc = NULL; +#endif + if (iter->ifaddrs) + freeifaddrs(iter->ifaddrs); + iter->ifaddrs = NULL; +} + +static +void internal_first(isc_interfaceiter_t *iter) { + +#ifdef __linux + linux_if_inet6_first(iter); +#endif + iter->pos = iter->ifaddrs; +} diff --git a/contrib/ntp/lib/isc/unix/ifiter_ioctl.c b/contrib/ntp/lib/isc/unix/ifiter_ioctl.c new file mode 100644 index 0000000..a684867 --- /dev/null +++ b/contrib/ntp/lib/isc/unix/ifiter_ioctl.c @@ -0,0 +1,1018 @@ +/* + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: ifiter_ioctl.c,v 1.62 2009/01/18 23:48:14 tbox Exp $ */ + +/*! \file + * \brief + * Obtain the list of network interfaces using the SIOCGLIFCONF ioctl. + * See netintro(4). + */ + +#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) +#ifdef ISC_PLATFORM_HAVEIF_LADDRCONF +#define lifc_len iflc_len +#define lifc_buf iflc_buf +#define lifc_req iflc_req +#define LIFCONF if_laddrconf +#else +#define ISC_HAVE_LIFC_FAMILY 1 +#define ISC_HAVE_LIFC_FLAGS 1 +#define LIFCONF lifconf +#endif + +#ifdef ISC_PLATFORM_HAVEIF_LADDRREQ +#define lifr_addr iflr_addr +#define lifr_name iflr_name +#define lifr_dstaddr iflr_dstaddr +#define lifr_broadaddr iflr_broadaddr +#define lifr_flags iflr_flags +#define lifr_index iflr_index +#define ss_family sa_family +#define LIFREQ if_laddrreq +#else +#define LIFREQ lifreq +#endif +#endif + +#define IFITER_MAGIC ISC_MAGIC('I', 'F', 'I', 'T') +#define VALID_IFITER(t) ISC_MAGIC_VALID(t, IFITER_MAGIC) + +struct isc_interfaceiter { + unsigned int magic; /* Magic number. */ + isc_mem_t *mctx; + int mode; + int socket; + struct ifconf ifc; + void *buf; /* Buffer for sysctl data. */ + unsigned int bufsize; /* Bytes allocated. */ + unsigned int pos; /* Current offset in + SIOCGIFCONF data */ +#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) + int socket6; + struct LIFCONF lifc; + void *buf6; /* Buffer for sysctl data. */ + unsigned int bufsize6; /* Bytes allocated. */ + unsigned int pos6; /* Current offset in + SIOCGLIFCONF data */ + isc_result_t result6; /* Last result code. */ + isc_boolean_t first6; +#endif +#ifdef HAVE_TRUCLUSTER + int clua_context; /* Cluster alias context */ + isc_boolean_t clua_done; + struct sockaddr clua_sa; +#endif +#ifdef __linux + FILE * proc; + char entry[ISC_IF_INET6_SZ]; + isc_result_t valid; +#endif + isc_interface_t current; /* Current interface data. */ + isc_result_t result; /* Last result code. */ +}; + +#ifdef HAVE_TRUCLUSTER +#include <clua/clua.h> +#include <sys/socket.h> +#endif + + +/*% + * Size of buffer for SIOCGLIFCONF, in bytes. We assume no sane system + * will have more than a megabyte of interface configuration data. + */ +#define IFCONF_BUFSIZE_INITIAL 4096 +#define IFCONF_BUFSIZE_MAX 1048576 + +#ifdef __linux +#ifndef IF_NAMESIZE +# ifdef IFNAMSIZ +# define IF_NAMESIZE IFNAMSIZ +# else +# define IF_NAMESIZE 16 +# endif +#endif +#endif + +int +isc_ioctl(int fildes, int req, char *arg) { + int trys; + int ret; + + for (trys = 0; trys < 3; trys++) { + if ((ret = ioctl(fildes, req, arg)) < 0) { + if (errno == EINTR) + continue; + } + break; + } + return (ret); +} + +static isc_result_t +getbuf4(isc_interfaceiter_t *iter) { + char strbuf[ISC_STRERRORSIZE]; + + iter->bufsize = IFCONF_BUFSIZE_INITIAL; + + for (;;) { + iter->buf = isc_mem_get(iter->mctx, iter->bufsize); + if (iter->buf == NULL) + return (ISC_R_NOMEMORY); + + memset(&iter->ifc.ifc_len, 0, sizeof(iter->ifc.ifc_len)); + iter->ifc.ifc_len = iter->bufsize; + iter->ifc.ifc_buf = iter->buf; + /* + * Ignore the HP/UX warning about "integer overflow during + * conversion". It comes from its own macro definition, + * and is really hard to shut up. + */ + if (isc_ioctl(iter->socket, SIOCGIFCONF, (char *)&iter->ifc) + == -1) { + if (errno != EINVAL) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_IFITERIOCTL, + ISC_MSG_GETIFCONFIG, + "get interface " + "configuration: %s"), + strbuf); + goto unexpected; + } + /* + * EINVAL. Retry with a bigger buffer. + */ + } else { + /* + * The ioctl succeeded. + * Some OS's just return what will fit rather + * than set EINVAL if the buffer is too small + * to fit all the interfaces in. If + * ifc.lifc_len is too near to the end of the + * buffer we will grow it just in case and + * retry. + */ + if (iter->ifc.ifc_len + 2 * sizeof(struct ifreq) + < iter->bufsize) + break; + } + if (iter->bufsize >= IFCONF_BUFSIZE_MAX) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_IFITERIOCTL, + ISC_MSG_BUFFERMAX, + "get interface " + "configuration: " + "maximum buffer " + "size exceeded")); + goto unexpected; + } + isc_mem_put(iter->mctx, iter->buf, iter->bufsize); + + iter->bufsize *= 2; + } + return (ISC_R_SUCCESS); + + unexpected: + isc_mem_put(iter->mctx, iter->buf, iter->bufsize); + iter->buf = NULL; + return (ISC_R_UNEXPECTED); +} + +#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) +static isc_result_t +getbuf6(isc_interfaceiter_t *iter) { + char strbuf[ISC_STRERRORSIZE]; + isc_result_t result; + + iter->bufsize6 = IFCONF_BUFSIZE_INITIAL; + + for (;;) { + iter->buf6 = isc_mem_get(iter->mctx, iter->bufsize6); + if (iter->buf6 == NULL) + return (ISC_R_NOMEMORY); + + memset(&iter->lifc, 0, sizeof(iter->lifc)); +#ifdef ISC_HAVE_LIFC_FAMILY + iter->lifc.lifc_family = AF_INET6; +#endif +#ifdef ISC_HAVE_LIFC_FLAGS + iter->lifc.lifc_flags = 0; +#endif + iter->lifc.lifc_len = iter->bufsize6; + iter->lifc.lifc_buf = iter->buf6; + /* + * Ignore the HP/UX warning about "integer overflow during + * conversion". It comes from its own macro definition, + * and is really hard to shut up. + */ + if (isc_ioctl(iter->socket6, SIOCGLIFCONF, (char *)&iter->lifc) + == -1) { +#ifdef __hpux + /* + * IPv6 interface scanning is not available on all + * kernels w/ IPv6 sockets. + */ + if (errno == ENOENT) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_INTERFACE, + ISC_LOG_DEBUG(1), + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_IFITERIOCTL, + ISC_MSG_GETIFCONFIG, + "get interface " + "configuration: %s"), + strbuf); + result = ISC_R_FAILURE; + goto cleanup; + } +#endif + if (errno != EINVAL) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_IFITERIOCTL, + ISC_MSG_GETIFCONFIG, + "get interface " + "configuration: %s"), + strbuf); + result = ISC_R_UNEXPECTED; + goto cleanup; + } + /* + * EINVAL. Retry with a bigger buffer. + */ + } else { + /* + * The ioctl succeeded. + * Some OS's just return what will fit rather + * than set EINVAL if the buffer is too small + * to fit all the interfaces in. If + * ifc.ifc_len is too near to the end of the + * buffer we will grow it just in case and + * retry. + */ + if (iter->lifc.lifc_len + 2 * sizeof(struct LIFREQ) + < iter->bufsize6) + break; + } + if (iter->bufsize6 >= IFCONF_BUFSIZE_MAX) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_IFITERIOCTL, + ISC_MSG_BUFFERMAX, + "get interface " + "configuration: " + "maximum buffer " + "size exceeded")); + result = ISC_R_UNEXPECTED; + goto cleanup; + } + isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6); + + iter->bufsize6 *= 2; + } + + if (iter->lifc.lifc_len != 0) + iter->mode = 6; + return (ISC_R_SUCCESS); + + cleanup: + isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6); + iter->buf6 = NULL; + return (result); +} +#endif + +isc_result_t +isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) { + isc_interfaceiter_t *iter; + isc_result_t result; + char strbuf[ISC_STRERRORSIZE]; + + REQUIRE(mctx != NULL); + REQUIRE(iterp != NULL); + REQUIRE(*iterp == NULL); + + iter = isc_mem_get(mctx, sizeof(*iter)); + if (iter == NULL) + return (ISC_R_NOMEMORY); + + iter->mctx = mctx; + iter->mode = 4; + iter->buf = NULL; + iter->pos = (unsigned int) -1; +#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) + iter->buf6 = NULL; + iter->pos6 = (unsigned int) -1; + iter->result6 = ISC_R_NOMORE; + iter->socket6 = -1; + iter->first6 = ISC_FALSE; +#endif + + /* + * Get the interface configuration, allocating more memory if + * necessary. + */ + +#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) + result = isc_net_probeipv6(); + if (result == ISC_R_SUCCESS) { + /* + * Create an unbound datagram socket to do the SIOCGLIFCONF + * ioctl on. HP/UX requires an AF_INET6 socket for + * SIOCGLIFCONF to get IPv6 addresses. + */ + if ((iter->socket6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_IFITERIOCTL, + ISC_MSG_MAKESCANSOCKET, + "making interface " + "scan socket: %s"), + strbuf); + result = ISC_R_UNEXPECTED; + goto socket6_failure; + } + result = iter->result6 = getbuf6(iter); + if (result != ISC_R_NOTIMPLEMENTED && result != ISC_R_SUCCESS) + goto ioctl6_failure; + } +#endif + if ((iter->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_IFITERIOCTL, + ISC_MSG_MAKESCANSOCKET, + "making interface " + "scan socket: %s"), + strbuf); + result = ISC_R_UNEXPECTED; + goto socket_failure; + } + result = getbuf4(iter); + if (result != ISC_R_SUCCESS) + goto ioctl_failure; + + /* + * A newly created iterator has an undefined position + * until isc_interfaceiter_first() is called. + */ +#ifdef HAVE_TRUCLUSTER + iter->clua_context = -1; + iter->clua_done = ISC_TRUE; +#endif +#ifdef __linux + iter->proc = fopen("/proc/net/if_inet6", "r"); + iter->valid = ISC_R_FAILURE; +#endif + iter->result = ISC_R_FAILURE; + + iter->magic = IFITER_MAGIC; + *iterp = iter; + return (ISC_R_SUCCESS); + + ioctl_failure: + if (iter->buf != NULL) + isc_mem_put(mctx, iter->buf, iter->bufsize); + (void) close(iter->socket); + + socket_failure: +#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) + if (iter->buf6 != NULL) + isc_mem_put(mctx, iter->buf6, iter->bufsize6); + ioctl6_failure: + if (iter->socket6 != -1) + (void) close(iter->socket6); + socket6_failure: +#endif + + isc_mem_put(mctx, iter, sizeof(*iter)); + return (result); +} + +#ifdef HAVE_TRUCLUSTER +static void +get_inaddr(isc_netaddr_t *dst, struct in_addr *src) { + dst->family = AF_INET; + memcpy(&dst->type.in, src, sizeof(struct in_addr)); +} + +static isc_result_t +internal_current_clusteralias(isc_interfaceiter_t *iter) { + struct clua_info ci; + if (clua_getaliasinfo(&iter->clua_sa, &ci) != CLUA_SUCCESS) + return (ISC_R_IGNORE); + memset(&iter->current, 0, sizeof(iter->current)); + iter->current.af = iter->clua_sa.sa_family; + memset(iter->current.name, 0, sizeof(iter->current.name)); + sprintf(iter->current.name, "clua%d", ci.aliasid); + iter->current.flags = INTERFACE_F_UP; + get_inaddr(&iter->current.address, &ci.addr); + get_inaddr(&iter->current.netmask, &ci.netmask); + return (ISC_R_SUCCESS); +} +#endif + +/* + * Get information about the current interface to iter->current. + * If successful, return ISC_R_SUCCESS. + * If the interface has an unsupported address family, or if + * some operation on it fails, return ISC_R_IGNORE to make + * the higher-level iterator code ignore it. + */ + +static isc_result_t +internal_current4(isc_interfaceiter_t *iter) { + struct ifreq *ifrp; + struct ifreq ifreq; + int family; + char strbuf[ISC_STRERRORSIZE]; +#if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR) + struct lifreq lifreq; +#else + char sabuf[256]; +#endif + int i, bits, prefixlen; + + REQUIRE(VALID_IFITER(iter)); + + if (iter->ifc.ifc_len == 0 || + iter->pos == (unsigned int)iter->ifc.ifc_len) { +#ifdef __linux + return (linux_if_inet6_current(iter)); +#else + return (ISC_R_NOMORE); +#endif + } + + INSIST( iter->pos < (unsigned int) iter->ifc.ifc_len); + + ifrp = (void *)((char *) iter->ifc.ifc_req + iter->pos); + + memset(&ifreq, 0, sizeof(ifreq)); + memcpy(&ifreq, ifrp, sizeof(ifreq)); + + family = ifreq.ifr_addr.sa_family; +#if defined(ISC_PLATFORM_HAVEIPV6) + if (family != AF_INET && family != AF_INET6) +#else + if (family != AF_INET) +#endif + return (ISC_R_IGNORE); + + memset(&iter->current, 0, sizeof(iter->current)); + iter->current.af = family; + + INSIST(sizeof(ifreq.ifr_name) <= sizeof(iter->current.name)); + memset(iter->current.name, 0, sizeof(iter->current.name)); + memcpy(iter->current.name, ifreq.ifr_name, sizeof(ifreq.ifr_name)); + + get_addr(family, &iter->current.address, + (struct sockaddr *)&ifrp->ifr_addr, ifreq.ifr_name); + + /* + * If the interface does not have a address ignore it. + */ + switch (family) { + case AF_INET: + if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY)) + return (ISC_R_IGNORE); + break; + case AF_INET6: + if (memcmp(&iter->current.address.type.in6, &in6addr_any, + sizeof(in6addr_any)) == 0) + return (ISC_R_IGNORE); + break; + } + + /* + * Get interface flags. + */ + + iter->current.flags = 0; + + /* + * Ignore the HP/UX warning about "integer overflow during + * conversion. It comes from its own macro definition, + * and is really hard to shut up. + */ + if (isc_ioctl(iter->socket, SIOCGIFFLAGS, (char *) &ifreq) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "%s: getting interface flags: %s", + ifreq.ifr_name, strbuf); + return (ISC_R_IGNORE); + } + + if ((ifreq.ifr_flags & IFF_UP) != 0) + iter->current.flags |= INTERFACE_F_UP; + +#ifdef IFF_POINTOPOINT + if ((ifreq.ifr_flags & IFF_POINTOPOINT) != 0) + iter->current.flags |= INTERFACE_F_POINTTOPOINT; +#endif + + if ((ifreq.ifr_flags & IFF_LOOPBACK) != 0) + iter->current.flags |= INTERFACE_F_LOOPBACK; + + if ((ifreq.ifr_flags & IFF_BROADCAST) != 0) + iter->current.flags |= INTERFACE_F_BROADCAST; + +#ifdef IFF_MULTICAST + if ((ifreq.ifr_flags & IFF_MULTICAST) != 0) + iter->current.flags |= INTERFACE_F_MULTICAST; +#endif + + if (family == AF_INET) + goto inet; + +#if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR) + memset(&lifreq, 0, sizeof(lifreq)); + memcpy(lifreq.lifr_name, iter->current.name, sizeof(lifreq.lifr_name)); + memcpy(&lifreq.lifr_addr, &iter->current.address.type.in6, + sizeof(iter->current.address.type.in6)); + + if (isc_ioctl(iter->socket, SIOCGLIFADDR, &lifreq) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "%s: getting interface address: %s", + ifreq.ifr_name, strbuf); + return (ISC_R_IGNORE); + } + prefixlen = lifreq.lifr_addrlen; +#else + isc_netaddr_format(&iter->current.address, sabuf, sizeof(sabuf)); + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_INTERFACE, + ISC_LOG_INFO, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_IFITERIOCTL, + ISC_MSG_GETIFCONFIG, + "prefix length for %s is unknown " + "(assume 128)"), sabuf); + prefixlen = 128; +#endif + + /* + * Netmask already zeroed. + */ + iter->current.netmask.family = family; + for (i = 0; i < 16; i++) { + if (prefixlen > 8) { + bits = 0; + prefixlen -= 8; + } else { + bits = 8 - prefixlen; + prefixlen = 0; + } + iter->current.netmask.type.in6.s6_addr[i] = (~0 << bits) & 0xff; + } + return (ISC_R_SUCCESS); + + inet: + if (family != AF_INET) + return (ISC_R_IGNORE); +#ifdef IFF_POINTOPOINT + /* + * If the interface is point-to-point, get the destination address. + */ + if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) { + /* + * Ignore the HP/UX warning about "integer overflow during + * conversion. It comes from its own macro definition, + * and is really hard to shut up. + */ + if (isc_ioctl(iter->socket, SIOCGIFDSTADDR, (char *)&ifreq) + < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_IFITERIOCTL, + ISC_MSG_GETDESTADDR, + "%s: getting " + "destination address: %s"), + ifreq.ifr_name, strbuf); + return (ISC_R_IGNORE); + } + get_addr(family, &iter->current.dstaddress, + (struct sockaddr *)&ifreq.ifr_dstaddr, ifreq.ifr_name); + } +#endif + + if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) { + /* + * Ignore the HP/UX warning about "integer overflow during + * conversion. It comes from its own macro definition, + * and is really hard to shut up. + */ + if (isc_ioctl(iter->socket, SIOCGIFBRDADDR, (char *)&ifreq) + < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_IFITERIOCTL, + ISC_MSG_GETBCSTADDR, + "%s: getting " + "broadcast address: %s"), + ifreq.ifr_name, strbuf); + return (ISC_R_IGNORE); + } + get_addr(family, &iter->current.broadcast, + (struct sockaddr *)&ifreq.ifr_broadaddr, ifreq.ifr_name); + } + + /* + * Get the network mask. + */ + memset(&ifreq, 0, sizeof(ifreq)); + memcpy(&ifreq, ifrp, sizeof(ifreq)); + /* + * Ignore the HP/UX warning about "integer overflow during + * conversion. It comes from its own macro definition, + * and is really hard to shut up. + */ + if (isc_ioctl(iter->socket, SIOCGIFNETMASK, (char *)&ifreq) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_IFITERIOCTL, + ISC_MSG_GETNETMASK, + "%s: getting netmask: %s"), + ifreq.ifr_name, strbuf); + return (ISC_R_IGNORE); + } + get_addr(family, &iter->current.netmask, + (struct sockaddr *)&ifreq.ifr_addr, ifreq.ifr_name); + return (ISC_R_SUCCESS); +} + +#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) +static isc_result_t +internal_current6(isc_interfaceiter_t *iter) { + struct LIFREQ *ifrp; + struct LIFREQ lifreq; + int family; + char strbuf[ISC_STRERRORSIZE]; + int fd; + + REQUIRE(VALID_IFITER(iter)); + if (iter->result6 != ISC_R_SUCCESS) + return (iter->result6); + REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len); + + ifrp = (void *)((char *)iter->lifc.lifc_req + iter->pos6); + + memset(&lifreq, 0, sizeof(lifreq)); + memcpy(&lifreq, ifrp, sizeof(lifreq)); + + family = lifreq.lifr_addr.ss_family; +#ifdef ISC_PLATFORM_HAVEIPV6 + if (family != AF_INET && family != AF_INET6) +#else + if (family != AF_INET) +#endif + return (ISC_R_IGNORE); + + memset(&iter->current, 0, sizeof(iter->current)); + iter->current.af = family; + + INSIST(sizeof(lifreq.lifr_name) <= sizeof(iter->current.name)); + memset(iter->current.name, 0, sizeof(iter->current.name)); + memcpy(iter->current.name, lifreq.lifr_name, sizeof(lifreq.lifr_name)); + + get_addr(family, &iter->current.address, + (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name); + + iter->current.ifindex = lifreq.lifr_index; + if (isc_netaddr_islinklocal(&iter->current.address)) + isc_netaddr_setzone(&iter->current.address, + (isc_uint32_t)lifreq.lifr_index); + + /* + * If the interface does not have a address ignore it. + */ + switch (family) { + case AF_INET: + if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY)) + return (ISC_R_IGNORE); + break; + case AF_INET6: + if (memcmp(&iter->current.address.type.in6, &in6addr_any, + sizeof(in6addr_any)) == 0) + return (ISC_R_IGNORE); + break; + } + + /* + * Get interface flags. + */ + + iter->current.flags = 0; + + if (family == AF_INET6) + fd = iter->socket6; + else + fd = iter->socket; + + /* + * Ignore the HP/UX warning about "integer overflow during + * conversion. It comes from its own macro definition, + * and is really hard to shut up. + */ + if (isc_ioctl(fd, SIOCGLIFFLAGS, (char *) &lifreq) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "%s: getting interface flags: %s", + lifreq.lifr_name, strbuf); + return (ISC_R_IGNORE); + } + + if ((lifreq.lifr_flags & IFF_UP) != 0) + iter->current.flags |= INTERFACE_F_UP; + +#ifdef IFF_POINTOPOINT + if ((lifreq.lifr_flags & IFF_POINTOPOINT) != 0) + iter->current.flags |= INTERFACE_F_POINTTOPOINT; +#endif + + if ((lifreq.lifr_flags & IFF_LOOPBACK) != 0) + iter->current.flags |= INTERFACE_F_LOOPBACK; + + if ((lifreq.lifr_flags & IFF_BROADCAST) != 0) { + iter->current.flags |= INTERFACE_F_BROADCAST; + } + +#ifdef IFF_MULTICAST + if ((lifreq.lifr_flags & IFF_MULTICAST) != 0) { + iter->current.flags |= INTERFACE_F_MULTICAST; + } +#endif + +#ifdef IFF_POINTOPOINT + /* + * If the interface is point-to-point, get the destination address. + */ + if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) { + /* + * Ignore the HP/UX warning about "integer overflow during + * conversion. It comes from its own macro definition, + * and is really hard to shut up. + */ + if (isc_ioctl(fd, SIOCGLIFDSTADDR, (char *)&lifreq) + < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_IFITERIOCTL, + ISC_MSG_GETDESTADDR, + "%s: getting " + "destination address: %s"), + lifreq.lifr_name, strbuf); + return (ISC_R_IGNORE); + } + get_addr(family, &iter->current.dstaddress, + (struct sockaddr *)&lifreq.lifr_dstaddr, + lifreq.lifr_name); + } +#endif + +#ifdef SIOCGLIFBRDADDR + if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) { + /* + * Ignore the HP/UX warning about "integer overflow during + * conversion. It comes from its own macro definition, + * and is really hard to shut up. + */ + if (isc_ioctl(iter->socket, SIOCGLIFBRDADDR, (char *)&lifreq) + < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_IFITERIOCTL, + ISC_MSG_GETBCSTADDR, + "%s: getting " + "broadcast address: %s"), + lifreq.lifr_name, strbuf); + return (ISC_R_IGNORE); + } + get_addr(family, &iter->current.broadcast, + (struct sockaddr *)&lifreq.lifr_broadaddr, + lifreq.lifr_name); + } +#endif /* SIOCGLIFBRDADDR */ + + /* + * Get the network mask. Netmask already zeroed. + */ + memset(&lifreq, 0, sizeof(lifreq)); + memcpy(&lifreq, ifrp, sizeof(lifreq)); + +#ifdef lifr_addrlen + /* + * Special case: if the system provides lifr_addrlen member, the + * netmask of an IPv6 address can be derived from the length, since + * an IPv6 address always has a contiguous mask. + */ + if (family == AF_INET6) { + int i, bits; + + iter->current.netmask.family = family; + for (i = 0; i < lifreq.lifr_addrlen; i += 8) { + bits = lifreq.lifr_addrlen - i; + bits = (bits < 8) ? (8 - bits) : 0; + iter->current.netmask.type.in6.s6_addr[i / 8] = + (~0 << bits) & 0xff; + } + + return (ISC_R_SUCCESS); + } +#endif + + /* + * Ignore the HP/UX warning about "integer overflow during + * conversion. It comes from its own macro definition, + * and is really hard to shut up. + */ + if (isc_ioctl(fd, SIOCGLIFNETMASK, (char *)&lifreq) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_IFITERIOCTL, + ISC_MSG_GETNETMASK, + "%s: getting netmask: %s"), + lifreq.lifr_name, strbuf); + return (ISC_R_IGNORE); + } + get_addr(family, &iter->current.netmask, + (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name); + + return (ISC_R_SUCCESS); +} +#endif + +static isc_result_t +internal_current(isc_interfaceiter_t *iter) { +#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) + if (iter->mode == 6) { + iter->result6 = internal_current6(iter); + if (iter->result6 != ISC_R_NOMORE) + return (iter->result6); + } +#endif +#ifdef HAVE_TRUCLUSTER + if (!iter->clua_done) + return(internal_current_clusteralias(iter)); +#endif + return (internal_current4(iter)); +} + +/* + * Step the iterator to the next interface. Unlike + * isc_interfaceiter_next(), this may leave the iterator + * positioned on an interface that will ultimately + * be ignored. Return ISC_R_NOMORE if there are no more + * interfaces, otherwise ISC_R_SUCCESS. + */ +static isc_result_t +internal_next4(isc_interfaceiter_t *iter) { +#ifdef ISC_PLATFORM_HAVESALEN + struct ifreq *ifrp; +#endif + + if (iter->pos < (unsigned int) iter->ifc.ifc_len) { +#ifdef ISC_PLATFORM_HAVESALEN + ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos); + + if (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr)) + iter->pos += sizeof(ifrp->ifr_name) + + ifrp->ifr_addr.sa_len; + else +#endif + iter->pos += sizeof(struct ifreq); + + } else { + INSIST(iter->pos == (unsigned int) iter->ifc.ifc_len); +#ifdef __linux + return (linux_if_inet6_next(iter)); +#else + return (ISC_R_NOMORE); +#endif + } + return (ISC_R_SUCCESS); +} + +#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) +static isc_result_t +internal_next6(isc_interfaceiter_t *iter) { +#ifdef ISC_PLATFORM_HAVESALEN + struct LIFREQ *ifrp; +#endif + + if (iter->result6 != ISC_R_SUCCESS && iter->result6 != ISC_R_IGNORE) + return (iter->result6); + + REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len); + +#ifdef ISC_PLATFORM_HAVESALEN + ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6); + + if (ifrp->lifr_addr.sa_len > sizeof(struct sockaddr)) + iter->pos6 += sizeof(ifrp->lifr_name) + ifrp->lifr_addr.sa_len; + else +#endif + iter->pos6 += sizeof(struct LIFREQ); + + if (iter->pos6 >= (unsigned int) iter->lifc.lifc_len) + return (ISC_R_NOMORE); + + return (ISC_R_SUCCESS); +} +#endif + +static isc_result_t +internal_next(isc_interfaceiter_t *iter) { +#ifdef HAVE_TRUCLUSTER + int clua_result; +#endif +#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) + if (iter->mode == 6) { + iter->result6 = internal_next6(iter); + if (iter->result6 != ISC_R_NOMORE) + return (iter->result6); + if (iter->first6) { + iter->first6 = ISC_FALSE; + return (ISC_R_SUCCESS); + } + } +#endif +#ifdef HAVE_TRUCLUSTER + if (!iter->clua_done) { + clua_result = clua_getaliasaddress(&iter->clua_sa, + &iter->clua_context); + if (clua_result != CLUA_SUCCESS) + iter->clua_done = ISC_TRUE; + return (ISC_R_SUCCESS); + } +#endif + return (internal_next4(iter)); +} + +static void +internal_destroy(isc_interfaceiter_t *iter) { + (void) close(iter->socket); +#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) + if (iter->socket6 != -1) + (void) close(iter->socket6); + if (iter->buf6 != NULL) { + isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6); + } +#endif +#ifdef __linux + if (iter->proc != NULL) + fclose(iter->proc); +#endif +} + +static +void internal_first(isc_interfaceiter_t *iter) { +#ifdef HAVE_TRUCLUSTER + int clua_result; +#endif + iter->pos = 0; +#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) + iter->pos6 = 0; + if (iter->result6 == ISC_R_NOMORE) + iter->result6 = ISC_R_SUCCESS; + iter->first6 = ISC_TRUE; +#endif +#ifdef HAVE_TRUCLUSTER + iter->clua_context = 0; + clua_result = clua_getaliasaddress(&iter->clua_sa, + &iter->clua_context); + iter->clua_done = ISC_TF(clua_result != CLUA_SUCCESS); +#endif +#ifdef __linux + linux_if_inet6_first(iter); +#endif +} diff --git a/contrib/ntp/lib/isc/unix/ifiter_sysctl.c b/contrib/ntp/lib/isc/unix/ifiter_sysctl.c new file mode 100644 index 0000000..0fbb377 --- /dev/null +++ b/contrib/ntp/lib/isc/unix/ifiter_sysctl.c @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: ifiter_sysctl.c,v 1.25 2007/06/19 23:47:18 tbox Exp $ */ + +/*! \file + * \brief + * Obtain the list of network interfaces using sysctl. + * See TCP/IP Illustrated Volume 2, sections 19.8, 19.14, + * and 19.16. + */ + +#include <sys/param.h> +#include <sys/sysctl.h> + +#include <net/route.h> +#include <net/if_dl.h> + +/* XXX what about Alpha? */ +#ifdef sgi +#define ROUNDUP(a) ((a) > 0 ? \ + (1 + (((a) - 1) | (sizeof(__uint64_t) - 1))) : \ + sizeof(__uint64_t)) +#else +#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) \ + : sizeof(long)) +#endif + +#define IFITER_MAGIC ISC_MAGIC('I', 'F', 'I', 'S') +#define VALID_IFITER(t) ISC_MAGIC_VALID(t, IFITER_MAGIC) + +struct isc_interfaceiter { + unsigned int magic; /* Magic number. */ + isc_mem_t *mctx; + void *buf; /* Buffer for sysctl data. */ + unsigned int bufsize; /* Bytes allocated. */ + unsigned int bufused; /* Bytes used. */ + unsigned int pos; /* Current offset in + sysctl data. */ + isc_interface_t current; /* Current interface data. */ + isc_result_t result; /* Last result code. */ +}; + +static int mib[6] = { + CTL_NET, + PF_ROUTE, + 0, + 0, /* Any address family. */ + NET_RT_IFLIST, + 0 /* Flags. */ +}; + +isc_result_t +isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) { + isc_interfaceiter_t *iter; + isc_result_t result; + size_t bufsize; + size_t bufused; + char strbuf[ISC_STRERRORSIZE]; + + REQUIRE(mctx != NULL); + REQUIRE(iterp != NULL); + REQUIRE(*iterp == NULL); + + iter = isc_mem_get(mctx, sizeof(*iter)); + if (iter == NULL) + return (ISC_R_NOMEMORY); + + iter->mctx = mctx; + iter->buf = 0; + + /* + * Determine the amount of memory needed. + */ + bufsize = 0; + if (sysctl(mib, 6, NULL, &bufsize, NULL, (size_t) 0) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_IFITERSYSCTL, + ISC_MSG_GETIFLISTSIZE, + "getting interface " + "list size: sysctl: %s"), + strbuf); + result = ISC_R_UNEXPECTED; + goto failure; + } + iter->bufsize = bufsize; + + iter->buf = isc_mem_get(iter->mctx, iter->bufsize); + if (iter->buf == NULL) { + result = ISC_R_NOMEMORY; + goto failure; + } + + bufused = bufsize; + if (sysctl(mib, 6, iter->buf, &bufused, NULL, (size_t) 0) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_IFITERSYSCTL, + ISC_MSG_GETIFLIST, + "getting interface list: " + "sysctl: %s"), + strbuf); + result = ISC_R_UNEXPECTED; + goto failure; + } + iter->bufused = bufused; + INSIST(iter->bufused <= iter->bufsize); + + /* + * A newly created iterator has an undefined position + * until isc_interfaceiter_first() is called. + */ + iter->pos = (unsigned int) -1; + iter->result = ISC_R_FAILURE; + + iter->magic = IFITER_MAGIC; + *iterp = iter; + return (ISC_R_SUCCESS); + + failure: + if (iter->buf != NULL) + isc_mem_put(mctx, iter->buf, iter->bufsize); + isc_mem_put(mctx, iter, sizeof(*iter)); + return (result); +} + +/* + * Get information about the current interface to iter->current. + * If successful, return ISC_R_SUCCESS. + * If the interface has an unsupported address family, + * return ISC_R_IGNORE. In case of other failure, + * return ISC_R_UNEXPECTED. + */ + +static isc_result_t +internal_current(isc_interfaceiter_t *iter) { + struct ifa_msghdr *ifam, *ifam_end; + + REQUIRE(VALID_IFITER(iter)); + REQUIRE (iter->pos < (unsigned int) iter->bufused); + + ifam = (struct ifa_msghdr *) ((char *) iter->buf + iter->pos); + ifam_end = (struct ifa_msghdr *) ((char *) iter->buf + iter->bufused); + + // Skip wrong RTM version headers + if (ifam->ifam_version != RTM_VERSION) + return (ISC_R_IGNORE); + + if (ifam->ifam_type == RTM_IFINFO) { + struct if_msghdr *ifm = (struct if_msghdr *) ifam; + struct sockaddr_dl *sdl = (struct sockaddr_dl *) (ifm + 1); + unsigned int namelen; + + memset(&iter->current, 0, sizeof(iter->current)); + + iter->current.ifindex = sdl->sdl_index; + namelen = sdl->sdl_nlen; + if (namelen > sizeof(iter->current.name) - 1) + namelen = sizeof(iter->current.name) - 1; + + memset(iter->current.name, 0, sizeof(iter->current.name)); + memcpy(iter->current.name, sdl->sdl_data, namelen); + + iter->current.flags = 0; + + if ((ifam->ifam_flags & IFF_UP) != 0) + iter->current.flags |= INTERFACE_F_UP; + + if ((ifam->ifam_flags & IFF_POINTOPOINT) != 0) + iter->current.flags |= INTERFACE_F_POINTTOPOINT; + + if ((ifam->ifam_flags & IFF_LOOPBACK) != 0) + iter->current.flags |= INTERFACE_F_LOOPBACK; + + if ((ifam->ifam_flags & IFF_BROADCAST) != 0) + iter->current.flags |= INTERFACE_F_BROADCAST; + +#ifdef IFF_MULTICAST + if ((ifam->ifam_flags & IFF_MULTICAST) != 0) + iter->current.flags |= INTERFACE_F_MULTICAST; +#endif + + /* + * This is not an interface address. + * Force another iteration. + */ + return (ISC_R_IGNORE); + } else if (ifam->ifam_type == RTM_NEWADDR) { + int i; + int family; + struct sockaddr *mask_sa = NULL; + struct sockaddr *addr_sa = NULL; + struct sockaddr *dst_sa = NULL; + + struct sockaddr *sa = (struct sockaddr *)(ifam + 1); + family = sa->sa_family; + + for (i = 0; i < RTAX_MAX; i++) + { + if ((ifam->ifam_addrs & (1 << i)) == 0) + continue; + + INSIST(sa < (struct sockaddr *) ifam_end); + + switch (i) { + case RTAX_NETMASK: /* Netmask */ + mask_sa = sa; + break; + case RTAX_IFA: /* Interface address */ + addr_sa = sa; + break; + case RTAX_BRD: /* Broadcast or destination address */ + dst_sa = sa; + break; + } +#ifdef ISC_PLATFORM_HAVESALEN + sa = (struct sockaddr *)((char*)(sa) + + ROUNDUP(sa->sa_len)); +#else +#ifdef sgi + /* + * Do as the contributed SGI code does. + */ + sa = (struct sockaddr *)((char*)(sa) + + ROUNDUP(_FAKE_SA_LEN_DST(sa))); +#else + /* XXX untested. */ + sa = (struct sockaddr *)((char*)(sa) + + ROUNDUP(sizeof(struct sockaddr))); +#endif +#endif + } + + if (addr_sa == NULL) + return (ISC_R_IGNORE); + + family = addr_sa->sa_family; + if (family != AF_INET && family != AF_INET6) + return (ISC_R_IGNORE); + + iter->current.af = family; + + get_addr(family, &iter->current.address, addr_sa, + iter->current.name); + + if (mask_sa != NULL) + get_addr(family, &iter->current.netmask, mask_sa, + iter->current.name); + + if (dst_sa != NULL && + (iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) + get_addr(family, &iter->current.dstaddress, dst_sa, + iter->current.name); + + if (dst_sa != NULL && + (iter->current.flags & INTERFACE_F_BROADCAST) != 0) + get_addr(family, &iter->current.broadcast, dst_sa, + iter->current.name); + + return (ISC_R_SUCCESS); + } else { + printf("%s", isc_msgcat_get(isc_msgcat, + ISC_MSGSET_IFITERSYSCTL, + ISC_MSG_UNEXPECTEDTYPE, + "warning: unexpected interface " + "list message type\n")); + return (ISC_R_IGNORE); + } +} + +/* + * Step the iterator to the next interface. Unlike + * isc_interfaceiter_next(), this may leave the iterator + * positioned on an interface that will ultimately + * be ignored. Return ISC_R_NOMORE if there are no more + * interfaces, otherwise ISC_R_SUCCESS. + */ +static isc_result_t +internal_next(isc_interfaceiter_t *iter) { + struct ifa_msghdr *ifam; + REQUIRE (iter->pos < (unsigned int) iter->bufused); + + ifam = (struct ifa_msghdr *) ((char *) iter->buf + iter->pos); + + iter->pos += ifam->ifam_msglen; + + if (iter->pos >= iter->bufused) + return (ISC_R_NOMORE); + + return (ISC_R_SUCCESS); +} + +static void +internal_destroy(isc_interfaceiter_t *iter) { + UNUSED(iter); /* Unused. */ + /* + * Do nothing. + */ +} + +static +void internal_first(isc_interfaceiter_t *iter) { + iter->pos = 0; +} diff --git a/contrib/ntp/lib/isc/unix/include/isc/dir.h b/contrib/ntp/lib/isc/unix/include/isc/dir.h new file mode 100644 index 0000000..e4a2ad0 --- /dev/null +++ b/contrib/ntp/lib/isc/unix/include/isc/dir.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: dir.h,v 1.21 2007/06/19 23:47:19 tbox Exp $ */ + +/* Principal Authors: DCL */ + +#ifndef ISC_DIR_H +#define ISC_DIR_H 1 + +/*! \file */ + +#include <sys/types.h> /* Required on some systems. */ +#include <dirent.h> + +#include <isc/lang.h> +#include <isc/result.h> + +#define ISC_DIR_NAMEMAX 256 +#define ISC_DIR_PATHMAX 1024 + +/*% Directory Entry */ +typedef struct isc_direntry { + /*! + * Ideally, this should be NAME_MAX, but AIX does not define it by + * default and dynamically allocating the space based on pathconf() + * complicates things undesirably, as does adding special conditionals + * just for AIX. So a comfortably sized buffer is chosen instead. + */ + char name[ISC_DIR_NAMEMAX]; + unsigned int length; +} isc_direntry_t; + +/*% Directory */ +typedef struct isc_dir { + unsigned int magic; + /*! + * As with isc_direntry_t->name, making this "right" for all systems + * is slightly problematic because AIX does not define PATH_MAX. + */ + char dirname[ISC_DIR_PATHMAX]; + isc_direntry_t entry; + DIR * handle; +} isc_dir_t; + +ISC_LANG_BEGINDECLS + +void +isc_dir_init(isc_dir_t *dir); + +isc_result_t +isc_dir_open(isc_dir_t *dir, const char *dirname); + +isc_result_t +isc_dir_read(isc_dir_t *dir); + +isc_result_t +isc_dir_reset(isc_dir_t *dir); + +void +isc_dir_close(isc_dir_t *dir); + +isc_result_t +isc_dir_chdir(const char *dirname); + +isc_result_t +isc_dir_chroot(const char *dirname); + +isc_result_t +isc_dir_createunique(char *templet); +/*!< + * Use a templet (such as from isc_file_mktemplate()) to create a uniquely + * named, empty directory. The templet string is modified in place. + * If result == ISC_R_SUCCESS, it is the name of the directory that was + * created. + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_DIR_H */ diff --git a/contrib/ntp/lib/isc/unix/include/isc/int.h b/contrib/ntp/lib/isc/unix/include/isc/int.h new file mode 100644 index 0000000..73feb3b --- /dev/null +++ b/contrib/ntp/lib/isc/unix/include/isc/int.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: int.h,v 1.16 2007/06/19 23:47:19 tbox Exp $ */ + +#ifndef ISC_INT_H +#define ISC_INT_H 1 + +/*! \file */ + +typedef char isc_int8_t; +typedef unsigned char isc_uint8_t; +typedef short isc_int16_t; +typedef unsigned short isc_uint16_t; +typedef int isc_int32_t; +typedef unsigned int isc_uint32_t; +typedef long long isc_int64_t; +typedef unsigned long long isc_uint64_t; + +#define ISC_INT8_MIN -128 +#define ISC_INT8_MAX 127 +#define ISC_UINT8_MAX 255 + +#define ISC_INT16_MIN -32768 +#define ISC_INT16_MAX 32767 +#define ISC_UINT16_MAX 65535 + +/*% + * Note that "int" is 32 bits on all currently supported Unix-like operating + * systems, but "long" can be either 32 bits or 64 bits, thus the 32 bit + * constants are not qualified with "L". + */ +#define ISC_INT32_MIN -2147483648 +#define ISC_INT32_MAX 2147483647 +#define ISC_UINT32_MAX 4294967295U + +#define ISC_INT64_MIN -9223372036854775808LL +#define ISC_INT64_MAX 9223372036854775807LL +#define ISC_UINT64_MAX 18446744073709551615ULL + +#endif /* ISC_INT_H */ diff --git a/contrib/ntp/lib/isc/unix/include/isc/keyboard.h b/contrib/ntp/lib/isc/unix/include/isc/keyboard.h new file mode 100644 index 0000000..43f5e7e --- /dev/null +++ b/contrib/ntp/lib/isc/unix/include/isc/keyboard.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: keyboard.h,v 1.11 2007/06/19 23:47:19 tbox Exp $ */ + +#ifndef ISC_KEYBOARD_H +#define ISC_KEYBOARD_H 1 + +/*! \file */ + +#include <termios.h> + +#include <isc/lang.h> +#include <isc/result.h> + +ISC_LANG_BEGINDECLS + +typedef struct { + int fd; + struct termios saved_mode; + isc_result_t result; +} isc_keyboard_t; + +isc_result_t +isc_keyboard_open(isc_keyboard_t *keyboard); + +isc_result_t +isc_keyboard_close(isc_keyboard_t *keyboard, unsigned int sleepseconds); + +isc_result_t +isc_keyboard_getchar(isc_keyboard_t *keyboard, unsigned char *cp); + +isc_boolean_t +isc_keyboard_canceled(isc_keyboard_t *keyboard); + +ISC_LANG_ENDDECLS + +#endif /* ISC_KEYBOARD_H */ diff --git a/contrib/ntp/lib/isc/unix/include/isc/net.h b/contrib/ntp/lib/isc/unix/include/isc/net.h new file mode 100644 index 0000000..37a0f3b --- /dev/null +++ b/contrib/ntp/lib/isc/unix/include/isc/net.h @@ -0,0 +1,364 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2008, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +#ifndef ISC_NET_H +#define ISC_NET_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file + * \brief + * Basic Networking Types + * + * This module is responsible for defining the following basic networking + * types: + * + *\li struct in_addr + *\li struct in6_addr + *\li struct in6_pktinfo + *\li struct sockaddr + *\li struct sockaddr_in + *\li struct sockaddr_in6 + *\li in_port_t + * + * It ensures that the AF_ and PF_ macros are defined. + * + * It declares ntoh[sl]() and hton[sl](). + * + * It declares inet_aton(), inet_ntop(), and inet_pton(). + * + * It ensures that #INADDR_LOOPBACK, #INADDR_ANY, #IN6ADDR_ANY_INIT, + * in6addr_any, and in6addr_loopback are available. + * + * It ensures that IN_MULTICAST() is available to check for multicast + * addresses. + * + * MP: + *\li No impact. + * + * Reliability: + *\li No anticipated impact. + * + * Resources: + *\li N/A. + * + * Security: + *\li No anticipated impact. + * + * Standards: + *\li BSD Socket API + *\li RFC2553 + */ + +/*** + *** Imports. + ***/ +#include <isc/platform.h> + +#include <sys/types.h> +#include <sys/socket.h> /* Contractual promise. */ + +#include <net/if.h> + +#include <netinet/in.h> /* Contractual promise. */ +#include <arpa/inet.h> /* Contractual promise. */ +#ifdef ISC_PLATFORM_NEEDNETINETIN6H +#include <netinet/in6.h> /* Required on UnixWare. */ +#endif +#ifdef ISC_PLATFORM_NEEDNETINET6IN6H +#include <netinet6/in6.h> /* Required on BSD/OS for in6_pktinfo. */ +#endif + +#ifndef ISC_PLATFORM_HAVEIPV6 +#include <isc/ipv6.h> /* Contractual promise. */ +#endif + +#include <isc/lang.h> +#include <isc/types.h> + +#ifdef ISC_PLATFORM_HAVEINADDR6 +#define in6_addr in_addr6 /*%< Required for pre RFC2133 implementations. */ +#endif + +#ifdef ISC_PLATFORM_HAVEIPV6 +#ifndef IN6ADDR_ANY_INIT +#ifdef s6_addr +/*% + * Required for some pre RFC2133 implementations. + * IN6ADDR_ANY_INIT and IN6ADDR_LOOPBACK_INIT were added in + * draft-ietf-ipngwg-bsd-api-04.txt or draft-ietf-ipngwg-bsd-api-05.txt. + * If 's6_addr' is defined then assume that there is a union and three + * levels otherwise assume two levels required. + */ +#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } } +#else +#define IN6ADDR_ANY_INIT { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } +#endif +#endif + +#ifndef IN6ADDR_LOOPBACK_INIT +#ifdef s6_addr +/*% IPv6 address loopback init */ +#define IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } } +#else +#define IN6ADDR_LOOPBACK_INIT { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } +#endif +#endif + +#ifndef IN6_IS_ADDR_V4MAPPED +/*% Is IPv6 address V4 mapped? */ +#define IN6_IS_ADDR_V4MAPPED(x) \ + (memcmp((x)->s6_addr, in6addr_any.s6_addr, 10) == 0 && \ + (x)->s6_addr[10] == 0xff && (x)->s6_addr[11] == 0xff) +#endif + +#ifndef IN6_IS_ADDR_V4COMPAT +/*% Is IPv6 address V4 compatible? */ +#define IN6_IS_ADDR_V4COMPAT(x) \ + (memcmp((x)->s6_addr, in6addr_any.s6_addr, 12) == 0 && \ + ((x)->s6_addr[12] != 0 || (x)->s6_addr[13] != 0 || \ + (x)->s6_addr[14] != 0 || \ + ((x)->s6_addr[15] != 0 && (x)->s6_addr[15] != 1))) +#endif + +#ifndef IN6_IS_ADDR_MULTICAST +/*% Is IPv6 address multicast? */ +#define IN6_IS_ADDR_MULTICAST(a) ((a)->s6_addr[0] == 0xff) +#endif + +#ifndef IN6_IS_ADDR_LINKLOCAL +/*% Is IPv6 address linklocal? */ +#define IN6_IS_ADDR_LINKLOCAL(a) \ + (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0x80)) +#endif + +#ifndef IN6_IS_ADDR_SITELOCAL +/*% is IPv6 address sitelocal? */ +#define IN6_IS_ADDR_SITELOCAL(a) \ + (((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0xc0)) +#endif + + +#ifndef IN6_IS_ADDR_LOOPBACK +/*% is IPv6 address loopback? */ +#define IN6_IS_ADDR_LOOPBACK(x) \ + (memcmp((x)->s6_addr, in6addr_loopback.s6_addr, 16) == 0) +#endif +#endif + +#ifndef AF_INET6 +/*% IPv6 */ +#define AF_INET6 99 +#endif + +#ifndef PF_INET6 +/*% IPv6 */ +#define PF_INET6 AF_INET6 +#endif + +#ifndef INADDR_LOOPBACK +/*% inaddr loopback */ +#define INADDR_LOOPBACK 0x7f000001UL +#endif + +#ifndef ISC_PLATFORM_HAVEIN6PKTINFO +/*% IPv6 packet info */ +struct in6_pktinfo { + struct in6_addr ipi6_addr; /*%< src/dst IPv6 address */ + unsigned int ipi6_ifindex; /*%< send/recv interface index */ +}; +#endif + +#if defined(ISC_PLATFORM_NEEDIN6ADDRANY) +extern const struct in6_addr isc_net_in6addrany; +/*% + * Cope with a missing in6addr_any and in6addr_loopback. + */ +#define in6addr_any isc_net_in6addrany +#endif + +#if defined(ISC_PLATFORM_HAVEIPV6) && defined(ISC_PLATFORM_NEEDIN6ADDRLOOPBACK) +extern const struct in6_addr isc_net_in6addrloop; +#define in6addr_loopback isc_net_in6addrloop +#endif + +#ifdef ISC_PLATFORM_FIXIN6ISADDR +#undef IN6_IS_ADDR_GEOGRAPHIC +/*! + * \brief + * Fix UnixWare 7.1.1's broken IN6_IS_ADDR_* definitions. + */ +#define IN6_IS_ADDR_GEOGRAPHIC(a) (((a)->S6_un.S6_l[0] & 0xE0) == 0x80) +#undef IN6_IS_ADDR_IPX +#define IN6_IS_ADDR_IPX(a) (((a)->S6_un.S6_l[0] & 0xFE) == 0x04) +#undef IN6_IS_ADDR_LINKLOCAL +#define IN6_IS_ADDR_LINKLOCAL(a) (((a)->S6_un.S6_l[0] & 0xC0FF) == 0x80FE) +#undef IN6_IS_ADDR_MULTICAST +#define IN6_IS_ADDR_MULTICAST(a) (((a)->S6_un.S6_l[0] & 0xFF) == 0xFF) +#undef IN6_IS_ADDR_NSAP +#define IN6_IS_ADDR_NSAP(a) (((a)->S6_un.S6_l[0] & 0xFE) == 0x02) +#undef IN6_IS_ADDR_PROVIDER +#define IN6_IS_ADDR_PROVIDER(a) (((a)->S6_un.S6_l[0] & 0xE0) == 0x40) +#undef IN6_IS_ADDR_SITELOCAL +#define IN6_IS_ADDR_SITELOCAL(a) (((a)->S6_un.S6_l[0] & 0xC0FF) == 0xC0FE) +#endif /* ISC_PLATFORM_FIXIN6ISADDR */ + +#ifdef ISC_PLATFORM_NEEDPORTT +/*% + * Ensure type in_port_t is defined. + */ +typedef isc_uint16_t in_port_t; +#endif + +#ifndef MSG_TRUNC +/*% + * If this system does not have MSG_TRUNC (as returned from recvmsg()) + * ISC_PLATFORM_RECVOVERFLOW will be defined. This will enable the MSG_TRUNC + * faking code in socket.c. + */ +#define ISC_PLATFORM_RECVOVERFLOW +#endif + +/*% IP address. */ +#define ISC__IPADDR(x) ((isc_uint32_t)htonl((isc_uint32_t)(x))) + +/*% Is IP address multicast? */ +#define ISC_IPADDR_ISMULTICAST(i) \ + (((isc_uint32_t)(i) & ISC__IPADDR(0xf0000000)) \ + == ISC__IPADDR(0xe0000000)) + +#define ISC_IPADDR_ISEXPERIMENTAL(i) \ + (((isc_uint32_t)(i) & ISC__IPADDR(0xf0000000)) \ + == ISC__IPADDR(0xf0000000)) + +/*** + *** Functions. + ***/ + +ISC_LANG_BEGINDECLS + +isc_result_t +isc_net_probeipv4(void); +/*%< + * Check if the system's kernel supports IPv4. + * + * Returns: + * + *\li #ISC_R_SUCCESS IPv4 is supported. + *\li #ISC_R_NOTFOUND IPv4 is not supported. + *\li #ISC_R_DISABLED IPv4 is disabled. + *\li #ISC_R_UNEXPECTED + */ + +isc_result_t +isc_net_probeipv6(void); +/*%< + * Check if the system's kernel supports IPv6. + * + * Returns: + * + *\li #ISC_R_SUCCESS IPv6 is supported. + *\li #ISC_R_NOTFOUND IPv6 is not supported. + *\li #ISC_R_DISABLED IPv6 is disabled. + *\li #ISC_R_UNEXPECTED + */ + +isc_result_t +isc_net_probe_ipv6only(void); +/*%< + * Check if the system's kernel supports the IPV6_V6ONLY socket option. + * + * Returns: + * + *\li #ISC_R_SUCCESS the option is supported for both TCP and UDP. + *\li #ISC_R_NOTFOUND IPv6 itself or the option is not supported. + *\li #ISC_R_UNEXPECTED + */ + +isc_result_t +isc_net_probe_ipv6pktinfo(void); +/* + * Check if the system's kernel supports the IPV6_(RECV)PKTINFO socket option + * for UDP sockets. + * + * Returns: + * + * \li #ISC_R_SUCCESS the option is supported. + * \li #ISC_R_NOTFOUND IPv6 itself or the option is not supported. + * \li #ISC_R_UNEXPECTED + */ + +void +isc_net_disableipv4(void); + +void +isc_net_disableipv6(void); + +void +isc_net_enableipv4(void); + +void +isc_net_enableipv6(void); + +isc_result_t +isc_net_probeunix(void); +/* + * Returns whether UNIX domain sockets are supported. + */ + +isc_result_t +isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high); +/*%< + * Returns system's default range of ephemeral UDP ports, if defined. + * If the range is not available or unknown, ISC_NET_PORTRANGELOW and + * ISC_NET_PORTRANGEHIGH will be returned. + * + * Requires: + * + *\li 'low' and 'high' must be non NULL. + * + * Returns: + * + *\li *low and *high will be the ports specifying the low and high ends of + * the range. + */ + +#ifdef ISC_PLATFORM_NEEDNTOP +const char * +isc_net_ntop(int af, const void *src, char *dst, size_t size); +#define inet_ntop isc_net_ntop +#endif + +#ifdef ISC_PLATFORM_NEEDPTON +int +isc_net_pton(int af, const char *src, void *dst); +#undef inet_pton +#define inet_pton isc_net_pton +#endif + +int +isc_net_aton(const char *cp, struct in_addr *addr); +#undef inet_aton +#define inet_aton isc_net_aton + +ISC_LANG_ENDDECLS + +#endif /* ISC_NET_H */ diff --git a/contrib/ntp/lib/isc/unix/include/isc/netdb.h b/contrib/ntp/lib/isc/unix/include/isc/netdb.h new file mode 100644 index 0000000..ff12a26 --- /dev/null +++ b/contrib/ntp/lib/isc/unix/include/isc/netdb.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: netdb.h,v 1.11 2007/06/19 23:47:19 tbox Exp $ */ + +#ifndef ISC_NETDB_H +#define ISC_NETDB_H 1 + +/***** + ***** Module Info + *****/ + +/*! \file + * \brief + * Portable netdb.h support. + * + * This module is responsible for defining the get<x>by<y> APIs. + * + * MP: + *\li No impact. + * + * Reliability: + *\li No anticipated impact. + * + * Resources: + *\li N/A. + * + * Security: + *\li No anticipated impact. + * + * Standards: + *\li BSD API + */ + +/*** + *** Imports. + ***/ + +#include <isc/net.h> + +#include <netdb.h> + +#endif /* ISC_NETDB_H */ diff --git a/contrib/ntp/lib/isc/unix/include/isc/offset.h b/contrib/ntp/lib/isc/unix/include/isc/offset.h new file mode 100644 index 0000000..8bf3779 --- /dev/null +++ b/contrib/ntp/lib/isc/unix/include/isc/offset.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: offset.h,v 1.17 2008/12/01 23:47:45 tbox Exp $ */ + +#ifndef ISC_OFFSET_H +#define ISC_OFFSET_H 1 + +/*! \file + * \brief + * File offsets are operating-system dependent. + */ +#include <limits.h> /* Required for CHAR_BIT. */ +#include <sys/types.h> +#include <stddef.h> /* For Linux Standard Base. */ + +typedef off_t isc_offset_t; + +/*% + * POSIX says "Additionally, blkcnt_t and off_t are extended signed integral + * types", so the maximum value is all 1s except for the high bit. + * This definition is more complex than it really needs to be because it was + * crafted to keep both the SunOS 5.6 and the HP/UX 11 compilers quiet about + * integer overflow. For example, though this is equivalent to just left + * shifting 1 to the high bit and then inverting the bits, the SunOS compiler + * is unhappy about shifting a positive "1" to negative in a signed integer. + */ +#define ISC_OFFSET_MAXIMUM \ + (~(((off_t)-1 >> (sizeof(off_t) * CHAR_BIT - 1)) \ + << (sizeof(off_t) * CHAR_BIT - 1))) + +#endif /* ISC_OFFSET_H */ diff --git a/contrib/ntp/lib/isc/unix/include/isc/stat.h b/contrib/ntp/lib/isc/unix/include/isc/stat.h new file mode 100644 index 0000000..b7a7986 --- /dev/null +++ b/contrib/ntp/lib/isc/unix/include/isc/stat.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: stat.h,v 1.5 2007/06/19 23:47:19 tbox Exp $ */ + +#ifndef ISC_STAT_H +#define ISC_STAT_H 1 + +/***** + ***** Module Info + *****/ + +/* + * Portable netdb.h support. + * + * This module is responsible for defining S_IS??? macros. + * + * MP: + * No impact. + * + * Reliability: + * No anticipated impact. + * + * Resources: + * N/A. + * + * Security: + * No anticipated impact. + * + */ + +/*** + *** Imports. + ***/ + +#include <sys/types.h> +#include <sys/stat.h> + +#endif /* ISC_STAT_H */ diff --git a/contrib/ntp/lib/isc/unix/include/isc/stdtime.h b/contrib/ntp/lib/isc/unix/include/isc/stdtime.h new file mode 100644 index 0000000..c4931bf --- /dev/null +++ b/contrib/ntp/lib/isc/unix/include/isc/stdtime.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +#ifndef ISC_STDTIME_H +#define ISC_STDTIME_H 1 + +/*! \file */ + +#include <isc/lang.h> +#include <isc/int.h> + +/*% + * It's public information that 'isc_stdtime_t' is an unsigned integral type. + * Applications that want maximum portability should not assume anything + * about its size. + */ +typedef isc_uint32_t isc_stdtime_t; + +/* but this flag helps... */ +#define STDTIME_ON_32BITS 1 + +/* + * isc_stdtime32_t is a 32-bit version of isc_stdtime_t. A variable of this + * type should only be used as an opaque integer (e.g.,) to compare two + * time values. + */ +typedef isc_uint32_t isc_stdtime32_t; + +ISC_LANG_BEGINDECLS +/* */ +void +isc_stdtime_get(isc_stdtime_t *t); +/*%< + * Set 't' to the number of seconds since 00:00:00 UTC, January 1, 1970. + * + * Requires: + * + *\li 't' is a valid pointer. + */ + +#define isc_stdtime_convert32(t, t32p) (*(t32p) = t) +/* + * Convert the standard time to its 32-bit version. + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_STDTIME_H */ diff --git a/contrib/ntp/lib/isc/unix/include/isc/strerror.h b/contrib/ntp/lib/isc/unix/include/isc/strerror.h new file mode 100644 index 0000000..899043b --- /dev/null +++ b/contrib/ntp/lib/isc/unix/include/isc/strerror.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: strerror.h,v 1.10 2008/12/01 23:47:45 tbox Exp $ */ + +#ifndef ISC_STRERROR_H +#define ISC_STRERROR_H + +/*! \file */ + +#include <sys/types.h> + +#include <isc/lang.h> + +ISC_LANG_BEGINDECLS + +/*% String Error Size */ +#define ISC_STRERRORSIZE 128 + +/*% + * Provide a thread safe wrapper to strerror(). + * + * Requires: + * 'buf' to be non NULL. + */ +void +isc__strerror(int num, char *buf, size_t bufsize); + +ISC_LANG_ENDDECLS + +#endif /* ISC_STRERROR_H */ diff --git a/contrib/ntp/lib/isc/unix/include/isc/syslog.h b/contrib/ntp/lib/isc/unix/include/isc/syslog.h new file mode 100644 index 0000000..7e0c88c --- /dev/null +++ b/contrib/ntp/lib/isc/unix/include/isc/syslog.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: syslog.h,v 1.7 2007/06/19 23:47:19 tbox Exp $ */ + +#ifndef ISC_SYSLOG_H +#define ISC_SYSLOG_H 1 + +/*! \file */ + +#include <isc/lang.h> +#include <isc/types.h> + +ISC_LANG_BEGINDECLS + +isc_result_t +isc_syslog_facilityfromstring(const char *str, int *facilityp); +/*%< + * Convert 'str' to the appropriate syslog facility constant. + * + * Requires: + * + *\li 'str' is not NULL + *\li 'facilityp' is not NULL + * + * Returns: + * \li #ISC_R_SUCCESS + * \li #ISC_R_NOTFOUND + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_SYSLOG_H */ diff --git a/contrib/ntp/lib/isc/unix/include/isc/time.h b/contrib/ntp/lib/isc/unix/include/isc/time.h new file mode 100644 index 0000000..dc1cef9 --- /dev/null +++ b/contrib/ntp/lib/isc/unix/include/isc/time.h @@ -0,0 +1,334 @@ +/* + * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: time.h,v 1.40 2009/01/05 23:47:54 tbox Exp $ */ + +#ifndef ISC_TIME_H +#define ISC_TIME_H 1 + +/*! \file */ + +#include <isc/lang.h> +#include <isc/types.h> + +/*** + *** Intervals + ***/ + +/*! + * \brief + * The contents of this structure are private, and MUST NOT be accessed + * directly by callers. + * + * The contents are exposed only to allow callers to avoid dynamic allocation. + */ +struct isc_interval { + unsigned int seconds; + unsigned int nanoseconds; +}; + +extern isc_interval_t *isc_interval_zero; + +ISC_LANG_BEGINDECLS + +void +isc_interval_set(isc_interval_t *i, + unsigned int seconds, unsigned int nanoseconds); +/*%< + * Set 'i' to a value representing an interval of 'seconds' seconds and + * 'nanoseconds' nanoseconds, suitable for use in isc_time_add() and + * isc_time_subtract(). + * + * Requires: + * + *\li 't' is a valid pointer. + *\li nanoseconds < 1000000000. + */ + +isc_boolean_t +isc_interval_iszero(const isc_interval_t *i); +/*%< + * Returns ISC_TRUE iff. 'i' is the zero interval. + * + * Requires: + * + *\li 'i' is a valid pointer. + */ + +/*** + *** Absolute Times + ***/ + +/*% + * The contents of this structure are private, and MUST NOT be accessed + * directly by callers. + * + * The contents are exposed only to allow callers to avoid dynamic allocation. + */ + +struct isc_time { + unsigned int seconds; + unsigned int nanoseconds; +}; + +extern isc_time_t *isc_time_epoch; + +void +isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds); +/*%< + * Set 't' to a value which represents the given number of seconds and + * nanoseconds since 00:00:00 January 1, 1970, UTC. + * + * Notes: + *\li The Unix version of this call is equivalent to: + *\code + * isc_time_settoepoch(t); + * isc_interval_set(i, seconds, nanoseconds); + * isc_time_add(t, i, t); + *\endcode + * + * Requires: + *\li 't' is a valid pointer. + *\li nanoseconds < 1000000000. + */ + +void +isc_time_settoepoch(isc_time_t *t); +/*%< + * Set 't' to the time of the epoch. + * + * Notes: + *\li The date of the epoch is platform-dependent. + * + * Requires: + * + *\li 't' is a valid pointer. + */ + +isc_boolean_t +isc_time_isepoch(const isc_time_t *t); +/*%< + * Returns ISC_TRUE iff. 't' is the epoch ("time zero"). + * + * Requires: + * + *\li 't' is a valid pointer. + */ + +isc_result_t +isc_time_now(isc_time_t *t); +/*%< + * Set 't' to the current absolute time. + * + * Requires: + * + *\li 't' is a valid pointer. + * + * Returns: + * + *\li Success + *\li Unexpected error + * Getting the time from the system failed. + *\li Out of range + * The time from the system is too large to be represented + * in the current definition of isc_time_t. + */ + +isc_result_t +isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i); +/*%< + * Set *t to the current absolute time + i. + * + * Note: + *\li This call is equivalent to: + * + *\code + * isc_time_now(t); + * isc_time_add(t, i, t); + *\endcode + * + * Requires: + * + *\li 't' and 'i' are valid pointers. + * + * Returns: + * + *\li Success + *\li Unexpected error + * Getting the time from the system failed. + *\li Out of range + * The interval added to the time from the system is too large to + * be represented in the current definition of isc_time_t. + */ + +int +isc_time_compare(const isc_time_t *t1, const isc_time_t *t2); +/*%< + * Compare the times referenced by 't1' and 't2' + * + * Requires: + * + *\li 't1' and 't2' are valid pointers. + * + * Returns: + * + *\li -1 t1 < t2 (comparing times, not pointers) + *\li 0 t1 = t2 + *\li 1 t1 > t2 + */ + +isc_result_t +isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result); +/*%< + * Add 'i' to 't', storing the result in 'result'. + * + * Requires: + * + *\li 't', 'i', and 'result' are valid pointers. + * + * Returns: + *\li Success + *\li Out of range + * The interval added to the time is too large to + * be represented in the current definition of isc_time_t. + */ + +isc_result_t +isc_time_subtract(const isc_time_t *t, const isc_interval_t *i, + isc_time_t *result); +/*%< + * Subtract 'i' from 't', storing the result in 'result'. + * + * Requires: + * + *\li 't', 'i', and 'result' are valid pointers. + * + * Returns: + *\li Success + *\li Out of range + * The interval is larger than the time since the epoch. + */ + +isc_uint64_t +isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2); +/*%< + * Find the difference in microseconds between time t1 and time t2. + * t2 is the subtrahend of t1; ie, difference = t1 - t2. + * + * Requires: + * + *\li 't1' and 't2' are valid pointers. + * + * Returns: + *\li The difference of t1 - t2, or 0 if t1 <= t2. + */ + +isc_uint32_t +isc_time_seconds(const isc_time_t *t); +/*%< + * Return the number of seconds since the epoch stored in a time structure. + * + * Requires: + * + *\li 't' is a valid pointer. + */ + +isc_result_t +isc_time_secondsastimet(const isc_time_t *t, time_t *secondsp); +/*%< + * Ensure the number of seconds in an isc_time_t is representable by a time_t. + * + * Notes: + *\li The number of seconds stored in an isc_time_t might be larger + * than the number of seconds a time_t is able to handle. Since + * time_t is mostly opaque according to the ANSI/ISO standard + * (essentially, all you can be sure of is that it is an arithmetic type, + * not even necessarily integral), it can be tricky to ensure that + * the isc_time_t is in the range a time_t can handle. Use this + * function in place of isc_time_seconds() any time you need to set a + * time_t from an isc_time_t. + * + * Requires: + *\li 't' is a valid pointer. + * + * Returns: + *\li Success + *\li Out of range + */ + +isc_uint32_t +isc_time_nanoseconds(const isc_time_t *t); +/*%< + * Return the number of nanoseconds stored in a time structure. + * + * Notes: + *\li This is the number of nanoseconds in excess of the number + * of seconds since the epoch; it will always be less than one + * full second. + * + * Requires: + *\li 't' is a valid pointer. + * + * Ensures: + *\li The returned value is less than 1*10^9. + */ + +void +isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len); +/*%< + * Format the time 't' into the buffer 'buf' of length 'len', + * using a format like "30-Aug-2000 04:06:47.997" and the local time zone. + * If the text does not fit in the buffer, the result is indeterminate, + * but is always guaranteed to be null terminated. + * + * Requires: + *\li 'len' > 0 + *\li 'buf' points to an array of at least len chars + * + */ + +void +isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len); +/*%< + * Format the time 't' into the buffer 'buf' of length 'len', + * using a format like "Mon, 30 Aug 2000 04:06:47 GMT" + * If the text does not fit in the buffer, the result is indeterminate, + * but is always guaranteed to be null terminated. + * + * Requires: + *\li 'len' > 0 + *\li 'buf' points to an array of at least len chars + * + */ + +void +isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len); +/*%< + * Format the time 't' into the buffer 'buf' of length 'len', + * using the ISO8601 format: "yyyy-mm-ddThh:mm:ssZ" + * If the text does not fit in the buffer, the result is indeterminate, + * but is always guaranteed to be null terminated. + * + * Requires: + *\li 'len' > 0 + *\li 'buf' points to an array of at least len chars + * + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_TIME_H */ diff --git a/contrib/ntp/lib/isc/unix/interfaceiter.c b/contrib/ntp/lib/isc/unix/interfaceiter.c new file mode 100644 index 0000000..c42fa68 --- /dev/null +++ b/contrib/ntp/lib/isc/unix/interfaceiter.c @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: interfaceiter.c,v 1.45 2008/12/01 03:51:47 marka Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <sys/types.h> +#include <sys/ioctl.h> +#ifdef HAVE_SYS_SOCKIO_H +#include <sys/sockio.h> /* Required for ifiter_ioctl.c. */ +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> + +#include <isc/interfaceiter.h> +#include <isc/log.h> +#include <isc/magic.h> +#include <isc/mem.h> +#include <isc/msgs.h> +#include <isc/net.h> +#include <isc/print.h> +#include <isc/result.h> +#include <isc/strerror.h> +#include <isc/string.h> +#include <isc/types.h> +#include <isc/util.h> + +/* Must follow <isc/net.h>. */ +#ifdef HAVE_NET_IF6_H +#include <net/if6.h> +#endif +#include <net/if.h> + +#ifdef HAVE_LINUX_IF_ADDR_H +# include <linux/if_addr.h> +#endif + +/* Common utility functions */ + +/*% + * Extract the network address part from a "struct sockaddr". + * \brief + * The address family is given explicitly + * instead of using src->sa_family, because the latter does not work + * for copying a network mask obtained by SIOCGIFNETMASK (it does + * not have a valid address family). + */ + +static void +get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src, + char *ifname) +{ + struct sockaddr_in6 *sa6; + +#if !defined(ISC_PLATFORM_HAVEIFNAMETOINDEX) || \ + !defined(ISC_PLATFORM_HAVESCOPEID) + UNUSED(ifname); +#endif + + /* clear any remaining value for safety */ + memset(dst, 0, sizeof(*dst)); + + dst->family = family; + switch (family) { + case AF_INET: + memcpy(&dst->type.in, + &((struct sockaddr_in *)(void *)src)->sin_addr, + sizeof(struct in_addr)); + break; + case AF_INET6: + sa6 = (struct sockaddr_in6 *)(void *)src; + memcpy(&dst->type.in6, &sa6->sin6_addr, + sizeof(struct in6_addr)); +#ifdef ISC_PLATFORM_HAVESCOPEID + if (sa6->sin6_scope_id != 0) + isc_netaddr_setzone(dst, sa6->sin6_scope_id); + else { + /* + * BSD variants embed scope zone IDs in the 128bit + * address as a kernel internal form. Unfortunately, + * the embedded IDs are not hidden from applications + * when getting access to them by sysctl or ioctl. + * We convert the internal format to the pure address + * part and the zone ID part. + * Since multicast addresses should not appear here + * and they cannot be distinguished from netmasks, + * we only consider unicast link-local addresses. + */ + if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) { + isc_uint16_t zone16; + + memcpy(&zone16, &sa6->sin6_addr.s6_addr[2], + sizeof(zone16)); + zone16 = ntohs(zone16); + if (zone16 != 0) { + /* the zone ID is embedded */ + isc_netaddr_setzone(dst, + (isc_uint32_t)zone16); + dst->type.in6.s6_addr[2] = 0; + dst->type.in6.s6_addr[3] = 0; +#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX + } else if (ifname != NULL) { + unsigned int zone; + + /* + * sin6_scope_id is still not provided, + * but the corresponding interface name + * is know. Use the interface ID as + * the link ID. + */ + zone = if_nametoindex(ifname); + if (zone != 0) { + isc_netaddr_setzone(dst, + (isc_uint32_t)zone); + } +#endif + } + } + } +#endif + break; + default: + INSIST(0); + break; + } +} + +/* + * Include system-dependent code. + */ + +#ifdef __linux +#define ISC_IF_INET6_SZ \ + sizeof("00000000000000000000000000000001 01 80 10 80 XXXXXXloXXXXXXXX\n") +static isc_result_t linux_if_inet6_next(isc_interfaceiter_t *); +static isc_result_t linux_if_inet6_current(isc_interfaceiter_t *); +static void linux_if_inet6_first(isc_interfaceiter_t *iter); +#endif + +#if HAVE_GETIFADDRS +#include "ifiter_getifaddrs.c" +#elif HAVE_IFLIST_SYSCTL +#include "ifiter_sysctl.c" +#else +#include "ifiter_ioctl.c" +#endif + +#ifdef __linux +static void +linux_if_inet6_first(isc_interfaceiter_t *iter) { + if (iter->proc != NULL) { + rewind(iter->proc); + (void)linux_if_inet6_next(iter); + } else + iter->valid = ISC_R_NOMORE; +} + +static isc_result_t +linux_if_inet6_next(isc_interfaceiter_t *iter) { + if (iter->proc != NULL && + fgets(iter->entry, sizeof(iter->entry), iter->proc) != NULL) + iter->valid = ISC_R_SUCCESS; + else + iter->valid = ISC_R_NOMORE; + return (iter->valid); +} + +static isc_result_t +linux_if_inet6_current(isc_interfaceiter_t *iter) { + char address[33]; + char name[IF_NAMESIZE+1]; + struct in6_addr addr6; + unsigned int ifindex; + int prefix, scope, flags; + int res; + unsigned int i; + + if (iter->valid != ISC_R_SUCCESS) + return (iter->valid); + if (iter->proc == NULL) { + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR, + "/proc/net/if_inet6:iter->proc == NULL"); + return (ISC_R_FAILURE); + } + + res = sscanf(iter->entry, "%32[a-f0-9] %x %x %x %x %16s\n", + address, &ifindex, &prefix, &scope, &flags, name); + if (res != 6) { + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR, + "/proc/net/if_inet6:sscanf() -> %d (expected 6)", + res); + return (ISC_R_FAILURE); + } + if (strlen(address) != 32) { + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_INTERFACE, ISC_LOG_ERROR, + "/proc/net/if_inet6:strlen(%s) != 32", address); + return (ISC_R_FAILURE); + } + /* + ** Ignore DAD addresses -- + ** we can't bind to them until they are resolved + */ +#ifdef IFA_F_TENTATIVE + if (flags & IFA_F_TENTATIVE) + return (ISC_R_IGNORE); +#endif + + for (i = 0; i < 16; i++) { + unsigned char byte; + static const char hex[] = "0123456789abcdef"; + byte = ((strchr(hex, address[i * 2]) - hex) << 4) | + (strchr(hex, address[i * 2 + 1]) - hex); + addr6.s6_addr[i] = byte; + } + iter->current.af = AF_INET6; + iter->current.flags = INTERFACE_F_UP; + isc_netaddr_fromin6(&iter->current.address, &addr6); + iter->current.ifindex = ifindex; + if (isc_netaddr_islinklocal(&iter->current.address)) { + isc_netaddr_setzone(&iter->current.address, + (isc_uint32_t)ifindex); + } + for (i = 0; i < 16; i++) { + if (prefix > 8) { + addr6.s6_addr[i] = 0xff; + prefix -= 8; + } else { + addr6.s6_addr[i] = (0xff << (8 - prefix)) & 0xff; + prefix = 0; + } + } + isc_netaddr_fromin6(&iter->current.netmask, &addr6); + strncpy(iter->current.name, name, sizeof(iter->current.name)); + return (ISC_R_SUCCESS); +} +#endif + +/* + * The remaining code is common to the sysctl and ioctl case. + */ + +isc_result_t +isc_interfaceiter_current(isc_interfaceiter_t *iter, + isc_interface_t *ifdata) +{ + REQUIRE(iter->result == ISC_R_SUCCESS); + memcpy(ifdata, &iter->current, sizeof(*ifdata)); + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_interfaceiter_first(isc_interfaceiter_t *iter) { + isc_result_t result; + + REQUIRE(VALID_IFITER(iter)); + + internal_first(iter); + for (;;) { + result = internal_current(iter); + if (result != ISC_R_IGNORE) + break; + result = internal_next(iter); + if (result != ISC_R_SUCCESS) + break; + } + iter->result = result; + return (result); +} + +isc_result_t +isc_interfaceiter_next(isc_interfaceiter_t *iter) { + isc_result_t result; + + REQUIRE(VALID_IFITER(iter)); + REQUIRE(iter->result == ISC_R_SUCCESS); + + for (;;) { + result = internal_next(iter); + if (result != ISC_R_SUCCESS) + break; + result = internal_current(iter); + if (result != ISC_R_IGNORE) + break; + } + iter->result = result; + return (result); +} + +void +isc_interfaceiter_destroy(isc_interfaceiter_t **iterp) +{ + isc_interfaceiter_t *iter; + REQUIRE(iterp != NULL); + iter = *iterp; + REQUIRE(VALID_IFITER(iter)); + + internal_destroy(iter); + if (iter->buf != NULL) + isc_mem_put(iter->mctx, iter->buf, iter->bufsize); + + iter->magic = 0; + isc_mem_put(iter->mctx, iter, sizeof(*iter)); + *iterp = NULL; +} diff --git a/contrib/ntp/lib/isc/unix/ipv6.c b/contrib/ntp/lib/isc/unix/ipv6.c new file mode 100644 index 0000000..61e984f --- /dev/null +++ b/contrib/ntp/lib/isc/unix/ipv6.c @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: ipv6.c,v 1.14 2007/06/19 23:47:18 tbox Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <isc/ipv6.h> + +const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; +const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; diff --git a/contrib/ntp/lib/isc/unix/keyboard.c b/contrib/ntp/lib/isc/unix/keyboard.c new file mode 100644 index 0000000..8ee62d3 --- /dev/null +++ b/contrib/ntp/lib/isc/unix/keyboard.c @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: keyboard.c,v 1.13 2007/06/19 23:47:18 tbox Exp $ */ + +#include <config.h> + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/uio.h> + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> +#include <fcntl.h> + +#include <isc/keyboard.h> +#include <isc/util.h> + +isc_result_t +isc_keyboard_open(isc_keyboard_t *keyboard) { + int fd; + isc_result_t ret; + struct termios current_mode; + + REQUIRE(keyboard != NULL); + + fd = open("/dev/tty", O_RDONLY, 0); + if (fd < 0) + return (ISC_R_IOERROR); + + keyboard->fd = fd; + + if (tcgetattr(fd, &keyboard->saved_mode) < 0) { + ret = ISC_R_IOERROR; + goto errout; + } + + current_mode = keyboard->saved_mode; + + current_mode.c_iflag &= + ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); + current_mode.c_oflag &= ~OPOST; + current_mode.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); + current_mode.c_cflag &= ~(CSIZE|PARENB); + current_mode.c_cflag |= CS8; + + current_mode.c_cc[VMIN] = 1; + current_mode.c_cc[VTIME] = 0; + if (tcsetattr(fd, TCSAFLUSH, ¤t_mode) < 0) { + ret = ISC_R_IOERROR; + goto errout; + } + + keyboard->result = ISC_R_SUCCESS; + + return (ISC_R_SUCCESS); + + errout: + close (fd); + + return (ret); +} + +isc_result_t +isc_keyboard_close(isc_keyboard_t *keyboard, unsigned int sleeptime) { + REQUIRE(keyboard != NULL); + + if (sleeptime > 0 && keyboard->result != ISC_R_CANCELED) + (void)sleep(sleeptime); + + (void)tcsetattr(keyboard->fd, TCSAFLUSH, &keyboard->saved_mode); + (void)close(keyboard->fd); + + keyboard->fd = -1; + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_keyboard_getchar(isc_keyboard_t *keyboard, unsigned char *cp) { + ssize_t cc; + unsigned char c; + cc_t *controlchars; + + REQUIRE(keyboard != NULL); + REQUIRE(cp != NULL); + + cc = read(keyboard->fd, &c, 1); + if (cc < 0) { + keyboard->result = ISC_R_IOERROR; + return (keyboard->result); + } + + controlchars = keyboard->saved_mode.c_cc; + if (c == controlchars[VINTR] || c == controlchars[VQUIT]) { + keyboard->result = ISC_R_CANCELED; + return (keyboard->result); + } + + *cp = c; + + return (ISC_R_SUCCESS); +} + +isc_boolean_t +isc_keyboard_canceled(isc_keyboard_t *keyboard) { + return (ISC_TF(keyboard->result == ISC_R_CANCELED)); +} diff --git a/contrib/ntp/lib/isc/unix/net.c b/contrib/ntp/lib/isc/unix/net.c new file mode 100644 index 0000000..2ba17d16 --- /dev/null +++ b/contrib/ntp/lib/isc/unix/net.c @@ -0,0 +1,522 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2008, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +#include <config.h> + +#include <sys/types.h> + +#if defined(HAVE_SYS_SYSCTL_H) +#if defined(HAVE_SYS_PARAM_H) +#include <sys/param.h> +#endif +#include <sys/sysctl.h> +#endif + +#include <errno.h> +#include <unistd.h> + +#include <isc/log.h> +#include <isc/msgs.h> +#include <isc/net.h> +#include <isc/once.h> +#include <isc/strerror.h> +#include <isc/string.h> +#include <isc/util.h> + +/*% + * Definitions about UDP port range specification. This is a total mess of + * portability variants: some use sysctl (but the sysctl names vary), some use + * system-specific interfaces, some have the same interface for IPv4 and IPv6, + * some separate them, etc... + */ + +/*% + * The last resort defaults: use all non well known port space + */ +#ifndef ISC_NET_PORTRANGELOW +#define ISC_NET_PORTRANGELOW 1024 +#endif /* ISC_NET_PORTRANGELOW */ +#ifndef ISC_NET_PORTRANGEHIGH +#define ISC_NET_PORTRANGEHIGH 65535 +#endif /* ISC_NET_PORTRANGEHIGH */ + +#ifdef HAVE_SYSCTLBYNAME + +/*% + * sysctl variants + */ +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__DragonFly__) +#define USE_SYSCTL_PORTRANGE +#define SYSCTL_V4PORTRANGE_LOW "net.inet.ip.portrange.hifirst" +#define SYSCTL_V4PORTRANGE_HIGH "net.inet.ip.portrange.hilast" +#define SYSCTL_V6PORTRANGE_LOW "net.inet.ip.portrange.hifirst" +#define SYSCTL_V6PORTRANGE_HIGH "net.inet.ip.portrange.hilast" +#endif + +#ifdef __NetBSD__ +#define USE_SYSCTL_PORTRANGE +#define SYSCTL_V4PORTRANGE_LOW "net.inet.ip.anonportmin" +#define SYSCTL_V4PORTRANGE_HIGH "net.inet.ip.anonportmax" +#define SYSCTL_V6PORTRANGE_LOW "net.inet6.ip6.anonportmin" +#define SYSCTL_V6PORTRANGE_HIGH "net.inet6.ip6.anonportmax" +#endif + +#else /* !HAVE_SYSCTLBYNAME */ + +#ifdef __OpenBSD__ +#define USE_SYSCTL_PORTRANGE +#define SYSCTL_V4PORTRANGE_LOW { CTL_NET, PF_INET, IPPROTO_IP, \ + IPCTL_IPPORT_HIFIRSTAUTO } +#define SYSCTL_V4PORTRANGE_HIGH { CTL_NET, PF_INET, IPPROTO_IP, \ + IPCTL_IPPORT_HILASTAUTO } +/* Same for IPv6 */ +#define SYSCTL_V6PORTRANGE_LOW SYSCTL_V4PORTRANGE_LOW +#define SYSCTL_V6PORTRANGE_HIGH SYSCTL_V4PORTRANGE_HIGH +#endif + +#endif /* HAVE_SYSCTLBYNAME */ + +#if defined(ISC_PLATFORM_NEEDIN6ADDRANY) +const struct in6_addr isc_net_in6addrany = IN6ADDR_ANY_INIT; +#endif + +#if defined(ISC_PLATFORM_HAVEIPV6) + +# if defined(ISC_PLATFORM_NEEDIN6ADDRLOOPBACK) +const struct in6_addr isc_net_in6addrloop = IN6ADDR_LOOPBACK_INIT; +# endif + +# if defined(WANT_IPV6) +static isc_once_t once_ipv6only = ISC_ONCE_INIT; +# endif + +# if defined(ISC_PLATFORM_HAVEIN6PKTINFO) +static isc_once_t once_ipv6pktinfo = ISC_ONCE_INIT; +# endif +#endif /* ISC_PLATFORM_HAVEIPV6 */ + +static isc_once_t once = ISC_ONCE_INIT; + +static isc_result_t ipv4_result = ISC_R_NOTFOUND; +static isc_result_t ipv6_result = ISC_R_NOTFOUND; +static isc_result_t unix_result = ISC_R_NOTFOUND; +static isc_result_t ipv6only_result = ISC_R_NOTFOUND; +static isc_result_t ipv6pktinfo_result = ISC_R_NOTFOUND; + +static isc_result_t +try_proto(int domain) { + int s; + isc_result_t result = ISC_R_SUCCESS; + char strbuf[ISC_STRERRORSIZE]; + + s = socket(domain, SOCK_STREAM, 0); + if (s == -1) { + switch (errno) { +#ifdef EAFNOSUPPORT + case EAFNOSUPPORT: +#endif +#ifdef EPROTONOSUPPORT + case EPROTONOSUPPORT: +#endif +#ifdef EINVAL + case EINVAL: +#endif + return (ISC_R_NOTFOUND); + default: + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "socket() %s: %s", + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, + "failed"), + strbuf); + return (ISC_R_UNEXPECTED); + } + } + +#ifdef ISC_PLATFORM_HAVEIPV6 +#ifdef WANT_IPV6 +#ifdef ISC_PLATFORM_HAVEIN6PKTINFO + if (domain == PF_INET6) { + struct sockaddr_in6 sin6; + GETSOCKNAME_SOCKLEN_TYPE len; /* NTP local change */ + + /* + * Check to see if IPv6 is broken, as is common on Linux. + */ + len = sizeof(sin6); + if (getsockname(s, (struct sockaddr *)&sin6, &len) < 0) + { + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR, + "retrieving the address of an IPv6 " + "socket from the kernel failed."); + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR, + "IPv6 is not supported."); + result = ISC_R_NOTFOUND; + } else { + if (len == sizeof(struct sockaddr_in6)) + result = ISC_R_SUCCESS; + else { + isc_log_write(isc_lctx, + ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, + ISC_LOG_ERROR, + "IPv6 structures in kernel and " + "user space do not match."); + isc_log_write(isc_lctx, + ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, + ISC_LOG_ERROR, + "IPv6 is not supported."); + result = ISC_R_NOTFOUND; + } + } + } +#endif +#endif +#endif + + (void)close(s); + + return (result); +} + +static void +initialize_action(void) { + ipv4_result = try_proto(PF_INET); +#ifdef ISC_PLATFORM_HAVEIPV6 +#ifdef WANT_IPV6 +#ifdef ISC_PLATFORM_HAVEIN6PKTINFO + ipv6_result = try_proto(PF_INET6); +#endif +#endif +#endif +#ifdef ISC_PLATFORM_HAVESYSUNH + unix_result = try_proto(PF_UNIX); +#endif +} + +static void +initialize(void) { + RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); +} + +isc_result_t +isc_net_probeipv4(void) { + initialize(); + return (ipv4_result); +} + +isc_result_t +isc_net_probeipv6(void) { + initialize(); + return (ipv6_result); +} + +isc_result_t +isc_net_probeunix(void) { + initialize(); + return (unix_result); +} + +#ifdef ISC_PLATFORM_HAVEIPV6 +#ifdef WANT_IPV6 +static void +try_ipv6only(void) { +#ifdef IPV6_V6ONLY + int s, on; + char strbuf[ISC_STRERRORSIZE]; +#endif + isc_result_t result; + + result = isc_net_probeipv6(); + if (result != ISC_R_SUCCESS) { + ipv6only_result = result; + return; + } + +#ifndef IPV6_V6ONLY + ipv6only_result = ISC_R_NOTFOUND; + return; +#else + /* check for TCP sockets */ + s = socket(PF_INET6, SOCK_STREAM, 0); + if (s == -1) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "socket() %s: %s", + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, + "failed"), + strbuf); + ipv6only_result = ISC_R_UNEXPECTED; + return; + } + + on = 1; + if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) { + ipv6only_result = ISC_R_NOTFOUND; + goto close; + } + + close(s); + + /* check for UDP sockets */ + s = socket(PF_INET6, SOCK_DGRAM, 0); + if (s == -1) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "socket() %s: %s", + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, + "failed"), + strbuf); + ipv6only_result = ISC_R_UNEXPECTED; + return; + } + + on = 1; + if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) { + ipv6only_result = ISC_R_NOTFOUND; + goto close; + } + + ipv6only_result = ISC_R_SUCCESS; + +close: + close(s); + return; +#endif /* IPV6_V6ONLY */ +} + +static void +initialize_ipv6only(void) { + RUNTIME_CHECK(isc_once_do(&once_ipv6only, + try_ipv6only) == ISC_R_SUCCESS); +} + +#ifdef ISC_PLATFORM_HAVEIN6PKTINFO +static void +try_ipv6pktinfo(void) { + int s, on; + char strbuf[ISC_STRERRORSIZE]; + isc_result_t result; + int optname; + + result = isc_net_probeipv6(); + if (result != ISC_R_SUCCESS) { + ipv6pktinfo_result = result; + return; + } + + /* we only use this for UDP sockets */ + s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (s == -1) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "socket() %s: %s", + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, + "failed"), + strbuf); + ipv6pktinfo_result = ISC_R_UNEXPECTED; + return; + } + +#ifdef IPV6_RECVPKTINFO + optname = IPV6_RECVPKTINFO; +#else + optname = IPV6_PKTINFO; +#endif + on = 1; + if (setsockopt(s, IPPROTO_IPV6, optname, &on, sizeof(on)) < 0) { + ipv6pktinfo_result = ISC_R_NOTFOUND; + goto close; + } + + ipv6pktinfo_result = ISC_R_SUCCESS; + +close: + close(s); + return; +} + +static void +initialize_ipv6pktinfo(void) { + RUNTIME_CHECK(isc_once_do(&once_ipv6pktinfo, + try_ipv6pktinfo) == ISC_R_SUCCESS); +} +#endif /* ISC_PLATFORM_HAVEIN6PKTINFO */ +#endif /* WANT_IPV6 */ +#endif /* ISC_PLATFORM_HAVEIPV6 */ + +isc_result_t +isc_net_probe_ipv6only(void) { +#ifdef ISC_PLATFORM_HAVEIPV6 +#ifdef WANT_IPV6 + initialize_ipv6only(); +#else + ipv6only_result = ISC_R_NOTFOUND; +#endif +#endif + return (ipv6only_result); +} + +isc_result_t +isc_net_probe_ipv6pktinfo(void) { +#ifdef ISC_PLATFORM_HAVEIPV6 +#ifdef ISC_PLATFORM_HAVEIN6PKTINFO +#ifdef WANT_IPV6 + initialize_ipv6pktinfo(); +#else + ipv6pktinfo_result = ISC_R_NOTFOUND; +#endif +#endif +#endif + return (ipv6pktinfo_result); +} + +#if defined(USE_SYSCTL_PORTRANGE) +#if defined(HAVE_SYSCTLBYNAME) +static isc_result_t +getudpportrange_sysctl(int af, in_port_t *low, in_port_t *high) { + int port_low, port_high; + size_t portlen; + const char *sysctlname_lowport, *sysctlname_hiport; + + if (af == AF_INET) { + sysctlname_lowport = SYSCTL_V4PORTRANGE_LOW; + sysctlname_hiport = SYSCTL_V4PORTRANGE_HIGH; + } else { + sysctlname_lowport = SYSCTL_V6PORTRANGE_LOW; + sysctlname_hiport = SYSCTL_V6PORTRANGE_HIGH; + } + portlen = sizeof(portlen); + if (sysctlbyname(sysctlname_lowport, &port_low, &portlen, + NULL, 0) < 0) { + return (ISC_R_FAILURE); + } + portlen = sizeof(portlen); + if (sysctlbyname(sysctlname_hiport, &port_high, &portlen, + NULL, 0) < 0) { + return (ISC_R_FAILURE); + } + if ((port_low & ~0xffff) != 0 || (port_high & ~0xffff) != 0) + return (ISC_R_RANGE); + + *low = (in_port_t)port_low; + *high = (in_port_t)port_high; + + return (ISC_R_SUCCESS); +} +#else /* !HAVE_SYSCTLBYNAME */ +static isc_result_t +getudpportrange_sysctl(int af, in_port_t *low, in_port_t *high) { + int mib_lo4[4] = SYSCTL_V4PORTRANGE_LOW; + int mib_hi4[4] = SYSCTL_V4PORTRANGE_HIGH; + int mib_lo6[4] = SYSCTL_V6PORTRANGE_LOW; + int mib_hi6[4] = SYSCTL_V6PORTRANGE_HIGH; + int *mib_lo, *mib_hi, miblen; + int port_low, port_high; + size_t portlen; + + if (af == AF_INET) { + mib_lo = mib_lo4; + mib_hi = mib_hi4; + miblen = sizeof(mib_lo4) / sizeof(mib_lo4[0]); + } else { + mib_lo = mib_lo6; + mib_hi = mib_hi6; + miblen = sizeof(mib_lo6) / sizeof(mib_lo6[0]); + } + + portlen = sizeof(portlen); + if (sysctl(mib_lo, miblen, &port_low, &portlen, NULL, 0) < 0) { + return (ISC_R_FAILURE); + } + + portlen = sizeof(portlen); + if (sysctl(mib_hi, miblen, &port_high, &portlen, NULL, 0) < 0) { + return (ISC_R_FAILURE); + } + + if ((port_low & ~0xffff) != 0 || (port_high & ~0xffff) != 0) + return (ISC_R_RANGE); + + *low = (in_port_t) port_low; + *high = (in_port_t) port_high; + + return (ISC_R_SUCCESS); +} +#endif /* HAVE_SYSCTLBYNAME */ +#endif /* USE_SYSCTL_PORTRANGE */ + +isc_result_t +isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high) { + int result = ISC_R_FAILURE; + + REQUIRE(low != NULL && high != NULL); + +#if defined(USE_SYSCTL_PORTRANGE) + result = getudpportrange_sysctl(af, low, high); +#else + UNUSED(af); +#endif + + if (result != ISC_R_SUCCESS) { + *low = ISC_NET_PORTRANGELOW; + *high = ISC_NET_PORTRANGEHIGH; + } + + return (ISC_R_SUCCESS); /* we currently never fail in this function */ +} + +void +isc_net_disableipv4(void) { + initialize(); + if (ipv4_result == ISC_R_SUCCESS) + ipv4_result = ISC_R_DISABLED; +} + +void +isc_net_disableipv6(void) { + initialize(); + if (ipv6_result == ISC_R_SUCCESS) + ipv6_result = ISC_R_DISABLED; +} + +void +isc_net_enableipv4(void) { + initialize(); + if (ipv4_result == ISC_R_DISABLED) + ipv4_result = ISC_R_SUCCESS; +} + +void +isc_net_enableipv6(void) { + initialize(); + if (ipv6_result == ISC_R_DISABLED) + ipv6_result = ISC_R_SUCCESS; +} diff --git a/contrib/ntp/lib/isc/unix/os.c b/contrib/ntp/lib/isc/unix/os.c new file mode 100644 index 0000000..c050d14 --- /dev/null +++ b/contrib/ntp/lib/isc/unix/os.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: os.c,v 1.18 2007/06/19 23:47:18 tbox Exp $ */ + +#include <config.h> + +#include <isc/os.h> + + +#ifdef HAVE_SYSCONF + +#include <unistd.h> + +#ifndef __hpux +static inline long +sysconf_ncpus(void) { +#if defined(_SC_NPROCESSORS_ONLN) + return sysconf((_SC_NPROCESSORS_ONLN)); +#elif defined(_SC_NPROC_ONLN) + return sysconf((_SC_NPROC_ONLN)); +#else + return (0); +#endif +} +#endif +#endif /* HAVE_SYSCONF */ + + +#ifdef __hpux + +#include <sys/pstat.h> + +static inline int +hpux_ncpus(void) { + struct pst_dynamic psd; + if (pstat_getdynamic(&psd, sizeof(psd), 1, 0) != -1) + return (psd.psd_proc_cnt); + else + return (0); +} + +#endif /* __hpux */ + +#if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTLBYNAME) +#include <sys/types.h> /* for FreeBSD */ +#include <sys/param.h> /* for NetBSD */ +#include <sys/sysctl.h> + +static int +sysctl_ncpus(void) { + int ncpu, result; + size_t len; + + len = sizeof(ncpu); + result = sysctlbyname("hw.ncpu", &ncpu, &len , 0, 0); + if (result != -1) + return (ncpu); + return (0); +} +#endif + +unsigned int +isc_os_ncpus(void) { + long ncpus = 0; + +#ifdef __hpux + ncpus = hpux_ncpus(); +#elif defined(HAVE_SYSCONF) + ncpus = sysconf_ncpus(); +#endif +#if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTLBYNAME) + if (ncpus <= 0) + ncpus = sysctl_ncpus(); +#endif + if (ncpus <= 0) + ncpus = 1; + + return ((unsigned int)ncpus); +} diff --git a/contrib/ntp/lib/isc/unix/resource.c b/contrib/ntp/lib/isc/unix/resource.c new file mode 100644 index 0000000..29596e2 --- /dev/null +++ b/contrib/ntp/lib/isc/unix/resource.c @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2004, 2007-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: resource.c,v 1.23 2009/02/13 23:48:14 tbox Exp $ */ + +#include <config.h> + +#include <sys/types.h> +#include <sys/time.h> /* Required on some systems for <sys/resource.h>. */ +#include <sys/resource.h> + +#include <isc/platform.h> +#include <isc/resource.h> +#include <isc/result.h> +#include <isc/util.h> + +#ifdef __linux__ +#include <linux/fs.h> /* To get the large NR_OPEN. */ +#endif + +#if defined(__hpux) && defined(HAVE_SYS_DYNTUNE_H) +#include <sys/dyntune.h> +#endif + +#include "errno2result.h" + +static isc_result_t +resource2rlim(isc_resource_t resource, int *rlim_resource) { + isc_result_t result = ISC_R_SUCCESS; + + switch (resource) { + case isc_resource_coresize: + *rlim_resource = RLIMIT_CORE; + break; + case isc_resource_cputime: + *rlim_resource = RLIMIT_CPU; + break; + case isc_resource_datasize: + *rlim_resource = RLIMIT_DATA; + break; + case isc_resource_filesize: + *rlim_resource = RLIMIT_FSIZE; + break; + case isc_resource_lockedmemory: +#ifdef RLIMIT_MEMLOCK + *rlim_resource = RLIMIT_MEMLOCK; +#else + result = ISC_R_NOTIMPLEMENTED; +#endif + break; + case isc_resource_openfiles: +#ifdef RLIMIT_NOFILE + *rlim_resource = RLIMIT_NOFILE; +#else + result = ISC_R_NOTIMPLEMENTED; +#endif + break; + case isc_resource_processes: +#ifdef RLIMIT_NPROC + *rlim_resource = RLIMIT_NPROC; +#else + result = ISC_R_NOTIMPLEMENTED; +#endif + break; + case isc_resource_residentsize: +#ifdef RLIMIT_RSS + *rlim_resource = RLIMIT_RSS; +#else + result = ISC_R_NOTIMPLEMENTED; +#endif + break; + case isc_resource_stacksize: + *rlim_resource = RLIMIT_STACK; + break; + default: + /* + * This test is not very robust if isc_resource_t + * changes, but generates a clear assertion message. + */ + REQUIRE(resource >= isc_resource_coresize && + resource <= isc_resource_stacksize); + + result = ISC_R_RANGE; + break; + } + + return (result); +} + +isc_result_t +isc_resource_setlimit(isc_resource_t resource, isc_resourcevalue_t value) { + struct rlimit rl; + ISC_PLATFORM_RLIMITTYPE rlim_value; + int unixresult; + int unixresource; + isc_result_t result; + + result = resource2rlim(resource, &unixresource); + if (result != ISC_R_SUCCESS) + return (result); + + if (value == ISC_RESOURCE_UNLIMITED) + rlim_value = RLIM_INFINITY; + + else { + /* + * isc_resourcevalue_t was chosen as an unsigned 64 bit + * integer so that it could contain the maximum range of + * reasonable values. Unfortunately, this exceeds the typical + * range on Unix systems. Ensure the range of + * ISC_PLATFORM_RLIMITTYPE is not overflowed. + */ + isc_resourcevalue_t rlim_max; + isc_boolean_t rlim_t_is_signed = + ISC_TF(((double)(ISC_PLATFORM_RLIMITTYPE)-1) < 0); + + if (rlim_t_is_signed) + rlim_max = ~((ISC_PLATFORM_RLIMITTYPE)1 << + (sizeof(ISC_PLATFORM_RLIMITTYPE) * 8 - 1)); + else + rlim_max = (ISC_PLATFORM_RLIMITTYPE)-1; + + if (value > rlim_max) + value = rlim_max; + + rlim_value = value; + } + + rl.rlim_cur = rl.rlim_max = rlim_value; + unixresult = setrlimit(unixresource, &rl); + + if (unixresult == 0) + return (ISC_R_SUCCESS); + +#if defined(OPEN_MAX) && defined(__APPLE__) + /* + * The Darwin kernel doesn't accept RLIM_INFINITY for rlim_cur; the + * maximum possible value is OPEN_MAX. BIND8 used to use + * sysconf(_SC_OPEN_MAX) for such a case, but this value is much + * smaller than OPEN_MAX and is not really effective. + */ + if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) { + rl.rlim_cur = OPEN_MAX; + unixresult = setrlimit(unixresource, &rl); + if (unixresult == 0) + return (ISC_R_SUCCESS); + } +#elif defined(__linux__) +#ifndef NR_OPEN +#define NR_OPEN (1024*1024) +#endif + + /* + * Some Linux kernels don't accept RLIM_INFINIT; the maximum + * possible value is the NR_OPEN defined in linux/fs.h. + */ + if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) { + rl.rlim_cur = rl.rlim_max = NR_OPEN; + unixresult = setrlimit(unixresource, &rl); + if (unixresult == 0) + return (ISC_R_SUCCESS); + } +#elif defined(__hpux) && defined(HAVE_SYS_DYNTUNE_H) + if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) { + uint64_t maxfiles; + if (gettune("maxfiles_lim", &maxfiles) == 0) { + rl.rlim_cur = rl.rlim_max = maxfiles; + unixresult = setrlimit(unixresource, &rl); + if (unixresult == 0) + return (ISC_R_SUCCESS); + } + } +#endif + if (resource == isc_resource_openfiles && rlim_value == RLIM_INFINITY) { + if (getrlimit(unixresource, &rl) == 0) { + rl.rlim_cur = rl.rlim_max; + unixresult = setrlimit(unixresource, &rl); + if (unixresult == 0) + return (ISC_R_SUCCESS); + } + } + return (isc__errno2result(errno)); +} + +isc_result_t +isc_resource_getlimit(isc_resource_t resource, isc_resourcevalue_t *value) { + int unixresult; + int unixresource; + struct rlimit rl; + isc_result_t result; + + result = resource2rlim(resource, &unixresource); + if (result == ISC_R_SUCCESS) { + unixresult = getrlimit(unixresource, &rl); + INSIST(unixresult == 0); + *value = rl.rlim_max; + } + + return (result); +} + +isc_result_t +isc_resource_getcurlimit(isc_resource_t resource, isc_resourcevalue_t *value) { + int unixresult; + int unixresource; + struct rlimit rl; + isc_result_t result; + + result = resource2rlim(resource, &unixresource); + if (result == ISC_R_SUCCESS) { + unixresult = getrlimit(unixresource, &rl); + INSIST(unixresult == 0); + *value = rl.rlim_cur; + } + + return (result); +} diff --git a/contrib/ntp/lib/isc/unix/socket.c b/contrib/ntp/lib/isc/unix/socket.c new file mode 100644 index 0000000..5fed888 --- /dev/null +++ b/contrib/ntp/lib/isc/unix/socket.c @@ -0,0 +1,6011 @@ +/* + * Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/*! \file */ + +#include <config.h> + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/uio.h> + +#include <errno.h> +#include <fcntl.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <isc/buffer.h> +#include <isc/bufferlist.h> +#include <isc/condition.h> +#include <isc/formatcheck.h> +#include <isc/list.h> +#include <isc/log.h> +#include <isc/mem.h> +#include <isc/msgs.h> +#include <isc/mutex.h> +#include <isc/net.h> +#include <isc/once.h> +#include <isc/platform.h> +#include <isc/print.h> +#include <isc/region.h> +#include <isc/socket.h> +#include <isc/stats.h> +#include <isc/strerror.h> +#include <isc/task.h> +#include <isc/thread.h> +#include <isc/util.h> +#include <isc/xml.h> + +#ifdef ISC_PLATFORM_HAVESYSUNH +#include <sys/un.h> +#endif +#ifdef ISC_PLATFORM_HAVEKQUEUE +#include <sys/event.h> +#endif +#ifdef ISC_PLATFORM_HAVEEPOLL +#include <sys/epoll.h> +#endif +#ifdef ISC_PLATFORM_HAVEDEVPOLL +#if defined(HAVE_SYS_DEVPOLL_H) +#include <sys/devpoll.h> +#elif defined(HAVE_DEVPOLL_H) +#include <devpoll.h> +#endif +#endif + +#include "errno2result.h" + +/* See task.c about the following definition: */ +#ifdef BIND9 +#ifdef ISC_PLATFORM_USETHREADS +#define USE_WATCHER_THREAD +#else +#define USE_SHARED_MANAGER +#endif /* ISC_PLATFORM_USETHREADS */ +#endif /* BIND9 */ + +#ifndef USE_WATCHER_THREAD +#include "socket_p.h" +#include "../task_p.h" +#endif /* USE_WATCHER_THREAD */ + +#if defined(SO_BSDCOMPAT) && defined(__linux__) +#include <sys/utsname.h> +#endif + +/*% + * Choose the most preferable multiplex method. + */ +#ifdef ISC_PLATFORM_HAVEKQUEUE +#define USE_KQUEUE +#elif defined (ISC_PLATFORM_HAVEEPOLL) +#define USE_EPOLL +#elif defined (ISC_PLATFORM_HAVEDEVPOLL) +#define USE_DEVPOLL +typedef struct { + unsigned int want_read : 1, + want_write : 1; +} pollinfo_t; +#else +#define USE_SELECT +#endif /* ISC_PLATFORM_HAVEKQUEUE */ + +#ifndef USE_WATCHER_THREAD +#if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL) +struct isc_socketwait { + int nevents; +}; +#elif defined (USE_SELECT) +struct isc_socketwait { + fd_set *readset; + fd_set *writeset; + int nfds; + int maxfd; +}; +#endif /* USE_KQUEUE */ +#endif /* !USE_WATCHER_THREAD */ + +/*% + * Maximum number of allowable open sockets. This is also the maximum + * allowable socket file descriptor. + * + * Care should be taken before modifying this value for select(): + * The API standard doesn't ensure select() accept more than (the system default + * of) FD_SETSIZE descriptors, and the default size should in fact be fine in + * the vast majority of cases. This constant should therefore be increased only + * when absolutely necessary and possible, i.e., the server is exhausting all + * available file descriptors (up to FD_SETSIZE) and the select() function + * and FD_xxx macros support larger values than FD_SETSIZE (which may not + * always by true, but we keep using some of them to ensure as much + * portability as possible). Note also that overall server performance + * may be rather worsened with a larger value of this constant due to + * inherent scalability problems of select(). + * + * As a special note, this value shouldn't have to be touched if + * this is a build for an authoritative only DNS server. + */ +#ifndef ISC_SOCKET_MAXSOCKETS +#if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL) +#define ISC_SOCKET_MAXSOCKETS 4096 +#elif defined(USE_SELECT) +#define ISC_SOCKET_MAXSOCKETS FD_SETSIZE +#endif /* USE_KQUEUE... */ +#endif /* ISC_SOCKET_MAXSOCKETS */ + +#ifdef USE_SELECT +/*% + * Mac OS X needs a special definition to support larger values in select(). + * We always define this because a larger value can be specified run-time. + */ +#ifdef __APPLE__ +#define _DARWIN_UNLIMITED_SELECT +#endif /* __APPLE__ */ +#endif /* USE_SELECT */ + +#ifdef ISC_SOCKET_USE_POLLWATCH +/*% + * If this macro is defined, enable workaround for a Solaris /dev/poll kernel + * bug: DP_POLL ioctl could keep sleeping even if socket I/O is possible for + * some of the specified FD. The idea is based on the observation that it's + * likely for a busy server to keep receiving packets. It specifically works + * as follows: the socket watcher is first initialized with the state of + * "poll_idle". While it's in the idle state it keeps sleeping until a socket + * event occurs. When it wakes up for a socket I/O event, it moves to the + * poll_active state, and sets the poll timeout to a short period + * (ISC_SOCKET_POLLWATCH_TIMEOUT msec). If timeout occurs in this state, the + * watcher goes to the poll_checking state with the same timeout period. + * In this state, the watcher tries to detect whether this is a break + * during intermittent events or the kernel bug is triggered. If the next + * polling reports an event within the short period, the previous timeout is + * likely to be a kernel bug, and so the watcher goes back to the active state. + * Otherwise, it moves to the idle state again. + * + * It's not clear whether this is a thread-related bug, but since we've only + * seen this with threads, this workaround is used only when enabling threads. + */ + +typedef enum { poll_idle, poll_active, poll_checking } pollstate_t; + +#ifndef ISC_SOCKET_POLLWATCH_TIMEOUT +#define ISC_SOCKET_POLLWATCH_TIMEOUT 10 +#endif /* ISC_SOCKET_POLLWATCH_TIMEOUT */ +#endif /* ISC_SOCKET_USE_POLLWATCH */ + +/*% + * Size of per-FD lock buckets. + */ +#ifdef ISC_PLATFORM_USETHREADS +#define FDLOCK_COUNT 1024 +#define FDLOCK_ID(fd) ((fd) % FDLOCK_COUNT) +#else +#define FDLOCK_COUNT 1 +#define FDLOCK_ID(fd) 0 +#endif /* ISC_PLATFORM_USETHREADS */ + +/*% + * Maximum number of events communicated with the kernel. There should normally + * be no need for having a large number. + */ +#if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL) +#ifndef ISC_SOCKET_MAXEVENTS +#define ISC_SOCKET_MAXEVENTS 64 +#endif +#endif + +/*% + * Some systems define the socket length argument as an int, some as size_t, + * some as socklen_t. This is here so it can be easily changed if needed. + */ +#ifndef ISC_SOCKADDR_LEN_T +#define ISC_SOCKADDR_LEN_T unsigned int +#endif + +/*% + * Define what the possible "soft" errors can be. These are non-fatal returns + * of various network related functions, like recv() and so on. + * + * For some reason, BSDI (and perhaps others) will sometimes return <0 + * from recv() but will have errno==0. This is broken, but we have to + * work around it here. + */ +#define SOFT_ERROR(e) ((e) == EAGAIN || \ + (e) == EWOULDBLOCK || \ + (e) == EINTR || \ + (e) == 0) + +#define DLVL(x) ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(x) + +/*!< + * DLVL(90) -- Function entry/exit and other tracing. + * DLVL(70) -- Socket "correctness" -- including returning of events, etc. + * DLVL(60) -- Socket data send/receive + * DLVL(50) -- Event tracing, including receiving/sending completion events. + * DLVL(20) -- Socket creation/destruction. + */ +#define TRACE_LEVEL 90 +#define CORRECTNESS_LEVEL 70 +#define IOEVENT_LEVEL 60 +#define EVENT_LEVEL 50 +#define CREATION_LEVEL 20 + +#define TRACE DLVL(TRACE_LEVEL) +#define CORRECTNESS DLVL(CORRECTNESS_LEVEL) +#define IOEVENT DLVL(IOEVENT_LEVEL) +#define EVENT DLVL(EVENT_LEVEL) +#define CREATION DLVL(CREATION_LEVEL) + +typedef isc_event_t intev_t; + +#define SOCKET_MAGIC ISC_MAGIC('I', 'O', 'i', 'o') +#define VALID_SOCKET(s) ISC_MAGIC_VALID(s, SOCKET_MAGIC) + +/*! + * IPv6 control information. If the socket is an IPv6 socket we want + * to collect the destination address and interface so the client can + * set them on outgoing packets. + */ +#ifdef ISC_PLATFORM_HAVEIN6PKTINFO +#ifndef USE_CMSG +#define USE_CMSG 1 +#endif +#endif + +/*% + * NetBSD and FreeBSD can timestamp packets. XXXMLG Should we have + * a setsockopt() like interface to request timestamps, and if the OS + * doesn't do it for us, call gettimeofday() on every UDP receive? + */ +#ifdef SO_TIMESTAMP +#ifndef USE_CMSG +#define USE_CMSG 1 +#endif +#endif + +/*% + * The size to raise the receive buffer to (from BIND 8). + */ +#define RCVBUFSIZE (32*1024) + +/*% + * The number of times a send operation is repeated if the result is EINTR. + */ +#define NRETRIES 10 + +typedef struct isc__socket isc__socket_t; +typedef struct isc__socketmgr isc__socketmgr_t; + +#define NEWCONNSOCK(ev) ((isc__socket_t *)(ev)->newsocket) + +struct isc__socket { + /* Not locked. */ + isc_socket_t common; + isc__socketmgr_t *manager; + isc_mutex_t lock; + isc_sockettype_t type; + const isc_statscounter_t *statsindex; + + /* Locked by socket lock. */ + ISC_LINK(isc__socket_t) link; + unsigned int references; + int fd; + int pf; + char name[16]; + void * tag; + + ISC_LIST(isc_socketevent_t) send_list; + ISC_LIST(isc_socketevent_t) recv_list; + ISC_LIST(isc_socket_newconnev_t) accept_list; + isc_socket_connev_t *connect_ev; + + /* + * Internal events. Posted when a descriptor is readable or + * writable. These are statically allocated and never freed. + * They will be set to non-purgable before use. + */ + intev_t readable_ev; + intev_t writable_ev; + + isc_sockaddr_t peer_address; /* remote address */ + + unsigned int pending_recv : 1, + pending_send : 1, + pending_accept : 1, + listener : 1, /* listener socket */ + connected : 1, + connecting : 1, /* connect pending */ + bound : 1, /* bound to local addr */ + dupped : 1; + +#ifdef ISC_NET_RECVOVERFLOW + unsigned char overflow; /* used for MSG_TRUNC fake */ +#endif + + char *recvcmsgbuf; + ISC_SOCKADDR_LEN_T recvcmsgbuflen; + char *sendcmsgbuf; + ISC_SOCKADDR_LEN_T sendcmsgbuflen; + + void *fdwatcharg; + isc_sockfdwatch_t fdwatchcb; + int fdwatchflags; + isc_task_t *fdwatchtask; +}; + +#define SOCKET_MANAGER_MAGIC ISC_MAGIC('I', 'O', 'm', 'g') +#define VALID_MANAGER(m) ISC_MAGIC_VALID(m, SOCKET_MANAGER_MAGIC) + +struct isc__socketmgr { + /* Not locked. */ + isc_socketmgr_t common; + isc_mem_t *mctx; + isc_mutex_t lock; + isc_mutex_t *fdlock; + isc_stats_t *stats; +#ifdef USE_KQUEUE + int kqueue_fd; + int nevents; + struct kevent *events; +#endif /* USE_KQUEUE */ +#ifdef USE_EPOLL + int epoll_fd; + int nevents; + struct epoll_event *events; +#endif /* USE_EPOLL */ +#ifdef USE_DEVPOLL + int devpoll_fd; + int nevents; + struct pollfd *events; +#endif /* USE_DEVPOLL */ +#ifdef USE_SELECT + int fd_bufsize; +#endif /* USE_SELECT */ + unsigned int maxsocks; +#ifdef ISC_PLATFORM_USETHREADS + int pipe_fds[2]; +#endif + + /* Locked by fdlock. */ + isc__socket_t **fds; + int *fdstate; +#ifdef USE_DEVPOLL + pollinfo_t *fdpollinfo; +#endif + + /* Locked by manager lock. */ + ISC_LIST(isc__socket_t) socklist; +#ifdef USE_SELECT + fd_set *read_fds; + fd_set *read_fds_copy; + fd_set *write_fds; + fd_set *write_fds_copy; + int maxfd; +#endif /* USE_SELECT */ + int reserved; /* unlocked */ +#ifdef USE_WATCHER_THREAD + isc_thread_t watcher; + isc_condition_t shutdown_ok; +#else /* USE_WATCHER_THREAD */ + unsigned int refs; +#endif /* USE_WATCHER_THREAD */ + int maxudp; +}; + +#ifdef USE_SHARED_MANAGER +static isc__socketmgr_t *socketmgr = NULL; +#endif /* USE_SHARED_MANAGER */ + +#define CLOSED 0 /* this one must be zero */ +#define MANAGED 1 +#define CLOSE_PENDING 2 + +/* + * send() and recv() iovec counts + */ +#define MAXSCATTERGATHER_SEND (ISC_SOCKET_MAXSCATTERGATHER) +#ifdef ISC_NET_RECVOVERFLOW +# define MAXSCATTERGATHER_RECV (ISC_SOCKET_MAXSCATTERGATHER + 1) +#else +# define MAXSCATTERGATHER_RECV (ISC_SOCKET_MAXSCATTERGATHER) +#endif + +static isc_result_t socket_create(isc_socketmgr_t *manager0, int pf, + isc_sockettype_t type, + isc_socket_t **socketp, + isc_socket_t *dup_socket); +static void send_recvdone_event(isc__socket_t *, isc_socketevent_t **); +static void send_senddone_event(isc__socket_t *, isc_socketevent_t **); +static void free_socket(isc__socket_t **); +static isc_result_t allocate_socket(isc__socketmgr_t *, isc_sockettype_t, + isc__socket_t **); +static void destroy(isc__socket_t **); +static void internal_accept(isc_task_t *, isc_event_t *); +static void internal_connect(isc_task_t *, isc_event_t *); +static void internal_recv(isc_task_t *, isc_event_t *); +static void internal_send(isc_task_t *, isc_event_t *); +static void internal_fdwatch_write(isc_task_t *, isc_event_t *); +static void internal_fdwatch_read(isc_task_t *, isc_event_t *); +static void process_cmsg(isc__socket_t *, struct msghdr *, isc_socketevent_t *); +static void build_msghdr_send(isc__socket_t *, isc_socketevent_t *, + struct msghdr *, struct iovec *, size_t *); +static void build_msghdr_recv(isc__socket_t *, isc_socketevent_t *, + struct msghdr *, struct iovec *, size_t *); +#ifdef USE_WATCHER_THREAD +static isc_boolean_t process_ctlfd(isc__socketmgr_t *manager); +#endif + +/*% + * The following can be either static or public, depending on build environment. + */ + +#ifdef BIND9 +#define ISC_SOCKETFUNC_SCOPE +#else +#define ISC_SOCKETFUNC_SCOPE static +#endif + +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, + isc_socket_t **socketp); +ISC_SOCKETFUNC_SCOPE void +isc__socket_attach(isc_socket_t *sock, isc_socket_t **socketp); +ISC_SOCKETFUNC_SCOPE void +isc__socket_detach(isc_socket_t **socketp); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp, + unsigned int maxsocks); +ISC_SOCKETFUNC_SCOPE void +isc__socketmgr_destroy(isc_socketmgr_t **managerp); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_recvv(isc_socket_t *sock, isc_bufferlist_t *buflist, + unsigned int minimum, isc_task_t *task, + isc_taskaction_t action, const void *arg); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_recv(isc_socket_t *sock, isc_region_t *region, + unsigned int minimum, isc_task_t *task, + isc_taskaction_t action, const void *arg); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_recv2(isc_socket_t *sock, isc_region_t *region, + unsigned int minimum, isc_task_t *task, + isc_socketevent_t *event, unsigned int flags); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_send(isc_socket_t *sock, isc_region_t *region, + isc_task_t *task, isc_taskaction_t action, const void *arg); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_sendto(isc_socket_t *sock, isc_region_t *region, + isc_task_t *task, isc_taskaction_t action, const void *arg, + isc_sockaddr_t *address, struct in6_pktinfo *pktinfo); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_sendv(isc_socket_t *sock, isc_bufferlist_t *buflist, + isc_task_t *task, isc_taskaction_t action, const void *arg); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_sendtov(isc_socket_t *sock, isc_bufferlist_t *buflist, + isc_task_t *task, isc_taskaction_t action, const void *arg, + isc_sockaddr_t *address, struct in6_pktinfo *pktinfo); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_sendto2(isc_socket_t *sock, isc_region_t *region, + isc_task_t *task, + isc_sockaddr_t *address, struct in6_pktinfo *pktinfo, + isc_socketevent_t *event, unsigned int flags); +ISC_SOCKETFUNC_SCOPE void +isc__socket_cleanunix(isc_sockaddr_t *sockaddr, isc_boolean_t active); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_permunix(isc_sockaddr_t *sockaddr, isc_uint32_t perm, + isc_uint32_t owner, isc_uint32_t group); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_bind(isc_socket_t *sock, isc_sockaddr_t *sockaddr, + unsigned int options); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_filter(isc_socket_t *sock, const char *filter); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_listen(isc_socket_t *sock, unsigned int backlog); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_accept(isc_socket_t *sock, + isc_task_t *task, isc_taskaction_t action, const void *arg); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_connect(isc_socket_t *sock, isc_sockaddr_t *addr, + isc_task_t *task, isc_taskaction_t action, + const void *arg); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_getpeername(isc_socket_t *sock, isc_sockaddr_t *addressp); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_getsockname(isc_socket_t *sock, isc_sockaddr_t *addressp); +ISC_SOCKETFUNC_SCOPE void +isc__socket_cancel(isc_socket_t *sock, isc_task_t *task, unsigned int how); +ISC_SOCKETFUNC_SCOPE isc_sockettype_t +isc__socket_gettype(isc_socket_t *sock); +ISC_SOCKETFUNC_SCOPE isc_boolean_t +isc__socket_isbound(isc_socket_t *sock); +ISC_SOCKETFUNC_SCOPE void +isc__socket_ipv6only(isc_socket_t *sock, isc_boolean_t yes); +#if defined(HAVE_LIBXML2) && defined(BIND9) +ISC_SOCKETFUNC_SCOPE void +isc__socketmgr_renderxml(isc_socketmgr_t *mgr0, xmlTextWriterPtr writer); +#endif + +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_fdwatchcreate(isc_socketmgr_t *manager, int fd, int flags, + isc_sockfdwatch_t callback, void *cbarg, + isc_task_t *task, isc_socket_t **socketp); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_fdwatchpoke(isc_socket_t *sock, int flags); +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_dup(isc_socket_t *sock, isc_socket_t **socketp); +ISC_SOCKETFUNC_SCOPE int +isc__socket_getfd(isc_socket_t *sock); + +static struct { + isc_socketmethods_t methods; + + /*% + * The following are defined just for avoiding unused static functions. + */ +#ifndef BIND9 + void *recvv, *send, *sendv, *sendto2, *cleanunix, *permunix, *filter, + *listen, *accept, *getpeername, *isbound; +#endif +} socketmethods = { + { + isc__socket_attach, + isc__socket_detach, + isc__socket_bind, + isc__socket_sendto, + isc__socket_connect, + isc__socket_recv, + isc__socket_cancel, + isc__socket_getsockname, + isc__socket_gettype, + isc__socket_ipv6only, + isc__socket_fdwatchpoke, + isc__socket_dup, + isc__socket_getfd + } +#ifndef BIND9 + , + (void *)isc__socket_recvv, (void *)isc__socket_send, + (void *)isc__socket_sendv, (void *)isc__socket_sendto2, + (void *)isc__socket_cleanunix, (void *)isc__socket_permunix, + (void *)isc__socket_filter, (void *)isc__socket_listen, + (void *)isc__socket_accept, (void *)isc__socket_getpeername, + (void *)isc__socket_isbound +#endif +}; + +static isc_socketmgrmethods_t socketmgrmethods = { + isc__socketmgr_destroy, + isc__socket_create, + isc__socket_fdwatchcreate +}; + +#define SELECT_POKE_SHUTDOWN (-1) +#define SELECT_POKE_NOTHING (-2) +#define SELECT_POKE_READ (-3) +#define SELECT_POKE_ACCEPT (-3) /*%< Same as _READ */ +#define SELECT_POKE_WRITE (-4) +#define SELECT_POKE_CONNECT (-4) /*%< Same as _WRITE */ +#define SELECT_POKE_CLOSE (-5) + +#define SOCK_DEAD(s) ((s)->references == 0) + +/*% + * Shortcut index arrays to get access to statistics counters. + */ +enum { + STATID_OPEN = 0, + STATID_OPENFAIL = 1, + STATID_CLOSE = 2, + STATID_BINDFAIL = 3, + STATID_CONNECTFAIL = 4, + STATID_CONNECT = 5, + STATID_ACCEPTFAIL = 6, + STATID_ACCEPT = 7, + STATID_SENDFAIL = 8, + STATID_RECVFAIL = 9 +}; +static const isc_statscounter_t upd4statsindex[] = { + isc_sockstatscounter_udp4open, + isc_sockstatscounter_udp4openfail, + isc_sockstatscounter_udp4close, + isc_sockstatscounter_udp4bindfail, + isc_sockstatscounter_udp4connectfail, + isc_sockstatscounter_udp4connect, + -1, + -1, + isc_sockstatscounter_udp4sendfail, + isc_sockstatscounter_udp4recvfail +}; +static const isc_statscounter_t upd6statsindex[] = { + isc_sockstatscounter_udp6open, + isc_sockstatscounter_udp6openfail, + isc_sockstatscounter_udp6close, + isc_sockstatscounter_udp6bindfail, + isc_sockstatscounter_udp6connectfail, + isc_sockstatscounter_udp6connect, + -1, + -1, + isc_sockstatscounter_udp6sendfail, + isc_sockstatscounter_udp6recvfail +}; +static const isc_statscounter_t tcp4statsindex[] = { + isc_sockstatscounter_tcp4open, + isc_sockstatscounter_tcp4openfail, + isc_sockstatscounter_tcp4close, + isc_sockstatscounter_tcp4bindfail, + isc_sockstatscounter_tcp4connectfail, + isc_sockstatscounter_tcp4connect, + isc_sockstatscounter_tcp4acceptfail, + isc_sockstatscounter_tcp4accept, + isc_sockstatscounter_tcp4sendfail, + isc_sockstatscounter_tcp4recvfail +}; +static const isc_statscounter_t tcp6statsindex[] = { + isc_sockstatscounter_tcp6open, + isc_sockstatscounter_tcp6openfail, + isc_sockstatscounter_tcp6close, + isc_sockstatscounter_tcp6bindfail, + isc_sockstatscounter_tcp6connectfail, + isc_sockstatscounter_tcp6connect, + isc_sockstatscounter_tcp6acceptfail, + isc_sockstatscounter_tcp6accept, + isc_sockstatscounter_tcp6sendfail, + isc_sockstatscounter_tcp6recvfail +}; +static const isc_statscounter_t unixstatsindex[] = { + isc_sockstatscounter_unixopen, + isc_sockstatscounter_unixopenfail, + isc_sockstatscounter_unixclose, + isc_sockstatscounter_unixbindfail, + isc_sockstatscounter_unixconnectfail, + isc_sockstatscounter_unixconnect, + isc_sockstatscounter_unixacceptfail, + isc_sockstatscounter_unixaccept, + isc_sockstatscounter_unixsendfail, + isc_sockstatscounter_unixrecvfail +}; +static const isc_statscounter_t fdwatchstatsindex[] = { + -1, + -1, + isc_sockstatscounter_fdwatchclose, + isc_sockstatscounter_fdwatchbindfail, + isc_sockstatscounter_fdwatchconnectfail, + isc_sockstatscounter_fdwatchconnect, + -1, + -1, + isc_sockstatscounter_fdwatchsendfail, + isc_sockstatscounter_fdwatchrecvfail +}; + +#if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL) || \ + defined(USE_WATCHER_THREAD) +static void +manager_log(isc__socketmgr_t *sockmgr, + isc_logcategory_t *category, isc_logmodule_t *module, int level, + const char *fmt, ...) ISC_FORMAT_PRINTF(5, 6); +static void +manager_log(isc__socketmgr_t *sockmgr, + isc_logcategory_t *category, isc_logmodule_t *module, int level, + const char *fmt, ...) +{ + char msgbuf[2048]; + va_list ap; + + if (! isc_log_wouldlog(isc_lctx, level)) + return; + + va_start(ap, fmt); + vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); + va_end(ap); + + isc_log_write(isc_lctx, category, module, level, + "sockmgr %p: %s", sockmgr, msgbuf); +} +#endif + +static void +socket_log(isc__socket_t *sock, isc_sockaddr_t *address, + isc_logcategory_t *category, isc_logmodule_t *module, int level, + isc_msgcat_t *msgcat, int msgset, int message, + const char *fmt, ...) ISC_FORMAT_PRINTF(9, 10); +static void +socket_log(isc__socket_t *sock, isc_sockaddr_t *address, + isc_logcategory_t *category, isc_logmodule_t *module, int level, + isc_msgcat_t *msgcat, int msgset, int message, + const char *fmt, ...) +{ + char msgbuf[2048]; + char peerbuf[ISC_SOCKADDR_FORMATSIZE]; + va_list ap; + + if (! isc_log_wouldlog(isc_lctx, level)) + return; + + va_start(ap, fmt); + vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); + va_end(ap); + + if (address == NULL) { + isc_log_iwrite(isc_lctx, category, module, level, + msgcat, msgset, message, + "socket %p: %s", sock, msgbuf); + } else { + isc_sockaddr_format(address, peerbuf, sizeof(peerbuf)); + isc_log_iwrite(isc_lctx, category, module, level, + msgcat, msgset, message, + "socket %p %s: %s", sock, peerbuf, msgbuf); + } +} + +#if defined(_AIX) && defined(ISC_NET_BSD44MSGHDR) && \ + defined(USE_CMSG) && defined(IPV6_RECVPKTINFO) +/* + * AIX has a kernel bug where IPV6_RECVPKTINFO gets cleared by + * setting IPV6_V6ONLY. + */ +static void +FIX_IPV6_RECVPKTINFO(isc__socket_t *sock) +{ + char strbuf[ISC_STRERRORSIZE]; + int on = 1; + + if (sock->pf != AF_INET6 || sock->type != isc_sockettype_udp) + return; + + if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, + (void *)&on, sizeof(on)) < 0) { + + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "setsockopt(%d, IPV6_RECVPKTINFO) " + "%s: %s", sock->fd, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, + "failed"), + strbuf); + } +} +#else +#define FIX_IPV6_RECVPKTINFO(sock) (void)0 +#endif + +/*% + * Increment socket-related statistics counters. + */ +static inline void +inc_stats(isc_stats_t *stats, isc_statscounter_t counterid) { + REQUIRE(counterid != -1); + + if (stats != NULL) + isc_stats_increment(stats, counterid); +} + +static inline isc_result_t +watch_fd(isc__socketmgr_t *manager, int fd, int msg) { + isc_result_t result = ISC_R_SUCCESS; + +#ifdef USE_KQUEUE + struct kevent evchange; + + memset(&evchange, 0, sizeof(evchange)); + if (msg == SELECT_POKE_READ) + evchange.filter = EVFILT_READ; + else + evchange.filter = EVFILT_WRITE; + evchange.flags = EV_ADD; + evchange.ident = fd; + if (kevent(manager->kqueue_fd, &evchange, 1, NULL, 0, NULL) != 0) + result = isc__errno2result(errno); + + return (result); +#elif defined(USE_EPOLL) + struct epoll_event event; + + if (msg == SELECT_POKE_READ) + event.events = EPOLLIN; + else + event.events = EPOLLOUT; + memset(&event.data, 0, sizeof(event.data)); + event.data.fd = fd; + if (epoll_ctl(manager->epoll_fd, EPOLL_CTL_ADD, fd, &event) == -1 && + errno != EEXIST) { + result = isc__errno2result(errno); + } + + return (result); +#elif defined(USE_DEVPOLL) + struct pollfd pfd; + int lockid = FDLOCK_ID(fd); + + memset(&pfd, 0, sizeof(pfd)); + if (msg == SELECT_POKE_READ) + pfd.events = POLLIN; + else + pfd.events = POLLOUT; + pfd.fd = fd; + pfd.revents = 0; + LOCK(&manager->fdlock[lockid]); + if (write(manager->devpoll_fd, &pfd, sizeof(pfd)) == -1) + result = isc__errno2result(errno); + else { + if (msg == SELECT_POKE_READ) + manager->fdpollinfo[fd].want_read = 1; + else + manager->fdpollinfo[fd].want_write = 1; + } + UNLOCK(&manager->fdlock[lockid]); + + return (result); +#elif defined(USE_SELECT) + LOCK(&manager->lock); + if (msg == SELECT_POKE_READ) + FD_SET(fd, manager->read_fds); + if (msg == SELECT_POKE_WRITE) + FD_SET(fd, manager->write_fds); + UNLOCK(&manager->lock); + + return (result); +#endif +} + +static inline isc_result_t +unwatch_fd(isc__socketmgr_t *manager, int fd, int msg) { + isc_result_t result = ISC_R_SUCCESS; + +#ifdef USE_KQUEUE + struct kevent evchange; + + memset(&evchange, 0, sizeof(evchange)); + if (msg == SELECT_POKE_READ) + evchange.filter = EVFILT_READ; + else + evchange.filter = EVFILT_WRITE; + evchange.flags = EV_DELETE; + evchange.ident = fd; + if (kevent(manager->kqueue_fd, &evchange, 1, NULL, 0, NULL) != 0) + result = isc__errno2result(errno); + + return (result); +#elif defined(USE_EPOLL) + struct epoll_event event; + + if (msg == SELECT_POKE_READ) + event.events = EPOLLIN; + else + event.events = EPOLLOUT; + memset(&event.data, 0, sizeof(event.data)); + event.data.fd = fd; + if (epoll_ctl(manager->epoll_fd, EPOLL_CTL_DEL, fd, &event) == -1 && + errno != ENOENT) { + char strbuf[ISC_STRERRORSIZE]; + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "epoll_ctl(DEL), %d: %s", fd, strbuf); + result = ISC_R_UNEXPECTED; + } + return (result); +#elif defined(USE_DEVPOLL) + struct pollfd pfds[2]; + size_t writelen = sizeof(pfds[0]); + int lockid = FDLOCK_ID(fd); + + memset(pfds, 0, sizeof(pfds)); + pfds[0].events = POLLREMOVE; + pfds[0].fd = fd; + + /* + * Canceling read or write polling via /dev/poll is tricky. Since it + * only provides a way of canceling per FD, we may need to re-poll the + * socket for the other operation. + */ + LOCK(&manager->fdlock[lockid]); + if (msg == SELECT_POKE_READ && + manager->fdpollinfo[fd].want_write == 1) { + pfds[1].events = POLLOUT; + pfds[1].fd = fd; + writelen += sizeof(pfds[1]); + } + if (msg == SELECT_POKE_WRITE && + manager->fdpollinfo[fd].want_read == 1) { + pfds[1].events = POLLIN; + pfds[1].fd = fd; + writelen += sizeof(pfds[1]); + } + + if (write(manager->devpoll_fd, pfds, writelen) == -1) + result = isc__errno2result(errno); + else { + if (msg == SELECT_POKE_READ) + manager->fdpollinfo[fd].want_read = 0; + else + manager->fdpollinfo[fd].want_write = 0; + } + UNLOCK(&manager->fdlock[lockid]); + + return (result); +#elif defined(USE_SELECT) + LOCK(&manager->lock); + if (msg == SELECT_POKE_READ) + FD_CLR(fd, manager->read_fds); + else if (msg == SELECT_POKE_WRITE) + FD_CLR(fd, manager->write_fds); + UNLOCK(&manager->lock); + + return (result); +#endif +} + +static void +wakeup_socket(isc__socketmgr_t *manager, int fd, int msg) { + isc_result_t result; + int lockid = FDLOCK_ID(fd); + + /* + * This is a wakeup on a socket. If the socket is not in the + * process of being closed, start watching it for either reads + * or writes. + */ + + INSIST(fd >= 0 && fd < (int)manager->maxsocks); + + if (msg == SELECT_POKE_CLOSE) { + /* No one should be updating fdstate, so no need to lock it */ + INSIST(manager->fdstate[fd] == CLOSE_PENDING); + manager->fdstate[fd] = CLOSED; + (void)unwatch_fd(manager, fd, SELECT_POKE_READ); + (void)unwatch_fd(manager, fd, SELECT_POKE_WRITE); + (void)close(fd); + return; + } + + LOCK(&manager->fdlock[lockid]); + if (manager->fdstate[fd] == CLOSE_PENDING) { + UNLOCK(&manager->fdlock[lockid]); + + /* + * We accept (and ignore) any error from unwatch_fd() as we are + * closing the socket, hoping it doesn't leave dangling state in + * the kernel. + * Note that unwatch_fd() must be called after releasing the + * fdlock; otherwise it could cause deadlock due to a lock order + * reversal. + */ + (void)unwatch_fd(manager, fd, SELECT_POKE_READ); + (void)unwatch_fd(manager, fd, SELECT_POKE_WRITE); + return; + } + if (manager->fdstate[fd] != MANAGED) { + UNLOCK(&manager->fdlock[lockid]); + return; + } + UNLOCK(&manager->fdlock[lockid]); + + /* + * Set requested bit. + */ + result = watch_fd(manager, fd, msg); + if (result != ISC_R_SUCCESS) { + /* + * XXXJT: what should we do? Ignoring the failure of watching + * a socket will make the application dysfunctional, but there + * seems to be no reasonable recovery process. + */ + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR, + "failed to start watching FD (%d): %s", + fd, isc_result_totext(result)); + } +} + +#ifdef USE_WATCHER_THREAD +/* + * Poke the select loop when there is something for us to do. + * The write is required (by POSIX) to complete. That is, we + * will not get partial writes. + */ +static void +select_poke(isc__socketmgr_t *mgr, int fd, int msg) { + int cc; + int buf[2]; + char strbuf[ISC_STRERRORSIZE]; + + buf[0] = fd; + buf[1] = msg; + + do { + cc = write(mgr->pipe_fds[1], buf, sizeof(buf)); +#ifdef ENOSR + /* + * Treat ENOSR as EAGAIN but loop slowly as it is + * unlikely to clear fast. + */ + if (cc < 0 && errno == ENOSR) { + sleep(1); + errno = EAGAIN; + } +#endif + } while (cc < 0 && SOFT_ERROR(errno)); + + if (cc < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + FATAL_ERROR(__FILE__, __LINE__, + isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_WRITEFAILED, + "write() failed " + "during watcher poke: %s"), + strbuf); + } + + INSIST(cc == sizeof(buf)); +} + +/* + * Read a message on the internal fd. + */ +static void +select_readmsg(isc__socketmgr_t *mgr, int *fd, int *msg) { + int buf[2]; + int cc; + char strbuf[ISC_STRERRORSIZE]; + + cc = read(mgr->pipe_fds[0], buf, sizeof(buf)); + if (cc < 0) { + *msg = SELECT_POKE_NOTHING; + *fd = -1; /* Silence compiler. */ + if (SOFT_ERROR(errno)) + return; + + isc__strerror(errno, strbuf, sizeof(strbuf)); + FATAL_ERROR(__FILE__, __LINE__, + isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_READFAILED, + "read() failed " + "during watcher poke: %s"), + strbuf); + + return; + } + INSIST(cc == sizeof(buf)); + + *fd = buf[0]; + *msg = buf[1]; +} +#else /* USE_WATCHER_THREAD */ +/* + * Update the state of the socketmgr when something changes. + */ +static void +select_poke(isc__socketmgr_t *manager, int fd, int msg) { + if (msg == SELECT_POKE_SHUTDOWN) + return; + else if (fd >= 0) + wakeup_socket(manager, fd, msg); + return; +} +#endif /* USE_WATCHER_THREAD */ + +/* + * Make a fd non-blocking. + */ +static isc_result_t +make_nonblock(int fd) { + int ret; + int flags; + char strbuf[ISC_STRERRORSIZE]; +#ifdef USE_FIONBIO_IOCTL + int on = 1; + + ret = ioctl(fd, FIONBIO, (char *)&on); +#else + flags = fcntl(fd, F_GETFL, 0); + flags |= PORT_NONBLOCK; + ret = fcntl(fd, F_SETFL, flags); +#endif + + if (ret == -1) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, +#ifdef USE_FIONBIO_IOCTL + "ioctl(%d, FIONBIO, &on): %s", fd, +#else + "fcntl(%d, F_SETFL, %d): %s", fd, flags, +#endif + strbuf); + + return (ISC_R_UNEXPECTED); + } + + return (ISC_R_SUCCESS); +} + +#ifdef USE_CMSG +/* + * Not all OSes support advanced CMSG macros: CMSG_LEN and CMSG_SPACE. + * In order to ensure as much portability as possible, we provide wrapper + * functions of these macros. + * Note that cmsg_space() could run slow on OSes that do not have + * CMSG_SPACE. + */ +static inline ISC_SOCKADDR_LEN_T +cmsg_len(ISC_SOCKADDR_LEN_T len) { +#ifdef CMSG_LEN + return (CMSG_LEN(len)); +#else + ISC_SOCKADDR_LEN_T hdrlen; + + /* + * Cast NULL so that any pointer arithmetic performed by CMSG_DATA + * is correct. + */ + hdrlen = (ISC_SOCKADDR_LEN_T)CMSG_DATA(((struct cmsghdr *)NULL)); + return (hdrlen + len); +#endif +} + +static inline ISC_SOCKADDR_LEN_T +cmsg_space(ISC_SOCKADDR_LEN_T len) { +#ifdef CMSG_SPACE + return (CMSG_SPACE(len)); +#else + struct msghdr msg; + struct cmsghdr *cmsgp; + /* + * XXX: The buffer length is an ad-hoc value, but should be enough + * in a practical sense. + */ + char dummybuf[sizeof(struct cmsghdr) + 1024]; + + memset(&msg, 0, sizeof(msg)); + msg.msg_control = dummybuf; + msg.msg_controllen = sizeof(dummybuf); + + cmsgp = (struct cmsghdr *)dummybuf; + cmsgp->cmsg_len = cmsg_len(len); + + cmsgp = CMSG_NXTHDR(&msg, cmsgp); + if (cmsgp != NULL) + return ((char *)cmsgp - (char *)msg.msg_control); + else + return (0); +#endif +} +#endif /* USE_CMSG */ + +/* + * Process control messages received on a socket. + */ +static void +process_cmsg(isc__socket_t *sock, struct msghdr *msg, isc_socketevent_t *dev) { +#ifdef USE_CMSG + struct cmsghdr *cmsgp; +#ifdef ISC_PLATFORM_HAVEIN6PKTINFO + struct in6_pktinfo *pktinfop; +#endif +#ifdef SO_TIMESTAMP + struct timeval *timevalp; +#endif +#endif + + /* + * sock is used only when ISC_NET_BSD44MSGHDR and USE_CMSG are defined. + * msg and dev are used only when ISC_NET_BSD44MSGHDR is defined. + * They are all here, outside of the CPP tests, because it is + * more consistent with the usual ISC coding style. + */ + UNUSED(sock); + UNUSED(msg); + UNUSED(dev); + +#ifdef ISC_NET_BSD44MSGHDR + +#ifdef MSG_TRUNC + if ((msg->msg_flags & MSG_TRUNC) == MSG_TRUNC) + dev->attributes |= ISC_SOCKEVENTATTR_TRUNC; +#endif + +#ifdef MSG_CTRUNC + if ((msg->msg_flags & MSG_CTRUNC) == MSG_CTRUNC) + dev->attributes |= ISC_SOCKEVENTATTR_CTRUNC; +#endif + +#ifndef USE_CMSG + return; +#else + if (msg->msg_controllen == 0U || msg->msg_control == NULL) + return; + +#ifdef SO_TIMESTAMP + timevalp = NULL; +#endif +#ifdef ISC_PLATFORM_HAVEIN6PKTINFO + pktinfop = NULL; +#endif + + cmsgp = CMSG_FIRSTHDR(msg); + while (cmsgp != NULL) { + socket_log(sock, NULL, TRACE, + isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_PROCESSCMSG, + "processing cmsg %p", cmsgp); + +#ifdef ISC_PLATFORM_HAVEIN6PKTINFO + if (cmsgp->cmsg_level == IPPROTO_IPV6 + && cmsgp->cmsg_type == IPV6_PKTINFO) { + + pktinfop = (struct in6_pktinfo *)CMSG_DATA(cmsgp); + memcpy(&dev->pktinfo, pktinfop, + sizeof(struct in6_pktinfo)); + dev->attributes |= ISC_SOCKEVENTATTR_PKTINFO; + socket_log(sock, NULL, TRACE, + isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_IFRECEIVED, + "interface received on ifindex %u", + dev->pktinfo.ipi6_ifindex); + if (IN6_IS_ADDR_MULTICAST(&pktinfop->ipi6_addr)) + dev->attributes |= ISC_SOCKEVENTATTR_MULTICAST; + goto next; + } +#endif + +#ifdef SO_TIMESTAMP + if (cmsgp->cmsg_level == SOL_SOCKET + && cmsgp->cmsg_type == SCM_TIMESTAMP) { + timevalp = (struct timeval *)CMSG_DATA(cmsgp); + dev->timestamp.seconds = timevalp->tv_sec; + dev->timestamp.nanoseconds = timevalp->tv_usec * 1000; + dev->attributes |= ISC_SOCKEVENTATTR_TIMESTAMP; + goto next; + } +#endif + + next: + cmsgp = CMSG_NXTHDR(msg, cmsgp); + } +#endif /* USE_CMSG */ + +#endif /* ISC_NET_BSD44MSGHDR */ +} + +/* + * Construct an iov array and attach it to the msghdr passed in. This is + * the SEND constructor, which will use the used region of the buffer + * (if using a buffer list) or will use the internal region (if a single + * buffer I/O is requested). + * + * Nothing can be NULL, and the done event must list at least one buffer + * on the buffer linked list for this function to be meaningful. + * + * If write_countp != NULL, *write_countp will hold the number of bytes + * this transaction can send. + */ +static void +build_msghdr_send(isc__socket_t *sock, isc_socketevent_t *dev, + struct msghdr *msg, struct iovec *iov, size_t *write_countp) +{ + unsigned int iovcount; + isc_buffer_t *buffer; + isc_region_t used; + size_t write_count; + size_t skip_count; + + memset(msg, 0, sizeof(*msg)); + + if (!sock->connected) { + msg->msg_name = (void *)&dev->address.type.sa; + msg->msg_namelen = dev->address.length; + } else { + msg->msg_name = NULL; + msg->msg_namelen = 0; + } + + buffer = ISC_LIST_HEAD(dev->bufferlist); + write_count = 0; + iovcount = 0; + + /* + * Single buffer I/O? Skip what we've done so far in this region. + */ + if (buffer == NULL) { + write_count = dev->region.length - dev->n; + iov[0].iov_base = (void *)(dev->region.base + dev->n); + iov[0].iov_len = write_count; + iovcount = 1; + + goto config; + } + + /* + * Multibuffer I/O. + * Skip the data in the buffer list that we have already written. + */ + skip_count = dev->n; + while (buffer != NULL) { + REQUIRE(ISC_BUFFER_VALID(buffer)); + if (skip_count < isc_buffer_usedlength(buffer)) + break; + skip_count -= isc_buffer_usedlength(buffer); + buffer = ISC_LIST_NEXT(buffer, link); + } + + while (buffer != NULL) { + INSIST(iovcount < MAXSCATTERGATHER_SEND); + + isc_buffer_usedregion(buffer, &used); + + if (used.length > 0) { + iov[iovcount].iov_base = (void *)(used.base + + skip_count); + iov[iovcount].iov_len = used.length - skip_count; + write_count += (used.length - skip_count); + skip_count = 0; + iovcount++; + } + buffer = ISC_LIST_NEXT(buffer, link); + } + + INSIST(skip_count == 0U); + + config: + msg->msg_iov = iov; + msg->msg_iovlen = iovcount; + +#ifdef ISC_NET_BSD44MSGHDR + msg->msg_control = NULL; + msg->msg_controllen = 0; + msg->msg_flags = 0; +#if defined(USE_CMSG) && defined(ISC_PLATFORM_HAVEIN6PKTINFO) + if ((sock->type == isc_sockettype_udp) + && ((dev->attributes & ISC_SOCKEVENTATTR_PKTINFO) != 0)) { +#if defined(IPV6_USE_MIN_MTU) + int use_min_mtu = 1; /* -1, 0, 1 */ +#endif + struct cmsghdr *cmsgp; + struct in6_pktinfo *pktinfop; + + socket_log(sock, NULL, TRACE, + isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_SENDTODATA, + "sendto pktinfo data, ifindex %u", + dev->pktinfo.ipi6_ifindex); + + msg->msg_controllen = cmsg_space(sizeof(struct in6_pktinfo)); + INSIST(msg->msg_controllen <= sock->sendcmsgbuflen); + msg->msg_control = (void *)sock->sendcmsgbuf; + + cmsgp = (struct cmsghdr *)sock->sendcmsgbuf; + cmsgp->cmsg_level = IPPROTO_IPV6; + cmsgp->cmsg_type = IPV6_PKTINFO; + cmsgp->cmsg_len = cmsg_len(sizeof(struct in6_pktinfo)); + pktinfop = (struct in6_pktinfo *)CMSG_DATA(cmsgp); + memcpy(pktinfop, &dev->pktinfo, sizeof(struct in6_pktinfo)); +#if defined(IPV6_USE_MIN_MTU) + /* + * Set IPV6_USE_MIN_MTU as a per packet option as FreeBSD + * ignores setsockopt(IPV6_USE_MIN_MTU) when IPV6_PKTINFO + * is used. + */ + cmsgp = (struct cmsghdr *)(sock->sendcmsgbuf + + msg->msg_controllen); + msg->msg_controllen += cmsg_space(sizeof(use_min_mtu)); + INSIST(msg->msg_controllen <= sock->sendcmsgbuflen); + + cmsgp->cmsg_level = IPPROTO_IPV6; + cmsgp->cmsg_type = IPV6_USE_MIN_MTU; + cmsgp->cmsg_len = cmsg_len(sizeof(use_min_mtu)); + memcpy(CMSG_DATA(cmsgp), &use_min_mtu, sizeof(use_min_mtu)); +#endif + } +#endif /* USE_CMSG && ISC_PLATFORM_HAVEIPV6 */ +#else /* ISC_NET_BSD44MSGHDR */ + msg->msg_accrights = NULL; + msg->msg_accrightslen = 0; +#endif /* ISC_NET_BSD44MSGHDR */ + + if (write_countp != NULL) + *write_countp = write_count; +} + +/* + * Construct an iov array and attach it to the msghdr passed in. This is + * the RECV constructor, which will use the available region of the buffer + * (if using a buffer list) or will use the internal region (if a single + * buffer I/O is requested). + * + * Nothing can be NULL, and the done event must list at least one buffer + * on the buffer linked list for this function to be meaningful. + * + * If read_countp != NULL, *read_countp will hold the number of bytes + * this transaction can receive. + */ +static void +build_msghdr_recv(isc__socket_t *sock, isc_socketevent_t *dev, + struct msghdr *msg, struct iovec *iov, size_t *read_countp) +{ + unsigned int iovcount; + isc_buffer_t *buffer; + isc_region_t available; + size_t read_count; + + memset(msg, 0, sizeof(struct msghdr)); + + if (sock->type == isc_sockettype_udp) { + memset(&dev->address, 0, sizeof(dev->address)); +#ifdef BROKEN_RECVMSG + if (sock->pf == AF_INET) { + msg->msg_name = (void *)&dev->address.type.sin; + msg->msg_namelen = sizeof(dev->address.type.sin6); + } else if (sock->pf == AF_INET6) { + msg->msg_name = (void *)&dev->address.type.sin6; + msg->msg_namelen = sizeof(dev->address.type.sin6); +#ifdef ISC_PLATFORM_HAVESYSUNH + } else if (sock->pf == AF_UNIX) { + msg->msg_name = (void *)&dev->address.type.sunix; + msg->msg_namelen = sizeof(dev->address.type.sunix); +#endif + } else { + msg->msg_name = (void *)&dev->address.type.sa; + msg->msg_namelen = sizeof(dev->address.type); + } +#else + msg->msg_name = (void *)&dev->address.type.sa; + msg->msg_namelen = sizeof(dev->address.type); +#endif +#ifdef ISC_NET_RECVOVERFLOW + /* If needed, steal one iovec for overflow detection. */ + maxiov--; +#endif + } else { /* TCP */ + msg->msg_name = NULL; + msg->msg_namelen = 0; + dev->address = sock->peer_address; + } + + buffer = ISC_LIST_HEAD(dev->bufferlist); + read_count = 0; + + /* + * Single buffer I/O? Skip what we've done so far in this region. + */ + if (buffer == NULL) { + read_count = dev->region.length - dev->n; + iov[0].iov_base = (void *)(dev->region.base + dev->n); + iov[0].iov_len = read_count; + iovcount = 1; + + goto config; + } + + /* + * Multibuffer I/O. + * Skip empty buffers. + */ + while (buffer != NULL) { + REQUIRE(ISC_BUFFER_VALID(buffer)); + if (isc_buffer_availablelength(buffer) != 0) + break; + buffer = ISC_LIST_NEXT(buffer, link); + } + + iovcount = 0; + while (buffer != NULL) { + INSIST(iovcount < MAXSCATTERGATHER_RECV); + + isc_buffer_availableregion(buffer, &available); + + if (available.length > 0) { + iov[iovcount].iov_base = (void *)(available.base); + iov[iovcount].iov_len = available.length; + read_count += available.length; + iovcount++; + } + buffer = ISC_LIST_NEXT(buffer, link); + } + + config: + + /* + * If needed, set up to receive that one extra byte. Note that + * we know there is at least one iov left, since we stole it + * at the top of this function. + */ +#ifdef ISC_NET_RECVOVERFLOW + if (sock->type == isc_sockettype_udp) { + iov[iovcount].iov_base = (void *)(&sock->overflow); + iov[iovcount].iov_len = 1; + iovcount++; + } +#endif + + msg->msg_iov = iov; + msg->msg_iovlen = iovcount; + +#ifdef ISC_NET_BSD44MSGHDR + msg->msg_control = NULL; + msg->msg_controllen = 0; + msg->msg_flags = 0; +#if defined(USE_CMSG) + if (sock->type == isc_sockettype_udp) { + msg->msg_control = sock->recvcmsgbuf; + msg->msg_controllen = sock->recvcmsgbuflen; + } +#endif /* USE_CMSG */ +#else /* ISC_NET_BSD44MSGHDR */ + msg->msg_accrights = NULL; + msg->msg_accrightslen = 0; +#endif /* ISC_NET_BSD44MSGHDR */ + + if (read_countp != NULL) + *read_countp = read_count; +} + +static void +set_dev_address(isc_sockaddr_t *address, isc__socket_t *sock, + isc_socketevent_t *dev) +{ + if (sock->type == isc_sockettype_udp) { + if (address != NULL) + dev->address = *address; + else + dev->address = sock->peer_address; + } else if (sock->type == isc_sockettype_tcp) { + INSIST(address == NULL); + dev->address = sock->peer_address; + } +} + +static void +destroy_socketevent(isc_event_t *event) { + isc_socketevent_t *ev = (isc_socketevent_t *)event; + + INSIST(ISC_LIST_EMPTY(ev->bufferlist)); + + (ev->destroy)(event); +} + +static isc_socketevent_t * +allocate_socketevent(isc__socket_t *sock, isc_eventtype_t eventtype, + isc_taskaction_t action, const void *arg) +{ + isc_socketevent_t *ev; + + ev = (isc_socketevent_t *)isc_event_allocate(sock->manager->mctx, + sock, eventtype, + action, arg, + sizeof(*ev)); + + if (ev == NULL) + return (NULL); + + ev->result = ISC_R_UNSET; + ISC_LINK_INIT(ev, ev_link); + ISC_LIST_INIT(ev->bufferlist); + ev->region.base = NULL; + ev->n = 0; + ev->offset = 0; + ev->attributes = 0; + ev->destroy = ev->ev_destroy; + ev->ev_destroy = destroy_socketevent; + + return (ev); +} + +#if defined(ISC_SOCKET_DEBUG) +static void +dump_msg(struct msghdr *msg) { + unsigned int i; + + printf("MSGHDR %p\n", msg); + printf("\tname %p, namelen %ld\n", msg->msg_name, + (long) msg->msg_namelen); + printf("\tiov %p, iovlen %ld\n", msg->msg_iov, + (long) msg->msg_iovlen); + for (i = 0; i < (unsigned int)msg->msg_iovlen; i++) + printf("\t\t%d\tbase %p, len %ld\n", i, + msg->msg_iov[i].iov_base, + (long) msg->msg_iov[i].iov_len); +#ifdef ISC_NET_BSD44MSGHDR + printf("\tcontrol %p, controllen %ld\n", msg->msg_control, + (long) msg->msg_controllen); +#endif +} +#endif + +#define DOIO_SUCCESS 0 /* i/o ok, event sent */ +#define DOIO_SOFT 1 /* i/o ok, soft error, no event sent */ +#define DOIO_HARD 2 /* i/o error, event sent */ +#define DOIO_EOF 3 /* EOF, no event sent */ + +static int +doio_recv(isc__socket_t *sock, isc_socketevent_t *dev) { + int cc; + struct iovec iov[MAXSCATTERGATHER_RECV]; + size_t read_count; + size_t actual_count; + struct msghdr msghdr; + isc_buffer_t *buffer; + int recv_errno; + char strbuf[ISC_STRERRORSIZE]; + + build_msghdr_recv(sock, dev, &msghdr, iov, &read_count); + +#if defined(ISC_SOCKET_DEBUG) + dump_msg(&msghdr); +#endif + + cc = recvmsg(sock->fd, &msghdr, 0); + recv_errno = errno; + +#if defined(ISC_SOCKET_DEBUG) + dump_msg(&msghdr); +#endif + + if (cc < 0) { + if (SOFT_ERROR(recv_errno)) + return (DOIO_SOFT); + + if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) { + isc__strerror(recv_errno, strbuf, sizeof(strbuf)); + socket_log(sock, NULL, IOEVENT, + isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_DOIORECV, + "doio_recv: recvmsg(%d) %d bytes, err %d/%s", + sock->fd, cc, recv_errno, strbuf); + } + +#define SOFT_OR_HARD(_system, _isc) \ + if (recv_errno == _system) { \ + if (sock->connected) { \ + dev->result = _isc; \ + inc_stats(sock->manager->stats, \ + sock->statsindex[STATID_RECVFAIL]); \ + return (DOIO_HARD); \ + } \ + return (DOIO_SOFT); \ + } +#define ALWAYS_HARD(_system, _isc) \ + if (recv_errno == _system) { \ + dev->result = _isc; \ + inc_stats(sock->manager->stats, \ + sock->statsindex[STATID_RECVFAIL]); \ + return (DOIO_HARD); \ + } + + SOFT_OR_HARD(ECONNREFUSED, ISC_R_CONNREFUSED); + SOFT_OR_HARD(ENETUNREACH, ISC_R_NETUNREACH); + SOFT_OR_HARD(EHOSTUNREACH, ISC_R_HOSTUNREACH); + SOFT_OR_HARD(EHOSTDOWN, ISC_R_HOSTDOWN); + /* HPUX 11.11 can return EADDRNOTAVAIL. */ + SOFT_OR_HARD(EADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL); + ALWAYS_HARD(ENOBUFS, ISC_R_NORESOURCES); + /* + * HPUX returns EPROTO and EINVAL on receiving some ICMP/ICMPv6 + * errors. + */ +#ifdef EPROTO + SOFT_OR_HARD(EPROTO, ISC_R_HOSTUNREACH); +#endif + SOFT_OR_HARD(EINVAL, ISC_R_HOSTUNREACH); + +#undef SOFT_OR_HARD +#undef ALWAYS_HARD + + dev->result = isc__errno2result(recv_errno); + inc_stats(sock->manager->stats, + sock->statsindex[STATID_RECVFAIL]); + return (DOIO_HARD); + } + + /* + * On TCP and UNIX sockets, zero length reads indicate EOF, + * while on UDP sockets, zero length reads are perfectly valid, + * although strange. + */ + switch (sock->type) { + case isc_sockettype_tcp: + case isc_sockettype_unix: + if (cc == 0) + return (DOIO_EOF); + break; + case isc_sockettype_udp: + break; + case isc_sockettype_fdwatch: + default: + INSIST(0); + } + + if (sock->type == isc_sockettype_udp) { + dev->address.length = msghdr.msg_namelen; + if (isc_sockaddr_getport(&dev->address) == 0) { + if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) { + socket_log(sock, &dev->address, IOEVENT, + isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_ZEROPORT, + "dropping source port zero packet"); + } + return (DOIO_SOFT); + } + /* + * Simulate a firewall blocking UDP responses bigger than + * 512 bytes. + */ + if (sock->manager->maxudp != 0 && cc > sock->manager->maxudp) + return (DOIO_SOFT); + } + + socket_log(sock, &dev->address, IOEVENT, + isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_PKTRECV, + "packet received correctly"); + + /* + * Overflow bit detection. If we received MORE bytes than we should, + * this indicates an overflow situation. Set the flag in the + * dev entry and adjust how much we read by one. + */ +#ifdef ISC_NET_RECVOVERFLOW + if ((sock->type == isc_sockettype_udp) && ((size_t)cc > read_count)) { + dev->attributes |= ISC_SOCKEVENTATTR_TRUNC; + cc--; + } +#endif + + /* + * If there are control messages attached, run through them and pull + * out the interesting bits. + */ + if (sock->type == isc_sockettype_udp) + process_cmsg(sock, &msghdr, dev); + + /* + * update the buffers (if any) and the i/o count + */ + dev->n += cc; + actual_count = cc; + buffer = ISC_LIST_HEAD(dev->bufferlist); + while (buffer != NULL && actual_count > 0U) { + REQUIRE(ISC_BUFFER_VALID(buffer)); + if (isc_buffer_availablelength(buffer) <= actual_count) { + actual_count -= isc_buffer_availablelength(buffer); + isc_buffer_add(buffer, + isc_buffer_availablelength(buffer)); + } else { + isc_buffer_add(buffer, actual_count); + actual_count = 0; + POST(actual_count); + break; + } + buffer = ISC_LIST_NEXT(buffer, link); + if (buffer == NULL) { + INSIST(actual_count == 0U); + } + } + + /* + * If we read less than we expected, update counters, + * and let the upper layer poke the descriptor. + */ + if (((size_t)cc != read_count) && (dev->n < dev->minimum)) + return (DOIO_SOFT); + + /* + * Full reads are posted, or partials if partials are ok. + */ + dev->result = ISC_R_SUCCESS; + return (DOIO_SUCCESS); +} + +/* + * Returns: + * DOIO_SUCCESS The operation succeeded. dev->result contains + * ISC_R_SUCCESS. + * + * DOIO_HARD A hard or unexpected I/O error was encountered. + * dev->result contains the appropriate error. + * + * DOIO_SOFT A soft I/O error was encountered. No senddone + * event was sent. The operation should be retried. + * + * No other return values are possible. + */ +static int +doio_send(isc__socket_t *sock, isc_socketevent_t *dev) { + int cc; + struct iovec iov[MAXSCATTERGATHER_SEND]; + size_t write_count; + struct msghdr msghdr; + char addrbuf[ISC_SOCKADDR_FORMATSIZE]; + int attempts = 0; + int send_errno; + char strbuf[ISC_STRERRORSIZE]; + + build_msghdr_send(sock, dev, &msghdr, iov, &write_count); + + resend: + cc = sendmsg(sock->fd, &msghdr, 0); + send_errno = errno; + + /* + * Check for error or block condition. + */ + if (cc < 0) { + if (send_errno == EINTR && ++attempts < NRETRIES) + goto resend; + + if (SOFT_ERROR(send_errno)) + return (DOIO_SOFT); + +#define SOFT_OR_HARD(_system, _isc) \ + if (send_errno == _system) { \ + if (sock->connected) { \ + dev->result = _isc; \ + inc_stats(sock->manager->stats, \ + sock->statsindex[STATID_SENDFAIL]); \ + return (DOIO_HARD); \ + } \ + return (DOIO_SOFT); \ + } +#define ALWAYS_HARD(_system, _isc) \ + if (send_errno == _system) { \ + dev->result = _isc; \ + inc_stats(sock->manager->stats, \ + sock->statsindex[STATID_SENDFAIL]); \ + return (DOIO_HARD); \ + } + + SOFT_OR_HARD(ECONNREFUSED, ISC_R_CONNREFUSED); + ALWAYS_HARD(EACCES, ISC_R_NOPERM); + ALWAYS_HARD(EAFNOSUPPORT, ISC_R_ADDRNOTAVAIL); + ALWAYS_HARD(EADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL); + ALWAYS_HARD(EHOSTUNREACH, ISC_R_HOSTUNREACH); +#ifdef EHOSTDOWN + ALWAYS_HARD(EHOSTDOWN, ISC_R_HOSTUNREACH); +#endif + ALWAYS_HARD(ENETUNREACH, ISC_R_NETUNREACH); + ALWAYS_HARD(ENOBUFS, ISC_R_NORESOURCES); + ALWAYS_HARD(EPERM, ISC_R_HOSTUNREACH); + ALWAYS_HARD(EPIPE, ISC_R_NOTCONNECTED); + ALWAYS_HARD(ECONNRESET, ISC_R_CONNECTIONRESET); + +#undef SOFT_OR_HARD +#undef ALWAYS_HARD + + /* + * The other error types depend on whether or not the + * socket is UDP or TCP. If it is UDP, some errors + * that we expect to be fatal under TCP are merely + * annoying, and are really soft errors. + * + * However, these soft errors are still returned as + * a status. + */ + isc_sockaddr_format(&dev->address, addrbuf, sizeof(addrbuf)); + isc__strerror(send_errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, "internal_send: %s: %s", + addrbuf, strbuf); + dev->result = isc__errno2result(send_errno); + inc_stats(sock->manager->stats, + sock->statsindex[STATID_SENDFAIL]); + return (DOIO_HARD); + } + + if (cc == 0) { + inc_stats(sock->manager->stats, + sock->statsindex[STATID_SENDFAIL]); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "doio_send: send() %s 0", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_RETURNED, "returned")); + } + + /* + * If we write less than we expected, update counters, poke. + */ + dev->n += cc; + if ((size_t)cc != write_count) + return (DOIO_SOFT); + + /* + * Exactly what we wanted to write. We're done with this + * entry. Post its completion event. + */ + dev->result = ISC_R_SUCCESS; + return (DOIO_SUCCESS); +} + +/* + * Kill. + * + * Caller must ensure that the socket is not locked and no external + * references exist. + */ +static void +closesocket(isc__socketmgr_t *manager, isc__socket_t *sock, int fd) { + isc_sockettype_t type = sock->type; + int lockid = FDLOCK_ID(fd); + + /* + * No one has this socket open, so the watcher doesn't have to be + * poked, and the socket doesn't have to be locked. + */ + LOCK(&manager->fdlock[lockid]); + manager->fds[fd] = NULL; + if (type == isc_sockettype_fdwatch) + manager->fdstate[fd] = CLOSED; + else + manager->fdstate[fd] = CLOSE_PENDING; + UNLOCK(&manager->fdlock[lockid]); + if (type == isc_sockettype_fdwatch) { + /* + * The caller may close the socket once this function returns, + * and `fd' may be reassigned for a new socket. So we do + * unwatch_fd() here, rather than defer it via select_poke(). + * Note: this may complicate data protection among threads and + * may reduce performance due to additional locks. One way to + * solve this would be to dup() the watched descriptor, but we + * take a simpler approach at this moment. + */ + (void)unwatch_fd(manager, fd, SELECT_POKE_READ); + (void)unwatch_fd(manager, fd, SELECT_POKE_WRITE); + } else + select_poke(manager, fd, SELECT_POKE_CLOSE); + + inc_stats(manager->stats, sock->statsindex[STATID_CLOSE]); + + /* + * update manager->maxfd here (XXX: this should be implemented more + * efficiently) + */ +#ifdef USE_SELECT + LOCK(&manager->lock); + if (manager->maxfd == fd) { + int i; + + manager->maxfd = 0; + for (i = fd - 1; i >= 0; i--) { + lockid = FDLOCK_ID(i); + + LOCK(&manager->fdlock[lockid]); + if (manager->fdstate[i] == MANAGED) { + manager->maxfd = i; + UNLOCK(&manager->fdlock[lockid]); + break; + } + UNLOCK(&manager->fdlock[lockid]); + } +#ifdef ISC_PLATFORM_USETHREADS + if (manager->maxfd < manager->pipe_fds[0]) + manager->maxfd = manager->pipe_fds[0]; +#endif + } + UNLOCK(&manager->lock); +#endif /* USE_SELECT */ +} + +static void +destroy(isc__socket_t **sockp) { + int fd; + isc__socket_t *sock = *sockp; + isc__socketmgr_t *manager = sock->manager; + + socket_log(sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_DESTROYING, "destroying"); + + INSIST(ISC_LIST_EMPTY(sock->accept_list)); + INSIST(ISC_LIST_EMPTY(sock->recv_list)); + INSIST(ISC_LIST_EMPTY(sock->send_list)); + INSIST(sock->connect_ev == NULL); + REQUIRE(sock->fd == -1 || sock->fd < (int)manager->maxsocks); + + if (sock->fd >= 0) { + fd = sock->fd; + sock->fd = -1; + closesocket(manager, sock, fd); + } + + LOCK(&manager->lock); + + ISC_LIST_UNLINK(manager->socklist, sock, link); + +#ifdef USE_WATCHER_THREAD + if (ISC_LIST_EMPTY(manager->socklist)) + SIGNAL(&manager->shutdown_ok); +#endif /* USE_WATCHER_THREAD */ + + /* can't unlock manager as its memory context is still used */ + free_socket(sockp); + + UNLOCK(&manager->lock); +} + +static isc_result_t +allocate_socket(isc__socketmgr_t *manager, isc_sockettype_t type, + isc__socket_t **socketp) +{ + isc__socket_t *sock; + isc_result_t result; + ISC_SOCKADDR_LEN_T cmsgbuflen; + + sock = isc_mem_get(manager->mctx, sizeof(*sock)); + + if (sock == NULL) + return (ISC_R_NOMEMORY); + + sock->common.magic = 0; + sock->common.impmagic = 0; + sock->references = 0; + + sock->manager = manager; + sock->type = type; + sock->fd = -1; + sock->dupped = 0; + sock->statsindex = NULL; + + ISC_LINK_INIT(sock, link); + + sock->recvcmsgbuf = NULL; + sock->sendcmsgbuf = NULL; + + /* + * set up cmsg buffers + */ + cmsgbuflen = 0; +#if defined(USE_CMSG) && defined(ISC_PLATFORM_HAVEIN6PKTINFO) + cmsgbuflen += cmsg_space(sizeof(struct in6_pktinfo)); +#endif +#if defined(USE_CMSG) && defined(SO_TIMESTAMP) + cmsgbuflen += cmsg_space(sizeof(struct timeval)); +#endif + sock->recvcmsgbuflen = cmsgbuflen; + if (sock->recvcmsgbuflen != 0U) { + sock->recvcmsgbuf = isc_mem_get(manager->mctx, cmsgbuflen); + if (sock->recvcmsgbuf == NULL) { + result = ISC_R_NOMEMORY; + goto error; + } + } + + cmsgbuflen = 0; +#if defined(USE_CMSG) && defined(ISC_PLATFORM_HAVEIN6PKTINFO) + cmsgbuflen += cmsg_space(sizeof(struct in6_pktinfo)); +#if defined(IPV6_USE_MIN_MTU) + /* + * Provide space for working around FreeBSD's broken IPV6_USE_MIN_MTU + * support. + */ + cmsgbuflen += cmsg_space(sizeof(int)); +#endif +#endif + sock->sendcmsgbuflen = cmsgbuflen; + if (sock->sendcmsgbuflen != 0U) { + sock->sendcmsgbuf = isc_mem_get(manager->mctx, cmsgbuflen); + if (sock->sendcmsgbuf == NULL) { + result = ISC_R_NOMEMORY; + goto error; + } + } + + memset(sock->name, 0, sizeof(sock->name)); + sock->tag = NULL; + + /* + * set up list of readers and writers to be initially empty + */ + ISC_LIST_INIT(sock->recv_list); + ISC_LIST_INIT(sock->send_list); + ISC_LIST_INIT(sock->accept_list); + sock->connect_ev = NULL; + sock->pending_recv = 0; + sock->pending_send = 0; + sock->pending_accept = 0; + sock->listener = 0; + sock->connected = 0; + sock->connecting = 0; + sock->bound = 0; + + /* + * initialize the lock + */ + result = isc_mutex_init(&sock->lock); + if (result != ISC_R_SUCCESS) { + sock->common.magic = 0; + sock->common.impmagic = 0; + goto error; + } + + /* + * Initialize readable and writable events + */ + ISC_EVENT_INIT(&sock->readable_ev, sizeof(intev_t), + ISC_EVENTATTR_NOPURGE, NULL, ISC_SOCKEVENT_INTR, + NULL, sock, sock, NULL, NULL); + ISC_EVENT_INIT(&sock->writable_ev, sizeof(intev_t), + ISC_EVENTATTR_NOPURGE, NULL, ISC_SOCKEVENT_INTW, + NULL, sock, sock, NULL, NULL); + + sock->common.magic = ISCAPI_SOCKET_MAGIC; + sock->common.impmagic = SOCKET_MAGIC; + *socketp = sock; + + return (ISC_R_SUCCESS); + + error: + if (sock->recvcmsgbuf != NULL) + isc_mem_put(manager->mctx, sock->recvcmsgbuf, + sock->recvcmsgbuflen); + if (sock->sendcmsgbuf != NULL) + isc_mem_put(manager->mctx, sock->sendcmsgbuf, + sock->sendcmsgbuflen); + isc_mem_put(manager->mctx, sock, sizeof(*sock)); + + return (result); +} + +/* + * This event requires that the various lists be empty, that the reference + * count be 1, and that the magic number is valid. The other socket bits, + * like the lock, must be initialized as well. The fd associated must be + * marked as closed, by setting it to -1 on close, or this routine will + * also close the socket. + */ +static void +free_socket(isc__socket_t **socketp) { + isc__socket_t *sock = *socketp; + + INSIST(sock->references == 0); + INSIST(VALID_SOCKET(sock)); + INSIST(!sock->connecting); + INSIST(!sock->pending_recv); + INSIST(!sock->pending_send); + INSIST(!sock->pending_accept); + INSIST(ISC_LIST_EMPTY(sock->recv_list)); + INSIST(ISC_LIST_EMPTY(sock->send_list)); + INSIST(ISC_LIST_EMPTY(sock->accept_list)); + INSIST(!ISC_LINK_LINKED(sock, link)); + + if (sock->recvcmsgbuf != NULL) + isc_mem_put(sock->manager->mctx, sock->recvcmsgbuf, + sock->recvcmsgbuflen); + if (sock->sendcmsgbuf != NULL) + isc_mem_put(sock->manager->mctx, sock->sendcmsgbuf, + sock->sendcmsgbuflen); + + sock->common.magic = 0; + sock->common.impmagic = 0; + + DESTROYLOCK(&sock->lock); + + isc_mem_put(sock->manager->mctx, sock, sizeof(*sock)); + + *socketp = NULL; +} + +#ifdef SO_BSDCOMPAT +/* + * This really should not be necessary to do. Having to workout + * which kernel version we are on at run time so that we don't cause + * the kernel to issue a warning about us using a deprecated socket option. + * Such warnings should *never* be on by default in production kernels. + * + * We can't do this a build time because executables are moved between + * machines and hence kernels. + * + * We can't just not set SO_BSDCOMAT because some kernels require it. + */ + +static isc_once_t bsdcompat_once = ISC_ONCE_INIT; +isc_boolean_t bsdcompat = ISC_TRUE; + +static void +clear_bsdcompat(void) { +#ifdef __linux__ + struct utsname buf; + char *endp; + long int major; + long int minor; + + uname(&buf); /* Can only fail if buf is bad in Linux. */ + + /* Paranoia in parsing can be increased, but we trust uname(). */ + major = strtol(buf.release, &endp, 10); + if (*endp == '.') { + minor = strtol(endp+1, &endp, 10); + if ((major > 2) || ((major == 2) && (minor >= 4))) { + bsdcompat = ISC_FALSE; + } + } +#endif /* __linux __ */ +} +#endif + +static isc_result_t +opensocket(isc__socketmgr_t *manager, isc__socket_t *sock, + isc__socket_t *dup_socket) +{ + isc_result_t result; + char strbuf[ISC_STRERRORSIZE]; + const char *err = "socket"; + int tries = 0; +#if defined(USE_CMSG) || defined(SO_BSDCOMPAT) + int on = 1; +#endif +#if defined(SO_RCVBUF) + ISC_SOCKADDR_LEN_T optlen; + int size; +#endif + + again: + if (dup_socket == NULL) { + switch (sock->type) { + case isc_sockettype_udp: + sock->fd = socket(sock->pf, SOCK_DGRAM, IPPROTO_UDP); + break; + case isc_sockettype_tcp: + sock->fd = socket(sock->pf, SOCK_STREAM, IPPROTO_TCP); + break; + case isc_sockettype_unix: + sock->fd = socket(sock->pf, SOCK_STREAM, 0); + break; + case isc_sockettype_fdwatch: + /* + * We should not be called for isc_sockettype_fdwatch + * sockets. + */ + INSIST(0); + break; + } + } else { + sock->fd = dup(dup_socket->fd); + sock->dupped = 1; + sock->bound = dup_socket->bound; + } + if (sock->fd == -1 && errno == EINTR && tries++ < 42) + goto again; + +#ifdef F_DUPFD + /* + * Leave a space for stdio and TCP to work in. + */ + if (manager->reserved != 0 && sock->type == isc_sockettype_udp && + sock->fd >= 0 && sock->fd < manager->reserved) { + int new, tmp; + new = fcntl(sock->fd, F_DUPFD, manager->reserved); + tmp = errno; + (void)close(sock->fd); + errno = tmp; + sock->fd = new; + err = "isc_socket_create: fcntl/reserved"; + } else if (sock->fd >= 0 && sock->fd < 20) { + int new, tmp; + new = fcntl(sock->fd, F_DUPFD, 20); + tmp = errno; + (void)close(sock->fd); + errno = tmp; + sock->fd = new; + err = "isc_socket_create: fcntl"; + } +#endif + + if (sock->fd >= (int)manager->maxsocks) { + (void)close(sock->fd); + isc_log_iwrite(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR, + isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_TOOMANYFDS, + "socket: file descriptor exceeds limit (%d/%u)", + sock->fd, manager->maxsocks); + return (ISC_R_NORESOURCES); + } + + if (sock->fd < 0) { + switch (errno) { + case EMFILE: + case ENFILE: + isc__strerror(errno, strbuf, sizeof(strbuf)); + isc_log_iwrite(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR, + isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_TOOMANYFDS, + "%s: %s", err, strbuf); + /* fallthrough */ + case ENOBUFS: + return (ISC_R_NORESOURCES); + + case EPROTONOSUPPORT: + case EPFNOSUPPORT: + case EAFNOSUPPORT: + /* + * Linux 2.2 (and maybe others) return EINVAL instead of + * EAFNOSUPPORT. + */ + case EINVAL: + return (ISC_R_FAMILYNOSUPPORT); + + default: + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "%s() %s: %s", err, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, + "failed"), + strbuf); + return (ISC_R_UNEXPECTED); + } + } + + if (dup_socket != NULL) + goto setup_done; + + result = make_nonblock(sock->fd); + if (result != ISC_R_SUCCESS) { + (void)close(sock->fd); + return (result); + } + +#ifdef SO_BSDCOMPAT + RUNTIME_CHECK(isc_once_do(&bsdcompat_once, + clear_bsdcompat) == ISC_R_SUCCESS); + if (sock->type != isc_sockettype_unix && bsdcompat && + setsockopt(sock->fd, SOL_SOCKET, SO_BSDCOMPAT, + (void *)&on, sizeof(on)) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "setsockopt(%d, SO_BSDCOMPAT) %s: %s", + sock->fd, + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed"), + strbuf); + /* Press on... */ + } +#endif + +#ifdef SO_NOSIGPIPE + if (setsockopt(sock->fd, SOL_SOCKET, SO_NOSIGPIPE, + (void *)&on, sizeof(on)) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "setsockopt(%d, SO_NOSIGPIPE) %s: %s", + sock->fd, + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed"), + strbuf); + /* Press on... */ + } +#endif + +#if defined(USE_CMSG) || defined(SO_RCVBUF) + if (sock->type == isc_sockettype_udp) { + +#if defined(USE_CMSG) +#if defined(SO_TIMESTAMP) + if (setsockopt(sock->fd, SOL_SOCKET, SO_TIMESTAMP, + (void *)&on, sizeof(on)) < 0 + && errno != ENOPROTOOPT) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "setsockopt(%d, SO_TIMESTAMP) %s: %s", + sock->fd, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, + "failed"), + strbuf); + /* Press on... */ + } +#endif /* SO_TIMESTAMP */ + +#if defined(ISC_PLATFORM_HAVEIPV6) + if (sock->pf == AF_INET6 && sock->recvcmsgbuflen == 0U) { + /* + * Warn explicitly because this anomaly can be hidden + * in usual operation (and unexpectedly appear later). + */ + UNEXPECTED_ERROR(__FILE__, __LINE__, + "No buffer available to receive " + "IPv6 destination"); + } +#ifdef ISC_PLATFORM_HAVEIN6PKTINFO +#ifdef IPV6_RECVPKTINFO + /* RFC 3542 */ + if ((sock->pf == AF_INET6) + && (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, + (void *)&on, sizeof(on)) < 0)) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "setsockopt(%d, IPV6_RECVPKTINFO) " + "%s: %s", sock->fd, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, + "failed"), + strbuf); + } +#else + /* RFC 2292 */ + if ((sock->pf == AF_INET6) + && (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_PKTINFO, + (void *)&on, sizeof(on)) < 0)) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "setsockopt(%d, IPV6_PKTINFO) %s: %s", + sock->fd, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, + "failed"), + strbuf); + } +#endif /* IPV6_RECVPKTINFO */ +#endif /* ISC_PLATFORM_HAVEIN6PKTINFO */ +#ifdef IPV6_USE_MIN_MTU /* RFC 3542, not too common yet*/ + /* use minimum MTU */ + if (sock->pf == AF_INET6 && + setsockopt(sock->fd, IPPROTO_IPV6, IPV6_USE_MIN_MTU, + (void *)&on, sizeof(on)) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "setsockopt(%d, IPV6_USE_MIN_MTU) " + "%s: %s", sock->fd, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, + "failed"), + strbuf); + } +#endif +#if defined(IPV6_MTU) + /* + * Use minimum MTU on IPv6 sockets. + */ + if (sock->pf == AF_INET6) { + int mtu = 1280; + (void)setsockopt(sock->fd, IPPROTO_IPV6, IPV6_MTU, + &mtu, sizeof(mtu)); + } +#endif +#if defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DONT) + /* + * Turn off Path MTU discovery on IPv6/UDP sockets. + */ + if (sock->pf == AF_INET6) { + int action = IPV6_PMTUDISC_DONT; + (void)setsockopt(sock->fd, IPPROTO_IPV6, + IPV6_MTU_DISCOVER, &action, + sizeof(action)); + } +#endif +#endif /* ISC_PLATFORM_HAVEIPV6 */ +#endif /* defined(USE_CMSG) */ + +#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) + /* + * Turn off Path MTU discovery on IPv4/UDP sockets. + */ + if (sock->pf == AF_INET) { + int action = IP_PMTUDISC_DONT; + (void)setsockopt(sock->fd, IPPROTO_IP, IP_MTU_DISCOVER, + &action, sizeof(action)); + } +#endif +#if defined(IP_DONTFRAG) + /* + * Turn off Path MTU discovery on IPv4/UDP sockets. + */ + if (sock->pf == AF_INET) { + int off = 0; + (void)setsockopt(sock->fd, IPPROTO_IP, IP_DONTFRAG, + &off, sizeof(off)); + } +#endif + +#if defined(SO_RCVBUF) + optlen = sizeof(size); + if (getsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF, + (void *)&size, &optlen) >= 0 && + size < RCVBUFSIZE) { + size = RCVBUFSIZE; + if (setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF, + (void *)&size, sizeof(size)) == -1) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "setsockopt(%d, SO_RCVBUF, %d) %s: %s", + sock->fd, size, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, + "failed"), + strbuf); + } + } +#endif + } +#endif /* defined(USE_CMSG) || defined(SO_RCVBUF) */ + +setup_done: + inc_stats(manager->stats, sock->statsindex[STATID_OPEN]); + + return (ISC_R_SUCCESS); +} + +/* + * Create a 'type' socket or duplicate an existing socket, managed + * by 'manager'. Events will be posted to 'task' and when dispatched + * 'action' will be called with 'arg' as the arg value. The new + * socket is returned in 'socketp'. + */ +static isc_result_t +socket_create(isc_socketmgr_t *manager0, int pf, isc_sockettype_t type, + isc_socket_t **socketp, isc_socket_t *dup_socket) +{ + isc__socket_t *sock = NULL; + isc__socketmgr_t *manager = (isc__socketmgr_t *)manager0; + isc_result_t result; + int lockid; + + REQUIRE(VALID_MANAGER(manager)); + REQUIRE(socketp != NULL && *socketp == NULL); + REQUIRE(type != isc_sockettype_fdwatch); + + result = allocate_socket(manager, type, &sock); + if (result != ISC_R_SUCCESS) + return (result); + + switch (sock->type) { + case isc_sockettype_udp: + sock->statsindex = + (pf == AF_INET) ? upd4statsindex : upd6statsindex; + break; + case isc_sockettype_tcp: + sock->statsindex = + (pf == AF_INET) ? tcp4statsindex : tcp6statsindex; + break; + case isc_sockettype_unix: + sock->statsindex = unixstatsindex; + break; + default: + INSIST(0); + } + + sock->pf = pf; + + result = opensocket(manager, sock, (isc__socket_t *)dup_socket); + if (result != ISC_R_SUCCESS) { + inc_stats(manager->stats, sock->statsindex[STATID_OPENFAIL]); + free_socket(&sock); + return (result); + } + + sock->common.methods = (isc_socketmethods_t *)&socketmethods; + sock->references = 1; + *socketp = (isc_socket_t *)sock; + + /* + * Note we don't have to lock the socket like we normally would because + * there are no external references to it yet. + */ + + lockid = FDLOCK_ID(sock->fd); + LOCK(&manager->fdlock[lockid]); + manager->fds[sock->fd] = sock; + manager->fdstate[sock->fd] = MANAGED; +#ifdef USE_DEVPOLL + INSIST(sock->manager->fdpollinfo[sock->fd].want_read == 0 && + sock->manager->fdpollinfo[sock->fd].want_write == 0); +#endif + UNLOCK(&manager->fdlock[lockid]); + + LOCK(&manager->lock); + ISC_LIST_APPEND(manager->socklist, sock, link); +#ifdef USE_SELECT + if (manager->maxfd < sock->fd) + manager->maxfd = sock->fd; +#endif + UNLOCK(&manager->lock); + + socket_log(sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_CREATED, dup_socket == NULL ? "dupped" : "created"); + + return (ISC_R_SUCCESS); +} + +/*% + * Create a new 'type' socket managed by 'manager'. Events + * will be posted to 'task' and when dispatched 'action' will be + * called with 'arg' as the arg value. The new socket is returned + * in 'socketp'. + */ +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_create(isc_socketmgr_t *manager0, int pf, isc_sockettype_t type, + isc_socket_t **socketp) +{ + return (socket_create(manager0, pf, type, socketp, NULL)); +} + +/*% + * Duplicate an existing socket. The new socket is returned + * in 'socketp'. + */ +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_dup(isc_socket_t *sock0, isc_socket_t **socketp) { + isc__socket_t *sock = (isc__socket_t *)sock0; + + REQUIRE(VALID_SOCKET(sock)); + REQUIRE(socketp != NULL && *socketp == NULL); + + return (socket_create((isc_socketmgr_t *) sock->manager, + sock->pf, sock->type, socketp, + sock0)); +} + +#ifdef BIND9 +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_open(isc_socket_t *sock0) { + isc_result_t result; + isc__socket_t *sock = (isc__socket_t *)sock0; + + REQUIRE(VALID_SOCKET(sock)); + + LOCK(&sock->lock); + REQUIRE(sock->references == 1); + REQUIRE(sock->type != isc_sockettype_fdwatch); + UNLOCK(&sock->lock); + /* + * We don't need to retain the lock hereafter, since no one else has + * this socket. + */ + REQUIRE(sock->fd == -1); + + result = opensocket(sock->manager, sock, NULL); + if (result != ISC_R_SUCCESS) + sock->fd = -1; + + if (result == ISC_R_SUCCESS) { + int lockid = FDLOCK_ID(sock->fd); + + LOCK(&sock->manager->fdlock[lockid]); + sock->manager->fds[sock->fd] = sock; + sock->manager->fdstate[sock->fd] = MANAGED; +#ifdef USE_DEVPOLL + INSIST(sock->manager->fdpollinfo[sock->fd].want_read == 0 && + sock->manager->fdpollinfo[sock->fd].want_write == 0); +#endif + UNLOCK(&sock->manager->fdlock[lockid]); + +#ifdef USE_SELECT + LOCK(&sock->manager->lock); + if (sock->manager->maxfd < sock->fd) + sock->manager->maxfd = sock->fd; + UNLOCK(&sock->manager->lock); +#endif + } + + return (result); +} +#endif /* BIND9 */ + +/* + * Create a new 'type' socket managed by 'manager'. Events + * will be posted to 'task' and when dispatched 'action' will be + * called with 'arg' as the arg value. The new socket is returned + * in 'socketp'. + */ +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_fdwatchcreate(isc_socketmgr_t *manager0, int fd, int flags, + isc_sockfdwatch_t callback, void *cbarg, + isc_task_t *task, isc_socket_t **socketp) +{ + isc__socketmgr_t *manager = (isc__socketmgr_t *)manager0; + isc__socket_t *sock = NULL; + isc_result_t result; + int lockid; + + REQUIRE(VALID_MANAGER(manager)); + REQUIRE(socketp != NULL && *socketp == NULL); + + result = allocate_socket(manager, isc_sockettype_fdwatch, &sock); + if (result != ISC_R_SUCCESS) + return (result); + + sock->fd = fd; + sock->fdwatcharg = cbarg; + sock->fdwatchcb = callback; + sock->fdwatchflags = flags; + sock->fdwatchtask = task; + sock->statsindex = fdwatchstatsindex; + + sock->common.methods = (isc_socketmethods_t *)&socketmethods; + sock->references = 1; + *socketp = (isc_socket_t *)sock; + + /* + * Note we don't have to lock the socket like we normally would because + * there are no external references to it yet. + */ + + lockid = FDLOCK_ID(sock->fd); + LOCK(&manager->fdlock[lockid]); + manager->fds[sock->fd] = sock; + manager->fdstate[sock->fd] = MANAGED; + UNLOCK(&manager->fdlock[lockid]); + + LOCK(&manager->lock); + ISC_LIST_APPEND(manager->socklist, sock, link); +#ifdef USE_SELECT + if (manager->maxfd < sock->fd) + manager->maxfd = sock->fd; +#endif + UNLOCK(&manager->lock); + + if (flags & ISC_SOCKFDWATCH_READ) + select_poke(sock->manager, sock->fd, SELECT_POKE_READ); + if (flags & ISC_SOCKFDWATCH_WRITE) + select_poke(sock->manager, sock->fd, SELECT_POKE_WRITE); + + socket_log(sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_CREATED, "fdwatch-created"); + + return (ISC_R_SUCCESS); +} + +/* + * Indicate to the manager that it should watch the socket again. + * This can be used to restart watching if the previous event handler + * didn't indicate there was more data to be processed. Primarily + * it is for writing but could be used for reading if desired + */ + +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_fdwatchpoke(isc_socket_t *sock0, int flags) +{ + isc__socket_t *sock = (isc__socket_t *)sock0; + + REQUIRE(VALID_SOCKET(sock)); + + /* + * We check both flags first to allow us to get the lock + * once but only if we need it. + */ + + if ((flags & (ISC_SOCKFDWATCH_READ | ISC_SOCKFDWATCH_WRITE)) != 0) { + LOCK(&sock->lock); + if (((flags & ISC_SOCKFDWATCH_READ) != 0) && + !sock->pending_recv) + select_poke(sock->manager, sock->fd, + SELECT_POKE_READ); + if (((flags & ISC_SOCKFDWATCH_WRITE) != 0) && + !sock->pending_send) + select_poke(sock->manager, sock->fd, + SELECT_POKE_WRITE); + UNLOCK(&sock->lock); + } + + socket_log(sock, NULL, TRACE, isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_POKED, "fdwatch-poked flags: %d", flags); + + return (ISC_R_SUCCESS); +} + +/* + * Attach to a socket. Caller must explicitly detach when it is done. + */ +ISC_SOCKETFUNC_SCOPE void +isc__socket_attach(isc_socket_t *sock0, isc_socket_t **socketp) { + isc__socket_t *sock = (isc__socket_t *)sock0; + + REQUIRE(VALID_SOCKET(sock)); + REQUIRE(socketp != NULL && *socketp == NULL); + + LOCK(&sock->lock); + sock->references++; + UNLOCK(&sock->lock); + + *socketp = (isc_socket_t *)sock; +} + +/* + * Dereference a socket. If this is the last reference to it, clean things + * up by destroying the socket. + */ +ISC_SOCKETFUNC_SCOPE void +isc__socket_detach(isc_socket_t **socketp) { + isc__socket_t *sock; + isc_boolean_t kill_socket = ISC_FALSE; + + REQUIRE(socketp != NULL); + sock = (isc__socket_t *)*socketp; + REQUIRE(VALID_SOCKET(sock)); + + LOCK(&sock->lock); + REQUIRE(sock->references > 0); + sock->references--; + if (sock->references == 0) + kill_socket = ISC_TRUE; + UNLOCK(&sock->lock); + + if (kill_socket) + destroy(&sock); + + *socketp = NULL; +} + +#ifdef BIND9 +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_close(isc_socket_t *sock0) { + isc__socket_t *sock = (isc__socket_t *)sock0; + int fd; + isc__socketmgr_t *manager; + + fflush(stdout); + REQUIRE(VALID_SOCKET(sock)); + + LOCK(&sock->lock); + + REQUIRE(sock->references == 1); + REQUIRE(sock->type != isc_sockettype_fdwatch); + REQUIRE(sock->fd >= 0 && sock->fd < (int)sock->manager->maxsocks); + + INSIST(!sock->connecting); + INSIST(!sock->pending_recv); + INSIST(!sock->pending_send); + INSIST(!sock->pending_accept); + INSIST(ISC_LIST_EMPTY(sock->recv_list)); + INSIST(ISC_LIST_EMPTY(sock->send_list)); + INSIST(ISC_LIST_EMPTY(sock->accept_list)); + INSIST(sock->connect_ev == NULL); + + manager = sock->manager; + fd = sock->fd; + sock->fd = -1; + sock->dupped = 0; + memset(sock->name, 0, sizeof(sock->name)); + sock->tag = NULL; + sock->listener = 0; + sock->connected = 0; + sock->connecting = 0; + sock->bound = 0; + isc_sockaddr_any(&sock->peer_address); + + UNLOCK(&sock->lock); + + closesocket(manager, sock, fd); + + return (ISC_R_SUCCESS); +} +#endif /* BIND9 */ + +/* + * I/O is possible on a given socket. Schedule an event to this task that + * will call an internal function to do the I/O. This will charge the + * task with the I/O operation and let our select loop handler get back + * to doing something real as fast as possible. + * + * The socket and manager must be locked before calling this function. + */ +static void +dispatch_recv(isc__socket_t *sock) { + intev_t *iev; + isc_socketevent_t *ev; + isc_task_t *sender; + + INSIST(!sock->pending_recv); + + if (sock->type != isc_sockettype_fdwatch) { + ev = ISC_LIST_HEAD(sock->recv_list); + if (ev == NULL) + return; + socket_log(sock, NULL, EVENT, NULL, 0, 0, + "dispatch_recv: event %p -> task %p", + ev, ev->ev_sender); + sender = ev->ev_sender; + } else { + sender = sock->fdwatchtask; + } + + sock->pending_recv = 1; + iev = &sock->readable_ev; + + sock->references++; + iev->ev_sender = sock; + if (sock->type == isc_sockettype_fdwatch) + iev->ev_action = internal_fdwatch_read; + else + iev->ev_action = internal_recv; + iev->ev_arg = sock; + + isc_task_send(sender, (isc_event_t **)&iev); +} + +static void +dispatch_send(isc__socket_t *sock) { + intev_t *iev; + isc_socketevent_t *ev; + isc_task_t *sender; + + INSIST(!sock->pending_send); + + if (sock->type != isc_sockettype_fdwatch) { + ev = ISC_LIST_HEAD(sock->send_list); + if (ev == NULL) + return; + socket_log(sock, NULL, EVENT, NULL, 0, 0, + "dispatch_send: event %p -> task %p", + ev, ev->ev_sender); + sender = ev->ev_sender; + } else { + sender = sock->fdwatchtask; + } + + sock->pending_send = 1; + iev = &sock->writable_ev; + + sock->references++; + iev->ev_sender = sock; + if (sock->type == isc_sockettype_fdwatch) + iev->ev_action = internal_fdwatch_write; + else + iev->ev_action = internal_send; + iev->ev_arg = sock; + + isc_task_send(sender, (isc_event_t **)&iev); +} + +/* + * Dispatch an internal accept event. + */ +static void +dispatch_accept(isc__socket_t *sock) { + intev_t *iev; + isc_socket_newconnev_t *ev; + + INSIST(!sock->pending_accept); + + /* + * Are there any done events left, or were they all canceled + * before the manager got the socket lock? + */ + ev = ISC_LIST_HEAD(sock->accept_list); + if (ev == NULL) + return; + + sock->pending_accept = 1; + iev = &sock->readable_ev; + + sock->references++; /* keep socket around for this internal event */ + iev->ev_sender = sock; + iev->ev_action = internal_accept; + iev->ev_arg = sock; + + isc_task_send(ev->ev_sender, (isc_event_t **)&iev); +} + +static void +dispatch_connect(isc__socket_t *sock) { + intev_t *iev; + isc_socket_connev_t *ev; + + iev = &sock->writable_ev; + + ev = sock->connect_ev; + INSIST(ev != NULL); /* XXX */ + + INSIST(sock->connecting); + + sock->references++; /* keep socket around for this internal event */ + iev->ev_sender = sock; + iev->ev_action = internal_connect; + iev->ev_arg = sock; + + isc_task_send(ev->ev_sender, (isc_event_t **)&iev); +} + +/* + * Dequeue an item off the given socket's read queue, set the result code + * in the done event to the one provided, and send it to the task it was + * destined for. + * + * If the event to be sent is on a list, remove it before sending. If + * asked to, send and detach from the socket as well. + * + * Caller must have the socket locked if the event is attached to the socket. + */ +static void +send_recvdone_event(isc__socket_t *sock, isc_socketevent_t **dev) { + isc_task_t *task; + + task = (*dev)->ev_sender; + + (*dev)->ev_sender = sock; + + if (ISC_LINK_LINKED(*dev, ev_link)) + ISC_LIST_DEQUEUE(sock->recv_list, *dev, ev_link); + + if (((*dev)->attributes & ISC_SOCKEVENTATTR_ATTACHED) + == ISC_SOCKEVENTATTR_ATTACHED) + isc_task_sendanddetach(&task, (isc_event_t **)dev); + else + isc_task_send(task, (isc_event_t **)dev); +} + +/* + * See comments for send_recvdone_event() above. + * + * Caller must have the socket locked if the event is attached to the socket. + */ +static void +send_senddone_event(isc__socket_t *sock, isc_socketevent_t **dev) { + isc_task_t *task; + + INSIST(dev != NULL && *dev != NULL); + + task = (*dev)->ev_sender; + (*dev)->ev_sender = sock; + + if (ISC_LINK_LINKED(*dev, ev_link)) + ISC_LIST_DEQUEUE(sock->send_list, *dev, ev_link); + + if (((*dev)->attributes & ISC_SOCKEVENTATTR_ATTACHED) + == ISC_SOCKEVENTATTR_ATTACHED) + isc_task_sendanddetach(&task, (isc_event_t **)dev); + else + isc_task_send(task, (isc_event_t **)dev); +} + +/* + * Call accept() on a socket, to get the new file descriptor. The listen + * socket is used as a prototype to create a new isc_socket_t. The new + * socket has one outstanding reference. The task receiving the event + * will be detached from just after the event is delivered. + * + * On entry to this function, the event delivered is the internal + * readable event, and the first item on the accept_list should be + * the done event we want to send. If the list is empty, this is a no-op, + * so just unlock and return. + */ +static void +internal_accept(isc_task_t *me, isc_event_t *ev) { + isc__socket_t *sock; + isc__socketmgr_t *manager; + isc_socket_newconnev_t *dev; + isc_task_t *task; + ISC_SOCKADDR_LEN_T addrlen; + int fd; + isc_result_t result = ISC_R_SUCCESS; + char strbuf[ISC_STRERRORSIZE]; + const char *err = "accept"; + + UNUSED(me); + + sock = ev->ev_sender; + INSIST(VALID_SOCKET(sock)); + + LOCK(&sock->lock); + socket_log(sock, NULL, TRACE, + isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK, + "internal_accept called, locked socket"); + + manager = sock->manager; + INSIST(VALID_MANAGER(manager)); + + INSIST(sock->listener); + INSIST(sock->pending_accept == 1); + sock->pending_accept = 0; + + INSIST(sock->references > 0); + sock->references--; /* the internal event is done with this socket */ + if (sock->references == 0) { + UNLOCK(&sock->lock); + destroy(&sock); + return; + } + + /* + * Get the first item off the accept list. + * If it is empty, unlock the socket and return. + */ + dev = ISC_LIST_HEAD(sock->accept_list); + if (dev == NULL) { + UNLOCK(&sock->lock); + return; + } + + /* + * Try to accept the new connection. If the accept fails with + * EAGAIN or EINTR, simply poke the watcher to watch this socket + * again. Also ignore ECONNRESET, which has been reported to + * be spuriously returned on Linux 2.2.19 although it is not + * a documented error for accept(). ECONNABORTED has been + * reported for Solaris 8. The rest are thrown in not because + * we have seen them but because they are ignored by other + * daemons such as BIND 8 and Apache. + */ + + addrlen = sizeof(NEWCONNSOCK(dev)->peer_address.type); + memset(&NEWCONNSOCK(dev)->peer_address.type, 0, addrlen); + fd = accept(sock->fd, &NEWCONNSOCK(dev)->peer_address.type.sa, + (void *)&addrlen); + +#ifdef F_DUPFD + /* + * Leave a space for stdio to work in. + */ + if (fd >= 0 && fd < 20) { + int new, tmp; + new = fcntl(fd, F_DUPFD, 20); + tmp = errno; + (void)close(fd); + errno = tmp; + fd = new; + err = "accept/fcntl"; + } +#endif + + if (fd < 0) { + if (SOFT_ERROR(errno)) + goto soft_error; + switch (errno) { + case ENFILE: + case EMFILE: + isc_log_iwrite(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR, + isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_TOOMANYFDS, + "%s: too many open file descriptors", + err); + goto soft_error; + + case ENOBUFS: + case ENOMEM: + case ECONNRESET: + case ECONNABORTED: + case EHOSTUNREACH: + case EHOSTDOWN: + case ENETUNREACH: + case ENETDOWN: + case ECONNREFUSED: +#ifdef EPROTO + case EPROTO: +#endif +#ifdef ENONET + case ENONET: +#endif + goto soft_error; + default: + break; + } + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "internal_accept: %s() %s: %s", err, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, + "failed"), + strbuf); + fd = -1; + result = ISC_R_UNEXPECTED; + } else { + if (addrlen == 0U) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "internal_accept(): " + "accept() failed to return " + "remote address"); + + (void)close(fd); + goto soft_error; + } else if (NEWCONNSOCK(dev)->peer_address.type.sa.sa_family != + sock->pf) + { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "internal_accept(): " + "accept() returned peer address " + "family %u (expected %u)", + NEWCONNSOCK(dev)->peer_address. + type.sa.sa_family, + sock->pf); + (void)close(fd); + goto soft_error; + } else if (fd >= (int)manager->maxsocks) { + isc_log_iwrite(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR, + isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_TOOMANYFDS, + "accept: " + "file descriptor exceeds limit (%d/%u)", + fd, manager->maxsocks); + (void)close(fd); + goto soft_error; + } + } + + if (fd != -1) { + NEWCONNSOCK(dev)->peer_address.length = addrlen; + NEWCONNSOCK(dev)->pf = sock->pf; + } + + /* + * Pull off the done event. + */ + ISC_LIST_UNLINK(sock->accept_list, dev, ev_link); + + /* + * Poke watcher if there are more pending accepts. + */ + if (!ISC_LIST_EMPTY(sock->accept_list)) + select_poke(sock->manager, sock->fd, SELECT_POKE_ACCEPT); + + UNLOCK(&sock->lock); + + if (fd != -1) { + result = make_nonblock(fd); + if (result != ISC_R_SUCCESS) { + (void)close(fd); + fd = -1; + } + } + + /* + * -1 means the new socket didn't happen. + */ + if (fd != -1) { + int lockid = FDLOCK_ID(fd); + + LOCK(&manager->fdlock[lockid]); + manager->fds[fd] = NEWCONNSOCK(dev); + manager->fdstate[fd] = MANAGED; + UNLOCK(&manager->fdlock[lockid]); + + LOCK(&manager->lock); + ISC_LIST_APPEND(manager->socklist, NEWCONNSOCK(dev), link); + + NEWCONNSOCK(dev)->fd = fd; + NEWCONNSOCK(dev)->bound = 1; + NEWCONNSOCK(dev)->connected = 1; + + /* + * Save away the remote address + */ + dev->address = NEWCONNSOCK(dev)->peer_address; + +#ifdef USE_SELECT + if (manager->maxfd < fd) + manager->maxfd = fd; +#endif + + socket_log(sock, &NEWCONNSOCK(dev)->peer_address, CREATION, + isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTEDCXN, + "accepted connection, new socket %p", + dev->newsocket); + + UNLOCK(&manager->lock); + + inc_stats(manager->stats, sock->statsindex[STATID_ACCEPT]); + } else { + inc_stats(manager->stats, sock->statsindex[STATID_ACCEPTFAIL]); + NEWCONNSOCK(dev)->references--; + free_socket((isc__socket_t **)&dev->newsocket); + } + + /* + * Fill in the done event details and send it off. + */ + dev->result = result; + task = dev->ev_sender; + dev->ev_sender = sock; + + isc_task_sendanddetach(&task, ISC_EVENT_PTR(&dev)); + return; + + soft_error: + select_poke(sock->manager, sock->fd, SELECT_POKE_ACCEPT); + UNLOCK(&sock->lock); + + inc_stats(manager->stats, sock->statsindex[STATID_ACCEPTFAIL]); + return; +} + +static void +internal_recv(isc_task_t *me, isc_event_t *ev) { + isc_socketevent_t *dev; + isc__socket_t *sock; + + INSIST(ev->ev_type == ISC_SOCKEVENT_INTR); + + sock = ev->ev_sender; + INSIST(VALID_SOCKET(sock)); + + LOCK(&sock->lock); + socket_log(sock, NULL, IOEVENT, + isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALRECV, + "internal_recv: task %p got event %p", me, ev); + + INSIST(sock->pending_recv == 1); + sock->pending_recv = 0; + + INSIST(sock->references > 0); + sock->references--; /* the internal event is done with this socket */ + if (sock->references == 0) { + UNLOCK(&sock->lock); + destroy(&sock); + return; + } + + /* + * Try to do as much I/O as possible on this socket. There are no + * limits here, currently. + */ + dev = ISC_LIST_HEAD(sock->recv_list); + while (dev != NULL) { + switch (doio_recv(sock, dev)) { + case DOIO_SOFT: + goto poke; + + case DOIO_EOF: + /* + * read of 0 means the remote end was closed. + * Run through the event queue and dispatch all + * the events with an EOF result code. + */ + do { + dev->result = ISC_R_EOF; + send_recvdone_event(sock, &dev); + dev = ISC_LIST_HEAD(sock->recv_list); + } while (dev != NULL); + goto poke; + + case DOIO_SUCCESS: + case DOIO_HARD: + send_recvdone_event(sock, &dev); + break; + } + + dev = ISC_LIST_HEAD(sock->recv_list); + } + + poke: + if (!ISC_LIST_EMPTY(sock->recv_list)) + select_poke(sock->manager, sock->fd, SELECT_POKE_READ); + + UNLOCK(&sock->lock); +} + +static void +internal_send(isc_task_t *me, isc_event_t *ev) { + isc_socketevent_t *dev; + isc__socket_t *sock; + + INSIST(ev->ev_type == ISC_SOCKEVENT_INTW); + + /* + * Find out what socket this is and lock it. + */ + sock = (isc__socket_t *)ev->ev_sender; + INSIST(VALID_SOCKET(sock)); + + LOCK(&sock->lock); + socket_log(sock, NULL, IOEVENT, + isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALSEND, + "internal_send: task %p got event %p", me, ev); + + INSIST(sock->pending_send == 1); + sock->pending_send = 0; + + INSIST(sock->references > 0); + sock->references--; /* the internal event is done with this socket */ + if (sock->references == 0) { + UNLOCK(&sock->lock); + destroy(&sock); + return; + } + + /* + * Try to do as much I/O as possible on this socket. There are no + * limits here, currently. + */ + dev = ISC_LIST_HEAD(sock->send_list); + while (dev != NULL) { + switch (doio_send(sock, dev)) { + case DOIO_SOFT: + goto poke; + + case DOIO_HARD: + case DOIO_SUCCESS: + send_senddone_event(sock, &dev); + break; + } + + dev = ISC_LIST_HEAD(sock->send_list); + } + + poke: + if (!ISC_LIST_EMPTY(sock->send_list)) + select_poke(sock->manager, sock->fd, SELECT_POKE_WRITE); + + UNLOCK(&sock->lock); +} + +static void +internal_fdwatch_write(isc_task_t *me, isc_event_t *ev) { + isc__socket_t *sock; + int more_data; + + INSIST(ev->ev_type == ISC_SOCKEVENT_INTW); + + /* + * Find out what socket this is and lock it. + */ + sock = (isc__socket_t *)ev->ev_sender; + INSIST(VALID_SOCKET(sock)); + + LOCK(&sock->lock); + socket_log(sock, NULL, IOEVENT, + isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALSEND, + "internal_fdwatch_write: task %p got event %p", me, ev); + + INSIST(sock->pending_send == 1); + + UNLOCK(&sock->lock); + more_data = (sock->fdwatchcb)(me, (isc_socket_t *)sock, + sock->fdwatcharg, ISC_SOCKFDWATCH_WRITE); + LOCK(&sock->lock); + + sock->pending_send = 0; + + INSIST(sock->references > 0); + sock->references--; /* the internal event is done with this socket */ + if (sock->references == 0) { + UNLOCK(&sock->lock); + destroy(&sock); + return; + } + + if (more_data) + select_poke(sock->manager, sock->fd, SELECT_POKE_WRITE); + + UNLOCK(&sock->lock); +} + +static void +internal_fdwatch_read(isc_task_t *me, isc_event_t *ev) { + isc__socket_t *sock; + int more_data; + + INSIST(ev->ev_type == ISC_SOCKEVENT_INTR); + + /* + * Find out what socket this is and lock it. + */ + sock = (isc__socket_t *)ev->ev_sender; + INSIST(VALID_SOCKET(sock)); + + LOCK(&sock->lock); + socket_log(sock, NULL, IOEVENT, + isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALRECV, + "internal_fdwatch_read: task %p got event %p", me, ev); + + INSIST(sock->pending_recv == 1); + + UNLOCK(&sock->lock); + more_data = (sock->fdwatchcb)(me, (isc_socket_t *)sock, + sock->fdwatcharg, ISC_SOCKFDWATCH_READ); + LOCK(&sock->lock); + + sock->pending_recv = 0; + + INSIST(sock->references > 0); + sock->references--; /* the internal event is done with this socket */ + if (sock->references == 0) { + UNLOCK(&sock->lock); + destroy(&sock); + return; + } + + if (more_data) + select_poke(sock->manager, sock->fd, SELECT_POKE_READ); + + UNLOCK(&sock->lock); +} + +/* + * Process read/writes on each fd here. Avoid locking + * and unlocking twice if both reads and writes are possible. + */ +static void +process_fd(isc__socketmgr_t *manager, int fd, isc_boolean_t readable, + isc_boolean_t writeable) +{ + isc__socket_t *sock; + isc_boolean_t unlock_sock; + isc_boolean_t unwatch_read = ISC_FALSE, unwatch_write = ISC_FALSE; + int lockid = FDLOCK_ID(fd); + + /* + * If the socket is going to be closed, don't do more I/O. + */ + LOCK(&manager->fdlock[lockid]); + if (manager->fdstate[fd] == CLOSE_PENDING) { + UNLOCK(&manager->fdlock[lockid]); + + (void)unwatch_fd(manager, fd, SELECT_POKE_READ); + (void)unwatch_fd(manager, fd, SELECT_POKE_WRITE); + return; + } + + sock = manager->fds[fd]; + unlock_sock = ISC_FALSE; + if (readable) { + if (sock == NULL) { + unwatch_read = ISC_TRUE; + goto check_write; + } + unlock_sock = ISC_TRUE; + LOCK(&sock->lock); + if (!SOCK_DEAD(sock)) { + if (sock->listener) + dispatch_accept(sock); + else + dispatch_recv(sock); + } + unwatch_read = ISC_TRUE; + } +check_write: + if (writeable) { + if (sock == NULL) { + unwatch_write = ISC_TRUE; + goto unlock_fd; + } + if (!unlock_sock) { + unlock_sock = ISC_TRUE; + LOCK(&sock->lock); + } + if (!SOCK_DEAD(sock)) { + if (sock->connecting) + dispatch_connect(sock); + else + dispatch_send(sock); + } + unwatch_write = ISC_TRUE; + } + if (unlock_sock) + UNLOCK(&sock->lock); + + unlock_fd: + UNLOCK(&manager->fdlock[lockid]); + if (unwatch_read) + (void)unwatch_fd(manager, fd, SELECT_POKE_READ); + if (unwatch_write) + (void)unwatch_fd(manager, fd, SELECT_POKE_WRITE); + +} + +#ifdef USE_KQUEUE +static isc_boolean_t +process_fds(isc__socketmgr_t *manager, struct kevent *events, int nevents) { + int i; + isc_boolean_t readable, writable; + isc_boolean_t done = ISC_FALSE; +#ifdef USE_WATCHER_THREAD + isc_boolean_t have_ctlevent = ISC_FALSE; +#endif + + if (nevents == manager->nevents) { + /* + * This is not an error, but something unexpected. If this + * happens, it may indicate the need for increasing + * ISC_SOCKET_MAXEVENTS. + */ + manager_log(manager, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, ISC_LOG_INFO, + "maximum number of FD events (%d) received", + nevents); + } + + for (i = 0; i < nevents; i++) { + REQUIRE(events[i].ident < manager->maxsocks); +#ifdef USE_WATCHER_THREAD + if (events[i].ident == (uintptr_t)manager->pipe_fds[0]) { + have_ctlevent = ISC_TRUE; + continue; + } +#endif + readable = ISC_TF(events[i].filter == EVFILT_READ); + writable = ISC_TF(events[i].filter == EVFILT_WRITE); + process_fd(manager, events[i].ident, readable, writable); + } + +#ifdef USE_WATCHER_THREAD + if (have_ctlevent) + done = process_ctlfd(manager); +#endif + + return (done); +} +#elif defined(USE_EPOLL) +static isc_boolean_t +process_fds(isc__socketmgr_t *manager, struct epoll_event *events, int nevents) +{ + int i; + isc_boolean_t done = ISC_FALSE; +#ifdef USE_WATCHER_THREAD + isc_boolean_t have_ctlevent = ISC_FALSE; +#endif + + if (nevents == manager->nevents) { + manager_log(manager, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, ISC_LOG_INFO, + "maximum number of FD events (%d) received", + nevents); + } + + for (i = 0; i < nevents; i++) { + REQUIRE(events[i].data.fd < (int)manager->maxsocks); +#ifdef USE_WATCHER_THREAD + if (events[i].data.fd == manager->pipe_fds[0]) { + have_ctlevent = ISC_TRUE; + continue; + } +#endif + if ((events[i].events & EPOLLERR) != 0 || + (events[i].events & EPOLLHUP) != 0) { + /* + * epoll does not set IN/OUT bits on an erroneous + * condition, so we need to try both anyway. This is a + * bit inefficient, but should be okay for such rare + * events. Note also that the read or write attempt + * won't block because we use non-blocking sockets. + */ + events[i].events |= (EPOLLIN | EPOLLOUT); + } + process_fd(manager, events[i].data.fd, + (events[i].events & EPOLLIN) != 0, + (events[i].events & EPOLLOUT) != 0); + } + +#ifdef USE_WATCHER_THREAD + if (have_ctlevent) + done = process_ctlfd(manager); +#endif + + return (done); +} +#elif defined(USE_DEVPOLL) +static isc_boolean_t +process_fds(isc__socketmgr_t *manager, struct pollfd *events, int nevents) { + int i; + isc_boolean_t done = ISC_FALSE; +#ifdef USE_WATCHER_THREAD + isc_boolean_t have_ctlevent = ISC_FALSE; +#endif + + if (nevents == manager->nevents) { + manager_log(manager, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, ISC_LOG_INFO, + "maximum number of FD events (%d) received", + nevents); + } + + for (i = 0; i < nevents; i++) { + REQUIRE(events[i].fd < (int)manager->maxsocks); +#ifdef USE_WATCHER_THREAD + if (events[i].fd == manager->pipe_fds[0]) { + have_ctlevent = ISC_TRUE; + continue; + } +#endif + process_fd(manager, events[i].fd, + (events[i].events & POLLIN) != 0, + (events[i].events & POLLOUT) != 0); + } + +#ifdef USE_WATCHER_THREAD + if (have_ctlevent) + done = process_ctlfd(manager); +#endif + + return (done); +} +#elif defined(USE_SELECT) +static void +process_fds(isc__socketmgr_t *manager, int maxfd, fd_set *readfds, + fd_set *writefds) +{ + int i; + + REQUIRE(maxfd <= (int)manager->maxsocks); + + for (i = 0; i < maxfd; i++) { +#ifdef USE_WATCHER_THREAD + if (i == manager->pipe_fds[0] || i == manager->pipe_fds[1]) + continue; +#endif /* USE_WATCHER_THREAD */ + process_fd(manager, i, FD_ISSET(i, readfds), + FD_ISSET(i, writefds)); + } +} +#endif + +#ifdef USE_WATCHER_THREAD +static isc_boolean_t +process_ctlfd(isc__socketmgr_t *manager) { + int msg, fd; + + for (;;) { + select_readmsg(manager, &fd, &msg); + + manager_log(manager, IOEVENT, + isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_WATCHERMSG, + "watcher got message %d " + "for socket %d"), msg, fd); + + /* + * Nothing to read? + */ + if (msg == SELECT_POKE_NOTHING) + break; + + /* + * Handle shutdown message. We really should + * jump out of this loop right away, but + * it doesn't matter if we have to do a little + * more work first. + */ + if (msg == SELECT_POKE_SHUTDOWN) + return (ISC_TRUE); + + /* + * This is a wakeup on a socket. Look + * at the event queue for both read and write, + * and decide if we need to watch on it now + * or not. + */ + wakeup_socket(manager, fd, msg); + } + + return (ISC_FALSE); +} + +/* + * This is the thread that will loop forever, always in a select or poll + * call. + * + * When select returns something to do, track down what thread gets to do + * this I/O and post the event to it. + */ +static isc_threadresult_t +watcher(void *uap) { + isc__socketmgr_t *manager = uap; + isc_boolean_t done; + int cc; +#ifdef USE_KQUEUE + const char *fnname = "kevent()"; +#elif defined (USE_EPOLL) + const char *fnname = "epoll_wait()"; +#elif defined(USE_DEVPOLL) + const char *fnname = "ioctl(DP_POLL)"; + struct dvpoll dvp; +#elif defined (USE_SELECT) + const char *fnname = "select()"; + int maxfd; + int ctlfd; +#endif + char strbuf[ISC_STRERRORSIZE]; +#ifdef ISC_SOCKET_USE_POLLWATCH + pollstate_t pollstate = poll_idle; +#endif + +#if defined (USE_SELECT) + /* + * Get the control fd here. This will never change. + */ + ctlfd = manager->pipe_fds[0]; +#endif + done = ISC_FALSE; + while (!done) { + do { +#ifdef USE_KQUEUE + cc = kevent(manager->kqueue_fd, NULL, 0, + manager->events, manager->nevents, NULL); +#elif defined(USE_EPOLL) + cc = epoll_wait(manager->epoll_fd, manager->events, + manager->nevents, -1); +#elif defined(USE_DEVPOLL) + dvp.dp_fds = manager->events; + dvp.dp_nfds = manager->nevents; +#ifndef ISC_SOCKET_USE_POLLWATCH + dvp.dp_timeout = -1; +#else + if (pollstate == poll_idle) + dvp.dp_timeout = -1; + else + dvp.dp_timeout = ISC_SOCKET_POLLWATCH_TIMEOUT; +#endif /* ISC_SOCKET_USE_POLLWATCH */ + cc = ioctl(manager->devpoll_fd, DP_POLL, &dvp); +#elif defined(USE_SELECT) + LOCK(&manager->lock); + memcpy(manager->read_fds_copy, manager->read_fds, + manager->fd_bufsize); + memcpy(manager->write_fds_copy, manager->write_fds, + manager->fd_bufsize); + maxfd = manager->maxfd + 1; + UNLOCK(&manager->lock); + + cc = select(maxfd, manager->read_fds_copy, + manager->write_fds_copy, NULL, NULL); +#endif /* USE_KQUEUE */ + + if (cc < 0 && !SOFT_ERROR(errno)) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + FATAL_ERROR(__FILE__, __LINE__, + "%s %s: %s", fnname, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, + "failed"), strbuf); + } + +#if defined(USE_DEVPOLL) && defined(ISC_SOCKET_USE_POLLWATCH) + if (cc == 0) { + if (pollstate == poll_active) + pollstate = poll_checking; + else if (pollstate == poll_checking) + pollstate = poll_idle; + } else if (cc > 0) { + if (pollstate == poll_checking) { + /* + * XXX: We'd like to use a more + * verbose log level as it's actually an + * unexpected event, but the kernel bug + * reportedly happens pretty frequently + * (and it can also be a false positive) + * so it would be just too noisy. + */ + manager_log(manager, + ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, + ISC_LOG_DEBUG(1), + "unexpected POLL timeout"); + } + pollstate = poll_active; + } +#endif + } while (cc < 0); + +#if defined(USE_KQUEUE) || defined (USE_EPOLL) || defined (USE_DEVPOLL) + done = process_fds(manager, manager->events, cc); +#elif defined(USE_SELECT) + process_fds(manager, maxfd, manager->read_fds_copy, + manager->write_fds_copy); + + /* + * Process reads on internal, control fd. + */ + if (FD_ISSET(ctlfd, manager->read_fds_copy)) + done = process_ctlfd(manager); +#endif + } + + manager_log(manager, TRACE, "%s", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_EXITING, "watcher exiting")); + + return ((isc_threadresult_t)0); +} +#endif /* USE_WATCHER_THREAD */ + +#ifdef BIND9 +ISC_SOCKETFUNC_SCOPE void +isc__socketmgr_setreserved(isc_socketmgr_t *manager0, isc_uint32_t reserved) { + isc__socketmgr_t *manager = (isc__socketmgr_t *)manager0; + + REQUIRE(VALID_MANAGER(manager)); + + manager->reserved = reserved; +} + +ISC_SOCKETFUNC_SCOPE void +isc___socketmgr_maxudp(isc_socketmgr_t *manager0, int maxudp) { + isc__socketmgr_t *manager = (isc__socketmgr_t *)manager0; + + REQUIRE(VALID_MANAGER(manager)); + + manager->maxudp = maxudp; +} +#endif /* BIND9 */ + +/* + * Create a new socket manager. + */ + +static isc_result_t +setup_watcher(isc_mem_t *mctx, isc__socketmgr_t *manager) { + isc_result_t result; +#if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL) + char strbuf[ISC_STRERRORSIZE]; +#endif + +#ifdef USE_KQUEUE + manager->nevents = ISC_SOCKET_MAXEVENTS; + manager->events = isc_mem_get(mctx, sizeof(struct kevent) * + manager->nevents); + if (manager->events == NULL) + return (ISC_R_NOMEMORY); + manager->kqueue_fd = kqueue(); + if (manager->kqueue_fd == -1) { + result = isc__errno2result(errno); + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "kqueue %s: %s", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed"), + strbuf); + isc_mem_put(mctx, manager->events, + sizeof(struct kevent) * manager->nevents); + return (result); + } + +#ifdef USE_WATCHER_THREAD + result = watch_fd(manager, manager->pipe_fds[0], SELECT_POKE_READ); + if (result != ISC_R_SUCCESS) { + close(manager->kqueue_fd); + isc_mem_put(mctx, manager->events, + sizeof(struct kevent) * manager->nevents); + return (result); + } +#endif /* USE_WATCHER_THREAD */ +#elif defined(USE_EPOLL) + manager->nevents = ISC_SOCKET_MAXEVENTS; + manager->events = isc_mem_get(mctx, sizeof(struct epoll_event) * + manager->nevents); + if (manager->events == NULL) + return (ISC_R_NOMEMORY); + manager->epoll_fd = epoll_create(manager->nevents); + if (manager->epoll_fd == -1) { + result = isc__errno2result(errno); + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "epoll_create %s: %s", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed"), + strbuf); + isc_mem_put(mctx, manager->events, + sizeof(struct epoll_event) * manager->nevents); + return (result); + } +#ifdef USE_WATCHER_THREAD + result = watch_fd(manager, manager->pipe_fds[0], SELECT_POKE_READ); + if (result != ISC_R_SUCCESS) { + close(manager->epoll_fd); + isc_mem_put(mctx, manager->events, + sizeof(struct epoll_event) * manager->nevents); + return (result); + } +#endif /* USE_WATCHER_THREAD */ +#elif defined(USE_DEVPOLL) + /* + * XXXJT: /dev/poll seems to reject large numbers of events, + * so we should be careful about redefining ISC_SOCKET_MAXEVENTS. + */ + manager->nevents = ISC_SOCKET_MAXEVENTS; + manager->events = isc_mem_get(mctx, sizeof(struct pollfd) * + manager->nevents); + if (manager->events == NULL) + return (ISC_R_NOMEMORY); + /* + * Note: fdpollinfo should be able to support all possible FDs, so + * it must have maxsocks entries (not nevents). + */ + manager->fdpollinfo = isc_mem_get(mctx, sizeof(pollinfo_t) * + manager->maxsocks); + if (manager->fdpollinfo == NULL) { + isc_mem_put(mctx, manager->events, + sizeof(struct pollfd) * manager->nevents); + return (ISC_R_NOMEMORY); + } + memset(manager->fdpollinfo, 0, sizeof(pollinfo_t) * manager->maxsocks); + manager->devpoll_fd = open("/dev/poll", O_RDWR); + if (manager->devpoll_fd == -1) { + result = isc__errno2result(errno); + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "open(/dev/poll) %s: %s", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed"), + strbuf); + isc_mem_put(mctx, manager->events, + sizeof(struct pollfd) * manager->nevents); + isc_mem_put(mctx, manager->fdpollinfo, + sizeof(pollinfo_t) * manager->maxsocks); + return (result); + } +#ifdef USE_WATCHER_THREAD + result = watch_fd(manager, manager->pipe_fds[0], SELECT_POKE_READ); + if (result != ISC_R_SUCCESS) { + close(manager->devpoll_fd); + isc_mem_put(mctx, manager->events, + sizeof(struct pollfd) * manager->nevents); + isc_mem_put(mctx, manager->fdpollinfo, + sizeof(pollinfo_t) * manager->maxsocks); + return (result); + } +#endif /* USE_WATCHER_THREAD */ +#elif defined(USE_SELECT) + UNUSED(result); + +#if ISC_SOCKET_MAXSOCKETS > FD_SETSIZE + /* + * Note: this code should also cover the case of MAXSOCKETS <= + * FD_SETSIZE, but we separate the cases to avoid possible portability + * issues regarding howmany() and the actual representation of fd_set. + */ + manager->fd_bufsize = howmany(manager->maxsocks, NFDBITS) * + sizeof(fd_mask); +#else + manager->fd_bufsize = sizeof(fd_set); +#endif + + manager->read_fds = NULL; + manager->read_fds_copy = NULL; + manager->write_fds = NULL; + manager->write_fds_copy = NULL; + + manager->read_fds = isc_mem_get(mctx, manager->fd_bufsize); + if (manager->read_fds != NULL) + manager->read_fds_copy = isc_mem_get(mctx, manager->fd_bufsize); + if (manager->read_fds_copy != NULL) + manager->write_fds = isc_mem_get(mctx, manager->fd_bufsize); + if (manager->write_fds != NULL) { + manager->write_fds_copy = isc_mem_get(mctx, + manager->fd_bufsize); + } + if (manager->write_fds_copy == NULL) { + if (manager->write_fds != NULL) { + isc_mem_put(mctx, manager->write_fds, + manager->fd_bufsize); + } + if (manager->read_fds_copy != NULL) { + isc_mem_put(mctx, manager->read_fds_copy, + manager->fd_bufsize); + } + if (manager->read_fds != NULL) { + isc_mem_put(mctx, manager->read_fds, + manager->fd_bufsize); + } + return (ISC_R_NOMEMORY); + } + memset(manager->read_fds, 0, manager->fd_bufsize); + memset(manager->write_fds, 0, manager->fd_bufsize); + +#ifdef USE_WATCHER_THREAD + (void)watch_fd(manager, manager->pipe_fds[0], SELECT_POKE_READ); + manager->maxfd = manager->pipe_fds[0]; +#else /* USE_WATCHER_THREAD */ + manager->maxfd = 0; +#endif /* USE_WATCHER_THREAD */ +#endif /* USE_KQUEUE */ + + return (ISC_R_SUCCESS); +} + +static void +cleanup_watcher(isc_mem_t *mctx, isc__socketmgr_t *manager) { +#ifdef USE_WATCHER_THREAD + isc_result_t result; + + result = unwatch_fd(manager, manager->pipe_fds[0], SELECT_POKE_READ); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "epoll_ctl(DEL) %s", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed")); + } +#endif /* USE_WATCHER_THREAD */ + +#ifdef USE_KQUEUE + close(manager->kqueue_fd); + isc_mem_put(mctx, manager->events, + sizeof(struct kevent) * manager->nevents); +#elif defined(USE_EPOLL) + close(manager->epoll_fd); + isc_mem_put(mctx, manager->events, + sizeof(struct epoll_event) * manager->nevents); +#elif defined(USE_DEVPOLL) + close(manager->devpoll_fd); + isc_mem_put(mctx, manager->events, + sizeof(struct pollfd) * manager->nevents); + isc_mem_put(mctx, manager->fdpollinfo, + sizeof(pollinfo_t) * manager->maxsocks); +#elif defined(USE_SELECT) + if (manager->read_fds != NULL) + isc_mem_put(mctx, manager->read_fds, manager->fd_bufsize); + if (manager->read_fds_copy != NULL) + isc_mem_put(mctx, manager->read_fds_copy, manager->fd_bufsize); + if (manager->write_fds != NULL) + isc_mem_put(mctx, manager->write_fds, manager->fd_bufsize); + if (manager->write_fds_copy != NULL) + isc_mem_put(mctx, manager->write_fds_copy, manager->fd_bufsize); +#endif /* USE_KQUEUE */ +} + +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp) { + return (isc__socketmgr_create2(mctx, managerp, 0)); +} + +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp, + unsigned int maxsocks) +{ + int i; + isc__socketmgr_t *manager; +#ifdef USE_WATCHER_THREAD + char strbuf[ISC_STRERRORSIZE]; +#endif + isc_result_t result; + + REQUIRE(managerp != NULL && *managerp == NULL); + +#ifdef USE_SHARED_MANAGER + if (socketmgr != NULL) { + /* Don't allow maxsocks to be updated */ + if (maxsocks > 0 && socketmgr->maxsocks != maxsocks) + return (ISC_R_EXISTS); + + socketmgr->refs++; + *managerp = (isc_socketmgr_t *)socketmgr; + return (ISC_R_SUCCESS); + } +#endif /* USE_SHARED_MANAGER */ + + if (maxsocks == 0) + maxsocks = ISC_SOCKET_MAXSOCKETS; + + manager = isc_mem_get(mctx, sizeof(*manager)); + if (manager == NULL) + return (ISC_R_NOMEMORY); + + /* zero-clear so that necessary cleanup on failure will be easy */ + memset(manager, 0, sizeof(*manager)); + manager->maxsocks = maxsocks; + manager->reserved = 0; + manager->maxudp = 0; + manager->fds = isc_mem_get(mctx, + manager->maxsocks * sizeof(isc__socket_t *)); + if (manager->fds == NULL) { + result = ISC_R_NOMEMORY; + goto free_manager; + } + manager->fdstate = isc_mem_get(mctx, manager->maxsocks * sizeof(int)); + if (manager->fdstate == NULL) { + result = ISC_R_NOMEMORY; + goto free_manager; + } + manager->stats = NULL; + + manager->common.methods = &socketmgrmethods; + manager->common.magic = ISCAPI_SOCKETMGR_MAGIC; + manager->common.impmagic = SOCKET_MANAGER_MAGIC; + manager->mctx = NULL; + memset(manager->fds, 0, manager->maxsocks * sizeof(isc_socket_t *)); + ISC_LIST_INIT(manager->socklist); + result = isc_mutex_init(&manager->lock); + if (result != ISC_R_SUCCESS) + goto free_manager; + manager->fdlock = isc_mem_get(mctx, FDLOCK_COUNT * sizeof(isc_mutex_t)); + if (manager->fdlock == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup_lock; + } + for (i = 0; i < FDLOCK_COUNT; i++) { + result = isc_mutex_init(&manager->fdlock[i]); + if (result != ISC_R_SUCCESS) { + while (--i >= 0) + DESTROYLOCK(&manager->fdlock[i]); + isc_mem_put(mctx, manager->fdlock, + FDLOCK_COUNT * sizeof(isc_mutex_t)); + manager->fdlock = NULL; + goto cleanup_lock; + } + } + +#ifdef USE_WATCHER_THREAD + if (isc_condition_init(&manager->shutdown_ok) != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_condition_init() %s", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed")); + result = ISC_R_UNEXPECTED; + goto cleanup_lock; + } + + /* + * Create the special fds that will be used to wake up the + * select/poll loop when something internal needs to be done. + */ + if (pipe(manager->pipe_fds) != 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "pipe() %s: %s", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed"), + strbuf); + result = ISC_R_UNEXPECTED; + goto cleanup_condition; + } + + RUNTIME_CHECK(make_nonblock(manager->pipe_fds[0]) == ISC_R_SUCCESS); +#if 0 + RUNTIME_CHECK(make_nonblock(manager->pipe_fds[1]) == ISC_R_SUCCESS); +#endif +#endif /* USE_WATCHER_THREAD */ + +#ifdef USE_SHARED_MANAGER + manager->refs = 1; +#endif /* USE_SHARED_MANAGER */ + + /* + * Set up initial state for the select loop + */ + result = setup_watcher(mctx, manager); + if (result != ISC_R_SUCCESS) + goto cleanup; + memset(manager->fdstate, 0, manager->maxsocks * sizeof(int)); +#ifdef USE_WATCHER_THREAD + /* + * Start up the select/poll thread. + */ + if (isc_thread_create(watcher, manager, &manager->watcher) != + ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_thread_create() %s", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed")); + cleanup_watcher(mctx, manager); + result = ISC_R_UNEXPECTED; + goto cleanup; + } +#endif /* USE_WATCHER_THREAD */ + isc_mem_attach(mctx, &manager->mctx); + +#ifdef USE_SHARED_MANAGER + socketmgr = manager; +#endif /* USE_SHARED_MANAGER */ + *managerp = (isc_socketmgr_t *)manager; + + return (ISC_R_SUCCESS); + +cleanup: +#ifdef USE_WATCHER_THREAD + (void)close(manager->pipe_fds[0]); + (void)close(manager->pipe_fds[1]); +#endif /* USE_WATCHER_THREAD */ + +#ifdef USE_WATCHER_THREAD +cleanup_condition: + (void)isc_condition_destroy(&manager->shutdown_ok); +#endif /* USE_WATCHER_THREAD */ + + +cleanup_lock: + if (manager->fdlock != NULL) { + for (i = 0; i < FDLOCK_COUNT; i++) + DESTROYLOCK(&manager->fdlock[i]); + } + DESTROYLOCK(&manager->lock); + +free_manager: + if (manager->fdlock != NULL) { + isc_mem_put(mctx, manager->fdlock, + FDLOCK_COUNT * sizeof(isc_mutex_t)); + } + if (manager->fdstate != NULL) { + isc_mem_put(mctx, manager->fdstate, + manager->maxsocks * sizeof(int)); + } + if (manager->fds != NULL) { + isc_mem_put(mctx, manager->fds, + manager->maxsocks * sizeof(isc_socket_t *)); + } + isc_mem_put(mctx, manager, sizeof(*manager)); + + return (result); +} + +#ifdef BIND9 +isc_result_t +isc__socketmgr_getmaxsockets(isc_socketmgr_t *manager0, unsigned int *nsockp) { + isc__socketmgr_t *manager = (isc__socketmgr_t *)manager0; + REQUIRE(VALID_MANAGER(manager)); + REQUIRE(nsockp != NULL); + + *nsockp = manager->maxsocks; + + return (ISC_R_SUCCESS); +} + +void +isc__socketmgr_setstats(isc_socketmgr_t *manager0, isc_stats_t *stats) { + isc__socketmgr_t *manager = (isc__socketmgr_t *)manager0; + + REQUIRE(VALID_MANAGER(manager)); + REQUIRE(ISC_LIST_EMPTY(manager->socklist)); + REQUIRE(manager->stats == NULL); + REQUIRE(isc_stats_ncounters(stats) == isc_sockstatscounter_max); + + isc_stats_attach(stats, &manager->stats); +} +#endif + +ISC_SOCKETFUNC_SCOPE void +isc__socketmgr_destroy(isc_socketmgr_t **managerp) { + isc__socketmgr_t *manager; + int i; + isc_mem_t *mctx; + + /* + * Destroy a socket manager. + */ + + REQUIRE(managerp != NULL); + manager = (isc__socketmgr_t *)*managerp; + REQUIRE(VALID_MANAGER(manager)); + +#ifdef USE_SHARED_MANAGER + manager->refs--; + if (manager->refs > 0) { + *managerp = NULL; + return; + } + socketmgr = NULL; +#endif /* USE_SHARED_MANAGER */ + + LOCK(&manager->lock); + + /* + * Wait for all sockets to be destroyed. + */ + while (!ISC_LIST_EMPTY(manager->socklist)) { +#ifdef USE_WATCHER_THREAD + manager_log(manager, CREATION, "%s", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_SOCKETSREMAIN, + "sockets exist")); + WAIT(&manager->shutdown_ok, &manager->lock); +#else /* USE_WATCHER_THREAD */ + UNLOCK(&manager->lock); + isc__taskmgr_dispatch(NULL); + LOCK(&manager->lock); +#endif /* USE_WATCHER_THREAD */ + } + + UNLOCK(&manager->lock); + + /* + * Here, poke our select/poll thread. Do this by closing the write + * half of the pipe, which will send EOF to the read half. + * This is currently a no-op in the non-threaded case. + */ + select_poke(manager, 0, SELECT_POKE_SHUTDOWN); + +#ifdef USE_WATCHER_THREAD + /* + * Wait for thread to exit. + */ + if (isc_thread_join(manager->watcher, NULL) != ISC_R_SUCCESS) + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_thread_join() %s", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed")); +#endif /* USE_WATCHER_THREAD */ + + /* + * Clean up. + */ + cleanup_watcher(manager->mctx, manager); + +#ifdef USE_WATCHER_THREAD + (void)close(manager->pipe_fds[0]); + (void)close(manager->pipe_fds[1]); + (void)isc_condition_destroy(&manager->shutdown_ok); +#endif /* USE_WATCHER_THREAD */ + + for (i = 0; i < (int)manager->maxsocks; i++) + if (manager->fdstate[i] == CLOSE_PENDING) /* no need to lock */ + (void)close(i); + + isc_mem_put(manager->mctx, manager->fds, + manager->maxsocks * sizeof(isc__socket_t *)); + isc_mem_put(manager->mctx, manager->fdstate, + manager->maxsocks * sizeof(int)); + + if (manager->stats != NULL) + isc_stats_detach(&manager->stats); + + if (manager->fdlock != NULL) { + for (i = 0; i < FDLOCK_COUNT; i++) + DESTROYLOCK(&manager->fdlock[i]); + isc_mem_put(manager->mctx, manager->fdlock, + FDLOCK_COUNT * sizeof(isc_mutex_t)); + } + DESTROYLOCK(&manager->lock); + manager->common.magic = 0; + manager->common.impmagic = 0; + mctx= manager->mctx; + isc_mem_put(mctx, manager, sizeof(*manager)); + + isc_mem_detach(&mctx); + + *managerp = NULL; + +#ifdef USE_SHARED_MANAGER + socketmgr = NULL; +#endif +} + +static isc_result_t +socket_recv(isc__socket_t *sock, isc_socketevent_t *dev, isc_task_t *task, + unsigned int flags) +{ + int io_state; + isc_boolean_t have_lock = ISC_FALSE; + isc_task_t *ntask = NULL; + isc_result_t result = ISC_R_SUCCESS; + + dev->ev_sender = task; + + if (sock->type == isc_sockettype_udp) { + io_state = doio_recv(sock, dev); + } else { + LOCK(&sock->lock); + have_lock = ISC_TRUE; + + if (ISC_LIST_EMPTY(sock->recv_list)) + io_state = doio_recv(sock, dev); + else + io_state = DOIO_SOFT; + } + + switch (io_state) { + case DOIO_SOFT: + /* + * We couldn't read all or part of the request right now, so + * queue it. + * + * Attach to socket and to task + */ + isc_task_attach(task, &ntask); + dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED; + + if (!have_lock) { + LOCK(&sock->lock); + have_lock = ISC_TRUE; + } + + /* + * Enqueue the request. If the socket was previously not being + * watched, poke the watcher to start paying attention to it. + */ + if (ISC_LIST_EMPTY(sock->recv_list) && !sock->pending_recv) + select_poke(sock->manager, sock->fd, SELECT_POKE_READ); + ISC_LIST_ENQUEUE(sock->recv_list, dev, ev_link); + + socket_log(sock, NULL, EVENT, NULL, 0, 0, + "socket_recv: event %p -> task %p", + dev, ntask); + + if ((flags & ISC_SOCKFLAG_IMMEDIATE) != 0) + result = ISC_R_INPROGRESS; + break; + + case DOIO_EOF: + dev->result = ISC_R_EOF; + /* fallthrough */ + + case DOIO_HARD: + case DOIO_SUCCESS: + if ((flags & ISC_SOCKFLAG_IMMEDIATE) == 0) + send_recvdone_event(sock, &dev); + break; + } + + if (have_lock) + UNLOCK(&sock->lock); + + return (result); +} + +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_recvv(isc_socket_t *sock0, isc_bufferlist_t *buflist, + unsigned int minimum, isc_task_t *task, + isc_taskaction_t action, const void *arg) +{ + isc__socket_t *sock = (isc__socket_t *)sock0; + isc_socketevent_t *dev; + isc__socketmgr_t *manager; + unsigned int iocount; + isc_buffer_t *buffer; + + REQUIRE(VALID_SOCKET(sock)); + REQUIRE(buflist != NULL); + REQUIRE(!ISC_LIST_EMPTY(*buflist)); + REQUIRE(task != NULL); + REQUIRE(action != NULL); + + manager = sock->manager; + REQUIRE(VALID_MANAGER(manager)); + + iocount = isc_bufferlist_availablecount(buflist); + REQUIRE(iocount > 0); + + INSIST(sock->bound); + + dev = allocate_socketevent(sock, ISC_SOCKEVENT_RECVDONE, action, arg); + if (dev == NULL) + return (ISC_R_NOMEMORY); + + /* + * UDP sockets are always partial read + */ + if (sock->type == isc_sockettype_udp) + dev->minimum = 1; + else { + if (minimum == 0) + dev->minimum = iocount; + else + dev->minimum = minimum; + } + + /* + * Move each buffer from the passed in list to our internal one. + */ + buffer = ISC_LIST_HEAD(*buflist); + while (buffer != NULL) { + ISC_LIST_DEQUEUE(*buflist, buffer, link); + ISC_LIST_ENQUEUE(dev->bufferlist, buffer, link); + buffer = ISC_LIST_HEAD(*buflist); + } + + return (socket_recv(sock, dev, task, 0)); +} + +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_recv(isc_socket_t *sock0, isc_region_t *region, + unsigned int minimum, isc_task_t *task, + isc_taskaction_t action, const void *arg) +{ + isc__socket_t *sock = (isc__socket_t *)sock0; + isc_socketevent_t *dev; + isc__socketmgr_t *manager; + + REQUIRE(VALID_SOCKET(sock)); + REQUIRE(action != NULL); + + manager = sock->manager; + REQUIRE(VALID_MANAGER(manager)); + + INSIST(sock->bound); + + dev = allocate_socketevent(sock, ISC_SOCKEVENT_RECVDONE, action, arg); + if (dev == NULL) + return (ISC_R_NOMEMORY); + + return (isc__socket_recv2(sock0, region, minimum, task, dev, 0)); +} + +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_recv2(isc_socket_t *sock0, isc_region_t *region, + unsigned int minimum, isc_task_t *task, + isc_socketevent_t *event, unsigned int flags) +{ + isc__socket_t *sock = (isc__socket_t *)sock0; + + event->ev_sender = sock; + event->result = ISC_R_UNSET; + ISC_LIST_INIT(event->bufferlist); + event->region = *region; + event->n = 0; + event->offset = 0; + event->attributes = 0; + + /* + * UDP sockets are always partial read. + */ + if (sock->type == isc_sockettype_udp) + event->minimum = 1; + else { + if (minimum == 0) + event->minimum = region->length; + else + event->minimum = minimum; + } + + return (socket_recv(sock, event, task, flags)); +} + +static isc_result_t +socket_send(isc__socket_t *sock, isc_socketevent_t *dev, isc_task_t *task, + isc_sockaddr_t *address, struct in6_pktinfo *pktinfo, + unsigned int flags) +{ + int io_state; + isc_boolean_t have_lock = ISC_FALSE; + isc_task_t *ntask = NULL; + isc_result_t result = ISC_R_SUCCESS; + + dev->ev_sender = task; + + set_dev_address(address, sock, dev); + if (pktinfo != NULL) { + dev->attributes |= ISC_SOCKEVENTATTR_PKTINFO; + dev->pktinfo = *pktinfo; + + if (!isc_sockaddr_issitelocal(&dev->address) && + !isc_sockaddr_islinklocal(&dev->address)) { + socket_log(sock, NULL, TRACE, isc_msgcat, + ISC_MSGSET_SOCKET, ISC_MSG_PKTINFOPROVIDED, + "pktinfo structure provided, ifindex %u " + "(set to 0)", pktinfo->ipi6_ifindex); + + /* + * Set the pktinfo index to 0 here, to let the + * kernel decide what interface it should send on. + */ + dev->pktinfo.ipi6_ifindex = 0; + } + } + + if (sock->type == isc_sockettype_udp) + io_state = doio_send(sock, dev); + else { + LOCK(&sock->lock); + have_lock = ISC_TRUE; + + if (ISC_LIST_EMPTY(sock->send_list)) + io_state = doio_send(sock, dev); + else + io_state = DOIO_SOFT; + } + + switch (io_state) { + case DOIO_SOFT: + /* + * We couldn't send all or part of the request right now, so + * queue it unless ISC_SOCKFLAG_NORETRY is set. + */ + if ((flags & ISC_SOCKFLAG_NORETRY) == 0) { + isc_task_attach(task, &ntask); + dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED; + + if (!have_lock) { + LOCK(&sock->lock); + have_lock = ISC_TRUE; + } + + /* + * Enqueue the request. If the socket was previously + * not being watched, poke the watcher to start + * paying attention to it. + */ + if (ISC_LIST_EMPTY(sock->send_list) && + !sock->pending_send) + select_poke(sock->manager, sock->fd, + SELECT_POKE_WRITE); + ISC_LIST_ENQUEUE(sock->send_list, dev, ev_link); + + socket_log(sock, NULL, EVENT, NULL, 0, 0, + "socket_send: event %p -> task %p", + dev, ntask); + + if ((flags & ISC_SOCKFLAG_IMMEDIATE) != 0) + result = ISC_R_INPROGRESS; + break; + } + + case DOIO_HARD: + case DOIO_SUCCESS: + if ((flags & ISC_SOCKFLAG_IMMEDIATE) == 0) + send_senddone_event(sock, &dev); + break; + } + + if (have_lock) + UNLOCK(&sock->lock); + + return (result); +} + +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_send(isc_socket_t *sock, isc_region_t *region, + isc_task_t *task, isc_taskaction_t action, const void *arg) +{ + /* + * REQUIRE() checking is performed in isc_socket_sendto(). + */ + return (isc__socket_sendto(sock, region, task, action, arg, NULL, + NULL)); +} + +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_sendto(isc_socket_t *sock0, isc_region_t *region, + isc_task_t *task, isc_taskaction_t action, const void *arg, + isc_sockaddr_t *address, struct in6_pktinfo *pktinfo) +{ + isc__socket_t *sock = (isc__socket_t *)sock0; + isc_socketevent_t *dev; + isc__socketmgr_t *manager; + + REQUIRE(VALID_SOCKET(sock)); + REQUIRE(region != NULL); + REQUIRE(task != NULL); + REQUIRE(action != NULL); + + manager = sock->manager; + REQUIRE(VALID_MANAGER(manager)); + + INSIST(sock->bound); + + dev = allocate_socketevent(sock, ISC_SOCKEVENT_SENDDONE, action, arg); + if (dev == NULL) + return (ISC_R_NOMEMORY); + + dev->region = *region; + + return (socket_send(sock, dev, task, address, pktinfo, 0)); +} + +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_sendv(isc_socket_t *sock, isc_bufferlist_t *buflist, + isc_task_t *task, isc_taskaction_t action, const void *arg) +{ + return (isc__socket_sendtov(sock, buflist, task, action, arg, NULL, + NULL)); +} + +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_sendtov(isc_socket_t *sock0, isc_bufferlist_t *buflist, + isc_task_t *task, isc_taskaction_t action, const void *arg, + isc_sockaddr_t *address, struct in6_pktinfo *pktinfo) +{ + isc__socket_t *sock = (isc__socket_t *)sock0; + isc_socketevent_t *dev; + isc__socketmgr_t *manager; + unsigned int iocount; + isc_buffer_t *buffer; + + REQUIRE(VALID_SOCKET(sock)); + REQUIRE(buflist != NULL); + REQUIRE(!ISC_LIST_EMPTY(*buflist)); + REQUIRE(task != NULL); + REQUIRE(action != NULL); + + manager = sock->manager; + REQUIRE(VALID_MANAGER(manager)); + + iocount = isc_bufferlist_usedcount(buflist); + REQUIRE(iocount > 0); + + dev = allocate_socketevent(sock, ISC_SOCKEVENT_SENDDONE, action, arg); + if (dev == NULL) + return (ISC_R_NOMEMORY); + + /* + * Move each buffer from the passed in list to our internal one. + */ + buffer = ISC_LIST_HEAD(*buflist); + while (buffer != NULL) { + ISC_LIST_DEQUEUE(*buflist, buffer, link); + ISC_LIST_ENQUEUE(dev->bufferlist, buffer, link); + buffer = ISC_LIST_HEAD(*buflist); + } + + return (socket_send(sock, dev, task, address, pktinfo, 0)); +} + +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_sendto2(isc_socket_t *sock0, isc_region_t *region, + isc_task_t *task, + isc_sockaddr_t *address, struct in6_pktinfo *pktinfo, + isc_socketevent_t *event, unsigned int flags) +{ + isc__socket_t *sock = (isc__socket_t *)sock0; + + REQUIRE(VALID_SOCKET(sock)); + REQUIRE((flags & ~(ISC_SOCKFLAG_IMMEDIATE|ISC_SOCKFLAG_NORETRY)) == 0); + if ((flags & ISC_SOCKFLAG_NORETRY) != 0) + REQUIRE(sock->type == isc_sockettype_udp); + event->ev_sender = sock; + event->result = ISC_R_UNSET; + ISC_LIST_INIT(event->bufferlist); + event->region = *region; + event->n = 0; + event->offset = 0; + event->attributes = 0; + + return (socket_send(sock, event, task, address, pktinfo, flags)); +} + +ISC_SOCKETFUNC_SCOPE void +isc__socket_cleanunix(isc_sockaddr_t *sockaddr, isc_boolean_t active) { +#ifdef ISC_PLATFORM_HAVESYSUNH + int s; + struct stat sb; + char strbuf[ISC_STRERRORSIZE]; + + if (sockaddr->type.sa.sa_family != AF_UNIX) + return; + +#ifndef S_ISSOCK +#if defined(S_IFMT) && defined(S_IFSOCK) +#define S_ISSOCK(mode) ((mode & S_IFMT)==S_IFSOCK) +#elif defined(_S_IFMT) && defined(S_IFSOCK) +#define S_ISSOCK(mode) ((mode & _S_IFMT)==S_IFSOCK) +#endif +#endif + +#ifndef S_ISFIFO +#if defined(S_IFMT) && defined(S_IFIFO) +#define S_ISFIFO(mode) ((mode & S_IFMT)==S_IFIFO) +#elif defined(_S_IFMT) && defined(S_IFIFO) +#define S_ISFIFO(mode) ((mode & _S_IFMT)==S_IFIFO) +#endif +#endif + +#if !defined(S_ISFIFO) && !defined(S_ISSOCK) +#error You need to define S_ISFIFO and S_ISSOCK as appropriate for your platform. See <sys/stat.h>. +#endif + +#ifndef S_ISFIFO +#define S_ISFIFO(mode) 0 +#endif + +#ifndef S_ISSOCK +#define S_ISSOCK(mode) 0 +#endif + + if (active) { + if (stat(sockaddr->type.sunix.sun_path, &sb) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR, + "isc_socket_cleanunix: stat(%s): %s", + sockaddr->type.sunix.sun_path, strbuf); + return; + } + if (!(S_ISSOCK(sb.st_mode) || S_ISFIFO(sb.st_mode))) { + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR, + "isc_socket_cleanunix: %s: not a socket", + sockaddr->type.sunix.sun_path); + return; + } + if (unlink(sockaddr->type.sunix.sun_path) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR, + "isc_socket_cleanunix: unlink(%s): %s", + sockaddr->type.sunix.sun_path, strbuf); + } + return; + } + + s = socket(AF_UNIX, SOCK_STREAM, 0); + if (s < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, ISC_LOG_WARNING, + "isc_socket_cleanunix: socket(%s): %s", + sockaddr->type.sunix.sun_path, strbuf); + return; + } + + if (stat(sockaddr->type.sunix.sun_path, &sb) < 0) { + switch (errno) { + case ENOENT: /* We exited cleanly last time */ + break; + default: + isc__strerror(errno, strbuf, sizeof(strbuf)); + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, ISC_LOG_WARNING, + "isc_socket_cleanunix: stat(%s): %s", + sockaddr->type.sunix.sun_path, strbuf); + break; + } + goto cleanup; + } + + if (!(S_ISSOCK(sb.st_mode) || S_ISFIFO(sb.st_mode))) { + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, ISC_LOG_WARNING, + "isc_socket_cleanunix: %s: not a socket", + sockaddr->type.sunix.sun_path); + goto cleanup; + } + + if (connect(s, (struct sockaddr *)&sockaddr->type.sunix, + sizeof(sockaddr->type.sunix)) < 0) { + switch (errno) { + case ECONNREFUSED: + case ECONNRESET: + if (unlink(sockaddr->type.sunix.sun_path) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, + ISC_LOG_WARNING, + "isc_socket_cleanunix: " + "unlink(%s): %s", + sockaddr->type.sunix.sun_path, + strbuf); + } + break; + default: + isc__strerror(errno, strbuf, sizeof(strbuf)); + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, ISC_LOG_WARNING, + "isc_socket_cleanunix: connect(%s): %s", + sockaddr->type.sunix.sun_path, strbuf); + break; + } + } + cleanup: + close(s); +#else + UNUSED(sockaddr); + UNUSED(active); +#endif +} + +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_permunix(isc_sockaddr_t *sockaddr, isc_uint32_t perm, + isc_uint32_t owner, isc_uint32_t group) +{ +#ifdef ISC_PLATFORM_HAVESYSUNH + isc_result_t result = ISC_R_SUCCESS; + char strbuf[ISC_STRERRORSIZE]; + char path[sizeof(sockaddr->type.sunix.sun_path)]; +#ifdef NEED_SECURE_DIRECTORY + char *slash; +#endif + + REQUIRE(sockaddr->type.sa.sa_family == AF_UNIX); + INSIST(strlen(sockaddr->type.sunix.sun_path) < sizeof(path)); + strcpy(path, sockaddr->type.sunix.sun_path); + +#ifdef NEED_SECURE_DIRECTORY + slash = strrchr(path, '/'); + if (slash != NULL) { + if (slash != path) + *slash = '\0'; + else + strcpy(path, "/"); + } else + strcpy(path, "."); +#endif + + if (chmod(path, perm) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR, + "isc_socket_permunix: chmod(%s, %d): %s", + path, perm, strbuf); + result = ISC_R_FAILURE; + } + if (chown(path, owner, group) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR, + "isc_socket_permunix: chown(%s, %d, %d): %s", + path, owner, group, + strbuf); + result = ISC_R_FAILURE; + } + return (result); +#else + UNUSED(sockaddr); + UNUSED(perm); + UNUSED(owner); + UNUSED(group); + return (ISC_R_NOTIMPLEMENTED); +#endif +} + +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_bind(isc_socket_t *sock0, isc_sockaddr_t *sockaddr, + unsigned int options) { + isc__socket_t *sock = (isc__socket_t *)sock0; + char strbuf[ISC_STRERRORSIZE]; + int on = 1; + + REQUIRE(VALID_SOCKET(sock)); + + LOCK(&sock->lock); + + INSIST(!sock->bound); + INSIST(!sock->dupped); + + if (sock->pf != sockaddr->type.sa.sa_family) { + UNLOCK(&sock->lock); + return (ISC_R_FAMILYMISMATCH); + } + + /* + * Only set SO_REUSEADDR when we want a specific port. + */ +#ifdef AF_UNIX + if (sock->pf == AF_UNIX) + goto bind_socket; +#endif + if ((options & ISC_SOCKET_REUSEADDRESS) != 0 && + isc_sockaddr_getport(sockaddr) != (in_port_t)0 && + setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, + sizeof(on)) < 0) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "setsockopt(%d) %s", sock->fd, + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed")); + /* Press on... */ + } +#ifdef AF_UNIX + bind_socket: +#endif + if (bind(sock->fd, &sockaddr->type.sa, sockaddr->length) < 0) { + inc_stats(sock->manager->stats, + sock->statsindex[STATID_BINDFAIL]); + + UNLOCK(&sock->lock); + switch (errno) { + case EACCES: + return (ISC_R_NOPERM); + case EADDRNOTAVAIL: + return (ISC_R_ADDRNOTAVAIL); + case EADDRINUSE: + return (ISC_R_ADDRINUSE); + case EINVAL: + return (ISC_R_BOUND); + default: + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, "bind: %s", + strbuf); + return (ISC_R_UNEXPECTED); + } + } + + socket_log(sock, sockaddr, TRACE, + isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_BOUND, "bound"); + sock->bound = 1; + + UNLOCK(&sock->lock); + return (ISC_R_SUCCESS); +} + +/* + * Enable this only for specific OS versions, and only when they have repaired + * their problems with it. Until then, this is is broken and needs to be + * diabled by default. See RT22589 for details. + */ +#undef ENABLE_ACCEPTFILTER + +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_filter(isc_socket_t *sock0, const char *filter) { + isc__socket_t *sock = (isc__socket_t *)sock0; +#if defined(SO_ACCEPTFILTER) && defined(ENABLE_ACCEPTFILTER) + char strbuf[ISC_STRERRORSIZE]; + struct accept_filter_arg afa; +#else + UNUSED(sock); + UNUSED(filter); +#endif + + REQUIRE(VALID_SOCKET(sock)); + +#if defined(SO_ACCEPTFILTER) && defined(ENABLE_ACCEPTFILTER) + bzero(&afa, sizeof(afa)); + strncpy(afa.af_name, filter, sizeof(afa.af_name)); + if (setsockopt(sock->fd, SOL_SOCKET, SO_ACCEPTFILTER, + &afa, sizeof(afa)) == -1) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + socket_log(sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_FILTER, "setsockopt(SO_ACCEPTFILTER): %s", + strbuf); + return (ISC_R_FAILURE); + } + return (ISC_R_SUCCESS); +#else + return (ISC_R_NOTIMPLEMENTED); +#endif +} + +/* + * Set up to listen on a given socket. We do this by creating an internal + * event that will be dispatched when the socket has read activity. The + * watcher will send the internal event to the task when there is a new + * connection. + * + * Unlike in read, we don't preallocate a done event here. Every time there + * is a new connection we'll have to allocate a new one anyway, so we might + * as well keep things simple rather than having to track them. + */ +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_listen(isc_socket_t *sock0, unsigned int backlog) { + isc__socket_t *sock = (isc__socket_t *)sock0; + char strbuf[ISC_STRERRORSIZE]; + + REQUIRE(VALID_SOCKET(sock)); + + LOCK(&sock->lock); + + REQUIRE(!sock->listener); + REQUIRE(sock->bound); + REQUIRE(sock->type == isc_sockettype_tcp || + sock->type == isc_sockettype_unix); + + if (backlog == 0) + backlog = SOMAXCONN; + + if (listen(sock->fd, (int)backlog) < 0) { + UNLOCK(&sock->lock); + isc__strerror(errno, strbuf, sizeof(strbuf)); + + UNEXPECTED_ERROR(__FILE__, __LINE__, "listen: %s", strbuf); + + return (ISC_R_UNEXPECTED); + } + + sock->listener = 1; + + UNLOCK(&sock->lock); + return (ISC_R_SUCCESS); +} + +/* + * This should try to do aggressive accept() XXXMLG + */ +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_accept(isc_socket_t *sock0, + isc_task_t *task, isc_taskaction_t action, const void *arg) +{ + isc__socket_t *sock = (isc__socket_t *)sock0; + isc_socket_newconnev_t *dev; + isc__socketmgr_t *manager; + isc_task_t *ntask = NULL; + isc__socket_t *nsock; + isc_result_t result; + isc_boolean_t do_poke = ISC_FALSE; + + REQUIRE(VALID_SOCKET(sock)); + manager = sock->manager; + REQUIRE(VALID_MANAGER(manager)); + + LOCK(&sock->lock); + + REQUIRE(sock->listener); + + /* + * Sender field is overloaded here with the task we will be sending + * this event to. Just before the actual event is delivered the + * actual ev_sender will be touched up to be the socket. + */ + dev = (isc_socket_newconnev_t *) + isc_event_allocate(manager->mctx, task, ISC_SOCKEVENT_NEWCONN, + action, arg, sizeof(*dev)); + if (dev == NULL) { + UNLOCK(&sock->lock); + return (ISC_R_NOMEMORY); + } + ISC_LINK_INIT(dev, ev_link); + + result = allocate_socket(manager, sock->type, &nsock); + if (result != ISC_R_SUCCESS) { + isc_event_free(ISC_EVENT_PTR(&dev)); + UNLOCK(&sock->lock); + return (result); + } + + /* + * Attach to socket and to task. + */ + isc_task_attach(task, &ntask); + if (isc_task_exiting(ntask)) { + free_socket(&nsock); + isc_task_detach(&ntask); + isc_event_free(ISC_EVENT_PTR(&dev)); + UNLOCK(&sock->lock); + return (ISC_R_SHUTTINGDOWN); + } + nsock->references++; + nsock->statsindex = sock->statsindex; + + dev->ev_sender = ntask; + dev->newsocket = (isc_socket_t *)nsock; + + /* + * Poke watcher here. We still have the socket locked, so there + * is no race condition. We will keep the lock for such a short + * bit of time waking it up now or later won't matter all that much. + */ + if (ISC_LIST_EMPTY(sock->accept_list)) + do_poke = ISC_TRUE; + + ISC_LIST_ENQUEUE(sock->accept_list, dev, ev_link); + + if (do_poke) + select_poke(manager, sock->fd, SELECT_POKE_ACCEPT); + + UNLOCK(&sock->lock); + return (ISC_R_SUCCESS); +} + +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_connect(isc_socket_t *sock0, isc_sockaddr_t *addr, + isc_task_t *task, isc_taskaction_t action, const void *arg) +{ + isc__socket_t *sock = (isc__socket_t *)sock0; + isc_socket_connev_t *dev; + isc_task_t *ntask = NULL; + isc__socketmgr_t *manager; + int cc; + char strbuf[ISC_STRERRORSIZE]; + char addrbuf[ISC_SOCKADDR_FORMATSIZE]; + + REQUIRE(VALID_SOCKET(sock)); + REQUIRE(addr != NULL); + REQUIRE(task != NULL); + REQUIRE(action != NULL); + + manager = sock->manager; + REQUIRE(VALID_MANAGER(manager)); + REQUIRE(addr != NULL); + + if (isc_sockaddr_ismulticast(addr)) + return (ISC_R_MULTICAST); + + LOCK(&sock->lock); + + REQUIRE(!sock->connecting); + + dev = (isc_socket_connev_t *)isc_event_allocate(manager->mctx, sock, + ISC_SOCKEVENT_CONNECT, + action, arg, + sizeof(*dev)); + if (dev == NULL) { + UNLOCK(&sock->lock); + return (ISC_R_NOMEMORY); + } + ISC_LINK_INIT(dev, ev_link); + + /* + * Try to do the connect right away, as there can be only one + * outstanding, and it might happen to complete. + */ + sock->peer_address = *addr; + cc = connect(sock->fd, &addr->type.sa, addr->length); + if (cc < 0) { + /* + * HP-UX "fails" to connect a UDP socket and sets errno to + * EINPROGRESS if it's non-blocking. We'd rather regard this as + * a success and let the user detect it if it's really an error + * at the time of sending a packet on the socket. + */ + if (sock->type == isc_sockettype_udp && errno == EINPROGRESS) { + cc = 0; + goto success; + } + if (SOFT_ERROR(errno) || errno == EINPROGRESS) + goto queue; + + switch (errno) { +#define ERROR_MATCH(a, b) case a: dev->result = b; goto err_exit; + ERROR_MATCH(EACCES, ISC_R_NOPERM); + ERROR_MATCH(EADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL); + ERROR_MATCH(EAFNOSUPPORT, ISC_R_ADDRNOTAVAIL); + ERROR_MATCH(ECONNREFUSED, ISC_R_CONNREFUSED); + ERROR_MATCH(EHOSTUNREACH, ISC_R_HOSTUNREACH); +#ifdef EHOSTDOWN + ERROR_MATCH(EHOSTDOWN, ISC_R_HOSTUNREACH); +#endif + ERROR_MATCH(ENETUNREACH, ISC_R_NETUNREACH); + ERROR_MATCH(ENOBUFS, ISC_R_NORESOURCES); + ERROR_MATCH(EPERM, ISC_R_HOSTUNREACH); + ERROR_MATCH(EPIPE, ISC_R_NOTCONNECTED); + ERROR_MATCH(ECONNRESET, ISC_R_CONNECTIONRESET); +#undef ERROR_MATCH + } + + sock->connected = 0; + + isc__strerror(errno, strbuf, sizeof(strbuf)); + isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, "connect(%s) %d/%s", + addrbuf, errno, strbuf); + + UNLOCK(&sock->lock); + inc_stats(sock->manager->stats, + sock->statsindex[STATID_CONNECTFAIL]); + isc_event_free(ISC_EVENT_PTR(&dev)); + return (ISC_R_UNEXPECTED); + + err_exit: + sock->connected = 0; + isc_task_send(task, ISC_EVENT_PTR(&dev)); + + UNLOCK(&sock->lock); + inc_stats(sock->manager->stats, + sock->statsindex[STATID_CONNECTFAIL]); + return (ISC_R_SUCCESS); + } + + /* + * If connect completed, fire off the done event. + */ + success: + if (cc == 0) { + sock->connected = 1; + sock->bound = 1; + dev->result = ISC_R_SUCCESS; + isc_task_send(task, ISC_EVENT_PTR(&dev)); + + UNLOCK(&sock->lock); + + inc_stats(sock->manager->stats, + sock->statsindex[STATID_CONNECT]); + + return (ISC_R_SUCCESS); + } + + queue: + + /* + * Attach to task. + */ + isc_task_attach(task, &ntask); + + sock->connecting = 1; + + dev->ev_sender = ntask; + + /* + * Poke watcher here. We still have the socket locked, so there + * is no race condition. We will keep the lock for such a short + * bit of time waking it up now or later won't matter all that much. + */ + if (sock->connect_ev == NULL) + select_poke(manager, sock->fd, SELECT_POKE_CONNECT); + + sock->connect_ev = dev; + + UNLOCK(&sock->lock); + return (ISC_R_SUCCESS); +} + +/* + * Called when a socket with a pending connect() finishes. + */ +static void +internal_connect(isc_task_t *me, isc_event_t *ev) { + isc__socket_t *sock; + isc_socket_connev_t *dev; + isc_task_t *task; + int cc; + ISC_SOCKADDR_LEN_T optlen; + char strbuf[ISC_STRERRORSIZE]; + char peerbuf[ISC_SOCKADDR_FORMATSIZE]; + + UNUSED(me); + INSIST(ev->ev_type == ISC_SOCKEVENT_INTW); + + sock = ev->ev_sender; + INSIST(VALID_SOCKET(sock)); + + LOCK(&sock->lock); + + /* + * When the internal event was sent the reference count was bumped + * to keep the socket around for us. Decrement the count here. + */ + INSIST(sock->references > 0); + sock->references--; + if (sock->references == 0) { + UNLOCK(&sock->lock); + destroy(&sock); + return; + } + + /* + * Has this event been canceled? + */ + dev = sock->connect_ev; + if (dev == NULL) { + INSIST(!sock->connecting); + UNLOCK(&sock->lock); + return; + } + + INSIST(sock->connecting); + sock->connecting = 0; + + /* + * Get any possible error status here. + */ + optlen = sizeof(cc); + if (getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, + (void *)&cc, (void *)&optlen) < 0) + cc = errno; + else + errno = cc; + + if (errno != 0) { + /* + * If the error is EAGAIN, just re-select on this + * fd and pretend nothing strange happened. + */ + if (SOFT_ERROR(errno) || errno == EINPROGRESS) { + sock->connecting = 1; + select_poke(sock->manager, sock->fd, + SELECT_POKE_CONNECT); + UNLOCK(&sock->lock); + + return; + } + + inc_stats(sock->manager->stats, + sock->statsindex[STATID_CONNECTFAIL]); + + /* + * Translate other errors into ISC_R_* flavors. + */ + switch (errno) { +#define ERROR_MATCH(a, b) case a: dev->result = b; break; + ERROR_MATCH(EACCES, ISC_R_NOPERM); + ERROR_MATCH(EADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL); + ERROR_MATCH(EAFNOSUPPORT, ISC_R_ADDRNOTAVAIL); + ERROR_MATCH(ECONNREFUSED, ISC_R_CONNREFUSED); + ERROR_MATCH(EHOSTUNREACH, ISC_R_HOSTUNREACH); +#ifdef EHOSTDOWN + ERROR_MATCH(EHOSTDOWN, ISC_R_HOSTUNREACH); +#endif + ERROR_MATCH(ENETUNREACH, ISC_R_NETUNREACH); + ERROR_MATCH(ENOBUFS, ISC_R_NORESOURCES); + ERROR_MATCH(EPERM, ISC_R_HOSTUNREACH); + ERROR_MATCH(EPIPE, ISC_R_NOTCONNECTED); + ERROR_MATCH(ETIMEDOUT, ISC_R_TIMEDOUT); + ERROR_MATCH(ECONNRESET, ISC_R_CONNECTIONRESET); +#undef ERROR_MATCH + default: + dev->result = ISC_R_UNEXPECTED; + isc_sockaddr_format(&sock->peer_address, peerbuf, + sizeof(peerbuf)); + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "internal_connect: connect(%s) %s", + peerbuf, strbuf); + } + } else { + inc_stats(sock->manager->stats, + sock->statsindex[STATID_CONNECT]); + dev->result = ISC_R_SUCCESS; + sock->connected = 1; + sock->bound = 1; + } + + sock->connect_ev = NULL; + + UNLOCK(&sock->lock); + + task = dev->ev_sender; + dev->ev_sender = sock; + isc_task_sendanddetach(&task, ISC_EVENT_PTR(&dev)); +} + +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_getpeername(isc_socket_t *sock0, isc_sockaddr_t *addressp) { + isc__socket_t *sock = (isc__socket_t *)sock0; + isc_result_t result; + + REQUIRE(VALID_SOCKET(sock)); + REQUIRE(addressp != NULL); + + LOCK(&sock->lock); + + if (sock->connected) { + *addressp = sock->peer_address; + result = ISC_R_SUCCESS; + } else { + result = ISC_R_NOTCONNECTED; + } + + UNLOCK(&sock->lock); + + return (result); +} + +ISC_SOCKETFUNC_SCOPE isc_result_t +isc__socket_getsockname(isc_socket_t *sock0, isc_sockaddr_t *addressp) { + isc__socket_t *sock = (isc__socket_t *)sock0; + ISC_SOCKADDR_LEN_T len; + isc_result_t result; + char strbuf[ISC_STRERRORSIZE]; + + REQUIRE(VALID_SOCKET(sock)); + REQUIRE(addressp != NULL); + + LOCK(&sock->lock); + + if (!sock->bound) { + result = ISC_R_NOTBOUND; + goto out; + } + + result = ISC_R_SUCCESS; + + len = sizeof(addressp->type); + if (getsockname(sock->fd, &addressp->type.sa, (void *)&len) < 0) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, "getsockname: %s", + strbuf); + result = ISC_R_UNEXPECTED; + goto out; + } + addressp->length = (unsigned int)len; + + out: + UNLOCK(&sock->lock); + + return (result); +} + +/* + * Run through the list of events on this socket, and cancel the ones + * queued for task "task" of type "how". "how" is a bitmask. + */ +ISC_SOCKETFUNC_SCOPE void +isc__socket_cancel(isc_socket_t *sock0, isc_task_t *task, unsigned int how) { + isc__socket_t *sock = (isc__socket_t *)sock0; + + REQUIRE(VALID_SOCKET(sock)); + + /* + * Quick exit if there is nothing to do. Don't even bother locking + * in this case. + */ + if (how == 0) + return; + + LOCK(&sock->lock); + + /* + * All of these do the same thing, more or less. + * Each will: + * o If the internal event is marked as "posted" try to + * remove it from the task's queue. If this fails, mark it + * as canceled instead, and let the task clean it up later. + * o For each I/O request for that task of that type, post + * its done event with status of "ISC_R_CANCELED". + * o Reset any state needed. + */ + if (((how & ISC_SOCKCANCEL_RECV) == ISC_SOCKCANCEL_RECV) + && !ISC_LIST_EMPTY(sock->recv_list)) { + isc_socketevent_t *dev; + isc_socketevent_t *next; + isc_task_t *current_task; + + dev = ISC_LIST_HEAD(sock->recv_list); + + while (dev != NULL) { + current_task = dev->ev_sender; + next = ISC_LIST_NEXT(dev, ev_link); + + if ((task == NULL) || (task == current_task)) { + dev->result = ISC_R_CANCELED; + send_recvdone_event(sock, &dev); + } + dev = next; + } + } + + if (((how & ISC_SOCKCANCEL_SEND) == ISC_SOCKCANCEL_SEND) + && !ISC_LIST_EMPTY(sock->send_list)) { + isc_socketevent_t *dev; + isc_socketevent_t *next; + isc_task_t *current_task; + + dev = ISC_LIST_HEAD(sock->send_list); + + while (dev != NULL) { + current_task = dev->ev_sender; + next = ISC_LIST_NEXT(dev, ev_link); + + if ((task == NULL) || (task == current_task)) { + dev->result = ISC_R_CANCELED; + send_senddone_event(sock, &dev); + } + dev = next; + } + } + + if (((how & ISC_SOCKCANCEL_ACCEPT) == ISC_SOCKCANCEL_ACCEPT) + && !ISC_LIST_EMPTY(sock->accept_list)) { + isc_socket_newconnev_t *dev; + isc_socket_newconnev_t *next; + isc_task_t *current_task; + + dev = ISC_LIST_HEAD(sock->accept_list); + while (dev != NULL) { + current_task = dev->ev_sender; + next = ISC_LIST_NEXT(dev, ev_link); + + if ((task == NULL) || (task == current_task)) { + + ISC_LIST_UNLINK(sock->accept_list, dev, + ev_link); + + NEWCONNSOCK(dev)->references--; + free_socket((isc__socket_t **)&dev->newsocket); + + dev->result = ISC_R_CANCELED; + dev->ev_sender = sock; + isc_task_sendanddetach(¤t_task, + ISC_EVENT_PTR(&dev)); + } + + dev = next; + } + } + + /* + * Connecting is not a list. + */ + if (((how & ISC_SOCKCANCEL_CONNECT) == ISC_SOCKCANCEL_CONNECT) + && sock->connect_ev != NULL) { + isc_socket_connev_t *dev; + isc_task_t *current_task; + + INSIST(sock->connecting); + sock->connecting = 0; + + dev = sock->connect_ev; + current_task = dev->ev_sender; + + if ((task == NULL) || (task == current_task)) { + sock->connect_ev = NULL; + + dev->result = ISC_R_CANCELED; + dev->ev_sender = sock; + isc_task_sendanddetach(¤t_task, + ISC_EVENT_PTR(&dev)); + } + } + + UNLOCK(&sock->lock); +} + +ISC_SOCKETFUNC_SCOPE isc_sockettype_t +isc__socket_gettype(isc_socket_t *sock0) { + isc__socket_t *sock = (isc__socket_t *)sock0; + + REQUIRE(VALID_SOCKET(sock)); + + return (sock->type); +} + +ISC_SOCKETFUNC_SCOPE isc_boolean_t +isc__socket_isbound(isc_socket_t *sock0) { + isc__socket_t *sock = (isc__socket_t *)sock0; + isc_boolean_t val; + + REQUIRE(VALID_SOCKET(sock)); + + LOCK(&sock->lock); + val = ((sock->bound) ? ISC_TRUE : ISC_FALSE); + UNLOCK(&sock->lock); + + return (val); +} + +ISC_SOCKETFUNC_SCOPE void +isc__socket_ipv6only(isc_socket_t *sock0, isc_boolean_t yes) { + isc__socket_t *sock = (isc__socket_t *)sock0; +#if defined(IPV6_V6ONLY) + int onoff = yes ? 1 : 0; +#else + UNUSED(yes); + UNUSED(sock); +#endif + + REQUIRE(VALID_SOCKET(sock)); + INSIST(!sock->dupped); + +#ifdef IPV6_V6ONLY + if (sock->pf == AF_INET6) { + if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, + (void *)&onoff, sizeof(int)) < 0) { + char strbuf[ISC_STRERRORSIZE]; + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "setsockopt(%d, IPV6_V6ONLY) " + "%s: %s", sock->fd, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, + "failed"), + strbuf); + } + } + FIX_IPV6_RECVPKTINFO(sock); /* AIX */ +#endif +} + +#ifndef USE_WATCHER_THREAD +/* + * In our assumed scenario, we can simply use a single static object. + * XXX: this is not true if the application uses multiple threads with + * 'multi-context' mode. Fixing this is a future TODO item. + */ +static isc_socketwait_t swait_private; + +int +isc__socketmgr_waitevents(isc_socketmgr_t *manager0, struct timeval *tvp, + isc_socketwait_t **swaitp) +{ + isc__socketmgr_t *manager = (isc__socketmgr_t *)manager0; + + + int n; +#ifdef USE_KQUEUE + struct timespec ts, *tsp; +#endif +#ifdef USE_EPOLL + int timeout; +#endif +#ifdef USE_DEVPOLL + struct dvpoll dvp; +#endif + + REQUIRE(swaitp != NULL && *swaitp == NULL); + +#ifdef USE_SHARED_MANAGER + if (manager == NULL) + manager = socketmgr; +#endif + if (manager == NULL) + return (0); + +#ifdef USE_KQUEUE + if (tvp != NULL) { + ts.tv_sec = tvp->tv_sec; + ts.tv_nsec = tvp->tv_usec * 1000; + tsp = &ts; + } else + tsp = NULL; + swait_private.nevents = kevent(manager->kqueue_fd, NULL, 0, + manager->events, manager->nevents, + tsp); + n = swait_private.nevents; +#elif defined(USE_EPOLL) + if (tvp != NULL) + timeout = tvp->tv_sec * 1000 + (tvp->tv_usec + 999) / 1000; + else + timeout = -1; + swait_private.nevents = epoll_wait(manager->epoll_fd, + manager->events, + manager->nevents, timeout); + n = swait_private.nevents; +#elif defined(USE_DEVPOLL) + dvp.dp_fds = manager->events; + dvp.dp_nfds = manager->nevents; + if (tvp != NULL) { + dvp.dp_timeout = tvp->tv_sec * 1000 + + (tvp->tv_usec + 999) / 1000; + } else + dvp.dp_timeout = -1; + swait_private.nevents = ioctl(manager->devpoll_fd, DP_POLL, &dvp); + n = swait_private.nevents; +#elif defined(USE_SELECT) + memcpy(manager->read_fds_copy, manager->read_fds, manager->fd_bufsize); + memcpy(manager->write_fds_copy, manager->write_fds, + manager->fd_bufsize); + + swait_private.readset = manager->read_fds_copy; + swait_private.writeset = manager->write_fds_copy; + swait_private.maxfd = manager->maxfd + 1; + + n = select(swait_private.maxfd, swait_private.readset, + swait_private.writeset, NULL, tvp); +#endif + + *swaitp = &swait_private; + return (n); +} + +isc_result_t +isc__socketmgr_dispatch(isc_socketmgr_t *manager0, isc_socketwait_t *swait) { + isc__socketmgr_t *manager = (isc__socketmgr_t *)manager0; + + REQUIRE(swait == &swait_private); + +#ifdef USE_SHARED_MANAGER + if (manager == NULL) + manager = socketmgr; +#endif + if (manager == NULL) + return (ISC_R_NOTFOUND); + +#if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL) + (void)process_fds(manager, manager->events, swait->nevents); + return (ISC_R_SUCCESS); +#elif defined(USE_SELECT) + process_fds(manager, swait->maxfd, swait->readset, swait->writeset); + return (ISC_R_SUCCESS); +#endif +} +#endif /* USE_WATCHER_THREAD */ + +#ifdef BIND9 +void +isc__socket_setname(isc_socket_t *socket0, const char *name, void *tag) { + isc__socket_t *socket = (isc__socket_t *)socket0; + + /* + * Name 'socket'. + */ + + REQUIRE(VALID_SOCKET(socket)); + + LOCK(&socket->lock); + memset(socket->name, 0, sizeof(socket->name)); + strncpy(socket->name, name, sizeof(socket->name) - 1); + socket->tag = tag; + UNLOCK(&socket->lock); +} + +ISC_SOCKETFUNC_SCOPE const char * +isc__socket_getname(isc_socket_t *socket0) { + isc__socket_t *socket = (isc__socket_t *)socket0; + + return (socket->name); +} + +void * +isc__socket_gettag(isc_socket_t *socket0) { + isc__socket_t *socket = (isc__socket_t *)socket0; + + return (socket->tag); +} +#endif /* BIND9 */ + +#ifdef USE_SOCKETIMPREGISTER +isc_result_t +isc__socket_register() { + return (isc_socket_register(isc__socketmgr_create)); +} +#endif + +ISC_SOCKETFUNC_SCOPE int +isc__socket_getfd(isc_socket_t *socket0) { + isc__socket_t *socket = (isc__socket_t *)socket0; + + return ((short) socket->fd); +} + +#if defined(HAVE_LIBXML2) && defined(BIND9) + +static const char * +_socktype(isc_sockettype_t type) +{ + if (type == isc_sockettype_udp) + return ("udp"); + else if (type == isc_sockettype_tcp) + return ("tcp"); + else if (type == isc_sockettype_unix) + return ("unix"); + else if (type == isc_sockettype_fdwatch) + return ("fdwatch"); + else + return ("not-initialized"); +} + +ISC_SOCKETFUNC_SCOPE void +isc_socketmgr_renderxml(isc_socketmgr_t *mgr0, xmlTextWriterPtr writer) { + isc__socketmgr_t *mgr = (isc__socketmgr_t *)mgr0; + isc__socket_t *sock; + char peerbuf[ISC_SOCKADDR_FORMATSIZE]; + isc_sockaddr_t addr; + ISC_SOCKADDR_LEN_T len; + + LOCK(&mgr->lock); + +#ifdef USE_SHARED_MANAGER + xmlTextWriterStartElement(writer, ISC_XMLCHAR "references"); + xmlTextWriterWriteFormatString(writer, "%d", mgr->refs); + xmlTextWriterEndElement(writer); +#endif /* USE_SHARED_MANAGER */ + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "sockets"); + sock = ISC_LIST_HEAD(mgr->socklist); + while (sock != NULL) { + LOCK(&sock->lock); + xmlTextWriterStartElement(writer, ISC_XMLCHAR "socket"); + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "id"); + xmlTextWriterWriteFormatString(writer, "%p", sock); + xmlTextWriterEndElement(writer); + + if (sock->name[0] != 0) { + xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"); + xmlTextWriterWriteFormatString(writer, "%s", + sock->name); + xmlTextWriterEndElement(writer); /* name */ + } + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "references"); + xmlTextWriterWriteFormatString(writer, "%d", sock->references); + xmlTextWriterEndElement(writer); + + xmlTextWriterWriteElement(writer, ISC_XMLCHAR "type", + ISC_XMLCHAR _socktype(sock->type)); + + if (sock->connected) { + isc_sockaddr_format(&sock->peer_address, peerbuf, + sizeof(peerbuf)); + xmlTextWriterWriteElement(writer, + ISC_XMLCHAR "peer-address", + ISC_XMLCHAR peerbuf); + } + + len = sizeof(addr); + if (getsockname(sock->fd, &addr.type.sa, (void *)&len) == 0) { + isc_sockaddr_format(&addr, peerbuf, sizeof(peerbuf)); + xmlTextWriterWriteElement(writer, + ISC_XMLCHAR "local-address", + ISC_XMLCHAR peerbuf); + } + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "states"); + if (sock->pending_recv) + xmlTextWriterWriteElement(writer, ISC_XMLCHAR "state", + ISC_XMLCHAR "pending-receive"); + if (sock->pending_send) + xmlTextWriterWriteElement(writer, ISC_XMLCHAR "state", + ISC_XMLCHAR "pending-send"); + if (sock->pending_accept) + xmlTextWriterWriteElement(writer, ISC_XMLCHAR "state", + ISC_XMLCHAR "pending_accept"); + if (sock->listener) + xmlTextWriterWriteElement(writer, ISC_XMLCHAR "state", + ISC_XMLCHAR "listener"); + if (sock->connected) + xmlTextWriterWriteElement(writer, ISC_XMLCHAR "state", + ISC_XMLCHAR "connected"); + if (sock->connecting) + xmlTextWriterWriteElement(writer, ISC_XMLCHAR "state", + ISC_XMLCHAR "connecting"); + if (sock->bound) + xmlTextWriterWriteElement(writer, ISC_XMLCHAR "state", + ISC_XMLCHAR "bound"); + + xmlTextWriterEndElement(writer); /* states */ + + xmlTextWriterEndElement(writer); /* socket */ + + UNLOCK(&sock->lock); + sock = ISC_LIST_NEXT(sock, link); + } + xmlTextWriterEndElement(writer); /* sockets */ + + UNLOCK(&mgr->lock); +} +#endif /* HAVE_LIBXML2 */ diff --git a/contrib/ntp/lib/isc/unix/socket_p.h b/contrib/ntp/lib/isc/unix/socket_p.h new file mode 100644 index 0000000..1316011 --- /dev/null +++ b/contrib/ntp/lib/isc/unix/socket_p.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: socket_p.h,v 1.15 2009/09/02 23:48:03 tbox Exp $ */ + +#ifndef ISC_SOCKET_P_H +#define ISC_SOCKET_P_H + +/*! \file */ + +#ifdef ISC_PLATFORM_NEEDSYSSELECTH +#include <sys/select.h> +#endif + +typedef struct isc_socketwait isc_socketwait_t; +int isc__socketmgr_waitevents(isc_socketmgr_t *, struct timeval *, + isc_socketwait_t **); +isc_result_t isc__socketmgr_dispatch(isc_socketmgr_t *, isc_socketwait_t *); +#endif /* ISC_SOCKET_P_H */ diff --git a/contrib/ntp/lib/isc/unix/stdio.c b/contrib/ntp/lib/isc/unix/stdio.c new file mode 100644 index 0000000..360c8c6 --- /dev/null +++ b/contrib/ntp/lib/isc/unix/stdio.c @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2004, 2007, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +#include <config.h> + +#include <errno.h> +#include <unistd.h> + +#include <isc/stdio.h> +#include <isc/stat.h> + +#include "errno2result.h" + +isc_result_t +isc_stdio_open(const char *filename, const char *mode, FILE **fp) { + FILE *f; + + f = fopen(filename, mode); + if (f == NULL) + return (isc__errno2result(errno)); + *fp = f; + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_stdio_close(FILE *f) { + int r; + + r = fclose(f); + if (r == 0) + return (ISC_R_SUCCESS); + else + return (isc__errno2result(errno)); +} + +isc_result_t +isc_stdio_seek(FILE *f, long offset, int whence) { + int r; + + r = fseek(f, offset, whence); + if (r == 0) + return (ISC_R_SUCCESS); + else + return (isc__errno2result(errno)); +} + +isc_result_t +isc_stdio_read(void *ptr, size_t size, size_t nmemb, FILE *f, size_t *nret) { + isc_result_t result = ISC_R_SUCCESS; + size_t r; + + clearerr(f); + r = fread(ptr, size, nmemb, f); + if (r != nmemb) { + if (feof(f)) + result = ISC_R_EOF; + else + result = isc__errno2result(errno); + } + if (nret != NULL) + *nret = r; + return (result); +} + +isc_result_t +isc_stdio_write(const void *ptr, size_t size, size_t nmemb, FILE *f, + size_t *nret) +{ + isc_result_t result = ISC_R_SUCCESS; + size_t r; + + clearerr(f); + r = fwrite(ptr, size, nmemb, f); + if (r != nmemb) + result = isc__errno2result(errno); + if (nret != NULL) + *nret = r; + return (result); +} + +isc_result_t +isc_stdio_flush(FILE *f) { + int r; + + r = fflush(f); + if (r == 0) + return (ISC_R_SUCCESS); + else + return (isc__errno2result(errno)); +} + +/* + * OpenBSD has deprecated ENOTSUP in favor of EOPNOTSUPP. + */ +#if defined(EOPNOTSUPP) && !defined(ENOTSUP) +#define ENOTSUP EOPNOTSUPP +#endif + +isc_result_t +isc_stdio_sync(FILE *f) { + int r; + + r = fsync(fileno(f)); + /* + * fsync is not supported on sockets and pipes which + * result in EINVAL / ENOTSUP. + */ + if (r == 0 || errno == EINVAL || errno == ENOTSUP) + return (ISC_R_SUCCESS); + else + return (isc__errno2result(errno)); +} + diff --git a/contrib/ntp/lib/isc/unix/stdtime.c b/contrib/ntp/lib/isc/unix/stdtime.c new file mode 100644 index 0000000..c5d0c47 --- /dev/null +++ b/contrib/ntp/lib/isc/unix/stdtime.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: stdtime.c,v 1.19 2007/06/19 23:47:18 tbox Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <stddef.h> /* NULL */ +#include <stdlib.h> /* NULL */ +#include <syslog.h> + +#include <sys/time.h> + +#include <isc/stdtime.h> +#include <isc/util.h> + +#ifndef ISC_FIX_TV_USEC +#define ISC_FIX_TV_USEC 1 +#endif + +#define US_PER_S 1000000 + +#if ISC_FIX_TV_USEC +static inline void +fix_tv_usec(struct timeval *tv) { + isc_boolean_t fixed = ISC_FALSE; + + if (tv->tv_usec < 0) { + fixed = ISC_TRUE; + do { + tv->tv_sec -= 1; + tv->tv_usec += US_PER_S; + } while (tv->tv_usec < 0); + } else if (tv->tv_usec >= US_PER_S) { + fixed = ISC_TRUE; + do { + tv->tv_sec += 1; + tv->tv_usec -= US_PER_S; + } while (tv->tv_usec >=US_PER_S); + } + /* + * Call syslog directly as we are called from the logging functions. + */ + if (fixed) + (void)syslog(LOG_ERR, "gettimeofday returned bad tv_usec: corrected"); +} +#endif + +void +isc_stdtime_get(isc_stdtime_t *t) { + struct timeval tv; + + /* + * Set 't' to the number of seconds since 00:00:00 UTC, January 1, + * 1970. + */ + + REQUIRE(t != NULL); + + RUNTIME_CHECK(gettimeofday(&tv, NULL) != -1); + +#if ISC_FIX_TV_USEC + fix_tv_usec(&tv); + INSIST(tv.tv_usec >= 0); +#else + INSIST(tv.tv_usec >= 0 && tv.tv_usec < US_PER_S); +#endif + + *t = (unsigned int)tv.tv_sec; +} diff --git a/contrib/ntp/lib/isc/unix/strerror.c b/contrib/ntp/lib/isc/unix/strerror.c new file mode 100644 index 0000000..2278009 --- /dev/null +++ b/contrib/ntp/lib/isc/unix/strerror.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: strerror.c,v 1.10 2009/02/16 23:48:04 tbox Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <stdio.h> +#include <string.h> + +#include <isc/mutex.h> +#include <isc/once.h> +#include <isc/print.h> +#include <isc/strerror.h> +#include <isc/util.h> + +#include "l_stdlib.h" /* NTP local change */ + +#ifdef HAVE_STRERROR +/*% + * We need to do this this way for profiled locks. + */ +static isc_mutex_t isc_strerror_lock; +static void init_lock(void) { + RUNTIME_CHECK(isc_mutex_init(&isc_strerror_lock) == ISC_R_SUCCESS); +} +#else +extern const char * const sys_errlist[]; +extern const int sys_nerr; +#endif + +void +isc__strerror(int num, char *buf, size_t size) { +#ifdef HAVE_STRERROR + char *msg; + unsigned int unum = (unsigned int)num; + static isc_once_t once = ISC_ONCE_INIT; + + REQUIRE(buf != NULL); + + RUNTIME_CHECK(isc_once_do(&once, init_lock) == ISC_R_SUCCESS); + + LOCK(&isc_strerror_lock); + msg = strerror(num); + if (msg != NULL) + snprintf(buf, size, "%s", msg); + else + snprintf(buf, size, "Unknown error: %u", unum); + UNLOCK(&isc_strerror_lock); +#else + unsigned int unum = (unsigned int)num; + + REQUIRE(buf != NULL); + + if (num >= 0 && num < sys_nerr) + snprintf(buf, size, "%s", sys_errlist[num]); + else + snprintf(buf, size, "Unknown error: %u", unum); +#endif +} diff --git a/contrib/ntp/lib/isc/unix/syslog.c b/contrib/ntp/lib/isc/unix/syslog.c new file mode 100644 index 0000000..997508e --- /dev/null +++ b/contrib/ntp/lib/isc/unix/syslog.c @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: syslog.c,v 1.8 2007/09/13 04:45:18 each Exp $ */ + +/*! \file */ + +#include <config.h> + +#include <stdlib.h> +#include <syslog.h> + +#include <isc/result.h> +#include <isc/string.h> +#include <isc/syslog.h> +#include <isc/util.h> + +static struct dsn_c_pvt_sfnt { + int val; + const char *strval; +} facilities[] = { + { LOG_KERN, "kern" }, + { LOG_USER, "user" }, + { LOG_MAIL, "mail" }, + { LOG_DAEMON, "daemon" }, + { LOG_AUTH, "auth" }, + { LOG_SYSLOG, "syslog" }, + { LOG_LPR, "lpr" }, +#ifdef LOG_NEWS + { LOG_NEWS, "news" }, +#endif +#ifdef LOG_UUCP + { LOG_UUCP, "uucp" }, +#endif +#ifdef LOG_CRON + { LOG_CRON, "cron" }, +#endif +#ifdef LOG_AUTHPRIV + { LOG_AUTHPRIV, "authpriv" }, +#endif +#ifdef LOG_FTP + { LOG_FTP, "ftp" }, +#endif + { LOG_LOCAL0, "local0"}, + { LOG_LOCAL1, "local1"}, + { LOG_LOCAL2, "local2"}, + { LOG_LOCAL3, "local3"}, + { LOG_LOCAL4, "local4"}, + { LOG_LOCAL5, "local5"}, + { LOG_LOCAL6, "local6"}, + { LOG_LOCAL7, "local7"}, + { 0, NULL } +}; + +isc_result_t +isc_syslog_facilityfromstring(const char *str, int *facilityp) { + int i; + + REQUIRE(str != NULL); + REQUIRE(facilityp != NULL); + + for (i = 0; facilities[i].strval != NULL; i++) { + if (strcasecmp(facilities[i].strval, str) == 0) { + *facilityp = facilities[i].val; + return (ISC_R_SUCCESS); + } + } + return (ISC_R_NOTFOUND); + +} diff --git a/contrib/ntp/lib/isc/unix/time.c b/contrib/ntp/lib/isc/unix/time.c new file mode 100644 index 0000000..ac23ae0 --- /dev/null +++ b/contrib/ntp/lib/isc/unix/time.c @@ -0,0 +1,420 @@ +/* + * Copyright (C) 2004-2008, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2001, 2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/*! \file */ + +#include <config.h> + +#include <errno.h> +#include <limits.h> +#include <syslog.h> +#include <time.h> + +#include <sys/time.h> /* Required for struct timeval on some platforms. */ + +#include <isc/log.h> +#include <isc/print.h> +#include <isc/strerror.h> +#include <isc/string.h> +#include <isc/time.h> +#include <isc/util.h> + +#define NS_PER_S 1000000000 /*%< Nanoseconds per second. */ +#define NS_PER_US 1000 /*%< Nanoseconds per microsecond. */ +#define US_PER_S 1000000 /*%< Microseconds per second. */ + +/* + * All of the INSIST()s checks of nanoseconds < NS_PER_S are for + * consistency checking of the type. In lieu of magic numbers, it + * is the best we've got. The check is only performed on functions which + * need an initialized type. + */ + +#ifndef ISC_FIX_TV_USEC +#define ISC_FIX_TV_USEC 1 +#endif + +/*% + *** Intervals + ***/ + +static isc_interval_t zero_interval = { 0, 0 }; +isc_interval_t *isc_interval_zero = &zero_interval; + +#if ISC_FIX_TV_USEC +static inline void +fix_tv_usec(struct timeval *tv) { + isc_boolean_t fixed = ISC_FALSE; + + if (tv->tv_usec < 0) { + fixed = ISC_TRUE; + do { + tv->tv_sec -= 1; + tv->tv_usec += US_PER_S; + } while (tv->tv_usec < 0); + } else if (tv->tv_usec >= US_PER_S) { + fixed = ISC_TRUE; + do { + tv->tv_sec += 1; + tv->tv_usec -= US_PER_S; + } while (tv->tv_usec >=US_PER_S); + } + /* + * Call syslog directly as was are called from the logging functions. + */ + if (fixed) + (void)syslog(LOG_ERR, "gettimeofday returned bad tv_usec: corrected"); +} +#endif + +void +isc_interval_set(isc_interval_t *i, + unsigned int seconds, unsigned int nanoseconds) +{ + REQUIRE(i != NULL); + REQUIRE(nanoseconds < NS_PER_S); + + i->seconds = seconds; + i->nanoseconds = nanoseconds; +} + +isc_boolean_t +isc_interval_iszero(const isc_interval_t *i) { + REQUIRE(i != NULL); + INSIST(i->nanoseconds < NS_PER_S); + + if (i->seconds == 0 && i->nanoseconds == 0) + return (ISC_TRUE); + + return (ISC_FALSE); +} + + +/*** + *** Absolute Times + ***/ + +static isc_time_t epoch = { 0, 0 }; +isc_time_t *isc_time_epoch = &epoch; + +void +isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds) { + REQUIRE(t != NULL); + REQUIRE(nanoseconds < NS_PER_S); + + t->seconds = seconds; + t->nanoseconds = nanoseconds; +} + +void +isc_time_settoepoch(isc_time_t *t) { + REQUIRE(t != NULL); + + t->seconds = 0; + t->nanoseconds = 0; +} + +isc_boolean_t +isc_time_isepoch(const isc_time_t *t) { + REQUIRE(t != NULL); + INSIST(t->nanoseconds < NS_PER_S); + + if (t->seconds == 0 && t->nanoseconds == 0) + return (ISC_TRUE); + + return (ISC_FALSE); +} + + +isc_result_t +isc_time_now(isc_time_t *t) { + struct timeval tv; + char strbuf[ISC_STRERRORSIZE]; + + REQUIRE(t != NULL); + + if (gettimeofday(&tv, NULL) == -1) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf); + return (ISC_R_UNEXPECTED); + } + + /* + * Does POSIX guarantee the signedness of tv_sec and tv_usec? If not, + * then this test will generate warnings for platforms on which it is + * unsigned. In any event, the chances of any of these problems + * happening are pretty much zero, but since the libisc library ensures + * certain things to be true ... + */ +#if ISC_FIX_TV_USEC + fix_tv_usec(&tv); + if (tv.tv_sec < 0) + return (ISC_R_UNEXPECTED); +#else + if (tv.tv_sec < 0 || tv.tv_usec < 0 || tv.tv_usec >= US_PER_S) + return (ISC_R_UNEXPECTED); +#endif + + /* + * Ensure the tv_sec value fits in t->seconds. + */ + if (sizeof(tv.tv_sec) > sizeof(t->seconds) && + ((tv.tv_sec | (unsigned int)-1) ^ (unsigned int)-1) != 0U) + return (ISC_R_RANGE); + + t->seconds = tv.tv_sec; + t->nanoseconds = tv.tv_usec * NS_PER_US; + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i) { + struct timeval tv; + char strbuf[ISC_STRERRORSIZE]; + + REQUIRE(t != NULL); + REQUIRE(i != NULL); + INSIST(i->nanoseconds < NS_PER_S); + + if (gettimeofday(&tv, NULL) == -1) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf); + return (ISC_R_UNEXPECTED); + } + + /* + * Does POSIX guarantee the signedness of tv_sec and tv_usec? If not, + * then this test will generate warnings for platforms on which it is + * unsigned. In any event, the chances of any of these problems + * happening are pretty much zero, but since the libisc library ensures + * certain things to be true ... + */ +#if ISC_FIX_TV_USEC + fix_tv_usec(&tv); + if (tv.tv_sec < 0) + return (ISC_R_UNEXPECTED); +#else + if (tv.tv_sec < 0 || tv.tv_usec < 0 || tv.tv_usec >= US_PER_S) + return (ISC_R_UNEXPECTED); +#endif + + /* + * Ensure the resulting seconds value fits in the size of an + * unsigned int. (It is written this way as a slight optimization; + * note that even if both values == INT_MAX, then when added + * and getting another 1 added below the result is UINT_MAX.) + */ + if ((tv.tv_sec > INT_MAX || i->seconds > INT_MAX) && + ((long long)tv.tv_sec + i->seconds > UINT_MAX)) + return (ISC_R_RANGE); + + t->seconds = tv.tv_sec + i->seconds; + t->nanoseconds = tv.tv_usec * NS_PER_US + i->nanoseconds; + if (t->nanoseconds >= NS_PER_S) { + t->seconds++; + t->nanoseconds -= NS_PER_S; + } + + return (ISC_R_SUCCESS); +} + +int +isc_time_compare(const isc_time_t *t1, const isc_time_t *t2) { + REQUIRE(t1 != NULL && t2 != NULL); + INSIST(t1->nanoseconds < NS_PER_S && t2->nanoseconds < NS_PER_S); + + if (t1->seconds < t2->seconds) + return (-1); + if (t1->seconds > t2->seconds) + return (1); + if (t1->nanoseconds < t2->nanoseconds) + return (-1); + if (t1->nanoseconds > t2->nanoseconds) + return (1); + return (0); +} + +isc_result_t +isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result) +{ + REQUIRE(t != NULL && i != NULL && result != NULL); + INSIST(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S); + + /* + * Ensure the resulting seconds value fits in the size of an + * unsigned int. (It is written this way as a slight optimization; + * note that even if both values == INT_MAX, then when added + * and getting another 1 added below the result is UINT_MAX.) + */ + if ((t->seconds > INT_MAX || i->seconds > INT_MAX) && + ((long long)t->seconds + i->seconds > UINT_MAX)) + return (ISC_R_RANGE); + + result->seconds = t->seconds + i->seconds; + result->nanoseconds = t->nanoseconds + i->nanoseconds; + if (result->nanoseconds >= NS_PER_S) { + result->seconds++; + result->nanoseconds -= NS_PER_S; + } + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_time_subtract(const isc_time_t *t, const isc_interval_t *i, + isc_time_t *result) +{ + REQUIRE(t != NULL && i != NULL && result != NULL); + INSIST(t->nanoseconds < NS_PER_S && i->nanoseconds < NS_PER_S); + + if ((unsigned int)t->seconds < i->seconds || + ((unsigned int)t->seconds == i->seconds && + t->nanoseconds < i->nanoseconds)) + return (ISC_R_RANGE); + + result->seconds = t->seconds - i->seconds; + if (t->nanoseconds >= i->nanoseconds) + result->nanoseconds = t->nanoseconds - i->nanoseconds; + else { + result->nanoseconds = NS_PER_S - i->nanoseconds + + t->nanoseconds; + result->seconds--; + } + + return (ISC_R_SUCCESS); +} + +isc_uint64_t +isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2) { + isc_uint64_t i1, i2, i3; + + REQUIRE(t1 != NULL && t2 != NULL); + INSIST(t1->nanoseconds < NS_PER_S && t2->nanoseconds < NS_PER_S); + + i1 = (isc_uint64_t)t1->seconds * NS_PER_S + t1->nanoseconds; + i2 = (isc_uint64_t)t2->seconds * NS_PER_S + t2->nanoseconds; + + if (i1 <= i2) + return (0); + + i3 = i1 - i2; + + /* + * Convert to microseconds. + */ + i3 /= NS_PER_US; + + return (i3); +} + +isc_uint32_t +isc_time_seconds(const isc_time_t *t) { + REQUIRE(t != NULL); + INSIST(t->nanoseconds < NS_PER_S); + + return ((isc_uint32_t)t->seconds); +} + +isc_result_t +isc_time_secondsastimet(const isc_time_t *t, time_t *secondsp) { + time_t seconds; + + REQUIRE(t != NULL); + INSIST(t->nanoseconds < NS_PER_S); + + /* + * Ensure that the number of seconds represented by t->seconds + * can be represented by a time_t. Since t->seconds is an unsigned + * int and since time_t is mostly opaque, this is trickier than + * it seems. (This standardized opaqueness of time_t is *very* + * frustrating; time_t is not even limited to being an integral + * type.) + * + * The mission, then, is to avoid generating any kind of warning + * about "signed versus unsigned" while trying to determine if the + * the unsigned int t->seconds is out range for tv_sec, which is + * pretty much only true if time_t is a signed integer of the same + * size as the return value of isc_time_seconds. + * + * If the paradox in the if clause below is true, t->seconds is out + * of range for time_t. + */ + seconds = (time_t)t->seconds; + + INSIST(sizeof(unsigned int) == sizeof(isc_uint32_t)); + INSIST(sizeof(time_t) >= sizeof(isc_uint32_t)); + + if (t->seconds > (~0U>>1) && seconds <= (time_t)(~0U>>1)) + return (ISC_R_RANGE); + + *secondsp = seconds; + + return (ISC_R_SUCCESS); +} + +isc_uint32_t +isc_time_nanoseconds(const isc_time_t *t) { + REQUIRE(t != NULL); + + ENSURE(t->nanoseconds < NS_PER_S); + + return ((isc_uint32_t)t->nanoseconds); +} + +void +isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len) { + time_t now; + unsigned int flen; + + REQUIRE(len > 0); + + now = (time_t) t->seconds; + flen = strftime(buf, len, "%d-%b-%Y %X", localtime(&now)); + INSIST(flen < len); + if (flen != 0) + snprintf(buf + flen, len - flen, + ".%03u", t->nanoseconds / 1000000); + else + snprintf(buf, len, "99-Bad-9999 99:99:99.999"); +} + +void +isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) { + time_t now; + unsigned int flen; + + REQUIRE(len > 0); + + now = (time_t)t->seconds; + flen = strftime(buf, len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now)); + INSIST(flen < len); +} + +void +isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len) { + time_t now; + unsigned int flen; + + REQUIRE(len > 0); + + now = (time_t)t->seconds; + flen = strftime(buf, len, "%Y-%m-%dT%H:%M:%SZ", gmtime(&now)); + INSIST(flen < len); +} diff --git a/contrib/ntp/lib/isc/version.c b/contrib/ntp/lib/isc/version.c new file mode 100644 index 0000000..bfe4d6d --- /dev/null +++ b/contrib/ntp/lib/isc/version.c @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: version.c,v 1.15 2007/06/19 23:47:17 tbox Exp $ */ + +/*! \file */ + +#include <isc/version.h> + +const char isc_version[] = VERSION; + +const unsigned int isc_libinterface = LIBINTERFACE; +const unsigned int isc_librevision = LIBREVISION; +const unsigned int isc_libage = LIBAGE; diff --git a/contrib/ntp/lib/isc/win32/DLLMain.c b/contrib/ntp/lib/isc/win32/DLLMain.c new file mode 100644 index 0000000..ed84fcf --- /dev/null +++ b/contrib/ntp/lib/isc/win32/DLLMain.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: DLLMain.c,v 1.7 2007/06/18 23:47:49 tbox Exp $ */ + +#include <windows.h> +#include <stdio.h> + +/* + * Called when we enter the DLL + */ +__declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE hinstDLL, + DWORD fdwReason, LPVOID lpvReserved) +{ + switch (fdwReason) + { + /* + * The DLL is loading due to process + * initialization or a call to LoadLibrary. + */ + case DLL_PROCESS_ATTACH: + break; + + /* The attached process creates a new thread. */ + case DLL_THREAD_ATTACH: + break; + + /* The thread of the attached process terminates. */ + case DLL_THREAD_DETACH: + break; + + /* + * The DLL is unloading from a process due to + * process termination or a call to FreeLibrary. + */ + case DLL_PROCESS_DETACH: + break; + + default: + break; + } + return (TRUE); +} + diff --git a/contrib/ntp/lib/isc/win32/app.c b/contrib/ntp/lib/isc/win32/app.c new file mode 100644 index 0000000..04b1638 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/app.c @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: app.c,v 1.9 2009/09/02 23:48:03 tbox Exp $ */ + +#include <config.h> + +#include <sys/types.h> + +#include <stddef.h> +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <process.h> + +#include <isc/app.h> +#include <isc/boolean.h> +#include <isc/condition.h> +#include <isc/msgs.h> +#include <isc/mutex.h> +#include <isc/event.h> +#include <isc/platform.h> +#include <isc/string.h> +#include <isc/task.h> +#include <isc/time.h> +#include <isc/util.h> +#include <isc/thread.h> + +static isc_eventlist_t on_run; +static isc_mutex_t lock; +static isc_boolean_t shutdown_requested = ISC_FALSE; +static isc_boolean_t running = ISC_FALSE; +/* + * We assume that 'want_shutdown' can be read and written atomically. + */ +static isc_boolean_t want_shutdown = ISC_FALSE; +/* + * We assume that 'want_reload' can be read and written atomically. + */ +static isc_boolean_t want_reload = ISC_FALSE; + +static isc_boolean_t blocked = ISC_FALSE; + +static isc_thread_t blockedthread; + +/* Events to wait for */ + +#define NUM_EVENTS 2 + +enum { + RELOAD_EVENT, + SHUTDOWN_EVENT +}; + +static HANDLE hEvents[NUM_EVENTS]; +DWORD dwWaitResult; + +/* + * We need to remember which thread is the main thread... + */ +static isc_thread_t main_thread; + +isc_result_t +isc__app_start(void) { + isc_result_t result; + + /* + * Start an ISC library application. + */ + + main_thread = GetCurrentThread(); + + result = isc_mutex_init(&lock); + if (result != ISC_R_SUCCESS) + return (result); + + /* Create the reload event in a non-signaled state */ + hEvents[RELOAD_EVENT] = CreateEvent(NULL, FALSE, FALSE, NULL); + + /* Create the shutdown event in a non-signaled state */ + hEvents[SHUTDOWN_EVENT] = CreateEvent(NULL, FALSE, FALSE, NULL); + + ISC_LIST_INIT(on_run); + return (ISC_R_SUCCESS); +} + +isc_result_t +isc__app_onrun(isc_mem_t *mctx, isc_task_t *task, isc_taskaction_t action, + void *arg) { + isc_event_t *event; + isc_task_t *cloned_task = NULL; + isc_result_t result; + + + LOCK(&lock); + if (running) { + result = ISC_R_ALREADYRUNNING; + goto unlock; + } + + /* + * Note that we store the task to which we're going to send the event + * in the event's "sender" field. + */ + isc_task_attach(task, &cloned_task); + event = isc_event_allocate(mctx, cloned_task, ISC_APPEVENT_SHUTDOWN, + action, arg, sizeof(*event)); + if (event == NULL) { + result = ISC_R_NOMEMORY; + goto unlock; + } + + ISC_LIST_APPEND(on_run, event, ev_link); + result = ISC_R_SUCCESS; + + unlock: + UNLOCK(&lock); + return (result); +} + +isc_result_t +isc__app_run(void) { + isc_event_t *event, *next_event; + isc_task_t *task; + HANDLE *pHandles = NULL; + + REQUIRE(main_thread == GetCurrentThread()); + LOCK(&lock); + if (!running) { + running = ISC_TRUE; + + /* + * Post any on-run events (in FIFO order). + */ + for (event = ISC_LIST_HEAD(on_run); + event != NULL; + event = next_event) { + next_event = ISC_LIST_NEXT(event, ev_link); + ISC_LIST_UNLINK(on_run, event, ev_link); + task = event->ev_sender; + event->ev_sender = NULL; + isc_task_sendanddetach(&task, &event); + } + + } + + UNLOCK(&lock); + + /* + * There is no danger if isc_app_shutdown() is called before we wait + * for events. + */ + + while (!want_shutdown) { + dwWaitResult = WaitForMultipleObjects(NUM_EVENTS, hEvents, + FALSE, INFINITE); + + /* See why we returned */ + + if (WaitSucceeded(dwWaitResult, NUM_EVENTS)) { + /* + * The return was due to one of the events + * being signaled + */ + switch (WaitSucceededIndex(dwWaitResult)) { + case RELOAD_EVENT: + want_reload = ISC_TRUE; + break; + + case SHUTDOWN_EVENT: + want_shutdown = ISC_TRUE; + break; + } + } + if (want_reload) { + want_reload = ISC_FALSE; + return (ISC_R_RELOAD); + } + + if (want_shutdown && blocked) + exit(-1); + } + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc__app_shutdown(void) { + isc_boolean_t want_kill = ISC_TRUE; + + LOCK(&lock); + REQUIRE(running); + + if (shutdown_requested) + want_kill = ISC_FALSE; /* We're only signaling once */ + else + shutdown_requested = ISC_TRUE; + + UNLOCK(&lock); + if (want_kill) + SetEvent(hEvents[SHUTDOWN_EVENT]); + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc__app_reload(void) { + isc_boolean_t want_reload = ISC_TRUE; + + LOCK(&lock); + REQUIRE(running); + + /* + * Don't send the reload signal if we're shutting down. + */ + if (shutdown_requested) + want_reload = ISC_FALSE; + + UNLOCK(&lock); + if (want_reload) + SetEvent(hEvents[RELOAD_EVENT]); + + return (ISC_R_SUCCESS); +} + +void +isc__app_finish(void) { + DESTROYLOCK(&lock); +} + +void +isc__app_block(void) { + REQUIRE(running); + REQUIRE(!blocked); + + blocked = ISC_TRUE; + blockedthread = GetCurrentThread(); +} + +void +isc__app_unblock(void) { + REQUIRE(running); + REQUIRE(blocked); + blocked = ISC_FALSE; + REQUIRE(blockedthread == GetCurrentThread()); +} diff --git a/contrib/ntp/lib/isc/win32/condition.c b/contrib/ntp/lib/isc/win32/condition.c new file mode 100644 index 0000000..27d4e76 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/condition.c @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2004, 2006, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: condition.c,v 1.23 2007/06/18 23:47:49 tbox Exp $ */ + +#include <config.h> + +#include <isc/condition.h> +#include <isc/assertions.h> +#include <isc/util.h> +#include <isc/thread.h> +#include <isc/time.h> + +#define LSIGNAL 0 +#define LBROADCAST 1 + +isc_result_t +isc_condition_init(isc_condition_t *cond) { + HANDLE h; + + REQUIRE(cond != NULL); + + cond->waiters = 0; + /* + * This handle is shared across all threads + */ + h = CreateEvent(NULL, FALSE, FALSE, NULL); + if (h == NULL) { + /* XXX */ + return (ISC_R_UNEXPECTED); + } + cond->events[LSIGNAL] = h; + + /* + * The threadlist will hold the actual events needed + * for the wait condition + */ + ISC_LIST_INIT(cond->threadlist); + + return (ISC_R_SUCCESS); +} + +/* + * Add the thread to the threadlist along with the required events + */ +static isc_result_t +register_thread(unsigned long thrd, isc_condition_t *gblcond, + isc_condition_thread_t **localcond) +{ + HANDLE hc; + isc_condition_thread_t *newthread; + + REQUIRE(localcond != NULL && *localcond == NULL); + + newthread = malloc(sizeof(isc_condition_thread_t)); + if (newthread == NULL) + return (ISC_R_NOMEMORY); + + /* + * Create the thread-specific handle + */ + hc = CreateEvent(NULL, FALSE, FALSE, NULL); + if (hc == NULL) { + free(newthread); + return (ISC_R_UNEXPECTED); + } + + /* + * Add the thread ID and handles to list of threads for broadcast + */ + newthread->handle[LSIGNAL] = gblcond->events[LSIGNAL]; + newthread->handle[LBROADCAST] = hc; + newthread->th = thrd; + + /* + * The thread is holding the manager lock so this is safe + */ + ISC_LIST_APPEND(gblcond->threadlist, newthread, link); + *localcond = newthread; + return (ISC_R_SUCCESS); +} + +static isc_result_t +find_thread_condition(unsigned long thrd, isc_condition_t *cond, + isc_condition_thread_t **threadcondp) +{ + isc_condition_thread_t *threadcond; + + REQUIRE(threadcondp != NULL && *threadcondp == NULL); + + /* + * Look for the thread ID. + */ + for (threadcond = ISC_LIST_HEAD(cond->threadlist); + threadcond != NULL; + threadcond = ISC_LIST_NEXT(threadcond, link)) { + + if (threadcond->th == thrd) { + *threadcondp = threadcond; + return (ISC_R_SUCCESS); + } + } + + /* + * Not found, so add it. + */ + return (register_thread(thrd, cond, threadcondp)); +} + +isc_result_t +isc_condition_signal(isc_condition_t *cond) { + + /* + * Unlike pthreads, the caller MUST hold the lock associated with + * the condition variable when calling us. + */ + REQUIRE(cond != NULL); + + if (!SetEvent(cond->events[LSIGNAL])) { + /* XXX */ + return (ISC_R_UNEXPECTED); + } + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_condition_broadcast(isc_condition_t *cond) { + + isc_condition_thread_t *threadcond; + isc_boolean_t failed = ISC_FALSE; + + /* + * Unlike pthreads, the caller MUST hold the lock associated with + * the condition variable when calling us. + */ + REQUIRE(cond != NULL); + + /* + * Notify every thread registered for this + */ + for (threadcond = ISC_LIST_HEAD(cond->threadlist); + threadcond != NULL; + threadcond = ISC_LIST_NEXT(threadcond, link)) { + + if (!SetEvent(threadcond->handle[LBROADCAST])) + failed = ISC_TRUE; + } + + if (failed) + return (ISC_R_UNEXPECTED); + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_condition_destroy(isc_condition_t *cond) { + + isc_condition_thread_t *next, *threadcond; + + REQUIRE(cond != NULL); + REQUIRE(cond->waiters == 0); + + (void)CloseHandle(cond->events[LSIGNAL]); + + /* + * Delete the threadlist + */ + threadcond = ISC_LIST_HEAD(cond->threadlist); + + while (threadcond != NULL) { + next = ISC_LIST_NEXT(threadcond, link); + DEQUEUE(cond->threadlist, threadcond, link); + (void) CloseHandle(threadcond->handle[LBROADCAST]); + free(threadcond); + threadcond = next; + } + + return (ISC_R_SUCCESS); +} + +/* + * This is always called when the mutex (lock) is held, but because + * we are waiting we need to release it and reacquire it as soon as the wait + * is over. This allows other threads to make use of the object guarded + * by the mutex but it should never try to delete it as long as the + * number of waiters > 0. Always reacquire the mutex regardless of the + * result of the wait. Note that EnterCriticalSection will wait to acquire + * the mutex. + */ +static isc_result_t +wait(isc_condition_t *cond, isc_mutex_t *mutex, DWORD milliseconds) { + DWORD result; + isc_result_t tresult; + isc_condition_thread_t *threadcond = NULL; + + /* + * Get the thread events needed for the wait + */ + tresult = find_thread_condition(isc_thread_self(), cond, &threadcond); + if (tresult != ISC_R_SUCCESS) + return (tresult); + + cond->waiters++; + LeaveCriticalSection(mutex); + result = WaitForMultipleObjects(2, threadcond->handle, FALSE, + milliseconds); + EnterCriticalSection(mutex); + cond->waiters--; + if (result == WAIT_FAILED) { + /* XXX */ + return (ISC_R_UNEXPECTED); + } + if (result == WAIT_TIMEOUT) + return (ISC_R_TIMEDOUT); + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_condition_wait(isc_condition_t *cond, isc_mutex_t *mutex) { + return (wait(cond, mutex, INFINITE)); +} + +isc_result_t +isc_condition_waituntil(isc_condition_t *cond, isc_mutex_t *mutex, + isc_time_t *t) { + DWORD milliseconds; + isc_uint64_t microseconds; + isc_time_t now; + + if (isc_time_now(&now) != ISC_R_SUCCESS) { + /* XXX */ + return (ISC_R_UNEXPECTED); + } + + microseconds = isc_time_microdiff(t, &now); + if (microseconds > 0xFFFFFFFFi64 * 1000) + milliseconds = 0xFFFFFFFF; + else + milliseconds = (DWORD)(microseconds / 1000); + + return (wait(cond, mutex, milliseconds)); +} diff --git a/contrib/ntp/lib/isc/win32/dir.c b/contrib/ntp/lib/isc/win32/dir.c new file mode 100644 index 0000000..14fadde --- /dev/null +++ b/contrib/ntp/lib/isc/win32/dir.c @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2004, 2007-2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/* Principal Authors: DCL */ + +#include <config.h> + +#include <string.h> +#include <direct.h> +#include <process.h> +#include <io.h> + +#include <sys/stat.h> + +#include <isc/dir.h> +#include <isc/magic.h> +#include <isc/assertions.h> +#include <isc/util.h> + +#include "errno2result.h" + +#define ISC_DIR_MAGIC ISC_MAGIC('D', 'I', 'R', '*') +#define VALID_DIR(dir) ISC_MAGIC_VALID(dir, ISC_DIR_MAGIC) + +static isc_result_t +start_directory(isc_dir_t *p); + +void +isc_dir_init(isc_dir_t *dir) { + REQUIRE(dir != NULL); + + dir->dirname[0] = '\0'; + + dir->entry.name[0] = '\0'; + dir->entry.length = 0; + memset(&(dir->entry.find_data), 0, sizeof(dir->entry.find_data)); + + dir->entry_filled = ISC_FALSE; + dir->search_handle = INVALID_HANDLE_VALUE; + + dir->magic = ISC_DIR_MAGIC; +} + +/* + * Allocate workspace and open directory stream. If either one fails, + * NULL will be returned. + */ +isc_result_t +isc_dir_open(isc_dir_t *dir, const char *dirname) { + char *p; + isc_result_t result; + + REQUIRE(dirname != NULL); + REQUIRE(VALID_DIR(dir) && dir->search_handle == INVALID_HANDLE_VALUE); + + /* + * Copy directory name. Need to have enough space for the name, + * a possible path separator, the wildcard, and the final NUL. + */ + if (strlen(dirname) + 3 > sizeof(dir->dirname)) + /* XXXDCL ? */ + return (ISC_R_NOSPACE); + strcpy(dir->dirname, dirname); + + /* + * Append path separator, if needed, and "*". + */ + p = dir->dirname + strlen(dir->dirname); + if (dir->dirname < p && *(p - 1) != '\\' && *(p - 1) != ':') + *p++ = '\\'; + *p++ = '*'; + *p = '\0'; + + /* + * Open stream. + */ + result = start_directory(dir); + + return (result); +} + +/* + * Return previously retrieved file or get next one. Unix's dirent has + * separate open and read functions, but the Win32 and DOS interfaces open + * the dir stream and reads the first file in one operation. + */ +isc_result_t +isc_dir_read(isc_dir_t *dir) { + REQUIRE(VALID_DIR(dir) && dir->search_handle != INVALID_HANDLE_VALUE); + + if (dir->entry_filled) + /* + * start_directory() already filled in the first entry. + */ + dir->entry_filled = ISC_FALSE; + + else { + /* + * Fetch next file in directory. + */ + if (FindNextFile(dir->search_handle, + &dir->entry.find_data) == FALSE) + /* + * Either the last file has been processed or + * an error has occurred. The former is not + * really an error, but the latter is. + */ + if (GetLastError() == ERROR_NO_MORE_FILES) + return (ISC_R_NOMORE); + else + return (ISC_R_UNEXPECTED); + } + + /* + * Make sure that the space for the name is long enough. + */ + strcpy(dir->entry.name, dir->entry.find_data.cFileName); + dir->entry.length = strlen(dir->entry.name); + + return (ISC_R_SUCCESS); +} + +/* + * Close directory stream. + */ +void +isc_dir_close(isc_dir_t *dir) { + REQUIRE(VALID_DIR(dir) && dir->search_handle != INVALID_HANDLE_VALUE); + + FindClose(dir->search_handle); + dir->search_handle = INVALID_HANDLE_VALUE; +} + +/* + * Reposition directory stream at start. + */ +isc_result_t +isc_dir_reset(isc_dir_t *dir) { + isc_result_t result; + + REQUIRE(VALID_DIR(dir) && dir->search_handle != INVALID_HANDLE_VALUE); + REQUIRE(dir->dirname != NULL); + + /* + * NT cannot reposition the seek pointer to the beginning of the + * the directory stream, but rather the directory needs to be + * closed and reopened. The latter might fail. + */ + + isc_dir_close(dir); + + result = start_directory(dir); + + return (result); +} + +/* + * Initialize isc_dir_t structure with new directory. The function + * returns 0 on failure and nonzero on success. + * + * Note: + * - Be sure to close previous stream before opening new one + */ +static isc_result_t +start_directory(isc_dir_t *dir) +{ + REQUIRE(VALID_DIR(dir)); + REQUIRE(dir->search_handle == INVALID_HANDLE_VALUE); + + dir->entry_filled = ISC_FALSE; + + /* + * Open stream and retrieve first file. + */ + dir->search_handle = FindFirstFile(dir->dirname, + &dir->entry.find_data); + + if (dir->search_handle == INVALID_HANDLE_VALUE) { + /* + * Something went wrong but we don't know what. GetLastError() + * could give us more information about the error, but the + * MSDN documentation is frustratingly thin about what + * possible errors could have resulted. (Score one for + * the Unix manual pages.) So there is just this lame error + * instead of being able to differentiate ISC_R_NOTFOUND + * from ISC_R_UNEXPECTED. + */ + return (ISC_R_FAILURE); + } + + /* + * Make sure that the space for the name is long enough. + */ + INSIST(sizeof(dir->entry.name) > + strlen(dir->entry.find_data.cFileName)); + + /* + * Fill in the data for the first entry of the directory. + */ + strcpy(dir->entry.name, dir->entry.find_data.cFileName); + dir->entry.length = strlen(dir->entry.name); + + dir->entry_filled = ISC_TRUE; + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_dir_chdir(const char *dirname) { + /* + * Change the current directory to 'dirname'. + */ + + REQUIRE(dirname != NULL); + + if (chdir(dirname) < 0) + return (isc__errno2result(errno)); + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_dir_chroot(const char *dirname) { + return (ISC_R_NOTIMPLEMENTED); +} + +isc_result_t +isc_dir_createunique(char *templet) { + isc_result_t result; + char *x; + char *p; + int i; + int pid; + + REQUIRE(templet != NULL); + + /* + * mkdtemp is not portable, so this emulates it. + */ + + pid = getpid(); + + /* + * Replace trailing Xs with the process-id, zero-filled. + */ + for (x = templet + strlen(templet) - 1; *x == 'X' && x >= templet; + x--, pid /= 10) + *x = pid % 10 + '0'; + + x++; /* Set x to start of ex-Xs. */ + + do { + i = mkdir(templet); + i = chmod(templet, 0700); + + if (i == 0 || errno != EEXIST) + break; + + /* + * The BSD algorithm. + */ + p = x; + while (*p != '\0') { + if (isdigit(*p & 0xff)) + *p = 'a'; + else if (*p != 'z') + ++*p; + else { + /* + * Reset character and move to next. + */ + *p++ = 'a'; + continue; + } + + break; + } + + if (*p == '\0') { + /* + * Tried all combinations. errno should already + * be EEXIST, but ensure it is anyway for + * isc__errno2result(). + */ + errno = EEXIST; + break; + } + } while (1); + + if (i == -1) + result = isc__errno2result(errno); + else + result = ISC_R_SUCCESS; + + return (result); +} diff --git a/contrib/ntp/lib/isc/win32/entropy.c b/contrib/ntp/lib/isc/win32/entropy.c new file mode 100644 index 0000000..5a316e6 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/entropy.c @@ -0,0 +1,307 @@ +/* + * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000-2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: entropy.c,v 1.10 2009/01/18 23:48:14 tbox Exp $ */ + +/* + * This is the system dependent part of the ISC entropy API. + */ + +#include <config.h> + +#include <windows.h> +#include <wincrypt.h> + +#include <process.h> +#include <io.h> +#include <share.h> + +/* + * There is only one variable in the entropy data structures that is not + * system independent, but pulling the structure that uses it into this file + * ultimately means pulling several other independent structures here also to + * resolve their interdependencies. Thus only the problem variable's type + * is defined here. + */ +#define FILESOURCE_HANDLE_TYPE HCRYPTPROV + +typedef struct { + int dummy; +} isc_entropyusocketsource_t; + +#include "../entropy.c" + +static unsigned int +get_from_filesource(isc_entropysource_t *source, isc_uint32_t desired) { + isc_entropy_t *ent = source->ent; + unsigned char buf[128]; + HCRYPTPROV hcryptprov = source->sources.file.handle; + ssize_t ndesired; + unsigned int added; + + if (source->bad) + return (0); + + desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0); + + added = 0; + while (desired > 0) { + ndesired = ISC_MIN(desired, sizeof(buf)); + if (!CryptGenRandom(hcryptprov, ndesired, buf)) { + CryptReleaseContext(hcryptprov, 0); + source->bad = ISC_TRUE; + goto out; + } + + entropypool_adddata(ent, buf, ndesired, ndesired * 8); + added += ndesired * 8; + desired -= ndesired; + } + + out: + return (added); +} + +/* + * Poll each source, trying to get data from it to stuff into the entropy + * pool. + */ +static void +fillpool(isc_entropy_t *ent, unsigned int desired, isc_boolean_t blocking) { + unsigned int added; + unsigned int remaining; + unsigned int needed; + unsigned int nsource; + isc_entropysource_t *source; + isc_entropysource_t *firstsource; + + REQUIRE(VALID_ENTROPY(ent)); + + needed = desired; + + /* + * This logic is a little strange, so an explanation is in order. + * + * If needed is 0, it means we are being asked to "fill to whatever + * we think is best." This means that if we have at least a + * partially full pool (say, > 1/4th of the pool) we probably don't + * need to add anything. + * + * Also, we will check to see if the "pseudo" count is too high. + * If it is, try to mix in better data. Too high is currently + * defined as 1/4th of the pool. + * + * Next, if we are asked to add a specific bit of entropy, make + * certain that we will do so. Clamp how much we try to add to + * (DIGEST_SIZE * 8 < needed < POOLBITS - entropy). + * + * Note that if we are in a blocking mode, we will only try to + * get as much data as we need, not as much as we might want + * to build up. + */ + if (needed == 0) { + REQUIRE(!blocking); + + if ((ent->pool.entropy >= RND_POOLBITS / 4) + && (ent->pool.pseudo <= RND_POOLBITS / 4)) + return; + + needed = THRESHOLD_BITS * 4; + } else { + needed = ISC_MAX(needed, THRESHOLD_BITS); + needed = ISC_MIN(needed, RND_POOLBITS); + } + + /* + * In any case, clamp how much we need to how much we can add. + */ + needed = ISC_MIN(needed, RND_POOLBITS - ent->pool.entropy); + + /* + * But wait! If we're not yet initialized, we need at least + * THRESHOLD_BITS + * of randomness. + */ + if (ent->initialized < THRESHOLD_BITS) + needed = ISC_MAX(needed, THRESHOLD_BITS - ent->initialized); + + /* + * Poll each file source to see if we can read anything useful from + * it. XXXMLG When where are multiple sources, we should keep a + * record of which one we last used so we can start from it (or the + * next one) to avoid letting some sources build up entropy while + * others are always drained. + */ + + added = 0; + remaining = needed; + if (ent->nextsource == NULL) { + ent->nextsource = ISC_LIST_HEAD(ent->sources); + if (ent->nextsource == NULL) + return; + } + source = ent->nextsource; + /* + * Remember the first source so we can break if we have looped back to + * the beginning and still have nothing + */ + firstsource = source; + again_file: + for (nsource = 0; nsource < ent->nsources; nsource++) { + unsigned int got; + + if (remaining == 0) + break; + + got = 0; + + if (source->type == ENTROPY_SOURCETYPE_FILE) + got = get_from_filesource(source, remaining); + + added += got; + + remaining -= ISC_MIN(remaining, got); + + source = ISC_LIST_NEXT(source, link); + if (source == NULL) + source = ISC_LIST_HEAD(ent->sources); + } + ent->nextsource = source; + + /* + * Go again only if there's been progress and we've not + * gone back to the beginning + */ + if (!(ent->nextsource == firstsource && added == 0)) { + if (blocking && remaining != 0) { + goto again_file; + } + } + + /* + * Here, if there are bits remaining to be had and we can block, + * check to see if we have a callback source. If so, call them. + */ + source = ISC_LIST_HEAD(ent->sources); + while ((remaining != 0) && (source != NULL)) { + unsigned int got; + + got = 0; + + if (source->type == ENTROPY_SOURCETYPE_CALLBACK) + got = get_from_callback(source, remaining, blocking); + + added += got; + remaining -= ISC_MIN(remaining, got); + + if (added >= needed) + break; + + source = ISC_LIST_NEXT(source, link); + } + + /* + * Mark as initialized if we've added enough data. + */ + if (ent->initialized < THRESHOLD_BITS) + ent->initialized += added; +} + + + +/* + * Requires "ent" be locked. + */ +static void +destroyfilesource(isc_entropyfilesource_t *source) { + CryptReleaseContext(source->handle, 0); +} + +static void +destroyusocketsource(isc_entropyusocketsource_t *source) { + UNUSED(source); +} + + +isc_result_t +isc_entropy_createfilesource(isc_entropy_t *ent, const char *fname) { + isc_result_t ret; + isc_entropysource_t *source; + HCRYPTPROV hcryptprov; + DWORD errval; + BOOL err; + + REQUIRE(VALID_ENTROPY(ent)); + REQUIRE(fname != NULL); + + LOCK(&ent->lock); + + source = NULL; + + /* + * The first time we just try to acquire the context + */ + err = CryptAcquireContext(&hcryptprov, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT); + if (!err){ + errval = GetLastError(); + ret = ISC_R_IOERROR; + goto errout; + } + + source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t)); + if (source == NULL) { + ret = ISC_R_NOMEMORY; + goto closecontext; + } + + /* + * From here down, no failures can occur. + */ + source->magic = SOURCE_MAGIC; + source->type = ENTROPY_SOURCETYPE_FILE; + source->ent = ent; + source->total = 0; + source->bad = ISC_FALSE; + memset(source->name, 0, sizeof(source->name)); + ISC_LINK_INIT(source, link); + source->sources.file.handle = hcryptprov; + + /* + * Hook it into the entropy system. + */ + ISC_LIST_APPEND(ent->sources, source, link); + ent->nsources++; + + UNLOCK(&ent->lock); + return (ISC_R_SUCCESS); + + closecontext: + CryptReleaseContext(hcryptprov, 0); + + errout: + if (source != NULL) + isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t)); + + UNLOCK(&ent->lock); + + return (ret); +} + + + + diff --git a/contrib/ntp/lib/isc/win32/errno2result.c b/contrib/ntp/lib/isc/win32/errno2result.c new file mode 100644 index 0000000..c3d54d6 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/errno2result.c @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000-2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: errno2result.c,v 1.17 2008/09/12 04:46:25 marka Exp $ */ + +#include <config.h> + +#include <winsock2.h> +#include "errno2result.h" +#include <isc/result.h> +#include <isc/strerror.h> +#include <isc/util.h> + +/* + * Convert a POSIX errno value into an isc_result_t. The + * list of supported errno values is not complete; new users + * of this function should add any expected errors that are + * not already there. + */ +isc_result_t +isc__errno2resultx(int posixerrno, const char *file, int line) { + char strbuf[ISC_STRERRORSIZE]; + + switch (posixerrno) { + case ENOTDIR: + case WSAELOOP: + case WSAEINVAL: + case EINVAL: /* XXX sometimes this is not for files */ + case ENAMETOOLONG: + case WSAENAMETOOLONG: + case EBADF: + case WSAEBADF: + return (ISC_R_INVALIDFILE); + case ENOENT: + return (ISC_R_FILENOTFOUND); + case EACCES: + case WSAEACCES: + case EPERM: + return (ISC_R_NOPERM); + case EEXIST: + return (ISC_R_FILEEXISTS); + case EIO: + return (ISC_R_IOERROR); + case ENOMEM: + return (ISC_R_NOMEMORY); + case ENFILE: + case EMFILE: + case WSAEMFILE: + return (ISC_R_TOOMANYOPENFILES); + case ERROR_CANCELLED: + return (ISC_R_CANCELED); + case ERROR_CONNECTION_REFUSED: + case WSAECONNREFUSED: + return (ISC_R_CONNREFUSED); + case WSAENOTCONN: + case ERROR_CONNECTION_INVALID: + return (ISC_R_NOTCONNECTED); + case ERROR_HOST_UNREACHABLE: + case WSAEHOSTUNREACH: + return (ISC_R_HOSTUNREACH); + case ERROR_NETWORK_UNREACHABLE: + case WSAENETUNREACH: + return (ISC_R_NETUNREACH); + case ERROR_NO_NETWORK: + return (ISC_R_NETUNREACH); + case ERROR_PORT_UNREACHABLE: + return (ISC_R_HOSTUNREACH); + case ERROR_SEM_TIMEOUT: + return (ISC_R_TIMEDOUT); + case WSAECONNRESET: + case WSAENETRESET: + case WSAECONNABORTED: + case WSAEDISCON: + case ERROR_OPERATION_ABORTED: + case ERROR_CONNECTION_ABORTED: + case ERROR_REQUEST_ABORTED: + return (ISC_R_CONNECTIONRESET); + case WSAEADDRNOTAVAIL: + return (ISC_R_ADDRNOTAVAIL); + case ERROR_NETNAME_DELETED: + case WSAENETDOWN: + return (ISC_R_NETUNREACH); + case WSAEHOSTDOWN: + return (ISC_R_HOSTUNREACH); + case WSAENOBUFS: + return (ISC_R_NORESOURCES); + default: + isc__strerror(posixerrno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(file, line, "unable to convert errno " + "to isc_result: %d: %s", posixerrno, strbuf); + /* + * XXXDCL would be nice if perhaps this function could + * return the system's error string, so the caller + * might have something more descriptive than "unexpected + * error" to log with. + */ + return (ISC_R_UNEXPECTED); + } +} diff --git a/contrib/ntp/lib/isc/win32/errno2result.h b/contrib/ntp/lib/isc/win32/errno2result.h new file mode 100644 index 0000000..41682db --- /dev/null +++ b/contrib/ntp/lib/isc/win32/errno2result.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: errno2result.h,v 1.10 2007/06/19 23:47:19 tbox Exp $ */ + +#ifndef UNIX_ERRNO2RESULT_H +#define UNIX_ERRNO2RESULT_H 1 + +/* XXXDCL this should be moved to lib/isc/include/isc/errno2result.h. */ + +#include <errno.h> /* Provides errno. */ + +#include <isc/lang.h> +#include <isc/types.h> + +ISC_LANG_BEGINDECLS + +#define isc__errno2result(posixerrno) \ + isc__errno2resultx(posixerrno, __FILE__, __LINE__) + +isc_result_t +isc__errno2resultx(int posixerrno, const char *file, int line); + +ISC_LANG_ENDDECLS + +#endif /* UNIX_ERRNO2RESULT_H */ diff --git a/contrib/ntp/lib/isc/win32/file.c b/contrib/ntp/lib/isc/win32/file.c new file mode 100644 index 0000000..c6b9e4f --- /dev/null +++ b/contrib/ntp/lib/isc/win32/file.c @@ -0,0 +1,619 @@ +/* + * Copyright (C) 2004, 2007, 2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000-2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +#include <config.h> + +#undef rename +#include <errno.h> +#include <limits.h> +#include <stdlib.h> +#include <io.h> +#include <process.h> + +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/utime.h> + +#include <isc/file.h> +#include <isc/mem.h> +#include <isc/result.h> +#include <isc/time.h> +#include <isc/util.h> +#include <isc/stat.h> +#include <isc/string.h> + +#include "errno2result.h" + +/* + * Emulate UNIX mkstemp, which returns an open FD to the new file + * + */ +static int +gettemp(char *path, int *doopen) { + char *start, *trv; + struct stat sbuf; + int pid; + + trv = strrchr(path, 'X'); + trv++; + pid = getpid(); + /* extra X's get set to 0's */ + while (*--trv == 'X') { + *trv = (pid % 10) + '0'; + pid /= 10; + } + /* + * check the target directory; if you have six X's and it + * doesn't exist this runs for a *very* long time. + */ + for (start = trv + 1;; --trv) { + if (trv <= path) + break; + if (*trv == '\\') { + *trv = '\0'; + if (stat(path, &sbuf)) + return (0); + if (!S_ISDIR(sbuf.st_mode)) { + errno = ENOTDIR; + return (0); + } + *trv = '\\'; + break; + } + } + + for (;;) { + if (doopen) { + if ((*doopen = + open(path, O_CREAT|O_EXCL|O_RDWR, + _S_IREAD | _S_IWRITE)) >= 0) + return (1); + if (errno != EEXIST) + return (0); + } else if (stat(path, &sbuf)) + return (errno == ENOENT ? 1 : 0); + + /* tricky little algorithm for backward compatibility */ + for (trv = start;;) { + if (!*trv) + return (0); + if (*trv == 'z') + *trv++ = 'a'; + else { + if (isdigit(*trv)) + *trv = 'a'; + else + ++*trv; + break; + } + } + } + /*NOTREACHED*/ +} + +static int +mkstemp(char *path) { + int fd; + + return (gettemp(path, &fd) ? fd : -1); +} + +/* + * XXXDCL As the API for accessing file statistics undoubtedly gets expanded, + * it might be good to provide a mechanism that allows for the results + * of a previous stat() to be used again without having to do another stat, + * such as perl's mechanism of using "_" in place of a file name to indicate + * that the results of the last stat should be used. But then you get into + * annoying MP issues. BTW, Win32 has stat(). + */ +static isc_result_t +file_stats(const char *file, struct stat *stats) { + isc_result_t result = ISC_R_SUCCESS; + + REQUIRE(file != NULL); + REQUIRE(stats != NULL); + + if (stat(file, stats) != 0) + result = isc__errno2result(errno); + + return (result); +} + +/* + * isc_file_safemovefile is needed to be defined here to ensure that + * any file with the new name is renamed to a backup name and then the + * rename is done. If all goes well then the backup can be deleted, + * otherwise it gets renamed back. + */ + +int +isc_file_safemovefile(const char *oldname, const char *newname) { + BOOL filestatus; + char buf[512]; + struct stat sbuf; + BOOL exists = FALSE; + int tmpfd; + + /* + * Make sure we have something to do + */ + if (stat(oldname, &sbuf) != 0) { + errno = ENOENT; + return (-1); + } + + /* + * Rename to a backup the new file if it still exists + */ + if (stat(newname, &sbuf) == 0) { + exists = TRUE; + strcpy(buf, newname); + strcat(buf, ".XXXXX"); + tmpfd = mkstemp(buf); + if (tmpfd > 0) + _close(tmpfd); + DeleteFile(buf); + _chmod(newname, _S_IREAD | _S_IWRITE); + + filestatus = MoveFile(newname, buf); + } + /* Now rename the file to the new name + */ + _chmod(oldname, _S_IREAD | _S_IWRITE); + + filestatus = MoveFile(oldname, newname); + if (filestatus == 0) { + /* + * Try to rename the backup back to the original name + * if the backup got created + */ + if (exists == TRUE) { + filestatus = MoveFile(buf, newname); + if (filestatus == 0) + errno = EACCES; + } + return (-1); + } + + /* + * Delete the backup file if it got created + */ + if (exists == TRUE) + filestatus = DeleteFile(buf); + return (0); +} + +isc_result_t +isc_file_getmodtime(const char *file, isc_time_t *time) { + int fh; + + REQUIRE(file != NULL); + REQUIRE(time != NULL); + + if ((fh = open(file, _O_RDONLY | _O_BINARY)) < 0) + return (isc__errno2result(errno)); + + if (!GetFileTime((HANDLE) _get_osfhandle(fh), + NULL, + NULL, + &time->absolute)) + { + close(fh); + errno = EINVAL; + return (isc__errno2result(errno)); + } + close(fh); + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_file_settime(const char *file, isc_time_t *time) { + int fh; + + REQUIRE(file != NULL && time != NULL); + + if ((fh = open(file, _O_RDWR | _O_BINARY)) < 0) + return (isc__errno2result(errno)); + + /* + * Set the date via the filedate system call and return. Failing + * this call implies the new file times are not supported by the + * underlying file system. + */ + if (!SetFileTime((HANDLE) _get_osfhandle(fh), + NULL, + &time->absolute, + &time->absolute)) + { + close(fh); + errno = EINVAL; + return (isc__errno2result(errno)); + } + + close(fh); + return (ISC_R_SUCCESS); + +} + +#undef TEMPLATE +#define TEMPLATE "XXXXXXXXXX.tmp" /* 14 characters. */ + +isc_result_t +isc_file_mktemplate(const char *path, char *buf, size_t buflen) { + return (isc_file_template(path, TEMPLATE, buf, buflen)); +} + +isc_result_t +isc_file_template(const char *path, const char *templet, char *buf, + size_t buflen) { + char *s; + + REQUIRE(path != NULL); + REQUIRE(templet != NULL); + REQUIRE(buf != NULL); + + s = strrchr(templet, '\\'); + if (s != NULL) + templet = s + 1; + + s = strrchr(path, '\\'); + + if (s != NULL) { + if ((s - path + 1 + strlen(templet) + 1) > buflen) + return (ISC_R_NOSPACE); + + strncpy(buf, path, s - path + 1); + buf[s - path + 1] = '\0'; + strcat(buf, templet); + } else { + if ((strlen(templet) + 1) > buflen) + return (ISC_R_NOSPACE); + + strcpy(buf, templet); + } + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_file_renameunique(const char *file, char *templet) { + int fd = -1; + int res = 0; + isc_result_t result = ISC_R_SUCCESS; + + REQUIRE(file != NULL); + REQUIRE(templet != NULL); + + fd = mkstemp(templet); + if (fd == -1) + result = isc__errno2result(errno); + else + close(fd); + + if (result == ISC_R_SUCCESS) { + res = isc_file_safemovefile(file, templet); + if (res != 0) { + result = isc__errno2result(errno); + (void)unlink(templet); + } + } + return (result); +} + +isc_result_t +isc_file_openuniqueprivate(char *templet, FILE **fp) { + int mode = _S_IREAD | _S_IWRITE; + return (isc_file_openuniquemode(templet, mode, fp)); +} + +isc_result_t +isc_file_openunique(char *templet, FILE **fp) { + int mode = _S_IREAD | _S_IWRITE; + return (isc_file_openuniquemode(templet, mode, fp)); +} + +isc_result_t +isc_file_openuniquemode(char *templet, int mode, FILE **fp) { + int fd; + FILE *f; + isc_result_t result = ISC_R_SUCCESS; + + REQUIRE(templet != NULL); + REQUIRE(fp != NULL && *fp == NULL); + + /* + * Win32 does not have mkstemp. Using emulation above. + */ + fd = mkstemp(templet); + + if (fd == -1) + result = isc__errno2result(errno); + if (result == ISC_R_SUCCESS) { +#if 1 + UNUSED(mode); +#else + (void)fchmod(fd, mode); +#endif + f = fdopen(fd, "w+"); + if (f == NULL) { + result = isc__errno2result(errno); + (void)remove(templet); + (void)close(fd); + } else + *fp = f; + } + + return (result); +} + +isc_result_t +isc_file_remove(const char *filename) { + int r; + + REQUIRE(filename != NULL); + + r = unlink(filename); + if (r == 0) + return (ISC_R_SUCCESS); + else + return (isc__errno2result(errno)); +} + +isc_result_t +isc_file_rename(const char *oldname, const char *newname) { + int r; + + REQUIRE(oldname != NULL); + REQUIRE(newname != NULL); + + r = isc_file_safemovefile(oldname, newname); + if (r == 0) + return (ISC_R_SUCCESS); + else + return (isc__errno2result(errno)); +} + +isc_boolean_t +isc_file_exists(const char *pathname) { + struct stat stats; + + REQUIRE(pathname != NULL); + + return (ISC_TF(file_stats(pathname, &stats) == ISC_R_SUCCESS)); +} + +isc_result_t +isc_file_isplainfile(const char *filename) { + /* + * This function returns success if filename is a plain file. + */ + struct stat filestat; + memset(&filestat,0,sizeof(struct stat)); + + if ((stat(filename, &filestat)) == -1) + return(isc__errno2result(errno)); + + if(! S_ISREG(filestat.st_mode)) + return(ISC_R_INVALIDFILE); + + return(ISC_R_SUCCESS); +} + +isc_boolean_t +isc_file_isabsolute(const char *filename) { + REQUIRE(filename != NULL); + /* + * Look for c:\path\... style, c:/path/... or \\computer\shar\path... + * the UNC style file specs + */ + if ((filename[0] == '\\') && (filename[1] == '\\')) + return (ISC_TRUE); + if (isalpha(filename[0]) && filename[1] == ':' && filename[2] == '\\') + return (ISC_TRUE); + if (isalpha(filename[0]) && filename[1] == ':' && filename[2] == '/') + return (ISC_TRUE); + return (ISC_FALSE); +} + +isc_boolean_t +isc_file_iscurrentdir(const char *filename) { + REQUIRE(filename != NULL); + return (ISC_TF(filename[0] == '.' && filename[1] == '\0')); +} + +isc_boolean_t +isc_file_ischdiridempotent(const char *filename) { + REQUIRE(filename != NULL); + + if (isc_file_isabsolute(filename)) + return (ISC_TRUE); + if (filename[0] == '\\') + return (ISC_TRUE); + if (filename[0] == '/') + return (ISC_TRUE); + if (isc_file_iscurrentdir(filename)) + return (ISC_TRUE); + return (ISC_FALSE); +} + +const char * +isc_file_basename(const char *filename) { + char *s; + + REQUIRE(filename != NULL); + + s = strrchr(filename, '\\'); + if (s == NULL) + return (filename); + return (s + 1); +} + +isc_result_t +isc_file_progname(const char *filename, char *progname, size_t namelen) { + const char *s; + char *p; + size_t len; + + REQUIRE(filename != NULL); + REQUIRE(progname != NULL); + + /* + * Strip the path from the name + */ + s = isc_file_basename(filename); + if (s == NULL) { + return (ISC_R_NOSPACE); + } + + /* + * Strip any and all suffixes + */ + p = strchr(s, '.'); + if (p == NULL) { + if (namelen <= strlen(s)) + return (ISC_R_NOSPACE); + + strcpy(progname, s); + return (ISC_R_SUCCESS); + } + + /* + * Copy the result to the buffer + */ + len = p - s; + if (len >= namelen) + return (ISC_R_NOSPACE); + + strncpy(progname, s, len); + progname[len] = '\0'; + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_file_absolutepath(const char *filename, char *path, size_t pathlen) { + char *ptrname; + DWORD retval; + + REQUIRE(filename != NULL); + REQUIRE(path != NULL); + + retval = GetFullPathName(filename, pathlen, path, &ptrname); + + /* Something went wrong in getting the path */ + if (retval == 0) + return (ISC_R_NOTFOUND); + /* Caller needs to provide a larger buffer to contain the string */ + if (retval >= pathlen) + return (ISC_R_NOSPACE); + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_file_truncate(const char *filename, isc_offset_t size) { + int fh; + + REQUIRE(filename != NULL && size >= 0); + + if ((fh = open(filename, _O_RDWR | _O_BINARY)) < 0) + return (isc__errno2result(errno)); + + if(_chsize(fh, size) != 0) { + close(fh); + return (isc__errno2result(errno)); + } + close(fh); + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_file_safecreate(const char *filename, FILE **fp) { + isc_result_t result; + int flags; + struct stat sb; + FILE *f; + int fd; + + REQUIRE(filename != NULL); + REQUIRE(fp != NULL && *fp == NULL); + + result = file_stats(filename, &sb); + if (result == ISC_R_SUCCESS) { + if ((sb.st_mode & S_IFREG) == 0) + return (ISC_R_INVALIDFILE); + flags = O_WRONLY | O_TRUNC; + } else if (result == ISC_R_FILENOTFOUND) { + flags = O_WRONLY | O_CREAT | O_EXCL; + } else + return (result); + + fd = open(filename, flags, S_IRUSR | S_IWUSR); + if (fd == -1) + return (isc__errno2result(errno)); + + f = fdopen(fd, "w"); + if (f == NULL) { + result = isc__errno2result(errno); + close(fd); + return (result); + } + + *fp = f; + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_file_splitpath(isc_mem_t *mctx, char *path, char **dirname, char **basename) +{ + char *dir, *file, *slash; + char *backslash; + + slash = strrchr(path, '/'); + + backslash = strrchr(path, '\\'); + if ((slash != NULL && backslash != NULL && backslash > slash) || + (slash == NULL && backslash != NULL)) + slash = backslash; + + if (slash == path) { + file = ++slash; + dir = isc_mem_strdup(mctx, "/"); + } else if (slash != NULL) { + file = ++slash; + dir = isc_mem_allocate(mctx, slash - path); + if (dir != NULL) + strlcpy(dir, path, slash - path); + } else { + file = path; + dir = isc_mem_strdup(mctx, "."); + } + + if (dir == NULL) + return (ISC_R_NOMEMORY); + + if (*file == '\0') { + isc_mem_free(mctx, dir); + return (ISC_R_INVALIDFILE); + } + + *dirname = dir; + *basename = file; + + return (ISC_R_SUCCESS); +} diff --git a/contrib/ntp/lib/isc/win32/fsaccess.c b/contrib/ntp/lib/isc/win32/fsaccess.c new file mode 100644 index 0000000..8de793f --- /dev/null +++ b/contrib/ntp/lib/isc/win32/fsaccess.c @@ -0,0 +1,375 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000-2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: fsaccess.c,v 1.15 2007/06/19 23:47:19 tbox Exp $ */ + +/* + * Note that Win32 does not have the concept of files having access + * and ownership bits. The FAT File system only has a readonly flag + * for everyone and that's all. NTFS uses ACL's which is a totally + * different concept of controlling access. + * + * This code needs to be revisited to set up proper access control for + * NTFS file systems. Nothing can be done for FAT file systems. + */ + +#include <config.h> + +#include <aclapi.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <io.h> +#include <errno.h> + +#include <isc/file.h> +#include <isc/stat.h> + +#include "errno2result.h" + +/* + * The OS-independent part of the API is in lib/isc. + */ +#include "../fsaccess.c" + +/* Store the user account name locally */ +static char username[255] = "\0"; +static DWORD namelen = 0; + +/* + * In order to set or retrieve access information, we need to obtain + * the File System type. These could be UNC-type shares. + */ + +BOOL +is_ntfs(const char * file) { + + char drive[255]; + char FSType[20]; + char tmpbuf[256]; + char *machinename; + char *sharename; + char filename[1024]; + + REQUIRE(filename != NULL); + + if (isc_file_absolutepath(file, filename, + sizeof(filename)) != ISC_R_SUCCESS) { + return (FALSE); + } + + /* + * Look for c:\path\... style, c:/path/... or \\computer\shar\path... + * the UNC style file specs + */ + if (isalpha(filename[0]) && filename[1] == ':' && + (filename[2] == '\\' || filename[2] == '/')) { + strncpy(drive, filename, 3); + drive[3] = '\0'; + } + + else if ((filename[0] == '\\') && (filename[1] == '\\')) { + /* Find the machine and share name and rebuild the UNC */ + strcpy(tmpbuf, filename); + machinename = strtok(tmpbuf, "\\"); + sharename = strtok(NULL, "\\"); + strcpy(drive, "\\\\"); + strcat(drive, machinename); + strcat(drive, "\\"); + strcat(drive, sharename); + strcat(drive, "\\"); + + } + else /* Not determinable */ + return (FALSE); + + GetVolumeInformation(drive, NULL, 0, NULL, 0, NULL, FSType, + sizeof(FSType)); + if(strcmp(FSType,"NTFS") == 0) + return (TRUE); + else + return (FALSE); +} + +/* + * If it's not NTFS, we assume that it is FAT and proceed + * with almost nothing to do. Only the write flag can be set or + * cleared. + */ +isc_result_t +FAT_fsaccess_set(const char *path, isc_fsaccess_t access) { + int mode; + isc_fsaccess_t bits; + + /* + * Done with checking bad bits. Set mode_t. + */ + mode = 0; + +#define SET_AND_CLEAR1(modebit) \ + if ((access & bits) != 0) { \ + mode |= modebit; \ + access &= ~bits; \ + } +#define SET_AND_CLEAR(user, group, other) \ + SET_AND_CLEAR1(user); \ + bits <<= STEP; \ + SET_AND_CLEAR1(group); \ + bits <<= STEP; \ + SET_AND_CLEAR1(other); + + bits = ISC_FSACCESS_READ | ISC_FSACCESS_LISTDIRECTORY; + + SET_AND_CLEAR(S_IRUSR, S_IRGRP, S_IROTH); + + bits = ISC_FSACCESS_WRITE | + ISC_FSACCESS_CREATECHILD | + ISC_FSACCESS_DELETECHILD; + + SET_AND_CLEAR(S_IWUSR, S_IWGRP, S_IWOTH); + + INSIST(access == 0); + + if (_chmod(path, mode) < 0) + return (isc__errno2result(errno)); + + return (ISC_R_SUCCESS); +} + +isc_result_t +NTFS_Access_Control(const char *filename, const char *user, int access, + isc_boolean_t isdir) { + SECURITY_DESCRIPTOR sd; + BYTE aclBuffer[1024]; + PACL pacl=(PACL)&aclBuffer; + BYTE sidBuffer[100]; + PSID psid=(PSID) &sidBuffer; + DWORD sidBufferSize = sizeof(sidBuffer); + BYTE adminSidBuffer[100]; + PSID padminsid=(PSID) &adminSidBuffer; + DWORD adminSidBufferSize = sizeof(adminSidBuffer); + BYTE otherSidBuffer[100]; + PSID pothersid=(PSID) &otherSidBuffer; + DWORD otherSidBufferSize = sizeof(otherSidBuffer); + char domainBuffer[100]; + DWORD domainBufferSize = sizeof(domainBuffer); + SID_NAME_USE snu; + int errval; + DWORD NTFSbits; + int caccess; + + + /* Initialize an ACL */ + if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) + return (ISC_R_NOPERM); + if (!InitializeAcl(pacl, sizeof(aclBuffer), ACL_REVISION)) + return (ISC_R_NOPERM); + if (!LookupAccountName(0, user, psid, &sidBufferSize, domainBuffer, + &domainBufferSize, &snu)) + return (ISC_R_NOPERM); + domainBufferSize = sizeof(domainBuffer); + if (!LookupAccountName(0, "Administrators", padminsid, + &adminSidBufferSize, domainBuffer, &domainBufferSize, &snu)) { + errval = GetLastError(); + return (ISC_R_NOPERM); + } + domainBufferSize = sizeof(domainBuffer); + if (!LookupAccountName(0, "Everyone", pothersid, + &otherSidBufferSize, domainBuffer, &domainBufferSize, &snu)) { + errval = GetLastError(); + return (ISC_R_NOPERM); + } + + caccess = access; + /* Owner check */ + + NTFSbits = 0; + if (caccess & ISC_FSACCESS_READ) + NTFSbits |= FILE_GENERIC_READ; + if (caccess & ISC_FSACCESS_WRITE) + NTFSbits |= FILE_GENERIC_WRITE; + if (caccess & ISC_FSACCESS_EXECUTE) + NTFSbits |= FILE_GENERIC_EXECUTE; + + /* For directories check the directory-specific bits */ + if (isdir == ISC_TRUE) { + if (caccess & ISC_FSACCESS_CREATECHILD) + NTFSbits |= FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE; + if (caccess & ISC_FSACCESS_DELETECHILD) + NTFSbits |= FILE_DELETE_CHILD; + if (caccess & ISC_FSACCESS_LISTDIRECTORY) + NTFSbits |= FILE_LIST_DIRECTORY; + if (caccess & ISC_FSACCESS_ACCESSCHILD) + NTFSbits |= FILE_TRAVERSE; + } + + if (NTFSbits == (FILE_GENERIC_READ | FILE_GENERIC_WRITE + | FILE_GENERIC_EXECUTE)) + NTFSbits |= FILE_ALL_ACCESS; + /* + * Owner and Administrator also get STANDARD_RIGHTS_ALL + * to ensure that they have full control + */ + + NTFSbits |= STANDARD_RIGHTS_ALL; + + /* Add the ACE to the ACL */ + if (!AddAccessAllowedAce(pacl, ACL_REVISION, NTFSbits, psid)) + return (ISC_R_NOPERM); + if (!AddAccessAllowedAce(pacl, ACL_REVISION, NTFSbits, padminsid)) + return (ISC_R_NOPERM); + + /* + * Group is ignored since we can be in multiple groups or no group + * and its meaning is not clear on Win32 + */ + + caccess = caccess >> STEP; + + /* + * Other check. We translate this to be the same as Everyone + */ + + caccess = caccess >> STEP; + + NTFSbits = 0; + if (caccess & ISC_FSACCESS_READ) + NTFSbits |= FILE_GENERIC_READ; + if (caccess & ISC_FSACCESS_WRITE) + NTFSbits |= FILE_GENERIC_WRITE; + if (caccess & ISC_FSACCESS_EXECUTE) + NTFSbits |= FILE_GENERIC_EXECUTE; + + /* For directories check the directory-specific bits */ + if (isdir == TRUE) { + if (caccess & ISC_FSACCESS_CREATECHILD) + NTFSbits |= FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE; + if (caccess & ISC_FSACCESS_DELETECHILD) + NTFSbits |= FILE_DELETE_CHILD; + if (caccess & ISC_FSACCESS_LISTDIRECTORY) + NTFSbits |= FILE_LIST_DIRECTORY; + if (caccess & ISC_FSACCESS_ACCESSCHILD) + NTFSbits |= FILE_TRAVERSE; + } + /* Add the ACE to the ACL */ + if (!AddAccessAllowedAce(pacl, ACL_REVISION, NTFSbits, + pothersid)) + return (ISC_R_NOPERM); + + if (!SetSecurityDescriptorDacl(&sd, TRUE, pacl, FALSE)) + return (ISC_R_NOPERM); + if (!SetFileSecurity(filename, DACL_SECURITY_INFORMATION, &sd)) { + return (ISC_R_NOPERM); + } + + return(ISC_R_SUCCESS); +} + +isc_result_t +NTFS_fsaccess_set(const char *path, isc_fsaccess_t access, + isc_boolean_t isdir){ + + /* + * For NTFS we first need to get the name of the account under + * which BIND is running + */ + if (namelen <= 0) { + namelen = sizeof(username); + if (GetUserName(username, &namelen) == 0) + return (ISC_R_FAILURE); + } + return (NTFS_Access_Control(path, username, access, isdir)); +} + +isc_result_t +isc_fsaccess_set(const char *path, isc_fsaccess_t access) { + struct stat statb; + isc_boolean_t is_dir = ISC_FALSE; + isc_result_t result; + + if (stat(path, &statb) != 0) + return (isc__errno2result(errno)); + + if ((statb.st_mode & S_IFDIR) != 0) + is_dir = ISC_TRUE; + else if ((statb.st_mode & S_IFREG) == 0) + return (ISC_R_INVALIDFILE); + + result = check_bad_bits(access, is_dir); + if (result != ISC_R_SUCCESS) + return (result); + + /* + * Determine if this is a FAT or NTFS disk and + * call the appropriate function to set the permissions + */ + if (is_ntfs(path)) + return (NTFS_fsaccess_set(path, access, is_dir)); + else + return (FAT_fsaccess_set(path, access)); +} + +isc_result_t +isc_fsaccess_changeowner(const char *filename, const char *user) { + SECURITY_DESCRIPTOR psd; + BYTE sidBuffer[500]; + BYTE groupBuffer[500]; + PSID psid=(PSID) &sidBuffer; + DWORD sidBufferSize = sizeof(sidBuffer); + char domainBuffer[100]; + DWORD domainBufferSize = sizeof(domainBuffer); + SID_NAME_USE snu; + PSID pSidGroup = (PSID) &groupBuffer; + DWORD groupBufferSize = sizeof(groupBuffer); + + + /* + * Determine if this is a FAT or NTFS disk and + * call the appropriate function to set the ownership + * FAT disks do not have ownership attributes so it's + * a noop. + */ + if (is_ntfs(filename) == FALSE) + return (ISC_R_SUCCESS); + + if (!InitializeSecurityDescriptor(&psd, SECURITY_DESCRIPTOR_REVISION)) + return (ISC_R_NOPERM); + + if (!LookupAccountName(0, user, psid, &sidBufferSize, domainBuffer, + &domainBufferSize, &snu)) + return (ISC_R_NOPERM); + + /* Make sure administrators can get to it */ + domainBufferSize = sizeof(domainBuffer); + if (!LookupAccountName(0, "Administrators", pSidGroup, + &groupBufferSize, domainBuffer, &domainBufferSize, &snu)) + return (ISC_R_NOPERM); + + if (!SetSecurityDescriptorOwner(&psd, psid, FALSE)) + return (ISC_R_NOPERM); + + if (!SetSecurityDescriptorGroup(&psd, pSidGroup, FALSE)) + return (ISC_R_NOPERM); + + if (!SetFileSecurity(filename, + OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION, + &psd)) + return (ISC_R_NOPERM); + + return (ISC_R_SUCCESS); +} + diff --git a/contrib/ntp/lib/isc/win32/include/isc/bind_registry.h b/contrib/ntp/lib/isc/win32/include/isc/bind_registry.h new file mode 100644 index 0000000..c4dc876 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/include/isc/bind_registry.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: bind_registry.h,v 1.8 2007/06/19 23:47:20 tbox Exp $ */ + +#ifndef ISC_BINDREGISTRY_H +#define ISC_BINDREGISTRY_H + +/* + * BIND makes use of the following Registry keys in various places, especially + * during startup and installation + */ + +#define BIND_SUBKEY "Software\\ISC\\BIND" +#define BIND_SESSION "CurrentSession" +#define BIND_SESSION_SUBKEY "Software\\ISC\\BIND\\CurrentSession" +#define BIND_UNINSTALL_SUBKEY \ + "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ISC BIND" + +#define EVENTLOG_APP_SUBKEY \ + "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application" +#define BIND_MESSAGE_SUBKEY \ + "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\named" +#define BIND_MESSAGE_NAME "named" + +#define BIND_SERVICE_SUBKEY \ + "SYSTEM\\CurrentControlSet\\Services\\named" + + +#define BIND_CONFIGFILE 0 +#define BIND_DEBUGLEVEL 1 +#define BIND_QUERYLOG 2 +#define BIND_FOREGROUND 3 +#define BIND_PORT 4 + +#endif /* ISC_BINDREGISTRY_H */ diff --git a/contrib/ntp/lib/isc/win32/include/isc/bindevt.h b/contrib/ntp/lib/isc/win32/include/isc/bindevt.h new file mode 100644 index 0000000..72cf2d1 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/include/isc/bindevt.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: bindevt.h,v 1.6 2007/06/19 23:47:20 tbox Exp $ */ + +#ifndef ISC_BINDEVT_H +#define ISC_BINDEVT_H 1 + +/* + * This is used for the event log for both logging the messages and + * later on by the event viewer when looking at the events + */ + +/* + * Values are 32 bit values layed out as follows: + * + * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +---+-+-+-----------------------+-------------------------------+ + * |Sev|C|R| Facility | Code | + * +---+-+-+-----------------------+-------------------------------+ + * + * where + * + * Sev - is the severity code + * + * 00 - Success + * 01 - Informational + * 10 - Warning + * 11 - Error + * + * C - is the Customer code flag + * + * R - is a reserved bit + * + * Facility - is the facility code + * + * Code - is the facility's status code + * + * + * Define the facility codes + */ + + +/* + * Define the severity codes + */ + + +/* + * MessageId: BIND_ERR_MSG + * + * MessageText: + * + * %1 + */ +#define BIND_ERR_MSG ((DWORD)0xC0000001L) + +/* + * MessageId: BIND_WARN_MSG + * + * MessageText: + * + * %1 + */ +#define BIND_WARN_MSG ((DWORD)0x80000002L) + +/* + * MessageId: BIND_INFO_MSG + * + * MessageText: + * + * %1 + */ +#define BIND_INFO_MSG ((DWORD)0x40000003L) + +#endif /* ISC_BINDEVT_H */ diff --git a/contrib/ntp/lib/isc/win32/include/isc/condition.h b/contrib/ntp/lib/isc/win32/include/isc/condition.h new file mode 100644 index 0000000..34015bc --- /dev/null +++ b/contrib/ntp/lib/isc/win32/include/isc/condition.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: condition.h,v 1.17 2007/06/18 23:47:49 tbox Exp $ */ + +#ifndef ISC_CONDITION_H +#define ISC_CONDITION_H 1 + +#include <windows.h> + +#include <isc/lang.h> +#include <isc/mutex.h> +#include <isc/thread.h> +#include <isc/types.h> + +typedef struct isc_condition_thread isc_condition_thread_t; + +struct isc_condition_thread { + unsigned long th; + HANDLE handle[2]; + ISC_LINK(isc_condition_thread_t) link; + +}; + +typedef struct isc_condition { + HANDLE events[2]; + unsigned int waiters; + ISC_LIST(isc_condition_thread_t) threadlist; +} isc_condition_t; + +ISC_LANG_BEGINDECLS + +isc_result_t +isc_condition_init(isc_condition_t *); + +isc_result_t +isc_condition_wait(isc_condition_t *, isc_mutex_t *); + +isc_result_t +isc_condition_signal(isc_condition_t *); + +isc_result_t +isc_condition_broadcast(isc_condition_t *); + +isc_result_t +isc_condition_destroy(isc_condition_t *); + +isc_result_t +isc_condition_waituntil(isc_condition_t *, isc_mutex_t *, isc_time_t *); + +ISC_LANG_ENDDECLS + +#endif /* ISC_CONDITION_H */ diff --git a/contrib/ntp/lib/isc/win32/include/isc/dir.h b/contrib/ntp/lib/isc/win32/include/isc/dir.h new file mode 100644 index 0000000..653427a --- /dev/null +++ b/contrib/ntp/lib/isc/win32/include/isc/dir.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: dir.h,v 1.15 2007/06/19 23:47:20 tbox Exp $ */ + +/* Principal Authors: DCL */ + +#ifndef ISC_DIR_H +#define ISC_DIR_H 1 + +#include <windows.h> +#include <stdlib.h> + +#include <isc/lang.h> +#include <isc/boolean.h> +#include <isc/result.h> + +#define ISC_DIR_NAMEMAX _MAX_FNAME +#define ISC_DIR_PATHMAX _MAX_PATH + +typedef struct { + char name[ISC_DIR_NAMEMAX]; + unsigned int length; + WIN32_FIND_DATA find_data; +} isc_direntry_t; + +typedef struct { + unsigned int magic; + char dirname[ISC_DIR_PATHMAX]; + isc_direntry_t entry; + isc_boolean_t entry_filled; + HANDLE search_handle; +} isc_dir_t; + +ISC_LANG_BEGINDECLS + +void +isc_dir_init(isc_dir_t *dir); + +isc_result_t +isc_dir_open(isc_dir_t *dir, const char *dirname); + +isc_result_t +isc_dir_read(isc_dir_t *dir); + +isc_result_t +isc_dir_reset(isc_dir_t *dir); + +void +isc_dir_close(isc_dir_t *dir); + +isc_result_t +isc_dir_chdir(const char *dirname); + +isc_result_t +isc_dir_chroot(const char *dirname); + +isc_result_t +isc_dir_createunique(char *templet); +/* + * Use a templet (such as from isc_file_mktemplate()) to create a uniquely + * named, empty directory. The templet string is modified in place. + * If result == ISC_R_SUCCESS, it is the name of the directory that was + * created. + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_DIR_H */ diff --git a/contrib/ntp/lib/isc/win32/include/isc/int.h b/contrib/ntp/lib/isc/win32/include/isc/int.h new file mode 100644 index 0000000..2ee8bf9 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/include/isc/int.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: int.h,v 1.13 2007/06/19 23:47:20 tbox Exp $ */ + +#ifndef ISC_INT_H +#define ISC_INT_H 1 + +#define _INTEGRAL_MAX_BITS 64 +#include <limits.h> + +typedef __int8 isc_int8_t; +typedef unsigned __int8 isc_uint8_t; +typedef __int16 isc_int16_t; +typedef unsigned __int16 isc_uint16_t; +typedef __int32 isc_int32_t; +typedef unsigned __int32 isc_uint32_t; +typedef __int64 isc_int64_t; +typedef unsigned __int64 isc_uint64_t; + +#define ISC_INT8_MIN -128 +#define ISC_INT8_MAX 127 +#define ISC_UINT8_MAX 255 + +#define ISC_INT16_MIN -32768 +#define ISC_INT16_MAX 32767 +#define ISC_UINT16_MAX 65535 + +/* + * Note that "int" is 32 bits on all currently supported Unix-like operating + * systems, but "long" can be either 32 bits or 64 bits, thus the 32 bit + * constants are not qualified with "L". + */ +#define ISC_INT32_MIN _I32_MIN +#define ISC_INT32_MAX _I32_MAX +#define ISC_UINT32_MAX _UI32_MAX + +#define ISC_INT64_MIN _I64_MIN +#define ISC_INT64_MAX _I64_MAX +#define ISC_UINT64_MAX _UI64_MAX + +#endif /* ISC_INT_H */ diff --git a/contrib/ntp/lib/isc/win32/include/isc/ipv6.h b/contrib/ntp/lib/isc/win32/include/isc/ipv6.h new file mode 100644 index 0000000..27384a3 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/include/isc/ipv6.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +#ifndef ISC_IPV6_H +#define ISC_IPV6_H 1 + +/***** + ***** Module Info + *****/ + +/* + * IPv6 definitions for systems which do not support IPv6. + * + * MP: + * No impact. + * + * Reliability: + * No anticipated impact. + * + * Resources: + * N/A. + * + * Security: + * No anticipated impact. + * + * Standards: + * RFC2553. + */ + +#if _MSC_VER < 1300 +#define in6_addr in_addr6 +#endif + +#ifndef IN6ADDR_ANY_INIT +#define IN6ADDR_ANY_INIT {{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }} +#endif +#ifndef IN6ADDR_LOOPBACK_INIT +#define IN6ADDR_LOOPBACK_INIT {{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }} +#endif + +LIBISC_EXTERNAL_DATA extern const struct in6_addr isc_net_in6addrany; +LIBISC_EXTERNAL_DATA extern const struct in6_addr isc_net_in6addrloop; + +/* + * Unspecified + */ +#ifndef IN6_IS_ADDR_UNSPECIFIED +#define IN6_IS_ADDR_UNSPECIFIED(a) (\ +*((u_long *)((a)->s6_addr) ) == 0 && \ +*((u_long *)((a)->s6_addr) + 1) == 0 && \ +*((u_long *)((a)->s6_addr) + 2) == 0 && \ +*((u_long *)((a)->s6_addr) + 3) == 0 \ +) +#endif + +/* + * Loopback + */ +#ifndef IN6_IS_ADDR_LOOPBACK +#define IN6_IS_ADDR_LOOPBACK(a) (\ +*((u_long *)((a)->s6_addr) ) == 0 && \ +*((u_long *)((a)->s6_addr) + 1) == 0 && \ +*((u_long *)((a)->s6_addr) + 2) == 0 && \ +*((u_long *)((a)->s6_addr) + 3) == htonl(1) \ +) +#endif + +/* + * IPv4 compatible + */ +#define IN6_IS_ADDR_V4COMPAT(a) (\ +*((u_long *)((a)->s6_addr) ) == 0 && \ +*((u_long *)((a)->s6_addr) + 1) == 0 && \ +*((u_long *)((a)->s6_addr) + 2) == 0 && \ +*((u_long *)((a)->s6_addr) + 3) != 0 && \ +*((u_long *)((a)->s6_addr) + 3) != htonl(1) \ +) + +/* + * Mapped + */ +#define IN6_IS_ADDR_V4MAPPED(a) (\ +*((u_long *)((a)->s6_addr) ) == 0 && \ +*((u_long *)((a)->s6_addr) + 1) == 0 && \ +*((u_long *)((a)->s6_addr) + 2) == htonl(0x0000ffff)) + +/* + * Multicast + */ +#define IN6_IS_ADDR_MULTICAST(a) \ + ((a)->s6_addr[0] == 0xffU) + +/* + * Unicast link / site local. + */ +#ifndef IN6_IS_ADDR_LINKLOCAL +#define IN6_IS_ADDR_LINKLOCAL(a) (\ + ((a)->s6_addr[0] == 0xfe) && \ + (((a)->s6_addr[1] & 0xc0) == 0x80)) +#endif + +#ifndef IN6_IS_ADDR_SITELOCAL +#define IN6_IS_ADDR_SITELOCAL(a) (\ + ((a)->s6_addr[0] == 0xfe) && \ + (((a)->s6_addr[1] & 0xc0) == 0xc0)) +#endif + +#endif /* ISC_IPV6_H */ diff --git a/contrib/ntp/lib/isc/win32/include/isc/keyboard.h b/contrib/ntp/lib/isc/win32/include/isc/keyboard.h new file mode 100644 index 0000000..e781c5f --- /dev/null +++ b/contrib/ntp/lib/isc/win32/include/isc/keyboard.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: keyboard.h,v 1.6 2007/06/19 23:47:20 tbox Exp $ */ + +#ifndef ISC_KEYBOARD_H +#define ISC_KEYBOARD_H 1 + +#include <isc/lang.h> +#include <isc/result.h> + +ISC_LANG_BEGINDECLS + +typedef struct { + int fd; + isc_result_t result; +} isc_keyboard_t; + +isc_result_t +isc_keyboard_open(isc_keyboard_t *keyboard); + +isc_result_t +isc_keyboard_close(isc_keyboard_t *keyboard, unsigned int sleepseconds); + +isc_result_t +isc_keyboard_getchar(isc_keyboard_t *keyboard, unsigned char *cp); + +isc_boolean_t +isc_keyboard_canceled(isc_keyboard_t *keyboard); + +ISC_LANG_ENDDECLS + +#endif /* ISC_KEYBOARD_H */ diff --git a/contrib/ntp/lib/isc/win32/include/isc/mutex.h b/contrib/ntp/lib/isc/win32/include/isc/mutex.h new file mode 100644 index 0000000..5cf1bae --- /dev/null +++ b/contrib/ntp/lib/isc/win32/include/isc/mutex.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2004, 2007-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: mutex.h,v 1.22 2009/01/18 23:48:14 tbox Exp $ */ + +#ifndef ISC_MUTEX_H +#define ISC_MUTEX_H 1 + +#include <isc/net.h> +#include <windows.h> + +#include <isc/result.h> + +typedef CRITICAL_SECTION isc_mutex_t; + +/* + * This definition is here since some versions of WINBASE.H + * omits it for some reason. + */ +#if (_WIN32_WINNT < 0x0400) +WINBASEAPI BOOL WINAPI +TryEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); +#endif /* _WIN32_WINNT < 0x0400 */ + +#define isc_mutex_init(mp) \ + (InitializeCriticalSection((mp)), ISC_R_SUCCESS) +#define isc_mutex_lock(mp) \ + (EnterCriticalSection((mp)), ISC_R_SUCCESS) +#define isc_mutex_unlock(mp) \ + (LeaveCriticalSection((mp)), ISC_R_SUCCESS) +#define isc_mutex_trylock(mp) \ + (TryEnterCriticalSection((mp)) ? ISC_R_SUCCESS : ISC_R_LOCKBUSY) +#define isc_mutex_destroy(mp) \ + (DeleteCriticalSection((mp)), ISC_R_SUCCESS) + +/* + * This is a placeholder for now since we are not keeping any mutex stats + */ +#define isc_mutex_stats(fp) do {} while (0) + +#endif /* ISC_MUTEX_H */ diff --git a/contrib/ntp/lib/isc/win32/include/isc/net.h b/contrib/ntp/lib/isc/win32/include/isc/net.h new file mode 100644 index 0000000..10be85b --- /dev/null +++ b/contrib/ntp/lib/isc/win32/include/isc/net.h @@ -0,0 +1,374 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2008, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +#ifndef ISC_NET_H +#define ISC_NET_H 1 + +#include <errno.h> + +/* + * Also define LWRES_IPV6_H to keep it from being included if liblwres is + * being used, or redefinition errors will occur. + */ +#define LWRES_IPV6_H 1 + + + +/***** + ***** Module Info + *****/ + +/* + * Basic Networking Types + * + * This module is responsible for defining the following basic networking + * types: + * + * struct in_addr + * struct in6_addr + * struct in6_pktinfo + * struct sockaddr + * struct sockaddr_in + * struct sockaddr_in6 + * in_port_t + * + * It ensures that the AF_ and PF_ macros are defined. + * + * It declares ntoh[sl]() and hton[sl](). + * + * It declares inet_aton(), inet_ntop(), and inet_pton(). + * + * It ensures that INADDR_ANY, IN6ADDR_ANY_INIT, in6addr_any, and + * in6addr_loopback are available. + * + * It ensures that IN_MULTICAST() is available to check for multicast + * addresses. + * + * MP: + * No impact. + * + * Reliability: + * No anticipated impact. + * + * Resources: + * N/A. + * + * Security: + * No anticipated impact. + * + * Standards: + * BSD Socket API + * RFC2553 + */ + +/*** + *** Imports. + ***/ +#include <isc/platform.h> + +/* + * Because of some sort of problem in the MS header files, this cannot + * be simple "#include <winsock2.h>", because winsock2.h tries to include + * windows.h, which then generates an error out of mswsock.h. _You_ + * figure it out. + */ +#ifndef _WINSOCKAPI_ +#define _WINSOCKAPI_ /* Prevent inclusion of winsock.h in windows.h */ +#endif + +#include <winsock2.h> + +#include <sys/types.h> + +#include <isc/lang.h> +#include <isc/types.h> + +#include <ws2tcpip.h> +#include <isc/ipv6.h> + +/* + * This is here because named client, interfacemgr.c, etc. use the name as + * a variable + */ +#undef interface + +#ifndef INADDR_LOOPBACK +#define INADDR_LOOPBACK 0x7f000001UL +#endif + +#ifndef ISC_PLATFORM_HAVEIN6PKTINFO +struct in6_pktinfo { + struct in6_addr ipi6_addr; /* src/dst IPv6 address */ + unsigned int ipi6_ifindex; /* send/recv interface index */ +}; +#endif + +#if _MSC_VER < 1300 +#define in6addr_any isc_net_in6addrany +#define in6addr_loopback isc_net_in6addrloop +#endif + +/* + * Ensure type in_port_t is defined. + */ +#ifdef ISC_PLATFORM_NEEDPORTT +typedef isc_uint16_t in_port_t; +#endif + +/* + * If this system does not have MSG_TRUNC (as returned from recvmsg()) + * ISC_PLATFORM_RECVOVERFLOW will be defined. This will enable the MSG_TRUNC + * faking code in socket.c. + */ +#ifndef MSG_TRUNC +#define ISC_PLATFORM_RECVOVERFLOW +#endif + +#define ISC__IPADDR(x) ((isc_uint32_t)htonl((isc_uint32_t)(x))) + +#define ISC_IPADDR_ISMULTICAST(i) \ + (((isc_uint32_t)(i) & ISC__IPADDR(0xf0000000)) \ + == ISC__IPADDR(0xe0000000)) + +#define ISC_IPADDR_ISEXPERIMENTAL(i) \ + (((isc_uint32_t)(i) & ISC__IPADDR(0xf0000000)) \ + == ISC__IPADDR(0xf0000000)) + +/* + * Fix the FD_SET and FD_CLR Macros to properly cast + */ +#undef FD_CLR +#define FD_CLR(fd, set) do { \ + u_int __i; \ + for (__i = 0; __i < ((fd_set FAR *)(set))->fd_count; __i++) { \ + if (((fd_set FAR *)(set))->fd_array[__i] == (SOCKET) fd) { \ + while (__i < ((fd_set FAR *)(set))->fd_count-1) { \ + ((fd_set FAR *)(set))->fd_array[__i] = \ + ((fd_set FAR *)(set))->fd_array[__i+1]; \ + __i++; \ + } \ + ((fd_set FAR *)(set))->fd_count--; \ + break; \ + } \ + } \ +} while (0) + +#undef FD_SET +#define FD_SET(fd, set) do { \ + u_int __i; \ + for (__i = 0; __i < ((fd_set FAR *)(set))->fd_count; __i++) { \ + if (((fd_set FAR *)(set))->fd_array[__i] == (SOCKET)(fd)) { \ + break; \ + } \ + } \ + if (__i == ((fd_set FAR *)(set))->fd_count) { \ + if (((fd_set FAR *)(set))->fd_count < FD_SETSIZE) { \ + ((fd_set FAR *)(set))->fd_array[__i] = (SOCKET)(fd); \ + ((fd_set FAR *)(set))->fd_count++; \ + } \ + } \ +} while (0) + +/* + * Windows Sockets errors redefined as regular Berkeley error constants. + * These are usually commented out in Windows NT to avoid conflicts with errno.h. + * Use the WSA constants instead. + * Starting with VC9 (VC++ 2010) many of these are defined incompatibly + * by errno.h -- #undef the conflicting values, which are not relevant to + * Win32. + */ + +#undef EWOULDBLOCK +#define EWOULDBLOCK WSAEWOULDBLOCK +#undef EINPROGRESS +#define EINPROGRESS WSAEINPROGRESS +#undef EALREADY +#define EALREADY WSAEALREADY +#undef ENOTSOCK +#define ENOTSOCK WSAENOTSOCK +#undef EDESTADDRREQ +#define EDESTADDRREQ WSAEDESTADDRREQ +#undef EMSGSIZE +#define EMSGSIZE WSAEMSGSIZE +#undef EPROTOTYPE +#define EPROTOTYPE WSAEPROTOTYPE +#undef ENOPROTOOPT +#define ENOPROTOOPT WSAENOPROTOOPT +#undef EPROTONOSUPPORT +#define EPROTONOSUPPORT WSAEPROTONOSUPPORT +#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT +#undef EOPNOTSUPP +#define EOPNOTSUPP WSAEOPNOTSUPP +#define EPFNOSUPPORT WSAEPFNOSUPPORT +#undef EAFNOSUPPORT +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#undef EADDRINUSE +#define EADDRINUSE WSAEADDRINUSE +#undef EADDRNOTAVAIL +#define EADDRNOTAVAIL WSAEADDRNOTAVAIL +#undef ENETDOWN +#define ENETDOWN WSAENETDOWN +#undef ENETUNREACH +#define ENETUNREACH WSAENETUNREACH +#undef ENETRESET +#define ENETRESET WSAENETRESET +#undef ECONNABORTED +#define ECONNABORTED WSAECONNABORTED +#undef ECONNRESET +#define ECONNRESET WSAECONNRESET +#undef ENOBUFS +#define ENOBUFS WSAENOBUFS +#undef EISCONN +#define EISCONN WSAEISCONN +#undef ENOTCONN +#define ENOTCONN WSAENOTCONN +#define ESHUTDOWN WSAESHUTDOWN +#define ETOOMANYREFS WSAETOOMANYREFS +#undef ETIMEDOUT +#define ETIMEDOUT WSAETIMEDOUT +#undef ECONNREFUSED +#define ECONNREFUSED WSAECONNREFUSED +#undef ELOOP +#define ELOOP WSAELOOP +#define EHOSTDOWN WSAEHOSTDOWN +#undef EHOSTUNREACH +#define EHOSTUNREACH WSAEHOSTUNREACH +#define EPROCLIM WSAEPROCLIM +#define EUSERS WSAEUSERS +#define EDQUOT WSAEDQUOT +#define ESTALE WSAESTALE +#define EREMOTE WSAEREMOTE + + +/*** + *** Functions. + ***/ + +ISC_LANG_BEGINDECLS + +isc_result_t +isc_net_probeipv4(void); +/* + * Check if the system's kernel supports IPv4. + * + * Returns: + * + * ISC_R_SUCCESS IPv4 is supported. + * ISC_R_NOTFOUND IPv4 is not supported. + * ISC_R_DISABLED IPv4 is disabled. + * ISC_R_UNEXPECTED + */ + +isc_result_t +isc_net_probeipv6(void); +/* + * Check if the system's kernel supports IPv6. + * + * Returns: + * + * ISC_R_SUCCESS IPv6 is supported. + * ISC_R_NOTFOUND IPv6 is not supported. + * ISC_R_DISABLED IPv6 is disabled. + * ISC_R_UNEXPECTED + */ + +isc_result_t +isc_net_probeunix(void); +/* + * Check if UNIX domain sockets are supported. + * + * Returns: + * + * ISC_R_SUCCESS + * ISC_R_NOTFOUND + */ + +isc_result_t +isc_net_probe_ipv6only(void); +/* + * Check if the system's kernel supports the IPV6_V6ONLY socket option. + * + * Returns: + * + * ISC_R_SUCCESS the option is supported for both TCP and UDP. + * ISC_R_NOTFOUND IPv6 itself or the option is not supported. + * ISC_R_UNEXPECTED + */ + +isc_result_t +isc_net_probe_ipv6pktinfo(void); +/* + * Check if the system's kernel supports the IPV6_(RECV)PKTINFO socket option + * for UDP sockets. + * + * Returns: + * + * ISC_R_SUCCESS the option is supported. + * ISC_R_NOTFOUND IPv6 itself or the option is not supported. + * ISC_R_UNEXPECTED + */ + +void +isc_net_disableipv4(void); + +void +isc_net_disableipv6(void); + +void +isc_net_enableipv4(void); + +void +isc_net_enableipv6(void); + +isc_result_t +isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high); +/*%< + * Returns system's default range of ephemeral UDP ports, if defined. + * If the range is not available or unknown, ISC_NET_PORTRANGELOW and + * ISC_NET_PORTRANGEHIGH will be returned. + * + * Requires: + * + *\li 'low' and 'high' must be non NULL. + * + * Returns: + * + *\li *low and *high will be the ports specifying the low and high ends of + * the range. + */ + +#ifdef ISC_PLATFORM_NEEDNTOP +const char * +isc_net_ntop(int af, const void *src, char *dst, size_t size); +#define inet_ntop isc_net_ntop +#endif + +#ifdef ISC_PLATFORM_NEEDPTON +int +isc_net_pton(int af, const char *src, void *dst); +#define inet_pton isc_net_pton +#endif + +int +isc_net_aton(const char *cp, struct in_addr *addr); +#define inet_aton isc_net_aton + +ISC_LANG_ENDDECLS + +#endif /* ISC_NET_H */ diff --git a/contrib/ntp/lib/isc/win32/include/isc/netdb.h b/contrib/ntp/lib/isc/win32/include/isc/netdb.h new file mode 100644 index 0000000..6625afd --- /dev/null +++ b/contrib/ntp/lib/isc/win32/include/isc/netdb.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: netdb.h,v 1.9 2007/06/19 23:47:20 tbox Exp $ */ + +#ifndef ISC_NETDB_H +#define ISC_NETDB_H 1 + +/***** + ***** Module Info + *****/ + +/* + * Portable netdb.h support. + * + * This module is responsible for defining the get<x>by<y> APIs. + * + * MP: + * No impact. + * + * Reliability: + * No anticipated impact. + * + * Resources: + * N/A. + * + * Security: + * No anticipated impact. + * + * Standards: + * BSD API + */ + +/*** + *** Imports. + ***/ + +#include <isc/net.h> + +#endif /* ISC_NETDB_H */ diff --git a/contrib/ntp/lib/isc/win32/include/isc/ntgroups.h b/contrib/ntp/lib/isc/win32/include/isc/ntgroups.h new file mode 100644 index 0000000..b4cd020 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/include/isc/ntgroups.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: ntgroups.h,v 1.5 2007/06/19 23:47:20 tbox Exp $ */ + +#ifndef ISC_NTGROUPS_H +#define ISC_NTGROUPS_H 1 + +#include <isc/lang.h> +#include <isc/result.h> + +ISC_LANG_BEGINDECLS + + +isc_result_t +isc_ntsecurity_getaccountgroups(char *name, char **Groups, unsigned int maxgroups, + unsigned int *total); + +ISC_LANG_ENDDECLS + +#endif /* ISC_NTGROUPS_H */ diff --git a/contrib/ntp/lib/isc/win32/include/isc/ntpaths.h b/contrib/ntp/lib/isc/win32/include/isc/ntpaths.h new file mode 100644 index 0000000..39bcb62 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/include/isc/ntpaths.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: ntpaths.h,v 1.20 2009/07/14 22:54:57 each Exp $ */ + +/* + * Windows-specific path definitions + * These routines are used to set up and return system-specific path + * information about the files enumerated in NtPaths + */ + +#ifndef ISC_NTPATHS_H +#define ISC_NTPATHS_H + +#include <isc/lang.h> + +/* + * Index of paths needed + */ +enum NtPaths { + NAMED_CONF_PATH, + LWRES_CONF_PATH, + RESOLV_CONF_PATH, + RNDC_CONF_PATH, + NAMED_PID_PATH, + LWRESD_PID_PATH, + LOCAL_STATE_DIR, + SYS_CONF_DIR, + RNDC_KEY_PATH, + SESSION_KEY_PATH +}; + +/* + * Define macros to get the path of the config files + */ +#define NAMED_CONFFILE isc_ntpaths_get(NAMED_CONF_PATH) +#define RNDC_CONFFILE isc_ntpaths_get(RNDC_CONF_PATH) +#define RNDC_KEYFILE isc_ntpaths_get(RNDC_KEY_PATH) +#define SESSION_KEYFILE isc_ntpaths_get(SESSION_KEY_PATH) +#define RESOLV_CONF isc_ntpaths_get(RESOLV_CONF_PATH) + +/* + * Information about where the files are on disk + */ +#define NS_LOCALSTATEDIR "/dns/bin" +#define NS_SYSCONFDIR "/dns/etc" + +ISC_LANG_BEGINDECLS + +void +isc_ntpaths_init(void); + +char * +isc_ntpaths_get(int); + +ISC_LANG_ENDDECLS + +#endif /* ISC_NTPATHS_H */ diff --git a/contrib/ntp/lib/isc/win32/include/isc/offset.h b/contrib/ntp/lib/isc/win32/include/isc/offset.h new file mode 100644 index 0000000..f22fdce --- /dev/null +++ b/contrib/ntp/lib/isc/win32/include/isc/offset.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: offset.h,v 1.6 2007/06/19 23:47:20 tbox Exp $ */ + +#ifndef ISC_OFFSET_H +#define ISC_OFFSET_H 1 + +/* + * File offsets are operating-system dependent. + */ +#include <limits.h> /* Required for CHAR_BIT. */ +#include <sys/types.h> + +typedef _off_t isc_offset_t; + +/* + * POSIX says "Additionally, blkcnt_t and off_t are extended signed integral + * types", so the maximum value is all 1s except for the high bit. + * This definition is more complex than it really needs to be because it was + * crafted to keep both the SunOS 5.6 and the HP/UX 11 compilers quiet about + * integer overflow. For example, though this is equivalent to just left + * shifting 1 to the high bit and then inverting the bits, the SunOS compiler + * is unhappy about shifting a positive "1" to negative in a signed integer. + */ +#define ISC_OFFSET_MAXIMUM \ + (~(((off_t)-1 >> (sizeof(off_t) * CHAR_BIT - 1)) \ + << (sizeof(off_t) * CHAR_BIT - 1))) + +#endif /* ISC_OFFSET_H */ diff --git a/contrib/ntp/lib/isc/win32/include/isc/once.h b/contrib/ntp/lib/isc/win32/include/isc/once.h new file mode 100644 index 0000000..0dc1686 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/include/isc/once.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: once.h,v 1.9 2007/06/19 23:47:20 tbox Exp $ */ + +#ifndef ISC_ONCE_H +#define ISC_ONCE_H 1 + +#include <isc/lang.h> +#include <isc/result.h> + +ISC_LANG_BEGINDECLS + +typedef struct { + int status; + LONG counter; +} isc_once_t; + +#define ISC_ONCE_INIT_NEEDED 0 +#define ISC_ONCE_INIT_DONE 1 + +#define ISC_ONCE_INIT { ISC_ONCE_INIT_NEEDED, 1 } + +isc_result_t +isc_once_do(isc_once_t *controller, void(*function)(void)); + +ISC_LANG_ENDDECLS + +#endif /* ISC_ONCE_H */ diff --git a/contrib/ntp/lib/isc/win32/include/isc/platform.h b/contrib/ntp/lib/isc/win32/include/isc/platform.h new file mode 100644 index 0000000..94b8ba5 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/include/isc/platform.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: platform.h,v 1.19 2009/09/29 23:48:04 tbox Exp $ */ + +#ifndef ISC_PLATFORM_H +#define ISC_PLATFORM_H 1 + +/***** + ***** Platform-dependent defines. + *****/ + +#define ISC_PLATFORM_USETHREADS + +/*** + *** Network. + ***/ + +#if _MSC_VER > 1200 +#define ISC_PLATFORM_HAVEIPV6 +#define ISC_PLATFORM_HAVEIN6PKTINFO +#define ISC_PLATFORM_HAVESCOPEID +#endif +#define ISC_PLATFORM_NEEDPORTT +#undef MSG_TRUNC +#define ISC_PLATFORM_NEEDNTOP +#define ISC_PLATFORM_NEEDPTON + +#ifndef ISC_PLATFORM_QUADFORMAT +#define ISC_PLATFORM_QUADFORMAT "I64" +#endif + +#define ISC_PLATFORM_NEEDSTRSEP +#define ISC_PLATFORM_NEEDSTRLCPY +#define ISC_PLATFORM_NEEDSTRLCAT +#define ISC_PLATFORM_NEEDSTRLCPY + +/* + * Used to control how extern data is linked; needed for Win32 platforms. + */ +#define ISC_PLATFORM_USEDECLSPEC 1 + +/* + * Define this here for now as winsock2.h defines h_errno + * and we don't want to redeclare it. + */ +#define ISC_PLATFORM_NONSTDHERRNO + +/* + * Define if the platform has <sys/un.h>. + */ +#undef ISC_PLATFORM_HAVESYSUNH + +/* + * Defines for the noreturn attribute. + */ +#define ISC_PLATFORM_NORETURN_PRE __declspec(noreturn) +#define ISC_PLATFORM_NORETURN_POST + +/* + * Set up a macro for importing and exporting from the DLL + * + * To build static libraries on win32, #define ISC_STATIC_WIN + */ +#ifndef ISC_STATIC_WIN +#define ISC_DLLEXP __declspec(dllexport) +#define ISC_DLLIMP __declspec(dllimport) +#else +#define ISC_DLLEXP +#define ISC_DLLIMP +#endif + +#ifdef LIBISC_EXPORTS +#define LIBISC_EXTERNAL_DATA ISC_DLLEXP +#else +#define LIBISC_EXTERNAL_DATA ISC_DLLIMP +#endif + +#ifdef LIBISCCFG_EXPORTS +#define LIBISCCFG_EXTERNAL_DATA ISC_DLLEXP +#else +#define LIBISCCFG_EXTERNAL_DATA ISC_DLLIMP +#endif + +#ifdef LIBISCCC_EXPORTS +#define LIBISCCC_EXTERNAL_DATA ISC_DLLEXP +#else +#define LIBISCCC_EXTERNAL_DATA ISC_DLLIMP +#endif + +#ifdef LIBDNS_EXPORTS +#define LIBDNS_EXTERNAL_DATA ISC_DLLEXP +#else +#define LIBDNS_EXTERNAL_DATA ISC_DLLIMP +#endif + +#ifdef LIBBIND9_EXPORTS +#define LIBBIND9_EXTERNAL_DATA ISC_DLLEXP +#else +#define LIBBIND9_EXTERNAL_DATA ISC_DLLIMP +#endif + +#endif /* ISC_PLATFORM_H */ diff --git a/contrib/ntp/lib/isc/win32/include/isc/stat.h b/contrib/ntp/lib/isc/win32/include/isc/stat.h new file mode 100644 index 0000000..f95e3b0 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/include/isc/stat.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001, 2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: stat.h,v 1.9 2009/10/01 23:48:08 tbox Exp $ */ + +#ifndef ISC_STAT_H +#define ISC_STAT_H 1 + +#include <sys/stat.h> + +/* open() under unix allows setting of read/write permissions + * at the owner, group and other levels. These don't exist in NT + * We'll just map them all to the NT equivalent + */ + +#define S_IREAD _S_IREAD /* read permission, owner */ +#define S_IWRITE _S_IWRITE /* write permission, owner */ +#define S_IEXEC _S_IEXEC /* execute/search permission, owner */ +#define S_IRUSR _S_IREAD /* Owner read permission */ +#define S_IWUSR _S_IWRITE /* Owner write permission */ +#define S_IRGRP _S_IREAD /* Group read permission */ +#define S_IWGRP _S_IWRITE /* Group write permission */ +#define S_IROTH _S_IREAD /* Other read permission */ +#define S_IWOTH _S_IWRITE /* Other write permission */ + +#ifndef S_IFMT +# define S_IFMT _S_IFMT +#endif +#ifndef S_IFDIR +# define S_IFDIR _S_IFDIR +#endif +#ifndef S_IFCHR +# define S_IFCHR _S_IFCHR +#endif +#ifndef S_IFREG +# define S_IFREG _S_IFREG +#endif + +#ifndef S_ISDIR +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif +#ifndef S_ISREG +# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#endif + +#define O_RDONLY _O_RDONLY +#define O_WRONLY _O_WRONLY +#define O_RDWR _O_RDWR +#define O_APPEND _O_APPEND +#define O_CREAT _O_CREAT +#define O_TRUNC _O_TRUNC +#define O_EXCL _O_EXCL + +#endif /* ISC_STAT_H */ diff --git a/contrib/ntp/lib/isc/win32/include/isc/stdtime.h b/contrib/ntp/lib/isc/win32/include/isc/stdtime.h new file mode 100644 index 0000000..abbbc16 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/include/isc/stdtime.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +#ifndef ISC_STDTIME_H +#define ISC_STDTIME_H 1 + +#include <isc/lang.h> +#include <isc/int.h> + +/* + * It's public information that 'isc_stdtime_t' is an unsigned integral type. + * Applications that want maximum portability should not assume anything + * about its size. + */ +typedef isc_uint32_t isc_stdtime_t; + +/* but this flag helps... */ +#define STDTIME_ON_32BITS 1 + +/* + * isc_stdtime32_t is a 32-bit version of isc_stdtime_t. A variable of this + * type should only be used as an opaque integer (e.g.,) to compare two + * time values. + */ +typedef isc_uint32_t isc_stdtime32_t; + +ISC_LANG_BEGINDECLS + +void +isc_stdtime_get(isc_stdtime_t *t); +/* + * Set 't' to the number of seconds since 00:00:00 UTC, January 1, 1970. + * + * Requires: + * + * 't' is a valid pointer. + */ + +#define isc_stdtime_convert32(t, t32p) (*(t32p) = t) +/* + * Convert the standard time to its 32-bit version. + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_STDTIME_H */ diff --git a/contrib/ntp/lib/isc/win32/include/isc/strerror.h b/contrib/ntp/lib/isc/win32/include/isc/strerror.h new file mode 100644 index 0000000..38d2ef2 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/include/isc/strerror.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: strerror.h,v 1.5 2007/06/19 23:47:20 tbox Exp $ */ + +#ifndef ISC_STRERROR_H +#define ISC_STRERROR_H + +#include <sys/types.h> + +#include <isc/lang.h> + +ISC_LANG_BEGINDECLS + +#define ISC_STRERRORSIZE 128 + +/* + * Provide a thread safe wrapper to strerrror(). + * + * Requires: + * 'buf' to be non NULL. + */ +void +isc__strerror(int num, char *buf, size_t bufsize); + +ISC_LANG_ENDDECLS + +#endif /* ISC_STRERROR_H */ diff --git a/contrib/ntp/lib/isc/win32/include/isc/syslog.h b/contrib/ntp/lib/isc/win32/include/isc/syslog.h new file mode 100644 index 0000000..765c0e5 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/include/isc/syslog.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: syslog.h,v 1.5 2007/06/19 23:47:20 tbox Exp $ */ + +#ifndef ISC_SYSLOG_H +#define ISC_SYSLOG_H 1 + +#include <isc/lang.h> +#include <isc/types.h> + +ISC_LANG_BEGINDECLS + +isc_result_t +isc_syslog_facilityfromstring(const char *str, int *facilityp); +/* + * Convert 'str' to the appropriate syslog facility constant. + * + * Requires: + * + * 'str' is not NULL + * 'facilityp' is not NULL + * + * Returns: + * ISC_R_SUCCESS + * ISC_R_NOTFOUND + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_SYSLOG_H */ diff --git a/contrib/ntp/lib/isc/win32/include/isc/thread.h b/contrib/ntp/lib/isc/win32/include/isc/thread.h new file mode 100644 index 0000000..2eb923b --- /dev/null +++ b/contrib/ntp/lib/isc/win32/include/isc/thread.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: thread.h,v 1.25 2009/09/29 04:37:08 marka Exp $ */ + +#ifndef ISC_THREAD_H +#define ISC_THREAD_H 1 + +#include <windows.h> + +#include <isc/lang.h> +#include <isc/result.h> + +/* + * Inlines to help with wait retrun checking + */ + +/* check handle for NULL and INVALID_HANDLE */ +inline BOOL IsValidHandle( HANDLE hHandle) { + return ((hHandle != NULL) && (hHandle != INVALID_HANDLE_VALUE)); +} + +/* validate wait return codes... */ +inline BOOL WaitSucceeded( DWORD dwWaitResult, DWORD dwHandleCount) { + return ((dwWaitResult >= WAIT_OBJECT_0) && + (dwWaitResult < WAIT_OBJECT_0 + dwHandleCount)); +} + +inline BOOL WaitAbandoned( DWORD dwWaitResult, DWORD dwHandleCount) { + return ((dwWaitResult >= WAIT_ABANDONED_0) && + (dwWaitResult < WAIT_ABANDONED_0 + dwHandleCount)); +} + +inline BOOL WaitTimeout( DWORD dwWaitResult) { + return (dwWaitResult == WAIT_TIMEOUT); +} + +inline BOOL WaitFailed( DWORD dwWaitResult) { + return (dwWaitResult == WAIT_FAILED); +} + +/* compute object indices for waits... */ +inline DWORD WaitSucceededIndex( DWORD dwWaitResult) { + return (dwWaitResult - WAIT_OBJECT_0); +} + +inline DWORD WaitAbandonedIndex( DWORD dwWaitResult) { + return (dwWaitResult - WAIT_ABANDONED_0); +} + + + +typedef HANDLE isc_thread_t; +typedef DWORD isc_threadresult_t; +typedef void * isc_threadarg_t; +typedef isc_threadresult_t (WINAPI *isc_threadfunc_t)(isc_threadarg_t); +typedef DWORD isc_thread_key_t; + +#define isc_thread_self (unsigned long)GetCurrentThreadId + +ISC_LANG_BEGINDECLS + +isc_result_t +isc_thread_create(isc_threadfunc_t, isc_threadarg_t, isc_thread_t *); + +isc_result_t +isc_thread_join(isc_thread_t, isc_threadresult_t *); + +void +isc_thread_setconcurrency(unsigned int level); + +int +isc_thread_key_create(isc_thread_key_t *key, void (*func)(void *)); + +int +isc_thread_key_delete(isc_thread_key_t key); + +void * +isc_thread_key_getspecific(isc_thread_key_t); + +int +isc_thread_key_setspecific(isc_thread_key_t key, void *value); + +ISC_LANG_ENDDECLS + +#endif /* ISC_THREAD_H */ diff --git a/contrib/ntp/lib/isc/win32/include/isc/time.h b/contrib/ntp/lib/isc/win32/include/isc/time.h new file mode 100644 index 0000000..8ffb24b --- /dev/null +++ b/contrib/ntp/lib/isc/win32/include/isc/time.h @@ -0,0 +1,291 @@ +/* + * Copyright (C) 2004, 2006-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: time.h,v 1.35 2009/01/05 23:47:54 tbox Exp $ */ + +#ifndef ISC_TIME_H +#define ISC_TIME_H 1 + +#include <windows.h> + +#include <isc/lang.h> +#include <isc/types.h> + +/*** + *** Intervals + ***/ + +/* + * The contents of this structure are private, and MUST NOT be accessed + * directly by callers. + * + * The contents are exposed only to allow callers to avoid dynamic allocation. + */ +struct isc_interval { + isc_int64_t interval; +}; + +LIBISC_EXTERNAL_DATA extern isc_interval_t *isc_interval_zero; + +ISC_LANG_BEGINDECLS + +void +isc_interval_set(isc_interval_t *i, + unsigned int seconds, unsigned int nanoseconds); +/* + * Set 'i' to a value representing an interval of 'seconds' seconds and + * 'nanoseconds' nanoseconds, suitable for use in isc_time_add() and + * isc_time_subtract(). + * + * Requires: + * + * 't' is a valid pointer. + * nanoseconds < 1000000000. + */ + +isc_boolean_t +isc_interval_iszero(const isc_interval_t *i); +/* + * Returns ISC_TRUE iff. 'i' is the zero interval. + * + * Requires: + * + * 'i' is a valid pointer. + */ + +/*** + *** Absolute Times + ***/ + +/* + * The contents of this structure are private, and MUST NOT be accessed + * directly by callers. + * + * The contents are exposed only to allow callers to avoid dynamic allocation. + */ + +struct isc_time { + FILETIME absolute; +}; + +LIBISC_EXTERNAL_DATA extern isc_time_t *isc_time_epoch; + +void +isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds); +/*%< + * Set 't' to a value which represents the given number of seconds and + * nanoseconds since 00:00:00 January 1, 1970, UTC. + * + * Requires: + *\li 't' is a valid pointer. + *\li nanoseconds < 1000000000. + */ + +void +isc_time_settoepoch(isc_time_t *t); +/* + * Set 't' to the time of the epoch. + * + * Notes: + * The date of the epoch is platform-dependent. + * + * Requires: + * + * 't' is a valid pointer. + */ + +isc_boolean_t +isc_time_isepoch(const isc_time_t *t); +/* + * Returns ISC_TRUE iff. 't' is the epoch ("time zero"). + * + * Requires: + * + * 't' is a valid pointer. + */ + +isc_result_t +isc_time_now(isc_time_t *t); +/* + * Set 't' to the current absolute time. + * + * Requires: + * + * 't' is a valid pointer. + * + * Returns: + * + * Success + * Unexpected error + * Getting the time from the system failed. + * Out of range + * The time from the system is too large to be represented + * in the current definition of isc_time_t. + */ + +isc_result_t +isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i); +/* + * Set *t to the current absolute time + i. + * + * Note: + * This call is equivalent to: + * + * isc_time_now(t); + * isc_time_add(t, i, t); + * + * Requires: + * + * 't' and 'i' are valid pointers. + * + * Returns: + * + * Success + * Unexpected error + * Getting the time from the system failed. + * Out of range + * The interval added to the time from the system is too large to + * be represented in the current definition of isc_time_t. + */ + +int +isc_time_compare(const isc_time_t *t1, const isc_time_t *t2); +/* + * Compare the times referenced by 't1' and 't2' + * + * Requires: + * + * 't1' and 't2' are valid pointers. + * + * Returns: + * + * -1 t1 < t2 (comparing times, not pointers) + * 0 t1 = t2 + * 1 t1 > t2 + */ + +isc_result_t +isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result); +/* + * Add 'i' to 't', storing the result in 'result'. + * + * Requires: + * + * 't', 'i', and 'result' are valid pointers. + * + * Returns: + * Success + * Out of range + * The interval added to the time is too large to + * be represented in the current definition of isc_time_t. + */ + +isc_result_t +isc_time_subtract(const isc_time_t *t, const isc_interval_t *i, + isc_time_t *result); +/* + * Subtract 'i' from 't', storing the result in 'result'. + * + * Requires: + * + * 't', 'i', and 'result' are valid pointers. + * + * Returns: + * Success + * Out of range + * The interval is larger than the time since the epoch. + */ + +isc_uint64_t +isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2); +/* + * Find the difference in milliseconds between time t1 and time t2. + * t2 is the subtrahend of t1; ie, difference = t1 - t2. + * + * Requires: + * + * 't1' and 't2' are valid pointers. + * + * Returns: + * The difference of t1 - t2, or 0 if t1 <= t2. + */ + +isc_uint32_t +isc_time_nanoseconds(const isc_time_t *t); +/* + * Return the number of nanoseconds stored in a time structure. + * + * Notes: + * This is the number of nanoseconds in excess of the number + * of seconds since the epoch; it will always be less than one + * full second. + * + * Requires: + * 't' is a valid pointer. + * + * Ensures: + * The returned value is less than 1*10^9. + */ + +void +isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len); +/* + * Format the time 't' into the buffer 'buf' of length 'len', + * using a format like "30-Aug-2000 04:06:47.997" and the local time zone. + * If the text does not fit in the buffer, the result is indeterminate, + * but is always guaranteed to be null terminated. + * + * Requires: + * 'len' > 0 + * 'buf' points to an array of at least len chars + * + */ + +void +isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len); +/* + * Format the time 't' into the buffer 'buf' of length 'len', + * using a format like "Mon, 30 Aug 2000 04:06:47 GMT" + * If the text does not fit in the buffer, the result is indeterminate, + * but is always guaranteed to be null terminated. + * + * Requires: + * 'len' > 0 + * 'buf' points to an array of at least len chars + * + */ + +void +isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len); +/*%< + * Format the time 't' into the buffer 'buf' of length 'len', + * using the ISO8601 format: "yyyy-mm-ddThh:mm:ssZ" + * If the text does not fit in the buffer, the result is indeterminate, + * but is always guaranteed to be null terminated. + * + * Requires: + *\li 'len' > 0 + *\li 'buf' points to an array of at least len chars + * + */ + +isc_uint32_t +isc_time_seconds(const isc_time_t *t); + +ISC_LANG_ENDDECLS + +#endif /* ISC_TIME_H */ diff --git a/contrib/ntp/lib/isc/win32/include/isc/win32os.h b/contrib/ntp/lib/isc/win32/include/isc/win32os.h new file mode 100644 index 0000000..bd40393 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/include/isc/win32os.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: win32os.h,v 1.7 2009/06/25 23:48:02 tbox Exp $ */ + +#ifndef ISC_WIN32OS_H +#define ISC_WIN32OS_H 1 + +#include <isc/lang.h> + +ISC_LANG_BEGINDECLS + +/* + * Return the number of CPUs available on the system, or 1 if this cannot + * be determined. + */ + +unsigned int +isc_win32os_majorversion(void); +/* + * Major Version of the O/S. + */ + +unsigned int +isc_win32os_minorversion(void); +/* + * Minor Version of the O/S. + */ + +unsigned int +isc_win32os_servicepackmajor(void); +/* + * Major Version of the Service Pack for O/S. + */ + +unsigned int +isc_win32os_servicepackminor(void); +/* + * Minor Version of the Service Pack for O/S. + */ + +int +isc_win32os_versioncheck(unsigned int major, unsigned int minor, + unsigned int updatemajor, unsigned int updateminor); + +/* + * Checks the current version of the operating system with the + * supplied version information. + * Returns: + * -1 if less than the version information supplied + * 0 if equal to all of the version information supplied + * +1 if greater than the version information supplied + */ + +ISC_LANG_ENDDECLS + +#endif /* ISC_WIN32OS_H */ diff --git a/contrib/ntp/lib/isc/win32/interfaceiter.c b/contrib/ntp/lib/isc/win32/interfaceiter.c new file mode 100644 index 0000000..8753aa8 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/interfaceiter.c @@ -0,0 +1,807 @@ +/* + * Copyright (C) 2004, 2007-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: interfaceiter.c,v 1.15 2009/01/18 23:48:14 tbox Exp $ */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <winsock2.h> +#include <ws2tcpip.h> +#include <gaa_compat.h> + +#include <isc/interfaceiter.h> +#include <isc/mem.h> +#include <isc/result.h> +#include <isc/string.h> +#include <isc/strerror.h> +#include <isc/types.h> +#include <isc/util.h> +#include <isc/win32os.h> + +void InitSockets(void); + + +#define IFITER_MAGIC 0x49464954U /* IFIT. */ +#define VALID_IFITER(t) ((t) != NULL && (t)->magic == IFITER_MAGIC) + +struct isc_interfaceiter { + unsigned int magic; /* Magic number. */ + /* common fields */ + isc_mem_t *mctx; + isc_interface_t current; /* Current interface data. */ + isc_result_t result; /* Last result code. */ + /* fields used if GetAdaptersAddresses is available at runtime */ + IP_ADAPTER_ADDRESSES * ipaa; /* GAA() result buffer */ + ULONG ipaasize; /* Bytes allocated */ + IP_ADAPTER_ADDRESSES * ipaaCur; /* enumeration position */ + IP_ADAPTER_UNICAST_ADDRESS *ipuaCur; /* enumeration subposition */ + /* fields used for the older address enumeration ioctls */ + int socket; + INTERFACE_INFO IFData; /* Current Interface Info */ + int numIF; /* Current Interface count */ + int v4IF; /* Number of IPv4 Interfaces */ + INTERFACE_INFO *buf4; /* Buffer for WSAIoctl data. */ + unsigned int buf4size; /* Bytes allocated. */ + INTERFACE_INFO *pos4; /* Current offset in IF List */ + SOCKET_ADDRESS_LIST *buf6; + unsigned int buf6size; /* Bytes allocated. */ + unsigned int pos6; /* buf6 index, counts down */ + struct in6_addr loop__1; /* ::1 node-scope localhost */ + struct in6_addr loopfe80__1; /* fe80::1 link-scope localhost */ +}; + +typedef ULONG (WINAPI *PGETADAPTERSADDRESSES)( + ULONG Family, + ULONG Flags, + PVOID Reserved, + PIP_ADAPTER_ADDRESSES AdapterAddresses, + PULONG SizePointer +); + +static isc_boolean_t use_GAA; +static isc_boolean_t use_GAA_determined; +static HMODULE hmod_iphlpapi; +static PGETADAPTERSADDRESSES pGAA; + + +/* + * Size of buffer for SIO_GET_INTERFACE_LIST, in number of interfaces. + * We assume no sane system will have more than than 1K of IP addresses on + * all of its adapters. + */ +#define IFCONF_SIZE_INITIAL 16 +#define IFCONF_SIZE_INCREMENT 64 +#define IFCONF_SIZE_MAX 1040 + + +/* Common utility functions */ + +/* + * Windows always provides 255.255.255.255 as the the broadcast + * address. ntpd needs to know the broadcast address which will target + * only that network interface, not all. Reconstruct it from the + * address and mask. + */ +static void +get_broadcastaddr(isc_netaddr_t *bcastaddr, isc_netaddr_t *addr, isc_netaddr_t *netmask) { + + isc_uint32_t * b; + isc_uint32_t a, n; + + b = (isc_uint32_t *)&bcastaddr->type.in; + a = *(isc_uint32_t *)&addr->type.in; + n = *(isc_uint32_t *)&netmask->type.in; + + *b = a | ~n; +} + +isc_result_t +isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) { + char strbuf[ISC_STRERRORSIZE]; + isc_interfaceiter_t *iter; + isc_result_t result; + unsigned int major; + unsigned int minor; + unsigned int spmajor; + ULONG err; + int tries; + int error; + unsigned long bytesReturned = 0; + + REQUIRE(mctx != NULL); + REQUIRE(iterp != NULL); + REQUIRE(*iterp == NULL); + + iter = isc_mem_get(mctx, sizeof(*iter)); + if (iter == NULL) + return (ISC_R_NOMEMORY); + + InitSockets(); + + iter->mctx = mctx; + iter->ipaa = NULL; + iter->buf4 = NULL; + iter->buf6 = NULL; + iter->pos4 = NULL; + iter->ipaaCur = NULL; + iter->ipuaCur = NULL; + iter->ipaasize = 0; + iter->pos6 = 0; + iter->buf6size = 0; + iter->buf4size = 0; + iter->result = ISC_R_FAILURE; + iter->numIF = 0; + iter->v4IF = 0; + + /* + * Use GetAdaptersAddresses in preference to ioctls when running + * on Windows XP SP1 or later. Earlier GetAdaptersAddresses do + * not appear to provide enough information to associate unicast + * addresses with their prefixes. + */ + if (!use_GAA_determined) { + major = isc_win32os_majorversion(); + minor = isc_win32os_minorversion(); + spmajor = isc_win32os_servicepackmajor(); + if (major > 5 || (5 == major && + (minor > 1 || (1 == minor && spmajor >= 1)))) { + if (NULL == hmod_iphlpapi) + hmod_iphlpapi = LoadLibrary("iphlpapi"); + if (NULL != hmod_iphlpapi) + pGAA = (PGETADAPTERSADDRESSES) + GetProcAddress( + hmod_iphlpapi, + "GetAdaptersAddresses"); + if (NULL != pGAA) + use_GAA = ISC_TRUE; + } + use_GAA_determined = ISC_TRUE; + } + + if (!use_GAA) + goto use_ioctls; + + iter->ipaasize = 16 * 1024; + + for (tries = 0; tries < 5; tries++) { + iter->ipaa = isc_mem_reallocate(mctx, iter->ipaa, + iter->ipaasize); + if (NULL == iter->ipaa) { + result = ISC_R_NOMEMORY; + goto put_iter; + } + err = (*pGAA)( + AF_UNSPEC, + GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST, + NULL, + iter->ipaa, + &iter->ipaasize); + if (NO_ERROR == err || ERROR_BUFFER_OVERFLOW != err) + break; + } + + if (NO_ERROR != err) { + isc__strerror(err, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "GetAdaptersAddresses: %s", + strbuf); + result = ISC_R_UNEXPECTED; + goto gaa_failure; + } + + iter->ipaaCur = iter->ipaa; + goto success; + + use_ioctls: + /* + * Create an unbound datagram socket to do the + * SIO_GET_INTERFACE_LIST WSAIoctl on. + */ + if ((iter->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + error = WSAGetLastError(); + if (error == WSAEAFNOSUPPORT) + goto inet6_only; + isc__strerror(error, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "making interface scan socket: %s", + strbuf); + result = ISC_R_UNEXPECTED; + goto put_iter; + } + + /* + * Get the interface configuration, allocating more memory if + * necessary. + */ + iter->buf4size = IFCONF_SIZE_INITIAL*sizeof(INTERFACE_INFO); + + for (;;) { + iter->buf4 = isc_mem_get(mctx, iter->buf4size); + if (iter->buf4 == NULL) { + result = ISC_R_NOMEMORY; + goto alloc_failure; + } + + if (WSAIoctl(iter->socket, SIO_GET_INTERFACE_LIST, + 0, 0, iter->buf4, iter->buf4size, + &bytesReturned, 0, 0) == SOCKET_ERROR) + { + error = WSAGetLastError(); + if (error != WSAEFAULT && error != WSAENOBUFS) { + errno = error; + isc__strerror(error, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "get interface configuration: %s", + strbuf); + result = ISC_R_UNEXPECTED; + goto ioctl_failure; + } + /* + * EINVAL. Retry with a bigger buffer. + */ + } else { + /* + * The WSAIoctl succeeded. + * If the number of the returned bytes is the same + * as the buffer size, we will grow it just in + * case and retry. + */ + if (bytesReturned > 0 && + (bytesReturned < iter->buf4size)) + break; + } + if (iter->buf4size >= IFCONF_SIZE_MAX*sizeof(INTERFACE_INFO)) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "get interface configuration: " + "maximum buffer size exceeded"); + result = ISC_R_UNEXPECTED; + goto ioctl_failure; + } + isc_mem_put(mctx, iter->buf4, iter->buf4size); + + iter->buf4size += IFCONF_SIZE_INCREMENT * + sizeof(INTERFACE_INFO); + } + + /* + * A newly created iterator has an undefined position + * until isc_interfaceiter_first() is called. + */ + iter->v4IF = bytesReturned/sizeof(INTERFACE_INFO); + + /* We don't need the socket any more, so close it */ + closesocket(iter->socket); + + inet6_only: + /* + * Create an unbound datagram socket to do the + * SIO_ADDRESS_LIST_QUERY WSAIoctl on. + */ + if ((iter->socket = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + error = WSAGetLastError(); + if (error == WSAEAFNOSUPPORT) + goto success; + isc__strerror(error, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "making interface scan socket: %s", + strbuf); + result = ISC_R_UNEXPECTED; + goto put_iter; + } + + /* + * Get the interface configuration, allocating more memory if + * necessary. + */ + iter->buf6size = sizeof(SOCKET_ADDRESS_LIST) + + IFCONF_SIZE_INITIAL*sizeof(SOCKET_ADDRESS); + + for (;;) { + iter->buf6 = isc_mem_get(mctx, iter->buf6size); + if (iter->buf6 == NULL) { + result = ISC_R_NOMEMORY; + goto ioctl_failure; + } + + if (WSAIoctl(iter->socket, SIO_ADDRESS_LIST_QUERY, + 0, 0, iter->buf6, iter->buf6size, + &bytesReturned, 0, 0) == SOCKET_ERROR) + { + error = WSAGetLastError(); + if (error != WSAEFAULT && error != WSAENOBUFS) { + errno = error; + isc__strerror(error, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "sio address list query: %s", + strbuf); + result = ISC_R_UNEXPECTED; + goto ioctl6_failure; + } + /* + * EINVAL. Retry with a bigger buffer. + */ + } else + break; + + if (iter->buf6size >= IFCONF_SIZE_MAX*sizeof(SOCKET_ADDRESS)) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "get interface configuration: " + "maximum buffer size exceeded"); + result = ISC_R_UNEXPECTED; + goto ioctl6_failure; + } + isc_mem_put(mctx, iter->buf6, iter->buf6size); + + iter->buf6size += IFCONF_SIZE_INCREMENT * + sizeof(SOCKET_ADDRESS); + } + + /* + * initialize loop__1 to [::1] and loopfe80__1 to [fe80::1]. + * used by internal_current6(). + */ + memset(&iter->loop__1, 0, sizeof(iter->loop__1)); + memset(&iter->loopfe80__1, 0, sizeof(iter->loopfe80__1)); + iter->loop__1.s6_addr[15] = 1; + iter->loopfe80__1.s6_addr[15] = 1; + iter->loopfe80__1.s6_addr[0] = 0xfe; + iter->loopfe80__1.s6_addr[1] = 0x80; + + closesocket(iter->socket); + + success: + iter->magic = IFITER_MAGIC; + *iterp = iter; + return (ISC_R_SUCCESS); + + gaa_failure: + isc_mem_put(mctx, iter->ipaa, iter->ipaasize); + goto put_iter; + + ioctl6_failure: + isc_mem_put(mctx, iter->buf6, iter->buf6size); + + ioctl_failure: + if (iter->buf4 != NULL) + isc_mem_put(mctx, iter->buf4, iter->buf4size); + + alloc_failure: + if (iter->socket >= 0) + (void) closesocket(iter->socket); + + put_iter: + isc_mem_put(mctx, iter, sizeof(*iter)); + return (result); +} + +static unsigned char +GAA_find_prefix(isc_interfaceiter_t *iter) { + IP_ADAPTER_PREFIX * ipap; + IP_ADAPTER_PREFIX * ipap_match; + int match_len; + int max_len; + isc_netaddr_t target; + u_short af; + isc_netaddr_t pfx; + int pfx_len; + size_t nbytes; + unsigned char nbits; + unsigned char * pbits; + unsigned int octets; + + match_len = 0; + ipap_match = NULL; + isc_netaddr_fromsockaddr(&target, + (isc_sockaddr_t *)iter->ipuaCur->Address.lpSockaddr); + af = (u_short)target.family; + INSIST(AF_INET == af || AF_INET6 == af); + max_len = (AF_INET6 == af) ? 128 : 32; + iter->current.netmask.family = af; + for (ipap = iter->ipaaCur->FirstPrefix; + ipap != NULL; + ipap = ipap->Next) { + if (ipap->Address.lpSockaddr->sa_family != af) + continue; + isc_netaddr_fromsockaddr(&pfx, + (isc_sockaddr_t *)ipap->Address.lpSockaddr); + pfx_len = ipap->PrefixLength; + INSIST(0 <= pfx_len && pfx_len <= max_len); + if (pfx_len > match_len && pfx_len < max_len && + isc_netaddr_eqprefix(&target, &pfx, pfx_len)) { + ipap_match = ipap; + match_len = pfx_len; + } + } + if (NULL == ipap_match) { + /* presume all-ones mask */ + if (AF_INET6 == af) + octets = sizeof(iter->current.netmask.type.in6); + else + octets = sizeof(iter->current.netmask.type.in); + memset(&iter->current.netmask.type, 0xFF, octets); + return (8 * (unsigned char)octets); + } + nbytes = match_len / 8; + nbits = match_len % 8; + memset(&iter->current.netmask.type.in6, 0xFF, nbytes); + pbits = (void *)&iter->current.netmask.type.in6; + pbits += nbytes; + *pbits |= 0xFF << (8 - nbits); + return ((unsigned char)match_len); +} + +static isc_result_t +internal_current_GAA(isc_interfaceiter_t *iter) { + IP_ADAPTER_ADDRESSES *adap; + IP_ADAPTER_UNICAST_ADDRESS *addr; + unsigned char prefix_len; + + REQUIRE(iter->ipaaCur != NULL); + REQUIRE(iter->ipuaCur != NULL); + adap = iter->ipaaCur; + addr = iter->ipuaCur; + if (IpDadStatePreferred != addr->DadState) + return (ISC_R_IGNORE); + memset(&iter->current, 0, sizeof(iter->current)); + iter->current.af = addr->Address.lpSockaddr->sa_family; + isc_netaddr_fromsockaddr(&iter->current.address, + (isc_sockaddr_t *)addr->Address.lpSockaddr); + if (AF_INET6 == iter->current.af) + iter->current.ifindex = adap->Ipv6IfIndex; + iter->current.name[0] = '\0'; + WideCharToMultiByte( + CP_ACP, + 0, + adap->FriendlyName, + -1, + iter->current.name, + sizeof(iter->current.name), + NULL, + NULL); + iter->current.name[sizeof(iter->current.name) - 1] = '\0'; + if (IfOperStatusUp == adap->OperStatus) + iter->current.flags |= INTERFACE_F_UP; + if (IF_TYPE_PPP == adap->IfType) + iter->current.flags |= INTERFACE_F_POINTTOPOINT; + else if (IF_TYPE_SOFTWARE_LOOPBACK == adap->IfType) + iter->current.flags |= INTERFACE_F_LOOPBACK; + if ((IP_ADAPTER_NO_MULTICAST & adap->Flags) == 0) + iter->current.flags |= INTERFACE_F_MULTICAST; + if (IpSuffixOriginRandom == addr->SuffixOrigin) + iter->current.flags |= INTERFACE_F_PRIVACY; + + prefix_len = GAA_find_prefix(iter); + /* I'm failing to see a broadcast flag via GAA */ + if (AF_INET == iter->current.af && prefix_len < 32 && + (INTERFACE_F_LOOPBACK & iter->current.flags) == 0) { + iter->current.flags |= INTERFACE_F_BROADCAST; + get_broadcastaddr(&iter->current.broadcast, + &iter->current.address, + &iter->current.netmask); + } + return (ISC_R_SUCCESS); +} + +/* + * Get information about the current interface to iter->current. + * If successful, return ISC_R_SUCCESS. + * If the interface has an unsupported address family, or if + * some operation on it fails, return ISC_R_IGNORE to make + * the higher-level iterator code ignore it. + */ + +static isc_result_t +internal_current(isc_interfaceiter_t *iter) { + BOOL ifNamed = FALSE; + unsigned long flags; + + REQUIRE(VALID_IFITER(iter)); + REQUIRE(iter->numIF >= 0); + + memset(&iter->current, 0, sizeof(iter->current)); + iter->current.af = AF_INET; + + isc_netaddr_fromsockaddr(&iter->current.address, + (isc_sockaddr_t *)&(iter->IFData.iiAddress)); + + /* + * Get interface flags. + */ + + iter->current.flags = 0; + flags = iter->IFData.iiFlags; + + if ((flags & IFF_UP) != 0) + iter->current.flags |= INTERFACE_F_UP; + + if ((flags & IFF_BROADCAST) != 0) + iter->current.flags |= INTERFACE_F_BROADCAST; + + if ((flags & IFF_MULTICAST) != 0) + iter->current.flags |= INTERFACE_F_MULTICAST; + + if ((flags & IFF_POINTTOPOINT) != 0) { + iter->current.flags |= INTERFACE_F_POINTTOPOINT; + snprintf(iter->current.name, sizeof(iter->current.name), + "PPP %d", iter->numIF); + ifNamed = TRUE; + } + + if ((flags & IFF_LOOPBACK) != 0) { + iter->current.flags |= INTERFACE_F_LOOPBACK; + snprintf(iter->current.name, sizeof(iter->current.name), + "v4loop %d", iter->numIF); + ifNamed = TRUE; + } + + /* + * If the interface is point-to-point, get the destination address. + */ + if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) + isc_netaddr_fromsockaddr(&iter->current.dstaddress, + (isc_sockaddr_t *)&(iter->IFData.iiBroadcastAddress)); + + /* + * Get the network mask. + */ + isc_netaddr_fromsockaddr(&iter->current.netmask, + (isc_sockaddr_t *)&(iter->IFData.iiNetmask)); + + /* + * If the interface is broadcast, get the broadcast address, + * based on the unicast address and network mask. + */ + if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) + get_broadcastaddr(&iter->current.broadcast, + &iter->current.address, + &iter->current.netmask); + + if (ifNamed == FALSE) + snprintf(iter->current.name, sizeof(iter->current.name), + "IPv4 %d", iter->numIF); + + return (ISC_R_SUCCESS); +} + +static isc_result_t +internal_current6(isc_interfaceiter_t *iter) { + BOOL ifNamed = FALSE; + struct sockaddr_in6 *psa6; + BOOL localhostSeen; + int i; + + REQUIRE(VALID_IFITER(iter)); + REQUIRE(iter->pos6 >= 0); + REQUIRE(iter->buf6 != 0); + + memset(&iter->current, 0, sizeof(iter->current)); + iter->current.af = AF_INET6; + + /* + * synthesize localhost ::1 before returning the rest, if ::1 + * is not on the list. + */ + if (iter->pos6 >= (unsigned)iter->buf6->iAddressCount) { + localhostSeen = FALSE; + for (i = 0; i < iter->buf6->iAddressCount; i++) { + psa6 = (struct sockaddr_in6 *) + iter->buf6->Address[i].lpSockaddr; + if (!memcmp(&iter->loop__1, &psa6->sin6_addr, + sizeof(iter->loop__1))) { + localhostSeen = TRUE; + break; + } + } + if (localhostSeen) + iter->pos6 = iter->buf6->iAddressCount - 1; + } + + if (iter->pos6 < (unsigned)iter->buf6->iAddressCount) { + isc_netaddr_fromsockaddr(&iter->current.address, + (isc_sockaddr_t *)iter->buf6->Address[iter->pos6].lpSockaddr); + } else { + iter->current.address.family = AF_INET6; + memcpy(&iter->current.address.type.in6, &iter->loop__1, + sizeof(iter->current.address.type.in6)); + } + + /* + * Get interface flags. + */ + + iter->current.flags = INTERFACE_F_UP | INTERFACE_F_MULTICAST; + + if (!memcmp(&iter->current.address.type.in6, &iter->loop__1, + sizeof(iter->current.address.type.in6)) || + !memcmp(&iter->current.address.type.in6, &iter->loopfe80__1, + sizeof(iter->current.address.type.in6))) { + + iter->current.flags |= INTERFACE_F_LOOPBACK; + snprintf(iter->current.name, sizeof(iter->current.name), + "v6loop %d", + iter->buf6->iAddressCount - iter->pos6); + ifNamed = TRUE; + } + + if (ifNamed == FALSE) + snprintf(iter->current.name, sizeof(iter->current.name), + "IPv6 %d", + iter->buf6->iAddressCount - iter->pos6); + + memset(iter->current.netmask.type.in6.s6_addr, 0xff, + sizeof(iter->current.netmask.type.in6.s6_addr)); + iter->current.netmask.family = AF_INET6; + return (ISC_R_SUCCESS); +} + +static isc_result_t +internal_next_GAA(isc_interfaceiter_t *iter) { + REQUIRE(use_GAA); + if (NULL == iter->ipaaCur) + return (ISC_R_NOMORE); + if (NULL == iter->ipuaCur) + iter->ipuaCur = iter->ipaaCur->FirstUnicastAddress; + else + iter->ipuaCur = iter->ipuaCur->Next; + while (NULL == iter->ipuaCur) { + iter->ipaaCur = iter->ipaaCur->Next; + if (NULL == iter->ipaaCur) + return (ISC_R_NOMORE); + iter->ipuaCur = iter->ipaaCur->FirstUnicastAddress; + } + return (ISC_R_SUCCESS); +} + +/* + * Step the iterator to the next interface. Unlike + * isc_interfaceiter_next(), this may leave the iterator + * positioned on an interface that will ultimately + * be ignored. Return ISC_R_NOMORE if there are no more + * interfaces, otherwise ISC_R_SUCCESS. + */ +static isc_result_t +internal_next(isc_interfaceiter_t *iter) { + if (iter->numIF >= iter->v4IF) + return (ISC_R_NOMORE); + + /* + * The first one needs to be set up to point to the last + * Element of the array. Go to the end and back up + * Microsoft's implementation is peculiar for returning + * the list in reverse order + */ + + if (iter->numIF == 0) + iter->pos4 = (INTERFACE_INFO *)(iter->buf4 + (iter->v4IF)); + + iter->pos4--; + if (&(iter->pos4) < &(iter->buf4)) + return (ISC_R_NOMORE); + + memset(&(iter->IFData), 0, sizeof(INTERFACE_INFO)); + memcpy(&(iter->IFData), iter->pos4, sizeof(INTERFACE_INFO)); + iter->numIF++; + + return (ISC_R_SUCCESS); +} + +static isc_result_t +internal_next6(isc_interfaceiter_t *iter) { + if (iter->pos6 == 0) + return (ISC_R_NOMORE); + iter->pos6--; + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_interfaceiter_current(isc_interfaceiter_t *iter, + isc_interface_t *ifdata) { + REQUIRE(iter->result == ISC_R_SUCCESS); + memcpy(ifdata, &iter->current, sizeof(*ifdata)); + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_interfaceiter_first(isc_interfaceiter_t *iter) { + REQUIRE(VALID_IFITER(iter)); + REQUIRE(use_GAA_determined); + /* + * SIO_ADDRESS_LIST_QUERY (used to query IPv6 addresses) + * intentionally omits localhost addresses [::1] and [::fe80] in + * some cases. ntpd depends on enumerating [::1] to listen on + * it, and ntpq and ntpdc default to "localhost" as the target, + * so they will attempt to talk to [::1]:123 and fail. This + * means we need to synthesize ::1, which we will do first, + * hence iAddressCount + 1. internal_next6() will decrement + * it before the first use as an index, and internal_current6() + * will treat pos6 == iAddressCount as a sign to synthesize + * [::1] if needed. + */ + if (!use_GAA && iter->buf6 != NULL) + iter->pos6 = iter->buf6->iAddressCount + 1; + iter->result = ISC_R_SUCCESS; + return (isc_interfaceiter_next(iter)); +} + +isc_result_t +isc_interfaceiter_next(isc_interfaceiter_t *iter) { + isc_result_t result; + + REQUIRE(VALID_IFITER(iter)); + REQUIRE(iter->result == ISC_R_SUCCESS); + REQUIRE(use_GAA_determined); + + if (use_GAA) { + do { + result = internal_next_GAA(iter); + if (ISC_R_NOMORE == result) + goto set_result; + result = internal_current_GAA(iter); + } while (ISC_R_IGNORE == result); + goto set_result; + } + + for (;;) { + result = internal_next(iter); + if (result == ISC_R_NOMORE) { + result = internal_next6(iter); + if (result != ISC_R_SUCCESS) + break; + result = internal_current6(iter); + if (result != ISC_R_IGNORE) + break; + } else if (result != ISC_R_SUCCESS) + break; + result = internal_current(iter); + if (result != ISC_R_IGNORE) + break; + } + set_result: + iter->result = result; + return (result); +} + +void +isc_interfaceiter_destroy(isc_interfaceiter_t **iterp) { + isc_interfaceiter_t *iter; + + REQUIRE(iterp != NULL); + iter = *iterp; + REQUIRE(VALID_IFITER(iter)); + REQUIRE(use_GAA_determined); + + if (use_GAA) { + REQUIRE(NULL == iter->buf4); + REQUIRE(NULL == iter->buf4); + if (iter->ipaa != NULL) + isc_mem_put(iter->mctx, iter->ipaa, iter->ipaasize); + } else { + REQUIRE(NULL == iter->ipaa); + if (iter->buf4 != NULL) + isc_mem_put(iter->mctx, iter->buf4, iter->buf4size); + if (iter->buf6 != NULL) + isc_mem_put(iter->mctx, iter->buf6, iter->buf6size); + } + + iter->magic = 0; + isc_mem_put(iter->mctx, iter, sizeof(*iter)); + *iterp = NULL; +} diff --git a/contrib/ntp/lib/isc/win32/ipv6.c b/contrib/ntp/lib/isc/win32/ipv6.c new file mode 100644 index 0000000..511ae21 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/ipv6.c @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: ipv6.c,v 1.8 2007/06/19 23:47:19 tbox Exp $ */ + +#include <isc/net.h> +#include <isc/platform.h> + +LIBISC_EXTERNAL_DATA const struct in6_addr isc_in6addr_any = + IN6ADDR_ANY_INIT; + +LIBISC_EXTERNAL_DATA const struct in6_addr isc_in6addr_loopback = + IN6ADDR_LOOPBACK_INIT; diff --git a/contrib/ntp/lib/isc/win32/keyboard.c b/contrib/ntp/lib/isc/win32/keyboard.c new file mode 100644 index 0000000..d569e7c --- /dev/null +++ b/contrib/ntp/lib/isc/win32/keyboard.c @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: keyboard.c,v 1.7 2007/06/19 23:47:19 tbox Exp $ */ + +#include <config.h> + +#include <sys/types.h> + +#include <windows.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> + +#include <io.h> + +#include <isc/keyboard.h> +#include <isc/util.h> + +isc_result_t +isc_keyboard_open(isc_keyboard_t *keyboard) { + int fd; + + REQUIRE(keyboard != NULL); + + fd = _fileno(stdin); + if (fd < 0) + return (ISC_R_IOERROR); + + keyboard->fd = fd; + + keyboard->result = ISC_R_SUCCESS; + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_keyboard_close(isc_keyboard_t *keyboard, unsigned int sleeptime) { + REQUIRE(keyboard != NULL); + + if (sleeptime > 0 && keyboard->result != ISC_R_CANCELED) + (void)Sleep(sleeptime*1000); + + keyboard->fd = -1; + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_keyboard_getchar(isc_keyboard_t *keyboard, unsigned char *cp) { + ssize_t cc; + unsigned char c; + + REQUIRE(keyboard != NULL); + REQUIRE(cp != NULL); + + cc = read(keyboard->fd, &c, 1); + if (cc < 0) { + keyboard->result = ISC_R_IOERROR; + return (keyboard->result); + } + + *cp = c; + + return (ISC_R_SUCCESS); +} + +isc_boolean_t +isc_keyboard_canceled(isc_keyboard_t *keyboard) { + return (ISC_TF(keyboard->result == ISC_R_CANCELED)); +} + diff --git a/contrib/ntp/lib/isc/win32/libgen.h b/contrib/ntp/lib/isc/win32/libgen.h new file mode 100644 index 0000000..1c58a95 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/libgen.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: libgen.h,v 1.3 2009/07/17 23:47:41 tbox Exp $ */ + +#ifndef LIBGEN_H +#define LIBGEN_H 1 + +char *basename(const char *); +char *dirname(const char *); + +#endif diff --git a/contrib/ntp/lib/isc/win32/libisc.def b/contrib/ntp/lib/isc/win32/libisc.def new file mode 100644 index 0000000..fb08410 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/libisc.def @@ -0,0 +1,583 @@ +LIBRARY libisc + +; Exported Functions +EXPORTS + +NTReportError +closelog +isc___mem_allocate +isc___mem_free +isc___mem_get +isc___mem_put +isc___mem_putanddetach +isc___mem_reallocate +isc___mem_strdup +isc___mempool_get +isc___mempool_put +isc___socketmgr_maxudp +isc__app_block +isc__app_finish +isc__app_onrun +isc__app_reload +isc__app_run +isc__app_shutdown +isc__app_start +isc__app_unblock +isc__backtrace_nsymbols +isc__backtrace_symtable +isc__buffer_activeregion +isc__buffer_add +isc__buffer_availableregion +isc__buffer_back +isc__buffer_clear +isc__buffer_consumedregion +isc__buffer_first +isc__buffer_forward +isc__buffer_init +isc__buffer_invalidate +isc__buffer_putmem +isc__buffer_putstr +isc__buffer_putuint16 +isc__buffer_putuint32 +isc__buffer_putuint48 +isc__buffer_putuint8 +isc__buffer_region +isc__buffer_remainingregion +isc__buffer_setactive +isc__buffer_subtract +isc__buffer_usedregion +isc__mem_attach +isc__mem_checkdestroyed +isc__mem_create +isc__mem_create2 +isc__mem_createx +isc__mem_createx2 +isc__mem_destroy +isc__mem_detach +isc__mem_getname +isc__mem_getquota +isc__mem_gettag +isc__mem_inuse +isc__mem_isovermem +isc__mem_ondestroy +isc__mem_references +isc__mem_setdestroycheck +isc__mem_setname +isc__mem_setquota +isc__mem_setwater +isc__mem_stats +isc__mem_waterack +isc__mempool_associatelock +isc__mempool_create +isc__mempool_destroy +isc__mempool_getallocated +isc__mempool_getfillcount +isc__mempool_getfreecount +isc__mempool_getfreemax +isc__mempool_getmaxalloc +isc__mempool_setfillcount +isc__mempool_setfreemax +isc__mempool_setmaxalloc +isc__mempool_setname +isc__socket_accept +isc__socket_attach +isc__socket_bind +isc__socket_cancel +isc__socket_cleanunix +isc__socket_close +isc__socket_connect +isc__socket_create +isc__socket_detach +isc__socket_dup +isc__socket_filter +isc__socket_getfd +isc__socket_getname +isc__socket_getpeername +isc__socket_getsockname +isc__socket_gettag +isc__socket_gettype +isc__socket_ipv6only +isc__socket_isbound +isc__socket_listen +isc__socket_open +isc__socket_permunix +isc__socket_recv +isc__socket_recv2 +isc__socket_recvv +isc__socket_send +isc__socket_sendto +isc__socket_sendto2 +isc__socket_sendtov +isc__socket_sendv +isc__socket_setname +isc__socketmgr_create +isc__socketmgr_create2 +isc__socketmgr_destroy +isc__socketmgr_getmaxsockets +isc__socketmgr_setreserved +isc__socketmgr_setstats +isc__strerror +isc__task_attach +isc__task_beginexclusive +isc__task_create +isc__task_destroy +isc__task_detach +isc__task_endexclusive +isc__task_getcurrenttime +isc__task_getname +isc__task_gettag +isc__task_onshutdown +isc__task_privilege +isc__task_purge +isc__task_purgeevent +isc__task_purgerange +isc__task_send +isc__task_sendanddetach +isc__task_setname +isc__task_setprivilege +isc__task_shutdown +isc__task_unsend +isc__task_unsendrange +isc__taskmgr_create +isc__taskmgr_destroy +isc__taskmgr_mode +isc__taskmgr_setmode +isc__timer_attach +isc__timer_create +isc__timer_detach +isc__timer_reset +isc__timer_touch +isc__timermgr_create +isc__timermgr_destroy +isc__timermgr_poke +isc_assertion_failed +isc_assertion_setcallback +isc_assertion_typetotext +isc_backtrace_getsymbol +isc_backtrace_getsymbolfromindex +isc_backtrace_gettrace +isc_base32_decoderegion +isc_base32_decodestring +isc_base32_tobuffer +isc_base32_totext +isc_base32hex_decoderegion +isc_base32hex_decodestring +isc_base32hex_tobuffer +isc_base32hex_totext +isc_base64_decodestring +isc_base64_tobuffer +isc_base64_totext +isc_bitstring_copy +isc_bitstring_init +isc_bitstring_invalidate +isc_buffer_allocate +isc_buffer_compact +isc_buffer_copyregion +isc_buffer_free +isc_buffer_getuint16 +isc_buffer_getuint32 +isc_buffer_getuint8 +isc_buffer_reinit +isc_bufferlist_availablecount +isc_bufferlist_usedcount +isc_commandline_parse +isc_condition_broadcast +isc_condition_destroy +isc_condition_init +isc_condition_signal +isc_condition_wait +isc_condition_waituntil +isc_dir_chdir +isc_dir_chroot +isc_dir_close +isc_dir_init +isc_dir_open +isc_dir_read +isc_dir_reset +isc_entropy_addcallbacksample +isc_entropy_addsample +isc_entropy_attach +isc_entropy_create +isc_entropy_createcallbacksource +isc_entropy_createfilesource +isc_entropy_createsamplesource +isc_entropy_destroysource +isc_entropy_detach +isc_entropy_getdata +isc_entropy_putdata +isc_entropy_stats +isc_entropy_status +isc_entropy_stopcallbacksources +isc_entropy_usebestsource +isc_error_fatal +isc_error_runtimecheck +isc_error_setfatal +isc_error_setunexpected +isc_error_unexpected +isc_event_allocate +isc_event_free +isc_file_absolutepath +isc_file_basename +isc_file_exists +isc_file_getmodtime +isc_file_isabsolute +isc_file_ischdiridempotent +isc_file_iscurrentdir +isc_file_isplainfile +isc_file_mktemplate +isc_file_openunique +isc_file_openuniquemode +isc_file_openuniqueprivate +isc_file_progname +isc_file_remove +isc_file_rename +isc_file_renameunique +isc_file_safecreate +isc_file_safemovefile +isc_file_settime +isc_file_splitpath +isc_file_template +isc_file_truncate +isc_fsaccess_add +isc_fsaccess_changeowner +isc_fsaccess_remove +isc_fsaccess_set +isc_hash_calc +isc_hash_create +isc_hash_ctxattach +isc_hash_ctxcalc +isc_hash_ctxcreate +isc_hash_ctxdetach +isc_hash_ctxinit +isc_hash_destroy +isc_hash_init +isc_heap_create +isc_heap_decreased +isc_heap_delete +isc_heap_destroy +isc_heap_element +isc_heap_increased +isc_heap_insert +isc_hex_decodestring +isc_hex_tobuffer +isc_hex_totext +isc_hmacmd5_init +isc_hmacmd5_invalidate +isc_hmacmd5_sign +isc_hmacmd5_update +isc_hmacmd5_verify +isc_hmacmd5_verify2 +isc_hmacsha1_init +isc_hmacsha1_invalidate +isc_hmacsha1_sign +isc_hmacsha1_update +isc_hmacsha1_verify +isc_hmacsha224_init +isc_hmacsha224_invalidate +isc_hmacsha224_sign +isc_hmacsha224_update +isc_hmacsha224_verify +isc_hmacsha256_init +isc_hmacsha256_invalidate +isc_hmacsha256_sign +isc_hmacsha256_update +isc_hmacsha256_verify +isc_hmacsha384_init +isc_hmacsha384_invalidate +isc_hmacsha384_sign +isc_hmacsha384_update +isc_hmacsha384_verify +isc_hmacsha512_init +isc_hmacsha512_invalidate +isc_hmacsha512_sign +isc_hmacsha512_update +isc_hmacsha512_verify +isc_httpdmgr_addurl +isc_httpdmgr_create +isc_httpdmgr_shutdown +isc_interfaceiter_create +isc_interfaceiter_current +isc_interfaceiter_destroy +isc_interfaceiter_first +isc_interfaceiter_next +isc_interval_iszero +isc_interval_set +isc_iterated_hash +isc_keyboard_canceled +isc_keyboard_close +isc_keyboard_getchar +isc_keyboard_open +isc_lex_close +isc_lex_create +isc_lex_destroy +isc_lex_getcomments +isc_lex_getlasttokentext +isc_lex_getmastertoken +isc_lex_getoctaltoken +isc_lex_getsourceline +isc_lex_getsourcename +isc_lex_getspecials +isc_lex_gettoken +isc_lex_isfile +isc_lex_openbuffer +isc_lex_openfile +isc_lex_openstream +isc_lex_setcomments +isc_lex_setspecials +isc_lex_ungettoken +isc_lfsr_generate +isc_lfsr_generate32 +isc_lfsr_init +isc_lfsr_skip +isc_lib_initmsgcat +isc_log_categorybyname +isc_log_closefilelogs +isc_log_create +isc_log_createchannel +isc_log_destroy +isc_log_getdebuglevel +isc_log_getduplicateinterval +isc_log_gettag +isc_log_ivwrite +isc_log_ivwrite1 +isc_log_iwrite +isc_log_iwrite1 +isc_log_modulebyname +isc_log_opensyslog +isc_log_registercategories +isc_log_registermodules +isc_log_setcontext +isc_log_setdebuglevel +isc_log_setduplicateinterval +isc_log_settag +isc_log_usechannel +isc_log_vwrite +isc_log_vwrite1 +isc_log_wouldlog +isc_log_write +isc_log_write1 +isc_logconfig_create +isc_logconfig_destroy +isc_logconfig_get +isc_logconfig_use +isc_md5_final +isc_md5_init +isc_md5_invalidate +isc_md5_update +isc_mem_renderxml +isc_msgcat_close +isc_msgcat_get +isc_msgcat_open +isc_mutexblock_destroy +isc_mutexblock_init +isc_net_aton +isc_net_disableipv4 +isc_net_disableipv6 +isc_net_getudpportrange +isc_net_ntop +isc_net_probe_ipv6only +isc_net_probe_ipv6pktinfo +isc_net_probeipv4 +isc_net_probeipv6 +isc_net_probeunix +isc_net_pton +isc_netaddr_any +isc_netaddr_any6 +isc_netaddr_eqprefix +isc_netaddr_equal +isc_netaddr_format +isc_netaddr_fromin +isc_netaddr_fromin6 +isc_netaddr_frompath +isc_netaddr_fromsockaddr +isc_netaddr_fromv4mapped +isc_netaddr_getzone +isc_netaddr_ismulticast +isc_netaddr_masktoprefixlen +isc_netaddr_prefixok +isc_netaddr_setzone +isc_netaddr_totext +isc_netscope_pton +isc_ntpaths_get +isc_ntpaths_init +isc_once_do +isc_ondestroy_init +isc_ondestroy_notify +isc_ondestroy_register +isc_os_ncpus +isc_parse_uint16 +isc_parse_uint32 +isc_parse_uint8 +isc_portset_add +isc_portset_addrange +isc_portset_create +isc_portset_destroy +isc_portset_isset +isc_portset_nports +isc_portset_remove +isc_portset_removerange +isc_quota_attach +isc_quota_destroy +isc_quota_detach +isc_quota_init +isc_quota_max +isc_quota_release +isc_quota_reserve +isc_quota_soft +isc_radix_create +isc_radix_destroy +isc_radix_insert +isc_radix_process +isc_radix_remove +isc_radix_search +isc_random_get +isc_random_jitter +isc_random_seed +isc_ratelimiter_attach +isc_ratelimiter_create +isc_ratelimiter_detach +isc_ratelimiter_enqueue +isc_ratelimiter_setinterval +isc_ratelimiter_setpertic +isc_ratelimiter_shutdown +isc_refcount_init +isc_region_compare +isc_resource_getcurlimit +isc_resource_getlimit +isc_resource_setlimit +isc_result_register +isc_result_totext +isc_rwlock_destroy +isc_rwlock_downgrade +isc_rwlock_init +isc_rwlock_lock +isc_rwlock_trylock +isc_rwlock_tryupgrade +isc_rwlock_unlock +isc_serial_eq +isc_serial_ge +isc_serial_gt +isc_serial_le +isc_serial_lt +isc_serial_ne +isc_sha1_final +isc_sha1_init +isc_sha1_invalidate +isc_sha1_update +isc_sha224_final +isc_sha224_init +isc_sha224_invalidate +isc_sha224_update +isc_sha256_data +isc_sha256_final +isc_sha256_init +isc_sha256_invalidate +isc_sha256_update +isc_sha384_final +isc_sha384_init +isc_sha384_invalidate +isc_sha384_update +isc_sha512_final +isc_sha512_init +isc_sha512_invalidate +isc_sha512_update +isc_sockaddr_any +isc_sockaddr_any6 +isc_sockaddr_anyofpf +isc_sockaddr_compare +isc_sockaddr_eqaddr +isc_sockaddr_eqaddrprefix +isc_sockaddr_equal +isc_sockaddr_format +isc_sockaddr_fromin +isc_sockaddr_fromin6 +isc_sockaddr_fromnetaddr +isc_sockaddr_frompath +isc_sockaddr_getport +isc_sockaddr_hash +isc_sockaddr_isexperimental +isc_sockaddr_ismulticast +isc_sockaddr_pf +isc_sockaddr_setport +isc_sockaddr_totext +isc_sockaddr_v6fromin +isc_socketmgr_renderxml +isc_stats_attach +isc_stats_create +isc_stats_decrement +isc_stats_detach +isc_stats_dump +isc_stats_increment +isc_stats_ncounters +isc_stdio_close +isc_stdio_flush +isc_stdio_open +isc_stdio_read +isc_stdio_seek +isc_stdio_sync +isc_stdio_write +isc_stdtime_get +isc_string_append +isc_string_append_truncate +isc_string_copy +isc_string_copy_truncate +isc_string_printf +isc_string_printf_truncate +isc_string_regiondup +isc_string_separate +isc_string_strlcat +isc_string_strlcpy +isc_string_touint64 +isc_symtab_create +isc_symtab_define +isc_symtab_destroy +isc_symtab_lookup +isc_symtab_undefine +isc_syslog_facilityfromstring +isc_taskmgr_renderxml +isc_taskpool_create +isc_taskpool_destroy +isc_taskpool_expand +isc_taskpool_gettask +isc_taskpool_setprivilege +isc_taskpool_size +isc_thread_create +isc_thread_join +isc_thread_key_create +isc_thread_key_delete +isc_thread_key_getspecific +isc_thread_key_setspecific +isc_thread_setconcurrency +isc_time_add +isc_time_compare +isc_time_formatISO8601 +isc_time_formattimestamp +isc_time_isepoch +isc_time_microdiff +isc_time_nanoseconds +isc_time_now +isc_time_nowplusinterval +isc_time_seconds +isc_time_set +isc_time_settoepoch +isc_time_subtract +isc_win32os_majorversion +isc_win32os_minorversion +isc_win32os_servicepackmajor +isc_win32os_servicepackminor +isc_win32os_versioncheck +openlog +syslog + +; Exported Data + +EXPORTS + +isc_commandline_argument DATA +isc_commandline_errprint DATA +isc_commandline_index DATA +isc_commandline_option DATA +isc_commandline_progname DATA +isc_commandline_reset DATA +isc_mem_debugging DATA + diff --git a/contrib/ntp/lib/isc/win32/libisc.dsp b/contrib/ntp/lib/isc/win32/libisc.dsp new file mode 100644 index 0000000..8e4441c --- /dev/null +++ b/contrib/ntp/lib/isc/win32/libisc.dsp @@ -0,0 +1,802 @@ +# Microsoft Developer Studio Project File - Name="libisc" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=libisc - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "libisc.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "libisc.mak" CFG="libisc - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "libisc - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "libisc - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "libisc - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "BIND9" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBISC_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "./" /I "../../../" /I "../../../../libxml2-2.7.3/include" /I "include" /I "../include" /I "../noatomic/include" /I "win32" /I "../../isccfg/include" /D "BIND9" /D "WIN32" /D "NDEBUG" /D "__STDC__" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBISC_EXPORTS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 ../../../../libxml2-2.7.3/win32/bin.msvc/libxml2.lib +# ADD LINK32 user32.lib advapi32.lib ws2_32.lib /nologo /dll /machine:I386 /out:"../../../Build/Release/libisc.dll" +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "BIND9" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBISC_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "./" /I "../../../" /I "../../../../libxml2-2.7.3/include" /I "include" /I "../include" /I "../noatomic/include" /I "win32" /I "../../isccfg/include" /D "BIND9" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "__STDC__" /D "_MBCS" /D "_USRDLL" /D "LIBISC_EXPORTS" /FR /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 ../../../../libxml2-2.7.3/win32/bin.msvc/libxml2.lib +# ADD LINK32 user32.lib advapi32.lib ws2_32.lib /nologo /dll /map /debug /machine:I386 /out:"../../../Build/Debug/libisc.dll" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "libisc - Win32 Release" +# Name "libisc - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\app.c +# End Source File +# Begin Source File + +SOURCE=.\condition.c +# End Source File +# Begin Source File + +SOURCE=.\dir.c +# End Source File +# Begin Source File + +SOURCE=.\DLLMain.c +# End Source File +# Begin Source File + +SOURCE=.\entropy.c +# End Source File +# Begin Source File + +SOURCE=.\errno2result.c +# End Source File +# Begin Source File + +SOURCE=.\file.c +# End Source File +# Begin Source File + +SOURCE=.\fsaccess.c +# End Source File +# Begin Source File + +SOURCE=.\interfaceiter.c +# End Source File +# Begin Source File + +SOURCE=.\ipv6.c +# End Source File +# Begin Source File + +SOURCE=..\iterated_hash.c +# End Source File +# Begin Source File + +SOURCE=.\keyboard.c +# End Source File +# Begin Source File + +SOURCE=.\net.c +# End Source File +# Begin Source File + +SOURCE=.\ntpaths.c +# End Source File +# Begin Source File + +SOURCE=.\once.c +# End Source File +# Begin Source File + +SOURCE=.\os.c +# End Source File +# Begin Source File + +SOURCE=.\resource.c +# End Source File +# Begin Source File + +SOURCE=.\socket.c +# End Source File +# Begin Source File + +SOURCE=.\strerror.c +# End Source File +# Begin Source File + +SOURCE=.\stdio.c +# End Source File +# Begin Source File + +SOURCE=.\stdtime.c +# End Source File +# Begin Source File + +SOURCE=.\syslog.c +# End Source File +# Begin Source File + +SOURCE=.\thread.c +# End Source File +# Begin Source File + +SOURCE=.\time.c +# End Source File +# Begin Source File + +SOURCE=.\version.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\include\isc\app.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\assertions.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\backtrace.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\backtrace-emptytbl.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\base32.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\base64.h +# End Source File +# Begin Source File + +SOURCE=.\include\isc\bind_registry.h +# End Source File +# Begin Source File + +SOURCE=.\include\isc\bindevt.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\bitstring.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\boolean.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\buffer.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\bufferlist.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\commandline.h +# End Source File +# Begin Source File + +SOURCE=.\include\isc\condition.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\config.h +# End Source File +# Begin Source File + +SOURCE=.\include\isc\dir.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\entropy.h +# End Source File +# Begin Source File + +SOURCE=.\errno2result.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\error.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\event.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\eventclass.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\file.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\formatcheck.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\fsaccess.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\hash.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\heap.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\hex.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\hmacmd5.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\hmacsha.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\httpd.h +# End Source File +# Begin Source File + +SOURCE=.\include\isc\int.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\interfaceiter.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\ipv6.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\iterated_hash.h +# End Source File +# Begin Source File + +SOURCE=.\include\isc\keyboard.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\lang.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\lex.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\lfsr.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\lib.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\list.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\log.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\magic.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\md5.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\mem.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\msgcat.h +# End Source File +# Begin Source File + +SOURCE=.\include\isc\msioctl.h +# End Source File +# Begin Source File + +SOURCE=.\include\isc\mutex.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\mutexblock.h +# End Source File +# Begin Source File + +SOURCE=.\include\isc\net.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\netaddr.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\netscope.h +# End Source File +# Begin Source File + +SOURCE=.\include\isc\netdb.h +# End Source File +# Begin Source File + +SOURCE=.\include\isc\ntpaths.h +# End Source File +# Begin Source File + +SOURCE=.\include\isc\offset.h +# End Source File +# Begin Source File + +SOURCE=.\include\isc\once.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\ondestroy.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\parseint.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\portset.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\os.h +# End Source File +# Begin Source File + +SOURCE=.\include\isc\platform.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\print.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\quota.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\radix.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\random.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\ratelimiter.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\refcount.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\region.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\resource.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\result.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\resultclass.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\rwlock.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\serial.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\sha1.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\sha2.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\sockaddr.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\socket.h +# End Source File +# Begin Source File + +SOURCE=.\include\isc\stats.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\stdio.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\strerror.h +# End Source File +# Begin Source File + +SOURCE=.\include\isc\stdtime.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\string.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\symtab.h +# End Source File +# Begin Source File + +SOURCE=.\include\isc\syslog.h +# End Source File +# Begin Source File + +SOURCE=.\syslog.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\task.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\taskpool.h +# End Source File +# Begin Source File + +SOURCE=.\include\isc\thread.h +# End Source File +# Begin Source File + +SOURCE=.\include\isc\time.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\timer.h +# End Source File +# Begin Source File + +SOURCE=.\include\isc\win32os.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\types.h +# End Source File +# Begin Source File + +SOURCE=.\unistd.h +# End Source File +# Begin Source File + +SOURCE=..\include\isc\util.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\versions.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Group "Main Isc Lib" + +# PROP Default_Filter "c" +# Begin Source File + +SOURCE=..\assertions.c +# End Source File +# Begin Source File + +SOURCE=..\backtrace.c +# End Source File +# Begin Source File + +SOURCE=..\backtrace-emptytbl.c +# End Source File +# Begin Source File + +SOURCE=..\base32.c +# End Source File +# Begin Source File + +SOURCE=..\base64.c +# End Source File +# Begin Source File + +SOURCE=..\bitstring.c +# End Source File +# Begin Source File + +SOURCE=..\buffer.c +# End Source File +# Begin Source File + +SOURCE=..\bufferlist.c +# End Source File +# Begin Source File + +SOURCE=..\commandline.c +# End Source File +# Begin Source File + +SOURCE=..\error.c +# End Source File +# Begin Source File + +SOURCE=..\event.c +# End Source File +# Begin Source File + +SOURCE=..\hash.c +# End Source File +# Begin Source File + +SOURCE=..\heap.c +# End Source File +# Begin Source File + +SOURCE=..\hex.c +# End Source File +# Begin Source File + +SOURCE=..\hmacmd5.c +# End Source File +# Begin Source File + +SOURCE=..\hmacsha.c +# End Source File +# Begin Source File + +SOURCE=..\httpd.c +# End Source File +# Begin Source File + +SOURCE=..\inet_aton.c +# End Source File +# Begin Source File + +SOURCE=..\inet_ntop.c +# End Source File +# Begin Source File + +SOURCE=..\inet_pton.c +# End Source File +# Begin Source File + +SOURCE=..\lex.c +# End Source File +# Begin Source File + +SOURCE=..\lfsr.c +# End Source File +# Begin Source File + +SOURCE=..\lib.c +# End Source File +# Begin Source File + +SOURCE=..\log.c +# End Source File +# Begin Source File + +SOURCE=..\md5.c +# End Source File +# Begin Source File + +SOURCE=..\mem.c +# End Source File +# Begin Source File + +SOURCE=..\nls\msgcat.c +# End Source File +# Begin Source File + +SOURCE=..\mutexblock.c +# End Source File +# Begin Source File + +SOURCE=..\netaddr.c +# End Source File +# Begin Source File + +SOURCE=..\netscope.c +# End Source File +# Begin Source File + +SOURCE=..\ondestroy.c +# End Source File +# Begin Source File + +SOURCE=..\parseint.c +# End Source File +# Begin Source File + +SOURCE=..\portset.c +# End Source File +# Begin Source File + +SOURCE=..\quota.c +# End Source File +# Begin Source File + +SOURCE=..\radix.c +# End Source File +# Begin Source File + +SOURCE=..\random.c +# End Source File +# Begin Source File + +SOURCE=..\ratelimiter.c +# End Source File +# Begin Source File + +SOURCE=..\refcount.c +# End Source File +# Begin Source File + +SOURCE=..\region.c +# End Source File +# Begin Source File + +SOURCE=..\result.c +# End Source File +# Begin Source File + +SOURCE=..\rwlock.c +# End Source File +# Begin Source File + +SOURCE=..\serial.c +# End Source File +# Begin Source File + +SOURCE=..\sha1.c +# End Source File +# Begin Source File + +SOURCE=..\sha2.c +# End Source File +# Begin Source File + +SOURCE=..\sockaddr.c +# End Source File +# Begin Source File + +SOURCE=..\stats.c +# End Source File +# Begin Source File + +SOURCE=..\string.c +# End Source File +# Begin Source File + +SOURCE=..\symtab.c +# End Source File +# Begin Source File + +SOURCE=..\task.c +# End Source File +# Begin Source File + +SOURCE=..\taskpool.c +# End Source File +# Begin Source File + +SOURCE=..\timer.c +# End Source File +# Begin Source File + +SOURCE=.\win32os.c +# End Source File +# End Group +# Begin Source File + +SOURCE=..\noatomic\include\atomic.h +# End Source File +# Begin Source File + +SOURCE=.\libisc.def +# End Source File +# End Target +# End Project diff --git a/contrib/ntp/lib/isc/win32/libisc.dsw b/contrib/ntp/lib/isc/win32/libisc.dsw new file mode 100644 index 0000000..c66c56e --- /dev/null +++ b/contrib/ntp/lib/isc/win32/libisc.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "libisc"=".\libisc.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/contrib/ntp/lib/isc/win32/libisc.mak b/contrib/ntp/lib/isc/win32/libisc.mak new file mode 100644 index 0000000..e15b46b --- /dev/null +++ b/contrib/ntp/lib/isc/win32/libisc.mak @@ -0,0 +1,2055 @@ +# Microsoft Developer Studio Generated NMAKE File, Based on libisc.dsp +!IF "$(CFG)" == "" +CFG=libisc - Win32 Debug +!MESSAGE No configuration specified. Defaulting to libisc - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "libisc - Win32 Release" && "$(CFG)" != "libisc - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "libisc.mak" CFG="libisc - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "libisc - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "libisc - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe +LIBXML=../../../../libxml2-2.7.3/win32/bin.msvc/libxml2.lib + +!IF "$(CFG)" == "libisc - Win32 Release" +_VC_MANIFEST_INC=0 +_VC_MANIFEST_BASENAME=__VC80 +!ELSE +_VC_MANIFEST_INC=1 +_VC_MANIFEST_BASENAME=__VC80.Debug +!ENDIF + +#################################################### +# Specifying name of temporary resource file used only in incremental builds: + +!if "$(_VC_MANIFEST_INC)" == "1" +_VC_MANIFEST_AUTO_RES=$(_VC_MANIFEST_BASENAME).auto.res +!else +_VC_MANIFEST_AUTO_RES= +!endif + +#################################################### +# _VC_MANIFEST_EMBED_EXE - command to embed manifest in EXE: + +!if "$(_VC_MANIFEST_INC)" == "1" + +#MT_SPECIAL_RETURN=1090650113 +#MT_SPECIAL_SWITCH=-notify_resource_update +MT_SPECIAL_RETURN=0 +MT_SPECIAL_SWITCH= +_VC_MANIFEST_EMBED_EXE= \ +if exist $@.manifest mt.exe -manifest $@.manifest -out:$(_VC_MANIFEST_BASENAME).auto.manifest $(MT_SPECIAL_SWITCH) & \ +if "%ERRORLEVEL%" == "$(MT_SPECIAL_RETURN)" \ +rc /r $(_VC_MANIFEST_BASENAME).auto.rc & \ +link $** /out:$@ $(LFLAGS) + +!else + +_VC_MANIFEST_EMBED_EXE= \ +if exist $@.manifest mt.exe -manifest $@.manifest -outputresource:$@;1 + +!endif + +#################################################### +# _VC_MANIFEST_EMBED_DLL - command to embed manifest in DLL: + +!if "$(_VC_MANIFEST_INC)" == "1" + +#MT_SPECIAL_RETURN=1090650113 +#MT_SPECIAL_SWITCH=-notify_resource_update +MT_SPECIAL_RETURN=0 +MT_SPECIAL_SWITCH= +_VC_MANIFEST_EMBED_EXE= \ +if exist $@.manifest mt.exe -manifest $@.manifest -out:$(_VC_MANIFEST_BASENAME).auto.manifest $(MT_SPECIAL_SWITCH) & \ +if "%ERRORLEVEL%" == "$(MT_SPECIAL_RETURN)" \ +rc /r $(_VC_MANIFEST_BASENAME).auto.rc & \ +link $** /out:$@ $(LFLAGS) + +!else + +_VC_MANIFEST_EMBED_EXE= \ +if exist $@.manifest mt.exe -manifest $@.manifest -outputresource:$@;2 + +!endif +#################################################### +# _VC_MANIFEST_CLEAN - command to clean resources files generated temporarily: + +!if "$(_VC_MANIFEST_INC)" == "1" + +_VC_MANIFEST_CLEAN=-del $(_VC_MANIFEST_BASENAME).auto.res \ + $(_VC_MANIFEST_BASENAME).auto.rc \ + $(_VC_MANIFEST_BASENAME).auto.manifest + +!else + +_VC_MANIFEST_CLEAN= + +!endif + +!IF "$(CFG)" == "libisc - Win32 Release" + +OUTDIR=.\Release +INTDIR=.\Release + +ALL : "..\..\..\Build\Release\libisc.dll" + + +CLEAN : + -@erase "$(INTDIR)\app.obj" + -@erase "$(INTDIR)\assertions.obj" + -@erase "$(INTDIR)\backtrace.obj" + -@erase "$(INTDIR)\backtrace-emptytbl.obj" + -@erase "$(INTDIR)\base32.obj" + -@erase "$(INTDIR)\base64.obj" + -@erase "$(INTDIR)\bitstring.obj" + -@erase "$(INTDIR)\buffer.obj" + -@erase "$(INTDIR)\bufferlist.obj" + -@erase "$(INTDIR)\commandline.obj" + -@erase "$(INTDIR)\condition.obj" + -@erase "$(INTDIR)\dir.obj" + -@erase "$(INTDIR)\DLLMain.obj" + -@erase "$(INTDIR)\entropy.obj" + -@erase "$(INTDIR)\errno2result.obj" + -@erase "$(INTDIR)\error.obj" + -@erase "$(INTDIR)\event.obj" + -@erase "$(INTDIR)\file.obj" + -@erase "$(INTDIR)\fsaccess.obj" + -@erase "$(INTDIR)\hash.obj" + -@erase "$(INTDIR)\heap.obj" + -@erase "$(INTDIR)\hex.obj" + -@erase "$(INTDIR)\hmacmd5.obj" + -@erase "$(INTDIR)\hmacsha.obj" + -@erase "$(INTDIR)\httpd.obj" + -@erase "$(INTDIR)\inet_aton.obj" + -@erase "$(INTDIR)\inet_ntop.obj" + -@erase "$(INTDIR)\inet_pton.obj" + -@erase "$(INTDIR)\interfaceiter.obj" + -@erase "$(INTDIR)\ipv6.obj" + -@erase "$(INTDIR)\iterated_hash.obj" + -@erase "$(INTDIR)\keyboard.obj" + -@erase "$(INTDIR)\lex.obj" + -@erase "$(INTDIR)\lfsr.obj" + -@erase "$(INTDIR)\lib.obj" + -@erase "$(INTDIR)\log.obj" + -@erase "$(INTDIR)\md5.obj" + -@erase "$(INTDIR)\mem.obj" + -@erase "$(INTDIR)\msgcat.obj" + -@erase "$(INTDIR)\mutexblock.obj" + -@erase "$(INTDIR)\net.obj" + -@erase "$(INTDIR)\netaddr.obj" + -@erase "$(INTDIR)\netscope.obj" + -@erase "$(INTDIR)\ntpaths.obj" + -@erase "$(INTDIR)\once.obj" + -@erase "$(INTDIR)\ondestroy.obj" + -@erase "$(INTDIR)\os.obj" + -@erase "$(INTDIR)\parseint.obj" + -@erase "$(INTDIR)\portset.obj" + -@erase "$(INTDIR)\quota.obj" + -@erase "$(INTDIR)\radix.obj" + -@erase "$(INTDIR)\random.obj" + -@erase "$(INTDIR)\ratelimiter.obj" + -@erase "$(INTDIR)\refcount.obj" + -@erase "$(INTDIR)\region.obj" + -@erase "$(INTDIR)\resource.obj" + -@erase "$(INTDIR)\result.obj" + -@erase "$(INTDIR)\rwlock.obj" + -@erase "$(INTDIR)\serial.obj" + -@erase "$(INTDIR)\sha1.obj" + -@erase "$(INTDIR)\sha2.obj" + -@erase "$(INTDIR)\sockaddr.obj" + -@erase "$(INTDIR)\socket.obj" + -@erase "$(INTDIR)\stats.obj" + -@erase "$(INTDIR)\stdio.obj" + -@erase "$(INTDIR)\stdtime.obj" + -@erase "$(INTDIR)\strerror.obj" + -@erase "$(INTDIR)\string.obj" + -@erase "$(INTDIR)\symtab.obj" + -@erase "$(INTDIR)\syslog.obj" + -@erase "$(INTDIR)\task.obj" + -@erase "$(INTDIR)\taskpool.obj" + -@erase "$(INTDIR)\thread.obj" + -@erase "$(INTDIR)\time.obj" + -@erase "$(INTDIR)\timer.obj" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\version.obj" + -@erase "$(INTDIR)\win32os.obj" + -@erase "$(OUTDIR)\libisc.exp" + -@erase "$(OUTDIR)\libisc.lib" + -@erase "..\..\..\Build\Release\libisc.dll" + -@$(_VC_MANIFEST_CLEAN) + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP_PROJ=/nologo /MD /W3 /GX /O2 /I "./" /I "../../../" /I "include" /I "../include" /I "../../../lib/isc/noatomic/include" /I "win32" /I "../../isccfg/include" /I "../../../../libxml2-2.7.3/include" /D "BIND9" /D "WIN32" /D "NDEBUG" /D "__STDC__" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBISC_EXPORTS" /Fp"$(INTDIR)\libisc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c +MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\libisc.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +LINK32_FLAGS=user32.lib advapi32.lib ws2_32.lib $(LIBXML) /nologo /dll /incremental:no /pdb:"$(OUTDIR)\libisc.pdb" /machine:I386 /def:".\libisc.def" /out:"../../../Build/Release/libisc.dll" /implib:"$(OUTDIR)\libisc.lib" +DEF_FILE= \ + ".\libisc.def" +LINK32_OBJS= \ + "$(INTDIR)\app.obj" \ + "$(INTDIR)\condition.obj" \ + "$(INTDIR)\dir.obj" \ + "$(INTDIR)\DLLMain.obj" \ + "$(INTDIR)\entropy.obj" \ + "$(INTDIR)\errno2result.obj" \ + "$(INTDIR)\file.obj" \ + "$(INTDIR)\fsaccess.obj" \ + "$(INTDIR)\interfaceiter.obj" \ + "$(INTDIR)\ipv6.obj" \ + "$(INTDIR)\iterated_hash.obj" \ + "$(INTDIR)\keyboard.obj" \ + "$(INTDIR)\net.obj" \ + "$(INTDIR)\ntpaths.obj" \ + "$(INTDIR)\once.obj" \ + "$(INTDIR)\os.obj" \ + "$(INTDIR)\resource.obj" \ + "$(INTDIR)\socket.obj" \ + "$(INTDIR)\stdio.obj" \ + "$(INTDIR)\stdtime.obj" \ + "$(INTDIR)\strerror.obj" \ + "$(INTDIR)\syslog.obj" \ + "$(INTDIR)\thread.obj" \ + "$(INTDIR)\time.obj" \ + "$(INTDIR)\version.obj" \ + "$(INTDIR)\win32os.obj" \ + "$(INTDIR)\assertions.obj" \ + "$(INTDIR)\backtrace.obj" \ + "$(INTDIR)\backtrace-emptytbl.obj" \ + "$(INTDIR)\base32.obj" \ + "$(INTDIR)\base64.obj" \ + "$(INTDIR)\bitstring.obj" \ + "$(INTDIR)\buffer.obj" \ + "$(INTDIR)\bufferlist.obj" \ + "$(INTDIR)\commandline.obj" \ + "$(INTDIR)\error.obj" \ + "$(INTDIR)\event.obj" \ + "$(INTDIR)\hash.obj" \ + "$(INTDIR)\heap.obj" \ + "$(INTDIR)\hex.obj" \ + "$(INTDIR)\hmacmd5.obj" \ + "$(INTDIR)\hmacsha.obj" \ + "$(INTDIR)\httpd.obj" \ + "$(INTDIR)\inet_aton.obj" \ + "$(INTDIR)\inet_ntop.obj" \ + "$(INTDIR)\inet_pton.obj" \ + "$(INTDIR)\lex.obj" \ + "$(INTDIR)\lfsr.obj" \ + "$(INTDIR)\lib.obj" \ + "$(INTDIR)\log.obj" \ + "$(INTDIR)\md5.obj" \ + "$(INTDIR)\mem.obj" \ + "$(INTDIR)\msgcat.obj" \ + "$(INTDIR)\mutexblock.obj" \ + "$(INTDIR)\netaddr.obj" \ + "$(INTDIR)\netscope.obj" \ + "$(INTDIR)\ondestroy.obj" \ + "$(INTDIR)\quota.obj" \ + "$(INTDIR)\radix.obj" \ + "$(INTDIR)\random.obj" \ + "$(INTDIR)\ratelimiter.obj" \ + "$(INTDIR)\refcount.obj" \ + "$(INTDIR)\result.obj" \ + "$(INTDIR)\rwlock.obj" \ + "$(INTDIR)\serial.obj" \ + "$(INTDIR)\sha1.obj" \ + "$(INTDIR)\sha2.obj" \ + "$(INTDIR)\sockaddr.obj" \ + "$(INTDIR)\stats.obj" \ + "$(INTDIR)\string.obj" \ + "$(INTDIR)\symtab.obj" \ + "$(INTDIR)\task.obj" \ + "$(INTDIR)\taskpool.obj" \ + "$(INTDIR)\timer.obj" \ + "$(INTDIR)\parseint.obj" \ + "$(INTDIR)\portset.obj" \ + "$(INTDIR)\region.obj" + +"..\..\..\Build\Release\libisc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + $(_VC_MANIFEST_EMBED_DLL) + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug +# Begin Custom Macros +OutDir=.\Debug +# End Custom Macros + +ALL : "..\..\..\Build\Debug\libisc.dll" "$(OUTDIR)\libisc.bsc" + + +CLEAN : + -@erase "$(INTDIR)\app.obj" + -@erase "$(INTDIR)\app.sbr" + -@erase "$(INTDIR)\assertions.obj" + -@erase "$(INTDIR)\assertions.sbr" + -@erase "$(INTDIR)\backtrace.obj" + -@erase "$(INTDIR)\backtrace-emptytbl.obj" + -@erase "$(INTDIR)\backtrace.sbr" + -@erase "$(INTDIR)\backtrace-emptytbl.sbr" + -@erase "$(INTDIR)\base32.obj" + -@erase "$(INTDIR)\base32.sbr" + -@erase "$(INTDIR)\base64.obj" + -@erase "$(INTDIR)\base64.sbr" + -@erase "$(INTDIR)\bitstring.obj" + -@erase "$(INTDIR)\bitstring.sbr" + -@erase "$(INTDIR)\buffer.obj" + -@erase "$(INTDIR)\buffer.sbr" + -@erase "$(INTDIR)\bufferlist.obj" + -@erase "$(INTDIR)\bufferlist.sbr" + -@erase "$(INTDIR)\commandline.obj" + -@erase "$(INTDIR)\commandline.sbr" + -@erase "$(INTDIR)\condition.obj" + -@erase "$(INTDIR)\condition.sbr" + -@erase "$(INTDIR)\dir.obj" + -@erase "$(INTDIR)\dir.sbr" + -@erase "$(INTDIR)\DLLMain.obj" + -@erase "$(INTDIR)\DLLMain.sbr" + -@erase "$(INTDIR)\entropy.obj" + -@erase "$(INTDIR)\entropy.sbr" + -@erase "$(INTDIR)\errno2result.obj" + -@erase "$(INTDIR)\errno2result.sbr" + -@erase "$(INTDIR)\error.obj" + -@erase "$(INTDIR)\error.sbr" + -@erase "$(INTDIR)\event.obj" + -@erase "$(INTDIR)\event.sbr" + -@erase "$(INTDIR)\file.obj" + -@erase "$(INTDIR)\file.sbr" + -@erase "$(INTDIR)\fsaccess.obj" + -@erase "$(INTDIR)\fsaccess.sbr" + -@erase "$(INTDIR)\hash.obj" + -@erase "$(INTDIR)\hash.sbr" + -@erase "$(INTDIR)\heap.obj" + -@erase "$(INTDIR)\heap.sbr" + -@erase "$(INTDIR)\hex.obj" + -@erase "$(INTDIR)\hex.sbr" + -@erase "$(INTDIR)\hmacmd5.obj" + -@erase "$(INTDIR)\hmacmd5.sbr" + -@erase "$(INTDIR)\hmacsha.obj" + -@erase "$(INTDIR)\hmacsha.sbr" + -@erase "$(INTDIR)\httpd.obj" + -@erase "$(INTDIR)\httpd.sbr" + -@erase "$(INTDIR)\inet_aton.obj" + -@erase "$(INTDIR)\inet_aton.sbr" + -@erase "$(INTDIR)\inet_ntop.obj" + -@erase "$(INTDIR)\inet_ntop.sbr" + -@erase "$(INTDIR)\inet_pton.obj" + -@erase "$(INTDIR)\inet_pton.sbr" + -@erase "$(INTDIR)\interfaceiter.obj" + -@erase "$(INTDIR)\interfaceiter.sbr" + -@erase "$(INTDIR)\ipv6.obj" + -@erase "$(INTDIR)\ipv6.sbr" + -@erase "$(INTDIR)\iterated_hash.obj" + -@erase "$(INTDIR)\iterated_hash.sbr" + -@erase "$(INTDIR)\keyboard.obj" + -@erase "$(INTDIR)\keyboard.sbr" + -@erase "$(INTDIR)\lex.obj" + -@erase "$(INTDIR)\lex.sbr" + -@erase "$(INTDIR)\lfsr.obj" + -@erase "$(INTDIR)\lfsr.sbr" + -@erase "$(INTDIR)\lib.obj" + -@erase "$(INTDIR)\lib.sbr" + -@erase "$(INTDIR)\log.obj" + -@erase "$(INTDIR)\log.sbr" + -@erase "$(INTDIR)\md5.obj" + -@erase "$(INTDIR)\md5.sbr" + -@erase "$(INTDIR)\mem.obj" + -@erase "$(INTDIR)\mem.sbr" + -@erase "$(INTDIR)\msgcat.obj" + -@erase "$(INTDIR)\msgcat.sbr" + -@erase "$(INTDIR)\mutexblock.obj" + -@erase "$(INTDIR)\mutexblock.sbr" + -@erase "$(INTDIR)\net.obj" + -@erase "$(INTDIR)\net.sbr" + -@erase "$(INTDIR)\netaddr.obj" + -@erase "$(INTDIR)\netaddr.sbr" + -@erase "$(INTDIR)\netscope.obj" + -@erase "$(INTDIR)\netscope.sbr" + -@erase "$(INTDIR)\ntpaths.obj" + -@erase "$(INTDIR)\ntpaths.sbr" + -@erase "$(INTDIR)\once.obj" + -@erase "$(INTDIR)\once.sbr" + -@erase "$(INTDIR)\ondestroy.obj" + -@erase "$(INTDIR)\ondestroy.sbr" + -@erase "$(INTDIR)\os.obj" + -@erase "$(INTDIR)\os.sbr" + -@erase "$(INTDIR)\parseint.obj" + -@erase "$(INTDIR)\parseint.sbr" + -@erase "$(INTDIR)\portset.obj" + -@erase "$(INTDIR)\portset.sbr" + -@erase "$(INTDIR)\quota.obj" + -@erase "$(INTDIR)\quota.sbr" + -@erase "$(INTDIR)\radix.obj" + -@erase "$(INTDIR)\radix.sbr" + -@erase "$(INTDIR)\random.obj" + -@erase "$(INTDIR)\random.sbr" + -@erase "$(INTDIR)\ratelimiter.obj" + -@erase "$(INTDIR)\ratelimiter.sbr" + -@erase "$(INTDIR)\refcount.obj" + -@erase "$(INTDIR)\refcount.sbr" + -@erase "$(INTDIR)\region.obj" + -@erase "$(INTDIR)\region.sbr" + -@erase "$(INTDIR)\resource.obj" + -@erase "$(INTDIR)\resource.sbr" + -@erase "$(INTDIR)\result.obj" + -@erase "$(INTDIR)\result.sbr" + -@erase "$(INTDIR)\rwlock.obj" + -@erase "$(INTDIR)\rwlock.sbr" + -@erase "$(INTDIR)\serial.obj" + -@erase "$(INTDIR)\serial.sbr" + -@erase "$(INTDIR)\sha1.obj" + -@erase "$(INTDIR)\sha1.sbr" + -@erase "$(INTDIR)\sha2.obj" + -@erase "$(INTDIR)\sha2.sbr" + -@erase "$(INTDIR)\sockaddr.obj" + -@erase "$(INTDIR)\sockaddr.sbr" + -@erase "$(INTDIR)\socket.obj" + -@erase "$(INTDIR)\socket.sbr" + -@erase "$(INTDIR)\stats.obj" + -@erase "$(INTDIR)\stats.sbr" + -@erase "$(INTDIR)\stdio.obj" + -@erase "$(INTDIR)\stdio.sbr" + -@erase "$(INTDIR)\stdtime.obj" + -@erase "$(INTDIR)\stdtime.sbr" + -@erase "$(INTDIR)\strerror.obj" + -@erase "$(INTDIR)\strerror.sbr" + -@erase "$(INTDIR)\string.obj" + -@erase "$(INTDIR)\string.sbr" + -@erase "$(INTDIR)\symtab.obj" + -@erase "$(INTDIR)\symtab.sbr" + -@erase "$(INTDIR)\syslog.obj" + -@erase "$(INTDIR)\syslog.sbr" + -@erase "$(INTDIR)\task.obj" + -@erase "$(INTDIR)\task.sbr" + -@erase "$(INTDIR)\taskpool.obj" + -@erase "$(INTDIR)\taskpool.sbr" + -@erase "$(INTDIR)\thread.obj" + -@erase "$(INTDIR)\thread.sbr" + -@erase "$(INTDIR)\time.obj" + -@erase "$(INTDIR)\time.sbr" + -@erase "$(INTDIR)\timer.obj" + -@erase "$(INTDIR)\timer.sbr" + -@erase "$(INTDIR)\vc60.idb" + -@erase "$(INTDIR)\vc60.pdb" + -@erase "$(INTDIR)\version.obj" + -@erase "$(INTDIR)\version.sbr" + -@erase "$(INTDIR)\win32os.obj" + -@erase "$(INTDIR)\win32os.sbr" + -@erase "$(OUTDIR)\libisc.bsc" + -@erase "$(OUTDIR)\libisc.exp" + -@erase "$(OUTDIR)\libisc.lib" + -@erase "$(OUTDIR)\libisc.map" + -@erase "$(OUTDIR)\libisc.pdb" + -@erase "..\..\..\Build\Debug\libisc.dll" + -@erase "..\..\..\Build\Debug\libisc.ilk" + -@$(_VC_MANIFEST_CLEAN) + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP_PROJ=/nologo /MDd /W3 /Gm /GX /ZI /Od /I "./" /I "../../../" /I "include" /I "../include" /I "../../../lib/isc/noatomic/include" /I "win32" /I "../../isccfg/include" /I "../../../../libxml2-2.7.3/include" /D "BIND9" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "__STDC__" /D "_MBCS" /D "_USRDLL" /D "LIBISC_EXPORTS" /FR"$(INTDIR)\\" /Fp"$(INTDIR)\libisc.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c +MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 +BSC32=bscmake.exe +BSC32_FLAGS=/nologo /o"$(OUTDIR)\libisc.bsc" +BSC32_SBRS= \ + "$(INTDIR)\app.sbr" \ + "$(INTDIR)\condition.sbr" \ + "$(INTDIR)\dir.sbr" \ + "$(INTDIR)\DLLMain.sbr" \ + "$(INTDIR)\entropy.sbr" \ + "$(INTDIR)\errno2result.sbr" \ + "$(INTDIR)\file.sbr" \ + "$(INTDIR)\fsaccess.sbr" \ + "$(INTDIR)\interfaceiter.sbr" \ + "$(INTDIR)\ipv6.sbr" \ + "$(INTDIR)\iterated_hash.sbr" \ + "$(INTDIR)\keyboard.sbr" \ + "$(INTDIR)\net.sbr" \ + "$(INTDIR)\ntpaths.sbr" \ + "$(INTDIR)\once.sbr" \ + "$(INTDIR)\os.sbr" \ + "$(INTDIR)\resource.sbr" \ + "$(INTDIR)\socket.sbr" \ + "$(INTDIR)\stdio.sbr" \ + "$(INTDIR)\stdtime.sbr" \ + "$(INTDIR)\strerror.sbr" \ + "$(INTDIR)\syslog.sbr" \ + "$(INTDIR)\thread.sbr" \ + "$(INTDIR)\time.sbr" \ + "$(INTDIR)\version.sbr" \ + "$(INTDIR)\win32os.sbr" \ + "$(INTDIR)\assertions.sbr" \ + "$(INTDIR)\backtrace.sbr" \ + "$(INTDIR)\backtrace-emptytbl.sbr" \ + "$(INTDIR)\base32.sbr" \ + "$(INTDIR)\base64.sbr" \ + "$(INTDIR)\bitstring.sbr" \ + "$(INTDIR)\buffer.sbr" \ + "$(INTDIR)\bufferlist.sbr" \ + "$(INTDIR)\commandline.sbr" \ + "$(INTDIR)\error.sbr" \ + "$(INTDIR)\event.sbr" \ + "$(INTDIR)\hash.sbr" \ + "$(INTDIR)\heap.sbr" \ + "$(INTDIR)\hex.sbr" \ + "$(INTDIR)\hmacmd5.sbr" \ + "$(INTDIR)\hmacsha.sbr" \ + "$(INTDIR)\httpd.sbr" \ + "$(INTDIR)\inet_aton.sbr" \ + "$(INTDIR)\inet_ntop.sbr" \ + "$(INTDIR)\inet_pton.sbr" \ + "$(INTDIR)\lex.sbr" \ + "$(INTDIR)\lfsr.sbr" \ + "$(INTDIR)\lib.sbr" \ + "$(INTDIR)\log.sbr" \ + "$(INTDIR)\md5.sbr" \ + "$(INTDIR)\mem.sbr" \ + "$(INTDIR)\msgcat.sbr" \ + "$(INTDIR)\mutexblock.sbr" \ + "$(INTDIR)\netaddr.sbr" \ + "$(INTDIR)\netscope.sbr" \ + "$(INTDIR)\ondestroy.sbr" \ + "$(INTDIR)\quota.sbr" \ + "$(INTDIR)\radix.sbr" \ + "$(INTDIR)\random.sbr" \ + "$(INTDIR)\ratelimiter.sbr" \ + "$(INTDIR)\refcount.sbr" \ + "$(INTDIR)\result.sbr" \ + "$(INTDIR)\rwlock.sbr" \ + "$(INTDIR)\serial.sbr" \ + "$(INTDIR)\sha1.sbr" \ + "$(INTDIR)\sha2.sbr" \ + "$(INTDIR)\sockaddr.sbr" \ + "$(INTDIR)\stats.sbr" \ + "$(INTDIR)\string.sbr" \ + "$(INTDIR)\symtab.sbr" \ + "$(INTDIR)\task.sbr" \ + "$(INTDIR)\taskpool.sbr" \ + "$(INTDIR)\timer.sbr" \ + "$(INTDIR)\parseint.sbr" \ + "$(INTDIR)\portset.sbr" \ + "$(INTDIR)\region.sbr" + +"$(OUTDIR)\libisc.bsc" : "$(OUTDIR)" $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +LINK32_FLAGS=user32.lib advapi32.lib ws2_32.lib $(LIBXML) /nologo /dll /incremental:yes /pdb:"$(OUTDIR)\libisc.pdb" /map:"$(INTDIR)\libisc.map" /debug /machine:I386 /def:".\libisc.def" /out:"../../../Build/Debug/libisc.dll" /implib:"$(OUTDIR)\libisc.lib" /pdbtype:sept +DEF_FILE= \ + ".\libisc.def" +LINK32_OBJS= \ + "$(INTDIR)\app.obj" \ + "$(INTDIR)\condition.obj" \ + "$(INTDIR)\dir.obj" \ + "$(INTDIR)\DLLMain.obj" \ + "$(INTDIR)\entropy.obj" \ + "$(INTDIR)\errno2result.obj" \ + "$(INTDIR)\file.obj" \ + "$(INTDIR)\fsaccess.obj" \ + "$(INTDIR)\interfaceiter.obj" \ + "$(INTDIR)\ipv6.obj" \ + "$(INTDIR)\iterated_hash.obj" \ + "$(INTDIR)\keyboard.obj" \ + "$(INTDIR)\net.obj" \ + "$(INTDIR)\ntpaths.obj" \ + "$(INTDIR)\once.obj" \ + "$(INTDIR)\os.obj" \ + "$(INTDIR)\resource.obj" \ + "$(INTDIR)\socket.obj" \ + "$(INTDIR)\stdio.obj" \ + "$(INTDIR)\stdtime.obj" \ + "$(INTDIR)\strerror.obj" \ + "$(INTDIR)\syslog.obj" \ + "$(INTDIR)\thread.obj" \ + "$(INTDIR)\time.obj" \ + "$(INTDIR)\version.obj" \ + "$(INTDIR)\win32os.obj" \ + "$(INTDIR)\assertions.obj" \ + "$(INTDIR)\backtrace.obj" \ + "$(INTDIR)\backtrace-emptytbl.obj" \ + "$(INTDIR)\base32.obj" \ + "$(INTDIR)\base64.obj" \ + "$(INTDIR)\bitstring.obj" \ + "$(INTDIR)\buffer.obj" \ + "$(INTDIR)\bufferlist.obj" \ + "$(INTDIR)\commandline.obj" \ + "$(INTDIR)\error.obj" \ + "$(INTDIR)\event.obj" \ + "$(INTDIR)\hash.obj" \ + "$(INTDIR)\heap.obj" \ + "$(INTDIR)\hex.obj" \ + "$(INTDIR)\hmacmd5.obj" \ + "$(INTDIR)\hmacsha.obj" \ + "$(INTDIR)\httpd.obj" \ + "$(INTDIR)\inet_aton.obj" \ + "$(INTDIR)\inet_ntop.obj" \ + "$(INTDIR)\inet_pton.obj" \ + "$(INTDIR)\lex.obj" \ + "$(INTDIR)\lfsr.obj" \ + "$(INTDIR)\lib.obj" \ + "$(INTDIR)\log.obj" \ + "$(INTDIR)\md5.obj" \ + "$(INTDIR)\mem.obj" \ + "$(INTDIR)\msgcat.obj" \ + "$(INTDIR)\mutexblock.obj" \ + "$(INTDIR)\netaddr.obj" \ + "$(INTDIR)\netscope.obj" \ + "$(INTDIR)\ondestroy.obj" \ + "$(INTDIR)\quota.obj" \ + "$(INTDIR)\radix.obj" \ + "$(INTDIR)\random.obj" \ + "$(INTDIR)\ratelimiter.obj" \ + "$(INTDIR)\refcount.obj" \ + "$(INTDIR)\result.obj" \ + "$(INTDIR)\rwlock.obj" \ + "$(INTDIR)\serial.obj" \ + "$(INTDIR)\sha1.obj" \ + "$(INTDIR)\sha2.obj" \ + "$(INTDIR)\sockaddr.obj" \ + "$(INTDIR)\stats.obj" \ + "$(INTDIR)\string.obj" \ + "$(INTDIR)\symtab.obj" \ + "$(INTDIR)\task.obj" \ + "$(INTDIR)\taskpool.obj" \ + "$(INTDIR)\timer.obj" \ + "$(INTDIR)\parseint.obj" \ + "$(INTDIR)\portset.obj" \ + "$(INTDIR)\region.obj" + +"..\..\..\Build\Debug\libisc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + $(_VC_MANIFEST_EMBED_DLL) + +!ENDIF + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.c{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cpp{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +.cxx{$(INTDIR)}.sbr:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + + +!IF "$(NO_EXTERNAL_DEPS)" != "1" +!IF EXISTS("libisc.dep") +!INCLUDE "libisc.dep" +!ELSE +!MESSAGE Warning: cannot find "libisc.dep" +!ENDIF +!ENDIF + + +!IF "$(CFG)" == "libisc - Win32 Release" || "$(CFG)" == "libisc - Win32 Debug" +SOURCE=.\app.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\app.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\app.obj" "$(INTDIR)\app.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + +SOURCE=.\condition.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\condition.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\condition.obj" "$(INTDIR)\condition.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + +SOURCE=.\dir.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\dir.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\dir.obj" "$(INTDIR)\dir.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + +SOURCE=.\DLLMain.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\DLLMain.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\DLLMain.obj" "$(INTDIR)\DLLMain.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + +SOURCE=.\entropy.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\entropy.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\entropy.obj" "$(INTDIR)\entropy.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + +SOURCE=.\errno2result.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\errno2result.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\errno2result.obj" "$(INTDIR)\errno2result.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + +SOURCE=.\file.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\file.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\file.obj" "$(INTDIR)\file.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + +SOURCE=.\fsaccess.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\fsaccess.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\fsaccess.obj" "$(INTDIR)\fsaccess.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + +SOURCE=.\interfaceiter.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\interfaceiter.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\interfaceiter.obj" "$(INTDIR)\interfaceiter.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + +SOURCE=.\ipv6.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\ipv6.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\ipv6.obj" "$(INTDIR)\ipv6.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + + +SOURCE=.\keyboard.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\keyboard.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\keyboard.obj" "$(INTDIR)\keyboard.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + +SOURCE=.\net.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\net.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\net.obj" "$(INTDIR)\net.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + +SOURCE=.\ntpaths.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\ntpaths.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\ntpaths.obj" "$(INTDIR)\ntpaths.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + +SOURCE=.\once.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\once.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\once.obj" "$(INTDIR)\once.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + +SOURCE=.\os.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\os.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\os.obj" "$(INTDIR)\os.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + +SOURCE=.\resource.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\resource.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\resource.obj" "$(INTDIR)\resource.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + +SOURCE=.\socket.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\socket.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\socket.obj" "$(INTDIR)\socket.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + +SOURCE=.\stdio.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\stdio.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\stdio.obj" "$(INTDIR)\stdio.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + +SOURCE=.\stdtime.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\stdtime.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\stdtime.obj" "$(INTDIR)\stdtime.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + +SOURCE=.\strerror.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\strerror.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\strerror.obj" "$(INTDIR)\strerror.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + +SOURCE=.\syslog.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\syslog.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\syslog.obj" "$(INTDIR)\syslog.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + +SOURCE=.\thread.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\thread.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\thread.obj" "$(INTDIR)\thread.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + +SOURCE=.\time.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\time.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\time.obj" "$(INTDIR)\time.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + +SOURCE=.\version.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\version.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\version.obj" "$(INTDIR)\version.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + +SOURCE=.\win32os.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\win32os.obj" : $(SOURCE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\win32os.obj" "$(INTDIR)\win32os.sbr" : $(SOURCE) "$(INTDIR)" + + +!ENDIF + +SOURCE=..\assertions.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\assertions.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\assertions.obj" "$(INTDIR)\assertions.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\backtrace.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\backtrace.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\backtrace.obj" "$(INTDIR)\backtrace.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\backtrace-emptytbl.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\backtrace-emptytbl.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\backtrace-emptytbl.obj" "$(INTDIR)\backtrace-emptytbl.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\base32.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\base32.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\base32.obj" "$(INTDIR)\base32.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\base64.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\base64.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\base64.obj" "$(INTDIR)\base64.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\bitstring.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\bitstring.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\bitstring.obj" "$(INTDIR)\bitstring.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\buffer.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\buffer.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\buffer.obj" "$(INTDIR)\buffer.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\bufferlist.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\bufferlist.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\bufferlist.obj" "$(INTDIR)\bufferlist.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\commandline.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\commandline.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\commandline.obj" "$(INTDIR)\commandline.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\error.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\error.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\error.obj" "$(INTDIR)\error.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\event.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\event.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\event.obj" "$(INTDIR)\event.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\hash.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\hash.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\hash.obj" "$(INTDIR)\hash.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\heap.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\heap.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\heap.obj" "$(INTDIR)\heap.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\hex.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\hex.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\hex.obj" "$(INTDIR)\hex.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\hmacmd5.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\hmacmd5.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\hmacmd5.obj" "$(INTDIR)\hmacmd5.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\hmacsha.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\hmacsha.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\hmacsha.obj" "$(INTDIR)\hmacsha.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\httpd.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\httpd.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\httpd.obj" "$(INTDIR)\httpd.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\inet_aton.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\inet_aton.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\inet_aton.obj" "$(INTDIR)\inet_aton.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\inet_ntop.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\inet_ntop.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\inet_ntop.obj" "$(INTDIR)\inet_ntop.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\inet_pton.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\inet_pton.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\inet_pton.obj" "$(INTDIR)\inet_pton.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\iterated_hash.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\iterated_hash.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\iterated_hash.obj" "$(INTDIR)\iterated_hash.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\lex.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\lex.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\lex.obj" "$(INTDIR)\lex.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\lfsr.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\lfsr.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\lfsr.obj" "$(INTDIR)\lfsr.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\lib.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\lib.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\lib.obj" "$(INTDIR)\lib.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\log.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\log.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\log.obj" "$(INTDIR)\log.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\md5.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\md5.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\md5.obj" "$(INTDIR)\md5.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\mem.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\mem.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\mem.obj" "$(INTDIR)\mem.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\nls\msgcat.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\msgcat.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\msgcat.obj" "$(INTDIR)\msgcat.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\mutexblock.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\mutexblock.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\mutexblock.obj" "$(INTDIR)\mutexblock.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\netaddr.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\netaddr.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\netaddr.obj" "$(INTDIR)\netaddr.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\netscope.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\netscope.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\netscope.obj" "$(INTDIR)\netscope.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\ondestroy.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\ondestroy.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\ondestroy.obj" "$(INTDIR)\ondestroy.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\parseint.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\parseint.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\parseint.obj" "$(INTDIR)\parseint.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\portset.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\portset.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\portset.obj" "$(INTDIR)\portset.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\quota.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\quota.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\quota.obj" "$(INTDIR)\quota.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\radix.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\radix.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\radix.obj" "$(INTDIR)\radix.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\random.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\random.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\random.obj" "$(INTDIR)\random.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\ratelimiter.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\ratelimiter.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\ratelimiter.obj" "$(INTDIR)\ratelimiter.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\refcount.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\refcount.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\refcount.obj" "$(INTDIR)\refcount.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\region.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\region.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\region.obj" "$(INTDIR)\region.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\result.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\result.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\result.obj" "$(INTDIR)\result.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\rwlock.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\rwlock.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\rwlock.obj" "$(INTDIR)\rwlock.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\serial.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\serial.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\serial.obj" "$(INTDIR)\serial.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\sha1.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\sha1.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\sha1.obj" "$(INTDIR)\sha1.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\sha2.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\sha2.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\sha2.obj" "$(INTDIR)\sha2.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\sockaddr.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\sockaddr.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\sockaddr.obj" "$(INTDIR)\sockaddr.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\stats.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\stats.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\stats.obj" "$(INTDIR)\stats.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\string.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\string.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\string.obj" "$(INTDIR)\string.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\symtab.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\symtab.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\symtab.obj" "$(INTDIR)\symtab.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\task.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\task.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\task.obj" "$(INTDIR)\task.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\taskpool.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\taskpool.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\taskpool.obj" "$(INTDIR)\taskpool.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +SOURCE=..\timer.c + +!IF "$(CFG)" == "libisc - Win32 Release" + + +"$(INTDIR)\timer.obj" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "libisc - Win32 Debug" + + +"$(INTDIR)\timer.obj" "$(INTDIR)\timer.sbr" : $(SOURCE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + + +!ENDIF + +#################################################### +# Commands to generate initial empty manifest file and the RC file +# that references it, and for generating the .res file: + +$(_VC_MANIFEST_BASENAME).auto.res : $(_VC_MANIFEST_BASENAME).auto.rc + +$(_VC_MANIFEST_BASENAME).auto.rc : $(_VC_MANIFEST_BASENAME).auto.manifest + type <<$@ +#include <winuser.h> +1RT_MANIFEST"$(_VC_MANIFEST_BASENAME).auto.manifest" +<< KEEP + +$(_VC_MANIFEST_BASENAME).auto.manifest : + type <<$@ +<?xml version='1.0' encoding='UTF-8' standalone='yes'?> +<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'> +</assembly> +<< KEEP diff --git a/contrib/ntp/lib/isc/win32/net.c b/contrib/ntp/lib/isc/win32/net.c new file mode 100644 index 0000000..12876da --- /dev/null +++ b/contrib/ntp/lib/isc/win32/net.c @@ -0,0 +1,338 @@ +/* + * Copyright (C) 2004, 2005, 2007-2009, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +#include <config.h> + +#include <errno.h> +#include <unistd.h> + +#include <isc/log.h> +#include <isc/msgs.h> +#include <isc/net.h> +#include <isc/once.h> +#include <isc/strerror.h> +#include <isc/string.h> +#include <isc/util.h> + +/*% + * Definitions about UDP port range specification. This is a total mess of + * portability variants: some use sysctl (but the sysctl names vary), some use + * system-specific interfaces, some have the same interface for IPv4 and IPv6, + * some separate them, etc... + */ + +/*% + * The last resort defaults: use all non well known port space + */ +#ifndef ISC_NET_PORTRANGELOW +#define ISC_NET_PORTRANGELOW 1024 +#endif /* ISC_NET_PORTRANGELOW */ +#ifndef ISC_NET_PORTRANGEHIGH +#define ISC_NET_PORTRANGEHIGH 65535 +#endif /* ISC_NET_PORTRANGEHIGH */ + +#if defined(ISC_PLATFORM_NEEDIN6ADDRANY) +const struct in6_addr isc_net_in6addrany = IN6ADDR_ANY_INIT; +#endif + +#if defined(ISC_PLATFORM_NEEDIN6ADDRLOOPBACK) +const struct in6_addr isc_net_in6addrloop = IN6ADDR_LOOPBACK_INIT; +#endif + + +static isc_once_t once = ISC_ONCE_INIT; +static isc_once_t once_ipv6only = ISC_ONCE_INIT; +static isc_once_t once_ipv6pktinfo = ISC_ONCE_INIT; +static isc_result_t ipv4_result = ISC_R_NOTFOUND; +static isc_result_t ipv6_result = ISC_R_NOTFOUND; +static isc_result_t ipv6only_result = ISC_R_NOTFOUND; +static isc_result_t ipv6pktinfo_result = ISC_R_NOTFOUND; + +void InitSockets(void); + +static isc_result_t +try_proto(int domain) { + SOCKET s; + char strbuf[ISC_STRERRORSIZE]; + int errval; + + s = socket(domain, SOCK_STREAM, IPPROTO_TCP); + if (s == INVALID_SOCKET) { + errval = WSAGetLastError(); + switch (errval) { + case WSAEAFNOSUPPORT: + case WSAEPROTONOSUPPORT: + case WSAEINVAL: + return (ISC_R_NOTFOUND); + default: + isc__strerror(errval, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "socket() %s: %s", + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, + "failed"), + strbuf); + return (ISC_R_UNEXPECTED); + } + } + + closesocket(s); + + return (ISC_R_SUCCESS); +} + +static void +initialize_action(void) { + InitSockets(); + ipv4_result = try_proto(PF_INET); +#ifdef ISC_PLATFORM_HAVEIPV6 +#ifdef WANT_IPV6 +#ifdef ISC_PLATFORM_HAVEIN6PKTINFO + ipv6_result = try_proto(PF_INET6); +#endif +#endif +#endif +} + +static void +initialize(void) { + RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); +} + +isc_result_t +isc_net_probeipv4(void) { + initialize(); + return (ipv4_result); +} + +isc_result_t +isc_net_probeipv6(void) { + initialize(); + return (ipv6_result); +} + +isc_result_t +isc_net_probeunix(void) { + return (ISC_R_NOTFOUND); +} + +#ifdef ISC_PLATFORM_HAVEIPV6 +#ifdef WANT_IPV6 +static void +try_ipv6only(void) { +#ifdef IPV6_V6ONLY + SOCKET s; + int on; + char strbuf[ISC_STRERRORSIZE]; +#endif + isc_result_t result; + + result = isc_net_probeipv6(); + if (result != ISC_R_SUCCESS) { + ipv6only_result = result; + return; + } + +#ifndef IPV6_V6ONLY + ipv6only_result = ISC_R_NOTFOUND; + return; +#else + /* check for TCP sockets */ + s = socket(PF_INET6, SOCK_STREAM, 0); + if (s == INVALID_SOCKET) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "socket() %s: %s", + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, + "failed"), + strbuf); + ipv6only_result = ISC_R_UNEXPECTED; + return; + } + + on = 1; + if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&on, + sizeof(on)) < 0) { + ipv6only_result = ISC_R_NOTFOUND; + goto close; + } + + closesocket(s); + + /* check for UDP sockets */ + s = socket(PF_INET6, SOCK_DGRAM, 0); + if (s == INVALID_SOCKET) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "socket() %s: %s", + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, + "failed"), + strbuf); + ipv6only_result = ISC_R_UNEXPECTED; + return; + } + + on = 1; + if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&on, + sizeof(on)) < 0) { + ipv6only_result = ISC_R_NOTFOUND; + goto close; + } + + ipv6only_result = ISC_R_SUCCESS; + +close: + closesocket(s); + return; +#endif /* IPV6_V6ONLY */ +} + +static void +initialize_ipv6only(void) { + RUNTIME_CHECK(isc_once_do(&once_ipv6only, + try_ipv6only) == ISC_R_SUCCESS); +} + +static void +try_ipv6pktinfo(void) { + int s, on; + char strbuf[ISC_STRERRORSIZE]; + isc_result_t result; + int optname; + + result = isc_net_probeipv6(); + if (result != ISC_R_SUCCESS) { + ipv6pktinfo_result = result; + return; + } + + /* we only use this for UDP sockets */ + s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (s == INVALID_SOCKET) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "socket() %s: %s", + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, + "failed"), + strbuf); + ipv6pktinfo_result = ISC_R_UNEXPECTED; + return; + } + +#ifdef IPV6_RECVPKTINFO + optname = IPV6_RECVPKTINFO; +#else + optname = IPV6_PKTINFO; +#endif + on = 1; + if (setsockopt(s, IPPROTO_IPV6, optname, (const char *) &on, + sizeof(on)) < 0) { + ipv6pktinfo_result = ISC_R_NOTFOUND; + goto close; + } + + ipv6pktinfo_result = ISC_R_SUCCESS; + +close: + closesocket(s); + return; +} + +static void +initialize_ipv6pktinfo(void) { + RUNTIME_CHECK(isc_once_do(&once_ipv6pktinfo, + try_ipv6pktinfo) == ISC_R_SUCCESS); +} +#endif /* WANT_IPV6 */ +#endif /* ISC_PLATFORM_HAVEIPV6 */ + +isc_result_t +isc_net_probe_ipv6only(void) { +#ifdef ISC_PLATFORM_HAVEIPV6 +#ifdef WANT_IPV6 + initialize_ipv6only(); +#else + ipv6only_result = ISC_R_NOTFOUND; +#endif +#endif + return (ipv6only_result); +} + +isc_result_t +isc_net_probe_ipv6pktinfo(void) { +#ifdef ISC_PLATFORM_HAVEIPV6 +#ifdef WANT_IPV6 + initialize_ipv6pktinfo(); +#else + ipv6pktinfo_result = ISC_R_NOTFOUND; +#endif +#endif + return (ipv6pktinfo_result); +} + +isc_result_t +isc_net_getudpportrange(int af, in_port_t *low, in_port_t *high) { + int result = ISC_R_FAILURE; + + REQUIRE(low != NULL && high != NULL); + + UNUSED(af); + + if (result != ISC_R_SUCCESS) { + *low = ISC_NET_PORTRANGELOW; + *high = ISC_NET_PORTRANGEHIGH; + } + + return (ISC_R_SUCCESS); /* we currently never fail in this function */ +} + +void +isc_net_disableipv4(void) { + initialize(); + if (ipv4_result == ISC_R_SUCCESS) + ipv4_result = ISC_R_DISABLED; +} + +void +isc_net_disableipv6(void) { + initialize(); + if (ipv6_result == ISC_R_SUCCESS) + ipv6_result = ISC_R_DISABLED; +} + +void +isc_net_enableipv4(void) { + initialize(); + if (ipv4_result == ISC_R_DISABLED) + ipv4_result = ISC_R_SUCCESS; +} + +void +isc_net_enableipv6(void) { + initialize(); + if (ipv6_result == ISC_R_DISABLED) + ipv6_result = ISC_R_SUCCESS; +} diff --git a/contrib/ntp/lib/isc/win32/netdb.h b/contrib/ntp/lib/isc/win32/netdb.h new file mode 100644 index 0000000..f8d936a --- /dev/null +++ b/contrib/ntp/lib/isc/win32/netdb.h @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2004, 2006, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: netdb.h,v 1.9 2009/01/18 23:48:14 tbox Exp $ */ + +#ifndef NETDB_H +#define NETDB_H 1 + +#include <stddef.h> +#include <winsock2.h> + +/* + * Define if <netdb.h> does not declare struct addrinfo. + */ + +struct addrinfo { + int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ + int ai_family; /* PF_xxx */ + int ai_socktype; /* SOCK_xxx */ + int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ + size_t ai_addrlen; /* Length of ai_addr */ + char *ai_canonname; /* Canonical name for hostname */ + struct sockaddr *ai_addr; /* Binary address */ + struct addrinfo *ai_next; /* Next structure in linked list */ +}; + + +/* + * Undefine all \#defines we are interested in as <netdb.h> may or may not have + * defined them. + */ + +/* + * Error return codes from gethostbyname() and gethostbyaddr() + * (left in extern int h_errno). + */ + +#undef NETDB_INTERNAL +#undef NETDB_SUCCESS +#undef HOST_NOT_FOUND +#undef TRY_AGAIN +#undef NO_RECOVERY +#undef NO_DATA +#undef NO_ADDRESS + +#define NETDB_INTERNAL -1 /* see errno */ +#define NETDB_SUCCESS 0 /* no problem */ +#define HOST_NOT_FOUND 1 /* Authoritative Answer Host not found */ +#define TRY_AGAIN 2 /* Non-Authoritative Host not found, or SERVERFAIL */ +#define NO_RECOVERY 3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */ +#define NO_DATA 4 /* Valid name, no data record of requested type */ +#define NO_ADDRESS NO_DATA /* no address, look for MX record */ + +/* + * Error return codes from getaddrinfo() + */ + +#undef EAI_ADDRFAMILY +#undef EAI_AGAIN +#undef EAI_BADFLAGS +#undef EAI_FAIL +#undef EAI_FAMILY +#undef EAI_MEMORY +#undef EAI_NODATA +#undef EAI_NONAME +#undef EAI_SERVICE +#undef EAI_SOCKTYPE +#undef EAI_SYSTEM +#undef EAI_BADHINTS +#undef EAI_PROTOCOL +#undef EAI_MAX + +#define EAI_ADDRFAMILY 1 /* address family for hostname not supported */ +#define EAI_AGAIN 2 /* temporary failure in name resolution */ +#define EAI_BADFLAGS 3 /* invalid value for ai_flags */ +#define EAI_FAIL 4 /* non-recoverable failure in name resolution */ +#define EAI_FAMILY 5 /* ai_family not supported */ +#define EAI_MEMORY 6 /* memory allocation failure */ +#define EAI_NODATA 7 /* no address associated with hostname */ +#define EAI_NONAME 8 /* hostname nor servname provided, or not known */ +#define EAI_SERVICE 9 /* servname not supported for ai_socktype */ +#define EAI_SOCKTYPE 10 /* ai_socktype not supported */ +#define EAI_SYSTEM 11 /* system error returned in errno */ +#define EAI_BADHINTS 12 +#define EAI_PROTOCOL 13 +#define EAI_MAX 14 + +/* + * Flag values for getaddrinfo() + */ +#undef AI_PASSIVE +#undef AI_CANONNAME +#undef AI_NUMERICHOST + +#define AI_PASSIVE 0x00000001 +#define AI_CANONNAME 0x00000002 +#define AI_NUMERICHOST 0x00000004 + +/* + * Flag values for getipnodebyname() + */ +#undef AI_V4MAPPED +#undef AI_ALL +#undef AI_ADDRCONFIG +#undef AI_DEFAULT + +#define AI_V4MAPPED 0x00000008 +#define AI_ALL 0x00000010 +#define AI_ADDRCONFIG 0x00000020 +#define AI_DEFAULT (AI_V4MAPPED|AI_ADDRCONFIG) + +/* + * Constants for getnameinfo() + */ +#undef NI_MAXHOST +#undef NI_MAXSERV + +#define NI_MAXHOST 1025 +#define NI_MAXSERV 32 + +/* + * Flag values for getnameinfo() + */ +#undef NI_NOFQDN +#undef NI_NUMERICHOST +#undef NI_NAMEREQD +#undef NI_NUMERICSERV +#undef NI_DGRAM +#undef NI_NUMERICSCOPE + +#define NI_NOFQDN 0x00000001 +#define NI_NUMERICHOST 0x00000002 +#define NI_NAMEREQD 0x00000004 +#define NI_NUMERICSERV 0x00000008 +#define NI_DGRAM 0x00000010 +#define NI_NUMERICSCOPE 0x00000020 /*2553bis-00*/ + +/* + * Structures for getrrsetbyname() + */ +struct rdatainfo { + unsigned int rdi_length; + unsigned char *rdi_data; +}; + +struct rrsetinfo { + unsigned int rri_flags; + int rri_rdclass; + int rri_rdtype; + unsigned int rri_ttl; + unsigned int rri_nrdatas; + unsigned int rri_nsigs; + char *rri_name; + struct rdatainfo *rri_rdatas; + struct rdatainfo *rri_sigs; +}; + +/* + * Flags for getrrsetbyname() + */ +#define RRSET_VALIDATED 0x00000001 + /* Set was dnssec validated */ + +/* + * Return codes for getrrsetbyname() + */ +#define ERRSET_SUCCESS 0 +#define ERRSET_NOMEMORY 1 +#define ERRSET_FAIL 2 +#define ERRSET_INVAL 3 + + +#endif /* NETDB_H */ diff --git a/contrib/ntp/lib/isc/win32/ntgroups.c b/contrib/ntp/lib/isc/win32/ntgroups.c new file mode 100644 index 0000000..729cf07 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/ntgroups.c @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2004, 2006, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: ntgroups.c,v 1.12 2009/09/29 23:48:04 tbox Exp $ */ + +/* + * The NT Groups have two groups that are not well documented and are + * not normally seen: None and Everyone. A user account belongs to + * any number of groups, but if it is not a member of any group then + * it is a member of the None Group. The None group is not listed + * anywhere. You cannot remove an account from the none group except + * by making it a member of some other group, The second group is the + * Everyone group. All accounts, no matter how many groups that they + * belong to, also belong to the Everyone group. You cannot remove an + * account from the Everyone group. + */ + +#ifndef UNICODE +#define UNICODE +#endif /* UNICODE */ + +/* + * Silence warnings. + */ +#define _CRT_SECURE_NO_DEPRECATE 1 + +#include <windows.h> +#include <assert.h> +#include <lm.h> + +#include <isc/ntgroups.h> +#include <isc/result.h> + +#define MAX_NAME_LENGTH 256 + +isc_result_t +isc_ntsecurity_getaccountgroups(char *username, char **GroupList, + unsigned int maxgroups, + unsigned int *totalGroups) { + LPGROUP_USERS_INFO_0 pTmpBuf; + LPLOCALGROUP_USERS_INFO_0 pTmpLBuf; + DWORD i; + LPLOCALGROUP_USERS_INFO_0 pBuf = NULL; + LPGROUP_USERS_INFO_0 pgrpBuf = NULL; + DWORD dwLevel = 0; + DWORD dwFlags = LG_INCLUDE_INDIRECT; + DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH; + DWORD dwEntriesRead = 0; + DWORD dwTotalEntries = 0; + NET_API_STATUS nStatus; + DWORD dwTotalCount = 0; + size_t retlen; + wchar_t user[MAX_NAME_LENGTH]; + + retlen = mbstowcs(user, username, MAX_NAME_LENGTH); + + *totalGroups = 0; + /* + * Call the NetUserGetLocalGroups function + * specifying information level 0. + * + * The LG_INCLUDE_INDIRECT flag specifies that the + * function should also return the names of the local + * groups in which the user is indirectly a member. + */ + nStatus = NetUserGetLocalGroups(NULL, + user, + dwLevel, + dwFlags, + (LPBYTE *) &pBuf, + dwPrefMaxLen, + &dwEntriesRead, + &dwTotalEntries); + /* + * See if the call succeeds, + */ + if (nStatus != NERR_Success) { + if (nStatus == ERROR_ACCESS_DENIED) + return (ISC_R_NOPERM); + if (nStatus == ERROR_MORE_DATA) + return (ISC_R_NOSPACE); + if (nStatus == NERR_UserNotFound) + dwEntriesRead = 0; + } + + dwTotalCount = 0; + if (pBuf != NULL) { + pTmpLBuf = pBuf; + /* + * Loop through the entries + */ + for (i = 0; + (i < dwEntriesRead && *totalGroups < maxgroups); i++) { + assert(pTmpLBuf != NULL); + if (pTmpLBuf == NULL) + break; + retlen = wcslen(pTmpLBuf->lgrui0_name); + GroupList[*totalGroups] = (char *) malloc(retlen +1); + if (GroupList[*totalGroups] == NULL) + return (ISC_R_NOMEMORY); + + retlen = wcstombs(GroupList[*totalGroups], + pTmpLBuf->lgrui0_name, retlen); + GroupList[*totalGroups][retlen] = '\0'; + if (strcmp(GroupList[*totalGroups], "None") == 0) + free(GroupList[*totalGroups]); + else + (*totalGroups)++; + pTmpLBuf++; + } + } + /* Free the allocated memory. */ + if (pBuf != NULL) + NetApiBufferFree(pBuf); + + + /* + * Call the NetUserGetGroups function, specifying level 0. + */ + nStatus = NetUserGetGroups(NULL, + user, + dwLevel, + (LPBYTE*)&pgrpBuf, + dwPrefMaxLen, + &dwEntriesRead, + &dwTotalEntries); + /* + * See if the call succeeds, + */ + if (nStatus != NERR_Success) { + if (nStatus == ERROR_ACCESS_DENIED) + return (ISC_R_NOPERM); + if (nStatus == ERROR_MORE_DATA) + return (ISC_R_NOSPACE); + if (nStatus == NERR_UserNotFound) + dwEntriesRead = 0; + } + + if (pgrpBuf != NULL) { + pTmpBuf = pgrpBuf; + /* + * Loop through the entries + */ + for (i = 0; + (i < dwEntriesRead && *totalGroups < maxgroups); i++) { + assert(pTmpBuf != NULL); + + if (pTmpBuf == NULL) + break; + retlen = wcslen(pTmpBuf->grui0_name); + GroupList[*totalGroups] = (char *) malloc(retlen +1); + if (GroupList[*totalGroups] == NULL) + return (ISC_R_NOMEMORY); + + retlen = wcstombs(GroupList[*totalGroups], + pTmpBuf->grui0_name, retlen); + GroupList[*totalGroups][retlen] = '\0'; + if (strcmp(GroupList[*totalGroups], "None") == 0) + free(GroupList[*totalGroups]); + else + (*totalGroups)++; + pTmpBuf++; + } + } + /* + * Free the allocated memory. + */ + if (pgrpBuf != NULL) + NetApiBufferFree(pgrpBuf); + + return (ISC_R_SUCCESS); +} diff --git a/contrib/ntp/lib/isc/win32/ntpaths.c b/contrib/ntp/lib/isc/win32/ntpaths.c new file mode 100644 index 0000000..1ff8c5a --- /dev/null +++ b/contrib/ntp/lib/isc/win32/ntpaths.c @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2004, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: ntpaths.c,v 1.15 2009/07/14 22:54:57 each Exp $ */ + +/* + * This module fetches the required path information that is specific + * to NT systems which can have its configuration and system files + * almost anywhere. It can be used to override whatever the application + * had previously assigned to the pointer. Basic information about the + * file locations are stored in the registry. + */ + +#include <config.h> +#include <isc/bind_registry.h> +#include <isc/ntpaths.h> + +/* + * Module Variables + */ + +static char systemDir[MAX_PATH]; +static char namedBase[MAX_PATH]; +static char ns_confFile[MAX_PATH]; +static char lwresd_confFile[MAX_PATH]; +static char lwresd_resolvconfFile[MAX_PATH]; +static char rndc_confFile[MAX_PATH]; +static char ns_defaultpidfile[MAX_PATH]; +static char lwresd_defaultpidfile[MAX_PATH]; +static char local_state_dir[MAX_PATH]; +static char sys_conf_dir[MAX_PATH]; +static char rndc_keyFile[MAX_PATH]; +static char session_keyFile[MAX_PATH]; + +static DWORD baseLen = MAX_PATH; +static BOOL Initialized = FALSE; + +void +isc_ntpaths_init() { + HKEY hKey; + BOOL keyFound = TRUE; + + memset(namedBase, 0, MAX_PATH); + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, BIND_SUBKEY, 0, KEY_READ, &hKey) + != ERROR_SUCCESS) + keyFound = FALSE; + + if (keyFound == TRUE) { + /* Get the named directory */ + if (RegQueryValueEx(hKey, "InstallDir", NULL, NULL, + (LPBYTE)namedBase, &baseLen) != ERROR_SUCCESS) + keyFound = FALSE; + RegCloseKey(hKey); + } + + GetSystemDirectory(systemDir, MAX_PATH); + + if (keyFound == FALSE) + /* Use the System Directory as a default */ + strcpy(namedBase, systemDir); + + strcpy(ns_confFile, namedBase); + strcat(ns_confFile, "\\etc\\named.conf"); + + strcpy(lwresd_confFile, namedBase); + strcat(lwresd_confFile, "\\etc\\lwresd.conf"); + + strcpy(lwresd_resolvconfFile, systemDir); + strcat(lwresd_resolvconfFile, "\\Drivers\\etc\\resolv.conf"); + + strcpy(rndc_keyFile, namedBase); + strcat(rndc_keyFile, "\\etc\\rndc.key"); + + strcpy(session_keyFile, namedBase); + strcat(session_keyFile, "\\etc\\session.key"); + + strcpy(rndc_confFile, namedBase); + strcat(rndc_confFile, "\\etc\\rndc.conf"); + strcpy(ns_defaultpidfile, namedBase); + strcat(ns_defaultpidfile, "\\etc\\named.pid"); + + strcpy(lwresd_defaultpidfile, namedBase); + strcat(lwresd_defaultpidfile, "\\etc\\lwresd.pid"); + + strcpy(local_state_dir, namedBase); + strcat(local_state_dir, "\\bin"); + + strcpy(sys_conf_dir, namedBase); + strcat(sys_conf_dir, "\\etc"); + + Initialized = TRUE; +} + +char * +isc_ntpaths_get(int ind) { + if (!Initialized) + isc_ntpaths_init(); + + switch (ind) { + case NAMED_CONF_PATH: + return (ns_confFile); + break; + case LWRES_CONF_PATH: + return (lwresd_confFile); + break; + case RESOLV_CONF_PATH: + return (lwresd_resolvconfFile); + break; + case RNDC_CONF_PATH: + return (rndc_confFile); + break; + case NAMED_PID_PATH: + return (ns_defaultpidfile); + break; + case LWRESD_PID_PATH: + return (lwresd_defaultpidfile); + break; + case LOCAL_STATE_DIR: + return (local_state_dir); + break; + case SYS_CONF_DIR: + return (sys_conf_dir); + break; + case RNDC_KEY_PATH: + return (rndc_keyFile); + break; + case SESSION_KEY_PATH: + return (session_keyFile); + break; + default: + return (NULL); + } +} diff --git a/contrib/ntp/lib/isc/win32/once.c b/contrib/ntp/lib/isc/win32/once.c new file mode 100644 index 0000000..b5047762 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/once.c @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: once.c,v 1.12 2007/06/18 23:47:49 tbox Exp $ */ + +/* Principal Authors: DCL */ + +#include <config.h> + +#include <windows.h> + +#include <isc/once.h> +#include <isc/assertions.h> +#include <isc/util.h> + +isc_result_t +isc_once_do(isc_once_t *controller, void(*function)(void)) { + REQUIRE(controller != NULL && function != NULL); + + if (controller->status == ISC_ONCE_INIT_NEEDED) { + + if (InterlockedDecrement(&controller->counter) == 0) { + if (controller->status == ISC_ONCE_INIT_NEEDED) { + function(); + controller->status = ISC_ONCE_INIT_DONE; + } + } else { + while (controller->status == ISC_ONCE_INIT_NEEDED) { + /* + * Sleep(0) indicates that this thread + * should be suspended to allow other + * waiting threads to execute. + */ + Sleep(0); + } + } + } + + return (ISC_R_SUCCESS); +} diff --git a/contrib/ntp/lib/isc/win32/os.c b/contrib/ntp/lib/isc/win32/os.c new file mode 100644 index 0000000..bbd5f1d --- /dev/null +++ b/contrib/ntp/lib/isc/win32/os.c @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000-2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: os.c,v 1.8 2007/06/19 23:47:19 tbox Exp $ */ + +#include <windows.h> + +#include <isc/os.h> + +static BOOL bInit = FALSE; +static SYSTEM_INFO SystemInfo; + +static void +initialize_action(void) { + if (bInit) + return; + + GetSystemInfo(&SystemInfo); + bInit = TRUE; +} + +unsigned int +isc_os_ncpus(void) { + long ncpus = 1; + initialize_action(); + ncpus = SystemInfo.dwNumberOfProcessors; + if (ncpus <= 0) + ncpus = 1; + + return ((unsigned int)ncpus); +} diff --git a/contrib/ntp/lib/isc/win32/resource.c b/contrib/ntp/lib/isc/win32/resource.c new file mode 100644 index 0000000..e7e7cf4 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/resource.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2004, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: resource.c,v 1.10 2008/07/11 23:47:09 tbox Exp $ */ + +#include <config.h> + +#include <stdio.h> + +#include <isc/platform.h> +#include <isc/resource.h> +#include <isc/result.h> +#include <isc/util.h> + +#include "errno2result.h" + +/* + * Windows limits the maximum number of open files to 2048 + */ + +#define WIN32_MAX_OPEN_FILES 2048 + +isc_result_t +isc_resource_setlimit(isc_resource_t resource, isc_resourcevalue_t value) { + isc_resourcevalue_t rlim_value; + int wresult; + + if (resource != isc_resource_openfiles) + return (ISC_R_NOTIMPLEMENTED); + + + if (value == ISC_RESOURCE_UNLIMITED) + rlim_value = WIN32_MAX_OPEN_FILES; + else + rlim_value = min(value, WIN32_MAX_OPEN_FILES); + + wresult = _setmaxstdio((int) rlim_value); + + if (wresult > 0) + return (ISC_R_SUCCESS); + else + return (isc__errno2result(errno)); +} + +isc_result_t +isc_resource_getlimit(isc_resource_t resource, isc_resourcevalue_t *value) { + + if (resource != isc_resource_openfiles) + return (ISC_R_NOTIMPLEMENTED); + + *value = WIN32_MAX_OPEN_FILES; + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_resource_getcurlimit(isc_resource_t resource, isc_resourcevalue_t *value) { + return (isc_resource_getlimit(resource, value)); +} diff --git a/contrib/ntp/lib/isc/win32/socket.c b/contrib/ntp/lib/isc/win32/socket.c new file mode 100644 index 0000000..ffcefb0 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/socket.c @@ -0,0 +1,3967 @@ +/* + * Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000-2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id$ */ + +/* This code uses functions which are only available on Server 2003 and + * higher, and Windows XP and higher. + * + * This code is by nature multithreaded and takes advantage of various + * features to pass on information through the completion port for + * when I/O is completed. All sends, receives, accepts, and connects are + * completed through the completion port. + * + * The number of Completion Port Worker threads used is the total number + * of CPU's + 1. This increases the likelihood that a Worker Thread is + * available for processing a completed request. + * + * XXXPDM 5 August, 2002 + */ + +#define MAKE_EXTERNAL 1 +#include <config.h> + +#include <sys/types.h> + +#ifndef _WINSOCKAPI_ +#define _WINSOCKAPI_ /* Prevent inclusion of winsock.h in windows.h */ +#endif + +#include <errno.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <io.h> +#include <fcntl.h> +#include <process.h> + +#include <isc/buffer.h> +#include <isc/bufferlist.h> +#include <isc/condition.h> +#include <isc/list.h> +#include <isc/log.h> +#include <isc/mem.h> +#include <isc/msgs.h> +#include <isc/mutex.h> +#include <isc/net.h> +#include <isc/once.h> +#include <isc/os.h> +#include <isc/platform.h> +#include <isc/print.h> +#include <isc/region.h> +#include <isc/socket.h> +#include <isc/stats.h> +#include <isc/strerror.h> +#include <isc/syslog.h> +#include <isc/task.h> +#include <isc/thread.h> +#include <isc/util.h> +#include <isc/win32os.h> + +#include <mswsock.h> + +#include "errno2result.h" + +/* + * How in the world can Microsoft exist with APIs like this? + * We can't actually call this directly, because it turns out + * no library exports this function. Instead, we need to + * issue a runtime call to get the address. + */ +LPFN_CONNECTEX ISCConnectEx; +LPFN_ACCEPTEX ISCAcceptEx; +LPFN_GETACCEPTEXSOCKADDRS ISCGetAcceptExSockaddrs; + +/* + * Run expensive internal consistency checks. + */ +#ifdef ISC_SOCKET_CONSISTENCY_CHECKS +#define CONSISTENT(sock) consistent(sock) +#else +#define CONSISTENT(sock) do {} while (0) +#endif +static void consistent(isc_socket_t *sock); + +/* + * Define this macro to control the behavior of connection + * resets on UDP sockets. See Microsoft KnowledgeBase Article Q263823 + * for details. + * NOTE: This requires that Windows 2000 systems install Service Pack 2 + * or later. + */ +#ifndef SIO_UDP_CONNRESET +#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12) +#endif + +/* + * Some systems define the socket length argument as an int, some as size_t, + * some as socklen_t. This is here so it can be easily changed if needed. + */ +#ifndef ISC_SOCKADDR_LEN_T +#define ISC_SOCKADDR_LEN_T unsigned int +#endif + +/* + * Define what the possible "soft" errors can be. These are non-fatal returns + * of various network related functions, like recv() and so on. + */ +#define SOFT_ERROR(e) ((e) == WSAEINTR || \ + (e) == WSAEWOULDBLOCK || \ + (e) == EWOULDBLOCK || \ + (e) == EINTR || \ + (e) == EAGAIN || \ + (e) == 0) + +/* + * Pending errors are not really errors and should be + * kept separate + */ +#define PENDING_ERROR(e) ((e) == WSA_IO_PENDING || (e) == 0) + +#define DOIO_SUCCESS 0 /* i/o ok, event sent */ +#define DOIO_SOFT 1 /* i/o ok, soft error, no event sent */ +#define DOIO_HARD 2 /* i/o error, event sent */ +#define DOIO_EOF 3 /* EOF, no event sent */ +#define DOIO_PENDING 4 /* status when i/o is in process */ +#define DOIO_NEEDMORE 5 /* IO was processed, but we need more due to minimum */ + +#define DLVL(x) ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(x) + +/* + * DLVL(90) -- Function entry/exit and other tracing. + * DLVL(70) -- Socket "correctness" -- including returning of events, etc. + * DLVL(60) -- Socket data send/receive + * DLVL(50) -- Event tracing, including receiving/sending completion events. + * DLVL(20) -- Socket creation/destruction. + */ +#define TRACE_LEVEL 90 +#define CORRECTNESS_LEVEL 70 +#define IOEVENT_LEVEL 60 +#define EVENT_LEVEL 50 +#define CREATION_LEVEL 20 + +#define TRACE DLVL(TRACE_LEVEL) +#define CORRECTNESS DLVL(CORRECTNESS_LEVEL) +#define IOEVENT DLVL(IOEVENT_LEVEL) +#define EVENT DLVL(EVENT_LEVEL) +#define CREATION DLVL(CREATION_LEVEL) + +typedef isc_event_t intev_t; + +/* + * Socket State + */ +enum { + SOCK_INITIALIZED, /* Socket Initialized */ + SOCK_OPEN, /* Socket opened but nothing yet to do */ + SOCK_DATA, /* Socket sending or receiving data */ + SOCK_LISTEN, /* TCP Socket listening for connects */ + SOCK_ACCEPT, /* TCP socket is waiting to accept */ + SOCK_CONNECT, /* TCP Socket connecting */ + SOCK_CLOSED, /* Socket has been closed */ +}; + +#define SOCKET_MAGIC ISC_MAGIC('I', 'O', 'i', 'o') +#define VALID_SOCKET(t) ISC_MAGIC_VALID(t, SOCKET_MAGIC) + +/* + * IPv6 control information. If the socket is an IPv6 socket we want + * to collect the destination address and interface so the client can + * set them on outgoing packets. + */ +#ifdef ISC_PLATFORM_HAVEIPV6 +#ifndef USE_CMSG +#define USE_CMSG 1 +#endif +#endif + +/* + * We really don't want to try and use these control messages. Win32 + * doesn't have this mechanism before XP. + */ +#undef USE_CMSG + +/* + * Message header for recvmsg and sendmsg calls. + * Used value-result for recvmsg, value only for sendmsg. + */ +struct msghdr { + SOCKADDR_STORAGE to_addr; /* UDP send/recv address */ + int to_addr_len; /* length of the address */ + WSABUF *msg_iov; /* scatter/gather array */ + u_int msg_iovlen; /* # elements in msg_iov */ + void *msg_control; /* ancillary data, see below */ + u_int msg_controllen; /* ancillary data buffer len */ + int msg_totallen; /* total length of this message */ +} msghdr; + +/* + * The size to raise the receive buffer to. + */ +#define RCVBUFSIZE (32*1024) + +/* + * The number of times a send operation is repeated if the result + * is WSAEINTR. + */ +#define NRETRIES 10 + +struct isc_socket { + /* Not locked. */ + unsigned int magic; + isc_socketmgr_t *manager; + isc_mutex_t lock; + isc_sockettype_t type; + + /* Pointers to scatter/gather buffers */ + WSABUF iov[ISC_SOCKET_MAXSCATTERGATHER]; + + /* Locked by socket lock. */ + ISC_LINK(isc_socket_t) link; + unsigned int references; /* EXTERNAL references */ + SOCKET fd; /* file handle */ + int pf; /* protocol family */ + char name[16]; + void * tag; + + /* + * Each recv() call uses this buffer. It is a per-socket receive + * buffer that allows us to decouple the system recv() from the + * recv_list done events. This means the items on the recv_list + * can be removed without having to cancel pending system recv() + * calls. It also allows us to read-ahead in some cases. + */ + struct { + SOCKADDR_STORAGE from_addr; // UDP send/recv address + int from_addr_len; // length of the address + char *base; // the base of the buffer + char *consume_position; // where to start copying data from next + unsigned int len; // the actual size of this buffer + unsigned int remaining; // the number of bytes remaining + } recvbuf; + + ISC_LIST(isc_socketevent_t) send_list; + ISC_LIST(isc_socketevent_t) recv_list; + ISC_LIST(isc_socket_newconnev_t) accept_list; + isc_socket_connev_t *connect_ev; + + isc_sockaddr_t address; /* remote address */ + + unsigned int listener : 1, /* listener socket */ + connected : 1, + pending_connect : 1, /* connect pending */ + bound : 1, /* bound to local addr */ + dupped : 1; /* created by isc_socket_dup() */ + unsigned int pending_iocp; /* Should equal the counters below. Debug. */ + unsigned int pending_recv; /* Number of outstanding recv() calls. */ + unsigned int pending_send; /* Number of outstanding send() calls. */ + unsigned int pending_accept; /* Number of outstanding accept() calls. */ + unsigned int state; /* Socket state. Debugging and consistency checking. */ + int state_lineno; /* line which last touched state */ +}; + +#define _set_state(sock, _state) do { (sock)->state = (_state); (sock)->state_lineno = __LINE__; } while (0) + +/* + * Buffer structure + */ +typedef struct buflist buflist_t; + +struct buflist { + void *buf; + unsigned int buflen; + ISC_LINK(buflist_t) link; +}; + +/* + * I/O Completion ports Info structures + */ + +static HANDLE hHeapHandle = NULL; +typedef struct IoCompletionInfo { + OVERLAPPED overlapped; + isc_socketevent_t *dev; /* send()/recv() done event */ + isc_socket_connev_t *cdev; /* connect() done event */ + isc_socket_newconnev_t *adev; /* accept() done event */ + void *acceptbuffer; + DWORD received_bytes; + int request_type; + struct msghdr messagehdr; + ISC_LIST(buflist_t) bufferlist; /*%< list of buffers */ +} IoCompletionInfo; + +/* + * Define a maximum number of I/O Completion Port worker threads + * to handle the load on the Completion Port. The actual number + * used is the number of CPU's + 1. + */ +#define MAX_IOCPTHREADS 20 + +#define SOCKET_MANAGER_MAGIC ISC_MAGIC('I', 'O', 'm', 'g') +#define VALID_MANAGER(m) ISC_MAGIC_VALID(m, SOCKET_MANAGER_MAGIC) + +struct isc_socketmgr { + /* Not locked. */ + unsigned int magic; + isc_mem_t *mctx; + isc_mutex_t lock; + isc_stats_t *stats; + + /* Locked by manager lock. */ + ISC_LIST(isc_socket_t) socklist; + isc_boolean_t bShutdown; + isc_condition_t shutdown_ok; + HANDLE hIoCompletionPort; + int maxIOCPThreads; + HANDLE hIOCPThreads[MAX_IOCPTHREADS]; + DWORD dwIOCPThreadIds[MAX_IOCPTHREADS]; + + /* + * Debugging. + * Modified by InterlockedIncrement() and InterlockedDecrement() + */ + LONG totalSockets; + LONG iocp_total; +}; + +enum { + SOCKET_RECV, + SOCKET_SEND, + SOCKET_ACCEPT, + SOCKET_CONNECT +}; + +/* + * send() and recv() iovec counts + */ +#define MAXSCATTERGATHER_SEND (ISC_SOCKET_MAXSCATTERGATHER) +#define MAXSCATTERGATHER_RECV (ISC_SOCKET_MAXSCATTERGATHER) + +static isc_result_t socket_create(isc_socketmgr_t *manager0, int pf, + isc_sockettype_t type, + isc_socket_t **socketp, + isc_socket_t *dup_socket); +static isc_threadresult_t WINAPI SocketIoThread(LPVOID ThreadContext); +static void maybe_free_socket(isc_socket_t **, int); +static void free_socket(isc_socket_t **, int); +static isc_boolean_t senddone_is_active(isc_socket_t *sock, isc_socketevent_t *dev); +static isc_boolean_t acceptdone_is_active(isc_socket_t *sock, isc_socket_newconnev_t *dev); +static isc_boolean_t connectdone_is_active(isc_socket_t *sock, isc_socket_connev_t *dev); +static void send_recvdone_event(isc_socket_t *sock, isc_socketevent_t **dev); +static void send_senddone_event(isc_socket_t *sock, isc_socketevent_t **dev); +static void send_acceptdone_event(isc_socket_t *sock, isc_socket_newconnev_t **adev); +static void send_connectdone_event(isc_socket_t *sock, isc_socket_connev_t **cdev); +static void send_recvdone_abort(isc_socket_t *sock, isc_result_t result); +static void queue_receive_event(isc_socket_t *sock, isc_task_t *task, isc_socketevent_t *dev); +static void queue_receive_request(isc_socket_t *sock); + +/* + * This is used to dump the contents of the sock structure + * You should make sure that the sock is locked before + * dumping it. Since the code uses simple printf() statements + * it should only be used interactively. + */ +void +sock_dump(isc_socket_t *sock) { + isc_socketevent_t *ldev; + isc_socket_newconnev_t *ndev; + +#if 0 + isc_sockaddr_t addr; + char socktext[256]; + + isc_socket_getpeername(sock, &addr); + isc_sockaddr_format(&addr, socktext, sizeof(socktext)); + printf("Remote Socket: %s\n", socktext); + isc_socket_getsockname(sock, &addr); + isc_sockaddr_format(&addr, socktext, sizeof(socktext)); + printf("This Socket: %s\n", socktext); +#endif + + printf("\n\t\tSock Dump\n"); + printf("\t\tfd: %u\n", sock->fd); + printf("\t\treferences: %d\n", sock->references); + printf("\t\tpending_accept: %d\n", sock->pending_accept); + printf("\t\tconnecting: %d\n", sock->pending_connect); + printf("\t\tconnected: %d\n", sock->connected); + printf("\t\tbound: %d\n", sock->bound); + printf("\t\tpending_iocp: %d\n", sock->pending_iocp); + printf("\t\tsocket type: %d\n", sock->type); + + printf("\n\t\tSock Recv List\n"); + ldev = ISC_LIST_HEAD(sock->recv_list); + while (ldev != NULL) { + printf("\t\tdev: %p\n", ldev); + ldev = ISC_LIST_NEXT(ldev, ev_link); + } + + printf("\n\t\tSock Send List\n"); + ldev = ISC_LIST_HEAD(sock->send_list); + while (ldev != NULL) { + printf("\t\tdev: %p\n", ldev); + ldev = ISC_LIST_NEXT(ldev, ev_link); + } + + printf("\n\t\tSock Accept List\n"); + ndev = ISC_LIST_HEAD(sock->accept_list); + while (ndev != NULL) { + printf("\t\tdev: %p\n", ldev); + ndev = ISC_LIST_NEXT(ndev, ev_link); + } +} + +static void +socket_log(int lineno, isc_socket_t *sock, isc_sockaddr_t *address, + isc_logcategory_t *category, isc_logmodule_t *module, int level, + isc_msgcat_t *msgcat, int msgset, int message, + const char *fmt, ...) ISC_FORMAT_PRINTF(9, 10); + +/* This function will add an entry to the I/O completion port + * that will signal the I/O thread to exit (gracefully) + */ +static void +signal_iocompletionport_exit(isc_socketmgr_t *manager) { + int i; + int errval; + char strbuf[ISC_STRERRORSIZE]; + + REQUIRE(VALID_MANAGER(manager)); + for (i = 0; i < manager->maxIOCPThreads; i++) { + if (!PostQueuedCompletionStatus(manager->hIoCompletionPort, + 0, 0, 0)) { + errval = GetLastError(); + isc__strerror(errval, strbuf, sizeof(strbuf)); + FATAL_ERROR(__FILE__, __LINE__, + isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_FAILED, + "Can't request service thread to exit: %s"), + strbuf); + } + } +} + +/* + * Create the worker threads for the I/O Completion Port + */ +void +iocompletionport_createthreads(int total_threads, isc_socketmgr_t *manager) { + int errval; + char strbuf[ISC_STRERRORSIZE]; + int i; + + INSIST(total_threads > 0); + REQUIRE(VALID_MANAGER(manager)); + /* + * We need at least one + */ + for (i = 0; i < total_threads; i++) { + manager->hIOCPThreads[i] = CreateThread(NULL, 0, SocketIoThread, + manager, 0, + &manager->dwIOCPThreadIds[i]); + if (manager->hIOCPThreads[i] == NULL) { + errval = GetLastError(); + isc__strerror(errval, strbuf, sizeof(strbuf)); + FATAL_ERROR(__FILE__, __LINE__, + isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_FAILED, + "Can't create IOCP thread: %s"), + strbuf); + exit(1); + } + } +} + +/* + * Create/initialise the I/O completion port + */ +void +iocompletionport_init(isc_socketmgr_t *manager) { + int errval; + char strbuf[ISC_STRERRORSIZE]; + + REQUIRE(VALID_MANAGER(manager)); + /* + * Create a private heap to handle the socket overlapped structure + * The minimum number of structures is 10, there is no maximum + */ + hHeapHandle = HeapCreate(0, 10 * sizeof(IoCompletionInfo), 0); + if (hHeapHandle == NULL) { + errval = GetLastError(); + isc__strerror(errval, strbuf, sizeof(strbuf)); + FATAL_ERROR(__FILE__, __LINE__, + isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_FAILED, + "HeapCreate() failed during " + "initialization: %s"), + strbuf); + exit(1); + } + + manager->maxIOCPThreads = min(isc_os_ncpus() + 1, MAX_IOCPTHREADS); + + /* Now Create the Completion Port */ + manager->hIoCompletionPort = CreateIoCompletionPort( + INVALID_HANDLE_VALUE, NULL, + 0, manager->maxIOCPThreads); + if (manager->hIoCompletionPort == NULL) { + errval = GetLastError(); + isc__strerror(errval, strbuf, sizeof(strbuf)); + FATAL_ERROR(__FILE__, __LINE__, + isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_FAILED, + "CreateIoCompletionPort() failed " + "during initialization: %s"), + strbuf); + exit(1); + } + + /* + * Worker threads for servicing the I/O + */ + iocompletionport_createthreads(manager->maxIOCPThreads, manager); +} + +/* + * Associate a socket with an IO Completion Port. This allows us to queue events for it + * and have our worker pool of threads process them. + */ +void +iocompletionport_update(isc_socket_t *sock) { + HANDLE hiocp; + char strbuf[ISC_STRERRORSIZE]; + + REQUIRE(VALID_SOCKET(sock)); + + hiocp = CreateIoCompletionPort((HANDLE)sock->fd, + sock->manager->hIoCompletionPort, (ULONG_PTR)sock, 0); + + if (hiocp == NULL) { + DWORD errval = GetLastError(); + isc__strerror(errval, strbuf, sizeof(strbuf)); + isc_log_iwrite(isc_lctx, + ISC_LOGCATEGORY_GENERAL, + ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR, + isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_TOOMANYHANDLES, + "iocompletionport_update: failed to open" + " io completion port: %s", + strbuf); + + /* XXXMLG temporary hack to make failures detected. + * This function should return errors to the caller, not + * exit here. + */ + FATAL_ERROR(__FILE__, __LINE__, + isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_FAILED, + "CreateIoCompletionPort() failed " + "during initialization: %s"), + strbuf); + exit(1); + } + + InterlockedIncrement(&sock->manager->iocp_total); +} + +/* + * Routine to cleanup and then close the socket. + * Only close the socket here if it is NOT associated + * with an event, otherwise the WSAWaitForMultipleEvents + * may fail due to the fact that the Wait should not + * be running while closing an event or a socket. + * The socket is locked before calling this function + */ +void +socket_close(isc_socket_t *sock) { + + REQUIRE(sock != NULL); + + if (sock->fd != INVALID_SOCKET) { + closesocket(sock->fd); + sock->fd = INVALID_SOCKET; + _set_state(sock, SOCK_CLOSED); + InterlockedDecrement(&sock->manager->totalSockets); + } +} + +static isc_once_t initialise_once = ISC_ONCE_INIT; +static isc_boolean_t initialised = ISC_FALSE; + +static void +initialise(void) { + WORD wVersionRequested; + WSADATA wsaData; + int err; + SOCKET sock; + GUID GUIDConnectEx = WSAID_CONNECTEX; + GUID GUIDAcceptEx = WSAID_ACCEPTEX; + GUID GUIDGetAcceptExSockaddrs = WSAID_GETACCEPTEXSOCKADDRS; + DWORD dwBytes; + + /* Need Winsock 2.2 or better */ + wVersionRequested = MAKEWORD(2, 2); + + err = WSAStartup(wVersionRequested, &wsaData); + if (err != 0) { + char strbuf[ISC_STRERRORSIZE]; + isc__strerror(err, strbuf, sizeof(strbuf)); + FATAL_ERROR(__FILE__, __LINE__, "WSAStartup() %s: %s", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed"), + strbuf); + exit(1); + } + /* + * The following APIs do not exist as functions in a library, but we must + * ask winsock for them. They are "extensions" -- but why they cannot be + * actual functions is beyond me. So, ask winsock for the pointers to the + * functions we need. + */ + sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + INSIST(sock != INVALID_SOCKET); + err = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, + &GUIDConnectEx, sizeof(GUIDConnectEx), + &ISCConnectEx, sizeof(ISCConnectEx), + &dwBytes, NULL, NULL); + INSIST(err == 0); + + err = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, + &GUIDAcceptEx, sizeof(GUIDAcceptEx), + &ISCAcceptEx, sizeof(ISCAcceptEx), + &dwBytes, NULL, NULL); + INSIST(err == 0); + + err = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, + &GUIDGetAcceptExSockaddrs, sizeof(GUIDGetAcceptExSockaddrs), + &ISCGetAcceptExSockaddrs, sizeof(ISCGetAcceptExSockaddrs), + &dwBytes, NULL, NULL); + INSIST(err == 0); + + closesocket(sock); + + initialised = ISC_TRUE; +} + +/* + * Initialize socket services + */ +void +InitSockets(void) { + RUNTIME_CHECK(isc_once_do(&initialise_once, + initialise) == ISC_R_SUCCESS); + if (!initialised) + exit(1); +} + +int +internal_sendmsg(isc_socket_t *sock, IoCompletionInfo *lpo, + struct msghdr *messagehdr, int flags, int *Error) +{ + int Result; + DWORD BytesSent; + DWORD Flags = flags; + int total_sent; + + *Error = 0; + Result = WSASendTo(sock->fd, messagehdr->msg_iov, + messagehdr->msg_iovlen, &BytesSent, + Flags, (SOCKADDR *)&messagehdr->to_addr, + messagehdr->to_addr_len, (LPWSAOVERLAPPED)lpo, + NULL); + + total_sent = (int)BytesSent; + + /* Check for errors.*/ + if (Result == SOCKET_ERROR) { + *Error = WSAGetLastError(); + + switch (*Error) { + case WSA_IO_INCOMPLETE: + case WSA_WAIT_IO_COMPLETION: + case WSA_IO_PENDING: + case NO_ERROR: /* Strange, but okay */ + sock->pending_iocp++; + sock->pending_send++; + break; + + default: + return (-1); + break; + } + } else { + sock->pending_iocp++; + sock->pending_send++; + } + + if (lpo != NULL) + return (0); + else + return (total_sent); +} + +static void +queue_receive_request(isc_socket_t *sock) { + DWORD Flags = 0; + DWORD NumBytes = 0; + int total_bytes = 0; + int Result; + int Error; + int need_retry; + WSABUF iov[1]; + IoCompletionInfo *lpo = NULL; + isc_result_t isc_result; + + retry: + need_retry = ISC_FALSE; + + /* + * If we already have a receive pending, do nothing. + */ + if (sock->pending_recv > 0) { + if (lpo != NULL) + HeapFree(hHeapHandle, 0, lpo); + return; + } + + /* + * If no one is waiting, do nothing. + */ + if (ISC_LIST_EMPTY(sock->recv_list)) { + if (lpo != NULL) + HeapFree(hHeapHandle, 0, lpo); + return; + } + + INSIST(sock->recvbuf.remaining == 0); + INSIST(sock->fd != INVALID_SOCKET); + + iov[0].len = sock->recvbuf.len; + iov[0].buf = sock->recvbuf.base; + + if (lpo == NULL) { + lpo = (IoCompletionInfo *)HeapAlloc(hHeapHandle, + HEAP_ZERO_MEMORY, + sizeof(IoCompletionInfo)); + RUNTIME_CHECK(lpo != NULL); + } else + ZeroMemory(lpo, sizeof(IoCompletionInfo)); + lpo->request_type = SOCKET_RECV; + + sock->recvbuf.from_addr_len = sizeof(sock->recvbuf.from_addr); + + Error = 0; + Result = WSARecvFrom((SOCKET)sock->fd, iov, 1, + &NumBytes, &Flags, + (SOCKADDR *)&sock->recvbuf.from_addr, + &sock->recvbuf.from_addr_len, + (LPWSAOVERLAPPED)lpo, NULL); + + /* Check for errors. */ + if (Result == SOCKET_ERROR) { + Error = WSAGetLastError(); + + switch (Error) { + case WSA_IO_PENDING: + sock->pending_iocp++; + sock->pending_recv++; + break; + + /* direct error: no completion event */ + case ERROR_HOST_UNREACHABLE: + case WSAENETRESET: + case WSAECONNRESET: + if (!sock->connected) { + /* soft error */ + need_retry = ISC_TRUE; + break; + } + /* FALLTHROUGH */ + + default: + isc_result = isc__errno2result(Error); + if (isc_result == ISC_R_UNEXPECTED) + UNEXPECTED_ERROR(__FILE__, __LINE__, + "WSARecvFrom: Windows error code: %d, isc result %d", + Error, isc_result); + send_recvdone_abort(sock, isc_result); + HeapFree(hHeapHandle, 0, lpo); + lpo = NULL; + break; + } + } else { + /* + * The recv() finished immediately, but we will still get + * a completion event. Rather than duplicate code, let + * that thread handle sending the data along its way. + */ + sock->pending_iocp++; + sock->pending_recv++; + } + + socket_log(__LINE__, sock, NULL, IOEVENT, + isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_DOIORECV, + "queue_io_request: fd %d result %d error %d", + sock->fd, Result, Error); + + CONSISTENT(sock); + + if (need_retry) + goto retry; +} + +static void +manager_log(isc_socketmgr_t *sockmgr, isc_logcategory_t *category, + isc_logmodule_t *module, int level, const char *fmt, ...) +{ + char msgbuf[2048]; + va_list ap; + + if (!isc_log_wouldlog(isc_lctx, level)) + return; + + va_start(ap, fmt); + vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); + va_end(ap); + + isc_log_write(isc_lctx, category, module, level, + "sockmgr %p: %s", sockmgr, msgbuf); +} + +static void +socket_log(int lineno, isc_socket_t *sock, isc_sockaddr_t *address, + isc_logcategory_t *category, isc_logmodule_t *module, int level, + isc_msgcat_t *msgcat, int msgset, int message, + const char *fmt, ...) +{ + char msgbuf[2048]; + char peerbuf[256]; + va_list ap; + + + if (!isc_log_wouldlog(isc_lctx, level)) + return; + + va_start(ap, fmt); + vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); + va_end(ap); + + if (address == NULL) { + isc_log_iwrite(isc_lctx, category, module, level, + msgcat, msgset, message, + "socket %p line %d: %s", sock, lineno, msgbuf); + } else { + isc_sockaddr_format(address, peerbuf, sizeof(peerbuf)); + isc_log_iwrite(isc_lctx, category, module, level, + msgcat, msgset, message, + "socket %p line %d peer %s: %s", sock, lineno, + peerbuf, msgbuf); + } + +} + +/* + * Make an fd SOCKET non-blocking. + */ +static isc_result_t +make_nonblock(SOCKET fd) { + int ret; + unsigned long flags = 1; + char strbuf[ISC_STRERRORSIZE]; + + /* Set the socket to non-blocking */ + ret = ioctlsocket(fd, FIONBIO, &flags); + + if (ret == -1) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "ioctlsocket(%d, FIOBIO, %d): %s", + fd, flags, strbuf); + + return (ISC_R_UNEXPECTED); + } + + return (ISC_R_SUCCESS); +} + +/* + * Windows 2000 systems incorrectly cause UDP sockets using WSARecvFrom + * to not work correctly, returning a WSACONNRESET error when a WSASendTo + * fails with an "ICMP port unreachable" response and preventing the + * socket from using the WSARecvFrom in subsequent operations. + * The function below fixes this, but requires that Windows 2000 + * Service Pack 2 or later be installed on the system. NT 4.0 + * systems are not affected by this and work correctly. + * See Microsoft Knowledge Base Article Q263823 for details of this. + */ +isc_result_t +connection_reset_fix(SOCKET fd) { + DWORD dwBytesReturned = 0; + BOOL bNewBehavior = FALSE; + DWORD status; + + if (isc_win32os_majorversion() < 5) + return (ISC_R_SUCCESS); /* NT 4.0 has no problem */ + + /* disable bad behavior using IOCTL: SIO_UDP_CONNRESET */ + status = WSAIoctl(fd, SIO_UDP_CONNRESET, &bNewBehavior, + sizeof(bNewBehavior), NULL, 0, + &dwBytesReturned, NULL, NULL); + if (status != SOCKET_ERROR) + return (ISC_R_SUCCESS); + else { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "WSAIoctl(SIO_UDP_CONNRESET, oldBehaviour) %s", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed")); + return (ISC_R_UNEXPECTED); + } +} + +/* + * Construct an iov array and attach it to the msghdr passed in. This is + * the SEND constructor, which will use the used region of the buffer + * (if using a buffer list) or will use the internal region (if a single + * buffer I/O is requested). + * + * Nothing can be NULL, and the done event must list at least one buffer + * on the buffer linked list for this function to be meaningful. + */ +static void +build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev, + struct msghdr *msg, char *cmsg, WSABUF *iov, + IoCompletionInfo *lpo) +{ + unsigned int iovcount; + isc_buffer_t *buffer; + buflist_t *cpbuffer; + isc_region_t used; + size_t write_count; + size_t skip_count; + + memset(msg, 0, sizeof(*msg)); + + memcpy(&msg->to_addr, &dev->address.type, dev->address.length); + msg->to_addr_len = dev->address.length; + + buffer = ISC_LIST_HEAD(dev->bufferlist); + write_count = 0; + iovcount = 0; + + /* + * Single buffer I/O? Skip what we've done so far in this region. + */ + if (buffer == NULL) { + write_count = dev->region.length - dev->n; + cpbuffer = HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY, sizeof(buflist_t)); + RUNTIME_CHECK(cpbuffer != NULL); + cpbuffer->buf = HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY, write_count); + RUNTIME_CHECK(cpbuffer->buf != NULL); + + socket_log(__LINE__, sock, NULL, TRACE, + isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK, + "alloc_buffer %p %d %p %d", cpbuffer, sizeof(buflist_t), + cpbuffer->buf, write_count); + + memcpy(cpbuffer->buf,(dev->region.base + dev->n), write_count); + cpbuffer->buflen = write_count; + ISC_LIST_ENQUEUE(lpo->bufferlist, cpbuffer, link); + iov[0].buf = cpbuffer->buf; + iov[0].len = write_count; + iovcount = 1; + + goto config; + } + + /* + * Multibuffer I/O. + * Skip the data in the buffer list that we have already written. + */ + skip_count = dev->n; + while (buffer != NULL) { + REQUIRE(ISC_BUFFER_VALID(buffer)); + if (skip_count < isc_buffer_usedlength(buffer)) + break; + skip_count -= isc_buffer_usedlength(buffer); + buffer = ISC_LIST_NEXT(buffer, link); + } + + while (buffer != NULL) { + INSIST(iovcount < MAXSCATTERGATHER_SEND); + + isc_buffer_usedregion(buffer, &used); + + if (used.length > 0) { + int uselen = used.length - skip_count; + cpbuffer = HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY, sizeof(buflist_t)); + RUNTIME_CHECK(cpbuffer != NULL); + cpbuffer->buf = HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY, uselen); + RUNTIME_CHECK(cpbuffer->buf != NULL); + + socket_log(__LINE__, sock, NULL, TRACE, + isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK, + "alloc_buffer %p %d %p %d", cpbuffer, sizeof(buflist_t), + cpbuffer->buf, write_count); + + memcpy(cpbuffer->buf,(used.base + skip_count), uselen); + cpbuffer->buflen = uselen; + iov[iovcount].buf = cpbuffer->buf; + iov[iovcount].len = used.length - skip_count; + write_count += uselen; + skip_count = 0; + iovcount++; + } + buffer = ISC_LIST_NEXT(buffer, link); + } + + INSIST(skip_count == 0); + + config: + msg->msg_iov = iov; + msg->msg_iovlen = iovcount; + msg->msg_totallen = write_count; +} + +static void +set_dev_address(isc_sockaddr_t *address, isc_socket_t *sock, + isc_socketevent_t *dev) +{ + if (sock->type == isc_sockettype_udp) { + if (address != NULL) + dev->address = *address; + else + dev->address = sock->address; + } else if (sock->type == isc_sockettype_tcp) { + INSIST(address == NULL); + dev->address = sock->address; + } +} + +static void +destroy_socketevent(isc_event_t *event) { + isc_socketevent_t *ev = (isc_socketevent_t *)event; + + INSIST(ISC_LIST_EMPTY(ev->bufferlist)); + + (ev->destroy)(event); +} + +static isc_socketevent_t * +allocate_socketevent(isc_socket_t *sock, isc_eventtype_t eventtype, + isc_taskaction_t action, const void *arg) +{ + isc_socketevent_t *ev; + + ev = (isc_socketevent_t *)isc_event_allocate(sock->manager->mctx, + sock, eventtype, + action, arg, + sizeof(*ev)); + if (ev == NULL) + return (NULL); + + ev->result = ISC_R_IOERROR; // XXXMLG temporary change to detect failure to set + ISC_LINK_INIT(ev, ev_link); + ISC_LIST_INIT(ev->bufferlist); + ev->region.base = NULL; + ev->n = 0; + ev->offset = 0; + ev->attributes = 0; + ev->destroy = ev->ev_destroy; + ev->ev_destroy = destroy_socketevent; + + return (ev); +} + +#if defined(ISC_SOCKET_DEBUG) +static void +dump_msg(struct msghdr *msg, isc_socket_t *sock) { + unsigned int i; + + printf("MSGHDR %p, Socket #: %u\n", msg, sock->fd); + printf("\tname %p, namelen %d\n", msg->msg_name, msg->msg_namelen); + printf("\tiov %p, iovlen %d\n", msg->msg_iov, msg->msg_iovlen); + for (i = 0; i < (unsigned int)msg->msg_iovlen; i++) + printf("\t\t%d\tbase %p, len %d\n", i, + msg->msg_iov[i].buf, + msg->msg_iov[i].len); +} +#endif + +/* + * map the error code + */ +int +map_socket_error(isc_socket_t *sock, int windows_errno, int *isc_errno, + char *errorstring, size_t bufsize) { + + int doreturn; + switch (windows_errno) { + case WSAECONNREFUSED: + *isc_errno = ISC_R_CONNREFUSED; + if (sock->connected) + doreturn = DOIO_HARD; + else + doreturn = DOIO_SOFT; + break; + case WSAENETUNREACH: + case ERROR_NETWORK_UNREACHABLE: + *isc_errno = ISC_R_NETUNREACH; + if (sock->connected) + doreturn = DOIO_HARD; + else + doreturn = DOIO_SOFT; + break; + case ERROR_PORT_UNREACHABLE: + case ERROR_HOST_UNREACHABLE: + case WSAEHOSTUNREACH: + *isc_errno = ISC_R_HOSTUNREACH; + if (sock->connected) + doreturn = DOIO_HARD; + else + doreturn = DOIO_SOFT; + break; + case WSAENETDOWN: + *isc_errno = ISC_R_NETDOWN; + if (sock->connected) + doreturn = DOIO_HARD; + else + doreturn = DOIO_SOFT; + break; + case WSAEHOSTDOWN: + *isc_errno = ISC_R_HOSTDOWN; + if (sock->connected) + doreturn = DOIO_HARD; + else + doreturn = DOIO_SOFT; + break; + case WSAEACCES: + *isc_errno = ISC_R_NOPERM; + if (sock->connected) + doreturn = DOIO_HARD; + else + doreturn = DOIO_SOFT; + break; + case WSAECONNRESET: + case WSAENETRESET: + case WSAECONNABORTED: + case WSAEDISCON: + *isc_errno = ISC_R_CONNECTIONRESET; + if (sock->connected) + doreturn = DOIO_HARD; + else + doreturn = DOIO_SOFT; + break; + case WSAENOTCONN: + *isc_errno = ISC_R_NOTCONNECTED; + if (sock->connected) + doreturn = DOIO_HARD; + else + doreturn = DOIO_SOFT; + break; + case ERROR_OPERATION_ABORTED: + case ERROR_CONNECTION_ABORTED: + case ERROR_REQUEST_ABORTED: + *isc_errno = ISC_R_CONNECTIONRESET; + doreturn = DOIO_HARD; + break; + case WSAENOBUFS: + *isc_errno = ISC_R_NORESOURCES; + doreturn = DOIO_HARD; + break; + case WSAEAFNOSUPPORT: + *isc_errno = ISC_R_FAMILYNOSUPPORT; + doreturn = DOIO_HARD; + break; + case WSAEADDRNOTAVAIL: + *isc_errno = ISC_R_ADDRNOTAVAIL; + doreturn = DOIO_HARD; + break; + case WSAEDESTADDRREQ: + *isc_errno = ISC_R_BADADDRESSFORM; + doreturn = DOIO_HARD; + break; + case ERROR_NETNAME_DELETED: + *isc_errno = ISC_R_NETDOWN; + doreturn = DOIO_HARD; + break; + default: + *isc_errno = ISC_R_IOERROR; + doreturn = DOIO_HARD; + break; + } + if (doreturn == DOIO_HARD) { + isc__strerror(windows_errno, errorstring, bufsize); + } + return (doreturn); +} + +static void +fill_recv(isc_socket_t *sock, isc_socketevent_t *dev) { + isc_region_t r; + int copylen; + isc_buffer_t *buffer; + + INSIST(dev->n < dev->minimum); + INSIST(sock->recvbuf.remaining > 0); + INSIST(sock->pending_recv == 0); + + if (sock->type == isc_sockettype_udp) { + dev->address.length = sock->recvbuf.from_addr_len; + memcpy(&dev->address.type, &sock->recvbuf.from_addr, + sock->recvbuf.from_addr_len); + if (isc_sockaddr_getport(&dev->address) == 0) { + if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) { + socket_log(__LINE__, sock, &dev->address, IOEVENT, + isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_ZEROPORT, + "dropping source port zero packet"); + } + sock->recvbuf.remaining = 0; + return; + } + } else if (sock->type == isc_sockettype_tcp) { + dev->address = sock->address; + } + + /* + * Run through the list of buffers we were given, and find the + * first one with space. Once it is found, loop through, filling + * the buffers as much as possible. + */ + buffer = ISC_LIST_HEAD(dev->bufferlist); + if (buffer != NULL) { // Multi-buffer receive + while (buffer != NULL && sock->recvbuf.remaining > 0) { + REQUIRE(ISC_BUFFER_VALID(buffer)); + if (isc_buffer_availablelength(buffer) > 0) { + isc_buffer_availableregion(buffer, &r); + copylen = min(r.length, sock->recvbuf.remaining); + memcpy(r.base, sock->recvbuf.consume_position, copylen); + sock->recvbuf.consume_position += copylen; + sock->recvbuf.remaining -= copylen; + isc_buffer_add(buffer, copylen); + dev->n += copylen; + } + buffer = ISC_LIST_NEXT(buffer, link); + } + } else { // Single-buffer receive + copylen = min(dev->region.length - dev->n, sock->recvbuf.remaining); + memcpy(dev->region.base + dev->n, sock->recvbuf.consume_position, copylen); + sock->recvbuf.consume_position += copylen; + sock->recvbuf.remaining -= copylen; + dev->n += copylen; + } + + /* + * UDP receives are all-consuming. That is, if we have 4k worth of + * data in our receive buffer, and the caller only gave us + * 1k of space, we will toss the remaining 3k of data. TCP + * will keep the extra data around and use it for later requests. + */ + if (sock->type == isc_sockettype_udp) + sock->recvbuf.remaining = 0; +} + +/* + * Copy out as much data from the internal buffer to done events. + * As each done event is filled, send it along its way. + */ +static void +completeio_recv(isc_socket_t *sock) +{ + isc_socketevent_t *dev; + + /* + * If we are in the process of filling our buffer, we cannot + * touch it yet, so don't. + */ + if (sock->pending_recv > 0) + return; + + while (sock->recvbuf.remaining > 0 && !ISC_LIST_EMPTY(sock->recv_list)) { + dev = ISC_LIST_HEAD(sock->recv_list); + + /* + * See if we have sufficient data in our receive buffer + * to handle this. If we do, copy out the data. + */ + fill_recv(sock, dev); + + /* + * Did we satisfy it? + */ + if (dev->n >= dev->minimum) { + dev->result = ISC_R_SUCCESS; + send_recvdone_event(sock, &dev); + } + } +} + +/* + * Returns: + * DOIO_SUCCESS The operation succeeded. dev->result contains + * ISC_R_SUCCESS. + * + * DOIO_HARD A hard or unexpected I/O error was encountered. + * dev->result contains the appropriate error. + * + * DOIO_SOFT A soft I/O error was encountered. No senddone + * event was sent. The operation should be retried. + * + * No other return values are possible. + */ +static int +completeio_send(isc_socket_t *sock, isc_socketevent_t *dev, + struct msghdr *messagehdr, int cc, int send_errno) +{ + char addrbuf[ISC_SOCKADDR_FORMATSIZE]; + char strbuf[ISC_STRERRORSIZE]; + + if (send_errno != 0) { + if (SOFT_ERROR(send_errno)) + return (DOIO_SOFT); + + return (map_socket_error(sock, send_errno, &dev->result, + strbuf, sizeof(strbuf))); + + /* + * The other error types depend on whether or not the + * socket is UDP or TCP. If it is UDP, some errors + * that we expect to be fatal under TCP are merely + * annoying, and are really soft errors. + * + * However, these soft errors are still returned as + * a status. + */ + isc_sockaddr_format(&dev->address, addrbuf, sizeof(addrbuf)); + isc__strerror(send_errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, "completeio_send: %s: %s", + addrbuf, strbuf); + dev->result = isc__errno2result(send_errno); + return (DOIO_HARD); + } + + /* + * If we write less than we expected, update counters, poke. + */ + dev->n += cc; + if (cc != messagehdr->msg_totallen) + return (DOIO_SOFT); + + /* + * Exactly what we wanted to write. We're done with this + * entry. Post its completion event. + */ + dev->result = ISC_R_SUCCESS; + return (DOIO_SUCCESS); +} + +static int +startio_send(isc_socket_t *sock, isc_socketevent_t *dev, int *nbytes, + int *send_errno) +{ + char *cmsg = NULL; + char strbuf[ISC_STRERRORSIZE]; + IoCompletionInfo *lpo; + int status; + struct msghdr *msghdr; + + lpo = (IoCompletionInfo *)HeapAlloc(hHeapHandle, + HEAP_ZERO_MEMORY, + sizeof(IoCompletionInfo)); + RUNTIME_CHECK(lpo != NULL); + lpo->request_type = SOCKET_SEND; + lpo->dev = dev; + msghdr = &lpo->messagehdr; + memset(msghdr, 0, sizeof(struct msghdr)); + ISC_LIST_INIT(lpo->bufferlist); + + build_msghdr_send(sock, dev, msghdr, cmsg, sock->iov, lpo); + + *nbytes = internal_sendmsg(sock, lpo, msghdr, 0, send_errno); + + if (*nbytes < 0) { + /* + * I/O has been initiated + * completion will be through the completion port + */ + if (PENDING_ERROR(*send_errno)) { + status = DOIO_PENDING; + goto done; + } + + if (SOFT_ERROR(*send_errno)) { + status = DOIO_SOFT; + goto done; + } + + /* + * If we got this far then something is wrong + */ + if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) { + isc__strerror(*send_errno, strbuf, sizeof(strbuf)); + socket_log(__LINE__, sock, NULL, IOEVENT, + isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_INTERNALSEND, + "startio_send: internal_sendmsg(%d) %d " + "bytes, err %d/%s", + sock->fd, *nbytes, *send_errno, strbuf); + } + status = DOIO_HARD; + goto done; + } + dev->result = ISC_R_SUCCESS; + status = DOIO_SOFT; + done: + _set_state(sock, SOCK_DATA); + return (status); +} + +static isc_result_t +allocate_socket(isc_socketmgr_t *manager, isc_sockettype_t type, + isc_socket_t **socketp) { + isc_socket_t *sock; + isc_result_t result; + + sock = isc_mem_get(manager->mctx, sizeof(*sock)); + + if (sock == NULL) + return (ISC_R_NOMEMORY); + + sock->magic = 0; + sock->references = 0; + + sock->manager = manager; + sock->type = type; + sock->fd = INVALID_SOCKET; + + ISC_LINK_INIT(sock, link); + + /* + * set up list of readers and writers to be initially empty + */ + ISC_LIST_INIT(sock->recv_list); + ISC_LIST_INIT(sock->send_list); + ISC_LIST_INIT(sock->accept_list); + sock->connect_ev = NULL; + sock->pending_accept = 0; + sock->pending_recv = 0; + sock->pending_send = 0; + sock->pending_iocp = 0; + sock->listener = 0; + sock->connected = 0; + sock->pending_connect = 0; + sock->bound = 0; + sock->dupped = 0; + memset(sock->name, 0, sizeof(sock->name)); // zero the name field + _set_state(sock, SOCK_INITIALIZED); + + sock->recvbuf.len = 65536; + sock->recvbuf.consume_position = sock->recvbuf.base; + sock->recvbuf.remaining = 0; + sock->recvbuf.base = isc_mem_get(manager->mctx, sock->recvbuf.len); // max buffer size + if (sock->recvbuf.base == NULL) { + sock->magic = 0; + goto error; + } + + /* + * initialize the lock + */ + result = isc_mutex_init(&sock->lock); + if (result != ISC_R_SUCCESS) { + sock->magic = 0; + isc_mem_put(manager->mctx, sock->recvbuf.base, sock->recvbuf.len); + sock->recvbuf.base = NULL; + goto error; + } + + socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0, + "allocated"); + + sock->magic = SOCKET_MAGIC; + *socketp = sock; + + return (ISC_R_SUCCESS); + + error: + isc_mem_put(manager->mctx, sock, sizeof(*sock)); + + return (result); +} + +/* + * Verify that the socket state is consistent. + */ +static void +consistent(isc_socket_t *sock) { + + isc_socketevent_t *dev; + isc_socket_newconnev_t *nev; + unsigned int count; + char *crash_reason; + isc_boolean_t crash = ISC_FALSE; + + REQUIRE(sock->pending_iocp == sock->pending_recv + sock->pending_send + + sock->pending_accept + sock->pending_connect); + + dev = ISC_LIST_HEAD(sock->send_list); + count = 0; + while (dev != NULL) { + count++; + dev = ISC_LIST_NEXT(dev, ev_link); + } + if (count > sock->pending_send) { + crash = ISC_TRUE; + crash_reason = "send_list > sock->pending_send"; + } + + nev = ISC_LIST_HEAD(sock->accept_list); + count = 0; + while (nev != NULL) { + count++; + nev = ISC_LIST_NEXT(nev, ev_link); + } + if (count > sock->pending_accept) { + crash = ISC_TRUE; + crash_reason = "send_list > sock->pending_send"; + } + + if (crash) { + socket_log(__LINE__, sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_DESTROYING, "SOCKET INCONSISTENT: %s", + crash_reason); + sock_dump(sock); + INSIST(crash == ISC_FALSE); + } +} + +/* + * Maybe free the socket. + * + * This function will verify tht the socket is no longer in use in any way, + * either internally or externally. This is the only place where this + * check is to be made; if some bit of code believes that IT is done with + * the socket (e.g., some reference counter reaches zero), it should call + * this function. + * + * When calling this function, the socket must be locked, and the manager + * must be unlocked. + * + * When this function returns, *socketp will be NULL. No tricks to try + * to hold on to this pointer are allowed. + */ +static void +maybe_free_socket(isc_socket_t **socketp, int lineno) { + isc_socket_t *sock = *socketp; + *socketp = NULL; + + INSIST(VALID_SOCKET(sock)); + CONSISTENT(sock); + + if (sock->pending_iocp > 0 + || sock->pending_recv > 0 + || sock->pending_send > 0 + || sock->pending_accept > 0 + || sock->references > 0 + || sock->pending_connect == 1 + || !ISC_LIST_EMPTY(sock->recv_list) + || !ISC_LIST_EMPTY(sock->send_list) + || !ISC_LIST_EMPTY(sock->accept_list) + || sock->fd != INVALID_SOCKET) { + UNLOCK(&sock->lock); + return; + } + UNLOCK(&sock->lock); + + free_socket(&sock, lineno); +} + +void +free_socket(isc_socket_t **sockp, int lineno) { + isc_socketmgr_t *manager; + isc_socket_t *sock = *sockp; + *sockp = NULL; + + manager = sock->manager; + + /* + * Seems we can free the socket after all. + */ + manager = sock->manager; + socket_log(__LINE__, sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_DESTROYING, "freeing socket line %d fd %d lock %p semaphore %p", + lineno, sock->fd, &sock->lock, sock->lock.LockSemaphore); + + sock->magic = 0; + DESTROYLOCK(&sock->lock); + + if (sock->recvbuf.base != NULL) + isc_mem_put(manager->mctx, sock->recvbuf.base, sock->recvbuf.len); + + LOCK(&manager->lock); + if (ISC_LINK_LINKED(sock, link)) + ISC_LIST_UNLINK(manager->socklist, sock, link); + isc_mem_put(manager->mctx, sock, sizeof(*sock)); + + if (ISC_LIST_EMPTY(manager->socklist)) + SIGNAL(&manager->shutdown_ok); + UNLOCK(&manager->lock); +} + +/* + * Create a new 'type' socket managed by 'manager'. Events + * will be posted to 'task' and when dispatched 'action' will be + * called with 'arg' as the arg value. The new socket is returned + * in 'socketp'. + */ +static isc_result_t +socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, + isc_socket_t **socketp, isc_socket_t *dup_socket) +{ + isc_socket_t *sock = NULL; + isc_result_t result; +#if defined(USE_CMSG) + int on = 1; +#endif +#if defined(SO_RCVBUF) + ISC_SOCKADDR_LEN_T optlen; + int size; +#endif + int socket_errno; + char strbuf[ISC_STRERRORSIZE]; + + REQUIRE(VALID_MANAGER(manager)); + REQUIRE(socketp != NULL && *socketp == NULL); + REQUIRE(type != isc_sockettype_fdwatch); + + if (dup_socket != NULL) + return (ISC_R_NOTIMPLEMENTED); + + result = allocate_socket(manager, type, &sock); + if (result != ISC_R_SUCCESS) + return (result); + + sock->pf = pf; +#if 0 + if (dup_socket == NULL) { +#endif + switch (type) { + case isc_sockettype_udp: + sock->fd = socket(pf, SOCK_DGRAM, IPPROTO_UDP); + if (sock->fd != INVALID_SOCKET) { + result = connection_reset_fix(sock->fd); + if (result != ISC_R_SUCCESS) { + socket_log(__LINE__, sock, + NULL, EVENT, NULL, 0, 0, + "closed %d %d %d " + "con_reset_fix_failed", + sock->pending_recv, + sock->pending_send, + sock->references); + closesocket(sock->fd); + _set_state(sock, SOCK_CLOSED); + sock->fd = INVALID_SOCKET; + free_socket(&sock, __LINE__); + return (result); + } + } + break; + case isc_sockettype_tcp: + sock->fd = socket(pf, SOCK_STREAM, IPPROTO_TCP); + break; + } +#if 0 + } else { + /* + * XXX: dup() is deprecated in windows, use _dup() + * instead. In future we may want to investigate + * WSADuplicateSocket(). + */ + sock->fd = _dup(dup_socket->fd); + sock->dupped = 1; + sock->bound = dup_socket->bound; + } +#endif + + if (sock->fd == INVALID_SOCKET) { + socket_errno = WSAGetLastError(); + free_socket(&sock, __LINE__); + + switch (socket_errno) { + case WSAEMFILE: + case WSAENOBUFS: + return (ISC_R_NORESOURCES); + + case WSAEPROTONOSUPPORT: + case WSAEPFNOSUPPORT: + case WSAEAFNOSUPPORT: + return (ISC_R_FAMILYNOSUPPORT); + + default: + isc__strerror(socket_errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "socket() %s: %s", + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, + "failed"), + strbuf); + return (ISC_R_UNEXPECTED); + } + } + + result = make_nonblock(sock->fd); + if (result != ISC_R_SUCCESS) { + socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0, + "closed %d %d %d make_nonblock_failed", + sock->pending_recv, sock->pending_send, + sock->references); + closesocket(sock->fd); + sock->fd = INVALID_SOCKET; + free_socket(&sock, __LINE__); + return (result); + } + + +#if defined(USE_CMSG) || defined(SO_RCVBUF) + if (type == isc_sockettype_udp) { + +#if defined(USE_CMSG) +#if defined(ISC_PLATFORM_HAVEIPV6) +#ifdef IPV6_RECVPKTINFO + /* 2292bis */ + if ((pf == AF_INET6) + && (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, + (char *)&on, sizeof(on)) < 0)) { + isc__strerror(WSAGetLastError(), strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "setsockopt(%d, IPV6_RECVPKTINFO) " + "%s: %s", sock->fd, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, + "failed"), + strbuf); + } +#else + /* 2292 */ + if ((pf == AF_INET6) + && (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_PKTINFO, + (char *)&on, sizeof(on)) < 0)) { + isc__strerror(WSAGetLastError(), strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "setsockopt(%d, IPV6_PKTINFO) %s: %s", + sock->fd, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, + "failed"), + strbuf); + } +#endif /* IPV6_RECVPKTINFO */ +#ifdef IPV6_USE_MIN_MTU /*2292bis, not too common yet*/ + /* use minimum MTU */ + if (pf == AF_INET6) { + (void)setsockopt(sock->fd, IPPROTO_IPV6, + IPV6_USE_MIN_MTU, + (char *)&on, sizeof(on)); + } +#endif +#endif /* ISC_PLATFORM_HAVEIPV6 */ +#endif /* defined(USE_CMSG) */ + +#if defined(SO_RCVBUF) + optlen = sizeof(size); + if (getsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF, + (char *)&size, &optlen) >= 0 && + size < RCVBUFSIZE) { + size = RCVBUFSIZE; + (void)setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF, + (char *)&size, sizeof(size)); + } +#endif + + } +#endif /* defined(USE_CMSG) || defined(SO_RCVBUF) */ + + _set_state(sock, SOCK_OPEN); + sock->references = 1; + *socketp = sock; + + iocompletionport_update(sock); + + /* + * Note we don't have to lock the socket like we normally would because + * there are no external references to it yet. + */ + LOCK(&manager->lock); + ISC_LIST_APPEND(manager->socklist, sock, link); + InterlockedIncrement(&manager->totalSockets); + UNLOCK(&manager->lock); + + socket_log(__LINE__, sock, NULL, CREATION, isc_msgcat, + ISC_MSGSET_SOCKET, ISC_MSG_CREATED, + "created %u type %u", sock->fd, type); + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc__socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type, + isc_socket_t **socketp) +{ + return (socket_create(manager, pf, type, socketp, NULL)); +} + +isc_result_t +isc__socket_dup(isc_socket_t *sock, isc_socket_t **socketp) { + REQUIRE(VALID_SOCKET(sock)); + REQUIRE(socketp != NULL && *socketp == NULL); + +#if 1 + return (ISC_R_NOTIMPLEMENTED); +#else + return (socket_create(sock->manager, sock->pf, sock->type, + socketp, sock)); +#endif +} + +isc_result_t +isc_socket_open(isc_socket_t *sock) { + REQUIRE(VALID_SOCKET(sock)); + REQUIRE(sock->type != isc_sockettype_fdwatch); + + return (ISC_R_NOTIMPLEMENTED); +} + +/* + * Attach to a socket. Caller must explicitly detach when it is done. + */ +void +isc__socket_attach(isc_socket_t *sock, isc_socket_t **socketp) { + REQUIRE(VALID_SOCKET(sock)); + REQUIRE(socketp != NULL && *socketp == NULL); + + LOCK(&sock->lock); + CONSISTENT(sock); + sock->references++; + UNLOCK(&sock->lock); + + *socketp = sock; +} + +/* + * Dereference a socket. If this is the last reference to it, clean things + * up by destroying the socket. + */ +void +isc__socket_detach(isc_socket_t **socketp) { + isc_socket_t *sock; + isc_boolean_t kill_socket = ISC_FALSE; + + REQUIRE(socketp != NULL); + sock = *socketp; + REQUIRE(VALID_SOCKET(sock)); + REQUIRE(sock->type != isc_sockettype_fdwatch); + + LOCK(&sock->lock); + CONSISTENT(sock); + REQUIRE(sock->references > 0); + sock->references--; + + socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0, + "detach_socket %d %d %d", + sock->pending_recv, sock->pending_send, + sock->references); + + if (sock->references == 0 && sock->fd != INVALID_SOCKET) { + closesocket(sock->fd); + sock->fd = INVALID_SOCKET; + _set_state(sock, SOCK_CLOSED); + } + + maybe_free_socket(&sock, __LINE__); + + *socketp = NULL; +} + +isc_result_t +isc_socket_close(isc_socket_t *sock) { + REQUIRE(VALID_SOCKET(sock)); + REQUIRE(sock->type != isc_sockettype_fdwatch); + + return (ISC_R_NOTIMPLEMENTED); +} + +/* + * Dequeue an item off the given socket's read queue, set the result code + * in the done event to the one provided, and send it to the task it was + * destined for. + * + * If the event to be sent is on a list, remove it before sending. If + * asked to, send and detach from the task as well. + * + * Caller must have the socket locked if the event is attached to the socket. + */ +static void +send_recvdone_event(isc_socket_t *sock, isc_socketevent_t **dev) { + isc_task_t *task; + + task = (*dev)->ev_sender; + (*dev)->ev_sender = sock; + + if (ISC_LINK_LINKED(*dev, ev_link)) + ISC_LIST_DEQUEUE(sock->recv_list, *dev, ev_link); + + if (((*dev)->attributes & ISC_SOCKEVENTATTR_ATTACHED) + == ISC_SOCKEVENTATTR_ATTACHED) + isc_task_sendanddetach(&task, (isc_event_t **)dev); + else + isc_task_send(task, (isc_event_t **)dev); + + CONSISTENT(sock); +} + +/* + * See comments for send_recvdone_event() above. + */ +static void +send_senddone_event(isc_socket_t *sock, isc_socketevent_t **dev) { + isc_task_t *task; + + INSIST(dev != NULL && *dev != NULL); + + task = (*dev)->ev_sender; + (*dev)->ev_sender = sock; + + if (ISC_LINK_LINKED(*dev, ev_link)) + ISC_LIST_DEQUEUE(sock->send_list, *dev, ev_link); + + if (((*dev)->attributes & ISC_SOCKEVENTATTR_ATTACHED) + == ISC_SOCKEVENTATTR_ATTACHED) + isc_task_sendanddetach(&task, (isc_event_t **)dev); + else + isc_task_send(task, (isc_event_t **)dev); + + CONSISTENT(sock); +} + +/* + * See comments for send_recvdone_event() above. + */ +static void +send_acceptdone_event(isc_socket_t *sock, isc_socket_newconnev_t **adev) { + isc_task_t *task; + + INSIST(adev != NULL && *adev != NULL); + + task = (*adev)->ev_sender; + (*adev)->ev_sender = sock; + + if (ISC_LINK_LINKED(*adev, ev_link)) + ISC_LIST_DEQUEUE(sock->accept_list, *adev, ev_link); + + isc_task_sendanddetach(&task, (isc_event_t **)adev); + + CONSISTENT(sock); +} + +/* + * See comments for send_recvdone_event() above. + */ +static void +send_connectdone_event(isc_socket_t *sock, isc_socket_connev_t **cdev) { + isc_task_t *task; + + INSIST(cdev != NULL && *cdev != NULL); + + task = (*cdev)->ev_sender; + (*cdev)->ev_sender = sock; + + sock->connect_ev = NULL; + + isc_task_sendanddetach(&task, (isc_event_t **)cdev); + + CONSISTENT(sock); +} + +/* + * On entry to this function, the event delivered is the internal + * readable event, and the first item on the accept_list should be + * the done event we want to send. If the list is empty, this is a no-op, + * so just close the new connection, unlock, and return. + * + * Note the socket is locked before entering here + */ +static void +internal_accept(isc_socket_t *sock, IoCompletionInfo *lpo, int accept_errno) { + isc_socket_newconnev_t *adev; + isc_result_t result = ISC_R_SUCCESS; + isc_socket_t *nsock; + struct sockaddr *localaddr; + int localaddr_len = sizeof(*localaddr); + struct sockaddr *remoteaddr; + int remoteaddr_len = sizeof(*remoteaddr); + + INSIST(VALID_SOCKET(sock)); + LOCK(&sock->lock); + CONSISTENT(sock); + + socket_log(__LINE__, sock, NULL, TRACE, + isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK, + "internal_accept called"); + + INSIST(sock->listener); + + INSIST(sock->pending_iocp > 0); + sock->pending_iocp--; + INSIST(sock->pending_accept > 0); + sock->pending_accept--; + + adev = lpo->adev; + + /* + * If the event is no longer in the list we can just return. + */ + if (!acceptdone_is_active(sock, adev)) + goto done; + + nsock = adev->newsocket; + + /* + * Pull off the done event. + */ + ISC_LIST_UNLINK(sock->accept_list, adev, ev_link); + + /* + * Extract the addresses from the socket, copy them into the structure, + * and return the new socket. + */ + ISCGetAcceptExSockaddrs(lpo->acceptbuffer, 0, + sizeof(SOCKADDR_STORAGE) + 16, sizeof(SOCKADDR_STORAGE) + 16, + (LPSOCKADDR *)&localaddr, &localaddr_len, + (LPSOCKADDR *)&remoteaddr, &remoteaddr_len); + memcpy(&adev->address.type, remoteaddr, remoteaddr_len); + adev->address.length = remoteaddr_len; + nsock->address = adev->address; + nsock->pf = adev->address.type.sa.sa_family; + + socket_log(__LINE__, nsock, &nsock->address, TRACE, + isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK, + "internal_accept parent %p", sock); + + result = make_nonblock(adev->newsocket->fd); + INSIST(result == ISC_R_SUCCESS); + + INSIST(setsockopt(nsock->fd, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, + (char *)&sock->fd, sizeof(sock->fd)) == 0); + + /* + * Hook it up into the manager. + */ + nsock->bound = 1; + nsock->connected = 1; + _set_state(nsock, SOCK_OPEN); + + LOCK(&nsock->manager->lock); + ISC_LIST_APPEND(nsock->manager->socklist, nsock, link); + InterlockedIncrement(&nsock->manager->totalSockets); + UNLOCK(&nsock->manager->lock); + + socket_log(__LINE__, sock, &nsock->address, CREATION, + isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTEDCXN, + "accepted_connection new_socket %p fd %d", + nsock, nsock->fd); + + adev->result = result; + send_acceptdone_event(sock, &adev); + +done: + CONSISTENT(sock); + UNLOCK(&sock->lock); + + HeapFree(hHeapHandle, 0, lpo->acceptbuffer); + lpo->acceptbuffer = NULL; +} + +/* + * Called when a socket with a pending connect() finishes. + * Note that the socket is locked before entering. + */ +static void +internal_connect(isc_socket_t *sock, IoCompletionInfo *lpo, int connect_errno) { + isc_socket_connev_t *cdev; + char strbuf[ISC_STRERRORSIZE]; + + INSIST(VALID_SOCKET(sock)); + + LOCK(&sock->lock); + + INSIST(sock->pending_iocp > 0); + sock->pending_iocp--; + INSIST(sock->pending_connect == 1); + sock->pending_connect = 0; + + /* + * Has this event been canceled? + */ + cdev = lpo->cdev; + if (!connectdone_is_active(sock, cdev)) { + sock->pending_connect = 0; + if (sock->fd != INVALID_SOCKET) { + closesocket(sock->fd); + sock->fd = INVALID_SOCKET; + _set_state(sock, SOCK_CLOSED); + } + CONSISTENT(sock); + UNLOCK(&sock->lock); + return; + } + + /* + * Check possible Windows network event error status here. + */ + if (connect_errno != 0) { + /* + * If the error is SOFT, just try again on this + * fd and pretend nothing strange happened. + */ + if (SOFT_ERROR(connect_errno) || + connect_errno == WSAEINPROGRESS) { + sock->pending_connect = 1; + CONSISTENT(sock); + UNLOCK(&sock->lock); + return; + } + + /* + * Translate other errors into ISC_R_* flavors. + */ + switch (connect_errno) { +#define ERROR_MATCH(a, b) case a: cdev->result = b; break; + ERROR_MATCH(WSAEACCES, ISC_R_NOPERM); + ERROR_MATCH(WSAEADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL); + ERROR_MATCH(WSAEAFNOSUPPORT, ISC_R_ADDRNOTAVAIL); + ERROR_MATCH(WSAECONNREFUSED, ISC_R_CONNREFUSED); + ERROR_MATCH(WSAEHOSTUNREACH, ISC_R_HOSTUNREACH); + ERROR_MATCH(WSAEHOSTDOWN, ISC_R_HOSTDOWN); + ERROR_MATCH(WSAENETUNREACH, ISC_R_NETUNREACH); + ERROR_MATCH(WSAENETDOWN, ISC_R_NETDOWN); + ERROR_MATCH(WSAENOBUFS, ISC_R_NORESOURCES); + ERROR_MATCH(WSAECONNRESET, ISC_R_CONNECTIONRESET); + ERROR_MATCH(WSAECONNABORTED, ISC_R_CONNECTIONRESET); + ERROR_MATCH(WSAETIMEDOUT, ISC_R_TIMEDOUT); +#undef ERROR_MATCH + default: + cdev->result = ISC_R_UNEXPECTED; + isc__strerror(connect_errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "internal_connect: connect() %s", + strbuf); + } + } else { + INSIST(setsockopt(sock->fd, SOL_SOCKET, + SO_UPDATE_CONNECT_CONTEXT, NULL, 0) == 0); + cdev->result = ISC_R_SUCCESS; + sock->connected = 1; + socket_log(__LINE__, sock, &sock->address, IOEVENT, + isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTEDCXN, + "internal_connect: success"); + } + + send_connectdone_event(sock, &cdev); + + UNLOCK(&sock->lock); +} + +/* + * Loop through the socket, returning ISC_R_EOF for each done event pending. + */ +static void +send_recvdone_abort(isc_socket_t *sock, isc_result_t result) { + isc_socketevent_t *dev; + + while (!ISC_LIST_EMPTY(sock->recv_list)) { + dev = ISC_LIST_HEAD(sock->recv_list); + dev->result = result; + send_recvdone_event(sock, &dev); + } +} + +/* + * Take the data we received in our private buffer, and if any recv() calls on + * our list are satisfied, send the corresponding done event. + * + * If we need more data (there are still items on the recv_list after we consume all + * our data) then arrange for another system recv() call to fill our buffers. + */ +static void +internal_recv(isc_socket_t *sock, int nbytes) +{ + INSIST(VALID_SOCKET(sock)); + + LOCK(&sock->lock); + CONSISTENT(sock); + + socket_log(__LINE__, sock, NULL, IOEVENT, + isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALRECV, + "internal_recv: %d bytes received", nbytes); + + /* + * If we got here, the I/O operation succeeded. However, we might still have removed this + * event from our notification list (or never placed it on it due to immediate completion.) + * Handle the reference counting here, and handle the cancellation event just after. + */ + INSIST(sock->pending_iocp > 0); + sock->pending_iocp--; + INSIST(sock->pending_recv > 0); + sock->pending_recv--; + + /* + * The only way we could have gotten here is that our I/O has successfully completed. + * Update our pointers, and move on. The only odd case here is that we might not + * have received enough data on a TCP stream to satisfy the minimum requirements. If + * this is the case, we will re-issue the recv() call for what we need. + * + * We do check for a recv() of 0 bytes on a TCP stream. This means the remote end + * has closed. + */ + if (nbytes == 0 && sock->type == isc_sockettype_tcp) { + send_recvdone_abort(sock, ISC_R_EOF); + maybe_free_socket(&sock, __LINE__); + return; + } + sock->recvbuf.remaining = nbytes; + sock->recvbuf.consume_position = sock->recvbuf.base; + completeio_recv(sock); + + /* + * If there are more receivers waiting for data, queue another receive + * here. + */ + queue_receive_request(sock); + + /* + * Unlock and/or destroy if we are the last thing this socket has left to do. + */ + maybe_free_socket(&sock, __LINE__); +} + +static void +internal_send(isc_socket_t *sock, isc_socketevent_t *dev, + struct msghdr *messagehdr, int nbytes, int send_errno, IoCompletionInfo *lpo) +{ + buflist_t *buffer; + + /* + * Find out what socket this is and lock it. + */ + INSIST(VALID_SOCKET(sock)); + + LOCK(&sock->lock); + CONSISTENT(sock); + + socket_log(__LINE__, sock, NULL, IOEVENT, + isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALSEND, + "internal_send: task got socket event %p", dev); + + buffer = ISC_LIST_HEAD(lpo->bufferlist); + while (buffer != NULL) { + ISC_LIST_DEQUEUE(lpo->bufferlist, buffer, link); + + socket_log(__LINE__, sock, NULL, TRACE, + isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK, + "free_buffer %p %p", buffer, buffer->buf); + + HeapFree(hHeapHandle, 0, buffer->buf); + HeapFree(hHeapHandle, 0, buffer); + buffer = ISC_LIST_HEAD(lpo->bufferlist); + } + + INSIST(sock->pending_iocp > 0); + sock->pending_iocp--; + INSIST(sock->pending_send > 0); + sock->pending_send--; + + /* If the event is no longer in the list we can just return */ + if (!senddone_is_active(sock, dev)) + goto done; + + /* + * Set the error code and send things on its way. + */ + switch (completeio_send(sock, dev, messagehdr, nbytes, send_errno)) { + case DOIO_SOFT: + break; + case DOIO_HARD: + case DOIO_SUCCESS: + send_senddone_event(sock, &dev); + break; + } + + done: + maybe_free_socket(&sock, __LINE__); +} + +/* + * These return if the done event passed in is on the list (or for connect, is + * the one we're waiting for. Using these ensures we will not double-send an + * event. + */ +static isc_boolean_t +senddone_is_active(isc_socket_t *sock, isc_socketevent_t *dev) +{ + isc_socketevent_t *ldev; + + ldev = ISC_LIST_HEAD(sock->send_list); + while (ldev != NULL && ldev != dev) + ldev = ISC_LIST_NEXT(ldev, ev_link); + + return (ldev == NULL ? ISC_FALSE : ISC_TRUE); +} + +static isc_boolean_t +acceptdone_is_active(isc_socket_t *sock, isc_socket_newconnev_t *dev) +{ + isc_socket_newconnev_t *ldev; + + ldev = ISC_LIST_HEAD(sock->accept_list); + while (ldev != NULL && ldev != dev) + ldev = ISC_LIST_NEXT(ldev, ev_link); + + return (ldev == NULL ? ISC_FALSE : ISC_TRUE); +} + +static isc_boolean_t +connectdone_is_active(isc_socket_t *sock, isc_socket_connev_t *dev) +{ + return (sock->connect_ev == dev ? ISC_TRUE : ISC_FALSE); +} + +// +// The Windows network stack seems to have two very distinct paths depending +// on what is installed. Specifically, if something is looking at network +// connections (like an anti-virus or anti-malware application, such as +// McAfee products) Windows may return additional error conditions which +// were not previously returned. +// +// One specific one is when a TCP SYN scan is used. In this situation, +// Windows responds with the SYN-ACK, but the scanner never responds with +// the 3rd packet, the ACK. Windows consiers this a partially open connection. +// Most Unix networking stacks, and Windows without McAfee installed, will +// not return this to the caller. However, with this product installed, +// Windows returns this as a failed status on the Accept() call. Here, we +// will just re-issue the ISCAcceptEx() call as if nothing had happened. +// +// This code should only be called when the listening socket has received +// such an error. Additionally, the "parent" socket must be locked. +// Additionally, the lpo argument is re-used here, and must not be freed +// by the caller. +// +static isc_result_t +restart_accept(isc_socket_t *parent, IoCompletionInfo *lpo) +{ + isc_socket_t *nsock = lpo->adev->newsocket; + SOCKET new_fd; + + /* + * AcceptEx() requires we pass in a socket. Note that we carefully + * do not close the previous socket in case of an error message returned by + * our new socket() call. If we return an error here, our caller will + * clean up. + */ + new_fd = socket(parent->pf, SOCK_STREAM, IPPROTO_TCP); + if (nsock->fd == INVALID_SOCKET) { + return (ISC_R_FAILURE); // parent will ask windows for error message + } + closesocket(nsock->fd); + nsock->fd = new_fd; + + memset(&lpo->overlapped, 0, sizeof(lpo->overlapped)); + + ISCAcceptEx(parent->fd, + nsock->fd, /* Accepted Socket */ + lpo->acceptbuffer, /* Buffer for initial Recv */ + 0, /* Length of Buffer */ + sizeof(SOCKADDR_STORAGE) + 16, /* Local address length + 16 */ + sizeof(SOCKADDR_STORAGE) + 16, /* Remote address lengh + 16 */ + (LPDWORD)&lpo->received_bytes, /* Bytes Recved */ + (LPOVERLAPPED)lpo /* Overlapped structure */ + ); + + InterlockedDecrement(&nsock->manager->iocp_total); + iocompletionport_update(nsock); + + return (ISC_R_SUCCESS); +} + +/* + * This is the I/O Completion Port Worker Function. It loops forever + * waiting for I/O to complete and then forwards them for further + * processing. There are a number of these in separate threads. + */ +static isc_threadresult_t WINAPI +SocketIoThread(LPVOID ThreadContext) { + isc_socketmgr_t *manager = ThreadContext; + BOOL bSuccess = FALSE; + DWORD nbytes; + IoCompletionInfo *lpo = NULL; + isc_socket_t *sock = NULL; + int request; + struct msghdr *messagehdr = NULL; + int errval; + char strbuf[ISC_STRERRORSIZE]; + int errstatus; + + REQUIRE(VALID_MANAGER(manager)); + + /* + * Set the thread priority high enough so I/O will + * preempt normal recv packet processing, but not + * higher than the timer sync thread. + */ + if (!SetThreadPriority(GetCurrentThread(), + THREAD_PRIORITY_ABOVE_NORMAL)) { + errval = GetLastError(); + isc__strerror(errval, strbuf, sizeof(strbuf)); + FATAL_ERROR(__FILE__, __LINE__, + isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_FAILED, + "Can't set thread priority: %s"), + strbuf); + } + + /* + * Loop forever waiting on I/O Completions and then processing them + */ + while (TRUE) { + wait_again: + bSuccess = GetQueuedCompletionStatus(manager->hIoCompletionPort, + &nbytes, (LPDWORD)&sock, + (LPWSAOVERLAPPED *)&lpo, + INFINITE); + if (lpo == NULL) /* Received request to exit */ + break; + + REQUIRE(VALID_SOCKET(sock)); + + request = lpo->request_type; + + errstatus = 0; + if (!bSuccess) { + isc_result_t isc_result; + + /* + * Did the I/O operation complete? + */ + errstatus = GetLastError(); + isc_result = isc__errno2resultx(errstatus, __FILE__, __LINE__); + + LOCK(&sock->lock); + CONSISTENT(sock); + switch (request) { + case SOCKET_RECV: + INSIST(sock->pending_iocp > 0); + sock->pending_iocp--; + INSIST(sock->pending_recv > 0); + sock->pending_recv--; + if (!sock->connected && + ((errstatus == ERROR_HOST_UNREACHABLE) || + (errstatus == WSAENETRESET) || + (errstatus == WSAECONNRESET))) { + /* ignore soft errors */ + queue_receive_request(sock); + break; + } + send_recvdone_abort(sock, isc_result); + if (isc_result == ISC_R_UNEXPECTED) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "SOCKET_RECV: Windows error code: %d, returning ISC error %d", + errstatus, isc_result); + } + break; + + case SOCKET_SEND: + INSIST(sock->pending_iocp > 0); + sock->pending_iocp--; + INSIST(sock->pending_send > 0); + sock->pending_send--; + if (senddone_is_active(sock, lpo->dev)) { + lpo->dev->result = isc_result; + socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0, + "canceled_send"); + send_senddone_event(sock, &lpo->dev); + } + break; + + case SOCKET_ACCEPT: + INSIST(sock->pending_iocp > 0); + INSIST(sock->pending_accept > 0); + + socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0, + "Accept: errstatus=%d isc_result=%d", errstatus, isc_result); + + if (acceptdone_is_active(sock, lpo->adev)) { + if (restart_accept(sock, lpo) == ISC_R_SUCCESS) { + UNLOCK(&sock->lock); + goto wait_again; + } else { + errstatus = GetLastError(); + isc_result = isc__errno2resultx(errstatus, __FILE__, __LINE__); + socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0, + "restart_accept() failed: errstatus=%d isc_result=%d", + errstatus, isc_result); + } + } + + sock->pending_iocp--; + sock->pending_accept--; + if (acceptdone_is_active(sock, lpo->adev)) { + closesocket(lpo->adev->newsocket->fd); + lpo->adev->newsocket->fd = INVALID_SOCKET; + lpo->adev->newsocket->references--; + free_socket(&lpo->adev->newsocket, __LINE__); + lpo->adev->result = isc_result; + socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0, + "canceled_accept"); + send_acceptdone_event(sock, &lpo->adev); + } + break; + + case SOCKET_CONNECT: + INSIST(sock->pending_iocp > 0); + sock->pending_iocp--; + INSIST(sock->pending_connect == 1); + sock->pending_connect = 0; + if (connectdone_is_active(sock, lpo->cdev)) { + lpo->cdev->result = isc_result; + socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0, + "canceled_connect"); + send_connectdone_event(sock, &lpo->cdev); + } + break; + } + maybe_free_socket(&sock, __LINE__); + + if (lpo != NULL) + HeapFree(hHeapHandle, 0, lpo); + continue; + } + + messagehdr = &lpo->messagehdr; + + switch (request) { + case SOCKET_RECV: + internal_recv(sock, nbytes); + break; + case SOCKET_SEND: + internal_send(sock, lpo->dev, messagehdr, nbytes, errstatus, lpo); + break; + case SOCKET_ACCEPT: + internal_accept(sock, lpo, errstatus); + break; + case SOCKET_CONNECT: + internal_connect(sock, lpo, errstatus); + break; + } + + if (lpo != NULL) + HeapFree(hHeapHandle, 0, lpo); + } + + /* + * Exit Completion Port Thread + */ + manager_log(manager, TRACE, + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_EXITING, "SocketIoThread exiting")); + return ((isc_threadresult_t)0); +} + +/* + * Create a new socket manager. + */ +isc_result_t +isc__socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp) { + return (isc_socketmgr_create2(mctx, managerp, 0)); +} + +isc_result_t +isc__socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp, + unsigned int maxsocks) +{ + isc_socketmgr_t *manager; + isc_result_t result; + + REQUIRE(managerp != NULL && *managerp == NULL); + + if (maxsocks != 0) + return (ISC_R_NOTIMPLEMENTED); + + manager = isc_mem_get(mctx, sizeof(*manager)); + if (manager == NULL) + return (ISC_R_NOMEMORY); + + InitSockets(); + + manager->magic = SOCKET_MANAGER_MAGIC; + manager->mctx = NULL; + manager->stats = NULL; + ISC_LIST_INIT(manager->socklist); + result = isc_mutex_init(&manager->lock); + if (result != ISC_R_SUCCESS) { + isc_mem_put(mctx, manager, sizeof(*manager)); + return (result); + } + if (isc_condition_init(&manager->shutdown_ok) != ISC_R_SUCCESS) { + DESTROYLOCK(&manager->lock); + isc_mem_put(mctx, manager, sizeof(*manager)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_condition_init() %s", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed")); + return (ISC_R_UNEXPECTED); + } + + isc_mem_attach(mctx, &manager->mctx); + + iocompletionport_init(manager); /* Create the Completion Ports */ + + manager->bShutdown = ISC_FALSE; + manager->totalSockets = 0; + manager->iocp_total = 0; + + *managerp = manager; + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc__socketmgr_getmaxsockets(isc_socketmgr_t *manager, unsigned int *nsockp) { + REQUIRE(VALID_MANAGER(manager)); + REQUIRE(nsockp != NULL); + + return (ISC_R_NOTIMPLEMENTED); +} + +void +isc__socketmgr_setstats(isc_socketmgr_t *manager, isc_stats_t *stats) { + REQUIRE(VALID_MANAGER(manager)); + REQUIRE(ISC_LIST_EMPTY(manager->socklist)); + REQUIRE(manager->stats == NULL); + REQUIRE(isc_stats_ncounters(stats) == isc_sockstatscounter_max); + + isc_stats_attach(stats, &manager->stats); +} + +void +isc__socketmgr_destroy(isc_socketmgr_t **managerp) { + isc_socketmgr_t *manager; + int i; + isc_mem_t *mctx; + + /* + * Destroy a socket manager. + */ + + REQUIRE(managerp != NULL); + manager = *managerp; + REQUIRE(VALID_MANAGER(manager)); + + LOCK(&manager->lock); + + /* + * Wait for all sockets to be destroyed. + */ + while (!ISC_LIST_EMPTY(manager->socklist)) { + manager_log(manager, CREATION, + isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_SOCKETSREMAIN, + "sockets exist")); + WAIT(&manager->shutdown_ok, &manager->lock); + } + + UNLOCK(&manager->lock); + + /* + * Here, we need to had some wait code for the completion port + * thread. + */ + signal_iocompletionport_exit(manager); + manager->bShutdown = ISC_TRUE; + + /* + * Wait for threads to exit. + */ + for (i = 0; i < manager->maxIOCPThreads; i++) { + if (isc_thread_join((isc_thread_t) manager->hIOCPThreads[i], + NULL) != ISC_R_SUCCESS) + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_thread_join() for Completion Port %s", + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed")); + } + /* + * Clean up. + */ + + CloseHandle(manager->hIoCompletionPort); + + (void)isc_condition_destroy(&manager->shutdown_ok); + + DESTROYLOCK(&manager->lock); + if (manager->stats != NULL) + isc_stats_detach(&manager->stats); + manager->magic = 0; + mctx= manager->mctx; + isc_mem_put(mctx, manager, sizeof(*manager)); + + isc_mem_detach(&mctx); + + *managerp = NULL; +} + +static void +queue_receive_event(isc_socket_t *sock, isc_task_t *task, isc_socketevent_t *dev) +{ + isc_task_t *ntask = NULL; + + isc_task_attach(task, &ntask); + dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED; + + /* + * Enqueue the request. + */ + INSIST(!ISC_LINK_LINKED(dev, ev_link)); + ISC_LIST_ENQUEUE(sock->recv_list, dev, ev_link); + + socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0, + "queue_receive_event: event %p -> task %p", + dev, ntask); +} + +/* + * Check the pending receive queue, and if we have data pending, give it to this + * caller. If we have none, queue an I/O request. If this caller is not the first + * on the list, then we will just queue this event and return. + * + * Caller must have the socket locked. + */ +static isc_result_t +socket_recv(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task, + unsigned int flags) +{ + int cc = 0; + isc_task_t *ntask = NULL; + isc_result_t result = ISC_R_SUCCESS; + int recv_errno = 0; + + dev->ev_sender = task; + + if (sock->fd == INVALID_SOCKET) + return (ISC_R_EOF); + + /* + * Queue our event on the list of things to do. Call our function to + * attempt to fill buffers as much as possible, and return done events. + * We are going to lie about our handling of the ISC_SOCKFLAG_IMMEDIATE + * here and tell our caller that we could not satisfy it immediately. + */ + queue_receive_event(sock, task, dev); + if ((flags & ISC_SOCKFLAG_IMMEDIATE) != 0) + result = ISC_R_INPROGRESS; + + completeio_recv(sock); + + /* + * If there are more receivers waiting for data, queue another receive + * here. If the + */ + queue_receive_request(sock); + + return (result); +} + +isc_result_t +isc__socket_recvv(isc_socket_t *sock, isc_bufferlist_t *buflist, + unsigned int minimum, isc_task_t *task, + isc_taskaction_t action, const void *arg) +{ + isc_socketevent_t *dev; + isc_socketmgr_t *manager; + unsigned int iocount; + isc_buffer_t *buffer; + isc_result_t ret; + + REQUIRE(VALID_SOCKET(sock)); + LOCK(&sock->lock); + CONSISTENT(sock); + + /* + * Make sure that the socket is not closed. XXXMLG change error here? + */ + if (sock->fd == INVALID_SOCKET) { + UNLOCK(&sock->lock); + return (ISC_R_CONNREFUSED); + } + + REQUIRE(buflist != NULL); + REQUIRE(!ISC_LIST_EMPTY(*buflist)); + REQUIRE(task != NULL); + REQUIRE(action != NULL); + + manager = sock->manager; + REQUIRE(VALID_MANAGER(manager)); + + iocount = isc_bufferlist_availablecount(buflist); + REQUIRE(iocount > 0); + + INSIST(sock->bound); + + dev = allocate_socketevent(sock, ISC_SOCKEVENT_RECVDONE, action, arg); + if (dev == NULL) { + UNLOCK(&sock->lock); + return (ISC_R_NOMEMORY); + } + + /* + * UDP sockets are always partial read + */ + if (sock->type == isc_sockettype_udp) + dev->minimum = 1; + else { + if (minimum == 0) + dev->minimum = iocount; + else + dev->minimum = minimum; + } + + /* + * Move each buffer from the passed in list to our internal one. + */ + buffer = ISC_LIST_HEAD(*buflist); + while (buffer != NULL) { + ISC_LIST_DEQUEUE(*buflist, buffer, link); + ISC_LIST_ENQUEUE(dev->bufferlist, buffer, link); + buffer = ISC_LIST_HEAD(*buflist); + } + + ret = socket_recv(sock, dev, task, 0); + + UNLOCK(&sock->lock); + return (ret); +} + +isc_result_t +isc__socket_recv(isc_socket_t *sock, isc_region_t *region, + unsigned int minimum, isc_task_t *task, + isc_taskaction_t action, const void *arg) +{ + isc_socketevent_t *dev; + isc_socketmgr_t *manager; + isc_result_t ret; + + REQUIRE(VALID_SOCKET(sock)); + LOCK(&sock->lock); + CONSISTENT(sock); + + /* + * make sure that the socket's not closed + */ + if (sock->fd == INVALID_SOCKET) { + UNLOCK(&sock->lock); + return (ISC_R_CONNREFUSED); + } + REQUIRE(action != NULL); + + manager = sock->manager; + REQUIRE(VALID_MANAGER(manager)); + + INSIST(sock->bound); + + dev = allocate_socketevent(sock, ISC_SOCKEVENT_RECVDONE, action, arg); + if (dev == NULL) { + UNLOCK(&sock->lock); + return (ISC_R_NOMEMORY); + } + + ret = isc_socket_recv2(sock, region, minimum, task, dev, 0); + UNLOCK(&sock->lock); + return (ret); +} + +isc_result_t +isc__socket_recv2(isc_socket_t *sock, isc_region_t *region, + unsigned int minimum, isc_task_t *task, + isc_socketevent_t *event, unsigned int flags) +{ + isc_result_t ret; + + REQUIRE(VALID_SOCKET(sock)); + LOCK(&sock->lock); + CONSISTENT(sock); + + event->result = ISC_R_UNEXPECTED; + event->ev_sender = sock; + /* + * make sure that the socket's not closed + */ + if (sock->fd == INVALID_SOCKET) { + UNLOCK(&sock->lock); + return (ISC_R_CONNREFUSED); + } + + ISC_LIST_INIT(event->bufferlist); + event->region = *region; + event->n = 0; + event->offset = 0; + event->attributes = 0; + + /* + * UDP sockets are always partial read. + */ + if (sock->type == isc_sockettype_udp) + event->minimum = 1; + else { + if (minimum == 0) + event->minimum = region->length; + else + event->minimum = minimum; + } + + ret = socket_recv(sock, event, task, flags); + UNLOCK(&sock->lock); + return (ret); +} + +/* + * Caller must have the socket locked. + */ +static isc_result_t +socket_send(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task, + isc_sockaddr_t *address, struct in6_pktinfo *pktinfo, + unsigned int flags) +{ + int io_state; + int send_errno = 0; + int cc = 0; + isc_task_t *ntask = NULL; + isc_result_t result = ISC_R_SUCCESS; + + dev->ev_sender = task; + + set_dev_address(address, sock, dev); + if (pktinfo != NULL) { + socket_log(__LINE__, sock, NULL, TRACE, isc_msgcat, ISC_MSGSET_SOCKET, + ISC_MSG_PKTINFOPROVIDED, + "pktinfo structure provided, ifindex %u (set to 0)", + pktinfo->ipi6_ifindex); + + dev->attributes |= ISC_SOCKEVENTATTR_PKTINFO; + dev->pktinfo = *pktinfo; + /* + * Set the pktinfo index to 0 here, to let the kernel decide + * what interface it should send on. + */ + dev->pktinfo.ipi6_ifindex = 0; + } + + io_state = startio_send(sock, dev, &cc, &send_errno); + switch (io_state) { + case DOIO_PENDING: /* I/O started. Nothing more to do */ + case DOIO_SOFT: + /* + * We couldn't send all or part of the request right now, so + * queue it unless ISC_SOCKFLAG_NORETRY is set. + */ + if ((flags & ISC_SOCKFLAG_NORETRY) == 0) { + isc_task_attach(task, &ntask); + dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED; + + /* + * Enqueue the request. + */ + INSIST(!ISC_LINK_LINKED(dev, ev_link)); + ISC_LIST_ENQUEUE(sock->send_list, dev, ev_link); + + socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0, + "socket_send: event %p -> task %p", + dev, ntask); + + if ((flags & ISC_SOCKFLAG_IMMEDIATE) != 0) + result = ISC_R_INPROGRESS; + break; + } + + case DOIO_SUCCESS: + break; + } + + return (result); +} + +isc_result_t +isc__socket_send(isc_socket_t *sock, isc_region_t *region, + isc_task_t *task, isc_taskaction_t action, const void *arg) +{ + /* + * REQUIRE() checking is performed in isc_socket_sendto(). + */ + return (isc_socket_sendto(sock, region, task, action, arg, NULL, + NULL)); +} + +isc_result_t +isc__socket_sendto(isc_socket_t *sock, isc_region_t *region, + isc_task_t *task, isc_taskaction_t action, const void *arg, + isc_sockaddr_t *address, struct in6_pktinfo *pktinfo) +{ + isc_socketevent_t *dev; + isc_socketmgr_t *manager; + isc_result_t ret; + + REQUIRE(VALID_SOCKET(sock)); + REQUIRE(sock->type != isc_sockettype_fdwatch); + + LOCK(&sock->lock); + CONSISTENT(sock); + + /* + * make sure that the socket's not closed + */ + if (sock->fd == INVALID_SOCKET) { + UNLOCK(&sock->lock); + return (ISC_R_CONNREFUSED); + } + REQUIRE(region != NULL); + REQUIRE(task != NULL); + REQUIRE(action != NULL); + + manager = sock->manager; + REQUIRE(VALID_MANAGER(manager)); + + INSIST(sock->bound); + + dev = allocate_socketevent(sock, ISC_SOCKEVENT_SENDDONE, action, arg); + if (dev == NULL) { + UNLOCK(&sock->lock); + return (ISC_R_NOMEMORY); + } + dev->region = *region; + + ret = socket_send(sock, dev, task, address, pktinfo, 0); + UNLOCK(&sock->lock); + return (ret); +} + +isc_result_t +isc__socket_sendv(isc_socket_t *sock, isc_bufferlist_t *buflist, + isc_task_t *task, isc_taskaction_t action, const void *arg) +{ + return (isc_socket_sendtov(sock, buflist, task, action, arg, NULL, + NULL)); +} + +isc_result_t +isc__socket_sendtov(isc_socket_t *sock, isc_bufferlist_t *buflist, + isc_task_t *task, isc_taskaction_t action, const void *arg, + isc_sockaddr_t *address, struct in6_pktinfo *pktinfo) +{ + isc_socketevent_t *dev; + isc_socketmgr_t *manager; + unsigned int iocount; + isc_buffer_t *buffer; + isc_result_t ret; + + REQUIRE(VALID_SOCKET(sock)); + + LOCK(&sock->lock); + CONSISTENT(sock); + + /* + * make sure that the socket's not closed + */ + if (sock->fd == INVALID_SOCKET) { + UNLOCK(&sock->lock); + return (ISC_R_CONNREFUSED); + } + REQUIRE(buflist != NULL); + REQUIRE(!ISC_LIST_EMPTY(*buflist)); + REQUIRE(task != NULL); + REQUIRE(action != NULL); + + manager = sock->manager; + REQUIRE(VALID_MANAGER(manager)); + + iocount = isc_bufferlist_usedcount(buflist); + REQUIRE(iocount > 0); + + dev = allocate_socketevent(sock, ISC_SOCKEVENT_SENDDONE, action, arg); + if (dev == NULL) { + UNLOCK(&sock->lock); + return (ISC_R_NOMEMORY); + } + + /* + * Move each buffer from the passed in list to our internal one. + */ + buffer = ISC_LIST_HEAD(*buflist); + while (buffer != NULL) { + ISC_LIST_DEQUEUE(*buflist, buffer, link); + ISC_LIST_ENQUEUE(dev->bufferlist, buffer, link); + buffer = ISC_LIST_HEAD(*buflist); + } + + ret = socket_send(sock, dev, task, address, pktinfo, 0); + UNLOCK(&sock->lock); + return (ret); +} + +isc_result_t +isc__socket_sendto2(isc_socket_t *sock, isc_region_t *region, + isc_task_t *task, + isc_sockaddr_t *address, struct in6_pktinfo *pktinfo, + isc_socketevent_t *event, unsigned int flags) +{ + isc_result_t ret; + + REQUIRE(VALID_SOCKET(sock)); + LOCK(&sock->lock); + CONSISTENT(sock); + + REQUIRE((flags & ~(ISC_SOCKFLAG_IMMEDIATE|ISC_SOCKFLAG_NORETRY)) == 0); + if ((flags & ISC_SOCKFLAG_NORETRY) != 0) + REQUIRE(sock->type == isc_sockettype_udp); + event->ev_sender = sock; + event->result = ISC_R_UNEXPECTED; + /* + * make sure that the socket's not closed + */ + if (sock->fd == INVALID_SOCKET) { + UNLOCK(&sock->lock); + return (ISC_R_CONNREFUSED); + } + ISC_LIST_INIT(event->bufferlist); + event->region = *region; + event->n = 0; + event->offset = 0; + event->attributes = 0; + + ret = socket_send(sock, event, task, address, pktinfo, flags); + UNLOCK(&sock->lock); + return (ret); +} + +isc_result_t +isc__socket_bind(isc_socket_t *sock, isc_sockaddr_t *sockaddr, + unsigned int options) { + int bind_errno; + char strbuf[ISC_STRERRORSIZE]; + int on = 1; + + REQUIRE(VALID_SOCKET(sock)); + LOCK(&sock->lock); + CONSISTENT(sock); + + /* + * make sure that the socket's not closed + */ + if (sock->fd == INVALID_SOCKET) { + UNLOCK(&sock->lock); + return (ISC_R_CONNREFUSED); + } + + INSIST(!sock->bound); + INSIST(!sock->dupped); + + if (sock->pf != sockaddr->type.sa.sa_family) { + UNLOCK(&sock->lock); + return (ISC_R_FAMILYMISMATCH); + } + /* + * Only set SO_REUSEADDR when we want a specific port. + */ + if ((options & ISC_SOCKET_REUSEADDRESS) != 0 && + isc_sockaddr_getport(sockaddr) != (in_port_t)0 && + setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, + sizeof(on)) < 0) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "setsockopt(%d) %s", sock->fd, + isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, "failed")); + /* Press on... */ + } + if (bind(sock->fd, &sockaddr->type.sa, sockaddr->length) < 0) { + bind_errno = WSAGetLastError(); + UNLOCK(&sock->lock); + switch (bind_errno) { + case WSAEACCES: + return (ISC_R_NOPERM); + case WSAEADDRNOTAVAIL: + return (ISC_R_ADDRNOTAVAIL); + case WSAEADDRINUSE: + return (ISC_R_ADDRINUSE); + case WSAEINVAL: + return (ISC_R_BOUND); + default: + isc__strerror(bind_errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, "bind: %s", + strbuf); + return (ISC_R_UNEXPECTED); + } + } + + socket_log(__LINE__, sock, sockaddr, TRACE, + isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_BOUND, "bound"); + sock->bound = 1; + + UNLOCK(&sock->lock); + return (ISC_R_SUCCESS); +} + +isc_result_t +isc__socket_filter(isc_socket_t *sock, const char *filter) { + UNUSED(sock); + UNUSED(filter); + + REQUIRE(VALID_SOCKET(sock)); + return (ISC_R_NOTIMPLEMENTED); +} + +/* + * Set up to listen on a given socket. We do this by creating an internal + * event that will be dispatched when the socket has read activity. The + * watcher will send the internal event to the task when there is a new + * connection. + * + * Unlike in read, we don't preallocate a done event here. Every time there + * is a new connection we'll have to allocate a new one anyway, so we might + * as well keep things simple rather than having to track them. + */ +isc_result_t +isc__socket_listen(isc_socket_t *sock, unsigned int backlog) { + char strbuf[ISC_STRERRORSIZE]; + + REQUIRE(VALID_SOCKET(sock)); + + LOCK(&sock->lock); + CONSISTENT(sock); + + /* + * make sure that the socket's not closed + */ + if (sock->fd == INVALID_SOCKET) { + UNLOCK(&sock->lock); + return (ISC_R_CONNREFUSED); + } + + REQUIRE(!sock->listener); + REQUIRE(sock->bound); + REQUIRE(sock->type == isc_sockettype_tcp); + + if (backlog == 0) + backlog = SOMAXCONN; + + if (listen(sock->fd, (int)backlog) < 0) { + UNLOCK(&sock->lock); + isc__strerror(WSAGetLastError(), strbuf, sizeof(strbuf)); + + UNEXPECTED_ERROR(__FILE__, __LINE__, "listen: %s", strbuf); + + return (ISC_R_UNEXPECTED); + } + + socket_log(__LINE__, sock, NULL, TRACE, + isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_BOUND, "listening"); + sock->listener = 1; + _set_state(sock, SOCK_LISTEN); + + UNLOCK(&sock->lock); + return (ISC_R_SUCCESS); +} + +/* + * This should try to do aggressive accept() XXXMLG + */ +isc_result_t +isc__socket_accept(isc_socket_t *sock, + isc_task_t *task, isc_taskaction_t action, const void *arg) +{ + isc_socket_newconnev_t *adev; + isc_socketmgr_t *manager; + isc_task_t *ntask = NULL; + isc_socket_t *nsock; + isc_result_t result; + IoCompletionInfo *lpo; + + REQUIRE(VALID_SOCKET(sock)); + + manager = sock->manager; + REQUIRE(VALID_MANAGER(manager)); + + LOCK(&sock->lock); + CONSISTENT(sock); + + /* + * make sure that the socket's not closed + */ + if (sock->fd == INVALID_SOCKET) { + UNLOCK(&sock->lock); + return (ISC_R_CONNREFUSED); + } + + REQUIRE(sock->listener); + + /* + * Sender field is overloaded here with the task we will be sending + * this event to. Just before the actual event is delivered the + * actual ev_sender will be touched up to be the socket. + */ + adev = (isc_socket_newconnev_t *) + isc_event_allocate(manager->mctx, task, ISC_SOCKEVENT_NEWCONN, + action, arg, sizeof(*adev)); + if (adev == NULL) { + UNLOCK(&sock->lock); + return (ISC_R_NOMEMORY); + } + ISC_LINK_INIT(adev, ev_link); + + result = allocate_socket(manager, sock->type, &nsock); + if (result != ISC_R_SUCCESS) { + isc_event_free((isc_event_t **)&adev); + UNLOCK(&sock->lock); + return (result); + } + + /* + * AcceptEx() requires we pass in a socket. + */ + nsock->fd = socket(sock->pf, SOCK_STREAM, IPPROTO_TCP); + if (nsock->fd == INVALID_SOCKET) { + free_socket(&nsock, __LINE__); + isc_event_free((isc_event_t **)&adev); + UNLOCK(&sock->lock); + return (ISC_R_FAILURE); // XXXMLG need real error message + } + + /* + * Attach to socket and to task. + */ + isc_task_attach(task, &ntask); + if (isc_task_exiting(ntask)) { + free_socket(&nsock, __LINE__); + isc_task_detach(&ntask); + isc_event_free(ISC_EVENT_PTR(&adev)); + UNLOCK(&sock->lock); + return (ISC_R_SHUTTINGDOWN); + } + nsock->references++; + + adev->ev_sender = ntask; + adev->newsocket = nsock; + _set_state(nsock, SOCK_ACCEPT); + + /* + * Queue io completion for an accept(). + */ + lpo = (IoCompletionInfo *)HeapAlloc(hHeapHandle, + HEAP_ZERO_MEMORY, + sizeof(IoCompletionInfo)); + RUNTIME_CHECK(lpo != NULL); + lpo->acceptbuffer = (void *)HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY, + (sizeof(SOCKADDR_STORAGE) + 16) * 2); + RUNTIME_CHECK(lpo->acceptbuffer != NULL); + + lpo->adev = adev; + lpo->request_type = SOCKET_ACCEPT; + + ISCAcceptEx(sock->fd, + nsock->fd, /* Accepted Socket */ + lpo->acceptbuffer, /* Buffer for initial Recv */ + 0, /* Length of Buffer */ + sizeof(SOCKADDR_STORAGE) + 16, /* Local address length + 16 */ + sizeof(SOCKADDR_STORAGE) + 16, /* Remote address lengh + 16 */ + (LPDWORD)&lpo->received_bytes, /* Bytes Recved */ + (LPOVERLAPPED)lpo /* Overlapped structure */ + ); + iocompletionport_update(nsock); + + socket_log(__LINE__, sock, NULL, TRACE, + isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_BOUND, + "accepting for nsock %p fd %d", nsock, nsock->fd); + + /* + * Enqueue the event + */ + ISC_LIST_ENQUEUE(sock->accept_list, adev, ev_link); + sock->pending_accept++; + sock->pending_iocp++; + + UNLOCK(&sock->lock); + return (ISC_R_SUCCESS); +} + +isc_result_t +isc__socket_connect(isc_socket_t *sock, isc_sockaddr_t *addr, + isc_task_t *task, isc_taskaction_t action, const void *arg) +{ + char strbuf[ISC_STRERRORSIZE]; + isc_socket_connev_t *cdev; + isc_task_t *ntask = NULL; + isc_socketmgr_t *manager; + IoCompletionInfo *lpo; + int bind_errno; + + REQUIRE(VALID_SOCKET(sock)); + REQUIRE(addr != NULL); + REQUIRE(task != NULL); + REQUIRE(action != NULL); + + manager = sock->manager; + REQUIRE(VALID_MANAGER(manager)); + REQUIRE(addr != NULL); + + if (isc_sockaddr_ismulticast(addr)) + return (ISC_R_MULTICAST); + + LOCK(&sock->lock); + CONSISTENT(sock); + + /* + * make sure that the socket's not closed + */ + if (sock->fd == INVALID_SOCKET) { + UNLOCK(&sock->lock); + return (ISC_R_CONNREFUSED); + } + + /* + * Windows sockets won't connect unless the socket is bound. + */ + if (!sock->bound) { + isc_sockaddr_t any; + + isc_sockaddr_anyofpf(&any, isc_sockaddr_pf(addr)); + if (bind(sock->fd, &any.type.sa, any.length) < 0) { + bind_errno = WSAGetLastError(); + UNLOCK(&sock->lock); + switch (bind_errno) { + case WSAEACCES: + return (ISC_R_NOPERM); + case WSAEADDRNOTAVAIL: + return (ISC_R_ADDRNOTAVAIL); + case WSAEADDRINUSE: + return (ISC_R_ADDRINUSE); + case WSAEINVAL: + return (ISC_R_BOUND); + default: + isc__strerror(bind_errno, strbuf, + sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "bind: %s", strbuf); + return (ISC_R_UNEXPECTED); + } + } + sock->bound = 1; + } + + REQUIRE(!sock->pending_connect); + + cdev = (isc_socket_connev_t *)isc_event_allocate(manager->mctx, sock, + ISC_SOCKEVENT_CONNECT, + action, arg, + sizeof(*cdev)); + if (cdev == NULL) { + UNLOCK(&sock->lock); + return (ISC_R_NOMEMORY); + } + ISC_LINK_INIT(cdev, ev_link); + + if (sock->type == isc_sockettype_tcp) { + /* + * Queue io completion for an accept(). + */ + lpo = (IoCompletionInfo *)HeapAlloc(hHeapHandle, + HEAP_ZERO_MEMORY, + sizeof(IoCompletionInfo)); + lpo->cdev = cdev; + lpo->request_type = SOCKET_CONNECT; + + sock->address = *addr; + ISCConnectEx(sock->fd, &addr->type.sa, addr->length, + NULL, 0, NULL, (LPOVERLAPPED)lpo); + + /* + * Attach to task. + */ + isc_task_attach(task, &ntask); + cdev->ev_sender = ntask; + + sock->pending_connect = 1; + _set_state(sock, SOCK_CONNECT); + + /* + * Enqueue the request. + */ + sock->connect_ev = cdev; + sock->pending_iocp++; + } else { + WSAConnect(sock->fd, &addr->type.sa, addr->length, NULL, NULL, NULL, NULL); + cdev->result = ISC_R_SUCCESS; + isc_task_send(task, (isc_event_t **)&cdev); + } + CONSISTENT(sock); + UNLOCK(&sock->lock); + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc__socket_getpeername(isc_socket_t *sock, isc_sockaddr_t *addressp) { + isc_result_t result; + + REQUIRE(VALID_SOCKET(sock)); + REQUIRE(addressp != NULL); + + LOCK(&sock->lock); + CONSISTENT(sock); + + /* + * make sure that the socket's not closed + */ + if (sock->fd == INVALID_SOCKET) { + UNLOCK(&sock->lock); + return (ISC_R_CONNREFUSED); + } + + if (sock->connected) { + *addressp = sock->address; + result = ISC_R_SUCCESS; + } else { + result = ISC_R_NOTCONNECTED; + } + + UNLOCK(&sock->lock); + + return (result); +} + +isc_result_t +isc__socket_getsockname(isc_socket_t *sock, isc_sockaddr_t *addressp) { + ISC_SOCKADDR_LEN_T len; + isc_result_t result; + char strbuf[ISC_STRERRORSIZE]; + + REQUIRE(VALID_SOCKET(sock)); + REQUIRE(addressp != NULL); + + LOCK(&sock->lock); + CONSISTENT(sock); + + /* + * make sure that the socket's not closed + */ + if (sock->fd == INVALID_SOCKET) { + UNLOCK(&sock->lock); + return (ISC_R_CONNREFUSED); + } + + if (!sock->bound) { + result = ISC_R_NOTBOUND; + goto out; + } + + result = ISC_R_SUCCESS; + + len = sizeof(addressp->type); + if (getsockname(sock->fd, &addressp->type.sa, (void *)&len) < 0) { + isc__strerror(WSAGetLastError(), strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, "getsockname: %s", + strbuf); + result = ISC_R_UNEXPECTED; + goto out; + } + addressp->length = (unsigned int)len; + + out: + UNLOCK(&sock->lock); + + return (result); +} + +/* + * Run through the list of events on this socket, and cancel the ones + * queued for task "task" of type "how". "how" is a bitmask. + */ +void +isc__socket_cancel(isc_socket_t *sock, isc_task_t *task, unsigned int how) { + + REQUIRE(VALID_SOCKET(sock)); + + /* + * Quick exit if there is nothing to do. Don't even bother locking + * in this case. + */ + if (how == 0) + return; + + LOCK(&sock->lock); + CONSISTENT(sock); + + /* + * make sure that the socket's not closed + */ + if (sock->fd == INVALID_SOCKET) { + UNLOCK(&sock->lock); + return; + } + + /* + * All of these do the same thing, more or less. + * Each will: + * o If the internal event is marked as "posted" try to + * remove it from the task's queue. If this fails, mark it + * as canceled instead, and let the task clean it up later. + * o For each I/O request for that task of that type, post + * its done event with status of "ISC_R_CANCELED". + * o Reset any state needed. + */ + + if ((how & ISC_SOCKCANCEL_RECV) == ISC_SOCKCANCEL_RECV) { + isc_socketevent_t *dev; + isc_socketevent_t *next; + isc_task_t *current_task; + + dev = ISC_LIST_HEAD(sock->recv_list); + while (dev != NULL) { + current_task = dev->ev_sender; + next = ISC_LIST_NEXT(dev, ev_link); + if ((task == NULL) || (task == current_task)) { + dev->result = ISC_R_CANCELED; + send_recvdone_event(sock, &dev); + } + dev = next; + } + } + how &= ~ISC_SOCKCANCEL_RECV; + + if ((how & ISC_SOCKCANCEL_SEND) == ISC_SOCKCANCEL_SEND) { + isc_socketevent_t *dev; + isc_socketevent_t *next; + isc_task_t *current_task; + + dev = ISC_LIST_HEAD(sock->send_list); + + while (dev != NULL) { + current_task = dev->ev_sender; + next = ISC_LIST_NEXT(dev, ev_link); + if ((task == NULL) || (task == current_task)) { + dev->result = ISC_R_CANCELED; + send_senddone_event(sock, &dev); + } + dev = next; + } + } + how &= ~ISC_SOCKCANCEL_SEND; + + if (((how & ISC_SOCKCANCEL_ACCEPT) == ISC_SOCKCANCEL_ACCEPT) + && !ISC_LIST_EMPTY(sock->accept_list)) { + isc_socket_newconnev_t *dev; + isc_socket_newconnev_t *next; + isc_task_t *current_task; + + dev = ISC_LIST_HEAD(sock->accept_list); + while (dev != NULL) { + current_task = dev->ev_sender; + next = ISC_LIST_NEXT(dev, ev_link); + + if ((task == NULL) || (task == current_task)) { + + dev->newsocket->references--; + closesocket(dev->newsocket->fd); + dev->newsocket->fd = INVALID_SOCKET; + free_socket(&dev->newsocket, __LINE__); + + dev->result = ISC_R_CANCELED; + send_acceptdone_event(sock, &dev); + } + + dev = next; + } + } + how &= ~ISC_SOCKCANCEL_ACCEPT; + + /* + * Connecting is not a list. + */ + if (((how & ISC_SOCKCANCEL_CONNECT) == ISC_SOCKCANCEL_CONNECT) + && sock->connect_ev != NULL) { + isc_socket_connev_t *dev; + isc_task_t *current_task; + + INSIST(sock->pending_connect); + + dev = sock->connect_ev; + current_task = dev->ev_sender; + + if ((task == NULL) || (task == current_task)) { + closesocket(sock->fd); + sock->fd = INVALID_SOCKET; + _set_state(sock, SOCK_CLOSED); + + sock->connect_ev = NULL; + dev->result = ISC_R_CANCELED; + send_connectdone_event(sock, &dev); + } + } + how &= ~ISC_SOCKCANCEL_CONNECT; + + maybe_free_socket(&sock, __LINE__); +} + +isc_sockettype_t +isc__socket_gettype(isc_socket_t *sock) { + isc_sockettype_t type; + + REQUIRE(VALID_SOCKET(sock)); + + LOCK(&sock->lock); + + /* + * make sure that the socket's not closed + */ + if (sock->fd == INVALID_SOCKET) { + UNLOCK(&sock->lock); + return (ISC_R_CONNREFUSED); + } + + type = sock->type; + UNLOCK(&sock->lock); + return (type); +} + +isc_boolean_t +isc__socket_isbound(isc_socket_t *sock) { + isc_boolean_t val; + + REQUIRE(VALID_SOCKET(sock)); + + LOCK(&sock->lock); + CONSISTENT(sock); + + /* + * make sure that the socket's not closed + */ + if (sock->fd == INVALID_SOCKET) { + UNLOCK(&sock->lock); + return (ISC_FALSE); + } + + val = ((sock->bound) ? ISC_TRUE : ISC_FALSE); + UNLOCK(&sock->lock); + + return (val); +} + +void +isc__socket_ipv6only(isc_socket_t *sock, isc_boolean_t yes) { +#if defined(IPV6_V6ONLY) + int onoff = yes ? 1 : 0; +#else + UNUSED(yes); +#endif + + REQUIRE(VALID_SOCKET(sock)); + +#ifdef IPV6_V6ONLY + if (sock->pf == AF_INET6) { + (void)setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, + (char *)&onoff, sizeof(onoff)); + } +#endif +} + +void +isc__socket_cleanunix(isc_sockaddr_t *addr, isc_boolean_t active) { + UNUSED(addr); + UNUSED(active); +} + +isc_result_t +isc__socket_permunix(isc_sockaddr_t *addr, isc_uint32_t perm, + isc_uint32_t owner, isc_uint32_t group) +{ + UNUSED(addr); + UNUSED(perm); + UNUSED(owner); + UNUSED(group); + return (ISC_R_NOTIMPLEMENTED); +} + +void +isc__socket_setname(isc_socket_t *socket, const char *name, void *tag) { + + /* + * Name 'socket'. + */ + + REQUIRE(VALID_SOCKET(socket)); + + LOCK(&socket->lock); + memset(socket->name, 0, sizeof(socket->name)); + strncpy(socket->name, name, sizeof(socket->name) - 1); + socket->tag = tag; + UNLOCK(&socket->lock); +} + +const char * +isc__socket_getname(isc_socket_t *socket) { + return (socket->name); +} + +void * +isc__socket_gettag(isc_socket_t *socket) { + return (socket->tag); +} + +int +isc__socket_getfd(isc_socket_t *socket) { + return ((short) socket->fd); +} + +void +isc__socketmgr_setreserved(isc_socketmgr_t *manager, isc_uint32_t reserved) { + UNUSED(manager); + UNUSED(reserved); +} + +void +isc___socketmgr_maxudp(isc_socketmgr_t *manager, int maxudp) { + + UNUSED(manager); + UNUSED(maxudp); +} + +#ifdef HAVE_LIBXML2 + +static const char * +_socktype(isc_sockettype_t type) +{ + if (type == isc_sockettype_udp) + return ("udp"); + else if (type == isc_sockettype_tcp) + return ("tcp"); + else if (type == isc_sockettype_unix) + return ("unix"); + else if (type == isc_sockettype_fdwatch) + return ("fdwatch"); + else + return ("not-initialized"); +} + +void +isc_socketmgr_renderxml(isc_socketmgr_t *mgr, xmlTextWriterPtr writer) +{ + isc_socket_t *sock; + char peerbuf[ISC_SOCKADDR_FORMATSIZE]; + isc_sockaddr_t addr; + ISC_SOCKADDR_LEN_T len; + + LOCK(&mgr->lock); + +#ifndef ISC_PLATFORM_USETHREADS + xmlTextWriterStartElement(writer, ISC_XMLCHAR "references"); + xmlTextWriterWriteFormatString(writer, "%d", mgr->refs); + xmlTextWriterEndElement(writer); +#endif + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "sockets"); + sock = ISC_LIST_HEAD(mgr->socklist); + while (sock != NULL) { + LOCK(&sock->lock); + xmlTextWriterStartElement(writer, ISC_XMLCHAR "socket"); + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "id"); + xmlTextWriterWriteFormatString(writer, "%p", sock); + xmlTextWriterEndElement(writer); + + if (sock->name[0] != 0) { + xmlTextWriterStartElement(writer, ISC_XMLCHAR "name"); + xmlTextWriterWriteFormatString(writer, "%s", + sock->name); + xmlTextWriterEndElement(writer); /* name */ + } + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "references"); + xmlTextWriterWriteFormatString(writer, "%d", sock->references); + xmlTextWriterEndElement(writer); + + xmlTextWriterWriteElement(writer, ISC_XMLCHAR "type", + ISC_XMLCHAR _socktype(sock->type)); + + if (sock->connected) { + isc_sockaddr_format(&sock->address, peerbuf, + sizeof(peerbuf)); + xmlTextWriterWriteElement(writer, + ISC_XMLCHAR "peer-address", + ISC_XMLCHAR peerbuf); + } + + len = sizeof(addr); + if (getsockname(sock->fd, &addr.type.sa, (void *)&len) == 0) { + isc_sockaddr_format(&addr, peerbuf, sizeof(peerbuf)); + xmlTextWriterWriteElement(writer, + ISC_XMLCHAR "local-address", + ISC_XMLCHAR peerbuf); + } + + xmlTextWriterStartElement(writer, ISC_XMLCHAR "states"); + if (sock->pending_recv) + xmlTextWriterWriteElement(writer, ISC_XMLCHAR "state", + ISC_XMLCHAR "pending-receive"); + if (sock->pending_send) + xmlTextWriterWriteElement(writer, ISC_XMLCHAR "state", + ISC_XMLCHAR "pending-send"); + if (sock->pending_accept) + xmlTextWriterWriteElement(writer, ISC_XMLCHAR "state", + ISC_XMLCHAR "pending_accept"); + if (sock->listener) + xmlTextWriterWriteElement(writer, ISC_XMLCHAR "state", + ISC_XMLCHAR "listener"); + if (sock->connected) + xmlTextWriterWriteElement(writer, ISC_XMLCHAR "state", + ISC_XMLCHAR "connected"); + if (sock->pending_connect) + xmlTextWriterWriteElement(writer, ISC_XMLCHAR "state", + ISC_XMLCHAR "connecting"); + if (sock->bound) + xmlTextWriterWriteElement(writer, ISC_XMLCHAR "state", + ISC_XMLCHAR "bound"); + + xmlTextWriterEndElement(writer); /* states */ + + xmlTextWriterEndElement(writer); /* socket */ + + UNLOCK(&sock->lock); + sock = ISC_LIST_NEXT(sock, link); + } + xmlTextWriterEndElement(writer); /* sockets */ + + UNLOCK(&mgr->lock); +} +#endif /* HAVE_LIBXML2 */ diff --git a/contrib/ntp/lib/isc/win32/stdio.c b/contrib/ntp/lib/isc/win32/stdio.c new file mode 100644 index 0000000..427a8e1 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/stdio.c @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: stdio.c,v 1.6 2007/06/19 23:47:19 tbox Exp $ */ + +#include <config.h> + +#include <io.h> +#include <errno.h> + +#include <isc/stdio.h> + +#include "errno2result.h" + +isc_result_t +isc_stdio_open(const char *filename, const char *mode, FILE **fp) { + FILE *f; + + f = fopen(filename, mode); + if (f == NULL) + return (isc__errno2result(errno)); + *fp = f; + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_stdio_close(FILE *f) { + int r; + + r = fclose(f); + if (r == 0) + return (ISC_R_SUCCESS); + else + return (isc__errno2result(errno)); +} + +isc_result_t +isc_stdio_seek(FILE *f, long offset, int whence) { + int r; + + r = fseek(f, offset, whence); + if (r == 0) + return (ISC_R_SUCCESS); + else + return (isc__errno2result(errno)); +} + +isc_result_t +isc_stdio_read(void *ptr, size_t size, size_t nmemb, FILE *f, size_t *nret) { + isc_result_t result = ISC_R_SUCCESS; + size_t r; + + clearerr(f); + r = fread(ptr, size, nmemb, f); + if (r != nmemb) { + if (feof(f)) + result = ISC_R_EOF; + else + result = isc__errno2result(errno); + } + if (nret != NULL) + *nret = r; + return (result); +} + +isc_result_t +isc_stdio_write(const void *ptr, size_t size, size_t nmemb, FILE *f, + size_t *nret) +{ + isc_result_t result = ISC_R_SUCCESS; + size_t r; + + clearerr(f); + r = fwrite(ptr, size, nmemb, f); + if (r != nmemb) + result = isc__errno2result(errno); + if (nret != NULL) + *nret = r; + return (result); +} + +isc_result_t +isc_stdio_flush(FILE *f) { + int r; + + r = fflush(f); + if (r == 0) + return (ISC_R_SUCCESS); + else + return (isc__errno2result(errno)); +} + +isc_result_t +isc_stdio_sync(FILE *f) { + int r; + + r = _commit(_fileno(f)); + if (r == 0) + return (ISC_R_SUCCESS); + else + return (isc__errno2result(errno)); +} + diff --git a/contrib/ntp/lib/isc/win32/stdtime.c b/contrib/ntp/lib/isc/win32/stdtime.c new file mode 100644 index 0000000..ca46251 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/stdtime.c @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: stdtime.c,v 1.12 2007/06/19 23:47:19 tbox Exp $ */ + +#include <config.h> + +#include <time.h> + +#include <isc/assertions.h> +#include <isc/stdtime.h> +#include <isc/util.h> + +void +isc_stdtime_get(isc_stdtime_t *t) { + /* + * Set 't' to the number of seconds past 00:00:00 UTC, January 1, 1970. + */ + + REQUIRE(t != NULL); + + (void)time((time_t *)t); +} diff --git a/contrib/ntp/lib/isc/win32/strerror.c b/contrib/ntp/lib/isc/win32/strerror.c new file mode 100644 index 0000000..4174332 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/strerror.c @@ -0,0 +1,459 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001, 2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: strerror.c,v 1.8 2007/06/19 23:47:19 tbox Exp $ */ + +#include <config.h> + +#include <stdio.h> +#include <string.h> +#include <winsock2.h> + +#include <isc/mutex.h> +#include <isc/once.h> +#include <isc/print.h> +#include <isc/strerror.h> +#include <isc/util.h> + +/* + * Forward declarations + */ + +char * +FormatError(int error); + +char * +GetWSAErrorMessage(int errval); + +char * +NTstrerror(int err, BOOL *bfreebuf); + +/* + * We need to do this this way for profiled locks. + */ + +static isc_mutex_t isc_strerror_lock; +static void init_lock(void) { + RUNTIME_CHECK(isc_mutex_init(&isc_strerror_lock) == ISC_R_SUCCESS); +} + +/* + * This routine needs to free up any buffer allocated by FormatMessage + * if that routine gets used. + */ + +void +isc__strerror(int num, char *buf, size_t size) { + char *msg; + BOOL freebuf; + unsigned int unum = num; + static isc_once_t once = ISC_ONCE_INIT; + + REQUIRE(buf != NULL); + + RUNTIME_CHECK(isc_once_do(&once, init_lock) == ISC_R_SUCCESS); + + LOCK(&isc_strerror_lock); + freebuf = FALSE; + msg = NTstrerror(num, &freebuf); + if (msg != NULL) + snprintf(buf, size, "%s", msg); + else + snprintf(buf, size, "Unknown error: %u", unum); + if(freebuf && msg != NULL) { + LocalFree(msg); + } + UNLOCK(&isc_strerror_lock); +} + +/* + * Note this will cause a memory leak unless the memory allocated here + * is freed by calling LocalFree. isc__strerror does this before unlocking. + * This only gets called if there is a system type of error and will likely + * be an unusual event. + */ +char * +FormatError(int error) { + LPVOID lpMsgBuf = NULL; + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + error, + /* Default language */ + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, + 0, + NULL); + + return (lpMsgBuf); +} + +/* + * This routine checks the error value and calls the WSA Windows Sockets + * Error message function GetWSAErrorMessage below if it's within that range + * since those messages are not available in the system error messages. + */ +char * +NTstrerror(int err, BOOL *bfreebuf) { + char *retmsg = NULL; + + /* Copy the error value first in case of other errors */ + DWORD errval = err; + + *bfreebuf = FALSE; + + /* Get the Winsock2 error messages */ + if (errval >= WSABASEERR && errval <= (WSABASEERR + 1015)) { + retmsg = GetWSAErrorMessage(errval); + if (retmsg != NULL) + return (retmsg); + } + /* + * If it's not one of the standard Unix error codes, + * try a system error message + */ + if (errval > (DWORD) _sys_nerr) { + *bfreebuf = TRUE; + return (FormatError(errval)); + } else { + return (strerror(errval)); + } +} + +/* + * This is a replacement for perror + */ +void __cdecl +NTperror(char *errmsg) { + /* Copy the error value first in case of other errors */ + int errval = errno; + BOOL bfreebuf = FALSE; + char *msg; + + msg = NTstrerror(errval, &bfreebuf); + fprintf(stderr, "%s: %s\n", errmsg, msg); + if(bfreebuf == TRUE) { + LocalFree(msg); + } + +} + +/* + * Return the error string related to Winsock2 errors. + * This function is necessary since FormatMessage knows nothing about them + * and there is no function to get them. + */ +char * +GetWSAErrorMessage(int errval) { + char *msg; + + switch (errval) { + + case WSAEINTR: + msg = "Interrupted system call"; + break; + + case WSAEBADF: + msg = "Bad file number"; + break; + + case WSAEACCES: + msg = "Permission denied"; + break; + + case WSAEFAULT: + msg = "Bad address"; + break; + + case WSAEINVAL: + msg = "Invalid argument"; + break; + + case WSAEMFILE: + msg = "Too many open sockets"; + break; + + case WSAEWOULDBLOCK: + msg = "Operation would block"; + break; + + case WSAEINPROGRESS: + msg = "Operation now in progress"; + break; + + case WSAEALREADY: + msg = "Operation already in progress"; + break; + + case WSAENOTSOCK: + msg = "Socket operation on non-socket"; + break; + + case WSAEDESTADDRREQ: + msg = "Destination address required"; + break; + + case WSAEMSGSIZE: + msg = "Message too long"; + break; + + case WSAEPROTOTYPE: + msg = "Protocol wrong type for socket"; + break; + + case WSAENOPROTOOPT: + msg = "Bad protocol option"; + break; + + case WSAEPROTONOSUPPORT: + msg = "Protocol not supported"; + break; + + case WSAESOCKTNOSUPPORT: + msg = "Socket type not supported"; + break; + + case WSAEOPNOTSUPP: + msg = "Operation not supported on socket"; + break; + + case WSAEPFNOSUPPORT: + msg = "Protocol family not supported"; + break; + + case WSAEAFNOSUPPORT: + msg = "Address family not supported"; + break; + + case WSAEADDRINUSE: + msg = "Address already in use"; + break; + + case WSAEADDRNOTAVAIL: + msg = "Can't assign requested address"; + break; + + case WSAENETDOWN: + msg = "Network is down"; + break; + + case WSAENETUNREACH: + msg = "Network is unreachable"; + break; + + case WSAENETRESET: + msg = "Net connection reset"; + break; + + case WSAECONNABORTED: + msg = "Software caused connection abort"; + break; + + case WSAECONNRESET: + msg = "Connection reset by peer"; + break; + + case WSAENOBUFS: + msg = "No buffer space available"; + break; + + case WSAEISCONN: + msg = "Socket is already connected"; + break; + + case WSAENOTCONN: + msg = "Socket is not connected"; + break; + + case WSAESHUTDOWN: + msg = "Can't send after socket shutdown"; + break; + + case WSAETOOMANYREFS: + msg = "Too many references: can't splice"; + break; + + case WSAETIMEDOUT: + msg = "Connection timed out"; + break; + + case WSAECONNREFUSED: + msg = "Connection refused"; + break; + + case WSAELOOP: + msg = "Too many levels of symbolic links"; + break; + + case WSAENAMETOOLONG: + msg = "File name too long"; + break; + + case WSAEHOSTDOWN: + msg = "Host is down"; + break; + + case WSAEHOSTUNREACH: + msg = "No route to host"; + break; + + case WSAENOTEMPTY: + msg = "Directory not empty"; + break; + + case WSAEPROCLIM: + msg = "Too many processes"; + break; + + case WSAEUSERS: + msg = "Too many users"; + break; + + case WSAEDQUOT: + msg = "Disc quota exceeded"; + break; + + case WSAESTALE: + msg = "Stale NFS file handle"; + break; + + case WSAEREMOTE: + msg = "Too many levels of remote in path"; + break; + + case WSASYSNOTREADY: + msg = "Network system is unavailable"; + break; + + case WSAVERNOTSUPPORTED: + msg = "Winsock version out of range"; + break; + + case WSANOTINITIALISED: + msg = "WSAStartup not yet called"; + break; + + case WSAEDISCON: + msg = "Graceful shutdown in progress"; + break; +/* + case WSAHOST_NOT_FOUND: + msg = "Host not found"; + break; + + case WSANO_DATA: + msg = "No host data of that type was found"; + break; +*/ + default: + msg = NULL; + break; + } + return (msg); +} + +/* + * These error messages are more informative about CryptAPI Errors than the + * standard error messages + */ + +char * +GetCryptErrorMessage(int errval) { + char *msg; + + switch (errval) { + + case NTE_BAD_FLAGS: + msg = "The dwFlags parameter has an illegal value."; + break; + case NTE_BAD_KEYSET: + msg = "The Registry entry for the key container " + "could not be opened and may not exist."; + break; + case NTE_BAD_KEYSET_PARAM: + msg = "The pszContainer or pszProvider parameter " + "is set to an illegal value."; + break; + case NTE_BAD_PROV_TYPE: + msg = "The value of the dwProvType parameter is out " + "of range. All provider types must be from " + "1 to 999, inclusive."; + break; + case NTE_BAD_SIGNATURE: + msg = "The provider DLL signature did not verify " + "correctly. Either the DLL or the digital " + "signature has been tampered with."; + break; + case NTE_EXISTS: + msg = "The dwFlags parameter is CRYPT_NEWKEYSET, but the key" + " container already exists."; + break; + case NTE_KEYSET_ENTRY_BAD: + msg = "The Registry entry for the pszContainer key container " + "was found (in the HKEY_CURRENT_USER window), but is " + "corrupt. See the section System Administration for " + " etails about CryptoAPI's Registry usage."; + break; + case NTE_KEYSET_NOT_DEF: + msg = "No Registry entry exists in the HKEY_CURRENT_USER " + "window for the key container specified by " + "pszContainer."; + break; + case NTE_NO_MEMORY: + msg = "The CSP ran out of memory during the operation."; + break; + case NTE_PROV_DLL_NOT_FOUND: + msg = "The provider DLL file does not exist or is not on the " + "current path."; + break; + case NTE_PROV_TYPE_ENTRY_BAD: + msg = "The Registry entry for the provider type specified by " + "dwProvType is corrupt. This error may relate to " + "either the user default CSP list or the machine " + "default CSP list. See the section System " + "Administration for details about CryptoAPI's " + "Registry usage."; + break; + case NTE_PROV_TYPE_NO_MATCH: + msg = "The provider type specified by dwProvType does not " + "match the provider type found in the Registry. Note " + "that this error can only occur when pszProvider " + "specifies an actual CSP name."; + break; + case NTE_PROV_TYPE_NOT_DEF: + msg = "No Registry entry exists for the provider type " + "specified by dwProvType."; + break; + case NTE_PROVIDER_DLL_FAIL: + msg = "The provider DLL file could not be loaded, and " + "may not exist. If it exists, then the file is " + "not a valid DLL."; + break; + case NTE_SIGNATURE_FILE_BAD: + msg = "An error occurred while loading the DLL file image, " + "prior to verifying its signature."; + break; + + default: + msg = NULL; + break; + } + return msg; +} + diff --git a/contrib/ntp/lib/isc/win32/syslog.c b/contrib/ntp/lib/isc/win32/syslog.c new file mode 100644 index 0000000..375784f --- /dev/null +++ b/contrib/ntp/lib/isc/win32/syslog.c @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001-2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: syslog.c,v 1.10 2007/06/19 23:47:19 tbox Exp $ */ + +#include <config.h> + +#include <stdio.h> +#include <windows.h> +#include <string.h> +#include <stdlib.h> +#include <syslog.h> + +#include <isc/bindevt.h> +#include <isc/result.h> +#include <isc/syslog.h> +#include <isc/util.h> + +static HANDLE hAppLog = NULL; +static FILE *log_stream; +static int debug_level = 0; + +static struct dsn_c_pvt_sfnt { + int val; + const char *strval; +} facilities[] = { + { LOG_KERN, "kern" }, + { LOG_USER, "user" }, + { LOG_MAIL, "mail" }, + { LOG_DAEMON, "daemon" }, + { LOG_AUTH, "auth" }, + { LOG_SYSLOG, "syslog" }, + { LOG_LPR, "lpr" }, +#ifdef LOG_NEWS + { LOG_NEWS, "news" }, +#endif +#ifdef LOG_UUCP + { LOG_UUCP, "uucp" }, +#endif +#ifdef LOG_CRON + { LOG_CRON, "cron" }, +#endif +#ifdef LOG_AUTHPRIV + { LOG_AUTHPRIV, "authpriv" }, +#endif +#ifdef LOG_FTP + { LOG_FTP, "ftp" }, +#endif + { LOG_LOCAL0, "local0"}, + { LOG_LOCAL1, "local1"}, + { LOG_LOCAL2, "local2"}, + { LOG_LOCAL3, "local3"}, + { LOG_LOCAL4, "local4"}, + { LOG_LOCAL5, "local5"}, + { LOG_LOCAL6, "local6"}, + { LOG_LOCAL7, "local7"}, + { 0, NULL } +}; + +isc_result_t +isc_syslog_facilityfromstring(const char *str, int *facilityp) { + int i; + + REQUIRE(str != NULL); + REQUIRE(facilityp != NULL); + + for (i = 0; facilities[i].strval != NULL; i++) { + if (strcasecmp(facilities[i].strval, str) == 0) { + *facilityp = facilities[i].val; + return (ISC_R_SUCCESS); + } + } + return (ISC_R_NOTFOUND); +} + +/* + * Log to the NT Event Log + */ +void +syslog(int level, const char *fmt, ...) { + va_list ap; + char buf[1024]; + char *str[1]; + + str[0] = buf; + + va_start(ap, fmt); + vsprintf(buf, fmt, ap); + va_end(ap); + + /* Make sure that the channel is open to write the event */ + if (hAppLog != NULL) { + switch (level) { + case LOG_INFO: + case LOG_NOTICE: + case LOG_DEBUG: + ReportEvent(hAppLog, EVENTLOG_INFORMATION_TYPE, 0, + BIND_INFO_MSG, NULL, 1, 0, str, NULL); + break; + case LOG_WARNING: + ReportEvent(hAppLog, EVENTLOG_WARNING_TYPE, 0, + BIND_WARN_MSG, NULL, 1, 0, str, NULL); + break; + default: + ReportEvent(hAppLog, EVENTLOG_ERROR_TYPE, 0, + BIND_ERR_MSG, NULL, 1, 0, str, NULL); + break; + } + } +} + +/* + * Initialize event logging + */ +void +openlog(const char *name, int flags, ...) { + /* Get a handle to the Application event log */ + hAppLog = RegisterEventSource(NULL, name); +} + +/* + * Close the Handle to the application Event Log + * We don't care whether or not we succeeded so ignore return values + * In fact if we failed then we would have nowhere to put the message + */ +void +closelog() { + DeregisterEventSource(hAppLog); +} + +/* + * Keep event logging synced with the current debug level + */ +void +ModifyLogLevel(int level) { + debug_level = level; +} + +/* + * Initialize logging for the port section of libbind. + * Piggyback onto stream given. + */ +void +InitNTLogging(FILE *stream, int debug) { + log_stream = stream; + ModifyLogLevel(debug); +} +/* + * This function is for reporting errors to the application + * event log in case the regular syslog is not available + * mainly during startup. It should not be used under normal + * circumstances. + */ +void +NTReportError(const char *name, const char *str) { + HANDLE hNTAppLog = NULL; + const char *buf[1]; + + buf[0] = str; + + hNTAppLog = RegisterEventSource(NULL, name); + + ReportEvent(hNTAppLog, EVENTLOG_ERROR_TYPE, 0, + BIND_ERR_MSG, NULL, 1, 0, buf, NULL); + + DeregisterEventSource(hNTAppLog); +} diff --git a/contrib/ntp/lib/isc/win32/syslog.h b/contrib/ntp/lib/isc/win32/syslog.h new file mode 100644 index 0000000..fd4b3a6 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/syslog.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2001, 2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: syslog.h,v 1.7 2007/06/19 23:47:19 tbox Exp $ */ + +#ifndef _SYSLOG_H +#define _SYSLOG_H + +#include <stdio.h> + +/* Constant definitions for openlog() */ +#define LOG_PID 1 +#define LOG_CONS 2 +/* NT event log does not support facility level */ +#define LOG_KERN 0 +#define LOG_USER 0 +#define LOG_MAIL 0 +#define LOG_DAEMON 0 +#define LOG_AUTH 0 +#define LOG_SYSLOG 0 +#define LOG_LPR 0 +#define LOG_LOCAL0 0 +#define LOG_LOCAL1 0 +#define LOG_LOCAL2 0 +#define LOG_LOCAL3 0 +#define LOG_LOCAL4 0 +#define LOG_LOCAL5 0 +#define LOG_LOCAL6 0 +#define LOG_LOCAL7 0 + +#define LOG_EMERG 0 /* system is unusable */ +#define LOG_ALERT 1 /* action must be taken immediately */ +#define LOG_CRIT 2 /* critical conditions */ +#define LOG_ERR 3 /* error conditions */ +#define LOG_WARNING 4 /* warning conditions */ +#define LOG_NOTICE 5 /* normal but signification condition */ +#define LOG_INFO 6 /* informational */ +#define LOG_DEBUG 7 /* debug-level messages */ + +void +syslog(int level, const char *fmt, ...); + +void +openlog(const char *, int, ...); + +void +closelog(void); + +void +ModifyLogLevel(int level); + +void +InitNTLogging(FILE *, int); + +void +NTReportError(const char *, const char *); +/* + * Include the event codes required for logging. + */ +#include <isc/bindevt.h> + +#endif diff --git a/contrib/ntp/lib/isc/win32/thread.c b/contrib/ntp/lib/isc/win32/thread.c new file mode 100644 index 0000000..85ffef1 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/thread.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: thread.c,v 1.24 2007/06/19 23:47:19 tbox Exp $ */ + +#include <config.h> + +#include <process.h> + +#include <isc/thread.h> + +isc_result_t +isc_thread_create(isc_threadfunc_t start, isc_threadarg_t arg, + isc_thread_t *threadp) +{ + isc_thread_t thread; + unsigned int id; + + thread = (isc_thread_t)_beginthreadex(NULL, 0, start, arg, 0, &id); + if (thread == NULL) { + /* XXX */ + return (ISC_R_UNEXPECTED); + } + + *threadp = thread; + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_thread_join(isc_thread_t thread, isc_threadresult_t *rp) { + DWORD result; + DWORD threadrc; + + result = WaitForSingleObject(thread, INFINITE); + if (result != WAIT_OBJECT_0) { + /* XXX */ + return (ISC_R_UNEXPECTED); + } + if (rp != NULL) { + if(!GetExitCodeThread(thread, &threadrc)) { + /* XXX */ + return (ISC_R_UNEXPECTED); + } + *rp = threadrc; + } + (void)CloseHandle(thread); + + return (ISC_R_SUCCESS); +} + +void +isc_thread_setconcurrency(unsigned int level) { + /* + * This is unnecessary on Win32 systems, but is here so that the + * call exists + */ +} + +void * +isc_thread_key_getspecific(isc_thread_key_t key) { + return(TlsGetValue(key)); +} + +int +isc_thread_key_setspecific(isc_thread_key_t key, void *value) { + return (TlsSetValue(key, value) ? 0 : GetLastError()); +} + +int +isc_thread_key_create(isc_thread_key_t *key, void (*func)(void *)) { + *key = TlsAlloc(); + + return ((*key != -1) ? 0 : GetLastError()); +} + +int +isc_thread_key_delete(isc_thread_key_t key) { + return (TlsFree(key) ? 0 : GetLastError()); +} diff --git a/contrib/ntp/lib/isc/win32/time.c b/contrib/ntp/lib/isc/win32/time.c new file mode 100644 index 0000000..aafd70b --- /dev/null +++ b/contrib/ntp/lib/isc/win32/time.c @@ -0,0 +1,320 @@ +/* + * Copyright (C) 2004, 2006-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2001, 2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: time.c,v 1.52 2009/08/14 07:51:08 marka Exp $ */ + +#include <config.h> + +#include <errno.h> +#include <limits.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <windows.h> + +#include <isc/assertions.h> +#include <isc/time.h> +#include <isc/util.h> + +/* + * struct FILETIME uses "100-nanoseconds intervals". + * NS / S = 1000000000 (10^9). + * While it is reasonably obvious that this makes the needed + * conversion factor 10^7, it is coded this way for additional clarity. + */ +#define NS_PER_S 1000000000 +#define NS_INTERVAL 100 +#define INTERVALS_PER_S (NS_PER_S / NS_INTERVAL) +#define UINT64_MAX _UI64_MAX + +/*** + *** Absolute Times + ***/ + +static isc_time_t epoch = { { 0, 0 } }; +LIBISC_EXTERNAL_DATA isc_time_t *isc_time_epoch = &epoch; + +/*** + *** Intervals + ***/ + +static isc_interval_t zero_interval = { 0 }; +LIBISC_EXTERNAL_DATA isc_interval_t *isc_interval_zero = &zero_interval; + +void +isc_interval_set(isc_interval_t *i, unsigned int seconds, + unsigned int nanoseconds) +{ + REQUIRE(i != NULL); + REQUIRE(nanoseconds < NS_PER_S); + + /* + * This rounds nanoseconds up not down. + */ + i->interval = (LONGLONG)seconds * INTERVALS_PER_S + + (nanoseconds + NS_INTERVAL - 1) / NS_INTERVAL; +} + +isc_boolean_t +isc_interval_iszero(const isc_interval_t *i) { + REQUIRE(i != NULL); + if (i->interval == 0) + return (ISC_TRUE); + + return (ISC_FALSE); +} + +void +isc_time_set(isc_time_t *t, unsigned int seconds, unsigned int nanoseconds) { + SYSTEMTIME epoch = { 1970, 1, 4, 1, 0, 0, 0, 0 }; + FILETIME temp; + ULARGE_INTEGER i1; + + REQUIRE(t != NULL); + REQUIRE(nanoseconds < NS_PER_S); + + SystemTimeToFileTime(&epoch, &temp); + + i1.LowPart = t->absolute.dwLowDateTime; + i1.HighPart = t->absolute.dwHighDateTime; + + i1.QuadPart += (unsigned __int64)nanoseconds/100; + i1.QuadPart += (unsigned __int64)seconds*10000000; + + t->absolute.dwLowDateTime = i1.LowPart; + t->absolute.dwHighDateTime = i1.HighPart; +} + +void +isc_time_settoepoch(isc_time_t *t) { + REQUIRE(t != NULL); + + t->absolute.dwLowDateTime = 0; + t->absolute.dwHighDateTime = 0; +} + +isc_boolean_t +isc_time_isepoch(const isc_time_t *t) { + REQUIRE(t != NULL); + + if (t->absolute.dwLowDateTime == 0 && + t->absolute.dwHighDateTime == 0) + return (ISC_TRUE); + + return (ISC_FALSE); +} + +isc_result_t +isc_time_now(isc_time_t *t) { + REQUIRE(t != NULL); + + GetSystemTimeAsFileTime(&t->absolute); + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_time_nowplusinterval(isc_time_t *t, const isc_interval_t *i) { + ULARGE_INTEGER i1; + + REQUIRE(t != NULL); + REQUIRE(i != NULL); + + GetSystemTimeAsFileTime(&t->absolute); + + i1.LowPart = t->absolute.dwLowDateTime; + i1.HighPart = t->absolute.dwHighDateTime; + + if (UINT64_MAX - i1.QuadPart < (unsigned __int64)i->interval) + return (ISC_R_RANGE); + + i1.QuadPart += i->interval; + + t->absolute.dwLowDateTime = i1.LowPart; + t->absolute.dwHighDateTime = i1.HighPart; + + return (ISC_R_SUCCESS); +} + +int +isc_time_compare(const isc_time_t *t1, const isc_time_t *t2) { + REQUIRE(t1 != NULL && t2 != NULL); + + return ((int)CompareFileTime(&t1->absolute, &t2->absolute)); +} + +isc_result_t +isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result) +{ + ULARGE_INTEGER i1; + + REQUIRE(t != NULL && i != NULL && result != NULL); + + i1.LowPart = t->absolute.dwLowDateTime; + i1.HighPart = t->absolute.dwHighDateTime; + + if (UINT64_MAX - i1.QuadPart < (unsigned __int64)i->interval) + return (ISC_R_RANGE); + + i1.QuadPart += i->interval; + + result->absolute.dwLowDateTime = i1.LowPart; + result->absolute.dwHighDateTime = i1.HighPart; + + return (ISC_R_SUCCESS); +} + +isc_result_t +isc_time_subtract(const isc_time_t *t, const isc_interval_t *i, + isc_time_t *result) { + ULARGE_INTEGER i1; + + REQUIRE(t != NULL && i != NULL && result != NULL); + + i1.LowPart = t->absolute.dwLowDateTime; + i1.HighPart = t->absolute.dwHighDateTime; + + if (i1.QuadPart < (unsigned __int64) i->interval) + return (ISC_R_RANGE); + + i1.QuadPart -= i->interval; + + result->absolute.dwLowDateTime = i1.LowPart; + result->absolute.dwHighDateTime = i1.HighPart; + + return (ISC_R_SUCCESS); +} + +isc_uint64_t +isc_time_microdiff(const isc_time_t *t1, const isc_time_t *t2) { + ULARGE_INTEGER i1, i2; + LONGLONG i3; + + REQUIRE(t1 != NULL && t2 != NULL); + + i1.LowPart = t1->absolute.dwLowDateTime; + i1.HighPart = t1->absolute.dwHighDateTime; + i2.LowPart = t2->absolute.dwLowDateTime; + i2.HighPart = t2->absolute.dwHighDateTime; + + if (i1.QuadPart <= i2.QuadPart) + return (0); + + /* + * Convert to microseconds. + */ + i3 = (i1.QuadPart - i2.QuadPart) / 10; + + return (i3); +} + +isc_uint32_t +isc_time_seconds(const isc_time_t *t) { + SYSTEMTIME epoch = { 1970, 1, 4, 1, 0, 0, 0, 0 }; + FILETIME temp; + ULARGE_INTEGER i1, i2; + LONGLONG i3; + + SystemTimeToFileTime(&epoch, &temp); + + i1.LowPart = t->absolute.dwLowDateTime; + i1.HighPart = t->absolute.dwHighDateTime; + i2.LowPart = temp.dwLowDateTime; + i2.HighPart = temp.dwHighDateTime; + + i3 = (i1.QuadPart - i2.QuadPart) / 10000000; + + return ((isc_uint32_t)i3); +} + +isc_uint32_t +isc_time_nanoseconds(const isc_time_t *t) { + ULARGE_INTEGER i; + + i.LowPart = t->absolute.dwLowDateTime; + i.HighPart = t->absolute.dwHighDateTime; + return ((isc_uint32_t)(i.QuadPart % 10000000) * 100); +} + +void +isc_time_formattimestamp(const isc_time_t *t, char *buf, unsigned int len) { + FILETIME localft; + SYSTEMTIME st; + char DateBuf[50]; + char TimeBuf[50]; + + static const char badtime[] = "99-Bad-9999 99:99:99.999"; + + REQUIRE(len > 0); + if (FileTimeToLocalFileTime(&t->absolute, &localft) && + FileTimeToSystemTime(&localft, &st)) { + GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, "dd-MMM-yyyy", + DateBuf, 50); + GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOTIMEMARKER| + TIME_FORCE24HOURFORMAT, &st, NULL, TimeBuf, 50); + + snprintf(buf, len, "%s %s.%03u", DateBuf, TimeBuf, + st.wMilliseconds); + + } else + snprintf(buf, len, badtime); +} + +void +isc_time_formathttptimestamp(const isc_time_t *t, char *buf, unsigned int len) { + SYSTEMTIME st; + char DateBuf[50]; + char TimeBuf[50]; + +/* strftime() format: "%a, %d %b %Y %H:%M:%S GMT" */ + + REQUIRE(len > 0); + if (FileTimeToSystemTime(&t->absolute, &st)) { + GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, + "ddd',', dd-MMM-yyyy", DateBuf, 50); + GetTimeFormat(LOCALE_USER_DEFAULT, + TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, + &st, "hh':'mm':'ss", TimeBuf, 50); + + snprintf(buf, len, "%s %s GMT", DateBuf, TimeBuf); + } else { + buf[0] = 0; + } +} + +void +isc_time_formatISO8601(const isc_time_t *t, char *buf, unsigned int len) { + SYSTEMTIME st; + char DateBuf[50]; + char TimeBuf[50]; + +/* strtime() format: "%Y-%m-%dT%H:%M:%SZ" */ + + REQUIRE(len > 0); + if (FileTimeToSystemTime(&t->absolute, &st)) { + GetDateFormat(LOCALE_NEUTRAL, 0, &st, "yyyy-MM-dd", + DateBuf, 50); + GetTimeFormat(LOCALE_NEUTRAL, + TIME_NOTIMEMARKER | TIME_FORCE24HOURFORMAT, + &st, "hh':'mm':'ss", TimeBuf, 50); + snprintf(buf, len, "%s%sZ", DateBuf, TimeBuf); + } else { + buf[0] = 0; + } +} diff --git a/contrib/ntp/lib/isc/win32/unistd.h b/contrib/ntp/lib/isc/win32/unistd.h new file mode 100644 index 0000000..bcb3b25 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/unistd.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2004, 2007-2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2000, 2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: unistd.h,v 1.10 2009/07/17 23:47:41 tbox Exp $ */ + +/* None of these are defined in NT, so define them for our use */ +#define O_NONBLOCK 1 +#define PORT_NONBLOCK O_NONBLOCK + +/* + * fcntl() commands + */ +#define F_SETFL 0 +#define F_GETFL 1 +#define F_SETFD 2 +#define F_GETFD 3 +/* + * Enough problems not having full fcntl() without worrying about this! + */ +#undef F_DUPFD + +int fcntl(int, int, ...); + +/* + * access() related definitions for winXP + */ +#include <io.h> +#ifndef F_OK +#define F_OK 0 +#endif + +#ifndef X_OK +#define X_OK 1 +#endif + +#ifndef W_OK +#define W_OK 2 +#endif + +#ifndef R_OK +#define R_OK 4 +#endif + +#define access _access + +#include <process.h> diff --git a/contrib/ntp/lib/isc/win32/version.c b/contrib/ntp/lib/isc/win32/version.c new file mode 100644 index 0000000..6d5c1fd --- /dev/null +++ b/contrib/ntp/lib/isc/win32/version.c @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 1998-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: version.c,v 1.7 2007/06/19 23:47:19 tbox Exp $ */ + +#include <versions.h> + +#include <isc/version.h> + +LIBISC_EXTERNAL_DATA const char isc_version[] = VERSION; + +LIBISC_EXTERNAL_DATA const unsigned int isc_libinterface = LIBINTERFACE; +LIBISC_EXTERNAL_DATA const unsigned int isc_librevision = LIBREVISION; +LIBISC_EXTERNAL_DATA const unsigned int isc_libage = LIBAGE; diff --git a/contrib/ntp/lib/isc/win32/win32os.c b/contrib/ntp/lib/isc/win32/win32os.c new file mode 100644 index 0000000..56498d0 --- /dev/null +++ b/contrib/ntp/lib/isc/win32/win32os.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2002 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: win32os.c,v 1.5 2007/06/19 23:47:19 tbox Exp $ */ + +#include <windows.h> + +#include <isc/win32os.h> + +static BOOL bInit = FALSE; +static OSVERSIONINFOEX osVer; + +static void +initialize_action(void) { + BOOL bSuccess; + + if (bInit) + return; + /* + * NOTE: VC++ 6.0 gets this function declaration wrong + * so we compensate by casting the argument + */ + osVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + bSuccess = GetVersionEx((OSVERSIONINFO *) &osVer); + + /* + * Versions of NT before NT4.0 SP6 did not return the + * extra info that the EX structure provides and returns + * a failure so we need to retry with the old structure. + */ + if(!bSuccess) { + osVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + bSuccess = GetVersionEx((OSVERSIONINFO *) &osVer); + } + bInit = TRUE; +} + +unsigned int +isc_win32os_majorversion(void) { + initialize_action(); + return ((unsigned int)osVer.dwMajorVersion); +} + +unsigned int +isc_win32os_minorversion(void) { + initialize_action(); + return ((unsigned int)osVer.dwMinorVersion); +} + +unsigned int +isc_win32os_servicepackmajor(void) { + initialize_action(); + return ((unsigned int)osVer.wServicePackMajor); +} + +unsigned int +isc_win32os_servicepackminor(void) { + initialize_action(); + return ((unsigned int)osVer.wServicePackMinor); +} + +int +isc_win32os_versioncheck(unsigned int major, unsigned int minor, + unsigned int spmajor, unsigned int spminor) { + + initialize_action(); + + if (major < isc_win32os_majorversion()) + return (1); + if (major > isc_win32os_majorversion()) + return (-1); + if (minor < isc_win32os_minorversion()) + return (1); + if (minor > isc_win32os_minorversion()) + return (-1); + if (spmajor < isc_win32os_servicepackmajor()) + return (1); + if (spmajor > isc_win32os_servicepackmajor()) + return (-1); + if (spminor < isc_win32os_servicepackminor()) + return (1); + if (spminor > isc_win32os_servicepackminor()) + return (-1); + + /* Exact */ + return (0); +}
\ No newline at end of file diff --git a/contrib/ntp/lib/isc/x86_32/include/isc/atomic.h b/contrib/ntp/lib/isc/x86_32/include/isc/atomic.h new file mode 100644 index 0000000..bf2148c --- /dev/null +++ b/contrib/ntp/lib/isc/x86_32/include/isc/atomic.h @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: atomic.h,v 1.10 2008/01/24 23:47:00 tbox Exp $ */ + +#ifndef ISC_ATOMIC_H +#define ISC_ATOMIC_H 1 + +#include <isc/platform.h> +#include <isc/types.h> + +#ifdef ISC_PLATFORM_USEGCCASM +/* + * This routine atomically increments the value stored in 'p' by 'val', and + * returns the previous value. + */ +static __inline__ isc_int32_t +isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) { + isc_int32_t prev = val; + + __asm__ volatile( +#ifdef ISC_PLATFORM_USETHREADS + "lock;" +#endif + "xadd %0, %1" + :"=q"(prev) + :"m"(*p), "0"(prev) + :"memory", "cc"); + + return (prev); +} + +#ifdef ISC_PLATFORM_HAVEXADDQ +static __inline__ isc_int64_t +isc_atomic_xaddq(isc_int64_t *p, isc_int64_t val) { + isc_int64_t prev = val; + + __asm__ volatile( +#ifdef ISC_PLATFORM_USETHREADS + "lock;" +#endif + "xaddq %0, %1" + :"=q"(prev) + :"m"(*p), "0"(prev) + :"memory", "cc"); + + return (prev); +} +#endif /* ISC_PLATFORM_HAVEXADDQ */ + +/* + * This routine atomically stores the value 'val' in 'p'. + */ +static __inline__ void +isc_atomic_store(isc_int32_t *p, isc_int32_t val) { + __asm__ volatile( +#ifdef ISC_PLATFORM_USETHREADS + /* + * xchg should automatically lock memory, but we add it + * explicitly just in case (it at least doesn't harm) + */ + "lock;" +#endif + + "xchgl %1, %0" + : + : "r"(val), "m"(*p) + : "memory"); +} + +/* + * This routine atomically replaces the value in 'p' with 'val', if the + * original value is equal to 'cmpval'. The original value is returned in any + * case. + */ +static __inline__ isc_int32_t +isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) { + __asm__ volatile( +#ifdef ISC_PLATFORM_USETHREADS + "lock;" +#endif + "cmpxchgl %1, %2" + : "=a"(cmpval) + : "r"(val), "m"(*p), "a"(cmpval) + : "memory"); + + return (cmpval); +} + +#elif defined(ISC_PLATFORM_USESTDASM) +/* + * The followings are "generic" assembly code which implements the same + * functionality in case the gcc extension cannot be used. It should be + * better to avoid inlining below, since we directly refer to specific + * positions of the stack frame, which would not actually point to the + * intended address in the embedded mnemonic. + */ +#include <isc/util.h> /* for 'UNUSED' macro */ + +static isc_int32_t +isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) { + UNUSED(p); + UNUSED(val); + + __asm ( + "movl 8(%ebp), %ecx\n" + "movl 12(%ebp), %edx\n" +#ifdef ISC_PLATFORM_USETHREADS + "lock;" +#endif + "xadd %edx, (%ecx)\n" + + /* + * set the return value directly in the register so that we + * can avoid guessing the correct position in the stack for a + * local variable. + */ + "movl %edx, %eax" + ); +} + +static void +isc_atomic_store(isc_int32_t *p, isc_int32_t val) { + UNUSED(p); + UNUSED(val); + + __asm ( + "movl 8(%ebp), %ecx\n" + "movl 12(%ebp), %edx\n" +#ifdef ISC_PLATFORM_USETHREADS + "lock;" +#endif + "xchgl (%ecx), %edx\n" + ); +} + +static isc_int32_t +isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) { + UNUSED(p); + UNUSED(cmpval); + UNUSED(val); + + __asm ( + "movl 8(%ebp), %ecx\n" + "movl 12(%ebp), %eax\n" /* must be %eax for cmpxchgl */ + "movl 16(%ebp), %edx\n" +#ifdef ISC_PLATFORM_USETHREADS + "lock;" +#endif + + /* + * If (%ecx) == %eax then (%ecx) := %edx. + % %eax is set to old (%ecx), which will be the return value. + */ + "cmpxchgl %edx, (%ecx)" + ); +} +#else /* !ISC_PLATFORM_USEGCCASM && !ISC_PLATFORM_USESTDASM */ + +#error "unsupported compiler. disable atomic ops by --disable-atomic" + +#endif +#endif /* ISC_ATOMIC_H */ diff --git a/contrib/ntp/lib/isc/x86_64/include/isc/atomic.h b/contrib/ntp/lib/isc/x86_64/include/isc/atomic.h new file mode 100644 index 0000000..f57bd2a --- /dev/null +++ b/contrib/ntp/lib/isc/x86_64/include/isc/atomic.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or 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. + */ + +/* $Id: atomic.h,v 1.6 2008/01/24 23:47:00 tbox Exp $ */ + +#ifndef ISC_ATOMIC_H +#define ISC_ATOMIC_H 1 + +#include <isc/platform.h> +#include <isc/types.h> + +#ifdef ISC_PLATFORM_USEGCCASM + +/* We share the gcc-version with x86_32 */ +#error "impossible case. check build configuration" + +#elif defined(ISC_PLATFORM_USESTDASM) +/* + * The followings are "generic" assembly code which implements the same + * functionality in case the gcc extension cannot be used. It should be + * better to avoid inlining below, since we directly refer to specific + * registers for arguments, which would not actually correspond to the + * intended address or value in the embedded mnemonic. + */ +#include <isc/util.h> /* for 'UNUSED' macro */ + +static isc_int32_t +isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) { + UNUSED(p); + UNUSED(val); + + __asm ( + "movq %rdi, %rdx\n" + "movl %esi, %eax\n" +#ifdef ISC_PLATFORM_USETHREADS + "lock;" +#endif + "xadd %eax, (%rdx)\n" + /* + * XXX: assume %eax will be used as the return value. + */ + ); +} + +#ifdef ISC_PLATFORM_HAVEXADDQ +static isc_int64_t +isc_atomic_xaddq(isc_int64_t *p, isc_int64_t val) { + UNUSED(p); + UNUSED(val); + + __asm ( + "movq %rdi, %rdx\n" + "movq %rsi, %rax\n" +#ifdef ISC_PLATFORM_USETHREADS + "lock;" +#endif + "xaddq %rax, (%rdx)\n" + /* + * XXX: assume %rax will be used as the return value. + */ + ); +} +#endif + +static void +isc_atomic_store(isc_int32_t *p, isc_int32_t val) { + UNUSED(p); + UNUSED(val); + + __asm ( + "movq %rdi, %rax\n" + "movl %esi, %edx\n" +#ifdef ISC_PLATFORM_USETHREADS + "lock;" +#endif + "xchgl (%rax), %edx\n" + /* + * XXX: assume %rax will be used as the return value. + */ + ); +} + +static isc_int32_t +isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) { + UNUSED(p); + UNUSED(cmpval); + UNUSED(val); + + __asm ( + "movl %edx, %ecx\n" + "movl %esi, %eax\n" + "movq %rdi, %rdx\n" + +#ifdef ISC_PLATFORM_USETHREADS + "lock;" +#endif + /* + * If (%rdi) == %eax then (%rdi) := %edx. + * %eax is set to old (%ecx), which will be the return value. + */ + "cmpxchgl %ecx, (%rdx)" + ); +} + +#else /* !ISC_PLATFORM_USEGCCASM && !ISC_PLATFORM_USESTDASM */ + +#error "unsupported compiler. disable atomic ops by --disable-atomic" + +#endif +#endif /* ISC_ATOMIC_H */ |