aboutsummaryrefslogtreecommitdiff
path: root/external/unbound/util/netevent.c
diff options
context:
space:
mode:
Diffstat (limited to 'external/unbound/util/netevent.c')
-rw-r--r--external/unbound/util/netevent.c2410
1 files changed, 0 insertions, 2410 deletions
diff --git a/external/unbound/util/netevent.c b/external/unbound/util/netevent.c
deleted file mode 100644
index 2084cea3e..000000000
--- a/external/unbound/util/netevent.c
+++ /dev/null
@@ -1,2410 +0,0 @@
-/*
- * util/netevent.c - event notification
- *
- * Copyright (c) 2007, NLnet Labs. All rights reserved.
- *
- * This software is open source.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of the NLNET LABS nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * \file
- *
- * This file contains event notification functions.
- */
-#include "config.h"
-#include "util/netevent.h"
-#include "util/ub_event.h"
-#include "util/log.h"
-#include "util/net_help.h"
-#include "util/fptr_wlist.h"
-#include "sldns/pkthdr.h"
-#include "sldns/sbuffer.h"
-#include "dnstap/dnstap.h"
-#include "dnscrypt/dnscrypt.h"
-#ifdef HAVE_OPENSSL_SSL_H
-#include <openssl/ssl.h>
-#endif
-#ifdef HAVE_OPENSSL_ERR_H
-#include <openssl/err.h>
-#endif
-
-/* -------- Start of local definitions -------- */
-/** if CMSG_ALIGN is not defined on this platform, a workaround */
-#ifndef CMSG_ALIGN
-# ifdef __CMSG_ALIGN
-# define CMSG_ALIGN(n) __CMSG_ALIGN(n)
-# elif defined(CMSG_DATA_ALIGN)
-# define CMSG_ALIGN _CMSG_DATA_ALIGN
-# else
-# define CMSG_ALIGN(len) (((len)+sizeof(long)-1) & ~(sizeof(long)-1))
-# endif
-#endif
-
-/** if CMSG_LEN is not defined on this platform, a workaround */
-#ifndef CMSG_LEN
-# define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr))+(len))
-#endif
-
-/** if CMSG_SPACE is not defined on this platform, a workaround */
-#ifndef CMSG_SPACE
-# ifdef _CMSG_HDR_ALIGN
-# define CMSG_SPACE(l) (CMSG_ALIGN(l)+_CMSG_HDR_ALIGN(sizeof(struct cmsghdr)))
-# else
-# define CMSG_SPACE(l) (CMSG_ALIGN(l)+CMSG_ALIGN(sizeof(struct cmsghdr)))
-# endif
-#endif
-
-/** The TCP reading or writing query timeout in milliseconds */
-#define TCP_QUERY_TIMEOUT 120000
-/** The TCP timeout in msec for fast queries, above half are used */
-#define TCP_QUERY_TIMEOUT_FAST 200
-
-#ifndef NONBLOCKING_IS_BROKEN
-/** number of UDP reads to perform per read indication from select */
-#define NUM_UDP_PER_SELECT 100
-#else
-#define NUM_UDP_PER_SELECT 1
-#endif
-
-/**
- * The internal event structure for keeping ub_event info for the event.
- * Possibly other structures (list, tree) this is part of.
- */
-struct internal_event {
- /** the comm base */
- struct comm_base* base;
- /** ub_event event type */
- struct ub_event* ev;
-};
-
-/**
- * Internal base structure, so that every thread has its own events.
- */
-struct internal_base {
- /** ub_event event_base type. */
- struct ub_event_base* base;
- /** seconds time pointer points here */
- time_t secs;
- /** timeval with current time */
- struct timeval now;
- /** the event used for slow_accept timeouts */
- struct ub_event* slow_accept;
- /** true if slow_accept is enabled */
- int slow_accept_enabled;
-};
-
-/**
- * Internal timer structure, to store timer event in.
- */
-struct internal_timer {
- /** the super struct from which derived */
- struct comm_timer super;
- /** the comm base */
- struct comm_base* base;
- /** ub_event event type */
- struct ub_event* ev;
- /** is timer enabled */
- uint8_t enabled;
-};
-
-/**
- * Internal signal structure, to store signal event in.
- */
-struct internal_signal {
- /** ub_event event type */
- struct ub_event* ev;
- /** next in signal list */
- struct internal_signal* next;
-};
-
-/** create a tcp handler with a parent */
-static struct comm_point* comm_point_create_tcp_handler(
- struct comm_base *base, struct comm_point* parent, size_t bufsize,
- comm_point_callback_type* callback, void* callback_arg);
-
-/* -------- End of local definitions -------- */
-
-struct comm_base*
-comm_base_create(int sigs)
-{
- struct comm_base* b = (struct comm_base*)calloc(1,
- sizeof(struct comm_base));
- const char *evnm="event", *evsys="", *evmethod="";
-
- if(!b)
- return NULL;
- b->eb = (struct internal_base*)calloc(1, sizeof(struct internal_base));
- if(!b->eb) {
- free(b);
- return NULL;
- }
- b->eb->base = ub_default_event_base(sigs, &b->eb->secs, &b->eb->now);
- if(!b->eb->base) {
- free(b->eb);
- free(b);
- return NULL;
- }
- ub_comm_base_now(b);
- ub_get_event_sys(b->eb->base, &evnm, &evsys, &evmethod);
- verbose(VERB_ALGO, "%s %s user %s method.", evnm, evsys, evmethod);
- return b;
-}
-
-struct comm_base*
-comm_base_create_event(struct ub_event_base* base)
-{
- struct comm_base* b = (struct comm_base*)calloc(1,
- sizeof(struct comm_base));
- if(!b)
- return NULL;
- b->eb = (struct internal_base*)calloc(1, sizeof(struct internal_base));
- if(!b->eb) {
- free(b);
- return NULL;
- }
- b->eb->base = base;
- ub_comm_base_now(b);
- return b;
-}
-
-void
-comm_base_delete(struct comm_base* b)
-{
- if(!b)
- return;
- if(b->eb->slow_accept_enabled) {
- if(ub_event_del(b->eb->slow_accept) != 0) {
- log_err("could not event_del slow_accept");
- }
- ub_event_free(b->eb->slow_accept);
- }
- ub_event_base_free(b->eb->base);
- b->eb->base = NULL;
- free(b->eb);
- free(b);
-}
-
-void
-comm_base_delete_no_base(struct comm_base* b)
-{
- if(!b)
- return;
- if(b->eb->slow_accept_enabled) {
- if(ub_event_del(b->eb->slow_accept) != 0) {
- log_err("could not event_del slow_accept");
- }
- ub_event_free(b->eb->slow_accept);
- }
- b->eb->base = NULL;
- free(b->eb);
- free(b);
-}
-
-void
-comm_base_timept(struct comm_base* b, time_t** tt, struct timeval** tv)
-{
- *tt = &b->eb->secs;
- *tv = &b->eb->now;
-}
-
-void
-comm_base_dispatch(struct comm_base* b)
-{
- int retval;
- retval = ub_event_base_dispatch(b->eb->base);
- if(retval < 0) {
- fatal_exit("event_dispatch returned error %d, "
- "errno is %s", retval, strerror(errno));
- }
-}
-
-void comm_base_exit(struct comm_base* b)
-{
- if(ub_event_base_loopexit(b->eb->base) != 0) {
- log_err("Could not loopexit");
- }
-}
-
-void comm_base_set_slow_accept_handlers(struct comm_base* b,
- void (*stop_acc)(void*), void (*start_acc)(void*), void* arg)
-{
- b->stop_accept = stop_acc;
- b->start_accept = start_acc;
- b->cb_arg = arg;
-}
-
-struct ub_event_base* comm_base_internal(struct comm_base* b)
-{
- return b->eb->base;
-}
-
-/** see if errno for udp has to be logged or not uses globals */
-static int
-udp_send_errno_needs_log(struct sockaddr* addr, socklen_t addrlen)
-{
- /* do not log transient errors (unless high verbosity) */
-#if defined(ENETUNREACH) || defined(EHOSTDOWN) || defined(EHOSTUNREACH) || defined(ENETDOWN)
- switch(errno) {
-# ifdef ENETUNREACH
- case ENETUNREACH:
-# endif
-# ifdef EHOSTDOWN
- case EHOSTDOWN:
-# endif
-# ifdef EHOSTUNREACH
- case EHOSTUNREACH:
-# endif
-# ifdef ENETDOWN
- case ENETDOWN:
-# endif
- if(verbosity < VERB_ALGO)
- return 0;
- default:
- break;
- }
-#endif
- /* permission denied is gotten for every send if the
- * network is disconnected (on some OS), squelch it */
- if( ((errno == EPERM)
-# ifdef EADDRNOTAVAIL
- /* 'Cannot assign requested address' also when disconnected */
- || (errno == EADDRNOTAVAIL)
-# endif
- ) && verbosity < VERB_DETAIL)
- return 0;
- /* squelch errors where people deploy AAAA ::ffff:bla for
- * authority servers, which we try for intranets. */
- if(errno == EINVAL && addr_is_ip4mapped(
- (struct sockaddr_storage*)addr, addrlen) &&
- verbosity < VERB_DETAIL)
- return 0;
- /* SO_BROADCAST sockopt can give access to 255.255.255.255,
- * but a dns cache does not need it. */
- if(errno == EACCES && addr_is_broadcast(
- (struct sockaddr_storage*)addr, addrlen) &&
- verbosity < VERB_DETAIL)
- return 0;
- return 1;
-}
-
-int tcp_connect_errno_needs_log(struct sockaddr* addr, socklen_t addrlen)
-{
- return udp_send_errno_needs_log(addr, addrlen);
-}
-
-/* send a UDP reply */
-int
-comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet,
- struct sockaddr* addr, socklen_t addrlen)
-{
- ssize_t sent;
- log_assert(c->fd != -1);
-#ifdef UNBOUND_DEBUG
- if(sldns_buffer_remaining(packet) == 0)
- log_err("error: send empty UDP packet");
-#endif
- log_assert(addr && addrlen > 0);
- sent = sendto(c->fd, (void*)sldns_buffer_begin(packet),
- sldns_buffer_remaining(packet), 0,
- addr, addrlen);
- if(sent == -1) {
- /* try again and block, waiting for IO to complete,
- * we want to send the answer, and we will wait for
- * the ethernet interface buffer to have space. */
-#ifndef USE_WINSOCK
- if(errno == EAGAIN ||
-# ifdef EWOULDBLOCK
- errno == EWOULDBLOCK ||
-# endif
- errno == ENOBUFS) {
-#else
- if(WSAGetLastError() == WSAEINPROGRESS ||
- WSAGetLastError() == WSAENOBUFS ||
- WSAGetLastError() == WSAEWOULDBLOCK) {
-#endif
- int e;
- fd_set_block(c->fd);
- sent = sendto(c->fd, (void*)sldns_buffer_begin(packet),
- sldns_buffer_remaining(packet), 0,
- addr, addrlen);
- e = errno;
- fd_set_nonblock(c->fd);
- errno = e;
- }
- }
- if(sent == -1) {
- if(!udp_send_errno_needs_log(addr, addrlen))
- return 0;
-#ifndef USE_WINSOCK
- verbose(VERB_OPS, "sendto failed: %s", strerror(errno));
-#else
- verbose(VERB_OPS, "sendto failed: %s",
- wsa_strerror(WSAGetLastError()));
-#endif
- log_addr(VERB_OPS, "remote address is",
- (struct sockaddr_storage*)addr, addrlen);
- return 0;
- } else if((size_t)sent != sldns_buffer_remaining(packet)) {
- log_err("sent %d in place of %d bytes",
- (int)sent, (int)sldns_buffer_remaining(packet));
- return 0;
- }
- return 1;
-}
-
-#if defined(AF_INET6) && defined(IPV6_PKTINFO) && (defined(HAVE_RECVMSG) || defined(HAVE_SENDMSG))
-/** print debug ancillary info */
-static void p_ancil(const char* str, struct comm_reply* r)
-{
- if(r->srctype != 4 && r->srctype != 6) {
- log_info("%s: unknown srctype %d", str, r->srctype);
- return;
- }
- if(r->srctype == 6) {
- char buf[1024];
- if(inet_ntop(AF_INET6, &r->pktinfo.v6info.ipi6_addr,
- buf, (socklen_t)sizeof(buf)) == 0) {
- (void)strlcpy(buf, "(inet_ntop error)", sizeof(buf));
- }
- buf[sizeof(buf)-1]=0;
- log_info("%s: %s %d", str, buf, r->pktinfo.v6info.ipi6_ifindex);
- } else if(r->srctype == 4) {
-#ifdef IP_PKTINFO
- char buf1[1024], buf2[1024];
- if(inet_ntop(AF_INET, &r->pktinfo.v4info.ipi_addr,
- buf1, (socklen_t)sizeof(buf1)) == 0) {
- (void)strlcpy(buf1, "(inet_ntop error)", sizeof(buf1));
- }
- buf1[sizeof(buf1)-1]=0;
-#ifdef HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST
- if(inet_ntop(AF_INET, &r->pktinfo.v4info.ipi_spec_dst,
- buf2, (socklen_t)sizeof(buf2)) == 0) {
- (void)strlcpy(buf2, "(inet_ntop error)", sizeof(buf2));
- }
- buf2[sizeof(buf2)-1]=0;
-#else
- buf2[0]=0;
-#endif
- log_info("%s: %d %s %s", str, r->pktinfo.v4info.ipi_ifindex,
- buf1, buf2);
-#elif defined(IP_RECVDSTADDR)
- char buf1[1024];
- if(inet_ntop(AF_INET, &r->pktinfo.v4addr,
- buf1, (socklen_t)sizeof(buf1)) == 0) {
- (void)strlcpy(buf1, "(inet_ntop error)", sizeof(buf1));
- }
- buf1[sizeof(buf1)-1]=0;
- log_info("%s: %s", str, buf1);
-#endif /* IP_PKTINFO or PI_RECVDSTDADDR */
- }
-}
-#endif /* AF_INET6 && IPV6_PKTINFO && HAVE_RECVMSG||HAVE_SENDMSG */
-
-/** send a UDP reply over specified interface*/
-static int
-comm_point_send_udp_msg_if(struct comm_point *c, sldns_buffer* packet,
- struct sockaddr* addr, socklen_t addrlen, struct comm_reply* r)
-{
-#if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_SENDMSG)
- ssize_t sent;
- struct msghdr msg;
- struct iovec iov[1];
- char control[256];
-#ifndef S_SPLINT_S
- struct cmsghdr *cmsg;
-#endif /* S_SPLINT_S */
-
- log_assert(c->fd != -1);
-#ifdef UNBOUND_DEBUG
- if(sldns_buffer_remaining(packet) == 0)
- log_err("error: send empty UDP packet");
-#endif
- log_assert(addr && addrlen > 0);
-
- msg.msg_name = addr;
- msg.msg_namelen = addrlen;
- iov[0].iov_base = sldns_buffer_begin(packet);
- iov[0].iov_len = sldns_buffer_remaining(packet);
- msg.msg_iov = iov;
- msg.msg_iovlen = 1;
- msg.msg_control = control;
-#ifndef S_SPLINT_S
- msg.msg_controllen = sizeof(control);
-#endif /* S_SPLINT_S */
- msg.msg_flags = 0;
-
-#ifndef S_SPLINT_S
- cmsg = CMSG_FIRSTHDR(&msg);
- if(r->srctype == 4) {
-#ifdef IP_PKTINFO
- void* cmsg_data;
- msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
- log_assert(msg.msg_controllen <= sizeof(control));
- cmsg->cmsg_level = IPPROTO_IP;
- cmsg->cmsg_type = IP_PKTINFO;
- memmove(CMSG_DATA(cmsg), &r->pktinfo.v4info,
- sizeof(struct in_pktinfo));
- /* unset the ifindex to not bypass the routing tables */
- cmsg_data = CMSG_DATA(cmsg);
- ((struct in_pktinfo *) cmsg_data)->ipi_ifindex = 0;
- cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
-#elif defined(IP_SENDSRCADDR)
- msg.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
- log_assert(msg.msg_controllen <= sizeof(control));
- cmsg->cmsg_level = IPPROTO_IP;
- cmsg->cmsg_type = IP_SENDSRCADDR;
- memmove(CMSG_DATA(cmsg), &r->pktinfo.v4addr,
- sizeof(struct in_addr));
- cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
-#else
- verbose(VERB_ALGO, "no IP_PKTINFO or IP_SENDSRCADDR");
- msg.msg_control = NULL;
-#endif /* IP_PKTINFO or IP_SENDSRCADDR */
- } else if(r->srctype == 6) {
- void* cmsg_data;
- msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
- log_assert(msg.msg_controllen <= sizeof(control));
- cmsg->cmsg_level = IPPROTO_IPV6;
- cmsg->cmsg_type = IPV6_PKTINFO;
- memmove(CMSG_DATA(cmsg), &r->pktinfo.v6info,
- sizeof(struct in6_pktinfo));
- /* unset the ifindex to not bypass the routing tables */
- cmsg_data = CMSG_DATA(cmsg);
- ((struct in6_pktinfo *) cmsg_data)->ipi6_ifindex = 0;
- cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
- } else {
- /* try to pass all 0 to use default route */
- msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
- log_assert(msg.msg_controllen <= sizeof(control));
- cmsg->cmsg_level = IPPROTO_IPV6;
- cmsg->cmsg_type = IPV6_PKTINFO;
- memset(CMSG_DATA(cmsg), 0, sizeof(struct in6_pktinfo));
- cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
- }
-#endif /* S_SPLINT_S */
- if(verbosity >= VERB_ALGO)
- p_ancil("send_udp over interface", r);
- sent = sendmsg(c->fd, &msg, 0);
- if(sent == -1) {
- /* try again and block, waiting for IO to complete,
- * we want to send the answer, and we will wait for
- * the ethernet interface buffer to have space. */
-#ifndef USE_WINSOCK
- if(errno == EAGAIN ||
-# ifdef EWOULDBLOCK
- errno == EWOULDBLOCK ||
-# endif
- errno == ENOBUFS) {
-#else
- if(WSAGetLastError() == WSAEINPROGRESS ||
- WSAGetLastError() == WSAENOBUFS ||
- WSAGetLastError() == WSAEWOULDBLOCK) {
-#endif
- int e;
- fd_set_block(c->fd);
- sent = sendmsg(c->fd, &msg, 0);
- e = errno;
- fd_set_nonblock(c->fd);
- errno = e;
- }
- }
- if(sent == -1) {
- if(!udp_send_errno_needs_log(addr, addrlen))
- return 0;
- verbose(VERB_OPS, "sendmsg failed: %s", strerror(errno));
- log_addr(VERB_OPS, "remote address is",
- (struct sockaddr_storage*)addr, addrlen);
-#ifdef __NetBSD__
- /* netbsd 7 has IP_PKTINFO for recv but not send */
- if(errno == EINVAL && r->srctype == 4)
- log_err("sendmsg: No support for sendmsg(IP_PKTINFO). "
- "Please disable interface-automatic");
-#endif
- return 0;
- } else if((size_t)sent != sldns_buffer_remaining(packet)) {
- log_err("sent %d in place of %d bytes",
- (int)sent, (int)sldns_buffer_remaining(packet));
- return 0;
- }
- return 1;
-#else
- (void)c;
- (void)packet;
- (void)addr;
- (void)addrlen;
- (void)r;
- log_err("sendmsg: IPV6_PKTINFO not supported");
- return 0;
-#endif /* AF_INET6 && IPV6_PKTINFO && HAVE_SENDMSG */
-}
-
-void
-comm_point_udp_ancil_callback(int fd, short event, void* arg)
-{
-#if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG)
- struct comm_reply rep;
- struct msghdr msg;
- struct iovec iov[1];
- ssize_t rcv;
- char ancil[256];
- int i;
-#ifndef S_SPLINT_S
- struct cmsghdr* cmsg;
-#endif /* S_SPLINT_S */
-
- rep.c = (struct comm_point*)arg;
- log_assert(rep.c->type == comm_udp);
-
- if(!(event&UB_EV_READ))
- return;
- log_assert(rep.c && rep.c->buffer && rep.c->fd == fd);
- ub_comm_base_now(rep.c->ev->base);
- for(i=0; i<NUM_UDP_PER_SELECT; i++) {
- sldns_buffer_clear(rep.c->buffer);
- rep.addrlen = (socklen_t)sizeof(rep.addr);
- log_assert(fd != -1);
- log_assert(sldns_buffer_remaining(rep.c->buffer) > 0);
- msg.msg_name = &rep.addr;
- msg.msg_namelen = (socklen_t)sizeof(rep.addr);
- iov[0].iov_base = sldns_buffer_begin(rep.c->buffer);
- iov[0].iov_len = sldns_buffer_remaining(rep.c->buffer);
- msg.msg_iov = iov;
- msg.msg_iovlen = 1;
- msg.msg_control = ancil;
-#ifndef S_SPLINT_S
- msg.msg_controllen = sizeof(ancil);
-#endif /* S_SPLINT_S */
- msg.msg_flags = 0;
- rcv = recvmsg(fd, &msg, 0);
- if(rcv == -1) {
- if(errno != EAGAIN && errno != EINTR) {
- log_err("recvmsg failed: %s", strerror(errno));
- }
- return;
- }
- rep.addrlen = msg.msg_namelen;
- sldns_buffer_skip(rep.c->buffer, rcv);
- sldns_buffer_flip(rep.c->buffer);
- rep.srctype = 0;
-#ifndef S_SPLINT_S
- for(cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
- cmsg = CMSG_NXTHDR(&msg, cmsg)) {
- if( cmsg->cmsg_level == IPPROTO_IPV6 &&
- cmsg->cmsg_type == IPV6_PKTINFO) {
- rep.srctype = 6;
- memmove(&rep.pktinfo.v6info, CMSG_DATA(cmsg),
- sizeof(struct in6_pktinfo));
- break;
-#ifdef IP_PKTINFO
- } else if( cmsg->cmsg_level == IPPROTO_IP &&
- cmsg->cmsg_type == IP_PKTINFO) {
- rep.srctype = 4;
- memmove(&rep.pktinfo.v4info, CMSG_DATA(cmsg),
- sizeof(struct in_pktinfo));
- break;
-#elif defined(IP_RECVDSTADDR)
- } else if( cmsg->cmsg_level == IPPROTO_IP &&
- cmsg->cmsg_type == IP_RECVDSTADDR) {
- rep.srctype = 4;
- memmove(&rep.pktinfo.v4addr, CMSG_DATA(cmsg),
- sizeof(struct in_addr));
- break;
-#endif /* IP_PKTINFO or IP_RECVDSTADDR */
- }
- }
- if(verbosity >= VERB_ALGO)
- p_ancil("receive_udp on interface", &rep);
-#endif /* S_SPLINT_S */
- fptr_ok(fptr_whitelist_comm_point(rep.c->callback));
- if((*rep.c->callback)(rep.c, rep.c->cb_arg, NETEVENT_NOERROR, &rep)) {
- /* send back immediate reply */
- (void)comm_point_send_udp_msg_if(rep.c, rep.c->buffer,
- (struct sockaddr*)&rep.addr, rep.addrlen, &rep);
- }
- if(rep.c->fd == -1) /* commpoint closed */
- break;
- }
-#else
- (void)fd;
- (void)event;
- (void)arg;
- fatal_exit("recvmsg: No support for IPV6_PKTINFO; IP_PKTINFO or IP_RECVDSTADDR. "
- "Please disable interface-automatic");
-#endif /* AF_INET6 && IPV6_PKTINFO && HAVE_RECVMSG */
-}
-
-void
-comm_point_udp_callback(int fd, short event, void* arg)
-{
- struct comm_reply rep;
- ssize_t rcv;
- int i;
- struct sldns_buffer *buffer;
-
- rep.c = (struct comm_point*)arg;
- log_assert(rep.c->type == comm_udp);
-
- if(!(event&UB_EV_READ))
- return;
- log_assert(rep.c && rep.c->buffer && rep.c->fd == fd);
- ub_comm_base_now(rep.c->ev->base);
- for(i=0; i<NUM_UDP_PER_SELECT; i++) {
- sldns_buffer_clear(rep.c->buffer);
- rep.addrlen = (socklen_t)sizeof(rep.addr);
- log_assert(fd != -1);
- log_assert(sldns_buffer_remaining(rep.c->buffer) > 0);
- rcv = recvfrom(fd, (void*)sldns_buffer_begin(rep.c->buffer),
- sldns_buffer_remaining(rep.c->buffer), 0,
- (struct sockaddr*)&rep.addr, &rep.addrlen);
- if(rcv == -1) {
-#ifndef USE_WINSOCK
- if(errno != EAGAIN && errno != EINTR)
- log_err("recvfrom %d failed: %s",
- fd, strerror(errno));
-#else
- if(WSAGetLastError() != WSAEINPROGRESS &&
- WSAGetLastError() != WSAECONNRESET &&
- WSAGetLastError()!= WSAEWOULDBLOCK)
- log_err("recvfrom failed: %s",
- wsa_strerror(WSAGetLastError()));
-#endif
- return;
- }
- sldns_buffer_skip(rep.c->buffer, rcv);
- sldns_buffer_flip(rep.c->buffer);
- rep.srctype = 0;
- fptr_ok(fptr_whitelist_comm_point(rep.c->callback));
- if((*rep.c->callback)(rep.c, rep.c->cb_arg, NETEVENT_NOERROR, &rep)) {
- /* send back immediate reply */
-#ifdef USE_DNSCRYPT
- buffer = rep.c->dnscrypt_buffer;
-#else
- buffer = rep.c->buffer;
-#endif
- (void)comm_point_send_udp_msg(rep.c, buffer,
- (struct sockaddr*)&rep.addr, rep.addrlen);
- }
- if(rep.c->fd != fd) /* commpoint closed to -1 or reused for
- another UDP port. Note rep.c cannot be reused with TCP fd. */
- break;
- }
-}
-
-/** Use a new tcp handler for new query fd, set to read query */
-static void
-setup_tcp_handler(struct comm_point* c, int fd, int cur, int max)
-{
- log_assert(c->type == comm_tcp);
- log_assert(c->fd == -1);
- sldns_buffer_clear(c->buffer);
-#ifdef USE_DNSCRYPT
- if (c->dnscrypt)
- sldns_buffer_clear(c->dnscrypt_buffer);
-#endif
- c->tcp_is_reading = 1;
- c->tcp_byte_count = 0;
- c->tcp_timeout_msec = TCP_QUERY_TIMEOUT;
- /* if more than half the tcp handlers are in use, use a shorter
- * timeout for this TCP connection, we need to make space for
- * other connections to be able to get attention */
- if(cur > max/2)
- c->tcp_timeout_msec = TCP_QUERY_TIMEOUT_FAST;
- comm_point_start_listening(c, fd, c->tcp_timeout_msec);
-}
-
-void comm_base_handle_slow_accept(int ATTR_UNUSED(fd),
- short ATTR_UNUSED(event), void* arg)
-{
- struct comm_base* b = (struct comm_base*)arg;
- /* timeout for the slow accept, re-enable accepts again */
- if(b->start_accept) {
- verbose(VERB_ALGO, "wait is over, slow accept disabled");
- fptr_ok(fptr_whitelist_start_accept(b->start_accept));
- (*b->start_accept)(b->cb_arg);
- b->eb->slow_accept_enabled = 0;
- }
-}
-
-int comm_point_perform_accept(struct comm_point* c,
- struct sockaddr_storage* addr, socklen_t* addrlen)
-{
- int new_fd;
- *addrlen = (socklen_t)sizeof(*addr);
- new_fd = accept(c->fd, (struct sockaddr*)addr, addrlen);
- if(new_fd == -1) {
-#ifndef USE_WINSOCK
- /* EINTR is signal interrupt. others are closed connection. */
- if( errno == EINTR || errno == EAGAIN
-#ifdef EWOULDBLOCK
- || errno == EWOULDBLOCK
-#endif
-#ifdef ECONNABORTED
- || errno == ECONNABORTED
-#endif
-#ifdef EPROTO
- || errno == EPROTO
-#endif /* EPROTO */
- )
- return -1;
-#if defined(ENFILE) && defined(EMFILE)
- if(errno == ENFILE || errno == EMFILE) {
- /* out of file descriptors, likely outside of our
- * control. stop accept() calls for some time */
- if(c->ev->base->stop_accept) {
- struct comm_base* b = c->ev->base;
- struct timeval tv;
- verbose(VERB_ALGO, "out of file descriptors: "
- "slow accept");
- b->eb->slow_accept_enabled = 1;
- fptr_ok(fptr_whitelist_stop_accept(
- b->stop_accept));
- (*b->stop_accept)(b->cb_arg);
- /* set timeout, no mallocs */
- tv.tv_sec = NETEVENT_SLOW_ACCEPT_TIME/1000;
- tv.tv_usec = (NETEVENT_SLOW_ACCEPT_TIME%1000)*1000;
- b->eb->slow_accept = ub_event_new(b->eb->base,
- -1, UB_EV_TIMEOUT,
- comm_base_handle_slow_accept, b);
- if(b->eb->slow_accept == NULL) {
- /* we do not want to log here, because
- * that would spam the logfiles.
- * error: "event_base_set failed." */
- }
- else if(ub_event_add(b->eb->slow_accept, &tv)
- != 0) {
- /* we do not want to log here,
- * error: "event_add failed." */
- }
- }
- return -1;
- }
-#endif
- log_err_addr("accept failed", strerror(errno), addr, *addrlen);
-#else /* USE_WINSOCK */
- if(WSAGetLastError() == WSAEINPROGRESS ||
- WSAGetLastError() == WSAECONNRESET)
- return -1;
- if(WSAGetLastError() == WSAEWOULDBLOCK) {
- ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
- return -1;
- }
- log_err_addr("accept failed", wsa_strerror(WSAGetLastError()),
- addr, *addrlen);
-#endif
- return -1;
- }
- fd_set_nonblock(new_fd);
- return new_fd;
-}
-
-#ifdef USE_WINSOCK
-static long win_bio_cb(BIO *b, int oper, const char* ATTR_UNUSED(argp),
- int ATTR_UNUSED(argi), long argl, long retvalue)
-{
- verbose(VERB_ALGO, "bio_cb %d, %s %s %s", oper,
- (oper&BIO_CB_RETURN)?"return":"before",
- (oper&BIO_CB_READ)?"read":((oper&BIO_CB_WRITE)?"write":"other"),
- WSAGetLastError()==WSAEWOULDBLOCK?"wsawb":"");
- /* on windows, check if previous operation caused EWOULDBLOCK */
- if( (oper == (BIO_CB_READ|BIO_CB_RETURN) && argl == 0) ||
- (oper == (BIO_CB_GETS|BIO_CB_RETURN) && argl == 0)) {
- if(WSAGetLastError() == WSAEWOULDBLOCK)
- ub_winsock_tcp_wouldblock((struct ub_event*)
- BIO_get_callback_arg(b), UB_EV_READ);
- }
- if( (oper == (BIO_CB_WRITE|BIO_CB_RETURN) && argl == 0) ||
- (oper == (BIO_CB_PUTS|BIO_CB_RETURN) && argl == 0)) {
- if(WSAGetLastError() == WSAEWOULDBLOCK)
- ub_winsock_tcp_wouldblock((struct ub_event*)
- BIO_get_callback_arg(b), UB_EV_WRITE);
- }
- /* return original return value */
- return retvalue;
-}
-
-/** set win bio callbacks for nonblocking operations */
-void
-comm_point_tcp_win_bio_cb(struct comm_point* c, void* thessl)
-{
- SSL* ssl = (SSL*)thessl;
- /* set them both just in case, but usually they are the same BIO */
- BIO_set_callback(SSL_get_rbio(ssl), &win_bio_cb);
- BIO_set_callback_arg(SSL_get_rbio(ssl), (char*)c->ev->ev);
- BIO_set_callback(SSL_get_wbio(ssl), &win_bio_cb);
- BIO_set_callback_arg(SSL_get_wbio(ssl), (char*)c->ev->ev);
-}
-#endif
-
-void
-comm_point_tcp_accept_callback(int fd, short event, void* arg)
-{
- struct comm_point* c = (struct comm_point*)arg, *c_hdl;
- int new_fd;
- log_assert(c->type == comm_tcp_accept);
- if(!(event & UB_EV_READ)) {
- log_info("ignoring tcp accept event %d", (int)event);
- return;
- }
- ub_comm_base_now(c->ev->base);
- /* find free tcp handler. */
- if(!c->tcp_free) {
- log_warn("accepted too many tcp, connections full");
- return;
- }
- /* accept incoming connection. */
- c_hdl = c->tcp_free;
- log_assert(fd != -1);
- (void)fd;
- new_fd = comm_point_perform_accept(c, &c_hdl->repinfo.addr,
- &c_hdl->repinfo.addrlen);
- if(new_fd == -1)
- return;
- if(c->ssl) {
- c_hdl->ssl = incoming_ssl_fd(c->ssl, new_fd);
- if(!c_hdl->ssl) {
- c_hdl->fd = new_fd;
- comm_point_close(c_hdl);
- return;
- }
- c_hdl->ssl_shake_state = comm_ssl_shake_read;
-#ifdef USE_WINSOCK
- comm_point_tcp_win_bio_cb(c_hdl, c_hdl->ssl);
-#endif
- }
-
- /* grab the tcp handler buffers */
- c->cur_tcp_count++;
- c->tcp_free = c_hdl->tcp_free;
- if(!c->tcp_free) {
- /* stop accepting incoming queries for now. */
- comm_point_stop_listening(c);
- }
- setup_tcp_handler(c_hdl, new_fd, c->cur_tcp_count, c->max_tcp_count);
-}
-
-/** Make tcp handler free for next assignment */
-static void
-reclaim_tcp_handler(struct comm_point* c)
-{
- log_assert(c->type == comm_tcp);
- if(c->ssl) {
-#ifdef HAVE_SSL
- SSL_shutdown(c->ssl);
- SSL_free(c->ssl);
- c->ssl = NULL;
-#endif
- }
- comm_point_close(c);
- if(c->tcp_parent) {
- c->tcp_parent->cur_tcp_count--;
- c->tcp_free = c->tcp_parent->tcp_free;
- c->tcp_parent->tcp_free = c;
- if(!c->tcp_free) {
- /* re-enable listening on accept socket */
- comm_point_start_listening(c->tcp_parent, -1, -1);
- }
- }
-}
-
-/** do the callback when writing is done */
-static void
-tcp_callback_writer(struct comm_point* c)
-{
- log_assert(c->type == comm_tcp);
- sldns_buffer_clear(c->buffer);
- if(c->tcp_do_toggle_rw)
- c->tcp_is_reading = 1;
- c->tcp_byte_count = 0;
- /* switch from listening(write) to listening(read) */
- comm_point_stop_listening(c);
- comm_point_start_listening(c, -1, -1);
-}
-
-/** do the callback when reading is done */
-static void
-tcp_callback_reader(struct comm_point* c)
-{
- log_assert(c->type == comm_tcp || c->type == comm_local);
- sldns_buffer_flip(c->buffer);
- if(c->tcp_do_toggle_rw)
- c->tcp_is_reading = 0;
- c->tcp_byte_count = 0;
- if(c->type == comm_tcp)
- comm_point_stop_listening(c);
- fptr_ok(fptr_whitelist_comm_point(c->callback));
- if( (*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, &c->repinfo) ) {
- comm_point_start_listening(c, -1, c->tcp_timeout_msec);
- }
-}
-
-/** continue ssl handshake */
-#ifdef HAVE_SSL
-static int
-ssl_handshake(struct comm_point* c)
-{
- int r;
- if(c->ssl_shake_state == comm_ssl_shake_hs_read) {
- /* read condition satisfied back to writing */
- comm_point_listen_for_rw(c, 1, 1);
- c->ssl_shake_state = comm_ssl_shake_none;
- return 1;
- }
- if(c->ssl_shake_state == comm_ssl_shake_hs_write) {
- /* write condition satisfied, back to reading */
- comm_point_listen_for_rw(c, 1, 0);
- c->ssl_shake_state = comm_ssl_shake_none;
- return 1;
- }
-
- ERR_clear_error();
- r = SSL_do_handshake(c->ssl);
- if(r != 1) {
- int want = SSL_get_error(c->ssl, r);
- if(want == SSL_ERROR_WANT_READ) {
- if(c->ssl_shake_state == comm_ssl_shake_read)
- return 1;
- c->ssl_shake_state = comm_ssl_shake_read;
- comm_point_listen_for_rw(c, 1, 0);
- return 1;
- } else if(want == SSL_ERROR_WANT_WRITE) {
- if(c->ssl_shake_state == comm_ssl_shake_write)
- return 1;
- c->ssl_shake_state = comm_ssl_shake_write;
- comm_point_listen_for_rw(c, 0, 1);
- return 1;
- } else if(r == 0) {
- return 0; /* closed */
- } else if(want == SSL_ERROR_SYSCALL) {
- /* SYSCALL and errno==0 means closed uncleanly */
- if(errno != 0)
- log_err("SSL_handshake syscall: %s",
- strerror(errno));
- return 0;
- } else {
- log_crypto_err("ssl handshake failed");
- log_addr(1, "ssl handshake failed", &c->repinfo.addr,
- c->repinfo.addrlen);
- return 0;
- }
- }
- /* this is where peer verification could take place */
- log_addr(VERB_ALGO, "SSL DNS connection", &c->repinfo.addr,
- c->repinfo.addrlen);
-
- /* setup listen rw correctly */
- if(c->tcp_is_reading) {
- if(c->ssl_shake_state != comm_ssl_shake_read)
- comm_point_listen_for_rw(c, 1, 0);
- } else {
- comm_point_listen_for_rw(c, 1, 1);
- }
- c->ssl_shake_state = comm_ssl_shake_none;
- return 1;
-}
-#endif /* HAVE_SSL */
-
-/** ssl read callback on TCP */
-static int
-ssl_handle_read(struct comm_point* c)
-{
-#ifdef HAVE_SSL
- int r;
- if(c->ssl_shake_state != comm_ssl_shake_none) {
- if(!ssl_handshake(c))
- return 0;
- if(c->ssl_shake_state != comm_ssl_shake_none)
- return 1;
- }
- if(c->tcp_byte_count < sizeof(uint16_t)) {
- /* read length bytes */
- ERR_clear_error();
- if((r=SSL_read(c->ssl, (void*)sldns_buffer_at(c->buffer,
- c->tcp_byte_count), (int)(sizeof(uint16_t) -
- c->tcp_byte_count))) <= 0) {
- int want = SSL_get_error(c->ssl, r);
- if(want == SSL_ERROR_ZERO_RETURN) {
- return 0; /* shutdown, closed */
- } else if(want == SSL_ERROR_WANT_READ) {
- return 1; /* read more later */
- } else if(want == SSL_ERROR_WANT_WRITE) {
- c->ssl_shake_state = comm_ssl_shake_hs_write;
- comm_point_listen_for_rw(c, 0, 1);
- return 1;
- } else if(want == SSL_ERROR_SYSCALL) {
- if(errno != 0)
- log_err("SSL_read syscall: %s",
- strerror(errno));
- return 0;
- }
- log_crypto_err("could not SSL_read");
- return 0;
- }
- c->tcp_byte_count += r;
- if(c->tcp_byte_count != sizeof(uint16_t))
- return 1;
- if(sldns_buffer_read_u16_at(c->buffer, 0) >
- sldns_buffer_capacity(c->buffer)) {
- verbose(VERB_QUERY, "ssl: dropped larger than buffer");
- return 0;
- }
- sldns_buffer_set_limit(c->buffer,
- sldns_buffer_read_u16_at(c->buffer, 0));
- if(sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE) {
- verbose(VERB_QUERY, "ssl: dropped bogus too short.");
- return 0;
- }
- verbose(VERB_ALGO, "Reading ssl tcp query of length %d",
- (int)sldns_buffer_limit(c->buffer));
- }
- log_assert(sldns_buffer_remaining(c->buffer) > 0);
- ERR_clear_error();
- r = SSL_read(c->ssl, (void*)sldns_buffer_current(c->buffer),
- (int)sldns_buffer_remaining(c->buffer));
- if(r <= 0) {
- int want = SSL_get_error(c->ssl, r);
- if(want == SSL_ERROR_ZERO_RETURN) {
- return 0; /* shutdown, closed */
- } else if(want == SSL_ERROR_WANT_READ) {
- return 1; /* read more later */
- } else if(want == SSL_ERROR_WANT_WRITE) {
- c->ssl_shake_state = comm_ssl_shake_hs_write;
- comm_point_listen_for_rw(c, 0, 1);
- return 1;
- } else if(want == SSL_ERROR_SYSCALL) {
- if(errno != 0)
- log_err("SSL_read syscall: %s",
- strerror(errno));
- return 0;
- }
- log_crypto_err("could not SSL_read");
- return 0;
- }
- sldns_buffer_skip(c->buffer, (ssize_t)r);
- if(sldns_buffer_remaining(c->buffer) <= 0) {
- tcp_callback_reader(c);
- }
- return 1;
-#else
- (void)c;
- return 0;
-#endif /* HAVE_SSL */
-}
-
-/** ssl write callback on TCP */
-static int
-ssl_handle_write(struct comm_point* c)
-{
-#ifdef HAVE_SSL
- int r;
- if(c->ssl_shake_state != comm_ssl_shake_none) {
- if(!ssl_handshake(c))
- return 0;
- if(c->ssl_shake_state != comm_ssl_shake_none)
- return 1;
- }
- /* ignore return, if fails we may simply block */
- (void)SSL_set_mode(c->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
- if(c->tcp_byte_count < sizeof(uint16_t)) {
- uint16_t len = htons(sldns_buffer_limit(c->buffer));
- ERR_clear_error();
- r = SSL_write(c->ssl,
- (void*)(((uint8_t*)&len)+c->tcp_byte_count),
- (int)(sizeof(uint16_t)-c->tcp_byte_count));
- if(r <= 0) {
- int want = SSL_get_error(c->ssl, r);
- if(want == SSL_ERROR_ZERO_RETURN) {
- return 0; /* closed */
- } else if(want == SSL_ERROR_WANT_READ) {
- c->ssl_shake_state = comm_ssl_shake_read;
- comm_point_listen_for_rw(c, 1, 0);
- return 1; /* wait for read condition */
- } else if(want == SSL_ERROR_WANT_WRITE) {
- return 1; /* write more later */
- } else if(want == SSL_ERROR_SYSCALL) {
- if(errno != 0)
- log_err("SSL_write syscall: %s",
- strerror(errno));
- return 0;
- }
- log_crypto_err("could not SSL_write");
- return 0;
- }
- c->tcp_byte_count += r;
- if(c->tcp_byte_count < sizeof(uint16_t))
- return 1;
- sldns_buffer_set_position(c->buffer, c->tcp_byte_count -
- sizeof(uint16_t));
- if(sldns_buffer_remaining(c->buffer) == 0) {
- tcp_callback_writer(c);
- return 1;
- }
- }
- log_assert(sldns_buffer_remaining(c->buffer) > 0);
- ERR_clear_error();
- r = SSL_write(c->ssl, (void*)sldns_buffer_current(c->buffer),
- (int)sldns_buffer_remaining(c->buffer));
- if(r <= 0) {
- int want = SSL_get_error(c->ssl, r);
- if(want == SSL_ERROR_ZERO_RETURN) {
- return 0; /* closed */
- } else if(want == SSL_ERROR_WANT_READ) {
- c->ssl_shake_state = comm_ssl_shake_read;
- comm_point_listen_for_rw(c, 1, 0);
- return 1; /* wait for read condition */
- } else if(want == SSL_ERROR_WANT_WRITE) {
- return 1; /* write more later */
- } else if(want == SSL_ERROR_SYSCALL) {
- if(errno != 0)
- log_err("SSL_write syscall: %s",
- strerror(errno));
- return 0;
- }
- log_crypto_err("could not SSL_write");
- return 0;
- }
- sldns_buffer_skip(c->buffer, (ssize_t)r);
-
- if(sldns_buffer_remaining(c->buffer) == 0) {
- tcp_callback_writer(c);
- }
- return 1;
-#else
- (void)c;
- return 0;
-#endif /* HAVE_SSL */
-}
-
-/** handle ssl tcp connection with dns contents */
-static int
-ssl_handle_it(struct comm_point* c)
-{
- if(c->tcp_is_reading)
- return ssl_handle_read(c);
- return ssl_handle_write(c);
-}
-
-/** Handle tcp reading callback.
- * @param fd: file descriptor of socket.
- * @param c: comm point to read from into buffer.
- * @param short_ok: if true, very short packets are OK (for comm_local).
- * @return: 0 on error
- */
-static int
-comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok)
-{
- ssize_t r;
- log_assert(c->type == comm_tcp || c->type == comm_local);
- if(c->ssl)
- return ssl_handle_it(c);
- if(!c->tcp_is_reading)
- return 0;
-
- log_assert(fd != -1);
- if(c->tcp_byte_count < sizeof(uint16_t)) {
- /* read length bytes */
- r = recv(fd,(void*)sldns_buffer_at(c->buffer,c->tcp_byte_count),
- sizeof(uint16_t)-c->tcp_byte_count, 0);
- if(r == 0)
- return 0;
- else if(r == -1) {
-#ifndef USE_WINSOCK
- if(errno == EINTR || errno == EAGAIN)
- return 1;
-#ifdef ECONNRESET
- if(errno == ECONNRESET && verbosity < 2)
- return 0; /* silence reset by peer */
-#endif
- log_err_addr("read (in tcp s)", strerror(errno),
- &c->repinfo.addr, c->repinfo.addrlen);
-#else /* USE_WINSOCK */
- if(WSAGetLastError() == WSAECONNRESET)
- return 0;
- if(WSAGetLastError() == WSAEINPROGRESS)
- return 1;
- if(WSAGetLastError() == WSAEWOULDBLOCK) {
- ub_winsock_tcp_wouldblock(c->ev->ev,
- UB_EV_READ);
- return 1;
- }
- log_err_addr("read (in tcp s)",
- wsa_strerror(WSAGetLastError()),
- &c->repinfo.addr, c->repinfo.addrlen);
-#endif
- return 0;
- }
- c->tcp_byte_count += r;
- if(c->tcp_byte_count != sizeof(uint16_t))
- return 1;
- if(sldns_buffer_read_u16_at(c->buffer, 0) >
- sldns_buffer_capacity(c->buffer)) {
- verbose(VERB_QUERY, "tcp: dropped larger than buffer");
- return 0;
- }
- sldns_buffer_set_limit(c->buffer,
- sldns_buffer_read_u16_at(c->buffer, 0));
- if(!short_ok &&
- sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE) {
- verbose(VERB_QUERY, "tcp: dropped bogus too short.");
- return 0;
- }
- verbose(VERB_ALGO, "Reading tcp query of length %d",
- (int)sldns_buffer_limit(c->buffer));
- }
-
- log_assert(sldns_buffer_remaining(c->buffer) > 0);
- r = recv(fd, (void*)sldns_buffer_current(c->buffer),
- sldns_buffer_remaining(c->buffer), 0);
- if(r == 0) {
- return 0;
- } else if(r == -1) {
-#ifndef USE_WINSOCK
- if(errno == EINTR || errno == EAGAIN)
- return 1;
- log_err_addr("read (in tcp r)", strerror(errno),
- &c->repinfo.addr, c->repinfo.addrlen);
-#else /* USE_WINSOCK */
- if(WSAGetLastError() == WSAECONNRESET)
- return 0;
- if(WSAGetLastError() == WSAEINPROGRESS)
- return 1;
- if(WSAGetLastError() == WSAEWOULDBLOCK) {
- ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
- return 1;
- }
- log_err_addr("read (in tcp r)",
- wsa_strerror(WSAGetLastError()),
- &c->repinfo.addr, c->repinfo.addrlen);
-#endif
- return 0;
- }
- sldns_buffer_skip(c->buffer, r);
- if(sldns_buffer_remaining(c->buffer) <= 0) {
- tcp_callback_reader(c);
- }
- return 1;
-}
-
-/**
- * Handle tcp writing callback.
- * @param fd: file descriptor of socket.
- * @param c: comm point to write buffer out of.
- * @return: 0 on error
- */
-static int
-comm_point_tcp_handle_write(int fd, struct comm_point* c)
-{
- ssize_t r;
- struct sldns_buffer *buffer;
- log_assert(c->type == comm_tcp);
-#ifdef USE_DNSCRYPT
- buffer = c->dnscrypt_buffer;
-#else
- buffer = c->buffer;
-#endif
- if(c->tcp_is_reading && !c->ssl)
- return 0;
- log_assert(fd != -1);
- if(c->tcp_byte_count == 0 && c->tcp_check_nb_connect) {
- /* check for pending error from nonblocking connect */
- /* from Stevens, unix network programming, vol1, 3rd ed, p450*/
- int error = 0;
- socklen_t len = (socklen_t)sizeof(error);
- if(getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&error,
- &len) < 0){
-#ifndef USE_WINSOCK
- error = errno; /* on solaris errno is error */
-#else /* USE_WINSOCK */
- error = WSAGetLastError();
-#endif
- }
-#ifndef USE_WINSOCK
-#if defined(EINPROGRESS) && defined(EWOULDBLOCK)
- if(error == EINPROGRESS || error == EWOULDBLOCK)
- return 1; /* try again later */
- else
-#endif
- if(error != 0 && verbosity < 2)
- return 0; /* silence lots of chatter in the logs */
- else if(error != 0) {
- log_err_addr("tcp connect", strerror(error),
- &c->repinfo.addr, c->repinfo.addrlen);
-#else /* USE_WINSOCK */
- /* examine error */
- if(error == WSAEINPROGRESS)
- return 1;
- else if(error == WSAEWOULDBLOCK) {
- ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
- return 1;
- } else if(error != 0 && verbosity < 2)
- return 0;
- else if(error != 0) {
- log_err_addr("tcp connect", wsa_strerror(error),
- &c->repinfo.addr, c->repinfo.addrlen);
-#endif /* USE_WINSOCK */
- return 0;
- }
- }
- if(c->ssl)
- return ssl_handle_it(c);
-
-#ifdef USE_MSG_FASTOPEN
- /* Only try this on first use of a connection that uses tfo,
- otherwise fall through to normal write */
- /* Also, TFO support on WINDOWS not implemented at the moment */
- if(c->tcp_do_fastopen == 1) {
- /* this form of sendmsg() does both a connect() and send() so need to
- look for various flavours of error*/
- uint16_t len = htons(sldns_buffer_limit(buffer));
- struct msghdr msg;
- struct iovec iov[2];
- c->tcp_do_fastopen = 0;
- memset(&msg, 0, sizeof(msg));
- iov[0].iov_base = (uint8_t*)&len + c->tcp_byte_count;
- iov[0].iov_len = sizeof(uint16_t) - c->tcp_byte_count;
- iov[1].iov_base = sldns_buffer_begin(buffer);
- iov[1].iov_len = sldns_buffer_limit(buffer);
- log_assert(iov[0].iov_len > 0);
- log_assert(iov[1].iov_len > 0);
- msg.msg_name = &c->repinfo.addr;
- msg.msg_namelen = c->repinfo.addrlen;
- msg.msg_iov = iov;
- msg.msg_iovlen = 2;
- r = sendmsg(fd, &msg, MSG_FASTOPEN);
- if (r == -1) {
-#if defined(EINPROGRESS) && defined(EWOULDBLOCK)
- /* Handshake is underway, maybe because no TFO cookie available.
- Come back to write the messsage*/
- if(errno == EINPROGRESS || errno == EWOULDBLOCK)
- return 1;
-#endif
- if(errno == EINTR || errno == EAGAIN)
- return 1;
- /* Not handling EISCONN here as shouldn't ever hit that case.*/
- if(errno != 0 && verbosity < 2)
- return 0; /* silence lots of chatter in the logs */
- else if(errno != 0)
- log_err_addr("tcp sendmsg", strerror(errno),
- &c->repinfo.addr, c->repinfo.addrlen);
- return 0;
- } else {
- c->tcp_byte_count += r;
- if(c->tcp_byte_count < sizeof(uint16_t))
- return 1;
- sldns_buffer_set_position(buffer, c->tcp_byte_count -
- sizeof(uint16_t));
- if(sldns_buffer_remaining(buffer) == 0) {
- tcp_callback_writer(c);
- return 1;
- }
- }
- }
-#endif /* USE_MSG_FASTOPEN */
-
- if(c->tcp_byte_count < sizeof(uint16_t)) {
- uint16_t len = htons(sldns_buffer_limit(buffer));
-#ifdef HAVE_WRITEV
- struct iovec iov[2];
- iov[0].iov_base = (uint8_t*)&len + c->tcp_byte_count;
- iov[0].iov_len = sizeof(uint16_t) - c->tcp_byte_count;
- iov[1].iov_base = sldns_buffer_begin(buffer);
- iov[1].iov_len = sldns_buffer_limit(buffer);
- log_assert(iov[0].iov_len > 0);
- log_assert(iov[1].iov_len > 0);
- r = writev(fd, iov, 2);
-#else /* HAVE_WRITEV */
- r = send(fd, (void*)(((uint8_t*)&len)+c->tcp_byte_count),
- sizeof(uint16_t)-c->tcp_byte_count, 0);
-#endif /* HAVE_WRITEV */
- if(r == -1) {
-#ifndef USE_WINSOCK
-# ifdef EPIPE
- if(errno == EPIPE && verbosity < 2)
- return 0; /* silence 'broken pipe' */
- #endif
- if(errno == EINTR || errno == EAGAIN)
- return 1;
-# ifdef HAVE_WRITEV
- log_err_addr("tcp writev", strerror(errno),
- &c->repinfo.addr, c->repinfo.addrlen);
-# else /* HAVE_WRITEV */
- log_err_addr("tcp send s", strerror(errno),
- &c->repinfo.addr, c->repinfo.addrlen);
-# endif /* HAVE_WRITEV */
-#else
- if(WSAGetLastError() == WSAENOTCONN)
- return 1;
- if(WSAGetLastError() == WSAEINPROGRESS)
- return 1;
- if(WSAGetLastError() == WSAEWOULDBLOCK) {
- ub_winsock_tcp_wouldblock(c->ev->ev,
- UB_EV_WRITE);
- return 1;
- }
- log_err_addr("tcp send s",
- wsa_strerror(WSAGetLastError()),
- &c->repinfo.addr, c->repinfo.addrlen);
-#endif
- return 0;
- }
- c->tcp_byte_count += r;
- if(c->tcp_byte_count < sizeof(uint16_t))
- return 1;
- sldns_buffer_set_position(buffer, c->tcp_byte_count -
- sizeof(uint16_t));
- if(sldns_buffer_remaining(buffer) == 0) {
- tcp_callback_writer(c);
- return 1;
- }
- }
- log_assert(sldns_buffer_remaining(buffer) > 0);
- r = send(fd, (void*)sldns_buffer_current(buffer),
- sldns_buffer_remaining(buffer), 0);
- if(r == -1) {
-#ifndef USE_WINSOCK
- if(errno == EINTR || errno == EAGAIN)
- return 1;
- log_err_addr("tcp send r", strerror(errno),
- &c->repinfo.addr, c->repinfo.addrlen);
-#else
- if(WSAGetLastError() == WSAEINPROGRESS)
- return 1;
- if(WSAGetLastError() == WSAEWOULDBLOCK) {
- ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
- return 1;
- }
- log_err_addr("tcp send r", wsa_strerror(WSAGetLastError()),
- &c->repinfo.addr, c->repinfo.addrlen);
-#endif
- return 0;
- }
- sldns_buffer_skip(buffer, r);
-
- if(sldns_buffer_remaining(buffer) == 0) {
- tcp_callback_writer(c);
- }
-
- return 1;
-}
-
-void
-comm_point_tcp_handle_callback(int fd, short event, void* arg)
-{
- struct comm_point* c = (struct comm_point*)arg;
- log_assert(c->type == comm_tcp);
- ub_comm_base_now(c->ev->base);
-
-#ifdef USE_DNSCRYPT
- /* Initialize if this is a dnscrypt socket */
- if(c->tcp_parent) {
- c->dnscrypt = c->tcp_parent->dnscrypt;
- }
- if(c->dnscrypt && c->dnscrypt_buffer == c->buffer) {
- c->dnscrypt_buffer = sldns_buffer_new(sldns_buffer_capacity(c->buffer));
- if(!c->dnscrypt_buffer) {
- log_err("Could not allocate dnscrypt buffer");
- return;
- }
- }
-#endif
-
- if(event&UB_EV_READ) {
- if(!comm_point_tcp_handle_read(fd, c, 0)) {
- reclaim_tcp_handler(c);
- if(!c->tcp_do_close) {
- fptr_ok(fptr_whitelist_comm_point(
- c->callback));
- (void)(*c->callback)(c, c->cb_arg,
- NETEVENT_CLOSED, NULL);
- }
- }
- return;
- }
- if(event&UB_EV_WRITE) {
- if(!comm_point_tcp_handle_write(fd, c)) {
- reclaim_tcp_handler(c);
- if(!c->tcp_do_close) {
- fptr_ok(fptr_whitelist_comm_point(
- c->callback));
- (void)(*c->callback)(c, c->cb_arg,
- NETEVENT_CLOSED, NULL);
- }
- }
- return;
- }
- if(event&UB_EV_TIMEOUT) {
- verbose(VERB_QUERY, "tcp took too long, dropped");
- reclaim_tcp_handler(c);
- if(!c->tcp_do_close) {
- fptr_ok(fptr_whitelist_comm_point(c->callback));
- (void)(*c->callback)(c, c->cb_arg,
- NETEVENT_TIMEOUT, NULL);
- }
- return;
- }
- log_err("Ignored event %d for tcphdl.", event);
-}
-
-void comm_point_local_handle_callback(int fd, short event, void* arg)
-{
- struct comm_point* c = (struct comm_point*)arg;
- log_assert(c->type == comm_local);
- ub_comm_base_now(c->ev->base);
-
- if(event&UB_EV_READ) {
- if(!comm_point_tcp_handle_read(fd, c, 1)) {
- fptr_ok(fptr_whitelist_comm_point(c->callback));
- (void)(*c->callback)(c, c->cb_arg, NETEVENT_CLOSED,
- NULL);
- }
- return;
- }
- log_err("Ignored event %d for localhdl.", event);
-}
-
-void comm_point_raw_handle_callback(int ATTR_UNUSED(fd),
- short event, void* arg)
-{
- struct comm_point* c = (struct comm_point*)arg;
- int err = NETEVENT_NOERROR;
- log_assert(c->type == comm_raw);
- ub_comm_base_now(c->ev->base);
-
- if(event&UB_EV_TIMEOUT)
- err = NETEVENT_TIMEOUT;
- fptr_ok(fptr_whitelist_comm_point_raw(c->callback));
- (void)(*c->callback)(c, c->cb_arg, err, NULL);
-}
-
-struct comm_point*
-comm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer,
- comm_point_callback_type* callback, void* callback_arg)
-{
- struct comm_point* c = (struct comm_point*)calloc(1,
- sizeof(struct comm_point));
- short evbits;
- if(!c)
- return NULL;
- c->ev = (struct internal_event*)calloc(1,
- sizeof(struct internal_event));
- if(!c->ev) {
- free(c);
- return NULL;
- }
- c->ev->base = base;
- c->fd = fd;
- c->buffer = buffer;
- c->timeout = NULL;
- c->tcp_is_reading = 0;
- c->tcp_byte_count = 0;
- c->tcp_parent = NULL;
- c->max_tcp_count = 0;
- c->cur_tcp_count = 0;
- c->tcp_handlers = NULL;
- c->tcp_free = NULL;
- c->type = comm_udp;
- c->tcp_do_close = 0;
- c->do_not_close = 0;
- c->tcp_do_toggle_rw = 0;
- c->tcp_check_nb_connect = 0;
-#ifdef USE_MSG_FASTOPEN
- c->tcp_do_fastopen = 0;
-#endif
-#ifdef USE_DNSCRYPT
- c->dnscrypt = 0;
- c->dnscrypt_buffer = buffer;
-#endif
- c->inuse = 0;
- c->callback = callback;
- c->cb_arg = callback_arg;
- evbits = UB_EV_READ | UB_EV_PERSIST;
- /* ub_event stuff */
- c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
- comm_point_udp_callback, c);
- if(c->ev->ev == NULL) {
- log_err("could not baseset udp event");
- comm_point_delete(c);
- return NULL;
- }
- if(fd!=-1 && ub_event_add(c->ev->ev, c->timeout) != 0 ) {
- log_err("could not add udp event");
- comm_point_delete(c);
- return NULL;
- }
- return c;
-}
-
-struct comm_point*
-comm_point_create_udp_ancil(struct comm_base *base, int fd,
- sldns_buffer* buffer,
- comm_point_callback_type* callback, void* callback_arg)
-{
- struct comm_point* c = (struct comm_point*)calloc(1,
- sizeof(struct comm_point));
- short evbits;
- if(!c)
- return NULL;
- c->ev = (struct internal_event*)calloc(1,
- sizeof(struct internal_event));
- if(!c->ev) {
- free(c);
- return NULL;
- }
- c->ev->base = base;
- c->fd = fd;
- c->buffer = buffer;
- c->timeout = NULL;
- c->tcp_is_reading = 0;
- c->tcp_byte_count = 0;
- c->tcp_parent = NULL;
- c->max_tcp_count = 0;
- c->cur_tcp_count = 0;
- c->tcp_handlers = NULL;
- c->tcp_free = NULL;
- c->type = comm_udp;
- c->tcp_do_close = 0;
- c->do_not_close = 0;
-#ifdef USE_DNSCRYPT
- c->dnscrypt = 0;
- c->dnscrypt_buffer = buffer;
-#endif
- c->inuse = 0;
- c->tcp_do_toggle_rw = 0;
- c->tcp_check_nb_connect = 0;
-#ifdef USE_MSG_FASTOPEN
- c->tcp_do_fastopen = 0;
-#endif
- c->callback = callback;
- c->cb_arg = callback_arg;
- evbits = UB_EV_READ | UB_EV_PERSIST;
- /* ub_event stuff */
- c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
- comm_point_udp_ancil_callback, c);
- if(c->ev->ev == NULL) {
- log_err("could not baseset udp event");
- comm_point_delete(c);
- return NULL;
- }
- if(fd!=-1 && ub_event_add(c->ev->ev, c->timeout) != 0 ) {
- log_err("could not add udp event");
- comm_point_delete(c);
- return NULL;
- }
- return c;
-}
-
-static struct comm_point*
-comm_point_create_tcp_handler(struct comm_base *base,
- struct comm_point* parent, size_t bufsize,
- comm_point_callback_type* callback, void* callback_arg)
-{
- struct comm_point* c = (struct comm_point*)calloc(1,
- sizeof(struct comm_point));
- short evbits;
- if(!c)
- return NULL;
- c->ev = (struct internal_event*)calloc(1,
- sizeof(struct internal_event));
- if(!c->ev) {
- free(c);
- return NULL;
- }
- c->ev->base = base;
- c->fd = -1;
- c->buffer = sldns_buffer_new(bufsize);
- if(!c->buffer) {
- free(c->ev);
- free(c);
- return NULL;
- }
- c->timeout = (struct timeval*)malloc(sizeof(struct timeval));
- if(!c->timeout) {
- sldns_buffer_free(c->buffer);
- free(c->ev);
- free(c);
- return NULL;
- }
- c->tcp_is_reading = 0;
- c->tcp_byte_count = 0;
- c->tcp_parent = parent;
- c->max_tcp_count = 0;
- c->cur_tcp_count = 0;
- c->tcp_handlers = NULL;
- c->tcp_free = NULL;
- c->type = comm_tcp;
- c->tcp_do_close = 0;
- c->do_not_close = 0;
- c->tcp_do_toggle_rw = 1;
- c->tcp_check_nb_connect = 0;
-#ifdef USE_MSG_FASTOPEN
- c->tcp_do_fastopen = 0;
-#endif
-#ifdef USE_DNSCRYPT
- c->dnscrypt = 0;
- // We don't know just yet if this is a dnscrypt channel. Allocation
- // will be done when handling the callback.
- c->dnscrypt_buffer = c->buffer;
-#endif
- c->repinfo.c = c;
- c->callback = callback;
- c->cb_arg = callback_arg;
- /* add to parent free list */
- c->tcp_free = parent->tcp_free;
- parent->tcp_free = c;
- /* ub_event stuff */
- evbits = UB_EV_PERSIST | UB_EV_READ | UB_EV_TIMEOUT;
- c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
- comm_point_tcp_handle_callback, c);
- if(c->ev->ev == NULL)
- {
- log_err("could not basetset tcphdl event");
- parent->tcp_free = c->tcp_free;
- free(c->ev);
- free(c);
- return NULL;
- }
- return c;
-}
-
-struct comm_point*
-comm_point_create_tcp(struct comm_base *base, int fd, int num, size_t bufsize,
- comm_point_callback_type* callback, void* callback_arg)
-{
- struct comm_point* c = (struct comm_point*)calloc(1,
- sizeof(struct comm_point));
- short evbits;
- int i;
- /* first allocate the TCP accept listener */
- if(!c)
- return NULL;
- c->ev = (struct internal_event*)calloc(1,
- sizeof(struct internal_event));
- if(!c->ev) {
- free(c);
- return NULL;
- }
- c->ev->base = base;
- c->fd = fd;
- c->buffer = NULL;
- c->timeout = NULL;
- c->tcp_is_reading = 0;
- c->tcp_byte_count = 0;
- c->tcp_parent = NULL;
- c->max_tcp_count = num;
- c->cur_tcp_count = 0;
- c->tcp_handlers = (struct comm_point**)calloc((size_t)num,
- sizeof(struct comm_point*));
- if(!c->tcp_handlers) {
- free(c->ev);
- free(c);
- return NULL;
- }
- c->tcp_free = NULL;
- c->type = comm_tcp_accept;
- c->tcp_do_close = 0;
- c->do_not_close = 0;
- c->tcp_do_toggle_rw = 0;
- c->tcp_check_nb_connect = 0;
-#ifdef USE_MSG_FASTOPEN
- c->tcp_do_fastopen = 0;
-#endif
-#ifdef USE_DNSCRYPT
- c->dnscrypt = 0;
- c->dnscrypt_buffer = NULL;
-#endif
- c->callback = NULL;
- c->cb_arg = NULL;
- evbits = UB_EV_READ | UB_EV_PERSIST;
- /* ub_event stuff */
- c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
- comm_point_tcp_accept_callback, c);
- if(c->ev->ev == NULL) {
- log_err("could not baseset tcpacc event");
- comm_point_delete(c);
- return NULL;
- }
- if (ub_event_add(c->ev->ev, c->timeout) != 0) {
- log_err("could not add tcpacc event");
- comm_point_delete(c);
- return NULL;
- }
- /* now prealloc the tcp handlers */
- for(i=0; i<num; i++) {
- c->tcp_handlers[i] = comm_point_create_tcp_handler(base,
- c, bufsize, callback, callback_arg);
- if(!c->tcp_handlers[i]) {
- comm_point_delete(c);
- return NULL;
- }
- }
-
- return c;
-}
-
-struct comm_point*
-comm_point_create_tcp_out(struct comm_base *base, size_t bufsize,
- comm_point_callback_type* callback, void* callback_arg)
-{
- struct comm_point* c = (struct comm_point*)calloc(1,
- sizeof(struct comm_point));
- short evbits;
- if(!c)
- return NULL;
- c->ev = (struct internal_event*)calloc(1,
- sizeof(struct internal_event));
- if(!c->ev) {
- free(c);
- return NULL;
- }
- c->ev->base = base;
- c->fd = -1;
- c->buffer = sldns_buffer_new(bufsize);
- if(!c->buffer) {
- free(c->ev);
- free(c);
- return NULL;
- }
- c->timeout = NULL;
- c->tcp_is_reading = 0;
- c->tcp_byte_count = 0;
- c->tcp_parent = NULL;
- c->max_tcp_count = 0;
- c->cur_tcp_count = 0;
- c->tcp_handlers = NULL;
- c->tcp_free = NULL;
- c->type = comm_tcp;
- c->tcp_do_close = 0;
- c->do_not_close = 0;
- c->tcp_do_toggle_rw = 1;
- c->tcp_check_nb_connect = 1;
-#ifdef USE_MSG_FASTOPEN
- c->tcp_do_fastopen = 1;
-#endif
-#ifdef USE_DNSCRYPT
- c->dnscrypt = 0;
- c->dnscrypt_buffer = c->buffer;
-#endif
- c->repinfo.c = c;
- c->callback = callback;
- c->cb_arg = callback_arg;
- evbits = UB_EV_PERSIST | UB_EV_WRITE;
- c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
- comm_point_tcp_handle_callback, c);
- if(c->ev->ev == NULL)
- {
- log_err("could not baseset tcpout event");
- sldns_buffer_free(c->buffer);
- free(c->ev);
- free(c);
- return NULL;
- }
-
- return c;
-}
-
-struct comm_point*
-comm_point_create_local(struct comm_base *base, int fd, size_t bufsize,
- comm_point_callback_type* callback, void* callback_arg)
-{
- struct comm_point* c = (struct comm_point*)calloc(1,
- sizeof(struct comm_point));
- short evbits;
- if(!c)
- return NULL;
- c->ev = (struct internal_event*)calloc(1,
- sizeof(struct internal_event));
- if(!c->ev) {
- free(c);
- return NULL;
- }
- c->ev->base = base;
- c->fd = fd;
- c->buffer = sldns_buffer_new(bufsize);
- if(!c->buffer) {
- free(c->ev);
- free(c);
- return NULL;
- }
- c->timeout = NULL;
- c->tcp_is_reading = 1;
- c->tcp_byte_count = 0;
- c->tcp_parent = NULL;
- c->max_tcp_count = 0;
- c->cur_tcp_count = 0;
- c->tcp_handlers = NULL;
- c->tcp_free = NULL;
- c->type = comm_local;
- c->tcp_do_close = 0;
- c->do_not_close = 1;
- c->tcp_do_toggle_rw = 0;
- c->tcp_check_nb_connect = 0;
-#ifdef USE_MSG_FASTOPEN
- c->tcp_do_fastopen = 0;
-#endif
-#ifdef USE_DNSCRYPT
- c->dnscrypt = 0;
- c->dnscrypt_buffer = c->buffer;
-#endif
- c->callback = callback;
- c->cb_arg = callback_arg;
- /* ub_event stuff */
- evbits = UB_EV_PERSIST | UB_EV_READ;
- c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
- comm_point_local_handle_callback, c);
- if(c->ev->ev == NULL) {
- log_err("could not baseset localhdl event");
- free(c->ev);
- free(c);
- return NULL;
- }
- if (ub_event_add(c->ev->ev, c->timeout) != 0) {
- log_err("could not add localhdl event");
- ub_event_free(c->ev->ev);
- free(c->ev);
- free(c);
- return NULL;
- }
- return c;
-}
-
-struct comm_point*
-comm_point_create_raw(struct comm_base* base, int fd, int writing,
- comm_point_callback_type* callback, void* callback_arg)
-{
- struct comm_point* c = (struct comm_point*)calloc(1,
- sizeof(struct comm_point));
- short evbits;
- if(!c)
- return NULL;
- c->ev = (struct internal_event*)calloc(1,
- sizeof(struct internal_event));
- if(!c->ev) {
- free(c);
- return NULL;
- }
- c->ev->base = base;
- c->fd = fd;
- c->buffer = NULL;
- c->timeout = NULL;
- c->tcp_is_reading = 0;
- c->tcp_byte_count = 0;
- c->tcp_parent = NULL;
- c->max_tcp_count = 0;
- c->cur_tcp_count = 0;
- c->tcp_handlers = NULL;
- c->tcp_free = NULL;
- c->type = comm_raw;
- c->tcp_do_close = 0;
- c->do_not_close = 1;
- c->tcp_do_toggle_rw = 0;
- c->tcp_check_nb_connect = 0;
-#ifdef USE_MSG_FASTOPEN
- c->tcp_do_fastopen = 0;
-#endif
-#ifdef USE_DNSCRYPT
- c->dnscrypt = 0;
- c->dnscrypt_buffer = c->buffer;
-#endif
- c->callback = callback;
- c->cb_arg = callback_arg;
- /* ub_event stuff */
- if(writing)
- evbits = UB_EV_PERSIST | UB_EV_WRITE;
- else evbits = UB_EV_PERSIST | UB_EV_READ;
- c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
- comm_point_raw_handle_callback, c);
- if(c->ev->ev == NULL) {
- log_err("could not baseset rawhdl event");
- free(c->ev);
- free(c);
- return NULL;
- }
- if (ub_event_add(c->ev->ev, c->timeout) != 0) {
- log_err("could not add rawhdl event");
- ub_event_free(c->ev->ev);
- free(c->ev);
- free(c);
- return NULL;
- }
- return c;
-}
-
-void
-comm_point_close(struct comm_point* c)
-{
- if(!c)
- return;
- if(c->fd != -1)
- if(ub_event_del(c->ev->ev) != 0) {
- log_err("could not event_del on close");
- }
- /* close fd after removing from event lists, or epoll.. is messed up */
- if(c->fd != -1 && !c->do_not_close) {
- verbose(VERB_ALGO, "close fd %d", c->fd);
-#ifndef USE_WINSOCK
- close(c->fd);
-#else
- closesocket(c->fd);
-#endif
- }
- c->fd = -1;
-}
-
-void
-comm_point_delete(struct comm_point* c)
-{
- if(!c)
- return;
- if(c->type == comm_tcp && c->ssl) {
-#ifdef HAVE_SSL
- SSL_shutdown(c->ssl);
- SSL_free(c->ssl);
-#endif
- }
- comm_point_close(c);
- if(c->tcp_handlers) {
- int i;
- for(i=0; i<c->max_tcp_count; i++)
- comm_point_delete(c->tcp_handlers[i]);
- free(c->tcp_handlers);
- }
- free(c->timeout);
- if(c->type == comm_tcp || c->type == comm_local) {
- sldns_buffer_free(c->buffer);
-#ifdef USE_DNSCRYPT
- if(c->dnscrypt && c->dnscrypt_buffer != c->buffer) {
- sldns_buffer_free(c->dnscrypt_buffer);
- }
-#endif
- }
- ub_event_free(c->ev->ev);
- free(c->ev);
- free(c);
-}
-
-void
-comm_point_send_reply(struct comm_reply *repinfo)
-{
- struct sldns_buffer* buffer;
- log_assert(repinfo && repinfo->c);
-#ifdef USE_DNSCRYPT
- buffer = repinfo->c->dnscrypt_buffer;
- if(!dnsc_handle_uncurved_request(repinfo)) {
- return;
- }
-#else
- buffer = repinfo->c->buffer;
-#endif
- if(repinfo->c->type == comm_udp) {
- if(repinfo->srctype)
- comm_point_send_udp_msg_if(repinfo->c,
- buffer, (struct sockaddr*)&repinfo->addr,
- repinfo->addrlen, repinfo);
- else
- comm_point_send_udp_msg(repinfo->c, buffer,
- (struct sockaddr*)&repinfo->addr, repinfo->addrlen);
-#ifdef USE_DNSTAP
- if(repinfo->c->dtenv != NULL &&
- repinfo->c->dtenv->log_client_response_messages)
- dt_msg_send_client_response(repinfo->c->dtenv,
- &repinfo->addr, repinfo->c->type, repinfo->c->buffer);
-#endif
- } else {
-#ifdef USE_DNSTAP
- if(repinfo->c->tcp_parent->dtenv != NULL &&
- repinfo->c->tcp_parent->dtenv->log_client_response_messages)
- dt_msg_send_client_response(repinfo->c->tcp_parent->dtenv,
- &repinfo->addr, repinfo->c->type, repinfo->c->buffer);
-#endif
- comm_point_start_listening(repinfo->c, -1,
- repinfo->c->tcp_timeout_msec);
- }
-}
-
-void
-comm_point_drop_reply(struct comm_reply* repinfo)
-{
- if(!repinfo)
- return;
- log_assert(repinfo && repinfo->c);
- log_assert(repinfo->c->type != comm_tcp_accept);
- if(repinfo->c->type == comm_udp)
- return;
- reclaim_tcp_handler(repinfo->c);
-}
-
-void
-comm_point_stop_listening(struct comm_point* c)
-{
- verbose(VERB_ALGO, "comm point stop listening %d", c->fd);
- if(ub_event_del(c->ev->ev) != 0) {
- log_err("event_del error to stoplisten");
- }
-}
-
-void
-comm_point_start_listening(struct comm_point* c, int newfd, int msec)
-{
- verbose(VERB_ALGO, "comm point start listening %d",
- c->fd==-1?newfd:c->fd);
- if(c->type == comm_tcp_accept && !c->tcp_free) {
- /* no use to start listening no free slots. */
- return;
- }
- if(msec != -1 && msec != 0) {
- if(!c->timeout) {
- c->timeout = (struct timeval*)malloc(sizeof(
- struct timeval));
- if(!c->timeout) {
- log_err("cpsl: malloc failed. No net read.");
- return;
- }
- }
- ub_event_add_bits(c->ev->ev, UB_EV_TIMEOUT);
-#ifndef S_SPLINT_S /* splint fails on struct timeval. */
- c->timeout->tv_sec = msec/1000;
- c->timeout->tv_usec = (msec%1000)*1000;
-#endif /* S_SPLINT_S */
- }
- if(c->type == comm_tcp) {
- ub_event_del_bits(c->ev->ev, UB_EV_READ|UB_EV_WRITE);
- if(c->tcp_is_reading)
- ub_event_add_bits(c->ev->ev, UB_EV_READ);
- else ub_event_add_bits(c->ev->ev, UB_EV_WRITE);
- }
- if(newfd != -1) {
- if(c->fd != -1) {
-#ifndef USE_WINSOCK
- close(c->fd);
-#else
- closesocket(c->fd);
-#endif
- }
- c->fd = newfd;
- ub_event_set_fd(c->ev->ev, c->fd);
- }
- if(ub_event_add(c->ev->ev, msec==0?NULL:c->timeout) != 0) {
- log_err("event_add failed. in cpsl.");
- }
-}
-
-void comm_point_listen_for_rw(struct comm_point* c, int rd, int wr)
-{
- verbose(VERB_ALGO, "comm point listen_for_rw %d %d", c->fd, wr);
- if(ub_event_del(c->ev->ev) != 0) {
- log_err("event_del error to cplf");
- }
- ub_event_del_bits(c->ev->ev, UB_EV_READ|UB_EV_WRITE);
- if(rd) ub_event_add_bits(c->ev->ev, UB_EV_READ);
- if(wr) ub_event_add_bits(c->ev->ev, UB_EV_WRITE);
- if(ub_event_add(c->ev->ev, c->timeout) != 0) {
- log_err("event_add failed. in cplf.");
- }
-}
-
-size_t comm_point_get_mem(struct comm_point* c)
-{
- size_t s;
- if(!c)
- return 0;
- s = sizeof(*c) + sizeof(*c->ev);
- if(c->timeout)
- s += sizeof(*c->timeout);
- if(c->type == comm_tcp || c->type == comm_local) {
- s += sizeof(*c->buffer) + sldns_buffer_capacity(c->buffer);
-#ifdef USE_DNSCRYPT
- s += sizeof(*c->dnscrypt_buffer);
- if(c->buffer != c->dnscrypt_buffer) {
- s += sldns_buffer_capacity(c->dnscrypt_buffer);
- }
-#endif
- }
- if(c->type == comm_tcp_accept) {
- int i;
- for(i=0; i<c->max_tcp_count; i++)
- s += comm_point_get_mem(c->tcp_handlers[i]);
- }
- return s;
-}
-
-struct comm_timer*
-comm_timer_create(struct comm_base* base, void (*cb)(void*), void* cb_arg)
-{
- struct internal_timer *tm = (struct internal_timer*)calloc(1,
- sizeof(struct internal_timer));
- if(!tm) {
- log_err("malloc failed");
- return NULL;
- }
- tm->super.ev_timer = tm;
- tm->base = base;
- tm->super.callback = cb;
- tm->super.cb_arg = cb_arg;
- tm->ev = ub_event_new(base->eb->base, -1, UB_EV_TIMEOUT,
- comm_timer_callback, &tm->super);
- if(tm->ev == NULL) {
- log_err("timer_create: event_base_set failed.");
- free(tm);
- return NULL;
- }
- return &tm->super;
-}
-
-void
-comm_timer_disable(struct comm_timer* timer)
-{
- if(!timer)
- return;
- ub_timer_del(timer->ev_timer->ev);
- timer->ev_timer->enabled = 0;
-}
-
-void
-comm_timer_set(struct comm_timer* timer, struct timeval* tv)
-{
- log_assert(tv);
- if(timer->ev_timer->enabled)
- comm_timer_disable(timer);
- if(ub_timer_add(timer->ev_timer->ev, timer->ev_timer->base->eb->base,
- comm_timer_callback, timer, tv) != 0)
- log_err("comm_timer_set: evtimer_add failed.");
- timer->ev_timer->enabled = 1;
-}
-
-void
-comm_timer_delete(struct comm_timer* timer)
-{
- if(!timer)
- return;
- comm_timer_disable(timer);
- /* Free the sub struct timer->ev_timer derived from the super struct timer.
- * i.e. assert(timer == timer->ev_timer)
- */
- ub_event_free(timer->ev_timer->ev);
- free(timer->ev_timer);
-}
-
-void
-comm_timer_callback(int ATTR_UNUSED(fd), short event, void* arg)
-{
- struct comm_timer* tm = (struct comm_timer*)arg;
- if(!(event&UB_EV_TIMEOUT))
- return;
- ub_comm_base_now(tm->ev_timer->base);
- tm->ev_timer->enabled = 0;
- fptr_ok(fptr_whitelist_comm_timer(tm->callback));
- (*tm->callback)(tm->cb_arg);
-}
-
-int
-comm_timer_is_set(struct comm_timer* timer)
-{
- return (int)timer->ev_timer->enabled;
-}
-
-size_t
-comm_timer_get_mem(struct comm_timer* ATTR_UNUSED(timer))
-{
- return sizeof(struct internal_timer);
-}
-
-struct comm_signal*
-comm_signal_create(struct comm_base* base,
- void (*callback)(int, void*), void* cb_arg)
-{
- struct comm_signal* com = (struct comm_signal*)malloc(
- sizeof(struct comm_signal));
- if(!com) {
- log_err("malloc failed");
- return NULL;
- }
- com->base = base;
- com->callback = callback;
- com->cb_arg = cb_arg;
- com->ev_signal = NULL;
- return com;
-}
-
-void
-comm_signal_callback(int sig, short event, void* arg)
-{
- struct comm_signal* comsig = (struct comm_signal*)arg;
- if(!(event & UB_EV_SIGNAL))
- return;
- ub_comm_base_now(comsig->base);
- fptr_ok(fptr_whitelist_comm_signal(comsig->callback));
- (*comsig->callback)(sig, comsig->cb_arg);
-}
-
-int
-comm_signal_bind(struct comm_signal* comsig, int sig)
-{
- struct internal_signal* entry = (struct internal_signal*)calloc(1,
- sizeof(struct internal_signal));
- if(!entry) {
- log_err("malloc failed");
- return 0;
- }
- log_assert(comsig);
- /* add signal event */
- entry->ev = ub_signal_new(comsig->base->eb->base, sig,
- comm_signal_callback, comsig);
- if(entry->ev == NULL) {
- log_err("Could not create signal event");
- free(entry);
- return 0;
- }
- if(ub_signal_add(entry->ev, NULL) != 0) {
- log_err("Could not add signal handler");
- ub_event_free(entry->ev);
- free(entry);
- return 0;
- }
- /* link into list */
- entry->next = comsig->ev_signal;
- comsig->ev_signal = entry;
- return 1;
-}
-
-void
-comm_signal_delete(struct comm_signal* comsig)
-{
- struct internal_signal* p, *np;
- if(!comsig)
- return;
- p=comsig->ev_signal;
- while(p) {
- np = p->next;
- ub_signal_del(p->ev);
- ub_event_free(p->ev);
- free(p);
- p = np;
- }
- free(comsig);
-}