From fb07813b04e9ddb2aa8dd7cdee1b4f4558556327 Mon Sep 17 00:00:00 2001 From: David Ask Date: Mon, 5 Jun 2017 22:19:58 +0200 Subject: [PATCH 01/11] Updated to pkgconfig dependency --- Package.swift | 7 +- Sources/CLibdill/AUTHORS | 25 - Sources/CLibdill/COPYING | 19 - Sources/CLibdill/bsock.c | 62 - Sources/CLibdill/chan.c | 283 - Sources/CLibdill/config.h | 30 - Sources/CLibdill/cr.c | 562 -- Sources/CLibdill/cr.h | 162 - Sources/CLibdill/crlf.c | 209 - Sources/CLibdill/ctx.c | 194 - Sources/CLibdill/ctx.h | 65 - Sources/CLibdill/dns/dns.c | 9131 ------------------------ Sources/CLibdill/dns/dns.h | 1198 ---- Sources/CLibdill/epoll.c.inc | 261 - Sources/CLibdill/epoll.h.inc | 46 - Sources/CLibdill/fd.c | 299 - Sources/CLibdill/fd.h | 69 - Sources/CLibdill/handle.c | 156 - Sources/CLibdill/handle.h | 40 - Sources/CLibdill/include/libdill.h | 1 - Sources/CLibdill/include/libdillimpl.h | 1 - Sources/CLibdill/iol.c | 62 - Sources/CLibdill/iol.h | 44 - Sources/CLibdill/ipaddr.c | 380 - Sources/CLibdill/ipc.c | 323 - Sources/CLibdill/kqueue.c.inc | 307 - Sources/CLibdill/kqueue.h.inc | 43 - Sources/CLibdill/libdill.c | 81 - Sources/CLibdill/libdill.h | 435 -- Sources/CLibdill/libdillimpl.h | 79 - Sources/CLibdill/list.h | 69 - Sources/CLibdill/msock.c | 65 - Sources/CLibdill/now.c | 119 - Sources/CLibdill/now.h | 52 - Sources/CLibdill/pfx.c | 197 - Sources/CLibdill/poll.c.inc | 227 - Sources/CLibdill/poll.h.inc | 48 - Sources/CLibdill/pollset.c | 41 - Sources/CLibdill/pollset.h | 61 - Sources/CLibdill/qlist.h | 67 - Sources/CLibdill/rbtree.c | 279 - Sources/CLibdill/rbtree.h | 66 - Sources/CLibdill/slist.h | 67 - Sources/CLibdill/stack.c | 147 - Sources/CLibdill/stack.h | 51 - Sources/CLibdill/tcp.c | 294 - Sources/CLibdill/utils.c | 89 - Sources/CLibdill/utils.h | 109 - 48 files changed, 4 insertions(+), 16618 deletions(-) delete mode 100644 Sources/CLibdill/AUTHORS delete mode 100644 Sources/CLibdill/COPYING delete mode 100644 Sources/CLibdill/bsock.c delete mode 100644 Sources/CLibdill/chan.c delete mode 100644 Sources/CLibdill/config.h delete mode 100644 Sources/CLibdill/cr.c delete mode 100644 Sources/CLibdill/cr.h delete mode 100644 Sources/CLibdill/crlf.c delete mode 100644 Sources/CLibdill/ctx.c delete mode 100644 Sources/CLibdill/ctx.h delete mode 100644 Sources/CLibdill/dns/dns.c delete mode 100644 Sources/CLibdill/dns/dns.h delete mode 100644 Sources/CLibdill/epoll.c.inc delete mode 100644 Sources/CLibdill/epoll.h.inc delete mode 100644 Sources/CLibdill/fd.c delete mode 100644 Sources/CLibdill/fd.h delete mode 100644 Sources/CLibdill/handle.c delete mode 100644 Sources/CLibdill/handle.h delete mode 120000 Sources/CLibdill/include/libdill.h delete mode 120000 Sources/CLibdill/include/libdillimpl.h delete mode 100644 Sources/CLibdill/iol.c delete mode 100644 Sources/CLibdill/iol.h delete mode 100644 Sources/CLibdill/ipaddr.c delete mode 100644 Sources/CLibdill/ipc.c delete mode 100644 Sources/CLibdill/kqueue.c.inc delete mode 100644 Sources/CLibdill/kqueue.h.inc delete mode 100644 Sources/CLibdill/libdill.c delete mode 100644 Sources/CLibdill/libdill.h delete mode 100644 Sources/CLibdill/libdillimpl.h delete mode 100644 Sources/CLibdill/list.h delete mode 100644 Sources/CLibdill/msock.c delete mode 100644 Sources/CLibdill/now.c delete mode 100644 Sources/CLibdill/now.h delete mode 100644 Sources/CLibdill/pfx.c delete mode 100644 Sources/CLibdill/poll.c.inc delete mode 100644 Sources/CLibdill/poll.h.inc delete mode 100644 Sources/CLibdill/pollset.c delete mode 100644 Sources/CLibdill/pollset.h delete mode 100644 Sources/CLibdill/qlist.h delete mode 100644 Sources/CLibdill/rbtree.c delete mode 100644 Sources/CLibdill/rbtree.h delete mode 100644 Sources/CLibdill/slist.h delete mode 100644 Sources/CLibdill/stack.c delete mode 100644 Sources/CLibdill/stack.h delete mode 100644 Sources/CLibdill/tcp.c delete mode 100644 Sources/CLibdill/utils.c delete mode 100644 Sources/CLibdill/utils.h diff --git a/Package.swift b/Package.swift index 9f5ed9d..cac279a 100644 --- a/Package.swift +++ b/Package.swift @@ -2,8 +2,9 @@ import PackageDescription let package = Package( name: "Venice", - targets: [ - Target(name: "CLibdill"), - Target(name: "Venice", dependencies: ["CLibdill"]), + + dependencies: [ + .Package(url: "https://github.com/Zewo/CLibdill.git", majorVersion: 1, minor: 0) ] + ) diff --git a/Sources/CLibdill/AUTHORS b/Sources/CLibdill/AUTHORS deleted file mode 100644 index e9922f3..0000000 --- a/Sources/CLibdill/AUTHORS +++ /dev/null @@ -1,25 +0,0 @@ -Full list of copyright holders: - -Alex Cornejo -Bent Cardan -Constantine Tarasenkov -Jim Jagielski -Jim Schimpf -Luca Barbato -Martin Lucina -Martin Sustrik * -Maximilian Pudelko -Michael Gehring -Nick Desaulniers -Nir Soffer -Paul Banks -Petr Skocik -Sergey Avseyev -Tai Chi Minh Ralph Eastwood * -Yue Xu -Zach Banks - -* Future patches by this author are submitted under the MIT/X11 license - -Copyrights for DNS resolution library in dns subdirectory are owned by: -William Ahern diff --git a/Sources/CLibdill/COPYING b/Sources/CLibdill/COPYING deleted file mode 100644 index 36e7426..0000000 --- a/Sources/CLibdill/COPYING +++ /dev/null @@ -1,19 +0,0 @@ - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom -the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -IN THE SOFTWARE. - diff --git a/Sources/CLibdill/bsock.c b/Sources/CLibdill/bsock.c deleted file mode 100644 index 2192b3c..0000000 --- a/Sources/CLibdill/bsock.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - - Copyright (c) 2017 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#include -#include - -#include "libdillimpl.h" -#include "utils.h" - -dill_unique_id(bsock_type); - -int bsend(int s, const void *buf, size_t len, int64_t deadline) { - struct bsock_vfs *b = hquery(s, bsock_type); - if(dill_slow(!b)) return -1; - struct iolist iol = {(void*)buf, len, NULL, 0}; - return b->bsendl(b, &iol, &iol, deadline); -} - -ssize_t brecv(int s, void *buf, size_t len, int64_t deadline) { - struct bsock_vfs *b = hquery(s, bsock_type); - if(dill_slow(!b)) return -1; - struct iolist iol = {buf, len, NULL, 0}; - return b->brecvl(b, &iol, &iol, deadline); -} - -int bsendl(int s, struct iolist *first, struct iolist *last, int64_t deadline) { - struct bsock_vfs *b = hquery(s, bsock_type); - if(dill_slow(!b)) return -1; - if(dill_slow(!first || !last || last->iol_next)) { - errno = EINVAL; return -1;} - return b->bsendl(b, first, last, deadline); -} - -ssize_t brecvl(int s, struct iolist *first, struct iolist *last, int64_t deadline) { - struct bsock_vfs *b = hquery(s, bsock_type); - if(dill_slow(!b)) return -1; - if(dill_slow((first && !last) || (!first && last) || last->iol_next)) { - errno = EINVAL; return -1;} - return b->brecvl(b, first, last, deadline); -} - diff --git a/Sources/CLibdill/chan.c b/Sources/CLibdill/chan.c deleted file mode 100644 index 8464529..0000000 --- a/Sources/CLibdill/chan.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - - Copyright (c) 2016 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#include -#include -#include -#include - -#include "cr.h" -#include "libdillimpl.h" -#include "list.h" -#include "utils.h" - -struct dill_chan { - /* Table of virtual functions. */ - struct hvfs vfs; - /* The size of one element stored in the channel, in bytes. */ - size_t sz; - /* List of clauses wanting to receive from the channel. */ - struct dill_list in; - /* List of clauses wanting to send to the channel. */ - struct dill_list out; - /* 1 if hdone() has been called on this channel. 0 otherwise. */ - unsigned int done : 1; - /* 1 if the object was created with chmake_mem(). */ - unsigned int mem : 1; -}; - -/* Channel clause. */ -struct dill_chclause { - struct dill_clause cl; - /* An item in either the dill_chan::in or dill_chan::out list. */ - struct dill_list item; - void *val; -}; - -DILL_CT_ASSERT(sizeof(struct chmem) >= sizeof(struct dill_chan)); - -/******************************************************************************/ -/* Handle implementation. */ -/******************************************************************************/ - -static const int dill_chan_type_placeholder = 0; -static const void *dill_chan_type = &dill_chan_type_placeholder; -static void *dill_chan_query(struct hvfs *vfs, const void *type); -static void dill_chan_close(struct hvfs *vfs); -static int dill_chan_done(struct hvfs *vfs, int64_t deadline); - -/******************************************************************************/ -/* Channel creation and deallocation. */ -/******************************************************************************/ - -int chmake_mem(size_t itemsz, struct chmem *mem) { - if(dill_slow(!mem)) {errno = EINVAL; return -1;} - /* Returns ECANCELED if the coroutine is shutting down. */ - int rc = dill_canblock(); - if(dill_slow(rc < 0)) return -1; - struct dill_chan *ch = (struct dill_chan*)mem; - ch->vfs.query = dill_chan_query; - ch->vfs.close = dill_chan_close; - ch->vfs.done = dill_chan_done; - ch->sz = itemsz; - dill_list_init(&ch->in); - dill_list_init(&ch->out); - ch->done = 0; - ch->mem = 1; - /* Allocate a handle to point to the channel. */ - return hmake(&ch->vfs); -} - -int chmake(size_t itemsz) { - struct dill_chan *ch = malloc(sizeof(struct dill_chan)); - if(dill_slow(!ch)) {errno = ENOMEM; return -1;} - int h = chmake_mem(itemsz, (struct chmem*)ch); - if(dill_slow(h < 0)) { - int err = errno; - free(ch); - errno = err; - return -1; - } - ch->mem = 0; - return h; -} - -static void *dill_chan_query(struct hvfs *vfs, const void *type) { - if(dill_fast(type == dill_chan_type)) return vfs; - errno = ENOTSUP; - return NULL; -} - -static void dill_chan_close(struct hvfs *vfs) { - struct dill_chan *ch = (struct dill_chan*)vfs; - dill_assert(ch); - /* Resume any remaining senders and receivers on the channel - with the EPIPE error. */ - while(!dill_list_empty(&ch->in)) { - struct dill_chclause *chcl = dill_cont(dill_list_next(&ch->in), - struct dill_chclause, item); - dill_trigger(&chcl->cl, EPIPE); - } - while(!dill_list_empty(&ch->out)) { - struct dill_chclause *chcl = dill_cont(dill_list_next(&ch->out), - struct dill_chclause, item); - dill_trigger(&chcl->cl, EPIPE); - } - if(!ch->mem) free(ch); -} - -/******************************************************************************/ -/* Sending and receiving. */ -/******************************************************************************/ - -static void dill_chcancel(struct dill_clause *cl) { - struct dill_chclause *chcl = dill_cont(cl, struct dill_chclause, cl); - dill_list_erase(&chcl->item); -} - -int chsend(int h, const void *val, size_t len, int64_t deadline) { - int rc = dill_canblock(); - if(dill_slow(rc < 0)) return -1; - /* Get the channel interface. */ - struct dill_chan *ch = hquery(h, dill_chan_type); - if(dill_slow(!ch)) return -1; - /* Check that the length provided matches the channel length */ - if(dill_slow(len != ch->sz)) {errno = EINVAL; return -1;} - /* Check if the channel is done. */ - if(dill_slow(ch->done)) {errno = EPIPE; return -1;} - /* Copy the message directly to the waiting receiver, if any. */ - if(!dill_list_empty(&ch->in)) { - struct dill_chclause *chcl = dill_cont(dill_list_next(&ch->in), - struct dill_chclause, item); - memcpy(chcl->val, val, len); - dill_trigger(&chcl->cl, 0); - return 0; - } - /* The clause is not available immediately. */ - if(dill_slow(deadline == 0)) {errno = ETIMEDOUT; return -1;} - /* Let's wait. */ - struct dill_chclause chcl; - dill_list_insert(&chcl.item, &ch->out); - chcl.val = (void*)val; - dill_waitfor(&chcl.cl, 0, dill_chcancel); - struct dill_tmclause tmcl; - dill_timer(&tmcl, 1, deadline); - int id = dill_wait(); - if(dill_slow(id < 0)) return -1; - if(dill_slow(id == 1)) {errno = ETIMEDOUT; return -1;} - if(dill_slow(errno != 0)) return -1; - return 0; -} - -int chrecv(int h, void *val, size_t len, int64_t deadline) { - int rc = dill_canblock(); - if(dill_slow(rc < 0)) return -1; - /* Get the channel interface. */ - struct dill_chan *ch = hquery(h, dill_chan_type); - if(dill_slow(!ch)) return -1; - /* Check that the length provided matches the channel length */ - if(dill_slow(len != ch->sz)) {errno = EINVAL; return -1;} - /* Check whether the channel is done. */ - if(dill_slow(ch->done)) {errno = EPIPE; return -1;} - /* If there's a sender waiting, copy the message directly from the sender. */ - if(!dill_list_empty(&ch->out)) { - struct dill_chclause *chcl = dill_cont(dill_list_next(&ch->out), - struct dill_chclause, item); - memcpy(val, chcl->val, len); - dill_trigger(&chcl->cl, 0); - return 0; - } - /* The clause is not immediately available. */ - if(dill_slow(deadline == 0)) {errno = ETIMEDOUT; return -1;} - /* Let's wait. */ - struct dill_chclause chcl; - dill_list_insert(&chcl.item, &ch->in); - chcl.val = val; - dill_waitfor(&chcl.cl, 0, dill_chcancel); - struct dill_tmclause tmcl; - dill_timer(&tmcl, 1, deadline); - int id = dill_wait(); - if(dill_slow(id < 0)) return -1; - if(dill_slow(id == 1)) {errno = ETIMEDOUT; return -1;} - if(dill_slow(errno != 0)) return -1; - return 0; -} - -static int dill_chan_done(struct hvfs *vfs, int64_t deadline) { - struct dill_chan *ch = (struct dill_chan*)vfs; - dill_assert(ch); - if(ch->done) {errno = EPIPE; return -1;} - ch->done = 1; - /* Resume any remaining senders and receivers on the channel - with the EPIPE error. */ - while(!dill_list_empty(&ch->in)) { - struct dill_chclause *chcl = dill_cont(dill_list_next(&ch->in), - struct dill_chclause, item); - dill_trigger(&chcl->cl, EPIPE); - } - while(!dill_list_empty(&ch->out)) { - struct dill_chclause *chcl = dill_cont(dill_list_next(&ch->out), - struct dill_chclause, item); - dill_trigger(&chcl->cl, EPIPE); - } - return 0; -} - -int choose(struct chclause *clauses, int nclauses, int64_t deadline) { - int rc = dill_canblock(); - if(dill_slow(rc < 0)) return -1; - if(dill_slow(nclauses < 0 || (nclauses != 0 && !clauses))) { - errno = EINVAL; return -1;} - int i; - for(i = 0; i != nclauses; ++i) { - struct chclause *cl = &clauses[i]; - struct dill_chan *ch = hquery(cl->ch, dill_chan_type); - if(dill_slow(!ch)) return i; - if(dill_slow(cl->len != ch->sz || (cl->len > 0 && !cl->val))) { - errno = EINVAL; return i;} - struct dill_chclause *chcl; - switch(cl->op) { - case CHSEND: - if(dill_slow(ch->done)) {errno = EPIPE; return i;} - if(dill_list_empty(&ch->in)) break; - chcl = dill_cont(dill_list_next(&ch->in), - struct dill_chclause, item); - memcpy(chcl->val, cl->val, cl->len); - dill_trigger(&chcl->cl, 0); - errno = 0; - return i; - case CHRECV: - if(dill_slow(ch->done)) {errno = EPIPE; return i;} - if(dill_list_empty(&ch->out)) break; - chcl = dill_cont(dill_list_next(&ch->out), - struct dill_chclause, item); - memcpy(cl->val, chcl->val, ch->sz); - dill_trigger(&chcl->cl, 0); - errno = 0; - return i; - default: - errno = EINVAL; - return i; - } - } - /* There are no clauses immediately available. */ - if(dill_slow(deadline == 0)) {errno = ETIMEDOUT; return -1;} - /* Let's wait. */ - struct dill_chclause chcls[nclauses]; - for(i = 0; i != nclauses; ++i) { - struct dill_chan *ch = hquery(clauses[i].ch, dill_chan_type); - dill_assert(ch); - dill_list_insert(&chcls[i].item, - clauses[i].op == CHRECV ? &ch->in : &ch->out); - chcls[i].val = clauses[i].val; - dill_waitfor(&chcls[i].cl, i, dill_chcancel); - } - struct dill_tmclause tmcl; - dill_timer(&tmcl, nclauses, deadline); - int id = dill_wait(); - if(dill_slow(id < 0)) return -1; - if(dill_slow(id == nclauses)) {errno = ETIMEDOUT; return -1;} - return id; -} - diff --git a/Sources/CLibdill/config.h b/Sources/CLibdill/config.h deleted file mode 100644 index e7e80e0..0000000 --- a/Sources/CLibdill/config.h +++ /dev/null @@ -1,30 +0,0 @@ -/* confdefs.h */ -#define PACKAGE_NAME "libdill" -#define PACKAGE_TARNAME "libdill" -#define PACKAGE_VERSION "1.6" -#define PACKAGE_STRING "libdill 1.6" -#define PACKAGE_BUGREPORT "libmill@freelists.org" -#define PACKAGE_URL "http://libdill.org/" -#define PACKAGE "libdill" -#define VERSION "1.6" -#define DILL_THREADS 1 -#define DILL_PTHREAD 1 -#define HAVE_POSIX_MEMALIGN 1 -#define HAVE_MPROTECT 1 -#define HAVE_CLOCK_GETTIME 1 -#define HAVE_KQUEUE 1 -#define HAVE_KQUEUE 1 -#define HAVE_STRUCT_SOCKADDR_SA_LEN 1 -#define STDC_HEADERS 1 -#define HAVE_SYS_TYPES_H 1 -#define HAVE_SYS_STAT_H 1 -#define HAVE_STDLIB_H 1 -#define HAVE_STRING_H 1 -#define HAVE_MEMORY_H 1 -#define HAVE_STRINGS_H 1 -#define HAVE_INTTYPES_H 1 -#define HAVE_STDINT_H 1 -#define HAVE_UNISTD_H 1 -#define HAVE_DLFCN_H 1 -#define LT_OBJDIR ".libs/" -#define DILL_SHARED 1 diff --git a/Sources/CLibdill/cr.c b/Sources/CLibdill/cr.c deleted file mode 100644 index 394f6d5..0000000 --- a/Sources/CLibdill/cr.c +++ /dev/null @@ -1,562 +0,0 @@ -/* - - Copyright (c) 2016 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#include -#include -#include -#include - -#if defined DILL_VALGRIND -#include -#endif - -#include "cr.h" -#include "pollset.h" -#include "stack.h" -#include "utils.h" -#include "ctx.h" - -/******************************************************************************/ -/* Autorelease pool fix. */ -/******************************************************************************/ - -/* On darwin most foundation reference types leak memory due to a lack of a autorelease - pool. Because of this we need to push and pop the pool frequently during libmill's - context switches. This dynamically finds the objc runtime functions and inserts - the push/pop calls appropriately. If any part of the rest of the application adds its own - autorelease pool it must do so that it does not span across a libmill context switch - otherwise the objc runtime will throw a fatal error. */ -#ifdef __APPLE__ -#include -#include -#include -#include - -static void *autoreleasePool = NULL; -static int runningTests = 0; -static int darwinPrepared = 0; - -static Class (*objc_getClass_fptr)(const char *name); -static id (*objc_msgSend_fptr)(id self, SEL, ...); -static SEL (*sel_getUid_fptr)(const char *str); - -static void *(*objc_autoreleasePoolPush_fptr)(void); -static void (*objc_autoreleasePoolPop_fptr)(void *ctx); - -/* Prepare the darwin environment, this mainly looks up Objective-C runtime - functions and also determines whether or not the process is running from - XCTest. The autorelease pools will only be added if not running in XCTest - because XCTest runs it's own autorelease pool around each test and if we - insert our own we corrupt the runtime. It's hard to fix because of how - libmill switches contexts. */ -void darwin_prepare() { - if (darwinPrepared) { - return; - } - - void *handle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL); - - if (handle) { - /* Using the dlsym find the objc runtime functions we need */ - objc_getClass_fptr = dlsym(handle, "objc_getClass"); - objc_msgSend_fptr = dlsym(handle, "objc_msgSend"); - sel_getUid_fptr = dlsym(handle, "sel_getUid"); - objc_autoreleasePoolPush_fptr = dlsym(handle, "objc_autoreleasePoolPush"); - objc_autoreleasePoolPop_fptr = dlsym(handle, "objc_autoreleasePoolPop"); - - /* This is a really elogated way to determine if we're running inside of XCTest. - Because some users may accidentally import XCTest into their binary we don't - just want to do class detection. - - This grabs [[[[NSProcessInfo processInfo] arguments] description] UTF8String] - and searches it for /Xcode/Agents/xctest OR /usr/bin/xctest OR PackageTests.xctest - in the future these searches may not be valid and need to be tweaked. */ - Class processInfoClass = objc_getClass_fptr("NSProcessInfo"); - id processInfo = objc_msgSend_fptr((id)processInfoClass, sel_getUid_fptr("processInfo")); - id arguments = objc_msgSend_fptr(processInfo, sel_getUid_fptr("arguments")); - id description = objc_msgSend_fptr(arguments, sel_getUid_fptr("description")); - const char *chars = (const char *)objc_msgSend_fptr(description, sel_getUid_fptr("UTF8String")); - - runningTests = (strstr(chars, "/Xcode/Agents/xctest") || - strstr(chars, "/usr/bin/xctest") || - strstr(chars, "PackageTests.xctest")); - - darwinPrepared = 1; - } - - if (!darwinPrepared) { - printf("libmill failed to prepare for Darwin platform."); - dill_assert(0); - } -} - -static inline void darwin_pool_push() { - darwin_prepare(); - - if (runningTests) { - return; - } - - dill_assert(!autoreleasePool); - autoreleasePool = objc_autoreleasePoolPush_fptr(); -} - -static inline void darwin_pool_pop() { - darwin_prepare(); - - if (runningTests) { - return; - } - - if (autoreleasePool) { - objc_autoreleasePoolPop_fptr(autoreleasePool); - autoreleasePool = NULL; - } -} - -static inline void darwin_pool_pop_push() { - darwin_prepare(); - - if (runningTests) { - return; - } - - if (autoreleasePool) { - objc_autoreleasePoolPop_fptr(autoreleasePool); - autoreleasePool = NULL; - } - - dill_assert(!autoreleasePool); - autoreleasePool = objc_autoreleasePoolPush_fptr(); -} -#endif - - -#if defined DILL_CENSUS - -/* When taking the stack size census, we will keep the maximum stack size in a list - indexed by the go() call, i.e., by file name and line number. */ -struct dill_census_item { - struct dill_slist crs; - const char *file; - int line; - size_t max_stack; -}; - -#endif - -/* Storage for the constant used by the go() macro. */ -volatile void *dill_unoptimisable = NULL; - -/******************************************************************************/ -/* Helpers. */ -/******************************************************************************/ - -static void dill_resume(struct dill_cr *cr, int id, int err) { -#ifdef __APPLE__ - darwin_pool_pop_push(); -#endif - - struct dill_ctx_cr *ctx = &dill_getctx->cr; - cr->id = id; - cr->err = err; - dill_qlist_push(&ctx->ready, &cr->ready); -} - -int dill_canblock(void) { - struct dill_ctx_cr *ctx = &dill_getctx->cr; - if(dill_slow(ctx->r->no_blocking1 || ctx->r->no_blocking2)) { - errno = ECANCELED; return -1;} - return 0; -} - -int dill_no_blocking(int val) { - struct dill_ctx_cr *ctx = &dill_getctx->cr; - int old = ctx->r->no_blocking2; - ctx->r->no_blocking2 = val; - return old; -} - -/******************************************************************************/ -/* Context. */ -/******************************************************************************/ - -int dill_ctx_cr_init(struct dill_ctx_cr *ctx) { - /* This function is definitely called from the main coroutine, given that - it's called only once and you can't even create a different coroutine - without calling it. */ - ctx->r = &ctx->main; - dill_qlist_init(&ctx->ready); - dill_rbtree_init(&ctx->timers); - /* We can't use now() here as the context is still being intialized. */ - ctx->last_poll = mnow(); - /* Initialize the main coroutine. */ - memset(&ctx->main, 0, sizeof(ctx->main)); - ctx->main.ready.next = NULL; - dill_slist_init(&ctx->main.clauses); -#if defined DILL_CENSUS - dill_slist_init(&ctx->census); -#endif - return 0; -} - -void dill_ctx_cr_term(struct dill_ctx_cr *ctx) { -#if defined DILL_CENSUS - struct dill_slist *it; - for(it = dill_slist_next(&ctx->census); it != &ctx->census; - it = dill_slist_next(it)) { - struct dill_census_item *ci = - dill_cont(it, struct dill_census_item, crs); - fprintf(stderr, "%s:%d - maximum stack size %zu B\n", - ci->file, ci->line, ci->max_stack); - } -#endif -} - -/******************************************************************************/ -/* Timers. */ -/******************************************************************************/ - -static void dill_timer_cancel(struct dill_clause *cl) { - struct dill_ctx_cr *ctx = &dill_getctx->cr; - struct dill_tmclause *tmcl = dill_cont(cl, struct dill_tmclause, cl); - dill_rbtree_erase(&ctx->timers, &tmcl->item); - /* This is a safeguard. If an item isn't properly removed from the rb-tree, - we can spot the fact by seeing that the cr has been set to NULL. */ - tmcl->cl.cr = NULL; -} - -/* Adds a timer clause to the list of clauses being waited on. */ -void dill_timer(struct dill_tmclause *tmcl, int id, int64_t deadline) { - struct dill_ctx_cr *ctx = &dill_getctx->cr; - /* If the deadline is infinite, there's nothing to wait for. */ - if(deadline < 0) return; - dill_rbtree_insert(&ctx->timers, deadline, &tmcl->item); - dill_waitfor(&tmcl->cl, id, dill_timer_cancel); -} - -/******************************************************************************/ -/* Handle implementation. */ -/******************************************************************************/ - -static const int dill_cr_type_placeholder = 0; -static const void *dill_cr_type = &dill_cr_type_placeholder; -static void *dill_cr_query(struct hvfs *vfs, const void *type); -static void dill_cr_close(struct hvfs *vfs); - -/******************************************************************************/ -/* Coroutine creation and termination */ -/******************************************************************************/ - -static void dill_cancel(struct dill_cr *cr, int err); - -/* The initial part of go(). Allocates a new stack and handle. */ -int dill_prologue(sigjmp_buf **jb, void **ptr, size_t len, - const char *file, int line) { -#ifdef __APPLE__ - darwin_pool_pop_push(); -#endif - - struct dill_ctx_cr *ctx = &dill_getctx->cr; - /* Return ECANCELED if shutting down. */ - int rc = dill_canblock(); - if(dill_slow(rc < 0)) {errno = ECANCELED; return -1;} - struct dill_cr *cr; - size_t stacksz; - if(!*ptr) { - /* Allocate a new stack. */ - cr = (struct dill_cr*)dill_allocstack(&stacksz); - if(dill_slow(!cr)) return -1; - } - else { - /* The stack is supplied by the user. - Align the top of the stack to a 16-byte boundary. */ - uintptr_t top = (uintptr_t)*ptr; - top += len; - top &= ~(uintptr_t)15; - stacksz = top - (uintptr_t)*ptr; - cr = (struct dill_cr*)top; - if(dill_slow(stacksz < sizeof(struct dill_cr))) { - errno = ENOMEM; return -1;} - } -#if defined DILL_CENSUS - /* Mark the bytes in the stack as unused. */ - uint8_t *bottom = ((char*)cr) - stacksz; - int i; - for(i = 0; i != stacksz; ++i) - bottom[i] = 0xa0 + (i % 13); -#endif - --cr; - cr->vfs.query = dill_cr_query; - cr->vfs.close = dill_cr_close; - cr->vfs.done = NULL; - int hndl = hmake(&cr->vfs); - if(dill_slow(hndl < 0)) { - int err = errno; dill_freestack(cr + 1); errno = err; return -1;} - cr->ready.next = NULL; - dill_slist_init(&cr->clauses); - cr->closer = NULL; - cr->no_blocking1 = 0; - cr->no_blocking2 = 0; - cr->done = 0; - cr->mem = *ptr ? 1 : 0; -#if defined DILL_VALGRIND - cr->sid = VALGRIND_STACK_REGISTER((char*)(cr + 1) - stacksz, cr); -#endif -#if defined DILL_CENSUS - /* Find the appropriate census item if it exists. It's O(n) but meh. */ - cr->census = NULL; - struct dill_slist *it; - for(it = dill_slist_next(&ctx->census); it != &ctx->census; - it = dill_slist_next(it)) { - cr->census = dill_cont(it, struct dill_census_item, crs); - if(cr->census->line == line && strcmp(cr->census->file, file) == 0) - break; - } - /* Allocate it if it does not exist. */ - if(it == &ctx->census) { - cr->census = malloc(sizeof(struct dill_census_item)); - dill_assert(cr->census); - dill_slist_push(&ctx->census, &cr->census->crs); - cr->census->file = file; - cr->census->line = line; - cr->census->max_stack = 0; - } - cr->stacksz = stacksz - sizeof(struct dill_cr); -#endif - /* Return the context of the parent coroutine to the caller so that it can - store its current state. It can't be done here because we are at the - wrong stack frame here. */ - *jb = &ctx->r->ctx; - /* Add parent coroutine to the list of coroutines ready for execution. */ - dill_resume(ctx->r, 0, 0); - /* Mark the new coroutine as running. */ - *ptr = ctx->r = cr; - return hndl; -} - -/* The final part of go(). Gets called when the coroutine is finished. */ -void dill_epilogue(void) { -#ifdef __APPLE__ - darwin_pool_pop_push(); -#endif - - struct dill_ctx_cr *ctx = &dill_getctx->cr; - /* Mark the coroutine as finished. */ - ctx->r->done = 1; - /* If there's a coroutine waiting for us to finish, unblock it now. */ - if(ctx->r->closer) - dill_cancel(ctx->r->closer, 0); - /* With no clauses added, this call will never return. */ - dill_assert(dill_slist_empty(&ctx->r->clauses)); - dill_wait(); -} - -static void *dill_cr_query(struct hvfs *vfs, const void *type) { - if(dill_slow(type != dill_cr_type)) {errno = ENOTSUP; return NULL;} - struct dill_cr *cr = dill_cont(vfs, struct dill_cr, vfs); - return cr; -} - -/* Gets called when coroutine handle is closed. */ -static void dill_cr_close(struct hvfs *vfs) { - struct dill_ctx_cr *ctx = &dill_getctx->cr; - struct dill_cr *cr = dill_cont(vfs, struct dill_cr, vfs); - /* If the coroutine has already finished, we are done. */ - if(!cr->done) { - /* No blocking calls from this point on. */ - cr->no_blocking1 = 1; - /* Resume the coroutine if it was blocked. */ - if(!cr->ready.next) - dill_cancel(cr, ECANCELED); - /* Wait for the coroutine to stop executing. With no clauses added, - the only mechanism to resume is through dill_cancel(). This is not really - a blocking call, although it looks like one. Given that the coroutine - that is being shut down is not permitted to block, we should get - control back pretty quickly. */ - cr->closer = ctx->r; - int rc = dill_wait(); - dill_assert(rc == -1 && errno == 0); - } -#if defined DILL_CENSUS - /* Find the first overwritten byte on the stack. - Determine stack usage based on that. */ - uint8_t *bottom = ((uint8_t*)cr) - cr->stacksz; - int i; - for(i = 0; i != cr->stacksz; ++i) { - if(bottom[i] != 0xa0 + (i % 13)) { - /* dill_cr is located on the stack so we have to take that into account. - Also, it may be necessary to align the top of the stack to - a 16-byte boundary, so add 16 bytes to account for that. */ - size_t used = cr->stacksz - i - sizeof(struct dill_cr) + 16; - if(used > cr->census->max_stack) - cr->census->max_stack = used; - break; - } - } -#endif -#if defined DILL_VALGRIND - VALGRIND_STACK_DEREGISTER(cr->sid); -#endif - /* Now that the coroutine is finished, deallocate it. */ - if(!cr->mem) dill_freestack(cr + 1); -} - -/******************************************************************************/ -/* Suspend/resume functionality. */ -/******************************************************************************/ - -void dill_waitfor(struct dill_clause *cl, int id, - void (*cancel)(struct dill_clause *cl)) { - struct dill_ctx_cr *ctx = &dill_getctx->cr; - /* Add a clause to the coroutine list of active clauses. */ - cl->cr = ctx->r; - dill_slist_push(&ctx->r->clauses, &cl->item); - cl->id = id; - cl->cancel = cancel; -} - -int dill_wait(void) { -#ifdef __APPLE__ - darwin_pool_pop_push(); -#endif - - struct dill_ctx_cr *ctx = &dill_getctx->cr; - /* Store the context of the current coroutine, if any. */ - if(dill_setjmp(ctx->r->ctx)) { - /* We get here once the coroutine is resumed. */ - dill_slist_init(&ctx->r->clauses); - errno = ctx->r->err; - return ctx->r->id; - } - /* For performance reasons, we want to avoid excessive checking of current - time, so we cache the value here. It will be recomputed only after - a blocking call. */ - int64_t nw = now(); - /* Wait for timeouts and external events. However, if there are ready - coroutines there's no need to poll for external events every time. - Still, we'll do it at least once a second. The external signal may - very well be a deadline or a user-issued command that cancels the CPU - intensive operation. */ - if(dill_qlist_empty(&ctx->ready) || nw > ctx->last_poll + 1000) { - int block = dill_qlist_empty(&ctx->ready); - while(1) { - /* Compute the timeout for the subsequent poll. */ - int timeout = 0; - if(block) { - if(dill_rbtree_empty(&ctx->timers)) - timeout = -1; - else { - int64_t deadline = dill_cont( - dill_rbtree_first(&ctx->timers), - struct dill_tmclause, item)->item.val; - timeout = (int) (nw >= deadline ? 0 : deadline - nw); - } - } - /* Wait for events. */ - int fired = dill_pollset_poll(timeout); - if(timeout != 0) nw = now(); - if(dill_slow(fired < 0)) continue; - /* Fire all expired timers. */ - if(!dill_rbtree_empty(&ctx->timers)) { - while(!dill_rbtree_empty(&ctx->timers)) { - struct dill_tmclause *tmcl = dill_cont( - dill_rbtree_first(&ctx->timers), - struct dill_tmclause, item); - if(tmcl->item.val > nw) - break; - dill_trigger(&tmcl->cl, ETIMEDOUT); - fired = 1; - } - } - /* Never retry the poll when in non-blocking mode. */ - if(!block || fired) - break; - /* If the timeout was hit but there were no expired timers, do the poll - again. It can happen if the timers were canceled in the - meantime. */ - } - ctx->last_poll = nw; - } - /* There's a coroutine ready to be executed so jump to it. */ - struct dill_slist *it = dill_qlist_pop(&ctx->ready); - it->next = NULL; - ctx->r = dill_cont(it, struct dill_cr, ready); - /* dill_longjmp has to be at the end of a function body, otherwise stack - unwinding information will be trimmed if a crash occurs in this - function. */ - dill_longjmp(ctx->r->ctx); - -#ifdef __APPLE__ - darwin_pool_pop_push(); -#endif - - return 0; -} - -static void dill_docancel(struct dill_cr *cr, int id, int err) { - /* Sanity check: Make sure that the coroutine was really suspended. */ - dill_assert(!cr->ready.next); - /* Remove the clauses from endpoints' lists of waiting coroutines. */ - struct dill_slist *it; - for(it = dill_slist_next(&cr->clauses); it != &cr->clauses; - it = dill_slist_next(it)) { - struct dill_clause *cl = dill_cont(it, struct dill_clause, item); - if(cl->cancel) cl->cancel(cl); - } - /* Schedule the newly unblocked coroutine for execution. */ - dill_resume(cr, id, err); -} - -void dill_trigger(struct dill_clause *cl, int err) { - dill_docancel(cl->cr, cl->id, err); -} - -static void dill_cancel(struct dill_cr *cr, int err) { - dill_docancel(cr, -1, err); -} - -int yield(void) { - struct dill_ctx_cr *ctx = &dill_getctx->cr; - int rc = dill_canblock(); - if(dill_slow(rc < 0)) return -1; - /* Put the current coroutine into the ready queue. */ - dill_resume(ctx->r, 0, 0); - /* Suspend. */ - return dill_wait(); -} - -int co(void **ptr, size_t len, void *fn, const char *file, int line, void (*routine)(void *)) { - sigjmp_buf *ctx; - void *stk = (ptr); - int h = dill_prologue(&ctx, &stk, len, file, line); - - if(h >= 0) { - if(!dill_setjmp(*ctx)) { - DILL_SETSP(stk); - routine(fn); - dill_epilogue(); - } - } - - return h; -} diff --git a/Sources/CLibdill/cr.h b/Sources/CLibdill/cr.h deleted file mode 100644 index eba2187..0000000 --- a/Sources/CLibdill/cr.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - - Copyright (c) 2016 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#ifndef DILL_CR_INCLUDED -#define DILL_CR_INCLUDED - -#include - -#include "libdillimpl.h" -#include "qlist.h" -#include "rbtree.h" -#include "slist.h" - -/* The coroutine. The memory layout looks like this: - +-------------------------------------------------------------+---------+ - | stack | dill_cr | - +-------------------------------------------------------------+---------+ - - dill_cr contains generic book-keeping info about the coroutine - - the stack is a standard C stack; it grows downwards (at the moment, libdill - doesn't support microarchitectures where stacks grow upwards) -*/ -struct dill_cr { - /* When the coroutine is ready for execution but not running yet, - it lives on this list (ctx->ready). 'id' is the result value to return - from dill_wait() when the coroutine is resumed. Additionally, errno - will be set to 'err'. */ - struct dill_slist ready; - /* Virtual function table. */ - struct hvfs vfs; - int id; - int err; - /* When the coroutine is suspended 'ctx' holds the context - (registers and such).*/ - sigjmp_buf ctx; - /* If the coroutine is blocked, here's the list of the clauses it's waiting on. */ - struct dill_slist clauses; - /* There are two possible reasons to disable blocking calls. - 1. The coroutine is being closed by its owner. - 2. The execution is happening within the context of an hclose() call. */ - unsigned int no_blocking1 : 1; - unsigned int no_blocking2 : 1; - /* Set when the coroutine has finished its execution. */ - unsigned int done : 1; - /* If true, the coroutine was launched with go_mem. */ - unsigned int mem : 1; - /* When the coroutine handle is being closed, this points to the - coroutine that is doing the hclose() call. */ - struct dill_cr *closer; -#if defined DILL_VALGRIND - /* Valgrind stack identifier. This way, valgrind knows which areas of - memory are used as stacks, and so it doesn't produce spurious warnings. - Well, sort of. The mechanism is not perfect, but it's still better - than nothing. */ - int sid; -#endif -#if defined DILL_CENSUS - /* Census record corresponding to this coroutine. */ - struct dill_census_item *census; - size_t stacksz; -#endif -/* Clang assumes that the client stack is aligned to 16-bytes on x86-64 - architectures. To achieve this, we align this structure (with the added - benefit of a minor optimization). */ -} __attribute__((aligned(16))); - -struct dill_ctx_cr { - /* Currently running coroutine. */ - struct dill_cr *r; - /* List of coroutines ready for execution. */ - struct dill_qlist ready; - /* All active timers. */ - struct dill_rbtree timers; - /* Last time poll was performed. */ - int64_t last_poll; - /* The main coroutine. We don't control the creation of the main coroutine's stack, - so we have to store this info here instead of the top of the stack. */ - struct dill_cr main; -#if defined DILL_CENSUS - struct dill_slist census; -#endif -}; - -struct dill_clause { - /* The coroutine that owns this clause. */ - struct dill_cr *cr; - /* List of the clauses the coroutine is waiting on. See dill_cr::clauses. */ - struct dill_slist item; - /* Number to return from dill_wait() if this clause triggers. */ - int id; - /* Function to call when this clause is canceled. */ - void (*cancel)(struct dill_clause *cl); -}; - -/* Timer clause. */ -struct dill_tmclause { - struct dill_clause cl; - /* An item in dill_ctx_cr::timers. */ - struct dill_rbtree_item item; -}; - -/* File descriptor clause. */ -struct dill_fdclause; - -int dill_ctx_cr_init(struct dill_ctx_cr *ctx); -void dill_ctx_cr_term(struct dill_ctx_cr *ctx); - -/* When dill_wait() is called next time, the coroutine will wait - (among other clauses) on this clause. 'id' must not be negative. - 'cancel' is a function to be called when the clause is canceled - without being triggered. */ -void dill_waitfor(struct dill_clause *cl, int id, - void (*cancel)(struct dill_clause *cl)); - -/* Suspend running coroutine. Move to executing different coroutines. - The coroutine will be resumed once one of the clauses previously added by - dill_waitfor() is triggered. When that happens, all the clauses, whether - triggered or not, will be canceled. The function returns the ID of the triggered - clause or -1 on error. In either case, it sets errno to 0 indicate - success or non-zero value to indicate error. */ -int dill_wait(void); - -/* Schedule a previously suspended coroutine for execution. Keep in mind that this - doesn't immediately run it, it just puts it into the coroutine ready queue. - It will cause dill_wait() to return the id supplied in dill_waitfor(). */ -void dill_trigger(struct dill_clause *cl, int err); - -/* Add a timer to the list of active clauses. */ -void dill_timer(struct dill_tmclause *tmcl, int id, int64_t deadline); - -/* Returns 0 if blocking functions are allowed. - Returns -1 and sets errno to ECANCELED otherwise. */ -int dill_canblock(void); - -/* When set to 1, blocking calls return ECANCELED. - Returns the old value of the flag */ -int dill_no_blocking(int val); - -/* Cleans cached info about the fd. */ -int dill_clean(int fd); - -#endif - - diff --git a/Sources/CLibdill/crlf.c b/Sources/CLibdill/crlf.c deleted file mode 100644 index 0744363..0000000 --- a/Sources/CLibdill/crlf.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - - Copyright (c) 2017 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#include -#include "libdillimpl.h" -#include -#include - -#include "utils.h" - -dill_unique_id(crlf_type); - -static void *crlf_hquery(struct hvfs *hvfs, const void *type); -static void crlf_hclose(struct hvfs *hvfs); -static int crlf_hdone(struct hvfs *hvfs, int64_t deadline); -static int crlf_msendl(struct msock_vfs *mvfs, - struct iolist *first, struct iolist *last, int64_t deadline); -static ssize_t crlf_mrecvl(struct msock_vfs *mvfs, - struct iolist *first, struct iolist *last, int64_t deadline); - -struct crlf_sock { - struct hvfs hvfs; - struct msock_vfs mvfs; - int u; - /* Given that we are doing one recv call per byte, let's cache the pointer - to bsock interface of the underlying socket to make it faster. */ - struct bsock_vfs *uvfs; - unsigned int indone : 1; - unsigned int outdone : 1; - unsigned int inerr : 1; - unsigned int outerr : 1; -}; - -static void *crlf_hquery(struct hvfs *hvfs, const void *type) { - struct crlf_sock *self = (struct crlf_sock*)hvfs; - if(type == msock_type) return &self->mvfs; - if(type == crlf_type) return self; - errno = ENOTSUP; - return NULL; -} - -int crlf_attach(int s) { - int err; - /* Make a private copy of the underlying socket. */ - int u = hdup(s); - if(dill_slow(u < 0)) return -1; - int rc = hclose(s); - dill_assert(rc == 0); - /* Create the object. */ - struct crlf_sock *self = malloc(sizeof(struct crlf_sock)); - if(dill_slow(!self)) {err = ENOMEM; goto error1;} - self->hvfs.query = crlf_hquery; - self->hvfs.close = crlf_hclose; - self->hvfs.done = crlf_hdone; - self->mvfs.msendl = crlf_msendl; - self->mvfs.mrecvl = crlf_mrecvl; - self->u = u; - self->uvfs = hquery(u, bsock_type); - if(dill_slow(!self->uvfs && errno == ENOTSUP)) {err = EPROTO; goto error2;} - if(dill_slow(!self->uvfs)) {err = errno; goto error2;} - self->indone = 0; - self->outdone = 0; - self->inerr = 0; - self->outerr = 0; - /* Create the handle. */ - int h = hmake(&self->hvfs); - if(dill_slow(h < 0)) {err = errno; goto error2;} - return h; -error2: - free(self); -error1: - rc = hclose(u); - dill_assert(rc == 0); - errno = err; - return -1; -} - -static int crlf_hdone(struct hvfs *hvfs, int64_t deadline) { - struct crlf_sock *self = (struct crlf_sock*)hvfs; - if(dill_slow(self->outdone)) {errno = EPIPE; return -1;} - if(dill_slow(self->outerr)) {errno = ECONNRESET; return -1;} - int rc = bsend(self->u, "\r\n", 2, deadline); - if(dill_slow(rc < 0)) {self->outerr = 1; return -1;} - self->outdone = 1; - return 0; -} - -int crlf_detach(int s, int64_t deadline) { - int err; - struct crlf_sock *self = hquery(s, crlf_type); - if(dill_slow(!self)) return -1; - if(dill_slow(self->inerr || self->outerr)) {err = ECONNRESET; goto error;} - /* If not done already start the terminal handshake. */ - if(!self->outdone) { - int rc = crlf_hdone(&self->hvfs, deadline); - if(dill_slow(rc < 0)) {err = errno; goto error;} - } - /* Drain incoming messages until termination message is received. */ - while(1) { - ssize_t sz = crlf_mrecvl(&self->mvfs, NULL, NULL, deadline); - if(sz < 0 && errno == EPIPE) break; - if(dill_slow(sz < 0)) {err = errno; goto error;} - } - int u = self->u; - free(self); - return u; -error: - crlf_hclose(&self->hvfs); - errno = err; - return -1; -} - -static int crlf_msendl(struct msock_vfs *mvfs, - struct iolist *first, struct iolist *last, int64_t deadline) { - struct crlf_sock *self = dill_cont(mvfs, struct crlf_sock, mvfs); - if(dill_slow(self->outdone)) {errno = EPIPE; return -1;} - if(dill_slow(self->outerr)) {errno = ECONNRESET; return -1;} - /* Make sure that message doesn't contain CRLF sequence. */ - uint8_t c = 0; - size_t sz = 0; - struct iolist *it; - for(it = first; it; it = it->iol_next) { - int i; - for(i = 0; i != it->iol_len; ++i) { - uint8_t c2 = ((uint8_t*)it->iol_base)[i]; - if(dill_slow(c == '\r' && c2 == '\n')) { - self->outerr = 1; errno = EINVAL; return -1;} - c = c2; - } - sz += it->iol_len; - } - /* Can't send empty line. Empty line is used as protocol terminator. */ - if(dill_slow(sz == 0)) {self->outerr = 1; errno = EINVAL; return -1;} - struct iolist iol = {(void*)"\r\n", 2, NULL, 0}; - last->iol_next = &iol; - int rc = self->uvfs->bsendl(self->uvfs, first, &iol, deadline); - last->iol_next = NULL; - if(dill_slow(rc < 0)) {self->outerr = 1; return -1;} - return 0; -} - -static ssize_t crlf_mrecvl(struct msock_vfs *mvfs, - struct iolist *first, struct iolist *last, int64_t deadline) { - struct crlf_sock *self = dill_cont(mvfs, struct crlf_sock, mvfs); - if(dill_slow(self->indone)) {errno = EPIPE; return -1;} - if(dill_slow(self->inerr)) {errno = ECONNRESET; return -1;} - size_t recvd = 0; - char c1 = 0; - char c2 = 0; - struct iolist iol = {&c2, 1, NULL, 0}; - struct iolist *it = first; - size_t column = 0; - while(1) { - /* The pipeline looks like this: buffer <- c1 <- c2 <- socket */ - /* buffer <- c1 */ - if(first) { - if(!it) {self->inerr = 1; errno = EMSGSIZE; return -1;} - if(recvd > 1) { - if(it->iol_base) ((char*)it->iol_base)[column] = c1; - ++column; - if(column == it->iol_len) { - column = 0; - it = it->iol_next; - } - } - } - /* c1 <- c2 */ - c1 = c2; - /* c2 <- socket */ - int rc = self->uvfs->brecvl(self->uvfs, &iol, &iol, deadline); - if(dill_slow(rc < 0)) {self->inerr = 1; return -1;} - ++recvd; - if(c1 == '\r' && c2 == '\n') break; - } - /* Empty line means that peer is terminating. */ - if(dill_slow(recvd == 2)) {self->indone = 1; errno = EPIPE; return -1;} - return recvd - 2; -} - -static void crlf_hclose(struct hvfs *hvfs) { - struct crlf_sock *self = (struct crlf_sock*)hvfs; - if(dill_fast(self->u >= 0)) { - int rc = hclose(self->u); - dill_assert(rc == 0); - } - free(self); -} - diff --git a/Sources/CLibdill/ctx.c b/Sources/CLibdill/ctx.c deleted file mode 100644 index 3ef7e37..0000000 --- a/Sources/CLibdill/ctx.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - - Copyright (c) 2016 Tai Chi Minh Ralph Eastwood - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#include "ctx.h" - -#if !defined DILL_THREADS - -struct dill_ctx dill_ctx_ = {0}; - -static void dill_ctx_atexit(void) { - dill_ctx_pollset_term(&dill_ctx_.pollset); - dill_ctx_stack_term(&dill_ctx_.stack); - dill_ctx_handle_term(&dill_ctx_.handle); - dill_ctx_cr_term(&dill_ctx_.cr); - dill_ctx_now_term(&dill_ctx_.now); -} - -struct dill_ctx *dill_ctx_init(void) { - int rc = dill_ctx_now_init(&dill_ctx_.now); - dill_assert(rc == 0); - rc = dill_ctx_cr_init(&dill_ctx_.cr); - dill_assert(rc == 0); - rc = dill_ctx_handle_init(&dill_ctx_.handle); - dill_assert(rc == 0); - rc = dill_ctx_stack_init(&dill_ctx_.stack); - dill_assert(rc == 0); - rc = dill_ctx_pollset_init(&dill_ctx_.pollset); - dill_assert(rc == 0); - rc = atexit(dill_ctx_atexit); - dill_assert(rc == 0); - dill_ctx_.initialized = 1; - return &dill_ctx_; -} - -#else - -#include - -/* Determine whether current thread is the main thread. */ -#if defined __linux__ -#define _GNU_SOURCE -#include -#include -static int dill_ismain() { - return syscall(SYS_gettid) == getpid(); -} -#elif defined __OpenBSD__ || defined __FreeBSD__ || \ - defined __APPLE__ || defined __DragonFly__ -#if defined __FreeBSD__ -#include -#endif -static int dill_ismain() { - return pthread_main_np(); -} -#elif defined __NetBSD__ -#include -static int dill_ismain() { - return _lwp_self() == 1; -} -#elif defined __sun -static int dill_ismain() { - return pthread_self() == 1; -} -#else -#error "Cannot determine which thread is the main thread." -#endif - -#if defined __GNUC__ && !defined DILL_THREAD_FALLBACK - -__thread struct dill_ctx dill_ctx_ = {0}; - -static pthread_key_t dill_key; -static pthread_once_t dill_keyonce = PTHREAD_ONCE_INIT; -static void *dill_main = NULL; - -static void dill_ctx_term(void *ptr) { - struct dill_ctx *ctx = ptr; - dill_ctx_pollset_term(&ctx->pollset); - dill_ctx_stack_term(&ctx->stack); - dill_ctx_handle_term(&ctx->handle); - dill_ctx_cr_term(&ctx->cr); - dill_ctx_now_term(&ctx->now); - if(dill_ismain()) dill_main = NULL; -} - -static void dill_ctx_atexit(void) { - if(dill_main) dill_ctx_term(dill_main); -} - -static void dill_makekey(void) { - int rc = pthread_key_create(&dill_key, dill_ctx_term); - dill_assert(!rc); -} - -struct dill_ctx *dill_ctx_init(void) { - int rc = dill_ctx_now_init(&dill_ctx_.now); - dill_assert(rc == 0); - rc = dill_ctx_cr_init(&dill_ctx_.cr); - dill_assert(rc == 0); - rc = dill_ctx_handle_init(&dill_ctx_.handle); - dill_assert(rc == 0); - rc = dill_ctx_stack_init(&dill_ctx_.stack); - dill_assert(rc == 0); - rc = dill_ctx_pollset_init(&dill_ctx_.pollset); - dill_assert(rc == 0); - rc = pthread_once(&dill_keyonce, dill_makekey); - dill_assert(rc == 0); - if(dill_ismain()) { - dill_main = &dill_ctx_; - rc = atexit(dill_ctx_atexit); - dill_assert(rc == 0); - } - rc = pthread_setspecific(dill_key, &dill_ctx_); - dill_assert(rc == 0); - dill_ctx_.initialized = 1; - return &dill_ctx_; -} - -#else - -static pthread_key_t dill_key; -static pthread_once_t dill_keyonce = PTHREAD_ONCE_INIT; -static void *dill_main = NULL; - -static void dill_ctx_term(void *ptr) { - struct dill_ctx *ctx = ptr; - dill_ctx_pollset_term(&ctx->pollset); - dill_ctx_stack_term(&ctx->stack); - dill_ctx_handle_term(&ctx->handle); - dill_ctx_cr_term(&ctx->cr); - dill_ctx_now_term(&ctx->now); - free(ctx); - if(dill_ismain()) dill_main = NULL; -} - -static void dill_ctx_atexit(void) { - if(dill_main) dill_ctx_term(dill_main); -} - -static void dill_makekey(void) { - int rc = pthread_key_create(&dill_key, dill_ctx_term); - dill_assert(!rc); -} - -struct dill_ctx *dill_getctx_(void) { - int rc = pthread_once(&dill_keyonce, dill_makekey); - dill_assert(rc == 0); - struct dill_ctx *ctx = pthread_getspecific(dill_key); - if(dill_fast(ctx)) return ctx; - ctx = malloc(sizeof(struct dill_ctx)); - dill_assert(ctx); - rc = dill_ctx_now_init(&ctx->now); - dill_assert(rc == 0); - rc = dill_ctx_cr_init(&ctx->cr); - dill_assert(rc == 0); - rc = dill_ctx_handle_init(&ctx->handle); - dill_assert(rc == 0); - rc = dill_ctx_stack_init(&ctx->stack); - dill_assert(rc == 0); - rc = dill_ctx_pollset_init(&ctx->pollset); - dill_assert(rc == 0); - if(dill_ismain()) { - dill_main = ctx; - rc = atexit(dill_ctx_atexit); - dill_assert(rc == 0); - } - rc = pthread_setspecific(dill_key, ctx); - dill_assert(rc == 0); - return ctx; -} - -#endif - -#endif - diff --git a/Sources/CLibdill/ctx.h b/Sources/CLibdill/ctx.h deleted file mode 100644 index 890a6f4..0000000 --- a/Sources/CLibdill/ctx.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - - Copyright (c) 2016 Tai Chi Minh Ralph Eastwood - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#ifndef DILL_CTX_INCLUDED -#define DILL_CTX_INCLUDED - -#include "cr.h" -#include "handle.h" -#include "now.h" -#include "pollset.h" -#include "stack.h" - -struct dill_ctx { -#if !defined DILL_THREAD_FALLBACK - int initialized; -#endif - struct dill_ctx_now now; - struct dill_ctx_cr cr; - struct dill_ctx_handle handle; - struct dill_ctx_stack stack; - struct dill_ctx_pollset pollset; -}; - -struct dill_ctx *dill_ctx_init(void); - -#if !defined DILL_THREADS - -extern struct dill_ctx dill_ctx_; -#define dill_getctx \ - (dill_fast(dill_ctx_.initialized) ? &dill_ctx_ : dill_ctx_init()) - -#elif defined __GNUC__ && !defined DILL_THREAD_FALLBACK - -extern __thread struct dill_ctx dill_ctx_; -#define dill_getctx \ - (dill_fast(dill_ctx_.initialized) ? &dill_ctx_ : dill_ctx_init()) - -#else - -struct dill_ctx *dill_getctx_(void); -#define dill_getctx (dill_getctx_()) - -#endif - -#endif - diff --git a/Sources/CLibdill/dns/dns.c b/Sources/CLibdill/dns/dns.c deleted file mode 100644 index 630dcef..0000000 --- a/Sources/CLibdill/dns/dns.c +++ /dev/null @@ -1,9131 +0,0 @@ -/* ========================================================================== - * dns.c - Recursive, Reentrant DNS Resolver. - * -------------------------------------------------------------------------- - * Copyright (c) 2008, 2009, 2010, 2012, 2013, 2014, 2015 William Ahern - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to permit - * persons to whom the Software is furnished to do so, subject to the - * following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - * ========================================================================== - */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#if !defined(__FreeBSD__) && !defined(__sun) -#ifndef _XOPEN_SOURCE -#define _XOPEN_SOURCE 600 -#endif - -#if defined(__FreeBSD__) -#define HAVE_STRUCT_SOCKADDR_SA_LEN -#endif - -#undef _BSD_SOURCE -#define _BSD_SOURCE - -#undef _DARWIN_C_SOURCE -#define _DARWIN_C_SOURCE - -#undef _NETBSD_SOURCE -#define _NETBSD_SOURCE -#endif - -#include /* INT_MAX */ -#include /* offsetof() */ -#ifdef _WIN32 -#define uint32_t unsigned int -#else -#include /* uint32_t */ -#endif -#include /* malloc(3) realloc(3) free(3) rand(3) random(3) arc4random(3) */ -#include /* FILE fopen(3) fclose(3) getc(3) rewind(3) */ -#include /* memcpy(3) strlen(3) memmove(3) memchr(3) memcmp(3) strchr(3) strsep(3) strcspn(3) */ -#include /* strcasecmp(3) strncasecmp(3) */ -#include /* isspace(3) isdigit(3) */ -#include /* time_t time(2) difftime(3) */ -#include /* SIGPIPE sigemptyset(3) sigaddset(3) sigpending(2) sigprocmask(2) pthread_sigmask(3) sigtimedwait(2) */ -#include /* errno EINVAL ENOENT */ -#undef NDEBUG -#include /* assert(3) */ - -#if _WIN32 -#ifndef FD_SETSIZE -#define FD_SETSIZE 256 -#endif -#include -#include -#else -#include /* FD_SETSIZE socklen_t */ -#include /* FD_ZERO FD_SET fd_set select(2) */ -#include /* AF_INET AF_INET6 AF_UNIX struct sockaddr struct sockaddr_in struct sockaddr_in6 socket(2) */ -#if defined(AF_UNIX) -#include /* struct sockaddr_un */ -#endif -#include /* F_SETFD F_GETFL F_SETFL O_NONBLOCK fcntl(2) */ -#include /* _POSIX_THREADS gethostname(3) close(2) */ -#include /* POLLIN POLLOUT */ -#include /* struct sockaddr_in struct sockaddr_in6 */ -#include /* inet_pton(3) inet_ntop(3) htons(3) ntohs(3) */ -#include /* struct addrinfo */ -#endif - -#include "dns.h" - - -/* - * C O M P I L E R A N N O T A T I O N S - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#define DNS_GNUC_PREREQ(M, m) \ - (defined __GNUC__ && ((__GNUC__ > M) || (__GNUC__ == M && __GNUC_MINOR__ >= m))) - -#ifndef HAVE_PRAGMA_MESSAGE -#define HAVE_PRAGMA_MESSAGE (DNS_GNUC_PREREQ(4, 4) || __clang__ || _MSC_VER) -#endif - -#if __GNUC__ -#define DNS_NOTUSED __attribute__((unused)) -#define DNS_NORETURN __attribute__((noreturn)) -#else -#define DNS_NOTUSED -#define DNS_NORETURN -#endif - -#if __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-parameter" -#pragma clang diagnostic ignored "-Wmissing-field-initializers" -#elif DNS_GNUC_PREREQ(4, 6) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" -#pragma GCC diagnostic ignored "-Wmissing-field-initializers" -#endif - - -/* - * S T A N D A R D M A C R O S - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef lengthof -#define lengthof(a) (sizeof (a) / sizeof (a)[0]) -#endif - -#ifndef endof -#define endof(a) (&(a)[lengthof((a))]) -#endif - - -/* - * M I S C E L L A N E O U S C O M P A T - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#if _WIN32 || _WIN64 -#define PRIuZ "Iu" -#else -#define PRIuZ "zu" -#endif - -#ifndef DNS_THREAD_SAFE -#if (defined _REENTRANT || defined _THREAD_SAFE) && _POSIX_THREADS > 0 -#define DNS_THREAD_SAFE 1 -#else -#define DNS_THREAD_SAFE 0 -#endif -#endif - - -/* - * D E B U G M A C R O S - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -int dns_debug = 0; - -#if DNS_DEBUG - -#undef DNS_DEBUG -#define DNS_DEBUG dns_debug - -#define DNS_SAY_(fmt, ...) \ - do { if (DNS_DEBUG > 0) fprintf(stderr, fmt "%.1s", __func__, __LINE__, __VA_ARGS__); } while (0) -#define DNS_SAY(...) DNS_SAY_("@@ (%s:%d) " __VA_ARGS__, "\n") -#define DNS_HAI DNS_SAY("HAI") - -#define DNS_SHOW_(P, fmt, ...) do { \ - if (DNS_DEBUG > 1) { \ - fprintf(stderr, "@@ BEGIN * * * * * * * * * * * *\n"); \ - fprintf(stderr, "@@ " fmt "%.0s\n", __VA_ARGS__); \ - dns_p_dump((P), stderr); \ - fprintf(stderr, "@@ END * * * * * * * * * * * * *\n\n"); \ - } \ -} while (0) - -#define DNS_SHOW(...) DNS_SHOW_(__VA_ARGS__, "") - -#else /* !DNS_DEBUG */ - -#undef DNS_DEBUG -#define DNS_DEBUG 0 - -#define DNS_SAY(...) -#define DNS_HAI -#define DNS_SHOW(...) - -#endif /* DNS_DEBUG */ - - -/* - * V E R S I O N R O U T I N E S - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -const char *dns_vendor(void) { - return DNS_VENDOR; -} /* dns_vendor() */ - - -int dns_v_rel(void) { - return DNS_V_REL; -} /* dns_v_rel() */ - - -int dns_v_abi(void) { - return DNS_V_ABI; -} /* dns_v_abi() */ - - -int dns_v_api(void) { - return DNS_V_API; -} /* dns_v_api() */ - - -/* - * E R R O R R O U T I N E S - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#if _WIN32 - -#define DNS_EINTR WSAEINTR -#define DNS_EINPROGRESS WSAEINPROGRESS -#define DNS_EISCONN WSAEISCONN -#define DNS_EWOULDBLOCK WSAEWOULDBLOCK -#define DNS_EALREADY WSAEALREADY -#define DNS_EAGAIN EAGAIN -#define DNS_ETIMEDOUT WSAETIMEDOUT - -#define dns_syerr() ((int)GetLastError()) -#define dns_soerr() ((int)WSAGetLastError()) - -#else - -#define DNS_EINTR EINTR -#define DNS_EINPROGRESS EINPROGRESS -#define DNS_EISCONN EISCONN -#define DNS_EWOULDBLOCK EWOULDBLOCK -#define DNS_EALREADY EALREADY -#define DNS_EAGAIN EAGAIN -#define DNS_ETIMEDOUT ETIMEDOUT - -#define dns_syerr() errno -#define dns_soerr() errno - -#endif - - -const char *dns_strerror(int error) { - switch (error) { - case DNS_ENOBUFS: - return "DNS packet buffer too small"; - case DNS_EILLEGAL: - return "Illegal DNS RR name or data"; - case DNS_EORDER: - return "Attempt to push RR out of section order"; - case DNS_ESECTION: - return "Invalid section specified"; - case DNS_EUNKNOWN: - return "Unknown DNS error"; - case DNS_EADDRESS: - return "Invalid textual address form"; - case DNS_ENOQUERY: - return "Bad execution state (missing query packet)"; - case DNS_ENOANSWER: - return "Bad execution state (missing answer packet)"; - case DNS_EFETCHED: - return "Answer already fetched"; - case DNS_ESERVICE: - return "The service passed was not recognized for the specified socket type"; - case DNS_ENONAME: - return "The name does not resolve for the supplied parameters"; - case DNS_EFAIL: - return "A non-recoverable error occurred when attempting to resolve the name"; - default: - return strerror(error); - } /* switch() */ -} /* dns_strerror() */ - - -/* - * A T O M I C R O U T I N E S - * - * Use GCC's __atomic built-ins if possible. Unlike the __sync built-ins, we - * can use the preprocessor to detect API and, more importantly, ISA - * support. We want to avoid linking headaches where the API depends on an - * external library if the ISA (e.g. i386) doesn't support lockless - * operation. - * - * TODO: Support C11's atomic API. Although that may require some finesse - * with how we define some public types, such as dns_atomic_t and struct - * dns_resolv_conf. - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef HAVE___ATOMIC_FETCH_ADD -#define HAVE___ATOMIC_FETCH_ADD (defined __ATOMIC_RELAXED) -#endif - -#ifndef HAVE___ATOMIC_FETCH_SUB -#define HAVE___ATOMIC_FETCH_SUB HAVE___ATOMIC_FETCH_ADD -#endif - -#ifndef DNS_ATOMIC_FETCH_ADD -#if HAVE___ATOMIC_FETCH_ADD && __GCC_ATOMIC_LONG_LOCK_FREE == 2 -#define DNS_ATOMIC_FETCH_ADD(i) __atomic_fetch_add((i), 1, __ATOMIC_RELAXED) -#else -#pragma message("no atomic_fetch_add available") -#define DNS_ATOMIC_FETCH_ADD(i) ((*(i))++) -#endif -#endif - -#ifndef DNS_ATOMIC_FETCH_SUB -#if HAVE___ATOMIC_FETCH_SUB && __GCC_ATOMIC_LONG_LOCK_FREE == 2 -#define DNS_ATOMIC_FETCH_SUB(i) __atomic_fetch_sub((i), 1, __ATOMIC_RELAXED) -#else -#pragma message("no atomic_fetch_sub available") -#define DNS_ATOMIC_FETCH_SUB(i) ((*(i))--) -#endif -#endif - -static inline unsigned dns_atomic_fetch_add(dns_atomic_t *i) { - return DNS_ATOMIC_FETCH_ADD(i); -} /* dns_atomic_fetch_add() */ - - -static inline unsigned dns_atomic_fetch_sub(dns_atomic_t *i) { - return DNS_ATOMIC_FETCH_SUB(i); -} /* dns_atomic_fetch_sub() */ - - -/* - * C R Y P T O R O U T I N E S - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/* - * P R N G - */ - -#ifndef DNS_RANDOM -#if defined(HAVE_ARC4RANDOM) \ - || defined(__OpenBSD__) \ - || defined(__FreeBSD__) \ - || defined(__NetBSD__) \ - || defined(__APPLE__) -#define DNS_RANDOM arc4random -#elif __linux -#define DNS_RANDOM random -#else -#define DNS_RANDOM rand -#endif -#endif - -#define DNS_RANDOM_arc4random 1 -#define DNS_RANDOM_random 2 -#define DNS_RANDOM_rand 3 -#define DNS_RANDOM_RAND_bytes 4 - -#define DNS_RANDOM_OPENSSL (DNS_RANDOM_RAND_bytes == DNS_PP_XPASTE(DNS_RANDOM_, DNS_RANDOM)) - -#if DNS_RANDOM_OPENSSL -#include -#endif - -static unsigned dns_random_(void) { -#if DNS_RANDOM_OPENSSL - unsigned r; - - assert(1 == RAND_bytes((unsigned char *)&r, sizeof r)); - - return r; -#else - return DNS_RANDOM(); -#endif -} /* dns_random_() */ - -unsigned (*dns_random)(void) __attribute__((weak)) = &dns_random_; - - -/* - * P E R M U T A T I O N G E N E R A T O R - */ - -#define DNS_K_TEA_KEY_SIZE 16 -#define DNS_K_TEA_BLOCK_SIZE 8 -#define DNS_K_TEA_CYCLES 32 -#define DNS_K_TEA_MAGIC 0x9E3779B9U - -struct dns_k_tea { - uint32_t key[DNS_K_TEA_KEY_SIZE / sizeof (uint32_t)]; - unsigned cycles; -}; /* struct dns_k_tea */ - - -static void dns_k_tea_init(struct dns_k_tea *tea, uint32_t key[], unsigned cycles) { - memcpy(tea->key, key, sizeof tea->key); - - tea->cycles = (cycles)? cycles : DNS_K_TEA_CYCLES; -} /* dns_k_tea_init() */ - - -static void dns_k_tea_encrypt(struct dns_k_tea *tea, uint32_t v[], uint32_t *w) { - uint32_t y, z, sum, n; - - y = v[0]; - z = v[1]; - sum = 0; - - for (n = 0; n < tea->cycles; n++) { - sum += DNS_K_TEA_MAGIC; - y += ((z << 4) + tea->key[0]) ^ (z + sum) ^ ((z >> 5) + tea->key[1]); - z += ((y << 4) + tea->key[2]) ^ (y + sum) ^ ((y >> 5) + tea->key[3]); - } - - w[0] = y; - w[1] = z; - - return /* void */; -} /* dns_k_tea_encrypt() */ - - -/* - * Permutation generator, based on a Luby-Rackoff Feistel construction. - * - * Specifically, this is a generic balanced Feistel block cipher using TEA - * (another block cipher) as the pseudo-random function, F. At best it's as - * strong as F (TEA), notwithstanding the seeding. F could be AES, SHA-1, or - * perhaps Bernstein's Salsa20 core; I am naively trying to keep things - * simple. - * - * The generator can create a permutation of any set of numbers, as long as - * the size of the set is an even power of 2. This limitation arises either - * out of an inherent property of balanced Feistel constructions, or by my - * own ignorance. I'll tackle an unbalanced construction after I wrap my - * head around Schneier and Kelsey's paper. - * - * CAVEAT EMPTOR. IANAC. - */ -#define DNS_K_PERMUTOR_ROUNDS 8 - -struct dns_k_permutor { - unsigned stepi, length, limit; - unsigned shift, mask, rounds; - - struct dns_k_tea tea; -}; /* struct dns_k_permutor */ - - -static inline unsigned dns_k_permutor_powof(unsigned n) { - unsigned m, i = 0; - - for (m = 1; m < n; m <<= 1, i++) - ;; - - return i; -} /* dns_k_permutor_powof() */ - -static void dns_k_permutor_init(struct dns_k_permutor *p, unsigned low, unsigned high) { - uint32_t key[DNS_K_TEA_KEY_SIZE / sizeof (uint32_t)]; - unsigned width, i; - - p->stepi = 0; - - p->length = (high - low) + 1; - p->limit = high; - - width = dns_k_permutor_powof(p->length); - width += width % 2; - - p->shift = width / 2; - p->mask = (1U << p->shift) - 1; - p->rounds = DNS_K_PERMUTOR_ROUNDS; - - for (i = 0; i < lengthof(key); i++) - key[i] = dns_random(); - - dns_k_tea_init(&p->tea, key, 0); - - return /* void */; -} /* dns_k_permutor_init() */ - - -static unsigned dns_k_permutor_F(struct dns_k_permutor *p, unsigned k, unsigned x) { - uint32_t in[DNS_K_TEA_BLOCK_SIZE / sizeof (uint32_t)], out[DNS_K_TEA_BLOCK_SIZE / sizeof (uint32_t)]; - - memset(in, '\0', sizeof in); - - in[0] = k; - in[1] = x; - - dns_k_tea_encrypt(&p->tea, in, out); - - return p->mask & out[0]; -} /* dns_k_permutor_F() */ - - -static unsigned dns_k_permutor_E(struct dns_k_permutor *p, unsigned n) { - unsigned l[2], r[2]; - unsigned i; - - i = 0; - l[i] = p->mask & (n >> p->shift); - r[i] = p->mask & (n >> 0); - - do { - l[(i + 1) % 2] = r[i % 2]; - r[(i + 1) % 2] = l[i % 2] ^ dns_k_permutor_F(p, i, r[i % 2]); - - i++; - } while (i < p->rounds - 1); - - return ((l[i % 2] & p->mask) << p->shift) | ((r[i % 2] & p->mask) << 0); -} /* dns_k_permutor_E() */ - - -DNS_NOTUSED static unsigned dns_k_permutor_D(struct dns_k_permutor *p, unsigned n) { - unsigned l[2], r[2]; - unsigned i; - - i = p->rounds - 1; - l[i % 2] = p->mask & (n >> p->shift); - r[i % 2] = p->mask & (n >> 0); - - do { - i--; - - r[i % 2] = l[(i + 1) % 2]; - l[i % 2] = r[(i + 1) % 2] ^ dns_k_permutor_F(p, i, l[(i + 1) % 2]); - } while (i > 0); - - return ((l[i % 2] & p->mask) << p->shift) | ((r[i % 2] & p->mask) << 0); -} /* dns_k_permutor_D() */ - - -static unsigned dns_k_permutor_step(struct dns_k_permutor *p) { - unsigned n; - - do { - n = dns_k_permutor_E(p, p->stepi++); - } while (n >= p->length); - - return n + (p->limit + 1 - p->length); -} /* dns_k_permutor_step() */ - - -/* - * Simple permutation box. Useful for shuffling rrsets from an iterator. - * Uses AES s-box to provide good diffusion. - * - * Seems to pass muster under runs test. - * - * $ for i in 0 1 2 3 4 5 6 7 8 9; do ./dns shuffle-16 > /tmp/out; done - * $ R -q -f /dev/stdin 2>/dev/null <<-EOF | awk '/p-value/{ print $8 }' - * library(lawstat) - * runs.test(scan(file="/tmp/out")) - * EOF - */ -static unsigned short dns_k_shuffle16(unsigned short n, unsigned s) { - static const unsigned char sbox[256] = - { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, - 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, - 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, - 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, - 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, - 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, - 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, - 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, - 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, - 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, - 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, - 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, - 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, - 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, - 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, - 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, - 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, - 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, - 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, - 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, - 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, - 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, - 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, - 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, - 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, - 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, - 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, - 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, - 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, - 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, - 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; - unsigned char a, b; - unsigned i; - - a = 0xff & (n >> 0); - b = 0xff & (n >> 8); - - for (i = 0; i < 4; i++) { - a ^= 0xff & s; - a = sbox[a] ^ b; - b = sbox[b] ^ a; - s >>= 8; - } - - return ((0xff00 & (a << 8)) | (0x00ff & (b << 0))); -} /* dns_k_shuffle16() */ - - -/* - * U T I L I T Y R O U T I N E S - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#define DNS_MAXINTERVAL 300 - -struct dns_clock { - time_t sample, elapsed; -}; /* struct dns_clock */ - -static void dns_begin(struct dns_clock *clk) { - clk->sample = time(0); - clk->elapsed = 0; -} /* dns_begin() */ - -static time_t dns_elapsed(struct dns_clock *clk) { - time_t curtime; - - if ((time_t)-1 == time(&curtime)) - return clk->elapsed; - - if (curtime > clk->sample) - clk->elapsed += (time_t)DNS_PP_MIN(difftime(curtime, clk->sample), DNS_MAXINTERVAL); - - clk->sample = curtime; - - return clk->elapsed; -} /* dns_elapsed() */ - - -DNS_NOTUSED static size_t dns_strnlen(const char *src, size_t m) { - size_t n = 0; - - while (*src++ && n < m) - ++n; - - return n; -} /* dns_strnlen() */ - - -DNS_NOTUSED static size_t dns_strnlcpy(char *dst, size_t lim, const char *src, size_t max) { - size_t len = dns_strnlen(src, max), n; - - if (lim > 0) { - n = DNS_PP_MIN(lim - 1, len); - memcpy(dst, src, n); - dst[n] = '\0'; - } - - return len; -} /* dns_strnlcpy() */ - - -#define DNS_HAVE_SOCKADDR_UN (defined AF_UNIX && !defined _WIN32) - -static size_t dns_af_len(int af) { - static const size_t table[AF_MAX] = { - [AF_INET6] = sizeof (struct sockaddr_in6), - [AF_INET] = sizeof (struct sockaddr_in), -#if DNS_HAVE_SOCKADDR_UN - [AF_UNIX] = sizeof (struct sockaddr_un), -#endif - }; - - return table[af]; -} /* dns_af_len() */ - -#define dns_sa_family(sa) (((struct sockaddr *)(sa))->sa_family) - -#define dns_sa_len(sa) dns_af_len(dns_sa_family(sa)) - - -#define DNS_SA_NOPORT &dns_sa_noport -static unsigned short dns_sa_noport; - -static unsigned short *dns_sa_port(int af, void *sa) { - switch (af) { - case AF_INET6: - return &((struct sockaddr_in6 *)sa)->sin6_port; - case AF_INET: - return &((struct sockaddr_in *)sa)->sin_port; - default: - return DNS_SA_NOPORT; - } -} /* dns_sa_port() */ - - -static void *dns_sa_addr(int af, void *sa, socklen_t *size) { - switch (af) { - case AF_INET6: { - struct in6_addr *in6 = &((struct sockaddr_in6 *)sa)->sin6_addr; - - if (size) - *size = sizeof *in6; - - return in6; - } - case AF_INET: { - struct in_addr *in = &((struct sockaddr_in *)sa)->sin_addr; - - if (size) - *size = sizeof *in; - - return in; - } - default: - if (size) - *size = 0; - - return 0; - } -} /* dns_sa_addr() */ - - -#if DNS_HAVE_SOCKADDR_UN -#define DNS_SUNPATHMAX (sizeof ((struct sockaddr_un *)0)->sun_path) -#endif - -DNS_NOTUSED static void *dns_sa_path(void *sa, socklen_t *size) { - switch (dns_sa_family(sa)) { -#if DNS_HAVE_SOCKADDR_UN - case AF_UNIX: { - char *path = ((struct sockaddr_un *)sa)->sun_path; - - if (size) - *size = dns_strnlen(path, DNS_SUNPATHMAX); - - return path; - } -#endif - default: - if (size) - *size = 0; - - return NULL; - } -} /* dns_sa_path() */ - - -static int dns_sa_cmp(void *a, void *b) { - int cmp, af; - - if ((cmp = dns_sa_family(a) - dns_sa_family(b))) - return cmp; - - switch ((af = dns_sa_family(a))) { - case AF_INET: { - struct in_addr *a4, *b4; - - if ((cmp = htons(*dns_sa_port(af, a)) - htons(*dns_sa_port(af, b)))) - return cmp; - - a4 = dns_sa_addr(af, a, NULL); - b4 = dns_sa_addr(af, b, NULL); - - if (ntohl(a4->s_addr) < ntohl(b4->s_addr)) - return -1; - if (ntohl(a4->s_addr) > ntohl(b4->s_addr)) - return 1; - - return 0; - } - case AF_INET6: { - struct in6_addr *a6, *b6; - size_t i; - - if ((cmp = htons(*dns_sa_port(af, a)) - htons(*dns_sa_port(af, b)))) - return cmp; - - a6 = dns_sa_addr(af, a, NULL); - b6 = dns_sa_addr(af, b, NULL); - - /* XXX: do we need to use in6_clearscope()? */ - for (i = 0; i < sizeof a6->s6_addr; i++) { - if ((cmp = a6->s6_addr[i] - b6->s6_addr[i])) - return cmp; - } - - return 0; - } -#if DNS_HAVE_SOCKADDR_UN - case AF_UNIX: { - char a_path[DNS_SUNPATHMAX + 1], b_path[sizeof a_path]; - - dns_strnlcpy(a_path, sizeof a_path, dns_sa_path(a, NULL), DNS_SUNPATHMAX); - dns_strnlcpy(b_path, sizeof b_path, dns_sa_path(b, NULL), DNS_SUNPATHMAX); - - return strcmp(a_path, b_path); - } -#endif - default: - return -1; - } -} /* dns_sa_cmp() */ - - -#if _WIN32 -static int dns_inet_pton(int af, const void *src, void *dst) { - union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u; - - u.sin.sin_family = af; -#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - u.sin.sin_len = dns_af_len(af); -#endif - - if (0 != WSAStringToAddressA((void *)src, af, (void *)0, (struct sockaddr *)&u, &(int){ sizeof u })) - return -1; - - switch (af) { - case AF_INET6: - *(struct in6_addr *)dst = u.sin6.sin6_addr; - - return 1; - case AF_INET: - *(struct in_addr *)dst = u.sin.sin_addr; - - return 1; - default: - return 0; - } -} /* dns_inet_pton() */ - -static const char *dns_inet_ntop(int af, const void *src, void *dst, unsigned long lim) { - union { struct sockaddr_in sin; struct sockaddr_in6 sin6; } u; - - /* NOTE: WSAAddressToString will print .sin_port unless zeroed. */ - memset(&u, 0, sizeof u); - - u.sin.sin_family = af; -#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - u.sin.sin_len = dns_af_len(af); -#endif - - switch (af) { - case AF_INET6: - u.sin6.sin6_addr = *(struct in6_addr *)src; - break; - case AF_INET: - u.sin.sin_addr = *(struct in_addr *)src; - - break; - default: - return 0; - } - - if (0 != WSAAddressToStringA((struct sockaddr *)&u, dns_sa_len(&u), (void *)0, dst, &lim)) - return 0; - - return dst; -} /* dns_inet_ntop() */ -#else -#define dns_inet_pton(...) inet_pton(__VA_ARGS__) -#define dns_inet_ntop(...) inet_ntop(__VA_ARGS__) -#endif - - -static dns_error_t dns_pton(int af, const void *src, void *dst) { - switch (dns_inet_pton(af, src, dst)) { - case 1: - return 0; - case -1: - return dns_soerr(); - default: - return DNS_EADDRESS; - } -} /* dns_pton() */ - - -static dns_error_t dns_ntop(int af, const void *src, void *dst, unsigned long lim) { - return (dns_inet_ntop(af, src, dst, lim))? 0 : dns_soerr(); -} /* dns_ntop() */ - - -size_t dns_strlcpy(char *dst, const char *src, size_t lim) { - char *d = dst; - char *e = &dst[lim]; - const char *s = src; - - if (d < e) { - do { - if ('\0' == (*d++ = *s++)) - return s - src - 1; - } while (d < e); - - d[-1] = '\0'; - } - - while (*s++ != '\0') - ;; - - return s - src - 1; -} /* dns_strlcpy() */ - - -size_t dns_strlcat(char *dst, const char *src, size_t lim) { - char *d = memchr(dst, '\0', lim); - char *e = &dst[lim]; - const char *s = src; - const char *p; - - if (d && d < e) { - do { - if ('\0' == (*d++ = *s++)) - return d - dst - 1; - } while (d < e); - - d[-1] = '\0'; - } - - p = s; - - while (*s++ != '\0') - ;; - - return lim + (s - p - 1); -} /* dns_strlcat() */ - - -#if _WIN32 - -static char *dns_strsep(char **sp, const char *delim) { - char *p; - - if (!(p = *sp)) - return 0; - - *sp += strcspn(p, delim); - - if (**sp != '\0') { - **sp = '\0'; - ++*sp; - } else - *sp = NULL; - - return p; -} /* dns_strsep() */ - -#else -#define dns_strsep(...) strsep(__VA_ARGS__) -#endif - - -#if _WIN32 -#define strcasecmp(...) _stricmp(__VA_ARGS__) -#define strncasecmp(...) _strnicmp(__VA_ARGS__) -#endif - - -static int dns_poll(int fd, short events, int timeout) { - fd_set rset, wset; - - if (!events) - return 0; - - assert(fd >= 0 && (unsigned)fd < FD_SETSIZE); - - FD_ZERO(&rset); - FD_ZERO(&wset); - - if (events & DNS_POLLIN) - FD_SET(fd, &rset); - - if (events & DNS_POLLOUT) - FD_SET(fd, &wset); - - select(fd + 1, &rset, &wset, 0, (timeout >= 0)? &(struct timeval){ timeout, 0 } : NULL); - - return 0; -} /* dns_poll() */ - - -#if !_WIN32 -DNS_NOTUSED static int dns_sigmask(int how, const sigset_t *set, sigset_t *oset) { -#if DNS_THREAD_SAFE - return pthread_sigmask(how, set, oset); -#else - return (0 == sigprocmask(how, set, oset))? 0 : errno; -#endif -} /* dns_sigmask() */ -#endif - - -static long dns_send(int fd, const void *src, size_t lim, int flags) { -#if _WIN32 || !defined SIGPIPE || defined SO_NOSIGPIPE - return send(fd, src, lim, flags); -#elif defined MSG_NOSIGNAL - return send(fd, src, lim, flags|MSG_NOSIGNAL); -#elif _POSIX_REALTIME_SIGNALS > 0 /* require sigtimedwait */ - /* - * SIGPIPE handling similar to the approach described in - * http://krokisplace.blogspot.com/2010/02/suppressing-sigpipe-in-library.html - */ - sigset_t pending, blocked, piped; - long count; - int saved, error; - - sigemptyset(&pending); - sigpending(&pending); - - if (!sigismember(&pending, SIGPIPE)) { - sigemptyset(&piped); - sigaddset(&piped, SIGPIPE); - sigemptyset(&blocked); - - if ((error = dns_sigmask(SIG_BLOCK, &piped, &blocked))) - goto error; - } - - count = send(fd, src, lim, flags); - - if (!sigismember(&pending, SIGPIPE)) { - saved = errno; - - if (count == -1 && errno == EPIPE) { - while (-1 == sigtimedwait(&piped, NULL, &(struct timespec){ 0, 0 }) && errno == EINTR) - ;; - } - - if ((error = dns_sigmask(SIG_SETMASK, &blocked, NULL))) - goto error; - - errno = saved; - } - - return count; -error: - errno = error; - - return -1; -#else -#error "unable to suppress SIGPIPE" - return send(fd, src, lim, flags); -#endif -} /* dns_send() */ - - -/* - * P A C K E T R O U T I N E S - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -unsigned dns_p_count(struct dns_packet *P, enum dns_section section) { - unsigned count; - - switch (section) { - case DNS_S_QD: - return ntohs(dns_header(P)->qdcount); - case DNS_S_AN: - return ntohs(dns_header(P)->ancount); - case DNS_S_NS: - return ntohs(dns_header(P)->nscount); - case DNS_S_AR: - return ntohs(dns_header(P)->arcount); - default: - count = 0; - - if (section & DNS_S_QD) - count += ntohs(dns_header(P)->qdcount); - if (section & DNS_S_AN) - count += ntohs(dns_header(P)->ancount); - if (section & DNS_S_NS) - count += ntohs(dns_header(P)->nscount); - if (section & DNS_S_AR) - count += ntohs(dns_header(P)->arcount); - - return count; - } -} /* dns_p_count() */ - - -struct dns_packet *dns_p_init(struct dns_packet *P, size_t size) { - if (!P) - return 0; - - assert(size >= offsetof(struct dns_packet, data) + 12); - - memset(P, 0, sizeof *P); - P->size = size - offsetof(struct dns_packet, data); - P->end = 12; - - memset(P->data, '\0', 12); - - return P; -} /* dns_p_init() */ - - -static unsigned short dns_p_qend(struct dns_packet *P) { - unsigned short qend = 12; - unsigned i, count = dns_p_count(P, DNS_S_QD); - - for (i = 0; i < count && qend < P->end; i++) { - if (P->end == (qend = dns_d_skip(qend, P))) - goto invalid; - - if (P->end - qend < 4) - goto invalid; - - qend += 4; - } - - return DNS_PP_MIN(qend, P->end); -invalid: - return P->end; -} /* dns_p_qend() */ - - -struct dns_packet *dns_p_make(size_t len, int *error) { - struct dns_packet *P; - size_t size = dns_p_calcsize(len); - - if (!(P = dns_p_init(malloc(size), size))) - *error = dns_syerr(); - - return P; -} /* dns_p_make() */ - - -static void dns_p_free(struct dns_packet *P) { - free(P); -} /* dns_p_free() */ - - -/* convience routine to free any existing packet before storing new packet */ -static struct dns_packet *dns_p_setptr(struct dns_packet **dst, struct dns_packet *src) { - dns_p_free(*dst); - - *dst = src; - - return src; -} /* dns_p_setptr() */ - - -static struct dns_packet *dns_p_movptr(struct dns_packet **dst, struct dns_packet **src) { - dns_p_setptr(dst, *src); - - *src = NULL; - - return *dst; -} /* dns_p_movptr() */ - - -int dns_p_grow(struct dns_packet **P) { - struct dns_packet *tmp; - size_t size; - int error; - - if (!*P) { - if (!(*P = dns_p_make(DNS_P_QBUFSIZ, &error))) - return error; - - return 0; - } - - size = dns_p_sizeof(*P); - size |= size >> 1; - size |= size >> 2; - size |= size >> 4; - size |= size >> 8; - size++; - - if (size > 65536) - return DNS_ENOBUFS; - - if (!(tmp = realloc(*P, dns_p_calcsize(size)))) - return dns_syerr(); - - tmp->size = size; - *P = tmp; - - return 0; -} /* dns_p_grow() */ - - -struct dns_packet *dns_p_copy(struct dns_packet *P, const struct dns_packet *P0) { - if (!P) - return 0; - - P->end = DNS_PP_MIN(P->size, P0->end); - - memcpy(P->data, P0->data, P->end); - - return P; -} /* dns_p_copy() */ - - -struct dns_packet *dns_p_merge(struct dns_packet *A, enum dns_section Amask, struct dns_packet *B, enum dns_section Bmask, int *error_) { - size_t bufsiz = DNS_PP_MIN(65535, ((A)? A->end : 0) + ((B)? B->end : 0)); - struct dns_packet *M; - enum dns_section section; - struct dns_rr rr, mr; - int error, copy; - - if (!A && B) { - A = B; - Amask = Bmask; - B = 0; - } - -merge: - if (!(M = dns_p_make(bufsiz, &error))) - goto error; - - for (section = DNS_S_QD; (DNS_S_ALL & section); section <<= 1) { - if (A && (section & Amask)) { - dns_rr_foreach(&rr, A, .section = section) { - if ((error = dns_rr_copy(M, &rr, A))) - goto error; - } - } - - if (B && (section & Bmask)) { - dns_rr_foreach(&rr, B, .section = section) { - copy = 1; - - dns_rr_foreach(&mr, M, .type = rr.type, .section = DNS_S_ALL) { - if (!(copy = dns_rr_cmp(&rr, B, &mr, M))) - break; - } - - if (copy && (error = dns_rr_copy(M, &rr, B))) - goto error; - } - } - } - - return M; -error: - dns_p_setptr(&M, NULL); - - if (error == DNS_ENOBUFS && bufsiz < 65535) { - bufsiz = DNS_PP_MIN(65535, bufsiz * 2); - - goto merge; - } - - *error_ = error; - - return 0; -} /* dns_p_merge() */ - - -static unsigned short dns_l_skip(unsigned short, const unsigned char *, size_t); - -void dns_p_dictadd(struct dns_packet *P, unsigned short dn) { - unsigned short lp, lptr, i; - - lp = dn; - - while (lp < P->end) { - if (0xc0 == (0xc0 & P->data[lp]) && P->end - lp >= 2 && lp != dn) { - lptr = ((0x3f & P->data[lp + 0]) << 8) - | ((0xff & P->data[lp + 1]) << 0); - - for (i = 0; i < lengthof(P->dict) && P->dict[i]; i++) { - if (P->dict[i] == lptr) { - P->dict[i] = dn; - - return; - } - } - } - - lp = dns_l_skip(lp, P->data, P->end); - } - - for (i = 0; i < lengthof(P->dict); i++) { - if (!P->dict[i]) { - P->dict[i] = dn; - - break; - } - } -} /* dns_p_dictadd() */ - - -int dns_p_push(struct dns_packet *P, enum dns_section section, const void *dn, size_t dnlen, enum dns_type type, enum dns_class class, unsigned ttl, const void *any) { - size_t end = P->end; - int error; - - if ((error = dns_d_push(P, dn, dnlen))) - goto error; - - if (P->size - P->end < 4) - goto nobufs; - - P->data[P->end++] = 0xff & (type >> 8); - P->data[P->end++] = 0xff & (type >> 0); - - P->data[P->end++] = 0xff & (class >> 8); - P->data[P->end++] = 0xff & (class >> 0); - - if (section == DNS_S_QD) - goto update; - - if (P->size - P->end < 6) - goto nobufs; - - P->data[P->end++] = 0x7f & (ttl >> 24); - P->data[P->end++] = 0xff & (ttl >> 16); - P->data[P->end++] = 0xff & (ttl >> 8); - P->data[P->end++] = 0xff & (ttl >> 0); - - if ((error = dns_any_push(P, (union dns_any *)any, type))) - goto error; - -update: - switch (section) { - case DNS_S_QD: - if (dns_p_count(P, DNS_S_AN|DNS_S_NS|DNS_S_AR)) - goto order; - - if (!P->qd.base && (error = dns_p_study(P))) - goto error; - - dns_header(P)->qdcount = htons(ntohs(dns_header(P)->qdcount) + 1); - - P->qd.end = P->end; - P->an.base = P->end; - P->an.end = P->end; - P->ns.base = P->end; - P->ns.end = P->end; - P->ar.base = P->end; - P->ar.end = P->end; - - break; - case DNS_S_AN: - if (dns_p_count(P, DNS_S_NS|DNS_S_AR)) - goto order; - - if (!P->an.base && (error = dns_p_study(P))) - goto error; - - dns_header(P)->ancount = htons(ntohs(dns_header(P)->ancount) + 1); - - P->an.end = P->end; - P->ns.base = P->end; - P->ns.end = P->end; - P->ar.base = P->end; - P->ar.end = P->end; - - break; - case DNS_S_NS: - if (dns_p_count(P, DNS_S_AR)) - goto order; - - if (!P->ns.base && (error = dns_p_study(P))) - goto error; - - dns_header(P)->nscount = htons(ntohs(dns_header(P)->nscount) + 1); - - P->ns.end = P->end; - P->ar.base = P->end; - P->ar.end = P->end; - - break; - case DNS_S_AR: - if (!P->ar.base && (error = dns_p_study(P))) - goto error; - - dns_header(P)->arcount = htons(ntohs(dns_header(P)->arcount) + 1); - - P->ar.end = P->end; - - break; - default: - error = DNS_ESECTION; - - goto error; - } /* switch() */ - - return 0; -nobufs: - error = DNS_ENOBUFS; - - goto error; -order: - error = DNS_EORDER; - - goto error; -error: - P->end = end; - - return error; -} /* dns_p_push() */ - - -static void dns_p_dump3(struct dns_packet *P, struct dns_rr_i *I, FILE *fp) { - enum dns_section section; - struct dns_rr rr; - int error; - union dns_any any; - char pretty[sizeof any * 2]; - size_t len; - - fputs(";; [HEADER]\n", fp); - fprintf(fp, ";; qr : %s(%d)\n", (dns_header(P)->qr)? "RESPONSE" : "QUERY", dns_header(P)->qr); - fprintf(fp, ";; opcode : %s(%d)\n", dns_stropcode(dns_header(P)->opcode), dns_header(P)->opcode); - fprintf(fp, ";; aa : %s(%d)\n", (dns_header(P)->aa)? "AUTHORITATIVE" : "NON-AUTHORITATIVE", dns_header(P)->aa); - fprintf(fp, ";; tc : %s(%d)\n", (dns_header(P)->tc)? "TRUNCATED" : "NOT-TRUNCATED", dns_header(P)->tc); - fprintf(fp, ";; rd : %s(%d)\n", (dns_header(P)->rd)? "RECURSION-DESIRED" : "RECURSION-NOT-DESIRED", dns_header(P)->rd); - fprintf(fp, ";; ra : %s(%d)\n", (dns_header(P)->ra)? "RECURSION-ALLOWED" : "RECURSION-NOT-ALLOWED", dns_header(P)->ra); - fprintf(fp, ";; rcode : %s(%d)\n", dns_strrcode(dns_header(P)->rcode), dns_header(P)->rcode); - - section = 0; - - while (dns_rr_grep(&rr, 1, I, P, &error)) { - if (section != rr.section) - fprintf(fp, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(P, rr.section)); - - if ((len = dns_rr_print(pretty, sizeof pretty, &rr, P, &error))) - fprintf(fp, "%s\n", pretty); - - section = rr.section; - } -} /* dns_p_dump3() */ - - -void dns_p_dump(struct dns_packet *P, FILE *fp) { - dns_p_dump3(P, dns_rr_i_new(P, .section = 0), fp); -} /* dns_p_dump() */ - - -static void dns_s_unstudy(struct dns_s_memo *m) - { m->base = 0; m->end = 0; } - -static void dns_p_unstudy(struct dns_packet *P) { - dns_s_unstudy(&P->qd); - dns_s_unstudy(&P->an); - dns_s_unstudy(&P->ns); - dns_s_unstudy(&P->ar); -} /* dns_p_unstudy() */ - -static int dns_s_study(struct dns_s_memo *m, enum dns_section section, unsigned base, struct dns_packet *P) { - unsigned short count, rp; - - count = dns_p_count(P, section); - - for (rp = base; count && rp < P->end; count--) - rp = dns_rr_skip(rp, P); - - m->base = base; - m->end = rp; - - return 0; -} /* dns_s_study() */ - -int dns_p_study(struct dns_packet *P) { - int error; - - if ((error = dns_s_study(&P->qd, DNS_S_QD, 12, P))) - goto error; - - if ((error = dns_s_study(&P->an, DNS_S_AN, P->qd.end, P))) - goto error; - - if ((error = dns_s_study(&P->ns, DNS_S_NS, P->an.end, P))) - goto error; - - if ((error = dns_s_study(&P->ar, DNS_S_AR, P->ns.end, P))) - goto error; - - return 0; -error: - dns_p_unstudy(P); - - return error; -} /* dns_p_study() */ - - -/* - * D O M A I N N A M E R O U T I N E S - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef DNS_D_MAXPTRS -#define DNS_D_MAXPTRS 127 /* Arbitrary; possible, valid depth is something like packet size / 2 + fudge. */ -#endif - -static size_t dns_l_expand(unsigned char *dst, size_t lim, unsigned short src, unsigned short *nxt, const unsigned char *data, size_t end) { - unsigned short len; - unsigned nptrs = 0; - -retry: - if (src >= end) - goto invalid; - - switch (0x03 & (data[src] >> 6)) { - case 0x00: - len = (0x3f & (data[src++])); - - if (end - src < len) - goto invalid; - - if (lim > 0) { - memcpy(dst, &data[src], DNS_PP_MIN(lim, len)); - - dst[DNS_PP_MIN(lim - 1, len)] = '\0'; - } - - *nxt = src + len; - - return len; - case 0x01: - goto invalid; - case 0x02: - goto invalid; - case 0x03: - if (++nptrs > DNS_D_MAXPTRS) - goto invalid; - - if (end - src < 2) - goto invalid; - - src = ((0x3f & data[src + 0]) << 8) - | ((0xff & data[src + 1]) << 0); - - goto retry; - } /* switch() */ - - /* NOT REACHED */ -invalid: - *nxt = end; - - return 0; -} /* dns_l_expand() */ - - -static unsigned short dns_l_skip(unsigned short src, const unsigned char *data, size_t end) { - unsigned short len; - - if (src >= end) - goto invalid; - - switch (0x03 & (data[src] >> 6)) { - case 0x00: - len = (0x3f & (data[src++])); - - if (end - src < len) - goto invalid; - - return (len)? src + len : end; - case 0x01: - goto invalid; - case 0x02: - goto invalid; - case 0x03: - return end; - } /* switch() */ - - /* NOT REACHED */ -invalid: - return end; -} /* dns_l_skip() */ - - -size_t dns_d_trim(void *dst_, size_t lim, const void *src_, size_t len, int flags) { - unsigned char *dst = dst_; - const unsigned char *src = src_; - size_t dp = 0, sp = 0; - int lc; - - /* trim any leading dot(s) */ - while (sp < len && src[sp] == '.') - sp++; - - for (lc = 0; sp < len; lc = src[sp++]) { - /* trim extra dot(s) */ - if (src[sp] == '.' && lc == '.') - continue; - - if (dp < lim) - dst[dp] = src[sp]; - - dp++; - } - - if ((flags & DNS_D_ANCHOR) && lc != '.') { - if (dp < lim) - dst[dp] = '.'; - - dp++; - } - - if (lim > 0) - dst[DNS_PP_MIN(dp, lim - 1)] = '\0'; - - return dp; -} /* dns_d_trim() */ - - -char *dns_d_init(void *dst, size_t lim, const void *src, size_t len, int flags) { - if (flags & DNS_D_TRIM) { - dns_d_trim(dst, lim, src, len, flags); - } if (flags & DNS_D_ANCHOR) { - dns_d_anchor(dst, lim, src, len); - } else { - memmove(dst, src, DNS_PP_MIN(lim, len)); - - if (lim > 0) - ((char *)dst)[DNS_PP_MIN(len, lim - 1)] = '\0'; - } - - return dst; -} /* dns_d_init() */ - - -size_t dns_d_anchor(void *dst, size_t lim, const void *src, size_t len) { - if (len == 0) - return 0; - - memmove(dst, src, DNS_PP_MIN(lim, len)); - - if (((const char *)src)[len - 1] != '.') { - if (len < lim) - ((char *)dst)[len] = '.'; - len++; - } - - if (lim > 0) - ((char *)dst)[DNS_PP_MIN(lim - 1, len)] = '\0'; - - return len; -} /* dns_d_anchor() */ - - -size_t dns_d_cleave(void *dst, size_t lim, const void *src, size_t len) { - const char *dot; - - /* XXX: Skip any leading dot. Handles cleaving root ".". */ - if (len == 0 || !(dot = memchr((const char *)src + 1, '.', len - 1))) - return 0; - - len -= dot - (const char *)src; - - /* XXX: Unless root, skip the label's trailing dot. */ - if (len > 1) { - src = ++dot; - len--; - } else - src = dot; - - memmove(dst, src, DNS_PP_MIN(lim, len)); - - if (lim > 0) - ((char *)dst)[DNS_PP_MIN(lim - 1, len)] = '\0'; - - return len; -} /* dns_d_cleave() */ - - -size_t dns_d_comp(void *dst_, size_t lim, const void *src_, size_t len, struct dns_packet *P, int *error) { - struct { unsigned char *b; size_t p, x; } dst, src; - unsigned char ch = '.'; - - dst.b = dst_; - dst.p = 0; - dst.x = 1; - - src.b = (unsigned char *)src_; - src.p = 0; - src.x = 0; - - while (src.x < len) { - ch = src.b[src.x]; - - if (ch == '.') { - if (dst.p < lim) - dst.b[dst.p] = (0x3f & (src.x - src.p)); - - dst.p = dst.x++; - src.p = ++src.x; - } else { - if (dst.x < lim) - dst.b[dst.x] = ch; - - dst.x++; - src.x++; - } - } /* while() */ - - if (src.x > src.p) { - if (dst.p < lim) - dst.b[dst.p] = (0x3f & (src.x - src.p)); - - dst.p = dst.x; - } - - if (dst.p > 1) { - if (dst.p < lim) - dst.b[dst.p] = 0x00; - - dst.p++; - } - -#if 1 - if (dst.p < lim) { - struct { unsigned char label[DNS_D_MAXLABEL + 1]; size_t len; unsigned short p, x, y; } a, b; - unsigned i; - - a.p = 0; - - while ((a.len = dns_l_expand(a.label, sizeof a.label, a.p, &a.x, dst.b, lim))) { - for (i = 0; i < lengthof(P->dict) && P->dict[i]; i++) { - b.p = P->dict[i]; - - while ((b.len = dns_l_expand(b.label, sizeof b.label, b.p, &b.x, P->data, P->end))) { - a.y = a.x; - b.y = b.x; - - while (a.len && b.len && 0 == strcasecmp((char *)a.label, (char *)b.label)) { - a.len = dns_l_expand(a.label, sizeof a.label, a.y, &a.y, dst.b, lim); - b.len = dns_l_expand(b.label, sizeof b.label, b.y, &b.y, P->data, P->end); - } - - if (a.len == 0 && b.len == 0 && b.p <= 0x3fff) { - dst.b[a.p++] = 0xc0 - | (0x3f & (b.p >> 8)); - dst.b[a.p++] = (0xff & (b.p >> 0)); - - return a.p; - } - - b.p = b.x; - } /* while() */ - } /* for() */ - - a.p = a.x; - } /* while() */ - } /* if () */ -#endif - - if (!dst.p) - *error = DNS_EILLEGAL; - - return dst.p; -} /* dns_d_comp() */ - - -unsigned short dns_d_skip(unsigned short src, struct dns_packet *P) { - unsigned short len; - - while (src < P->end) { - switch (0x03 & (P->data[src] >> 6)) { - case 0x00: /* FOLLOWS */ - len = (0x3f & P->data[src++]); - - if (0 == len) { -/* success ==> */ return src; - } else if (P->end - src > len) { - src += len; - - break; - } else - goto invalid; - - /* NOT REACHED */ - case 0x01: /* RESERVED */ - goto invalid; - case 0x02: /* RESERVED */ - goto invalid; - case 0x03: /* POINTER */ - if (P->end - src < 2) - goto invalid; - - src += 2; - -/* success ==> */ return src; - } /* switch() */ - } /* while() */ - -invalid: - return P->end; -} /* dns_d_skip() */ - - -#include - -size_t dns_d_expand(void *dst, size_t lim, unsigned short src, struct dns_packet *P, int *error) { - size_t dstp = 0; - unsigned nptrs = 0; - unsigned char len; - - while (src < P->end) { - switch ((0x03 & (P->data[src] >> 6))) { - case 0x00: /* FOLLOWS */ - len = (0x3f & P->data[src]); - - if (0 == len) { - if (dstp == 0) { - if (dstp < lim) - ((unsigned char *)dst)[dstp] = '.'; - - dstp++; - } - - /* NUL terminate */ - if (lim > 0) - ((unsigned char *)dst)[DNS_PP_MIN(dstp, lim - 1)] = '\0'; - -/* success ==> */ return dstp; - } - - src++; - - if (P->end - src < len) - goto toolong; - - if (dstp < lim) - memcpy(&((unsigned char *)dst)[dstp], &P->data[src], DNS_PP_MIN(len, lim - dstp)); - - src += len; - dstp += len; - - if (dstp < lim) - ((unsigned char *)dst)[dstp] = '.'; - - dstp++; - - nptrs = 0; - - continue; - case 0x01: /* RESERVED */ - goto reserved; - case 0x02: /* RESERVED */ - goto reserved; - case 0x03: /* POINTER */ - if (++nptrs > DNS_D_MAXPTRS) - goto toolong; - - if (P->end - src < 2) - goto toolong; - - src = ((0x3f & P->data[src + 0]) << 8) - | ((0xff & P->data[src + 1]) << 0); - - continue; - } /* switch() */ - } /* while() */ - -toolong: - *error = DNS_EILLEGAL; - - if (lim > 0) - ((unsigned char *)dst)[DNS_PP_MIN(dstp, lim - 1)] = '\0'; - - return 0; -reserved: - *error = DNS_EILLEGAL; - - if (lim > 0) - ((unsigned char *)dst)[DNS_PP_MIN(dstp, lim - 1)] = '\0'; - - return 0; -} /* dns_d_expand() */ - - -int dns_d_push(struct dns_packet *P, const void *dn, size_t len) { - size_t lim = P->size - P->end; - unsigned dp = P->end; - int error = DNS_EILLEGAL; /* silence compiler */ - - len = dns_d_comp(&P->data[dp], lim, dn, len, P, &error); - - if (len == 0) - return error; - if (len > lim) - return DNS_ENOBUFS; - - P->end += len; - - dns_p_dictadd(P, dp); - - return 0; -} /* dns_d_push() */ - - -size_t dns_d_cname(void *dst, size_t lim, const void *dn, size_t len, struct dns_packet *P, int *error_) { - char host[DNS_D_MAXNAME + 1]; - struct dns_rr_i i; - struct dns_rr rr; - unsigned depth; - int error; - - if (sizeof host <= dns_d_anchor(host, sizeof host, dn, len)) - { error = ENAMETOOLONG; goto error; } - - for (depth = 0; depth < 7; depth++) { - dns_rr_i_init(memset(&i, 0, sizeof i), P); - - i.section = DNS_S_ALL & ~DNS_S_QD; - i.name = host; - i.type = DNS_T_CNAME; - - if (!dns_rr_grep(&rr, 1, &i, P, &error)) - break; - - if ((error = dns_cname_parse((struct dns_cname *)host, &rr, P))) - goto error; - } - - return dns_strlcpy(dst, host, lim); -error: - *error_ = error; - - return 0; -} /* dns_d_cname() */ - - -/* - * R E S O U R C E R E C O R D R O U T I N E S - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -int dns_rr_copy(struct dns_packet *P, struct dns_rr *rr, struct dns_packet *Q) { - unsigned char dn[DNS_D_MAXNAME + 1]; - union dns_any any; - size_t len; - int error; - - if (!(len = dns_d_expand(dn, sizeof dn, rr->dn.p, Q, &error))) - return error; - else if (len >= sizeof dn) - return DNS_EILLEGAL; - - if (rr->section != DNS_S_QD && (error = dns_any_parse(dns_any_init(&any, sizeof any), rr, Q))) - return error; - - return dns_p_push(P, rr->section, dn, len, rr->type, rr->class, rr->ttl, &any); -} /* dns_rr_copy() */ - - -int dns_rr_parse(struct dns_rr *rr, unsigned short src, struct dns_packet *P) { - unsigned short p = src; - - if (src >= P->end) - goto invalid; - - rr->dn.p = p; - rr->dn.len = (p = dns_d_skip(p, P)) - rr->dn.p; - - if (P->end - p < 4) - goto invalid; - - rr->type = ((0xff & P->data[p + 0]) << 8) - | ((0xff & P->data[p + 1]) << 0); - - rr->class = ((0xff & P->data[p + 2]) << 8) - | ((0xff & P->data[p + 3]) << 0); - - p += 4; - - if (src < dns_p_qend(P)) { - rr->section = DNS_S_QUESTION; - - rr->ttl = 0; - rr->rd.p = 0; - rr->rd.len = 0; - - return 0; - } - - if (P->end - p < 4) - goto invalid; - - rr->ttl = ((0x7f & P->data[p + 0]) << 24) - | ((0xff & P->data[p + 1]) << 16) - | ((0xff & P->data[p + 2]) << 8) - | ((0xff & P->data[p + 3]) << 0); - - p += 4; - - if (P->end - p < 2) - goto invalid; - - rr->rd.len = ((0xff & P->data[p + 0]) << 8) - | ((0xff & P->data[p + 1]) << 0); - rr->rd.p = p + 2; - - p += 2; - - if (P->end - p < rr->rd.len) - goto invalid; - - return 0; -invalid: - return DNS_EILLEGAL; -} /* dns_rr_parse() */ - - -static unsigned short dns_rr_len(const unsigned short src, struct dns_packet *P) { - unsigned short rp, rdlen; - - rp = dns_d_skip(src, P); - - if (P->end - rp < 4) - return P->end - src; - - rp += 4; /* TYPE, CLASS */ - - if (rp <= dns_p_qend(P)) - return rp - src; - - if (P->end - rp < 6) - return P->end - src; - - rp += 6; /* TTL, RDLEN */ - - rdlen = ((0xff & P->data[rp - 2]) << 8) - | ((0xff & P->data[rp - 1]) << 0); - - if (P->end - rp < rdlen) - return P->end - src; - - rp += rdlen; - - return rp - src; -} /* dns_rr_len() */ - - -unsigned short dns_rr_skip(unsigned short src, struct dns_packet *P) { - return src + dns_rr_len(src, P); -} /* dns_rr_skip() */ - - -static enum dns_section dns_rr_section(unsigned short src, struct dns_packet *P) { - enum dns_section section; - unsigned count, index; - unsigned short rp; - - if (src >= P->qd.base && src < P->qd.end) - return DNS_S_QD; - if (src >= P->an.base && src < P->an.end) - return DNS_S_AN; - if (src >= P->ns.base && src < P->ns.end) - return DNS_S_NS; - if (src >= P->ar.base && src < P->ar.end) - return DNS_S_AR; - - /* NOTE: Possibly bad memoization. Try it the hard-way. */ - - for (rp = 12, index = 0; rp < src && rp < P->end; index++) - rp = dns_rr_skip(rp, P); - - section = DNS_S_QD; - count = dns_p_count(P, section); - - while (index >= count && section <= DNS_S_AR) { - section <<= 1; - count += dns_p_count(P, section); - } - - return DNS_S_ALL & section; -} /* dns_rr_section() */ - - -static enum dns_type dns_rr_type(unsigned short src, struct dns_packet *P) { - struct dns_rr rr; - int error; - - if ((error = dns_rr_parse(&rr, src, P))) - return 0; - - return rr.type; -} /* dns_rr_type() */ - - -int dns_rr_cmp(struct dns_rr *r0, struct dns_packet *P0, struct dns_rr *r1, struct dns_packet *P1) { - char host0[DNS_D_MAXNAME + 1], host1[DNS_D_MAXNAME + 1]; - union dns_any any0, any1; - int cmp, error; - size_t len; - - if ((cmp = r0->type - r1->type)) - return cmp; - - if ((cmp = r0->class - r1->class)) - return cmp; - - /* - * FIXME: Do label-by-label comparison to handle illegally long names? - */ - - if (!(len = dns_d_expand(host0, sizeof host0, r0->dn.p, P0, &error)) - || len >= sizeof host0) - return -1; - - if (!(len = dns_d_expand(host1, sizeof host1, r1->dn.p, P1, &error)) - || len >= sizeof host1) - return 1; - - if ((cmp = strcasecmp(host0, host1))) - return cmp; - - if (DNS_S_QD & (r0->section | r1->section)) { - if (r0->section == r1->section) - return 0; - - return (r0->section == DNS_S_QD)? -1 : 1; - } - - if ((error = dns_any_parse(&any0, r0, P0))) - return -1; - - if ((error = dns_any_parse(&any1, r1, P1))) - return 1; - - return dns_any_cmp(&any0, r0->type, &any1, r1->type); -} /* dns_rr_cmp() */ - - -static _Bool dns_rr_exists(struct dns_rr *rr0, struct dns_packet *P0, struct dns_packet *P1) { - struct dns_rr rr1; - - dns_rr_foreach(&rr1, P1, .section = rr0->section, .type = rr0->type) { - if (0 == dns_rr_cmp(rr0, P0, &rr1, P1)) - return 1; - } - - return 0; -} /* dns_rr_exists() */ - - -static unsigned short dns_rr_offset(struct dns_rr *rr) { - return rr->dn.p; -} /* dns_rr_offset() */ - - -static _Bool dns_rr_i_match(struct dns_rr *rr, struct dns_rr_i *i, struct dns_packet *P) { - if (i->section && !(rr->section & i->section)) - return 0; - - if (i->type && rr->type != i->type && i->type != DNS_T_ALL) - return 0; - - if (i->class && rr->class != i->class && i->class != DNS_C_ANY) - return 0; - - if (i->name) { - char dn[DNS_D_MAXNAME + 1]; - size_t len; - int error; - - if (!(len = dns_d_expand(dn, sizeof dn, rr->dn.p, P, &error)) - || len >= sizeof dn) - return 0; - - if (0 != strcasecmp(dn, i->name)) - return 0; - } - - if (i->data && i->type && rr->section > DNS_S_QD) { - union dns_any rd; - int error; - - if ((error = dns_any_parse(&rd, rr, P))) - return 0; - - if (0 != dns_any_cmp(&rd, rr->type, i->data, i->type)) - return 0; - } - - return 1; -} /* dns_rr_i_match() */ - - -static unsigned short dns_rr_i_start(struct dns_rr_i *i, struct dns_packet *P) { - unsigned short rp; - struct dns_rr r0, rr; - int error; - - if ((i->section & DNS_S_QD) && P->qd.base) - rp = P->qd.base; - else if ((i->section & DNS_S_AN) && P->an.base) - rp = P->an.base; - else if ((i->section & DNS_S_NS) && P->ns.base) - rp = P->ns.base; - else if ((i->section & DNS_S_AR) && P->ar.base) - rp = P->ar.base; - else - rp = 12; - - for (; rp < P->end; rp = dns_rr_skip(rp, P)) { - if ((error = dns_rr_parse(&rr, rp, P))) - continue; - - rr.section = dns_rr_section(rp, P); - - if (!dns_rr_i_match(&rr, i, P)) - continue; - - r0 = rr; - - goto lower; - } - - return P->end; -lower: - if (i->sort == &dns_rr_i_packet) - return dns_rr_offset(&r0); - - while ((rp = dns_rr_skip(rp, P)) < P->end) { - if ((error = dns_rr_parse(&rr, rp, P))) - continue; - - rr.section = dns_rr_section(rp, P); - - if (!dns_rr_i_match(&rr, i, P)) - continue; - - if (i->sort(&rr, &r0, i, P) < 0) - r0 = rr; - } - - return dns_rr_offset(&r0); -} /* dns_rr_i_start() */ - - -static unsigned short dns_rr_i_skip(unsigned short rp, struct dns_rr_i *i, struct dns_packet *P) { - struct dns_rr r0, r1, rr; - int error; - - if ((error = dns_rr_parse(&r0, rp, P))) - return P->end; - - r0.section = dns_rr_section(rp, P); - - rp = (i->sort == &dns_rr_i_packet)? dns_rr_skip(rp, P) : 12; - - for (; rp < P->end; rp = dns_rr_skip(rp, P)) { - if ((error = dns_rr_parse(&rr, rp, P))) - continue; - - rr.section = dns_rr_section(rp, P); - - if (!dns_rr_i_match(&rr, i, P)) - continue; - - if (i->sort(&rr, &r0, i, P) <= 0) - continue; - - r1 = rr; - - goto lower; - } - - return P->end; -lower: - if (i->sort == &dns_rr_i_packet) - return dns_rr_offset(&r1); - - while ((rp = dns_rr_skip(rp, P)) < P->end) { - if ((error = dns_rr_parse(&rr, rp, P))) - continue; - - rr.section = dns_rr_section(rp, P); - - if (!dns_rr_i_match(&rr, i, P)) - continue; - - if (i->sort(&rr, &r0, i, P) <= 0) - continue; - - if (i->sort(&rr, &r1, i, P) >= 0) - continue; - - r1 = rr; - } - - return dns_rr_offset(&r1); -} /* dns_rr_i_skip() */ - - -int dns_rr_i_packet(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) { - (void)i; - (void)P; - - return (int)a->dn.p - (int)b->dn.p; -} /* dns_rr_i_packet() */ - - -int dns_rr_i_order(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) { - int cmp; - - (void)i; - - if ((cmp = a->section - b->section)) - return cmp; - - if (a->type != b->type) - return (int)a->dn.p - (int)b->dn.p; - - return dns_rr_cmp(a, P, b, P); -} /* dns_rr_i_order() */ - - -int dns_rr_i_shuffle(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) { - int cmp; - - (void)i; - (void)P; - - while (!i->state.regs[0]) - i->state.regs[0] = dns_random(); - - if ((cmp = a->section - b->section)) - return cmp; - - return dns_k_shuffle16(a->dn.p, i->state.regs[0]) - dns_k_shuffle16(b->dn.p, i->state.regs[0]); -} /* dns_rr_i_shuffle() */ - - -struct dns_rr_i *dns_rr_i_init(struct dns_rr_i *i, struct dns_packet *P) { - static const struct dns_rr_i i_initializer; - - (void)P; - - i->state = i_initializer.state; - i->saved = i->state; - - return i; -} /* dns_rr_i_init() */ - - -unsigned dns_rr_grep(struct dns_rr *rr, unsigned lim, struct dns_rr_i *i, struct dns_packet *P, int *error_) { - unsigned count = 0; - int error; - - switch (i->state.exec) { - case 0: - if (!i->sort) - i->sort = &dns_rr_i_packet; - - i->state.next = dns_rr_i_start(i, P); - i->state.exec++; - - /* FALL THROUGH */ - case 1: - while (count < lim && i->state.next < P->end) { - if ((error = dns_rr_parse(rr, i->state.next, P))) - goto error; - - rr->section = dns_rr_section(i->state.next, P); - - rr++; - count++; - i->state.count++; - - i->state.next = dns_rr_i_skip(i->state.next, i, P); - } /* while() */ - - break; - } /* switch() */ - - return count; -error: - *error_ = error; - - return count; -} /* dns_rr_grep() */ - - -static size_t dns__printchar(void *dst, size_t lim, size_t cp, unsigned char ch) { - if (cp < lim) - ((unsigned char *)dst)[cp] = ch; - - return 1; -} /* dns__printchar() */ - - -static size_t dns__printstring(void *dst, size_t lim, size_t cp, const void *src, size_t len) { - if (cp < lim) - memcpy(&((unsigned char *)dst)[cp], src, DNS_PP_MIN(len, lim - cp)); - - return len; -} /* dns__printstring() */ - -#define dns__printstring5(a, b, c, d, e) dns__printstring((a), (b), (c), (d), (e)) -#define dns__printstring4(a, b, c, d) dns__printstring((a), (b), (c), (d), strlen((d))) -#define dns__printstring(...) DNS_PP_CALL(DNS_PP_XPASTE(dns__printstring, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__) - - -static void dns__printnul(void *dst, size_t lim, size_t off) { - if (lim > 0) - ((unsigned char *)dst)[DNS_PP_MIN(off, lim - 1)] = '\0'; -} /* dns__printnul() */ - - -static size_t dns__print10(void *dst, size_t lim, size_t off, unsigned n, unsigned pad) { - unsigned char tmp[32]; - unsigned dp = off; - unsigned cp = 0; - unsigned d = 1000000000; - unsigned ch; - - pad = DNS_PP_MAX(1, pad); - - while (d) { - if ((ch = n / d) || cp > 0) { - n -= ch * d; - - tmp[cp] = '0' + ch; - - cp++; - } - - d /= 10; - } - - while (cp < pad) { - dp += dns__printchar(dst, lim, dp, '0'); - pad--; - } - - dp += dns__printstring(dst, lim, dp, tmp, cp); - - return dp - off; -} /* dns__print10() */ - - -size_t dns_rr_print(void *dst, size_t lim, struct dns_rr *rr, struct dns_packet *P, int *error_) { - union dns_any any; - size_t cp, n, rdlen; - void *rd; - int error; - - cp = 0; - - if (rr->section == DNS_S_QD) - cp += dns__printchar(dst, lim, cp, ';'); - - if (!(n = dns_d_expand(&((unsigned char *)dst)[cp], (cp < lim)? lim - cp : 0, rr->dn.p, P, &error))) - goto error; - - cp += n; - - if (rr->section != DNS_S_QD) { - cp += dns__printchar(dst, lim, cp, ' '); - cp += dns__print10(dst, lim, cp, rr->ttl, 0); - } - - cp += dns__printchar(dst, lim, cp, ' '); - cp += dns__printstring(dst, lim, cp, dns_strclass(rr->class), strlen(dns_strclass(rr->class))); - cp += dns__printchar(dst, lim, cp, ' '); - cp += dns__printstring(dst, lim, cp, dns_strtype(rr->type), strlen(dns_strtype(rr->type))); - - if (rr->section == DNS_S_QD) - goto epilog; - - cp += dns__printchar(dst, lim, cp, ' '); - - if ((error = dns_any_parse(dns_any_init(&any, sizeof any), rr, P))) - goto error; - - if (cp < lim) { - rd = &((unsigned char *)dst)[cp]; - rdlen = lim - cp; - } else { - rd = 0; - rdlen = 0; - } - - cp += dns_any_print(rd, rdlen, &any, rr->type); - -epilog: - dns__printnul(dst, lim, cp); - - return cp; -error: - *error_ = error; - - return 0; -} /* dns_rr_print() */ - - -int dns_a_parse(struct dns_a *a, struct dns_rr *rr, struct dns_packet *P) { - unsigned long addr; - - if (rr->rd.len != 4) - return DNS_EILLEGAL; - - addr = ((0xff & P->data[rr->rd.p + 0]) << 24) - | ((0xff & P->data[rr->rd.p + 1]) << 16) - | ((0xff & P->data[rr->rd.p + 2]) << 8) - | ((0xff & P->data[rr->rd.p + 3]) << 0); - - a->addr.s_addr = htonl(addr); - - return 0; -} /* dns_a_parse() */ - - -int dns_a_push(struct dns_packet *P, struct dns_a *a) { - unsigned long addr; - - if (P->size - P->end < 6) - return DNS_ENOBUFS; - - P->data[P->end++] = 0x00; - P->data[P->end++] = 0x04; - - addr = ntohl(a->addr.s_addr); - - P->data[P->end++] = 0xff & (addr >> 24); - P->data[P->end++] = 0xff & (addr >> 16); - P->data[P->end++] = 0xff & (addr >> 8); - P->data[P->end++] = 0xff & (addr >> 0); - - return 0; -} /* dns_a_push() */ - - -size_t dns_a_arpa(void *dst, size_t lim, const struct dns_a *a) { - unsigned long a4 = ntohl(a->addr.s_addr); - size_t cp = 0; - unsigned i; - - for (i = 4; i > 0; i--) { - cp += dns__print10(dst, lim, cp, (0xff & a4), 0); - cp += dns__printchar(dst, lim, cp, '.'); - a4 >>= 8; - } - - cp += dns__printstring(dst, lim, cp, "in-addr.arpa."); - - dns__printnul(dst, lim, cp); - - return cp; -} /* dns_a_arpa() */ - - -int dns_a_cmp(const struct dns_a *a, const struct dns_a *b) { - if (ntohl(a->addr.s_addr) < ntohl(b->addr.s_addr)) - return -1; - if (ntohl(a->addr.s_addr) > ntohl(b->addr.s_addr)) - return 1; - - return 0; -} /* dns_a_cmp() */ - - -size_t dns_a_print(void *dst, size_t lim, struct dns_a *a) { - char addr[INET_ADDRSTRLEN + 1] = "0.0.0.0"; - size_t len; - - dns_inet_ntop(AF_INET, &a->addr, addr, sizeof addr); - - dns__printnul(dst, lim, (len = dns__printstring(dst, lim, 0, addr))); - - return len; -} /* dns_a_print() */ - - -int dns_aaaa_parse(struct dns_aaaa *aaaa, struct dns_rr *rr, struct dns_packet *P) { - if (rr->rd.len != sizeof aaaa->addr.s6_addr) - return DNS_EILLEGAL; - - memcpy(aaaa->addr.s6_addr, &P->data[rr->rd.p], sizeof aaaa->addr.s6_addr); - - return 0; -} /* dns_aaaa_parse() */ - - -int dns_aaaa_push(struct dns_packet *P, struct dns_aaaa *aaaa) { - if (P->size - P->end < 2 + sizeof aaaa->addr.s6_addr) - return DNS_ENOBUFS; - - P->data[P->end++] = 0x00; - P->data[P->end++] = 0x10; - - memcpy(&P->data[P->end], aaaa->addr.s6_addr, sizeof aaaa->addr.s6_addr); - - P->end += sizeof aaaa->addr.s6_addr; - - return 0; -} /* dns_aaaa_push() */ - - -int dns_aaaa_cmp(const struct dns_aaaa *a, const struct dns_aaaa *b) { - unsigned i; - int cmp; - - for (i = 0; i < lengthof(a->addr.s6_addr); i++) { - if ((cmp = (a->addr.s6_addr[i] - b->addr.s6_addr[i]))) - return cmp; - } - - return 0; -} /* dns_aaaa_cmp() */ - - -size_t dns_aaaa_arpa(void *dst, size_t lim, const struct dns_aaaa *aaaa) { - static const unsigned char hex[16] = "0123456789abcdef"; - size_t cp = 0; - unsigned nyble; - int i, j; - - for (i = sizeof aaaa->addr.s6_addr - 1; i >= 0; i--) { - nyble = aaaa->addr.s6_addr[i]; - - for (j = 0; j < 2; j++) { - cp += dns__printchar(dst, lim, cp, hex[0x0f & nyble]); - cp += dns__printchar(dst, lim, cp, '.'); - nyble >>= 4; - } - } - - cp += dns__printstring(dst, lim, cp, "ip6.arpa."); - - dns__printnul(dst, lim, cp); - - return cp; -} /* dns_aaaa_arpa() */ - - -size_t dns_aaaa_print(void *dst, size_t lim, struct dns_aaaa *aaaa) { - char addr[INET6_ADDRSTRLEN + 1] = "::"; - size_t len; - - dns_inet_ntop(AF_INET6, &aaaa->addr, addr, sizeof addr); - - dns__printnul(dst, lim, (len = dns__printstring(dst, lim, 0, addr))); - - return len; -} /* dns_aaaa_print() */ - - -int dns_mx_parse(struct dns_mx *mx, struct dns_rr *rr, struct dns_packet *P) { - size_t len; - int error; - - if (rr->rd.len < 3) - return DNS_EILLEGAL; - - mx->preference = (0xff00 & (P->data[rr->rd.p + 0] << 8)) - | (0x00ff & (P->data[rr->rd.p + 1] << 0)); - - if (!(len = dns_d_expand(mx->host, sizeof mx->host, rr->rd.p + 2, P, &error))) - return error; - else if (len >= sizeof mx->host) - return DNS_EILLEGAL; - - return 0; -} /* dns_mx_parse() */ - - -int dns_mx_push(struct dns_packet *P, struct dns_mx *mx) { - size_t end, len; - int error; - - if (P->size - P->end < 5) - return DNS_ENOBUFS; - - end = P->end; - P->end += 2; - - P->data[P->end++] = 0xff & (mx->preference >> 8); - P->data[P->end++] = 0xff & (mx->preference >> 0); - - if ((error = dns_d_push(P, mx->host, strlen(mx->host)))) - goto error; - - len = P->end - end - 2; - - P->data[end + 0] = 0xff & (len >> 8); - P->data[end + 1] = 0xff & (len >> 0); - - return 0; -error: - P->end = end; - - return error; -} /* dns_mx_push() */ - - -int dns_mx_cmp(const struct dns_mx *a, const struct dns_mx *b) { - int cmp; - - if ((cmp = a->preference - b->preference)) - return cmp; - - return strcasecmp(a->host, b->host); -} /* dns_mx_cmp() */ - - -size_t dns_mx_print(void *dst, size_t lim, struct dns_mx *mx) { - size_t cp = 0; - - cp += dns__print10(dst, lim, cp, mx->preference, 0); - cp += dns__printchar(dst, lim, cp, ' '); - cp += dns__printstring(dst, lim, cp, mx->host, strlen(mx->host)); - - dns__printnul(dst, lim, cp); - - return cp; -} /* dns_mx_print() */ - - -size_t dns_mx_cname(void *dst, size_t lim, struct dns_mx *mx) { - return dns_strlcpy(dst, mx->host, lim); -} /* dns_mx_cname() */ - - -int dns_ns_parse(struct dns_ns *ns, struct dns_rr *rr, struct dns_packet *P) { - size_t len; - int error; - - if (!(len = dns_d_expand(ns->host, sizeof ns->host, rr->rd.p, P, &error))) - return error; - else if (len >= sizeof ns->host) - return DNS_EILLEGAL; - - return 0; -} /* dns_ns_parse() */ - - -int dns_ns_push(struct dns_packet *P, struct dns_ns *ns) { - size_t end, len; - int error; - - if (P->size - P->end < 3) - return DNS_ENOBUFS; - - end = P->end; - P->end += 2; - - if ((error = dns_d_push(P, ns->host, strlen(ns->host)))) - goto error; - - len = P->end - end - 2; - - P->data[end + 0] = 0xff & (len >> 8); - P->data[end + 1] = 0xff & (len >> 0); - - return 0; -error: - P->end = end; - - return error; -} /* dns_ns_push() */ - - -int dns_ns_cmp(const struct dns_ns *a, const struct dns_ns *b) { - return strcasecmp(a->host, b->host); -} /* dns_ns_cmp() */ - - -size_t dns_ns_print(void *dst, size_t lim, struct dns_ns *ns) { - size_t cp; - - cp = dns__printstring(dst, lim, 0, ns->host, strlen(ns->host)); - - dns__printnul(dst, lim, cp); - - return cp; -} /* dns_ns_print() */ - - -size_t dns_ns_cname(void *dst, size_t lim, struct dns_ns *ns) { - return dns_strlcpy(dst, ns->host, lim); -} /* dns_ns_cname() */ - - -int dns_cname_parse(struct dns_cname *cname, struct dns_rr *rr, struct dns_packet *P) { - return dns_ns_parse((struct dns_ns *)cname, rr, P); -} /* dns_cname_parse() */ - - -int dns_cname_push(struct dns_packet *P, struct dns_cname *cname) { - return dns_ns_push(P, (struct dns_ns *)cname); -} /* dns_cname_push() */ - - -int dns_cname_cmp(const struct dns_cname *a, const struct dns_cname *b) { - return strcasecmp(a->host, b->host); -} /* dns_cname_cmp() */ - - -size_t dns_cname_print(void *dst, size_t lim, struct dns_cname *cname) { - return dns_ns_print(dst, lim, (struct dns_ns *)cname); -} /* dns_cname_print() */ - - -size_t dns_cname_cname(void *dst, size_t lim, struct dns_cname *cname) { - return dns_strlcpy(dst, cname->host, lim); -} /* dns_cname_cname() */ - - -int dns_soa_parse(struct dns_soa *soa, struct dns_rr *rr, struct dns_packet *P) { - struct { void *dst; size_t lim; } dn[] = - { { soa->mname, sizeof soa->mname }, - { soa->rname, sizeof soa->rname } }; - unsigned *ts[] = - { &soa->serial, &soa->refresh, &soa->retry, &soa->expire, &soa->minimum }; - unsigned short rp; - unsigned i, j, n; - int error; - - /* MNAME / RNAME */ - if ((rp = rr->rd.p) >= P->end) - return DNS_EILLEGAL; - - for (i = 0; i < lengthof(dn); i++) { - if (!(n = dns_d_expand(dn[i].dst, dn[i].lim, rp, P, &error))) - return error; - else if (n >= dn[i].lim) - return DNS_EILLEGAL; - - if ((rp = dns_d_skip(rp, P)) >= P->end) - return DNS_EILLEGAL; - } - - /* SERIAL / REFRESH / RETRY / EXPIRE / MINIMUM */ - for (i = 0; i < lengthof(ts); i++) { - for (j = 0; j < 4; j++, rp++) { - if (rp >= P->end) - return DNS_EILLEGAL; - - *ts[i] <<= 8; - *ts[i] |= (0xff & P->data[rp]); - } - } - - return 0; -} /* dns_soa_parse() */ - - -int dns_soa_push(struct dns_packet *P, struct dns_soa *soa) { - void *dn[] = { soa->mname, soa->rname }; - unsigned ts[] = { (0xffffffff & soa->serial), - (0x7fffffff & soa->refresh), - (0x7fffffff & soa->retry), - (0x7fffffff & soa->expire), - (0xffffffff & soa->minimum) }; - unsigned i, j; - size_t end, len; - int error; - - end = P->end; - - if ((P->end += 2) >= P->size) - goto toolong; - - /* MNAME / RNAME */ - for (i = 0; i < lengthof(dn); i++) { - if ((error = dns_d_push(P, dn[i], strlen(dn[i])))) - goto error; - } - - /* SERIAL / REFRESH / RETRY / EXPIRE / MINIMUM */ - for (i = 0; i < lengthof(ts); i++) { - if ((P->end += 4) >= P->size) - goto toolong; - - for (j = 1; j <= 4; j++) { - P->data[P->end - j] = (0xff & ts[i]); - ts[i] >>= 8; - } - } - - len = P->end - end - 2; - P->data[end + 0] = (0xff & (len >> 8)); - P->data[end + 1] = (0xff & (len >> 0)); - - return 0; -toolong: - error = DNS_ENOBUFS; - - /* FALL THROUGH */ -error: - P->end = end; - - return error; -} /* dns_soa_push() */ - - -int dns_soa_cmp(const struct dns_soa *a, const struct dns_soa *b) { - int cmp; - - if ((cmp = strcasecmp(a->mname, b->mname))) - return cmp; - - if ((cmp = strcasecmp(a->rname, b->rname))) - return cmp; - - if (a->serial > b->serial) - return -1; - else if (a->serial < b->serial) - return 1; - - if (a->refresh > b->refresh) - return -1; - else if (a->refresh < b->refresh) - return 1; - - if (a->retry > b->retry) - return -1; - else if (a->retry < b->retry) - return 1; - - if (a->expire > b->expire) - return -1; - else if (a->expire < b->expire) - return 1; - - if (a->minimum > b->minimum) - return -1; - else if (a->minimum < b->minimum) - return 1; - - return 0; -} /* dns_soa_cmp() */ - - -size_t dns_soa_print(void *dst, size_t lim, struct dns_soa *soa) { - size_t cp = 0; - - cp += dns__printstring(dst, lim, cp, soa->mname, strlen(soa->mname)); - cp += dns__printchar(dst, lim, cp, ' '); - cp += dns__printstring(dst, lim, cp, soa->rname, strlen(soa->rname)); - cp += dns__printchar(dst, lim, cp, ' '); - cp += dns__print10(dst, lim, cp, soa->serial, 0); - cp += dns__printchar(dst, lim, cp, ' '); - cp += dns__print10(dst, lim, cp, soa->refresh, 0); - cp += dns__printchar(dst, lim, cp, ' '); - cp += dns__print10(dst, lim, cp, soa->retry, 0); - cp += dns__printchar(dst, lim, cp, ' '); - cp += dns__print10(dst, lim, cp, soa->expire, 0); - cp += dns__printchar(dst, lim, cp, ' '); - cp += dns__print10(dst, lim, cp, soa->minimum, 0); - - dns__printnul(dst, lim, cp); - - return cp; -} /* dns_soa_print() */ - - -int dns_srv_parse(struct dns_srv *srv, struct dns_rr *rr, struct dns_packet *P) { - unsigned short rp; - unsigned i; - size_t n; - int error; - - memset(srv, '\0', sizeof *srv); - - rp = rr->rd.p; - - if (rr->rd.len < 7) - return DNS_EILLEGAL; - - for (i = 0; i < 2; i++, rp++) { - srv->priority <<= 8; - srv->priority |= (0xff & P->data[rp]); - } - - for (i = 0; i < 2; i++, rp++) { - srv->weight <<= 8; - srv->weight |= (0xff & P->data[rp]); - } - - for (i = 0; i < 2; i++, rp++) { - srv->port <<= 8; - srv->port |= (0xff & P->data[rp]); - } - - if (!(n = dns_d_expand(srv->target, sizeof srv->target, rp, P, &error))) - return error; - else if (n >= sizeof srv->target) - return DNS_EILLEGAL; - - return 0; -} /* dns_srv_parse() */ - - -int dns_srv_push(struct dns_packet *P, struct dns_srv *srv) { - size_t end, len; - int error; - - end = P->end; - - if (P->size - P->end < 2) - goto toolong; - - P->end += 2; - - if (P->size - P->end < 6) - goto toolong; - - P->data[P->end++] = 0xff & (srv->priority >> 8); - P->data[P->end++] = 0xff & (srv->priority >> 0); - - P->data[P->end++] = 0xff & (srv->weight >> 8); - P->data[P->end++] = 0xff & (srv->weight >> 0); - - P->data[P->end++] = 0xff & (srv->port >> 8); - P->data[P->end++] = 0xff & (srv->port >> 0); - - if (0 == (len = dns_d_comp(&P->data[P->end], P->size - P->end, srv->target, strlen(srv->target), P, &error))) - goto error; - else if (P->size - P->end < len) - goto toolong; - - P->end += len; - - if (P->end > 65535) - goto toolong; - - len = P->end - end - 2; - - P->data[end + 0] = 0xff & (len >> 8); - P->data[end + 1] = 0xff & (len >> 0); - - return 0; -toolong: - error = DNS_ENOBUFS; - - /* FALL THROUGH */ -error: - P->end = end; - - return error; -} /* dns_srv_push() */ - - -int dns_srv_cmp(const struct dns_srv *a, const struct dns_srv *b) { - int cmp; - - if ((cmp = a->priority - b->priority)) - return cmp; - - /* - * FIXME: We need some sort of random seed to implement the dynamic - * weighting required by RFC 2782. - */ - if ((cmp = a->weight - b->weight)) - return cmp; - - if ((cmp = a->port - b->port)) - return cmp; - - return strcasecmp(a->target, b->target); -} /* dns_srv_cmp() */ - - -size_t dns_srv_print(void *dst, size_t lim, struct dns_srv *srv) { - size_t cp = 0; - - cp += dns__print10(dst, lim, cp, srv->priority, 0); - cp += dns__printchar(dst, lim, cp, ' '); - cp += dns__print10(dst, lim, cp, srv->weight, 0); - cp += dns__printchar(dst, lim, cp, ' '); - cp += dns__print10(dst, lim, cp, srv->port, 0); - cp += dns__printchar(dst, lim, cp, ' '); - cp += dns__printstring(dst, lim, cp, srv->target, strlen(srv->target)); - - dns__printnul(dst, lim, cp); - - return cp; -} /* dns_srv_print() */ - - -size_t dns_srv_cname(void *dst, size_t lim, struct dns_srv *srv) { - return dns_strlcpy(dst, srv->target, lim); -} /* dns_srv_cname() */ - - -unsigned int dns_opt_ttl(const struct dns_opt *opt) { - unsigned int ttl = 0; - - ttl |= (0xffU & opt->rcode) << 24U; - ttl |= (0xffU & opt->version) << 16U; - - return ttl; -} /* dns_opt_ttl() */ - - -unsigned short dns_opt_class(const struct dns_opt *opt) { - return opt->maxsize; -} /* dns_opt_class() */ - - -struct dns_opt *dns_opt_init(struct dns_opt *opt, size_t size) { - assert(size >= offsetof(struct dns_opt, data)); - - opt->size = size - offsetof(struct dns_opt, data); - opt->len = 0; - - opt->rcode = 0; - opt->version = 0; - opt->maxsize = 512; - - return opt; -} /* dns_opt_init() */ - - -int dns_opt_parse(struct dns_opt *opt, struct dns_rr *rr, struct dns_packet *P) { - (void)rr; - (void)P; - - opt->len = 0; - - return 0; -} /* dns_opt_parse() */ - - -int dns_opt_push(struct dns_packet *P, struct dns_opt *opt) { - (void)P; - (void)opt; - - return 0; -} /* dns_opt_push() */ - - -int dns_opt_cmp(const struct dns_opt *a, const struct dns_opt *b) { - (void)a; - (void)b; - - return 0; -} /* dns_opt_cmp() */ - - -size_t dns_opt_print(void *dst, size_t lim, struct dns_opt *opt) { - size_t p = 0, src; - - p += dns__printchar(dst, lim, p, '"'); - - for (src = 0; src < opt->len; src++) { - p += dns__printchar(dst, lim, p, '\\'); - p += dns__print10(dst, lim, p, opt->data[src], 3); - } - - p += dns__printchar(dst, lim, p, '"'); - - dns__printnul(dst, lim, p); - - return p; -} /* dns_opt_print() */ - - -int dns_ptr_parse(struct dns_ptr *ptr, struct dns_rr *rr, struct dns_packet *P) { - return dns_ns_parse((struct dns_ns *)ptr, rr, P); -} /* dns_ptr_parse() */ - - -int dns_ptr_push(struct dns_packet *P, struct dns_ptr *ptr) { - return dns_ns_push(P, (struct dns_ns *)ptr); -} /* dns_ptr_push() */ - - -size_t dns_ptr_qname(void *dst, size_t lim, int af, void *addr) { - unsigned len = (af == AF_INET6) - ? dns_aaaa_arpa(dst, lim, addr) - : dns_a_arpa(dst, lim, addr); - - dns__printnul(dst, lim, len); - - return len; -} /* dns_ptr_qname() */ - - -int dns_ptr_cmp(const struct dns_ptr *a, const struct dns_ptr *b) { - return strcasecmp(a->host, b->host); -} /* dns_ptr_cmp() */ - - -size_t dns_ptr_print(void *dst, size_t lim, struct dns_ptr *ptr) { - return dns_ns_print(dst, lim, (struct dns_ns *)ptr); -} /* dns_ptr_print() */ - - -size_t dns_ptr_cname(void *dst, size_t lim, struct dns_ptr *ptr) { - return dns_strlcpy(dst, ptr->host, lim); -} /* dns_ptr_cname() */ - - -int dns_sshfp_parse(struct dns_sshfp *fp, struct dns_rr *rr, struct dns_packet *P) { - unsigned p = rr->rd.p, pe = rr->rd.p + rr->rd.len; - - if (pe - p < 2) - return DNS_EILLEGAL; - - fp->algo = P->data[p++]; - fp->type = P->data[p++]; - - switch (fp->type) { - case DNS_SSHFP_SHA1: - if (pe - p < sizeof fp->digest.sha1) - return DNS_EILLEGAL; - - memcpy(fp->digest.sha1, &P->data[p], sizeof fp->digest.sha1); - - break; - default: - break; - } /* switch() */ - - return 0; -} /* dns_sshfp_parse() */ - - -int dns_sshfp_push(struct dns_packet *P, struct dns_sshfp *fp) { - unsigned p = P->end, pe = P->size, n; - - if (pe - p < 4) - return DNS_ENOBUFS; - - p += 2; - P->data[p++] = 0xff & fp->algo; - P->data[p++] = 0xff & fp->type; - - switch (fp->type) { - case DNS_SSHFP_SHA1: - if (pe - p < sizeof fp->digest.sha1) - return DNS_ENOBUFS; - - memcpy(&P->data[p], fp->digest.sha1, sizeof fp->digest.sha1); - p += sizeof fp->digest.sha1; - - break; - default: - return DNS_EILLEGAL; - } /* switch() */ - - n = p - P->end - 2; - P->data[P->end++] = 0xff & (n >> 8); - P->data[P->end++] = 0xff & (n >> 0); - P->end = p; - - return 0; -} /* dns_sshfp_push() */ - - -int dns_sshfp_cmp(const struct dns_sshfp *a, const struct dns_sshfp *b) { - int cmp; - - if ((cmp = a->algo - b->algo) || (cmp = a->type - b->type)) - return cmp; - - switch (a->type) { - case DNS_SSHFP_SHA1: - return memcmp(a->digest.sha1, b->digest.sha1, sizeof a->digest.sha1); - default: - return 0; - } /* switch() */ - - /* NOT REACHED */ -} /* dns_sshfp_cmp() */ - - -size_t dns_sshfp_print(void *dst, size_t lim, struct dns_sshfp *fp) { - static const unsigned char hex[16] = "0123456789abcdef"; - size_t i, p = 0; - - p += dns__print10(dst, lim, p, fp->algo, 0); - p += dns__printchar(dst, lim, p, ' '); - p += dns__print10(dst, lim, p, fp->type, 0); - p += dns__printchar(dst, lim, p, ' '); - - switch (fp->type) { - case DNS_SSHFP_SHA1: - for (i = 0; i < sizeof fp->digest.sha1; i++) { - p += dns__printchar(dst, lim, p, hex[0x0f & (fp->digest.sha1[i] >> 4)]); - p += dns__printchar(dst, lim, p, hex[0x0f & (fp->digest.sha1[i] >> 0)]); - } - - break; - default: - p += dns__printchar(dst, lim, p, '0'); - - break; - } /* switch() */ - - dns__printnul(dst, lim, p); - - return p; -} /* dns_sshfp_print() */ - - -struct dns_txt *dns_txt_init(struct dns_txt *txt, size_t size) { - assert(size > offsetof(struct dns_txt, data)); - - txt->size = size - offsetof(struct dns_txt, data); - txt->len = 0; - - return txt; -} /* dns_txt_init() */ - - -int dns_txt_parse(struct dns_txt *txt, struct dns_rr *rr, struct dns_packet *P) { - struct { unsigned char *b; size_t p, end; } dst, src; - unsigned n; - - dst.b = txt->data; - dst.p = 0; - dst.end = txt->size; - - src.b = P->data; - src.p = rr->rd.p; - src.end = src.p + rr->rd.len; - - while (src.p < src.end) { - n = 0xff & P->data[src.p++]; - - if (src.end - src.p < n || dst.end - dst.p < n) - return DNS_EILLEGAL; - - memcpy(&dst.b[dst.p], &src.b[src.p], n); - - dst.p += n; - src.p += n; - } - - txt->len = dst.p; - - return 0; -} /* dns_txt_parse() */ - - -int dns_txt_push(struct dns_packet *P, struct dns_txt *txt) { - struct { unsigned char *b; size_t p, end; } dst, src; - unsigned n; - - dst.b = P->data; - dst.p = P->end; - dst.end = P->size; - - src.b = txt->data; - src.p = 0; - src.end = txt->len; - - if (dst.end - dst.p < 2) - return DNS_ENOBUFS; - - n = txt->len + ((txt->len + 254) / 255); - - dst.b[dst.p++] = 0xff & (n >> 8); - dst.b[dst.p++] = 0xff & (n >> 0); - - while (src.p < src.end) { - n = DNS_PP_MIN(255, src.end - src.p); - - if (dst.p >= dst.end) - return DNS_ENOBUFS; - - dst.b[dst.p++] = n; - - if (dst.end - dst.p < n) - return DNS_ENOBUFS; - - memcpy(&dst.b[dst.p], &src.b[src.p], n); - - dst.p += n; - src.p += n; - } - - P->end = dst.p; - - return 0; -} /* dns_txt_push() */ - - -int dns_txt_cmp(const struct dns_txt *a, const struct dns_txt *b) { - (void)a; - (void)b; - - return -1; -} /* dns_txt_cmp() */ - - -size_t dns_txt_print(void *dst_, size_t lim, struct dns_txt *txt) { - struct { unsigned char *b; size_t p, end; } dst, src; - unsigned ch; - - dst.b = dst_; - dst.end = lim; - dst.p = 0; - - src.b = txt->data; - src.end = txt->len; - src.p = 0; - - dst.p += dns__printchar(dst.b, dst.end, dst.p, '"'); - - while (src.p < src.end) { - ch = src.b[src.p]; - - if (0 == (src.p++ % 255) && src.p != 1) { - dst.p += dns__printchar(dst.b, dst.end, dst.p, '"'); - dst.p += dns__printchar(dst.b, dst.end, dst.p, ' '); - dst.p += dns__printchar(dst.b, dst.end, dst.p, '"'); - } - - if (ch < 32 || ch > 126 || ch == '"' || ch == '\\') { - dst.p += dns__printchar(dst.b, dst.end, dst.p, '\\'); - dst.p += dns__print10(dst.b, dst.end, dst.p, ch, 3); - } else { - dst.p += dns__printchar(dst.b, dst.end, dst.p, ch); - } - } - - dst.p += dns__printchar(dst.b, dst.end, dst.p, '"'); - - dns__printnul(dst.b, dst.end, dst.p); - - return dst.p; -} /* dns_txt_print() */ - - -static const struct { - enum dns_type type; - const char *name; - int (*parse)(); - int (*push)(); - int (*cmp)(); - size_t (*print)(); - size_t (*cname)(); -} dns_rrtypes[] = { - { DNS_T_A, "A", &dns_a_parse, &dns_a_push, &dns_a_cmp, &dns_a_print, 0 }, - { DNS_T_AAAA, "AAAA", &dns_aaaa_parse, &dns_aaaa_push, &dns_aaaa_cmp, &dns_aaaa_print, 0 }, - { DNS_T_MX, "MX", &dns_mx_parse, &dns_mx_push, &dns_mx_cmp, &dns_mx_print, &dns_mx_cname }, - { DNS_T_NS, "NS", &dns_ns_parse, &dns_ns_push, &dns_ns_cmp, &dns_ns_print, &dns_ns_cname }, - { DNS_T_CNAME, "CNAME", &dns_cname_parse, &dns_cname_push, &dns_cname_cmp, &dns_cname_print, &dns_cname_cname }, - { DNS_T_SOA, "SOA", &dns_soa_parse, &dns_soa_push, &dns_soa_cmp, &dns_soa_print, 0 }, - { DNS_T_SRV, "SRV", &dns_srv_parse, &dns_srv_push, &dns_srv_cmp, &dns_srv_print, &dns_srv_cname }, - { DNS_T_OPT, "OPT", &dns_opt_parse, &dns_opt_push, &dns_opt_cmp, &dns_opt_print, 0 }, - { DNS_T_PTR, "PTR", &dns_ptr_parse, &dns_ptr_push, &dns_ptr_cmp, &dns_ptr_print, &dns_ptr_cname }, - { DNS_T_TXT, "TXT", &dns_txt_parse, &dns_txt_push, &dns_txt_cmp, &dns_txt_print, 0 }, - { DNS_T_SPF, "SPF", &dns_txt_parse, &dns_txt_push, &dns_txt_cmp, &dns_txt_print, 0 }, - { DNS_T_SSHFP, "SSHFP", &dns_sshfp_parse, &dns_sshfp_push, &dns_sshfp_cmp, &dns_sshfp_print, 0 }, -}; /* dns_rrtypes[] */ - - -union dns_any *dns_any_init(union dns_any *any, size_t size) { - return (union dns_any *)dns_txt_init(&any->rdata, size); -} /* dns_any_init() */ - - -int dns_any_parse(union dns_any *any, struct dns_rr *rr, struct dns_packet *P) { - unsigned i; - - for (i = 0; i < lengthof(dns_rrtypes); i++) { - if (dns_rrtypes[i].type == rr->type) - return dns_rrtypes[i].parse(any, rr, P); - } - - if (rr->rd.len > any->rdata.size) - return DNS_EILLEGAL; - - memcpy(any->rdata.data, &P->data[rr->rd.p], rr->rd.len); - any->rdata.len = rr->rd.len; - - return 0; -} /* dns_any_parse() */ - - -int dns_any_push(struct dns_packet *P, union dns_any *any, enum dns_type type) { - unsigned i; - - for (i = 0; i < lengthof(dns_rrtypes); i++) { - if (dns_rrtypes[i].type == type) - return dns_rrtypes[i].push(P, any); - } - - if (P->size - P->end < any->rdata.len + 2) - return DNS_ENOBUFS; - - P->data[P->end++] = 0xff & (any->rdata.len >> 8); - P->data[P->end++] = 0xff & (any->rdata.len >> 0); - - memcpy(&P->data[P->end], any->rdata.data, any->rdata.len); - P->end += any->rdata.len; - - return 0; -} /* dns_any_push() */ - - -int dns_any_cmp(const union dns_any *a, enum dns_type x, const union dns_any *b, enum dns_type y) { - unsigned i; - int cmp; - - if ((cmp = x - y)) - return cmp; - - for (i = 0; i < lengthof(dns_rrtypes); i++) { - if (dns_rrtypes[i].type == x) - return dns_rrtypes[i].cmp(a, b); - } - - return -1; -} /* dns_any_cmp() */ - - -size_t dns_any_print(void *dst_, size_t lim, union dns_any *any, enum dns_type type) { - struct { unsigned char *b; size_t p, end; } dst, src; - unsigned i, ch; - - for (i = 0; i < lengthof(dns_rrtypes); i++) { - if (dns_rrtypes[i].type == type) - return dns_rrtypes[i].print(dst_, lim, any); - } - - dst.b = dst_; - dst.end = lim; - dst.p = 0; - - src.b = any->rdata.data; - src.end = any->rdata.len; - src.p = 0; - - dst.p += dns__printchar(dst.b, dst.end, dst.p, '"'); - - while (src.p < src.end) { - ch = src.b[src.p++]; - - dst.p += dns__printchar(dst.b, dst.end, dst.p, '\\'); - dst.p += dns__print10(dst.b, dst.end, dst.p, ch, 3); - } - - dst.p += dns__printchar(dst.b, dst.end, dst.p, '"'); - - dns__printnul(dst.b, dst.end, dst.p); - - return dst.p; -} /* dns_any_print() */ - - -size_t dns_any_cname(void *dst, size_t lim, union dns_any *any, enum dns_type type) { - unsigned i; - - for (i = 0; i < lengthof(dns_rrtypes); i++) { - if (dns_rrtypes[i].type == type) - return (dns_rrtypes[i].cname)? dns_rrtypes[i].cname(dst, lim, any) : 0; - } - - return 0; -} /* dns_any_cname() */ - - -/* - * H O S T S R O U T I N E S - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -struct dns_hosts { - struct dns_hosts_entry { - char host[DNS_D_MAXNAME + 1]; - char arpa[73 + 1]; - - int af; - - union { - struct in_addr a4; - struct in6_addr a6; - } addr; - - _Bool alias; - - struct dns_hosts_entry *next; - } *head, **tail; - - dns_atomic_t refcount; -}; /* struct dns_hosts */ - - -struct dns_hosts *dns_hosts_open(int *error) { - static const struct dns_hosts hosts_initializer = { .refcount = 1 }; - struct dns_hosts *hosts; - - if (!(hosts = malloc(sizeof *hosts))) - goto syerr; - - *hosts = hosts_initializer; - - hosts->tail = &hosts->head; - - return hosts; -syerr: - *error = dns_syerr(); - - free(hosts); - - return 0; -} /* dns_hosts_open() */ - - -void dns_hosts_close(struct dns_hosts *hosts) { - struct dns_hosts_entry *ent, *xnt; - - if (!hosts || 1 != dns_hosts_release(hosts)) - return; - - for (ent = hosts->head; ent; ent = xnt) { - xnt = ent->next; - - free(ent); - } - - free(hosts); - - return; -} /* dns_hosts_close() */ - - -dns_refcount_t dns_hosts_acquire(struct dns_hosts *hosts) { - return dns_atomic_fetch_add(&hosts->refcount); -} /* dns_hosts_acquire() */ - - -dns_refcount_t dns_hosts_release(struct dns_hosts *hosts) { - return dns_atomic_fetch_sub(&hosts->refcount); -} /* dns_hosts_release() */ - - -struct dns_hosts *dns_hosts_mortal(struct dns_hosts *hosts) { - if (hosts) - dns_hosts_release(hosts); - - return hosts; -} /* dns_hosts_mortal() */ - - -struct dns_hosts *dns_hosts_local(int *error_) { - struct dns_hosts *hosts; - int error; - - if (!(hosts = dns_hosts_open(&error))) - goto error; - - if ((error = dns_hosts_loadpath(hosts, "/etc/hosts"))) - goto error; - - return hosts; -error: - *error_ = error; - - dns_hosts_close(hosts); - - return 0; -} /* dns_hosts_local() */ - - -#define dns_hosts_issep(ch) (isspace(ch)) -#define dns_hosts_iscom(ch) ((ch) == '#' || (ch) == ';') - -int dns_hosts_loadfile(struct dns_hosts *hosts, FILE *fp) { - struct dns_hosts_entry ent; - char word[DNS_PP_MAX(INET6_ADDRSTRLEN, DNS_D_MAXNAME) + 1]; - unsigned wp, wc, skip; - int ch, error; - - rewind(fp); - - do { - memset(&ent, '\0', sizeof ent); - wc = 0; - skip = 0; - - do { - memset(word, '\0', sizeof word); - wp = 0; - - while (EOF != (ch = fgetc(fp)) && ch != '\n') { - skip |= !!dns_hosts_iscom(ch); - - if (skip) - continue; - - if (dns_hosts_issep(ch)) - break; - - if (wp < sizeof word - 1) - word[wp] = ch; - wp++; - } - - if (!wp) - continue; - - wc++; - - switch (wc) { - case 0: - break; - case 1: - ent.af = (strchr(word, ':'))? AF_INET6 : AF_INET; - skip = (1 != dns_inet_pton(ent.af, word, &ent.addr)); - - break; - default: - if (!wp) - break; - - dns_d_anchor(ent.host, sizeof ent.host, word, wp); - - if ((error = dns_hosts_insert(hosts, ent.af, &ent.addr, ent.host, (wc > 2)))) - return error; - - break; - } /* switch() */ - } while (ch != EOF && ch != '\n'); - } while (ch != EOF); - - return 0; -} /* dns_hosts_loadfile() */ - - -int dns_hosts_loadpath(struct dns_hosts *hosts, const char *path) { - FILE *fp; - int error; - - if (!(fp = fopen(path, "r"))) - return dns_syerr(); - - error = dns_hosts_loadfile(hosts, fp); - - fclose(fp); - - return error; -} /* dns_hosts_loadpath() */ - - -int dns_hosts_dump(struct dns_hosts *hosts, FILE *fp) { - struct dns_hosts_entry *ent, *xnt; - char addr[INET6_ADDRSTRLEN + 1]; - unsigned i; - - for (ent = hosts->head; ent; ent = xnt) { - xnt = ent->next; - - dns_inet_ntop(ent->af, &ent->addr, addr, sizeof addr); - - fputs(addr, fp); - - for (i = strlen(addr); i < INET_ADDRSTRLEN; i++) - fputc(' ', fp); - - fputc(' ', fp); - - fputs(ent->host, fp); - fputc('\n', fp); - } - - return 0; -} /* dns_hosts_dump() */ - - -int dns_hosts_insert(struct dns_hosts *hosts, int af, const void *addr, const void *host, _Bool alias) { - struct dns_hosts_entry *ent; - int error; - - if (!(ent = malloc(sizeof *ent))) - goto syerr; - - dns_d_anchor(ent->host, sizeof ent->host, host, strlen(host)); - - switch ((ent->af = af)) { - case AF_INET6: - memcpy(&ent->addr.a6, addr, sizeof ent->addr.a6); - - dns_aaaa_arpa(ent->arpa, sizeof ent->arpa, addr); - - break; - case AF_INET: - memcpy(&ent->addr.a4, addr, sizeof ent->addr.a4); - - dns_a_arpa(ent->arpa, sizeof ent->arpa, addr); - - break; - default: - error = EINVAL; - - goto error; - } /* switch() */ - - ent->alias = alias; - - ent->next = 0; - *hosts->tail = ent; - hosts->tail = &ent->next; - - return 0; -syerr: - error = dns_syerr(); -error: - free(ent); - - return error; -} /* dns_hosts_insert() */ - - -struct dns_packet *dns_hosts_query(struct dns_hosts *hosts, struct dns_packet *Q, int *error_) { - struct dns_packet *P = dns_p_new(512); - struct dns_packet *A = 0; - struct dns_rr rr; - struct dns_hosts_entry *ent; - int error, af; - char qname[DNS_D_MAXNAME + 1]; - size_t qlen; - - if ((error = dns_rr_parse(&rr, 12, Q))) - goto error; - - if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, Q, &error))) - goto error; - else if (qlen >= sizeof qname) - goto toolong; - - if ((error = dns_p_push(P, DNS_S_QD, qname, qlen, rr.type, rr.class, 0, 0))) - goto error; - - switch (rr.type) { - case DNS_T_PTR: - for (ent = hosts->head; ent; ent = ent->next) { - if (ent->alias || 0 != strcasecmp(qname, ent->arpa)) - continue; - - if ((error = dns_p_push(P, DNS_S_AN, qname, qlen, rr.type, rr.class, 0, ent->host))) - goto error; - } - - break; - case DNS_T_AAAA: - af = AF_INET6; - - goto loop; - case DNS_T_A: - af = AF_INET; - -loop: for (ent = hosts->head; ent; ent = ent->next) { - if (ent->af != af || 0 != strcasecmp(qname, ent->host)) - continue; - - if ((error = dns_p_push(P, DNS_S_AN, qname, qlen, rr.type, rr.class, 0, &ent->addr))) - goto error; - } - - break; - default: - break; - } /* switch() */ - - - if (!(A = dns_p_copy(dns_p_make(P->end, &error), P))) - goto error; - - return A; -toolong: - error = DNS_EILLEGAL; -error: - *error_ = error; - - dns_p_free(A); - - return 0; -} /* dns_hosts_query() */ - - -/* - * R E S O L V . C O N F R O U T I N E S - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -struct dns_resolv_conf *dns_resconf_open(int *error) { - static const struct dns_resolv_conf resconf_initializer - = { .lookup = "bf", .options = { .ndots = 1, .timeout = 5, .attempts = 2, .tcp = DNS_RESCONF_TCP_ENABLE, }, - .iface = { .ss_family = AF_INET }, }; - struct dns_resolv_conf *resconf; - struct sockaddr_in *sin; - - if (!(resconf = malloc(sizeof *resconf))) - goto syerr; - - *resconf = resconf_initializer; - - sin = (struct sockaddr_in *)&resconf->nameserver[0]; - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = INADDR_ANY; - sin->sin_port = htons(53); -#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - sin->sin_len = dns_af_len(sin->sin_family); -#endif - - if (0 != gethostname(resconf->search[0], sizeof resconf->search[0])) - goto syerr; - - dns_d_anchor(resconf->search[0], sizeof resconf->search[0], resconf->search[0], strlen(resconf->search[0])); - dns_d_cleave(resconf->search[0], sizeof resconf->search[0], resconf->search[0], strlen(resconf->search[0])); - - /* - * XXX: If gethostname() returned a string without any label - * separator, then search[0][0] should be NUL. - */ - - dns_resconf_acquire(resconf); - - return resconf; -syerr: - *error = dns_syerr(); - - free(resconf); - - return 0; -} /* dns_resconf_open() */ - - -void dns_resconf_close(struct dns_resolv_conf *resconf) { - if (!resconf || 1 != dns_resconf_release(resconf)) - return /* void */; - - free(resconf); -} /* dns_resconf_close() */ - - -dns_refcount_t dns_resconf_acquire(struct dns_resolv_conf *resconf) { - return dns_atomic_fetch_add(&resconf->_.refcount); -} /* dns_resconf_acquire() */ - - -dns_refcount_t dns_resconf_release(struct dns_resolv_conf *resconf) { - return dns_atomic_fetch_sub(&resconf->_.refcount); -} /* dns_resconf_release() */ - - -struct dns_resolv_conf *dns_resconf_mortal(struct dns_resolv_conf *resconf) { - if (resconf) - dns_resconf_release(resconf); - - return resconf; -} /* dns_resconf_mortal() */ - - -struct dns_resolv_conf *dns_resconf_local(int *error_) { - struct dns_resolv_conf *resconf; - int error; - - if (!(resconf = dns_resconf_open(&error))) - goto error; - - if ((error = dns_resconf_loadpath(resconf, "/etc/resolv.conf"))) - goto error; - - if ((error = dns_nssconf_loadpath(resconf, "/etc/nsswitch.conf"))) { - if (error != ENOENT) - goto error; - } - - return resconf; -error: - *error_ = error; - - dns_resconf_close(resconf); - - return 0; -} /* dns_resconf_local() */ - - -struct dns_resolv_conf *dns_resconf_root(int *error) { - struct dns_resolv_conf *resconf; - - if ((resconf = dns_resconf_local(error))) - resconf->options.recurse = 1; - - return resconf; -} /* dns_resconf_root() */ - - -static time_t dns_resconf_timeout(const struct dns_resolv_conf *resconf) { - return (time_t)DNS_PP_MIN(INT_MAX, resconf->options.timeout); -} /* dns_resconf_timeout() */ - - -enum dns_resconf_keyword { - DNS_RESCONF_NAMESERVER, - DNS_RESCONF_DOMAIN, - DNS_RESCONF_SEARCH, - DNS_RESCONF_LOOKUP, - DNS_RESCONF_FILE, - DNS_RESCONF_BIND, - DNS_RESCONF_CACHE, - DNS_RESCONF_OPTIONS, - DNS_RESCONF_EDNS0, - DNS_RESCONF_NDOTS, - DNS_RESCONF_TIMEOUT, - DNS_RESCONF_ATTEMPTS, - DNS_RESCONF_ROTATE, - DNS_RESCONF_RECURSE, - DNS_RESCONF_SMART, - DNS_RESCONF_TCP, - DNS_RESCONF_TCPx, - DNS_RESCONF_INTERFACE, - DNS_RESCONF_ZERO, - DNS_RESCONF_ONE, - DNS_RESCONF_ENABLE, - DNS_RESCONF_ONLY, - DNS_RESCONF_DISABLE, -}; /* enum dns_resconf_keyword */ - -static enum dns_resconf_keyword dns_resconf_keyword(const char *word) { - static const char *words[] = { - [DNS_RESCONF_NAMESERVER] = "nameserver", - [DNS_RESCONF_DOMAIN] = "domain", - [DNS_RESCONF_SEARCH] = "search", - [DNS_RESCONF_LOOKUP] = "lookup", - [DNS_RESCONF_FILE] = "file", - [DNS_RESCONF_BIND] = "bind", - [DNS_RESCONF_CACHE] = "cache", - [DNS_RESCONF_OPTIONS] = "options", - [DNS_RESCONF_EDNS0] = "edns0", - [DNS_RESCONF_ROTATE] = "rotate", - [DNS_RESCONF_RECURSE] = "recurse", - [DNS_RESCONF_SMART] = "smart", - [DNS_RESCONF_TCP] = "tcp", - [DNS_RESCONF_INTERFACE] = "interface", - [DNS_RESCONF_ZERO] = "0", - [DNS_RESCONF_ONE] = "1", - [DNS_RESCONF_ENABLE] = "enable", - [DNS_RESCONF_ONLY] = "only", - [DNS_RESCONF_DISABLE] = "disable", - }; - unsigned i; - - for (i = 0; i < lengthof(words); i++) { - if (words[i] && 0 == strcasecmp(words[i], word)) - return i; - } - - if (0 == strncasecmp(word, "ndots:", sizeof "ndots:" - 1)) - return DNS_RESCONF_NDOTS; - - if (0 == strncasecmp(word, "timeout:", sizeof "timeout:" - 1)) - return DNS_RESCONF_TIMEOUT; - - if (0 == strncasecmp(word, "attempts:", sizeof "attempts:" - 1)) - return DNS_RESCONF_ATTEMPTS; - - if (0 == strncasecmp(word, "tcp:", sizeof "tcp:" - 1)) - return DNS_RESCONF_TCPx; - - return -1; -} /* dns_resconf_keyword() */ - - -/** OpenBSD-style "[1.2.3.4]:53" nameserver syntax */ -int dns_resconf_pton(struct sockaddr_storage *ss, const char *src) { - struct { char buf[128], *p; } addr = { "", addr.buf }; - unsigned short port = 0; - int ch, af = AF_INET, error; - - while ((ch = *src++)) { - switch (ch) { - case ' ': - /* FALL THROUGH */ - case '\t': - break; - case '[': - break; - case ']': - while ((ch = *src++)) { - if (isdigit((unsigned char)ch)) { - port *= 10; - port += ch - '0'; - } - } - - goto inet; - case ':': - af = AF_INET6; - - /* FALL THROUGH */ - default: - if (addr.p < endof(addr.buf) - 1) - *addr.p++ = ch; - - break; - } /* switch() */ - } /* while() */ -inet: - - if ((error = dns_pton(af, addr.buf, dns_sa_addr(af, ss, NULL)))) - return error; - - port = (!port)? 53 : port; - *dns_sa_port(af, ss) = htons(port); - dns_sa_family(ss) = af; - - return 0; -} /* dns_resconf_pton() */ - -#define dns_resconf_issep(ch) (isspace(ch) || (ch) == ',') -#define dns_resconf_iscom(ch) ((ch) == '#' || (ch) == ';') - -int dns_resconf_loadfile(struct dns_resolv_conf *resconf, FILE *fp) { - unsigned sa_count = 0; - char words[6][DNS_D_MAXNAME + 1]; - unsigned wp, wc, i, j, n; - int ch, error; - - rewind(fp); - - do { - memset(words, '\0', sizeof words); - wp = 0; - wc = 0; - - while (EOF != (ch = getc(fp)) && ch != '\n') { - if (dns_resconf_issep(ch)) { - if (wp > 0) { - wp = 0; - - if (++wc >= lengthof(words)) - goto skip; - } - } else if (dns_resconf_iscom(ch)) { -skip: - do { - ch = getc(fp); - } while (ch != EOF && ch != '\n'); - - break; - } else { - dns__printchar(words[wc], sizeof words[wc], wp, ch); - wp++; - } - } - - if (wp > 0) - wc++; - - if (wc < 2) - continue; - - switch (dns_resconf_keyword(words[0])) { - case DNS_RESCONF_NAMESERVER: - if (sa_count >= lengthof(resconf->nameserver)) - continue; - - if ((error = dns_resconf_pton(&resconf->nameserver[sa_count], words[1]))) - continue; - - sa_count++; - - break; - case DNS_RESCONF_DOMAIN: - case DNS_RESCONF_SEARCH: - memset(resconf->search, '\0', sizeof resconf->search); - - for (i = 1, j = 0; i < wc && j < lengthof(resconf->search); i++, j++) - dns_d_anchor(resconf->search[j], sizeof resconf->search[j], words[i], strlen(words[i])); - - break; - case DNS_RESCONF_LOOKUP: - for (i = 1, j = 0; i < wc && j < lengthof(resconf->lookup); i++) { - switch (dns_resconf_keyword(words[i])) { - case DNS_RESCONF_FILE: - resconf->lookup[j++] = 'f'; - - break; - case DNS_RESCONF_BIND: - resconf->lookup[j++] = 'b'; - - break; - case DNS_RESCONF_CACHE: - resconf->lookup[j++] = 'c'; - - break; - default: - break; - } /* switch() */ - } /* for() */ - - break; - case DNS_RESCONF_OPTIONS: - for (i = 1; i < wc; i++) { - switch (dns_resconf_keyword(words[i])) { - case DNS_RESCONF_EDNS0: - resconf->options.edns0 = 1; - - break; - case DNS_RESCONF_NDOTS: - for (j = sizeof "ndots:" - 1, n = 0; isdigit((int)words[i][j]); j++) { - n *= 10; - n += words[i][j] - '0'; - } /* for() */ - - resconf->options.ndots = n; - - break; - case DNS_RESCONF_TIMEOUT: - for (j = sizeof "timeout:" - 1, n = 0; isdigit((int)words[i][j]); j++) { - n *= 10; - n += words[i][j] - '0'; - } /* for() */ - - resconf->options.timeout = n; - - break; - case DNS_RESCONF_ATTEMPTS: - for (j = sizeof "attempts:" - 1, n = 0; isdigit((int)words[i][j]); j++) { - n *= 10; - n += words[i][j] - '0'; - } /* for() */ - - resconf->options.attempts = n; - - break; - case DNS_RESCONF_ROTATE: - resconf->options.rotate = 1; - - break; - case DNS_RESCONF_RECURSE: - resconf->options.recurse = 1; - - break; - case DNS_RESCONF_SMART: - resconf->options.smart = 1; - - break; - case DNS_RESCONF_TCP: - resconf->options.tcp = DNS_RESCONF_TCP_ONLY; - - break; - case DNS_RESCONF_TCPx: - switch (dns_resconf_keyword(&words[i][sizeof "tcp:" - 1])) { - case DNS_RESCONF_ENABLE: - resconf->options.tcp = DNS_RESCONF_TCP_ENABLE; - - break; - case DNS_RESCONF_ONE: - case DNS_RESCONF_ONLY: - resconf->options.tcp = DNS_RESCONF_TCP_ONLY; - - break; - case DNS_RESCONF_ZERO: - case DNS_RESCONF_DISABLE: - resconf->options.tcp = DNS_RESCONF_TCP_DISABLE; - - break; - default: - break; - } /* switch() */ - - break; - default: - break; - } /* switch() */ - } /* for() */ - - break; - case DNS_RESCONF_INTERFACE: - for (i = 0, n = 0; isdigit((int)words[2][i]); i++) { - n *= 10; - n += words[2][i] - '0'; - } - - dns_resconf_setiface(resconf, words[1], n); - - break; - default: - break; - } /* switch() */ - } while (ch != EOF); - - return 0; -} /* dns_resconf_loadfile() */ - - -int dns_resconf_loadpath(struct dns_resolv_conf *resconf, const char *path) { - FILE *fp; - int error; - - if (!(fp = fopen(path, "r"))) - return dns_syerr(); - - error = dns_resconf_loadfile(resconf, fp); - - fclose(fp); - - return error; -} /* dns_resconf_loadpath() */ - - -struct dns_anyconf { - char *token[16]; - unsigned count; - char buffer[1024], *tp, *cp; -}; /* struct dns_anyconf */ - - -static void dns_anyconf_reset(struct dns_anyconf *cf) { - cf->count = 0; - cf->tp = cf->cp = cf->buffer; -} /* dns_anyconf_reset() */ - - -static int dns_anyconf_push(struct dns_anyconf *cf) { - if (!(cf->cp < endof(cf->buffer) && cf->count < lengthof(cf->token))) - return ENOMEM; - - *cf->cp++ = '\0'; - cf->token[cf->count++] = cf->tp; - cf->tp = cf->cp; - - return 0; -} /* dns_anyconf_push() */ - - -static void dns_anyconf_pop(struct dns_anyconf *cf) { - if (cf->count > 0) { - --cf->count; - cf->tp = cf->cp = cf->token[cf->count]; - cf->token[cf->count] = 0; - } -} /* dns_anyconf_pop() */ - - -static int dns_anyconf_addc(struct dns_anyconf *cf, int ch) { - if (!(cf->cp < endof(cf->buffer))) - return ENOMEM; - - *cf->cp++ = ch; - - return 0; -} /* dns_anyconf_addc() */ - - -static _Bool dns_anyconf_match(const char *pat, int mc) { - _Bool match; - int pc; - - if (*pat == '^') { - match = 0; - ++pat; - } else { - match = 1; - } - - while ((pc = *(const unsigned char *)pat++)) { - switch (pc) { - case '%': - if (!(pc = *(const unsigned char *)pat++)) - return !match; - - switch (pc) { - case 'a': - if (isalpha(mc)) - return match; - break; - case 'd': - if (isdigit(mc)) - return match; - break; - case 'w': - if (isalnum(mc)) - return match; - break; - case 's': - if (isspace(mc)) - return match; - break; - default: - if (mc == pc) - return match; - break; - } /* switch() */ - - break; - default: - if (mc == pc) - return match; - break; - } /* switch() */ - } /* while() */ - - return !match; -} /* dns_anyconf_match() */ - - -static int dns_anyconf_peek(FILE *fp) { - int ch; - ch = getc(fp); - ungetc(ch, fp); - return ch; -} /* dns_anyconf_peek() */ - - -static size_t dns_anyconf_skip(const char *pat, FILE *fp) { - size_t count = 0; - int ch; - - while (EOF != (ch = getc(fp))) { - if (dns_anyconf_match(pat, ch)) { - count++; - continue; - } - - ungetc(ch, fp); - - break; - } - - return count; -} /* dns_anyconf_skip() */ - - -static size_t dns_anyconf_scan(struct dns_anyconf *cf, const char *pat, FILE *fp, int *error) { - size_t len; - int ch; - - while (EOF != (ch = getc(fp))) { - if (dns_anyconf_match(pat, ch)) { - if ((*error = dns_anyconf_addc(cf, ch))) - return 0; - - continue; - } else { - ungetc(ch, fp); - - break; - } - } - - if ((len = cf->cp - cf->tp)) { - if ((*error = dns_anyconf_push(cf))) - return 0; - - return len; - } else { - *error = 0; - - return 0; - } -} /* dns_anyconf_scan() */ - - -DNS_NOTUSED static void dns_anyconf_dump(struct dns_anyconf *cf, FILE *fp) { - unsigned i; - - fprintf(fp, "tokens:"); - - for (i = 0; i < cf->count; i++) { - fprintf(fp, " %s", cf->token[i]); - } - - fputc('\n', fp); -} /* dns_anyconf_dump() */ - - -enum dns_nssconf_keyword { - DNS_NSSCONF_INVALID = 0, - DNS_NSSCONF_HOSTS = 1, - DNS_NSSCONF_SUCCESS, - DNS_NSSCONF_NOTFOUND, - DNS_NSSCONF_UNAVAIL, - DNS_NSSCONF_TRYAGAIN, - DNS_NSSCONF_CONTINUE, - DNS_NSSCONF_RETURN, - DNS_NSSCONF_FILES, - DNS_NSSCONF_DNS, - DNS_NSSCONF_MDNS, - - DNS_NSSCONF_LAST, -}; /* enum dns_nssconf_keyword */ - -static enum dns_nssconf_keyword dns_nssconf_keyword(const char *word) { - static const char *list[] = { - [DNS_NSSCONF_HOSTS] = "hosts", - [DNS_NSSCONF_SUCCESS] = "success", - [DNS_NSSCONF_NOTFOUND] = "notfound", - [DNS_NSSCONF_UNAVAIL] = "unavail", - [DNS_NSSCONF_TRYAGAIN] = "tryagain", - [DNS_NSSCONF_CONTINUE] = "continue", - [DNS_NSSCONF_RETURN] = "return", - [DNS_NSSCONF_FILES] = "files", - [DNS_NSSCONF_DNS] = "dns", - [DNS_NSSCONF_MDNS] = "mdns", - }; - unsigned i; - - for (i = 1; i < lengthof(list); i++) { - if (list[i] && 0 == strcasecmp(list[i], word)) - return i; - } - - return DNS_NSSCONF_INVALID; -} /* dns_nssconf_keyword() */ - - -static enum dns_nssconf_keyword dns_nssconf_c2k(int ch) { - static const char map[] = { - ['S'] = DNS_NSSCONF_SUCCESS, - ['N'] = DNS_NSSCONF_NOTFOUND, - ['U'] = DNS_NSSCONF_UNAVAIL, - ['T'] = DNS_NSSCONF_TRYAGAIN, - ['C'] = DNS_NSSCONF_CONTINUE, - ['R'] = DNS_NSSCONF_RETURN, - ['f'] = DNS_NSSCONF_FILES, - ['F'] = DNS_NSSCONF_FILES, - ['d'] = DNS_NSSCONF_DNS, - ['D'] = DNS_NSSCONF_DNS, - ['b'] = DNS_NSSCONF_DNS, - ['B'] = DNS_NSSCONF_DNS, - ['m'] = DNS_NSSCONF_MDNS, - ['M'] = DNS_NSSCONF_MDNS, - }; - - return (ch >= 0 && ch < (int)lengthof(map))? map[ch] : DNS_NSSCONF_INVALID; -} /* dns_nssconf_c2k() */ - - -DNS_PRAGMA_PUSH -DNS_PRAGMA_QUIET - -static int dns_nssconf_k2c(int k) { - static const char map[DNS_NSSCONF_LAST] = { - [DNS_NSSCONF_SUCCESS] = 'S', - [DNS_NSSCONF_NOTFOUND] = 'N', - [DNS_NSSCONF_UNAVAIL] = 'U', - [DNS_NSSCONF_TRYAGAIN] = 'T', - [DNS_NSSCONF_CONTINUE] = 'C', - [DNS_NSSCONF_RETURN] = 'R', - [DNS_NSSCONF_FILES] = 'f', - [DNS_NSSCONF_DNS] = 'b', - [DNS_NSSCONF_MDNS] = 'm', - }; - - return (k >= 0 && k < (int)lengthof(map))? (map[k]? map[k] : '?') : '?'; -} /* dns_nssconf_k2c() */ - -static const char *dns_nssconf_k2s(int k) { - static const char *const map[DNS_NSSCONF_LAST] = { - [DNS_NSSCONF_SUCCESS] = "SUCCESS", - [DNS_NSSCONF_NOTFOUND] = "NOTFOUND", - [DNS_NSSCONF_UNAVAIL] = "UNAVAIL", - [DNS_NSSCONF_TRYAGAIN] = "TRYAGAIN", - [DNS_NSSCONF_CONTINUE] = "continue", - [DNS_NSSCONF_RETURN] = "return", - [DNS_NSSCONF_FILES] = "files", - [DNS_NSSCONF_DNS] = "dns", - [DNS_NSSCONF_MDNS] = "mdns", - }; - - return (k >= 0 && k < (int)lengthof(map))? (map[k]? map[k] : "") : ""; -} /* dns_nssconf_k2s() */ - -DNS_PRAGMA_POP - - -int dns_nssconf_loadfile(struct dns_resolv_conf *resconf, FILE *fp) { - enum dns_nssconf_keyword source, status, action; - char lookup[sizeof resconf->lookup] = "", *lp; - struct dns_anyconf cf; - size_t i; - int error; - - while (!feof(fp) && !ferror(fp)) { - dns_anyconf_reset(&cf); - - dns_anyconf_skip("%s", fp); - - if (!dns_anyconf_scan(&cf, "%w_", fp, &error)) - goto nextent; - - if (DNS_NSSCONF_HOSTS != dns_nssconf_keyword(cf.token[0])) - goto nextent; - - dns_anyconf_pop(&cf); - - if (!dns_anyconf_skip(": \t", fp)) - goto nextent; - - *(lp = lookup) = '\0'; - - while (dns_anyconf_scan(&cf, "%w_", fp, &error)) { - dns_anyconf_skip(" \t", fp); - - if ('[' == dns_anyconf_peek(fp)) { - dns_anyconf_skip("[ \t", fp); - - while (dns_anyconf_scan(&cf, "%w_", fp, &error)) { - dns_anyconf_skip("= \t", fp); - if (!dns_anyconf_scan(&cf, "%w_", fp, &error)) { - dns_anyconf_pop(&cf); /* discard status */ - dns_anyconf_skip("^#;]\n", fp); /* skip to end of criteria */ - break; - } - dns_anyconf_skip(" \t", fp); - } - - dns_anyconf_skip("] \t", fp); - } - - if ((size_t)(endof(lookup) - lp) < cf.count + 1) /* +1 for '\0' */ - goto nextsrc; - - source = dns_nssconf_keyword(cf.token[0]); - - switch (source) { - case DNS_NSSCONF_DNS: - case DNS_NSSCONF_MDNS: - case DNS_NSSCONF_FILES: - *lp++ = dns_nssconf_k2c(source); - break; - default: - goto nextsrc; - } - - for (i = 1; i + 1 < cf.count; i += 2) { - status = dns_nssconf_keyword(cf.token[i]); - action = dns_nssconf_keyword(cf.token[i + 1]); - - switch (status) { - case DNS_NSSCONF_SUCCESS: - case DNS_NSSCONF_NOTFOUND: - case DNS_NSSCONF_UNAVAIL: - case DNS_NSSCONF_TRYAGAIN: - *lp++ = dns_nssconf_k2c(status); - break; - default: - continue; - } - - switch (action) { - case DNS_NSSCONF_CONTINUE: - case DNS_NSSCONF_RETURN: - break; - default: - action = (status == DNS_NSSCONF_SUCCESS) - ? DNS_NSSCONF_RETURN - : DNS_NSSCONF_CONTINUE; - break; - } - - *lp++ = dns_nssconf_k2c(action); - } -nextsrc: - *lp = '\0'; - dns_anyconf_reset(&cf); - } -nextent: - dns_anyconf_skip("^\n", fp); - } - - if (*lookup) - strncpy(resconf->lookup, lookup, sizeof resconf->lookup); - - return 0; -} /* dns_nssconf_loadfile() */ - - -int dns_nssconf_loadpath(struct dns_resolv_conf *resconf, const char *path) { - FILE *fp; - int error; - - if (!(fp = fopen(path, "r"))) - return dns_syerr(); - - error = dns_nssconf_loadfile(resconf, fp); - - fclose(fp); - - return error; -} /* dns_nssconf_loadpath() */ - - -struct dns_nssconf_source { - enum dns_nssconf_keyword source, success, notfound, unavail, tryagain; -}; /* struct dns_nssconf_source */ - -typedef unsigned dns_nssconf_i; - -static inline int dns_nssconf_peek(const struct dns_resolv_conf *resconf, dns_nssconf_i state) { - return (state < lengthof(resconf->lookup) && resconf->lookup[state])? resconf->lookup[state] : 0; -} /* dns_nssconf_peek() */ - -static _Bool dns_nssconf_next(struct dns_nssconf_source *src, const struct dns_resolv_conf *resconf, dns_nssconf_i *state) { - int source, status, action; - - src->source = DNS_NSSCONF_INVALID; - src->success = DNS_NSSCONF_RETURN; - src->notfound = DNS_NSSCONF_CONTINUE; - src->unavail = DNS_NSSCONF_CONTINUE; - src->tryagain = DNS_NSSCONF_CONTINUE; - - while ((source = dns_nssconf_peek(resconf, *state))) { - source = dns_nssconf_c2k(source); - ++*state; - - switch (source) { - case DNS_NSSCONF_FILES: - case DNS_NSSCONF_DNS: - case DNS_NSSCONF_MDNS: - src->source = source; - break; - default: - continue; - } - - while ((status = dns_nssconf_peek(resconf, *state)) && (action = dns_nssconf_peek(resconf, *state + 1))) { - status = dns_nssconf_c2k(status); - action = dns_nssconf_c2k(action); - - switch (action) { - case DNS_NSSCONF_RETURN: - case DNS_NSSCONF_CONTINUE: - break; - default: - goto done; - } - - switch (status) { - case DNS_NSSCONF_SUCCESS: - src->success = action; - break; - case DNS_NSSCONF_NOTFOUND: - src->notfound = action; - break; - case DNS_NSSCONF_UNAVAIL: - src->unavail = action; - break; - case DNS_NSSCONF_TRYAGAIN: - src->tryagain = action; - break; - default: - goto done; - } - - *state += 2; - } - - break; - } -done: - return src->source != DNS_NSSCONF_INVALID; -} /* dns_nssconf_next() */ - - -static int dns_nssconf_dump_status(int status, int action, unsigned *count, FILE *fp) { - switch (status) { - case DNS_NSSCONF_SUCCESS: - if (action == DNS_NSSCONF_RETURN) - return 0; - break; - default: - if (action == DNS_NSSCONF_CONTINUE) - return 0; - break; - } - - fputc(' ', fp); - - if (!*count) - fputc('[', fp); - - fprintf(fp, "%s=%s", dns_nssconf_k2s(status), dns_nssconf_k2s(action)); - - ++*count; - - return 0; -} /* dns_nssconf_dump_status() */ - - -int dns_nssconf_dump(struct dns_resolv_conf *resconf, FILE *fp) { - struct dns_nssconf_source src; - dns_nssconf_i i = 0; - - fputs("hosts:", fp); - - while (dns_nssconf_next(&src, resconf, &i)) { - unsigned n = 0; - - fprintf(fp, " %s", dns_nssconf_k2s(src.source)); - - dns_nssconf_dump_status(DNS_NSSCONF_SUCCESS, src.success, &n, fp); - dns_nssconf_dump_status(DNS_NSSCONF_NOTFOUND, src.notfound, &n, fp); - dns_nssconf_dump_status(DNS_NSSCONF_UNAVAIL, src.unavail, &n, fp); - dns_nssconf_dump_status(DNS_NSSCONF_TRYAGAIN, src.tryagain, &n, fp); - - if (n) - fputc(']', fp); - } - - fputc('\n', fp); - - return 0; -} /* dns_nssconf_dump() */ - - -int dns_resconf_setiface(struct dns_resolv_conf *resconf, const char *addr, unsigned short port) { - int af = (strchr(addr, ':'))? AF_INET6 : AF_INET; - int error; - - if ((error = dns_pton(af, addr, dns_sa_addr(af, &resconf->iface, NULL)))) - return error; - - *dns_sa_port(af, &resconf->iface) = htons(port); - resconf->iface.ss_family = af; - - return 0; -} /* dns_resconf_setiface() */ - - -size_t dns_resconf_search(void *dst, size_t lim, const void *qname, size_t qlen, struct dns_resolv_conf *resconf, dns_resconf_i_t *state) { - unsigned srchi = 0xff & (*state >> 8); - unsigned ndots = 0xff & (*state >> 16); - unsigned slen, len = 0; - const char *qp, *qe; - -// assert(0xff > lengthof(resconf->search)); - - switch (0xff & *state) { - case 0: - qp = qname; - qe = qp + qlen; - - while ((qp = memchr(qp, '.', qe - qp))) - { ndots++; qp++; } - - ++*state; - - if (ndots >= resconf->options.ndots) { - len = dns_d_anchor(dst, lim, qname, qlen); - - break; - } - - /* FALL THROUGH */ - case 1: - if (srchi < lengthof(resconf->search) && (slen = strlen(resconf->search[srchi]))) { - len = dns__printstring(dst, lim, 0, qname, qlen); - len = dns_d_anchor(dst, lim, dst, len); - len += dns__printstring(dst, lim, len, resconf->search[srchi], slen); - - srchi++; - - break; - } - - ++*state; - - /* FALL THROUGH */ - case 2: - ++*state; - - if (ndots < resconf->options.ndots) { - len = dns_d_anchor(dst, lim, qname, qlen); - - break; - } - - /* FALL THROUGH */ - default: - break; - } /* switch() */ - - dns__printnul(dst, lim, len); - - *state = ((0xff & *state) << 0) - | ((0xff & srchi) << 8) - | ((0xff & ndots) << 16); - - return len; -} /* dns_resconf_search() */ - - -int dns_resconf_dump(struct dns_resolv_conf *resconf, FILE *fp) { - unsigned i; - int af; - - for (i = 0; i < lengthof(resconf->nameserver) && (af = resconf->nameserver[i].ss_family) != AF_UNSPEC; i++) { - char addr[INET6_ADDRSTRLEN + 1] = "[INVALID]"; - unsigned short port; - - dns_inet_ntop(af, dns_sa_addr(af, &resconf->nameserver[i], NULL), addr, sizeof addr); - port = ntohs(*dns_sa_port(af, &resconf->nameserver[i])); - - if (port == 53) - fprintf(fp, "nameserver %s\n", addr); - else - fprintf(fp, "nameserver [%s]:%hu\n", addr, port); - } - - - fprintf(fp, "search"); - - for (i = 0; i < lengthof(resconf->search) && resconf->search[i][0]; i++) - fprintf(fp, " %s", resconf->search[i]); - - fputc('\n', fp); - - - fputs("; ", fp); - dns_nssconf_dump(resconf, fp); - - fprintf(fp, "lookup"); - - for (i = 0; i < lengthof(resconf->lookup) && resconf->lookup[i]; i++) { - switch (resconf->lookup[i]) { - case 'b': - fprintf(fp, " bind"); break; - case 'f': - fprintf(fp, " file"); break; - case 'c': - fprintf(fp, " cache"); break; - } - } - - fputc('\n', fp); - - - fprintf(fp, "options ndots:%u timeout:%u attempts:%u", resconf->options.ndots, resconf->options.timeout, resconf->options.attempts); - - if (resconf->options.edns0) - fprintf(fp, " edns0"); - if (resconf->options.rotate) - fprintf(fp, " rotate"); - if (resconf->options.recurse) - fprintf(fp, " recurse"); - if (resconf->options.smart) - fprintf(fp, " smart"); - - switch (resconf->options.tcp) { - case DNS_RESCONF_TCP_ENABLE: - break; - case DNS_RESCONF_TCP_ONLY: - fprintf(fp, " tcp"); - break; - case DNS_RESCONF_TCP_DISABLE: - fprintf(fp, " tcp:disable"); - break; - } - - fputc('\n', fp); - - - if ((af = resconf->iface.ss_family) != AF_UNSPEC) { - char addr[INET6_ADDRSTRLEN + 1] = "[INVALID]"; - - dns_inet_ntop(af, dns_sa_addr(af, &resconf->iface, NULL), addr, sizeof addr); - - fprintf(fp, "interface %s %hu\n", addr, ntohs(*dns_sa_port(af, &resconf->iface))); - } - - return 0; -} /* dns_resconf_dump() */ - - -/* - * H I N T S E R V E R R O U T I N E S - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -struct dns_hints_soa { - unsigned char zone[DNS_D_MAXNAME + 1]; - - struct { - struct sockaddr_storage ss; - unsigned priority; - } addrs[16]; - - unsigned count; - - struct dns_hints_soa *next; -}; /* struct dns_hints_soa */ - - -struct dns_hints { - dns_atomic_t refcount; - - struct dns_hints_soa *head; -}; /* struct dns_hints */ - - -struct dns_hints *dns_hints_open(struct dns_resolv_conf *resconf, int *error) { - static const struct dns_hints H_initializer; - struct dns_hints *H; - - (void)resconf; - - if (!(H = malloc(sizeof *H))) - goto syerr; - - *H = H_initializer; - - dns_hints_acquire(H); - - return H; -syerr: - *error = dns_syerr(); - - free(H); - - return 0; -} /* dns_hints_open() */ - - -void dns_hints_close(struct dns_hints *H) { - struct dns_hints_soa *soa, *nxt; - - if (!H || 1 != dns_hints_release(H)) - return /* void */; - - for (soa = H->head; soa; soa = nxt) { - nxt = soa->next; - - free(soa); - } - - free(H); - - return /* void */; -} /* dns_hints_close() */ - - -dns_refcount_t dns_hints_acquire(struct dns_hints *H) { - return dns_atomic_fetch_add(&H->refcount); -} /* dns_hints_acquire() */ - - -dns_refcount_t dns_hints_release(struct dns_hints *H) { - return dns_atomic_fetch_sub(&H->refcount); -} /* dns_hints_release() */ - - -struct dns_hints *dns_hints_mortal(struct dns_hints *hints) { - if (hints) - dns_hints_release(hints); - - return hints; -} /* dns_hints_mortal() */ - - -struct dns_hints *dns_hints_local(struct dns_resolv_conf *resconf, int *error_) { - struct dns_hints *hints = 0; - int error; - - if (resconf) - dns_resconf_acquire(resconf); - else if (!(resconf = dns_resconf_local(&error))) - goto error; - - if (!(hints = dns_hints_open(resconf, &error))) - goto error; - - error = 0; - - if (0 == dns_hints_insert_resconf(hints, ".", resconf, &error) && error) - goto error; - - dns_resconf_close(resconf); - - return hints; -error: - *error_ = error; - - dns_resconf_close(resconf); - dns_hints_close(hints); - - return 0; -} /* dns_hints_local() */ - - -struct dns_hints *dns_hints_root(struct dns_resolv_conf *resconf, int *error_) { - static const struct { - int af; - char addr[INET6_ADDRSTRLEN]; - } root_hints[] = { - { AF_INET, "198.41.0.4" }, /* A.ROOT-SERVERS.NET. */ - { AF_INET6, "2001:503:ba3e::2:30" }, /* A.ROOT-SERVERS.NET. */ - { AF_INET, "192.228.79.201" }, /* B.ROOT-SERVERS.NET. */ - { AF_INET6, "2001:500:84::b" }, /* B.ROOT-SERVERS.NET. */ - { AF_INET, "192.33.4.12" }, /* C.ROOT-SERVERS.NET. */ - { AF_INET6, "2001:500:2::c" }, /* C.ROOT-SERVERS.NET. */ - { AF_INET, "199.7.91.13" }, /* D.ROOT-SERVERS.NET. */ - { AF_INET6, "2001:500:2d::d" }, /* D.ROOT-SERVERS.NET. */ - { AF_INET, "192.203.230.10" }, /* E.ROOT-SERVERS.NET. */ - { AF_INET, "192.5.5.241" }, /* F.ROOT-SERVERS.NET. */ - { AF_INET6, "2001:500:2f::f" }, /* F.ROOT-SERVERS.NET. */ - { AF_INET, "192.112.36.4" }, /* G.ROOT-SERVERS.NET. */ - { AF_INET, "128.63.2.53" }, /* H.ROOT-SERVERS.NET. */ - { AF_INET6, "2001:500:1::803f:235" }, /* H.ROOT-SERVERS.NET. */ - { AF_INET, "192.36.148.17" }, /* I.ROOT-SERVERS.NET. */ - { AF_INET6, "2001:7FE::53" }, /* I.ROOT-SERVERS.NET. */ - { AF_INET, "192.58.128.30" }, /* J.ROOT-SERVERS.NET. */ - { AF_INET6, "2001:503:c27::2:30" }, /* J.ROOT-SERVERS.NET. */ - { AF_INET, "193.0.14.129" }, /* K.ROOT-SERVERS.NET. */ - { AF_INET6, "2001:7FD::1" }, /* K.ROOT-SERVERS.NET. */ - { AF_INET, "199.7.83.42" }, /* L.ROOT-SERVERS.NET. */ - { AF_INET6, "2001:500:3::42" }, /* L.ROOT-SERVERS.NET. */ - { AF_INET, "202.12.27.33" }, /* M.ROOT-SERVERS.NET. */ - { AF_INET6, "2001:DC3::35" }, /* M.ROOT-SERVERS.NET. */ - }; - struct dns_hints *hints = 0; - struct sockaddr_storage ss; - unsigned i; - int error, af; - - if (!(hints = dns_hints_open(resconf, &error))) - goto error; - - for (i = 0; i < lengthof(root_hints); i++) { - af = root_hints[i].af; - - if ((error = dns_pton(af, root_hints[i].addr, dns_sa_addr(af, &ss, NULL)))) - goto error; - - *dns_sa_port(af, &ss) = htons(53); - ss.ss_family = af; - - if ((error = dns_hints_insert(hints, ".", (struct sockaddr *)&ss, 1))) - goto error; - } - - return hints; -error: - *error_ = error; - - dns_hints_close(hints); - - return 0; -} /* dns_hints_root() */ - - -static struct dns_hints_soa *dns_hints_fetch(struct dns_hints *H, const char *zone) { - struct dns_hints_soa *soa; - - for (soa = H->head; soa; soa = soa->next) { - if (0 == strcasecmp(zone, (char *)soa->zone)) - return soa; - } - - return 0; -} /* dns_hints_fetch() */ - - -int dns_hints_insert(struct dns_hints *H, const char *zone, const struct sockaddr *sa, unsigned priority) { - static const struct dns_hints_soa soa_initializer; - struct dns_hints_soa *soa; - unsigned i; - - if (!(soa = dns_hints_fetch(H, zone))) { - if (!(soa = malloc(sizeof *soa))) - return dns_syerr(); - - *soa = soa_initializer; - - dns__printstring(soa->zone, sizeof soa->zone, 0, zone); - - soa->next = H->head; - H->head = soa; - } - - i = soa->count % lengthof(soa->addrs); - - memcpy(&soa->addrs[i].ss, sa, dns_sa_len(sa)); - - soa->addrs[i].priority = DNS_PP_MAX(1, priority); - - if (soa->count < lengthof(soa->addrs)) - soa->count++; - - return 0; -} /* dns_hints_insert() */ - - -unsigned dns_hints_insert_resconf(struct dns_hints *H, const char *zone, const struct dns_resolv_conf *resconf, int *error_) { - unsigned i, n, p; - int error; - - for (i = 0, n = 0, p = 1; i < lengthof(resconf->nameserver) && resconf->nameserver[i].ss_family != AF_UNSPEC; i++, n++) { - if ((error = dns_hints_insert(H, zone, (struct sockaddr *)&resconf->nameserver[i], p))) - goto error; - - p += !resconf->options.rotate; - } - - return n; -error: - *error_ = error; - - return n; -} /* dns_hints_insert_resconf() */ - - -static int dns_hints_i_cmp(unsigned a, unsigned b, struct dns_hints_i *i, struct dns_hints_soa *soa) { - int cmp; - - if ((cmp = soa->addrs[a].priority - soa->addrs[b].priority)) - return cmp; - - return dns_k_shuffle16(a, i->state.seed) - dns_k_shuffle16(b, i->state.seed); -} /* dns_hints_i_cmp() */ - - -static unsigned dns_hints_i_start(struct dns_hints_i *i, struct dns_hints_soa *soa) { - unsigned p0, p; - - p0 = 0; - - for (p = 1; p < soa->count; p++) { - if (dns_hints_i_cmp(p, p0, i, soa) < 0) - p0 = p; - } - - return p0; -} /* dns_hints_i_start() */ - - -static unsigned dns_hints_i_skip(unsigned p0, struct dns_hints_i *i, struct dns_hints_soa *soa) { - unsigned pZ, p; - - for (pZ = 0; pZ < soa->count; pZ++) { - if (dns_hints_i_cmp(pZ, p0, i, soa) > 0) - goto cont; - } - - return soa->count; -cont: - for (p = pZ + 1; p < soa->count; p++) { - if (dns_hints_i_cmp(p, p0, i, soa) <= 0) - continue; - - if (dns_hints_i_cmp(p, pZ, i, soa) >= 0) - continue; - - pZ = p; - } - - - return pZ; -} /* dns_hints_i_skip() */ - - -struct dns_hints_i *dns_hints_i_init(struct dns_hints_i *i, struct dns_hints *hints) { - static const struct dns_hints_i i_initializer; - struct dns_hints_soa *soa; - - i->state = i_initializer.state; - - do { - i->state.seed = dns_random(); - } while (0 == i->state.seed); - - if ((soa = dns_hints_fetch(hints, i->zone))) { - i->state.next = dns_hints_i_start(i, soa); - } - - return i; -} /* dns_hints_i_init() */ - - -unsigned dns_hints_grep(struct sockaddr **sa, socklen_t *sa_len, unsigned lim, struct dns_hints_i *i, struct dns_hints *H) { - struct dns_hints_soa *soa; - unsigned n; - - if (!(soa = dns_hints_fetch(H, i->zone))) - return 0; - - n = 0; - - while (i->state.next < soa->count && n < lim) { - *sa = (struct sockaddr *)&soa->addrs[i->state.next].ss; - *sa_len = dns_sa_len(*sa); - - sa++; - sa_len++; - n++; - - i->state.next = dns_hints_i_skip(i->state.next, i, soa); - } - - return n; -} /* dns_hints_grep() */ - - -struct dns_packet *dns_hints_query(struct dns_hints *hints, struct dns_packet *Q, int *error_) { - struct dns_packet *A, *P; - struct dns_rr rr; - char zone[DNS_D_MAXNAME + 1]; - size_t zlen; - struct dns_hints_i i; - struct sockaddr *sa; - socklen_t slen; - int error; - - if (!dns_rr_grep(&rr, 1, dns_rr_i_new(Q, .section = DNS_S_QUESTION), Q, &error)) - goto error; - - if (!(zlen = dns_d_expand(zone, sizeof zone, rr.dn.p, Q, &error))) - goto error; - else if (zlen >= sizeof zone) - goto toolong; - - P = dns_p_new(512); - dns_header(P)->qr = 1; - - if ((error = dns_rr_copy(P, &rr, Q))) - goto error; - - if ((error = dns_p_push(P, DNS_S_AUTHORITY, ".", strlen("."), DNS_T_NS, DNS_C_IN, 0, "hints.local."))) - goto error; - - do { - i.zone = zone; - - dns_hints_i_init(&i, hints); - - while (dns_hints_grep(&sa, &slen, 1, &i, hints)) { - int af = sa->sa_family; - int rtype = (af == AF_INET6)? DNS_T_AAAA : DNS_T_A; - - if ((error = dns_p_push(P, DNS_S_ADDITIONAL, "hints.local.", strlen("hints.local."), rtype, DNS_C_IN, 0, dns_sa_addr(af, sa, NULL)))) - goto error; - } - } while ((zlen = dns_d_cleave(zone, sizeof zone, zone, zlen))); - - if (!(A = dns_p_copy(dns_p_make(P->end, &error), P))) - goto error; - - return A; -toolong: - error = DNS_EILLEGAL; -error: - *error_ = error; - - return 0; -} /* dns_hints_query() */ - - -/** ugly hack to support specifying ports other than 53 in resolv.conf. */ -static unsigned short dns_hints_port(struct dns_hints *hints, int af, void *addr) { - struct dns_hints_soa *soa; - void *addrsoa; - socklen_t addrlen; - unsigned short port; - unsigned i; - - for (soa = hints->head; soa; soa = soa->next) { - for (i = 0; i < soa->count; i++) { - if (af != soa->addrs[i].ss.ss_family) - continue; - - if (!(addrsoa = dns_sa_addr(af, &soa->addrs[i].ss, &addrlen))) - continue; - - if (memcmp(addr, addrsoa, addrlen)) - continue; - - port = *dns_sa_port(af, &soa->addrs[i].ss); - - return (port)? port : htons(53); - } - } - - return htons(53); -} /* dns_hints_port() */ - - -int dns_hints_dump(struct dns_hints *hints, FILE *fp) { - struct dns_hints_soa *soa; - char addr[INET6_ADDRSTRLEN]; - unsigned i; - int af, error; - - for (soa = hints->head; soa; soa = soa->next) { - fprintf(fp, "ZONE \"%s\"\n", soa->zone); - - for (i = 0; i < soa->count; i++) { - af = soa->addrs[i].ss.ss_family; - - if ((error = dns_ntop(af, dns_sa_addr(af, &soa->addrs[i].ss, NULL), addr, sizeof addr))) - return error; - - fprintf(fp, "\t(%d) [%s]:%hu\n", (int)soa->addrs[i].priority, addr, ntohs(*dns_sa_port(af, &soa->addrs[i].ss))); - } - } - - return 0; -} /* dns_hints_dump() */ - - -/* - * C A C H E R O U T I N E S - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -static dns_refcount_t dns_cache_acquire(struct dns_cache *cache) { - return dns_atomic_fetch_add(&cache->_.refcount); -} /* dns_cache_acquire() */ - - -static dns_refcount_t dns_cache_release(struct dns_cache *cache) { - return dns_atomic_fetch_sub(&cache->_.refcount); -} /* dns_cache_release() */ - - -static struct dns_packet *dns_cache_query(struct dns_packet *query, struct dns_cache *cache, int *error) { - (void)query; - (void)cache; - (void)error; - - return NULL; -} /* dns_cache_submit() */ - - -static int dns_cache_submit(struct dns_packet *query, struct dns_cache *cache) { - (void)query; - (void)cache; - - return 0; -} /* dns_cache_submit() */ - - -static int dns_cache_check(struct dns_cache *cache) { - (void)cache; - - return 0; -} /* dns_cache_check() */ - - -static struct dns_packet *dns_cache_fetch(struct dns_cache *cache, int *error) { - (void)cache; - (void)error; - - return NULL; -} /* dns_cache_fetch() */ - - -static int dns_cache_pollfd(struct dns_cache *cache) { - (void)cache; - - return -1; -} /* dns_cache_pollfd() */ - - -static short dns_cache_events(struct dns_cache *cache) { - (void)cache; - - return 0; -} /* dns_cache_events() */ - - -static void dns_cache_clear(struct dns_cache *cache) { - (void)cache; - - return; -} /* dns_cache_clear() */ - - -struct dns_cache *dns_cache_init(struct dns_cache *cache) { - static const struct dns_cache c_init = { - .acquire = &dns_cache_acquire, - .release = &dns_cache_release, - .query = &dns_cache_query, - .submit = &dns_cache_submit, - .check = &dns_cache_check, - .fetch = &dns_cache_fetch, - .pollfd = &dns_cache_pollfd, - .events = &dns_cache_events, - .clear = &dns_cache_clear, - ._ = { .refcount = 1, }, - }; - - *cache = c_init; - - return cache; -} /* dns_cache_init() */ - - -void dns_cache_close(struct dns_cache *cache) { - if (cache) - cache->release(cache); -} /* dns_cache_close() */ - - -/* - * S O C K E T R O U T I N E S - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -static void dns_socketclose(int *fd, const struct dns_options *opts) { - if (opts && opts->closefd.cb) - opts->closefd.cb(fd, opts->closefd.arg); - - if (*fd != -1) { -#if _WIN32 - closesocket(*fd); -#else - close(*fd); -#endif - *fd = -1; - } -} /* dns_socketclose() */ - - -#define DNS_SO_MAXTRY 7 - -static int dns_socket(struct sockaddr *local, int type, int *error_) { - int error, fd = -1; -#if defined(O_NONBLOCK) - int flags; -#elif defined(FIONBIO) - unsigned long opt; -#endif - - if (-1 == (fd = socket(local->sa_family, type, 0))) - goto soerr; - -#if defined(F_SETFD) - if (-1 == fcntl(fd, F_SETFD, 1)) - goto syerr; -#endif - -#if defined(O_NONBLOCK) - if (-1 == (flags = fcntl(fd, F_GETFL))) - goto syerr; - - if (-1 == fcntl(fd, F_SETFL, flags | O_NONBLOCK)) - goto syerr; -#elif defined(FIONBIO) - opt = 1; - - if (0 != ioctlsocket(fd, FIONBIO, &opt)) - goto soerr; -#endif - -#if defined(SO_NOSIGPIPE) - if (type != SOCK_DGRAM) { - if (0 != setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &(int){ 1 }, sizeof (int))) - goto soerr; - } -#endif - - if (local->sa_family != AF_INET && local->sa_family != AF_INET6) - return fd; - - if (type != SOCK_DGRAM) - return fd; - - if (*dns_sa_port(local->sa_family, local) == 0) { - struct sockaddr_storage tmp; - unsigned i, port; - - memcpy(&tmp, local, dns_sa_len(local)); - - for (i = 0; i < DNS_SO_MAXTRY; i++) { - port = 1025 + (dns_random() % 64510); - - *dns_sa_port(tmp.ss_family, &tmp) = htons(port); - - if (0 == bind(fd, (struct sockaddr *)&tmp, dns_sa_len(&tmp))) - return fd; - } - } - - if (0 == bind(fd, local, dns_sa_len(local))) - return fd; - - /* FALL THROUGH */ -soerr: - error = dns_soerr(); - - goto error; -#if defined(F_SETFD) || defined(O_NONBLOCK) -syerr: - error = dns_syerr(); - - goto error; -#endif -error: - *error_ = error; - - dns_socketclose(&fd, NULL); - - return -1; -} /* dns_socket() */ - - -enum { - DNS_SO_UDP_INIT = 1, - DNS_SO_UDP_CONN, - DNS_SO_UDP_SEND, - DNS_SO_UDP_RECV, - DNS_SO_UDP_DONE, - - DNS_SO_TCP_INIT, - DNS_SO_TCP_CONN, - DNS_SO_TCP_SEND, - DNS_SO_TCP_RECV, - DNS_SO_TCP_DONE, -}; - -struct dns_socket { - struct dns_options opts; - - int udp; - int tcp; - - int *old; - unsigned onum, olim; - - int type; - - struct sockaddr_storage local, remote; - - struct dns_k_permutor qids; - - struct dns_stat stat; - - /* - * NOTE: dns_so_reset() zeroes everything from here down. - */ - int state; - - unsigned short qid; - char qname[DNS_D_MAXNAME + 1]; - size_t qlen; - enum dns_type qtype; - enum dns_class qclass; - - struct dns_packet *query; - size_t qout; - - struct dns_clock elapsed; - - struct dns_packet *answer; - size_t alen, apos; -}; /* struct dns_socket */ - - -/* - * NOTE: Actual closure delayed so that kqueue(2) and epoll(2) callers have - * a chance to recognize a state change after installing a persistent event - * and where sequential descriptors with the same integer value returned - * from _pollfd() would be ambiguous. See dns_so_closefds(). - */ -static int dns_so_closefd(struct dns_socket *so, int *fd) { - int error; - - if (*fd == -1) - return 0; - - if (so->opts.closefd.cb) { - if ((error = so->opts.closefd.cb(fd, so->opts.closefd.arg))) { - return error; - } else if (*fd == -1) - return 0; - } - - if (!(so->onum < so->olim)) { - unsigned olim = DNS_PP_MAX(4, so->olim * 2); - void *old; - - if (!(old = realloc(so->old, sizeof so->old[0] * olim))) - return dns_syerr(); - - so->old = old; - so->olim = olim; - } - - so->old[so->onum++] = *fd; - *fd = -1; - - return 0; -} /* dns_so_closefd() */ - - -#define DNS_SO_CLOSE_UDP 0x01 -#define DNS_SO_CLOSE_TCP 0x02 -#define DNS_SO_CLOSE_OLD 0x04 -#define DNS_SO_CLOSE_ALL (DNS_SO_CLOSE_UDP|DNS_SO_CLOSE_TCP|DNS_SO_CLOSE_OLD) - -static void dns_so_closefds(struct dns_socket *so, int which) { - if (DNS_SO_CLOSE_UDP & which) - dns_socketclose(&so->udp, &so->opts); - if (DNS_SO_CLOSE_TCP & which) - dns_socketclose(&so->tcp, &so->opts); - if (DNS_SO_CLOSE_OLD & which) { - unsigned i; - for (i = 0; i < so->onum; i++) - dns_socketclose(&so->old[i], &so->opts); - so->onum = 0; - free(so->old); - so->old = 0; - so->olim = 0; - } -} /* dns_so_closefds() */ - - -static void dns_so_destroy(struct dns_socket *); - -static struct dns_socket *dns_so_init(struct dns_socket *so, const struct sockaddr *local, int type, const struct dns_options *opts, int *error) { - static const struct dns_socket so_initializer = { .opts = DNS_OPTS_INITIALIZER, .udp = -1, .tcp = -1, }; - - *so = so_initializer; - so->type = type; - - if (opts) - so->opts = *opts; - - if (local) - memcpy(&so->local, local, dns_sa_len(local)); - - if (-1 == (so->udp = dns_socket((struct sockaddr *)&so->local, SOCK_DGRAM, error))) - goto error; - - dns_k_permutor_init(&so->qids, 1, 65535); - - return so; -error: - dns_so_destroy(so); - - return 0; -} /* dns_so_init() */ - - -struct dns_socket *dns_so_open(const struct sockaddr *local, int type, const struct dns_options *opts, int *error) { - struct dns_socket *so; - - if (!(so = malloc(sizeof *so))) - goto syerr; - - if (!dns_so_init(so, local, type, opts, error)) - goto error; - - return so; -syerr: - *error = dns_syerr(); -error: - dns_so_close(so); - - return 0; -} /* dns_so_open() */ - - -static void dns_so_destroy(struct dns_socket *so) { - dns_so_reset(so); - dns_so_closefds(so, DNS_SO_CLOSE_ALL); -} /* dns_so_destroy() */ - - -void dns_so_close(struct dns_socket *so) { - if (!so) - return; - - dns_so_destroy(so); - - free(so); -} /* dns_so_close() */ - - -void dns_so_reset(struct dns_socket *so) { - dns_p_setptr(&so->answer, NULL); - - memset(&so->state, '\0', sizeof *so - offsetof(struct dns_socket, state)); -} /* dns_so_reset() */ - - -unsigned short dns_so_mkqid(struct dns_socket *so) { - return dns_k_permutor_step(&so->qids); -} /* dns_so_mkqid() */ - - -#define DNS_SO_MINBUF 768 - -static int dns_so_newanswer(struct dns_socket *so, size_t len) { - size_t size = offsetof(struct dns_packet, data) + DNS_PP_MAX(len, DNS_SO_MINBUF); - void *p; - - if (!(p = realloc(so->answer, size))) - return dns_syerr(); - - so->answer = dns_p_init(p, size); - - return 0; -} /* dns_so_newanswer() */ - - -int dns_so_submit(struct dns_socket *so, struct dns_packet *Q, struct sockaddr *host) { - struct dns_rr rr; - int error = -1; - - dns_so_reset(so); - - if ((error = dns_rr_parse(&rr, 12, Q))) - goto error; - - if (!(so->qlen = dns_d_expand(so->qname, sizeof so->qname, rr.dn.p, Q, &error))) - goto error; - /* - * NOTE: don't bail if expansion is too long; caller may be - * intentionally sending long names. However, we won't be able to - * verify it on return. - */ - - so->qtype = rr.type; - so->qclass = rr.class; - - if ((error = dns_so_newanswer(so, DNS_SO_MINBUF))) - goto syerr; - - memcpy(&so->remote, host, dns_sa_len(host)); - - so->query = Q; - so->qout = 0; - - dns_begin(&so->elapsed); - - if (dns_header(so->query)->qid == 0) - dns_header(so->query)->qid = dns_so_mkqid(so); - - so->qid = dns_header(so->query)->qid; - so->state = (so->type == SOCK_STREAM)? DNS_SO_TCP_INIT : DNS_SO_UDP_INIT; - - so->stat.queries++; - - return 0; -syerr: - error = dns_syerr(); -error: - dns_so_reset(so); - - return error; -} /* dns_so_submit() */ - - -static int dns_so_verify(struct dns_socket *so, struct dns_packet *P) { - char qname[DNS_D_MAXNAME + 1]; - size_t qlen; - struct dns_rr rr; - int error = -1; - - if (so->qid != dns_header(so->answer)->qid) - return DNS_EUNKNOWN; - - if (!dns_p_count(so->answer, DNS_S_QD)) - return DNS_EUNKNOWN; - - if (0 != dns_rr_parse(&rr, 12, so->answer)) - return DNS_EUNKNOWN; - - if (rr.type != so->qtype || rr.class != so->qclass) - return DNS_EUNKNOWN; - - if (!(qlen = dns_d_expand(qname, sizeof qname, rr.dn.p, P, &error))) - return error; - else if (qlen >= sizeof qname || qlen != so->qlen) - return DNS_EUNKNOWN; - - if (0 != strcasecmp(so->qname, qname)) - return DNS_EUNKNOWN; - - return 0; -} /* dns_so_verify() */ - - -static _Bool dns_so_tcp_keep(struct dns_socket *so) { - struct sockaddr_storage remote; - - if (so->tcp == -1) - return 0; - - if (0 != getpeername(so->tcp, (struct sockaddr *)&remote, &(socklen_t){ sizeof remote })) - return 0; - - return 0 == dns_sa_cmp(&remote, &so->remote); -} /* dns_so_tcp_keep() */ - - -#if defined __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Warray-bounds" -#endif - -static int dns_so_tcp_send(struct dns_socket *so) { - unsigned char *qsrc; - size_t qend; - long n; - - so->query->data[-2] = 0xff & (so->query->end >> 8); - so->query->data[-1] = 0xff & (so->query->end >> 0); - - qsrc = &so->query->data[-2] + so->qout; - qend = so->query->end + 2; - - while (so->qout < qend) { - if (0 > (n = dns_send(so->tcp, (void *)&qsrc[so->qout], qend - so->qout, 0))) - return dns_soerr(); - - so->qout += n; - so->stat.tcp.sent.bytes += n; - } - - so->stat.tcp.sent.count++; - - return 0; -} /* dns_so_tcp_send() */ - - -static int dns_so_tcp_recv(struct dns_socket *so) { - unsigned char *asrc; - size_t aend, alen; - int error; - long n; - - aend = so->alen + 2; - - while (so->apos < aend) { - asrc = &so->answer->data[-2]; - - if (0 > (n = recv(so->tcp, (void *)&asrc[so->apos], aend - so->apos, 0))) - return dns_soerr(); - else if (n == 0) - return DNS_EUNKNOWN; /* FIXME */ - - so->apos += n; - so->stat.tcp.rcvd.bytes += n; - - if (so->alen == 0 && so->apos >= 2) { - alen = ((0xff & so->answer->data[-2]) << 8) - | ((0xff & so->answer->data[-1]) << 0); - - if ((error = dns_so_newanswer(so, alen))) - return error; - - so->alen = alen; - aend = alen + 2; - } - } - - so->answer->end = so->alen; - so->stat.tcp.rcvd.count++; - - return 0; -} /* dns_so_tcp_recv() */ - -#if __clang__ -#pragma clang diagnostic pop -#endif - - -int dns_so_check(struct dns_socket *so) { - int error; - long n; - -retry: - switch (so->state) { - case DNS_SO_UDP_INIT: - so->state++; - case DNS_SO_UDP_CONN: - if (0 != connect(so->udp, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote))) - goto soerr; - - so->state++; - case DNS_SO_UDP_SEND: - if (0 > (n = send(so->udp, (void *)so->query->data, so->query->end, 0))) - goto soerr; - - so->stat.udp.sent.bytes += n; - so->stat.udp.sent.count++; - - so->state++; - case DNS_SO_UDP_RECV: - if (0 > (n = recv(so->udp, (void *)so->answer->data, so->answer->size, 0))) - goto soerr; - - so->stat.udp.rcvd.bytes += n; - so->stat.udp.rcvd.count++; - - if ((so->answer->end = n) < 12) - goto trash; - - if ((error = dns_so_verify(so, so->answer))) - goto trash; - - so->state++; - case DNS_SO_UDP_DONE: - if (!dns_header(so->answer)->tc || so->type == SOCK_DGRAM) - return 0; - - so->state++; - case DNS_SO_TCP_INIT: - if (dns_so_tcp_keep(so)) { - so->state = DNS_SO_TCP_SEND; - - goto retry; - } - - if ((error = dns_so_closefd(so, &so->tcp))) - goto error; - - if (-1 == (so->tcp = dns_socket((struct sockaddr *)&so->local, SOCK_STREAM, &error))) - goto error; - - so->state++; - case DNS_SO_TCP_CONN: - if (0 != connect(so->tcp, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote))) { - if (dns_soerr() != DNS_EISCONN) - goto soerr; - } - - so->state++; - case DNS_SO_TCP_SEND: - if ((error = dns_so_tcp_send(so))) - goto error; - - so->state++; - case DNS_SO_TCP_RECV: - if ((error = dns_so_tcp_recv(so))) - goto error; - - so->state++; - case DNS_SO_TCP_DONE: - /* close unless DNS_RESCONF_TCP_ONLY (see dns_res_tcp2type) */ - if (so->type != SOCK_STREAM) { - if ((error = dns_so_closefd(so, &so->tcp))) - goto error; - } - - if (so->answer->end < 12) - return DNS_EILLEGAL; - - if ((error = dns_so_verify(so, so->answer))) - goto error; - - return 0; - default: - error = DNS_EUNKNOWN; - - goto error; - } /* switch() */ - -trash: - goto retry; -soerr: - error = dns_soerr(); - - goto error; -error: - switch (error) { - case DNS_EINTR: - goto retry; - case DNS_EINPROGRESS: - /* FALL THROUGH */ - case DNS_EALREADY: - /* FALL THROUGH */ -#if DNS_EWOULDBLOCK != DNS_EAGAIN - case DNS_EWOULDBLOCK: - /* FALL THROUGH */ -#endif - error = DNS_EAGAIN; - - break; - } /* switch() */ - - return error; -} /* dns_so_check() */ - - -struct dns_packet *dns_so_fetch(struct dns_socket *so, int *error) { - struct dns_packet *answer; - - switch (so->state) { - case DNS_SO_UDP_DONE: - case DNS_SO_TCP_DONE: - answer = so->answer; - so->answer = 0; - - return answer; - default: - *error = DNS_EUNKNOWN; - - return 0; - } -} /* dns_so_fetch() */ - - -struct dns_packet *dns_so_query(struct dns_socket *so, struct dns_packet *Q, struct sockaddr *host, int *error_) { - struct dns_packet *A; - int error; - - if (!so->state) { - if ((error = dns_so_submit(so, Q, host))) - goto error; - } - - if ((error = dns_so_check(so))) - goto error; - - if (!(A = dns_so_fetch(so, &error))) - goto error; - - dns_so_reset(so); - - return A; -error: - *error_ = error; - - return 0; -} /* dns_so_query() */ - - -time_t dns_so_elapsed(struct dns_socket *so) { - return dns_elapsed(&so->elapsed); -} /* dns_so_elapsed() */ - - -void dns_so_clear(struct dns_socket *so) { - dns_so_closefds(so, DNS_SO_CLOSE_OLD); -} /* dns_so_clear() */ - - -static int dns_so_events2(struct dns_socket *so, enum dns_events type) { - int events = 0; - - switch (so->state) { - case DNS_SO_UDP_CONN: - case DNS_SO_UDP_SEND: - events |= DNS_POLLOUT; - - break; - case DNS_SO_UDP_RECV: - events |= DNS_POLLIN; - - break; - case DNS_SO_TCP_CONN: - case DNS_SO_TCP_SEND: - events |= DNS_POLLOUT; - - break; - case DNS_SO_TCP_RECV: - events |= DNS_POLLIN; - - break; - } /* switch() */ - - switch (type) { - case DNS_LIBEVENT: - return DNS_POLL2EV(events); - default: - return events; - } /* switch() */ -} /* dns_so_events2() */ - - -int dns_so_events(struct dns_socket *so) { - return dns_so_events2(so, so->opts.events); -} /* dns_so_events() */ - - -int dns_so_pollfd(struct dns_socket *so) { - switch (so->state) { - case DNS_SO_UDP_CONN: - case DNS_SO_UDP_SEND: - case DNS_SO_UDP_RECV: - return so->udp; - case DNS_SO_TCP_CONN: - case DNS_SO_TCP_SEND: - case DNS_SO_TCP_RECV: - return so->tcp; - } /* switch() */ - - return -1; -} /* dns_so_pollfd() */ - - -int dns_so_poll(struct dns_socket *so, int timeout) { - return dns_poll(dns_so_pollfd(so), dns_so_events2(so, DNS_SYSPOLL), timeout); -} /* dns_so_poll() */ - - -const struct dns_stat *dns_so_stat(struct dns_socket *so) { - return &so->stat; -} /* dns_so_stat() */ - - -/* - * R E S O L V E R R O U T I N E S - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -enum dns_res_state { - DNS_R_INIT, - DNS_R_GLUE, - DNS_R_SWITCH, /* (B)IND, (F)ILE, (C)ACHE */ - - DNS_R_FILE, /* Lookup in local hosts database */ - - DNS_R_CACHE, /* Lookup in application cache */ - DNS_R_SUBMIT, - DNS_R_CHECK, - DNS_R_FETCH, - - DNS_R_BIND, /* Lookup in the network */ - DNS_R_SEARCH, - DNS_R_HINTS, - DNS_R_ITERATE, - DNS_R_FOREACH_NS, - DNS_R_RESOLV0_NS, /* Prologue: Setup next frame and recurse */ - DNS_R_RESOLV1_NS, /* Epilog: Inspect answer */ - DNS_R_FOREACH_A, - DNS_R_QUERY_A, - DNS_R_CNAME0_A, - DNS_R_CNAME1_A, - - DNS_R_FINISH, - DNS_R_SMART0_A, - DNS_R_SMART1_A, - DNS_R_DONE, - DNS_R_SERVFAIL, -}; /* enum dns_res_state */ - - -#define DNS_R_MAXDEPTH 8 -#define DNS_R_ENDFRAME (DNS_R_MAXDEPTH - 1) - -struct dns_resolver { - struct dns_socket so; - - struct dns_resolv_conf *resconf; - struct dns_hosts *hosts; - struct dns_hints *hints; - struct dns_cache *cache; - - dns_atomic_t refcount; - - /* Reset zeroes everything below here. */ - - char qname[DNS_D_MAXNAME + 1]; - size_t qlen; - - enum dns_type qtype; - enum dns_class qclass; - - struct dns_clock elapsed; - - dns_resconf_i_t search; - - struct dns_rr_i smart; - - struct dns_packet *nodata; /* answer if nothing better */ - - unsigned sp; - - struct dns_res_frame { - enum dns_res_state state; - - int error; - int which; /* (B)IND, (F)ILE; index into resconf->lookup */ - - unsigned attempts; - - struct dns_packet *query, *answer, *hints; - - struct dns_rr_i hints_i, hints_j; - struct dns_rr hints_ns, ans_cname; - } stack[DNS_R_MAXDEPTH]; -}; /* struct dns_resolver */ - - -static int dns_res_tcp2type(int tcp) { - switch (tcp) { - case DNS_RESCONF_TCP_ONLY: - return SOCK_STREAM; - case DNS_RESCONF_TCP_DISABLE: - return SOCK_DGRAM; - default: - return 0; - } -} /* dns_res_tcp2type() */ - -struct dns_resolver *dns_res_open(struct dns_resolv_conf *resconf, struct dns_hosts *hosts, struct dns_hints *hints, struct dns_cache *cache, const struct dns_options *opts, int *_error) { - static const struct dns_resolver R_initializer - = { .refcount = 1, }; - struct dns_resolver *R = 0; - int type, error; - - /* - * Grab ref count early because the caller may have passed us a mortal - * reference, and we want to do the right thing if we return early - * from an error. - */ - if (resconf) - dns_resconf_acquire(resconf); - if (hosts) - dns_hosts_acquire(hosts); - if (hints) - dns_hints_acquire(hints); - if (cache) - dns_cache_acquire(cache); - - /* - * Don't try to load it ourselves because a NULL object might be an - * error from, say, dns_resconf_root(), and loading - * dns_resconf_local() by default would create undesirable surpises. - */ - if (!resconf || !hosts || !hints) - goto _error; - - if (!(R = malloc(sizeof *R))) - goto syerr; - - *R = R_initializer; - type = dns_res_tcp2type(resconf->options.tcp); - - if (!dns_so_init(&R->so, (struct sockaddr *)&resconf->iface, type, opts, &error)) - goto error; - - R->resconf = resconf; - R->hosts = hosts; - R->hints = hints; - R->cache = cache; - - return R; -syerr: - error = dns_syerr(); -error: - *_error = error; -_error: - dns_res_close(R); - - dns_resconf_close(resconf); - dns_hosts_close(hosts); - dns_hints_close(hints); - dns_cache_close(cache); - - return 0; -} /* dns_res_open() */ - - -struct dns_resolver *dns_res_stub(const struct dns_options *opts, int *error) { - struct dns_resolv_conf *resconf = 0; - struct dns_hosts *hosts = 0; - struct dns_hints *hints = 0; - struct dns_resolver *res = 0; - - if (!(resconf = dns_resconf_local(error))) - goto epilog; - - if (!(hosts = dns_hosts_local(error))) - goto epilog; - - if (!(hints = dns_hints_local(resconf, error))) - goto epilog; - - if (!(res = dns_res_open(resconf, hosts, hints, NULL, opts, error))) - goto epilog; - -epilog: - dns_resconf_close(resconf); - dns_hosts_close(hosts); - dns_hints_close(hints); - - return res; -} /* dns_res_stub() */ - - -static void dns_res_reset_frame(struct dns_resolver *R, struct dns_res_frame *frame) { - (void)R; - - dns_p_setptr(&frame->query, NULL); - dns_p_setptr(&frame->answer, NULL); - dns_p_setptr(&frame->hints, NULL); - - memset(frame, '\0', sizeof *frame); -} /* dns_res_reset_frame() */ - - -void dns_res_reset(struct dns_resolver *R) { - unsigned i; - - dns_so_reset(&R->so); - - dns_p_setptr(&R->nodata, NULL); - - for (i = 0; i < lengthof(R->stack); i++) - dns_res_reset_frame(R, &R->stack[i]); - - memset(&R->qname, '\0', sizeof *R - offsetof(struct dns_resolver, qname)); -} /* dns_res_reset() */ - - -void dns_res_close(struct dns_resolver *R) { - if (!R || 1 < dns_res_release(R)) - return; - - dns_res_reset(R); - - dns_so_destroy(&R->so); - - dns_hints_close(R->hints); - dns_hosts_close(R->hosts); - dns_resconf_close(R->resconf); - dns_cache_close(R->cache); - - free(R); -} /* dns_res_close() */ - - -dns_refcount_t dns_res_acquire(struct dns_resolver *R) { - return dns_atomic_fetch_add(&R->refcount); -} /* dns_res_acquire() */ - - -dns_refcount_t dns_res_release(struct dns_resolver *R) { - return dns_atomic_fetch_sub(&R->refcount); -} /* dns_res_release() */ - - -struct dns_resolver *dns_res_mortal(struct dns_resolver *res) { - if (res) - dns_res_release(res); - return res; -} /* dns_res_mortal() */ - - -static struct dns_packet *dns_res_merge(struct dns_packet *P0, struct dns_packet *P1, int *error_) { - size_t bufsiz = P0->end + P1->end; - struct dns_packet *P[3] = { P0, P1, 0 }; - struct dns_rr rr[3]; - int error, copy, i; - enum dns_section section; - -retry: - if (!(P[2] = dns_p_make(bufsiz, &error))) - goto error; - - dns_rr_foreach(&rr[0], P[0], .section = DNS_S_QD) { - if ((error = dns_rr_copy(P[2], &rr[0], P[0]))) - goto error; - } - - for (section = DNS_S_AN; (DNS_S_ALL & section); section <<= 1) { - for (i = 0; i < 2; i++) { - dns_rr_foreach(&rr[i], P[i], .section = section) { - copy = 1; - - dns_rr_foreach(&rr[2], P[2], .type = rr[i].type, .section = (DNS_S_ALL & ~DNS_S_QD)) { - if (0 == dns_rr_cmp(&rr[i], P[i], &rr[2], P[2])) { - copy = 0; - - break; - } - } - - if (copy && (error = dns_rr_copy(P[2], &rr[i], P[i]))) { - if (error == DNS_ENOBUFS && bufsiz < 65535) { - dns_p_setptr(&P[2], NULL); - - bufsiz = DNS_PP_MAX(65535, bufsiz * 2); - - goto retry; - } - - goto error; - } - } /* foreach(rr) */ - } /* foreach(packet) */ - } /* foreach(section) */ - - return P[2]; -error: - *error_ = error; - - dns_p_free(P[2]); - - return 0; -} /* dns_res_merge() */ - - -static struct dns_packet *dns_res_glue(struct dns_resolver *R, struct dns_packet *Q) { - struct dns_packet *P = dns_p_new(512); - char qname[DNS_D_MAXNAME + 1]; - size_t qlen; - enum dns_type qtype; - struct dns_rr rr; - unsigned sp; - int error; - - if (!(qlen = dns_d_expand(qname, sizeof qname, 12, Q, &error)) - || qlen >= sizeof qname) - return 0; - - if (!(qtype = dns_rr_type(12, Q))) - return 0; - - if ((error = dns_p_push(P, DNS_S_QD, qname, strlen(qname), qtype, DNS_C_IN, 0, 0))) - return 0; - - for (sp = 0; sp <= R->sp; sp++) { - if (!R->stack[sp].answer) - continue; - - dns_rr_foreach(&rr, R->stack[sp].answer, .name = qname, .type = qtype, .section = (DNS_S_ALL & ~DNS_S_QD)) { - rr.section = DNS_S_AN; - - if ((error = dns_rr_copy(P, &rr, R->stack[sp].answer))) - return 0; - } - } - - if (dns_p_count(P, DNS_S_AN) > 0) - goto copy; - - /* Otherwise, look for a CNAME */ - for (sp = 0; sp <= R->sp; sp++) { - if (!R->stack[sp].answer) - continue; - - dns_rr_foreach(&rr, R->stack[sp].answer, .name = qname, .type = DNS_T_CNAME, .section = (DNS_S_ALL & ~DNS_S_QD)) { - rr.section = DNS_S_AN; - - if ((error = dns_rr_copy(P, &rr, R->stack[sp].answer))) - return 0; - } - } - - if (!dns_p_count(P, DNS_S_AN)) - return 0; - -copy: - return dns_p_copy(dns_p_make(P->end, &error), P); -} /* dns_res_glue() */ - - -static struct dns_packet *dns_res_mkquery(struct dns_resolver *R, const char *qname, enum dns_type qtype, enum dns_class qclass, int *error_) { - struct dns_packet *Q = 0; - int error; - - if (!(Q = dns_p_init(malloc(DNS_P_QBUFSIZ), DNS_P_QBUFSIZ))) - goto syerr; - - if ((error = dns_p_push(Q, DNS_S_QD, qname, strlen(qname), qtype, qclass, 0, 0))) - goto error; - - dns_header(Q)->rd = !R->resconf->options.recurse; - - return Q; -syerr: - error = dns_syerr(); -error: - dns_p_free(Q); - - *error_ = error; - - return 0; -} /* dns_res_mkquery() */ - - -/* - * Sort NS records by three criteria: - * - * 1) Whether glue is present. - * 2) Whether glue record is original or of recursive lookup. - * 3) Randomly shuffle records which share the above criteria. - * - * NOTE: Assumes only NS records passed, AND ASSUMES no new NS records will - * be added during an iteration. - * - * FIXME: Only groks A glue, not AAAA glue. - */ -static int dns_res_nameserv_cmp(struct dns_rr *a, struct dns_rr *b, struct dns_rr_i *i, struct dns_packet *P) { - _Bool glued[2] = { 0 }; - struct dns_rr x = { 0 }, y = { 0 }; - struct dns_ns ns; - int cmp, error; - - if (!(error = dns_ns_parse(&ns, a, P))) - glued[0] = !!dns_rr_grep(&x, 1, dns_rr_i_new(P, .section = (DNS_S_ALL & ~DNS_S_QD), .name = ns.host, .type = DNS_T_A), P, &error); - - if (!(error = dns_ns_parse(&ns, b, P))) - glued[1] = !!dns_rr_grep(&y, 1, dns_rr_i_new(P, .section = (DNS_S_ALL & ~DNS_S_QD), .name = ns.host, .type = DNS_T_A), P, &error); - - if ((cmp = glued[1] - glued[0])) { - return cmp; - } else if ((cmp = (dns_rr_offset(&y) < i->args[0]) - (dns_rr_offset(&x) < i->args[0]))) { - return cmp; - } else { - return dns_rr_i_shuffle(a, b, i, P); - } -} /* dns_res_nameserv_cmp() */ - - -#define dgoto(sp, i) \ - do { R->stack[(sp)].state = (i); goto exec; } while (0) - -static int dns_res_exec(struct dns_resolver *R) { - struct dns_res_frame *F; - struct dns_packet *P; - char host[DNS_D_MAXNAME + 1]; - size_t len; - struct dns_rr rr; - struct sockaddr_in sin; - int error; - -exec: - - F = &R->stack[R->sp]; - - switch (F->state) { - case DNS_R_INIT: - F->state++; - case DNS_R_GLUE: - if (R->sp == 0) - dgoto(R->sp, DNS_R_SWITCH); - - if (!F->query) - goto noquery; - - if (!(F->answer = dns_res_glue(R, F->query))) - dgoto(R->sp, DNS_R_SWITCH); - - if (!(len = dns_d_expand(host, sizeof host, 12, F->query, &error))) - goto error; - else if (len >= sizeof host) - goto toolong; - - dns_rr_foreach(&rr, F->answer, .name = host, .type = dns_rr_type(12, F->query), .section = DNS_S_AN) { - dgoto(R->sp, DNS_R_FINISH); - } - - dns_rr_foreach(&rr, F->answer, .name = host, .type = DNS_T_CNAME, .section = DNS_S_AN) { - F->ans_cname = rr; - - dgoto(R->sp, DNS_R_CNAME0_A); - } - - F->state++; - case DNS_R_SWITCH: - while (F->which < (int)sizeof R->resconf->lookup && R->resconf->lookup[F->which]) { - switch (R->resconf->lookup[F->which++]) { - case 'b': case 'B': - dgoto(R->sp, DNS_R_BIND); - case 'f': case 'F': - dgoto(R->sp, DNS_R_FILE); - case 'c': case 'C': - if (R->cache) - dgoto(R->sp, DNS_R_CACHE); - - break; - default: - break; - } - } - - /* - * FIXME: Examine more closely whether our logic is correct - * and DNS_R_SERVFAIL is the correct default response. - * - * Case 1: We got here because we never got an answer on the - * wire. All queries timed-out and we reached maximum - * attempts count. See DNS_R_FOREACH_NS. In that case - * DNS_R_SERVFAIL is the correct state, unless we want to - * return DNS_ETIMEDOUT. - * - * Case 2: We were a stub resolver and got an unsatisfactory - * answer (empty ANSWER section) which caused us to jump - * back to DNS_R_SEARCH and ultimately to DNS_R_SWITCH. We - * return the answer returned from the wire, which we - * stashed in R->nodata. - * - * Case 3: We reached maximum attempts count as in case #1, - * but never got an authoritative response which caused us - * to short-circuit. See end of DNS_R_QUERY_A case. We - * should probably prepare R->nodata as in case #2. - */ - if (R->sp == 0 && R->nodata) { /* XXX: can we just return nodata regardless? */ - dns_p_movptr(&F->answer, &R->nodata); - dgoto(R->sp, DNS_R_FINISH); - } - - dgoto(R->sp, DNS_R_SERVFAIL); - case DNS_R_FILE: - if (R->sp > 0) { - if (!dns_p_setptr(&F->answer, dns_hosts_query(R->hosts, F->query, &error))) - goto error; - - if (dns_p_count(F->answer, DNS_S_AN) > 0) - dgoto(R->sp, DNS_R_FINISH); - - dns_p_setptr(&F->answer, NULL); - } else { - R->search = 0; - - while ((len = dns_resconf_search(host, sizeof host, R->qname, R->qlen, R->resconf, &R->search))) { -/* - * FIXME: Some sort of bug, either with this code or with GCC 3.3.5 on - * OpenBSD 4.4, overwites the stack guard. If the bug is in this file, it - * appears to be localized somewhere around here. It can also be mitigated - * in dns_hosts_query(). In any event, the bug manifests only when using - * compound literals. alloca(), malloc(), calloc(), etc, all work fine. - * Valgrind (tested on Linux) cannot detect any issues, but stack issues are - * not Valgrind's forte. Neither can I spot anything in the assembly, but - * that's not my forte. - */ -#if __OpenBSD__ && __GNUC__ - struct dns_packet *query = __builtin_alloca(DNS_P_QBUFSIZ); - - dns_p_init(query, DNS_P_QBUFSIZ); -#else - struct dns_packet *query = dns_p_new(DNS_P_QBUFSIZ); -#endif - - if ((error = dns_p_push(query, DNS_S_QD, host, len, R->qtype, R->qclass, 0, 0))) - goto error; - - if (!dns_p_setptr(&F->answer, dns_hosts_query(R->hosts, query, &error))) - goto error; - - if (dns_p_count(F->answer, DNS_S_AN) > 0) - dgoto(R->sp, DNS_R_FINISH); - - dns_p_setptr(&F->answer, NULL); - } - } - - dgoto(R->sp, DNS_R_SWITCH); - case DNS_R_CACHE: - error = 0; - - if (!F->query && !(F->query = dns_res_mkquery(R, R->qname, R->qtype, R->qclass, &error))) - goto error; - - if (dns_p_setptr(&F->answer, R->cache->query(F->query, R->cache, &error))) { - if (dns_p_count(F->answer, DNS_S_AN) > 0) - dgoto(R->sp, DNS_R_FINISH); - - dns_p_setptr(&F->answer, NULL); - - dgoto(R->sp, DNS_R_SWITCH); - } else if (error) - goto error; - - F->state++; - case DNS_R_SUBMIT: - if ((error = R->cache->submit(F->query, R->cache))) - goto error; - - F->state++; - case DNS_R_CHECK: - if ((error = R->cache->check(R->cache))) - goto error; - - F->state++; - case DNS_R_FETCH: - error = 0; - - if (dns_p_setptr(&F->answer, R->cache->fetch(R->cache, &error))) { - if (dns_p_count(F->answer, DNS_S_AN) > 0) - dgoto(R->sp, DNS_R_FINISH); - - dns_p_setptr(&F->answer, NULL); - - dgoto(R->sp, DNS_R_SWITCH); - } else if (error) - goto error; - - dgoto(R->sp, DNS_R_SWITCH); - case DNS_R_BIND: - if (R->sp > 0) { - if (!F->query) - goto noquery; - - dgoto(R->sp, DNS_R_HINTS); - } - - R->search = 0; - - F->state++; - case DNS_R_SEARCH: - /* - * XXX: We probably should only apply the domain search - * algorithm if R->sp == 0. - */ - if (!(len = dns_resconf_search(host, sizeof host, R->qname, R->qlen, R->resconf, &R->search))) - dgoto(R->sp, DNS_R_SWITCH); - - if (!(P = dns_p_make(DNS_P_QBUFSIZ, &error))) - goto error; - - dns_header(P)->rd = !R->resconf->options.recurse; - - dns_p_setptr(&F->query, P); - - if ((error = dns_p_push(F->query, DNS_S_QD, host, len, R->qtype, R->qclass, 0, 0))) - goto error; - - F->state++; - case DNS_R_HINTS: - if (!dns_p_setptr(&F->hints, dns_hints_query(R->hints, F->query, &error))) - goto error; - - F->state++; - case DNS_R_ITERATE: - dns_rr_i_init(&F->hints_i, F->hints); - - F->hints_i.section = DNS_S_AUTHORITY; - F->hints_i.type = DNS_T_NS; - F->hints_i.sort = &dns_res_nameserv_cmp; - F->hints_i.args[0] = F->hints->end; - - F->state++; - case DNS_R_FOREACH_NS: - dns_rr_i_save(&F->hints_i); - - /* Load our next nameserver host. */ - if (!dns_rr_grep(&F->hints_ns, 1, &F->hints_i, F->hints, &error)) { - if (++F->attempts < R->resconf->options.attempts) - dgoto(R->sp, DNS_R_ITERATE); - - dgoto(R->sp, DNS_R_SWITCH); - } - - dns_rr_i_init(&F->hints_j, F->hints); - - /* Assume there are glue records */ - dgoto(R->sp, DNS_R_FOREACH_A); - case DNS_R_RESOLV0_NS: - /* Have we reached our max depth? */ - if (&F[1] >= endof(R->stack)) - dgoto(R->sp, DNS_R_FOREACH_NS); - - dns_res_reset_frame(R, &F[1]); - - if (!(F[1].query = dns_p_make(DNS_P_QBUFSIZ, &error))) - goto error; - - if ((error = dns_ns_parse((struct dns_ns *)host, &F->hints_ns, F->hints))) - goto error; - - if ((error = dns_p_push(F[1].query, DNS_S_QD, host, strlen(host), DNS_T_A, DNS_C_IN, 0, 0))) - goto error; - - F->state++; - - dgoto(++R->sp, DNS_R_INIT); - case DNS_R_RESOLV1_NS: - if (!(len = dns_d_expand(host, sizeof host, 12, F[1].query, &error))) - goto error; - else if (len >= sizeof host) - goto toolong; - - dns_rr_foreach(&rr, F[1].answer, .name = host, .type = DNS_T_A, .section = (DNS_S_ALL & ~DNS_S_QD)) { - rr.section = DNS_S_AR; - - if ((error = dns_rr_copy(F->hints, &rr, F[1].answer))) - goto error; - - dns_rr_i_rewind(&F->hints_i); /* Now there's glue. */ - } - - dgoto(R->sp, DNS_R_FOREACH_NS); - case DNS_R_FOREACH_A: - /* - * NOTE: Iterator initialized in DNS_R_FOREACH_NS because - * this state is re-entrant, but we need to reset - * .name to a valid pointer each time. - */ - if ((error = dns_ns_parse((struct dns_ns *)host, &F->hints_ns, F->hints))) - goto error; - - F->hints_j.name = host; - F->hints_j.type = DNS_T_A; - F->hints_j.section = DNS_S_ALL & ~DNS_S_QD; - - if (!dns_rr_grep(&rr, 1, &F->hints_j, F->hints, &error)) { - if (!dns_rr_i_count(&F->hints_j)) - dgoto(R->sp, DNS_R_RESOLV0_NS); - - dgoto(R->sp, DNS_R_FOREACH_NS); - } - - sin.sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - sin.sin_len = dns_af_len(sin.sin_family); -#endif - - if ((error = dns_a_parse((struct dns_a *)&sin.sin_addr, &rr, F->hints))) - goto error; - - if (R->sp == 0) - sin.sin_port = dns_hints_port(R->hints, AF_INET, (struct sockaddr *)&sin.sin_addr); - else - sin.sin_port = htons(53); - - if (DNS_DEBUG) { - char addr[INET_ADDRSTRLEN + 1]; - dns_a_print(addr, sizeof addr, (struct dns_a *)&sin.sin_addr); - DNS_SHOW(F->query, "ASKING: %s/%s @ DEPTH: %u)", host, addr, R->sp); - } - - if ((error = dns_so_submit(&R->so, F->query, (struct sockaddr *)&sin))) - goto error; - - F->state++; - case DNS_R_QUERY_A: - if (dns_so_elapsed(&R->so) >= dns_resconf_timeout(R->resconf)) - dgoto(R->sp, DNS_R_FOREACH_A); - - if ((error = dns_so_check(&R->so))) - goto error; - - if (!dns_p_setptr(&F->answer, dns_so_fetch(&R->so, &error))) - goto error; - - if (DNS_DEBUG) { - DNS_SHOW(F->answer, "ANSWER @ DEPTH: %u)", R->sp); - } - - if ((error = dns_rr_parse(&rr, 12, F->query))) - goto error; - - if (!(len = dns_d_expand(host, sizeof host, rr.dn.p, F->query, &error))) - goto error; - else if (len >= sizeof host) - goto toolong; - - dns_rr_foreach(&rr, F->answer, .section = DNS_S_AN, .name = host, .type = rr.type) { - dgoto(R->sp, DNS_R_FINISH); /* Found */ - } - - dns_rr_foreach(&rr, F->answer, .section = DNS_S_AN, .name = host, .type = DNS_T_CNAME) { - F->ans_cname = rr; - - dgoto(R->sp, DNS_R_CNAME0_A); - } - - /* - * XXX: The condition here should probably check whether - * R->sp == 0, because DNS_R_SEARCH runs regardless of - * options.recurse. See DNS_R_BIND. - */ - if (!R->resconf->options.recurse) { - /* Make first answer our tentative answer */ - if (!R->nodata) - dns_p_movptr(&R->nodata, &F->answer); - - dgoto(R->sp, DNS_R_SEARCH); - } - - dns_rr_foreach(&rr, F->answer, .section = DNS_S_NS, .type = DNS_T_NS) { - dns_p_movptr(&F->hints, &F->answer); - - dgoto(R->sp, DNS_R_ITERATE); - } - - /* XXX: Should this go further up? */ - if (dns_header(F->answer)->aa) - dgoto(R->sp, DNS_R_FINISH); - - /* XXX: Should we copy F->answer to R->nodata? */ - - dgoto(R->sp, DNS_R_FOREACH_A); - case DNS_R_CNAME0_A: - if (&F[1] >= endof(R->stack)) - dgoto(R->sp, DNS_R_FINISH); - - if ((error = dns_cname_parse((struct dns_cname *)host, &F->ans_cname, F->answer))) - goto error; - - dns_res_reset_frame(R, &F[1]); - - if (!(F[1].query = dns_p_make(DNS_P_QBUFSIZ, &error))) - goto error; - - if ((error = dns_p_push(F[1].query, DNS_S_QD, host, strlen(host), dns_rr_type(12, F->query), DNS_C_IN, 0, 0))) - goto error; - - F->state++; - - dgoto(++R->sp, DNS_R_INIT); - case DNS_R_CNAME1_A: - if (!(P = dns_res_merge(F->answer, F[1].answer, &error))) - goto error; - - dns_p_setptr(&F->answer, P); - - dgoto(R->sp, DNS_R_FINISH); - case DNS_R_FINISH: - if (!F->answer) - goto noanswer; - - if (!R->resconf->options.smart || R->sp > 0) - dgoto(R->sp, DNS_R_DONE); - - R->smart.section = DNS_S_AN; - R->smart.type = R->qtype; - - dns_rr_i_init(&R->smart, F->answer); - - F->state++; - case DNS_R_SMART0_A: - if (&F[1] >= endof(R->stack)) - dgoto(R->sp, DNS_R_DONE); - - while (dns_rr_grep(&rr, 1, &R->smart, F->answer, &error)) { - union { - struct dns_ns ns; - struct dns_mx mx; - struct dns_srv srv; - } rd; - const char *qname; - enum dns_type qtype; - enum dns_class qclass; - - switch (rr.type) { - case DNS_T_NS: - if ((error = dns_ns_parse(&rd.ns, &rr, F->answer))) - goto error; - - qname = rd.ns.host; - qtype = DNS_T_A; - qclass = DNS_C_IN; - - break; - case DNS_T_MX: - if ((error = dns_mx_parse(&rd.mx, &rr, F->answer))) - goto error; - - qname = rd.mx.host; - qtype = DNS_T_A; - qclass = DNS_C_IN; - - break; - case DNS_T_SRV: - if ((error = dns_srv_parse(&rd.srv, &rr, F->answer))) - goto error; - - qname = rd.srv.target; - qtype = DNS_T_A; - qclass = DNS_C_IN; - - break; - default: - continue; - } /* switch() */ - - dns_res_reset_frame(R, &F[1]); - - if (!(F[1].query = dns_res_mkquery(R, qname, qtype, qclass, &error))) - goto error; - - F->state++; - - dgoto(++R->sp, DNS_R_INIT); - } /* while() */ - - /* - * NOTE: SMTP specification says to fallback to A record. - * - * XXX: Should we add a mock MX answer? - */ - if (R->qtype == DNS_T_MX && R->smart.state.count == 0) { - dns_res_reset_frame(R, &F[1]); - - if (!(F[1].query = dns_res_mkquery(R, R->qname, DNS_T_A, DNS_C_IN, &error))) - goto error; - - R->smart.state.count++; - F->state++; - - dgoto(++R->sp, DNS_R_INIT); - } - - dgoto(R->sp, DNS_R_DONE); - case DNS_R_SMART1_A: - if (!F[1].answer) - goto noanswer; - - /* - * FIXME: For CNAME chains (which are typically illegal in - * this context), we should rewrite the record host name - * to the original smart qname. All the user cares about - * is locating that A/AAAA record. - */ - dns_rr_foreach(&rr, F[1].answer, .section = DNS_S_AN, .type = DNS_T_A) { - rr.section = DNS_S_AR; - - if (dns_rr_exists(&rr, F[1].answer, F->answer)) - continue; - - while ((error = dns_rr_copy(F->answer, &rr, F[1].answer))) { - if (error != DNS_ENOBUFS) - goto error; - if ((error = dns_p_grow(&F->answer))) - goto error; - } - } - - dgoto(R->sp, DNS_R_SMART0_A); - case DNS_R_DONE: - if (!F->answer) - goto noanswer; - - if (R->sp > 0) - dgoto(--R->sp, F[-1].state); - - break; - case DNS_R_SERVFAIL: - if (!dns_p_setptr(&F->answer, dns_p_make(DNS_P_QBUFSIZ, &error))) - goto error; - - dns_header(F->answer)->qr = 1; - dns_header(F->answer)->rcode = DNS_RC_SERVFAIL; - - if ((error = dns_p_push(F->answer, DNS_S_QD, R->qname, strlen(R->qname), R->qtype, R->qclass, 0, 0))) - goto error; - - dgoto(R->sp, DNS_R_DONE); - default: - error = EINVAL; - - goto error; - } /* switch () */ - - return 0; -noquery: - error = DNS_ENOQUERY; - - goto error; -noanswer: - error = DNS_ENOANSWER; - - goto error; -toolong: - error = DNS_EILLEGAL; - - /* FALL THROUGH */ -error: - return error; -} /* dns_res_exec() */ - -#undef goto - - -void dns_res_clear(struct dns_resolver *R) { - switch (R->stack[R->sp].state) { - case DNS_R_CHECK: - R->cache->clear(R->cache); - break; - default: - dns_so_clear(&R->so); - break; - } -} /* dns_res_clear() */ - - -static int dns_res_events2(struct dns_resolver *R, enum dns_events type) { - int events; - - switch (R->stack[R->sp].state) { - case DNS_R_CHECK: - events = R->cache->events(R->cache); - - return (type == DNS_LIBEVENT)? DNS_POLL2EV(events) : events; - default: - return dns_so_events2(&R->so, type); - } -} /* dns_res_events2() */ - - -int dns_res_events(struct dns_resolver *R) { - return dns_res_events2(R, R->so.opts.events); -} /* dns_res_events() */ - - -int dns_res_pollfd(struct dns_resolver *R) { - switch (R->stack[R->sp].state) { - case DNS_R_CHECK: - return R->cache->pollfd(R->cache); - default: - return dns_so_pollfd(&R->so); - } -} /* dns_res_pollfd() */ - - -time_t dns_res_timeout(struct dns_resolver *R) { - time_t elapsed; - - switch (R->stack[R->sp].state) { -#if 0 - case DNS_R_QUERY_AAAA: -#endif - case DNS_R_QUERY_A: - elapsed = dns_so_elapsed(&R->so); - - if (elapsed <= dns_resconf_timeout(R->resconf)) - return R->resconf->options.timeout - elapsed; - - break; - default: - break; - } /* switch() */ - - /* - * NOTE: We're not in a pollable state, or the user code hasn't - * called dns_res_check properly. The calling code is probably - * broken. Put them into a slow-burn pattern. - */ - return 1; -} /* dns_res_timeout() */ - - -time_t dns_res_elapsed(struct dns_resolver *R) { - return dns_elapsed(&R->elapsed); -} /* dns_res_elapsed() */ - - -int dns_res_poll(struct dns_resolver *R, int timeout) { - return dns_poll(dns_res_pollfd(R), dns_res_events2(R, DNS_SYSPOLL), timeout); -} /* dns_res_poll() */ - - -int dns_res_submit2(struct dns_resolver *R, const char *qname, size_t qlen, enum dns_type qtype, enum dns_class qclass) { - dns_res_reset(R); - - /* Don't anchor; that can conflict with searchlist generation. */ - dns_d_init(R->qname, sizeof R->qname, qname, (R->qlen = qlen), 0); - - R->qtype = qtype; - R->qclass = qclass; - - dns_begin(&R->elapsed); - - return 0; -} /* dns_res_submit2() */ - - -int dns_res_submit(struct dns_resolver *R, const char *qname, enum dns_type qtype, enum dns_class qclass) { - return dns_res_submit2(R, qname, strlen(qname), qtype, qclass); -} /* dns_res_submit() */ - - -int dns_res_check(struct dns_resolver *R) { - int error; - - if (R->stack[0].state != DNS_R_DONE) { - if ((error = dns_res_exec(R))) - return error; - } - - return 0; -} /* dns_res_check() */ - - -struct dns_packet *dns_res_fetch(struct dns_resolver *R, int *error) { - struct dns_packet *answer; - - if (R->stack[0].state != DNS_R_DONE) { - *error = DNS_EUNKNOWN; - - return 0; - } - - if (!(answer = R->stack[0].answer)) { - *error = DNS_EFETCHED; - - return 0; - } - - R->stack[0].answer = 0; - - return answer; -} /* dns_res_fetch() */ - - -struct dns_packet *dns_res_query(struct dns_resolver *res, const char *qname, enum dns_type qtype, enum dns_class qclass, int timeout, int *error_) { - int error; - - if ((error = dns_res_submit(res, qname, qtype, qclass))) - goto error; - - while ((error = dns_res_check(res))) { - if (dns_res_elapsed(res) > timeout) - error = DNS_ETIMEDOUT; - - if (error != DNS_EAGAIN) - goto error; - - if ((error = dns_res_poll(res, 1))) - goto error; - } - - return dns_res_fetch(res, error_); -error: - *error_ = error; - - return 0; -} /* dns_res_query() */ - - -const struct dns_stat *dns_res_stat(struct dns_resolver *res) { - return dns_so_stat(&res->so); -} /* dns_res_stat() */ - - -void dns_res_sethints(struct dns_resolver *res, struct dns_hints *hints) { - dns_hints_acquire(hints); /* acquire first in case same hints object */ - dns_hints_close(res->hints); - res->hints = hints; -} /* dns_res_sethints() */ - - -/* - * A D D R I N F O R O U T I N E S - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -struct dns_addrinfo { - struct addrinfo hints; - struct dns_resolver *res; - - char qname[DNS_D_MAXNAME + 1]; - enum dns_type qtype; - unsigned short qport, port; - - struct dns_packet *answer; - struct dns_packet *glue; - - struct dns_rr_i i, g; - struct dns_rr rr; - - char cname[DNS_D_MAXNAME + 1]; - - int state; - int found; - - struct dns_stat st; -}; /* struct dns_addrinfo */ - - -static dns_error_t dns_ai_parseport(unsigned short *port, const char *serv, const struct addrinfo *hints) { - const char *cp = serv; - unsigned long n = 0; - - while (*cp >= '0' && *cp <= '9' && n < 65536) { - n *= 10; - n += *cp++ - '0'; - } - - if (*cp == '\0') { - if (cp == serv || n >= 65536) - return DNS_ESERVICE; - - *port = n; - - return 0; - } - - if (hints->ai_flags & AI_NUMERICSERV) - return DNS_ESERVICE; - - /* TODO: try getaddrinfo(NULL, serv, { .ai_flags = AI_NUMERICSERV }) */ - - return DNS_ESERVICE; -} /* dns_ai_parseport() */ - - -struct dns_addrinfo *dns_ai_open(const char *host, const char *serv, enum dns_type qtype, const struct addrinfo *hints, struct dns_resolver *res, int *error_) { - static const struct dns_addrinfo ai_initializer; - struct dns_addrinfo *ai; - int error; - - if (res) { - dns_res_acquire(res); - } else if (!(hints->ai_flags & AI_NUMERICHOST)) { - /* - * NOTE: it's assumed that *_error is set from a previous - * API function call, such as dns_res_stub(). Should change - * this semantic, but it's applied elsewhere, too. - */ - return NULL; - } - - if (!(ai = malloc(sizeof *ai))) - goto syerr; - - *ai = ai_initializer; - ai->hints = *hints; - - ai->res = res; - res = NULL; - - if (sizeof ai->qname <= dns_strlcpy(ai->qname, host, sizeof ai->qname)) - { error = ENAMETOOLONG; goto error; } - - ai->qtype = qtype; - ai->qport = 0; - - if (serv && (error = dns_ai_parseport(&ai->qport, serv, hints))) - goto error; - - ai->port = ai->qport; - - return ai; -syerr: - error = dns_syerr(); -error: - *error_ = error; - - dns_ai_close(ai); - dns_res_close(res); - - return NULL; -} /* dns_ai_open() */ - - -void dns_ai_close(struct dns_addrinfo *ai) { - if (!ai) - return; - - dns_res_close(ai->res); - - if (ai->answer != ai->glue) - dns_p_free(ai->glue); - - dns_p_free(ai->answer); - free(ai); -} /* dns_ai_close() */ - - -static int dns_ai_setent(struct addrinfo **ent, union dns_any *any, enum dns_type type, struct dns_addrinfo *ai) { - struct sockaddr *saddr; - struct sockaddr_in sin; - struct sockaddr_in6 sin6; - const char *cname; - size_t clen; - - switch (type) { - case DNS_T_A: - saddr = memset(&sin, '\0', sizeof sin); - - sin.sin_family = AF_INET; - sin.sin_port = htons(ai->port); -#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - sin.sin_len = dns_af_len(sin.sin_family); -#endif - - memcpy(&sin.sin_addr, any, sizeof sin.sin_addr); - - break; - case DNS_T_AAAA: - saddr = memset(&sin6, '\0', sizeof sin6); - - sin6.sin6_family = AF_INET6; - sin6.sin6_port = htons(ai->port); -#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - sin6.sin6_len = dns_af_len(sin6.sin6_family); -#endif - - memcpy(&sin6.sin6_addr, any, sizeof sin6.sin6_addr); - - break; - default: - return EINVAL; - } /* switch() */ - - if (ai->hints.ai_flags & AI_CANONNAME) { - cname = (*ai->cname)? ai->cname : ai->qname; - clen = strlen(cname); - } else { - cname = NULL; - clen = 0; - } - - if (!(*ent = malloc(sizeof **ent + dns_sa_len(saddr) + ((ai->hints.ai_flags & AI_CANONNAME)? clen + 1 : 0)))) - return dns_syerr(); - - memset(*ent, '\0', sizeof **ent); - - (*ent)->ai_family = saddr->sa_family; - (*ent)->ai_socktype = ai->hints.ai_socktype; - (*ent)->ai_protocol = ai->hints.ai_protocol; - - (*ent)->ai_addr = memcpy((unsigned char *)*ent + sizeof **ent, saddr, dns_sa_len(saddr)); - (*ent)->ai_addrlen = dns_sa_len(saddr); - - if (ai->hints.ai_flags & AI_CANONNAME) - (*ent)->ai_canonname = memcpy((unsigned char *)*ent + sizeof **ent + dns_sa_len(saddr), cname, clen + 1); - - ai->found++; - - return 0; -} /* dns_ai_setent() */ - - -enum dns_ai_state { - DNS_AI_S_INIT, - DNS_AI_S_NUMERIC, - DNS_AI_S_SUBMIT, - DNS_AI_S_CHECK, - DNS_AI_S_FETCH, - DNS_AI_S_FOREACH_I, - DNS_AI_S_FOREACH_G, - DNS_AI_S_SUBMIT_G, - DNS_AI_S_CHECK_G, - DNS_AI_S_FETCH_G, - DNS_AI_S_DONE, -}; /* enum dns_ai_state */ - -#define dns_ai_goto(which) do { ai->state = (which); goto exec; } while (0) - -int dns_ai_nextent(struct addrinfo **ent, struct dns_addrinfo *ai) { - struct dns_packet *ans, *glue; - struct dns_rr rr; - char qname[DNS_D_MAXNAME + 1]; - union dns_any any; - size_t len; - int error; - - *ent = 0; - -exec: - - switch (ai->state) { - case DNS_AI_S_INIT: - ai->state++; - case DNS_AI_S_NUMERIC: - if (1 == dns_inet_pton(AF_INET, ai->qname, &any.a)) { - ai->state = DNS_AI_S_DONE; - - return dns_ai_setent(ent, &any, DNS_T_A, ai); - } - - if (1 == dns_inet_pton(AF_INET6, ai->qname, &any.aaaa)) { - ai->state = DNS_AI_S_DONE; - - return dns_ai_setent(ent, &any, DNS_T_AAAA, ai); - } - - if (ai->hints.ai_flags & AI_NUMERICHOST) - dns_ai_goto(DNS_AI_S_DONE); - - ai->state++; - case DNS_AI_S_SUBMIT: - assert(ai->res); - - if ((error = dns_res_submit(ai->res, ai->qname, ai->qtype, DNS_C_IN))) - return error; - - ai->state++; - case DNS_AI_S_CHECK: - if ((error = dns_res_check(ai->res))) - return error; - - ai->state++; - case DNS_AI_S_FETCH: - if (!(ai->answer = dns_res_fetch(ai->res, &error))) - return error; - - if ((error = dns_p_study(ai->answer))) - return error; - - ai->glue = ai->answer; - - dns_rr_i_init(&ai->i, ai->answer); - - ai->i.section = DNS_S_AN; - ai->i.type = ai->qtype; - ai->i.sort = &dns_rr_i_order; - - ai->state++; - case DNS_AI_S_FOREACH_I: - /* Search generator may have changed our qname. */ - if (!(len = dns_d_expand(qname, sizeof qname, 12, ai->answer, &error))) - return error; - else if (len >= sizeof qname) - return DNS_EILLEGAL; - - if (!dns_d_cname(ai->cname, sizeof ai->cname, qname, strlen(qname), ai->answer, &error)) - return error; - - ai->i.name = ai->cname; - - if (!dns_rr_grep(&rr, 1, &ai->i, ai->answer, &error)) - dns_ai_goto(DNS_AI_S_DONE); - - if ((error = dns_any_parse(&any, &rr, ai->answer))) - return error; - - ai->port = ai->qport; - - switch (rr.type) { - case DNS_T_A: - case DNS_T_AAAA: - return dns_ai_setent(ent, &any, rr.type, ai); - default: - if (!dns_any_cname(ai->cname, sizeof ai->cname, &any, rr.type)) - dns_ai_goto(DNS_AI_S_FOREACH_I); - - /* - * Find the "real" canonical name. Some authorities - * publish aliases where an RFC defines a canonical - * name. We trust that the resolver followed any - * CNAME chains on it's own, regardless of whether - * the "smart" option is enabled. - */ - if (!dns_d_cname(ai->cname, sizeof ai->cname, ai->cname, strlen(ai->cname), ai->answer, &error)) - return error; - - if (rr.type == DNS_T_SRV) - ai->port = any.srv.port; - - break; - } /* switch() */ - - dns_rr_i_init(&ai->g, ai->glue); - - ai->g.section = DNS_S_ALL & ~DNS_S_QD; - ai->g.name = ai->cname; - ai->g.type = (ai->hints.ai_family == AF_INET6)? DNS_T_AAAA : DNS_T_A; - - ai->state++; - case DNS_AI_S_FOREACH_G: - if (!dns_rr_grep(&rr, 1, &ai->g, ai->glue, &error)) { - if (dns_rr_i_count(&ai->g) > 0) - dns_ai_goto(DNS_AI_S_FOREACH_I); - else - dns_ai_goto(DNS_AI_S_SUBMIT_G); - } - - if ((error = dns_any_parse(&any, &rr, ai->glue))) - return error; - - return dns_ai_setent(ent, &any, rr.type, ai); - case DNS_AI_S_SUBMIT_G: - if (dns_rr_grep(&rr, 1, dns_rr_i_new(ai->glue, .section = DNS_S_QD, .name = ai->g.name, .type = ai->g.type), ai->glue, &error)) - dns_ai_goto(DNS_AI_S_FOREACH_I); - - if ((error = dns_res_submit(ai->res, ai->g.name, ai->g.type, DNS_C_IN))) - return error; - - ai->state++; - case DNS_AI_S_CHECK_G: - if ((error = dns_res_check(ai->res))) - return error; - - ai->state++; - case DNS_AI_S_FETCH_G: - if (!(ans = dns_res_fetch(ai->res, &error))) - return error; - - dns_p_study(ans); - - glue = dns_p_merge(ai->glue, DNS_S_ALL, ans, DNS_S_ALL, &error); - - dns_p_free(ans); - - if (!glue) - return error; - - if (ai->glue != ai->answer) - dns_p_free(ai->glue); - - ai->glue = glue; - - dns_rr_i_init(&ai->g, ai->glue); - - /* ai->g.name should already point to ai->cname */ - if (!dns_d_cname(ai->cname, sizeof ai->cname, ai->cname, strlen(ai->cname), ai->glue, &error)) - dns_ai_goto(DNS_AI_S_FOREACH_I); - - /* NOTE: Keep all the other iterator filters */ - - dns_ai_goto(DNS_AI_S_FOREACH_G); - case DNS_AI_S_DONE: - if (ai->found) { - return ENOENT; /* TODO: Just return 0 */ - } else if (ai->answer) { - switch (dns_header(ai->answer)->rcode) { - case DNS_RC_NOERROR: - /* FALL THROUGH */ - case DNS_RC_NXDOMAIN: - return DNS_ENONAME; - default: - return DNS_EFAIL; - } - } else { - return DNS_EFAIL; - } - default: - return EINVAL; - } /* switch() */ -} /* dns_ai_nextent() */ - - -time_t dns_ai_elapsed(struct dns_addrinfo *ai) { - return (ai->res)? dns_res_elapsed(ai->res) : 0; -} /* dns_ai_elapsed() */ - - -void dns_ai_clear(struct dns_addrinfo *ai) { - if (ai->res) - dns_res_clear(ai->res); -} /* dns_ai_clear() */ - - -int dns_ai_events(struct dns_addrinfo *ai) { - return (ai->res)? dns_res_events(ai->res) : 0; -} /* dns_ai_events() */ - - -int dns_ai_pollfd(struct dns_addrinfo *ai) { - return (ai->res)? dns_res_pollfd(ai->res) : -1; -} /* dns_ai_pollfd() */ - - -time_t dns_ai_timeout(struct dns_addrinfo *ai) { - return (ai->res)? dns_res_timeout(ai->res) : 0; -} /* dns_ai_timeout() */ - - -int dns_ai_poll(struct dns_addrinfo *ai, int timeout) { - return (ai->res)? dns_res_poll(ai->res, timeout) : 0; -} /* dns_ai_poll() */ - - -size_t dns_ai_print(void *dst, size_t lim, struct addrinfo *ent, struct dns_addrinfo *ai) { - char addr[DNS_PP_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) + 1]; - size_t cp = 0; - - cp += dns__printstring(dst, lim, cp, "[ "); - cp += dns__printstring(dst, lim, cp, ai->qname); - cp += dns__printstring(dst, lim, cp, " IN "); - cp += dns__printstring(dst, lim, cp, dns_strtype(ai->qtype)); - cp += dns__printstring(dst, lim, cp, " ]\n"); - - cp += dns__printstring(dst, lim, cp, ".ai_family = "); - - switch (ent->ai_family) { - case AF_INET: - cp += dns__printstring(dst, lim, cp, "AF_INET"); - break; - case AF_INET6: - cp += dns__printstring(dst, lim, cp, "AF_INET6"); - break; - default: - cp += dns__print10(dst, lim, cp, ent->ai_family, 0); - break; - } - - cp += dns__printchar(dst, lim, cp, '\n'); - - cp += dns__printstring(dst, lim, cp, ".ai_socktype = "); - - switch (ent->ai_socktype) { - case SOCK_STREAM: - cp += dns__printstring(dst, lim, cp, "SOCK_STREAM"); - break; - case SOCK_DGRAM: - cp += dns__printstring(dst, lim, cp, "SOCK_DGRAM"); - break; - default: - cp += dns__print10(dst, lim, cp, ent->ai_socktype, 0); - break; - } - - cp += dns__printchar(dst, lim, cp, '\n'); - - cp += dns__printstring(dst, lim, cp, ".ai_addr = ["); - - dns_inet_ntop(dns_sa_family(ent->ai_addr), dns_sa_addr(dns_sa_family(ent->ai_addr), ent->ai_addr, NULL), addr, sizeof addr); - - cp += dns__printstring(dst, lim, cp, addr); - cp += dns__printstring(dst, lim, cp, "]:"); - - cp += dns__print10(dst, lim, cp, ntohs(*dns_sa_port(dns_sa_family(ent->ai_addr), ent->ai_addr)), 0); - cp += dns__printchar(dst, lim, cp, '\n'); - - cp += dns__printstring(dst, lim, cp, ".ai_canonname = "); - cp += dns__printstring(dst, lim, cp, (ent->ai_canonname)? ent->ai_canonname : "[NULL]"); - cp += dns__printchar(dst, lim, cp, '\n'); - - dns__printnul(dst, lim, cp); - - return cp; -} /* dns_ai_print() */ - - -const struct dns_stat *dns_ai_stat(struct dns_addrinfo *ai) { - return (ai->res)? dns_res_stat(ai->res) : &ai->st; -} /* dns_ai_stat() */ - - -/* - * M I S C E L L A N E O U S R O U T I N E S - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -static const struct { - char name[16]; - enum dns_section type; -} dns_sections[] = { - { "QUESTION", DNS_S_QUESTION }, - { "QD", DNS_S_QUESTION }, - { "ANSWER", DNS_S_ANSWER }, - { "AN", DNS_S_ANSWER }, - { "AUTHORITY", DNS_S_AUTHORITY }, - { "NS", DNS_S_AUTHORITY }, - { "ADDITIONAL", DNS_S_ADDITIONAL }, - { "AR", DNS_S_ADDITIONAL }, -}; - -const char *(dns_strsection)(enum dns_section section, void *dst, size_t lim) { - unsigned i, p = 0; - - for (i = 0; i < lengthof(dns_sections); i++) { - if (dns_sections[i].type & section) { - if (p > 0) - p += dns__printchar(dst, lim, p, '|'); - - p += dns__printstring(dst, lim, p, dns_sections[i].name); - - section &= ~dns_sections[i].type; - } - } - - if (!p) - p += dns__print10(dst, lim, 0, (0xffff & section), 0); - - dns__printnul(dst, lim, p); - - return dst; -} /* dns_strsection() */ - - -enum dns_section dns_isection(const char *src) { - enum dns_section section = 0; - char sbuf[128]; - char *name, *next; - unsigned i; - - dns_strlcpy(sbuf, src, sizeof sbuf); - next = sbuf; - - while ((name = dns_strsep(&next, "|+, \t"))) { - for (i = 0; i < lengthof(dns_sections); i++) { - if (!strcasecmp(dns_sections[i].name, name)) { - section |= dns_sections[i].type; - break; - } - } - } - - return section; -} /* dns_isection() */ - - -static const struct { - char name[8]; - enum dns_class type; -} dns_classes[] = { - { "IN", DNS_C_IN }, -}; - -const char *(dns_strclass)(enum dns_class type, void *dst, size_t lim) { - unsigned i; - - for (i = 0; i < lengthof(dns_classes); i++) { - if (dns_classes[i].type == type) { - dns__printnul(dst, lim, dns__printstring(dst, lim, 0, dns_classes[i].name)); - - return dst; - } - } - - dns__printnul(dst, lim, dns__print10(dst, lim, 0, (0xffff & type), 0)); - - return dst; -} /* dns_strclass() */ - - -enum dns_class dns_iclass(const char *name) { - unsigned i; - - for (i = 0; i < lengthof(dns_classes); i++) { - if (!strcasecmp(dns_classes[i].name, name)) - return dns_classes[i].type; - } - - return 0; -} /* dns_iclass() */ - - -const char *(dns_strtype)(enum dns_type type, void *dst, size_t lim) { - unsigned i; - - for (i = 0; i < lengthof(dns_rrtypes); i++) { - if (dns_rrtypes[i].type == type) { - dns__printnul(dst, lim, dns__printstring(dst, lim, 0, dns_rrtypes[i].name)); - - return dst; - } - } - - dns__printnul(dst, lim, dns__print10(dst, lim, 0, (0xffff & type), 0)); - - return dst; -} /* dns_strtype() */ - - -enum dns_type dns_itype(const char *type) { - unsigned i; - - for (i = 0; i < lengthof(dns_rrtypes); i++) { - if (!strcasecmp(dns_rrtypes[i].name, type)) - return dns_rrtypes[i].type; - } - - return 0; -} /* dns_itype() */ - - -static char dns_opcodes[16][16] = { - [DNS_OP_QUERY] = "QUERY", - [DNS_OP_IQUERY] = "IQUERY", - [DNS_OP_STATUS] = "STATUS", - [DNS_OP_NOTIFY] = "NOTIFY", - [DNS_OP_UPDATE] = "UPDATE", -}; - -const char *dns_stropcode(enum dns_opcode opcode) { - opcode &= 0xf; - - if ('\0' == dns_opcodes[opcode][0]) - dns__printnul(dns_opcodes[opcode], sizeof dns_opcodes[opcode], dns__print10(dns_opcodes[opcode], sizeof dns_opcodes[opcode], 0, opcode, 0)); - - return dns_opcodes[opcode]; -} /* dns_stropcode() */ - - -enum dns_opcode dns_iopcode(const char *name) { - unsigned opcode; - - for (opcode = 0; opcode < lengthof(dns_opcodes); opcode++) { - if (!strcasecmp(name, dns_opcodes[opcode])) - return opcode; - } - - return lengthof(dns_opcodes) - 1; -} /* dns_iopcode() */ - - -static char dns_rcodes[16][16] = { - [DNS_RC_NOERROR] = "NOERROR", - [DNS_RC_FORMERR] = "FORMERR", - [DNS_RC_SERVFAIL] = "SERVFAIL", - [DNS_RC_NXDOMAIN] = "NXDOMAIN", - [DNS_RC_NOTIMP] = "NOTIMP", - [DNS_RC_REFUSED] = "REFUSED", - [DNS_RC_YXDOMAIN] = "YXDOMAIN", - [DNS_RC_YXRRSET] = "YXRRSET", - [DNS_RC_NXRRSET] = "NXRRSET", - [DNS_RC_NOTAUTH] = "NOTAUTH", - [DNS_RC_NOTZONE] = "NOTZONE", -}; - -const char *dns_strrcode(enum dns_rcode rcode) { - rcode &= 0xf; - - if ('\0' == dns_rcodes[rcode][0]) - dns__printnul(dns_rcodes[rcode], sizeof dns_rcodes[rcode], dns__print10(dns_rcodes[rcode], sizeof dns_rcodes[rcode], 0, rcode, 0)); - - return dns_rcodes[rcode]; -} /* dns_strrcode() */ - - -enum dns_rcode dns_ircode(const char *name) { - unsigned rcode; - - for (rcode = 0; rcode < lengthof(dns_rcodes); rcode++) { - if (!strcasecmp(name, dns_rcodes[rcode])) - return rcode; - } - - return lengthof(dns_rcodes) - 1; -} /* dns_ircode() */ - - - -/* - * C O M M A N D - L I N E / R E G R E S S I O N R O U T I N E S - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#if DNS_MAIN - -#include -#include -#include - -#include - -#if _WIN32 -#include -#endif - -#if !_WIN32 -#include -#endif - - -struct { - struct { - const char *path[8]; - unsigned count; - } resconf, nssconf, hosts, cache; - - const char *qname; - enum dns_type qtype; - - int (*sort)(); - - int verbose; -} MAIN = { - .sort = &dns_rr_i_packet, -}; - - -void hexdump(const unsigned char *src, size_t len, FILE *fp) { - static const unsigned char hex[] = "0123456789abcdef"; - static const unsigned char tmpl[] = " | |\n"; - unsigned char ln[sizeof tmpl]; - const unsigned char *sp, *se; - unsigned char *h, *g; - unsigned i, n; - - sp = src; - se = sp + len; - - while (sp < se) { - memcpy(ln, tmpl, sizeof ln); - - h = &ln[2]; - g = &ln[53]; - - for (n = 0; n < 2; n++) { - for (i = 0; i < 8 && se - sp > 0; i++, sp++) { - h[0] = hex[0x0f & (*sp >> 4)]; - h[1] = hex[0x0f & (*sp >> 0)]; - h += 3; - - *g++ = (isgraph(*sp))? *sp : '.'; - } - - h++; - } - - fputs((char *)ln, fp); - } - - return /* void */; -} /* hexdump() */ - - -DNS_NORETURN static void panic(const char *fmt, ...) { - va_list ap; - - va_start(ap, fmt); - -#if _WIN32 - vfprintf(stderr, fmt, ap); - - exit(EXIT_FAILURE); -#else - verrx(EXIT_FAILURE, fmt, ap); -#endif -} /* panic() */ - -#define panic_(fn, ln, fmt, ...) \ - panic(fmt "%0s", (fn), (ln), __VA_ARGS__) -#define panic(...) \ - panic_(__func__, __LINE__, "(%s:%d) " __VA_ARGS__, "") - - -static void *grow(unsigned char *p, size_t size) { - void *tmp; - - if (!(tmp = realloc(p, size))) - panic("realloc(%"PRIuZ"): %s", size, dns_strerror(errno)); - - return tmp; -} /* grow() */ - - -static size_t add(size_t a, size_t b) { - if (~a < b) - panic("%"PRIuZ" + %"PRIuZ": integer overflow", a, b); - - return a + b; -} /* add() */ - - -static size_t append(unsigned char **dst, size_t osize, const void *src, size_t len) { - size_t size = add(osize, len); - - *dst = grow(*dst, size); - memcpy(*dst + osize, src, len); - - return size; -} /* append() */ - - -static size_t slurp(unsigned char **dst, size_t osize, FILE *fp, const char *path) { - size_t size = osize; - unsigned char buf[1024]; - size_t count; - - while ((count = fread(buf, 1, sizeof buf, fp))) - size = append(dst, size, buf, count); - - if (ferror(fp)) - panic("%s: %s", path, dns_strerror(errno)); - - return size; -} /* slurp() */ - - -static struct dns_resolv_conf *resconf(void) { - static struct dns_resolv_conf *resconf; - const char *path; - unsigned i; - int error; - - if (resconf) - return resconf; - - if (!(resconf = dns_resconf_open(&error))) - panic("dns_resconf_open: %s", dns_strerror(error)); - - if (!MAIN.resconf.count) - MAIN.resconf.path[MAIN.resconf.count++] = "/etc/resolv.conf"; - - for (i = 0; i < MAIN.resconf.count; i++) { - path = MAIN.resconf.path[i]; - - if (0 == strcmp(path, "-")) - error = dns_resconf_loadfile(resconf, stdin); - else - error = dns_resconf_loadpath(resconf, path); - - if (error) - panic("%s: %s", path, dns_strerror(error)); - } - - for (i = 0; i < MAIN.nssconf.count; i++) { - path = MAIN.nssconf.path[i]; - - if (0 == strcmp(path, "-")) - error = dns_nssconf_loadfile(resconf, stdin); - else - error = dns_nssconf_loadpath(resconf, path); - - if (error) - panic("%s: %s", path, dns_strerror(error)); - } - - if (!MAIN.nssconf.count) { - path = "/etc/nsswitch.conf"; - - if (!(error = dns_nssconf_loadpath(resconf, path))) - MAIN.nssconf.path[MAIN.nssconf.count++] = path; - else if (error != ENOENT) - panic("%s: %s", path, dns_strerror(error)); - } - - return resconf; -} /* resconf() */ - - -static struct dns_hosts *hosts(void) { - static struct dns_hosts *hosts; - const char *path; - unsigned i; - int error; - - if (hosts) - return hosts; - - if (!MAIN.hosts.count) { - MAIN.hosts.path[MAIN.hosts.count++] = "/etc/hosts"; - - /* Explicitly test dns_hosts_local() */ - if (!(hosts = dns_hosts_local(&error))) - panic("%s: %s", "/etc/hosts", dns_strerror(error)); - - return hosts; - } - - if (!(hosts = dns_hosts_open(&error))) - panic("dns_hosts_open: %s", dns_strerror(error)); - - for (i = 0; i < MAIN.hosts.count; i++) { - path = MAIN.hosts.path[i]; - - if (0 == strcmp(path, "-")) - error = dns_hosts_loadfile(hosts, stdin); - else - error = dns_hosts_loadpath(hosts, path); - - if (error) - panic("%s: %s", path, dns_strerror(error)); - } - - return hosts; -} /* hosts() */ - - -#if DNS_CACHE -#include "cache.h" - -struct dns_cache *cache(void) { - static struct cache *cache; - const char *path; - unsigned i; - int error; - - if (cache) - return cache_resi(cache); - if (!MAIN.cache.count) - return NULL; - - if (!(cache = cache_open(&error))) - panic("%s: %s", MAIN.cache.path[0], dns_strerror(error)); - - for (i = 0; i < MAIN.cache.count; i++) { - path = MAIN.cache.path[i]; - - if (!strcmp(path, "-")) { - if ((error = cache_loadfile(cache, stdin, NULL, 0))) - panic("%s: %s", path, dns_strerror(error)); - } else if ((error = cache_loadpath(cache, path, NULL, 0))) - panic("%s: %s", path, dns_strerror(error)); - } - - return cache_resi(cache); -} /* cache() */ -#else -struct dns_cache *cache(void) { return NULL; } -#endif - - -static void print_packet(struct dns_packet *P, FILE *fp) { - dns_p_dump3(P, dns_rr_i_new(P, .sort = MAIN.sort), fp); - - if (MAIN.verbose > 2) - hexdump(P->data, P->end, fp); -} /* print_packet() */ - - -static int parse_packet(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) { - struct dns_packet *P = dns_p_new(512); - struct dns_packet *Q = dns_p_new(512); - enum dns_section section; - struct dns_rr rr; - int error; - union dns_any any; - char pretty[sizeof any * 2]; - size_t len; - - P->end = fread(P->data, 1, P->size, stdin); - - fputs(";; [HEADER]\n", stdout); - fprintf(stdout, ";; qr : %s(%d)\n", (dns_header(P)->qr)? "RESPONSE" : "QUERY", dns_header(P)->qr); - fprintf(stdout, ";; opcode : %s(%d)\n", dns_stropcode(dns_header(P)->opcode), dns_header(P)->opcode); - fprintf(stdout, ";; aa : %s(%d)\n", (dns_header(P)->aa)? "AUTHORITATIVE" : "NON-AUTHORITATIVE", dns_header(P)->aa); - fprintf(stdout, ";; tc : %s(%d)\n", (dns_header(P)->tc)? "TRUNCATED" : "NOT-TRUNCATED", dns_header(P)->tc); - fprintf(stdout, ";; rd : %s(%d)\n", (dns_header(P)->rd)? "RECURSION-DESIRED" : "RECURSION-NOT-DESIRED", dns_header(P)->rd); - fprintf(stdout, ";; ra : %s(%d)\n", (dns_header(P)->ra)? "RECURSION-ALLOWED" : "RECURSION-NOT-ALLOWED", dns_header(P)->ra); - fprintf(stdout, ";; rcode : %s(%d)\n", dns_strrcode(dns_header(P)->rcode), dns_header(P)->rcode); - - section = 0; - - dns_rr_foreach(&rr, P, .sort = MAIN.sort) { - if (section != rr.section) - fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(P, rr.section)); - - if ((len = dns_rr_print(pretty, sizeof pretty, &rr, P, &error))) - fprintf(stdout, "%s\n", pretty); - - dns_rr_copy(Q, &rr, P); - - section = rr.section; - } - - fputs("; ; ; ; ; ; ; ;\n\n", stdout); - - section = 0; - -#if 0 - dns_rr_foreach(&rr, Q, .name = "ns8.yahoo.com.") { -#else - struct dns_rr rrset[32]; - struct dns_rr_i *rri = dns_rr_i_new(Q, .name = dns_d_new("ns8.yahoo.com", DNS_D_ANCHOR), .sort = MAIN.sort); - unsigned rrcount = dns_rr_grep(rrset, lengthof(rrset), rri, Q, &error); - - for (unsigned i = 0; i < rrcount; i++) { - rr = rrset[i]; -#endif - if (section != rr.section) - fprintf(stdout, "\n;; [%s:%d]\n", dns_strsection(rr.section), dns_p_count(Q, rr.section)); - - if ((len = dns_rr_print(pretty, sizeof pretty, &rr, Q, &error))) - fprintf(stdout, "%s\n", pretty); - - section = rr.section; - } - - if (MAIN.verbose > 1) { - fprintf(stderr, "orig:%"PRIuZ"\n", P->end); - hexdump(P->data, P->end, stdout); - - fprintf(stderr, "copy:%"PRIuZ"\n", Q->end); - hexdump(Q->data, Q->end, stdout); - } - - return 0; -} /* parse_packet() */ - - -static int parse_domain(int argc, char *argv[]) { - char *dn; - - dn = (argc > 1)? argv[1] : "f.l.google.com"; - - printf("[%s]\n", dn); - - dn = dns_d_new(dn); - - do { - puts(dn); - } while (dns_d_cleave(dn, strlen(dn) + 1, dn, strlen(dn))); - - return 0; -} /* parse_domain() */ - - -static int trim_domain(int argc, char **argv) { - for (argc--, argv++; argc > 0; argc--, argv++) { - char name[DNS_D_MAXNAME + 1]; - - dns_d_trim(name, sizeof name, *argv, strlen(*argv), DNS_D_ANCHOR); - - puts(name); - } - - return 0; -} /* trim_domain() */ - - -static int expand_domain(int argc, char *argv[]) { - unsigned short rp = 0; - unsigned char *src = NULL; - unsigned char *dst; - struct dns_packet *pkt; - size_t lim = 0, len; - int error; - - if (argc > 1) - rp = atoi(argv[1]); - - len = slurp(&src, 0, stdin, "-"); - - if (!(pkt = dns_p_make(len, &error))) - panic("malloc(%"PRIuZ"): %s", len, dns_strerror(error)); - - memcpy(pkt->data, src, len); - pkt->end = len; - - lim = 1; - dst = grow(NULL, lim); - - while (lim <= (len = dns_d_expand(dst, lim, rp, pkt, &error))) { - lim = add(len, 1); - dst = grow(dst, lim); - } - - if (!len) - panic("expand: %s", dns_strerror(error)); - - fwrite(dst, 1, len, stdout); - fflush(stdout); - - free(src); - free(dst); - free(pkt); - - return 0; -} /* expand_domain() */ - - -static int show_resconf(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) { - unsigned i; - - resconf(); /* load it */ - - fputs("; SOURCES\n", stdout); - - for (i = 0; i < MAIN.resconf.count; i++) - fprintf(stdout, "; %s\n", MAIN.resconf.path[i]); - - for (i = 0; i < MAIN.nssconf.count; i++) - fprintf(stdout, "; %s\n", MAIN.nssconf.path[i]); - - fputs(";\n", stdout); - - dns_resconf_dump(resconf(), stdout); - - return 0; -} /* show_resconf() */ - - -static int show_nssconf(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) { - unsigned i; - - resconf(); - - fputs("# SOURCES\n", stdout); - - for (i = 0; i < MAIN.resconf.count; i++) - fprintf(stdout, "# %s\n", MAIN.resconf.path[i]); - - for (i = 0; i < MAIN.nssconf.count; i++) - fprintf(stdout, "# %s\n", MAIN.nssconf.path[i]); - - fputs("#\n", stdout); - - dns_nssconf_dump(resconf(), stdout); - - return 0; -} /* show_nssconf() */ - - -static int show_hosts(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) { - unsigned i; - - hosts(); - - fputs("# SOURCES\n", stdout); - - for (i = 0; i < MAIN.hosts.count; i++) - fprintf(stdout, "# %s\n", MAIN.hosts.path[i]); - - fputs("#\n", stdout); - - dns_hosts_dump(hosts(), stdout); - - return 0; -} /* show_hosts() */ - - -static int query_hosts(int argc, char *argv[]) { - struct dns_packet *Q = dns_p_new(512); - struct dns_packet *A; - char qname[DNS_D_MAXNAME + 1]; - size_t qlen; - int error; - - if (!MAIN.qname) - MAIN.qname = (argc > 1)? argv[1] : "localhost"; - if (!MAIN.qtype) - MAIN.qtype = DNS_T_A; - - hosts(); - - if (MAIN.qtype == DNS_T_PTR && !strstr(MAIN.qname, "arpa")) { - union { struct in_addr a; struct in6_addr a6; } addr; - int af = (strchr(MAIN.qname, ':'))? AF_INET6 : AF_INET; - - if ((error = dns_pton(af, MAIN.qname, &addr))) - panic("%s: %s", MAIN.qname, dns_strerror(error)); - - qlen = dns_ptr_qname(qname, sizeof qname, af, &addr); - } else - qlen = dns__printstring(qname, sizeof qname, 0, MAIN.qname); - - if ((error = dns_p_push(Q, DNS_S_QD, qname, qlen, MAIN.qtype, DNS_C_IN, 0, 0))) - panic("%s: %s", qname, dns_strerror(error)); - - if (!(A = dns_hosts_query(hosts(), Q, &error))) - panic("%s: %s", qname, dns_strerror(error)); - - print_packet(A, stdout); - - free(A); - - return 0; -} /* query_hosts() */ - - -static int search_list(int argc, char *argv[]) { - const char *qname = (argc > 1)? argv[1] : "f.l.google.com"; - unsigned long i = 0; - char name[DNS_D_MAXNAME + 1]; - - printf("[%s]\n", qname); - - while (dns_resconf_search(name, sizeof name, qname, strlen(qname), resconf(), &i)) - puts(name); - - return 0; -} /* search_list() */ - - -int permute_set(int argc, char *argv[]) { - unsigned lo, hi, i; - struct dns_k_permutor p; - - hi = (--argc > 0)? atoi(argv[argc]) : 8; - lo = (--argc > 0)? atoi(argv[argc]) : 0; - - fprintf(stderr, "[%u .. %u]\n", lo, hi); - - dns_k_permutor_init(&p, lo, hi); - - for (i = lo; i <= hi; i++) - fprintf(stdout, "%u\n", dns_k_permutor_step(&p)); -// printf("%u -> %u -> %u\n", i, dns_k_permutor_E(&p, i), dns_k_permutor_D(&p, dns_k_permutor_E(&p, i))); - - return 0; -} /* permute_set() */ - - -int shuffle_16(int argc, char *argv[]) { - unsigned n, r; - - if (--argc > 0) { - n = 0xffff & atoi(argv[argc]); - r = (--argc > 0)? (unsigned)atoi(argv[argc]) : dns_random(); - - fprintf(stdout, "%hu\n", dns_k_shuffle16(n, r)); - } else { - r = dns_random(); - - for (n = 0; n < 65536; n++) - fprintf(stdout, "%hu\n", dns_k_shuffle16(n, r)); - } - - return 0; -} /* shuffle_16() */ - - -int dump_random(int argc, char *argv[]) { - unsigned char b[32]; - unsigned i, j, n, r; - - n = (argc > 1)? atoi(argv[1]) : 32; - - while (n) { - i = 0; - - do { - r = dns_random(); - - for (j = 0; j < sizeof r && i < n && i < sizeof b; i++, j++) { - b[i] = 0xff & r; - r >>= 8; - } - } while (i < n && i < sizeof b); - - hexdump(b, i, stdout); - - n -= i; - } - - return 0; -} /* dump_random() */ - - -static int send_query(int argc, char *argv[]) { - struct dns_packet *A, *Q = dns_p_new(512); - char host[INET6_ADDRSTRLEN + 1]; - struct sockaddr_storage ss; - struct dns_socket *so; - int error, type; - - if (argc > 1) { - ss.ss_family = (strchr(argv[1], ':'))? AF_INET6 : AF_INET; - - if ((error = dns_pton(ss.ss_family, argv[1], dns_sa_addr(ss.ss_family, &ss, NULL)))) - panic("%s: %s", argv[1], dns_strerror(error)); - - *dns_sa_port(ss.ss_family, &ss) = htons(53); - } else - memcpy(&ss, &resconf()->nameserver[0], dns_sa_len(&resconf()->nameserver[0])); - - if (!dns_inet_ntop(ss.ss_family, dns_sa_addr(ss.ss_family, &ss, NULL), host, sizeof host)) - panic("bad host address, or none provided"); - - if (!MAIN.qname) - MAIN.qname = "ipv6.google.com"; - if (!MAIN.qtype) - MAIN.qtype = DNS_T_AAAA; - - if ((error = dns_p_push(Q, DNS_S_QD, MAIN.qname, strlen(MAIN.qname), MAIN.qtype, DNS_C_IN, 0, 0))) - panic("dns_p_push: %s", dns_strerror(error)); - - dns_header(Q)->rd = 1; - - if (strstr(argv[0], "udp")) - type = SOCK_DGRAM; - else if (strstr(argv[0], "tcp")) - type = SOCK_STREAM; - else - type = dns_res_tcp2type(resconf()->options.tcp); - - fprintf(stderr, "querying %s for %s IN %s\n", host, MAIN.qname, dns_strtype(MAIN.qtype)); - - if (!(so = dns_so_open((struct sockaddr *)&resconf()->iface, type, dns_opts(), &error))) - panic("dns_so_open: %s", dns_strerror(error)); - - while (!(A = dns_so_query(so, Q, (struct sockaddr *)&ss, &error))) { - if (error != DNS_EAGAIN) - panic("dns_so_query: %s (%d)", dns_strerror(error), error); - if (dns_so_elapsed(so) > 10) - panic("query timed-out"); - - dns_so_poll(so, 1); - } - - print_packet(A, stdout); - - dns_so_close(so); - - return 0; -} /* send_query() */ - - -static int print_arpa(int argc, char *argv[]) { - const char *ip = (argc > 1)? argv[1] : "::1"; - int af = (strchr(ip, ':'))? AF_INET6 : AF_INET; - union { struct in_addr a4; struct in6_addr a6; } addr; - char host[DNS_D_MAXNAME + 1]; - - if (1 != dns_inet_pton(af, ip, &addr) || 0 == dns_ptr_qname(host, sizeof host, af, &addr)) - panic("%s: invalid address", ip); - - fprintf(stdout, "%s\n", host); - - return 0; -} /* print_arpa() */ - - -static int show_hints(int argc, char *argv[]) { - struct dns_hints *(*load)(struct dns_resolv_conf *, int *); - const char *which, *how, *who; - struct dns_hints *hints; - int error; - - which = (argc > 1)? argv[1] : "local"; - how = (argc > 2)? argv[2] : "plain"; - who = (argc > 3)? argv[3] : "google.com"; - - load = (0 == strcmp(which, "local")) - ? &dns_hints_local - : &dns_hints_root; - - if (!(hints = load(resconf(), &error))) - panic("%s: %s", argv[0], dns_strerror(error)); - - if (0 == strcmp(how, "plain")) { - dns_hints_dump(hints, stdout); - } else { - struct dns_packet *query, *answer; - - query = dns_p_new(512); - - if ((error = dns_p_push(query, DNS_S_QUESTION, who, strlen(who), DNS_T_A, DNS_C_IN, 0, 0))) - panic("%s: %s", who, dns_strerror(error)); - - if (!(answer = dns_hints_query(hints, query, &error))) - panic("%s: %s", who, dns_strerror(error)); - - print_packet(answer, stdout); - - free(answer); - } - - dns_hints_close(hints); - - return 0; -} /* show_hints() */ - - -static int resolve_query(int argc DNS_NOTUSED, char *argv[]) { - _Bool recurse = !!strstr(argv[0], "recurse"); - struct dns_hints *(*hints)() = (recurse)? &dns_hints_root : &dns_hints_local; - struct dns_resolver *R; - struct dns_packet *ans; - const struct dns_stat *st; - int error; - - if (!MAIN.qname) - MAIN.qname = "www.google.com"; - if (!MAIN.qtype) - MAIN.qtype = DNS_T_A; - - resconf()->options.recurse = recurse; - - if (!(R = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(), dns_opts(), &error))) - panic("%s: %s", MAIN.qname, dns_strerror(error)); - - if ((error = dns_res_submit(R, MAIN.qname, MAIN.qtype, DNS_C_IN))) - panic("%s: %s", MAIN.qname, dns_strerror(error)); - - while ((error = dns_res_check(R))) { - if (error != DNS_EAGAIN) - panic("dns_res_check: %s (%d)", dns_strerror(error), error); - if (dns_res_elapsed(R) > 30) - panic("query timed-out"); - - dns_res_poll(R, 1); - } - - ans = dns_res_fetch(R, &error); - print_packet(ans, stdout); - free(ans); - - st = dns_res_stat(R); - putchar('\n'); - printf(";; queries: %"PRIuZ"\n", st->queries); - printf(";; udp sent: %"PRIuZ" in %"PRIuZ" bytes\n", st->udp.sent.count, st->udp.sent.bytes); - printf(";; udp rcvd: %"PRIuZ" in %"PRIuZ" bytes\n", st->udp.rcvd.count, st->udp.rcvd.bytes); - printf(";; tcp sent: %"PRIuZ" in %"PRIuZ" bytes\n", st->tcp.sent.count, st->tcp.sent.bytes); - printf(";; tcp rcvd: %"PRIuZ" in %"PRIuZ" bytes\n", st->tcp.rcvd.count, st->tcp.rcvd.bytes); - - dns_res_close(R); - - return 0; -} /* resolve_query() */ - - -static int resolve_addrinfo(int argc DNS_NOTUSED, char *argv[]) { - _Bool recurse = !!strstr(argv[0], "recurse"); - struct dns_hints *(*hints)() = (recurse)? &dns_hints_root : &dns_hints_local; - struct dns_resolver *res = NULL; - struct dns_addrinfo *ai = NULL; - struct addrinfo ai_hints = { .ai_family = PF_UNSPEC, .ai_socktype = SOCK_STREAM, .ai_flags = AI_CANONNAME }; - struct addrinfo *ent; - char pretty[512]; - int error; - - if (!MAIN.qname) - MAIN.qname = "www.google.com"; - if (!MAIN.qtype) - MAIN.qtype = DNS_T_A; - - resconf()->options.recurse = recurse; - - if (!(res = dns_res_open(resconf(), hosts(), dns_hints_mortal(hints(resconf(), &error)), cache(), dns_opts(), &error))) - panic("%s: %s", MAIN.qname, dns_strerror(error)); - - if (!(ai = dns_ai_open(MAIN.qname, "80", MAIN.qtype, &ai_hints, res, &error))) - panic("%s: %s", MAIN.qname, dns_strerror(error)); - - do { - switch (error = dns_ai_nextent(&ent, ai)) { - case 0: - dns_ai_print(pretty, sizeof pretty, ent, ai); - - fputs(pretty, stdout); - - free(ent); - - break; - case ENOENT: - break; - case DNS_EAGAIN: - if (dns_ai_elapsed(ai) > 30) - panic("query timed-out"); - - dns_ai_poll(ai, 1); - - break; - default: - panic("dns_ai_nextent: %s (%d)", dns_strerror(error), error); - } - } while (error != ENOENT); - - dns_res_close(res); - dns_ai_close(ai); - - return 0; -} /* resolve_addrinfo() */ - - -static int echo_port(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) { - union { - struct sockaddr sa; - struct sockaddr_in sin; - } port; - int fd; - - memset(&port, 0, sizeof port); - port.sin.sin_family = AF_INET; - port.sin.sin_port = htons(5354); - port.sin.sin_addr.s_addr = inet_addr("127.0.0.1"); -#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - port.sin.sin_len = dns_af_len(port.sin.sin_family); -#endif - - if (-1 == (fd = socket(PF_INET, SOCK_DGRAM, 0))) - panic("socket: %s", strerror(errno)); - - if (0 != bind(fd, &port.sa, sizeof port.sa)) - panic("127.0.0.1:5353: %s", dns_strerror(errno)); - - for (;;) { - struct dns_packet *pkt = dns_p_new(512); - struct sockaddr_storage ss; - socklen_t slen = sizeof ss; - ssize_t count; -#if defined(MSG_WAITALL) /* MinGW issue */ - int rflags = MSG_WAITALL; -#else - int rflags = 0; -#endif - - count = recvfrom(fd, (char *)pkt->data, pkt->size, rflags, (struct sockaddr *)&ss, &slen); - - if (!count || count < 0) - panic("recvfrom: %s", strerror(errno)); - - pkt->end = count; - - dns_p_dump(pkt, stdout); - - (void)sendto(fd, (char *)pkt->data, pkt->end, 0, (struct sockaddr *)&ss, slen); - } - - return 0; -} /* echo_port() */ - - -static int isection(int argc, char *argv[]) { - const char *name = (argc > 1)? argv[1] : ""; - int type; - - type = dns_isection(name); - name = dns_strsection(type); - - printf("%s (%d)\n", name, type); - - return 0; -} /* isection() */ - - -static int iclass(int argc, char *argv[]) { - const char *name = (argc > 1)? argv[1] : ""; - int type; - - type = dns_iclass(name); - name = dns_strclass(type); - - printf("%s (%d)\n", name, type); - - return 0; -} /* iclass() */ - - -static int itype(int argc, char *argv[]) { - const char *name = (argc > 1)? argv[1] : ""; - int type; - - type = dns_itype(name); - name = dns_strtype(type); - - printf("%s (%d)\n", name, type); - - return 0; -} /* itype() */ - - -static int iopcode(int argc, char *argv[]) { - const char *name = (argc > 1)? argv[1] : ""; - int type; - - type = dns_iopcode(name); - name = dns_stropcode(type); - - printf("%s (%d)\n", name, type); - - return 0; -} /* iopcode() */ - - -static int ircode(int argc, char *argv[]) { - const char *name = (argc > 1)? argv[1] : ""; - int type; - - type = dns_ircode(name); - name = dns_strrcode(type); - - printf("%s (%d)\n", name, type); - - return 0; -} /* ircode() */ - - -#define SIZE1(x) { DNS_PP_STRINGIFY(x), sizeof (x) } -#define SIZE2(x, ...) SIZE1(x), SIZE1(__VA_ARGS__) -#define SIZE3(x, ...) SIZE1(x), SIZE2(__VA_ARGS__) -#define SIZE4(x, ...) SIZE1(x), SIZE3(__VA_ARGS__) -#define SIZE(...) DNS_PP_CALL(DNS_PP_XPASTE(SIZE, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__) - -static int sizes(int argc DNS_NOTUSED, char *argv[] DNS_NOTUSED) { - static const struct { const char *name; size_t size; } type[] = { - SIZE(struct dns_header, struct dns_packet, struct dns_rr, struct dns_rr_i), - SIZE(struct dns_a, struct dns_aaaa, struct dns_mx, struct dns_ns), - SIZE(struct dns_cname, struct dns_soa, struct dns_ptr, struct dns_srv), - SIZE(struct dns_sshfp, struct dns_txt, union dns_any), - SIZE(struct dns_resolv_conf, struct dns_hosts, struct dns_hints, struct dns_hints_i), - SIZE(struct dns_options, struct dns_socket, struct dns_resolver, struct dns_addrinfo), - SIZE(struct dns_cache), SIZE(size_t), SIZE(void *), SIZE(long) - }; - unsigned i, max; - - for (i = 0, max = 0; i < lengthof(type); i++) - max = DNS_PP_MAX(max, strlen(type[i].name)); - - for (i = 0; i < lengthof(type); i++) - printf("%*s : %"PRIuZ"\n", max, type[i].name, type[i].size); - - return 0; -} /* sizes() */ - - -static const struct { const char *cmd; int (*run)(); const char *help; } cmds[] = { - { "parse-packet", &parse_packet, "parse binary packet from stdin" }, - { "parse-domain", &parse_domain, "anchor and iteratively cleave domain" }, - { "trim-domain", &trim_domain, "trim and anchor domain name" }, - { "expand-domain", &expand_domain, "expand domain at offset NN in packet from stdin" }, - { "show-resconf", &show_resconf, "show resolv.conf data" }, - { "show-hosts", &show_hosts, "show hosts data" }, - { "show-nssconf", &show_nssconf, "show nsswitch.conf data" }, - { "query-hosts", &query_hosts, "query A, AAAA or PTR in hosts data" }, - { "search-list", &search_list, "generate query search list from domain" }, - { "permute-set", &permute_set, "generate random permutation -> (0 .. N or N .. M)" }, - { "shuffle-16", &shuffle_16, "simple 16-bit permutation" }, - { "dump-random", &dump_random, "generate random bytes" }, - { "send-query", &send_query, "send query to host" }, - { "send-query-udp", &send_query, "send udp query to host" }, - { "send-query-tcp", &send_query, "send tcp query to host" }, - { "print-arpa", &print_arpa, "print arpa. zone name of address" }, - { "show-hints", &show_hints, "print hints: show-hints [local|root] [plain|packet]" }, - { "resolve-stub", &resolve_query, "resolve as stub resolver" }, - { "resolve-recurse", &resolve_query, "resolve as recursive resolver" }, - { "addrinfo-stub", &resolve_addrinfo, "resolve through getaddrinfo clone" }, - { "addrinfo-recurse", &resolve_addrinfo, "resolve through getaddrinfo clone" }, -/* { "resolve-nameinfo", &resolve_query, "resolve as recursive resolver" }, */ - { "echo", &echo_port, "server echo mode, for nmap fuzzing" }, - { "isection", &isection, "parse section string" }, - { "iclass", &iclass, "parse class string" }, - { "itype", &itype, "parse type string" }, - { "iopcode", &iopcode, "parse opcode string" }, - { "ircode", &ircode, "parse rcode string" }, - { "sizes", &sizes, "print data structure sizes" }, -}; - - -static void print_usage(const char *progname, FILE *fp) { - static const char *usage = - " [OPTIONS] COMMAND [ARGS]\n" - " -c PATH Path to resolv.conf\n" - " -n PATH Path to nsswitch.conf\n" - " -l PATH Path to local hosts\n" - " -z PATH Path to zone cache\n" - " -q QNAME Query name\n" - " -t QTYPE Query type\n" - " -s HOW Sort records\n" - " -v Be more verbose (-vv show packets; -vvv hexdump packets)\n" - " -V Print version info\n" - " -h Print this usage message\n" - "\n"; - unsigned i, n, m; - - fputs(progname, fp); - fputs(usage, fp); - - for (i = 0, m = 0; i < lengthof(cmds); i++) { - if (strlen(cmds[i].cmd) > m) - m = strlen(cmds[i].cmd); - } - - for (i = 0; i < lengthof(cmds); i++) { - fprintf(fp, " %s ", cmds[i].cmd); - - for (n = strlen(cmds[i].cmd); n < m; n++) - putc(' ', fp); - - fputs(cmds[i].help, fp); - putc('\n', fp); - } - - fputs("\nReport bugs to William Ahern \n", fp); -} /* print_usage() */ - - -static void print_version(const char *progname, FILE *fp) { - fprintf(fp, "%s (dns.c) %.8X\n", progname, dns_v_rel()); - fprintf(fp, "vendor %s\n", dns_vendor()); - fprintf(fp, "release %.8X\n", dns_v_rel()); - fprintf(fp, "abi %.8X\n", dns_v_abi()); - fprintf(fp, "api %.8X\n", dns_v_api()); -} /* print_version() */ - - -int main(int argc, char **argv) { - extern int optind; - extern char *optarg; - const char *progname = argv[0]; - unsigned i; - int ch; - - while (-1 != (ch = getopt(argc, argv, "q:t:c:n:l:z:s:vVh"))) { - switch (ch) { - case 'c': - assert(MAIN.resconf.count < lengthof(MAIN.resconf.path)); - - MAIN.resconf.path[MAIN.resconf.count++] = optarg; - - break; - case 'n': - assert(MAIN.nssconf.count < lengthof(MAIN.nssconf.path)); - - MAIN.nssconf.path[MAIN.nssconf.count++] = optarg; - - break; - case 'l': - assert(MAIN.hosts.count < lengthof(MAIN.hosts.path)); - - MAIN.hosts.path[MAIN.hosts.count++] = optarg; - - break; - case 'z': - assert(MAIN.cache.count < lengthof(MAIN.cache.path)); - - MAIN.cache.path[MAIN.cache.count++] = optarg; - - break; - case 'q': - MAIN.qname = optarg; - - break; - case 't': - for (i = 0; i < lengthof(dns_rrtypes); i++) { - if (0 == strcasecmp(dns_rrtypes[i].name, optarg)) - { MAIN.qtype = dns_rrtypes[i].type; break; } - } - - if (MAIN.qtype) - break; - - for (i = 0; isdigit((int)optarg[i]); i++) { - MAIN.qtype *= 10; - MAIN.qtype += optarg[i] - '0'; - } - - if (!MAIN.qtype) - panic("%s: invalid query type", optarg); - - break; - case 's': - if (0 == strcasecmp(optarg, "packet")) - MAIN.sort = &dns_rr_i_packet; - else if (0 == strcasecmp(optarg, "shuffle")) - MAIN.sort = &dns_rr_i_shuffle; - else if (0 == strcasecmp(optarg, "order")) - MAIN.sort = &dns_rr_i_order; - else - panic("%s: invalid sort method", optarg); - - break; - case 'v': - dns_debug = ++MAIN.verbose; - - break; - case 'V': - print_version(progname, stdout); - - return 0; - case 'h': - print_usage(progname, stdout); - - return 0; - default: - print_usage(progname, stderr); - - return EXIT_FAILURE; - } /* switch() */ - } /* while() */ - - argc -= optind; - argv += optind; - - for (i = 0; i < lengthof(cmds) && argv[0]; i++) { - if (0 == strcmp(cmds[i].cmd, argv[0])) - return cmds[i].run(argc, argv); - } - - print_usage(progname, stderr); - - return EXIT_FAILURE; -} /* main() */ - - -#endif /* DNS_MAIN */ - - -/* - * pop file-scoped compiler annotations - */ -#if __clang__ -#pragma clang diagnostic pop -#elif DNS_GNUC_PREREQ(4, 6) -#pragma GCC diagnostic pop -#endif - diff --git a/Sources/CLibdill/dns/dns.h b/Sources/CLibdill/dns/dns.h deleted file mode 100644 index 7eb3e7d..0000000 --- a/Sources/CLibdill/dns/dns.h +++ /dev/null @@ -1,1198 +0,0 @@ -/* ========================================================================== - * dns.h - Recursive, Reentrant DNS Resolver. - * -------------------------------------------------------------------------- - * Copyright (c) 2009, 2010, 2012, 2013, 2014, 2015 William Ahern - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to permit - * persons to whom the Software is furnished to do so, subject to the - * following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - * ========================================================================== - */ -#ifndef DNS_H -#define DNS_H - -#include /* size_t offsetof() */ -#include /* FILE */ - -#include /* strlen(3) */ - -#include /* time_t */ - -#if _WIN32 -#include -#include -#else -#include /* BYTE_ORDER BIG_ENDIAN _BIG_ENDIAN */ -#include /* socklen_t */ -#include /* struct socket */ - -#include /* POLLIN POLLOUT */ - -#include /* struct in_addr struct in6_addr */ - -#include /* struct addrinfo */ -#endif - - -/* - * V E R S I O N - * - * Vendor: Entity for which versions numbers are relevant. (If forking - * change DNS_VENDOR to avoid confusion.) - * - * Three versions: - * - * REL Official "release"--bug fixes, new features, etc. - * ABI Changes to existing object sizes or parameter types. - * API Changes that might effect application source. - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#define DNS_VENDOR "william@25thandClement.com" - -#define DNS_V_REL 0x20150630 -#define DNS_V_ABI 0x20150612 -#define DNS_V_API 0x20150612 - - -const char *dns_vendor(void); - -int dns_v_rel(void); -int dns_v_abi(void); -int dns_v_api(void); - - -/* - * E R R O R S - * - * Errors and exceptions are always returned through an int. This should - * hopefully make integration easier in the majority of circumstances, and - * also cut down on useless compiler warnings. - * - * System and library errors are returned together. POSIX guarantees that - * all system errors are positive integers. Library errors are always - * negative integers in the range DNS_EBASE to DNS_ELAST, with the high bits - * set to the three magic ASCII characters "dns". - * - * dns_strerror() returns static English string descriptions of all known - * errors, and punts the remainder to strerror(3). - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#define DNS_EBASE -(('d' << 24) | ('n' << 16) | ('s' << 8) | 64) - -#define dns_error_t int /* for documentation only */ - -enum dns_errno { - DNS_ENOBUFS = DNS_EBASE, - DNS_EILLEGAL, - DNS_EORDER, - DNS_ESECTION, - DNS_EUNKNOWN, - DNS_EADDRESS, - DNS_ENOQUERY, - DNS_ENOANSWER, - DNS_EFETCHED, - DNS_ESERVICE, /* EAI_SERVICE */ - DNS_ENONAME, /* EAI_NONAME */ - DNS_EFAIL, /* EAI_FAIL */ - DNS_ELAST, -}; /* dns_errno */ - -const char *dns_strerror(dns_error_t); - -extern int dns_debug; - - -/* - * C O M P I L E R A N N O T A T I O N S - * - * GCC with -Wextra, and clang by default, complain about overrides in - * initializer lists. Overriding previous member initializers is well - * defined behavior in C. dns.c relies on this behavior to define default, - * overrideable member values when instantiating configuration objects. - * - * dns_quietinit() guards a compound literal expression with pragmas to - * silence these shrill warnings. This alleviates the burden of requiring - * third-party projects to adjust their compiler flags. - * - * NOTE: If you take the address of the compound literal, take the address - * of the transformed expression, otherwise the compound literal lifetime is - * tied to the scope of the GCC statement expression. - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#if defined __clang__ -#define DNS_PRAGMA_PUSH _Pragma("clang diagnostic push") -#define DNS_PRAGMA_QUIET _Pragma("clang diagnostic ignored \"-Winitializer-overrides\"") -#define DNS_PRAGMA_POP _Pragma("clang diagnostic pop") - -#define dns_quietinit(...) \ - DNS_PRAGMA_PUSH DNS_PRAGMA_QUIET __VA_ARGS__ DNS_PRAGMA_POP -#elif (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4 -#define DNS_PRAGMA_PUSH _Pragma("GCC diagnostic push") -#define DNS_PRAGMA_QUIET _Pragma("GCC diagnostic ignored \"-Woverride-init\"") -#define DNS_PRAGMA_POP _Pragma("GCC diagnostic pop") - -/* GCC parses the _Pragma operator less elegantly than clang. */ -#define dns_quietinit(...) \ - __extension__ ({ DNS_PRAGMA_PUSH DNS_PRAGMA_QUIET __VA_ARGS__; DNS_PRAGMA_POP }) -#else -#define DNS_PRAGMA_PUSH -#define DNS_PRAGMA_QUIET -#define DNS_PRAGMA_POP -#define dns_quietinit(...) __VA_ARGS__ -#endif - -#if defined __GNUC__ -#define DNS_PRAGMA_EXTENSION __extension__ -#else -#define DNS_PRAGMA_EXTENSION -#endif - - -/* - * E V E N T S I N T E R F A C E S - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#if defined(POLLIN) -#define DNS_POLLIN POLLIN -#else -#define DNS_POLLIN 1 -#endif - -#if defined(POLLOUT) -#define DNS_POLLOUT POLLOUT -#else -#define DNS_POLLOUT 2 -#endif - - -/* - * See Application Interface below for configuring libevent bitmasks instead - * of poll(2) bitmasks. - */ -#define DNS_EVREAD 2 -#define DNS_EVWRITE 4 - - -#define DNS_POLL2EV(set) \ - (((set) & DNS_POLLIN)? DNS_EVREAD : 0) | (((set) & DNS_POLLOUT)? DNS_EVWRITE : 0) - -#define DNS_EV2POLL(set) \ - (((set) & DNS_EVREAD)? DNS_POLLIN : 0) | (((set) & DNS_EVWRITE)? DNS_POLLOUT : 0) - - -/* - * E N U M E R A T I O N I N T E R F A C E S - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -enum dns_section { - DNS_S_QD = 0x01, -#define DNS_S_QUESTION DNS_S_QD - - DNS_S_AN = 0x02, -#define DNS_S_ANSWER DNS_S_AN - - DNS_S_NS = 0x04, -#define DNS_S_AUTHORITY DNS_S_NS - - DNS_S_AR = 0x08, -#define DNS_S_ADDITIONAL DNS_S_AR - - DNS_S_ALL = 0x0f -}; /* enum dns_section */ - - -enum dns_class { - DNS_C_IN = 1, - - DNS_C_ANY = 255 -}; /* enum dns_class */ - - -enum dns_type { - DNS_T_A = 1, - DNS_T_NS = 2, - DNS_T_CNAME = 5, - DNS_T_SOA = 6, - DNS_T_PTR = 12, - DNS_T_MX = 15, - DNS_T_TXT = 16, - DNS_T_AAAA = 28, - DNS_T_SRV = 33, - DNS_T_OPT = 41, - DNS_T_SSHFP = 44, - DNS_T_SPF = 99, - - DNS_T_ALL = 255 -}; /* enum dns_type */ - - -enum dns_opcode { - DNS_OP_QUERY = 0, - DNS_OP_IQUERY = 1, - DNS_OP_STATUS = 2, - DNS_OP_NOTIFY = 4, - DNS_OP_UPDATE = 5, -}; /* dns_opcode */ - - -enum dns_rcode { - DNS_RC_NOERROR = 0, - DNS_RC_FORMERR = 1, - DNS_RC_SERVFAIL = 2, - DNS_RC_NXDOMAIN = 3, - DNS_RC_NOTIMP = 4, - DNS_RC_REFUSED = 5, - DNS_RC_YXDOMAIN = 6, - DNS_RC_YXRRSET = 7, - DNS_RC_NXRRSET = 8, - DNS_RC_NOTAUTH = 9, - DNS_RC_NOTZONE = 10, -}; /* dns_rcode */ - - -/* - * NOTE: These string functions need a small buffer in case the literal - * integer value needs to be printed and returned. UNLESS this buffer is - * SPECIFIED, the returned string has ONLY BLOCK SCOPE. - */ -#define DNS_STRMAXLEN 47 /* "QUESTION|ANSWER|AUTHORITY|ADDITIONAL" */ - -const char *dns_strsection(enum dns_section, void *, size_t); -#define dns_strsection3(a, b, c) \ - dns_strsection((a), (b), (c)) -#define dns_strsection1(a) dns_strsection((a), (char [DNS_STRMAXLEN + 1]){ 0 }, DNS_STRMAXLEN + 1) -#define dns_strsection(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_strsection, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__) - -enum dns_section dns_isection(const char *); - -const char *dns_strclass(enum dns_class, void *, size_t); -#define dns_strclass3(a, b, c) dns_strclass((a), (b), (c)) -#define dns_strclass1(a) dns_strclass((a), (char [DNS_STRMAXLEN + 1]){ 0 }, DNS_STRMAXLEN + 1) -#define dns_strclass(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_strclass, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__) - -enum dns_class dns_iclass(const char *); - -const char *dns_strtype(enum dns_type, void *, size_t); -#define dns_strtype3(a, b, c) dns_strtype((a), (b), (c)) -#define dns_strtype1(a) dns_strtype((a), (char [DNS_STRMAXLEN + 1]){ 0 }, DNS_STRMAXLEN + 1) -#define dns_strtype(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_strtype, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__) - -enum dns_type dns_itype(const char *); - -const char *dns_stropcode(enum dns_opcode); - -enum dns_opcode dns_iopcode(const char *); - -const char *dns_strrcode(enum dns_rcode); - -enum dns_rcode dns_ircode(const char *); - - -/* - * A T O M I C I N T E R F A C E S - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -typedef unsigned long dns_atomic_t; - -typedef unsigned long dns_refcount_t; /* must be same value type as dns_atomic_t */ - - -/* - * C R Y P T O I N T E R F A C E S - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -extern unsigned (*dns_random)(void); - - -/* - * P A C K E T I N T E R F A C E - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -struct dns_header { - unsigned qid:16; - -#if (defined BYTE_ORDER && BYTE_ORDER == BIG_ENDIAN) || (defined __sun && defined _BIG_ENDIAN) - unsigned qr:1; - unsigned opcode:4; - unsigned aa:1; - unsigned tc:1; - unsigned rd:1; - - unsigned ra:1; - unsigned unused:3; - unsigned rcode:4; -#else - unsigned rd:1; - unsigned tc:1; - unsigned aa:1; - unsigned opcode:4; - unsigned qr:1; - - unsigned rcode:4; - unsigned unused:3; - unsigned ra:1; -#endif - - unsigned qdcount:16; - unsigned ancount:16; - unsigned nscount:16; - unsigned arcount:16; -}; /* struct dns_header */ - -#define dns_header(p) (&(p)->header) - - -#ifndef DNS_P_QBUFSIZ -#define DNS_P_QBUFSIZ dns_p_calcsize(256 + 4) -#endif - -#ifndef DNS_P_DICTSIZE -#define DNS_P_DICTSIZE 16 -#endif - -struct dns_packet { - unsigned short dict[DNS_P_DICTSIZE]; - - struct dns_s_memo { - unsigned short base, end; - } qd, an, ns, ar; - - struct { struct dns_packet *cqe_next, *cqe_prev; } cqe; - - size_t size, end; - - int:16; /* tcp padding */ - - DNS_PRAGMA_EXTENSION union { - struct dns_header header; - unsigned char data[1]; - }; -}; /* struct dns_packet */ - -#define dns_p_calcsize(n) (offsetof(struct dns_packet, data) + DNS_PP_MAX(12, (n))) - -#define dns_p_sizeof(P) dns_p_calcsize((P)->end) - -/** takes size of maximum desired payload */ -#define dns_p_new(n) (dns_p_init((struct dns_packet *)&(union { unsigned char b[dns_p_calcsize((n))]; struct dns_packet p; }){ { 0 } }, dns_p_calcsize((n)))) - -/** takes size of entire packet structure as allocated */ -struct dns_packet *dns_p_init(struct dns_packet *, size_t); - -/** takes size of maximum desired payload */ -struct dns_packet *dns_p_make(size_t, int *); - -int dns_p_grow(struct dns_packet **); - -struct dns_packet *dns_p_copy(struct dns_packet *, const struct dns_packet *); - -#define dns_p_opcode(P) (dns_header(P)->opcode) - -#define dns_p_rcode(P) (dns_header(P)->rcode) - -unsigned dns_p_count(struct dns_packet *, enum dns_section); - -int dns_p_push(struct dns_packet *, enum dns_section, const void *, size_t, enum dns_type, enum dns_class, unsigned, const void *); - -void dns_p_dictadd(struct dns_packet *, unsigned short); - -struct dns_packet *dns_p_merge(struct dns_packet *, enum dns_section, struct dns_packet *, enum dns_section, int *); - -void dns_p_dump(struct dns_packet *, FILE *); - -int dns_p_study(struct dns_packet *); - - -/* - * D O M A I N N A M E I N T E R F A C E S - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#define DNS_D_MAXLABEL 63 /* + 1 '\0' */ -#define DNS_D_MAXNAME 255 /* + 1 '\0' */ - -#define DNS_D_ANCHOR 1 /* anchor domain w/ root "." */ -#define DNS_D_CLEAVE 2 /* cleave sub-domain */ -#define DNS_D_TRIM 4 /* remove superfluous dots */ - -#define dns_d_new3(a, b, f) dns_d_init(&(char[DNS_D_MAXNAME + 1]){ 0 }, DNS_D_MAXNAME + 1, (a), (b), (f)) -#define dns_d_new2(a, f) dns_d_new3((a), strlen((a)), (f)) -#define dns_d_new1(a) dns_d_new3((a), strlen((a)), DNS_D_ANCHOR) -#define dns_d_new(...) DNS_PP_CALL(DNS_PP_XPASTE(dns_d_new, DNS_PP_NARG(__VA_ARGS__)), __VA_ARGS__) - -char *dns_d_init(void *, size_t, const void *, size_t, int); - -size_t dns_d_anchor(void *, size_t, const void *, size_t); - -size_t dns_d_cleave(void *, size_t, const void *, size_t); - -size_t dns_d_comp(void *, size_t, const void *, size_t, struct dns_packet *, int *); - -size_t dns_d_expand(void *, size_t, unsigned short, struct dns_packet *, int *); - -unsigned short dns_d_skip(unsigned short, struct dns_packet *); - -int dns_d_push(struct dns_packet *, const void *, size_t); - -size_t dns_d_cname(void *, size_t, const void *, size_t, struct dns_packet *, int *error); - - -/* - * R E S O U R C E R E C O R D I N T E R F A C E S - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -struct dns_rr { - enum dns_section section; - - struct { - unsigned short p; - unsigned short len; - } dn; - - enum dns_type type; - enum dns_class class; - unsigned ttl; - - struct { - unsigned short p; - unsigned short len; - } rd; -}; /* struct dns_rr */ - - -int dns_rr_copy(struct dns_packet *, struct dns_rr *, struct dns_packet *); - -int dns_rr_parse(struct dns_rr *, unsigned short, struct dns_packet *); - -unsigned short dns_rr_skip(unsigned short, struct dns_packet *); - -int dns_rr_cmp(struct dns_rr *, struct dns_packet *, struct dns_rr *, struct dns_packet *); - -size_t dns_rr_print(void *, size_t, struct dns_rr *, struct dns_packet *, int *); - - -#define dns_rr_i_new(P, ...) \ - dns_rr_i_init(&dns_quietinit((struct dns_rr_i){ 0, __VA_ARGS__ }), (P)) - -struct dns_rr_i { - enum dns_section section; - const void *name; - enum dns_type type; - enum dns_class class; - const void *data; - - int follow; - - int (*sort)(); - unsigned args[2]; - - struct { - unsigned short next; - unsigned short count; - - unsigned exec; - unsigned regs[2]; - } state, saved; -}; /* struct dns_rr_i */ - -int dns_rr_i_packet(struct dns_rr *, struct dns_rr *, struct dns_rr_i *, struct dns_packet *); - -int dns_rr_i_order(struct dns_rr *, struct dns_rr *, struct dns_rr_i *, struct dns_packet *); - -int dns_rr_i_shuffle(struct dns_rr *, struct dns_rr *, struct dns_rr_i *, struct dns_packet *); - -struct dns_rr_i *dns_rr_i_init(struct dns_rr_i *, struct dns_packet *); - -#define dns_rr_i_save(i) ((i)->saved = (i)->state) -#define dns_rr_i_rewind(i) ((i)->state = (i)->saved) -#define dns_rr_i_count(i) ((i)->state.count) - -unsigned dns_rr_grep(struct dns_rr *, unsigned, struct dns_rr_i *, struct dns_packet *, int *); - -#define dns_rr_foreach_(rr, P, ...) \ - for (struct dns_rr_i DNS_PP_XPASTE(i, __LINE__) = *dns_rr_i_new((P), __VA_ARGS__); dns_rr_grep((rr), 1, &DNS_PP_XPASTE(i, __LINE__), (P), &(int){ 0 }); ) - -#define dns_rr_foreach(...) dns_rr_foreach_(__VA_ARGS__) - - -/* - * A R E S O U R C E R E C O R D - */ - -struct dns_a { - struct in_addr addr; -}; /* struct dns_a */ - -int dns_a_parse(struct dns_a *, struct dns_rr *, struct dns_packet *); - -int dns_a_push(struct dns_packet *, struct dns_a *); - -int dns_a_cmp(const struct dns_a *, const struct dns_a *); - -size_t dns_a_print(void *, size_t, struct dns_a *); - - -/* - * AAAA R E S O U R C E R E C O R D - */ - -struct dns_aaaa { - struct in6_addr addr; -}; /* struct dns_aaaa */ - -int dns_aaaa_parse(struct dns_aaaa *, struct dns_rr *, struct dns_packet *); - -int dns_aaaa_push(struct dns_packet *, struct dns_aaaa *); - -int dns_aaaa_cmp(const struct dns_aaaa *, const struct dns_aaaa *); - -size_t dns_aaaa_print(void *, size_t, struct dns_aaaa *); - - -/* - * MX R E S O U R C E R E C O R D - */ - -struct dns_mx { - unsigned short preference; - char host[DNS_D_MAXNAME + 1]; -}; /* struct dns_mx */ - -int dns_mx_parse(struct dns_mx *, struct dns_rr *, struct dns_packet *); - -int dns_mx_push(struct dns_packet *, struct dns_mx *); - -int dns_mx_cmp(const struct dns_mx *, const struct dns_mx *); - -size_t dns_mx_print(void *, size_t, struct dns_mx *); - -size_t dns_mx_cname(void *, size_t, struct dns_mx *); - - -/* - * NS R E S O U R C E R E C O R D - */ - -struct dns_ns { - char host[DNS_D_MAXNAME + 1]; -}; /* struct dns_ns */ - -int dns_ns_parse(struct dns_ns *, struct dns_rr *, struct dns_packet *); - -int dns_ns_push(struct dns_packet *, struct dns_ns *); - -int dns_ns_cmp(const struct dns_ns *, const struct dns_ns *); - -size_t dns_ns_print(void *, size_t, struct dns_ns *); - -size_t dns_ns_cname(void *, size_t, struct dns_ns *); - - -/* - * CNAME R E S O U R C E R E C O R D - */ - -struct dns_cname { - char host[DNS_D_MAXNAME + 1]; -}; /* struct dns_cname */ - -int dns_cname_parse(struct dns_cname *, struct dns_rr *, struct dns_packet *); - -int dns_cname_push(struct dns_packet *, struct dns_cname *); - -int dns_cname_cmp(const struct dns_cname *, const struct dns_cname *); - -size_t dns_cname_print(void *, size_t, struct dns_cname *); - -size_t dns_cname_cname(void *, size_t, struct dns_cname *); - - -/* - * SOA R E S O U R C E R E C O R D - */ - -struct dns_soa { - char mname[DNS_D_MAXNAME + 1]; - char rname[DNS_D_MAXNAME + 1]; - unsigned serial, refresh, retry, expire, minimum; -}; /* struct dns_soa */ - -int dns_soa_parse(struct dns_soa *, struct dns_rr *, struct dns_packet *); - -int dns_soa_push(struct dns_packet *, struct dns_soa *); - -int dns_soa_cmp(const struct dns_soa *, const struct dns_soa *); - -size_t dns_soa_print(void *, size_t, struct dns_soa *); - - -/* - * PTR R E S O U R C E R E C O R D - */ - -struct dns_ptr { - char host[DNS_D_MAXNAME + 1]; -}; /* struct dns_ptr */ - -int dns_ptr_parse(struct dns_ptr *, struct dns_rr *, struct dns_packet *); - -int dns_ptr_push(struct dns_packet *, struct dns_ptr *); - -int dns_ptr_cmp(const struct dns_ptr *, const struct dns_ptr *); - -size_t dns_ptr_print(void *, size_t, struct dns_ptr *); - -size_t dns_ptr_cname(void *, size_t, struct dns_ptr *); - - -/* - * SRV R E S O U R C E R E C O R D - */ - -struct dns_srv { - unsigned short priority; - unsigned short weight; - unsigned short port; - char target[DNS_D_MAXNAME + 1]; -}; /* struct dns_srv */ - -int dns_srv_parse(struct dns_srv *, struct dns_rr *, struct dns_packet *); - -int dns_srv_push(struct dns_packet *, struct dns_srv *); - -int dns_srv_cmp(const struct dns_srv *, const struct dns_srv *); - -size_t dns_srv_print(void *, size_t, struct dns_srv *); - -size_t dns_srv_cname(void *, size_t, struct dns_srv *); - - -/* - * OPT R E S O U R C E R E C O R D - */ - -#define DNS_OPT_MINDATA 512 - -#define DNS_OPT_BADVERS 16 - -struct dns_opt { - size_t size, len; - - unsigned char rcode, version; - unsigned short maxsize; - - unsigned char data[DNS_OPT_MINDATA]; -}; /* struct dns_opt */ - -unsigned int dns_opt_ttl(const struct dns_opt *); - -unsigned short dns_opt_class(const struct dns_opt *); - -struct dns_opt *dns_opt_init(struct dns_opt *, size_t); - -int dns_opt_parse(struct dns_opt *, struct dns_rr *, struct dns_packet *); - -int dns_opt_push(struct dns_packet *, struct dns_opt *); - -int dns_opt_cmp(const struct dns_opt *, const struct dns_opt *); - -size_t dns_opt_print(void *, size_t, struct dns_opt *); - - -/* - * SSHFP R E S O U R C E R E C O R D - */ - -struct dns_sshfp { - enum dns_sshfp_key { - DNS_SSHFP_RSA = 1, - DNS_SSHFP_DSA = 2, - } algo; - - enum dns_sshfp_digest { - DNS_SSHFP_SHA1 = 1, - } type; - - union { - unsigned char sha1[20]; - } digest; -}; /* struct dns_sshfp */ - -int dns_sshfp_parse(struct dns_sshfp *, struct dns_rr *, struct dns_packet *); - -int dns_sshfp_push(struct dns_packet *, struct dns_sshfp *); - -int dns_sshfp_cmp(const struct dns_sshfp *, const struct dns_sshfp *); - -size_t dns_sshfp_print(void *, size_t, struct dns_sshfp *); - - -/* - * TXT R E S O U R C E R E C O R D - */ - -#ifndef DNS_TXT_MINDATA -#define DNS_TXT_MINDATA 1024 -#endif - -struct dns_txt { - size_t size, len; - unsigned char data[DNS_TXT_MINDATA]; -}; /* struct dns_txt */ - -struct dns_txt *dns_txt_init(struct dns_txt *, size_t); - -int dns_txt_parse(struct dns_txt *, struct dns_rr *, struct dns_packet *); - -int dns_txt_push(struct dns_packet *, struct dns_txt *); - -int dns_txt_cmp(const struct dns_txt *, const struct dns_txt *); - -size_t dns_txt_print(void *, size_t, struct dns_txt *); - - -/* - * ANY R E S O U R C E R E C O R D - */ - -union dns_any { - struct dns_a a; - struct dns_aaaa aaaa; - struct dns_mx mx; - struct dns_ns ns; - struct dns_cname cname; - struct dns_soa soa; - struct dns_ptr ptr; - struct dns_srv srv; - struct dns_opt opt; - struct dns_sshfp sshfp; - struct dns_txt txt, spf, rdata; -}; /* union dns_any */ - -#define DNS_ANY_INIT(any) { .rdata = { .size = sizeof *(any) } } - -union dns_any *dns_any_init(union dns_any *, size_t); - -int dns_any_parse(union dns_any *, struct dns_rr *, struct dns_packet *); - -int dns_any_push(struct dns_packet *, union dns_any *, enum dns_type); - -int dns_any_cmp(const union dns_any *, enum dns_type, const union dns_any *, enum dns_type); - -size_t dns_any_print(void *, size_t, union dns_any *, enum dns_type); - -size_t dns_any_cname(void *, size_t, union dns_any *, enum dns_type); - - -/* - * H O S T S I N T E R F A C E - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -struct dns_hosts; - -struct dns_hosts *dns_hosts_open(int *); - -void dns_hosts_close(struct dns_hosts *); - -dns_refcount_t dns_hosts_acquire(struct dns_hosts *); - -dns_refcount_t dns_hosts_release(struct dns_hosts *); - -struct dns_hosts *dns_hosts_mortal(struct dns_hosts *); - -struct dns_hosts *dns_hosts_local(int *); - -int dns_hosts_loadfile(struct dns_hosts *, FILE *); - -int dns_hosts_loadpath(struct dns_hosts *, const char *); - -int dns_hosts_dump(struct dns_hosts *, FILE *); - -int dns_hosts_insert(struct dns_hosts *, int, const void *, const void *, _Bool); - -struct dns_packet *dns_hosts_query(struct dns_hosts *, struct dns_packet *, int *); - - -/* - * R E S O L V . C O N F I N T E R F A C E - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -struct dns_resolv_conf { - struct sockaddr_storage nameserver[3]; - - char search[4][DNS_D_MAXNAME + 1]; - - /* (f)ile, (b)ind, (c)ache */ - char lookup[4 * (1 + (4 * 2))]; - - struct { - _Bool edns0; - - unsigned ndots; - - unsigned timeout; - - unsigned attempts; - - _Bool rotate; - - _Bool recurse; - - _Bool smart; - - enum { - DNS_RESCONF_TCP_ENABLE, - DNS_RESCONF_TCP_ONLY, - DNS_RESCONF_TCP_DISABLE, - } tcp; - } options; - - struct sockaddr_storage iface; - - struct { /* PRIVATE */ - dns_atomic_t refcount; - } _; -}; /* struct dns_resolv_conf */ - -struct dns_resolv_conf *dns_resconf_open(int *); - -void dns_resconf_close(struct dns_resolv_conf *); - -dns_refcount_t dns_resconf_acquire(struct dns_resolv_conf *); - -dns_refcount_t dns_resconf_release(struct dns_resolv_conf *); - -struct dns_resolv_conf *dns_resconf_mortal(struct dns_resolv_conf *); - -struct dns_resolv_conf *dns_resconf_local(int *); - -struct dns_resolv_conf *dns_resconf_root(int *); - -int dns_resconf_pton(struct sockaddr_storage *, const char *); - -int dns_resconf_loadfile(struct dns_resolv_conf *, FILE *); - -int dns_resconf_loadpath(struct dns_resolv_conf *, const char *); - -int dns_nssconf_loadfile(struct dns_resolv_conf *, FILE *); - -int dns_nssconf_loadpath(struct dns_resolv_conf *, const char *); - -int dns_resconf_dump(struct dns_resolv_conf *, FILE *); - -int dns_nssconf_dump(struct dns_resolv_conf *, FILE *); - -int dns_resconf_setiface(struct dns_resolv_conf *, const char *, unsigned short); - -typedef unsigned long dns_resconf_i_t; - -size_t dns_resconf_search(void *, size_t, const void *, size_t, struct dns_resolv_conf *, dns_resconf_i_t *); - - -/* - * H I N T S E R V E R I N T E R F A C E - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -struct dns_hints; - -struct dns_hints *dns_hints_open(struct dns_resolv_conf *, int *); - -void dns_hints_close(struct dns_hints *); - -dns_refcount_t dns_hints_acquire(struct dns_hints *); - -dns_refcount_t dns_hints_release(struct dns_hints *); - -struct dns_hints *dns_hints_mortal(struct dns_hints *); - -int dns_hints_insert(struct dns_hints *, const char *, const struct sockaddr *, unsigned); - -unsigned dns_hints_insert_resconf(struct dns_hints *, const char *, const struct dns_resolv_conf *, int *); - -struct dns_hints *dns_hints_local(struct dns_resolv_conf *, int *); - -struct dns_hints *dns_hints_root(struct dns_resolv_conf *, int *); - -int dns_hints_dump(struct dns_hints *, FILE *); - - -struct dns_hints_i { - const char *zone; - - struct { - unsigned next; - unsigned seed; - } state; -}; /* struct dns_hints_i */ - -#define dns_hints_i_new(...) (&(struct dns_hints_i){ __VA_ARGS__ }) - -unsigned dns_hints_grep(struct sockaddr **, socklen_t *, unsigned, struct dns_hints_i *, struct dns_hints *); - - -/* - * C A C H E I N T E R F A C E - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -struct dns_cache { - void *state; - - dns_refcount_t (*acquire)(struct dns_cache *); - dns_refcount_t (*release)(struct dns_cache *); - - struct dns_packet *(*query)(struct dns_packet *, struct dns_cache *, int *); - - int (*submit)(struct dns_packet *, struct dns_cache *); - int (*check)(struct dns_cache *); - struct dns_packet *(*fetch)(struct dns_cache *, int *); - - int (*pollfd)(struct dns_cache *); - short (*events)(struct dns_cache *); - void (*clear)(struct dns_cache *); - - union { - long i; - void *p; - } arg[3]; - - struct { /* PRIVATE */ - dns_atomic_t refcount; - } _; -}; /* struct dns_cache */ - - -struct dns_cache *dns_cache_init(struct dns_cache *); - -void dns_cache_close(struct dns_cache *); - - -/* - * A P P L I C A T I O N I N T E R F A C E - * - * Options to change the behavior of the API. Applies across all the - * different components. - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#define DNS_OPTS_INITIALIZER_ { 0, 0 }, 0 -#define DNS_OPTS_INITIALIZER { DNS_OPTS_INITIALIZER_ } -#define DNS_OPTS_INIT(...) { DNS_OPTS_INITIALIZER_, __VA_ARGS__ } - -#define dns_opts(...) (&dns_quietinit((struct dns_options)DNS_OPTS_INIT(__VA_ARGS__))) - -struct dns_options { - /* - * If the callback closes *fd, it must set it to -1. Otherwise, the - * descriptor is queued and lazily closed at object destruction or - * by an explicit call to _clear(). This allows safe use of - * kqueue(2), epoll(2), et al -style persistent events. - */ - struct { - void *arg; - int (*cb)(int *fd, void *arg); - } closefd; - - /* bitmask for _events() routines */ - enum dns_events { - DNS_SYSPOLL, - DNS_LIBEVENT, - } events; -}; /* struct dns_options */ - - -/* - * S T A T S I N T E R F A C E S - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -struct dns_stat { - size_t queries; - - struct { - struct { - size_t count, bytes; - } sent, rcvd; - } udp, tcp; -}; /* struct dns_stat */ - - -/* - * S O C K E T I N T E R F A C E - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -struct dns_socket; - -struct dns_socket *dns_so_open(const struct sockaddr *, int, const struct dns_options *, int *error); - -void dns_so_close(struct dns_socket *); - -void dns_so_reset(struct dns_socket *); - -unsigned short dns_so_mkqid(struct dns_socket *so); - -struct dns_packet *dns_so_query(struct dns_socket *, struct dns_packet *, struct sockaddr *, int *); - -int dns_so_submit(struct dns_socket *, struct dns_packet *, struct sockaddr *); - -int dns_so_check(struct dns_socket *); - -struct dns_packet *dns_so_fetch(struct dns_socket *, int *); - -time_t dns_so_elapsed(struct dns_socket *); - -void dns_so_clear(struct dns_socket *); - -int dns_so_events(struct dns_socket *); - -int dns_so_pollfd(struct dns_socket *); - -int dns_so_poll(struct dns_socket *, int); - -const struct dns_stat *dns_so_stat(struct dns_socket *); - - -/* - * R E S O L V E R I N T E R F A C E - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -struct dns_resolver; - -struct dns_resolver *dns_res_open(struct dns_resolv_conf *, struct dns_hosts *hosts, struct dns_hints *, struct dns_cache *, const struct dns_options *, int *); - -struct dns_resolver *dns_res_stub(const struct dns_options *, int *); - -void dns_res_reset(struct dns_resolver *); - -void dns_res_close(struct dns_resolver *); - -dns_refcount_t dns_res_acquire(struct dns_resolver *); - -dns_refcount_t dns_res_release(struct dns_resolver *); - -struct dns_resolver *dns_res_mortal(struct dns_resolver *); - -int dns_res_submit(struct dns_resolver *, const char *, enum dns_type, enum dns_class); - -int dns_res_submit2(struct dns_resolver *, const char *, size_t, enum dns_type, enum dns_class); - -int dns_res_check(struct dns_resolver *); - -struct dns_packet *dns_res_fetch(struct dns_resolver *, int *); - -time_t dns_res_elapsed(struct dns_resolver *); - -void dns_res_clear(struct dns_resolver *); - -int dns_res_events(struct dns_resolver *); - -int dns_res_pollfd(struct dns_resolver *); - -time_t dns_res_timeout(struct dns_resolver *); - -int dns_res_poll(struct dns_resolver *, int); - -struct dns_packet *dns_res_query(struct dns_resolver *, const char *, enum dns_type, enum dns_class, int, int *); - -const struct dns_stat *dns_res_stat(struct dns_resolver *); - -void dns_res_sethints(struct dns_resolver *, struct dns_hints *); - - -/* - * A D D R I N F O I N T E R F A C E - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -struct dns_addrinfo; - -struct dns_addrinfo *dns_ai_open(const char *, const char *, enum dns_type, const struct addrinfo *, struct dns_resolver *, int *); - -void dns_ai_close(struct dns_addrinfo *); - -int dns_ai_nextent(struct addrinfo **, struct dns_addrinfo *); - -size_t dns_ai_print(void *, size_t, struct addrinfo *, struct dns_addrinfo *); - -time_t dns_ai_elapsed(struct dns_addrinfo *); - -void dns_ai_clear(struct dns_addrinfo *); - -int dns_ai_events(struct dns_addrinfo *); - -int dns_ai_pollfd(struct dns_addrinfo *); - -time_t dns_ai_timeout(struct dns_addrinfo *); - -int dns_ai_poll(struct dns_addrinfo *, int); - -const struct dns_stat *dns_ai_stat(struct dns_addrinfo *); - - -/* - * U T I L I T Y I N T E R F A C E S - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -size_t dns_strlcpy(char *, const char *, size_t); - -size_t dns_strlcat(char *, const char *, size_t); - - -/* - * M A C R O M A G I C S - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#define DNS_PP_MIN(a, b) (((a) < (b))? (a) : (b)) -#define DNS_PP_MAX(a, b) (((a) > (b))? (a) : (b)) -#define DNS_PP_NARG_(a, b, c, d, e, f, g, h, i, j, k, N,...) N -#define DNS_PP_NARG(...) DNS_PP_NARG_(__VA_ARGS__, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) -#define DNS_PP_CALL(F, ...) F(__VA_ARGS__) -#define DNS_PP_PASTE(x, y) x##y -#define DNS_PP_XPASTE(x, y) DNS_PP_PASTE(x, y) -#define DNS_PP_STRINGIFY_(s) #s -#define DNS_PP_STRINGIFY(s) DNS_PP_STRINGIFY_(s) -#define DNS_PP_D1 0 -#define DNS_PP_D2 1 -#define DNS_PP_D3 2 -#define DNS_PP_D4 3 -#define DNS_PP_D5 4 -#define DNS_PP_D6 5 -#define DNS_PP_D7 6 -#define DNS_PP_D8 7 -#define DNS_PP_D9 8 -#define DNS_PP_D10 9 -#define DNS_PP_D11 10 -#define DNS_PP_DEC(N) DNS_PP_XPASTE(DNS_PP_D, N) - -#endif /* DNS_H */ diff --git a/Sources/CLibdill/epoll.c.inc b/Sources/CLibdill/epoll.c.inc deleted file mode 100644 index 90a363f..0000000 --- a/Sources/CLibdill/epoll.c.inc +++ /dev/null @@ -1,261 +0,0 @@ -/* - - Copyright (c) 2016 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#include -#include -#include -#include -#include - -#include "cr.h" -#include "list.h" -#include "pollset.h" -#include "utils.h" -#include "ctx.h" - -#define DILL_ENDLIST 0xffffffff - -#define DILL_EPOLLSETSIZE 128 - -/* One of these is associated with each file descriptor. */ -struct dill_fdinfo { - /* A coroutines waiting to read from the fd or NULL. */ - struct dill_fdclause *in; - /* A coroutines waiting to write to the fd or NULL. */ - struct dill_fdclause *out; - /* Cached current state of epollset. */ - uint32_t currevs; - /* 1-based index, 0 stands for "not part of the list", DILL_ENDLIST - stands for "no more elements in the list. */ - uint32_t next; - /* 1 if the file descriptor is cached. 0 otherwise. */ - unsigned int cached : 1; -}; - -int dill_ctx_pollset_init(struct dill_ctx_pollset *ctx) { - int err; - /* Allocate one info per fd. */ - ctx->nfdinfos = dill_maxfds(); - ctx->fdinfos = calloc(ctx->nfdinfos, sizeof(struct dill_fdinfo)); - if(dill_slow(!ctx->fdinfos)) {err = ENOMEM; goto error1;} - /* Changelist is empty. */ - ctx->changelist = DILL_ENDLIST; - /* Create the kernel-side pollset. */ - ctx->efd = epoll_create(1); - if(dill_slow(ctx->efd < 0)) {err = errno; goto error2;} - return 0; -error2: - free(ctx->fdinfos); - ctx->fdinfos = NULL; -error1: - errno = err; - return -1; -} - -void dill_ctx_pollset_term(struct dill_ctx_pollset *ctx) { - int rc = close(ctx->efd); - dill_assert(rc == 0); - free(ctx->fdinfos); -} - -static void dill_fdcancelin(struct dill_clause *cl) { - struct dill_fdinfo *fdinfo = - dill_cont(cl, struct dill_fdclause, cl)->fdinfo; - fdinfo->in = NULL; - if(!fdinfo->next) { - struct dill_ctx_pollset *ctx = &dill_getctx->pollset; - fdinfo->next = ctx->changelist; - ctx->changelist = fdinfo - ctx->fdinfos + 1; - } -} - -static void dill_fdcancelout(struct dill_clause *cl) { - struct dill_fdinfo *fdinfo = - dill_cont(cl, struct dill_fdclause, cl)->fdinfo; - fdinfo->out = NULL; - if(!fdinfo->next) { - struct dill_ctx_pollset *ctx = &dill_getctx->pollset; - fdinfo->next = ctx->changelist; - ctx->changelist = fdinfo - ctx->fdinfos + 1; - } -} - -int dill_pollset_in(struct dill_fdclause *fdcl, int id, int fd) { - struct dill_ctx_pollset *ctx = &dill_getctx->pollset; - if(dill_slow(fd < 0 || fd >= ctx->nfdinfos)) {errno = EBADF; return -1;} - struct dill_fdinfo *fdi = &ctx->fdinfos[fd]; - /* If not yet cached, check whether the fd exists and if it does, - add it to the pollset. */ - if(dill_slow(!fdi->cached)) { - struct epoll_event ev; - ev.data.fd = fd; - ev.events = EPOLLIN; - int rc = epoll_ctl(ctx->efd, EPOLL_CTL_ADD, fd, &ev); - if(dill_slow(rc < 0)) { - if(errno == ELOOP || errno == EPERM) {errno = ENOTSUP; return -1;} - return -1; - } - fdi->in = NULL; - fdi->out = NULL; - fdi->currevs = EPOLLIN; - fdi->next = 0; - fdi->cached = 1; - } - if(dill_slow(fdi->in)) {errno = EBUSY; return -1;} - /* If the fd is not yet in the pollset, add it there. */ - else if(!fdi->next) { - fdi->next = ctx->changelist; - ctx->changelist = fd + 1; - } - fdcl->fdinfo = fdi; - fdi->in = fdcl; - dill_waitfor(&fdcl->cl, id, dill_fdcancelin); - return 0; -} - -int dill_pollset_out(struct dill_fdclause *fdcl, int id, int fd) { - struct dill_ctx_pollset *ctx = &dill_getctx->pollset; - if(dill_slow(fd < 0 || fd >= ctx->nfdinfos)) {errno = EBADF; return -1;} - struct dill_fdinfo *fdi = &ctx->fdinfos[fd]; - /* If not yet cached, check whether the fd exists and if it does, - add it to pollset. */ - if(dill_slow(!fdi->cached)) { - struct epoll_event ev; - ev.data.fd = fd; - ev.events = EPOLLOUT; - int rc = epoll_ctl(ctx->efd, EPOLL_CTL_ADD, fd, &ev); - if(dill_slow(rc < 0)) { - if(errno == ELOOP || errno == EPERM) {errno = ENOTSUP; return -1;} - return -1; - } - fdi->in = NULL; - fdi->out = NULL; - fdi->currevs = EPOLLOUT; - fdi->next = 0; - fdi->cached = 1; - } - if(dill_slow(fdi->out)) {errno = EBUSY; return -1;} - /* If the fd is not yet in the pollset, add it there. */ - else if(!fdi->next) { - fdi->next = ctx->changelist; - ctx->changelist = fd + 1; - } - fdcl->fdinfo = fdi; - fdi->out = fdcl; - dill_waitfor(&fdcl->cl, id, dill_fdcancelout); - return 0; -} - -int dill_pollset_clean(int fd) { - struct dill_ctx_pollset *ctx = &dill_getctx->pollset; - struct dill_fdinfo *fdi = &ctx->fdinfos[fd]; - if(!fdi->cached) return 0; - /* We cannot clean an fd that someone is waiting for. */ - if(dill_slow(fdi->in || fdi->out)) {errno = EBUSY; return -1;} - /* Remove the file descriptor from the pollset if it is still there. */ - if(fdi->currevs) { - struct epoll_event ev; - ev.data.fd = fd; - ev.events = 0; - int rc = epoll_ctl(ctx->efd, EPOLL_CTL_DEL, fd, &ev); - dill_assert(rc == 0 || errno == ENOENT); - fdi->currevs = 0; - } - /* If needed, remove the fd from the changelist. */ - if(fdi->next) { - uint32_t *pidx = &ctx->changelist; - while(1) { - dill_assert(*pidx != 0 && *pidx != DILL_ENDLIST); - if(*pidx - 1 == fd) break; - pidx = &ctx->fdinfos[*pidx - 1].next; - } - *pidx = fdi->next; - fdi->next = 0; - } - /* Mark the fd as not used. */ - fdi->cached = 0; - return 0; -} - -int dill_pollset_poll(int timeout) { - struct dill_ctx_pollset *ctx = &dill_getctx->pollset; - /* Apply any changes to the pollset. - TODO: Use epoll_ctl_batch once available. */ - while(ctx->changelist != DILL_ENDLIST) { - int fd = ctx->changelist - 1; - struct dill_fdinfo *fdi = &ctx->fdinfos[fd]; - struct epoll_event ev; - ev.data.fd = fd; - ev.events = 0; - if(fdi->in) - ev.events |= EPOLLIN; - if(fdi->out) - ev.events |= EPOLLOUT; - if(fdi->currevs != ev.events) { - int op; - if(!ev.events) - op = EPOLL_CTL_DEL; - else if(!fdi->currevs) - op = EPOLL_CTL_ADD; - else - op = EPOLL_CTL_MOD; - fdi->currevs = ev.events; - int rc = epoll_ctl(ctx->efd, op, fd, &ev); - dill_assert(rc == 0); - } - ctx->changelist = fdi->next; - fdi->next = 0; - } - /* Wait for events. */ - struct epoll_event evs[DILL_EPOLLSETSIZE]; - int numevs = epoll_wait(ctx->efd, evs, DILL_EPOLLSETSIZE, timeout); - if(numevs < 0 && errno == EINTR) return -1; - dill_assert(numevs >= 0); - /* Fire file descriptor events. */ - int i; - for(i = 0; i != numevs; ++i) { - int fd = evs[i].data.fd; - struct dill_fdinfo *fdi = &ctx->fdinfos[fd]; - /* Resume blocked coroutines. */ - if(fdi->in && (evs[i].events & (EPOLLIN | EPOLLERR | EPOLLHUP))) { - dill_trigger(&fdi->in->cl, 0); - /* Remove the fd from the pollset if needed. */ - if(!fdi->in && !fdi->next) { - fdi->next = ctx->changelist; - ctx->changelist = fd + 1; - } - } - if(fdi->out && (evs[i].events & (EPOLLOUT | EPOLLERR | EPOLLHUP))) { - dill_trigger(&fdi->out->cl, 0); - /* Remove the fd from the pollset if needed. */ - if(!fdi->out && !fdi->next) { - fdi->next = ctx->changelist; - ctx->changelist = fd + 1; - } - } - } - /* Return 0 on timeout or 1 if at least one coroutine was resumed. */ - return numevs > 0 ? 1 : 0; -} - diff --git a/Sources/CLibdill/epoll.h.inc b/Sources/CLibdill/epoll.h.inc deleted file mode 100644 index 892cc54..0000000 --- a/Sources/CLibdill/epoll.h.inc +++ /dev/null @@ -1,46 +0,0 @@ -/* - - Copyright (c) 2016 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#ifndef DILL_EPOLL_INCLUDED -#define DILL_EPOLL_INCLUDED - -#include - -#include "cr.h" -#include "list.h" - -struct dill_fdinfo; - -struct dill_fdclause { - struct dill_clause cl; - struct dill_fdinfo *fdinfo; - -}; - -struct dill_ctx_pollset { - int efd; - struct dill_fdinfo *fdinfos; - size_t nfdinfos; - uint32_t changelist; -}; - -#endif diff --git a/Sources/CLibdill/fd.c b/Sources/CLibdill/fd.c deleted file mode 100644 index 62a90cf..0000000 --- a/Sources/CLibdill/fd.c +++ /dev/null @@ -1,299 +0,0 @@ -/* - - Copyright (c) 2017 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#include -#include "libdill.h" -#include -#include - -#include "fd.h" -#include "iol.h" -#include "utils.h" - -#if defined MSG_NOSIGNAL -#define FD_NOSIGNAL MSG_NOSIGNAL -#else -#define FD_NOSIGNAL 0 -#endif - -void fd_initrxbuf(struct fd_rxbuf *rxbuf) { - dill_assert(rxbuf); - rxbuf->len = 0; - rxbuf->pos = 0; -} - -int fd_unblock(int s) { - /* Switch to non-blocking mode. */ - int opt = fcntl(s, F_GETFL, 0); - if (opt == -1) - opt = 0; - int rc = fcntl(s, F_SETFL, opt | O_NONBLOCK); - if(dill_slow(rc < 0)) return -1; - /* Allow re-using the same local address rapidly. */ - opt = 1; - rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)); - if(dill_slow(rc < 0)) return -1; - /* If possible, prevent SIGPIPE signal when writing to the connection - already closed by the peer. */ -#ifdef SO_NOSIGPIPE - opt = 1; - rc = setsockopt (s, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof (opt)); - if(dill_slow(rc < 0 && errno != EINVAL)) return -1; -#endif - return 0; -} - -int fd_connect(int s, const struct sockaddr *addr, socklen_t addrlen, - int64_t deadline) { - /* Initiate connect. */ - int rc = connect(s, addr, addrlen); - if(rc == 0) return 0; - if(dill_slow(errno != EINPROGRESS)) return -1; - /* Connect is in progress. Let's wait till it's done. */ - rc = fdout(s, deadline); - if(dill_slow(rc == -1)) return -1; - /* Retrieve the error from the socket, if any. */ - int err = 0; - socklen_t errsz = sizeof(err); - rc = getsockopt(s, SOL_SOCKET, SO_ERROR, (void*)&err, &errsz); - if(dill_slow(rc != 0)) return -1; - if(dill_slow(err != 0)) {errno = err; return -1;} - return 0; -} - -int fd_accept(int s, struct sockaddr *addr, socklen_t *addrlen, - int64_t deadline) { - int as; - while(1) { - /* Try to accept new connection synchronously. */ - as = accept(s, addr, addrlen); - if(dill_fast(as >= 0)) - break; - /* If connection was aborted by the peer grab the next one. */ - if(dill_slow(errno == ECONNABORTED)) continue; - /* Propagate other errors to the caller. */ - if(dill_slow(errno != EAGAIN && errno != EWOULDBLOCK)) return -1; - /* Operation is in progress. Wait till new connection is available. */ - int rc = fdin(s, deadline); - if(dill_slow(rc < 0)) return -1; - } - int rc = fd_unblock(as); - if(dill_slow(rc < 0)) return -1; - return as; -} - -int fd_send(int s, struct iolist *first, struct iolist *last, - int64_t deadline) { - /* Make a local iovec array. */ - /* TODO: This is dangerous, it may cause stack overflow. - There should probably be a on-heap per-socket buffer for that. */ - size_t niov; - int rc = iol_check(first, last, &niov, NULL); - if(dill_slow(rc < 0)) return -1; - struct iovec iov[niov]; - iol_toiov(first, iov); - /* Message header will act as an iterator in the following loop. */ - struct msghdr hdr; - memset(&hdr, 0, sizeof(hdr)); - hdr.msg_iov = iov; - hdr.msg_iovlen = niov; - /* It is very likely that at least one byte can be sent. Therefore, - to improve efficiency, try to send and resort to fdout() only after - send failed. */ - while(1) { - while(hdr.msg_iovlen && !hdr.msg_iov[0].iov_len) { - hdr.msg_iov++; - hdr.msg_iovlen--; - } - if(!hdr.msg_iovlen) return 0; - ssize_t sz = sendmsg(s, &hdr, FD_NOSIGNAL); - dill_assert(sz != 0); - if(sz < 0) { - if(dill_slow(errno != EWOULDBLOCK && errno != EAGAIN)) { - if(errno == EPIPE) errno = ECONNRESET; - return -1; - } - sz = 0; - } - /* Adjust the iovec array so that it doesn't contain data - that was already sent. */ - while(sz) { - struct iovec *head = &hdr.msg_iov[0]; - if(head->iov_len > sz) { - head->iov_base += sz; - head->iov_len -= sz; - break; - } - sz -= head->iov_len; - hdr.msg_iov++; - hdr.msg_iovlen--; - if(!hdr.msg_iovlen) return 0; - } - /* Wait till more data can be sent. */ - int rc = fdout(s, deadline); - if(dill_slow(rc < 0)) return -1; - } -} - -/* Same as fd_recv() but with no rx buffering. */ -static ssize_t fd_recv_(int s, struct iolist *first, struct iolist *last, - int64_t deadline) { - /* Make a local iovec array. */ - /* TODO: This is dangerous, it may cause stack overflow. - There should probably be a on-heap per-socket buffer for that. */ - size_t niov; - int rc = iol_check(first, last, &niov, NULL); - if(dill_slow(rc < 0)) return -1; - struct iovec iov[niov]; - iol_toiov(first, iov); - /* Message header will act as an iterator in the following loop. */ - struct msghdr hdr; - memset(&hdr, 0, sizeof(hdr)); - hdr.msg_iov = iov; - hdr.msg_iovlen = niov; - while(1) { - ssize_t sz = recvmsg(s, &hdr, 0); - if(dill_slow(sz == 0)) {errno = EPIPE; return -1;} - if(sz < 0) { - if(dill_slow(errno != EWOULDBLOCK && errno != EAGAIN)) { - if(errno == EPIPE) errno = ECONNRESET; - return -1; - } - /* Wait for more data. */ - int rc = fdin(s, deadline); - if(dill_slow(rc < 0)) return -1; - continue; - } - return sz; - } -} - -/* Skip len bytes. If len is negative skip until error occurs. */ -static ssize_t fd_skip(int s, ssize_t len, int64_t deadline) { - uint8_t buf[512]; - while(len) { - size_t to_recv = len < 0 || len > sizeof(buf) ? sizeof(buf) : len; - struct iolist iol = {buf, to_recv, NULL, 0}; - int sz = fd_recv_(s, &iol, &iol, deadline); - if(dill_slow(sz < 0)) return -1; - if(len >= 0) len -= sz; - } - return 0; -} - -/* Copy data from rxbuf to one iolist structure. - Returns number of bytes copied. */ -static size_t fd_copy(struct fd_rxbuf *rxbuf, struct iolist *iol) { - size_t rmn = rxbuf->len - rxbuf->pos; - if(rmn < iol->iol_len) { - if(dill_fast(iol->iol_base)) - memcpy(iol->iol_base, rxbuf->data + rxbuf->pos, rmn); - rxbuf->len = 0; - rxbuf->pos = 0; - return rmn; - } - else { - if(dill_fast(iol->iol_base)) - memcpy(iol->iol_base, rxbuf->data + rxbuf->pos, iol->iol_len); - rxbuf->pos += iol->iol_len; - return iol->iol_len; - } -} - -ssize_t fd_recv(int s, struct fd_rxbuf *rxbuf, struct iolist *first, - struct iolist *last, int64_t deadline) { - /* Skip all data until error occurs. */ - if(dill_slow(!first && !last)) return fd_skip(s, -1, deadline); - /* Fill in data from the rxbuf. */ - size_t sz; - ssize_t read = 0; - while(1) { - sz = fd_copy(rxbuf, first); - read += sz; - if(sz < first->iol_len) break; - first = first->iol_next; - if(!first) return read; - } - /* Copy the current iolist element so that we can modify it without - changing the original list. */ - struct iolist curr; - curr.iol_base = first->iol_base ? first->iol_base + sz : NULL; - curr.iol_len = first->iol_len - sz; - curr.iol_next = first->iol_next; - curr.iol_rsvd = 0; - /* Find out how much data is still missing. */ - size_t miss = 0; - struct iolist *it = &curr; - while(it) { - miss += it->iol_len; - it = it->iol_next; - } - /* If requested amount of data is larger than rx buffer avoid the copy - and read it directly into user's buffer. */ - if(miss > sizeof(rxbuf->data)) - return read + fd_recv_(s, &curr, curr.iol_next ? last : &curr, deadline); - /* If small amount of data is requested use rx buffer. */ - while(1) { - /* Read as much data as possible to the buffer to avoid extra - syscalls. Do the speculative recv() first to avoid extra - polling. Do fdin() only after recv() fails to get data. */ - ssize_t sz = recv(s, rxbuf->data, sizeof(rxbuf->data), 0); - if(dill_slow(sz == 0)) {errno = EPIPE; return -1;} - if(sz < 0) { - if(dill_slow(errno != EWOULDBLOCK && errno != EAGAIN)) { - if(errno == EPIPE) errno = ECONNRESET; - return -1; - } - /* Wait for more data. */ - int rc = fdin(s, deadline); - if(dill_slow(rc < 0)) return -1; - continue; - } - rxbuf->len = sz; - rxbuf->pos = 0; - /* Copy the data from rxbuffer to the iolist. */ - while(1) { - sz = fd_copy(rxbuf, &curr); - read += sz; - if(sz < curr.iol_len) return read; - if(!curr.iol_next) return read; - curr = *curr.iol_next; - } - } -} - -void fd_close(int s) { - fdclean(s); - /* Discard any pending outbound data. If SO_LINGER option cannot - be set, never mind and continue anyway. */ - struct linger lng; - lng.l_onoff=1; - lng.l_linger=0; - setsockopt(s, SOL_SOCKET, SO_LINGER, (void*)&lng, sizeof(lng)); - /* We are not checking the error here. close() has inconsistent behaviour - and leaking a file descriptor is better than crashing the entire - program. */ - close(s); -} - diff --git a/Sources/CLibdill/fd.h b/Sources/CLibdill/fd.h deleted file mode 100644 index 25ca61d..0000000 --- a/Sources/CLibdill/fd.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - - Copyright (c) 2016 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#ifndef DILL_FD_INCLUDED -#define DILL_FD_INCLUDED - -#include -#include -#include - -#include "libdill.h" - -struct fd_rxbuf { - size_t len; - size_t pos; - uint8_t data[2000]; -}; - -void fd_initrxbuf( - struct fd_rxbuf *rxbuf); -int fd_unblock( - int s); -int fd_connect( - int s, - const struct sockaddr *addr, - socklen_t addrlen, - int64_t deadline); -int fd_accept( - int s, - struct sockaddr *addr, - socklen_t *addrlen, - int64_t deadline); -int fd_send( - int s, - struct iolist *first, - struct iolist *last, - int64_t deadline); -ssize_t fd_recv( - int s, - struct fd_rxbuf *rxbuf, - struct iolist *first, - struct iolist *last, - int64_t deadline); -void fd_close( - int s); - -#endif - diff --git a/Sources/CLibdill/handle.c b/Sources/CLibdill/handle.c deleted file mode 100644 index afa73de..0000000 --- a/Sources/CLibdill/handle.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - - Copyright (c) 2016 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#include -#include -#include -#include -#include -#include - -#include "cr.h" -#include "handle.h" -#include "libdillimpl.h" -#include "utils.h" -#include "ctx.h" - -struct dill_handle { - /* Table of virtual functions. */ - struct hvfs *vfs; - /* Index of the next handle in the linked list of unused handles. -1 means - 'the end of the list'. -2 means 'handle is in use'. */ - int next; - /* Cache the last call to hquery. */ - const void *type; - void *ptr; -}; - -#define CHECKHANDLE(h, err) \ - if(dill_slow((h) < 0 || (h) >= ctx->nhandles ||\ - ctx->handles[(h)].next != -2)) {\ - errno = EBADF; return (err);}\ - struct dill_handle *hndl = &ctx->handles[(h)]; - -int dill_ctx_handle_init(struct dill_ctx_handle *ctx) { - ctx->handles = NULL; - ctx->nhandles = 0; - ctx->unused = -1; - return 0; -} - -void dill_ctx_handle_term(struct dill_ctx_handle *ctx) { - free(ctx->handles); -} - -int hmake(struct hvfs *vfs) { - struct dill_ctx_handle *ctx = &dill_getctx->handle; - if(dill_slow(!vfs || !vfs->query || !vfs->close)) { - errno = EINVAL; return -1;} - /* Returns ECANCELED if shutting down. */ - int rc = dill_canblock(); - if(dill_slow(rc < 0)) return -1; - /* If there's no space for the new handle, expand the array. */ - if(dill_slow(ctx->unused == -1)) { - /* Start with 256 handles, double the size when needed. */ - int sz = ctx->nhandles ? ctx->nhandles * 2 : 256; - struct dill_handle *hndls = - realloc(ctx->handles, sz * sizeof(struct dill_handle)); - if(dill_slow(!hndls)) {errno = ENOMEM; return -1;} - /* Add newly allocated handles to the list of unused handles. */ - int i; - for(i = ctx->nhandles; i != sz - 1; ++i) - hndls[i].next = i + 1; - hndls[sz - 1].next = -1; - ctx->unused = ctx->nhandles; - /* Adjust the array. */ - ctx->handles = hndls; - ctx->nhandles = sz; - } - /* Return first handle from the list of unused handles. */ - int h = ctx->unused; - ctx->unused = ctx->handles[h].next; - vfs->refcount = 1; - ctx->handles[h].vfs = vfs; - ctx->handles[h].next = -2; - ctx->handles[h].type = NULL; - ctx->handles[h].ptr = NULL; - return h; -} - -int hdup(int h) { - struct dill_ctx_handle *ctx = &dill_getctx->handle; - CHECKHANDLE(h, -1); - int refcount = hndl->vfs->refcount; - int res = hmake(hndl->vfs); - if(dill_slow(res < 0)) return -1; - ctx->handles[res].vfs->refcount = refcount + 1; - return res; -} - -void *hquery(int h, const void *type) { - struct dill_ctx_handle *ctx = &dill_getctx->handle; - CHECKHANDLE(h, NULL); - /* Try and use the cached pointer first; otherwise do the expensive virtual call.*/ - if(dill_fast(hndl->ptr != NULL && hndl->type == type)) - return hndl->ptr; - else { - void *ptr = hndl->vfs->query(hndl->vfs, type); - if(dill_slow(!ptr)) return NULL; - /* Update cache. */ - hndl->type = type; - hndl->ptr = ptr; - return ptr; - } -} - -int hclose(int h) { - struct dill_ctx_handle *ctx = &dill_getctx->handle; - CHECKHANDLE(h, -1); - /* If there are multiple duplicates of this handle, just remove one reference. */ - if(hndl->vfs->refcount > 1) { - --hndl->vfs->refcount; - return 0; - } - /* This will guarantee that blocking functions cannot be called anywhere - inside the context of the close. */ - int old = dill_no_blocking(1); - /* Send the stop signal to the handle. */ - hndl->vfs->close(hndl->vfs); - /* Restore the previous state. */ - dill_no_blocking(old); - /* Mark the cache as invalid. */ - hndl->ptr = NULL; - /* Return a handle to the shared pool. */ - hndl->next = ctx->unused; - ctx->unused = h; - return 0; -} - -int hdone(int h, int64_t deadline) { - struct dill_ctx_handle *ctx = &dill_getctx->handle; - CHECKHANDLE(h, -1); - if(dill_slow(!hndl->vfs->done)) {errno = ENOTSUP; return -1;} - return hndl->vfs->done(hndl->vfs, deadline); -} - diff --git a/Sources/CLibdill/handle.h b/Sources/CLibdill/handle.h deleted file mode 100644 index 719f605..0000000 --- a/Sources/CLibdill/handle.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - - Copyright (c) 2016 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#ifndef DILL_HANDLE_INCLUDED -#define DILL_HANDLE_INCLUDED - -struct dill_handle; - -struct dill_ctx_handle { - /* Array of handles. The size of the array is stored in 'nhandles'. */ - struct dill_handle *handles; - int nhandles; - /* Points to the first item in the list of unused handles. */ - int unused; -}; - -int dill_ctx_handle_init(struct dill_ctx_handle *ctx); -void dill_ctx_handle_term(struct dill_ctx_handle *ctx); - -#endif - diff --git a/Sources/CLibdill/include/libdill.h b/Sources/CLibdill/include/libdill.h deleted file mode 120000 index 0153301..0000000 --- a/Sources/CLibdill/include/libdill.h +++ /dev/null @@ -1 +0,0 @@ -../libdill.h \ No newline at end of file diff --git a/Sources/CLibdill/include/libdillimpl.h b/Sources/CLibdill/include/libdillimpl.h deleted file mode 120000 index e150960..0000000 --- a/Sources/CLibdill/include/libdillimpl.h +++ /dev/null @@ -1 +0,0 @@ -../libdillimpl.h \ No newline at end of file diff --git a/Sources/CLibdill/iol.c b/Sources/CLibdill/iol.c deleted file mode 100644 index 51c89f6..0000000 --- a/Sources/CLibdill/iol.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - - Copyright (c) 2017 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#include - -#include "iol.h" -#include "utils.h" - -int iol_check(struct iolist *first, struct iolist *last, - size_t *nbufs, size_t *nbytes) { - if(dill_slow(!first || !last || last->iol_next)) { - errno = EINVAL; return -1;} - size_t nbf = 0, nbt = 0, res = 0; - struct iolist *it; - for(it = first; it; it = it->iol_next) { - if(dill_slow(it->iol_rsvd || (!it->iol_next && it != last))) - goto error; - it->iol_rsvd = 1; - nbf++; - nbt += it->iol_len; - } - for(it = first; it; it = it->iol_next) it->iol_rsvd = 0; - if(nbufs) *nbufs = nbf; - if(nbytes) *nbytes = nbt; - return 0; -error:; - struct iolist *it2; - for(it2 = first; it2 != it; it2 = it2->iol_next) it->iol_rsvd = 0; - errno = EINVAL; - return -1; -} - -void iol_toiov(struct iolist *first, struct iovec *iov) { - while(first) { - iov->iov_base = first->iol_base; - iov->iov_len = first->iol_len; - ++iov; - first = first->iol_next; - } -} - diff --git a/Sources/CLibdill/iol.h b/Sources/CLibdill/iol.h deleted file mode 100644 index 74b8fa4..0000000 --- a/Sources/CLibdill/iol.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - - Copyright (c) 2017 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#ifndef DILL_IOL_INCLUDED -#define DILL_IOL_INCLUDED - -#include - -#include "libdill.h" - -/* Checks whether iolist is valid. Returns 0 in case of success or -1 in case - of error. Fills in number of buffers in the list and overall number of bytes - if requested. */ -int iol_check(struct iolist *first, struct iolist *last, - size_t *nbufs, size_t *nbytes); - -/* Copy the iolist into an iovec. Iovec must have at least as much elements - as the iolist, otherwise undefined behaviour ensues. The data buffers - as such are not affected by this operation .*/ -void iol_toiov(struct iolist *first, struct iovec *iov); - -#endif - diff --git a/Sources/CLibdill/ipaddr.c b/Sources/CLibdill/ipaddr.c deleted file mode 100644 index ba437dd..0000000 --- a/Sources/CLibdill/ipaddr.c +++ /dev/null @@ -1,380 +0,0 @@ -/* - - Copyright (c) 2015 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#if defined __linux__ -#define _GNU_SOURCE -#include -#include -#endif - -#include -#include -#include -#include -#include -#include -#if !defined __sun -#include -#endif -#include -#include -#include - -#include "dns/dns.h" - -#include "libdill.h" -#include "utils.h" - -/* Make sure that both IPv4 and IPv6 address fits into ipaddr. */ -DILL_CT_ASSERT(sizeof(struct ipaddr) >= sizeof(struct sockaddr_in)); -DILL_CT_ASSERT(sizeof(struct ipaddr) >= sizeof(struct sockaddr_in6)); - -static struct dns_resolv_conf *dill_dns_conf = NULL; -static struct dns_hosts *dill_dns_hosts = NULL; -static struct dns_hints *dill_dns_hints = NULL; - -static int ipaddr_ipany(struct ipaddr *addr, int port, int mode) -{ - if(dill_slow(port < 0 || port > 0xffff)) {errno = EINVAL; return -1;} - if (mode == 0 || mode == IPADDR_IPV4 || mode == IPADDR_PREF_IPV4) { - struct sockaddr_in *ipv4 = (struct sockaddr_in*)addr; - ipv4->sin_family = AF_INET; - ipv4->sin_addr.s_addr = htonl(INADDR_ANY); - ipv4->sin_port = htons((uint16_t)port); -#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - ipv4->sin_len = sizeof(struct sockaddr_in); -#endif - return 0; - } - else { - struct sockaddr_in6 *ipv6 = (struct sockaddr_in6*)addr; - ipv6->sin6_family = AF_INET6; - memcpy(&ipv6->sin6_addr, &in6addr_any, sizeof(in6addr_any)); - ipv6->sin6_port = htons((uint16_t)port); -#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - ipv6->sin6_len = sizeof(struct sockaddr_in6); -#endif - return 0; - } -} - -/* Convert literal IPv4 address to a binary one. */ -static int ipaddr_ipv4_literal(struct ipaddr *addr, const char *name, - int port) { - struct sockaddr_in *ipv4 = (struct sockaddr_in*)addr; - int rc = inet_pton(AF_INET, name, &ipv4->sin_addr); - dill_assert(rc >= 0); - if(dill_slow(rc != 1)) {errno = EINVAL; return -1;} - ipv4->sin_family = AF_INET; - ipv4->sin_port = htons((uint16_t)port); -#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - ipv4->sin_len = sizeof(struct sockaddr_in); -#endif - return 0; -} - -/* Convert literal IPv6 address to a binary one. */ -static int ipaddr_ipv6_literal(struct ipaddr *addr, const char *name, - int port) { - struct sockaddr_in6 *ipv6 = (struct sockaddr_in6*)addr; - int rc = inet_pton(AF_INET6, name, &ipv6->sin6_addr); - dill_assert(rc >= 0); - if(dill_slow(rc != 1)) {errno = EINVAL; return -1;} - ipv6->sin6_family = AF_INET6; - ipv6->sin6_port = htons((uint16_t)port); -#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - ipv6->sin6_len = sizeof(struct sockaddr_in6); -#endif - return 0; -} - -/* Convert literal IPv4 or IPv6 address to a binary one. */ -static int ipaddr_literal(struct ipaddr *addr, const char *name, int port, - int mode) { - if(dill_slow(!addr || port < 0 || port > 0xffff)) { - errno = EINVAL; - return -1; - } - int rc; - switch(mode) { - case IPADDR_IPV4: - return ipaddr_ipv4_literal(addr, name, port); - case IPADDR_IPV6: - return ipaddr_ipv6_literal(addr, name, port); - case 0: - case IPADDR_PREF_IPV4: - rc = ipaddr_ipv4_literal(addr, name, port); - if(rc == 0) - return 0; - return ipaddr_ipv6_literal(addr, name, port); - case IPADDR_PREF_IPV6: - rc = ipaddr_ipv6_literal(addr, name, port); - if(rc == 0) - return 0; - return ipaddr_ipv4_literal(addr, name, port); - default: - dill_assert(0); - } -} - -int ipaddr_family(const struct ipaddr *addr) { - return ((struct sockaddr*)addr)->sa_family; -} - -int ipaddr_len(const struct ipaddr *addr) { - return ipaddr_family(addr) == AF_INET ? - sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); -} - -const struct sockaddr *ipaddr_sockaddr(const struct ipaddr *addr) { - return (const struct sockaddr*)addr; -} - -int ipaddr_port(const struct ipaddr *addr) { - return ntohs(ipaddr_family(addr) == AF_INET ? - ((struct sockaddr_in*)addr)->sin_port : - ((struct sockaddr_in6*)addr)->sin6_port); -} - -void ipaddr_setport(struct ipaddr *addr, int port) { - if(ipaddr_family(addr) == AF_INET) - ((struct sockaddr_in*)addr)->sin_port = htons(port); - else - ((struct sockaddr_in6*)addr)->sin6_port = htons(port); -} - -/* Convert IP address from network format to ASCII dot notation. */ -const char *ipaddr_str(const struct ipaddr *addr, char *ipstr) { - if(ipaddr_family(addr) == AF_INET) { - return inet_ntop(AF_INET, &(((struct sockaddr_in*)addr)->sin_addr), - ipstr, INET_ADDRSTRLEN); - } - else { - return inet_ntop(AF_INET6, &(((struct sockaddr_in6*)addr)->sin6_addr), - ipstr, INET6_ADDRSTRLEN); - } -} - -int ipaddr_local(struct ipaddr *addr, const char *name, int port, int mode) { - if(!name) - return ipaddr_ipany(addr, port, mode); - int rc = ipaddr_literal(addr, name, port, mode); -#if defined __sun - return rc; -#else - if(rc == 0) - return 0; - /* Address is not a literal. It must be an interface name then. */ - struct ifaddrs *ifaces = NULL; - rc = getifaddrs (&ifaces); - dill_assert (rc == 0); - dill_assert (ifaces); - /* Find first IPv4 and first IPv6 address. */ - struct ifaddrs *ipv4 = NULL; - struct ifaddrs *ipv6 = NULL; - struct ifaddrs *it; - for(it = ifaces; it != NULL; it = it->ifa_next) { - if(!it->ifa_addr) - continue; - if(strcmp(it->ifa_name, name) != 0) - continue; - switch(it->ifa_addr->sa_family) { - case AF_INET: - dill_assert(!ipv4); - ipv4 = it; - break; - case AF_INET6: - dill_assert(!ipv6); - ipv6 = it; - break; - } - if(ipv4 && ipv6) - break; - } - /* Choose the correct address family based on mode. */ - switch(mode) { - case IPADDR_IPV4: - ipv6 = NULL; - break; - case IPADDR_IPV6: - ipv4 = NULL; - break; - case 0: - case IPADDR_PREF_IPV4: - if(ipv4) - ipv6 = NULL; - break; - case IPADDR_PREF_IPV6: - if(ipv6) - ipv4 = NULL; - break; - default: - dill_assert(0); - } - if(ipv4) { - struct sockaddr_in *inaddr = (struct sockaddr_in*)addr; - memcpy(inaddr, ipv4->ifa_addr, sizeof (struct sockaddr_in)); - inaddr->sin_port = htons(port); - freeifaddrs(ifaces); - return 0; - } - if(ipv6) { - struct sockaddr_in6 *inaddr = (struct sockaddr_in6*)addr; - memcpy(inaddr, ipv6->ifa_addr, sizeof (struct sockaddr_in6)); - inaddr->sin6_port = htons(port); - freeifaddrs(ifaces); - return 0; - } - freeifaddrs(ifaces); - errno = ENODEV; - return -1; -#endif -} - -static void dns_freeaddrinfo(struct addrinfo *ent) { - free(ent); -} - -int ipaddr_remote(struct ipaddr *addr, const char *name, int port, int mode, - int64_t deadline) { - int rc = ipaddr_literal(addr, name, port, mode); - if(rc == 0) - return 0; - /* Load DNS config files, unless they are already chached. */ - if(dill_slow(!dill_dns_conf)) { - /* TODO: Maybe re-read the configuration once in a while? */ - dill_dns_conf = dns_resconf_local(&rc); - if(!dill_dns_conf) { - errno = ENOENT; - return -1; - } - dill_dns_hosts = dns_hosts_local(&rc); - dill_assert(dill_dns_hosts); - dill_dns_hints = dns_hints_local(dill_dns_conf, &rc); - dill_assert(dill_dns_hints); - } - /* Let's do asynchronous DNS query here. */ - struct dns_resolver *resolver = dns_res_open(dill_dns_conf, - dill_dns_hosts, dill_dns_hints, NULL, dns_opts(), &rc); - if(!resolver) { - if(errno == ENFILE || errno == EMFILE) { - return -1; - } - dill_assert(resolver); - } - dill_assert(port >= 0 && port <= 0xffff); - char portstr[8]; - snprintf(portstr, sizeof(portstr), "%d", port); - struct addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - struct dns_addrinfo *ai = dns_ai_open(name, portstr, DNS_T_A, &hints, - resolver, &rc); - dill_assert(ai); - dns_res_close(resolver); - struct addrinfo *ipv4 = NULL; - struct addrinfo *ipv6 = NULL; - struct addrinfo *it = NULL; - while(1) { - rc = dns_ai_nextent(&it, ai); - if(rc == EAGAIN) { - int fd = dns_ai_pollfd(ai); - int events = dns_ai_events(ai); - dill_assert(fd >= 0); - int rc = (events & DNS_POLLOUT) - ? fdout(fd, deadline) : fdin(fd, deadline); - /* There's no guarantee that the file descriptor will be reused - in next iteration. We have to clean the fdwait cache here - to be on the safe side. */ - int err = errno; - fdclean(fd); - errno = err; - if(dill_slow(rc < 0)) { - dns_ai_close(ai); - return -1; - } - continue; - } - if(rc == ENOENT || (rc >= DNS_EBASE && rc <= DNS_ELAST)) - break; - if(!ipv4 && it && it->ai_family == AF_INET) { - ipv4 = it; - it = NULL; - } - if(!ipv6 && it && it->ai_family == AF_INET6) { - ipv6 = it; - it = NULL; - } - dns_freeaddrinfo(it); /* Ended up useless */ - if(ipv4 && ipv6) - break; - } - switch(mode) { - case IPADDR_IPV4: - dns_freeaddrinfo(ipv6); - ipv6 = NULL; - break; - case IPADDR_IPV6: - dns_freeaddrinfo(ipv4); - ipv4 = NULL; - break; - case 0: - case IPADDR_PREF_IPV4: - if(ipv4) { - dns_freeaddrinfo(ipv6); - ipv6 = NULL; - } - break; - case IPADDR_PREF_IPV6: - if(ipv6) { - dns_freeaddrinfo(ipv4); - ipv4 = NULL; - } - break; - default: - dill_assert(0); - } - if(ipv4) { - struct sockaddr_in *inaddr = (struct sockaddr_in*)addr; - memcpy(inaddr, ipv4->ai_addr, sizeof (struct sockaddr_in)); - inaddr->sin_port = htons(port); - dns_freeaddrinfo(ipv4); - dns_freeaddrinfo(ipv6); - dns_ai_close(ai); - return 0; - } - if(ipv6) { - struct sockaddr_in6 *inaddr = (struct sockaddr_in6*)addr; - memcpy(inaddr, ipv6->ai_addr, sizeof (struct sockaddr_in6)); - inaddr->sin6_port = htons(port); - dns_freeaddrinfo(ipv4); - dns_freeaddrinfo(ipv6); - dns_ai_close(ai); - return 0; - } - dns_ai_close(ai); - errno = EADDRNOTAVAIL; - return -1; -} - diff --git a/Sources/CLibdill/ipc.c b/Sources/CLibdill/ipc.c deleted file mode 100644 index 9ff6fb4..0000000 --- a/Sources/CLibdill/ipc.c +++ /dev/null @@ -1,323 +0,0 @@ -/* - - Copyright (c) 2017 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#include -#include -#include -#include -#include - -#include "libdillimpl.h" -#include "fd.h" -#include "utils.h" - -static int ipc_resolve(const char *addr, struct sockaddr_un *su); -static int ipc_makeconn(int fd); - -/******************************************************************************/ -/* UNIX connection socket */ -/******************************************************************************/ - -dill_unique_id(ipc_type); - -static void *ipc_hquery(struct hvfs *hvfs, const void *type); -static void ipc_hclose(struct hvfs *hvfs); -static int ipc_hdone(struct hvfs *hvfs, int64_t deadline); -static int ipc_bsendl(struct bsock_vfs *bvfs, - struct iolist *first, struct iolist *last, int64_t deadline); -static ssize_t ipc_brecvl(struct bsock_vfs *bvfs, - struct iolist *first, struct iolist *last, int64_t deadline); - -struct ipc_conn { - struct hvfs hvfs; - struct bsock_vfs bvfs; - int fd; - struct fd_rxbuf rxbuf; - unsigned int indone : 1; - unsigned int outdone : 1; - unsigned int inerr : 1; - unsigned int outerr : 1; -}; - -static void *ipc_hquery(struct hvfs *hvfs, const void *type) { - struct ipc_conn *self = (struct ipc_conn*)hvfs; - if(type == bsock_type) return &self->bvfs; - if(type == ipc_type) return self; - errno = ENOTSUP; - return NULL; -} - -int ipc_connect(const char *addr, int64_t deadline) { - int err; - /* Create a UNIX address out of the address string. */ - struct sockaddr_un su; - int rc = ipc_resolve(addr, &su); - if(rc < 0) {err = errno; goto error1;} - /* Open a socket. */ - int s = socket(AF_UNIX, SOCK_STREAM, 0); - if(dill_slow(s < 0)) {err = errno; goto error1;} - /* Set it to non-blocking mode. */ - rc = fd_unblock(s); - if(dill_slow(rc < 0)) {err = errno; goto error2;} - /* Connect to the remote endpoint. */ - rc = fd_connect(s, (struct sockaddr*)&su, sizeof(su), deadline); - if(dill_slow(rc < 0)) {err = errno; goto error2;} - /* Create the handle. */ - int h = ipc_makeconn(s); - if(dill_slow(h < 0)) {err = errno; goto error2;} - return h; -error2: - fd_close(s); -error1: - errno = err; - return -1; -} - -static int ipc_bsendl(struct bsock_vfs *bvfs, - struct iolist *first, struct iolist *last, int64_t deadline) { - struct ipc_conn *self = dill_cont(bvfs, struct ipc_conn, bvfs); - if(dill_slow(self->outdone)) {errno = EPIPE; return -1;} - if(dill_slow(self->outerr)) {errno = ECONNRESET; return -1;} - ssize_t sz = fd_send(self->fd, first, last, deadline); - if(dill_fast(sz >= 0)) return sz; - self->outerr = 1; - return -1; -} - -static ssize_t ipc_brecvl(struct bsock_vfs *bvfs, - struct iolist *first, struct iolist *last, int64_t deadline) { - struct ipc_conn *self = dill_cont(bvfs, struct ipc_conn, bvfs); - if(dill_slow(self->indone)) {errno = EPIPE; return -1;} - if(dill_slow(self->inerr)) {errno = ECONNRESET; return -1;} - int sz = fd_recv(self->fd, &self->rxbuf, first, last, deadline); - if(dill_fast(sz > 0)) return sz; - if(errno == EPIPE) self->indone = 1; - else self->inerr = 1; - return -1; -} - -static int ipc_hdone(struct hvfs *hvfs, int64_t deadline) { - struct ipc_conn *self = (struct ipc_conn*)hvfs; - if(dill_slow(self->outdone)) {errno = EPIPE; return -1;} - if(dill_slow(self->outerr)) {errno = ECONNRESET; return -1;} - /* Shutdown is done asynchronously on kernel level. - No need to use the deadline. */ - int rc = shutdown(self->fd, SHUT_WR); - if(dill_slow(rc < 0)) { - if(errno == ENOTCONN) {self->outerr = 1; errno = ECONNRESET; return -1;} - if(errno == ENOBUFS) {self->outerr = 1; errno = ENOMEM; return -1;} - dill_assert(0); - } - self->outdone = 1; - return 0; -} - -int ipc_close(int s, int64_t deadline) { - int err; - struct ipc_conn *self = hquery(s, ipc_type); - if(dill_slow(!self)) return -1; - if(dill_slow(self->inerr || self->outerr)) {err = ECONNRESET; goto error;} - /* If not done already, flush the outbound data and start the terminal - handshake. */ - if(!self->outdone) { - int rc = ipc_hdone(&self->hvfs, deadline); - if(dill_slow(rc < 0)) {err = errno; goto error;} - } - /* Now we are going to read all the inbound data until we reach end of the - stream. That way we can be sure that the peer either received all our - data or consciously closed the connection without reading all of it. */ - int rc = ipc_brecvl(&self->bvfs, NULL, NULL, deadline); - dill_assert(rc < 0); - if(dill_slow(errno != EPIPE)) {err = errno; goto error;} - return 0; -error: - ipc_hclose(&self->hvfs); - errno = err; - return -1; -} - -static void ipc_hclose(struct hvfs *hvfs) { - struct ipc_conn *self = (struct ipc_conn*)hvfs; - fd_close(self->fd); - free(self); -} - -/******************************************************************************/ -/* UNIX listener socket */ -/******************************************************************************/ - -dill_unique_id(ipc_listener_type); - -static void *ipc_listener_hquery(struct hvfs *hvfs, const void *type); -static void ipc_listener_hclose(struct hvfs *hvfs); - -struct ipc_listener { - struct hvfs hvfs; - int fd; -}; - -static void *ipc_listener_hquery(struct hvfs *hvfs, const void *type) { - struct ipc_listener *self = (struct ipc_listener*)hvfs; - if(type == ipc_listener_type) return self; - errno = ENOTSUP; - return NULL; -} - -int ipc_listen(const char *addr, int backlog) { - int err; - /* Create a UNIX address out of the address string. */ - struct sockaddr_un su; - int rc = ipc_resolve(addr, &su); - if(rc < 0) {err = errno; goto error1;} - /* Open the listening socket. */ - int s = socket(AF_UNIX, SOCK_STREAM, 0); - if(dill_slow(s < 0)) {err = errno; goto error1;} - /* Set it to non-blocking mode. */ - rc = fd_unblock(s); - if(dill_slow(rc < 0)) {err = errno; goto error2;} - /* Start listening for incoming connections. */ - rc = bind(s, (struct sockaddr*)&su, sizeof(su)); - if(dill_slow(rc < 0)) {err = errno; goto error2;} - rc = listen(s, backlog); - if(dill_slow(rc < 0)) {err = errno; goto error2;} - /* Create the object. */ - struct ipc_listener *self = malloc(sizeof(struct ipc_listener)); - if(dill_slow(!self)) {err = ENOMEM; goto error2;} - self->hvfs.query = ipc_listener_hquery; - self->hvfs.close = ipc_listener_hclose; - self->hvfs.done = NULL; - self->fd = s; - /* Create handle. */ - int h = hmake(&self->hvfs); - if(dill_slow(h < 0)) {err = errno; goto error3;} - return h; -error3: - free(self); -error2: - close(s); -error1: - errno = err; - return -1; -} - -int ipc_accept(int s, int64_t deadline) { - int err; - /* Retrieve the listener object. */ - struct ipc_listener *lst = hquery(s, ipc_listener_type); - if(dill_slow(!lst)) {err = errno; goto error1;} - /* Try to get new connection in a non-blocking way. */ - int as = fd_accept(lst->fd, NULL, NULL, deadline); - if(dill_slow(as < 0)) {err = errno; goto error1;} - /* Set it to non-blocking mode. */ - int rc = fd_unblock(as); - if(dill_slow(rc < 0)) {err = errno; goto error2;} - /* Create the handle. */ - int h = ipc_makeconn(as); - if(dill_slow(h < 0)) {err = errno; goto error2;} - return h; -error2: - fd_close(as); -error1: - errno = err; - return -1; -} - -static void ipc_listener_hclose(struct hvfs *hvfs) { - struct ipc_listener *self = (struct ipc_listener*)hvfs; - fd_close(self->fd); - free(self); -} - -/******************************************************************************/ -/* UNIX pair */ -/******************************************************************************/ - -int ipc_pair(int s[2]) { - int err; - /* Create the pair. */ - int fds[2]; - int rc = socketpair(AF_UNIX, SOCK_STREAM, 0, fds); - if(rc < 0) {err = errno; goto error1;} - /* Set the sockets to non-blocking mode. */ - rc = fd_unblock(fds[0]); - if(dill_slow(rc < 0)) {err = errno; goto error3;} - rc = fd_unblock(fds[1]); - if(dill_slow(rc < 0)) {err = errno; goto error3;} - /* Create the handles. */ - s[0] = ipc_makeconn(fds[0]); - if(dill_slow(s[0] < 0)) {err = errno; goto error3;} - s[1] = ipc_makeconn(fds[1]); - if(dill_slow(s[1] < 0)) {err = errno; goto error4;} - return 0; -error4: - rc = hclose(s[0]); - goto error2; -error3: - fd_close(fds[0]); -error2: - fd_close(fds[1]); -error1: - errno = err; - return -1; -} - -/******************************************************************************/ -/* Helpers */ -/******************************************************************************/ - -static int ipc_resolve(const char *addr, struct sockaddr_un *su) { - dill_assert(su); - if(strlen(addr) >= sizeof(su->sun_path)) {errno = ENAMETOOLONG; return -1;} - su->sun_family = AF_UNIX; - strncpy(su->sun_path, addr, sizeof(su->sun_path)); - return 0; -} - -static int ipc_makeconn(int fd) { - int err; - /* Create the object. */ - struct ipc_conn *self = malloc(sizeof(struct ipc_conn)); - if(dill_slow(!self)) {err = ENOMEM; goto error1;} - self->hvfs.query = ipc_hquery; - self->hvfs.close = ipc_hclose; - self->hvfs.done = ipc_hdone; - self->bvfs.bsendl = ipc_bsendl; - self->bvfs.brecvl = ipc_brecvl; - self->fd = fd; - fd_initrxbuf(&self->rxbuf); - self->indone = 0; - self->outdone = 0; - self->inerr = 0; - self->outerr = 0; - /* Create the handle. */ - int h = hmake(&self->hvfs); - if(dill_slow(h < 0)) {err = errno; goto error2;} - return h; -error2: - free(self); -error1: - errno = err; - return -1; -} - diff --git a/Sources/CLibdill/kqueue.c.inc b/Sources/CLibdill/kqueue.c.inc deleted file mode 100644 index 92a0674..0000000 --- a/Sources/CLibdill/kqueue.c.inc +++ /dev/null @@ -1,307 +0,0 @@ -/* - - Copyright (c) 2016 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cr.h" -#include "list.h" -#include "pollset.h" -#include "utils.h" -#include "ctx.h" - -#define DILL_ENDLIST 0xffffffff - -#define DILL_CHNGSSIZE 128 -#define DILL_EVSSIZE 128 - -#define FDW_IN 1 -#define FDW_OUT 2 - -struct dill_fdinfo { - struct dill_fdclause *in; - struct dill_fdclause *out; - uint16_t currevs; - uint16_t firing; - /* 1-based index, 0 stands for "not part of the list", DILL_ENDLIST - stands for "no more elements in the list. */ - uint32_t next; - /* 1 if the file descriptor is cached. 0 otherwise. */ - unsigned int cached : 1; -}; - -int dill_ctx_pollset_init(struct dill_ctx_pollset *ctx) { - int err; - /* Allocate one info per fd. */ - ctx->nfdinfos = dill_maxfds(); - ctx->fdinfos = calloc(ctx->nfdinfos, sizeof(struct dill_fdinfo)); - if(dill_slow(!ctx->fdinfos)) {err = ENOMEM; goto error1;} - /* Changelist is empty. */ - ctx->changelist = DILL_ENDLIST; - /* Create kernel-side pollset. */ - ctx->kfd = kqueue(); - if(dill_slow(ctx->kfd < 0)) {err = errno; goto error2;} - return 0; -error2: - free(ctx->fdinfos); - ctx->fdinfos = NULL; -error1: - errno = err; - return -1; -} - -void dill_ctx_pollset_term(struct dill_ctx_pollset *ctx) { - /* Kqueue documentation says that a kqueue descriptor won't - survive a fork. However, implementations seem to disagree. - On FreeBSD the following function succeeds. On OSX it returns - EACCESS. Therefore we ignore the return value. */ - close(ctx->kfd); - free(ctx->fdinfos); -} - -static void dill_fdcancelin(struct dill_clause *cl) { - struct dill_fdinfo *fdinfo = - dill_cont(cl, struct dill_fdclause, cl)->fdinfo; - fdinfo->in = NULL; - if(!fdinfo->next) { - struct dill_ctx_pollset *ctx = &dill_getctx->pollset; - fdinfo->next = ctx->changelist; - ctx->changelist = fdinfo - ctx->fdinfos + 1; - } -} - -static void dill_fdcancelout(struct dill_clause *cl) { - struct dill_fdinfo *fdinfo = - dill_cont(cl, struct dill_fdclause, cl)->fdinfo; - fdinfo->out = NULL; - if(!fdinfo->next) { - struct dill_ctx_pollset *ctx = &dill_getctx->pollset; - fdinfo->next = ctx->changelist; - ctx->changelist = fdinfo - ctx->fdinfos + 1; - } -} - -int dill_pollset_in(struct dill_fdclause *fdcl, int id, int fd) { - struct dill_ctx_pollset *ctx = &dill_getctx->pollset; - if(dill_slow(fd < 0 || fd >= ctx->nfdinfos)) {errno = EBADF; return -1;} - struct dill_fdinfo *fdi = &ctx->fdinfos[fd]; - /* If not yet cached, check whether fd exists and if so add it - to pollset. */ - if(dill_slow(!fdi->cached)) { - struct kevent ev; - EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0); - int rc = kevent(ctx->kfd, &ev, 1, NULL, 0, NULL); - if(dill_slow(rc < 0 && errno == EBADF)) return -1; - dill_assert(rc >= 0); - fdi->in = NULL; - fdi->out = NULL; - fdi->currevs = FDW_IN; - fdi->firing = 0; - fdi->next = 0; - fdi->cached = 1; - } - if(dill_slow(fdi->in)) {errno = EBUSY; return -1;} - /* If fd is not yet in the pollset, add it there. */ - else if(!fdi->next) { - fdi->next = ctx->changelist; - ctx->changelist = fd + 1; - } - fdcl->fdinfo = fdi; - fdi->in = fdcl; - dill_waitfor(&fdcl->cl, id, dill_fdcancelin); - return 0; -} - -int dill_pollset_out(struct dill_fdclause *fdcl, int id, int fd) { - struct dill_ctx_pollset *ctx = &dill_getctx->pollset; - if(dill_slow(fd < 0 || fd >= ctx->nfdinfos)) {errno = EBADF; return -1;} - struct dill_fdinfo *fdi = &ctx->fdinfos[fd]; - /* If not yet cached, check whether the fd exists and if it does, - add it to the pollset. */ - if(dill_slow(!fdi->cached)) { - struct kevent ev; - EV_SET(&ev, fd, EVFILT_WRITE, EV_ADD, 0, 0, 0); - int rc = kevent(ctx->kfd, &ev, 1, NULL, 0, NULL); - if(dill_slow(rc < 0 && errno == EBADF)) return -1; - dill_assert(rc >= 0); - fdi->in = NULL; - fdi->out = NULL; - fdi->currevs = FDW_OUT; - fdi->firing = 0; - fdi->next = 0; - fdi->cached = 1; - } - if(dill_slow(fdi->out)) {errno = EBUSY; return -1;} - /* If the fd is not yet in the pollset, add it there. */ - else if(!fdi->next) { - fdi->next = ctx->changelist; - ctx->changelist = fd + 1; - } - fdcl->fdinfo = fdi; - fdi->out = fdcl; - dill_waitfor(&fdcl->cl, id, dill_fdcancelout); - return 0; -} - -int dill_pollset_clean(int fd) { - struct dill_ctx_pollset *ctx = &dill_getctx->pollset; - struct dill_fdinfo *fdi = &ctx->fdinfos[fd]; - if(!fdi->cached) return 0; - /* We cannot clean an fd that someone is waiting for. */ - if(dill_slow(fdi->in || fdi->out)) {errno = EBUSY; return -1;} - /* Remove the file descriptor from the pollset if it is still there. */ - int nevs = 0; - struct kevent evs[2]; - if(fdi->currevs & FDW_IN) { - EV_SET(&evs[nevs], fd, EVFILT_READ, EV_DELETE, 0, 0, 0); - ++nevs; - } - if(fdi->currevs & FDW_OUT) { - EV_SET(&evs[nevs], fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0); - ++nevs; - } - if(nevs) { - int rc = kevent(ctx->kfd, evs, nevs, NULL, 0, NULL); - dill_assert(rc != -1); - } - fdi->currevs = 0; - /* If needed, remove the fd from the changelist. */ - if(fdi->next) { - uint32_t *pidx = &ctx->changelist; - while(1) { - dill_assert(*pidx != 0 && *pidx != DILL_ENDLIST); - if(*pidx - 1 == fd) break; - pidx = &ctx->fdinfos[*pidx - 1].next; - } - *pidx = fdi->next; - fdi->next = 0; - } - /* Mark the fd as not used. */ - fdi->cached = 0; - return 0; -} - -int dill_pollset_poll(int timeout) { - struct dill_ctx_pollset *ctx = &dill_getctx->pollset; - /* Apply any changes to the pollset. */ - struct kevent chngs[DILL_CHNGSSIZE]; - int nchngs = 0; - while(ctx->changelist != DILL_ENDLIST) { - /* Flush the changes to the pollset even if there is one empty entry - left in the changeset. That way, we make sure that both in & out - associated with the next file descriptor can be filled in if we - choose not to flush the changes yet. */ - if(nchngs >= DILL_CHNGSSIZE - 1) { - int rc = kevent(ctx->kfd, chngs, nchngs, NULL, 0, NULL); - dill_assert(rc != -1); - nchngs = 0; - } - int fd = ctx->changelist - 1; - struct dill_fdinfo *fdi = &ctx->fdinfos[fd]; - if(fdi->in) { - if(!(fdi->currevs & FDW_IN)) { - EV_SET(&chngs[nchngs], fd, EVFILT_READ, EV_ADD, 0, 0, 0); - fdi->currevs |= FDW_IN; - ++nchngs; - } - } - else { - if(fdi->currevs & FDW_IN) { - EV_SET(&chngs[nchngs], fd, EVFILT_READ, EV_DELETE, 0, 0, 0); - fdi->currevs &= ~FDW_IN; - ++nchngs; - } - } - if(fdi->out) { - if(!(fdi->currevs & FDW_OUT)) { - EV_SET(&chngs[nchngs], fd, EVFILT_WRITE, EV_ADD, 0, 0, 0); - fdi->currevs |= FDW_OUT; - ++nchngs; - } - } - else { - if(fdi->currevs & FDW_OUT) { - EV_SET(&chngs[nchngs], fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0); - fdi->currevs &= ~FDW_OUT; - ++nchngs; - } - } - fdi->firing = 0; - ctx->changelist = fdi->next; - fdi->next = 0; - } - /* Wait for events. */ - struct kevent evs[DILL_EVSSIZE]; - struct timespec ts; - if(timeout >= 0) { - ts.tv_sec = timeout / 1000; - ts.tv_nsec = (((long)timeout) % 1000) * 1000000; - } - int nevs = kevent(ctx->kfd, chngs, nchngs, evs, DILL_EVSSIZE, - timeout < 0 ? NULL : &ts); - if(nevs < 0 && errno == EINTR) return -1; - dill_assert(nevs >= 0); - /* Join events on file descriptor basis. - Put all the firing fds into the changelist. */ - int i; - for(i = 0; i != nevs; ++i) { - dill_assert(evs[i].flags != EV_ERROR); - int fd = (int)evs[i].ident; - struct dill_fdinfo *fdi = &ctx->fdinfos[fd]; - /* Add firing event to the result list. */ - if(evs[i].flags == EV_EOF) - fdi->firing |= (FDW_IN | FDW_OUT); - else { - if(evs[i].filter == EVFILT_READ) - fdi->firing |= FDW_IN; - if(evs[i].filter == EVFILT_WRITE) - fdi->firing |= FDW_OUT; - } - if(!fdi->next) { - fdi->next = ctx->changelist; - ctx->changelist = fd + 1; - } - } - /* Resume blocked coroutines. */ - uint32_t chl = ctx->changelist; - while(chl != DILL_ENDLIST) { - int fd = chl - 1; - struct dill_fdinfo *fdi = &ctx->fdinfos[fd]; - if(fdi->in && (fdi->firing & FDW_IN)) - dill_trigger(&fdi->in->cl, 0); - if(fdi->out && (fdi->firing & FDW_OUT)) - dill_trigger(&fdi->out->cl, 0); - fdi->firing = 0; - chl = fdi->next; - } - /* Return 0 on timeout or 1 if at least one coroutine was resumed. */ - return nevs > 0 ? 1 : 0; -} - diff --git a/Sources/CLibdill/kqueue.h.inc b/Sources/CLibdill/kqueue.h.inc deleted file mode 100644 index 869b0b2..0000000 --- a/Sources/CLibdill/kqueue.h.inc +++ /dev/null @@ -1,43 +0,0 @@ -/* - - Copyright (c) 2016 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#ifndef DILL_KQUEUE_INCLUDED -#define DILL_KQUEUE_INCLUDED - -#include "cr.h" -#include "list.h" - -struct dill_fdinfo; - -struct dill_fdclause { - struct dill_clause cl; - struct dill_fdinfo *fdinfo; -}; - -struct dill_ctx_pollset { - int kfd; - int nfdinfos; - struct dill_fdinfo *fdinfos; - uint32_t changelist; -}; - -#endif diff --git a/Sources/CLibdill/libdill.c b/Sources/CLibdill/libdill.c deleted file mode 100644 index a7cd3ae..0000000 --- a/Sources/CLibdill/libdill.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - - Copyright (c) 2017 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#include - -#include "cr.h" -#include "libdill.h" -#include "pollset.h" -#include "utils.h" - -int msleep(int64_t deadline) { - /* Return ECANCELED if shutting down. */ - int rc = dill_canblock(); - if(dill_slow(rc < 0)) return -1; - /* Actual waiting. */ - struct dill_tmclause tmcl; - dill_timer(&tmcl, 1, deadline); - int id = dill_wait(); - if(dill_slow(id < 0)) return -1; - return 0; -} - -int fdin(int fd, int64_t deadline) { - /* Return ECANCELED if shutting down. */ - int rc = dill_canblock(); - if(dill_slow(rc < 0)) return -1; - /* Start waiting for the fd. */ - struct dill_fdclause fdcl; - rc = dill_pollset_in(&fdcl, 1, fd); - if(dill_slow(rc < 0)) return -1; - /* Optionally, start waiting for a timer. */ - struct dill_tmclause tmcl; - dill_timer(&tmcl, 2, deadline); - /* Block. */ - int id = dill_wait(); - if(dill_slow(id < 0)) return -1; - if(dill_slow(id == 2)) {errno = ETIMEDOUT; return -1;} - return 0; -} - -int fdout(int fd, int64_t deadline) { - /* Return ECANCELED if shutting down. */ - int rc = dill_canblock(); - if(dill_slow(rc < 0)) return -1; - /* Start waiting for the fd. */ - struct dill_fdclause fdcl; - rc = dill_pollset_out(&fdcl, 1, fd); - if(dill_slow(rc < 0)) return -1; - /* Optionally, start waiting for a timer. */ - struct dill_tmclause tmcl; - dill_timer(&tmcl, 2, deadline); - /* Block. */ - int id = dill_wait(); - if(dill_slow(id < 0)) return -1; - if(dill_slow(id == 2)) {errno = ETIMEDOUT; return -1;} - return 0; -} - -int fdclean(int fd) { - return dill_pollset_clean(fd); -} - diff --git a/Sources/CLibdill/libdill.h b/Sources/CLibdill/libdill.h deleted file mode 100644 index ed53705..0000000 --- a/Sources/CLibdill/libdill.h +++ /dev/null @@ -1,435 +0,0 @@ -/* - - Copyright (c) 2017 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#ifndef LIBDILL_H_INCLUDED -#define LIBDILL_H_INCLUDED - -#include -#include -#include -#include -#include -#include - -#if defined __linux__ -#include -#endif - -/******************************************************************************/ -/* ABI versioning support */ -/******************************************************************************/ - -/* Don't change this unless you know exactly what you're doing and have */ -/* read and understood the following documents: */ -/* www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html */ -/* www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html */ - -/* The current interface version. */ -#define DILL_VERSION_CURRENT 14 - -/* The latest revision of the current interface. */ -#define DILL_VERSION_REVISION 0 - -/* How many past interface versions are still supported. */ -#define DILL_VERSION_AGE 1 - -/******************************************************************************/ -/* Symbol visibility */ -/******************************************************************************/ - -#if !defined __GNUC__ && !defined __clang__ -#error "Unsupported compiler!" -#endif - -#if DILL_NO_EXPORTS -#define DILL_EXPORT -#else -#define DILL_EXPORT __attribute__ ((visibility("default"))) -#endif - -/* Old versions of GCC don't support visibility attribute. */ -#if defined __GNUC__ && __GNUC__ < 4 -#undef DILL_EXPORT -#define DILL_EXPORT -#endif - -/******************************************************************************/ -/* Helpers */ -/******************************************************************************/ - -DILL_EXPORT int64_t now(void); - -/******************************************************************************/ -/* Handles */ -/******************************************************************************/ - -DILL_EXPORT int hdup(int h); -DILL_EXPORT int hclose(int h); -DILL_EXPORT int hdone(int h, int64_t deadline); - -/******************************************************************************/ -/* Coroutines */ -/******************************************************************************/ - -#define coroutine __attribute__((noinline)) - -DILL_EXPORT extern volatile void *dill_unoptimisable; - -DILL_EXPORT __attribute__((noinline)) int dill_prologue(sigjmp_buf **ctx, - void **ptr, size_t len, const char *file, int line); -DILL_EXPORT __attribute__((noinline)) void dill_epilogue(void); - -/* The following macros use alloca(sizeof(size_t)) because clang - doesn't support alloca with size zero. */ - -/* This assembly setjmp/longjmp mechanism is in the same order as glibc and - musl, but glibc implements pointer mangling, which is hard to support. - This should be binary-compatible with musl, though. */ - -/* Stack-switching on X86-64. */ -#if defined(__x86_64__) && !defined DILL_ARCH_FALLBACK -#define dill_setjmp(ctx) ({\ - int ret;\ - asm("lea LJMPRET%=(%%rip), %%rcx\n\t"\ - "xor %%rax, %%rax\n\t"\ - "mov %%rbx, (%%rdx)\n\t"\ - "mov %%rbp, 8(%%rdx)\n\t"\ - "mov %%r12, 16(%%rdx)\n\t"\ - "mov %%r13, 24(%%rdx)\n\t"\ - "mov %%r14, 32(%%rdx)\n\t"\ - "mov %%r15, 40(%%rdx)\n\t"\ - "mov %%rsp, 48(%%rdx)\n\t"\ - "mov %%rcx, 56(%%rdx)\n\t"\ - "LJMPRET%=:\n\t"\ - : "=a" (ret)\ - : "d" (ctx)\ - : "memory", "rcx", "rsi", "rdi", "r8", "r9", "r10", "r11", "cc");\ - ret;\ -}) -#define dill_longjmp(ctx) \ - asm("movq 56(%%rdx), %%rcx\n\t"\ - "movq 48(%%rdx), %%rsp\n\t"\ - "movq 40(%%rdx), %%r15\n\t"\ - "movq 32(%%rdx), %%r14\n\t"\ - "movq 24(%%rdx), %%r13\n\t"\ - "movq 16(%%rdx), %%r12\n\t"\ - "movq 8(%%rdx), %%rbp\n\t"\ - "movq (%%rdx), %%rbx\n\t"\ - ".cfi_def_cfa %%rdx, 0 \n\t"\ - ".cfi_offset %%rbx, 0 \n\t"\ - ".cfi_offset %%rbp, 8 \n\t"\ - ".cfi_offset %%r12, 16 \n\t"\ - ".cfi_offset %%r13, 24 \n\t"\ - ".cfi_offset %%r14, 32 \n\t"\ - ".cfi_offset %%r15, 40 \n\t"\ - ".cfi_offset %%rsp, 48 \n\t"\ - ".cfi_offset %%rip, 56 \n\t"\ - "jmp *%%rcx\n\t"\ - : : "d" (ctx), "a" (1)) -#define DILL_SETSP(x) \ - asm(""::"r"(alloca(sizeof(size_t))));\ - asm volatile("leaq (%%rax), %%rsp"::"rax"(x)); - -/* Stack switching on X86. */ -#elif defined(__i386__) && !defined DILL_ARCH_FALLBACK -#define dill_setjmp(ctx) ({\ - int ret;\ - asm("movl $LJMPRET%=, %%ecx\n\t"\ - "movl %%ebx, (%%edx)\n\t"\ - "movl %%esi, 4(%%edx)\n\t"\ - "movl %%edi, 8(%%edx)\n\t"\ - "movl %%ebp, 12(%%edx)\n\t"\ - "movl %%esp, 16(%%edx)\n\t"\ - "movl %%ecx, 20(%%edx)\n\t"\ - "xorl %%eax, %%eax\n\t"\ - "LJMPRET%=:\n\t"\ - : "=a" (ret) : "d" (ctx) : "memory");\ - ret;\ -}) -#define dill_longjmp(ctx) \ - asm("movl (%%edx), %%ebx\n\t"\ - "movl 4(%%edx), %%esi\n\t"\ - "movl 8(%%edx), %%edi\n\t"\ - "movl 12(%%edx), %%ebp\n\t"\ - "movl 16(%%edx), %%esp\n\t"\ - "movl 20(%%edx), %%ecx\n\t"\ - ".cfi_def_cfa %%edx, 0 \n\t"\ - ".cfi_offset %%ebx, 0 \n\t"\ - ".cfi_offset %%esi, 4 \n\t"\ - ".cfi_offset %%edi, 8 \n\t"\ - ".cfi_offset %%ebp, 12 \n\t"\ - ".cfi_offset %%esp, 16 \n\t"\ - ".cfi_offset %%eip, 20 \n\t"\ - "jmp *%%ecx\n\t"\ - : : "d" (ctx), "a" (1)) -#define DILL_SETSP(x) \ - asm(""::"r"(alloca(sizeof(size_t))));\ - asm volatile("leal (%%eax), %%esp"::"eax"(x)); - -/* Stack-switching on other microarchitectures. */ -#else -#define dill_setjmp(ctx) sigsetjmp(ctx, 0) -#define dill_longjmp(ctx) siglongjmp(ctx, 1) -/* For newer GCCs, -fstack-protector breaks on this; use -fno-stack-protector. - Alternatively, implement a custom DILL_SETSP for your microarchitecture. */ -#define DILL_SETSP(x) \ - dill_unoptimisable = alloca((char*)alloca(sizeof(size_t)) - (char*)(x)); -#endif - -/* Statement expressions are a gcc-ism but they are also supported by clang. - Given that there's no other way to do this, screw other compilers for now. - See https://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Statement-Exprs.html */ - -/* A bug in gcc have been observed where name clash between variable in the - outer scope and a local variable in this macro causes the variable to - get weird values. To avoid that, we use fancy names (dill_*__). */ - -#define go_mem(fn, ptr, len) \ - ({\ - sigjmp_buf *dill_ctx__;\ - void *dill_stk__ = (ptr);\ - int dill_handle__ = dill_prologue(&dill_ctx__, &dill_stk__, (len),\ - __FILE__, __LINE__);\ - if(dill_handle__ >= 0) {\ - if(!dill_setjmp(*dill_ctx__)) {\ - DILL_SETSP(dill_stk__);\ - fn;\ - dill_epilogue();\ - }\ - }\ - dill_handle__;\ - }) - -#define go(fn) go_mem(fn, NULL, 0) - -DILL_EXPORT int co(void **ptr, size_t len, - void *fn, const char *file, int line, - void (*routine)(void *)); -DILL_EXPORT int yield(void); -DILL_EXPORT int msleep(int64_t deadline); -DILL_EXPORT int fdclean(int fd); -DILL_EXPORT int fdin(int fd, int64_t deadline); -DILL_EXPORT int fdout(int fd, int64_t deadline); - -/******************************************************************************/ -/* Channels */ -/******************************************************************************/ - -#define CHSEND 1 -#define CHRECV 2 - -struct chclause { - int op; - int ch; - void *val; - size_t len; -}; - -struct chmem { -#if defined(__i386__) - char reserved[44]; -#else - char reserved[88]; -#endif -}; - -DILL_EXPORT int chmake(size_t itemsz); -DILL_EXPORT int chmake_mem(size_t itemsz, struct chmem *mem); -DILL_EXPORT int chsend(int ch, const void *val, size_t len, int64_t deadline); -DILL_EXPORT int chrecv(int ch, void *val, size_t len, int64_t deadline); -DILL_EXPORT int choose(struct chclause *clauses, int nclauses, - int64_t deadline); - -#define chdone(ch) hdone((ch), -1) - -#if !defined DILL_DISABLE_SOCKETS - -/******************************************************************************/ -/* Gather/scatter list. */ -/******************************************************************************/ - -struct iolist { - void *iol_base; - size_t iol_len; - struct iolist *iol_next; - int iol_rsvd; -}; - -/******************************************************************************/ -/* Bytestream sockets. */ -/******************************************************************************/ - -DILL_EXPORT int bsend( - int s, - const void *buf, - size_t len, - int64_t deadline); -DILL_EXPORT ssize_t brecv( - int s, - void *buf, - size_t len, - int64_t deadline); -DILL_EXPORT int bsendl( - int s, - struct iolist *first, - struct iolist *last, - int64_t deadline); -DILL_EXPORT ssize_t brecvl( - int s, - struct iolist *first, - struct iolist *last, - int64_t deadline); - -/******************************************************************************/ -/* Message sockets. */ -/******************************************************************************/ - -DILL_EXPORT int msend( - int s, - const void *buf, - size_t len, - int64_t deadline); -DILL_EXPORT ssize_t mrecv( - int s, - void *buf, - size_t len, - int64_t deadline); -DILL_EXPORT int msendl( - int s, - struct iolist *first, - struct iolist *last, - int64_t deadline); -DILL_EXPORT ssize_t mrecvl( - int s, - struct iolist *first, - struct iolist *last, - int64_t deadline); - -/******************************************************************************/ -/* IP address resolution. */ -/******************************************************************************/ - -struct sockaddr; - -#define IPADDR_IPV4 1 -#define IPADDR_IPV6 2 -#define IPADDR_PREF_IPV4 3 -#define IPADDR_PREF_IPV6 4 -#define IPADDR_MAXSTRLEN 46 - -struct ipaddr { - char data[32]; -}; - -DILL_EXPORT int ipaddr_local( - struct ipaddr *addr, - const char *name, - int port, - int mode); -DILL_EXPORT int ipaddr_remote( - struct ipaddr *addr, - const char *name, - int port, - int mode, - int64_t deadline); -DILL_EXPORT const char *ipaddr_str( - const struct ipaddr *addr, - char *ipstr); -DILL_EXPORT int ipaddr_family( - const struct ipaddr *addr); -DILL_EXPORT const struct sockaddr *ipaddr_sockaddr( - const struct ipaddr *addr); -DILL_EXPORT int ipaddr_len( - const struct ipaddr *addr); -DILL_EXPORT int ipaddr_port( - const struct ipaddr *addr); -DILL_EXPORT void ipaddr_setport( - struct ipaddr *addr, - int port); - -/******************************************************************************/ -/* TCP protocol. */ -/******************************************************************************/ - -DILL_EXPORT int tcp_listen( - struct ipaddr *addr, - int backlog); -DILL_EXPORT int tcp_accept( - int s, - struct ipaddr *addr, - int64_t deadline); -DILL_EXPORT int tcp_connect( - const struct ipaddr *addr, - int64_t deadline); -DILL_EXPORT int tcp_close( - int s, - int64_t deadline); - -/******************************************************************************/ -/* IPC protocol. */ -/******************************************************************************/ - -DILL_EXPORT int ipc_listen( - const char *addr, - int backlog); -DILL_EXPORT int ipc_accept( - int s, - int64_t deadline); -DILL_EXPORT int ipc_connect( - const char *addr, - int64_t deadline); -DILL_EXPORT int ipc_close( - int s, - int64_t deadline); -DILL_EXPORT int ipc_pair( - int s[2]); - -/******************************************************************************/ -/* PFX protocol. */ -/* Messages are prefixed by 8-byte size in network byte order. */ -/* The protocol is terminated by 0xffffffffffffffff. */ -/******************************************************************************/ - -DILL_EXPORT int pfx_attach( - int s); -DILL_EXPORT int pfx_detach( - int s, - int64_t deadline); - -/******************************************************************************/ -/* CRLF protocol. */ -/* Messages are delimited by CRLF (0x0d 0x0a) sequences. */ -/* The protocol is terminated by an empty line. */ -/******************************************************************************/ - -DILL_EXPORT int crlf_attach( - int s); -DILL_EXPORT int crlf_detach( - int s, - int64_t deadline); - -#endif - -#endif - diff --git a/Sources/CLibdill/libdillimpl.h b/Sources/CLibdill/libdillimpl.h deleted file mode 100644 index a7b852a..0000000 --- a/Sources/CLibdill/libdillimpl.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - - Copyright (c) 2017 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#ifndef LIBDILLIMPL_H_INCLUDED -#define LIBDILLIMPL_H_INCLUDED - -#include "libdill.h" - -/******************************************************************************/ -/* Handles */ -/******************************************************************************/ - -struct hvfs { - void *context; - void *(*query)(struct hvfs *vfs, const void *type); - void (*close)(struct hvfs *vfs); - int (*done)(struct hvfs *vfs, int64_t deadline); - /* Reserved. Do not use directly! */ - unsigned int refcount; -}; - -DILL_EXPORT int hmake(struct hvfs *vfs); -DILL_EXPORT void *hquery(int h, const void *type); - -#if !defined DILL_DISABLE_SOCKETS - -/******************************************************************************/ -/* Bytestream sockets. */ -/******************************************************************************/ - -DILL_EXPORT extern const void *bsock_type; - -struct bsock_vfs { - void *context; - int (*bsendl)(struct bsock_vfs *vfs, - struct iolist *first, struct iolist *last, int64_t deadline); - ssize_t (*brecvl)(struct bsock_vfs *vfs, - struct iolist *first, struct iolist *last, int64_t deadline); -}; - -/******************************************************************************/ -/* Message sockets. */ -/******************************************************************************/ - -DILL_EXPORT extern const void *msock_type; - -struct msock_vfs { - void *context; - int (*msendl)(struct msock_vfs *vfs, - struct iolist *first, struct iolist *last, int64_t deadline); - ssize_t (*mrecvl)(struct msock_vfs *vfs, - struct iolist *first, struct iolist *last, int64_t deadline); -}; - -#endif - -#endif - diff --git a/Sources/CLibdill/list.h b/Sources/CLibdill/list.h deleted file mode 100644 index 5166422..0000000 --- a/Sources/CLibdill/list.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - - Copyright (c) 2016 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#ifndef DILL_LIST_INCLUDED -#define DILL_LIST_INCLUDED - -#include "utils.h" - -/* Doubly-linked list. */ -struct dill_list { - struct dill_list *next; - struct dill_list *prev; -}; - -/* Initialize the list. */ -static inline void dill_list_init(struct dill_list *self) { - self->next = self; - self->prev = self; -} - -/* True if the list has no items. */ -static inline int dill_list_empty(struct dill_list *self) { - return self->next == self; -} - -/* Returns an iterator to one past the item pointed to by 'it'. If 'it' is the - list itself it returns the first item of the list. At the end of - the list, it returns the list itself. */ -#define dill_list_next(it) ((it)->next) - -/* Adds the item to the list before the item pointed to by 'before'. If 'before' - is the list itself the item is inserted to the end of the list. */ -static inline void dill_list_insert(struct dill_list *item, - struct dill_list *before) { - item->next = before; - item->prev = before->prev; - before->prev->next = item; - before->prev = item; -} - -/* Removes the item from the list. */ -static void dill_list_erase(struct dill_list *item) { - item->prev->next = item->next; - item->next->prev = item->prev; -} - -#endif - diff --git a/Sources/CLibdill/msock.c b/Sources/CLibdill/msock.c deleted file mode 100644 index ce8d36c..0000000 --- a/Sources/CLibdill/msock.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - - Copyright (c) 2017 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#include -#include - -#include "libdillimpl.h" -#include "utils.h" - -dill_unique_id(msock_type); - -int msend(int s, const void *buf, size_t len, int64_t deadline) { - struct msock_vfs *m = hquery(s, msock_type); - if(dill_slow(!m)) return -1; - struct iolist iol = {(void*)buf, len, NULL, 0}; - return m->msendl(m, &iol, &iol, deadline); -} - -ssize_t mrecv(int s, void *buf, size_t len, int64_t deadline) { - struct msock_vfs *m = hquery(s, msock_type); - if(dill_slow(!m)) return -1; - struct iolist iol = {buf, len, NULL, 0}; - return m->mrecvl(m, &iol, &iol, deadline); -} - -int msendl(int s, struct iolist *first, struct iolist *last, int64_t deadline) { - struct msock_vfs *m = hquery(s, msock_type); - if(dill_slow(!m)) return -1; - if(dill_slow(!first || !last || last->iol_next)) { - errno = EINVAL; return -1;} - return m->msendl(m, first, last, deadline); -} - -ssize_t mrecvl(int s, struct iolist *first, struct iolist *last, - int64_t deadline) { - struct msock_vfs *m = hquery(s, msock_type); - if(dill_slow(!m)) return -1; - if(dill_slow((last && last->iol_next) || - (!first && last) || - (first && !last))) { - errno = EINVAL; return -1;} - return m->mrecvl(m, first, last, deadline); -} - diff --git a/Sources/CLibdill/now.c b/Sources/CLibdill/now.c deleted file mode 100644 index cc428e6..0000000 --- a/Sources/CLibdill/now.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - - Copyright (c) 2017 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#include - -#if defined(__x86_64__) || defined(__i386__) -#include -#endif - -#include "ctx.h" - -int64_t mnow(void) { - -/* Implementation using Mach timers. */ -#if defined __APPLE__ - static mach_timebase_info_data_t dill_mtid = {0}; - if (dill_slow(!dill_mtid.denom)) - mach_timebase_info(&dill_mtid); - uint64_t ticks = mach_absolute_time(); - return (int64_t)(ticks * dill_mtid.numer / dill_mtid.denom / 1000000); -#else - -/* Implementation using clock_gettime(). */ -#if defined CLOCK_MONOTONIC_COARSE - clock_t id = CLOCK_MONOTONIC_COARSE; -#elif defined CLOCK_MONOTONIC_FAST - clock_t id = CLOCK_MONOTONIC_FAST; -#elif defined CLOCK_MONOTONIC - clock_t id = CLOCK_MONOTONIC; -#else -#define DILL_NOW_FALLBACK -#endif -#if !defined DILL_NOW_FALLBACK - struct timespec ts; - int rc = clock_gettime(id, &ts); - dill_assert (rc == 0); - return ((int64_t)ts.tv_sec) * 1000 + (((int64_t)ts.tv_nsec) / 1000000); - -/* Implementation using gettimeofday(). This is slow and error-prone - (the time can jump backwards!), but it's just a last resort option. */ -#else - struct timeval tv; - int rc = gettimeofday(&tv, NULL); - dill_assert (rc == 0); - return ((int64_t)tv.tv_sec) * 1000 + (((int64_t)tv.tv_usec) / 1000); -#endif - -#endif -} - -/* Like now(), this function can be called only after context is initialized - but unlike now() it doesn't do time caching. */ -int64_t now_(void) { -#if defined __APPLE__ - struct dill_ctx_now *ctx = &dill_getctx->now; - uint64_t ticks = mach_absolute_time(); - return (int64_t)(ticks * ctx->mtid.numer / ctx->mtid.denom / 1000000); -#else - return mnow(); -#endif -} - -int64_t now(void) { -#if defined(__x86_64__) || defined(__i386__) - /* On x86 platforms, rdtsc instruction can be used to quickly check time - in form of CPU cycles. If less than 1M cycles have elapsed since the - last now_() call we assume it's still the same millisecond and return - cached time. This optimization can give a huge speedup with old systems. - 1M number is chosen is such a way that it results in getting time every - millisecond on 1GHz processors. On faster processors we'll query time - somewhat more often but the number of queries should still be - statistically insignificant. On slower processors we'll start losing - precision, e.g. on 500MHz processor we can diverge by 1ms. */ - struct dill_ctx_now *ctx = &dill_getctx->now; - uint64_t tsc = __rdtsc(); - int64_t diff = tsc - ctx->last_tsc; - if(diff < 0) diff = -diff; - if(dill_fast(diff < 1000000ULL)) return ctx->last_time; - ctx->last_tsc = tsc; - ctx->last_time = now_(); - return ctx->last_time; -#else - return now_(); -#endif -} - -int dill_ctx_now_init(struct dill_ctx_now *ctx) { -#if defined __APPLE__ - mach_timebase_info(&ctx->mtid); -#endif -#if defined(__x86_64__) || defined(__i386__) - ctx->last_time = mnow(); - ctx->last_tsc = __rdtsc(); -#endif - return 0; -} - -void dill_ctx_now_term(struct dill_ctx_now *ctx) { -} - diff --git a/Sources/CLibdill/now.h b/Sources/CLibdill/now.h deleted file mode 100644 index 7ccec4b..0000000 --- a/Sources/CLibdill/now.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - - Copyright (c) 2017 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#ifndef DILL_NOW_INCLUDED -#define DILL_NOW_INCLUDED - -#include - -#if defined __APPLE__ -#include -#endif - -struct dill_ctx_now { -#if defined __APPLE__ - mach_timebase_info_data_t mtid; -#endif -#if defined(__x86_64__) || defined(__i386__) - int64_t last_time; - uint64_t last_tsc; -#endif -}; - -int dill_ctx_now_init(struct dill_ctx_now *ctx); -void dill_ctx_now_term(struct dill_ctx_now *ctx); - -/* Same as now() except that it doesn't use the context. - I.e. it can be called before calling dill_ctx_now_init(). */ -int64_t mnow(void); - -#endif - diff --git a/Sources/CLibdill/pfx.c b/Sources/CLibdill/pfx.c deleted file mode 100644 index b5da05f..0000000 --- a/Sources/CLibdill/pfx.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - - Copyright (c) 2017 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#include -#include "libdillimpl.h" -#include -#include - -#include "utils.h" - -dill_unique_id(pfx_type); - -static void *pfx_hquery(struct hvfs *hvfs, const void *type); -static void pfx_hclose(struct hvfs *hvfs); -static int pfx_hdone(struct hvfs *hvfs, int64_t deadline); -static int pfx_msendl(struct msock_vfs *mvfs, - struct iolist *first, struct iolist *last, int64_t deadline); -static ssize_t pfx_mrecvl(struct msock_vfs *mvfs, - struct iolist *first, struct iolist *last, int64_t deadline); - -struct pfx_sock { - struct hvfs hvfs; - struct msock_vfs mvfs; - int u; - unsigned int indone : 1; - unsigned int outdone: 1; - unsigned int inerr : 1; - unsigned int outerr : 1; -}; - -static void *pfx_hquery(struct hvfs *hvfs, const void *type) { - struct pfx_sock *self = (struct pfx_sock*)hvfs; - if(type == msock_type) return &self->mvfs; - if(type == pfx_type) return self; - errno = ENOTSUP; - return NULL; -} - -int pfx_attach(int s) { - int err; - /* Make a private copy of the underlying socket. */ - int u = hdup(s); - if(dill_slow(u < 0)) return -1; - int rc = hclose(s); - dill_assert(rc == 0); - /* Check whether underlying socket is a bytestream. */ - void *q = hquery(u, bsock_type); - if(dill_slow(!q && errno == ENOTSUP)) {err = EPROTO; goto error1;} - if(dill_slow(!q)) {err = errno; goto error1;} - /* Create the object. */ - struct pfx_sock *self = malloc(sizeof(struct pfx_sock)); - if(dill_slow(!self)) {err = ENOMEM; goto error1;} - self->hvfs.query = pfx_hquery; - self->hvfs.close = pfx_hclose; - self->hvfs.done = pfx_hdone; - self->mvfs.msendl = pfx_msendl; - self->mvfs.mrecvl = pfx_mrecvl; - self->u = u; - self->indone = 0; - self->outdone = 0; - self->inerr = 0; - self->outerr = 0; - /* Create the handle. */ - int h = hmake(&self->hvfs); - if(dill_slow(h < 0)) {int err = errno; goto error2;} - return h; -error2: - free(self); -error1: - rc = hclose(u); - dill_assert(rc == 0); - errno = err; - return -1; -} - -static int pfx_hdone(struct hvfs *hvfs, int64_t deadline) { - struct pfx_sock *self = (struct pfx_sock*)hvfs; - if(dill_slow(self->outdone)) {errno = EPIPE; return -1;} - if(dill_slow(self->outerr)) {errno = ECONNRESET; return -1;} - uint64_t sz = 0xffffffffffffffff; - int rc = bsend(self->u, &sz, 8, deadline); - if(dill_slow(rc < 0)) {self->outerr = 1; return -1;} - self->outdone = 1; - return 0; -} - -int pfx_detach(int s, int64_t deadline) { - int err; - struct pfx_sock *self = hquery(s, pfx_type); - if(dill_slow(!self)) return -1; - if(dill_slow(self->inerr || self->outerr)) {err = ECONNRESET; goto error;} - /* If not done already start the terminal handshake. */ - if(!self->outdone) { - int rc = pfx_hdone(&self->hvfs, deadline); - if(dill_slow(rc < 0)) {err = errno; goto error;} - } - /* Drain incoming messages until termination message is received. */ - while(1) { - ssize_t sz = pfx_mrecvl(&self->mvfs, NULL, NULL, deadline); - if(sz < 0 && errno == EPIPE) break; - if(dill_slow(sz < 0)) {err = errno; goto error;} - } - int u = self->u; - free(self); - return u; -error: - pfx_hclose(&self->hvfs); - errno = err; - return -1; -} - -static int pfx_msendl(struct msock_vfs *mvfs, - struct iolist *first, struct iolist *last, int64_t deadline) { - struct pfx_sock *self = dill_cont(mvfs, struct pfx_sock, mvfs); - if(dill_slow(self->outdone)) {errno = EPIPE; return -1;} - if(dill_slow(self->outerr)) {errno = ECONNRESET; return -1;} - uint8_t szbuf[8]; - size_t sz = 0; - struct iolist *it; - for(it = first; it; it = it->iol_next) - sz += it->iol_len; - dill_putll(szbuf, (uint64_t)sz); - struct iolist hdr = {szbuf, 8, first, 0}; - int rc = bsendl(self->u, &hdr, last, deadline); - if(dill_slow(rc < 0)) {self->outerr = 1; return -1;} - return 0; -} - -static ssize_t pfx_mrecvl(struct msock_vfs *mvfs, - struct iolist *first, struct iolist *last, int64_t deadline) { - struct pfx_sock *self = dill_cont(mvfs, struct pfx_sock, mvfs); - if(dill_slow(self->indone)) {errno = EPIPE; return -1;} - if(dill_slow(self->inerr)) {errno = ECONNRESET; return -1;} - uint8_t szbuf[8]; - int rc = brecv(self->u, szbuf, 8, deadline); - if(dill_slow(rc < 0)) {self->inerr = 1; return -1;} - uint64_t sz = dill_getll(szbuf); - /* Peer is terminating. */ - if(dill_slow(sz == 0xffffffffffffffff)) { - self->indone = 1; errno = EPIPE; return -1;} - /* Skip the message. */ - if(!first) { - rc = brecv(self->u, NULL, sz, deadline); - if(dill_slow(rc < 0)) {self->inerr = 1; return -1;} - return sz; - } - /* Trim iolist to reflect the size of the message. */ - size_t rmn = sz; - struct iolist *it = first; - while(1) { - if(it->iol_len >= rmn) break; - rmn -= it->iol_len; - it = it->iol_next; - if(dill_slow(!it)) {self->inerr = 1; errno = EMSGSIZE; return -1;} - } - size_t old_len = it->iol_len; - struct iolist *old_next = it->iol_next; - it->iol_len = rmn; - it->iol_next = NULL; - rc = brecvl(self->u, first, last, deadline); - /* Get iolist to its original state. */ - it->iol_len = old_len; - it->iol_next = old_next; - if(dill_slow(rc < 0)) {self->inerr = 1; return -1;} - return sz; -} - -static void pfx_hclose(struct hvfs *hvfs) { - struct pfx_sock *self = (struct pfx_sock*)hvfs; - if(dill_fast(self->u >= 0)) { - int rc = hclose(self->u); - dill_assert(rc == 0); - } - free(self); -} - diff --git a/Sources/CLibdill/poll.c.inc b/Sources/CLibdill/poll.c.inc deleted file mode 100644 index a575799..0000000 --- a/Sources/CLibdill/poll.c.inc +++ /dev/null @@ -1,227 +0,0 @@ -/* - - Copyright (c) 2016 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#include -#include -#include -#include -#include - -#include "cr.h" -#include "list.h" -#include "pollset.h" -#include "utils.h" -#include "ctx.h" - -/* - - ctx->pollset_size - | - ctx->pollset V - +-------+-------+-------+-----+-------+--------------------------------+ - | pfd 0 | pfd 1 | pfd 2 | ... | pfd N | empty | - +-------+-------+-------+-----+-------+--------------------------------+ - ^ ^ ^ - | | | - idx +------idx------+ | - | | | - +------+------+------+----------------------------------------+--------+ - | fd=0 | fd=1 | fd=2 | ... | fd=max | - +------+------+------+----------------------------------------+--------+ - ctx->fdinfos ^ - | - ctx->nfdinfos - -*/ - -/* Additional info about file descriptor. */ -struct dill_fdinfo { - /* Index of the file descriptor in the pollset. - -1 means the fd is not in the pollset. */ - int idx; - /* Clause waiting for in. NULL if none. */ - struct dill_fdclause *in; - /* Clause waiting for out. NULL if none. */ - struct dill_fdclause *out; - /* 1 is the file descriptor was used before, 0 otherwise. */ - unsigned int cached : 1; -}; - -int dill_ctx_pollset_init(struct dill_ctx_pollset *ctx) { - int err; - ctx->nfdinfos = dill_maxfds(); - /* Allocate largest possible pollset. */ - ctx->pollset_size = 0; - ctx->pollset = malloc(sizeof(struct pollfd) * ctx->nfdinfos); - if(dill_slow(!ctx->pollset)) {err = ENOMEM; goto error1;} - ctx->fdinfos = malloc(sizeof(struct dill_fdinfo) * ctx->nfdinfos); - if(dill_slow(!ctx->fdinfos)) {err = ENOMEM; goto error2;} - /* Intialise fd infos. There's no fd in the pollset, - so set all indices to -1. */ - int i; - for(i = 0; i != ctx->nfdinfos; ++i) { - ctx->fdinfos[i].idx = -1; - ctx->fdinfos[i].in = NULL; - ctx->fdinfos[i].out = NULL; - ctx->fdinfos[i].cached = 0; - } - return 0; -error2: - free(ctx->pollset); - ctx->pollset = NULL; -error1: - errno = err; - return -1; -} - -void dill_ctx_pollset_term(struct dill_ctx_pollset *ctx) { - free(ctx->pollset); - free(ctx->fdinfos); -} - -static void dill_fdcancelin(struct dill_clause *cl) { - struct dill_ctx_pollset *ctx = &dill_getctx->pollset; - struct dill_fdinfo *fdi = dill_cont(cl, struct dill_fdclause, cl)->fdinfo; - fdi->in = NULL; - ctx->pollset[fdi->idx].events &= ~POLLIN; - /* fd is left in the pollset. It will be purged once the event loop - iterates once more. */ -} - -static void dill_fdcancelout(struct dill_clause *cl) { - struct dill_ctx_pollset *ctx = &dill_getctx->pollset; - struct dill_fdinfo *fdi = dill_cont(cl, struct dill_fdclause, cl)->fdinfo; - fdi->out = NULL; - ctx->pollset[fdi->idx].events &= ~POLLOUT; - /* fd is left in the pollset. It will be purged once the event loop - iterates once more. */ -} - -int dill_pollset_in(struct dill_fdclause *fdcl, int id, int fd) { - struct dill_ctx_pollset *ctx = &dill_getctx->pollset; - if(dill_slow(fd < 0 || fd >= ctx->nfdinfos)) {errno = EBADF; return -1;} - struct dill_fdinfo *fdi = &ctx->fdinfos[fd]; - if(dill_slow(!fdi->cached)) { - int flags = fcntl(fd, F_GETFD); - if(flags < 0 && errno == EBADF) return -1; - dill_assert(flags >= 0); - fdi->cached = 1; - } - if(fdi->idx < 0) { - fdi->idx = ctx->pollset_size; - ++ctx->pollset_size; - ctx->pollset[fdi->idx].fd = fd; - } - if(dill_slow(fdi->in)) {errno = EBUSY; return -1;} - ctx->pollset[fdi->idx].events |= POLLIN; - fdcl->fdinfo = fdi; - fdi->in = fdcl; - dill_waitfor(&fdcl->cl, id, dill_fdcancelin); - return 0; -} - -int dill_pollset_out(struct dill_fdclause *fdcl, int id, int fd) { - struct dill_ctx_pollset *ctx = &dill_getctx->pollset; - if(dill_slow(fd < 0 || fd >= ctx->nfdinfos)) {errno = EBADF; return -1;} - struct dill_fdinfo *fdi = &ctx->fdinfos[fd]; - if(dill_slow(!fdi->cached)) { - int flags = fcntl(fd, F_GETFD); - if(flags < 0 && errno == EBADF) return -1; - dill_assert(flags >= 0); - fdi->cached = 1; - } - if(fdi->idx < 0) { - fdi->idx = ctx->pollset_size; - ++ctx->pollset_size; - ctx->pollset[fdi->idx].fd = fd; - } - if(dill_slow(fdi->out)) {errno = EBUSY; return -1;} - ctx->pollset[fdi->idx].events |= POLLOUT; - fdcl->fdinfo = fdi; - fdi->out = fdcl; - dill_waitfor(&fdcl->cl, id, dill_fdcancelout); - return 0; -} - -int dill_pollset_clean(int fd) { - struct dill_ctx_pollset *ctx = &dill_getctx->pollset; - struct dill_fdinfo *fdi = &ctx->fdinfos[fd]; - if(!fdi->cached) return 0; - if(dill_slow(fdi->in || fdi->out)) {errno = EBUSY; return -1;} - /* If the fd happens to still be in the pollset remove it. */ - if(fdi->idx >= 0) { - --ctx->pollset_size; - if(fdi->idx != ctx->pollset_size) { - struct pollfd *pfd = &ctx->pollset[fdi->idx]; - struct pollfd *lastpfd = &ctx->pollset[ctx->pollset_size]; - *pfd = *lastpfd; - ctx->fdinfos[pfd->fd].idx = fdi->idx; - } - fdi->idx = -1; - } - fdi->cached = 0; - return 0; -} - -int dill_pollset_poll(int timeout) { - struct dill_ctx_pollset *ctx = &dill_getctx->pollset; - /* Wait for events. */ - int numevs = poll(ctx->pollset, ctx->pollset_size, timeout); - if(numevs < 0 && errno == EINTR) return -1; - dill_assert(numevs >= 0); - /* Fire file descriptor events as needed. */ - int i; - for(i = 0; i != ctx->pollset_size; ++i) { - struct pollfd *pfd = &ctx->pollset[i]; - struct dill_fdinfo *fdi = &ctx->fdinfos[pfd->fd]; - /* Resume the blocked coroutines. */ - if(fdi->in && - pfd->revents & (POLLIN | POLLERR | POLLHUP | POLLNVAL)) { - pfd->events &= ~POLLIN; - dill_trigger(&fdi->in->cl, 0); - } - if(fdi->out && - pfd->revents & (POLLOUT | POLLERR | POLLHUP | POLLNVAL)) { - pfd->events &= ~POLLOUT; - dill_trigger(&fdi->out->cl, 0); - } - /* If nobody is polling for the fd remove it from the pollset. */ - if(!pfd->events) { - fdi->idx = -1; - dill_assert(!fdi->in && !fdi->out); - --ctx->pollset_size; - /* Pollset has to be compact. Thus, unless we are removing the - last item from the pollset we want to move the last item - to the vacant slot left by the removed fd. */ - if(i != ctx->pollset_size) { - struct pollfd *lastpfd = &ctx->pollset[ctx->pollset_size]; - *pfd = *lastpfd; - ctx->fdinfos[pfd->fd].idx = i; - } - --i; - } - } - return numevs > 0; -} - diff --git a/Sources/CLibdill/poll.h.inc b/Sources/CLibdill/poll.h.inc deleted file mode 100644 index 5a26b70..0000000 --- a/Sources/CLibdill/poll.h.inc +++ /dev/null @@ -1,48 +0,0 @@ -/* - - Copyright (c) 2016 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#ifndef DILL_POLL_INCLUDED -#define DILL_POLL_INCLUDED - -#include - -#include "cr.h" -#include "list.h" - -struct dill_fdinfo; - -struct dill_fdclause { - struct dill_clause cl; - struct dill_fdinfo *fdinfo; -}; - -struct dill_ctx_pollset { - /* Pollset, as used by poll(2). */ - int pollset_size; - struct pollfd *pollset; - /* Info about all file descriptors. - File descriptors are used as indices in this array. */ - int nfdinfos; - struct dill_fdinfo *fdinfos; -}; - -#endif diff --git a/Sources/CLibdill/pollset.c b/Sources/CLibdill/pollset.c deleted file mode 100644 index da306d9..0000000 --- a/Sources/CLibdill/pollset.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - - Copyright (c) 2016 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -/* Include the poll-mechanism-specific stuff. */ - -/* User overloads. */ -#if defined DILL_EPOLL -#include "epoll.c.inc" -#elif defined DILL_KQUEUE -#include "kqueue.c.inc" -#elif defined DILL_POLL -#include "poll.c.inc" -/* Defaults. */ -#elif defined HAVE_EPOLL -#include "epoll.c.inc" -#elif defined HAVE_KQUEUE -#include "kqueue.c.inc" -#else -#include "poll.c.inc" -#endif diff --git a/Sources/CLibdill/pollset.h b/Sources/CLibdill/pollset.h deleted file mode 100644 index 0a8d6f8..0000000 --- a/Sources/CLibdill/pollset.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - - Copyright (c) 2016 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#ifndef DILL_POLLSET_INCLUDED -#define DILL_POLLSET_INCLUDED - -/* User overloads. */ -#if defined DILL_EPOLL -#include "epoll.h.inc" -#elif defined DILL_KQUEUE -#include "kqueue.h.inc" -#elif defined DILL_POLL -#include "poll.h.inc" -/* Defaults. */ -#elif defined HAVE_EPOLL -#include "epoll.h.inc" -#elif defined HAVE_KQUEUE -#include "kqueue.h.inc" -#else -#include "poll.h.inc" -#endif - -int dill_ctx_pollset_init(struct dill_ctx_pollset *ctx); -void dill_ctx_pollset_term(struct dill_ctx_pollset *ctx); - -/* Add waiting for an in event on the fd to the list of current clauses. */ -int dill_pollset_in(struct dill_fdclause *fdcl, int id, int fd); - -/* Add waiting for an out event on the fd to the list of current clauses. */ -int dill_pollset_out(struct dill_fdclause *fdcl, int id, int fd); - -/* Drop any cached info about the file descriptor. */ -int dill_pollset_clean(int fd); - -/* Wait for events. 'timeout' is in milliseconds. Return 0 if the timeout expired or - 1 if at least one clause was triggered. */ -int dill_pollset_poll(int timeout); - -#endif - diff --git a/Sources/CLibdill/qlist.h b/Sources/CLibdill/qlist.h deleted file mode 100644 index 4192175..0000000 --- a/Sources/CLibdill/qlist.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - - Copyright (c) 2016 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#ifndef DILL_QLIST_INCLUDED -#define DILL_QLIST_INCLUDED - -#include "slist.h" -#include "utils.h" - -/* Singly-linked list that's first-in-first-out, so it's actually a queue. - To iterate over the items, use the underlying slist. */ - -struct dill_qlist { - struct dill_slist slist; - struct dill_slist *last; -}; - -/* Initialize the list. */ -static inline void dill_qlist_init(struct dill_qlist *self) { - dill_slist_init(&self->slist); - self->last = &self->slist; -} - -/* True if the list has no items. */ -static inline int dill_qlist_empty(struct dill_qlist *self) { - return self->slist.next == &self->slist; -} - -/* Push an item to the end of the list. */ -static inline void dill_qlist_push(struct dill_qlist *self, - struct dill_slist *item) { - item->next = &self->slist; - self->last->next = item; - self->last = item; -} - -/* Pop an item from the beginning of the list. */ -static inline struct dill_slist *dill_qlist_pop(struct dill_qlist *self) { - struct dill_slist *item = self->slist.next; - self->slist.next = item->next; - if(item == self->last) self->last = &self->slist; - return item; -} - -#endif - diff --git a/Sources/CLibdill/rbtree.c b/Sources/CLibdill/rbtree.c deleted file mode 100644 index efdfe74..0000000 --- a/Sources/CLibdill/rbtree.c +++ /dev/null @@ -1,279 +0,0 @@ -/* - - Copyright (c) 2016 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - - -/* This implementation is based on Emin Martinian's implementation of the algorithm: - http://web.mit.edu/~emin/Desktop/ref_to_emin/www.old/source_code/red_black_tree/index.html */ - -#include - -#include "rbtree.h" - -void dill_rbtree_init(struct dill_rbtree *self) { - struct dill_rbtree_item *temp; - temp = &self->nil; - temp->up = temp->left = temp->right=temp; - temp->red = 0; - temp->val = 0; - temp = &self->root; - temp->up = temp->left=temp->right = &self->nil; - temp->val = 0; - temp->red = 0; -} - -static void dill_rbtree_lrotate(struct dill_rbtree* self, - struct dill_rbtree_item* x) { - struct dill_rbtree_item *y; - struct dill_rbtree_item *nil = &self->nil; - y = x->right; - x->right = y->left; - if(y->left != nil) y->left->up=x; - y->up = x->up; - if(x == x->up->left) { - x->up->left = y; - } else { - x->up->right = y; - } - y->left = x; - x->up = y; -} - -static void dill_rbtree_rrotate(struct dill_rbtree *self, - struct dill_rbtree_item *y) { - struct dill_rbtree_item *x; - struct dill_rbtree_item *nil = &self->nil; - x = y->left; - y->left = x->right; - if(nil != x->right) x->right->up = y; - x->up = y->up; - if(y == y->up->left) { - y->up->left = x; - } else { - y->up->right = x; - } - x->right = y; - y->up = x; -} - -static void dill_rbtree_insert_help(struct dill_rbtree *self, - struct dill_rbtree_item *z) { - struct dill_rbtree_item *x; - struct dill_rbtree_item *y; - struct dill_rbtree_item *nil = &self->nil; - z->left = z->right = nil; - y = &self->root; - x = self->root.left; - while(x != nil) { - y=x; - if(x->val > z->val) { - x = x->left; - } else { - x = x->right; - } - } - z->up = y; - if((y == &self->root) || (y->val > z->val)) { - y->left = z; - } else { - y->right = z; - } -} - -void dill_rbtree_insert(struct dill_rbtree *tree, int64_t val, - struct dill_rbtree_item *item) { - struct dill_rbtree_item *y; - struct dill_rbtree_item *x; - x = item; - x->val = val; - dill_rbtree_insert_help(tree, x); - x->red = 1; - while(x->up->red) { - if(x->up == x->up->up->left) { - y = x->up->up->right; - if(y->red) { - x->up->red = 0; - y->red = 0; - x->up->up->red = 1; - x = x->up->up; - } else { - if(x == x->up->right) { - x = x->up; - dill_rbtree_lrotate(tree, x); - } - x->up->red = 0; - x->up->up->red = 1; - dill_rbtree_rrotate(tree, x->up->up); - } - } else { - y = x->up->up->left; - if(y->red) { - x->up->red = 0; - y->red = 0; - x->up->up->red = 1; - x = x->up->up; - } else { - if(x == x->up->left) { - x = x->up; - dill_rbtree_rrotate(tree, x); - } - x->up->red = 0; - x->up->up->red = 1; - dill_rbtree_lrotate(tree, x->up->up); - } - } - } - tree->root.left->red = 0; -} - -int dill_rbtree_empty(struct dill_rbtree *self) { - struct dill_rbtree_item* nil = &self->nil; - return self->root.left == nil; -} - -struct dill_rbtree_item *dill_rbtree_first(struct dill_rbtree *self) { - struct dill_rbtree_item* nil = &self->nil; - struct dill_rbtree_item *x = self->root.left; - if(x == nil) return NULL; - while(x->left != nil) x = x->left; - return x; -} - -static struct dill_rbtree_item *dill_rbtree_next_help(struct dill_rbtree *tree, - struct dill_rbtree_item *x) { - struct dill_rbtree_item *y; - struct dill_rbtree_item *nil = &tree->nil; - struct dill_rbtree_item *root = &tree->root; - if(nil != (y = x->right)) { - while(y->left != nil) { - y = y->left; - } - return y; - } else { - y = x->up; - while(x == y->right) { - x = y; - y = y->up; - } - if(y == root) return nil; - return y; - } -} - -struct dill_rbtree_item *dill_rbtree_next(struct dill_rbtree *tree, - struct dill_rbtree_item *x) { - struct dill_rbtree_item *it = dill_rbtree_next_help(tree, x); - if(it == &tree->nil) return NULL; - return it; -} - -static void dill_rbtree_fixup(struct dill_rbtree *tree, - struct dill_rbtree_item *x) { - struct dill_rbtree_item *root = tree->root.left; - struct dill_rbtree_item *w; - while((!x->red) && (root != x)) { - if (x == x->up->left) { - w = x->up->right; - if(w->red) { - w->red = 0; - x->up->red = 1; - dill_rbtree_lrotate(tree, x->up); - w = x->up->right; - } - if((!w->right->red) && (!w->left->red)) { - w->red = 1; - x = x->up; - } else { - if(!w->right->red) { - w->left->red = 0; - w->red = 1; - dill_rbtree_rrotate(tree, w); - w = x->up->right; - } - w->red = x->up->red; - x->up->red = 0; - w->right->red = 0; - dill_rbtree_lrotate(tree, x->up); - x = root; - } - } else { - w = x->up->left; - if(w->red) { - w->red = 0; - x->up->red = 1; - dill_rbtree_rrotate(tree, x->up); - w = x->up->left; - } - if((!w->right->red) && (!w->left->red)) { - w->red = 1; - x = x->up; - } else { - if(!w->left->red) { - w->right->red = 0; - w->red = 1; - dill_rbtree_lrotate(tree, w); - w = x->up->left; - } - w->red = x->up->red; - x->up->red = 0; - w->left->red = 0; - dill_rbtree_rrotate(tree, x->up); - x = root; - } - } - } - x->red = 0; -} - -void dill_rbtree_erase(struct dill_rbtree *tree, struct dill_rbtree_item *z) { - struct dill_rbtree_item *y; - struct dill_rbtree_item *x; - struct dill_rbtree_item *nil=&tree->nil; - struct dill_rbtree_item *root=&tree->root; - y = ((z->left == nil) || (z->right == nil)) ? z : - dill_rbtree_next_help(tree, z); - x = (y->left == nil) ? y->right : y->left; - if(root == (x->up = y->up)) { - root->left = x; - } else { - if(y == y->up->left) { - y->up->left = x; - } else { - y->up->right = x; - } - } - if(y != z) { - if(!(y->red)) dill_rbtree_fixup(tree, x); - y->left = z->left; - y->right = z->right; - y->up = z->up; - y->red = z->red; - z->left->up = z->right->up=y; - if(z == z->up->left) { - z->up->left=y; - } else { - z->up->right=y; - } - } else { - if(!(y->red)) dill_rbtree_fixup(tree, x); - } -} - diff --git a/Sources/CLibdill/rbtree.h b/Sources/CLibdill/rbtree.h deleted file mode 100644 index 42f9b5f..0000000 --- a/Sources/CLibdill/rbtree.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - - Copyright (c) 2016 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#ifndef DILL_RBTREE_INCLUDED -#define DILL_RBTREE_INCLUDED - -#include -#include - -struct dill_rbtree_item { - int red; - struct dill_rbtree_item *left; - struct dill_rbtree_item *right; - struct dill_rbtree_item *up; - int64_t val; -}; - -struct dill_rbtree { - struct dill_rbtree_item root; - struct dill_rbtree_item nil; -}; - -/* Initialize the tree. */ -void dill_rbtree_init(struct dill_rbtree *self); - -/* Returns 1 if there are no items in the tree. 0 otherwise. */ -int dill_rbtree_empty(struct dill_rbtree *self); - -/* Insert an item into the tree & set its value to 'val' */ -void dill_rbtree_insert(struct dill_rbtree *self, int64_t val, - struct dill_rbtree_item *item); - -/* Remove an item from a tree. */ -void dill_rbtree_erase(struct dill_rbtree *self, struct dill_rbtree_item *item); - -/* Return an item with the lowest value. If there are no items in the tree, NULL - is returned. */ -struct dill_rbtree_item *dill_rbtree_first(struct dill_rbtree *self); - -/* Iterate through the tree. Items are returned starting with those with - the lowest values and ending with those with the highest values. Items with - equal values are returned in no particular order. If 'it' points to the - last item, NULL is returned. */ -struct dill_rbtree_item *dill_rbtree_next(struct dill_rbtree *self, - struct dill_rbtree_item *it); - -#endif diff --git a/Sources/CLibdill/slist.h b/Sources/CLibdill/slist.h deleted file mode 100644 index 8408ef8..0000000 --- a/Sources/CLibdill/slist.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - - Copyright (c) 2016 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#ifndef DILL_SLIST_INCLUDED -#define DILL_SLIST_INCLUDED - -#include "utils.h" - -/* A Singly-linked list that's last-in-first-out, so it's actually a stack. - To prevent confusion with C's call stack, we'll call it slist. */ - -struct dill_slist { - struct dill_slist *next; -}; - -/* Initialize the list. */ -static inline void dill_slist_init(struct dill_slist *self) { - self->next = self; -} - -/* True if the list has no items. */ -static inline int dill_slist_empty(struct dill_slist *self) { - return self->next == self; -} - -/* Returns the next item in the list. If 'it' is the list itself, it returns the - first element in the list. If there are no more elements in the list, - returns a pointer to the list itself. */ -#define dill_slist_next(it) ((it)->next) - -/* Push the item to the beginning of the list. */ -static inline void dill_slist_push(struct dill_slist *self, - struct dill_slist *item) { - item->next = self->next; - self->next = item; -} - -/* Pop an item from the beginning of the list. */ -static inline struct dill_slist *dill_slist_pop(struct dill_slist *self) { - struct dill_slist *item = self->next; - self->next = item->next; - return item; -} - -#endif - diff --git a/Sources/CLibdill/stack.c b/Sources/CLibdill/stack.c deleted file mode 100644 index 75497a0..0000000 --- a/Sources/CLibdill/stack.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - - Copyright (c) 2016 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include "stack.h" -#include "utils.h" -#include "ctx.h" - -/* The stacks are cached. The advantage of this is twofold. First, caching is - faster than malloc(). Second, it results in fewer calls to - mprotect(). */ - -/* Stack size in bytes. */ -static size_t dill_stack_size = 256 * 1024; -/* Maximum number of unused cached stacks. */ -static int dill_max_cached_stacks = 64; - -/* Returns the smallest value that's greater than val and is a multiple of unit. */ -static size_t dill_align(size_t val, size_t unit) { - return val % unit ? val + unit - val % unit : val; -} - -/* Get memory page size. The query is done once. The value is cached. */ -static size_t dill_page_size(void) { - static long pgsz = 0; - if(dill_fast(pgsz)) - return (size_t)pgsz; - pgsz = sysconf(_SC_PAGE_SIZE); - dill_assert(pgsz > 0); - return (size_t)pgsz; -} - -int dill_ctx_stack_init(struct dill_ctx_stack *ctx) { - ctx->count = 0; - dill_slist_init(&ctx->cache); - return 0; -} - -void dill_ctx_stack_term(struct dill_ctx_stack *ctx) { - /* Deallocate leftover coroutines. */ - struct dill_slist *it; - while((it = dill_slist_pop(&ctx->cache)) != &ctx->cache) { -#if (HAVE_POSIX_MEMALIGN && HAVE_MPROTECT) & !defined DILL_NOGUARD - void *ptr = ((uint8_t*)(it + 1)) - dill_stack_size - dill_page_size(); - int rc = mprotect(ptr, dill_page_size(), PROT_READ|PROT_WRITE); - dill_assert(rc == 0); - free(ptr); -#else - void *ptr = ((uint8_t*)(it + 1)) - dill_stack_size; - free(ptr); -#endif - } -} - -void *dill_allocstack(size_t *stack_size) { - struct dill_ctx_stack *ctx = &dill_getctx->stack; - if(stack_size) - *stack_size = dill_stack_size; - /* If there's a cached stack, use it. */ - if(!dill_slist_empty(&ctx->cache)) { - --ctx->count; - return (void*)(dill_slist_pop(&ctx->cache) + 1); - } - /* Allocate a new stack. */ - uint8_t *top; -#if (HAVE_POSIX_MEMALIGN && HAVE_MPROTECT) & !defined DILL_NOGUARD - /* Allocate the stack so that it's memory-page-aligned. - Add one page as a stack overflow guard. */ - size_t sz = dill_align(dill_stack_size, dill_page_size()) + - dill_page_size(); - uint8_t *ptr; - int rc = posix_memalign((void**)&ptr, dill_page_size(), sz); - if(dill_slow(rc != 0)) { - errno = rc; - return NULL; - } - /* The bottom page is used as a stack guard. This way a stack overflow will - cause a segfault instead of randomly overwriting the heap. */ - rc = mprotect(ptr, dill_page_size(), PROT_NONE); - if(dill_slow(rc != 0)) { - int err = errno; - free(ptr); - errno = err; - return NULL; - } - top = ptr + dill_page_size() + dill_stack_size; -#else - /* Simple allocation without a guard page. */ - uint8_t *ptr = malloc(dill_stack_size); - if(dill_slow(!ptr)) { - errno = ENOMEM; - return NULL; - } - top = ptr + dill_stack_size; -#endif - return top; -} - -void dill_freestack(void *stack) { - struct dill_ctx_stack *ctx = &dill_getctx->stack; - struct dill_slist *item = ((struct dill_slist*)stack) - 1; - /* If there are free slots in the cache, put the stack into the cache. */ - if(ctx->count < dill_max_cached_stacks) { - dill_slist_push(&ctx->cache, item); - ++ctx->count; - return; - } - /* If the stack cache is full, deallocate the stack. */ -#if (HAVE_POSIX_MEMALIGN && HAVE_MPROTECT) & !defined DILL_NOGUARD - void *ptr = ((uint8_t*)(item + 1)) - dill_stack_size - dill_page_size(); - int rc = mprotect(ptr, dill_page_size(), PROT_READ|PROT_WRITE); - dill_assert(rc == 0); - free(ptr); -#else - void *ptr = ((uint8_t*)(item + 1)) - dill_stack_size; - free(ptr); -#endif -} - diff --git a/Sources/CLibdill/stack.h b/Sources/CLibdill/stack.h deleted file mode 100644 index d0010a4..0000000 --- a/Sources/CLibdill/stack.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - - Copyright (c) 2016 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#ifndef DILL_STACK_INCLUDED -#define DILL_STACK_INCLUDED - -#include - -#include "slist.h" - -/* A stack of unused coroutine stacks. This allows for extra-fast allocation - of a new stack. The LIFO nature of this structure minimises cache misses. - When the stack is cached its dill_qlist_item is placed on its top rather - then on the bottom. That way we minimise page misses. */ -struct dill_ctx_stack { - int count; - struct dill_slist cache; -}; - -int dill_ctx_stack_init(struct dill_ctx_stack *ctx); -void dill_ctx_stack_term(struct dill_ctx_stack *ctx); - -/* Allocates new stack. Returns pointer to the *top* of the stack. - For now we assume that the stack grows downwards. */ -void *dill_allocstack(size_t *stack_size); - -/* Deallocates a stack. The argument is pointer to the top of the stack. */ -void dill_freestack(void *stack); - -#endif diff --git a/Sources/CLibdill/tcp.c b/Sources/CLibdill/tcp.c deleted file mode 100644 index 36379ac..0000000 --- a/Sources/CLibdill/tcp.c +++ /dev/null @@ -1,294 +0,0 @@ -/* - - Copyright (c) 2017 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#include -#include -#include - -#include "libdillimpl.h" -#include "fd.h" -#include "utils.h" - -/* Secretly export the symbols. More thinking should be done about how - to do this cleanly without breaking encapsulation. */ -DILL_EXPORT extern const void *tcp_type; -DILL_EXPORT extern const void *tcp_listener_type; -DILL_EXPORT int tcp_fd(int s); - -static int tcp_makeconn(int fd); - -/******************************************************************************/ -/* TCP connection socket */ -/******************************************************************************/ - -dill_unique_id(tcp_type); - -static void *tcp_hquery(struct hvfs *hvfs, const void *type); -static void tcp_hclose(struct hvfs *hvfs); -static int tcp_hdone(struct hvfs *hvfs, int64_t deadline); -static int tcp_bsendl(struct bsock_vfs *bvfs, - struct iolist *first, struct iolist *last, int64_t deadline); -static ssize_t tcp_brecvl(struct bsock_vfs *bvfs, - struct iolist *first, struct iolist *last, int64_t deadline); - -struct tcp_conn { - struct hvfs hvfs; - struct bsock_vfs bvfs; - int fd; - struct fd_rxbuf rxbuf; - unsigned int indone : 1; - unsigned int outdone: 1; - unsigned int inerr : 1; - unsigned int outerr : 1; -}; - -static void *tcp_hquery(struct hvfs *hvfs, const void *type) { - struct tcp_conn *self = (struct tcp_conn*)hvfs; - if(type == bsock_type) return &self->bvfs; - if(type == tcp_type) return self; - errno = ENOTSUP; - return NULL; -} - -int tcp_connect(const struct ipaddr *addr, int64_t deadline) { - int err; - /* Open a socket. */ - int s = socket(ipaddr_family(addr), SOCK_STREAM, 0); - if(dill_slow(s < 0)) {err = errno; goto error1;} - /* Set it to non-blocking mode. */ - int rc = fd_unblock(s); - if(dill_slow(rc < 0)) {err = errno; goto error2;} - /* Connect to the remote endpoint. */ - rc = fd_connect(s, ipaddr_sockaddr(addr), ipaddr_len(addr), deadline); - if(dill_slow(rc < 0)) {err = errno; goto error2;} - /* Create the handle. */ - int h = tcp_makeconn(s); - if(dill_slow(h < 0)) {err = errno; goto error2;} - return h; -error2: - fd_close(s); -error1: - errno = err; - return -1; -} - -static int tcp_bsendl(struct bsock_vfs *bvfs, - struct iolist *first, struct iolist *last, int64_t deadline) { - struct tcp_conn *self = dill_cont(bvfs, struct tcp_conn, bvfs); - if(dill_slow(self->outdone)) {errno = EPIPE; return -1;} - if(dill_slow(self->outerr)) {errno = ECONNRESET; return -1;} - ssize_t sz = fd_send(self->fd, first, last, deadline); - if(dill_fast(sz >= 0)) return sz; - self->outerr = 1; - return -1; -} - -static ssize_t tcp_brecvl(struct bsock_vfs *bvfs, - struct iolist *first, struct iolist *last, int64_t deadline) { - struct tcp_conn *self = dill_cont(bvfs, struct tcp_conn, bvfs); - if(dill_slow(self->indone)) {errno = EPIPE; return -1;} - if(dill_slow(self->inerr)) {errno = ECONNRESET; return -1;} - int sz = fd_recv(self->fd, &self->rxbuf, first, last, deadline); - if(dill_fast(sz > 0)) return sz; - if(errno == EPIPE) self->indone = 1; - else self->inerr = 1; - return -1; -} - -static int tcp_hdone(struct hvfs *hvfs, int64_t deadline) { - struct tcp_conn *self = (struct tcp_conn*)hvfs; - if(dill_slow(self->outdone)) {errno = EPIPE; return -1;} - if(dill_slow(self->outerr)) {errno = ECONNRESET; return -1;} - /* Flushing the tx buffer is done asynchronously on kernel level. */ - int rc = shutdown(self->fd, SHUT_WR); - if(dill_slow(rc < 0)) { - if(errno == ENOTCONN) {self->outerr = 1; errno = ECONNRESET; return -1;} - if(errno == ENOBUFS) {self->outerr = 1; errno = ENOMEM; return -1;} - dill_assert(rc == 0); - } - self->outdone = 1; - return 0; -} - -int tcp_close(int s, int64_t deadline) { - int err; - struct tcp_conn *self = hquery(s, tcp_type); - if(dill_slow(!self)) return -1; - if(dill_slow(self->inerr || self->outerr)) {err = ECONNRESET; goto error;} - /* If not done already, flush the outbound data and start the terminal - handshake. */ - if(!self->outdone) { - int rc = tcp_hdone(&self->hvfs, deadline); - if(dill_slow(rc < 0)) {err = errno; goto error;} - } - /* Now we are going to read all the inbound data until we reach end of the - stream. That way we can be sure that the peer either received all our - data or consciously closed the connection without reading all of it. */ - int rc = 0; - while(rc >= 0) - rc = tcp_brecvl(&self->bvfs, NULL, NULL, deadline); - dill_assert(rc < 0); - if(dill_slow(errno != EPIPE)) {err = errno; goto error;} - return 0; -error: - tcp_hclose(&self->hvfs); - errno = err; - return -1; -} - -static void tcp_hclose(struct hvfs *hvfs) { - struct tcp_conn *self = (struct tcp_conn*)hvfs; - fd_close(self->fd); - free(self); -} - -/******************************************************************************/ -/* TCP listener socket */ -/******************************************************************************/ - -dill_unique_id(tcp_listener_type); - -static void *tcp_listener_hquery(struct hvfs *hvfs, const void *type); -static void tcp_listener_hclose(struct hvfs *hvfs); - -struct tcp_listener { - struct hvfs hvfs; - int fd; - struct ipaddr addr; -}; - -static void *tcp_listener_hquery(struct hvfs *hvfs, const void *type) { - struct tcp_listener *self = (struct tcp_listener*)hvfs; - if(type == tcp_listener_type) return self; - errno = ENOTSUP; - return NULL; -} - -int tcp_listen(struct ipaddr *addr, int backlog) { - int err; - /* Open the listening socket. */ - int s = socket(ipaddr_family(addr), SOCK_STREAM, 0); - if(dill_slow(s < 0)) {err = errno; goto error1;} - /* Set it to non-blocking mode. */ - int rc = fd_unblock(s); - if(dill_slow(rc < 0)) {err = errno; goto error2;} - /* Start listening for incoming connections. */ - rc = bind(s, ipaddr_sockaddr(addr), ipaddr_len(addr)); - if(dill_slow(rc < 0)) {err = errno; goto error2;} - rc = listen(s, backlog); - if(dill_slow(rc < 0)) {err = errno; goto error2;} - /* If the user requested an ephemeral port, - retrieve the port number assigned by the OS. */ - if(ipaddr_port(addr) == 0) { - struct ipaddr baddr; - socklen_t len = sizeof(struct ipaddr); - rc = getsockname(s, (struct sockaddr*)&baddr, &len); - if(rc < 0) {err = errno; goto error2;} - ipaddr_setport(addr, ipaddr_port(&baddr)); - } - /* Create the object. */ - struct tcp_listener *self = malloc(sizeof(struct tcp_listener)); - if(dill_slow(!self)) {err = ENOMEM; goto error2;} - self->hvfs.query = tcp_listener_hquery; - self->hvfs.close = tcp_listener_hclose; - self->hvfs.done = NULL; - self->fd = s; - /* Create handle. */ - int h = hmake(&self->hvfs); - if(dill_slow(h < 0)) {err = errno; goto error3;} - return h; -error3: - free(self); -error2: - close(s); -error1: - errno = err; - return -1; -} - -int tcp_accept(int s, struct ipaddr *addr, int64_t deadline) { - int err; - /* Retrieve the listener object. */ - struct tcp_listener *lst = hquery(s, tcp_listener_type); - if(dill_slow(!lst)) {err = errno; goto error1;} - /* Try to get new connection in a non-blocking way. */ - socklen_t addrlen = sizeof(struct ipaddr); - int as = fd_accept(lst->fd, (struct sockaddr*)addr, &addrlen, deadline); - if(dill_slow(as < 0)) {err = errno; goto error1;} - /* Create the handle. */ - int h = tcp_makeconn(as); - if(dill_slow(h < 0)) {err = errno; goto error2;} - return h; -error2: - fd_close(as); -error1: - errno = err; - return -1; -} - -int tcp_fd(int s) { - struct tcp_listener *lst = hquery(s, tcp_listener_type); - if(lst) return lst->fd; - struct tcp_conn *conn = hquery(s, tcp_type); - if(conn) return conn->fd; - return -1; -} - -static void tcp_listener_hclose(struct hvfs *hvfs) { - struct tcp_listener *self = (struct tcp_listener*)hvfs; - fd_close(self->fd); - free(self); -} - -/******************************************************************************/ -/* Helpers */ -/******************************************************************************/ - -static int tcp_makeconn(int fd) { - int err; - /* Create the object. */ - struct tcp_conn *self = malloc(sizeof(struct tcp_conn)); - if(dill_slow(!self)) {err = ENOMEM; goto error1;} - self->hvfs.query = tcp_hquery; - self->hvfs.close = tcp_hclose; - self->hvfs.done = tcp_hdone; - self->bvfs.bsendl = tcp_bsendl; - self->bvfs.brecvl = tcp_brecvl; - self->fd = fd; - fd_initrxbuf(&self->rxbuf); - self->indone = 0; - self->outdone = 0; - self->inerr = 0; - self->outerr = 0; - /* Create the handle. */ - int h = hmake(&self->hvfs); - if(dill_slow(h < 0)) {err = errno; goto error2;} - return h; -error2: - free(self); -error1: - errno = err; - return -1; -} - diff --git a/Sources/CLibdill/utils.c b/Sources/CLibdill/utils.c deleted file mode 100644 index 16a4d1c..0000000 --- a/Sources/CLibdill/utils.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - - Copyright (c) 2017 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#include -#include - -#include "utils.h" - -int dill_maxfds(void) { - /* Get the maximum number of file descriptors. */ - struct rlimit rlim; - int rc = getrlimit(RLIMIT_NOFILE, &rlim); - dill_assert(rc == 0); - int maxfds = rlim.rlim_max; -#if defined BSD - /* On newer versions of OSX, the above behaves weirdly and returns -1, - so use OPEN_MAX instead. */ - if(maxfds < 0) return OPEN_MAX; -#endif - return maxfds; -} - -uint16_t dill_gets(const uint8_t *buf) { - return (((uint16_t)buf[0]) << 8) | - ((uint16_t)buf[1]); -} - -void dill_puts(uint8_t *buf, uint16_t val) { - buf[0] = (uint8_t)(((val) >> 8) & 0xff); - buf[1] = (uint8_t)(val & 0xff); -} - -uint32_t dill_getl(const uint8_t *buf) { - return (((uint32_t)buf[0]) << 24) | - (((uint32_t)buf[1]) << 16) | - (((uint32_t)buf[2]) << 8) | - ((uint32_t)buf[3]); -} - -void dill_putl(uint8_t *buf, uint32_t val) { - buf[0] = (uint8_t)(((val) >> 24) & 0xff); - buf[1] = (uint8_t)(((val) >> 16) & 0xff); - buf[2] = (uint8_t)(((val) >> 8) & 0xff); - buf[3] = (uint8_t)(val & 0xff); -} - -uint64_t dill_getll(const uint8_t *buf) { - return (((uint64_t)buf[0]) << 56) | - (((uint64_t)buf[1]) << 48) | - (((uint64_t)buf[2]) << 40) | - (((uint64_t)buf[3]) << 32) | - (((uint64_t)buf[4]) << 24) | - (((uint64_t)buf[5]) << 16) | - (((uint64_t)buf[6]) << 8) | - (((uint64_t)buf[7] << 0)); -} - -void dill_putll(uint8_t *buf, uint64_t val) { - buf[0] = (uint8_t)((val >> 56) & 0xff); - buf[1] = (uint8_t)((val >> 48) & 0xff); - buf[2] = (uint8_t)((val >> 40) & 0xff); - buf[3] = (uint8_t)((val >> 32) & 0xff); - buf[4] = (uint8_t)((val >> 24) & 0xff); - buf[5] = (uint8_t)((val >> 16) & 0xff); - buf[6] = (uint8_t)((val >> 8) & 0xff); - buf[7] = (uint8_t)(val & 0xff); -} - diff --git a/Sources/CLibdill/utils.h b/Sources/CLibdill/utils.h deleted file mode 100644 index 61f5012..0000000 --- a/Sources/CLibdill/utils.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - - Copyright (c) 2017 Martin Sustrik - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom - the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - -*/ - -#ifndef DILL_UTILS_H_INCLUDED -#define DILL_UTILS_H_INCLUDED - -#include -#include -#include -#include - -#define dill_concat(x,y) x##y - -/* Defines a unique identifier of type const void*. */ -#define dill_unique_id(name) \ - static const int dill_concat(name, ___) = 0;\ - const void *name = & dill_concat(name, ___); - -/* Takes a pointer to a member variable and computes pointer to the structure - that contains it. 'type' is type of the structure, not the member. */ -#define dill_cont(ptr, type, member) \ - (ptr ? ((type*) (((char*) ptr) - offsetof(type, member))) : NULL) - -/* Compile-time assert. */ -#define DILL_CT_ASSERT_HELPER2(prefix, line) \ - prefix##line -#define DILL_CT_ASSERT_HELPER1(prefix, line) \ - DILL_CT_ASSERT_HELPER2(prefix, line) -#define DILL_CT_ASSERT(x) \ - typedef int DILL_CT_ASSERT_HELPER1(ct_assert_,__COUNTER__) [(x) ? 1 : -1] - -/* Optimisation hints. */ -#if defined __GNUC__ || defined __llvm__ -#define dill_fast(x) __builtin_expect(!!(x), 1) -#define dill_slow(x) __builtin_expect(!!(x), 0) -#else -#define dill_fast(x) (x) -#define dill_slow(x) (x) -#endif - -/* Define our own assert. This way we are sure that it stays in place even - if the standard C assert would be thrown away by the compiler. It also - allows us to overload it as needed. */ -#define dill_assert(x) \ - do {\ - if (dill_slow(!(x))) {\ - fprintf(stderr, "Assert failed: " #x " (%s:%d)\n",\ - __FILE__, __LINE__);\ - fflush(stderr);\ - abort();\ - }\ - } while (0) - -/* Workaround missing __rdtsc in Clang < 3.5 (or Clang < 6.0 on Xcode) */ -#if defined(__x86_64__) || defined(__i386__) -#if defined __clang__ -#if (!defined(__apple_build_version__) && \ - ((__clang_major__ < 3) || \ - ((__clang_major__ == 3) && (__clang_minor__ < 5)))) || \ - (defined(__apple_build_version__) && (__clang_major__ < 6)) -static inline uint64_t __rdtsc() { -#if defined __i386__ - uint64_t x; - asm volatile ("rdtsc" : "=A" (x)); - return x; -#else - uint64_t a, d; - asm volatile ("rdtsc" : "=a" (a), "=d" (d)); - return (d << 32) | a; -#endif -} -#endif -#endif -#endif - -/* Returns the maximum possible file descriptor number */ -int dill_maxfds(void); - -/* Encoding and decoding integers from network byte order. */ -uint16_t dill_gets(const uint8_t *buf); -void dill_puts(uint8_t *buf, uint16_t val); -uint32_t dill_getl(const uint8_t *buf); -void dill_putl(uint8_t *buf, uint32_t val); -uint64_t dill_getll(const uint8_t *buf); -void dill_putll(uint8_t *buf, uint64_t val); - -#endif - From 8e6498db6c83d9a88f56cfbff1c56ddc6d538f15 Mon Sep 17 00:00:00 2001 From: Paulo Faria Date: Wed, 7 Jun 2017 19:33:15 -0300 Subject: [PATCH 02/11] install libdill on travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index b2b6a74..d334b28 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,7 @@ sudo: required dist: trusty osx_image: xcode8.3 install: + - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew install zewo/tap/libdill; fi - eval "$(curl -sL https://raw.githubusercontent.com/Zewo/Zewo/master/Scripts/Travis/install.sh)" script: - bash <(curl -s https://raw.githubusercontent.com/Zewo/Zewo/master/Scripts/Travis/build-test.sh) Venice From a9863962d2c3a5188529d49cf62f6bf0ef92b47c Mon Sep 17 00:00:00 2001 From: Paulo Faria Date: Thu, 8 Jun 2017 01:27:38 -0300 Subject: [PATCH 03/11] install libdill via make on linux --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index d334b28..71412e7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,11 @@ dist: trusty osx_image: xcode8.3 install: - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew install zewo/tap/libdill; fi + - if [ "$TRAVIS_OS_NAME" == "linux" ]; then git clone https://github.com/Zewo/libdill .; fi + - if [ "$TRAVIS_OS_NAME" == "linux" ]; then ./autogen.sh; fi + - if [ "$TRAVIS_OS_NAME" == "linux" ]; then ./configure; fi + - if [ "$TRAVIS_OS_NAME" == "linux" ]; then make; fi + - if [ "$TRAVIS_OS_NAME" == "linux" ]; then make install; fi - eval "$(curl -sL https://raw.githubusercontent.com/Zewo/Zewo/master/Scripts/Travis/install.sh)" script: - bash <(curl -s https://raw.githubusercontent.com/Zewo/Zewo/master/Scripts/Travis/build-test.sh) Venice From a66dc41c162a7271818d9861f80311d8b8bb754d Mon Sep 17 00:00:00 2001 From: Paulo Faria Date: Thu, 8 Jun 2017 01:30:00 -0300 Subject: [PATCH 04/11] install libdill in a separate dir --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 71412e7..a32674c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,11 +9,13 @@ dist: trusty osx_image: xcode8.3 install: - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew install zewo/tap/libdill; fi - - if [ "$TRAVIS_OS_NAME" == "linux" ]; then git clone https://github.com/Zewo/libdill .; fi + - if [ "$TRAVIS_OS_NAME" == "linux" ]; then git clone https://github.com/Zewo/libdill; fi + - if [ "$TRAVIS_OS_NAME" == "linux" ]; then cd libdill; fi - if [ "$TRAVIS_OS_NAME" == "linux" ]; then ./autogen.sh; fi - if [ "$TRAVIS_OS_NAME" == "linux" ]; then ./configure; fi - if [ "$TRAVIS_OS_NAME" == "linux" ]; then make; fi - if [ "$TRAVIS_OS_NAME" == "linux" ]; then make install; fi + - if [ "$TRAVIS_OS_NAME" == "linux" ]; then cd ..; fi - eval "$(curl -sL https://raw.githubusercontent.com/Zewo/Zewo/master/Scripts/Travis/install.sh)" script: - bash <(curl -s https://raw.githubusercontent.com/Zewo/Zewo/master/Scripts/Travis/build-test.sh) Venice From 3f7c4403eeb3a25003636be526fde7d319208d78 Mon Sep 17 00:00:00 2001 From: Paulo Faria Date: Thu, 8 Jun 2017 01:32:06 -0300 Subject: [PATCH 05/11] sudo make install --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a32674c..0c9d6d7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ install: - if [ "$TRAVIS_OS_NAME" == "linux" ]; then ./autogen.sh; fi - if [ "$TRAVIS_OS_NAME" == "linux" ]; then ./configure; fi - if [ "$TRAVIS_OS_NAME" == "linux" ]; then make; fi - - if [ "$TRAVIS_OS_NAME" == "linux" ]; then make install; fi + - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo make install; fi - if [ "$TRAVIS_OS_NAME" == "linux" ]; then cd ..; fi - eval "$(curl -sL https://raw.githubusercontent.com/Zewo/Zewo/master/Scripts/Travis/install.sh)" script: From a784245697c12f561bd6bccd0bc572f0fe9cce73 Mon Sep 17 00:00:00 2001 From: Paulo Faria Date: Thu, 8 Jun 2017 01:57:11 -0300 Subject: [PATCH 06/11] install pkgconfig on linux travis --- .travis.yml | 4 ++++ Package.swift | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0c9d6d7..8d2ea6f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,10 @@ notifications: os: - linux - osx +addons: + apt: + packages: + - pkg-config language: generic sudo: required dist: trusty diff --git a/Package.swift b/Package.swift index cac279a..69c1f38 100644 --- a/Package.swift +++ b/Package.swift @@ -2,9 +2,7 @@ import PackageDescription let package = Package( name: "Venice", - dependencies: [ .Package(url: "https://github.com/Zewo/CLibdill.git", majorVersion: 1, minor: 0) ] - ) From df78f1174982a37461f5c7c49ace655239eb756b Mon Sep 17 00:00:00 2001 From: Paulo Faria Date: Thu, 8 Jun 2017 02:05:29 -0300 Subject: [PATCH 07/11] export PKG_CONFIG_PATH --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8d2ea6f..d75cca1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,10 +3,6 @@ notifications: os: - linux - osx -addons: - apt: - packages: - - pkg-config language: generic sudo: required dist: trusty @@ -20,6 +16,10 @@ install: - if [ "$TRAVIS_OS_NAME" == "linux" ]; then make; fi - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo make install; fi - if [ "$TRAVIS_OS_NAME" == "linux" ]; then cd ..; fi + - if [ "$TRAVIS_OS_NAME" == "linux" ]; then cd ..; fi + - echo $PKG_CONFIG_PATH + - export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig + - echo $PKG_CONFIG_PATH - eval "$(curl -sL https://raw.githubusercontent.com/Zewo/Zewo/master/Scripts/Travis/install.sh)" script: - bash <(curl -s https://raw.githubusercontent.com/Zewo/Zewo/master/Scripts/Travis/build-test.sh) Venice From b557abecf6f0808c198bb2fc0efe917d2244222b Mon Sep 17 00:00:00 2001 From: Paulo Faria Date: Thu, 8 Jun 2017 02:12:01 -0300 Subject: [PATCH 08/11] remove echo and extra cd --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index d75cca1..13d24e4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,10 +16,7 @@ install: - if [ "$TRAVIS_OS_NAME" == "linux" ]; then make; fi - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo make install; fi - if [ "$TRAVIS_OS_NAME" == "linux" ]; then cd ..; fi - - if [ "$TRAVIS_OS_NAME" == "linux" ]; then cd ..; fi - - echo $PKG_CONFIG_PATH - export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig - - echo $PKG_CONFIG_PATH - eval "$(curl -sL https://raw.githubusercontent.com/Zewo/Zewo/master/Scripts/Travis/install.sh)" script: - bash <(curl -s https://raw.githubusercontent.com/Zewo/Zewo/master/Scripts/Travis/build-test.sh) Venice From 1accfe8850ec4c298e8cfeb218ab85d59a7bedf2 Mon Sep 17 00:00:00 2001 From: Paulo Faria Date: Thu, 8 Jun 2017 02:24:50 -0300 Subject: [PATCH 09/11] echo debug info --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 13d24e4..a60466a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,10 @@ install: - if [ "$TRAVIS_OS_NAME" == "linux" ]; then make; fi - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo make install; fi - if [ "$TRAVIS_OS_NAME" == "linux" ]; then cd ..; fi + - pkg-config --list-all - export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig + - pkg-config --list-all + - ls -la /usr/local/lib - eval "$(curl -sL https://raw.githubusercontent.com/Zewo/Zewo/master/Scripts/Travis/install.sh)" script: - bash <(curl -s https://raw.githubusercontent.com/Zewo/Zewo/master/Scripts/Travis/build-test.sh) Venice From 9540e0c486a8cddcbb92c0a4d9a17eb57363529d Mon Sep 17 00:00:00 2001 From: Paulo Faria Date: Thu, 8 Jun 2017 02:30:35 -0300 Subject: [PATCH 10/11] echo ld library path --- .travis.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index a60466a..24c7153 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,10 +16,9 @@ install: - if [ "$TRAVIS_OS_NAME" == "linux" ]; then make; fi - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo make install; fi - if [ "$TRAVIS_OS_NAME" == "linux" ]; then cd ..; fi - - pkg-config --list-all - - export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig - - pkg-config --list-all - - ls -la /usr/local/lib + - echo $LD_LIBRARY_PATH + - export LD_LIBRARY_PATH=/usr/local/lib + - echo $LD_LIBRARY_PATH - eval "$(curl -sL https://raw.githubusercontent.com/Zewo/Zewo/master/Scripts/Travis/install.sh)" script: - bash <(curl -s https://raw.githubusercontent.com/Zewo/Zewo/master/Scripts/Travis/build-test.sh) Venice From 9f48ae6e35009f3abe610453f4af0cdcca36308e Mon Sep 17 00:00:00 2001 From: Paulo Faria Date: Thu, 8 Jun 2017 02:35:11 -0300 Subject: [PATCH 11/11] echo libdill pc file --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 24c7153..eac6d5e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,9 +16,8 @@ install: - if [ "$TRAVIS_OS_NAME" == "linux" ]; then make; fi - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo make install; fi - if [ "$TRAVIS_OS_NAME" == "linux" ]; then cd ..; fi - - echo $LD_LIBRARY_PATH + - cat /usr/local/lib/pkgconfig/libdill.pc - export LD_LIBRARY_PATH=/usr/local/lib - - echo $LD_LIBRARY_PATH - eval "$(curl -sL https://raw.githubusercontent.com/Zewo/Zewo/master/Scripts/Travis/install.sh)" script: - bash <(curl -s https://raw.githubusercontent.com/Zewo/Zewo/master/Scripts/Travis/build-test.sh) Venice