xref: /netbsd-src/external/bsd/unbound/dist/util/netevent.c (revision 14b2fa6e0fd53c02fbfc60c724004dec5d666054)
13b6c3722Schristos /*
23b6c3722Schristos  * util/netevent.c - event notification
33b6c3722Schristos  *
43b6c3722Schristos  * Copyright (c) 2007, NLnet Labs. All rights reserved.
53b6c3722Schristos  *
63b6c3722Schristos  * This software is open source.
73b6c3722Schristos  *
83b6c3722Schristos  * Redistribution and use in source and binary forms, with or without
93b6c3722Schristos  * modification, are permitted provided that the following conditions
103b6c3722Schristos  * are met:
113b6c3722Schristos  *
123b6c3722Schristos  * Redistributions of source code must retain the above copyright notice,
133b6c3722Schristos  * this list of conditions and the following disclaimer.
143b6c3722Schristos  *
153b6c3722Schristos  * Redistributions in binary form must reproduce the above copyright notice,
163b6c3722Schristos  * this list of conditions and the following disclaimer in the documentation
173b6c3722Schristos  * and/or other materials provided with the distribution.
183b6c3722Schristos  *
193b6c3722Schristos  * Neither the name of the NLNET LABS nor the names of its contributors may
203b6c3722Schristos  * be used to endorse or promote products derived from this software without
213b6c3722Schristos  * specific prior written permission.
223b6c3722Schristos  *
233b6c3722Schristos  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
243b6c3722Schristos  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
253b6c3722Schristos  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
263b6c3722Schristos  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
273b6c3722Schristos  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
283b6c3722Schristos  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
293b6c3722Schristos  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
303b6c3722Schristos  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
313b6c3722Schristos  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
323b6c3722Schristos  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
333b6c3722Schristos  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
343b6c3722Schristos  */
353b6c3722Schristos 
363b6c3722Schristos /**
373b6c3722Schristos  * \file
383b6c3722Schristos  *
393b6c3722Schristos  * This file contains event notification functions.
403b6c3722Schristos  */
413b6c3722Schristos #include "config.h"
423b6c3722Schristos #include "util/netevent.h"
433b6c3722Schristos #include "util/ub_event.h"
443b6c3722Schristos #include "util/log.h"
453b6c3722Schristos #include "util/net_help.h"
46f42d8de7Schristos #include "util/tcp_conn_limit.h"
473b6c3722Schristos #include "util/fptr_wlist.h"
48*14b2fa6eSchristos #include "util/proxy_protocol.h"
49*14b2fa6eSchristos #include "util/timeval_func.h"
503b6c3722Schristos #include "sldns/pkthdr.h"
513b6c3722Schristos #include "sldns/sbuffer.h"
527cd94d69Schristos #include "sldns/str2wire.h"
533b6c3722Schristos #include "dnstap/dnstap.h"
540cd9f4ecSchristos #include "dnscrypt/dnscrypt.h"
55f42d8de7Schristos #include "services/listen_dnsport.h"
561481e2a9Schristos #ifdef HAVE_SYS_TYPES_H
571481e2a9Schristos #include <sys/types.h>
581481e2a9Schristos #endif
591481e2a9Schristos #ifdef HAVE_SYS_SOCKET_H
601481e2a9Schristos #include <sys/socket.h>
611481e2a9Schristos #endif
621481e2a9Schristos #ifdef HAVE_NETDB_H
631481e2a9Schristos #include <netdb.h>
641481e2a9Schristos #endif
65*14b2fa6eSchristos #ifdef HAVE_POLL_H
66*14b2fa6eSchristos #include <poll.h>
67*14b2fa6eSchristos #endif
681481e2a9Schristos 
693b6c3722Schristos #ifdef HAVE_OPENSSL_SSL_H
703b6c3722Schristos #include <openssl/ssl.h>
713b6c3722Schristos #endif
723b6c3722Schristos #ifdef HAVE_OPENSSL_ERR_H
733b6c3722Schristos #include <openssl/err.h>
743b6c3722Schristos #endif
75*14b2fa6eSchristos #ifdef HAVE_LINUX_NET_TSTAMP_H
76*14b2fa6eSchristos #include <linux/net_tstamp.h>
77*14b2fa6eSchristos #endif
783b6c3722Schristos /* -------- Start of local definitions -------- */
793b6c3722Schristos /** if CMSG_ALIGN is not defined on this platform, a workaround */
803b6c3722Schristos #ifndef CMSG_ALIGN
813b6c3722Schristos #  ifdef __CMSG_ALIGN
823b6c3722Schristos #    define CMSG_ALIGN(n) __CMSG_ALIGN(n)
833b6c3722Schristos #  elif defined(CMSG_DATA_ALIGN)
843b6c3722Schristos #    define CMSG_ALIGN _CMSG_DATA_ALIGN
853b6c3722Schristos #  else
863b6c3722Schristos #    define CMSG_ALIGN(len) (((len)+sizeof(long)-1) & ~(sizeof(long)-1))
873b6c3722Schristos #  endif
883b6c3722Schristos #endif
893b6c3722Schristos 
903b6c3722Schristos /** if CMSG_LEN is not defined on this platform, a workaround */
913b6c3722Schristos #ifndef CMSG_LEN
923b6c3722Schristos #  define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr))+(len))
933b6c3722Schristos #endif
943b6c3722Schristos 
953b6c3722Schristos /** if CMSG_SPACE is not defined on this platform, a workaround */
963b6c3722Schristos #ifndef CMSG_SPACE
973b6c3722Schristos #  ifdef _CMSG_HDR_ALIGN
983b6c3722Schristos #    define CMSG_SPACE(l) (CMSG_ALIGN(l)+_CMSG_HDR_ALIGN(sizeof(struct cmsghdr)))
993b6c3722Schristos #  else
1003b6c3722Schristos #    define CMSG_SPACE(l) (CMSG_ALIGN(l)+CMSG_ALIGN(sizeof(struct cmsghdr)))
1013b6c3722Schristos #  endif
1023b6c3722Schristos #endif
1033b6c3722Schristos 
104f42d8de7Schristos /** The TCP writing query timeout in milliseconds */
1050cd9f4ecSchristos #define TCP_QUERY_TIMEOUT 120000
106f42d8de7Schristos /** The minimum actual TCP timeout to use, regardless of what we advertise,
107f42d8de7Schristos  * in msec */
108f42d8de7Schristos #define TCP_QUERY_TIMEOUT_MINIMUM 200
1093b6c3722Schristos 
1103b6c3722Schristos #ifndef NONBLOCKING_IS_BROKEN
1113b6c3722Schristos /** number of UDP reads to perform per read indication from select */
1123b6c3722Schristos #define NUM_UDP_PER_SELECT 100
1133b6c3722Schristos #else
1143b6c3722Schristos #define NUM_UDP_PER_SELECT 1
1153b6c3722Schristos #endif
1163b6c3722Schristos 
117*14b2fa6eSchristos /** timeout in millisec to wait for write to unblock, packets dropped after.*/
118*14b2fa6eSchristos #define SEND_BLOCKED_WAIT_TIMEOUT 200
119*14b2fa6eSchristos /** max number of times to wait for write to unblock, packets dropped after.*/
120*14b2fa6eSchristos #define SEND_BLOCKED_MAX_RETRY 5
121*14b2fa6eSchristos 
122*14b2fa6eSchristos /** Let's make timestamping code cleaner and redefine SO_TIMESTAMP* */
123*14b2fa6eSchristos #ifndef SO_TIMESTAMP
124*14b2fa6eSchristos #define SO_TIMESTAMP 29
125*14b2fa6eSchristos #endif
126*14b2fa6eSchristos #ifndef SO_TIMESTAMPNS
127*14b2fa6eSchristos #define SO_TIMESTAMPNS 35
128*14b2fa6eSchristos #endif
129*14b2fa6eSchristos #ifndef SO_TIMESTAMPING
130*14b2fa6eSchristos #define SO_TIMESTAMPING 37
131*14b2fa6eSchristos #endif
1323b6c3722Schristos /**
1333b6c3722Schristos  * The internal event structure for keeping ub_event info for the event.
1343b6c3722Schristos  * Possibly other structures (list, tree) this is part of.
1353b6c3722Schristos  */
1363b6c3722Schristos struct internal_event {
1373b6c3722Schristos 	/** the comm base */
1383b6c3722Schristos 	struct comm_base* base;
1393b6c3722Schristos 	/** ub_event event type */
1403b6c3722Schristos 	struct ub_event* ev;
1413b6c3722Schristos };
1423b6c3722Schristos 
1433b6c3722Schristos /**
1443b6c3722Schristos  * Internal base structure, so that every thread has its own events.
1453b6c3722Schristos  */
1463b6c3722Schristos struct internal_base {
1473b6c3722Schristos 	/** ub_event event_base type. */
1483b6c3722Schristos 	struct ub_event_base* base;
1493b6c3722Schristos 	/** seconds time pointer points here */
1503b6c3722Schristos 	time_t secs;
1513b6c3722Schristos 	/** timeval with current time */
1523b6c3722Schristos 	struct timeval now;
1533b6c3722Schristos 	/** the event used for slow_accept timeouts */
1543b6c3722Schristos 	struct ub_event* slow_accept;
1553b6c3722Schristos 	/** true if slow_accept is enabled */
1563b6c3722Schristos 	int slow_accept_enabled;
157*14b2fa6eSchristos 	/** last log time for slow logging of file descriptor errors */
158*14b2fa6eSchristos 	time_t last_slow_log;
159*14b2fa6eSchristos 	/** last log time for slow logging of write wait failures */
160*14b2fa6eSchristos 	time_t last_writewait_log;
1613b6c3722Schristos };
1623b6c3722Schristos 
1633b6c3722Schristos /**
1643b6c3722Schristos  * Internal timer structure, to store timer event in.
1653b6c3722Schristos  */
1663b6c3722Schristos struct internal_timer {
1673b6c3722Schristos 	/** the super struct from which derived */
1683b6c3722Schristos 	struct comm_timer super;
1693b6c3722Schristos 	/** the comm base */
1703b6c3722Schristos 	struct comm_base* base;
1713b6c3722Schristos 	/** ub_event event type */
1723b6c3722Schristos 	struct ub_event* ev;
1733b6c3722Schristos 	/** is timer enabled */
1743b6c3722Schristos 	uint8_t enabled;
1753b6c3722Schristos };
1763b6c3722Schristos 
1773b6c3722Schristos /**
1783b6c3722Schristos  * Internal signal structure, to store signal event in.
1793b6c3722Schristos  */
1803b6c3722Schristos struct internal_signal {
1813b6c3722Schristos 	/** ub_event event type */
1823b6c3722Schristos 	struct ub_event* ev;
1833b6c3722Schristos 	/** next in signal list */
1843b6c3722Schristos 	struct internal_signal* next;
1853b6c3722Schristos };
1863b6c3722Schristos 
1873b6c3722Schristos /** create a tcp handler with a parent */
1883b6c3722Schristos static struct comm_point* comm_point_create_tcp_handler(
1893b6c3722Schristos 	struct comm_base *base, struct comm_point* parent, size_t bufsize,
190f42d8de7Schristos 	struct sldns_buffer* spoolbuf, comm_point_callback_type* callback,
1911481e2a9Schristos 	void* callback_arg, struct unbound_socket* socket);
1923b6c3722Schristos 
1933b6c3722Schristos /* -------- End of local definitions -------- */
1943b6c3722Schristos 
1953b6c3722Schristos struct comm_base*
comm_base_create(int sigs)1963b6c3722Schristos comm_base_create(int sigs)
1973b6c3722Schristos {
1983b6c3722Schristos 	struct comm_base* b = (struct comm_base*)calloc(1,
1993b6c3722Schristos 		sizeof(struct comm_base));
2003b6c3722Schristos 	const char *evnm="event", *evsys="", *evmethod="";
2013b6c3722Schristos 
2023b6c3722Schristos 	if(!b)
2033b6c3722Schristos 		return NULL;
2043b6c3722Schristos 	b->eb = (struct internal_base*)calloc(1, sizeof(struct internal_base));
2053b6c3722Schristos 	if(!b->eb) {
2063b6c3722Schristos 		free(b);
2073b6c3722Schristos 		return NULL;
2083b6c3722Schristos 	}
2093b6c3722Schristos 	b->eb->base = ub_default_event_base(sigs, &b->eb->secs, &b->eb->now);
2103b6c3722Schristos 	if(!b->eb->base) {
2113b6c3722Schristos 		free(b->eb);
2123b6c3722Schristos 		free(b);
2133b6c3722Schristos 		return NULL;
2143b6c3722Schristos 	}
2153b6c3722Schristos 	ub_comm_base_now(b);
2163b6c3722Schristos 	ub_get_event_sys(b->eb->base, &evnm, &evsys, &evmethod);
21787edd195Schristos 	verbose(VERB_ALGO, "%s %s uses %s method.", evnm, evsys, evmethod);
2183b6c3722Schristos 	return b;
2193b6c3722Schristos }
2203b6c3722Schristos 
2213b6c3722Schristos struct comm_base*
comm_base_create_event(struct ub_event_base * base)2223b6c3722Schristos comm_base_create_event(struct ub_event_base* base)
2233b6c3722Schristos {
2243b6c3722Schristos 	struct comm_base* b = (struct comm_base*)calloc(1,
2253b6c3722Schristos 		sizeof(struct comm_base));
2263b6c3722Schristos 	if(!b)
2273b6c3722Schristos 		return NULL;
2283b6c3722Schristos 	b->eb = (struct internal_base*)calloc(1, sizeof(struct internal_base));
2293b6c3722Schristos 	if(!b->eb) {
2303b6c3722Schristos 		free(b);
2313b6c3722Schristos 		return NULL;
2323b6c3722Schristos 	}
2333b6c3722Schristos 	b->eb->base = base;
2343b6c3722Schristos 	ub_comm_base_now(b);
2353b6c3722Schristos 	return b;
2363b6c3722Schristos }
2373b6c3722Schristos 
2383b6c3722Schristos void
comm_base_delete(struct comm_base * b)2393b6c3722Schristos comm_base_delete(struct comm_base* b)
2403b6c3722Schristos {
2413b6c3722Schristos 	if(!b)
2423b6c3722Schristos 		return;
2433b6c3722Schristos 	if(b->eb->slow_accept_enabled) {
2443b6c3722Schristos 		if(ub_event_del(b->eb->slow_accept) != 0) {
2453b6c3722Schristos 			log_err("could not event_del slow_accept");
2463b6c3722Schristos 		}
2473b6c3722Schristos 		ub_event_free(b->eb->slow_accept);
2483b6c3722Schristos 	}
2493b6c3722Schristos 	ub_event_base_free(b->eb->base);
2503b6c3722Schristos 	b->eb->base = NULL;
2513b6c3722Schristos 	free(b->eb);
2523b6c3722Schristos 	free(b);
2533b6c3722Schristos }
2543b6c3722Schristos 
2553b6c3722Schristos void
comm_base_delete_no_base(struct comm_base * b)2563b6c3722Schristos comm_base_delete_no_base(struct comm_base* b)
2573b6c3722Schristos {
2583b6c3722Schristos 	if(!b)
2593b6c3722Schristos 		return;
2603b6c3722Schristos 	if(b->eb->slow_accept_enabled) {
2613b6c3722Schristos 		if(ub_event_del(b->eb->slow_accept) != 0) {
2623b6c3722Schristos 			log_err("could not event_del slow_accept");
2633b6c3722Schristos 		}
2643b6c3722Schristos 		ub_event_free(b->eb->slow_accept);
2653b6c3722Schristos 	}
2663b6c3722Schristos 	b->eb->base = NULL;
2673b6c3722Schristos 	free(b->eb);
2683b6c3722Schristos 	free(b);
2693b6c3722Schristos }
2703b6c3722Schristos 
2713b6c3722Schristos void
comm_base_timept(struct comm_base * b,time_t ** tt,struct timeval ** tv)2723b6c3722Schristos comm_base_timept(struct comm_base* b, time_t** tt, struct timeval** tv)
2733b6c3722Schristos {
2743b6c3722Schristos 	*tt = &b->eb->secs;
2753b6c3722Schristos 	*tv = &b->eb->now;
2763b6c3722Schristos }
2773b6c3722Schristos 
2783b6c3722Schristos void
comm_base_dispatch(struct comm_base * b)2793b6c3722Schristos comm_base_dispatch(struct comm_base* b)
2803b6c3722Schristos {
2813b6c3722Schristos 	int retval;
2823b6c3722Schristos 	retval = ub_event_base_dispatch(b->eb->base);
2833b6c3722Schristos 	if(retval < 0) {
2843b6c3722Schristos 		fatal_exit("event_dispatch returned error %d, "
2853b6c3722Schristos 			"errno is %s", retval, strerror(errno));
2863b6c3722Schristos 	}
2873b6c3722Schristos }
2883b6c3722Schristos 
comm_base_exit(struct comm_base * b)2893b6c3722Schristos void comm_base_exit(struct comm_base* b)
2903b6c3722Schristos {
2913b6c3722Schristos 	if(ub_event_base_loopexit(b->eb->base) != 0) {
2923b6c3722Schristos 		log_err("Could not loopexit");
2933b6c3722Schristos 	}
2943b6c3722Schristos }
2953b6c3722Schristos 
comm_base_set_slow_accept_handlers(struct comm_base * b,void (* stop_acc)(void *),void (* start_acc)(void *),void * arg)2963b6c3722Schristos void comm_base_set_slow_accept_handlers(struct comm_base* b,
2973b6c3722Schristos 	void (*stop_acc)(void*), void (*start_acc)(void*), void* arg)
2983b6c3722Schristos {
2993b6c3722Schristos 	b->stop_accept = stop_acc;
3003b6c3722Schristos 	b->start_accept = start_acc;
3013b6c3722Schristos 	b->cb_arg = arg;
3023b6c3722Schristos }
3033b6c3722Schristos 
comm_base_internal(struct comm_base * b)3043b6c3722Schristos struct ub_event_base* comm_base_internal(struct comm_base* b)
3053b6c3722Schristos {
3063b6c3722Schristos 	return b->eb->base;
3073b6c3722Schristos }
3083b6c3722Schristos 
3093b6c3722Schristos /** see if errno for udp has to be logged or not uses globals */
3103b6c3722Schristos static int
udp_send_errno_needs_log(struct sockaddr * addr,socklen_t addrlen)3113b6c3722Schristos udp_send_errno_needs_log(struct sockaddr* addr, socklen_t addrlen)
3123b6c3722Schristos {
3133b6c3722Schristos 	/* do not log transient errors (unless high verbosity) */
3143b6c3722Schristos #if defined(ENETUNREACH) || defined(EHOSTDOWN) || defined(EHOSTUNREACH) || defined(ENETDOWN)
3153b6c3722Schristos 	switch(errno) {
3163b6c3722Schristos #  ifdef ENETUNREACH
3173b6c3722Schristos 		case ENETUNREACH:
3183b6c3722Schristos #  endif
3193b6c3722Schristos #  ifdef EHOSTDOWN
3203b6c3722Schristos 		case EHOSTDOWN:
3213b6c3722Schristos #  endif
3223b6c3722Schristos #  ifdef EHOSTUNREACH
3233b6c3722Schristos 		case EHOSTUNREACH:
3243b6c3722Schristos #  endif
3253b6c3722Schristos #  ifdef ENETDOWN
3263b6c3722Schristos 		case ENETDOWN:
3273b6c3722Schristos #  endif
3281481e2a9Schristos 		case EPERM:
3291481e2a9Schristos 		case EACCES:
3303b6c3722Schristos 			if(verbosity < VERB_ALGO)
3313b6c3722Schristos 				return 0;
3323b6c3722Schristos 		default:
3333b6c3722Schristos 			break;
3343b6c3722Schristos 	}
3353b6c3722Schristos #endif
3363b6c3722Schristos 	/* permission denied is gotten for every send if the
3373b6c3722Schristos 	 * network is disconnected (on some OS), squelch it */
3383b6c3722Schristos 	if( ((errno == EPERM)
3393b6c3722Schristos #  ifdef EADDRNOTAVAIL
3403b6c3722Schristos 		/* 'Cannot assign requested address' also when disconnected */
3413b6c3722Schristos 		|| (errno == EADDRNOTAVAIL)
3423b6c3722Schristos #  endif
3431481e2a9Schristos 		) && verbosity < VERB_ALGO)
3443b6c3722Schristos 		return 0;
3457cd94d69Schristos #  ifdef EADDRINUSE
3467cd94d69Schristos 	/* If SO_REUSEADDR is set, we could try to connect to the same server
3477cd94d69Schristos 	 * from the same source port twice. */
3487cd94d69Schristos 	if(errno == EADDRINUSE && verbosity < VERB_DETAIL)
3497cd94d69Schristos 		return 0;
3507cd94d69Schristos #  endif
3513b6c3722Schristos 	/* squelch errors where people deploy AAAA ::ffff:bla for
3523b6c3722Schristos 	 * authority servers, which we try for intranets. */
3533b6c3722Schristos 	if(errno == EINVAL && addr_is_ip4mapped(
3543b6c3722Schristos 		(struct sockaddr_storage*)addr, addrlen) &&
3553b6c3722Schristos 		verbosity < VERB_DETAIL)
3563b6c3722Schristos 		return 0;
3573b6c3722Schristos 	/* SO_BROADCAST sockopt can give access to 255.255.255.255,
3583b6c3722Schristos 	 * but a dns cache does not need it. */
3593b6c3722Schristos 	if(errno == EACCES && addr_is_broadcast(
3603b6c3722Schristos 		(struct sockaddr_storage*)addr, addrlen) &&
3613b6c3722Schristos 		verbosity < VERB_DETAIL)
3623b6c3722Schristos 		return 0;
3633b6c3722Schristos 	return 1;
3643b6c3722Schristos }
3653b6c3722Schristos 
tcp_connect_errno_needs_log(struct sockaddr * addr,socklen_t addrlen)3663b6c3722Schristos int tcp_connect_errno_needs_log(struct sockaddr* addr, socklen_t addrlen)
3673b6c3722Schristos {
3683b6c3722Schristos 	return udp_send_errno_needs_log(addr, addrlen);
3693b6c3722Schristos }
3703b6c3722Schristos 
3713b6c3722Schristos /* send a UDP reply */
3723b6c3722Schristos int
comm_point_send_udp_msg(struct comm_point * c,sldns_buffer * packet,struct sockaddr * addr,socklen_t addrlen,int is_connected)3733b6c3722Schristos comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet,
37416776186Schristos 	struct sockaddr* addr, socklen_t addrlen, int is_connected)
3753b6c3722Schristos {
3763b6c3722Schristos 	ssize_t sent;
3773b6c3722Schristos 	log_assert(c->fd != -1);
3783b6c3722Schristos #ifdef UNBOUND_DEBUG
3793b6c3722Schristos 	if(sldns_buffer_remaining(packet) == 0)
3803b6c3722Schristos 		log_err("error: send empty UDP packet");
3813b6c3722Schristos #endif
3823b6c3722Schristos 	log_assert(addr && addrlen > 0);
38316776186Schristos 	if(!is_connected) {
3843b6c3722Schristos 		sent = sendto(c->fd, (void*)sldns_buffer_begin(packet),
3853b6c3722Schristos 			sldns_buffer_remaining(packet), 0,
3863b6c3722Schristos 			addr, addrlen);
38716776186Schristos 	} else {
38816776186Schristos 		sent = send(c->fd, (void*)sldns_buffer_begin(packet),
38916776186Schristos 			sldns_buffer_remaining(packet), 0);
39016776186Schristos 	}
3913b6c3722Schristos 	if(sent == -1) {
3923b6c3722Schristos 		/* try again and block, waiting for IO to complete,
3933b6c3722Schristos 		 * we want to send the answer, and we will wait for
3943b6c3722Schristos 		 * the ethernet interface buffer to have space. */
3953b6c3722Schristos #ifndef USE_WINSOCK
396*14b2fa6eSchristos 		if(errno == EAGAIN || errno == EINTR ||
3973b6c3722Schristos #  ifdef EWOULDBLOCK
3983b6c3722Schristos 			errno == EWOULDBLOCK ||
3993b6c3722Schristos #  endif
4003b6c3722Schristos 			errno == ENOBUFS) {
4013b6c3722Schristos #else
4023b6c3722Schristos 		if(WSAGetLastError() == WSAEINPROGRESS ||
403*14b2fa6eSchristos 			WSAGetLastError() == WSAEINTR ||
4043b6c3722Schristos 			WSAGetLastError() == WSAENOBUFS ||
4053b6c3722Schristos 			WSAGetLastError() == WSAEWOULDBLOCK) {
4063b6c3722Schristos #endif
407*14b2fa6eSchristos 			int retries = 0;
408*14b2fa6eSchristos 			/* if we set the fd blocking, other threads suddenly
409*14b2fa6eSchristos 			 * have a blocking fd that they operate on */
410*14b2fa6eSchristos 			while(sent == -1 && retries < SEND_BLOCKED_MAX_RETRY && (
411*14b2fa6eSchristos #ifndef USE_WINSOCK
412*14b2fa6eSchristos 				errno == EAGAIN || errno == EINTR ||
413*14b2fa6eSchristos #  ifdef EWOULDBLOCK
414*14b2fa6eSchristos 				errno == EWOULDBLOCK ||
415*14b2fa6eSchristos #  endif
416*14b2fa6eSchristos 				errno == ENOBUFS
417*14b2fa6eSchristos #else
418*14b2fa6eSchristos 				WSAGetLastError() == WSAEINPROGRESS ||
419*14b2fa6eSchristos 				WSAGetLastError() == WSAEINTR ||
420*14b2fa6eSchristos 				WSAGetLastError() == WSAENOBUFS ||
421*14b2fa6eSchristos 				WSAGetLastError() == WSAEWOULDBLOCK
422*14b2fa6eSchristos #endif
423*14b2fa6eSchristos 			)) {
424*14b2fa6eSchristos #if defined(HAVE_POLL) || defined(USE_WINSOCK)
425*14b2fa6eSchristos 				int send_nobufs = (
426*14b2fa6eSchristos #ifndef USE_WINSOCK
427*14b2fa6eSchristos 					errno == ENOBUFS
428*14b2fa6eSchristos #else
429*14b2fa6eSchristos 					WSAGetLastError() == WSAENOBUFS
430*14b2fa6eSchristos #endif
431*14b2fa6eSchristos 				);
432*14b2fa6eSchristos 				struct pollfd p;
433*14b2fa6eSchristos 				int pret;
434*14b2fa6eSchristos 				memset(&p, 0, sizeof(p));
435*14b2fa6eSchristos 				p.fd = c->fd;
436*14b2fa6eSchristos 				p.events = POLLOUT | POLLERR | POLLHUP;
437*14b2fa6eSchristos #  ifndef USE_WINSOCK
438*14b2fa6eSchristos 				pret = poll(&p, 1, SEND_BLOCKED_WAIT_TIMEOUT);
439*14b2fa6eSchristos #  else
440*14b2fa6eSchristos 				pret = WSAPoll(&p, 1,
441*14b2fa6eSchristos 					SEND_BLOCKED_WAIT_TIMEOUT);
442*14b2fa6eSchristos #  endif
443*14b2fa6eSchristos 				if(pret == 0) {
444*14b2fa6eSchristos 					/* timer expired */
445*14b2fa6eSchristos 					struct comm_base* b = c->ev->base;
446*14b2fa6eSchristos 					if(b->eb->last_writewait_log+SLOW_LOG_TIME <=
447*14b2fa6eSchristos 						b->eb->secs) {
448*14b2fa6eSchristos 						b->eb->last_writewait_log = b->eb->secs;
449*14b2fa6eSchristos 						verbose(VERB_OPS, "send udp blocked "
450*14b2fa6eSchristos 							"for long, dropping packet.");
451*14b2fa6eSchristos 					}
452*14b2fa6eSchristos 					return 0;
453*14b2fa6eSchristos 				} else if(pret < 0 &&
454*14b2fa6eSchristos #ifndef USE_WINSOCK
455*14b2fa6eSchristos 					errno != EAGAIN && errno != EINTR &&
456*14b2fa6eSchristos #  ifdef EWOULDBLOCK
457*14b2fa6eSchristos 					errno != EWOULDBLOCK &&
458*14b2fa6eSchristos #  endif
459*14b2fa6eSchristos 					errno != ENOBUFS
460*14b2fa6eSchristos #else
461*14b2fa6eSchristos 					WSAGetLastError() != WSAEINPROGRESS &&
462*14b2fa6eSchristos 					WSAGetLastError() != WSAEINTR &&
463*14b2fa6eSchristos 					WSAGetLastError() != WSAENOBUFS &&
464*14b2fa6eSchristos 					WSAGetLastError() != WSAEWOULDBLOCK
465*14b2fa6eSchristos #endif
466*14b2fa6eSchristos 					) {
467*14b2fa6eSchristos 					log_err("poll udp out failed: %s",
468*14b2fa6eSchristos 						sock_strerror(errno));
469*14b2fa6eSchristos 					return 0;
470*14b2fa6eSchristos 				} else if((pret < 0 &&
471*14b2fa6eSchristos #ifndef USE_WINSOCK
472*14b2fa6eSchristos 					errno == ENOBUFS
473*14b2fa6eSchristos #else
474*14b2fa6eSchristos 					WSAGetLastError() == WSAENOBUFS
475*14b2fa6eSchristos #endif
476*14b2fa6eSchristos 					) || (send_nobufs && retries > 0)) {
477*14b2fa6eSchristos 					/* ENOBUFS, and poll returned without
478*14b2fa6eSchristos 					 * a timeout. Or the retried send call
479*14b2fa6eSchristos 					 * returned ENOBUFS. It is good to
480*14b2fa6eSchristos 					 * wait a bit for the error to clear. */
481*14b2fa6eSchristos 					/* The timeout is 20*(2^(retries+1)),
482*14b2fa6eSchristos 					 * it increases exponentially, starting
483*14b2fa6eSchristos 					 * at 40 msec. After 5 tries, 1240 msec
484*14b2fa6eSchristos 					 * have passed in total, when poll
485*14b2fa6eSchristos 					 * returned the error, and 1200 msec
486*14b2fa6eSchristos 					 * when send returned the errors. */
487*14b2fa6eSchristos #ifndef USE_WINSOCK
488*14b2fa6eSchristos 					pret = poll(NULL, 0, (SEND_BLOCKED_WAIT_TIMEOUT/10)<<(retries+1));
489*14b2fa6eSchristos #else
490*14b2fa6eSchristos 					pret = WSAPoll(NULL, 0, (SEND_BLOCKED_WAIT_TIMEOUT/10)<<(retries+1));
491*14b2fa6eSchristos #endif
492*14b2fa6eSchristos 					if(pret < 0 &&
493*14b2fa6eSchristos #ifndef USE_WINSOCK
494*14b2fa6eSchristos 						errno != EAGAIN && errno != EINTR &&
495*14b2fa6eSchristos #  ifdef EWOULDBLOCK
496*14b2fa6eSchristos 						errno != EWOULDBLOCK &&
497*14b2fa6eSchristos #  endif
498*14b2fa6eSchristos 						errno != ENOBUFS
499*14b2fa6eSchristos #else
500*14b2fa6eSchristos 						WSAGetLastError() != WSAEINPROGRESS &&
501*14b2fa6eSchristos 						WSAGetLastError() != WSAEINTR &&
502*14b2fa6eSchristos 						WSAGetLastError() != WSAENOBUFS &&
503*14b2fa6eSchristos 						WSAGetLastError() != WSAEWOULDBLOCK
504*14b2fa6eSchristos #endif
505*14b2fa6eSchristos 					) {
506*14b2fa6eSchristos 						log_err("poll udp out timer failed: %s",
507*14b2fa6eSchristos 							sock_strerror(errno));
508*14b2fa6eSchristos 					}
509*14b2fa6eSchristos 				}
510*14b2fa6eSchristos #endif /* defined(HAVE_POLL) || defined(USE_WINSOCK) */
511*14b2fa6eSchristos 				retries++;
51216776186Schristos 				if (!is_connected) {
5133b6c3722Schristos 					sent = sendto(c->fd, (void*)sldns_buffer_begin(packet),
5143b6c3722Schristos 						sldns_buffer_remaining(packet), 0,
5153b6c3722Schristos 						addr, addrlen);
51616776186Schristos 				} else {
51716776186Schristos 					sent = send(c->fd, (void*)sldns_buffer_begin(packet),
51816776186Schristos 						sldns_buffer_remaining(packet), 0);
51916776186Schristos 				}
520*14b2fa6eSchristos 			}
5213b6c3722Schristos 		}
5223b6c3722Schristos 	}
5233b6c3722Schristos 	if(sent == -1) {
5243b6c3722Schristos 		if(!udp_send_errno_needs_log(addr, addrlen))
5253b6c3722Schristos 			return 0;
52616776186Schristos 		if (!is_connected) {
52716776186Schristos 			verbose(VERB_OPS, "sendto failed: %s", sock_strerror(errno));
52816776186Schristos 		} else {
52916776186Schristos 			verbose(VERB_OPS, "send failed: %s", sock_strerror(errno));
53016776186Schristos 		}
53116776186Schristos 		if(addr)
5323b6c3722Schristos 			log_addr(VERB_OPS, "remote address is",
5333b6c3722Schristos 				(struct sockaddr_storage*)addr, addrlen);
5343b6c3722Schristos 		return 0;
5353b6c3722Schristos 	} else if((size_t)sent != sldns_buffer_remaining(packet)) {
5363b6c3722Schristos 		log_err("sent %d in place of %d bytes",
5373b6c3722Schristos 			(int)sent, (int)sldns_buffer_remaining(packet));
5383b6c3722Schristos 		return 0;
5393b6c3722Schristos 	}
5403b6c3722Schristos 	return 1;
5413b6c3722Schristos }
5423b6c3722Schristos 
5433b6c3722Schristos #if defined(AF_INET6) && defined(IPV6_PKTINFO) && (defined(HAVE_RECVMSG) || defined(HAVE_SENDMSG))
5443b6c3722Schristos /** print debug ancillary info */
5453b6c3722Schristos static void p_ancil(const char* str, struct comm_reply* r)
5463b6c3722Schristos {
5473b6c3722Schristos 	if(r->srctype != 4 && r->srctype != 6) {
5483b6c3722Schristos 		log_info("%s: unknown srctype %d", str, r->srctype);
5493b6c3722Schristos 		return;
5503b6c3722Schristos 	}
5511481e2a9Schristos 
5523b6c3722Schristos 	if(r->srctype == 6) {
5531481e2a9Schristos #ifdef IPV6_PKTINFO
5543b6c3722Schristos 		char buf[1024];
5553b6c3722Schristos 		if(inet_ntop(AF_INET6, &r->pktinfo.v6info.ipi6_addr,
5563b6c3722Schristos 			buf, (socklen_t)sizeof(buf)) == 0) {
5573b6c3722Schristos 			(void)strlcpy(buf, "(inet_ntop error)", sizeof(buf));
5583b6c3722Schristos 		}
5593b6c3722Schristos 		buf[sizeof(buf)-1]=0;
5603b6c3722Schristos 		log_info("%s: %s %d", str, buf, r->pktinfo.v6info.ipi6_ifindex);
5611481e2a9Schristos #endif
5623b6c3722Schristos 	} else if(r->srctype == 4) {
5633b6c3722Schristos #ifdef IP_PKTINFO
5643b6c3722Schristos 		char buf1[1024], buf2[1024];
5653b6c3722Schristos 		if(inet_ntop(AF_INET, &r->pktinfo.v4info.ipi_addr,
5663b6c3722Schristos 			buf1, (socklen_t)sizeof(buf1)) == 0) {
5673b6c3722Schristos 			(void)strlcpy(buf1, "(inet_ntop error)", sizeof(buf1));
5683b6c3722Schristos 		}
5693b6c3722Schristos 		buf1[sizeof(buf1)-1]=0;
5703b6c3722Schristos #ifdef HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST
5713b6c3722Schristos 		if(inet_ntop(AF_INET, &r->pktinfo.v4info.ipi_spec_dst,
5723b6c3722Schristos 			buf2, (socklen_t)sizeof(buf2)) == 0) {
5733b6c3722Schristos 			(void)strlcpy(buf2, "(inet_ntop error)", sizeof(buf2));
5743b6c3722Schristos 		}
5753b6c3722Schristos 		buf2[sizeof(buf2)-1]=0;
5763b6c3722Schristos #else
5773b6c3722Schristos 		buf2[0]=0;
5783b6c3722Schristos #endif
5793b6c3722Schristos 		log_info("%s: %d %s %s", str, r->pktinfo.v4info.ipi_ifindex,
5803b6c3722Schristos 			buf1, buf2);
5813b6c3722Schristos #elif defined(IP_RECVDSTADDR)
5823b6c3722Schristos 		char buf1[1024];
5833b6c3722Schristos 		if(inet_ntop(AF_INET, &r->pktinfo.v4addr,
5843b6c3722Schristos 			buf1, (socklen_t)sizeof(buf1)) == 0) {
5853b6c3722Schristos 			(void)strlcpy(buf1, "(inet_ntop error)", sizeof(buf1));
5863b6c3722Schristos 		}
5873b6c3722Schristos 		buf1[sizeof(buf1)-1]=0;
5883b6c3722Schristos 		log_info("%s: %s", str, buf1);
5893b6c3722Schristos #endif /* IP_PKTINFO or PI_RECVDSTDADDR */
5903b6c3722Schristos 	}
5913b6c3722Schristos }
5923b6c3722Schristos #endif /* AF_INET6 && IPV6_PKTINFO && HAVE_RECVMSG||HAVE_SENDMSG */
5933b6c3722Schristos 
5943b6c3722Schristos /** send a UDP reply over specified interface*/
5953b6c3722Schristos static int
5963b6c3722Schristos comm_point_send_udp_msg_if(struct comm_point *c, sldns_buffer* packet,
5973b6c3722Schristos 	struct sockaddr* addr, socklen_t addrlen, struct comm_reply* r)
5983b6c3722Schristos {
5993b6c3722Schristos #if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_SENDMSG)
6003b6c3722Schristos 	ssize_t sent;
6013b6c3722Schristos 	struct msghdr msg;
6023b6c3722Schristos 	struct iovec iov[1];
60316776186Schristos 	union {
60416776186Schristos 		struct cmsghdr hdr;
60516776186Schristos 		char buf[256];
60616776186Schristos 	} control;
6073b6c3722Schristos #ifndef S_SPLINT_S
6083b6c3722Schristos 	struct cmsghdr *cmsg;
6093b6c3722Schristos #endif /* S_SPLINT_S */
6103b6c3722Schristos 
6113b6c3722Schristos 	log_assert(c->fd != -1);
6123b6c3722Schristos #ifdef UNBOUND_DEBUG
6133b6c3722Schristos 	if(sldns_buffer_remaining(packet) == 0)
6143b6c3722Schristos 		log_err("error: send empty UDP packet");
6153b6c3722Schristos #endif
6163b6c3722Schristos 	log_assert(addr && addrlen > 0);
6173b6c3722Schristos 
6183b6c3722Schristos 	msg.msg_name = addr;
6193b6c3722Schristos 	msg.msg_namelen = addrlen;
6203b6c3722Schristos 	iov[0].iov_base = sldns_buffer_begin(packet);
6213b6c3722Schristos 	iov[0].iov_len = sldns_buffer_remaining(packet);
6223b6c3722Schristos 	msg.msg_iov = iov;
6233b6c3722Schristos 	msg.msg_iovlen = 1;
62416776186Schristos 	msg.msg_control = control.buf;
6253b6c3722Schristos #ifndef S_SPLINT_S
62616776186Schristos 	msg.msg_controllen = sizeof(control.buf);
6273b6c3722Schristos #endif /* S_SPLINT_S */
6283b6c3722Schristos 	msg.msg_flags = 0;
6293b6c3722Schristos 
6303b6c3722Schristos #ifndef S_SPLINT_S
6313b6c3722Schristos 	cmsg = CMSG_FIRSTHDR(&msg);
6323b6c3722Schristos 	if(r->srctype == 4) {
6333b6c3722Schristos #ifdef IP_PKTINFO
6343b6c3722Schristos 		void* cmsg_data;
6353b6c3722Schristos 		msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
63616776186Schristos 		log_assert(msg.msg_controllen <= sizeof(control.buf));
6373b6c3722Schristos 		cmsg->cmsg_level = IPPROTO_IP;
6383b6c3722Schristos 		cmsg->cmsg_type = IP_PKTINFO;
6393b6c3722Schristos 		memmove(CMSG_DATA(cmsg), &r->pktinfo.v4info,
6403b6c3722Schristos 			sizeof(struct in_pktinfo));
6413b6c3722Schristos 		/* unset the ifindex to not bypass the routing tables */
6423b6c3722Schristos 		cmsg_data = CMSG_DATA(cmsg);
6433b6c3722Schristos 		((struct in_pktinfo *) cmsg_data)->ipi_ifindex = 0;
6443b6c3722Schristos 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
645*14b2fa6eSchristos 		/* zero the padding bytes inserted by the CMSG_LEN */
646*14b2fa6eSchristos 		if(sizeof(struct in_pktinfo) < cmsg->cmsg_len)
647*14b2fa6eSchristos 			memset(((uint8_t*)(CMSG_DATA(cmsg))) +
648*14b2fa6eSchristos 				sizeof(struct in_pktinfo), 0, cmsg->cmsg_len
649*14b2fa6eSchristos 				- sizeof(struct in_pktinfo));
6503b6c3722Schristos #elif defined(IP_SENDSRCADDR)
6513b6c3722Schristos 		msg.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
65216776186Schristos 		log_assert(msg.msg_controllen <= sizeof(control.buf));
6533b6c3722Schristos 		cmsg->cmsg_level = IPPROTO_IP;
6543b6c3722Schristos 		cmsg->cmsg_type = IP_SENDSRCADDR;
6553b6c3722Schristos 		memmove(CMSG_DATA(cmsg), &r->pktinfo.v4addr,
6563b6c3722Schristos 			sizeof(struct in_addr));
6573b6c3722Schristos 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
658*14b2fa6eSchristos 		/* zero the padding bytes inserted by the CMSG_LEN */
659*14b2fa6eSchristos 		if(sizeof(struct in_addr) < cmsg->cmsg_len)
660*14b2fa6eSchristos 			memset(((uint8_t*)(CMSG_DATA(cmsg))) +
661*14b2fa6eSchristos 				sizeof(struct in_addr), 0, cmsg->cmsg_len
662*14b2fa6eSchristos 				- sizeof(struct in_addr));
6633b6c3722Schristos #else
6643b6c3722Schristos 		verbose(VERB_ALGO, "no IP_PKTINFO or IP_SENDSRCADDR");
6653b6c3722Schristos 		msg.msg_control = NULL;
6663b6c3722Schristos #endif /* IP_PKTINFO or IP_SENDSRCADDR */
6673b6c3722Schristos 	} else if(r->srctype == 6) {
6683b6c3722Schristos 		void* cmsg_data;
6693b6c3722Schristos 		msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
67016776186Schristos 		log_assert(msg.msg_controllen <= sizeof(control.buf));
6713b6c3722Schristos 		cmsg->cmsg_level = IPPROTO_IPV6;
6723b6c3722Schristos 		cmsg->cmsg_type = IPV6_PKTINFO;
6733b6c3722Schristos 		memmove(CMSG_DATA(cmsg), &r->pktinfo.v6info,
6743b6c3722Schristos 			sizeof(struct in6_pktinfo));
6753b6c3722Schristos 		/* unset the ifindex to not bypass the routing tables */
6763b6c3722Schristos 		cmsg_data = CMSG_DATA(cmsg);
6773b6c3722Schristos 		((struct in6_pktinfo *) cmsg_data)->ipi6_ifindex = 0;
6783b6c3722Schristos 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
679*14b2fa6eSchristos 		/* zero the padding bytes inserted by the CMSG_LEN */
680*14b2fa6eSchristos 		if(sizeof(struct in6_pktinfo) < cmsg->cmsg_len)
681*14b2fa6eSchristos 			memset(((uint8_t*)(CMSG_DATA(cmsg))) +
682*14b2fa6eSchristos 				sizeof(struct in6_pktinfo), 0, cmsg->cmsg_len
683*14b2fa6eSchristos 				- sizeof(struct in6_pktinfo));
6843b6c3722Schristos 	} else {
6853b6c3722Schristos 		/* try to pass all 0 to use default route */
6863b6c3722Schristos 		msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
68716776186Schristos 		log_assert(msg.msg_controllen <= sizeof(control.buf));
6883b6c3722Schristos 		cmsg->cmsg_level = IPPROTO_IPV6;
6893b6c3722Schristos 		cmsg->cmsg_type = IPV6_PKTINFO;
6903b6c3722Schristos 		memset(CMSG_DATA(cmsg), 0, sizeof(struct in6_pktinfo));
6913b6c3722Schristos 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
692*14b2fa6eSchristos 		/* zero the padding bytes inserted by the CMSG_LEN */
693*14b2fa6eSchristos 		if(sizeof(struct in6_pktinfo) < cmsg->cmsg_len)
694*14b2fa6eSchristos 			memset(((uint8_t*)(CMSG_DATA(cmsg))) +
695*14b2fa6eSchristos 				sizeof(struct in6_pktinfo), 0, cmsg->cmsg_len
696*14b2fa6eSchristos 				- sizeof(struct in6_pktinfo));
6973b6c3722Schristos 	}
6983b6c3722Schristos #endif /* S_SPLINT_S */
699*14b2fa6eSchristos 	if(verbosity >= VERB_ALGO && r->srctype != 0)
7003b6c3722Schristos 		p_ancil("send_udp over interface", r);
7013b6c3722Schristos 	sent = sendmsg(c->fd, &msg, 0);
7023b6c3722Schristos 	if(sent == -1) {
7033b6c3722Schristos 		/* try again and block, waiting for IO to complete,
7043b6c3722Schristos 		 * we want to send the answer, and we will wait for
7053b6c3722Schristos 		 * the ethernet interface buffer to have space. */
7063b6c3722Schristos #ifndef USE_WINSOCK
707*14b2fa6eSchristos 		if(errno == EAGAIN || errno == EINTR ||
7083b6c3722Schristos #  ifdef EWOULDBLOCK
7093b6c3722Schristos 			errno == EWOULDBLOCK ||
7103b6c3722Schristos #  endif
7113b6c3722Schristos 			errno == ENOBUFS) {
7123b6c3722Schristos #else
7133b6c3722Schristos 		if(WSAGetLastError() == WSAEINPROGRESS ||
714*14b2fa6eSchristos 			WSAGetLastError() == WSAEINTR ||
7153b6c3722Schristos 			WSAGetLastError() == WSAENOBUFS ||
7163b6c3722Schristos 			WSAGetLastError() == WSAEWOULDBLOCK) {
7173b6c3722Schristos #endif
718*14b2fa6eSchristos 			int retries = 0;
719*14b2fa6eSchristos 			while(sent == -1 && retries < SEND_BLOCKED_MAX_RETRY && (
720*14b2fa6eSchristos #ifndef USE_WINSOCK
721*14b2fa6eSchristos 				errno == EAGAIN || errno == EINTR ||
722*14b2fa6eSchristos #  ifdef EWOULDBLOCK
723*14b2fa6eSchristos 				errno == EWOULDBLOCK ||
724*14b2fa6eSchristos #  endif
725*14b2fa6eSchristos 				errno == ENOBUFS
726*14b2fa6eSchristos #else
727*14b2fa6eSchristos 				WSAGetLastError() == WSAEINPROGRESS ||
728*14b2fa6eSchristos 				WSAGetLastError() == WSAEINTR ||
729*14b2fa6eSchristos 				WSAGetLastError() == WSAENOBUFS ||
730*14b2fa6eSchristos 				WSAGetLastError() == WSAEWOULDBLOCK
731*14b2fa6eSchristos #endif
732*14b2fa6eSchristos 			)) {
733*14b2fa6eSchristos #if defined(HAVE_POLL) || defined(USE_WINSOCK)
734*14b2fa6eSchristos 				int send_nobufs = (
735*14b2fa6eSchristos #ifndef USE_WINSOCK
736*14b2fa6eSchristos 					errno == ENOBUFS
737*14b2fa6eSchristos #else
738*14b2fa6eSchristos 					WSAGetLastError() == WSAENOBUFS
739*14b2fa6eSchristos #endif
740*14b2fa6eSchristos 				);
741*14b2fa6eSchristos 				struct pollfd p;
742*14b2fa6eSchristos 				int pret;
743*14b2fa6eSchristos 				memset(&p, 0, sizeof(p));
744*14b2fa6eSchristos 				p.fd = c->fd;
745*14b2fa6eSchristos 				p.events = POLLOUT | POLLERR | POLLHUP;
746*14b2fa6eSchristos #  ifndef USE_WINSOCK
747*14b2fa6eSchristos 				pret = poll(&p, 1, SEND_BLOCKED_WAIT_TIMEOUT);
748*14b2fa6eSchristos #  else
749*14b2fa6eSchristos 				pret = WSAPoll(&p, 1,
750*14b2fa6eSchristos 					SEND_BLOCKED_WAIT_TIMEOUT);
751*14b2fa6eSchristos #  endif
752*14b2fa6eSchristos 				if(pret == 0) {
753*14b2fa6eSchristos 					/* timer expired */
754*14b2fa6eSchristos 					struct comm_base* b = c->ev->base;
755*14b2fa6eSchristos 					if(b->eb->last_writewait_log+SLOW_LOG_TIME <=
756*14b2fa6eSchristos 						b->eb->secs) {
757*14b2fa6eSchristos 						b->eb->last_writewait_log = b->eb->secs;
758*14b2fa6eSchristos 						verbose(VERB_OPS, "send udp blocked "
759*14b2fa6eSchristos 							"for long, dropping packet.");
760*14b2fa6eSchristos 					}
761*14b2fa6eSchristos 					return 0;
762*14b2fa6eSchristos 				} else if(pret < 0 &&
763*14b2fa6eSchristos #ifndef USE_WINSOCK
764*14b2fa6eSchristos 					errno != EAGAIN && errno != EINTR &&
765*14b2fa6eSchristos #  ifdef EWOULDBLOCK
766*14b2fa6eSchristos 					errno != EWOULDBLOCK &&
767*14b2fa6eSchristos #  endif
768*14b2fa6eSchristos 					errno != ENOBUFS
769*14b2fa6eSchristos #else
770*14b2fa6eSchristos 					WSAGetLastError() != WSAEINPROGRESS &&
771*14b2fa6eSchristos 					WSAGetLastError() != WSAEINTR &&
772*14b2fa6eSchristos 					WSAGetLastError() != WSAENOBUFS &&
773*14b2fa6eSchristos 					WSAGetLastError() != WSAEWOULDBLOCK
774*14b2fa6eSchristos #endif
775*14b2fa6eSchristos 					) {
776*14b2fa6eSchristos 					log_err("poll udp out failed: %s",
777*14b2fa6eSchristos 						sock_strerror(errno));
778*14b2fa6eSchristos 					return 0;
779*14b2fa6eSchristos 				} else if((pret < 0 &&
780*14b2fa6eSchristos #ifndef USE_WINSOCK
781*14b2fa6eSchristos 					errno == ENOBUFS
782*14b2fa6eSchristos #else
783*14b2fa6eSchristos 					WSAGetLastError() == WSAENOBUFS
784*14b2fa6eSchristos #endif
785*14b2fa6eSchristos 					) || (send_nobufs && retries > 0)) {
786*14b2fa6eSchristos 					/* ENOBUFS, and poll returned without
787*14b2fa6eSchristos 					 * a timeout. Or the retried send call
788*14b2fa6eSchristos 					 * returned ENOBUFS. It is good to
789*14b2fa6eSchristos 					 * wait a bit for the error to clear. */
790*14b2fa6eSchristos 					/* The timeout is 20*(2^(retries+1)),
791*14b2fa6eSchristos 					 * it increases exponentially, starting
792*14b2fa6eSchristos 					 * at 40 msec. After 5 tries, 1240 msec
793*14b2fa6eSchristos 					 * have passed in total, when poll
794*14b2fa6eSchristos 					 * returned the error, and 1200 msec
795*14b2fa6eSchristos 					 * when send returned the errors. */
796*14b2fa6eSchristos #ifndef USE_WINSOCK
797*14b2fa6eSchristos 					pret = poll(NULL, 0, (SEND_BLOCKED_WAIT_TIMEOUT/10)<<(retries+1));
798*14b2fa6eSchristos #else
799*14b2fa6eSchristos 					pret = WSAPoll(NULL, 0, (SEND_BLOCKED_WAIT_TIMEOUT/10)<<(retries+1));
800*14b2fa6eSchristos #endif
801*14b2fa6eSchristos 					if(pret < 0 &&
802*14b2fa6eSchristos #ifndef USE_WINSOCK
803*14b2fa6eSchristos 						errno != EAGAIN && errno != EINTR &&
804*14b2fa6eSchristos #  ifdef EWOULDBLOCK
805*14b2fa6eSchristos 						errno != EWOULDBLOCK &&
806*14b2fa6eSchristos #  endif
807*14b2fa6eSchristos 						errno != ENOBUFS
808*14b2fa6eSchristos #else
809*14b2fa6eSchristos 						WSAGetLastError() != WSAEINPROGRESS &&
810*14b2fa6eSchristos 						WSAGetLastError() != WSAEINTR &&
811*14b2fa6eSchristos 						WSAGetLastError() != WSAENOBUFS &&
812*14b2fa6eSchristos 						WSAGetLastError() != WSAEWOULDBLOCK
813*14b2fa6eSchristos #endif
814*14b2fa6eSchristos 					) {
815*14b2fa6eSchristos 						log_err("poll udp out timer failed: %s",
816*14b2fa6eSchristos 							sock_strerror(errno));
817*14b2fa6eSchristos 					}
818*14b2fa6eSchristos 				}
819*14b2fa6eSchristos #endif /* defined(HAVE_POLL) || defined(USE_WINSOCK) */
820*14b2fa6eSchristos 				retries++;
8213b6c3722Schristos 				sent = sendmsg(c->fd, &msg, 0);
822*14b2fa6eSchristos 			}
8233b6c3722Schristos 		}
8243b6c3722Schristos 	}
8253b6c3722Schristos 	if(sent == -1) {
8263b6c3722Schristos 		if(!udp_send_errno_needs_log(addr, addrlen))
8273b6c3722Schristos 			return 0;
8283b6c3722Schristos 		verbose(VERB_OPS, "sendmsg failed: %s", strerror(errno));
8293b6c3722Schristos 		log_addr(VERB_OPS, "remote address is",
8303b6c3722Schristos 			(struct sockaddr_storage*)addr, addrlen);
8313b6c3722Schristos #ifdef __NetBSD__
8323b6c3722Schristos 		/* netbsd 7 has IP_PKTINFO for recv but not send */
8333b6c3722Schristos 		if(errno == EINVAL && r->srctype == 4)
8343b6c3722Schristos 			log_err("sendmsg: No support for sendmsg(IP_PKTINFO). "
8353b6c3722Schristos 				"Please disable interface-automatic");
8363b6c3722Schristos #endif
8373b6c3722Schristos 		return 0;
8383b6c3722Schristos 	} else if((size_t)sent != sldns_buffer_remaining(packet)) {
8393b6c3722Schristos 		log_err("sent %d in place of %d bytes",
8403b6c3722Schristos 			(int)sent, (int)sldns_buffer_remaining(packet));
8413b6c3722Schristos 		return 0;
8423b6c3722Schristos 	}
8433b6c3722Schristos 	return 1;
8443b6c3722Schristos #else
8453b6c3722Schristos 	(void)c;
8463b6c3722Schristos 	(void)packet;
8473b6c3722Schristos 	(void)addr;
8483b6c3722Schristos 	(void)addrlen;
8493b6c3722Schristos 	(void)r;
8503b6c3722Schristos 	log_err("sendmsg: IPV6_PKTINFO not supported");
8513b6c3722Schristos 	return 0;
8523b6c3722Schristos #endif /* AF_INET6 && IPV6_PKTINFO && HAVE_SENDMSG */
8533b6c3722Schristos }
8543b6c3722Schristos 
85516776186Schristos /** return true is UDP receive error needs to be logged */
85616776186Schristos static int udp_recv_needs_log(int err)
85716776186Schristos {
85816776186Schristos 	switch(err) {
85916776186Schristos 	case EACCES: /* some hosts send ICMP 'Permission Denied' */
86016776186Schristos #ifndef USE_WINSOCK
86116776186Schristos 	case ECONNREFUSED:
86216776186Schristos #  ifdef ENETUNREACH
86316776186Schristos 	case ENETUNREACH:
86416776186Schristos #  endif
86516776186Schristos #  ifdef EHOSTDOWN
86616776186Schristos 	case EHOSTDOWN:
86716776186Schristos #  endif
86816776186Schristos #  ifdef EHOSTUNREACH
86916776186Schristos 	case EHOSTUNREACH:
87016776186Schristos #  endif
87116776186Schristos #  ifdef ENETDOWN
87216776186Schristos 	case ENETDOWN:
87316776186Schristos #  endif
87416776186Schristos #else /* USE_WINSOCK */
87516776186Schristos 	case WSAECONNREFUSED:
87616776186Schristos 	case WSAENETUNREACH:
87716776186Schristos 	case WSAEHOSTDOWN:
87816776186Schristos 	case WSAEHOSTUNREACH:
87916776186Schristos 	case WSAENETDOWN:
88016776186Schristos #endif
88116776186Schristos 		if(verbosity >= VERB_ALGO)
88216776186Schristos 			return 1;
88316776186Schristos 		return 0;
88416776186Schristos 	default:
88516776186Schristos 		break;
88616776186Schristos 	}
88716776186Schristos 	return 1;
88816776186Schristos }
88916776186Schristos 
890*14b2fa6eSchristos /** Parses the PROXYv2 header from buf and updates the comm_reply struct.
891*14b2fa6eSchristos  *  Returns 1 on success, 0 on failure. */
892*14b2fa6eSchristos static int consume_pp2_header(struct sldns_buffer* buf, struct comm_reply* rep,
893*14b2fa6eSchristos 	int stream) {
894*14b2fa6eSchristos 	size_t size;
895*14b2fa6eSchristos 	struct pp2_header *header;
896*14b2fa6eSchristos 	int err = pp2_read_header(sldns_buffer_begin(buf),
897*14b2fa6eSchristos 		sldns_buffer_remaining(buf));
898*14b2fa6eSchristos 	if(err) return 0;
899*14b2fa6eSchristos 	header = (struct pp2_header*)sldns_buffer_begin(buf);
900*14b2fa6eSchristos 	size = PP2_HEADER_SIZE + ntohs(header->len);
901*14b2fa6eSchristos 	if((header->ver_cmd & 0xF) == PP2_CMD_LOCAL) {
902*14b2fa6eSchristos 		/* A connection from the proxy itself.
903*14b2fa6eSchristos 		 * No need to do anything with addresses. */
904*14b2fa6eSchristos 		goto done;
905*14b2fa6eSchristos 	}
906*14b2fa6eSchristos 	if(header->fam_prot == PP2_UNSPEC_UNSPEC) {
907*14b2fa6eSchristos 		/* Unspecified family and protocol. This could be used for
908*14b2fa6eSchristos 		 * health checks by proxies.
909*14b2fa6eSchristos 		 * No need to do anything with addresses. */
910*14b2fa6eSchristos 		goto done;
911*14b2fa6eSchristos 	}
912*14b2fa6eSchristos 	/* Read the proxied address */
913*14b2fa6eSchristos 	switch(header->fam_prot) {
914*14b2fa6eSchristos 		case PP2_INET_STREAM:
915*14b2fa6eSchristos 		case PP2_INET_DGRAM:
916*14b2fa6eSchristos 			{
917*14b2fa6eSchristos 			struct sockaddr_in* addr =
918*14b2fa6eSchristos 				(struct sockaddr_in*)&rep->client_addr;
919*14b2fa6eSchristos 			addr->sin_family = AF_INET;
920*14b2fa6eSchristos 			addr->sin_addr.s_addr = header->addr.addr4.src_addr;
921*14b2fa6eSchristos 			addr->sin_port = header->addr.addr4.src_port;
922*14b2fa6eSchristos 			rep->client_addrlen = (socklen_t)sizeof(struct sockaddr_in);
923*14b2fa6eSchristos 			}
924*14b2fa6eSchristos 			/* Ignore the destination address; it should be us. */
925*14b2fa6eSchristos 			break;
926*14b2fa6eSchristos 		case PP2_INET6_STREAM:
927*14b2fa6eSchristos 		case PP2_INET6_DGRAM:
928*14b2fa6eSchristos 			{
929*14b2fa6eSchristos 			struct sockaddr_in6* addr =
930*14b2fa6eSchristos 				(struct sockaddr_in6*)&rep->client_addr;
931*14b2fa6eSchristos 			memset(addr, 0, sizeof(*addr));
932*14b2fa6eSchristos 			addr->sin6_family = AF_INET6;
933*14b2fa6eSchristos 			memcpy(&addr->sin6_addr,
934*14b2fa6eSchristos 				header->addr.addr6.src_addr, 16);
935*14b2fa6eSchristos 			addr->sin6_port = header->addr.addr6.src_port;
936*14b2fa6eSchristos 			rep->client_addrlen = (socklen_t)sizeof(struct sockaddr_in6);
937*14b2fa6eSchristos 			}
938*14b2fa6eSchristos 			/* Ignore the destination address; it should be us. */
939*14b2fa6eSchristos 			break;
940*14b2fa6eSchristos 		default:
941*14b2fa6eSchristos 			log_err("proxy_protocol: unsupported family and "
942*14b2fa6eSchristos 				"protocol 0x%x", (int)header->fam_prot);
943*14b2fa6eSchristos 			return 0;
944*14b2fa6eSchristos 	}
945*14b2fa6eSchristos 	rep->is_proxied = 1;
946*14b2fa6eSchristos done:
947*14b2fa6eSchristos 	if(!stream) {
948*14b2fa6eSchristos 		/* We are reading a whole packet;
949*14b2fa6eSchristos 		 * Move the rest of the data to overwrite the PROXYv2 header */
950*14b2fa6eSchristos 		/* XXX can we do better to avoid memmove? */
951*14b2fa6eSchristos 		memmove(header, ((char*)header)+size,
952*14b2fa6eSchristos 			sldns_buffer_limit(buf)-size);
953*14b2fa6eSchristos 		sldns_buffer_set_limit(buf, sldns_buffer_limit(buf)-size);
954*14b2fa6eSchristos 	}
955*14b2fa6eSchristos 	return 1;
956*14b2fa6eSchristos }
957*14b2fa6eSchristos 
958*14b2fa6eSchristos #if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG)
9593b6c3722Schristos void
9603b6c3722Schristos comm_point_udp_ancil_callback(int fd, short event, void* arg)
9613b6c3722Schristos {
9623b6c3722Schristos 	struct comm_reply rep;
9633b6c3722Schristos 	struct msghdr msg;
9643b6c3722Schristos 	struct iovec iov[1];
9653b6c3722Schristos 	ssize_t rcv;
96616776186Schristos 	union {
96716776186Schristos 		struct cmsghdr hdr;
96816776186Schristos 		char buf[256];
96916776186Schristos 	} ancil;
9703b6c3722Schristos 	int i;
9713b6c3722Schristos #ifndef S_SPLINT_S
9723b6c3722Schristos 	struct cmsghdr* cmsg;
9733b6c3722Schristos #endif /* S_SPLINT_S */
974*14b2fa6eSchristos #ifdef HAVE_LINUX_NET_TSTAMP_H
975*14b2fa6eSchristos 	struct timespec *ts;
976*14b2fa6eSchristos #endif /* HAVE_LINUX_NET_TSTAMP_H */
9773b6c3722Schristos 
9783b6c3722Schristos 	rep.c = (struct comm_point*)arg;
9793b6c3722Schristos 	log_assert(rep.c->type == comm_udp);
9803b6c3722Schristos 
9813b6c3722Schristos 	if(!(event&UB_EV_READ))
9823b6c3722Schristos 		return;
9833b6c3722Schristos 	log_assert(rep.c && rep.c->buffer && rep.c->fd == fd);
9843b6c3722Schristos 	ub_comm_base_now(rep.c->ev->base);
9853b6c3722Schristos 	for(i=0; i<NUM_UDP_PER_SELECT; i++) {
9863b6c3722Schristos 		sldns_buffer_clear(rep.c->buffer);
987*14b2fa6eSchristos 		timeval_clear(&rep.c->recv_tv);
988*14b2fa6eSchristos 		rep.remote_addrlen = (socklen_t)sizeof(rep.remote_addr);
9893b6c3722Schristos 		log_assert(fd != -1);
9903b6c3722Schristos 		log_assert(sldns_buffer_remaining(rep.c->buffer) > 0);
991*14b2fa6eSchristos 		msg.msg_name = &rep.remote_addr;
992*14b2fa6eSchristos 		msg.msg_namelen = (socklen_t)sizeof(rep.remote_addr);
9933b6c3722Schristos 		iov[0].iov_base = sldns_buffer_begin(rep.c->buffer);
9943b6c3722Schristos 		iov[0].iov_len = sldns_buffer_remaining(rep.c->buffer);
9953b6c3722Schristos 		msg.msg_iov = iov;
9963b6c3722Schristos 		msg.msg_iovlen = 1;
99716776186Schristos 		msg.msg_control = ancil.buf;
9983b6c3722Schristos #ifndef S_SPLINT_S
99916776186Schristos 		msg.msg_controllen = sizeof(ancil.buf);
10003b6c3722Schristos #endif /* S_SPLINT_S */
10013b6c3722Schristos 		msg.msg_flags = 0;
1002*14b2fa6eSchristos 		rcv = recvmsg(fd, &msg, MSG_DONTWAIT);
10033b6c3722Schristos 		if(rcv == -1) {
100416776186Schristos 			if(errno != EAGAIN && errno != EINTR
100516776186Schristos 				&& udp_recv_needs_log(errno)) {
10063b6c3722Schristos 				log_err("recvmsg failed: %s", strerror(errno));
10073b6c3722Schristos 			}
10083b6c3722Schristos 			return;
10093b6c3722Schristos 		}
1010*14b2fa6eSchristos 		rep.remote_addrlen = msg.msg_namelen;
10113b6c3722Schristos 		sldns_buffer_skip(rep.c->buffer, rcv);
10123b6c3722Schristos 		sldns_buffer_flip(rep.c->buffer);
10133b6c3722Schristos 		rep.srctype = 0;
1014*14b2fa6eSchristos 		rep.is_proxied = 0;
10153b6c3722Schristos #ifndef S_SPLINT_S
10163b6c3722Schristos 		for(cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
10173b6c3722Schristos 			cmsg = CMSG_NXTHDR(&msg, cmsg)) {
10183b6c3722Schristos 			if( cmsg->cmsg_level == IPPROTO_IPV6 &&
10193b6c3722Schristos 				cmsg->cmsg_type == IPV6_PKTINFO) {
10203b6c3722Schristos 				rep.srctype = 6;
10213b6c3722Schristos 				memmove(&rep.pktinfo.v6info, CMSG_DATA(cmsg),
10223b6c3722Schristos 					sizeof(struct in6_pktinfo));
10233b6c3722Schristos 				break;
10243b6c3722Schristos #ifdef IP_PKTINFO
10253b6c3722Schristos 			} else if( cmsg->cmsg_level == IPPROTO_IP &&
10263b6c3722Schristos 				cmsg->cmsg_type == IP_PKTINFO) {
10273b6c3722Schristos 				rep.srctype = 4;
10283b6c3722Schristos 				memmove(&rep.pktinfo.v4info, CMSG_DATA(cmsg),
10293b6c3722Schristos 					sizeof(struct in_pktinfo));
10303b6c3722Schristos 				break;
10313b6c3722Schristos #elif defined(IP_RECVDSTADDR)
10323b6c3722Schristos 			} else if( cmsg->cmsg_level == IPPROTO_IP &&
10333b6c3722Schristos 				cmsg->cmsg_type == IP_RECVDSTADDR) {
10343b6c3722Schristos 				rep.srctype = 4;
10353b6c3722Schristos 				memmove(&rep.pktinfo.v4addr, CMSG_DATA(cmsg),
10363b6c3722Schristos 					sizeof(struct in_addr));
10373b6c3722Schristos 				break;
10383b6c3722Schristos #endif /* IP_PKTINFO or IP_RECVDSTADDR */
1039*14b2fa6eSchristos #ifdef HAVE_LINUX_NET_TSTAMP_H
1040*14b2fa6eSchristos 			} else if( cmsg->cmsg_level == SOL_SOCKET &&
1041*14b2fa6eSchristos 				cmsg->cmsg_type == SO_TIMESTAMPNS) {
1042*14b2fa6eSchristos 				ts = (struct timespec *)CMSG_DATA(cmsg);
1043*14b2fa6eSchristos 				TIMESPEC_TO_TIMEVAL(&rep.c->recv_tv, ts);
1044*14b2fa6eSchristos 			} else if( cmsg->cmsg_level == SOL_SOCKET &&
1045*14b2fa6eSchristos 				cmsg->cmsg_type == SO_TIMESTAMPING) {
1046*14b2fa6eSchristos 				ts = (struct timespec *)CMSG_DATA(cmsg);
1047*14b2fa6eSchristos 				TIMESPEC_TO_TIMEVAL(&rep.c->recv_tv, ts);
1048*14b2fa6eSchristos 			} else if( cmsg->cmsg_level == SOL_SOCKET &&
1049*14b2fa6eSchristos 				cmsg->cmsg_type == SO_TIMESTAMP) {
1050*14b2fa6eSchristos 				memmove(&rep.c->recv_tv, CMSG_DATA(cmsg), sizeof(struct timeval));
1051*14b2fa6eSchristos #endif /* HAVE_LINUX_NET_TSTAMP_H */
10523b6c3722Schristos 			}
10533b6c3722Schristos 		}
1054*14b2fa6eSchristos 
1055*14b2fa6eSchristos 		if(verbosity >= VERB_ALGO && rep.srctype != 0)
10563b6c3722Schristos 			p_ancil("receive_udp on interface", &rep);
10573b6c3722Schristos #endif /* S_SPLINT_S */
1058*14b2fa6eSchristos 
1059*14b2fa6eSchristos 		if(rep.c->pp2_enabled && !consume_pp2_header(rep.c->buffer,
1060*14b2fa6eSchristos 			&rep, 0)) {
1061*14b2fa6eSchristos 			log_err("proxy_protocol: could not consume PROXYv2 header");
1062*14b2fa6eSchristos 			return;
1063*14b2fa6eSchristos 		}
1064*14b2fa6eSchristos 		if(!rep.is_proxied) {
1065*14b2fa6eSchristos 			rep.client_addrlen = rep.remote_addrlen;
1066*14b2fa6eSchristos 			memmove(&rep.client_addr, &rep.remote_addr,
1067*14b2fa6eSchristos 				rep.remote_addrlen);
1068*14b2fa6eSchristos 		}
1069*14b2fa6eSchristos 
10703b6c3722Schristos 		fptr_ok(fptr_whitelist_comm_point(rep.c->callback));
10713b6c3722Schristos 		if((*rep.c->callback)(rep.c, rep.c->cb_arg, NETEVENT_NOERROR, &rep)) {
10723b6c3722Schristos 			/* send back immediate reply */
1073*14b2fa6eSchristos 			struct sldns_buffer *buffer;
1074*14b2fa6eSchristos #ifdef USE_DNSCRYPT
1075*14b2fa6eSchristos 			buffer = rep.c->dnscrypt_buffer;
1076*14b2fa6eSchristos #else
1077*14b2fa6eSchristos 			buffer = rep.c->buffer;
1078*14b2fa6eSchristos #endif
1079*14b2fa6eSchristos 			(void)comm_point_send_udp_msg_if(rep.c, buffer,
1080*14b2fa6eSchristos 				(struct sockaddr*)&rep.remote_addr,
1081*14b2fa6eSchristos 				rep.remote_addrlen, &rep);
10823b6c3722Schristos 		}
10837cd94d69Schristos 		if(!rep.c || rep.c->fd == -1) /* commpoint closed */
10843b6c3722Schristos 			break;
10853b6c3722Schristos 	}
10863b6c3722Schristos }
1087*14b2fa6eSchristos #endif /* AF_INET6 && IPV6_PKTINFO && HAVE_RECVMSG */
10883b6c3722Schristos 
10893b6c3722Schristos void
10903b6c3722Schristos comm_point_udp_callback(int fd, short event, void* arg)
10913b6c3722Schristos {
10923b6c3722Schristos 	struct comm_reply rep;
10933b6c3722Schristos 	ssize_t rcv;
10943b6c3722Schristos 	int i;
10950cd9f4ecSchristos 	struct sldns_buffer *buffer;
10963b6c3722Schristos 
10973b6c3722Schristos 	rep.c = (struct comm_point*)arg;
10983b6c3722Schristos 	log_assert(rep.c->type == comm_udp);
10993b6c3722Schristos 
11003b6c3722Schristos 	if(!(event&UB_EV_READ))
11013b6c3722Schristos 		return;
11023b6c3722Schristos 	log_assert(rep.c && rep.c->buffer && rep.c->fd == fd);
11033b6c3722Schristos 	ub_comm_base_now(rep.c->ev->base);
11043b6c3722Schristos 	for(i=0; i<NUM_UDP_PER_SELECT; i++) {
11053b6c3722Schristos 		sldns_buffer_clear(rep.c->buffer);
1106*14b2fa6eSchristos 		rep.remote_addrlen = (socklen_t)sizeof(rep.remote_addr);
11073b6c3722Schristos 		log_assert(fd != -1);
11083b6c3722Schristos 		log_assert(sldns_buffer_remaining(rep.c->buffer) > 0);
11093b6c3722Schristos 		rcv = recvfrom(fd, (void*)sldns_buffer_begin(rep.c->buffer),
1110*14b2fa6eSchristos 			sldns_buffer_remaining(rep.c->buffer), MSG_DONTWAIT,
1111*14b2fa6eSchristos 			(struct sockaddr*)&rep.remote_addr, &rep.remote_addrlen);
11123b6c3722Schristos 		if(rcv == -1) {
11133b6c3722Schristos #ifndef USE_WINSOCK
111416776186Schristos 			if(errno != EAGAIN && errno != EINTR
111516776186Schristos 				&& udp_recv_needs_log(errno))
11163b6c3722Schristos 				log_err("recvfrom %d failed: %s",
11173b6c3722Schristos 					fd, strerror(errno));
11183b6c3722Schristos #else
11193b6c3722Schristos 			if(WSAGetLastError() != WSAEINPROGRESS &&
11203b6c3722Schristos 				WSAGetLastError() != WSAECONNRESET &&
112116776186Schristos 				WSAGetLastError()!= WSAEWOULDBLOCK &&
112216776186Schristos 				udp_recv_needs_log(WSAGetLastError()))
11233b6c3722Schristos 				log_err("recvfrom failed: %s",
11243b6c3722Schristos 					wsa_strerror(WSAGetLastError()));
11253b6c3722Schristos #endif
11263b6c3722Schristos 			return;
11273b6c3722Schristos 		}
11283b6c3722Schristos 		sldns_buffer_skip(rep.c->buffer, rcv);
11293b6c3722Schristos 		sldns_buffer_flip(rep.c->buffer);
11303b6c3722Schristos 		rep.srctype = 0;
1131*14b2fa6eSchristos 		rep.is_proxied = 0;
1132*14b2fa6eSchristos 
1133*14b2fa6eSchristos 		if(rep.c->pp2_enabled && !consume_pp2_header(rep.c->buffer,
1134*14b2fa6eSchristos 			&rep, 0)) {
1135*14b2fa6eSchristos 			log_err("proxy_protocol: could not consume PROXYv2 header");
1136*14b2fa6eSchristos 			return;
1137*14b2fa6eSchristos 		}
1138*14b2fa6eSchristos 		if(!rep.is_proxied) {
1139*14b2fa6eSchristos 			rep.client_addrlen = rep.remote_addrlen;
1140*14b2fa6eSchristos 			memmove(&rep.client_addr, &rep.remote_addr,
1141*14b2fa6eSchristos 				rep.remote_addrlen);
1142*14b2fa6eSchristos 		}
1143*14b2fa6eSchristos 
11443b6c3722Schristos 		fptr_ok(fptr_whitelist_comm_point(rep.c->callback));
11453b6c3722Schristos 		if((*rep.c->callback)(rep.c, rep.c->cb_arg, NETEVENT_NOERROR, &rep)) {
11463b6c3722Schristos 			/* send back immediate reply */
11470cd9f4ecSchristos #ifdef USE_DNSCRYPT
11480cd9f4ecSchristos 			buffer = rep.c->dnscrypt_buffer;
11490cd9f4ecSchristos #else
11500cd9f4ecSchristos 			buffer = rep.c->buffer;
11510cd9f4ecSchristos #endif
11520cd9f4ecSchristos 			(void)comm_point_send_udp_msg(rep.c, buffer,
1153*14b2fa6eSchristos 				(struct sockaddr*)&rep.remote_addr,
1154*14b2fa6eSchristos 				rep.remote_addrlen, 0);
11553b6c3722Schristos 		}
11567cd94d69Schristos 		if(!rep.c || rep.c->fd != fd) /* commpoint closed to -1 or reused for
11573b6c3722Schristos 		another UDP port. Note rep.c cannot be reused with TCP fd. */
11583b6c3722Schristos 			break;
11593b6c3722Schristos 	}
11603b6c3722Schristos }
11613b6c3722Schristos 
116216776186Schristos int adjusted_tcp_timeout(struct comm_point* c)
116316776186Schristos {
116416776186Schristos 	if(c->tcp_timeout_msec < TCP_QUERY_TIMEOUT_MINIMUM)
116516776186Schristos 		return TCP_QUERY_TIMEOUT_MINIMUM;
116616776186Schristos 	return c->tcp_timeout_msec;
116716776186Schristos }
116816776186Schristos 
11693b6c3722Schristos /** Use a new tcp handler for new query fd, set to read query */
11703b6c3722Schristos static void
11710cd9f4ecSchristos setup_tcp_handler(struct comm_point* c, int fd, int cur, int max)
11723b6c3722Schristos {
1173f42d8de7Schristos 	int handler_usage;
117416776186Schristos 	log_assert(c->type == comm_tcp || c->type == comm_http);
11753b6c3722Schristos 	log_assert(c->fd == -1);
11763b6c3722Schristos 	sldns_buffer_clear(c->buffer);
11770cd9f4ecSchristos #ifdef USE_DNSCRYPT
11780cd9f4ecSchristos 	if (c->dnscrypt)
11790cd9f4ecSchristos 		sldns_buffer_clear(c->dnscrypt_buffer);
11800cd9f4ecSchristos #endif
11813b6c3722Schristos 	c->tcp_is_reading = 1;
11823b6c3722Schristos 	c->tcp_byte_count = 0;
11831481e2a9Schristos 	c->tcp_keepalive = 0;
11840cd9f4ecSchristos 	/* if more than half the tcp handlers are in use, use a shorter
11850cd9f4ecSchristos 	 * timeout for this TCP connection, we need to make space for
11860cd9f4ecSchristos 	 * other connections to be able to get attention */
1187f42d8de7Schristos 	/* If > 50% TCP handler structures in use, set timeout to 1/100th
1188f42d8de7Schristos 	 * 	configured value.
1189f42d8de7Schristos 	 * If > 65%TCP handler structures in use, set to 1/500th configured
1190f42d8de7Schristos 	 * 	value.
1191f42d8de7Schristos 	 * If > 80% TCP handler structures in use, set to 0.
1192f42d8de7Schristos 	 *
1193f42d8de7Schristos 	 * If the timeout to use falls below 200 milliseconds, an actual
1194f42d8de7Schristos 	 * timeout of 200ms is used.
1195f42d8de7Schristos 	 */
1196f42d8de7Schristos 	handler_usage = (cur * 100) / max;
1197f42d8de7Schristos 	if(handler_usage > 50 && handler_usage <= 65)
1198f42d8de7Schristos 		c->tcp_timeout_msec /= 100;
1199f42d8de7Schristos 	else if (handler_usage > 65 && handler_usage <= 80)
1200f42d8de7Schristos 		c->tcp_timeout_msec /= 500;
1201f42d8de7Schristos 	else if (handler_usage > 80)
1202f42d8de7Schristos 		c->tcp_timeout_msec = 0;
120316776186Schristos 	comm_point_start_listening(c, fd, adjusted_tcp_timeout(c));
12043b6c3722Schristos }
12053b6c3722Schristos 
12063b6c3722Schristos void comm_base_handle_slow_accept(int ATTR_UNUSED(fd),
12073b6c3722Schristos 	short ATTR_UNUSED(event), void* arg)
12083b6c3722Schristos {
12093b6c3722Schristos 	struct comm_base* b = (struct comm_base*)arg;
12103b6c3722Schristos 	/* timeout for the slow accept, re-enable accepts again */
12113b6c3722Schristos 	if(b->start_accept) {
12123b6c3722Schristos 		verbose(VERB_ALGO, "wait is over, slow accept disabled");
12133b6c3722Schristos 		fptr_ok(fptr_whitelist_start_accept(b->start_accept));
12143b6c3722Schristos 		(*b->start_accept)(b->cb_arg);
12153b6c3722Schristos 		b->eb->slow_accept_enabled = 0;
12163b6c3722Schristos 	}
12173b6c3722Schristos }
12183b6c3722Schristos 
12193b6c3722Schristos int comm_point_perform_accept(struct comm_point* c,
12203b6c3722Schristos 	struct sockaddr_storage* addr, socklen_t* addrlen)
12213b6c3722Schristos {
12223b6c3722Schristos 	int new_fd;
12233b6c3722Schristos 	*addrlen = (socklen_t)sizeof(*addr);
12247cd94d69Schristos #ifndef HAVE_ACCEPT4
12253b6c3722Schristos 	new_fd = accept(c->fd, (struct sockaddr*)addr, addrlen);
12267cd94d69Schristos #else
12277cd94d69Schristos 	/* SOCK_NONBLOCK saves extra calls to fcntl for the same result */
12287cd94d69Schristos 	new_fd = accept4(c->fd, (struct sockaddr*)addr, addrlen, SOCK_NONBLOCK);
12297cd94d69Schristos #endif
12303b6c3722Schristos 	if(new_fd == -1) {
12313b6c3722Schristos #ifndef USE_WINSOCK
12323b6c3722Schristos 		/* EINTR is signal interrupt. others are closed connection. */
12333b6c3722Schristos 		if(	errno == EINTR || errno == EAGAIN
12343b6c3722Schristos #ifdef EWOULDBLOCK
12353b6c3722Schristos 			|| errno == EWOULDBLOCK
12363b6c3722Schristos #endif
12373b6c3722Schristos #ifdef ECONNABORTED
12383b6c3722Schristos 			|| errno == ECONNABORTED
12393b6c3722Schristos #endif
12403b6c3722Schristos #ifdef EPROTO
12413b6c3722Schristos 			|| errno == EPROTO
12423b6c3722Schristos #endif /* EPROTO */
12433b6c3722Schristos 			)
12443b6c3722Schristos 			return -1;
12453b6c3722Schristos #if defined(ENFILE) && defined(EMFILE)
12463b6c3722Schristos 		if(errno == ENFILE || errno == EMFILE) {
12473b6c3722Schristos 			/* out of file descriptors, likely outside of our
12483b6c3722Schristos 			 * control. stop accept() calls for some time */
12493b6c3722Schristos 			if(c->ev->base->stop_accept) {
12503b6c3722Schristos 				struct comm_base* b = c->ev->base;
12513b6c3722Schristos 				struct timeval tv;
12523b6c3722Schristos 				verbose(VERB_ALGO, "out of file descriptors: "
12533b6c3722Schristos 					"slow accept");
1254*14b2fa6eSchristos 				ub_comm_base_now(b);
1255*14b2fa6eSchristos 				if(b->eb->last_slow_log+SLOW_LOG_TIME <=
1256*14b2fa6eSchristos 					b->eb->secs) {
1257*14b2fa6eSchristos 					b->eb->last_slow_log = b->eb->secs;
1258*14b2fa6eSchristos 					verbose(VERB_OPS, "accept failed, "
1259*14b2fa6eSchristos 						"slow down accept for %d "
1260*14b2fa6eSchristos 						"msec: %s",
1261*14b2fa6eSchristos 						NETEVENT_SLOW_ACCEPT_TIME,
1262*14b2fa6eSchristos 						sock_strerror(errno));
1263*14b2fa6eSchristos 				}
12643b6c3722Schristos 				b->eb->slow_accept_enabled = 1;
12653b6c3722Schristos 				fptr_ok(fptr_whitelist_stop_accept(
12663b6c3722Schristos 					b->stop_accept));
12673b6c3722Schristos 				(*b->stop_accept)(b->cb_arg);
12683b6c3722Schristos 				/* set timeout, no mallocs */
12693b6c3722Schristos 				tv.tv_sec = NETEVENT_SLOW_ACCEPT_TIME/1000;
12700cd9f4ecSchristos 				tv.tv_usec = (NETEVENT_SLOW_ACCEPT_TIME%1000)*1000;
12713b6c3722Schristos 				b->eb->slow_accept = ub_event_new(b->eb->base,
12723b6c3722Schristos 					-1, UB_EV_TIMEOUT,
12733b6c3722Schristos 					comm_base_handle_slow_accept, b);
12743b6c3722Schristos 				if(b->eb->slow_accept == NULL) {
12753b6c3722Schristos 					/* we do not want to log here, because
12763b6c3722Schristos 					 * that would spam the logfiles.
12773b6c3722Schristos 					 * error: "event_base_set failed." */
12783b6c3722Schristos 				}
12793b6c3722Schristos 				else if(ub_event_add(b->eb->slow_accept, &tv)
12803b6c3722Schristos 					!= 0) {
12813b6c3722Schristos 					/* we do not want to log here,
12823b6c3722Schristos 					 * error: "event_add failed." */
12833b6c3722Schristos 				}
1284*14b2fa6eSchristos 			} else {
1285*14b2fa6eSchristos 				log_err("accept, with no slow down, "
1286*14b2fa6eSchristos 					"failed: %s", sock_strerror(errno));
12873b6c3722Schristos 			}
12883b6c3722Schristos 			return -1;
12893b6c3722Schristos 		}
12903b6c3722Schristos #endif
12913b6c3722Schristos #else /* USE_WINSOCK */
12923b6c3722Schristos 		if(WSAGetLastError() == WSAEINPROGRESS ||
12933b6c3722Schristos 			WSAGetLastError() == WSAECONNRESET)
12943b6c3722Schristos 			return -1;
12953b6c3722Schristos 		if(WSAGetLastError() == WSAEWOULDBLOCK) {
12963b6c3722Schristos 			ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
12973b6c3722Schristos 			return -1;
12983b6c3722Schristos 		}
12993b6c3722Schristos #endif
130016776186Schristos 		log_err_addr("accept failed", sock_strerror(errno), addr,
130116776186Schristos 			*addrlen);
13023b6c3722Schristos 		return -1;
13033b6c3722Schristos 	}
1304f42d8de7Schristos 	if(c->tcp_conn_limit && c->type == comm_tcp_accept) {
1305f42d8de7Schristos 		c->tcl_addr = tcl_addr_lookup(c->tcp_conn_limit, addr, *addrlen);
1306f42d8de7Schristos 		if(!tcl_new_connection(c->tcl_addr)) {
1307f42d8de7Schristos 			if(verbosity >= 3)
1308f42d8de7Schristos 				log_err_addr("accept rejected",
1309f42d8de7Schristos 				"connection limit exceeded", addr, *addrlen);
1310f42d8de7Schristos 			close(new_fd);
1311f42d8de7Schristos 			return -1;
1312f42d8de7Schristos 		}
1313f42d8de7Schristos 	}
13147cd94d69Schristos #ifndef HAVE_ACCEPT4
13153b6c3722Schristos 	fd_set_nonblock(new_fd);
13167cd94d69Schristos #endif
13173b6c3722Schristos 	return new_fd;
13183b6c3722Schristos }
13193b6c3722Schristos 
13203b6c3722Schristos #ifdef USE_WINSOCK
13213b6c3722Schristos static long win_bio_cb(BIO *b, int oper, const char* ATTR_UNUSED(argp),
13221481e2a9Schristos #ifdef HAVE_BIO_SET_CALLBACK_EX
13231481e2a9Schristos 	size_t ATTR_UNUSED(len),
13241481e2a9Schristos #endif
13251481e2a9Schristos         int ATTR_UNUSED(argi), long argl,
13261481e2a9Schristos #ifndef HAVE_BIO_SET_CALLBACK_EX
13271481e2a9Schristos 	long retvalue
13281481e2a9Schristos #else
13291481e2a9Schristos 	int retvalue, size_t* ATTR_UNUSED(processed)
13301481e2a9Schristos #endif
13311481e2a9Schristos 	)
13323b6c3722Schristos {
13337cd94d69Schristos 	int wsa_err = WSAGetLastError(); /* store errcode before it is gone */
13343b6c3722Schristos 	verbose(VERB_ALGO, "bio_cb %d, %s %s %s", oper,
13353b6c3722Schristos 		(oper&BIO_CB_RETURN)?"return":"before",
13363b6c3722Schristos 		(oper&BIO_CB_READ)?"read":((oper&BIO_CB_WRITE)?"write":"other"),
13377cd94d69Schristos 		wsa_err==WSAEWOULDBLOCK?"wsawb":"");
13383b6c3722Schristos 	/* on windows, check if previous operation caused EWOULDBLOCK */
13393b6c3722Schristos 	if( (oper == (BIO_CB_READ|BIO_CB_RETURN) && argl == 0) ||
13403b6c3722Schristos 		(oper == (BIO_CB_GETS|BIO_CB_RETURN) && argl == 0)) {
13417cd94d69Schristos 		if(wsa_err == WSAEWOULDBLOCK)
13423b6c3722Schristos 			ub_winsock_tcp_wouldblock((struct ub_event*)
13433b6c3722Schristos 				BIO_get_callback_arg(b), UB_EV_READ);
13443b6c3722Schristos 	}
13453b6c3722Schristos 	if( (oper == (BIO_CB_WRITE|BIO_CB_RETURN) && argl == 0) ||
13463b6c3722Schristos 		(oper == (BIO_CB_PUTS|BIO_CB_RETURN) && argl == 0)) {
13477cd94d69Schristos 		if(wsa_err == WSAEWOULDBLOCK)
13483b6c3722Schristos 			ub_winsock_tcp_wouldblock((struct ub_event*)
13493b6c3722Schristos 				BIO_get_callback_arg(b), UB_EV_WRITE);
13503b6c3722Schristos 	}
13513b6c3722Schristos 	/* return original return value */
13523b6c3722Schristos 	return retvalue;
13533b6c3722Schristos }
13543b6c3722Schristos 
13553b6c3722Schristos /** set win bio callbacks for nonblocking operations */
13563b6c3722Schristos void
13573b6c3722Schristos comm_point_tcp_win_bio_cb(struct comm_point* c, void* thessl)
13583b6c3722Schristos {
13593b6c3722Schristos 	SSL* ssl = (SSL*)thessl;
13603b6c3722Schristos 	/* set them both just in case, but usually they are the same BIO */
13611481e2a9Schristos #ifdef HAVE_BIO_SET_CALLBACK_EX
13621481e2a9Schristos 	BIO_set_callback_ex(SSL_get_rbio(ssl), &win_bio_cb);
13631481e2a9Schristos #else
13643b6c3722Schristos 	BIO_set_callback(SSL_get_rbio(ssl), &win_bio_cb);
13651481e2a9Schristos #endif
13663b6c3722Schristos 	BIO_set_callback_arg(SSL_get_rbio(ssl), (char*)c->ev->ev);
13671481e2a9Schristos #ifdef HAVE_BIO_SET_CALLBACK_EX
13681481e2a9Schristos 	BIO_set_callback_ex(SSL_get_wbio(ssl), &win_bio_cb);
13691481e2a9Schristos #else
13703b6c3722Schristos 	BIO_set_callback(SSL_get_wbio(ssl), &win_bio_cb);
13711481e2a9Schristos #endif
13723b6c3722Schristos 	BIO_set_callback_arg(SSL_get_wbio(ssl), (char*)c->ev->ev);
13733b6c3722Schristos }
13743b6c3722Schristos #endif
13753b6c3722Schristos 
137616776186Schristos #ifdef HAVE_NGHTTP2
137716776186Schristos /** Create http2 session server.  Per connection, after TCP accepted.*/
137816776186Schristos static int http2_session_server_create(struct http2_session* h2_session)
137916776186Schristos {
138016776186Schristos 	log_assert(h2_session->callbacks);
138116776186Schristos 	h2_session->is_drop = 0;
138216776186Schristos 	if(nghttp2_session_server_new(&h2_session->session,
138316776186Schristos 			h2_session->callbacks,
138416776186Schristos 		h2_session) == NGHTTP2_ERR_NOMEM) {
138516776186Schristos 		log_err("failed to create nghttp2 session server");
138616776186Schristos 		return 0;
138716776186Schristos 	}
138816776186Schristos 
138916776186Schristos 	return 1;
139016776186Schristos }
139116776186Schristos 
139216776186Schristos /** Submit http2 setting to session. Once per session. */
139316776186Schristos static int http2_submit_settings(struct http2_session* h2_session)
139416776186Schristos {
139516776186Schristos 	int ret;
139616776186Schristos 	nghttp2_settings_entry settings[1] = {
139716776186Schristos 		{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
139816776186Schristos 		 h2_session->c->http2_max_streams}};
139916776186Schristos 
140016776186Schristos 	ret = nghttp2_submit_settings(h2_session->session, NGHTTP2_FLAG_NONE,
140116776186Schristos 		settings, 1);
140216776186Schristos 	if(ret) {
140316776186Schristos 		verbose(VERB_QUERY, "http2: submit_settings failed, "
140416776186Schristos 			"error: %s", nghttp2_strerror(ret));
140516776186Schristos 		return 0;
140616776186Schristos 	}
140716776186Schristos 	return 1;
140816776186Schristos }
140916776186Schristos #endif /* HAVE_NGHTTP2 */
141016776186Schristos 
141116776186Schristos 
14123b6c3722Schristos void
14133b6c3722Schristos comm_point_tcp_accept_callback(int fd, short event, void* arg)
14143b6c3722Schristos {
14153b6c3722Schristos 	struct comm_point* c = (struct comm_point*)arg, *c_hdl;
14163b6c3722Schristos 	int new_fd;
14173b6c3722Schristos 	log_assert(c->type == comm_tcp_accept);
14183b6c3722Schristos 	if(!(event & UB_EV_READ)) {
14193b6c3722Schristos 		log_info("ignoring tcp accept event %d", (int)event);
14203b6c3722Schristos 		return;
14213b6c3722Schristos 	}
14223b6c3722Schristos 	ub_comm_base_now(c->ev->base);
14233b6c3722Schristos 	/* find free tcp handler. */
14243b6c3722Schristos 	if(!c->tcp_free) {
14253b6c3722Schristos 		log_warn("accepted too many tcp, connections full");
14263b6c3722Schristos 		return;
14273b6c3722Schristos 	}
14283b6c3722Schristos 	/* accept incoming connection. */
14293b6c3722Schristos 	c_hdl = c->tcp_free;
143087edd195Schristos 	/* clear leftover flags from previous use, and then set the
143187edd195Schristos 	 * correct event base for the event structure for libevent */
143287edd195Schristos 	ub_event_free(c_hdl->ev->ev);
14331481e2a9Schristos 	c_hdl->ev->ev = NULL;
143416776186Schristos 	if((c_hdl->type == comm_tcp && c_hdl->tcp_req_info) ||
143516776186Schristos 		c_hdl->type == comm_local || c_hdl->type == comm_raw)
143616776186Schristos 		c_hdl->tcp_do_toggle_rw = 0;
143716776186Schristos 	else	c_hdl->tcp_do_toggle_rw = 1;
143816776186Schristos 
143916776186Schristos 	if(c_hdl->type == comm_http) {
144016776186Schristos #ifdef HAVE_NGHTTP2
144116776186Schristos 		if(!c_hdl->h2_session ||
144216776186Schristos 			!http2_session_server_create(c_hdl->h2_session)) {
144316776186Schristos 			log_warn("failed to create nghttp2");
144416776186Schristos 			return;
144516776186Schristos 		}
144616776186Schristos 		if(!c_hdl->h2_session ||
144716776186Schristos 			!http2_submit_settings(c_hdl->h2_session)) {
144816776186Schristos 			log_warn("failed to submit http2 settings");
144916776186Schristos 			return;
145016776186Schristos 		}
145116776186Schristos 		if(!c->ssl) {
145216776186Schristos 			c_hdl->tcp_do_toggle_rw = 0;
145316776186Schristos 			c_hdl->use_h2 = 1;
145416776186Schristos 		}
145516776186Schristos #endif
145616776186Schristos 		c_hdl->ev->ev = ub_event_new(c_hdl->ev->base->eb->base, -1,
145716776186Schristos 			UB_EV_PERSIST | UB_EV_READ | UB_EV_TIMEOUT,
145816776186Schristos 			comm_point_http_handle_callback, c_hdl);
145916776186Schristos 	} else {
146016776186Schristos 		c_hdl->ev->ev = ub_event_new(c_hdl->ev->base->eb->base, -1,
146116776186Schristos 			UB_EV_PERSIST | UB_EV_READ | UB_EV_TIMEOUT,
146216776186Schristos 			comm_point_tcp_handle_callback, c_hdl);
146316776186Schristos 	}
146487edd195Schristos 	if(!c_hdl->ev->ev) {
146587edd195Schristos 		log_warn("could not ub_event_new, dropped tcp");
146687edd195Schristos 		return;
146787edd195Schristos 	}
14683b6c3722Schristos 	log_assert(fd != -1);
14690cd9f4ecSchristos 	(void)fd;
1470*14b2fa6eSchristos 	new_fd = comm_point_perform_accept(c, &c_hdl->repinfo.remote_addr,
1471*14b2fa6eSchristos 		&c_hdl->repinfo.remote_addrlen);
14723b6c3722Schristos 	if(new_fd == -1)
14733b6c3722Schristos 		return;
1474*14b2fa6eSchristos 	/* Copy remote_address to client_address.
1475*14b2fa6eSchristos 	 * Simplest way/time for streams to do that. */
1476*14b2fa6eSchristos 	c_hdl->repinfo.client_addrlen = c_hdl->repinfo.remote_addrlen;
1477*14b2fa6eSchristos 	memmove(&c_hdl->repinfo.client_addr,
1478*14b2fa6eSchristos 		&c_hdl->repinfo.remote_addr,
1479*14b2fa6eSchristos 		c_hdl->repinfo.remote_addrlen);
14803b6c3722Schristos 	if(c->ssl) {
14813b6c3722Schristos 		c_hdl->ssl = incoming_ssl_fd(c->ssl, new_fd);
14823b6c3722Schristos 		if(!c_hdl->ssl) {
14833b6c3722Schristos 			c_hdl->fd = new_fd;
14843b6c3722Schristos 			comm_point_close(c_hdl);
14853b6c3722Schristos 			return;
14863b6c3722Schristos 		}
14873b6c3722Schristos 		c_hdl->ssl_shake_state = comm_ssl_shake_read;
14883b6c3722Schristos #ifdef USE_WINSOCK
14893b6c3722Schristos 		comm_point_tcp_win_bio_cb(c_hdl, c_hdl->ssl);
14903b6c3722Schristos #endif
14913b6c3722Schristos 	}
14923b6c3722Schristos 
14933b6c3722Schristos 	/* grab the tcp handler buffers */
14943b6c3722Schristos 	c->cur_tcp_count++;
14953b6c3722Schristos 	c->tcp_free = c_hdl->tcp_free;
14961481e2a9Schristos 	c_hdl->tcp_free = NULL;
14973b6c3722Schristos 	if(!c->tcp_free) {
14983b6c3722Schristos 		/* stop accepting incoming queries for now. */
14993b6c3722Schristos 		comm_point_stop_listening(c);
15003b6c3722Schristos 	}
15010cd9f4ecSchristos 	setup_tcp_handler(c_hdl, new_fd, c->cur_tcp_count, c->max_tcp_count);
15023b6c3722Schristos }
15033b6c3722Schristos 
15043b6c3722Schristos /** Make tcp handler free for next assignment */
15053b6c3722Schristos static void
15063b6c3722Schristos reclaim_tcp_handler(struct comm_point* c)
15073b6c3722Schristos {
15083b6c3722Schristos 	log_assert(c->type == comm_tcp);
15093b6c3722Schristos 	if(c->ssl) {
15103b6c3722Schristos #ifdef HAVE_SSL
15113b6c3722Schristos 		SSL_shutdown(c->ssl);
15123b6c3722Schristos 		SSL_free(c->ssl);
15133b6c3722Schristos 		c->ssl = NULL;
15143b6c3722Schristos #endif
15153b6c3722Schristos 	}
15163b6c3722Schristos 	comm_point_close(c);
15173b6c3722Schristos 	if(c->tcp_parent) {
15181481e2a9Schristos 		if(c != c->tcp_parent->tcp_free) {
15193b6c3722Schristos 			c->tcp_parent->cur_tcp_count--;
15203b6c3722Schristos 			c->tcp_free = c->tcp_parent->tcp_free;
15213b6c3722Schristos 			c->tcp_parent->tcp_free = c;
15221481e2a9Schristos 		}
15233b6c3722Schristos 		if(!c->tcp_free) {
15243b6c3722Schristos 			/* re-enable listening on accept socket */
15253b6c3722Schristos 			comm_point_start_listening(c->tcp_parent, -1, -1);
15263b6c3722Schristos 		}
15273b6c3722Schristos 	}
152816776186Schristos 	c->tcp_more_read_again = NULL;
152916776186Schristos 	c->tcp_more_write_again = NULL;
15301481e2a9Schristos 	c->tcp_byte_count = 0;
1531*14b2fa6eSchristos 	c->pp2_header_state = pp2_header_none;
15321481e2a9Schristos 	sldns_buffer_clear(c->buffer);
15333b6c3722Schristos }
15343b6c3722Schristos 
15353b6c3722Schristos /** do the callback when writing is done */
15363b6c3722Schristos static void
15373b6c3722Schristos tcp_callback_writer(struct comm_point* c)
15383b6c3722Schristos {
15393b6c3722Schristos 	log_assert(c->type == comm_tcp);
154016776186Schristos 	if(!c->tcp_write_and_read) {
15413b6c3722Schristos 		sldns_buffer_clear(c->buffer);
154216776186Schristos 		c->tcp_byte_count = 0;
154316776186Schristos 	}
15443b6c3722Schristos 	if(c->tcp_do_toggle_rw)
15453b6c3722Schristos 		c->tcp_is_reading = 1;
15463b6c3722Schristos 	/* switch from listening(write) to listening(read) */
1547f42d8de7Schristos 	if(c->tcp_req_info) {
1548f42d8de7Schristos 		tcp_req_info_handle_writedone(c->tcp_req_info);
1549f42d8de7Schristos 	} else {
15503b6c3722Schristos 		comm_point_stop_listening(c);
155116776186Schristos 		if(c->tcp_write_and_read) {
155216776186Schristos 			fptr_ok(fptr_whitelist_comm_point(c->callback));
155316776186Schristos 			if( (*c->callback)(c, c->cb_arg, NETEVENT_PKT_WRITTEN,
155416776186Schristos 				&c->repinfo) ) {
155516776186Schristos 				comm_point_start_listening(c, -1,
155616776186Schristos 					adjusted_tcp_timeout(c));
155716776186Schristos 			}
155816776186Schristos 		} else {
155916776186Schristos 			comm_point_start_listening(c, -1,
156016776186Schristos 					adjusted_tcp_timeout(c));
156116776186Schristos 		}
15623b6c3722Schristos 	}
1563f42d8de7Schristos }
15643b6c3722Schristos 
15653b6c3722Schristos /** do the callback when reading is done */
15663b6c3722Schristos static void
15673b6c3722Schristos tcp_callback_reader(struct comm_point* c)
15683b6c3722Schristos {
15693b6c3722Schristos 	log_assert(c->type == comm_tcp || c->type == comm_local);
15703b6c3722Schristos 	sldns_buffer_flip(c->buffer);
15713b6c3722Schristos 	if(c->tcp_do_toggle_rw)
15723b6c3722Schristos 		c->tcp_is_reading = 0;
15733b6c3722Schristos 	c->tcp_byte_count = 0;
1574f42d8de7Schristos 	if(c->tcp_req_info) {
1575f42d8de7Schristos 		tcp_req_info_handle_readdone(c->tcp_req_info);
1576f42d8de7Schristos 	} else {
15773b6c3722Schristos 		if(c->type == comm_tcp)
15783b6c3722Schristos 			comm_point_stop_listening(c);
15793b6c3722Schristos 		fptr_ok(fptr_whitelist_comm_point(c->callback));
15803b6c3722Schristos 		if( (*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, &c->repinfo) ) {
158116776186Schristos 			comm_point_start_listening(c, -1,
158216776186Schristos 					adjusted_tcp_timeout(c));
15833b6c3722Schristos 		}
15843b6c3722Schristos 	}
1585f42d8de7Schristos }
15863b6c3722Schristos 
15877cd94d69Schristos #ifdef HAVE_SSL
158887edd195Schristos /** true if the ssl handshake error has to be squelched from the logs */
158916776186Schristos int
159087edd195Schristos squelch_err_ssl_handshake(unsigned long err)
159187edd195Schristos {
159287edd195Schristos 	if(verbosity >= VERB_QUERY)
159387edd195Schristos 		return 0; /* only squelch on low verbosity */
15941481e2a9Schristos 	if(ERR_GET_LIB(err) == ERR_LIB_SSL &&
15951481e2a9Schristos 		(ERR_GET_REASON(err) == SSL_R_HTTPS_PROXY_REQUEST ||
15961481e2a9Schristos 		 ERR_GET_REASON(err) == SSL_R_HTTP_REQUEST ||
15971481e2a9Schristos 		 ERR_GET_REASON(err) == SSL_R_WRONG_VERSION_NUMBER ||
15981481e2a9Schristos 		 ERR_GET_REASON(err) == SSL_R_SSLV3_ALERT_BAD_CERTIFICATE
159987edd195Schristos #ifdef SSL_F_TLS_POST_PROCESS_CLIENT_HELLO
16001481e2a9Schristos 		 || ERR_GET_REASON(err) == SSL_R_NO_SHARED_CIPHER
160187edd195Schristos #endif
160287edd195Schristos #ifdef SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO
16031481e2a9Schristos 		 || ERR_GET_REASON(err) == SSL_R_UNKNOWN_PROTOCOL
16041481e2a9Schristos 		 || ERR_GET_REASON(err) == SSL_R_UNSUPPORTED_PROTOCOL
160587edd195Schristos #  ifdef SSL_R_VERSION_TOO_LOW
16061481e2a9Schristos 		 || ERR_GET_REASON(err) == SSL_R_VERSION_TOO_LOW
160787edd195Schristos #  endif
160887edd195Schristos #endif
16091481e2a9Schristos 		))
161087edd195Schristos 		return 1;
161187edd195Schristos 	return 0;
161287edd195Schristos }
161387edd195Schristos #endif /* HAVE_SSL */
161487edd195Schristos 
16153b6c3722Schristos /** continue ssl handshake */
16163b6c3722Schristos #ifdef HAVE_SSL
16173b6c3722Schristos static int
16183b6c3722Schristos ssl_handshake(struct comm_point* c)
16193b6c3722Schristos {
16203b6c3722Schristos 	int r;
16213b6c3722Schristos 	if(c->ssl_shake_state == comm_ssl_shake_hs_read) {
16223b6c3722Schristos 		/* read condition satisfied back to writing */
16231481e2a9Schristos 		comm_point_listen_for_rw(c, 0, 1);
16243b6c3722Schristos 		c->ssl_shake_state = comm_ssl_shake_none;
16253b6c3722Schristos 		return 1;
16263b6c3722Schristos 	}
16273b6c3722Schristos 	if(c->ssl_shake_state == comm_ssl_shake_hs_write) {
16283b6c3722Schristos 		/* write condition satisfied, back to reading */
16293b6c3722Schristos 		comm_point_listen_for_rw(c, 1, 0);
16303b6c3722Schristos 		c->ssl_shake_state = comm_ssl_shake_none;
16313b6c3722Schristos 		return 1;
16323b6c3722Schristos 	}
16333b6c3722Schristos 
16343b6c3722Schristos 	ERR_clear_error();
16353b6c3722Schristos 	r = SSL_do_handshake(c->ssl);
16363b6c3722Schristos 	if(r != 1) {
16373b6c3722Schristos 		int want = SSL_get_error(c->ssl, r);
16383b6c3722Schristos 		if(want == SSL_ERROR_WANT_READ) {
16393b6c3722Schristos 			if(c->ssl_shake_state == comm_ssl_shake_read)
16403b6c3722Schristos 				return 1;
16413b6c3722Schristos 			c->ssl_shake_state = comm_ssl_shake_read;
16423b6c3722Schristos 			comm_point_listen_for_rw(c, 1, 0);
16433b6c3722Schristos 			return 1;
16443b6c3722Schristos 		} else if(want == SSL_ERROR_WANT_WRITE) {
16453b6c3722Schristos 			if(c->ssl_shake_state == comm_ssl_shake_write)
16463b6c3722Schristos 				return 1;
16473b6c3722Schristos 			c->ssl_shake_state = comm_ssl_shake_write;
16483b6c3722Schristos 			comm_point_listen_for_rw(c, 0, 1);
16493b6c3722Schristos 			return 1;
16503b6c3722Schristos 		} else if(r == 0) {
16513b6c3722Schristos 			return 0; /* closed */
16523b6c3722Schristos 		} else if(want == SSL_ERROR_SYSCALL) {
16533b6c3722Schristos 			/* SYSCALL and errno==0 means closed uncleanly */
165416776186Schristos #ifdef EPIPE
165516776186Schristos 			if(errno == EPIPE && verbosity < 2)
165616776186Schristos 				return 0; /* silence 'broken pipe' */
165716776186Schristos #endif
165816776186Schristos #ifdef ECONNRESET
165916776186Schristos 			if(errno == ECONNRESET && verbosity < 2)
166016776186Schristos 				return 0; /* silence reset by peer */
166116776186Schristos #endif
16621481e2a9Schristos 			if(!tcp_connect_errno_needs_log(
1663*14b2fa6eSchristos 				(struct sockaddr*)&c->repinfo.remote_addr,
1664*14b2fa6eSchristos 				c->repinfo.remote_addrlen))
16651481e2a9Schristos 				return 0; /* silence connect failures that
16661481e2a9Schristos 				show up because after connect this is the
16671481e2a9Schristos 				first system call that accesses the socket */
16683b6c3722Schristos 			if(errno != 0)
16693b6c3722Schristos 				log_err("SSL_handshake syscall: %s",
16703b6c3722Schristos 					strerror(errno));
16713b6c3722Schristos 			return 0;
16723b6c3722Schristos 		} else {
167387edd195Schristos 			unsigned long err = ERR_get_error();
167487edd195Schristos 			if(!squelch_err_ssl_handshake(err)) {
1675*14b2fa6eSchristos 				log_crypto_err_io_code("ssl handshake failed",
1676*14b2fa6eSchristos 					want, err);
1677*14b2fa6eSchristos 				log_addr(VERB_OPS, "ssl handshake failed",
1678*14b2fa6eSchristos 					&c->repinfo.remote_addr,
1679*14b2fa6eSchristos 					c->repinfo.remote_addrlen);
168087edd195Schristos 			}
16813b6c3722Schristos 			return 0;
16823b6c3722Schristos 		}
16833b6c3722Schristos 	}
16843b6c3722Schristos 	/* this is where peer verification could take place */
16857cd94d69Schristos 	if((SSL_get_verify_mode(c->ssl)&SSL_VERIFY_PEER)) {
16867cd94d69Schristos 		/* verification */
16877cd94d69Schristos 		if(SSL_get_verify_result(c->ssl) == X509_V_OK) {
16881481e2a9Schristos #ifdef HAVE_SSL_GET1_PEER_CERTIFICATE
16891481e2a9Schristos 			X509* x = SSL_get1_peer_certificate(c->ssl);
16901481e2a9Schristos #else
16917cd94d69Schristos 			X509* x = SSL_get_peer_certificate(c->ssl);
16921481e2a9Schristos #endif
16937cd94d69Schristos 			if(!x) {
16947cd94d69Schristos 				log_addr(VERB_ALGO, "SSL connection failed: "
16957cd94d69Schristos 					"no certificate",
1696*14b2fa6eSchristos 					&c->repinfo.remote_addr,
1697*14b2fa6eSchristos 					c->repinfo.remote_addrlen);
16987cd94d69Schristos 				return 0;
16997cd94d69Schristos 			}
17007cd94d69Schristos 			log_cert(VERB_ALGO, "peer certificate", x);
17017cd94d69Schristos #ifdef HAVE_SSL_GET0_PEERNAME
17027cd94d69Schristos 			if(SSL_get0_peername(c->ssl)) {
17037cd94d69Schristos 				char buf[255];
17047cd94d69Schristos 				snprintf(buf, sizeof(buf), "SSL connection "
17057cd94d69Schristos 					"to %s authenticated",
17067cd94d69Schristos 					SSL_get0_peername(c->ssl));
1707*14b2fa6eSchristos 				log_addr(VERB_ALGO, buf, &c->repinfo.remote_addr,
1708*14b2fa6eSchristos 					c->repinfo.remote_addrlen);
17097cd94d69Schristos 			} else {
17107cd94d69Schristos #endif
17117cd94d69Schristos 				log_addr(VERB_ALGO, "SSL connection "
1712*14b2fa6eSchristos 					"authenticated", &c->repinfo.remote_addr,
1713*14b2fa6eSchristos 					c->repinfo.remote_addrlen);
17147cd94d69Schristos #ifdef HAVE_SSL_GET0_PEERNAME
17157cd94d69Schristos 			}
17167cd94d69Schristos #endif
17177cd94d69Schristos 			X509_free(x);
17187cd94d69Schristos 		} else {
17191481e2a9Schristos #ifdef HAVE_SSL_GET1_PEER_CERTIFICATE
17201481e2a9Schristos 			X509* x = SSL_get1_peer_certificate(c->ssl);
17211481e2a9Schristos #else
17227cd94d69Schristos 			X509* x = SSL_get_peer_certificate(c->ssl);
17231481e2a9Schristos #endif
17247cd94d69Schristos 			if(x) {
17257cd94d69Schristos 				log_cert(VERB_ALGO, "peer certificate", x);
17267cd94d69Schristos 				X509_free(x);
17277cd94d69Schristos 			}
17287cd94d69Schristos 			log_addr(VERB_ALGO, "SSL connection failed: "
17297cd94d69Schristos 				"failed to authenticate",
1730*14b2fa6eSchristos 				&c->repinfo.remote_addr,
1731*14b2fa6eSchristos 				c->repinfo.remote_addrlen);
17327cd94d69Schristos 			return 0;
17337cd94d69Schristos 		}
17347cd94d69Schristos 	} else {
17357cd94d69Schristos 		/* unauthenticated, the verify peer flag was not set
17367cd94d69Schristos 		 * in c->ssl when the ssl object was created from ssl_ctx */
1737*14b2fa6eSchristos 		log_addr(VERB_ALGO, "SSL connection", &c->repinfo.remote_addr,
1738*14b2fa6eSchristos 			c->repinfo.remote_addrlen);
17397cd94d69Schristos 	}
17403b6c3722Schristos 
17411481e2a9Schristos #ifdef HAVE_SSL_GET0_ALPN_SELECTED
174216776186Schristos 	/* check if http2 use is negotiated */
174316776186Schristos 	if(c->type == comm_http && c->h2_session) {
174416776186Schristos 		const unsigned char *alpn;
174516776186Schristos 		unsigned int alpnlen = 0;
174616776186Schristos 		SSL_get0_alpn_selected(c->ssl, &alpn, &alpnlen);
174716776186Schristos 		if(alpnlen == 2 && memcmp("h2", alpn, 2) == 0) {
174816776186Schristos 			/* connection upgraded to HTTP2 */
174916776186Schristos 			c->tcp_do_toggle_rw = 0;
175016776186Schristos 			c->use_h2 = 1;
175116776186Schristos 		}
175216776186Schristos 	}
17531481e2a9Schristos #endif
175416776186Schristos 
17553b6c3722Schristos 	/* setup listen rw correctly */
17563b6c3722Schristos 	if(c->tcp_is_reading) {
17573b6c3722Schristos 		if(c->ssl_shake_state != comm_ssl_shake_read)
17583b6c3722Schristos 			comm_point_listen_for_rw(c, 1, 0);
17593b6c3722Schristos 	} else {
17601481e2a9Schristos 		comm_point_listen_for_rw(c, 0, 1);
17613b6c3722Schristos 	}
17623b6c3722Schristos 	c->ssl_shake_state = comm_ssl_shake_none;
17633b6c3722Schristos 	return 1;
17643b6c3722Schristos }
17653b6c3722Schristos #endif /* HAVE_SSL */
17663b6c3722Schristos 
17673b6c3722Schristos /** ssl read callback on TCP */
17683b6c3722Schristos static int
17693b6c3722Schristos ssl_handle_read(struct comm_point* c)
17703b6c3722Schristos {
17713b6c3722Schristos #ifdef HAVE_SSL
17723b6c3722Schristos 	int r;
17733b6c3722Schristos 	if(c->ssl_shake_state != comm_ssl_shake_none) {
17743b6c3722Schristos 		if(!ssl_handshake(c))
17753b6c3722Schristos 			return 0;
17763b6c3722Schristos 		if(c->ssl_shake_state != comm_ssl_shake_none)
17773b6c3722Schristos 			return 1;
17783b6c3722Schristos 	}
1779*14b2fa6eSchristos 	if(c->pp2_enabled && c->pp2_header_state != pp2_header_done) {
1780*14b2fa6eSchristos 		struct pp2_header* header = NULL;
1781*14b2fa6eSchristos 		size_t want_read_size = 0;
1782*14b2fa6eSchristos 		size_t current_read_size = 0;
1783*14b2fa6eSchristos 		if(c->pp2_header_state == pp2_header_none) {
1784*14b2fa6eSchristos 			want_read_size = PP2_HEADER_SIZE;
1785*14b2fa6eSchristos 			if(sldns_buffer_remaining(c->buffer)<want_read_size) {
1786*14b2fa6eSchristos 				log_err_addr("proxy_protocol: not enough "
1787*14b2fa6eSchristos 					"buffer size to read PROXYv2 header", "",
1788*14b2fa6eSchristos 					&c->repinfo.remote_addr,
1789*14b2fa6eSchristos 					c->repinfo.remote_addrlen);
1790*14b2fa6eSchristos 				return 0;
1791*14b2fa6eSchristos 			}
1792*14b2fa6eSchristos 			verbose(VERB_ALGO, "proxy_protocol: reading fixed "
1793*14b2fa6eSchristos 				"part of PROXYv2 header (len %lu)",
1794*14b2fa6eSchristos 				(unsigned long)want_read_size);
1795*14b2fa6eSchristos 			current_read_size = want_read_size;
1796*14b2fa6eSchristos 			if(c->tcp_byte_count < current_read_size) {
1797*14b2fa6eSchristos 				ERR_clear_error();
1798*14b2fa6eSchristos 				if((r=SSL_read(c->ssl, (void*)sldns_buffer_at(
1799*14b2fa6eSchristos 					c->buffer, c->tcp_byte_count),
1800*14b2fa6eSchristos 					current_read_size -
1801*14b2fa6eSchristos 					c->tcp_byte_count)) <= 0) {
1802*14b2fa6eSchristos 					int want = SSL_get_error(c->ssl, r);
1803*14b2fa6eSchristos 					if(want == SSL_ERROR_ZERO_RETURN) {
1804*14b2fa6eSchristos 						if(c->tcp_req_info)
1805*14b2fa6eSchristos 							return tcp_req_info_handle_read_close(c->tcp_req_info);
1806*14b2fa6eSchristos 						return 0; /* shutdown, closed */
1807*14b2fa6eSchristos 					} else if(want == SSL_ERROR_WANT_READ) {
1808*14b2fa6eSchristos #ifdef USE_WINSOCK
1809*14b2fa6eSchristos 						ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
1810*14b2fa6eSchristos #endif
1811*14b2fa6eSchristos 						return 1; /* read more later */
1812*14b2fa6eSchristos 					} else if(want == SSL_ERROR_WANT_WRITE) {
1813*14b2fa6eSchristos 						c->ssl_shake_state = comm_ssl_shake_hs_write;
1814*14b2fa6eSchristos 						comm_point_listen_for_rw(c, 0, 1);
1815*14b2fa6eSchristos 						return 1;
1816*14b2fa6eSchristos 					} else if(want == SSL_ERROR_SYSCALL) {
1817*14b2fa6eSchristos #ifdef ECONNRESET
1818*14b2fa6eSchristos 						if(errno == ECONNRESET && verbosity < 2)
1819*14b2fa6eSchristos 							return 0; /* silence reset by peer */
1820*14b2fa6eSchristos #endif
1821*14b2fa6eSchristos 						if(errno != 0)
1822*14b2fa6eSchristos 							log_err("SSL_read syscall: %s",
1823*14b2fa6eSchristos 								strerror(errno));
1824*14b2fa6eSchristos 						return 0;
1825*14b2fa6eSchristos 					}
1826*14b2fa6eSchristos 					log_crypto_err_io("could not SSL_read",
1827*14b2fa6eSchristos 						want);
1828*14b2fa6eSchristos 					return 0;
1829*14b2fa6eSchristos 				}
1830*14b2fa6eSchristos 				c->tcp_byte_count += r;
1831*14b2fa6eSchristos 				sldns_buffer_skip(c->buffer, r);
1832*14b2fa6eSchristos 				if(c->tcp_byte_count != current_read_size) return 1;
1833*14b2fa6eSchristos 				c->pp2_header_state = pp2_header_init;
1834*14b2fa6eSchristos 			}
1835*14b2fa6eSchristos 		}
1836*14b2fa6eSchristos 		if(c->pp2_header_state == pp2_header_init) {
1837*14b2fa6eSchristos 			int err;
1838*14b2fa6eSchristos 			err = pp2_read_header(
1839*14b2fa6eSchristos 				sldns_buffer_begin(c->buffer),
1840*14b2fa6eSchristos 				sldns_buffer_limit(c->buffer));
1841*14b2fa6eSchristos 			if(err) {
1842*14b2fa6eSchristos 				log_err("proxy_protocol: could not parse "
1843*14b2fa6eSchristos 					"PROXYv2 header (%s)",
1844*14b2fa6eSchristos 					pp_lookup_error(err));
1845*14b2fa6eSchristos 				return 0;
1846*14b2fa6eSchristos 			}
1847*14b2fa6eSchristos 			header = (struct pp2_header*)sldns_buffer_begin(c->buffer);
1848*14b2fa6eSchristos 			want_read_size = ntohs(header->len);
1849*14b2fa6eSchristos 			if(sldns_buffer_limit(c->buffer) <
1850*14b2fa6eSchristos 				PP2_HEADER_SIZE + want_read_size) {
1851*14b2fa6eSchristos 				log_err_addr("proxy_protocol: not enough "
1852*14b2fa6eSchristos 					"buffer size to read PROXYv2 header", "",
1853*14b2fa6eSchristos 					&c->repinfo.remote_addr,
1854*14b2fa6eSchristos 					c->repinfo.remote_addrlen);
1855*14b2fa6eSchristos 				return 0;
1856*14b2fa6eSchristos 			}
1857*14b2fa6eSchristos 			verbose(VERB_ALGO, "proxy_protocol: reading variable "
1858*14b2fa6eSchristos 				"part of PROXYv2 header (len %lu)",
1859*14b2fa6eSchristos 				(unsigned long)want_read_size);
1860*14b2fa6eSchristos 			current_read_size = PP2_HEADER_SIZE + want_read_size;
1861*14b2fa6eSchristos 			if(want_read_size == 0) {
1862*14b2fa6eSchristos 				/* nothing more to read; header is complete */
1863*14b2fa6eSchristos 				c->pp2_header_state = pp2_header_done;
1864*14b2fa6eSchristos 			} else if(c->tcp_byte_count < current_read_size) {
1865*14b2fa6eSchristos 				ERR_clear_error();
1866*14b2fa6eSchristos 				if((r=SSL_read(c->ssl, (void*)sldns_buffer_at(
1867*14b2fa6eSchristos 					c->buffer, c->tcp_byte_count),
1868*14b2fa6eSchristos 					current_read_size -
1869*14b2fa6eSchristos 					c->tcp_byte_count)) <= 0) {
1870*14b2fa6eSchristos 					int want = SSL_get_error(c->ssl, r);
1871*14b2fa6eSchristos 					if(want == SSL_ERROR_ZERO_RETURN) {
1872*14b2fa6eSchristos 						if(c->tcp_req_info)
1873*14b2fa6eSchristos 							return tcp_req_info_handle_read_close(c->tcp_req_info);
1874*14b2fa6eSchristos 						return 0; /* shutdown, closed */
1875*14b2fa6eSchristos 					} else if(want == SSL_ERROR_WANT_READ) {
1876*14b2fa6eSchristos #ifdef USE_WINSOCK
1877*14b2fa6eSchristos 						ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
1878*14b2fa6eSchristos #endif
1879*14b2fa6eSchristos 						return 1; /* read more later */
1880*14b2fa6eSchristos 					} else if(want == SSL_ERROR_WANT_WRITE) {
1881*14b2fa6eSchristos 						c->ssl_shake_state = comm_ssl_shake_hs_write;
1882*14b2fa6eSchristos 						comm_point_listen_for_rw(c, 0, 1);
1883*14b2fa6eSchristos 						return 1;
1884*14b2fa6eSchristos 					} else if(want == SSL_ERROR_SYSCALL) {
1885*14b2fa6eSchristos #ifdef ECONNRESET
1886*14b2fa6eSchristos 						if(errno == ECONNRESET && verbosity < 2)
1887*14b2fa6eSchristos 							return 0; /* silence reset by peer */
1888*14b2fa6eSchristos #endif
1889*14b2fa6eSchristos 						if(errno != 0)
1890*14b2fa6eSchristos 							log_err("SSL_read syscall: %s",
1891*14b2fa6eSchristos 								strerror(errno));
1892*14b2fa6eSchristos 						return 0;
1893*14b2fa6eSchristos 					}
1894*14b2fa6eSchristos 					log_crypto_err_io("could not SSL_read",
1895*14b2fa6eSchristos 						want);
1896*14b2fa6eSchristos 					return 0;
1897*14b2fa6eSchristos 				}
1898*14b2fa6eSchristos 				c->tcp_byte_count += r;
1899*14b2fa6eSchristos 				sldns_buffer_skip(c->buffer, r);
1900*14b2fa6eSchristos 				if(c->tcp_byte_count != current_read_size) return 1;
1901*14b2fa6eSchristos 				c->pp2_header_state = pp2_header_done;
1902*14b2fa6eSchristos 			}
1903*14b2fa6eSchristos 		}
1904*14b2fa6eSchristos 		if(c->pp2_header_state != pp2_header_done || !header) {
1905*14b2fa6eSchristos 			log_err_addr("proxy_protocol: wrong state for the "
1906*14b2fa6eSchristos 				"PROXYv2 header", "", &c->repinfo.remote_addr,
1907*14b2fa6eSchristos 				c->repinfo.remote_addrlen);
1908*14b2fa6eSchristos 			return 0;
1909*14b2fa6eSchristos 		}
1910*14b2fa6eSchristos 		sldns_buffer_flip(c->buffer);
1911*14b2fa6eSchristos 		if(!consume_pp2_header(c->buffer, &c->repinfo, 1)) {
1912*14b2fa6eSchristos 			log_err_addr("proxy_protocol: could not consume "
1913*14b2fa6eSchristos 				"PROXYv2 header", "", &c->repinfo.remote_addr,
1914*14b2fa6eSchristos 				c->repinfo.remote_addrlen);
1915*14b2fa6eSchristos 			return 0;
1916*14b2fa6eSchristos 		}
1917*14b2fa6eSchristos 		verbose(VERB_ALGO, "proxy_protocol: successful read of "
1918*14b2fa6eSchristos 			"PROXYv2 header");
1919*14b2fa6eSchristos 		/* Clear and reset the buffer to read the following
1920*14b2fa6eSchristos 		 * DNS packet(s). */
1921*14b2fa6eSchristos 		sldns_buffer_clear(c->buffer);
1922*14b2fa6eSchristos 		c->tcp_byte_count = 0;
1923*14b2fa6eSchristos 		return 1;
1924*14b2fa6eSchristos 	}
19253b6c3722Schristos 	if(c->tcp_byte_count < sizeof(uint16_t)) {
19263b6c3722Schristos 		/* read length bytes */
19273b6c3722Schristos 		ERR_clear_error();
19283b6c3722Schristos 		if((r=SSL_read(c->ssl, (void*)sldns_buffer_at(c->buffer,
19293b6c3722Schristos 			c->tcp_byte_count), (int)(sizeof(uint16_t) -
19303b6c3722Schristos 			c->tcp_byte_count))) <= 0) {
19313b6c3722Schristos 			int want = SSL_get_error(c->ssl, r);
19323b6c3722Schristos 			if(want == SSL_ERROR_ZERO_RETURN) {
1933f42d8de7Schristos 				if(c->tcp_req_info)
1934f42d8de7Schristos 					return tcp_req_info_handle_read_close(c->tcp_req_info);
19353b6c3722Schristos 				return 0; /* shutdown, closed */
19363b6c3722Schristos 			} else if(want == SSL_ERROR_WANT_READ) {
19371481e2a9Schristos #ifdef USE_WINSOCK
19387cd94d69Schristos 				ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
19391481e2a9Schristos #endif
19403b6c3722Schristos 				return 1; /* read more later */
19413b6c3722Schristos 			} else if(want == SSL_ERROR_WANT_WRITE) {
19423b6c3722Schristos 				c->ssl_shake_state = comm_ssl_shake_hs_write;
19433b6c3722Schristos 				comm_point_listen_for_rw(c, 0, 1);
19443b6c3722Schristos 				return 1;
19453b6c3722Schristos 			} else if(want == SSL_ERROR_SYSCALL) {
194687edd195Schristos #ifdef ECONNRESET
194787edd195Schristos 				if(errno == ECONNRESET && verbosity < 2)
194887edd195Schristos 					return 0; /* silence reset by peer */
194987edd195Schristos #endif
19503b6c3722Schristos 				if(errno != 0)
19513b6c3722Schristos 					log_err("SSL_read syscall: %s",
19523b6c3722Schristos 						strerror(errno));
19533b6c3722Schristos 				return 0;
19543b6c3722Schristos 			}
1955*14b2fa6eSchristos 			log_crypto_err_io("could not SSL_read", want);
19563b6c3722Schristos 			return 0;
19573b6c3722Schristos 		}
19583b6c3722Schristos 		c->tcp_byte_count += r;
19597cd94d69Schristos 		if(c->tcp_byte_count < sizeof(uint16_t))
19603b6c3722Schristos 			return 1;
19613b6c3722Schristos 		if(sldns_buffer_read_u16_at(c->buffer, 0) >
19623b6c3722Schristos 			sldns_buffer_capacity(c->buffer)) {
19633b6c3722Schristos 			verbose(VERB_QUERY, "ssl: dropped larger than buffer");
19643b6c3722Schristos 			return 0;
19653b6c3722Schristos 		}
19663b6c3722Schristos 		sldns_buffer_set_limit(c->buffer,
19673b6c3722Schristos 			sldns_buffer_read_u16_at(c->buffer, 0));
19683b6c3722Schristos 		if(sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE) {
19693b6c3722Schristos 			verbose(VERB_QUERY, "ssl: dropped bogus too short.");
19703b6c3722Schristos 			return 0;
19713b6c3722Schristos 		}
19727cd94d69Schristos 		sldns_buffer_skip(c->buffer, (ssize_t)(c->tcp_byte_count-sizeof(uint16_t)));
19733b6c3722Schristos 		verbose(VERB_ALGO, "Reading ssl tcp query of length %d",
19743b6c3722Schristos 			(int)sldns_buffer_limit(c->buffer));
19753b6c3722Schristos 	}
19767cd94d69Schristos 	if(sldns_buffer_remaining(c->buffer) > 0) {
19773b6c3722Schristos 		ERR_clear_error();
19783b6c3722Schristos 		r = SSL_read(c->ssl, (void*)sldns_buffer_current(c->buffer),
19793b6c3722Schristos 			(int)sldns_buffer_remaining(c->buffer));
19803b6c3722Schristos 		if(r <= 0) {
19813b6c3722Schristos 			int want = SSL_get_error(c->ssl, r);
19823b6c3722Schristos 			if(want == SSL_ERROR_ZERO_RETURN) {
1983f42d8de7Schristos 				if(c->tcp_req_info)
1984f42d8de7Schristos 					return tcp_req_info_handle_read_close(c->tcp_req_info);
19853b6c3722Schristos 				return 0; /* shutdown, closed */
19863b6c3722Schristos 			} else if(want == SSL_ERROR_WANT_READ) {
19871481e2a9Schristos #ifdef USE_WINSOCK
19887cd94d69Schristos 				ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
19891481e2a9Schristos #endif
19903b6c3722Schristos 				return 1; /* read more later */
19913b6c3722Schristos 			} else if(want == SSL_ERROR_WANT_WRITE) {
19923b6c3722Schristos 				c->ssl_shake_state = comm_ssl_shake_hs_write;
19933b6c3722Schristos 				comm_point_listen_for_rw(c, 0, 1);
19943b6c3722Schristos 				return 1;
19953b6c3722Schristos 			} else if(want == SSL_ERROR_SYSCALL) {
199687edd195Schristos #ifdef ECONNRESET
199787edd195Schristos 				if(errno == ECONNRESET && verbosity < 2)
199887edd195Schristos 					return 0; /* silence reset by peer */
199987edd195Schristos #endif
20003b6c3722Schristos 				if(errno != 0)
20013b6c3722Schristos 					log_err("SSL_read syscall: %s",
20023b6c3722Schristos 						strerror(errno));
20033b6c3722Schristos 				return 0;
20043b6c3722Schristos 			}
2005*14b2fa6eSchristos 			log_crypto_err_io("could not SSL_read", want);
20063b6c3722Schristos 			return 0;
20073b6c3722Schristos 		}
20083b6c3722Schristos 		sldns_buffer_skip(c->buffer, (ssize_t)r);
20097cd94d69Schristos 	}
20103b6c3722Schristos 	if(sldns_buffer_remaining(c->buffer) <= 0) {
20113b6c3722Schristos 		tcp_callback_reader(c);
20123b6c3722Schristos 	}
20133b6c3722Schristos 	return 1;
20143b6c3722Schristos #else
20153b6c3722Schristos 	(void)c;
20163b6c3722Schristos 	return 0;
20173b6c3722Schristos #endif /* HAVE_SSL */
20183b6c3722Schristos }
20193b6c3722Schristos 
20203b6c3722Schristos /** ssl write callback on TCP */
20213b6c3722Schristos static int
20223b6c3722Schristos ssl_handle_write(struct comm_point* c)
20233b6c3722Schristos {
20243b6c3722Schristos #ifdef HAVE_SSL
20253b6c3722Schristos 	int r;
20263b6c3722Schristos 	if(c->ssl_shake_state != comm_ssl_shake_none) {
20273b6c3722Schristos 		if(!ssl_handshake(c))
20283b6c3722Schristos 			return 0;
20293b6c3722Schristos 		if(c->ssl_shake_state != comm_ssl_shake_none)
20303b6c3722Schristos 			return 1;
20313b6c3722Schristos 	}
20323b6c3722Schristos 	/* ignore return, if fails we may simply block */
203387edd195Schristos 	(void)SSL_set_mode(c->ssl, (long)SSL_MODE_ENABLE_PARTIAL_WRITE);
203416776186Schristos 	if((c->tcp_write_and_read?c->tcp_write_byte_count:c->tcp_byte_count) < sizeof(uint16_t)) {
203516776186Schristos 		uint16_t len = htons(c->tcp_write_and_read?c->tcp_write_pkt_len:sldns_buffer_limit(c->buffer));
20363b6c3722Schristos 		ERR_clear_error();
203716776186Schristos 		if(c->tcp_write_and_read) {
203816776186Schristos 			if(c->tcp_write_pkt_len + 2 < LDNS_RR_BUF_SIZE) {
203916776186Schristos 				/* combine the tcp length and the query for
204016776186Schristos 				 * write, this emulates writev */
204116776186Schristos 				uint8_t buf[LDNS_RR_BUF_SIZE];
204216776186Schristos 				memmove(buf, &len, sizeof(uint16_t));
204316776186Schristos 				memmove(buf+sizeof(uint16_t),
204416776186Schristos 					c->tcp_write_pkt,
204516776186Schristos 					c->tcp_write_pkt_len);
204616776186Schristos 				r = SSL_write(c->ssl,
204716776186Schristos 					(void*)(buf+c->tcp_write_byte_count),
204816776186Schristos 					c->tcp_write_pkt_len + 2 -
204916776186Schristos 					c->tcp_write_byte_count);
205016776186Schristos 			} else {
205116776186Schristos 				r = SSL_write(c->ssl,
205216776186Schristos 					(void*)(((uint8_t*)&len)+c->tcp_write_byte_count),
205316776186Schristos 					(int)(sizeof(uint16_t)-c->tcp_write_byte_count));
205416776186Schristos 			}
205516776186Schristos 		} else if(sizeof(uint16_t)+sldns_buffer_remaining(c->buffer) <
20567cd94d69Schristos 			LDNS_RR_BUF_SIZE) {
20577cd94d69Schristos 			/* combine the tcp length and the query for write,
20587cd94d69Schristos 			 * this emulates writev */
20597cd94d69Schristos 			uint8_t buf[LDNS_RR_BUF_SIZE];
20607cd94d69Schristos 			memmove(buf, &len, sizeof(uint16_t));
20617cd94d69Schristos 			memmove(buf+sizeof(uint16_t),
20627cd94d69Schristos 				sldns_buffer_current(c->buffer),
20637cd94d69Schristos 				sldns_buffer_remaining(c->buffer));
20647cd94d69Schristos 			r = SSL_write(c->ssl, (void*)(buf+c->tcp_byte_count),
20657cd94d69Schristos 				(int)(sizeof(uint16_t)+
20667cd94d69Schristos 				sldns_buffer_remaining(c->buffer)
20677cd94d69Schristos 				- c->tcp_byte_count));
20687cd94d69Schristos 		} else {
20693b6c3722Schristos 			r = SSL_write(c->ssl,
20703b6c3722Schristos 				(void*)(((uint8_t*)&len)+c->tcp_byte_count),
20713b6c3722Schristos 				(int)(sizeof(uint16_t)-c->tcp_byte_count));
20727cd94d69Schristos 		}
20733b6c3722Schristos 		if(r <= 0) {
20743b6c3722Schristos 			int want = SSL_get_error(c->ssl, r);
20753b6c3722Schristos 			if(want == SSL_ERROR_ZERO_RETURN) {
20763b6c3722Schristos 				return 0; /* closed */
20773b6c3722Schristos 			} else if(want == SSL_ERROR_WANT_READ) {
207887edd195Schristos 				c->ssl_shake_state = comm_ssl_shake_hs_read;
20793b6c3722Schristos 				comm_point_listen_for_rw(c, 1, 0);
20803b6c3722Schristos 				return 1; /* wait for read condition */
20813b6c3722Schristos 			} else if(want == SSL_ERROR_WANT_WRITE) {
20821481e2a9Schristos #ifdef USE_WINSOCK
20837cd94d69Schristos 				ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
20841481e2a9Schristos #endif
20853b6c3722Schristos 				return 1; /* write more later */
20863b6c3722Schristos 			} else if(want == SSL_ERROR_SYSCALL) {
208787edd195Schristos #ifdef EPIPE
208887edd195Schristos 				if(errno == EPIPE && verbosity < 2)
208987edd195Schristos 					return 0; /* silence 'broken pipe' */
209087edd195Schristos #endif
20913b6c3722Schristos 				if(errno != 0)
20923b6c3722Schristos 					log_err("SSL_write syscall: %s",
20933b6c3722Schristos 						strerror(errno));
20943b6c3722Schristos 				return 0;
20953b6c3722Schristos 			}
2096*14b2fa6eSchristos 			log_crypto_err_io("could not SSL_write", want);
20973b6c3722Schristos 			return 0;
20983b6c3722Schristos 		}
209916776186Schristos 		if(c->tcp_write_and_read) {
210016776186Schristos 			c->tcp_write_byte_count += r;
210116776186Schristos 			if(c->tcp_write_byte_count < sizeof(uint16_t))
210216776186Schristos 				return 1;
210316776186Schristos 		} else {
21043b6c3722Schristos 			c->tcp_byte_count += r;
21053b6c3722Schristos 			if(c->tcp_byte_count < sizeof(uint16_t))
21063b6c3722Schristos 				return 1;
21073b6c3722Schristos 			sldns_buffer_set_position(c->buffer, c->tcp_byte_count -
21083b6c3722Schristos 				sizeof(uint16_t));
210916776186Schristos 		}
211016776186Schristos 		if((!c->tcp_write_and_read && sldns_buffer_remaining(c->buffer) == 0) || (c->tcp_write_and_read && c->tcp_write_byte_count == c->tcp_write_pkt_len + 2)) {
21113b6c3722Schristos 			tcp_callback_writer(c);
21123b6c3722Schristos 			return 1;
21133b6c3722Schristos 		}
21143b6c3722Schristos 	}
211516776186Schristos 	log_assert(c->tcp_write_and_read || sldns_buffer_remaining(c->buffer) > 0);
211616776186Schristos 	log_assert(!c->tcp_write_and_read || c->tcp_write_byte_count < c->tcp_write_pkt_len + 2);
21173b6c3722Schristos 	ERR_clear_error();
211816776186Schristos 	if(c->tcp_write_and_read) {
211916776186Schristos 		r = SSL_write(c->ssl, (void*)(c->tcp_write_pkt + c->tcp_write_byte_count - 2),
212016776186Schristos 			(int)(c->tcp_write_pkt_len + 2 - c->tcp_write_byte_count));
212116776186Schristos 	} else {
21223b6c3722Schristos 		r = SSL_write(c->ssl, (void*)sldns_buffer_current(c->buffer),
21233b6c3722Schristos 			(int)sldns_buffer_remaining(c->buffer));
212416776186Schristos 	}
21253b6c3722Schristos 	if(r <= 0) {
21263b6c3722Schristos 		int want = SSL_get_error(c->ssl, r);
21273b6c3722Schristos 		if(want == SSL_ERROR_ZERO_RETURN) {
21283b6c3722Schristos 			return 0; /* closed */
21293b6c3722Schristos 		} else if(want == SSL_ERROR_WANT_READ) {
213087edd195Schristos 			c->ssl_shake_state = comm_ssl_shake_hs_read;
21313b6c3722Schristos 			comm_point_listen_for_rw(c, 1, 0);
21323b6c3722Schristos 			return 1; /* wait for read condition */
21333b6c3722Schristos 		} else if(want == SSL_ERROR_WANT_WRITE) {
21341481e2a9Schristos #ifdef USE_WINSOCK
21357cd94d69Schristos 			ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
21361481e2a9Schristos #endif
21373b6c3722Schristos 			return 1; /* write more later */
21383b6c3722Schristos 		} else if(want == SSL_ERROR_SYSCALL) {
213987edd195Schristos #ifdef EPIPE
214087edd195Schristos 			if(errno == EPIPE && verbosity < 2)
214187edd195Schristos 				return 0; /* silence 'broken pipe' */
214287edd195Schristos #endif
21433b6c3722Schristos 			if(errno != 0)
21443b6c3722Schristos 				log_err("SSL_write syscall: %s",
21453b6c3722Schristos 					strerror(errno));
21463b6c3722Schristos 			return 0;
21473b6c3722Schristos 		}
2148*14b2fa6eSchristos 		log_crypto_err_io("could not SSL_write", want);
21493b6c3722Schristos 		return 0;
21503b6c3722Schristos 	}
215116776186Schristos 	if(c->tcp_write_and_read) {
215216776186Schristos 		c->tcp_write_byte_count += r;
215316776186Schristos 	} else {
21543b6c3722Schristos 		sldns_buffer_skip(c->buffer, (ssize_t)r);
215516776186Schristos 	}
21563b6c3722Schristos 
215716776186Schristos 	if((!c->tcp_write_and_read && sldns_buffer_remaining(c->buffer) == 0) || (c->tcp_write_and_read && c->tcp_write_byte_count == c->tcp_write_pkt_len + 2)) {
21583b6c3722Schristos 		tcp_callback_writer(c);
21593b6c3722Schristos 	}
21603b6c3722Schristos 	return 1;
21613b6c3722Schristos #else
21623b6c3722Schristos 	(void)c;
21633b6c3722Schristos 	return 0;
21643b6c3722Schristos #endif /* HAVE_SSL */
21653b6c3722Schristos }
21663b6c3722Schristos 
21673b6c3722Schristos /** handle ssl tcp connection with dns contents */
21683b6c3722Schristos static int
216916776186Schristos ssl_handle_it(struct comm_point* c, int is_write)
21703b6c3722Schristos {
217116776186Schristos 	/* handle case where renegotiation wants read during write call
217216776186Schristos 	 * or write during read calls */
217316776186Schristos 	if(is_write && c->ssl_shake_state == comm_ssl_shake_hs_write)
217416776186Schristos 		return ssl_handle_read(c);
217516776186Schristos 	else if(!is_write && c->ssl_shake_state == comm_ssl_shake_hs_read)
217616776186Schristos 		return ssl_handle_write(c);
217716776186Schristos 	/* handle read events for read operation and write events for a
217816776186Schristos 	 * write operation */
217916776186Schristos 	else if(!is_write)
21803b6c3722Schristos 		return ssl_handle_read(c);
21813b6c3722Schristos 	return ssl_handle_write(c);
21823b6c3722Schristos }
21833b6c3722Schristos 
2184*14b2fa6eSchristos /**
2185*14b2fa6eSchristos  * Handle tcp reading callback.
21863b6c3722Schristos  * @param fd: file descriptor of socket.
21873b6c3722Schristos  * @param c: comm point to read from into buffer.
21883b6c3722Schristos  * @param short_ok: if true, very short packets are OK (for comm_local).
21893b6c3722Schristos  * @return: 0 on error
21903b6c3722Schristos  */
21913b6c3722Schristos static int
21923b6c3722Schristos comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok)
21933b6c3722Schristos {
21943b6c3722Schristos 	ssize_t r;
2195*14b2fa6eSchristos 	int recv_initial = 0;
21963b6c3722Schristos 	log_assert(c->type == comm_tcp || c->type == comm_local);
21973b6c3722Schristos 	if(c->ssl)
219816776186Schristos 		return ssl_handle_it(c, 0);
219916776186Schristos 	if(!c->tcp_is_reading && !c->tcp_write_and_read)
22003b6c3722Schristos 		return 0;
22013b6c3722Schristos 
22023b6c3722Schristos 	log_assert(fd != -1);
2203*14b2fa6eSchristos 	if(c->pp2_enabled && c->pp2_header_state != pp2_header_done) {
2204*14b2fa6eSchristos 		struct pp2_header* header = NULL;
2205*14b2fa6eSchristos 		size_t want_read_size = 0;
2206*14b2fa6eSchristos 		size_t current_read_size = 0;
2207*14b2fa6eSchristos 		if(c->pp2_header_state == pp2_header_none) {
2208*14b2fa6eSchristos 			want_read_size = PP2_HEADER_SIZE;
2209*14b2fa6eSchristos 			if(sldns_buffer_remaining(c->buffer)<want_read_size) {
2210*14b2fa6eSchristos 				log_err_addr("proxy_protocol: not enough "
2211*14b2fa6eSchristos 					"buffer size to read PROXYv2 header", "",
2212*14b2fa6eSchristos 					&c->repinfo.remote_addr,
2213*14b2fa6eSchristos 					c->repinfo.remote_addrlen);
2214*14b2fa6eSchristos 				return 0;
2215*14b2fa6eSchristos 			}
2216*14b2fa6eSchristos 			verbose(VERB_ALGO, "proxy_protocol: reading fixed "
2217*14b2fa6eSchristos 				"part of PROXYv2 header (len %lu)",
2218*14b2fa6eSchristos 				(unsigned long)want_read_size);
2219*14b2fa6eSchristos 			current_read_size = want_read_size;
2220*14b2fa6eSchristos 			if(c->tcp_byte_count < current_read_size) {
2221*14b2fa6eSchristos 				r = recv(fd, (void*)sldns_buffer_at(c->buffer,
2222*14b2fa6eSchristos 					c->tcp_byte_count),
2223*14b2fa6eSchristos 					current_read_size-c->tcp_byte_count, MSG_DONTWAIT);
2224f42d8de7Schristos 				if(r == 0) {
2225f42d8de7Schristos 					if(c->tcp_req_info)
2226f42d8de7Schristos 						return tcp_req_info_handle_read_close(c->tcp_req_info);
22273b6c3722Schristos 					return 0;
2228f42d8de7Schristos 				} else if(r == -1) {
2229*14b2fa6eSchristos 					goto recv_error_initial;
2230*14b2fa6eSchristos 				}
2231*14b2fa6eSchristos 				c->tcp_byte_count += r;
2232*14b2fa6eSchristos 				sldns_buffer_skip(c->buffer, r);
2233*14b2fa6eSchristos 				if(c->tcp_byte_count != current_read_size) return 1;
2234*14b2fa6eSchristos 				c->pp2_header_state = pp2_header_init;
2235*14b2fa6eSchristos 			}
2236*14b2fa6eSchristos 		}
2237*14b2fa6eSchristos 		if(c->pp2_header_state == pp2_header_init) {
2238*14b2fa6eSchristos 			int err;
2239*14b2fa6eSchristos 			err = pp2_read_header(
2240*14b2fa6eSchristos 				sldns_buffer_begin(c->buffer),
2241*14b2fa6eSchristos 				sldns_buffer_limit(c->buffer));
2242*14b2fa6eSchristos 			if(err) {
2243*14b2fa6eSchristos 				log_err("proxy_protocol: could not parse "
2244*14b2fa6eSchristos 					"PROXYv2 header (%s)",
2245*14b2fa6eSchristos 					pp_lookup_error(err));
2246*14b2fa6eSchristos 				return 0;
2247*14b2fa6eSchristos 			}
2248*14b2fa6eSchristos 			header = (struct pp2_header*)sldns_buffer_begin(c->buffer);
2249*14b2fa6eSchristos 			want_read_size = ntohs(header->len);
2250*14b2fa6eSchristos 			if(sldns_buffer_limit(c->buffer) <
2251*14b2fa6eSchristos 				PP2_HEADER_SIZE + want_read_size) {
2252*14b2fa6eSchristos 				log_err_addr("proxy_protocol: not enough "
2253*14b2fa6eSchristos 					"buffer size to read PROXYv2 header", "",
2254*14b2fa6eSchristos 					&c->repinfo.remote_addr,
2255*14b2fa6eSchristos 					c->repinfo.remote_addrlen);
2256*14b2fa6eSchristos 				return 0;
2257*14b2fa6eSchristos 			}
2258*14b2fa6eSchristos 			verbose(VERB_ALGO, "proxy_protocol: reading variable "
2259*14b2fa6eSchristos 				"part of PROXYv2 header (len %lu)",
2260*14b2fa6eSchristos 				(unsigned long)want_read_size);
2261*14b2fa6eSchristos 			current_read_size = PP2_HEADER_SIZE + want_read_size;
2262*14b2fa6eSchristos 			if(want_read_size == 0) {
2263*14b2fa6eSchristos 				/* nothing more to read; header is complete */
2264*14b2fa6eSchristos 				c->pp2_header_state = pp2_header_done;
2265*14b2fa6eSchristos 			} else if(c->tcp_byte_count < current_read_size) {
2266*14b2fa6eSchristos 				r = recv(fd, (void*)sldns_buffer_at(c->buffer,
2267*14b2fa6eSchristos 					c->tcp_byte_count),
2268*14b2fa6eSchristos 					current_read_size-c->tcp_byte_count, MSG_DONTWAIT);
2269*14b2fa6eSchristos 				if(r == 0) {
2270*14b2fa6eSchristos 					if(c->tcp_req_info)
2271*14b2fa6eSchristos 						return tcp_req_info_handle_read_close(c->tcp_req_info);
2272*14b2fa6eSchristos 					return 0;
2273*14b2fa6eSchristos 				} else if(r == -1) {
2274*14b2fa6eSchristos 					goto recv_error;
2275*14b2fa6eSchristos 				}
2276*14b2fa6eSchristos 				c->tcp_byte_count += r;
2277*14b2fa6eSchristos 				sldns_buffer_skip(c->buffer, r);
2278*14b2fa6eSchristos 				if(c->tcp_byte_count != current_read_size) return 1;
2279*14b2fa6eSchristos 				c->pp2_header_state = pp2_header_done;
2280*14b2fa6eSchristos 			}
2281*14b2fa6eSchristos 		}
2282*14b2fa6eSchristos 		if(c->pp2_header_state != pp2_header_done || !header) {
2283*14b2fa6eSchristos 			log_err_addr("proxy_protocol: wrong state for the "
2284*14b2fa6eSchristos 				"PROXYv2 header", "", &c->repinfo.remote_addr,
2285*14b2fa6eSchristos 				c->repinfo.remote_addrlen);
2286*14b2fa6eSchristos 			return 0;
2287*14b2fa6eSchristos 		}
2288*14b2fa6eSchristos 		sldns_buffer_flip(c->buffer);
2289*14b2fa6eSchristos 		if(!consume_pp2_header(c->buffer, &c->repinfo, 1)) {
2290*14b2fa6eSchristos 			log_err_addr("proxy_protocol: could not consume "
2291*14b2fa6eSchristos 				"PROXYv2 header", "", &c->repinfo.remote_addr,
2292*14b2fa6eSchristos 				c->repinfo.remote_addrlen);
2293*14b2fa6eSchristos 			return 0;
2294*14b2fa6eSchristos 		}
2295*14b2fa6eSchristos 		verbose(VERB_ALGO, "proxy_protocol: successful read of "
2296*14b2fa6eSchristos 			"PROXYv2 header");
2297*14b2fa6eSchristos 		/* Clear and reset the buffer to read the following
2298*14b2fa6eSchristos 		    * DNS packet(s). */
2299*14b2fa6eSchristos 		sldns_buffer_clear(c->buffer);
2300*14b2fa6eSchristos 		c->tcp_byte_count = 0;
2301*14b2fa6eSchristos 		return 1;
2302*14b2fa6eSchristos 	}
2303*14b2fa6eSchristos 
2304*14b2fa6eSchristos 	if(c->tcp_byte_count < sizeof(uint16_t)) {
2305*14b2fa6eSchristos 		/* read length bytes */
2306*14b2fa6eSchristos 		r = recv(fd,(void*)sldns_buffer_at(c->buffer,c->tcp_byte_count),
2307*14b2fa6eSchristos 			sizeof(uint16_t)-c->tcp_byte_count, MSG_DONTWAIT);
2308*14b2fa6eSchristos 		if(r == 0) {
2309*14b2fa6eSchristos 			if(c->tcp_req_info)
2310*14b2fa6eSchristos 				return tcp_req_info_handle_read_close(c->tcp_req_info);
2311*14b2fa6eSchristos 			return 0;
2312*14b2fa6eSchristos 		} else if(r == -1) {
2313*14b2fa6eSchristos 			if(c->pp2_enabled) goto recv_error;
2314*14b2fa6eSchristos 			goto recv_error_initial;
2315*14b2fa6eSchristos 		}
2316*14b2fa6eSchristos 		c->tcp_byte_count += r;
2317*14b2fa6eSchristos 		if(c->tcp_byte_count != sizeof(uint16_t))
2318*14b2fa6eSchristos 			return 1;
2319*14b2fa6eSchristos 		if(sldns_buffer_read_u16_at(c->buffer, 0) >
2320*14b2fa6eSchristos 			sldns_buffer_capacity(c->buffer)) {
2321*14b2fa6eSchristos 			verbose(VERB_QUERY, "tcp: dropped larger than buffer");
2322*14b2fa6eSchristos 			return 0;
2323*14b2fa6eSchristos 		}
2324*14b2fa6eSchristos 		sldns_buffer_set_limit(c->buffer,
2325*14b2fa6eSchristos 			sldns_buffer_read_u16_at(c->buffer, 0));
2326*14b2fa6eSchristos 		if(!short_ok &&
2327*14b2fa6eSchristos 			sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE) {
2328*14b2fa6eSchristos 			verbose(VERB_QUERY, "tcp: dropped bogus too short.");
2329*14b2fa6eSchristos 			return 0;
2330*14b2fa6eSchristos 		}
2331*14b2fa6eSchristos 		verbose(VERB_ALGO, "Reading tcp query of length %d",
2332*14b2fa6eSchristos 			(int)sldns_buffer_limit(c->buffer));
2333*14b2fa6eSchristos 	}
2334*14b2fa6eSchristos 
2335*14b2fa6eSchristos 	if(sldns_buffer_remaining(c->buffer) == 0)
2336*14b2fa6eSchristos 		log_err("in comm_point_tcp_handle_read buffer_remaining is "
2337*14b2fa6eSchristos 			"not > 0 as expected, continuing with (harmless) 0 "
2338*14b2fa6eSchristos 			"length recv");
2339*14b2fa6eSchristos 	r = recv(fd, (void*)sldns_buffer_current(c->buffer),
2340*14b2fa6eSchristos 		sldns_buffer_remaining(c->buffer), MSG_DONTWAIT);
2341*14b2fa6eSchristos 	if(r == 0) {
2342*14b2fa6eSchristos 		if(c->tcp_req_info)
2343*14b2fa6eSchristos 			return tcp_req_info_handle_read_close(c->tcp_req_info);
2344*14b2fa6eSchristos 		return 0;
2345*14b2fa6eSchristos 	} else if(r == -1) {
2346*14b2fa6eSchristos 		goto recv_error;
2347*14b2fa6eSchristos 	}
2348*14b2fa6eSchristos 	sldns_buffer_skip(c->buffer, r);
2349*14b2fa6eSchristos 	if(sldns_buffer_remaining(c->buffer) <= 0) {
2350*14b2fa6eSchristos 		tcp_callback_reader(c);
2351*14b2fa6eSchristos 	}
2352*14b2fa6eSchristos 	return 1;
2353*14b2fa6eSchristos 
2354*14b2fa6eSchristos recv_error_initial:
2355*14b2fa6eSchristos 	recv_initial = 1;
2356*14b2fa6eSchristos recv_error:
23573b6c3722Schristos #ifndef USE_WINSOCK
23583b6c3722Schristos 	if(errno == EINTR || errno == EAGAIN)
23593b6c3722Schristos 		return 1;
2360*14b2fa6eSchristos 	if(recv_initial) {
23613b6c3722Schristos #ifdef ECONNRESET
23623b6c3722Schristos 		if(errno == ECONNRESET && verbosity < 2)
23633b6c3722Schristos 			return 0; /* silence reset by peer */
23643b6c3722Schristos #endif
23651481e2a9Schristos #ifdef ECONNREFUSED
23661481e2a9Schristos 		if(errno == ECONNREFUSED && verbosity < 2)
23671481e2a9Schristos 			return 0; /* silence reset by peer */
23681481e2a9Schristos #endif
236916776186Schristos #ifdef ENETUNREACH
237016776186Schristos 		if(errno == ENETUNREACH && verbosity < 2)
237116776186Schristos 			return 0; /* silence it */
237216776186Schristos #endif
237316776186Schristos #ifdef EHOSTDOWN
237416776186Schristos 		if(errno == EHOSTDOWN && verbosity < 2)
237516776186Schristos 			return 0; /* silence it */
237616776186Schristos #endif
237716776186Schristos #ifdef EHOSTUNREACH
237816776186Schristos 		if(errno == EHOSTUNREACH && verbosity < 2)
237916776186Schristos 			return 0; /* silence it */
238016776186Schristos #endif
238116776186Schristos #ifdef ENETDOWN
238216776186Schristos 		if(errno == ENETDOWN && verbosity < 2)
238316776186Schristos 			return 0; /* silence it */
238416776186Schristos #endif
238516776186Schristos #ifdef EACCES
238616776186Schristos 		if(errno == EACCES && verbosity < 2)
238716776186Schristos 			return 0; /* silence it */
238816776186Schristos #endif
238916776186Schristos #ifdef ENOTCONN
239016776186Schristos 		if(errno == ENOTCONN) {
2391*14b2fa6eSchristos 			log_err_addr("read (in tcp s) failed and this "
2392*14b2fa6eSchristos 				"could be because TCP Fast Open is "
2393*14b2fa6eSchristos 				"enabled [--disable-tfo-client "
2394*14b2fa6eSchristos 				"--disable-tfo-server] but does not "
2395*14b2fa6eSchristos 				"work", sock_strerror(errno),
2396*14b2fa6eSchristos 				&c->repinfo.remote_addr,
2397*14b2fa6eSchristos 				c->repinfo.remote_addrlen);
239816776186Schristos 			return 0;
239916776186Schristos 		}
240016776186Schristos #endif
2401*14b2fa6eSchristos 	}
24023b6c3722Schristos #else /* USE_WINSOCK */
2403*14b2fa6eSchristos 	if(recv_initial) {
24041481e2a9Schristos 		if(WSAGetLastError() == WSAECONNREFUSED && verbosity < 2)
24051481e2a9Schristos 			return 0;
24061481e2a9Schristos 		if(WSAGetLastError() == WSAEHOSTDOWN && verbosity < 2)
24071481e2a9Schristos 			return 0;
24081481e2a9Schristos 		if(WSAGetLastError() == WSAEHOSTUNREACH && verbosity < 2)
24091481e2a9Schristos 			return 0;
24101481e2a9Schristos 		if(WSAGetLastError() == WSAENETDOWN && verbosity < 2)
24111481e2a9Schristos 			return 0;
24121481e2a9Schristos 		if(WSAGetLastError() == WSAENETUNREACH && verbosity < 2)
24131481e2a9Schristos 			return 0;
2414*14b2fa6eSchristos 	}
24153b6c3722Schristos 	if(WSAGetLastError() == WSAECONNRESET)
24163b6c3722Schristos 		return 0;
24173b6c3722Schristos 	if(WSAGetLastError() == WSAEINPROGRESS)
24183b6c3722Schristos 		return 1;
24193b6c3722Schristos 	if(WSAGetLastError() == WSAEWOULDBLOCK) {
24203b6c3722Schristos 		ub_winsock_tcp_wouldblock(c->ev->ev,
24213b6c3722Schristos 			UB_EV_READ);
24223b6c3722Schristos 		return 1;
24233b6c3722Schristos 	}
24243b6c3722Schristos #endif
242516776186Schristos 	log_err_addr("read (in tcp s)", sock_strerror(errno),
2426*14b2fa6eSchristos 		&c->repinfo.remote_addr, c->repinfo.remote_addrlen);
24273b6c3722Schristos 	return 0;
24283b6c3722Schristos }
24293b6c3722Schristos 
24303b6c3722Schristos /**
24313b6c3722Schristos  * Handle tcp writing callback.
24323b6c3722Schristos  * @param fd: file descriptor of socket.
24333b6c3722Schristos  * @param c: comm point to write buffer out of.
24343b6c3722Schristos  * @return: 0 on error
24353b6c3722Schristos  */
24363b6c3722Schristos static int
24373b6c3722Schristos comm_point_tcp_handle_write(int fd, struct comm_point* c)
24383b6c3722Schristos {
24393b6c3722Schristos 	ssize_t r;
24400cd9f4ecSchristos 	struct sldns_buffer *buffer;
24413b6c3722Schristos 	log_assert(c->type == comm_tcp);
24420cd9f4ecSchristos #ifdef USE_DNSCRYPT
24430cd9f4ecSchristos 	buffer = c->dnscrypt_buffer;
24440cd9f4ecSchristos #else
24450cd9f4ecSchristos 	buffer = c->buffer;
24460cd9f4ecSchristos #endif
244716776186Schristos 	if(c->tcp_is_reading && !c->ssl && !c->tcp_write_and_read)
24483b6c3722Schristos 		return 0;
24493b6c3722Schristos 	log_assert(fd != -1);
245016776186Schristos 	if(((!c->tcp_write_and_read && c->tcp_byte_count == 0) || (c->tcp_write_and_read && c->tcp_write_byte_count == 0)) && c->tcp_check_nb_connect) {
24513b6c3722Schristos 		/* check for pending error from nonblocking connect */
24523b6c3722Schristos 		/* from Stevens, unix network programming, vol1, 3rd ed, p450*/
24533b6c3722Schristos 		int error = 0;
24543b6c3722Schristos 		socklen_t len = (socklen_t)sizeof(error);
24553b6c3722Schristos 		if(getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&error,
24563b6c3722Schristos 			&len) < 0){
24573b6c3722Schristos #ifndef USE_WINSOCK
24583b6c3722Schristos 			error = errno; /* on solaris errno is error */
24593b6c3722Schristos #else /* USE_WINSOCK */
24603b6c3722Schristos 			error = WSAGetLastError();
24613b6c3722Schristos #endif
24623b6c3722Schristos 		}
24633b6c3722Schristos #ifndef USE_WINSOCK
24643b6c3722Schristos #if defined(EINPROGRESS) && defined(EWOULDBLOCK)
24653b6c3722Schristos 		if(error == EINPROGRESS || error == EWOULDBLOCK)
24663b6c3722Schristos 			return 1; /* try again later */
24673b6c3722Schristos 		else
24683b6c3722Schristos #endif
24693b6c3722Schristos 		if(error != 0 && verbosity < 2)
24703b6c3722Schristos 			return 0; /* silence lots of chatter in the logs */
24713b6c3722Schristos                 else if(error != 0) {
24723b6c3722Schristos 			log_err_addr("tcp connect", strerror(error),
2473*14b2fa6eSchristos 				&c->repinfo.remote_addr,
2474*14b2fa6eSchristos 				c->repinfo.remote_addrlen);
24753b6c3722Schristos #else /* USE_WINSOCK */
24763b6c3722Schristos 		/* examine error */
24773b6c3722Schristos 		if(error == WSAEINPROGRESS)
24783b6c3722Schristos 			return 1;
24793b6c3722Schristos 		else if(error == WSAEWOULDBLOCK) {
24803b6c3722Schristos 			ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
24813b6c3722Schristos 			return 1;
24823b6c3722Schristos 		} else if(error != 0 && verbosity < 2)
24833b6c3722Schristos 			return 0;
24843b6c3722Schristos 		else if(error != 0) {
24853b6c3722Schristos 			log_err_addr("tcp connect", wsa_strerror(error),
2486*14b2fa6eSchristos 				&c->repinfo.remote_addr,
2487*14b2fa6eSchristos 				c->repinfo.remote_addrlen);
24883b6c3722Schristos #endif /* USE_WINSOCK */
24893b6c3722Schristos 			return 0;
24903b6c3722Schristos 		}
24913b6c3722Schristos 	}
24923b6c3722Schristos 	if(c->ssl)
249316776186Schristos 		return ssl_handle_it(c, 1);
24943b6c3722Schristos 
24950cd9f4ecSchristos #ifdef USE_MSG_FASTOPEN
24960cd9f4ecSchristos 	/* Only try this on first use of a connection that uses tfo,
24970cd9f4ecSchristos 	   otherwise fall through to normal write */
24980cd9f4ecSchristos 	/* Also, TFO support on WINDOWS not implemented at the moment */
24990cd9f4ecSchristos 	if(c->tcp_do_fastopen == 1) {
25000cd9f4ecSchristos 		/* this form of sendmsg() does both a connect() and send() so need to
25010cd9f4ecSchristos 		   look for various flavours of error*/
250216776186Schristos 		uint16_t len = htons(c->tcp_write_and_read?c->tcp_write_pkt_len:sldns_buffer_limit(buffer));
25030cd9f4ecSchristos 		struct msghdr msg;
25040cd9f4ecSchristos 		struct iovec iov[2];
25050cd9f4ecSchristos 		c->tcp_do_fastopen = 0;
25060cd9f4ecSchristos 		memset(&msg, 0, sizeof(msg));
250716776186Schristos 		if(c->tcp_write_and_read) {
250816776186Schristos 			iov[0].iov_base = (uint8_t*)&len + c->tcp_write_byte_count;
250916776186Schristos 			iov[0].iov_len = sizeof(uint16_t) - c->tcp_write_byte_count;
251016776186Schristos 			iov[1].iov_base = c->tcp_write_pkt;
251116776186Schristos 			iov[1].iov_len = c->tcp_write_pkt_len;
251216776186Schristos 		} else {
25130cd9f4ecSchristos 			iov[0].iov_base = (uint8_t*)&len + c->tcp_byte_count;
25140cd9f4ecSchristos 			iov[0].iov_len = sizeof(uint16_t) - c->tcp_byte_count;
25150cd9f4ecSchristos 			iov[1].iov_base = sldns_buffer_begin(buffer);
25160cd9f4ecSchristos 			iov[1].iov_len = sldns_buffer_limit(buffer);
251716776186Schristos 		}
25180cd9f4ecSchristos 		log_assert(iov[0].iov_len > 0);
2519*14b2fa6eSchristos 		msg.msg_name = &c->repinfo.remote_addr;
2520*14b2fa6eSchristos 		msg.msg_namelen = c->repinfo.remote_addrlen;
25210cd9f4ecSchristos 		msg.msg_iov = iov;
25220cd9f4ecSchristos 		msg.msg_iovlen = 2;
25230cd9f4ecSchristos 		r = sendmsg(fd, &msg, MSG_FASTOPEN);
25240cd9f4ecSchristos 		if (r == -1) {
25250cd9f4ecSchristos #if defined(EINPROGRESS) && defined(EWOULDBLOCK)
25260cd9f4ecSchristos 			/* Handshake is underway, maybe because no TFO cookie available.
25270cd9f4ecSchristos 			   Come back to write the message*/
25280cd9f4ecSchristos 			if(errno == EINPROGRESS || errno == EWOULDBLOCK)
25290cd9f4ecSchristos 				return 1;
25300cd9f4ecSchristos #endif
25310cd9f4ecSchristos 			if(errno == EINTR || errno == EAGAIN)
25320cd9f4ecSchristos 				return 1;
25330cd9f4ecSchristos 			/* Not handling EISCONN here as shouldn't ever hit that case.*/
25341481e2a9Schristos 			if(errno != EPIPE
25351481e2a9Schristos #ifdef EOPNOTSUPP
25361481e2a9Schristos 				/* if /proc/sys/net/ipv4/tcp_fastopen is
25371481e2a9Schristos 				 * disabled on Linux, sendmsg may return
25381481e2a9Schristos 				 * 'Operation not supported', if so
25391481e2a9Schristos 				 * fallthrough to ordinary connect. */
25401481e2a9Schristos 				&& errno != EOPNOTSUPP
25411481e2a9Schristos #endif
25421481e2a9Schristos 				&& errno != 0) {
25431481e2a9Schristos 				if(verbosity < 2)
25440cd9f4ecSchristos 					return 0; /* silence lots of chatter in the logs */
25450cd9f4ecSchristos 				log_err_addr("tcp sendmsg", strerror(errno),
2546*14b2fa6eSchristos 					&c->repinfo.remote_addr,
2547*14b2fa6eSchristos 					c->repinfo.remote_addrlen);
25480cd9f4ecSchristos 				return 0;
25490cd9f4ecSchristos 			}
25501481e2a9Schristos 			verbose(VERB_ALGO, "tcp sendmsg for fastopen failed (with %s), try normal connect", strerror(errno));
25510cd9f4ecSchristos 			/* fallthrough to nonFASTOPEN
25520cd9f4ecSchristos 			 * (MSG_FASTOPEN on Linux 3 produces EPIPE)
25530cd9f4ecSchristos 			 * we need to perform connect() */
2554*14b2fa6eSchristos 			if(connect(fd, (struct sockaddr *)&c->repinfo.remote_addr,
2555*14b2fa6eSchristos 				c->repinfo.remote_addrlen) == -1) {
25560cd9f4ecSchristos #ifdef EINPROGRESS
25570cd9f4ecSchristos 				if(errno == EINPROGRESS)
25580cd9f4ecSchristos 					return 1; /* wait until connect done*/
25590cd9f4ecSchristos #endif
25600cd9f4ecSchristos #ifdef USE_WINSOCK
25610cd9f4ecSchristos 				if(WSAGetLastError() == WSAEINPROGRESS ||
25620cd9f4ecSchristos 					WSAGetLastError() == WSAEWOULDBLOCK)
25630cd9f4ecSchristos 					return 1; /* wait until connect done*/
25640cd9f4ecSchristos #endif
25650cd9f4ecSchristos 				if(tcp_connect_errno_needs_log(
2566*14b2fa6eSchristos 					(struct sockaddr *)&c->repinfo.remote_addr,
2567*14b2fa6eSchristos 					c->repinfo.remote_addrlen)) {
25680cd9f4ecSchristos 					log_err_addr("outgoing tcp: connect after EPIPE for fastopen",
2569*14b2fa6eSchristos 						strerror(errno),
2570*14b2fa6eSchristos 						&c->repinfo.remote_addr,
2571*14b2fa6eSchristos 						c->repinfo.remote_addrlen);
25720cd9f4ecSchristos 				}
25730cd9f4ecSchristos 				return 0;
25740cd9f4ecSchristos 			}
25750cd9f4ecSchristos 
25760cd9f4ecSchristos 		} else {
257716776186Schristos 			if(c->tcp_write_and_read) {
257816776186Schristos 				c->tcp_write_byte_count += r;
257916776186Schristos 				if(c->tcp_write_byte_count < sizeof(uint16_t))
258016776186Schristos 					return 1;
258116776186Schristos 			} else {
25820cd9f4ecSchristos 				c->tcp_byte_count += r;
25830cd9f4ecSchristos 				if(c->tcp_byte_count < sizeof(uint16_t))
25840cd9f4ecSchristos 					return 1;
25850cd9f4ecSchristos 				sldns_buffer_set_position(buffer, c->tcp_byte_count -
25860cd9f4ecSchristos 					sizeof(uint16_t));
258716776186Schristos 			}
258816776186Schristos 			if((!c->tcp_write_and_read && sldns_buffer_remaining(buffer) == 0) || (c->tcp_write_and_read && c->tcp_write_byte_count == c->tcp_write_pkt_len + 2)) {
25890cd9f4ecSchristos 				tcp_callback_writer(c);
25900cd9f4ecSchristos 				return 1;
25910cd9f4ecSchristos 			}
25920cd9f4ecSchristos 		}
25930cd9f4ecSchristos 	}
25940cd9f4ecSchristos #endif /* USE_MSG_FASTOPEN */
25950cd9f4ecSchristos 
259616776186Schristos 	if((c->tcp_write_and_read?c->tcp_write_byte_count:c->tcp_byte_count) < sizeof(uint16_t)) {
259716776186Schristos 		uint16_t len = htons(c->tcp_write_and_read?c->tcp_write_pkt_len:sldns_buffer_limit(buffer));
25983b6c3722Schristos #ifdef HAVE_WRITEV
25993b6c3722Schristos 		struct iovec iov[2];
260016776186Schristos 		if(c->tcp_write_and_read) {
260116776186Schristos 			iov[0].iov_base = (uint8_t*)&len + c->tcp_write_byte_count;
260216776186Schristos 			iov[0].iov_len = sizeof(uint16_t) - c->tcp_write_byte_count;
260316776186Schristos 			iov[1].iov_base = c->tcp_write_pkt;
260416776186Schristos 			iov[1].iov_len = c->tcp_write_pkt_len;
260516776186Schristos 		} else {
26063b6c3722Schristos 			iov[0].iov_base = (uint8_t*)&len + c->tcp_byte_count;
26073b6c3722Schristos 			iov[0].iov_len = sizeof(uint16_t) - c->tcp_byte_count;
26080cd9f4ecSchristos 			iov[1].iov_base = sldns_buffer_begin(buffer);
26090cd9f4ecSchristos 			iov[1].iov_len = sldns_buffer_limit(buffer);
261016776186Schristos 		}
26113b6c3722Schristos 		log_assert(iov[0].iov_len > 0);
26123b6c3722Schristos 		r = writev(fd, iov, 2);
26133b6c3722Schristos #else /* HAVE_WRITEV */
261416776186Schristos 		if(c->tcp_write_and_read) {
261516776186Schristos 			r = send(fd, (void*)(((uint8_t*)&len)+c->tcp_write_byte_count),
261616776186Schristos 				sizeof(uint16_t)-c->tcp_write_byte_count, 0);
261716776186Schristos 		} else {
26183b6c3722Schristos 			r = send(fd, (void*)(((uint8_t*)&len)+c->tcp_byte_count),
26193b6c3722Schristos 				sizeof(uint16_t)-c->tcp_byte_count, 0);
262016776186Schristos 		}
26213b6c3722Schristos #endif /* HAVE_WRITEV */
26223b6c3722Schristos 		if(r == -1) {
26233b6c3722Schristos #ifndef USE_WINSOCK
26243b6c3722Schristos #  ifdef EPIPE
26253b6c3722Schristos                 	if(errno == EPIPE && verbosity < 2)
26263b6c3722Schristos                         	return 0; /* silence 'broken pipe' */
26273b6c3722Schristos   #endif
26283b6c3722Schristos 			if(errno == EINTR || errno == EAGAIN)
26293b6c3722Schristos 				return 1;
263087edd195Schristos #ifdef ECONNRESET
263187edd195Schristos 			if(errno == ECONNRESET && verbosity < 2)
263287edd195Schristos 				return 0; /* silence reset by peer */
263387edd195Schristos #endif
26343b6c3722Schristos #  ifdef HAVE_WRITEV
26353b6c3722Schristos 			log_err_addr("tcp writev", strerror(errno),
2636*14b2fa6eSchristos 				&c->repinfo.remote_addr,
2637*14b2fa6eSchristos 				c->repinfo.remote_addrlen);
26383b6c3722Schristos #  else /* HAVE_WRITEV */
26393b6c3722Schristos 			log_err_addr("tcp send s", strerror(errno),
2640*14b2fa6eSchristos 				&c->repinfo.remote_addr,
2641*14b2fa6eSchristos 				c->repinfo.remote_addrlen);
26423b6c3722Schristos #  endif /* HAVE_WRITEV */
26433b6c3722Schristos #else
26443b6c3722Schristos 			if(WSAGetLastError() == WSAENOTCONN)
26453b6c3722Schristos 				return 1;
26463b6c3722Schristos 			if(WSAGetLastError() == WSAEINPROGRESS)
26473b6c3722Schristos 				return 1;
26483b6c3722Schristos 			if(WSAGetLastError() == WSAEWOULDBLOCK) {
26493b6c3722Schristos 				ub_winsock_tcp_wouldblock(c->ev->ev,
26503b6c3722Schristos 					UB_EV_WRITE);
26513b6c3722Schristos 				return 1;
26523b6c3722Schristos 			}
265387edd195Schristos 			if(WSAGetLastError() == WSAECONNRESET && verbosity < 2)
265487edd195Schristos 				return 0; /* silence reset by peer */
26553b6c3722Schristos 			log_err_addr("tcp send s",
26563b6c3722Schristos 				wsa_strerror(WSAGetLastError()),
2657*14b2fa6eSchristos 				&c->repinfo.remote_addr,
2658*14b2fa6eSchristos 				c->repinfo.remote_addrlen);
26593b6c3722Schristos #endif
26603b6c3722Schristos 			return 0;
26613b6c3722Schristos 		}
266216776186Schristos 		if(c->tcp_write_and_read) {
266316776186Schristos 			c->tcp_write_byte_count += r;
266416776186Schristos 			if(c->tcp_write_byte_count < sizeof(uint16_t))
266516776186Schristos 				return 1;
266616776186Schristos 		} else {
26673b6c3722Schristos 			c->tcp_byte_count += r;
26683b6c3722Schristos 			if(c->tcp_byte_count < sizeof(uint16_t))
26693b6c3722Schristos 				return 1;
26700cd9f4ecSchristos 			sldns_buffer_set_position(buffer, c->tcp_byte_count -
26713b6c3722Schristos 				sizeof(uint16_t));
267216776186Schristos 		}
267316776186Schristos 		if((!c->tcp_write_and_read && sldns_buffer_remaining(buffer) == 0) || (c->tcp_write_and_read && c->tcp_write_byte_count == c->tcp_write_pkt_len + 2)) {
26743b6c3722Schristos 			tcp_callback_writer(c);
26753b6c3722Schristos 			return 1;
26763b6c3722Schristos 		}
26773b6c3722Schristos 	}
267816776186Schristos 	log_assert(c->tcp_write_and_read || sldns_buffer_remaining(buffer) > 0);
267916776186Schristos 	log_assert(!c->tcp_write_and_read || c->tcp_write_byte_count < c->tcp_write_pkt_len + 2);
268016776186Schristos 	if(c->tcp_write_and_read) {
268116776186Schristos 		r = send(fd, (void*)(c->tcp_write_pkt + c->tcp_write_byte_count - 2),
268216776186Schristos 			c->tcp_write_pkt_len + 2 - c->tcp_write_byte_count, 0);
268316776186Schristos 	} else {
26840cd9f4ecSchristos 		r = send(fd, (void*)sldns_buffer_current(buffer),
26850cd9f4ecSchristos 			sldns_buffer_remaining(buffer), 0);
268616776186Schristos 	}
26873b6c3722Schristos 	if(r == -1) {
26883b6c3722Schristos #ifndef USE_WINSOCK
26893b6c3722Schristos 		if(errno == EINTR || errno == EAGAIN)
26903b6c3722Schristos 			return 1;
269187edd195Schristos #ifdef ECONNRESET
269287edd195Schristos 		if(errno == ECONNRESET && verbosity < 2)
269387edd195Schristos 			return 0; /* silence reset by peer */
269487edd195Schristos #endif
26953b6c3722Schristos #else
26963b6c3722Schristos 		if(WSAGetLastError() == WSAEINPROGRESS)
26973b6c3722Schristos 			return 1;
26983b6c3722Schristos 		if(WSAGetLastError() == WSAEWOULDBLOCK) {
26993b6c3722Schristos 			ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
27003b6c3722Schristos 			return 1;
27013b6c3722Schristos 		}
270287edd195Schristos 		if(WSAGetLastError() == WSAECONNRESET && verbosity < 2)
270387edd195Schristos 			return 0; /* silence reset by peer */
27043b6c3722Schristos #endif
270516776186Schristos 		log_err_addr("tcp send r", sock_strerror(errno),
2706*14b2fa6eSchristos 			&c->repinfo.remote_addr,
2707*14b2fa6eSchristos 			c->repinfo.remote_addrlen);
27083b6c3722Schristos 		return 0;
27093b6c3722Schristos 	}
271016776186Schristos 	if(c->tcp_write_and_read) {
271116776186Schristos 		c->tcp_write_byte_count += r;
271216776186Schristos 	} else {
27130cd9f4ecSchristos 		sldns_buffer_skip(buffer, r);
271416776186Schristos 	}
27153b6c3722Schristos 
271616776186Schristos 	if((!c->tcp_write_and_read && sldns_buffer_remaining(buffer) == 0) || (c->tcp_write_and_read && c->tcp_write_byte_count == c->tcp_write_pkt_len + 2)) {
27173b6c3722Schristos 		tcp_callback_writer(c);
27183b6c3722Schristos 	}
27193b6c3722Schristos 
27203b6c3722Schristos 	return 1;
27213b6c3722Schristos }
27223b6c3722Schristos 
2723*14b2fa6eSchristos /** read again to drain buffers when there could be more to read, returns 0
2724*14b2fa6eSchristos  * on failure which means the comm point is closed. */
2725*14b2fa6eSchristos static int
2726f42d8de7Schristos tcp_req_info_read_again(int fd, struct comm_point* c)
2727f42d8de7Schristos {
2728f42d8de7Schristos 	while(c->tcp_req_info->read_again) {
2729f42d8de7Schristos 		int r;
2730f42d8de7Schristos 		c->tcp_req_info->read_again = 0;
2731f42d8de7Schristos 		if(c->tcp_is_reading)
2732f42d8de7Schristos 			r = comm_point_tcp_handle_read(fd, c, 0);
2733f42d8de7Schristos 		else 	r = comm_point_tcp_handle_write(fd, c);
2734f42d8de7Schristos 		if(!r) {
2735f42d8de7Schristos 			reclaim_tcp_handler(c);
2736f42d8de7Schristos 			if(!c->tcp_do_close) {
2737f42d8de7Schristos 				fptr_ok(fptr_whitelist_comm_point(
2738f42d8de7Schristos 					c->callback));
2739f42d8de7Schristos 				(void)(*c->callback)(c, c->cb_arg,
2740f42d8de7Schristos 					NETEVENT_CLOSED, NULL);
2741f42d8de7Schristos 			}
2742*14b2fa6eSchristos 			return 0;
2743f42d8de7Schristos 		}
2744f42d8de7Schristos 	}
2745*14b2fa6eSchristos 	return 1;
2746f42d8de7Schristos }
2747f42d8de7Schristos 
274816776186Schristos /** read again to drain buffers when there could be more to read */
274916776186Schristos static void
275016776186Schristos tcp_more_read_again(int fd, struct comm_point* c)
275116776186Schristos {
275216776186Schristos 	/* if the packet is done, but another one could be waiting on
275316776186Schristos 	 * the connection, the callback signals this, and we try again */
275416776186Schristos 	/* this continues until the read routines get EAGAIN or so,
275516776186Schristos 	 * and thus does not call the callback, and the bool is 0 */
275616776186Schristos 	int* moreread = c->tcp_more_read_again;
275716776186Schristos 	while(moreread && *moreread) {
275816776186Schristos 		*moreread = 0;
275916776186Schristos 		if(!comm_point_tcp_handle_read(fd, c, 0)) {
276016776186Schristos 			reclaim_tcp_handler(c);
276116776186Schristos 			if(!c->tcp_do_close) {
276216776186Schristos 				fptr_ok(fptr_whitelist_comm_point(
276316776186Schristos 					c->callback));
276416776186Schristos 				(void)(*c->callback)(c, c->cb_arg,
276516776186Schristos 					NETEVENT_CLOSED, NULL);
276616776186Schristos 			}
276716776186Schristos 			return;
276816776186Schristos 		}
276916776186Schristos 	}
277016776186Schristos }
277116776186Schristos 
277216776186Schristos /** write again to fill up when there could be more to write */
277316776186Schristos static void
277416776186Schristos tcp_more_write_again(int fd, struct comm_point* c)
277516776186Schristos {
277616776186Schristos 	/* if the packet is done, but another is waiting to be written,
277716776186Schristos 	 * the callback signals it and we try again. */
277816776186Schristos 	/* this continues until the write routines get EAGAIN or so,
277916776186Schristos 	 * and thus does not call the callback, and the bool is 0 */
278016776186Schristos 	int* morewrite = c->tcp_more_write_again;
278116776186Schristos 	while(morewrite && *morewrite) {
278216776186Schristos 		*morewrite = 0;
278316776186Schristos 		if(!comm_point_tcp_handle_write(fd, c)) {
278416776186Schristos 			reclaim_tcp_handler(c);
278516776186Schristos 			if(!c->tcp_do_close) {
278616776186Schristos 				fptr_ok(fptr_whitelist_comm_point(
278716776186Schristos 					c->callback));
278816776186Schristos 				(void)(*c->callback)(c, c->cb_arg,
278916776186Schristos 					NETEVENT_CLOSED, NULL);
279016776186Schristos 			}
279116776186Schristos 			return;
279216776186Schristos 		}
279316776186Schristos 	}
279416776186Schristos }
279516776186Schristos 
27963b6c3722Schristos void
27973b6c3722Schristos comm_point_tcp_handle_callback(int fd, short event, void* arg)
27983b6c3722Schristos {
27993b6c3722Schristos 	struct comm_point* c = (struct comm_point*)arg;
28003b6c3722Schristos 	log_assert(c->type == comm_tcp);
28013b6c3722Schristos 	ub_comm_base_now(c->ev->base);
28023b6c3722Schristos 
2803*14b2fa6eSchristos 	if(c->fd == -1 || c->fd != fd)
2804*14b2fa6eSchristos 		return; /* duplicate event, but commpoint closed. */
2805*14b2fa6eSchristos 
28060cd9f4ecSchristos #ifdef USE_DNSCRYPT
28070cd9f4ecSchristos 	/* Initialize if this is a dnscrypt socket */
28080cd9f4ecSchristos 	if(c->tcp_parent) {
28090cd9f4ecSchristos 		c->dnscrypt = c->tcp_parent->dnscrypt;
28100cd9f4ecSchristos 	}
28110cd9f4ecSchristos 	if(c->dnscrypt && c->dnscrypt_buffer == c->buffer) {
28120cd9f4ecSchristos 		c->dnscrypt_buffer = sldns_buffer_new(sldns_buffer_capacity(c->buffer));
28130cd9f4ecSchristos 		if(!c->dnscrypt_buffer) {
28140cd9f4ecSchristos 			log_err("Could not allocate dnscrypt buffer");
28150cd9f4ecSchristos 			reclaim_tcp_handler(c);
28160cd9f4ecSchristos 			if(!c->tcp_do_close) {
28170cd9f4ecSchristos 				fptr_ok(fptr_whitelist_comm_point(
28180cd9f4ecSchristos 					c->callback));
28190cd9f4ecSchristos 				(void)(*c->callback)(c, c->cb_arg,
28200cd9f4ecSchristos 					NETEVENT_CLOSED, NULL);
28210cd9f4ecSchristos 			}
28220cd9f4ecSchristos 			return;
28230cd9f4ecSchristos 		}
28240cd9f4ecSchristos 	}
28250cd9f4ecSchristos #endif
28260cd9f4ecSchristos 
282787edd195Schristos 	if(event&UB_EV_TIMEOUT) {
282887edd195Schristos 		verbose(VERB_QUERY, "tcp took too long, dropped");
282987edd195Schristos 		reclaim_tcp_handler(c);
283087edd195Schristos 		if(!c->tcp_do_close) {
283187edd195Schristos 			fptr_ok(fptr_whitelist_comm_point(c->callback));
283287edd195Schristos 			(void)(*c->callback)(c, c->cb_arg,
283387edd195Schristos 				NETEVENT_TIMEOUT, NULL);
283487edd195Schristos 		}
283587edd195Schristos 		return;
283687edd195Schristos 	}
283716776186Schristos 	if(event&UB_EV_READ
283816776186Schristos #ifdef USE_MSG_FASTOPEN
283916776186Schristos 		&& !(c->tcp_do_fastopen && (event&UB_EV_WRITE))
284016776186Schristos #endif
284116776186Schristos 		) {
2842f42d8de7Schristos 		int has_tcpq = (c->tcp_req_info != NULL);
284316776186Schristos 		int* moreread = c->tcp_more_read_again;
28443b6c3722Schristos 		if(!comm_point_tcp_handle_read(fd, c, 0)) {
28453b6c3722Schristos 			reclaim_tcp_handler(c);
28463b6c3722Schristos 			if(!c->tcp_do_close) {
28473b6c3722Schristos 				fptr_ok(fptr_whitelist_comm_point(
28483b6c3722Schristos 					c->callback));
28493b6c3722Schristos 				(void)(*c->callback)(c, c->cb_arg,
28503b6c3722Schristos 					NETEVENT_CLOSED, NULL);
28513b6c3722Schristos 			}
285216776186Schristos 			return;
28533b6c3722Schristos 		}
2854*14b2fa6eSchristos 		if(has_tcpq && c->tcp_req_info && c->tcp_req_info->read_again) {
2855*14b2fa6eSchristos 			if(!tcp_req_info_read_again(fd, c))
2856*14b2fa6eSchristos 				return;
2857*14b2fa6eSchristos 		}
285816776186Schristos 		if(moreread && *moreread)
285916776186Schristos 			tcp_more_read_again(fd, c);
28603b6c3722Schristos 		return;
28613b6c3722Schristos 	}
28623b6c3722Schristos 	if(event&UB_EV_WRITE) {
2863f42d8de7Schristos 		int has_tcpq = (c->tcp_req_info != NULL);
286416776186Schristos 		int* morewrite = c->tcp_more_write_again;
28653b6c3722Schristos 		if(!comm_point_tcp_handle_write(fd, c)) {
28663b6c3722Schristos 			reclaim_tcp_handler(c);
28673b6c3722Schristos 			if(!c->tcp_do_close) {
28683b6c3722Schristos 				fptr_ok(fptr_whitelist_comm_point(
28693b6c3722Schristos 					c->callback));
28703b6c3722Schristos 				(void)(*c->callback)(c, c->cb_arg,
28713b6c3722Schristos 					NETEVENT_CLOSED, NULL);
28723b6c3722Schristos 			}
287316776186Schristos 			return;
28743b6c3722Schristos 		}
2875*14b2fa6eSchristos 		if(has_tcpq && c->tcp_req_info && c->tcp_req_info->read_again) {
2876*14b2fa6eSchristos 			if(!tcp_req_info_read_again(fd, c))
2877*14b2fa6eSchristos 				return;
2878*14b2fa6eSchristos 		}
287916776186Schristos 		if(morewrite && *morewrite)
288016776186Schristos 			tcp_more_write_again(fd, c);
28813b6c3722Schristos 		return;
28823b6c3722Schristos 	}
28833b6c3722Schristos 	log_err("Ignored event %d for tcphdl.", event);
28843b6c3722Schristos }
28853b6c3722Schristos 
28867cd94d69Schristos /** Make http handler free for next assignment */
28877cd94d69Schristos static void
28887cd94d69Schristos reclaim_http_handler(struct comm_point* c)
28897cd94d69Schristos {
28907cd94d69Schristos 	log_assert(c->type == comm_http);
28917cd94d69Schristos 	if(c->ssl) {
28927cd94d69Schristos #ifdef HAVE_SSL
28937cd94d69Schristos 		SSL_shutdown(c->ssl);
28947cd94d69Schristos 		SSL_free(c->ssl);
28957cd94d69Schristos 		c->ssl = NULL;
28967cd94d69Schristos #endif
28977cd94d69Schristos 	}
28987cd94d69Schristos 	comm_point_close(c);
28997cd94d69Schristos 	if(c->tcp_parent) {
29001481e2a9Schristos 		if(c != c->tcp_parent->tcp_free) {
29017cd94d69Schristos 			c->tcp_parent->cur_tcp_count--;
29027cd94d69Schristos 			c->tcp_free = c->tcp_parent->tcp_free;
29037cd94d69Schristos 			c->tcp_parent->tcp_free = c;
29041481e2a9Schristos 		}
29057cd94d69Schristos 		if(!c->tcp_free) {
29067cd94d69Schristos 			/* re-enable listening on accept socket */
29077cd94d69Schristos 			comm_point_start_listening(c->tcp_parent, -1, -1);
29087cd94d69Schristos 		}
29097cd94d69Schristos 	}
29107cd94d69Schristos }
29117cd94d69Schristos 
29127cd94d69Schristos /** read more data for http (with ssl) */
29137cd94d69Schristos static int
29147cd94d69Schristos ssl_http_read_more(struct comm_point* c)
29157cd94d69Schristos {
29167cd94d69Schristos #ifdef HAVE_SSL
29177cd94d69Schristos 	int r;
29187cd94d69Schristos 	log_assert(sldns_buffer_remaining(c->buffer) > 0);
29197cd94d69Schristos 	ERR_clear_error();
29207cd94d69Schristos 	r = SSL_read(c->ssl, (void*)sldns_buffer_current(c->buffer),
29217cd94d69Schristos 		(int)sldns_buffer_remaining(c->buffer));
29227cd94d69Schristos 	if(r <= 0) {
29237cd94d69Schristos 		int want = SSL_get_error(c->ssl, r);
29247cd94d69Schristos 		if(want == SSL_ERROR_ZERO_RETURN) {
29257cd94d69Schristos 			return 0; /* shutdown, closed */
29267cd94d69Schristos 		} else if(want == SSL_ERROR_WANT_READ) {
29277cd94d69Schristos 			return 1; /* read more later */
29287cd94d69Schristos 		} else if(want == SSL_ERROR_WANT_WRITE) {
29297cd94d69Schristos 			c->ssl_shake_state = comm_ssl_shake_hs_write;
29307cd94d69Schristos 			comm_point_listen_for_rw(c, 0, 1);
29317cd94d69Schristos 			return 1;
29327cd94d69Schristos 		} else if(want == SSL_ERROR_SYSCALL) {
293387edd195Schristos #ifdef ECONNRESET
293487edd195Schristos 			if(errno == ECONNRESET && verbosity < 2)
293587edd195Schristos 				return 0; /* silence reset by peer */
293687edd195Schristos #endif
29377cd94d69Schristos 			if(errno != 0)
29387cd94d69Schristos 				log_err("SSL_read syscall: %s",
29397cd94d69Schristos 					strerror(errno));
29407cd94d69Schristos 			return 0;
29417cd94d69Schristos 		}
2942*14b2fa6eSchristos 		log_crypto_err_io("could not SSL_read", want);
29437cd94d69Schristos 		return 0;
29447cd94d69Schristos 	}
29451481e2a9Schristos 	verbose(VERB_ALGO, "ssl http read more skip to %d + %d",
29461481e2a9Schristos 		(int)sldns_buffer_position(c->buffer), (int)r);
29477cd94d69Schristos 	sldns_buffer_skip(c->buffer, (ssize_t)r);
29487cd94d69Schristos 	return 1;
29497cd94d69Schristos #else
29507cd94d69Schristos 	(void)c;
29517cd94d69Schristos 	return 0;
29527cd94d69Schristos #endif /* HAVE_SSL */
29537cd94d69Schristos }
29547cd94d69Schristos 
29557cd94d69Schristos /** read more data for http */
29567cd94d69Schristos static int
29577cd94d69Schristos http_read_more(int fd, struct comm_point* c)
29587cd94d69Schristos {
29597cd94d69Schristos 	ssize_t r;
29607cd94d69Schristos 	log_assert(sldns_buffer_remaining(c->buffer) > 0);
29617cd94d69Schristos 	r = recv(fd, (void*)sldns_buffer_current(c->buffer),
2962*14b2fa6eSchristos 		sldns_buffer_remaining(c->buffer), MSG_DONTWAIT);
29637cd94d69Schristos 	if(r == 0) {
29647cd94d69Schristos 		return 0;
29657cd94d69Schristos 	} else if(r == -1) {
29667cd94d69Schristos #ifndef USE_WINSOCK
29677cd94d69Schristos 		if(errno == EINTR || errno == EAGAIN)
29687cd94d69Schristos 			return 1;
29697cd94d69Schristos #else /* USE_WINSOCK */
29707cd94d69Schristos 		if(WSAGetLastError() == WSAECONNRESET)
29717cd94d69Schristos 			return 0;
29727cd94d69Schristos 		if(WSAGetLastError() == WSAEINPROGRESS)
29737cd94d69Schristos 			return 1;
29747cd94d69Schristos 		if(WSAGetLastError() == WSAEWOULDBLOCK) {
29757cd94d69Schristos 			ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
29767cd94d69Schristos 			return 1;
29777cd94d69Schristos 		}
29787cd94d69Schristos #endif
297916776186Schristos 		log_err_addr("read (in http r)", sock_strerror(errno),
2980*14b2fa6eSchristos 			&c->repinfo.remote_addr, c->repinfo.remote_addrlen);
29817cd94d69Schristos 		return 0;
29827cd94d69Schristos 	}
29831481e2a9Schristos 	verbose(VERB_ALGO, "http read more skip to %d + %d",
29841481e2a9Schristos 		(int)sldns_buffer_position(c->buffer), (int)r);
29857cd94d69Schristos 	sldns_buffer_skip(c->buffer, r);
29867cd94d69Schristos 	return 1;
29877cd94d69Schristos }
29887cd94d69Schristos 
29897cd94d69Schristos /** return true if http header has been read (one line complete) */
29907cd94d69Schristos static int
29917cd94d69Schristos http_header_done(sldns_buffer* buf)
29927cd94d69Schristos {
29937cd94d69Schristos 	size_t i;
29947cd94d69Schristos 	for(i=sldns_buffer_position(buf); i<sldns_buffer_limit(buf); i++) {
29957cd94d69Schristos 		/* there was a \r before the \n, but we ignore that */
29967cd94d69Schristos 		if((char)sldns_buffer_read_u8_at(buf, i) == '\n')
29977cd94d69Schristos 			return 1;
29987cd94d69Schristos 	}
29997cd94d69Schristos 	return 0;
30007cd94d69Schristos }
30017cd94d69Schristos 
30027cd94d69Schristos /** return character string into buffer for header line, moves buffer
30037cd94d69Schristos  * past that line and puts zero terminator into linefeed-newline */
30047cd94d69Schristos static char*
30057cd94d69Schristos http_header_line(sldns_buffer* buf)
30067cd94d69Schristos {
30077cd94d69Schristos 	char* result = (char*)sldns_buffer_current(buf);
30087cd94d69Schristos 	size_t i;
30097cd94d69Schristos 	for(i=sldns_buffer_position(buf); i<sldns_buffer_limit(buf); i++) {
30107cd94d69Schristos 		/* terminate the string on the \r */
30117cd94d69Schristos 		if((char)sldns_buffer_read_u8_at(buf, i) == '\r')
30127cd94d69Schristos 			sldns_buffer_write_u8_at(buf, i, 0);
30137cd94d69Schristos 		/* terminate on the \n and skip past the it and done */
30147cd94d69Schristos 		if((char)sldns_buffer_read_u8_at(buf, i) == '\n') {
30157cd94d69Schristos 			sldns_buffer_write_u8_at(buf, i, 0);
30167cd94d69Schristos 			sldns_buffer_set_position(buf, i+1);
30177cd94d69Schristos 			return result;
30187cd94d69Schristos 		}
30197cd94d69Schristos 	}
30207cd94d69Schristos 	return NULL;
30217cd94d69Schristos }
30227cd94d69Schristos 
30237cd94d69Schristos /** move unread buffer to start and clear rest for putting the rest into it */
30247cd94d69Schristos static void
30257cd94d69Schristos http_moveover_buffer(sldns_buffer* buf)
30267cd94d69Schristos {
30277cd94d69Schristos 	size_t pos = sldns_buffer_position(buf);
30287cd94d69Schristos 	size_t len = sldns_buffer_remaining(buf);
30297cd94d69Schristos 	sldns_buffer_clear(buf);
30307cd94d69Schristos 	memmove(sldns_buffer_begin(buf), sldns_buffer_at(buf, pos), len);
30317cd94d69Schristos 	sldns_buffer_set_position(buf, len);
30327cd94d69Schristos }
30337cd94d69Schristos 
30347cd94d69Schristos /** a http header is complete, process it */
30357cd94d69Schristos static int
30367cd94d69Schristos http_process_initial_header(struct comm_point* c)
30377cd94d69Schristos {
30387cd94d69Schristos 	char* line = http_header_line(c->buffer);
30397cd94d69Schristos 	if(!line) return 1;
30407cd94d69Schristos 	verbose(VERB_ALGO, "http header: %s", line);
30417cd94d69Schristos 	if(strncasecmp(line, "HTTP/1.1 ", 9) == 0) {
30427cd94d69Schristos 		/* check returncode */
30437cd94d69Schristos 		if(line[9] != '2') {
30447cd94d69Schristos 			verbose(VERB_ALGO, "http bad status %s", line+9);
30457cd94d69Schristos 			return 0;
30467cd94d69Schristos 		}
30477cd94d69Schristos 	} else if(strncasecmp(line, "Content-Length: ", 16) == 0) {
30487cd94d69Schristos 		if(!c->http_is_chunked)
30497cd94d69Schristos 			c->tcp_byte_count = (size_t)atoi(line+16);
30507cd94d69Schristos 	} else if(strncasecmp(line, "Transfer-Encoding: chunked", 19+7) == 0) {
30517cd94d69Schristos 		c->tcp_byte_count = 0;
30527cd94d69Schristos 		c->http_is_chunked = 1;
30537cd94d69Schristos 	} else if(line[0] == 0) {
30547cd94d69Schristos 		/* end of initial headers */
30557cd94d69Schristos 		c->http_in_headers = 0;
30567cd94d69Schristos 		if(c->http_is_chunked)
30577cd94d69Schristos 			c->http_in_chunk_headers = 1;
30587cd94d69Schristos 		/* remove header text from front of buffer
30597cd94d69Schristos 		 * the buffer is going to be used to return the data segment
30607cd94d69Schristos 		 * itself and we don't want the header to get returned
30617cd94d69Schristos 		 * prepended with it */
30627cd94d69Schristos 		http_moveover_buffer(c->buffer);
30637cd94d69Schristos 		sldns_buffer_flip(c->buffer);
30647cd94d69Schristos 		return 1;
30657cd94d69Schristos 	}
30667cd94d69Schristos 	/* ignore other headers */
30677cd94d69Schristos 	return 1;
30687cd94d69Schristos }
30697cd94d69Schristos 
30707cd94d69Schristos /** a chunk header is complete, process it, return 0=fail, 1=continue next
30717cd94d69Schristos  * header line, 2=done with chunked transfer*/
30727cd94d69Schristos static int
30737cd94d69Schristos http_process_chunk_header(struct comm_point* c)
30747cd94d69Schristos {
30757cd94d69Schristos 	char* line = http_header_line(c->buffer);
30767cd94d69Schristos 	if(!line) return 1;
30777cd94d69Schristos 	if(c->http_in_chunk_headers == 3) {
30787cd94d69Schristos 		verbose(VERB_ALGO, "http chunk trailer: %s", line);
30797cd94d69Schristos 		/* are we done ? */
30807cd94d69Schristos 		if(line[0] == 0 && c->tcp_byte_count == 0) {
30817cd94d69Schristos 			/* callback of http reader when NETEVENT_DONE,
30827cd94d69Schristos 			 * end of data, with no data in buffer */
30837cd94d69Schristos 			sldns_buffer_set_position(c->buffer, 0);
30847cd94d69Schristos 			sldns_buffer_set_limit(c->buffer, 0);
30857cd94d69Schristos 			fptr_ok(fptr_whitelist_comm_point(c->callback));
30867cd94d69Schristos 			(void)(*c->callback)(c, c->cb_arg, NETEVENT_DONE, NULL);
30877cd94d69Schristos 			/* return that we are done */
30887cd94d69Schristos 			return 2;
30897cd94d69Schristos 		}
30907cd94d69Schristos 		if(line[0] == 0) {
30917cd94d69Schristos 			/* continue with header of the next chunk */
30927cd94d69Schristos 			c->http_in_chunk_headers = 1;
30937cd94d69Schristos 			/* remove header text from front of buffer */
30947cd94d69Schristos 			http_moveover_buffer(c->buffer);
30957cd94d69Schristos 			sldns_buffer_flip(c->buffer);
30967cd94d69Schristos 			return 1;
30977cd94d69Schristos 		}
30987cd94d69Schristos 		/* ignore further trail headers */
30997cd94d69Schristos 		return 1;
31007cd94d69Schristos 	}
31017cd94d69Schristos 	verbose(VERB_ALGO, "http chunk header: %s", line);
31027cd94d69Schristos 	if(c->http_in_chunk_headers == 1) {
31037cd94d69Schristos 		/* read chunked start line */
31047cd94d69Schristos 		char* end = NULL;
31057cd94d69Schristos 		c->tcp_byte_count = (size_t)strtol(line, &end, 16);
31067cd94d69Schristos 		if(end == line)
31077cd94d69Schristos 			return 0;
31087cd94d69Schristos 		c->http_in_chunk_headers = 0;
31097cd94d69Schristos 		/* remove header text from front of buffer */
31107cd94d69Schristos 		http_moveover_buffer(c->buffer);
31117cd94d69Schristos 		sldns_buffer_flip(c->buffer);
31127cd94d69Schristos 		if(c->tcp_byte_count == 0) {
31137cd94d69Schristos 			/* done with chunks, process chunk_trailer lines */
31147cd94d69Schristos 			c->http_in_chunk_headers = 3;
31157cd94d69Schristos 		}
31167cd94d69Schristos 		return 1;
31177cd94d69Schristos 	}
31187cd94d69Schristos 	/* ignore other headers */
31197cd94d69Schristos 	return 1;
31207cd94d69Schristos }
31217cd94d69Schristos 
31221481e2a9Schristos /** handle nonchunked data segment, 0=fail, 1=wait */
31237cd94d69Schristos static int
31247cd94d69Schristos http_nonchunk_segment(struct comm_point* c)
31257cd94d69Schristos {
31267cd94d69Schristos 	/* c->buffer at position..limit has new data we read in.
31277cd94d69Schristos 	 * the buffer itself is full of nonchunked data.
31287cd94d69Schristos 	 * we are looking to read tcp_byte_count more data
31297cd94d69Schristos 	 * and then the transfer is done. */
31307cd94d69Schristos 	size_t remainbufferlen;
31311481e2a9Schristos 	size_t got_now = sldns_buffer_limit(c->buffer);
31327cd94d69Schristos 	if(c->tcp_byte_count <= got_now) {
31337cd94d69Schristos 		/* done, this is the last data fragment */
31347cd94d69Schristos 		c->http_stored = 0;
31357cd94d69Schristos 		sldns_buffer_set_position(c->buffer, 0);
31367cd94d69Schristos 		fptr_ok(fptr_whitelist_comm_point(c->callback));
31377cd94d69Schristos 		(void)(*c->callback)(c, c->cb_arg, NETEVENT_DONE, NULL);
31387cd94d69Schristos 		return 1;
31397cd94d69Schristos 	}
31407cd94d69Schristos 	/* if we have the buffer space,
31417cd94d69Schristos 	 * read more data collected into the buffer */
31427cd94d69Schristos 	remainbufferlen = sldns_buffer_capacity(c->buffer) -
31437cd94d69Schristos 		sldns_buffer_limit(c->buffer);
31441481e2a9Schristos 	if(remainbufferlen+got_now >= c->tcp_byte_count ||
31451481e2a9Schristos 		remainbufferlen >= (size_t)(c->ssl?16384:2048)) {
31467cd94d69Schristos 		size_t total = sldns_buffer_limit(c->buffer);
31477cd94d69Schristos 		sldns_buffer_clear(c->buffer);
31487cd94d69Schristos 		sldns_buffer_set_position(c->buffer, total);
31497cd94d69Schristos 		c->http_stored = total;
31507cd94d69Schristos 		/* return and wait to read more */
31517cd94d69Schristos 		return 1;
31527cd94d69Schristos 	}
31537cd94d69Schristos 	/* call callback with this data amount, then
31547cd94d69Schristos 	 * wait for more */
31551481e2a9Schristos 	c->tcp_byte_count -= got_now;
31567cd94d69Schristos 	c->http_stored = 0;
31577cd94d69Schristos 	sldns_buffer_set_position(c->buffer, 0);
31587cd94d69Schristos 	fptr_ok(fptr_whitelist_comm_point(c->callback));
31597cd94d69Schristos 	(void)(*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, NULL);
31607cd94d69Schristos 	/* c->callback has to buffer_clear(c->buffer). */
31617cd94d69Schristos 	/* return and wait to read more */
31627cd94d69Schristos 	return 1;
31637cd94d69Schristos }
31647cd94d69Schristos 
316516776186Schristos /** handle chunked data segment, return 0=fail, 1=wait, 2=process more */
31667cd94d69Schristos static int
31677cd94d69Schristos http_chunked_segment(struct comm_point* c)
31687cd94d69Schristos {
31697cd94d69Schristos 	/* the c->buffer has from position..limit new data we read. */
31707cd94d69Schristos 	/* the current chunk has length tcp_byte_count.
31717cd94d69Schristos 	 * once we read that read more chunk headers.
31727cd94d69Schristos 	 */
31737cd94d69Schristos 	size_t remainbufferlen;
31747cd94d69Schristos 	size_t got_now = sldns_buffer_limit(c->buffer) - c->http_stored;
317516776186Schristos 	verbose(VERB_ALGO, "http_chunked_segment: got now %d, tcpbytcount %d, http_stored %d, buffer pos %d, buffer limit %d", (int)got_now, (int)c->tcp_byte_count, (int)c->http_stored, (int)sldns_buffer_position(c->buffer), (int)sldns_buffer_limit(c->buffer));
31767cd94d69Schristos 	if(c->tcp_byte_count <= got_now) {
31777cd94d69Schristos 		/* the chunk has completed (with perhaps some extra data
31787cd94d69Schristos 		 * from next chunk header and next chunk) */
31797cd94d69Schristos 		/* save too much info into temp buffer */
31807cd94d69Schristos 		size_t fraglen;
31817cd94d69Schristos 		struct comm_reply repinfo;
31827cd94d69Schristos 		c->http_stored = 0;
31837cd94d69Schristos 		sldns_buffer_skip(c->buffer, (ssize_t)c->tcp_byte_count);
31847cd94d69Schristos 		sldns_buffer_clear(c->http_temp);
31857cd94d69Schristos 		sldns_buffer_write(c->http_temp,
31867cd94d69Schristos 			sldns_buffer_current(c->buffer),
31877cd94d69Schristos 			sldns_buffer_remaining(c->buffer));
31887cd94d69Schristos 		sldns_buffer_flip(c->http_temp);
31897cd94d69Schristos 
31907cd94d69Schristos 		/* callback with this fragment */
31917cd94d69Schristos 		fraglen = sldns_buffer_position(c->buffer);
31927cd94d69Schristos 		sldns_buffer_set_position(c->buffer, 0);
31937cd94d69Schristos 		sldns_buffer_set_limit(c->buffer, fraglen);
31947cd94d69Schristos 		repinfo = c->repinfo;
31957cd94d69Schristos 		fptr_ok(fptr_whitelist_comm_point(c->callback));
31967cd94d69Schristos 		(void)(*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, &repinfo);
31977cd94d69Schristos 		/* c->callback has to buffer_clear(). */
31987cd94d69Schristos 
31997cd94d69Schristos 		/* is commpoint deleted? */
32007cd94d69Schristos 		if(!repinfo.c) {
32017cd94d69Schristos 			return 1;
32027cd94d69Schristos 		}
32037cd94d69Schristos 		/* copy waiting info */
32047cd94d69Schristos 		sldns_buffer_clear(c->buffer);
32057cd94d69Schristos 		sldns_buffer_write(c->buffer,
32067cd94d69Schristos 			sldns_buffer_begin(c->http_temp),
32077cd94d69Schristos 			sldns_buffer_remaining(c->http_temp));
32087cd94d69Schristos 		sldns_buffer_flip(c->buffer);
32097cd94d69Schristos 		/* process end of chunk trailer header lines, until
32107cd94d69Schristos 		 * an empty line */
32117cd94d69Schristos 		c->http_in_chunk_headers = 3;
32127cd94d69Schristos 		/* process more data in buffer (if any) */
32137cd94d69Schristos 		return 2;
32147cd94d69Schristos 	}
32157cd94d69Schristos 	c->tcp_byte_count -= got_now;
32167cd94d69Schristos 
32177cd94d69Schristos 	/* if we have the buffer space,
32187cd94d69Schristos 	 * read more data collected into the buffer */
32197cd94d69Schristos 	remainbufferlen = sldns_buffer_capacity(c->buffer) -
32207cd94d69Schristos 		sldns_buffer_limit(c->buffer);
32217cd94d69Schristos 	if(remainbufferlen >= c->tcp_byte_count ||
32227cd94d69Schristos 		remainbufferlen >= 2048) {
32237cd94d69Schristos 		size_t total = sldns_buffer_limit(c->buffer);
32247cd94d69Schristos 		sldns_buffer_clear(c->buffer);
32257cd94d69Schristos 		sldns_buffer_set_position(c->buffer, total);
32267cd94d69Schristos 		c->http_stored = total;
32277cd94d69Schristos 		/* return and wait to read more */
32287cd94d69Schristos 		return 1;
32297cd94d69Schristos 	}
32307cd94d69Schristos 
32317cd94d69Schristos 	/* callback of http reader for a new part of the data */
32327cd94d69Schristos 	c->http_stored = 0;
32337cd94d69Schristos 	sldns_buffer_set_position(c->buffer, 0);
32347cd94d69Schristos 	fptr_ok(fptr_whitelist_comm_point(c->callback));
32357cd94d69Schristos 	(void)(*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, NULL);
32367cd94d69Schristos 	/* c->callback has to buffer_clear(c->buffer). */
32377cd94d69Schristos 	/* return and wait to read more */
32387cd94d69Schristos 	return 1;
32397cd94d69Schristos }
32407cd94d69Schristos 
324116776186Schristos #ifdef HAVE_NGHTTP2
324216776186Schristos /** Create new http2 session. Called when creating handling comm point. */
324316776186Schristos static struct http2_session* http2_session_create(struct comm_point* c)
324416776186Schristos {
324516776186Schristos 	struct http2_session* session = calloc(1, sizeof(*session));
324616776186Schristos 	if(!session) {
324716776186Schristos 		log_err("malloc failure while creating http2 session");
324816776186Schristos 		return NULL;
324916776186Schristos 	}
325016776186Schristos 	session->c = c;
325116776186Schristos 
325216776186Schristos 	return session;
325316776186Schristos }
325416776186Schristos #endif
325516776186Schristos 
325616776186Schristos /** Delete http2 session. After closing connection or on error */
325716776186Schristos static void http2_session_delete(struct http2_session* h2_session)
325816776186Schristos {
325916776186Schristos #ifdef HAVE_NGHTTP2
326016776186Schristos 	if(h2_session->callbacks)
326116776186Schristos 		nghttp2_session_callbacks_del(h2_session->callbacks);
326216776186Schristos 	free(h2_session);
326316776186Schristos #else
326416776186Schristos 	(void)h2_session;
326516776186Schristos #endif
326616776186Schristos }
326716776186Schristos 
326816776186Schristos #ifdef HAVE_NGHTTP2
326916776186Schristos struct http2_stream* http2_stream_create(int32_t stream_id)
327016776186Schristos {
327116776186Schristos 	struct http2_stream* h2_stream = calloc(1, sizeof(*h2_stream));
327216776186Schristos 	if(!h2_stream) {
327316776186Schristos 		log_err("malloc failure while creating http2 stream");
327416776186Schristos 		return NULL;
327516776186Schristos 	}
327616776186Schristos 	h2_stream->stream_id = stream_id;
327716776186Schristos 	return h2_stream;
327816776186Schristos }
327916776186Schristos 
328016776186Schristos /** Delete http2 stream. After session delete or stream close callback */
328116776186Schristos static void http2_stream_delete(struct http2_session* h2_session,
328216776186Schristos 	struct http2_stream* h2_stream)
328316776186Schristos {
328416776186Schristos 	if(h2_stream->mesh_state) {
328516776186Schristos 		mesh_state_remove_reply(h2_stream->mesh, h2_stream->mesh_state,
328616776186Schristos 			h2_session->c);
328716776186Schristos 		h2_stream->mesh_state = NULL;
328816776186Schristos 	}
328916776186Schristos 	http2_req_stream_clear(h2_stream);
329016776186Schristos 	free(h2_stream);
329116776186Schristos }
329216776186Schristos #endif
329316776186Schristos 
329416776186Schristos void http2_stream_add_meshstate(struct http2_stream* h2_stream,
329516776186Schristos 	struct mesh_area* mesh, struct mesh_state* m)
329616776186Schristos {
329716776186Schristos 	h2_stream->mesh = mesh;
329816776186Schristos 	h2_stream->mesh_state = m;
329916776186Schristos }
330016776186Schristos 
330116776186Schristos /** delete http2 session server. After closing connection. */
330216776186Schristos static void http2_session_server_delete(struct http2_session* h2_session)
330316776186Schristos {
330416776186Schristos #ifdef HAVE_NGHTTP2
330516776186Schristos 	struct http2_stream* h2_stream, *next;
330616776186Schristos 	nghttp2_session_del(h2_session->session); /* NULL input is fine */
330716776186Schristos 	h2_session->session = NULL;
330816776186Schristos 	for(h2_stream = h2_session->first_stream; h2_stream;) {
330916776186Schristos 		next = h2_stream->next;
331016776186Schristos 		http2_stream_delete(h2_session, h2_stream);
331116776186Schristos 		h2_stream = next;
331216776186Schristos 	}
331316776186Schristos 	h2_session->first_stream = NULL;
331416776186Schristos 	h2_session->is_drop = 0;
331516776186Schristos 	h2_session->postpone_drop = 0;
331616776186Schristos 	h2_session->c->h2_stream = NULL;
331716776186Schristos #endif
331816776186Schristos 	(void)h2_session;
331916776186Schristos }
332016776186Schristos 
332116776186Schristos #ifdef HAVE_NGHTTP2
332216776186Schristos void http2_session_add_stream(struct http2_session* h2_session,
332316776186Schristos 	struct http2_stream* h2_stream)
332416776186Schristos {
332516776186Schristos 	if(h2_session->first_stream)
332616776186Schristos 		h2_session->first_stream->prev = h2_stream;
332716776186Schristos 	h2_stream->next = h2_session->first_stream;
332816776186Schristos 	h2_session->first_stream = h2_stream;
332916776186Schristos }
333016776186Schristos 
333116776186Schristos /** remove stream from session linked list. After stream close callback or
333216776186Schristos  * closing connection */
333316776186Schristos static void http2_session_remove_stream(struct http2_session* h2_session,
333416776186Schristos 	struct http2_stream* h2_stream)
333516776186Schristos {
333616776186Schristos 	if(h2_stream->prev)
333716776186Schristos 		h2_stream->prev->next = h2_stream->next;
333816776186Schristos 	else
333916776186Schristos 		h2_session->first_stream = h2_stream->next;
334016776186Schristos 	if(h2_stream->next)
334116776186Schristos 		h2_stream->next->prev = h2_stream->prev;
334216776186Schristos 
334316776186Schristos }
334416776186Schristos 
334516776186Schristos int http2_stream_close_cb(nghttp2_session* ATTR_UNUSED(session),
334616776186Schristos 	int32_t stream_id, uint32_t ATTR_UNUSED(error_code), void* cb_arg)
334716776186Schristos {
334816776186Schristos 	struct http2_stream* h2_stream;
334916776186Schristos 	struct http2_session* h2_session = (struct http2_session*)cb_arg;
335016776186Schristos 	if(!(h2_stream = nghttp2_session_get_stream_user_data(
335116776186Schristos 		h2_session->session, stream_id))) {
335216776186Schristos 		return 0;
335316776186Schristos 	}
335416776186Schristos 	http2_session_remove_stream(h2_session, h2_stream);
335516776186Schristos 	http2_stream_delete(h2_session, h2_stream);
335616776186Schristos 	return 0;
335716776186Schristos }
335816776186Schristos 
335916776186Schristos ssize_t http2_recv_cb(nghttp2_session* ATTR_UNUSED(session), uint8_t* buf,
336016776186Schristos 	size_t len, int ATTR_UNUSED(flags), void* cb_arg)
336116776186Schristos {
336216776186Schristos 	struct http2_session* h2_session = (struct http2_session*)cb_arg;
336316776186Schristos 	ssize_t ret;
336416776186Schristos 
336516776186Schristos 	log_assert(h2_session->c->type == comm_http);
336616776186Schristos 	log_assert(h2_session->c->h2_session);
336716776186Schristos 
336816776186Schristos #ifdef HAVE_SSL
336916776186Schristos 	if(h2_session->c->ssl) {
337016776186Schristos 		int r;
337116776186Schristos 		ERR_clear_error();
337216776186Schristos 		r = SSL_read(h2_session->c->ssl, buf, len);
337316776186Schristos 		if(r <= 0) {
337416776186Schristos 			int want = SSL_get_error(h2_session->c->ssl, r);
337516776186Schristos 			if(want == SSL_ERROR_ZERO_RETURN) {
337616776186Schristos 				return NGHTTP2_ERR_EOF;
337716776186Schristos 			} else if(want == SSL_ERROR_WANT_READ) {
337816776186Schristos 				return NGHTTP2_ERR_WOULDBLOCK;
337916776186Schristos 			} else if(want == SSL_ERROR_WANT_WRITE) {
338016776186Schristos 				h2_session->c->ssl_shake_state = comm_ssl_shake_hs_write;
338116776186Schristos 				comm_point_listen_for_rw(h2_session->c, 0, 1);
338216776186Schristos 				return NGHTTP2_ERR_WOULDBLOCK;
338316776186Schristos 			} else if(want == SSL_ERROR_SYSCALL) {
338416776186Schristos #ifdef ECONNRESET
338516776186Schristos 				if(errno == ECONNRESET && verbosity < 2)
338616776186Schristos 					return NGHTTP2_ERR_CALLBACK_FAILURE;
338716776186Schristos #endif
338816776186Schristos 				if(errno != 0)
338916776186Schristos 					log_err("SSL_read syscall: %s",
339016776186Schristos 						strerror(errno));
339116776186Schristos 				return NGHTTP2_ERR_CALLBACK_FAILURE;
339216776186Schristos 			}
3393*14b2fa6eSchristos 			log_crypto_err_io("could not SSL_read", want);
339416776186Schristos 			return NGHTTP2_ERR_CALLBACK_FAILURE;
339516776186Schristos 		}
339616776186Schristos 		return r;
339716776186Schristos 	}
339816776186Schristos #endif /* HAVE_SSL */
339916776186Schristos 
3400*14b2fa6eSchristos 	ret = recv(h2_session->c->fd, buf, len, MSG_DONTWAIT);
340116776186Schristos 	if(ret == 0) {
340216776186Schristos 		return NGHTTP2_ERR_EOF;
340316776186Schristos 	} else if(ret < 0) {
340416776186Schristos #ifndef USE_WINSOCK
340516776186Schristos 		if(errno == EINTR || errno == EAGAIN)
340616776186Schristos 			return NGHTTP2_ERR_WOULDBLOCK;
340716776186Schristos #ifdef ECONNRESET
340816776186Schristos 		if(errno == ECONNRESET && verbosity < 2)
340916776186Schristos 			return NGHTTP2_ERR_CALLBACK_FAILURE;
341016776186Schristos #endif
341116776186Schristos 		log_err_addr("could not http2 recv: %s", strerror(errno),
3412*14b2fa6eSchristos 			&h2_session->c->repinfo.remote_addr,
3413*14b2fa6eSchristos 			h2_session->c->repinfo.remote_addrlen);
341416776186Schristos #else /* USE_WINSOCK */
341516776186Schristos 		if(WSAGetLastError() == WSAECONNRESET)
341616776186Schristos 			return NGHTTP2_ERR_CALLBACK_FAILURE;
341716776186Schristos 		if(WSAGetLastError() == WSAEINPROGRESS)
341816776186Schristos 			return NGHTTP2_ERR_WOULDBLOCK;
341916776186Schristos 		if(WSAGetLastError() == WSAEWOULDBLOCK) {
342016776186Schristos 			ub_winsock_tcp_wouldblock(h2_session->c->ev->ev,
342116776186Schristos 				UB_EV_READ);
342216776186Schristos 			return NGHTTP2_ERR_WOULDBLOCK;
342316776186Schristos 		}
342416776186Schristos 		log_err_addr("could not http2 recv: %s",
342516776186Schristos 			wsa_strerror(WSAGetLastError()),
3426*14b2fa6eSchristos 			&h2_session->c->repinfo.remote_addr,
3427*14b2fa6eSchristos 			h2_session->c->repinfo.remote_addrlen);
342816776186Schristos #endif
342916776186Schristos 		return NGHTTP2_ERR_CALLBACK_FAILURE;
343016776186Schristos 	}
343116776186Schristos 	return ret;
343216776186Schristos }
343316776186Schristos #endif /* HAVE_NGHTTP2 */
343416776186Schristos 
343516776186Schristos /** Handle http2 read */
343616776186Schristos static int
343716776186Schristos comm_point_http2_handle_read(int ATTR_UNUSED(fd), struct comm_point* c)
343816776186Schristos {
343916776186Schristos #ifdef HAVE_NGHTTP2
344016776186Schristos 	int ret;
344116776186Schristos 	log_assert(c->h2_session);
344216776186Schristos 
344316776186Schristos 	/* reading until recv cb returns NGHTTP2_ERR_WOULDBLOCK */
344416776186Schristos 	ret = nghttp2_session_recv(c->h2_session->session);
344516776186Schristos 	if(ret) {
344616776186Schristos 		if(ret != NGHTTP2_ERR_EOF &&
344716776186Schristos 			ret != NGHTTP2_ERR_CALLBACK_FAILURE) {
344816776186Schristos 			char a[256];
3449*14b2fa6eSchristos 			addr_to_str(&c->repinfo.remote_addr,
3450*14b2fa6eSchristos 				c->repinfo.remote_addrlen, a, sizeof(a));
345116776186Schristos 			verbose(VERB_QUERY, "http2: session_recv from %s failed, "
345216776186Schristos 				"error: %s", a, nghttp2_strerror(ret));
345316776186Schristos 		}
345416776186Schristos 		return 0;
345516776186Schristos 	}
345616776186Schristos 	if(nghttp2_session_want_write(c->h2_session->session)) {
345716776186Schristos 		c->tcp_is_reading = 0;
345816776186Schristos 		comm_point_stop_listening(c);
345916776186Schristos 		comm_point_start_listening(c, -1, adjusted_tcp_timeout(c));
346016776186Schristos 	} else if(!nghttp2_session_want_read(c->h2_session->session))
346116776186Schristos 		return 0; /* connection can be closed */
346216776186Schristos 	return 1;
346316776186Schristos #else
346416776186Schristos 	(void)c;
346516776186Schristos 	return 0;
346616776186Schristos #endif
346716776186Schristos }
346816776186Schristos 
34697cd94d69Schristos /**
34707cd94d69Schristos  * Handle http reading callback.
34717cd94d69Schristos  * @param fd: file descriptor of socket.
34727cd94d69Schristos  * @param c: comm point to read from into buffer.
34737cd94d69Schristos  * @return: 0 on error
34747cd94d69Schristos  */
34757cd94d69Schristos static int
34767cd94d69Schristos comm_point_http_handle_read(int fd, struct comm_point* c)
34777cd94d69Schristos {
34787cd94d69Schristos 	log_assert(c->type == comm_http);
34797cd94d69Schristos 	log_assert(fd != -1);
34807cd94d69Schristos 
34817cd94d69Schristos 	/* if we are in ssl handshake, handle SSL handshake */
34827cd94d69Schristos #ifdef HAVE_SSL
34837cd94d69Schristos 	if(c->ssl && c->ssl_shake_state != comm_ssl_shake_none) {
34847cd94d69Schristos 		if(!ssl_handshake(c))
34857cd94d69Schristos 			return 0;
34867cd94d69Schristos 		if(c->ssl_shake_state != comm_ssl_shake_none)
34877cd94d69Schristos 			return 1;
34887cd94d69Schristos 	}
34897cd94d69Schristos #endif /* HAVE_SSL */
34907cd94d69Schristos 
34917cd94d69Schristos 	if(!c->tcp_is_reading)
34927cd94d69Schristos 		return 1;
349316776186Schristos 
349416776186Schristos 	if(c->use_h2) {
349516776186Schristos 		return comm_point_http2_handle_read(fd, c);
349616776186Schristos 	}
349716776186Schristos 
349816776186Schristos 	/* http version is <= http/1.1 */
349916776186Schristos 
350016776186Schristos 	if(c->http_min_version >= http_version_2) {
350116776186Schristos 		/* HTTP/2 failed, not allowed to use lower version. */
350216776186Schristos 		return 0;
350316776186Schristos 	}
350416776186Schristos 
35057cd94d69Schristos 	/* read more data */
35067cd94d69Schristos 	if(c->ssl) {
35077cd94d69Schristos 		if(!ssl_http_read_more(c))
35087cd94d69Schristos 			return 0;
35097cd94d69Schristos 	} else {
35107cd94d69Schristos 		if(!http_read_more(fd, c))
35117cd94d69Schristos 			return 0;
35127cd94d69Schristos 	}
35137cd94d69Schristos 
35141481e2a9Schristos 	if(c->http_stored >= sldns_buffer_position(c->buffer)) {
35151481e2a9Schristos 		/* read did not work but we wanted more data, there is
35161481e2a9Schristos 		 * no bytes to process now. */
35171481e2a9Schristos 		return 1;
35181481e2a9Schristos 	}
35197cd94d69Schristos 	sldns_buffer_flip(c->buffer);
352016776186Schristos 	/* if we are partway in a segment of data, position us at the point
352116776186Schristos 	 * where we left off previously */
352216776186Schristos 	if(c->http_stored < sldns_buffer_limit(c->buffer))
352316776186Schristos 		sldns_buffer_set_position(c->buffer, c->http_stored);
352416776186Schristos 	else	sldns_buffer_set_position(c->buffer, sldns_buffer_limit(c->buffer));
352516776186Schristos 
35267cd94d69Schristos 	while(sldns_buffer_remaining(c->buffer) > 0) {
352716776186Schristos 		/* Handle HTTP/1.x data */
35287cd94d69Schristos 		/* if we are reading headers, read more headers */
35297cd94d69Schristos 		if(c->http_in_headers || c->http_in_chunk_headers) {
35307cd94d69Schristos 			/* if header is done, process the header */
35317cd94d69Schristos 			if(!http_header_done(c->buffer)) {
35327cd94d69Schristos 				/* copy remaining data to front of buffer
35337cd94d69Schristos 				 * and set rest for writing into it */
35347cd94d69Schristos 				http_moveover_buffer(c->buffer);
35357cd94d69Schristos 				/* return and wait to read more */
35367cd94d69Schristos 				return 1;
35377cd94d69Schristos 			}
35387cd94d69Schristos 			if(!c->http_in_chunk_headers) {
35397cd94d69Schristos 				/* process initial headers */
35407cd94d69Schristos 				if(!http_process_initial_header(c))
35417cd94d69Schristos 					return 0;
35427cd94d69Schristos 			} else {
35437cd94d69Schristos 				/* process chunk headers */
35447cd94d69Schristos 				int r = http_process_chunk_header(c);
35457cd94d69Schristos 				if(r == 0) return 0;
35467cd94d69Schristos 				if(r == 2) return 1; /* done */
35477cd94d69Schristos 				/* r == 1, continue */
35487cd94d69Schristos 			}
35497cd94d69Schristos 			/* see if we have more to process */
35507cd94d69Schristos 			continue;
35517cd94d69Schristos 		}
35527cd94d69Schristos 
35537cd94d69Schristos 		if(!c->http_is_chunked) {
35547cd94d69Schristos 			/* if we are reading nonchunks, process that*/
35557cd94d69Schristos 			return http_nonchunk_segment(c);
35567cd94d69Schristos 		} else {
35577cd94d69Schristos 			/* if we are reading chunks, read the chunk */
35587cd94d69Schristos 			int r = http_chunked_segment(c);
35597cd94d69Schristos 			if(r == 0) return 0;
35607cd94d69Schristos 			if(r == 1) return 1;
35617cd94d69Schristos 			continue;
35627cd94d69Schristos 		}
35637cd94d69Schristos 	}
35647cd94d69Schristos 	/* broke out of the loop; could not process header instead need
35657cd94d69Schristos 	 * to read more */
35667cd94d69Schristos 	/* moveover any remaining data and read more data */
35677cd94d69Schristos 	http_moveover_buffer(c->buffer);
35687cd94d69Schristos 	/* return and wait to read more */
35697cd94d69Schristos 	return 1;
35707cd94d69Schristos }
35717cd94d69Schristos 
35727cd94d69Schristos /** check pending connect for http */
35737cd94d69Schristos static int
35747cd94d69Schristos http_check_connect(int fd, struct comm_point* c)
35757cd94d69Schristos {
35767cd94d69Schristos 	/* check for pending error from nonblocking connect */
35777cd94d69Schristos 	/* from Stevens, unix network programming, vol1, 3rd ed, p450*/
35787cd94d69Schristos 	int error = 0;
35797cd94d69Schristos 	socklen_t len = (socklen_t)sizeof(error);
35807cd94d69Schristos 	if(getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&error,
35817cd94d69Schristos 		&len) < 0){
35827cd94d69Schristos #ifndef USE_WINSOCK
35837cd94d69Schristos 		error = errno; /* on solaris errno is error */
35847cd94d69Schristos #else /* USE_WINSOCK */
35857cd94d69Schristos 		error = WSAGetLastError();
35867cd94d69Schristos #endif
35877cd94d69Schristos 	}
35887cd94d69Schristos #ifndef USE_WINSOCK
35897cd94d69Schristos #if defined(EINPROGRESS) && defined(EWOULDBLOCK)
35907cd94d69Schristos 	if(error == EINPROGRESS || error == EWOULDBLOCK)
35917cd94d69Schristos 		return 1; /* try again later */
35927cd94d69Schristos 	else
35937cd94d69Schristos #endif
35947cd94d69Schristos 	if(error != 0 && verbosity < 2)
35957cd94d69Schristos 		return 0; /* silence lots of chatter in the logs */
35967cd94d69Schristos 	else if(error != 0) {
35977cd94d69Schristos 		log_err_addr("http connect", strerror(error),
3598*14b2fa6eSchristos 			&c->repinfo.remote_addr, c->repinfo.remote_addrlen);
35997cd94d69Schristos #else /* USE_WINSOCK */
36007cd94d69Schristos 	/* examine error */
36017cd94d69Schristos 	if(error == WSAEINPROGRESS)
36027cd94d69Schristos 		return 1;
36037cd94d69Schristos 	else if(error == WSAEWOULDBLOCK) {
36047cd94d69Schristos 		ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
36057cd94d69Schristos 		return 1;
36067cd94d69Schristos 	} else if(error != 0 && verbosity < 2)
36077cd94d69Schristos 		return 0;
36087cd94d69Schristos 	else if(error != 0) {
36097cd94d69Schristos 		log_err_addr("http connect", wsa_strerror(error),
3610*14b2fa6eSchristos 			&c->repinfo.remote_addr, c->repinfo.remote_addrlen);
36117cd94d69Schristos #endif /* USE_WINSOCK */
36127cd94d69Schristos 		return 0;
36137cd94d69Schristos 	}
36147cd94d69Schristos 	/* keep on processing this socket */
36157cd94d69Schristos 	return 2;
36167cd94d69Schristos }
36177cd94d69Schristos 
36187cd94d69Schristos /** write more data for http (with ssl) */
36197cd94d69Schristos static int
36207cd94d69Schristos ssl_http_write_more(struct comm_point* c)
36217cd94d69Schristos {
36227cd94d69Schristos #ifdef HAVE_SSL
36237cd94d69Schristos 	int r;
36247cd94d69Schristos 	log_assert(sldns_buffer_remaining(c->buffer) > 0);
36257cd94d69Schristos 	ERR_clear_error();
36267cd94d69Schristos 	r = SSL_write(c->ssl, (void*)sldns_buffer_current(c->buffer),
36277cd94d69Schristos 		(int)sldns_buffer_remaining(c->buffer));
36287cd94d69Schristos 	if(r <= 0) {
36297cd94d69Schristos 		int want = SSL_get_error(c->ssl, r);
36307cd94d69Schristos 		if(want == SSL_ERROR_ZERO_RETURN) {
36317cd94d69Schristos 			return 0; /* closed */
36327cd94d69Schristos 		} else if(want == SSL_ERROR_WANT_READ) {
363387edd195Schristos 			c->ssl_shake_state = comm_ssl_shake_hs_read;
36347cd94d69Schristos 			comm_point_listen_for_rw(c, 1, 0);
36357cd94d69Schristos 			return 1; /* wait for read condition */
36367cd94d69Schristos 		} else if(want == SSL_ERROR_WANT_WRITE) {
36377cd94d69Schristos 			return 1; /* write more later */
36387cd94d69Schristos 		} else if(want == SSL_ERROR_SYSCALL) {
363987edd195Schristos #ifdef EPIPE
364087edd195Schristos 			if(errno == EPIPE && verbosity < 2)
364187edd195Schristos 				return 0; /* silence 'broken pipe' */
364287edd195Schristos #endif
36437cd94d69Schristos 			if(errno != 0)
36447cd94d69Schristos 				log_err("SSL_write syscall: %s",
36457cd94d69Schristos 					strerror(errno));
36467cd94d69Schristos 			return 0;
36477cd94d69Schristos 		}
3648*14b2fa6eSchristos 		log_crypto_err_io("could not SSL_write", want);
36497cd94d69Schristos 		return 0;
36507cd94d69Schristos 	}
36517cd94d69Schristos 	sldns_buffer_skip(c->buffer, (ssize_t)r);
36527cd94d69Schristos 	return 1;
36537cd94d69Schristos #else
36547cd94d69Schristos 	(void)c;
36557cd94d69Schristos 	return 0;
36567cd94d69Schristos #endif /* HAVE_SSL */
36577cd94d69Schristos }
36587cd94d69Schristos 
36597cd94d69Schristos /** write more data for http */
36607cd94d69Schristos static int
36617cd94d69Schristos http_write_more(int fd, struct comm_point* c)
36627cd94d69Schristos {
36637cd94d69Schristos 	ssize_t r;
36647cd94d69Schristos 	log_assert(sldns_buffer_remaining(c->buffer) > 0);
36657cd94d69Schristos 	r = send(fd, (void*)sldns_buffer_current(c->buffer),
36667cd94d69Schristos 		sldns_buffer_remaining(c->buffer), 0);
36677cd94d69Schristos 	if(r == -1) {
36687cd94d69Schristos #ifndef USE_WINSOCK
36697cd94d69Schristos 		if(errno == EINTR || errno == EAGAIN)
36707cd94d69Schristos 			return 1;
36717cd94d69Schristos #else
36727cd94d69Schristos 		if(WSAGetLastError() == WSAEINPROGRESS)
36737cd94d69Schristos 			return 1;
36747cd94d69Schristos 		if(WSAGetLastError() == WSAEWOULDBLOCK) {
36757cd94d69Schristos 			ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
36767cd94d69Schristos 			return 1;
36777cd94d69Schristos 		}
36787cd94d69Schristos #endif
367916776186Schristos 		log_err_addr("http send r", sock_strerror(errno),
3680*14b2fa6eSchristos 			&c->repinfo.remote_addr, c->repinfo.remote_addrlen);
36817cd94d69Schristos 		return 0;
36827cd94d69Schristos 	}
36837cd94d69Schristos 	sldns_buffer_skip(c->buffer, r);
36847cd94d69Schristos 	return 1;
36857cd94d69Schristos }
36867cd94d69Schristos 
368716776186Schristos #ifdef HAVE_NGHTTP2
368816776186Schristos ssize_t http2_send_cb(nghttp2_session* ATTR_UNUSED(session), const uint8_t* buf,
368916776186Schristos 	size_t len, int ATTR_UNUSED(flags), void* cb_arg)
369016776186Schristos {
369116776186Schristos 	ssize_t ret;
369216776186Schristos 	struct http2_session* h2_session = (struct http2_session*)cb_arg;
369316776186Schristos 	log_assert(h2_session->c->type == comm_http);
369416776186Schristos 	log_assert(h2_session->c->h2_session);
369516776186Schristos 
369616776186Schristos #ifdef HAVE_SSL
369716776186Schristos 	if(h2_session->c->ssl) {
369816776186Schristos 		int r;
369916776186Schristos 		ERR_clear_error();
370016776186Schristos 		r = SSL_write(h2_session->c->ssl, buf, len);
370116776186Schristos 		if(r <= 0) {
370216776186Schristos 			int want = SSL_get_error(h2_session->c->ssl, r);
370316776186Schristos 			if(want == SSL_ERROR_ZERO_RETURN) {
370416776186Schristos 				return NGHTTP2_ERR_CALLBACK_FAILURE;
370516776186Schristos 			} else if(want == SSL_ERROR_WANT_READ) {
370616776186Schristos 				h2_session->c->ssl_shake_state = comm_ssl_shake_hs_read;
370716776186Schristos 				comm_point_listen_for_rw(h2_session->c, 1, 0);
370816776186Schristos 				return NGHTTP2_ERR_WOULDBLOCK;
370916776186Schristos 			} else if(want == SSL_ERROR_WANT_WRITE) {
371016776186Schristos 				return NGHTTP2_ERR_WOULDBLOCK;
371116776186Schristos 			} else if(want == SSL_ERROR_SYSCALL) {
371216776186Schristos #ifdef EPIPE
371316776186Schristos 				if(errno == EPIPE && verbosity < 2)
371416776186Schristos 					return NGHTTP2_ERR_CALLBACK_FAILURE;
371516776186Schristos #endif
371616776186Schristos 				if(errno != 0)
371716776186Schristos 					log_err("SSL_write syscall: %s",
371816776186Schristos 						strerror(errno));
371916776186Schristos 				return NGHTTP2_ERR_CALLBACK_FAILURE;
372016776186Schristos 			}
3721*14b2fa6eSchristos 			log_crypto_err_io("could not SSL_write", want);
372216776186Schristos 			return NGHTTP2_ERR_CALLBACK_FAILURE;
372316776186Schristos 		}
372416776186Schristos 		return r;
372516776186Schristos 	}
372616776186Schristos #endif /* HAVE_SSL */
372716776186Schristos 
372816776186Schristos 	ret = send(h2_session->c->fd, buf, len, 0);
372916776186Schristos 	if(ret == 0) {
373016776186Schristos 		return NGHTTP2_ERR_CALLBACK_FAILURE;
373116776186Schristos 	} else if(ret < 0) {
373216776186Schristos #ifndef USE_WINSOCK
373316776186Schristos 		if(errno == EINTR || errno == EAGAIN)
373416776186Schristos 			return NGHTTP2_ERR_WOULDBLOCK;
373516776186Schristos #ifdef EPIPE
373616776186Schristos 		if(errno == EPIPE && verbosity < 2)
373716776186Schristos 			return NGHTTP2_ERR_CALLBACK_FAILURE;
373816776186Schristos #endif
373916776186Schristos #ifdef ECONNRESET
374016776186Schristos 		if(errno == ECONNRESET && verbosity < 2)
374116776186Schristos 			return NGHTTP2_ERR_CALLBACK_FAILURE;
374216776186Schristos #endif
374316776186Schristos 		log_err_addr("could not http2 write: %s", strerror(errno),
3744*14b2fa6eSchristos 			&h2_session->c->repinfo.remote_addr,
3745*14b2fa6eSchristos 			h2_session->c->repinfo.remote_addrlen);
374616776186Schristos #else /* USE_WINSOCK */
374716776186Schristos 		if(WSAGetLastError() == WSAENOTCONN)
374816776186Schristos 			return NGHTTP2_ERR_WOULDBLOCK;
374916776186Schristos 		if(WSAGetLastError() == WSAEINPROGRESS)
375016776186Schristos 			return NGHTTP2_ERR_WOULDBLOCK;
375116776186Schristos 		if(WSAGetLastError() == WSAEWOULDBLOCK) {
375216776186Schristos 			ub_winsock_tcp_wouldblock(h2_session->c->ev->ev,
375316776186Schristos 				UB_EV_WRITE);
375416776186Schristos 			return NGHTTP2_ERR_WOULDBLOCK;
375516776186Schristos 		}
375616776186Schristos 		if(WSAGetLastError() == WSAECONNRESET && verbosity < 2)
375716776186Schristos 			return NGHTTP2_ERR_CALLBACK_FAILURE;
375816776186Schristos 		log_err_addr("could not http2 write: %s",
375916776186Schristos 			wsa_strerror(WSAGetLastError()),
3760*14b2fa6eSchristos 			&h2_session->c->repinfo.remote_addr,
3761*14b2fa6eSchristos 			h2_session->c->repinfo.remote_addrlen);
376216776186Schristos #endif
376316776186Schristos 		return NGHTTP2_ERR_CALLBACK_FAILURE;
376416776186Schristos 	}
376516776186Schristos 	return ret;
376616776186Schristos }
376716776186Schristos #endif /* HAVE_NGHTTP2 */
376816776186Schristos 
376916776186Schristos /** Handle http2 writing */
377016776186Schristos static int
377116776186Schristos comm_point_http2_handle_write(int ATTR_UNUSED(fd), struct comm_point* c)
377216776186Schristos {
377316776186Schristos #ifdef HAVE_NGHTTP2
377416776186Schristos 	int ret;
377516776186Schristos 	log_assert(c->h2_session);
377616776186Schristos 
377716776186Schristos 	ret = nghttp2_session_send(c->h2_session->session);
377816776186Schristos 	if(ret) {
377916776186Schristos 		verbose(VERB_QUERY, "http2: session_send failed, "
378016776186Schristos 			"error: %s", nghttp2_strerror(ret));
378116776186Schristos 		return 0;
378216776186Schristos 	}
378316776186Schristos 
378416776186Schristos 	if(nghttp2_session_want_read(c->h2_session->session)) {
378516776186Schristos 		c->tcp_is_reading = 1;
378616776186Schristos 		comm_point_stop_listening(c);
378716776186Schristos 		comm_point_start_listening(c, -1, adjusted_tcp_timeout(c));
378816776186Schristos 	} else if(!nghttp2_session_want_write(c->h2_session->session))
378916776186Schristos 		return 0; /* connection can be closed */
379016776186Schristos 	return 1;
379116776186Schristos #else
379216776186Schristos 	(void)c;
379316776186Schristos 	return 0;
379416776186Schristos #endif
379516776186Schristos }
379616776186Schristos 
37977cd94d69Schristos /**
37987cd94d69Schristos  * Handle http writing callback.
37997cd94d69Schristos  * @param fd: file descriptor of socket.
38007cd94d69Schristos  * @param c: comm point to write buffer out of.
38017cd94d69Schristos  * @return: 0 on error
38027cd94d69Schristos  */
38037cd94d69Schristos static int
38047cd94d69Schristos comm_point_http_handle_write(int fd, struct comm_point* c)
38057cd94d69Schristos {
38067cd94d69Schristos 	log_assert(c->type == comm_http);
38077cd94d69Schristos 	log_assert(fd != -1);
38087cd94d69Schristos 
38097cd94d69Schristos 	/* check pending connect errors, if that fails, we wait for more,
38107cd94d69Schristos 	 * or we can continue to write contents */
38117cd94d69Schristos 	if(c->tcp_check_nb_connect) {
38127cd94d69Schristos 		int r = http_check_connect(fd, c);
38137cd94d69Schristos 		if(r == 0) return 0;
38147cd94d69Schristos 		if(r == 1) return 1;
38157cd94d69Schristos 		c->tcp_check_nb_connect = 0;
38167cd94d69Schristos 	}
38177cd94d69Schristos 	/* if we are in ssl handshake, handle SSL handshake */
38187cd94d69Schristos #ifdef HAVE_SSL
38197cd94d69Schristos 	if(c->ssl && c->ssl_shake_state != comm_ssl_shake_none) {
38207cd94d69Schristos 		if(!ssl_handshake(c))
38217cd94d69Schristos 			return 0;
38227cd94d69Schristos 		if(c->ssl_shake_state != comm_ssl_shake_none)
38237cd94d69Schristos 			return 1;
38247cd94d69Schristos 	}
38257cd94d69Schristos #endif /* HAVE_SSL */
38267cd94d69Schristos 	if(c->tcp_is_reading)
38277cd94d69Schristos 		return 1;
382816776186Schristos 
382916776186Schristos 	if(c->use_h2) {
383016776186Schristos 		return comm_point_http2_handle_write(fd, c);
383116776186Schristos 	}
383216776186Schristos 
383316776186Schristos 	/* http version is <= http/1.1 */
383416776186Schristos 
383516776186Schristos 	if(c->http_min_version >= http_version_2) {
383616776186Schristos 		/* HTTP/2 failed, not allowed to use lower version. */
383716776186Schristos 		return 0;
383816776186Schristos 	}
383916776186Schristos 
38407cd94d69Schristos 	/* if we are writing, write more */
38417cd94d69Schristos 	if(c->ssl) {
38427cd94d69Schristos 		if(!ssl_http_write_more(c))
38437cd94d69Schristos 			return 0;
38447cd94d69Schristos 	} else {
38457cd94d69Schristos 		if(!http_write_more(fd, c))
38467cd94d69Schristos 			return 0;
38477cd94d69Schristos 	}
38487cd94d69Schristos 
38497cd94d69Schristos 	/* we write a single buffer contents, that can contain
38507cd94d69Schristos 	 * the http request, and then flip to read the results */
38517cd94d69Schristos 	/* see if write is done */
38527cd94d69Schristos 	if(sldns_buffer_remaining(c->buffer) == 0) {
38537cd94d69Schristos 		sldns_buffer_clear(c->buffer);
38547cd94d69Schristos 		if(c->tcp_do_toggle_rw)
38557cd94d69Schristos 			c->tcp_is_reading = 1;
38567cd94d69Schristos 		c->tcp_byte_count = 0;
38577cd94d69Schristos 		/* switch from listening(write) to listening(read) */
38587cd94d69Schristos 		comm_point_stop_listening(c);
38597cd94d69Schristos 		comm_point_start_listening(c, -1, -1);
38607cd94d69Schristos 	}
38617cd94d69Schristos 	return 1;
38627cd94d69Schristos }
38637cd94d69Schristos 
38647cd94d69Schristos void
38657cd94d69Schristos comm_point_http_handle_callback(int fd, short event, void* arg)
38667cd94d69Schristos {
38677cd94d69Schristos 	struct comm_point* c = (struct comm_point*)arg;
38687cd94d69Schristos 	log_assert(c->type == comm_http);
38697cd94d69Schristos 	ub_comm_base_now(c->ev->base);
38707cd94d69Schristos 
387187edd195Schristos 	if(event&UB_EV_TIMEOUT) {
387287edd195Schristos 		verbose(VERB_QUERY, "http took too long, dropped");
387387edd195Schristos 		reclaim_http_handler(c);
387487edd195Schristos 		if(!c->tcp_do_close) {
387587edd195Schristos 			fptr_ok(fptr_whitelist_comm_point(c->callback));
387687edd195Schristos 			(void)(*c->callback)(c, c->cb_arg,
387787edd195Schristos 				NETEVENT_TIMEOUT, NULL);
387887edd195Schristos 		}
387987edd195Schristos 		return;
388087edd195Schristos 	}
38817cd94d69Schristos 	if(event&UB_EV_READ) {
38827cd94d69Schristos 		if(!comm_point_http_handle_read(fd, c)) {
38837cd94d69Schristos 			reclaim_http_handler(c);
38847cd94d69Schristos 			if(!c->tcp_do_close) {
38857cd94d69Schristos 				fptr_ok(fptr_whitelist_comm_point(
38867cd94d69Schristos 					c->callback));
38877cd94d69Schristos 				(void)(*c->callback)(c, c->cb_arg,
38887cd94d69Schristos 					NETEVENT_CLOSED, NULL);
38897cd94d69Schristos 			}
38907cd94d69Schristos 		}
38917cd94d69Schristos 		return;
38927cd94d69Schristos 	}
38937cd94d69Schristos 	if(event&UB_EV_WRITE) {
38947cd94d69Schristos 		if(!comm_point_http_handle_write(fd, c)) {
38957cd94d69Schristos 			reclaim_http_handler(c);
38967cd94d69Schristos 			if(!c->tcp_do_close) {
38977cd94d69Schristos 				fptr_ok(fptr_whitelist_comm_point(
38987cd94d69Schristos 					c->callback));
38997cd94d69Schristos 				(void)(*c->callback)(c, c->cb_arg,
39007cd94d69Schristos 					NETEVENT_CLOSED, NULL);
39017cd94d69Schristos 			}
39027cd94d69Schristos 		}
39037cd94d69Schristos 		return;
39047cd94d69Schristos 	}
39057cd94d69Schristos 	log_err("Ignored event %d for httphdl.", event);
39067cd94d69Schristos }
39077cd94d69Schristos 
39083b6c3722Schristos void comm_point_local_handle_callback(int fd, short event, void* arg)
39093b6c3722Schristos {
39103b6c3722Schristos 	struct comm_point* c = (struct comm_point*)arg;
39113b6c3722Schristos 	log_assert(c->type == comm_local);
39123b6c3722Schristos 	ub_comm_base_now(c->ev->base);
39133b6c3722Schristos 
39143b6c3722Schristos 	if(event&UB_EV_READ) {
39153b6c3722Schristos 		if(!comm_point_tcp_handle_read(fd, c, 1)) {
39163b6c3722Schristos 			fptr_ok(fptr_whitelist_comm_point(c->callback));
39173b6c3722Schristos 			(void)(*c->callback)(c, c->cb_arg, NETEVENT_CLOSED,
39183b6c3722Schristos 				NULL);
39193b6c3722Schristos 		}
39203b6c3722Schristos 		return;
39213b6c3722Schristos 	}
39223b6c3722Schristos 	log_err("Ignored event %d for localhdl.", event);
39233b6c3722Schristos }
39243b6c3722Schristos 
39253b6c3722Schristos void comm_point_raw_handle_callback(int ATTR_UNUSED(fd),
39263b6c3722Schristos 	short event, void* arg)
39273b6c3722Schristos {
39283b6c3722Schristos 	struct comm_point* c = (struct comm_point*)arg;
39293b6c3722Schristos 	int err = NETEVENT_NOERROR;
39303b6c3722Schristos 	log_assert(c->type == comm_raw);
39313b6c3722Schristos 	ub_comm_base_now(c->ev->base);
39323b6c3722Schristos 
39333b6c3722Schristos 	if(event&UB_EV_TIMEOUT)
39343b6c3722Schristos 		err = NETEVENT_TIMEOUT;
39353b6c3722Schristos 	fptr_ok(fptr_whitelist_comm_point_raw(c->callback));
39363b6c3722Schristos 	(void)(*c->callback)(c, c->cb_arg, err, NULL);
39373b6c3722Schristos }
39383b6c3722Schristos 
39393b6c3722Schristos struct comm_point*
39403b6c3722Schristos comm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer,
3941*14b2fa6eSchristos 	int pp2_enabled, comm_point_callback_type* callback,
3942*14b2fa6eSchristos 	void* callback_arg, struct unbound_socket* socket)
39433b6c3722Schristos {
39443b6c3722Schristos 	struct comm_point* c = (struct comm_point*)calloc(1,
39453b6c3722Schristos 		sizeof(struct comm_point));
39463b6c3722Schristos 	short evbits;
39473b6c3722Schristos 	if(!c)
39483b6c3722Schristos 		return NULL;
39493b6c3722Schristos 	c->ev = (struct internal_event*)calloc(1,
39503b6c3722Schristos 		sizeof(struct internal_event));
39513b6c3722Schristos 	if(!c->ev) {
39523b6c3722Schristos 		free(c);
39533b6c3722Schristos 		return NULL;
39543b6c3722Schristos 	}
39553b6c3722Schristos 	c->ev->base = base;
39563b6c3722Schristos 	c->fd = fd;
39573b6c3722Schristos 	c->buffer = buffer;
39583b6c3722Schristos 	c->timeout = NULL;
39593b6c3722Schristos 	c->tcp_is_reading = 0;
39603b6c3722Schristos 	c->tcp_byte_count = 0;
39613b6c3722Schristos 	c->tcp_parent = NULL;
39623b6c3722Schristos 	c->max_tcp_count = 0;
39633b6c3722Schristos 	c->cur_tcp_count = 0;
39643b6c3722Schristos 	c->tcp_handlers = NULL;
39653b6c3722Schristos 	c->tcp_free = NULL;
39663b6c3722Schristos 	c->type = comm_udp;
39673b6c3722Schristos 	c->tcp_do_close = 0;
39683b6c3722Schristos 	c->do_not_close = 0;
39693b6c3722Schristos 	c->tcp_do_toggle_rw = 0;
39703b6c3722Schristos 	c->tcp_check_nb_connect = 0;
39710cd9f4ecSchristos #ifdef USE_MSG_FASTOPEN
39720cd9f4ecSchristos 	c->tcp_do_fastopen = 0;
39730cd9f4ecSchristos #endif
39740cd9f4ecSchristos #ifdef USE_DNSCRYPT
39750cd9f4ecSchristos 	c->dnscrypt = 0;
39760cd9f4ecSchristos 	c->dnscrypt_buffer = buffer;
39770cd9f4ecSchristos #endif
39783b6c3722Schristos 	c->inuse = 0;
39793b6c3722Schristos 	c->callback = callback;
39803b6c3722Schristos 	c->cb_arg = callback_arg;
39811481e2a9Schristos 	c->socket = socket;
3982*14b2fa6eSchristos 	c->pp2_enabled = pp2_enabled;
3983*14b2fa6eSchristos 	c->pp2_header_state = pp2_header_none;
39843b6c3722Schristos 	evbits = UB_EV_READ | UB_EV_PERSIST;
39853b6c3722Schristos 	/* ub_event stuff */
39863b6c3722Schristos 	c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
39873b6c3722Schristos 		comm_point_udp_callback, c);
39883b6c3722Schristos 	if(c->ev->ev == NULL) {
39893b6c3722Schristos 		log_err("could not baseset udp event");
39903b6c3722Schristos 		comm_point_delete(c);
39913b6c3722Schristos 		return NULL;
39923b6c3722Schristos 	}
39933b6c3722Schristos 	if(fd!=-1 && ub_event_add(c->ev->ev, c->timeout) != 0 ) {
39943b6c3722Schristos 		log_err("could not add udp event");
39953b6c3722Schristos 		comm_point_delete(c);
39963b6c3722Schristos 		return NULL;
39973b6c3722Schristos 	}
399816776186Schristos 	c->event_added = 1;
39993b6c3722Schristos 	return c;
40003b6c3722Schristos }
40013b6c3722Schristos 
4002*14b2fa6eSchristos #if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG)
40033b6c3722Schristos struct comm_point*
40043b6c3722Schristos comm_point_create_udp_ancil(struct comm_base *base, int fd,
4005*14b2fa6eSchristos 	sldns_buffer* buffer, int pp2_enabled,
40061481e2a9Schristos 	comm_point_callback_type* callback, void* callback_arg, struct unbound_socket* socket)
40073b6c3722Schristos {
40083b6c3722Schristos 	struct comm_point* c = (struct comm_point*)calloc(1,
40093b6c3722Schristos 		sizeof(struct comm_point));
40103b6c3722Schristos 	short evbits;
40113b6c3722Schristos 	if(!c)
40123b6c3722Schristos 		return NULL;
40133b6c3722Schristos 	c->ev = (struct internal_event*)calloc(1,
40143b6c3722Schristos 		sizeof(struct internal_event));
40153b6c3722Schristos 	if(!c->ev) {
40163b6c3722Schristos 		free(c);
40173b6c3722Schristos 		return NULL;
40183b6c3722Schristos 	}
40193b6c3722Schristos 	c->ev->base = base;
40203b6c3722Schristos 	c->fd = fd;
40213b6c3722Schristos 	c->buffer = buffer;
40223b6c3722Schristos 	c->timeout = NULL;
40233b6c3722Schristos 	c->tcp_is_reading = 0;
40243b6c3722Schristos 	c->tcp_byte_count = 0;
40253b6c3722Schristos 	c->tcp_parent = NULL;
40263b6c3722Schristos 	c->max_tcp_count = 0;
40273b6c3722Schristos 	c->cur_tcp_count = 0;
40283b6c3722Schristos 	c->tcp_handlers = NULL;
40293b6c3722Schristos 	c->tcp_free = NULL;
40303b6c3722Schristos 	c->type = comm_udp;
40313b6c3722Schristos 	c->tcp_do_close = 0;
40323b6c3722Schristos 	c->do_not_close = 0;
40330cd9f4ecSchristos #ifdef USE_DNSCRYPT
40340cd9f4ecSchristos 	c->dnscrypt = 0;
40350cd9f4ecSchristos 	c->dnscrypt_buffer = buffer;
40360cd9f4ecSchristos #endif
40373b6c3722Schristos 	c->inuse = 0;
40383b6c3722Schristos 	c->tcp_do_toggle_rw = 0;
40393b6c3722Schristos 	c->tcp_check_nb_connect = 0;
40400cd9f4ecSchristos #ifdef USE_MSG_FASTOPEN
40410cd9f4ecSchristos 	c->tcp_do_fastopen = 0;
40420cd9f4ecSchristos #endif
40433b6c3722Schristos 	c->callback = callback;
40443b6c3722Schristos 	c->cb_arg = callback_arg;
40451481e2a9Schristos 	c->socket = socket;
4046*14b2fa6eSchristos 	c->pp2_enabled = pp2_enabled;
4047*14b2fa6eSchristos 	c->pp2_header_state = pp2_header_none;
40483b6c3722Schristos 	evbits = UB_EV_READ | UB_EV_PERSIST;
40493b6c3722Schristos 	/* ub_event stuff */
40503b6c3722Schristos 	c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
40513b6c3722Schristos 		comm_point_udp_ancil_callback, c);
40523b6c3722Schristos 	if(c->ev->ev == NULL) {
40533b6c3722Schristos 		log_err("could not baseset udp event");
40543b6c3722Schristos 		comm_point_delete(c);
40553b6c3722Schristos 		return NULL;
40563b6c3722Schristos 	}
40573b6c3722Schristos 	if(fd!=-1 && ub_event_add(c->ev->ev, c->timeout) != 0 ) {
40583b6c3722Schristos 		log_err("could not add udp event");
40593b6c3722Schristos 		comm_point_delete(c);
40603b6c3722Schristos 		return NULL;
40613b6c3722Schristos 	}
406216776186Schristos 	c->event_added = 1;
40633b6c3722Schristos 	return c;
40643b6c3722Schristos }
4065*14b2fa6eSchristos #endif
40663b6c3722Schristos 
40673b6c3722Schristos static struct comm_point*
40683b6c3722Schristos comm_point_create_tcp_handler(struct comm_base *base,
40693b6c3722Schristos 	struct comm_point* parent, size_t bufsize,
4070f42d8de7Schristos 	struct sldns_buffer* spoolbuf, comm_point_callback_type* callback,
40711481e2a9Schristos 	void* callback_arg, struct unbound_socket* socket)
40723b6c3722Schristos {
40733b6c3722Schristos 	struct comm_point* c = (struct comm_point*)calloc(1,
40743b6c3722Schristos 		sizeof(struct comm_point));
40753b6c3722Schristos 	short evbits;
40763b6c3722Schristos 	if(!c)
40773b6c3722Schristos 		return NULL;
40783b6c3722Schristos 	c->ev = (struct internal_event*)calloc(1,
40793b6c3722Schristos 		sizeof(struct internal_event));
40803b6c3722Schristos 	if(!c->ev) {
40813b6c3722Schristos 		free(c);
40823b6c3722Schristos 		return NULL;
40833b6c3722Schristos 	}
40843b6c3722Schristos 	c->ev->base = base;
40853b6c3722Schristos 	c->fd = -1;
40863b6c3722Schristos 	c->buffer = sldns_buffer_new(bufsize);
40873b6c3722Schristos 	if(!c->buffer) {
40883b6c3722Schristos 		free(c->ev);
40893b6c3722Schristos 		free(c);
40903b6c3722Schristos 		return NULL;
40913b6c3722Schristos 	}
40923b6c3722Schristos 	c->timeout = (struct timeval*)malloc(sizeof(struct timeval));
40933b6c3722Schristos 	if(!c->timeout) {
40943b6c3722Schristos 		sldns_buffer_free(c->buffer);
40953b6c3722Schristos 		free(c->ev);
40963b6c3722Schristos 		free(c);
40973b6c3722Schristos 		return NULL;
40983b6c3722Schristos 	}
40993b6c3722Schristos 	c->tcp_is_reading = 0;
41003b6c3722Schristos 	c->tcp_byte_count = 0;
41013b6c3722Schristos 	c->tcp_parent = parent;
4102f42d8de7Schristos 	c->tcp_timeout_msec = parent->tcp_timeout_msec;
4103f42d8de7Schristos 	c->tcp_conn_limit = parent->tcp_conn_limit;
4104f42d8de7Schristos 	c->tcl_addr = NULL;
4105f42d8de7Schristos 	c->tcp_keepalive = 0;
41063b6c3722Schristos 	c->max_tcp_count = 0;
41073b6c3722Schristos 	c->cur_tcp_count = 0;
41083b6c3722Schristos 	c->tcp_handlers = NULL;
41093b6c3722Schristos 	c->tcp_free = NULL;
41103b6c3722Schristos 	c->type = comm_tcp;
41113b6c3722Schristos 	c->tcp_do_close = 0;
41123b6c3722Schristos 	c->do_not_close = 0;
41133b6c3722Schristos 	c->tcp_do_toggle_rw = 1;
41143b6c3722Schristos 	c->tcp_check_nb_connect = 0;
41150cd9f4ecSchristos #ifdef USE_MSG_FASTOPEN
41160cd9f4ecSchristos 	c->tcp_do_fastopen = 0;
41170cd9f4ecSchristos #endif
41180cd9f4ecSchristos #ifdef USE_DNSCRYPT
41190cd9f4ecSchristos 	c->dnscrypt = 0;
41200cd9f4ecSchristos 	/* We don't know just yet if this is a dnscrypt channel. Allocation
41210cd9f4ecSchristos 	 * will be done when handling the callback. */
41220cd9f4ecSchristos 	c->dnscrypt_buffer = c->buffer;
41230cd9f4ecSchristos #endif
41243b6c3722Schristos 	c->repinfo.c = c;
41253b6c3722Schristos 	c->callback = callback;
41263b6c3722Schristos 	c->cb_arg = callback_arg;
41271481e2a9Schristos 	c->socket = socket;
4128*14b2fa6eSchristos 	c->pp2_enabled = parent->pp2_enabled;
4129*14b2fa6eSchristos 	c->pp2_header_state = pp2_header_none;
4130f42d8de7Schristos 	if(spoolbuf) {
4131f42d8de7Schristos 		c->tcp_req_info = tcp_req_info_create(spoolbuf);
4132f42d8de7Schristos 		if(!c->tcp_req_info) {
4133f42d8de7Schristos 			log_err("could not create tcp commpoint");
4134f42d8de7Schristos 			sldns_buffer_free(c->buffer);
4135f42d8de7Schristos 			free(c->timeout);
4136f42d8de7Schristos 			free(c->ev);
4137f42d8de7Schristos 			free(c);
4138f42d8de7Schristos 			return NULL;
4139f42d8de7Schristos 		}
4140f42d8de7Schristos 		c->tcp_req_info->cp = c;
4141f42d8de7Schristos 		c->tcp_do_close = 1;
4142f42d8de7Schristos 		c->tcp_do_toggle_rw = 0;
4143f42d8de7Schristos 	}
41443b6c3722Schristos 	/* add to parent free list */
41453b6c3722Schristos 	c->tcp_free = parent->tcp_free;
41463b6c3722Schristos 	parent->tcp_free = c;
41473b6c3722Schristos 	/* ub_event stuff */
41483b6c3722Schristos 	evbits = UB_EV_PERSIST | UB_EV_READ | UB_EV_TIMEOUT;
41493b6c3722Schristos 	c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
41503b6c3722Schristos 		comm_point_tcp_handle_callback, c);
41513b6c3722Schristos 	if(c->ev->ev == NULL)
41523b6c3722Schristos 	{
41533b6c3722Schristos 		log_err("could not basetset tcphdl event");
41543b6c3722Schristos 		parent->tcp_free = c->tcp_free;
4155f42d8de7Schristos 		tcp_req_info_delete(c->tcp_req_info);
4156f42d8de7Schristos 		sldns_buffer_free(c->buffer);
4157f42d8de7Schristos 		free(c->timeout);
41583b6c3722Schristos 		free(c->ev);
41593b6c3722Schristos 		free(c);
41603b6c3722Schristos 		return NULL;
41613b6c3722Schristos 	}
41623b6c3722Schristos 	return c;
41633b6c3722Schristos }
41643b6c3722Schristos 
416516776186Schristos static struct comm_point*
416616776186Schristos comm_point_create_http_handler(struct comm_base *base,
416716776186Schristos 	struct comm_point* parent, size_t bufsize, int harden_large_queries,
416816776186Schristos 	uint32_t http_max_streams, char* http_endpoint,
41691481e2a9Schristos 	comm_point_callback_type* callback, void* callback_arg,
41701481e2a9Schristos 	struct unbound_socket* socket)
417116776186Schristos {
417216776186Schristos 	struct comm_point* c = (struct comm_point*)calloc(1,
417316776186Schristos 		sizeof(struct comm_point));
417416776186Schristos 	short evbits;
417516776186Schristos 	if(!c)
417616776186Schristos 		return NULL;
417716776186Schristos 	c->ev = (struct internal_event*)calloc(1,
417816776186Schristos 		sizeof(struct internal_event));
417916776186Schristos 	if(!c->ev) {
418016776186Schristos 		free(c);
418116776186Schristos 		return NULL;
418216776186Schristos 	}
418316776186Schristos 	c->ev->base = base;
418416776186Schristos 	c->fd = -1;
418516776186Schristos 	c->buffer = sldns_buffer_new(bufsize);
418616776186Schristos 	if(!c->buffer) {
418716776186Schristos 		free(c->ev);
418816776186Schristos 		free(c);
418916776186Schristos 		return NULL;
419016776186Schristos 	}
419116776186Schristos 	c->timeout = (struct timeval*)malloc(sizeof(struct timeval));
419216776186Schristos 	if(!c->timeout) {
419316776186Schristos 		sldns_buffer_free(c->buffer);
419416776186Schristos 		free(c->ev);
419516776186Schristos 		free(c);
419616776186Schristos 		return NULL;
419716776186Schristos 	}
419816776186Schristos 	c->tcp_is_reading = 0;
419916776186Schristos 	c->tcp_byte_count = 0;
420016776186Schristos 	c->tcp_parent = parent;
420116776186Schristos 	c->tcp_timeout_msec = parent->tcp_timeout_msec;
420216776186Schristos 	c->tcp_conn_limit = parent->tcp_conn_limit;
420316776186Schristos 	c->tcl_addr = NULL;
420416776186Schristos 	c->tcp_keepalive = 0;
420516776186Schristos 	c->max_tcp_count = 0;
420616776186Schristos 	c->cur_tcp_count = 0;
420716776186Schristos 	c->tcp_handlers = NULL;
420816776186Schristos 	c->tcp_free = NULL;
420916776186Schristos 	c->type = comm_http;
421016776186Schristos 	c->tcp_do_close = 1;
421116776186Schristos 	c->do_not_close = 0;
421216776186Schristos 	c->tcp_do_toggle_rw = 1; /* will be set to 0 after http2 upgrade */
421316776186Schristos 	c->tcp_check_nb_connect = 0;
421416776186Schristos #ifdef USE_MSG_FASTOPEN
421516776186Schristos 	c->tcp_do_fastopen = 0;
421616776186Schristos #endif
421716776186Schristos #ifdef USE_DNSCRYPT
421816776186Schristos 	c->dnscrypt = 0;
421916776186Schristos 	c->dnscrypt_buffer = NULL;
422016776186Schristos #endif
422116776186Schristos 	c->repinfo.c = c;
422216776186Schristos 	c->callback = callback;
422316776186Schristos 	c->cb_arg = callback_arg;
42241481e2a9Schristos 	c->socket = socket;
4225*14b2fa6eSchristos 	c->pp2_enabled = 0;
4226*14b2fa6eSchristos 	c->pp2_header_state = pp2_header_none;
422716776186Schristos 
422816776186Schristos 	c->http_min_version = http_version_2;
422916776186Schristos 	c->http2_stream_max_qbuffer_size = bufsize;
423016776186Schristos 	if(harden_large_queries && bufsize > 512)
423116776186Schristos 		c->http2_stream_max_qbuffer_size = 512;
423216776186Schristos 	c->http2_max_streams = http_max_streams;
423316776186Schristos 	if(!(c->http_endpoint = strdup(http_endpoint))) {
423416776186Schristos 		log_err("could not strdup http_endpoint");
423516776186Schristos 		sldns_buffer_free(c->buffer);
423616776186Schristos 		free(c->timeout);
423716776186Schristos 		free(c->ev);
423816776186Schristos 		free(c);
423916776186Schristos 		return NULL;
424016776186Schristos 	}
424116776186Schristos 	c->use_h2 = 0;
424216776186Schristos #ifdef HAVE_NGHTTP2
424316776186Schristos 	if(!(c->h2_session = http2_session_create(c))) {
424416776186Schristos 		log_err("could not create http2 session");
424516776186Schristos 		free(c->http_endpoint);
424616776186Schristos 		sldns_buffer_free(c->buffer);
424716776186Schristos 		free(c->timeout);
424816776186Schristos 		free(c->ev);
424916776186Schristos 		free(c);
425016776186Schristos 		return NULL;
425116776186Schristos 	}
425216776186Schristos 	if(!(c->h2_session->callbacks = http2_req_callbacks_create())) {
425316776186Schristos 		log_err("could not create http2 callbacks");
425416776186Schristos 		http2_session_delete(c->h2_session);
425516776186Schristos 		free(c->http_endpoint);
425616776186Schristos 		sldns_buffer_free(c->buffer);
425716776186Schristos 		free(c->timeout);
425816776186Schristos 		free(c->ev);
425916776186Schristos 		free(c);
426016776186Schristos 		return NULL;
426116776186Schristos 	}
426216776186Schristos #endif
426316776186Schristos 
426416776186Schristos 	/* add to parent free list */
426516776186Schristos 	c->tcp_free = parent->tcp_free;
426616776186Schristos 	parent->tcp_free = c;
426716776186Schristos 	/* ub_event stuff */
426816776186Schristos 	evbits = UB_EV_PERSIST | UB_EV_READ | UB_EV_TIMEOUT;
426916776186Schristos 	c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
427016776186Schristos 		comm_point_http_handle_callback, c);
427116776186Schristos 	if(c->ev->ev == NULL)
427216776186Schristos 	{
427316776186Schristos 		log_err("could not set http handler event");
427416776186Schristos 		parent->tcp_free = c->tcp_free;
427516776186Schristos 		http2_session_delete(c->h2_session);
427616776186Schristos 		sldns_buffer_free(c->buffer);
427716776186Schristos 		free(c->timeout);
427816776186Schristos 		free(c->ev);
427916776186Schristos 		free(c);
428016776186Schristos 		return NULL;
428116776186Schristos 	}
428216776186Schristos 	return c;
428316776186Schristos }
428416776186Schristos 
42853b6c3722Schristos struct comm_point*
4286f42d8de7Schristos comm_point_create_tcp(struct comm_base *base, int fd, int num,
428716776186Schristos 	int idle_timeout, int harden_large_queries,
428816776186Schristos 	uint32_t http_max_streams, char* http_endpoint,
428916776186Schristos 	struct tcl_list* tcp_conn_limit, size_t bufsize,
429016776186Schristos 	struct sldns_buffer* spoolbuf, enum listen_type port_type,
4291*14b2fa6eSchristos 	int pp2_enabled, comm_point_callback_type* callback,
4292*14b2fa6eSchristos 	void* callback_arg, struct unbound_socket* socket)
42933b6c3722Schristos {
42943b6c3722Schristos 	struct comm_point* c = (struct comm_point*)calloc(1,
42953b6c3722Schristos 		sizeof(struct comm_point));
42963b6c3722Schristos 	short evbits;
42973b6c3722Schristos 	int i;
42983b6c3722Schristos 	/* first allocate the TCP accept listener */
42993b6c3722Schristos 	if(!c)
43003b6c3722Schristos 		return NULL;
43013b6c3722Schristos 	c->ev = (struct internal_event*)calloc(1,
43023b6c3722Schristos 		sizeof(struct internal_event));
43033b6c3722Schristos 	if(!c->ev) {
43043b6c3722Schristos 		free(c);
43053b6c3722Schristos 		return NULL;
43063b6c3722Schristos 	}
43073b6c3722Schristos 	c->ev->base = base;
43083b6c3722Schristos 	c->fd = fd;
43093b6c3722Schristos 	c->buffer = NULL;
43103b6c3722Schristos 	c->timeout = NULL;
43113b6c3722Schristos 	c->tcp_is_reading = 0;
43123b6c3722Schristos 	c->tcp_byte_count = 0;
4313f42d8de7Schristos 	c->tcp_timeout_msec = idle_timeout;
4314f42d8de7Schristos 	c->tcp_conn_limit = tcp_conn_limit;
4315f42d8de7Schristos 	c->tcl_addr = NULL;
4316f42d8de7Schristos 	c->tcp_keepalive = 0;
43173b6c3722Schristos 	c->tcp_parent = NULL;
43183b6c3722Schristos 	c->max_tcp_count = num;
43193b6c3722Schristos 	c->cur_tcp_count = 0;
43203b6c3722Schristos 	c->tcp_handlers = (struct comm_point**)calloc((size_t)num,
43213b6c3722Schristos 		sizeof(struct comm_point*));
43223b6c3722Schristos 	if(!c->tcp_handlers) {
43233b6c3722Schristos 		free(c->ev);
43243b6c3722Schristos 		free(c);
43253b6c3722Schristos 		return NULL;
43263b6c3722Schristos 	}
43273b6c3722Schristos 	c->tcp_free = NULL;
43283b6c3722Schristos 	c->type = comm_tcp_accept;
43293b6c3722Schristos 	c->tcp_do_close = 0;
43303b6c3722Schristos 	c->do_not_close = 0;
43313b6c3722Schristos 	c->tcp_do_toggle_rw = 0;
43323b6c3722Schristos 	c->tcp_check_nb_connect = 0;
43330cd9f4ecSchristos #ifdef USE_MSG_FASTOPEN
43340cd9f4ecSchristos 	c->tcp_do_fastopen = 0;
43350cd9f4ecSchristos #endif
43360cd9f4ecSchristos #ifdef USE_DNSCRYPT
43370cd9f4ecSchristos 	c->dnscrypt = 0;
43380cd9f4ecSchristos 	c->dnscrypt_buffer = NULL;
43390cd9f4ecSchristos #endif
43403b6c3722Schristos 	c->callback = NULL;
43413b6c3722Schristos 	c->cb_arg = NULL;
43421481e2a9Schristos 	c->socket = socket;
4343*14b2fa6eSchristos 	c->pp2_enabled = (port_type==listen_type_http?0:pp2_enabled);
4344*14b2fa6eSchristos 	c->pp2_header_state = pp2_header_none;
43453b6c3722Schristos 	evbits = UB_EV_READ | UB_EV_PERSIST;
43463b6c3722Schristos 	/* ub_event stuff */
43473b6c3722Schristos 	c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
43483b6c3722Schristos 		comm_point_tcp_accept_callback, c);
43493b6c3722Schristos 	if(c->ev->ev == NULL) {
43503b6c3722Schristos 		log_err("could not baseset tcpacc event");
43513b6c3722Schristos 		comm_point_delete(c);
43523b6c3722Schristos 		return NULL;
43533b6c3722Schristos 	}
43543b6c3722Schristos 	if (ub_event_add(c->ev->ev, c->timeout) != 0) {
43553b6c3722Schristos 		log_err("could not add tcpacc event");
43563b6c3722Schristos 		comm_point_delete(c);
43573b6c3722Schristos 		return NULL;
43583b6c3722Schristos 	}
435916776186Schristos 	c->event_added = 1;
436016776186Schristos 	/* now prealloc the handlers */
43613b6c3722Schristos 	for(i=0; i<num; i++) {
436216776186Schristos 		if(port_type == listen_type_tcp ||
436316776186Schristos 			port_type == listen_type_ssl ||
436416776186Schristos 			port_type == listen_type_tcp_dnscrypt) {
43653b6c3722Schristos 			c->tcp_handlers[i] = comm_point_create_tcp_handler(base,
43661481e2a9Schristos 				c, bufsize, spoolbuf, callback, callback_arg, socket);
436716776186Schristos 		} else if(port_type == listen_type_http) {
436816776186Schristos 			c->tcp_handlers[i] = comm_point_create_http_handler(
436916776186Schristos 				base, c, bufsize, harden_large_queries,
437016776186Schristos 				http_max_streams, http_endpoint,
43711481e2a9Schristos 				callback, callback_arg, socket);
437216776186Schristos 		}
437316776186Schristos 		else {
437416776186Schristos 			log_err("could not create tcp handler, unknown listen "
437516776186Schristos 				"type");
437616776186Schristos 			return NULL;
437716776186Schristos 		}
43783b6c3722Schristos 		if(!c->tcp_handlers[i]) {
43793b6c3722Schristos 			comm_point_delete(c);
43803b6c3722Schristos 			return NULL;
43813b6c3722Schristos 		}
43823b6c3722Schristos 	}
43833b6c3722Schristos 
43843b6c3722Schristos 	return c;
43853b6c3722Schristos }
43863b6c3722Schristos 
43873b6c3722Schristos struct comm_point*
43883b6c3722Schristos comm_point_create_tcp_out(struct comm_base *base, size_t bufsize,
43890cd9f4ecSchristos         comm_point_callback_type* callback, void* callback_arg)
43903b6c3722Schristos {
43913b6c3722Schristos 	struct comm_point* c = (struct comm_point*)calloc(1,
43923b6c3722Schristos 		sizeof(struct comm_point));
43933b6c3722Schristos 	short evbits;
43943b6c3722Schristos 	if(!c)
43953b6c3722Schristos 		return NULL;
43963b6c3722Schristos 	c->ev = (struct internal_event*)calloc(1,
43973b6c3722Schristos 		sizeof(struct internal_event));
43983b6c3722Schristos 	if(!c->ev) {
43993b6c3722Schristos 		free(c);
44003b6c3722Schristos 		return NULL;
44013b6c3722Schristos 	}
44023b6c3722Schristos 	c->ev->base = base;
44033b6c3722Schristos 	c->fd = -1;
44043b6c3722Schristos 	c->buffer = sldns_buffer_new(bufsize);
44053b6c3722Schristos 	if(!c->buffer) {
44063b6c3722Schristos 		free(c->ev);
44073b6c3722Schristos 		free(c);
44083b6c3722Schristos 		return NULL;
44093b6c3722Schristos 	}
44103b6c3722Schristos 	c->timeout = NULL;
44113b6c3722Schristos 	c->tcp_is_reading = 0;
44123b6c3722Schristos 	c->tcp_byte_count = 0;
4413f42d8de7Schristos 	c->tcp_timeout_msec = TCP_QUERY_TIMEOUT;
4414f42d8de7Schristos 	c->tcp_conn_limit = NULL;
4415f42d8de7Schristos 	c->tcl_addr = NULL;
4416f42d8de7Schristos 	c->tcp_keepalive = 0;
44173b6c3722Schristos 	c->tcp_parent = NULL;
44183b6c3722Schristos 	c->max_tcp_count = 0;
44193b6c3722Schristos 	c->cur_tcp_count = 0;
44203b6c3722Schristos 	c->tcp_handlers = NULL;
44213b6c3722Schristos 	c->tcp_free = NULL;
44223b6c3722Schristos 	c->type = comm_tcp;
44233b6c3722Schristos 	c->tcp_do_close = 0;
44243b6c3722Schristos 	c->do_not_close = 0;
44253b6c3722Schristos 	c->tcp_do_toggle_rw = 1;
44263b6c3722Schristos 	c->tcp_check_nb_connect = 1;
44270cd9f4ecSchristos #ifdef USE_MSG_FASTOPEN
44280cd9f4ecSchristos 	c->tcp_do_fastopen = 1;
44290cd9f4ecSchristos #endif
44300cd9f4ecSchristos #ifdef USE_DNSCRYPT
44310cd9f4ecSchristos 	c->dnscrypt = 0;
44320cd9f4ecSchristos 	c->dnscrypt_buffer = c->buffer;
44330cd9f4ecSchristos #endif
44343b6c3722Schristos 	c->repinfo.c = c;
44353b6c3722Schristos 	c->callback = callback;
44363b6c3722Schristos 	c->cb_arg = callback_arg;
4437*14b2fa6eSchristos 	c->pp2_enabled = 0;
4438*14b2fa6eSchristos 	c->pp2_header_state = pp2_header_none;
44393b6c3722Schristos 	evbits = UB_EV_PERSIST | UB_EV_WRITE;
44403b6c3722Schristos 	c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
44413b6c3722Schristos 		comm_point_tcp_handle_callback, c);
44423b6c3722Schristos 	if(c->ev->ev == NULL)
44433b6c3722Schristos 	{
44443b6c3722Schristos 		log_err("could not baseset tcpout event");
44453b6c3722Schristos 		sldns_buffer_free(c->buffer);
44463b6c3722Schristos 		free(c->ev);
44473b6c3722Schristos 		free(c);
44483b6c3722Schristos 		return NULL;
44493b6c3722Schristos 	}
44503b6c3722Schristos 
44513b6c3722Schristos 	return c;
44523b6c3722Schristos }
44533b6c3722Schristos 
44543b6c3722Schristos struct comm_point*
44557cd94d69Schristos comm_point_create_http_out(struct comm_base *base, size_t bufsize,
44567cd94d69Schristos         comm_point_callback_type* callback, void* callback_arg,
44577cd94d69Schristos 	sldns_buffer* temp)
44587cd94d69Schristos {
44597cd94d69Schristos 	struct comm_point* c = (struct comm_point*)calloc(1,
44607cd94d69Schristos 		sizeof(struct comm_point));
44617cd94d69Schristos 	short evbits;
44627cd94d69Schristos 	if(!c)
44637cd94d69Schristos 		return NULL;
44647cd94d69Schristos 	c->ev = (struct internal_event*)calloc(1,
44657cd94d69Schristos 		sizeof(struct internal_event));
44667cd94d69Schristos 	if(!c->ev) {
44677cd94d69Schristos 		free(c);
44687cd94d69Schristos 		return NULL;
44697cd94d69Schristos 	}
44707cd94d69Schristos 	c->ev->base = base;
44717cd94d69Schristos 	c->fd = -1;
44727cd94d69Schristos 	c->buffer = sldns_buffer_new(bufsize);
44737cd94d69Schristos 	if(!c->buffer) {
44747cd94d69Schristos 		free(c->ev);
44757cd94d69Schristos 		free(c);
44767cd94d69Schristos 		return NULL;
44777cd94d69Schristos 	}
44787cd94d69Schristos 	c->timeout = NULL;
44797cd94d69Schristos 	c->tcp_is_reading = 0;
44807cd94d69Schristos 	c->tcp_byte_count = 0;
44817cd94d69Schristos 	c->tcp_parent = NULL;
44827cd94d69Schristos 	c->max_tcp_count = 0;
44837cd94d69Schristos 	c->cur_tcp_count = 0;
44847cd94d69Schristos 	c->tcp_handlers = NULL;
44857cd94d69Schristos 	c->tcp_free = NULL;
44867cd94d69Schristos 	c->type = comm_http;
44877cd94d69Schristos 	c->tcp_do_close = 0;
44887cd94d69Schristos 	c->do_not_close = 0;
44897cd94d69Schristos 	c->tcp_do_toggle_rw = 1;
44907cd94d69Schristos 	c->tcp_check_nb_connect = 1;
44917cd94d69Schristos 	c->http_in_headers = 1;
44927cd94d69Schristos 	c->http_in_chunk_headers = 0;
44937cd94d69Schristos 	c->http_is_chunked = 0;
44947cd94d69Schristos 	c->http_temp = temp;
44957cd94d69Schristos #ifdef USE_MSG_FASTOPEN
44967cd94d69Schristos 	c->tcp_do_fastopen = 1;
44977cd94d69Schristos #endif
44987cd94d69Schristos #ifdef USE_DNSCRYPT
44997cd94d69Schristos 	c->dnscrypt = 0;
45007cd94d69Schristos 	c->dnscrypt_buffer = c->buffer;
45017cd94d69Schristos #endif
45027cd94d69Schristos 	c->repinfo.c = c;
45037cd94d69Schristos 	c->callback = callback;
45047cd94d69Schristos 	c->cb_arg = callback_arg;
4505*14b2fa6eSchristos 	c->pp2_enabled = 0;
4506*14b2fa6eSchristos 	c->pp2_header_state = pp2_header_none;
45077cd94d69Schristos 	evbits = UB_EV_PERSIST | UB_EV_WRITE;
45087cd94d69Schristos 	c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
45097cd94d69Schristos 		comm_point_http_handle_callback, c);
45107cd94d69Schristos 	if(c->ev->ev == NULL)
45117cd94d69Schristos 	{
45127cd94d69Schristos 		log_err("could not baseset tcpout event");
45137cd94d69Schristos #ifdef HAVE_SSL
45147cd94d69Schristos 		SSL_free(c->ssl);
45157cd94d69Schristos #endif
45167cd94d69Schristos 		sldns_buffer_free(c->buffer);
45177cd94d69Schristos 		free(c->ev);
45187cd94d69Schristos 		free(c);
45197cd94d69Schristos 		return NULL;
45207cd94d69Schristos 	}
45217cd94d69Schristos 
45227cd94d69Schristos 	return c;
45237cd94d69Schristos }
45247cd94d69Schristos 
45257cd94d69Schristos struct comm_point*
45263b6c3722Schristos comm_point_create_local(struct comm_base *base, int fd, size_t bufsize,
45270cd9f4ecSchristos         comm_point_callback_type* callback, void* callback_arg)
45283b6c3722Schristos {
45293b6c3722Schristos 	struct comm_point* c = (struct comm_point*)calloc(1,
45303b6c3722Schristos 		sizeof(struct comm_point));
45313b6c3722Schristos 	short evbits;
45323b6c3722Schristos 	if(!c)
45333b6c3722Schristos 		return NULL;
45343b6c3722Schristos 	c->ev = (struct internal_event*)calloc(1,
45353b6c3722Schristos 		sizeof(struct internal_event));
45363b6c3722Schristos 	if(!c->ev) {
45373b6c3722Schristos 		free(c);
45383b6c3722Schristos 		return NULL;
45393b6c3722Schristos 	}
45403b6c3722Schristos 	c->ev->base = base;
45413b6c3722Schristos 	c->fd = fd;
45423b6c3722Schristos 	c->buffer = sldns_buffer_new(bufsize);
45433b6c3722Schristos 	if(!c->buffer) {
45443b6c3722Schristos 		free(c->ev);
45453b6c3722Schristos 		free(c);
45463b6c3722Schristos 		return NULL;
45473b6c3722Schristos 	}
45483b6c3722Schristos 	c->timeout = NULL;
45493b6c3722Schristos 	c->tcp_is_reading = 1;
45503b6c3722Schristos 	c->tcp_byte_count = 0;
45513b6c3722Schristos 	c->tcp_parent = NULL;
45523b6c3722Schristos 	c->max_tcp_count = 0;
45533b6c3722Schristos 	c->cur_tcp_count = 0;
45543b6c3722Schristos 	c->tcp_handlers = NULL;
45553b6c3722Schristos 	c->tcp_free = NULL;
45563b6c3722Schristos 	c->type = comm_local;
45573b6c3722Schristos 	c->tcp_do_close = 0;
45583b6c3722Schristos 	c->do_not_close = 1;
45593b6c3722Schristos 	c->tcp_do_toggle_rw = 0;
45603b6c3722Schristos 	c->tcp_check_nb_connect = 0;
45610cd9f4ecSchristos #ifdef USE_MSG_FASTOPEN
45620cd9f4ecSchristos 	c->tcp_do_fastopen = 0;
45630cd9f4ecSchristos #endif
45640cd9f4ecSchristos #ifdef USE_DNSCRYPT
45650cd9f4ecSchristos 	c->dnscrypt = 0;
45660cd9f4ecSchristos 	c->dnscrypt_buffer = c->buffer;
45670cd9f4ecSchristos #endif
45683b6c3722Schristos 	c->callback = callback;
45693b6c3722Schristos 	c->cb_arg = callback_arg;
4570*14b2fa6eSchristos 	c->pp2_enabled = 0;
4571*14b2fa6eSchristos 	c->pp2_header_state = pp2_header_none;
45723b6c3722Schristos 	/* ub_event stuff */
45733b6c3722Schristos 	evbits = UB_EV_PERSIST | UB_EV_READ;
45743b6c3722Schristos 	c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
45753b6c3722Schristos 		comm_point_local_handle_callback, c);
45763b6c3722Schristos 	if(c->ev->ev == NULL) {
45773b6c3722Schristos 		log_err("could not baseset localhdl event");
45783b6c3722Schristos 		free(c->ev);
45793b6c3722Schristos 		free(c);
45803b6c3722Schristos 		return NULL;
45813b6c3722Schristos 	}
45823b6c3722Schristos 	if (ub_event_add(c->ev->ev, c->timeout) != 0) {
45833b6c3722Schristos 		log_err("could not add localhdl event");
45843b6c3722Schristos 		ub_event_free(c->ev->ev);
45853b6c3722Schristos 		free(c->ev);
45863b6c3722Schristos 		free(c);
45873b6c3722Schristos 		return NULL;
45883b6c3722Schristos 	}
458916776186Schristos 	c->event_added = 1;
45903b6c3722Schristos 	return c;
45913b6c3722Schristos }
45923b6c3722Schristos 
45933b6c3722Schristos struct comm_point*
45943b6c3722Schristos comm_point_create_raw(struct comm_base* base, int fd, int writing,
45950cd9f4ecSchristos 	comm_point_callback_type* callback, void* callback_arg)
45963b6c3722Schristos {
45973b6c3722Schristos 	struct comm_point* c = (struct comm_point*)calloc(1,
45983b6c3722Schristos 		sizeof(struct comm_point));
45993b6c3722Schristos 	short evbits;
46003b6c3722Schristos 	if(!c)
46013b6c3722Schristos 		return NULL;
46023b6c3722Schristos 	c->ev = (struct internal_event*)calloc(1,
46033b6c3722Schristos 		sizeof(struct internal_event));
46043b6c3722Schristos 	if(!c->ev) {
46053b6c3722Schristos 		free(c);
46063b6c3722Schristos 		return NULL;
46073b6c3722Schristos 	}
46083b6c3722Schristos 	c->ev->base = base;
46093b6c3722Schristos 	c->fd = fd;
46103b6c3722Schristos 	c->buffer = NULL;
46113b6c3722Schristos 	c->timeout = NULL;
46123b6c3722Schristos 	c->tcp_is_reading = 0;
46133b6c3722Schristos 	c->tcp_byte_count = 0;
46143b6c3722Schristos 	c->tcp_parent = NULL;
46153b6c3722Schristos 	c->max_tcp_count = 0;
46163b6c3722Schristos 	c->cur_tcp_count = 0;
46173b6c3722Schristos 	c->tcp_handlers = NULL;
46183b6c3722Schristos 	c->tcp_free = NULL;
46193b6c3722Schristos 	c->type = comm_raw;
46203b6c3722Schristos 	c->tcp_do_close = 0;
46213b6c3722Schristos 	c->do_not_close = 1;
46223b6c3722Schristos 	c->tcp_do_toggle_rw = 0;
46233b6c3722Schristos 	c->tcp_check_nb_connect = 0;
46240cd9f4ecSchristos #ifdef USE_MSG_FASTOPEN
46250cd9f4ecSchristos 	c->tcp_do_fastopen = 0;
46260cd9f4ecSchristos #endif
46270cd9f4ecSchristos #ifdef USE_DNSCRYPT
46280cd9f4ecSchristos 	c->dnscrypt = 0;
46290cd9f4ecSchristos 	c->dnscrypt_buffer = c->buffer;
46300cd9f4ecSchristos #endif
46313b6c3722Schristos 	c->callback = callback;
46323b6c3722Schristos 	c->cb_arg = callback_arg;
4633*14b2fa6eSchristos 	c->pp2_enabled = 0;
4634*14b2fa6eSchristos 	c->pp2_header_state = pp2_header_none;
46353b6c3722Schristos 	/* ub_event stuff */
46363b6c3722Schristos 	if(writing)
46373b6c3722Schristos 		evbits = UB_EV_PERSIST | UB_EV_WRITE;
46383b6c3722Schristos 	else 	evbits = UB_EV_PERSIST | UB_EV_READ;
46393b6c3722Schristos 	c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
46403b6c3722Schristos 		comm_point_raw_handle_callback, c);
46413b6c3722Schristos 	if(c->ev->ev == NULL) {
46423b6c3722Schristos 		log_err("could not baseset rawhdl event");
46433b6c3722Schristos 		free(c->ev);
46443b6c3722Schristos 		free(c);
46453b6c3722Schristos 		return NULL;
46463b6c3722Schristos 	}
46473b6c3722Schristos 	if (ub_event_add(c->ev->ev, c->timeout) != 0) {
46483b6c3722Schristos 		log_err("could not add rawhdl event");
46493b6c3722Schristos 		ub_event_free(c->ev->ev);
46503b6c3722Schristos 		free(c->ev);
46513b6c3722Schristos 		free(c);
46523b6c3722Schristos 		return NULL;
46533b6c3722Schristos 	}
465416776186Schristos 	c->event_added = 1;
46553b6c3722Schristos 	return c;
46563b6c3722Schristos }
46573b6c3722Schristos 
46583b6c3722Schristos void
46593b6c3722Schristos comm_point_close(struct comm_point* c)
46603b6c3722Schristos {
46613b6c3722Schristos 	if(!c)
46623b6c3722Schristos 		return;
46637cd94d69Schristos 	if(c->fd != -1) {
466416776186Schristos 		verbose(5, "comm_point_close of %d: event_del", c->fd);
466516776186Schristos 		if(c->event_added) {
46663b6c3722Schristos 			if(ub_event_del(c->ev->ev) != 0) {
46673b6c3722Schristos 				log_err("could not event_del on close");
46683b6c3722Schristos 			}
466916776186Schristos 			c->event_added = 0;
467016776186Schristos 		}
46717cd94d69Schristos 	}
4672f42d8de7Schristos 	tcl_close_connection(c->tcl_addr);
4673f42d8de7Schristos 	if(c->tcp_req_info)
4674f42d8de7Schristos 		tcp_req_info_clear(c->tcp_req_info);
467516776186Schristos 	if(c->h2_session)
467616776186Schristos 		http2_session_server_delete(c->h2_session);
4677*14b2fa6eSchristos 	/* stop the comm point from reading or writing after it is closed. */
4678*14b2fa6eSchristos 	if(c->tcp_more_read_again && *c->tcp_more_read_again)
4679*14b2fa6eSchristos 		*c->tcp_more_read_again = 0;
4680*14b2fa6eSchristos 	if(c->tcp_more_write_again && *c->tcp_more_write_again)
4681*14b2fa6eSchristos 		*c->tcp_more_write_again = 0;
468216776186Schristos 
46833b6c3722Schristos 	/* close fd after removing from event lists, or epoll.. is messed up */
46843b6c3722Schristos 	if(c->fd != -1 && !c->do_not_close) {
46851481e2a9Schristos #ifdef USE_WINSOCK
46867cd94d69Schristos 		if(c->type == comm_tcp || c->type == comm_http) {
46877cd94d69Schristos 			/* delete sticky events for the fd, it gets closed */
46887cd94d69Schristos 			ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
46897cd94d69Schristos 			ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
46907cd94d69Schristos 		}
46911481e2a9Schristos #endif
46923b6c3722Schristos 		verbose(VERB_ALGO, "close fd %d", c->fd);
469316776186Schristos 		sock_close(c->fd);
46943b6c3722Schristos 	}
46953b6c3722Schristos 	c->fd = -1;
46963b6c3722Schristos }
46973b6c3722Schristos 
46983b6c3722Schristos void
46993b6c3722Schristos comm_point_delete(struct comm_point* c)
47003b6c3722Schristos {
47013b6c3722Schristos 	if(!c)
47023b6c3722Schristos 		return;
47037cd94d69Schristos 	if((c->type == comm_tcp || c->type == comm_http) && c->ssl) {
47043b6c3722Schristos #ifdef HAVE_SSL
47053b6c3722Schristos 		SSL_shutdown(c->ssl);
47063b6c3722Schristos 		SSL_free(c->ssl);
47073b6c3722Schristos #endif
47083b6c3722Schristos 	}
470916776186Schristos 	if(c->type == comm_http && c->http_endpoint) {
471016776186Schristos 		free(c->http_endpoint);
471116776186Schristos 		c->http_endpoint = NULL;
471216776186Schristos 	}
47133b6c3722Schristos 	comm_point_close(c);
47143b6c3722Schristos 	if(c->tcp_handlers) {
47153b6c3722Schristos 		int i;
47163b6c3722Schristos 		for(i=0; i<c->max_tcp_count; i++)
47173b6c3722Schristos 			comm_point_delete(c->tcp_handlers[i]);
47183b6c3722Schristos 		free(c->tcp_handlers);
47193b6c3722Schristos 	}
47203b6c3722Schristos 	free(c->timeout);
47217cd94d69Schristos 	if(c->type == comm_tcp || c->type == comm_local || c->type == comm_http) {
47223b6c3722Schristos 		sldns_buffer_free(c->buffer);
47230cd9f4ecSchristos #ifdef USE_DNSCRYPT
47240cd9f4ecSchristos 		if(c->dnscrypt && c->dnscrypt_buffer != c->buffer) {
47250cd9f4ecSchristos 			sldns_buffer_free(c->dnscrypt_buffer);
47260cd9f4ecSchristos 		}
47270cd9f4ecSchristos #endif
4728f42d8de7Schristos 		if(c->tcp_req_info) {
4729f42d8de7Schristos 			tcp_req_info_delete(c->tcp_req_info);
4730f42d8de7Schristos 		}
473116776186Schristos 		if(c->h2_session) {
473216776186Schristos 			http2_session_delete(c->h2_session);
473316776186Schristos 		}
47340cd9f4ecSchristos 	}
47353b6c3722Schristos 	ub_event_free(c->ev->ev);
47363b6c3722Schristos 	free(c->ev);
47373b6c3722Schristos 	free(c);
47383b6c3722Schristos }
47393b6c3722Schristos 
47403b6c3722Schristos void
47413b6c3722Schristos comm_point_send_reply(struct comm_reply *repinfo)
47423b6c3722Schristos {
47430cd9f4ecSchristos 	struct sldns_buffer* buffer;
47443b6c3722Schristos 	log_assert(repinfo && repinfo->c);
47450cd9f4ecSchristos #ifdef USE_DNSCRYPT
47460cd9f4ecSchristos 	buffer = repinfo->c->dnscrypt_buffer;
47470cd9f4ecSchristos 	if(!dnsc_handle_uncurved_request(repinfo)) {
47480cd9f4ecSchristos 		return;
47490cd9f4ecSchristos 	}
47500cd9f4ecSchristos #else
47510cd9f4ecSchristos 	buffer = repinfo->c->buffer;
47520cd9f4ecSchristos #endif
47533b6c3722Schristos 	if(repinfo->c->type == comm_udp) {
47543b6c3722Schristos 		if(repinfo->srctype)
4755*14b2fa6eSchristos 			comm_point_send_udp_msg_if(repinfo->c, buffer,
4756*14b2fa6eSchristos 				(struct sockaddr*)&repinfo->remote_addr,
4757*14b2fa6eSchristos 				repinfo->remote_addrlen, repinfo);
47583b6c3722Schristos 		else
47590cd9f4ecSchristos 			comm_point_send_udp_msg(repinfo->c, buffer,
4760*14b2fa6eSchristos 				(struct sockaddr*)&repinfo->remote_addr,
4761*14b2fa6eSchristos 				repinfo->remote_addrlen, 0);
47623b6c3722Schristos #ifdef USE_DNSTAP
47631481e2a9Schristos 		/*
47641481e2a9Schristos 		 * sending src (client)/dst (local service) addresses over DNSTAP from udp callback
47651481e2a9Schristos 		 */
47661481e2a9Schristos 		if(repinfo->c->dtenv != NULL && repinfo->c->dtenv->log_client_response_messages) {
47671481e2a9Schristos 			log_addr(VERB_ALGO, "from local addr", (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->socket->addr->ai_addrlen);
4768*14b2fa6eSchristos 			log_addr(VERB_ALGO, "response to client", &repinfo->client_addr, repinfo->client_addrlen);
4769*14b2fa6eSchristos 			dt_msg_send_client_response(repinfo->c->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->type, repinfo->c->buffer);
47701481e2a9Schristos 		}
47713b6c3722Schristos #endif
47723b6c3722Schristos 	} else {
47733b6c3722Schristos #ifdef USE_DNSTAP
47741481e2a9Schristos 		/*
47751481e2a9Schristos 		 * sending src (client)/dst (local service) addresses over DNSTAP from TCP callback
47761481e2a9Schristos 		 */
47771481e2a9Schristos 		if(repinfo->c->tcp_parent->dtenv != NULL && repinfo->c->tcp_parent->dtenv->log_client_response_messages) {
47781481e2a9Schristos 			log_addr(VERB_ALGO, "from local addr", (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->socket->addr->ai_addrlen);
4779*14b2fa6eSchristos 			log_addr(VERB_ALGO, "response to client", &repinfo->client_addr, repinfo->client_addrlen);
4780*14b2fa6eSchristos 			dt_msg_send_client_response(repinfo->c->tcp_parent->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->type,
47811481e2a9Schristos 				( repinfo->c->tcp_req_info? repinfo->c->tcp_req_info->spool_buffer: repinfo->c->buffer ));
47821481e2a9Schristos 		}
47833b6c3722Schristos #endif
4784f42d8de7Schristos 		if(repinfo->c->tcp_req_info) {
4785f42d8de7Schristos 			tcp_req_info_send_reply(repinfo->c->tcp_req_info);
478616776186Schristos 		} else if(repinfo->c->use_h2) {
478716776186Schristos 			if(!http2_submit_dns_response(repinfo->c->h2_session)) {
478816776186Schristos 				comm_point_drop_reply(repinfo);
478916776186Schristos 				return;
479016776186Schristos 			}
479116776186Schristos 			repinfo->c->h2_stream = NULL;
479216776186Schristos 			repinfo->c->tcp_is_reading = 0;
479316776186Schristos 			comm_point_stop_listening(repinfo->c);
479416776186Schristos 			comm_point_start_listening(repinfo->c, -1,
479516776186Schristos 				adjusted_tcp_timeout(repinfo->c));
479616776186Schristos 			return;
4797f42d8de7Schristos 		} else {
47980cd9f4ecSchristos 			comm_point_start_listening(repinfo->c, -1,
479916776186Schristos 				adjusted_tcp_timeout(repinfo->c));
48003b6c3722Schristos 		}
48013b6c3722Schristos 	}
4802f42d8de7Schristos }
48033b6c3722Schristos 
48043b6c3722Schristos void
48053b6c3722Schristos comm_point_drop_reply(struct comm_reply* repinfo)
48063b6c3722Schristos {
48073b6c3722Schristos 	if(!repinfo)
48083b6c3722Schristos 		return;
480987edd195Schristos 	log_assert(repinfo->c);
48103b6c3722Schristos 	log_assert(repinfo->c->type != comm_tcp_accept);
48113b6c3722Schristos 	if(repinfo->c->type == comm_udp)
48123b6c3722Schristos 		return;
4813f42d8de7Schristos 	if(repinfo->c->tcp_req_info)
4814f42d8de7Schristos 		repinfo->c->tcp_req_info->is_drop = 1;
481516776186Schristos 	if(repinfo->c->type == comm_http) {
481616776186Schristos 		if(repinfo->c->h2_session) {
481716776186Schristos 			repinfo->c->h2_session->is_drop = 1;
481816776186Schristos 			if(!repinfo->c->h2_session->postpone_drop)
481916776186Schristos 				reclaim_http_handler(repinfo->c);
482016776186Schristos 			return;
482116776186Schristos 		}
482216776186Schristos 		reclaim_http_handler(repinfo->c);
482316776186Schristos 		return;
482416776186Schristos 	}
48253b6c3722Schristos 	reclaim_tcp_handler(repinfo->c);
48263b6c3722Schristos }
48273b6c3722Schristos 
48283b6c3722Schristos void
48293b6c3722Schristos comm_point_stop_listening(struct comm_point* c)
48303b6c3722Schristos {
48313b6c3722Schristos 	verbose(VERB_ALGO, "comm point stop listening %d", c->fd);
483216776186Schristos 	if(c->event_added) {
48333b6c3722Schristos 		if(ub_event_del(c->ev->ev) != 0) {
48343b6c3722Schristos 			log_err("event_del error to stoplisten");
48353b6c3722Schristos 		}
483616776186Schristos 		c->event_added = 0;
483716776186Schristos 	}
48383b6c3722Schristos }
48393b6c3722Schristos 
48403b6c3722Schristos void
48410cd9f4ecSchristos comm_point_start_listening(struct comm_point* c, int newfd, int msec)
48423b6c3722Schristos {
484387edd195Schristos 	verbose(VERB_ALGO, "comm point start listening %d (%d msec)",
484487edd195Schristos 		c->fd==-1?newfd:c->fd, msec);
48453b6c3722Schristos 	if(c->type == comm_tcp_accept && !c->tcp_free) {
48463b6c3722Schristos 		/* no use to start listening no free slots. */
48473b6c3722Schristos 		return;
48483b6c3722Schristos 	}
484916776186Schristos 	if(c->event_added) {
485016776186Schristos 		if(ub_event_del(c->ev->ev) != 0) {
485116776186Schristos 			log_err("event_del error to startlisten");
485216776186Schristos 		}
485316776186Schristos 		c->event_added = 0;
485416776186Schristos 	}
48550cd9f4ecSchristos 	if(msec != -1 && msec != 0) {
48563b6c3722Schristos 		if(!c->timeout) {
48573b6c3722Schristos 			c->timeout = (struct timeval*)malloc(sizeof(
48583b6c3722Schristos 				struct timeval));
48593b6c3722Schristos 			if(!c->timeout) {
48603b6c3722Schristos 				log_err("cpsl: malloc failed. No net read.");
48613b6c3722Schristos 				return;
48623b6c3722Schristos 			}
48633b6c3722Schristos 		}
48643b6c3722Schristos 		ub_event_add_bits(c->ev->ev, UB_EV_TIMEOUT);
48653b6c3722Schristos #ifndef S_SPLINT_S /* splint fails on struct timeval. */
48660cd9f4ecSchristos 		c->timeout->tv_sec = msec/1000;
48670cd9f4ecSchristos 		c->timeout->tv_usec = (msec%1000)*1000;
48683b6c3722Schristos #endif /* S_SPLINT_S */
48691481e2a9Schristos 	} else {
48701481e2a9Schristos 		if(msec == 0 || !c->timeout) {
48711481e2a9Schristos 			ub_event_del_bits(c->ev->ev, UB_EV_TIMEOUT);
48721481e2a9Schristos 		}
48733b6c3722Schristos 	}
48747cd94d69Schristos 	if(c->type == comm_tcp || c->type == comm_http) {
48753b6c3722Schristos 		ub_event_del_bits(c->ev->ev, UB_EV_READ|UB_EV_WRITE);
487616776186Schristos 		if(c->tcp_write_and_read) {
487716776186Schristos 			verbose(5, "startlistening %d mode rw", (newfd==-1?c->fd:newfd));
487816776186Schristos 			ub_event_add_bits(c->ev->ev, UB_EV_READ|UB_EV_WRITE);
487916776186Schristos 		} else if(c->tcp_is_reading) {
488016776186Schristos 			verbose(5, "startlistening %d mode r", (newfd==-1?c->fd:newfd));
48813b6c3722Schristos 			ub_event_add_bits(c->ev->ev, UB_EV_READ);
488216776186Schristos 		} else	{
488316776186Schristos 			verbose(5, "startlistening %d mode w", (newfd==-1?c->fd:newfd));
488416776186Schristos 			ub_event_add_bits(c->ev->ev, UB_EV_WRITE);
488516776186Schristos 		}
48863b6c3722Schristos 	}
48873b6c3722Schristos 	if(newfd != -1) {
488816776186Schristos 		if(c->fd != -1 && c->fd != newfd) {
488916776186Schristos 			verbose(5, "cpsl close of fd %d for %d", c->fd, newfd);
489016776186Schristos 			sock_close(c->fd);
48913b6c3722Schristos 		}
48923b6c3722Schristos 		c->fd = newfd;
48933b6c3722Schristos 		ub_event_set_fd(c->ev->ev, c->fd);
48943b6c3722Schristos 	}
48950cd9f4ecSchristos 	if(ub_event_add(c->ev->ev, msec==0?NULL:c->timeout) != 0) {
48963b6c3722Schristos 		log_err("event_add failed. in cpsl.");
48971481e2a9Schristos 		return;
48983b6c3722Schristos 	}
489916776186Schristos 	c->event_added = 1;
49003b6c3722Schristos }
49013b6c3722Schristos 
49023b6c3722Schristos void comm_point_listen_for_rw(struct comm_point* c, int rd, int wr)
49033b6c3722Schristos {
49043b6c3722Schristos 	verbose(VERB_ALGO, "comm point listen_for_rw %d %d", c->fd, wr);
490516776186Schristos 	if(c->event_added) {
49063b6c3722Schristos 		if(ub_event_del(c->ev->ev) != 0) {
49073b6c3722Schristos 			log_err("event_del error to cplf");
49083b6c3722Schristos 		}
490916776186Schristos 		c->event_added = 0;
491016776186Schristos 	}
49111481e2a9Schristos 	if(!c->timeout) {
49121481e2a9Schristos 		ub_event_del_bits(c->ev->ev, UB_EV_TIMEOUT);
49131481e2a9Schristos 	}
49143b6c3722Schristos 	ub_event_del_bits(c->ev->ev, UB_EV_READ|UB_EV_WRITE);
49153b6c3722Schristos 	if(rd) ub_event_add_bits(c->ev->ev, UB_EV_READ);
49163b6c3722Schristos 	if(wr) ub_event_add_bits(c->ev->ev, UB_EV_WRITE);
49173b6c3722Schristos 	if(ub_event_add(c->ev->ev, c->timeout) != 0) {
49183b6c3722Schristos 		log_err("event_add failed. in cplf.");
49191481e2a9Schristos 		return;
49203b6c3722Schristos 	}
492116776186Schristos 	c->event_added = 1;
49223b6c3722Schristos }
49233b6c3722Schristos 
49243b6c3722Schristos size_t comm_point_get_mem(struct comm_point* c)
49253b6c3722Schristos {
49263b6c3722Schristos 	size_t s;
49273b6c3722Schristos 	if(!c)
49283b6c3722Schristos 		return 0;
49293b6c3722Schristos 	s = sizeof(*c) + sizeof(*c->ev);
49303b6c3722Schristos 	if(c->timeout)
49313b6c3722Schristos 		s += sizeof(*c->timeout);
49320cd9f4ecSchristos 	if(c->type == comm_tcp || c->type == comm_local) {
49333b6c3722Schristos 		s += sizeof(*c->buffer) + sldns_buffer_capacity(c->buffer);
49340cd9f4ecSchristos #ifdef USE_DNSCRYPT
49350cd9f4ecSchristos 		s += sizeof(*c->dnscrypt_buffer);
49360cd9f4ecSchristos 		if(c->buffer != c->dnscrypt_buffer) {
49370cd9f4ecSchristos 			s += sldns_buffer_capacity(c->dnscrypt_buffer);
49380cd9f4ecSchristos 		}
49390cd9f4ecSchristos #endif
49400cd9f4ecSchristos 	}
49413b6c3722Schristos 	if(c->type == comm_tcp_accept) {
49423b6c3722Schristos 		int i;
49433b6c3722Schristos 		for(i=0; i<c->max_tcp_count; i++)
49443b6c3722Schristos 			s += comm_point_get_mem(c->tcp_handlers[i]);
49453b6c3722Schristos 	}
49463b6c3722Schristos 	return s;
49473b6c3722Schristos }
49483b6c3722Schristos 
49493b6c3722Schristos struct comm_timer*
49503b6c3722Schristos comm_timer_create(struct comm_base* base, void (*cb)(void*), void* cb_arg)
49513b6c3722Schristos {
49523b6c3722Schristos 	struct internal_timer *tm = (struct internal_timer*)calloc(1,
49533b6c3722Schristos 		sizeof(struct internal_timer));
49543b6c3722Schristos 	if(!tm) {
49553b6c3722Schristos 		log_err("malloc failed");
49563b6c3722Schristos 		return NULL;
49573b6c3722Schristos 	}
49583b6c3722Schristos 	tm->super.ev_timer = tm;
49593b6c3722Schristos 	tm->base = base;
49603b6c3722Schristos 	tm->super.callback = cb;
49613b6c3722Schristos 	tm->super.cb_arg = cb_arg;
49623b6c3722Schristos 	tm->ev = ub_event_new(base->eb->base, -1, UB_EV_TIMEOUT,
49633b6c3722Schristos 		comm_timer_callback, &tm->super);
49643b6c3722Schristos 	if(tm->ev == NULL) {
49653b6c3722Schristos 		log_err("timer_create: event_base_set failed.");
49663b6c3722Schristos 		free(tm);
49673b6c3722Schristos 		return NULL;
49683b6c3722Schristos 	}
49693b6c3722Schristos 	return &tm->super;
49703b6c3722Schristos }
49713b6c3722Schristos 
49723b6c3722Schristos void
49733b6c3722Schristos comm_timer_disable(struct comm_timer* timer)
49743b6c3722Schristos {
49753b6c3722Schristos 	if(!timer)
49763b6c3722Schristos 		return;
49773b6c3722Schristos 	ub_timer_del(timer->ev_timer->ev);
49783b6c3722Schristos 	timer->ev_timer->enabled = 0;
49793b6c3722Schristos }
49803b6c3722Schristos 
49813b6c3722Schristos void
49823b6c3722Schristos comm_timer_set(struct comm_timer* timer, struct timeval* tv)
49833b6c3722Schristos {
49843b6c3722Schristos 	log_assert(tv);
49853b6c3722Schristos 	if(timer->ev_timer->enabled)
49863b6c3722Schristos 		comm_timer_disable(timer);
49873b6c3722Schristos 	if(ub_timer_add(timer->ev_timer->ev, timer->ev_timer->base->eb->base,
49883b6c3722Schristos 		comm_timer_callback, timer, tv) != 0)
49893b6c3722Schristos 		log_err("comm_timer_set: evtimer_add failed.");
49903b6c3722Schristos 	timer->ev_timer->enabled = 1;
49913b6c3722Schristos }
49923b6c3722Schristos 
49933b6c3722Schristos void
49943b6c3722Schristos comm_timer_delete(struct comm_timer* timer)
49953b6c3722Schristos {
49963b6c3722Schristos 	if(!timer)
49973b6c3722Schristos 		return;
49983b6c3722Schristos 	comm_timer_disable(timer);
49993b6c3722Schristos 	/* Free the sub struct timer->ev_timer derived from the super struct timer.
50003b6c3722Schristos 	 * i.e. assert(timer == timer->ev_timer)
50013b6c3722Schristos 	 */
50023b6c3722Schristos 	ub_event_free(timer->ev_timer->ev);
50033b6c3722Schristos 	free(timer->ev_timer);
50043b6c3722Schristos }
50053b6c3722Schristos 
50063b6c3722Schristos void
50073b6c3722Schristos comm_timer_callback(int ATTR_UNUSED(fd), short event, void* arg)
50083b6c3722Schristos {
50093b6c3722Schristos 	struct comm_timer* tm = (struct comm_timer*)arg;
50103b6c3722Schristos 	if(!(event&UB_EV_TIMEOUT))
50113b6c3722Schristos 		return;
50123b6c3722Schristos 	ub_comm_base_now(tm->ev_timer->base);
50133b6c3722Schristos 	tm->ev_timer->enabled = 0;
50143b6c3722Schristos 	fptr_ok(fptr_whitelist_comm_timer(tm->callback));
50153b6c3722Schristos 	(*tm->callback)(tm->cb_arg);
50163b6c3722Schristos }
50173b6c3722Schristos 
50183b6c3722Schristos int
50193b6c3722Schristos comm_timer_is_set(struct comm_timer* timer)
50203b6c3722Schristos {
50213b6c3722Schristos 	return (int)timer->ev_timer->enabled;
50223b6c3722Schristos }
50233b6c3722Schristos 
50243b6c3722Schristos size_t
50253b6c3722Schristos comm_timer_get_mem(struct comm_timer* ATTR_UNUSED(timer))
50263b6c3722Schristos {
50273b6c3722Schristos 	return sizeof(struct internal_timer);
50283b6c3722Schristos }
50293b6c3722Schristos 
50303b6c3722Schristos struct comm_signal*
50313b6c3722Schristos comm_signal_create(struct comm_base* base,
50323b6c3722Schristos         void (*callback)(int, void*), void* cb_arg)
50333b6c3722Schristos {
50343b6c3722Schristos 	struct comm_signal* com = (struct comm_signal*)malloc(
50353b6c3722Schristos 		sizeof(struct comm_signal));
50363b6c3722Schristos 	if(!com) {
50373b6c3722Schristos 		log_err("malloc failed");
50383b6c3722Schristos 		return NULL;
50393b6c3722Schristos 	}
50403b6c3722Schristos 	com->base = base;
50413b6c3722Schristos 	com->callback = callback;
50423b6c3722Schristos 	com->cb_arg = cb_arg;
50433b6c3722Schristos 	com->ev_signal = NULL;
50443b6c3722Schristos 	return com;
50453b6c3722Schristos }
50463b6c3722Schristos 
50473b6c3722Schristos void
50483b6c3722Schristos comm_signal_callback(int sig, short event, void* arg)
50493b6c3722Schristos {
50503b6c3722Schristos 	struct comm_signal* comsig = (struct comm_signal*)arg;
50513b6c3722Schristos 	if(!(event & UB_EV_SIGNAL))
50523b6c3722Schristos 		return;
50533b6c3722Schristos 	ub_comm_base_now(comsig->base);
50543b6c3722Schristos 	fptr_ok(fptr_whitelist_comm_signal(comsig->callback));
50553b6c3722Schristos 	(*comsig->callback)(sig, comsig->cb_arg);
50563b6c3722Schristos }
50573b6c3722Schristos 
50583b6c3722Schristos int
50593b6c3722Schristos comm_signal_bind(struct comm_signal* comsig, int sig)
50603b6c3722Schristos {
50613b6c3722Schristos 	struct internal_signal* entry = (struct internal_signal*)calloc(1,
50623b6c3722Schristos 		sizeof(struct internal_signal));
50633b6c3722Schristos 	if(!entry) {
50643b6c3722Schristos 		log_err("malloc failed");
50653b6c3722Schristos 		return 0;
50663b6c3722Schristos 	}
50673b6c3722Schristos 	log_assert(comsig);
50683b6c3722Schristos 	/* add signal event */
50693b6c3722Schristos 	entry->ev = ub_signal_new(comsig->base->eb->base, sig,
50703b6c3722Schristos 		comm_signal_callback, comsig);
50713b6c3722Schristos 	if(entry->ev == NULL) {
50723b6c3722Schristos 		log_err("Could not create signal event");
50733b6c3722Schristos 		free(entry);
50743b6c3722Schristos 		return 0;
50753b6c3722Schristos 	}
50763b6c3722Schristos 	if(ub_signal_add(entry->ev, NULL) != 0) {
50773b6c3722Schristos 		log_err("Could not add signal handler");
50783b6c3722Schristos 		ub_event_free(entry->ev);
50793b6c3722Schristos 		free(entry);
50803b6c3722Schristos 		return 0;
50813b6c3722Schristos 	}
50823b6c3722Schristos 	/* link into list */
50833b6c3722Schristos 	entry->next = comsig->ev_signal;
50843b6c3722Schristos 	comsig->ev_signal = entry;
50853b6c3722Schristos 	return 1;
50863b6c3722Schristos }
50873b6c3722Schristos 
50883b6c3722Schristos void
50893b6c3722Schristos comm_signal_delete(struct comm_signal* comsig)
50903b6c3722Schristos {
50913b6c3722Schristos 	struct internal_signal* p, *np;
50923b6c3722Schristos 	if(!comsig)
50933b6c3722Schristos 		return;
50943b6c3722Schristos 	p=comsig->ev_signal;
50953b6c3722Schristos 	while(p) {
50963b6c3722Schristos 		np = p->next;
50973b6c3722Schristos 		ub_signal_del(p->ev);
50983b6c3722Schristos 		ub_event_free(p->ev);
50993b6c3722Schristos 		free(p);
51003b6c3722Schristos 		p = np;
51013b6c3722Schristos 	}
51023b6c3722Schristos 	free(comsig);
51033b6c3722Schristos }
5104