1238106Sdes/*
2238106Sdes * util/netevent.c - event notification
3238106Sdes *
4238106Sdes * Copyright (c) 2007, NLnet Labs. All rights reserved.
5238106Sdes *
6238106Sdes * This software is open source.
7238106Sdes *
8238106Sdes * Redistribution and use in source and binary forms, with or without
9238106Sdes * modification, are permitted provided that the following conditions
10238106Sdes * are met:
11238106Sdes *
12238106Sdes * Redistributions of source code must retain the above copyright notice,
13238106Sdes * this list of conditions and the following disclaimer.
14238106Sdes *
15238106Sdes * Redistributions in binary form must reproduce the above copyright notice,
16238106Sdes * this list of conditions and the following disclaimer in the documentation
17238106Sdes * and/or other materials provided with the distribution.
18238106Sdes *
19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may
20238106Sdes * be used to endorse or promote products derived from this software without
21238106Sdes * specific prior written permission.
22238106Sdes *
23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24269257Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25269257Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26269257Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27269257Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28269257Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29269257Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30269257Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31269257Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32269257Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33269257Sdes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34238106Sdes */
35238106Sdes
36238106Sdes/**
37238106Sdes * \file
38238106Sdes *
39238106Sdes * This file contains event notification functions.
40238106Sdes */
41238106Sdes#include "config.h"
42238106Sdes#include "util/netevent.h"
43238106Sdes#include "util/log.h"
44238106Sdes#include "util/net_help.h"
45238106Sdes#include "util/fptr_wlist.h"
46269257Sdes#include "ldns/pkthdr.h"
47269257Sdes#include "ldns/sbuffer.h"
48249141Sdes#ifdef HAVE_OPENSSL_SSL_H
49238106Sdes#include <openssl/ssl.h>
50249141Sdes#endif
51249141Sdes#ifdef HAVE_OPENSSL_ERR_H
52238106Sdes#include <openssl/err.h>
53249141Sdes#endif
54238106Sdes
55238106Sdes/* -------- Start of local definitions -------- */
56238106Sdes/** if CMSG_ALIGN is not defined on this platform, a workaround */
57238106Sdes#ifndef CMSG_ALIGN
58238106Sdes#  ifdef _CMSG_DATA_ALIGN
59238106Sdes#    define CMSG_ALIGN _CMSG_DATA_ALIGN
60238106Sdes#  else
61238106Sdes#    define CMSG_ALIGN(len) (((len)+sizeof(long)-1) & ~(sizeof(long)-1))
62238106Sdes#  endif
63238106Sdes#endif
64238106Sdes
65238106Sdes/** if CMSG_LEN is not defined on this platform, a workaround */
66238106Sdes#ifndef CMSG_LEN
67238106Sdes#  define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr))+(len))
68238106Sdes#endif
69238106Sdes
70238106Sdes/** if CMSG_SPACE is not defined on this platform, a workaround */
71238106Sdes#ifndef CMSG_SPACE
72238106Sdes#  ifdef _CMSG_HDR_ALIGN
73238106Sdes#    define CMSG_SPACE(l) (CMSG_ALIGN(l)+_CMSG_HDR_ALIGN(sizeof(struct cmsghdr)))
74238106Sdes#  else
75238106Sdes#    define CMSG_SPACE(l) (CMSG_ALIGN(l)+CMSG_ALIGN(sizeof(struct cmsghdr)))
76238106Sdes#  endif
77238106Sdes#endif
78238106Sdes
79238106Sdes/** The TCP reading or writing query timeout in seconds */
80238106Sdes#define TCP_QUERY_TIMEOUT 120
81238106Sdes
82238106Sdes#ifndef NONBLOCKING_IS_BROKEN
83238106Sdes/** number of UDP reads to perform per read indication from select */
84238106Sdes#define NUM_UDP_PER_SELECT 100
85238106Sdes#else
86238106Sdes#define NUM_UDP_PER_SELECT 1
87238106Sdes#endif
88238106Sdes
89238106Sdes/* We define libevent structures here to hide the libevent stuff. */
90238106Sdes
91238106Sdes#ifdef USE_MINI_EVENT
92238106Sdes#  ifdef USE_WINSOCK
93238106Sdes#    include "util/winsock_event.h"
94238106Sdes#  else
95238106Sdes#    include "util/mini_event.h"
96238106Sdes#  endif /* USE_WINSOCK */
97238106Sdes#else /* USE_MINI_EVENT */
98238106Sdes   /* we use libevent */
99249141Sdes#  ifdef HAVE_EVENT_H
100249141Sdes#    include <event.h>
101249141Sdes#  else
102249141Sdes#    include "event2/event.h"
103249141Sdes#    include "event2/event_struct.h"
104249141Sdes#    include "event2/event_compat.h"
105249141Sdes#  endif
106238106Sdes#endif /* USE_MINI_EVENT */
107238106Sdes
108238106Sdes/**
109238106Sdes * The internal event structure for keeping libevent info for the event.
110238106Sdes * Possibly other structures (list, tree) this is part of.
111238106Sdes */
112238106Sdesstruct internal_event {
113238106Sdes	/** the comm base */
114238106Sdes	struct comm_base* base;
115238106Sdes	/** libevent event type, alloced here */
116238106Sdes	struct event ev;
117238106Sdes};
118238106Sdes
119238106Sdes/**
120238106Sdes * Internal base structure, so that every thread has its own events.
121238106Sdes */
122238106Sdesstruct internal_base {
123238106Sdes	/** libevent event_base type. */
124238106Sdes	struct event_base* base;
125238106Sdes	/** seconds time pointer points here */
126269257Sdes	time_t secs;
127238106Sdes	/** timeval with current time */
128238106Sdes	struct timeval now;
129238106Sdes	/** the event used for slow_accept timeouts */
130238106Sdes	struct event slow_accept;
131238106Sdes	/** true if slow_accept is enabled */
132238106Sdes	int slow_accept_enabled;
133238106Sdes};
134238106Sdes
135238106Sdes/**
136238106Sdes * Internal timer structure, to store timer event in.
137238106Sdes */
138238106Sdesstruct internal_timer {
139238106Sdes	/** the comm base */
140238106Sdes	struct comm_base* base;
141238106Sdes	/** libevent event type, alloced here */
142238106Sdes	struct event ev;
143238106Sdes	/** is timer enabled */
144238106Sdes	uint8_t enabled;
145238106Sdes};
146238106Sdes
147238106Sdes/**
148238106Sdes * Internal signal structure, to store signal event in.
149238106Sdes */
150238106Sdesstruct internal_signal {
151238106Sdes	/** libevent event type, alloced here */
152238106Sdes	struct event ev;
153238106Sdes	/** next in signal list */
154238106Sdes	struct internal_signal* next;
155238106Sdes};
156238106Sdes
157238106Sdes/** create a tcp handler with a parent */
158238106Sdesstatic struct comm_point* comm_point_create_tcp_handler(
159238106Sdes	struct comm_base *base, struct comm_point* parent, size_t bufsize,
160238106Sdes        comm_point_callback_t* callback, void* callback_arg);
161238106Sdes
162238106Sdes/* -------- End of local definitions -------- */
163238106Sdes
164238106Sdes#ifdef USE_MINI_EVENT
165238106Sdes/** minievent updates the time when it blocks. */
166238106Sdes#define comm_base_now(x) /* nothing to do */
167238106Sdes#else /* !USE_MINI_EVENT */
168238106Sdes/** fillup the time values in the event base */
169238106Sdesstatic void
170238106Sdescomm_base_now(struct comm_base* b)
171238106Sdes{
172238106Sdes	if(gettimeofday(&b->eb->now, NULL) < 0) {
173238106Sdes		log_err("gettimeofday: %s", strerror(errno));
174238106Sdes	}
175269257Sdes	b->eb->secs = (time_t)b->eb->now.tv_sec;
176238106Sdes}
177238106Sdes#endif /* USE_MINI_EVENT */
178238106Sdes
179238106Sdesstruct comm_base*
180238106Sdescomm_base_create(int sigs)
181238106Sdes{
182238106Sdes	struct comm_base* b = (struct comm_base*)calloc(1,
183238106Sdes		sizeof(struct comm_base));
184238106Sdes	if(!b)
185238106Sdes		return NULL;
186238106Sdes	b->eb = (struct internal_base*)calloc(1, sizeof(struct internal_base));
187238106Sdes	if(!b->eb) {
188238106Sdes		free(b);
189238106Sdes		return NULL;
190238106Sdes	}
191238106Sdes#ifdef USE_MINI_EVENT
192238106Sdes	(void)sigs;
193238106Sdes	/* use mini event time-sharing feature */
194238106Sdes	b->eb->base = event_init(&b->eb->secs, &b->eb->now);
195238106Sdes#else
196238106Sdes#  if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)
197238106Sdes	/* libev */
198238106Sdes	if(sigs)
199238106Sdes		b->eb->base=(struct event_base *)ev_default_loop(EVFLAG_AUTO);
200238106Sdes	else
201238106Sdes		b->eb->base=(struct event_base *)ev_loop_new(EVFLAG_AUTO);
202238106Sdes#  else
203238106Sdes	(void)sigs;
204238106Sdes#    ifdef HAVE_EVENT_BASE_NEW
205238106Sdes	b->eb->base = event_base_new();
206238106Sdes#    else
207238106Sdes	b->eb->base = event_init();
208238106Sdes#    endif
209238106Sdes#  endif
210238106Sdes#endif
211238106Sdes	if(!b->eb->base) {
212238106Sdes		free(b->eb);
213238106Sdes		free(b);
214238106Sdes		return NULL;
215238106Sdes	}
216238106Sdes	comm_base_now(b);
217238106Sdes	/* avoid event_get_method call which causes crashes even when
218238106Sdes	 * not printing, because its result is passed */
219238106Sdes	verbose(VERB_ALGO,
220238106Sdes#if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)
221238106Sdes		"libev"
222238106Sdes#elif defined(USE_MINI_EVENT)
223238106Sdes		"event "
224238106Sdes#else
225238106Sdes		"libevent "
226238106Sdes#endif
227238106Sdes		"%s uses %s method.",
228238106Sdes		event_get_version(),
229238106Sdes#ifdef HAVE_EVENT_BASE_GET_METHOD
230238106Sdes		event_base_get_method(b->eb->base)
231238106Sdes#else
232238106Sdes		"not_obtainable"
233238106Sdes#endif
234238106Sdes	);
235238106Sdes	return b;
236238106Sdes}
237238106Sdes
238269257Sdesstruct comm_base*
239269257Sdescomm_base_create_event(struct event_base* base)
240269257Sdes{
241269257Sdes	struct comm_base* b = (struct comm_base*)calloc(1,
242269257Sdes		sizeof(struct comm_base));
243269257Sdes	if(!b)
244269257Sdes		return NULL;
245269257Sdes	b->eb = (struct internal_base*)calloc(1, sizeof(struct internal_base));
246269257Sdes	if(!b->eb) {
247269257Sdes		free(b);
248269257Sdes		return NULL;
249269257Sdes	}
250269257Sdes	b->eb->base = base;
251269257Sdes	comm_base_now(b);
252269257Sdes	return b;
253269257Sdes}
254269257Sdes
255238106Sdesvoid
256238106Sdescomm_base_delete(struct comm_base* b)
257238106Sdes{
258238106Sdes	if(!b)
259238106Sdes		return;
260238106Sdes	if(b->eb->slow_accept_enabled) {
261238106Sdes		if(event_del(&b->eb->slow_accept) != 0) {
262238106Sdes			log_err("could not event_del slow_accept");
263238106Sdes		}
264238106Sdes	}
265238106Sdes#ifdef USE_MINI_EVENT
266238106Sdes	event_base_free(b->eb->base);
267238106Sdes#elif defined(HAVE_EVENT_BASE_FREE) && defined(HAVE_EVENT_BASE_ONCE)
268238106Sdes	/* only libevent 1.2+ has it, but in 1.2 it is broken -
269238106Sdes	   assertion fails on signal handling ev that is not deleted
270238106Sdes 	   in libevent 1.3c (event_base_once appears) this is fixed. */
271238106Sdes	event_base_free(b->eb->base);
272238106Sdes#endif /* HAVE_EVENT_BASE_FREE and HAVE_EVENT_BASE_ONCE */
273238106Sdes	b->eb->base = NULL;
274238106Sdes	free(b->eb);
275238106Sdes	free(b);
276238106Sdes}
277238106Sdes
278238106Sdesvoid
279269257Sdescomm_base_delete_no_base(struct comm_base* b)
280238106Sdes{
281269257Sdes	if(!b)
282269257Sdes		return;
283269257Sdes	if(b->eb->slow_accept_enabled) {
284269257Sdes		if(event_del(&b->eb->slow_accept) != 0) {
285269257Sdes			log_err("could not event_del slow_accept");
286269257Sdes		}
287269257Sdes	}
288269257Sdes	b->eb->base = NULL;
289269257Sdes	free(b->eb);
290269257Sdes	free(b);
291269257Sdes}
292269257Sdes
293269257Sdesvoid
294269257Sdescomm_base_timept(struct comm_base* b, time_t** tt, struct timeval** tv)
295269257Sdes{
296238106Sdes	*tt = &b->eb->secs;
297238106Sdes	*tv = &b->eb->now;
298238106Sdes}
299238106Sdes
300238106Sdesvoid
301238106Sdescomm_base_dispatch(struct comm_base* b)
302238106Sdes{
303238106Sdes	int retval;
304238106Sdes	retval = event_base_dispatch(b->eb->base);
305238106Sdes	if(retval != 0) {
306238106Sdes		fatal_exit("event_dispatch returned error %d, "
307238106Sdes			"errno is %s", retval, strerror(errno));
308238106Sdes	}
309238106Sdes}
310238106Sdes
311238106Sdesvoid comm_base_exit(struct comm_base* b)
312238106Sdes{
313238106Sdes	if(event_base_loopexit(b->eb->base, NULL) != 0) {
314238106Sdes		log_err("Could not loopexit");
315238106Sdes	}
316238106Sdes}
317238106Sdes
318238106Sdesvoid comm_base_set_slow_accept_handlers(struct comm_base* b,
319238106Sdes	void (*stop_acc)(void*), void (*start_acc)(void*), void* arg)
320238106Sdes{
321238106Sdes	b->stop_accept = stop_acc;
322238106Sdes	b->start_accept = start_acc;
323238106Sdes	b->cb_arg = arg;
324238106Sdes}
325238106Sdes
326238106Sdesstruct event_base* comm_base_internal(struct comm_base* b)
327238106Sdes{
328238106Sdes	return b->eb->base;
329238106Sdes}
330238106Sdes
331238106Sdes/** see if errno for udp has to be logged or not uses globals */
332238106Sdesstatic int
333238106Sdesudp_send_errno_needs_log(struct sockaddr* addr, socklen_t addrlen)
334238106Sdes{
335238106Sdes	/* do not log transient errors (unless high verbosity) */
336238106Sdes#if defined(ENETUNREACH) || defined(EHOSTDOWN) || defined(EHOSTUNREACH) || defined(ENETDOWN)
337238106Sdes	switch(errno) {
338238106Sdes#  ifdef ENETUNREACH
339238106Sdes		case ENETUNREACH:
340238106Sdes#  endif
341238106Sdes#  ifdef EHOSTDOWN
342238106Sdes		case EHOSTDOWN:
343238106Sdes#  endif
344238106Sdes#  ifdef EHOSTUNREACH
345238106Sdes		case EHOSTUNREACH:
346238106Sdes#  endif
347238106Sdes#  ifdef ENETDOWN
348238106Sdes		case ENETDOWN:
349238106Sdes#  endif
350238106Sdes			if(verbosity < VERB_ALGO)
351238106Sdes				return 0;
352238106Sdes		default:
353238106Sdes			break;
354238106Sdes	}
355238106Sdes#endif
356269257Sdes	/* permission denied is gotten for every send if the
357269257Sdes	 * network is disconnected (on some OS), squelch it */
358269257Sdes	if(errno == EPERM && verbosity < VERB_DETAIL)
359269257Sdes		return 0;
360238106Sdes	/* squelch errors where people deploy AAAA ::ffff:bla for
361238106Sdes	 * authority servers, which we try for intranets. */
362238106Sdes	if(errno == EINVAL && addr_is_ip4mapped(
363238106Sdes		(struct sockaddr_storage*)addr, addrlen) &&
364238106Sdes		verbosity < VERB_DETAIL)
365238106Sdes		return 0;
366238106Sdes	/* SO_BROADCAST sockopt can give access to 255.255.255.255,
367238106Sdes	 * but a dns cache does not need it. */
368238106Sdes	if(errno == EACCES && addr_is_broadcast(
369238106Sdes		(struct sockaddr_storage*)addr, addrlen) &&
370238106Sdes		verbosity < VERB_DETAIL)
371238106Sdes		return 0;
372238106Sdes	return 1;
373238106Sdes}
374238106Sdes
375238106Sdesint tcp_connect_errno_needs_log(struct sockaddr* addr, socklen_t addrlen)
376238106Sdes{
377238106Sdes	return udp_send_errno_needs_log(addr, addrlen);
378238106Sdes}
379238106Sdes
380238106Sdes/* send a UDP reply */
381238106Sdesint
382269257Sdescomm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet,
383238106Sdes	struct sockaddr* addr, socklen_t addrlen)
384238106Sdes{
385238106Sdes	ssize_t sent;
386238106Sdes	log_assert(c->fd != -1);
387238106Sdes#ifdef UNBOUND_DEBUG
388269257Sdes	if(sldns_buffer_remaining(packet) == 0)
389238106Sdes		log_err("error: send empty UDP packet");
390238106Sdes#endif
391238106Sdes	log_assert(addr && addrlen > 0);
392269257Sdes	sent = sendto(c->fd, (void*)sldns_buffer_begin(packet),
393269257Sdes		sldns_buffer_remaining(packet), 0,
394238106Sdes		addr, addrlen);
395238106Sdes	if(sent == -1) {
396238106Sdes		if(!udp_send_errno_needs_log(addr, addrlen))
397238106Sdes			return 0;
398238106Sdes#ifndef USE_WINSOCK
399238106Sdes		verbose(VERB_OPS, "sendto failed: %s", strerror(errno));
400238106Sdes#else
401238106Sdes		verbose(VERB_OPS, "sendto failed: %s",
402238106Sdes			wsa_strerror(WSAGetLastError()));
403238106Sdes#endif
404238106Sdes		log_addr(VERB_OPS, "remote address is",
405238106Sdes			(struct sockaddr_storage*)addr, addrlen);
406238106Sdes		return 0;
407269257Sdes	} else if((size_t)sent != sldns_buffer_remaining(packet)) {
408238106Sdes		log_err("sent %d in place of %d bytes",
409269257Sdes			(int)sent, (int)sldns_buffer_remaining(packet));
410238106Sdes		return 0;
411238106Sdes	}
412238106Sdes	return 1;
413238106Sdes}
414238106Sdes
415238106Sdes#if defined(AF_INET6) && defined(IPV6_PKTINFO) && (defined(HAVE_RECVMSG) || defined(HAVE_SENDMSG))
416238106Sdes/** print debug ancillary info */
417238106Sdesstatic void p_ancil(const char* str, struct comm_reply* r)
418238106Sdes{
419238106Sdes	if(r->srctype != 4 && r->srctype != 6) {
420238106Sdes		log_info("%s: unknown srctype %d", str, r->srctype);
421238106Sdes		return;
422238106Sdes	}
423238106Sdes	if(r->srctype == 6) {
424238106Sdes		char buf[1024];
425238106Sdes		if(inet_ntop(AF_INET6, &r->pktinfo.v6info.ipi6_addr,
426238106Sdes			buf, (socklen_t)sizeof(buf)) == 0) {
427269257Sdes			(void)strlcpy(buf, "(inet_ntop error)", sizeof(buf));
428238106Sdes		}
429238106Sdes		buf[sizeof(buf)-1]=0;
430238106Sdes		log_info("%s: %s %d", str, buf, r->pktinfo.v6info.ipi6_ifindex);
431238106Sdes	} else if(r->srctype == 4) {
432238106Sdes#ifdef IP_PKTINFO
433238106Sdes		char buf1[1024], buf2[1024];
434238106Sdes		if(inet_ntop(AF_INET, &r->pktinfo.v4info.ipi_addr,
435238106Sdes			buf1, (socklen_t)sizeof(buf1)) == 0) {
436269257Sdes			(void)strlcpy(buf1, "(inet_ntop error)", sizeof(buf1));
437238106Sdes		}
438238106Sdes		buf1[sizeof(buf1)-1]=0;
439238106Sdes#ifdef HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST
440238106Sdes		if(inet_ntop(AF_INET, &r->pktinfo.v4info.ipi_spec_dst,
441238106Sdes			buf2, (socklen_t)sizeof(buf2)) == 0) {
442269257Sdes			(void)strlcpy(buf2, "(inet_ntop error)", sizeof(buf2));
443238106Sdes		}
444238106Sdes		buf2[sizeof(buf2)-1]=0;
445238106Sdes#else
446238106Sdes		buf2[0]=0;
447238106Sdes#endif
448238106Sdes		log_info("%s: %d %s %s", str, r->pktinfo.v4info.ipi_ifindex,
449238106Sdes			buf1, buf2);
450238106Sdes#elif defined(IP_RECVDSTADDR)
451238106Sdes		char buf1[1024];
452238106Sdes		if(inet_ntop(AF_INET, &r->pktinfo.v4addr,
453238106Sdes			buf1, (socklen_t)sizeof(buf1)) == 0) {
454269257Sdes			(void)strlcpy(buf1, "(inet_ntop error)", sizeof(buf1));
455238106Sdes		}
456238106Sdes		buf1[sizeof(buf1)-1]=0;
457238106Sdes		log_info("%s: %s", str, buf1);
458238106Sdes#endif /* IP_PKTINFO or PI_RECVDSTDADDR */
459238106Sdes	}
460238106Sdes}
461238106Sdes#endif /* AF_INET6 && IPV6_PKTINFO && HAVE_RECVMSG||HAVE_SENDMSG */
462238106Sdes
463238106Sdes/** send a UDP reply over specified interface*/
464238106Sdesstatic int
465269257Sdescomm_point_send_udp_msg_if(struct comm_point *c, sldns_buffer* packet,
466238106Sdes	struct sockaddr* addr, socklen_t addrlen, struct comm_reply* r)
467238106Sdes{
468238106Sdes#if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_SENDMSG)
469238106Sdes	ssize_t sent;
470238106Sdes	struct msghdr msg;
471238106Sdes	struct iovec iov[1];
472238106Sdes	char control[256];
473238106Sdes#ifndef S_SPLINT_S
474238106Sdes	struct cmsghdr *cmsg;
475238106Sdes#endif /* S_SPLINT_S */
476238106Sdes
477238106Sdes	log_assert(c->fd != -1);
478238106Sdes#ifdef UNBOUND_DEBUG
479269257Sdes	if(sldns_buffer_remaining(packet) == 0)
480238106Sdes		log_err("error: send empty UDP packet");
481238106Sdes#endif
482238106Sdes	log_assert(addr && addrlen > 0);
483238106Sdes
484238106Sdes	msg.msg_name = addr;
485238106Sdes	msg.msg_namelen = addrlen;
486269257Sdes	iov[0].iov_base = sldns_buffer_begin(packet);
487269257Sdes	iov[0].iov_len = sldns_buffer_remaining(packet);
488238106Sdes	msg.msg_iov = iov;
489238106Sdes	msg.msg_iovlen = 1;
490238106Sdes	msg.msg_control = control;
491238106Sdes#ifndef S_SPLINT_S
492238106Sdes	msg.msg_controllen = sizeof(control);
493238106Sdes#endif /* S_SPLINT_S */
494238106Sdes	msg.msg_flags = 0;
495238106Sdes
496238106Sdes#ifndef S_SPLINT_S
497238106Sdes	cmsg = CMSG_FIRSTHDR(&msg);
498238106Sdes	if(r->srctype == 4) {
499238106Sdes#ifdef IP_PKTINFO
500238106Sdes		msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
501238106Sdes		log_assert(msg.msg_controllen <= sizeof(control));
502238106Sdes		cmsg->cmsg_level = IPPROTO_IP;
503238106Sdes		cmsg->cmsg_type = IP_PKTINFO;
504238106Sdes		memmove(CMSG_DATA(cmsg), &r->pktinfo.v4info,
505238106Sdes			sizeof(struct in_pktinfo));
506238106Sdes		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
507238106Sdes#elif defined(IP_SENDSRCADDR)
508238106Sdes		msg.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
509238106Sdes		log_assert(msg.msg_controllen <= sizeof(control));
510238106Sdes		cmsg->cmsg_level = IPPROTO_IP;
511238106Sdes		cmsg->cmsg_type = IP_SENDSRCADDR;
512238106Sdes		memmove(CMSG_DATA(cmsg), &r->pktinfo.v4addr,
513238106Sdes			sizeof(struct in_addr));
514238106Sdes		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
515238106Sdes#else
516238106Sdes		verbose(VERB_ALGO, "no IP_PKTINFO or IP_SENDSRCADDR");
517238106Sdes		msg.msg_control = NULL;
518238106Sdes#endif /* IP_PKTINFO or IP_SENDSRCADDR */
519238106Sdes	} else if(r->srctype == 6) {
520238106Sdes		msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
521238106Sdes		log_assert(msg.msg_controllen <= sizeof(control));
522238106Sdes		cmsg->cmsg_level = IPPROTO_IPV6;
523238106Sdes		cmsg->cmsg_type = IPV6_PKTINFO;
524238106Sdes		memmove(CMSG_DATA(cmsg), &r->pktinfo.v6info,
525238106Sdes			sizeof(struct in6_pktinfo));
526238106Sdes		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
527238106Sdes	} else {
528238106Sdes		/* try to pass all 0 to use default route */
529238106Sdes		msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
530238106Sdes		log_assert(msg.msg_controllen <= sizeof(control));
531238106Sdes		cmsg->cmsg_level = IPPROTO_IPV6;
532238106Sdes		cmsg->cmsg_type = IPV6_PKTINFO;
533238106Sdes		memset(CMSG_DATA(cmsg), 0, sizeof(struct in6_pktinfo));
534238106Sdes		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
535238106Sdes	}
536238106Sdes#endif /* S_SPLINT_S */
537238106Sdes	if(verbosity >= VERB_ALGO)
538238106Sdes		p_ancil("send_udp over interface", r);
539238106Sdes	sent = sendmsg(c->fd, &msg, 0);
540238106Sdes	if(sent == -1) {
541238106Sdes		if(!udp_send_errno_needs_log(addr, addrlen))
542238106Sdes			return 0;
543238106Sdes		verbose(VERB_OPS, "sendmsg failed: %s", strerror(errno));
544238106Sdes		log_addr(VERB_OPS, "remote address is",
545238106Sdes			(struct sockaddr_storage*)addr, addrlen);
546238106Sdes		return 0;
547269257Sdes	} else if((size_t)sent != sldns_buffer_remaining(packet)) {
548238106Sdes		log_err("sent %d in place of %d bytes",
549269257Sdes			(int)sent, (int)sldns_buffer_remaining(packet));
550238106Sdes		return 0;
551238106Sdes	}
552238106Sdes	return 1;
553238106Sdes#else
554238106Sdes	(void)c;
555238106Sdes	(void)packet;
556238106Sdes	(void)addr;
557238106Sdes	(void)addrlen;
558238106Sdes	(void)r;
559238106Sdes	log_err("sendmsg: IPV6_PKTINFO not supported");
560238106Sdes	return 0;
561238106Sdes#endif /* AF_INET6 && IPV6_PKTINFO && HAVE_SENDMSG */
562238106Sdes}
563238106Sdes
564238106Sdesvoid
565238106Sdescomm_point_udp_ancil_callback(int fd, short event, void* arg)
566238106Sdes{
567238106Sdes#if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG)
568238106Sdes	struct comm_reply rep;
569238106Sdes	struct msghdr msg;
570238106Sdes	struct iovec iov[1];
571238106Sdes	ssize_t rcv;
572238106Sdes	char ancil[256];
573238106Sdes	int i;
574238106Sdes#ifndef S_SPLINT_S
575238106Sdes	struct cmsghdr* cmsg;
576238106Sdes#endif /* S_SPLINT_S */
577238106Sdes
578238106Sdes	rep.c = (struct comm_point*)arg;
579238106Sdes	log_assert(rep.c->type == comm_udp);
580238106Sdes
581238106Sdes	if(!(event&EV_READ))
582238106Sdes		return;
583238106Sdes	log_assert(rep.c && rep.c->buffer && rep.c->fd == fd);
584238106Sdes	comm_base_now(rep.c->ev->base);
585238106Sdes	for(i=0; i<NUM_UDP_PER_SELECT; i++) {
586269257Sdes		sldns_buffer_clear(rep.c->buffer);
587238106Sdes		rep.addrlen = (socklen_t)sizeof(rep.addr);
588238106Sdes		log_assert(fd != -1);
589269257Sdes		log_assert(sldns_buffer_remaining(rep.c->buffer) > 0);
590238106Sdes		msg.msg_name = &rep.addr;
591238106Sdes		msg.msg_namelen = (socklen_t)sizeof(rep.addr);
592269257Sdes		iov[0].iov_base = sldns_buffer_begin(rep.c->buffer);
593269257Sdes		iov[0].iov_len = sldns_buffer_remaining(rep.c->buffer);
594238106Sdes		msg.msg_iov = iov;
595238106Sdes		msg.msg_iovlen = 1;
596238106Sdes		msg.msg_control = ancil;
597238106Sdes#ifndef S_SPLINT_S
598238106Sdes		msg.msg_controllen = sizeof(ancil);
599238106Sdes#endif /* S_SPLINT_S */
600238106Sdes		msg.msg_flags = 0;
601238106Sdes		rcv = recvmsg(fd, &msg, 0);
602238106Sdes		if(rcv == -1) {
603238106Sdes			if(errno != EAGAIN && errno != EINTR) {
604238106Sdes				log_err("recvmsg failed: %s", strerror(errno));
605238106Sdes			}
606238106Sdes			return;
607238106Sdes		}
608238106Sdes		rep.addrlen = msg.msg_namelen;
609269257Sdes		sldns_buffer_skip(rep.c->buffer, rcv);
610269257Sdes		sldns_buffer_flip(rep.c->buffer);
611238106Sdes		rep.srctype = 0;
612238106Sdes#ifndef S_SPLINT_S
613238106Sdes		for(cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
614238106Sdes			cmsg = CMSG_NXTHDR(&msg, cmsg)) {
615238106Sdes			if( cmsg->cmsg_level == IPPROTO_IPV6 &&
616238106Sdes				cmsg->cmsg_type == IPV6_PKTINFO) {
617238106Sdes				rep.srctype = 6;
618238106Sdes				memmove(&rep.pktinfo.v6info, CMSG_DATA(cmsg),
619238106Sdes					sizeof(struct in6_pktinfo));
620238106Sdes				break;
621238106Sdes#ifdef IP_PKTINFO
622238106Sdes			} else if( cmsg->cmsg_level == IPPROTO_IP &&
623238106Sdes				cmsg->cmsg_type == IP_PKTINFO) {
624238106Sdes				rep.srctype = 4;
625238106Sdes				memmove(&rep.pktinfo.v4info, CMSG_DATA(cmsg),
626238106Sdes					sizeof(struct in_pktinfo));
627238106Sdes				break;
628238106Sdes#elif defined(IP_RECVDSTADDR)
629238106Sdes			} else if( cmsg->cmsg_level == IPPROTO_IP &&
630238106Sdes				cmsg->cmsg_type == IP_RECVDSTADDR) {
631238106Sdes				rep.srctype = 4;
632238106Sdes				memmove(&rep.pktinfo.v4addr, CMSG_DATA(cmsg),
633238106Sdes					sizeof(struct in_addr));
634238106Sdes				break;
635238106Sdes#endif /* IP_PKTINFO or IP_RECVDSTADDR */
636238106Sdes			}
637238106Sdes		}
638238106Sdes		if(verbosity >= VERB_ALGO)
639238106Sdes			p_ancil("receive_udp on interface", &rep);
640238106Sdes#endif /* S_SPLINT_S */
641238106Sdes		fptr_ok(fptr_whitelist_comm_point(rep.c->callback));
642238106Sdes		if((*rep.c->callback)(rep.c, rep.c->cb_arg, NETEVENT_NOERROR, &rep)) {
643238106Sdes			/* send back immediate reply */
644238106Sdes			(void)comm_point_send_udp_msg_if(rep.c, rep.c->buffer,
645238106Sdes				(struct sockaddr*)&rep.addr, rep.addrlen, &rep);
646238106Sdes		}
647238106Sdes		if(rep.c->fd == -1) /* commpoint closed */
648238106Sdes			break;
649238106Sdes	}
650238106Sdes#else
651238106Sdes	(void)fd;
652238106Sdes	(void)event;
653238106Sdes	(void)arg;
654238106Sdes	fatal_exit("recvmsg: No support for IPV6_PKTINFO. "
655238106Sdes		"Please disable interface-automatic");
656238106Sdes#endif /* AF_INET6 && IPV6_PKTINFO && HAVE_RECVMSG */
657238106Sdes}
658238106Sdes
659238106Sdesvoid
660238106Sdescomm_point_udp_callback(int fd, short event, void* arg)
661238106Sdes{
662238106Sdes	struct comm_reply rep;
663238106Sdes	ssize_t rcv;
664238106Sdes	int i;
665238106Sdes
666238106Sdes	rep.c = (struct comm_point*)arg;
667238106Sdes	log_assert(rep.c->type == comm_udp);
668238106Sdes
669238106Sdes	if(!(event&EV_READ))
670238106Sdes		return;
671238106Sdes	log_assert(rep.c && rep.c->buffer && rep.c->fd == fd);
672238106Sdes	comm_base_now(rep.c->ev->base);
673238106Sdes	for(i=0; i<NUM_UDP_PER_SELECT; i++) {
674269257Sdes		sldns_buffer_clear(rep.c->buffer);
675238106Sdes		rep.addrlen = (socklen_t)sizeof(rep.addr);
676238106Sdes		log_assert(fd != -1);
677269257Sdes		log_assert(sldns_buffer_remaining(rep.c->buffer) > 0);
678269257Sdes		rcv = recvfrom(fd, (void*)sldns_buffer_begin(rep.c->buffer),
679269257Sdes			sldns_buffer_remaining(rep.c->buffer), 0,
680238106Sdes			(struct sockaddr*)&rep.addr, &rep.addrlen);
681238106Sdes		if(rcv == -1) {
682238106Sdes#ifndef USE_WINSOCK
683238106Sdes			if(errno != EAGAIN && errno != EINTR)
684238106Sdes				log_err("recvfrom %d failed: %s",
685238106Sdes					fd, strerror(errno));
686238106Sdes#else
687238106Sdes			if(WSAGetLastError() != WSAEINPROGRESS &&
688238106Sdes				WSAGetLastError() != WSAECONNRESET &&
689238106Sdes				WSAGetLastError()!= WSAEWOULDBLOCK)
690238106Sdes				log_err("recvfrom failed: %s",
691238106Sdes					wsa_strerror(WSAGetLastError()));
692238106Sdes#endif
693238106Sdes			return;
694238106Sdes		}
695269257Sdes		sldns_buffer_skip(rep.c->buffer, rcv);
696269257Sdes		sldns_buffer_flip(rep.c->buffer);
697238106Sdes		rep.srctype = 0;
698238106Sdes		fptr_ok(fptr_whitelist_comm_point(rep.c->callback));
699238106Sdes		if((*rep.c->callback)(rep.c, rep.c->cb_arg, NETEVENT_NOERROR, &rep)) {
700238106Sdes			/* send back immediate reply */
701238106Sdes			(void)comm_point_send_udp_msg(rep.c, rep.c->buffer,
702238106Sdes				(struct sockaddr*)&rep.addr, rep.addrlen);
703238106Sdes		}
704238106Sdes		if(rep.c->fd != fd) /* commpoint closed to -1 or reused for
705238106Sdes		another UDP port. Note rep.c cannot be reused with TCP fd. */
706238106Sdes			break;
707238106Sdes	}
708238106Sdes}
709238106Sdes
710238106Sdes/** Use a new tcp handler for new query fd, set to read query */
711238106Sdesstatic void
712238106Sdessetup_tcp_handler(struct comm_point* c, int fd)
713238106Sdes{
714238106Sdes	log_assert(c->type == comm_tcp);
715238106Sdes	log_assert(c->fd == -1);
716269257Sdes	sldns_buffer_clear(c->buffer);
717238106Sdes	c->tcp_is_reading = 1;
718238106Sdes	c->tcp_byte_count = 0;
719238106Sdes	comm_point_start_listening(c, fd, TCP_QUERY_TIMEOUT);
720238106Sdes}
721238106Sdes
722238106Sdesvoid comm_base_handle_slow_accept(int ATTR_UNUSED(fd),
723238106Sdes	short ATTR_UNUSED(event), void* arg)
724238106Sdes{
725238106Sdes	struct comm_base* b = (struct comm_base*)arg;
726238106Sdes	/* timeout for the slow accept, re-enable accepts again */
727238106Sdes	if(b->start_accept) {
728238106Sdes		verbose(VERB_ALGO, "wait is over, slow accept disabled");
729238106Sdes		fptr_ok(fptr_whitelist_start_accept(b->start_accept));
730238106Sdes		(*b->start_accept)(b->cb_arg);
731238106Sdes		b->eb->slow_accept_enabled = 0;
732238106Sdes	}
733238106Sdes}
734238106Sdes
735238106Sdesint comm_point_perform_accept(struct comm_point* c,
736238106Sdes	struct sockaddr_storage* addr, socklen_t* addrlen)
737238106Sdes{
738238106Sdes	int new_fd;
739238106Sdes	*addrlen = (socklen_t)sizeof(*addr);
740238106Sdes	new_fd = accept(c->fd, (struct sockaddr*)addr, addrlen);
741238106Sdes	if(new_fd == -1) {
742238106Sdes#ifndef USE_WINSOCK
743238106Sdes		/* EINTR is signal interrupt. others are closed connection. */
744238106Sdes		if(	errno == EINTR || errno == EAGAIN
745238106Sdes#ifdef EWOULDBLOCK
746238106Sdes			|| errno == EWOULDBLOCK
747238106Sdes#endif
748238106Sdes#ifdef ECONNABORTED
749238106Sdes			|| errno == ECONNABORTED
750238106Sdes#endif
751238106Sdes#ifdef EPROTO
752238106Sdes			|| errno == EPROTO
753238106Sdes#endif /* EPROTO */
754238106Sdes			)
755238106Sdes			return -1;
756238106Sdes#if defined(ENFILE) && defined(EMFILE)
757238106Sdes		if(errno == ENFILE || errno == EMFILE) {
758238106Sdes			/* out of file descriptors, likely outside of our
759238106Sdes			 * control. stop accept() calls for some time */
760238106Sdes			if(c->ev->base->stop_accept) {
761238106Sdes				struct comm_base* b = c->ev->base;
762238106Sdes				struct timeval tv;
763238106Sdes				verbose(VERB_ALGO, "out of file descriptors: "
764238106Sdes					"slow accept");
765238106Sdes				b->eb->slow_accept_enabled = 1;
766238106Sdes				fptr_ok(fptr_whitelist_stop_accept(
767238106Sdes					b->stop_accept));
768238106Sdes				(*b->stop_accept)(b->cb_arg);
769238106Sdes				/* set timeout, no mallocs */
770238106Sdes				tv.tv_sec = NETEVENT_SLOW_ACCEPT_TIME/1000;
771238106Sdes				tv.tv_usec = NETEVENT_SLOW_ACCEPT_TIME%1000;
772238106Sdes				event_set(&b->eb->slow_accept, -1, EV_TIMEOUT,
773238106Sdes					comm_base_handle_slow_accept, b);
774238106Sdes				if(event_base_set(b->eb->base,
775238106Sdes					&b->eb->slow_accept) != 0) {
776238106Sdes					/* we do not want to log here, because
777238106Sdes					 * that would spam the logfiles.
778238106Sdes					 * error: "event_base_set failed." */
779238106Sdes				}
780238106Sdes				if(event_add(&b->eb->slow_accept, &tv) != 0) {
781238106Sdes					/* we do not want to log here,
782238106Sdes					 * error: "event_add failed." */
783238106Sdes				}
784238106Sdes			}
785238106Sdes			return -1;
786238106Sdes		}
787238106Sdes#endif
788238106Sdes		log_err("accept failed: %s", strerror(errno));
789238106Sdes#else /* USE_WINSOCK */
790238106Sdes		if(WSAGetLastError() == WSAEINPROGRESS ||
791238106Sdes			WSAGetLastError() == WSAECONNRESET)
792238106Sdes			return -1;
793238106Sdes		if(WSAGetLastError() == WSAEWOULDBLOCK) {
794238106Sdes			winsock_tcp_wouldblock(&c->ev->ev, EV_READ);
795238106Sdes			return -1;
796238106Sdes		}
797238106Sdes		log_err("accept failed: %s", wsa_strerror(WSAGetLastError()));
798238106Sdes#endif
799238106Sdes		log_addr(0, "remote address is", addr, *addrlen);
800238106Sdes		return -1;
801238106Sdes	}
802238106Sdes	fd_set_nonblock(new_fd);
803238106Sdes	return new_fd;
804238106Sdes}
805238106Sdes
806238106Sdes#ifdef USE_WINSOCK
807238106Sdesstatic long win_bio_cb(BIO *b, int oper, const char* ATTR_UNUSED(argp),
808238106Sdes        int ATTR_UNUSED(argi), long argl, long retvalue)
809238106Sdes{
810238106Sdes	verbose(VERB_ALGO, "bio_cb %d, %s %s %s", oper,
811238106Sdes		(oper&BIO_CB_RETURN)?"return":"before",
812238106Sdes		(oper&BIO_CB_READ)?"read":((oper&BIO_CB_WRITE)?"write":"other"),
813238106Sdes		WSAGetLastError()==WSAEWOULDBLOCK?"wsawb":"");
814238106Sdes	/* on windows, check if previous operation caused EWOULDBLOCK */
815238106Sdes	if( (oper == (BIO_CB_READ|BIO_CB_RETURN) && argl == 0) ||
816238106Sdes		(oper == (BIO_CB_GETS|BIO_CB_RETURN) && argl == 0)) {
817238106Sdes		if(WSAGetLastError() == WSAEWOULDBLOCK)
818238106Sdes			winsock_tcp_wouldblock((struct event*)
819238106Sdes				BIO_get_callback_arg(b), EV_READ);
820238106Sdes	}
821238106Sdes	if( (oper == (BIO_CB_WRITE|BIO_CB_RETURN) && argl == 0) ||
822238106Sdes		(oper == (BIO_CB_PUTS|BIO_CB_RETURN) && argl == 0)) {
823238106Sdes		if(WSAGetLastError() == WSAEWOULDBLOCK)
824238106Sdes			winsock_tcp_wouldblock((struct event*)
825238106Sdes				BIO_get_callback_arg(b), EV_WRITE);
826238106Sdes	}
827238106Sdes	/* return original return value */
828238106Sdes	return retvalue;
829238106Sdes}
830238106Sdes
831238106Sdes/** set win bio callbacks for nonblocking operations */
832238106Sdesvoid
833238106Sdescomm_point_tcp_win_bio_cb(struct comm_point* c, void* thessl)
834238106Sdes{
835238106Sdes	SSL* ssl = (SSL*)thessl;
836238106Sdes	/* set them both just in case, but usually they are the same BIO */
837238106Sdes	BIO_set_callback(SSL_get_rbio(ssl), &win_bio_cb);
838238106Sdes	BIO_set_callback_arg(SSL_get_rbio(ssl), (char*)&c->ev->ev);
839238106Sdes	BIO_set_callback(SSL_get_wbio(ssl), &win_bio_cb);
840238106Sdes	BIO_set_callback_arg(SSL_get_wbio(ssl), (char*)&c->ev->ev);
841238106Sdes}
842238106Sdes#endif
843238106Sdes
844238106Sdesvoid
845238106Sdescomm_point_tcp_accept_callback(int fd, short event, void* arg)
846238106Sdes{
847238106Sdes	struct comm_point* c = (struct comm_point*)arg, *c_hdl;
848238106Sdes	int new_fd;
849238106Sdes	log_assert(c->type == comm_tcp_accept);
850238106Sdes	if(!(event & EV_READ)) {
851238106Sdes		log_info("ignoring tcp accept event %d", (int)event);
852238106Sdes		return;
853238106Sdes	}
854238106Sdes	comm_base_now(c->ev->base);
855238106Sdes	/* find free tcp handler. */
856238106Sdes	if(!c->tcp_free) {
857238106Sdes		log_warn("accepted too many tcp, connections full");
858238106Sdes		return;
859238106Sdes	}
860238106Sdes	/* accept incoming connection. */
861238106Sdes	c_hdl = c->tcp_free;
862238106Sdes	log_assert(fd != -1);
863238106Sdes	new_fd = comm_point_perform_accept(c, &c_hdl->repinfo.addr,
864238106Sdes		&c_hdl->repinfo.addrlen);
865238106Sdes	if(new_fd == -1)
866238106Sdes		return;
867238106Sdes	if(c->ssl) {
868238106Sdes		c_hdl->ssl = incoming_ssl_fd(c->ssl, new_fd);
869238106Sdes		if(!c_hdl->ssl) {
870238106Sdes			c_hdl->fd = new_fd;
871238106Sdes			comm_point_close(c_hdl);
872238106Sdes			return;
873238106Sdes		}
874238106Sdes		c_hdl->ssl_shake_state = comm_ssl_shake_read;
875238106Sdes#ifdef USE_WINSOCK
876238106Sdes		comm_point_tcp_win_bio_cb(c_hdl, c_hdl->ssl);
877238106Sdes#endif
878238106Sdes	}
879238106Sdes
880238106Sdes	/* grab the tcp handler buffers */
881238106Sdes	c->tcp_free = c_hdl->tcp_free;
882238106Sdes	if(!c->tcp_free) {
883238106Sdes		/* stop accepting incoming queries for now. */
884238106Sdes		comm_point_stop_listening(c);
885238106Sdes	}
886238106Sdes	/* addr is dropped. Not needed for tcp reply. */
887238106Sdes	setup_tcp_handler(c_hdl, new_fd);
888238106Sdes}
889238106Sdes
890238106Sdes/** Make tcp handler free for next assignment */
891238106Sdesstatic void
892238106Sdesreclaim_tcp_handler(struct comm_point* c)
893238106Sdes{
894238106Sdes	log_assert(c->type == comm_tcp);
895238106Sdes	if(c->ssl) {
896249141Sdes#ifdef HAVE_SSL
897238106Sdes		SSL_shutdown(c->ssl);
898238106Sdes		SSL_free(c->ssl);
899238106Sdes		c->ssl = NULL;
900249141Sdes#endif
901238106Sdes	}
902238106Sdes	comm_point_close(c);
903238106Sdes	if(c->tcp_parent) {
904238106Sdes		c->tcp_free = c->tcp_parent->tcp_free;
905238106Sdes		c->tcp_parent->tcp_free = c;
906238106Sdes		if(!c->tcp_free) {
907238106Sdes			/* re-enable listening on accept socket */
908238106Sdes			comm_point_start_listening(c->tcp_parent, -1, -1);
909238106Sdes		}
910238106Sdes	}
911238106Sdes}
912238106Sdes
913238106Sdes/** do the callback when writing is done */
914238106Sdesstatic void
915238106Sdestcp_callback_writer(struct comm_point* c)
916238106Sdes{
917238106Sdes	log_assert(c->type == comm_tcp);
918269257Sdes	sldns_buffer_clear(c->buffer);
919238106Sdes	if(c->tcp_do_toggle_rw)
920238106Sdes		c->tcp_is_reading = 1;
921238106Sdes	c->tcp_byte_count = 0;
922238106Sdes	/* switch from listening(write) to listening(read) */
923238106Sdes	comm_point_stop_listening(c);
924238106Sdes	comm_point_start_listening(c, -1, -1);
925238106Sdes}
926238106Sdes
927238106Sdes/** do the callback when reading is done */
928238106Sdesstatic void
929238106Sdestcp_callback_reader(struct comm_point* c)
930238106Sdes{
931238106Sdes	log_assert(c->type == comm_tcp || c->type == comm_local);
932269257Sdes	sldns_buffer_flip(c->buffer);
933238106Sdes	if(c->tcp_do_toggle_rw)
934238106Sdes		c->tcp_is_reading = 0;
935238106Sdes	c->tcp_byte_count = 0;
936238106Sdes	if(c->type == comm_tcp)
937238106Sdes		comm_point_stop_listening(c);
938238106Sdes	fptr_ok(fptr_whitelist_comm_point(c->callback));
939238106Sdes	if( (*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, &c->repinfo) ) {
940238106Sdes		comm_point_start_listening(c, -1, TCP_QUERY_TIMEOUT);
941238106Sdes	}
942238106Sdes}
943238106Sdes
944238106Sdes/** continue ssl handshake */
945249141Sdes#ifdef HAVE_SSL
946238106Sdesstatic int
947238106Sdesssl_handshake(struct comm_point* c)
948238106Sdes{
949238106Sdes	int r;
950238106Sdes	if(c->ssl_shake_state == comm_ssl_shake_hs_read) {
951238106Sdes		/* read condition satisfied back to writing */
952238106Sdes		comm_point_listen_for_rw(c, 1, 1);
953238106Sdes		c->ssl_shake_state = comm_ssl_shake_none;
954238106Sdes		return 1;
955238106Sdes	}
956238106Sdes	if(c->ssl_shake_state == comm_ssl_shake_hs_write) {
957238106Sdes		/* write condition satisfied, back to reading */
958238106Sdes		comm_point_listen_for_rw(c, 1, 0);
959238106Sdes		c->ssl_shake_state = comm_ssl_shake_none;
960238106Sdes		return 1;
961238106Sdes	}
962238106Sdes
963238106Sdes	ERR_clear_error();
964238106Sdes	r = SSL_do_handshake(c->ssl);
965238106Sdes	if(r != 1) {
966238106Sdes		int want = SSL_get_error(c->ssl, r);
967238106Sdes		if(want == SSL_ERROR_WANT_READ) {
968238106Sdes			if(c->ssl_shake_state == comm_ssl_shake_read)
969238106Sdes				return 1;
970238106Sdes			c->ssl_shake_state = comm_ssl_shake_read;
971238106Sdes			comm_point_listen_for_rw(c, 1, 0);
972238106Sdes			return 1;
973238106Sdes		} else if(want == SSL_ERROR_WANT_WRITE) {
974238106Sdes			if(c->ssl_shake_state == comm_ssl_shake_write)
975238106Sdes				return 1;
976238106Sdes			c->ssl_shake_state = comm_ssl_shake_write;
977238106Sdes			comm_point_listen_for_rw(c, 0, 1);
978238106Sdes			return 1;
979238106Sdes		} else if(r == 0) {
980238106Sdes			return 0; /* closed */
981238106Sdes		} else if(want == SSL_ERROR_SYSCALL) {
982238106Sdes			/* SYSCALL and errno==0 means closed uncleanly */
983238106Sdes			if(errno != 0)
984238106Sdes				log_err("SSL_handshake syscall: %s",
985238106Sdes					strerror(errno));
986238106Sdes			return 0;
987238106Sdes		} else {
988238106Sdes			log_crypto_err("ssl handshake failed");
989238106Sdes			log_addr(1, "ssl handshake failed", &c->repinfo.addr,
990238106Sdes				c->repinfo.addrlen);
991238106Sdes			return 0;
992238106Sdes		}
993238106Sdes	}
994238106Sdes	/* this is where peer verification could take place */
995238106Sdes	log_addr(VERB_ALGO, "SSL DNS connection", &c->repinfo.addr,
996238106Sdes		c->repinfo.addrlen);
997238106Sdes
998238106Sdes	/* setup listen rw correctly */
999238106Sdes	if(c->tcp_is_reading) {
1000238106Sdes		if(c->ssl_shake_state != comm_ssl_shake_read)
1001238106Sdes			comm_point_listen_for_rw(c, 1, 0);
1002238106Sdes	} else {
1003238106Sdes		comm_point_listen_for_rw(c, 1, 1);
1004238106Sdes	}
1005238106Sdes	c->ssl_shake_state = comm_ssl_shake_none;
1006238106Sdes	return 1;
1007238106Sdes}
1008249141Sdes#endif /* HAVE_SSL */
1009238106Sdes
1010238106Sdes/** ssl read callback on TCP */
1011238106Sdesstatic int
1012238106Sdesssl_handle_read(struct comm_point* c)
1013238106Sdes{
1014249141Sdes#ifdef HAVE_SSL
1015238106Sdes	int r;
1016238106Sdes	if(c->ssl_shake_state != comm_ssl_shake_none) {
1017238106Sdes		if(!ssl_handshake(c))
1018238106Sdes			return 0;
1019238106Sdes		if(c->ssl_shake_state != comm_ssl_shake_none)
1020238106Sdes			return 1;
1021238106Sdes	}
1022238106Sdes	if(c->tcp_byte_count < sizeof(uint16_t)) {
1023238106Sdes		/* read length bytes */
1024238106Sdes		ERR_clear_error();
1025269257Sdes		if((r=SSL_read(c->ssl, (void*)sldns_buffer_at(c->buffer,
1026238106Sdes			c->tcp_byte_count), (int)(sizeof(uint16_t) -
1027238106Sdes			c->tcp_byte_count))) <= 0) {
1028238106Sdes			int want = SSL_get_error(c->ssl, r);
1029238106Sdes			if(want == SSL_ERROR_ZERO_RETURN) {
1030238106Sdes				return 0; /* shutdown, closed */
1031238106Sdes			} else if(want == SSL_ERROR_WANT_READ) {
1032238106Sdes				return 1; /* read more later */
1033238106Sdes			} else if(want == SSL_ERROR_WANT_WRITE) {
1034238106Sdes				c->ssl_shake_state = comm_ssl_shake_hs_write;
1035238106Sdes				comm_point_listen_for_rw(c, 0, 1);
1036238106Sdes				return 1;
1037238106Sdes			} else if(want == SSL_ERROR_SYSCALL) {
1038238106Sdes				if(errno != 0)
1039238106Sdes					log_err("SSL_read syscall: %s",
1040238106Sdes						strerror(errno));
1041238106Sdes				return 0;
1042238106Sdes			}
1043238106Sdes			log_crypto_err("could not SSL_read");
1044238106Sdes			return 0;
1045238106Sdes		}
1046238106Sdes		c->tcp_byte_count += r;
1047238106Sdes		if(c->tcp_byte_count != sizeof(uint16_t))
1048238106Sdes			return 1;
1049269257Sdes		if(sldns_buffer_read_u16_at(c->buffer, 0) >
1050269257Sdes			sldns_buffer_capacity(c->buffer)) {
1051238106Sdes			verbose(VERB_QUERY, "ssl: dropped larger than buffer");
1052238106Sdes			return 0;
1053238106Sdes		}
1054269257Sdes		sldns_buffer_set_limit(c->buffer,
1055269257Sdes			sldns_buffer_read_u16_at(c->buffer, 0));
1056269257Sdes		if(sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE) {
1057238106Sdes			verbose(VERB_QUERY, "ssl: dropped bogus too short.");
1058238106Sdes			return 0;
1059238106Sdes		}
1060238106Sdes		verbose(VERB_ALGO, "Reading ssl tcp query of length %d",
1061269257Sdes			(int)sldns_buffer_limit(c->buffer));
1062238106Sdes	}
1063269257Sdes	log_assert(sldns_buffer_remaining(c->buffer) > 0);
1064238106Sdes	ERR_clear_error();
1065269257Sdes	r = SSL_read(c->ssl, (void*)sldns_buffer_current(c->buffer),
1066269257Sdes		(int)sldns_buffer_remaining(c->buffer));
1067238106Sdes	if(r <= 0) {
1068238106Sdes		int want = SSL_get_error(c->ssl, r);
1069238106Sdes		if(want == SSL_ERROR_ZERO_RETURN) {
1070238106Sdes			return 0; /* shutdown, closed */
1071238106Sdes		} else if(want == SSL_ERROR_WANT_READ) {
1072238106Sdes			return 1; /* read more later */
1073238106Sdes		} else if(want == SSL_ERROR_WANT_WRITE) {
1074238106Sdes			c->ssl_shake_state = comm_ssl_shake_hs_write;
1075238106Sdes			comm_point_listen_for_rw(c, 0, 1);
1076238106Sdes			return 1;
1077238106Sdes		} else if(want == SSL_ERROR_SYSCALL) {
1078238106Sdes			if(errno != 0)
1079238106Sdes				log_err("SSL_read syscall: %s",
1080238106Sdes					strerror(errno));
1081238106Sdes			return 0;
1082238106Sdes		}
1083238106Sdes		log_crypto_err("could not SSL_read");
1084238106Sdes		return 0;
1085238106Sdes	}
1086269257Sdes	sldns_buffer_skip(c->buffer, (ssize_t)r);
1087269257Sdes	if(sldns_buffer_remaining(c->buffer) <= 0) {
1088238106Sdes		tcp_callback_reader(c);
1089238106Sdes	}
1090238106Sdes	return 1;
1091249141Sdes#else
1092249141Sdes	(void)c;
1093249141Sdes	return 0;
1094249141Sdes#endif /* HAVE_SSL */
1095238106Sdes}
1096238106Sdes
1097238106Sdes/** ssl write callback on TCP */
1098238106Sdesstatic int
1099238106Sdesssl_handle_write(struct comm_point* c)
1100238106Sdes{
1101249141Sdes#ifdef HAVE_SSL
1102238106Sdes	int r;
1103238106Sdes	if(c->ssl_shake_state != comm_ssl_shake_none) {
1104238106Sdes		if(!ssl_handshake(c))
1105238106Sdes			return 0;
1106238106Sdes		if(c->ssl_shake_state != comm_ssl_shake_none)
1107238106Sdes			return 1;
1108238106Sdes	}
1109238106Sdes	/* ignore return, if fails we may simply block */
1110238106Sdes	(void)SSL_set_mode(c->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
1111238106Sdes	if(c->tcp_byte_count < sizeof(uint16_t)) {
1112269257Sdes		uint16_t len = htons(sldns_buffer_limit(c->buffer));
1113238106Sdes		ERR_clear_error();
1114238106Sdes		r = SSL_write(c->ssl,
1115238106Sdes			(void*)(((uint8_t*)&len)+c->tcp_byte_count),
1116238106Sdes			(int)(sizeof(uint16_t)-c->tcp_byte_count));
1117238106Sdes		if(r <= 0) {
1118238106Sdes			int want = SSL_get_error(c->ssl, r);
1119238106Sdes			if(want == SSL_ERROR_ZERO_RETURN) {
1120238106Sdes				return 0; /* closed */
1121238106Sdes			} else if(want == SSL_ERROR_WANT_READ) {
1122238106Sdes				c->ssl_shake_state = comm_ssl_shake_read;
1123238106Sdes				comm_point_listen_for_rw(c, 1, 0);
1124238106Sdes				return 1; /* wait for read condition */
1125238106Sdes			} else if(want == SSL_ERROR_WANT_WRITE) {
1126238106Sdes				return 1; /* write more later */
1127238106Sdes			} else if(want == SSL_ERROR_SYSCALL) {
1128238106Sdes				if(errno != 0)
1129238106Sdes					log_err("SSL_write syscall: %s",
1130238106Sdes						strerror(errno));
1131238106Sdes				return 0;
1132238106Sdes			}
1133238106Sdes			log_crypto_err("could not SSL_write");
1134238106Sdes			return 0;
1135238106Sdes		}
1136238106Sdes		c->tcp_byte_count += r;
1137238106Sdes		if(c->tcp_byte_count < sizeof(uint16_t))
1138238106Sdes			return 1;
1139269257Sdes		sldns_buffer_set_position(c->buffer, c->tcp_byte_count -
1140238106Sdes			sizeof(uint16_t));
1141269257Sdes		if(sldns_buffer_remaining(c->buffer) == 0) {
1142238106Sdes			tcp_callback_writer(c);
1143238106Sdes			return 1;
1144238106Sdes		}
1145238106Sdes	}
1146269257Sdes	log_assert(sldns_buffer_remaining(c->buffer) > 0);
1147238106Sdes	ERR_clear_error();
1148269257Sdes	r = SSL_write(c->ssl, (void*)sldns_buffer_current(c->buffer),
1149269257Sdes		(int)sldns_buffer_remaining(c->buffer));
1150238106Sdes	if(r <= 0) {
1151238106Sdes		int want = SSL_get_error(c->ssl, r);
1152238106Sdes		if(want == SSL_ERROR_ZERO_RETURN) {
1153238106Sdes			return 0; /* closed */
1154238106Sdes		} else if(want == SSL_ERROR_WANT_READ) {
1155238106Sdes			c->ssl_shake_state = comm_ssl_shake_read;
1156238106Sdes			comm_point_listen_for_rw(c, 1, 0);
1157238106Sdes			return 1; /* wait for read condition */
1158238106Sdes		} else if(want == SSL_ERROR_WANT_WRITE) {
1159238106Sdes			return 1; /* write more later */
1160238106Sdes		} else if(want == SSL_ERROR_SYSCALL) {
1161238106Sdes			if(errno != 0)
1162238106Sdes				log_err("SSL_write syscall: %s",
1163238106Sdes					strerror(errno));
1164238106Sdes			return 0;
1165238106Sdes		}
1166238106Sdes		log_crypto_err("could not SSL_write");
1167238106Sdes		return 0;
1168238106Sdes	}
1169269257Sdes	sldns_buffer_skip(c->buffer, (ssize_t)r);
1170238106Sdes
1171269257Sdes	if(sldns_buffer_remaining(c->buffer) == 0) {
1172238106Sdes		tcp_callback_writer(c);
1173238106Sdes	}
1174238106Sdes	return 1;
1175249141Sdes#else
1176249141Sdes	(void)c;
1177249141Sdes	return 0;
1178249141Sdes#endif /* HAVE_SSL */
1179238106Sdes}
1180238106Sdes
1181238106Sdes/** handle ssl tcp connection with dns contents */
1182238106Sdesstatic int
1183238106Sdesssl_handle_it(struct comm_point* c)
1184238106Sdes{
1185238106Sdes	if(c->tcp_is_reading)
1186238106Sdes		return ssl_handle_read(c);
1187238106Sdes	return ssl_handle_write(c);
1188238106Sdes}
1189238106Sdes
1190238106Sdes/** Handle tcp reading callback.
1191238106Sdes * @param fd: file descriptor of socket.
1192238106Sdes * @param c: comm point to read from into buffer.
1193238106Sdes * @param short_ok: if true, very short packets are OK (for comm_local).
1194238106Sdes * @return: 0 on error
1195238106Sdes */
1196238106Sdesstatic int
1197238106Sdescomm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok)
1198238106Sdes{
1199238106Sdes	ssize_t r;
1200238106Sdes	log_assert(c->type == comm_tcp || c->type == comm_local);
1201238106Sdes	if(c->ssl)
1202238106Sdes		return ssl_handle_it(c);
1203238106Sdes	if(!c->tcp_is_reading)
1204238106Sdes		return 0;
1205238106Sdes
1206238106Sdes	log_assert(fd != -1);
1207238106Sdes	if(c->tcp_byte_count < sizeof(uint16_t)) {
1208238106Sdes		/* read length bytes */
1209269257Sdes		r = recv(fd,(void*)sldns_buffer_at(c->buffer,c->tcp_byte_count),
1210238106Sdes			sizeof(uint16_t)-c->tcp_byte_count, 0);
1211238106Sdes		if(r == 0)
1212238106Sdes			return 0;
1213238106Sdes		else if(r == -1) {
1214238106Sdes#ifndef USE_WINSOCK
1215238106Sdes			if(errno == EINTR || errno == EAGAIN)
1216238106Sdes				return 1;
1217238106Sdes#ifdef ECONNRESET
1218238106Sdes			if(errno == ECONNRESET && verbosity < 2)
1219238106Sdes				return 0; /* silence reset by peer */
1220238106Sdes#endif
1221238106Sdes			log_err("read (in tcp s): %s", strerror(errno));
1222238106Sdes#else /* USE_WINSOCK */
1223238106Sdes			if(WSAGetLastError() == WSAECONNRESET)
1224238106Sdes				return 0;
1225238106Sdes			if(WSAGetLastError() == WSAEINPROGRESS)
1226238106Sdes				return 1;
1227238106Sdes			if(WSAGetLastError() == WSAEWOULDBLOCK) {
1228238106Sdes				winsock_tcp_wouldblock(&c->ev->ev, EV_READ);
1229238106Sdes				return 1;
1230238106Sdes			}
1231238106Sdes			log_err("read (in tcp s): %s",
1232238106Sdes				wsa_strerror(WSAGetLastError()));
1233238106Sdes#endif
1234238106Sdes			log_addr(0, "remote address is", &c->repinfo.addr,
1235238106Sdes				c->repinfo.addrlen);
1236238106Sdes			return 0;
1237238106Sdes		}
1238238106Sdes		c->tcp_byte_count += r;
1239238106Sdes		if(c->tcp_byte_count != sizeof(uint16_t))
1240238106Sdes			return 1;
1241269257Sdes		if(sldns_buffer_read_u16_at(c->buffer, 0) >
1242269257Sdes			sldns_buffer_capacity(c->buffer)) {
1243238106Sdes			verbose(VERB_QUERY, "tcp: dropped larger than buffer");
1244238106Sdes			return 0;
1245238106Sdes		}
1246269257Sdes		sldns_buffer_set_limit(c->buffer,
1247269257Sdes			sldns_buffer_read_u16_at(c->buffer, 0));
1248238106Sdes		if(!short_ok &&
1249269257Sdes			sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE) {
1250238106Sdes			verbose(VERB_QUERY, "tcp: dropped bogus too short.");
1251238106Sdes			return 0;
1252238106Sdes		}
1253238106Sdes		verbose(VERB_ALGO, "Reading tcp query of length %d",
1254269257Sdes			(int)sldns_buffer_limit(c->buffer));
1255238106Sdes	}
1256238106Sdes
1257269257Sdes	log_assert(sldns_buffer_remaining(c->buffer) > 0);
1258269257Sdes	r = recv(fd, (void*)sldns_buffer_current(c->buffer),
1259269257Sdes		sldns_buffer_remaining(c->buffer), 0);
1260238106Sdes	if(r == 0) {
1261238106Sdes		return 0;
1262238106Sdes	} else if(r == -1) {
1263238106Sdes#ifndef USE_WINSOCK
1264238106Sdes		if(errno == EINTR || errno == EAGAIN)
1265238106Sdes			return 1;
1266238106Sdes		log_err("read (in tcp r): %s", strerror(errno));
1267238106Sdes#else /* USE_WINSOCK */
1268238106Sdes		if(WSAGetLastError() == WSAECONNRESET)
1269238106Sdes			return 0;
1270238106Sdes		if(WSAGetLastError() == WSAEINPROGRESS)
1271238106Sdes			return 1;
1272238106Sdes		if(WSAGetLastError() == WSAEWOULDBLOCK) {
1273238106Sdes			winsock_tcp_wouldblock(&c->ev->ev, EV_READ);
1274238106Sdes			return 1;
1275238106Sdes		}
1276238106Sdes		log_err("read (in tcp r): %s",
1277238106Sdes			wsa_strerror(WSAGetLastError()));
1278238106Sdes#endif
1279238106Sdes		log_addr(0, "remote address is", &c->repinfo.addr,
1280238106Sdes			c->repinfo.addrlen);
1281238106Sdes		return 0;
1282238106Sdes	}
1283269257Sdes	sldns_buffer_skip(c->buffer, r);
1284269257Sdes	if(sldns_buffer_remaining(c->buffer) <= 0) {
1285238106Sdes		tcp_callback_reader(c);
1286238106Sdes	}
1287238106Sdes	return 1;
1288238106Sdes}
1289238106Sdes
1290238106Sdes/**
1291238106Sdes * Handle tcp writing callback.
1292238106Sdes * @param fd: file descriptor of socket.
1293238106Sdes * @param c: comm point to write buffer out of.
1294238106Sdes * @return: 0 on error
1295238106Sdes */
1296238106Sdesstatic int
1297238106Sdescomm_point_tcp_handle_write(int fd, struct comm_point* c)
1298238106Sdes{
1299238106Sdes	ssize_t r;
1300238106Sdes	log_assert(c->type == comm_tcp);
1301238106Sdes	if(c->tcp_is_reading && !c->ssl)
1302238106Sdes		return 0;
1303238106Sdes	log_assert(fd != -1);
1304238106Sdes	if(c->tcp_byte_count == 0 && c->tcp_check_nb_connect) {
1305238106Sdes		/* check for pending error from nonblocking connect */
1306238106Sdes		/* from Stevens, unix network programming, vol1, 3rd ed, p450*/
1307238106Sdes		int error = 0;
1308238106Sdes		socklen_t len = (socklen_t)sizeof(error);
1309238106Sdes		if(getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&error,
1310238106Sdes			&len) < 0){
1311238106Sdes#ifndef USE_WINSOCK
1312238106Sdes			error = errno; /* on solaris errno is error */
1313238106Sdes#else /* USE_WINSOCK */
1314238106Sdes			error = WSAGetLastError();
1315238106Sdes#endif
1316238106Sdes		}
1317238106Sdes#ifndef USE_WINSOCK
1318238106Sdes#if defined(EINPROGRESS) && defined(EWOULDBLOCK)
1319238106Sdes		if(error == EINPROGRESS || error == EWOULDBLOCK)
1320238106Sdes			return 1; /* try again later */
1321238106Sdes		else
1322238106Sdes#endif
1323238106Sdes		if(error != 0 && verbosity < 2)
1324238106Sdes			return 0; /* silence lots of chatter in the logs */
1325238106Sdes                else if(error != 0) {
1326238106Sdes			log_err("tcp connect: %s", strerror(error));
1327238106Sdes#else /* USE_WINSOCK */
1328238106Sdes		/* examine error */
1329238106Sdes		if(error == WSAEINPROGRESS)
1330238106Sdes			return 1;
1331238106Sdes		else if(error == WSAEWOULDBLOCK) {
1332238106Sdes			winsock_tcp_wouldblock(&c->ev->ev, EV_WRITE);
1333238106Sdes			return 1;
1334238106Sdes		} else if(error != 0 && verbosity < 2)
1335238106Sdes			return 0;
1336238106Sdes		else if(error != 0) {
1337238106Sdes			log_err("tcp connect: %s", wsa_strerror(error));
1338238106Sdes#endif /* USE_WINSOCK */
1339238106Sdes			log_addr(0, "remote address is", &c->repinfo.addr,
1340238106Sdes				c->repinfo.addrlen);
1341238106Sdes			return 0;
1342238106Sdes		}
1343238106Sdes	}
1344238106Sdes	if(c->ssl)
1345238106Sdes		return ssl_handle_it(c);
1346238106Sdes
1347238106Sdes	if(c->tcp_byte_count < sizeof(uint16_t)) {
1348269257Sdes		uint16_t len = htons(sldns_buffer_limit(c->buffer));
1349238106Sdes#ifdef HAVE_WRITEV
1350238106Sdes		struct iovec iov[2];
1351238106Sdes		iov[0].iov_base = (uint8_t*)&len + c->tcp_byte_count;
1352238106Sdes		iov[0].iov_len = sizeof(uint16_t) - c->tcp_byte_count;
1353269257Sdes		iov[1].iov_base = sldns_buffer_begin(c->buffer);
1354269257Sdes		iov[1].iov_len = sldns_buffer_limit(c->buffer);
1355238106Sdes		log_assert(iov[0].iov_len > 0);
1356238106Sdes		log_assert(iov[1].iov_len > 0);
1357238106Sdes		r = writev(fd, iov, 2);
1358238106Sdes#else /* HAVE_WRITEV */
1359238106Sdes		r = send(fd, (void*)(((uint8_t*)&len)+c->tcp_byte_count),
1360238106Sdes			sizeof(uint16_t)-c->tcp_byte_count, 0);
1361238106Sdes#endif /* HAVE_WRITEV */
1362238106Sdes		if(r == -1) {
1363238106Sdes#ifndef USE_WINSOCK
1364238106Sdes#ifdef EPIPE
1365238106Sdes                	if(errno == EPIPE && verbosity < 2)
1366238106Sdes                        	return 0; /* silence 'broken pipe' */
1367238106Sdes#endif
1368238106Sdes			if(errno == EINTR || errno == EAGAIN)
1369238106Sdes				return 1;
1370238106Sdes			log_err("tcp writev: %s", strerror(errno));
1371238106Sdes#else
1372238106Sdes			if(WSAGetLastError() == WSAENOTCONN)
1373238106Sdes				return 1;
1374238106Sdes			if(WSAGetLastError() == WSAEINPROGRESS)
1375238106Sdes				return 1;
1376238106Sdes			if(WSAGetLastError() == WSAEWOULDBLOCK) {
1377238106Sdes				winsock_tcp_wouldblock(&c->ev->ev, EV_WRITE);
1378238106Sdes				return 1;
1379238106Sdes			}
1380238106Sdes			log_err("tcp send s: %s",
1381238106Sdes				wsa_strerror(WSAGetLastError()));
1382238106Sdes#endif
1383238106Sdes			log_addr(0, "remote address is", &c->repinfo.addr,
1384238106Sdes				c->repinfo.addrlen);
1385238106Sdes			return 0;
1386238106Sdes		}
1387238106Sdes		c->tcp_byte_count += r;
1388238106Sdes		if(c->tcp_byte_count < sizeof(uint16_t))
1389238106Sdes			return 1;
1390269257Sdes		sldns_buffer_set_position(c->buffer, c->tcp_byte_count -
1391238106Sdes			sizeof(uint16_t));
1392269257Sdes		if(sldns_buffer_remaining(c->buffer) == 0) {
1393238106Sdes			tcp_callback_writer(c);
1394238106Sdes			return 1;
1395238106Sdes		}
1396238106Sdes	}
1397269257Sdes	log_assert(sldns_buffer_remaining(c->buffer) > 0);
1398269257Sdes	r = send(fd, (void*)sldns_buffer_current(c->buffer),
1399269257Sdes		sldns_buffer_remaining(c->buffer), 0);
1400238106Sdes	if(r == -1) {
1401238106Sdes#ifndef USE_WINSOCK
1402238106Sdes		if(errno == EINTR || errno == EAGAIN)
1403238106Sdes			return 1;
1404238106Sdes		log_err("tcp send r: %s", strerror(errno));
1405238106Sdes#else
1406238106Sdes		if(WSAGetLastError() == WSAEINPROGRESS)
1407238106Sdes			return 1;
1408238106Sdes		if(WSAGetLastError() == WSAEWOULDBLOCK) {
1409238106Sdes			winsock_tcp_wouldblock(&c->ev->ev, EV_WRITE);
1410238106Sdes			return 1;
1411238106Sdes		}
1412238106Sdes		log_err("tcp send r: %s",
1413238106Sdes			wsa_strerror(WSAGetLastError()));
1414238106Sdes#endif
1415238106Sdes		log_addr(0, "remote address is", &c->repinfo.addr,
1416238106Sdes			c->repinfo.addrlen);
1417238106Sdes		return 0;
1418238106Sdes	}
1419269257Sdes	sldns_buffer_skip(c->buffer, r);
1420238106Sdes
1421269257Sdes	if(sldns_buffer_remaining(c->buffer) == 0) {
1422238106Sdes		tcp_callback_writer(c);
1423238106Sdes	}
1424238106Sdes
1425238106Sdes	return 1;
1426238106Sdes}
1427238106Sdes
1428238106Sdesvoid
1429238106Sdescomm_point_tcp_handle_callback(int fd, short event, void* arg)
1430238106Sdes{
1431238106Sdes	struct comm_point* c = (struct comm_point*)arg;
1432238106Sdes	log_assert(c->type == comm_tcp);
1433238106Sdes	comm_base_now(c->ev->base);
1434238106Sdes
1435238106Sdes	if(event&EV_READ) {
1436238106Sdes		if(!comm_point_tcp_handle_read(fd, c, 0)) {
1437238106Sdes			reclaim_tcp_handler(c);
1438238106Sdes			if(!c->tcp_do_close) {
1439238106Sdes				fptr_ok(fptr_whitelist_comm_point(
1440238106Sdes					c->callback));
1441238106Sdes				(void)(*c->callback)(c, c->cb_arg,
1442238106Sdes					NETEVENT_CLOSED, NULL);
1443238106Sdes			}
1444238106Sdes		}
1445238106Sdes		return;
1446238106Sdes	}
1447238106Sdes	if(event&EV_WRITE) {
1448238106Sdes		if(!comm_point_tcp_handle_write(fd, c)) {
1449238106Sdes			reclaim_tcp_handler(c);
1450238106Sdes			if(!c->tcp_do_close) {
1451238106Sdes				fptr_ok(fptr_whitelist_comm_point(
1452238106Sdes					c->callback));
1453238106Sdes				(void)(*c->callback)(c, c->cb_arg,
1454238106Sdes					NETEVENT_CLOSED, NULL);
1455238106Sdes			}
1456238106Sdes		}
1457238106Sdes		return;
1458238106Sdes	}
1459238106Sdes	if(event&EV_TIMEOUT) {
1460238106Sdes		verbose(VERB_QUERY, "tcp took too long, dropped");
1461238106Sdes		reclaim_tcp_handler(c);
1462238106Sdes		if(!c->tcp_do_close) {
1463238106Sdes			fptr_ok(fptr_whitelist_comm_point(c->callback));
1464238106Sdes			(void)(*c->callback)(c, c->cb_arg,
1465238106Sdes				NETEVENT_TIMEOUT, NULL);
1466238106Sdes		}
1467238106Sdes		return;
1468238106Sdes	}
1469238106Sdes	log_err("Ignored event %d for tcphdl.", event);
1470238106Sdes}
1471238106Sdes
1472238106Sdesvoid comm_point_local_handle_callback(int fd, short event, void* arg)
1473238106Sdes{
1474238106Sdes	struct comm_point* c = (struct comm_point*)arg;
1475238106Sdes	log_assert(c->type == comm_local);
1476238106Sdes	comm_base_now(c->ev->base);
1477238106Sdes
1478238106Sdes	if(event&EV_READ) {
1479238106Sdes		if(!comm_point_tcp_handle_read(fd, c, 1)) {
1480238106Sdes			fptr_ok(fptr_whitelist_comm_point(c->callback));
1481238106Sdes			(void)(*c->callback)(c, c->cb_arg, NETEVENT_CLOSED,
1482238106Sdes				NULL);
1483238106Sdes		}
1484238106Sdes		return;
1485238106Sdes	}
1486238106Sdes	log_err("Ignored event %d for localhdl.", event);
1487238106Sdes}
1488238106Sdes
1489238106Sdesvoid comm_point_raw_handle_callback(int ATTR_UNUSED(fd),
1490238106Sdes	short event, void* arg)
1491238106Sdes{
1492238106Sdes	struct comm_point* c = (struct comm_point*)arg;
1493238106Sdes	int err = NETEVENT_NOERROR;
1494238106Sdes	log_assert(c->type == comm_raw);
1495238106Sdes	comm_base_now(c->ev->base);
1496238106Sdes
1497238106Sdes	if(event&EV_TIMEOUT)
1498238106Sdes		err = NETEVENT_TIMEOUT;
1499238106Sdes	fptr_ok(fptr_whitelist_comm_point_raw(c->callback));
1500238106Sdes	(void)(*c->callback)(c, c->cb_arg, err, NULL);
1501238106Sdes}
1502238106Sdes
1503238106Sdesstruct comm_point*
1504269257Sdescomm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer,
1505238106Sdes	comm_point_callback_t* callback, void* callback_arg)
1506238106Sdes{
1507238106Sdes	struct comm_point* c = (struct comm_point*)calloc(1,
1508238106Sdes		sizeof(struct comm_point));
1509238106Sdes	short evbits;
1510238106Sdes	if(!c)
1511238106Sdes		return NULL;
1512238106Sdes	c->ev = (struct internal_event*)calloc(1,
1513238106Sdes		sizeof(struct internal_event));
1514238106Sdes	if(!c->ev) {
1515238106Sdes		free(c);
1516238106Sdes		return NULL;
1517238106Sdes	}
1518238106Sdes	c->ev->base = base;
1519238106Sdes	c->fd = fd;
1520238106Sdes	c->buffer = buffer;
1521238106Sdes	c->timeout = NULL;
1522238106Sdes	c->tcp_is_reading = 0;
1523238106Sdes	c->tcp_byte_count = 0;
1524238106Sdes	c->tcp_parent = NULL;
1525238106Sdes	c->max_tcp_count = 0;
1526238106Sdes	c->tcp_handlers = NULL;
1527238106Sdes	c->tcp_free = NULL;
1528238106Sdes	c->type = comm_udp;
1529238106Sdes	c->tcp_do_close = 0;
1530238106Sdes	c->do_not_close = 0;
1531238106Sdes	c->tcp_do_toggle_rw = 0;
1532238106Sdes	c->tcp_check_nb_connect = 0;
1533238106Sdes	c->inuse = 0;
1534238106Sdes	c->callback = callback;
1535238106Sdes	c->cb_arg = callback_arg;
1536238106Sdes	evbits = EV_READ | EV_PERSIST;
1537238106Sdes	/* libevent stuff */
1538238106Sdes	event_set(&c->ev->ev, c->fd, evbits, comm_point_udp_callback, c);
1539238106Sdes	if(event_base_set(base->eb->base, &c->ev->ev) != 0) {
1540238106Sdes		log_err("could not baseset udp event");
1541238106Sdes		comm_point_delete(c);
1542238106Sdes		return NULL;
1543238106Sdes	}
1544238106Sdes	if(fd!=-1 && event_add(&c->ev->ev, c->timeout) != 0 ) {
1545238106Sdes		log_err("could not add udp event");
1546238106Sdes		comm_point_delete(c);
1547238106Sdes		return NULL;
1548238106Sdes	}
1549238106Sdes	return c;
1550238106Sdes}
1551238106Sdes
1552238106Sdesstruct comm_point*
1553238106Sdescomm_point_create_udp_ancil(struct comm_base *base, int fd,
1554269257Sdes	sldns_buffer* buffer,
1555238106Sdes	comm_point_callback_t* callback, void* callback_arg)
1556238106Sdes{
1557238106Sdes	struct comm_point* c = (struct comm_point*)calloc(1,
1558238106Sdes		sizeof(struct comm_point));
1559238106Sdes	short evbits;
1560238106Sdes	if(!c)
1561238106Sdes		return NULL;
1562238106Sdes	c->ev = (struct internal_event*)calloc(1,
1563238106Sdes		sizeof(struct internal_event));
1564238106Sdes	if(!c->ev) {
1565238106Sdes		free(c);
1566238106Sdes		return NULL;
1567238106Sdes	}
1568238106Sdes	c->ev->base = base;
1569238106Sdes	c->fd = fd;
1570238106Sdes	c->buffer = buffer;
1571238106Sdes	c->timeout = NULL;
1572238106Sdes	c->tcp_is_reading = 0;
1573238106Sdes	c->tcp_byte_count = 0;
1574238106Sdes	c->tcp_parent = NULL;
1575238106Sdes	c->max_tcp_count = 0;
1576238106Sdes	c->tcp_handlers = NULL;
1577238106Sdes	c->tcp_free = NULL;
1578238106Sdes	c->type = comm_udp;
1579238106Sdes	c->tcp_do_close = 0;
1580238106Sdes	c->do_not_close = 0;
1581238106Sdes	c->inuse = 0;
1582238106Sdes	c->tcp_do_toggle_rw = 0;
1583238106Sdes	c->tcp_check_nb_connect = 0;
1584238106Sdes	c->callback = callback;
1585238106Sdes	c->cb_arg = callback_arg;
1586238106Sdes	evbits = EV_READ | EV_PERSIST;
1587238106Sdes	/* libevent stuff */
1588238106Sdes	event_set(&c->ev->ev, c->fd, evbits, comm_point_udp_ancil_callback, c);
1589238106Sdes	if(event_base_set(base->eb->base, &c->ev->ev) != 0) {
1590238106Sdes		log_err("could not baseset udp event");
1591238106Sdes		comm_point_delete(c);
1592238106Sdes		return NULL;
1593238106Sdes	}
1594238106Sdes	if(fd!=-1 && event_add(&c->ev->ev, c->timeout) != 0 ) {
1595238106Sdes		log_err("could not add udp event");
1596238106Sdes		comm_point_delete(c);
1597238106Sdes		return NULL;
1598238106Sdes	}
1599238106Sdes	return c;
1600238106Sdes}
1601238106Sdes
1602238106Sdesstatic struct comm_point*
1603238106Sdescomm_point_create_tcp_handler(struct comm_base *base,
1604238106Sdes	struct comm_point* parent, size_t bufsize,
1605238106Sdes        comm_point_callback_t* callback, void* callback_arg)
1606238106Sdes{
1607238106Sdes	struct comm_point* c = (struct comm_point*)calloc(1,
1608238106Sdes		sizeof(struct comm_point));
1609238106Sdes	short evbits;
1610238106Sdes	if(!c)
1611238106Sdes		return NULL;
1612238106Sdes	c->ev = (struct internal_event*)calloc(1,
1613238106Sdes		sizeof(struct internal_event));
1614238106Sdes	if(!c->ev) {
1615238106Sdes		free(c);
1616238106Sdes		return NULL;
1617238106Sdes	}
1618238106Sdes	c->ev->base = base;
1619238106Sdes	c->fd = -1;
1620269257Sdes	c->buffer = sldns_buffer_new(bufsize);
1621238106Sdes	if(!c->buffer) {
1622238106Sdes		free(c->ev);
1623238106Sdes		free(c);
1624238106Sdes		return NULL;
1625238106Sdes	}
1626238106Sdes	c->timeout = (struct timeval*)malloc(sizeof(struct timeval));
1627238106Sdes	if(!c->timeout) {
1628269257Sdes		sldns_buffer_free(c->buffer);
1629238106Sdes		free(c->ev);
1630238106Sdes		free(c);
1631238106Sdes		return NULL;
1632238106Sdes	}
1633238106Sdes	c->tcp_is_reading = 0;
1634238106Sdes	c->tcp_byte_count = 0;
1635238106Sdes	c->tcp_parent = parent;
1636238106Sdes	c->max_tcp_count = 0;
1637238106Sdes	c->tcp_handlers = NULL;
1638238106Sdes	c->tcp_free = NULL;
1639238106Sdes	c->type = comm_tcp;
1640238106Sdes	c->tcp_do_close = 0;
1641238106Sdes	c->do_not_close = 0;
1642238106Sdes	c->tcp_do_toggle_rw = 1;
1643238106Sdes	c->tcp_check_nb_connect = 0;
1644238106Sdes	c->repinfo.c = c;
1645238106Sdes	c->callback = callback;
1646238106Sdes	c->cb_arg = callback_arg;
1647238106Sdes	/* add to parent free list */
1648238106Sdes	c->tcp_free = parent->tcp_free;
1649238106Sdes	parent->tcp_free = c;
1650238106Sdes	/* libevent stuff */
1651238106Sdes	evbits = EV_PERSIST | EV_READ | EV_TIMEOUT;
1652238106Sdes	event_set(&c->ev->ev, c->fd, evbits, comm_point_tcp_handle_callback, c);
1653238106Sdes	if(event_base_set(base->eb->base, &c->ev->ev) != 0)
1654238106Sdes	{
1655238106Sdes		log_err("could not basetset tcphdl event");
1656238106Sdes		parent->tcp_free = c->tcp_free;
1657238106Sdes		free(c->ev);
1658238106Sdes		free(c);
1659238106Sdes		return NULL;
1660238106Sdes	}
1661238106Sdes	return c;
1662238106Sdes}
1663238106Sdes
1664238106Sdesstruct comm_point*
1665238106Sdescomm_point_create_tcp(struct comm_base *base, int fd, int num, size_t bufsize,
1666238106Sdes        comm_point_callback_t* callback, void* callback_arg)
1667238106Sdes{
1668238106Sdes	struct comm_point* c = (struct comm_point*)calloc(1,
1669238106Sdes		sizeof(struct comm_point));
1670238106Sdes	short evbits;
1671238106Sdes	int i;
1672238106Sdes	/* first allocate the TCP accept listener */
1673238106Sdes	if(!c)
1674238106Sdes		return NULL;
1675238106Sdes	c->ev = (struct internal_event*)calloc(1,
1676238106Sdes		sizeof(struct internal_event));
1677238106Sdes	if(!c->ev) {
1678238106Sdes		free(c);
1679238106Sdes		return NULL;
1680238106Sdes	}
1681238106Sdes	c->ev->base = base;
1682238106Sdes	c->fd = fd;
1683238106Sdes	c->buffer = NULL;
1684238106Sdes	c->timeout = NULL;
1685238106Sdes	c->tcp_is_reading = 0;
1686238106Sdes	c->tcp_byte_count = 0;
1687238106Sdes	c->tcp_parent = NULL;
1688238106Sdes	c->max_tcp_count = num;
1689238106Sdes	c->tcp_handlers = (struct comm_point**)calloc((size_t)num,
1690238106Sdes		sizeof(struct comm_point*));
1691238106Sdes	if(!c->tcp_handlers) {
1692238106Sdes		free(c->ev);
1693238106Sdes		free(c);
1694238106Sdes		return NULL;
1695238106Sdes	}
1696238106Sdes	c->tcp_free = NULL;
1697238106Sdes	c->type = comm_tcp_accept;
1698238106Sdes	c->tcp_do_close = 0;
1699238106Sdes	c->do_not_close = 0;
1700238106Sdes	c->tcp_do_toggle_rw = 0;
1701238106Sdes	c->tcp_check_nb_connect = 0;
1702238106Sdes	c->callback = NULL;
1703238106Sdes	c->cb_arg = NULL;
1704238106Sdes	evbits = EV_READ | EV_PERSIST;
1705238106Sdes	/* libevent stuff */
1706238106Sdes	event_set(&c->ev->ev, c->fd, evbits, comm_point_tcp_accept_callback, c);
1707238106Sdes	if(event_base_set(base->eb->base, &c->ev->ev) != 0 ||
1708238106Sdes		event_add(&c->ev->ev, c->timeout) != 0 )
1709238106Sdes	{
1710238106Sdes		log_err("could not add tcpacc event");
1711238106Sdes		comm_point_delete(c);
1712238106Sdes		return NULL;
1713238106Sdes	}
1714238106Sdes
1715238106Sdes	/* now prealloc the tcp handlers */
1716238106Sdes	for(i=0; i<num; i++) {
1717238106Sdes		c->tcp_handlers[i] = comm_point_create_tcp_handler(base,
1718238106Sdes			c, bufsize, callback, callback_arg);
1719238106Sdes		if(!c->tcp_handlers[i]) {
1720238106Sdes			comm_point_delete(c);
1721238106Sdes			return NULL;
1722238106Sdes		}
1723238106Sdes	}
1724238106Sdes
1725238106Sdes	return c;
1726238106Sdes}
1727238106Sdes
1728238106Sdesstruct comm_point*
1729238106Sdescomm_point_create_tcp_out(struct comm_base *base, size_t bufsize,
1730238106Sdes        comm_point_callback_t* callback, void* callback_arg)
1731238106Sdes{
1732238106Sdes	struct comm_point* c = (struct comm_point*)calloc(1,
1733238106Sdes		sizeof(struct comm_point));
1734238106Sdes	short evbits;
1735238106Sdes	if(!c)
1736238106Sdes		return NULL;
1737238106Sdes	c->ev = (struct internal_event*)calloc(1,
1738238106Sdes		sizeof(struct internal_event));
1739238106Sdes	if(!c->ev) {
1740238106Sdes		free(c);
1741238106Sdes		return NULL;
1742238106Sdes	}
1743238106Sdes	c->ev->base = base;
1744238106Sdes	c->fd = -1;
1745269257Sdes	c->buffer = sldns_buffer_new(bufsize);
1746238106Sdes	if(!c->buffer) {
1747238106Sdes		free(c->ev);
1748238106Sdes		free(c);
1749238106Sdes		return NULL;
1750238106Sdes	}
1751238106Sdes	c->timeout = NULL;
1752238106Sdes	c->tcp_is_reading = 0;
1753238106Sdes	c->tcp_byte_count = 0;
1754238106Sdes	c->tcp_parent = NULL;
1755238106Sdes	c->max_tcp_count = 0;
1756238106Sdes	c->tcp_handlers = NULL;
1757238106Sdes	c->tcp_free = NULL;
1758238106Sdes	c->type = comm_tcp;
1759238106Sdes	c->tcp_do_close = 0;
1760238106Sdes	c->do_not_close = 0;
1761238106Sdes	c->tcp_do_toggle_rw = 1;
1762238106Sdes	c->tcp_check_nb_connect = 1;
1763238106Sdes	c->repinfo.c = c;
1764238106Sdes	c->callback = callback;
1765238106Sdes	c->cb_arg = callback_arg;
1766238106Sdes	evbits = EV_PERSIST | EV_WRITE;
1767238106Sdes	event_set(&c->ev->ev, c->fd, evbits, comm_point_tcp_handle_callback, c);
1768238106Sdes	if(event_base_set(base->eb->base, &c->ev->ev) != 0)
1769238106Sdes	{
1770238106Sdes		log_err("could not basetset tcpout event");
1771269257Sdes		sldns_buffer_free(c->buffer);
1772238106Sdes		free(c->ev);
1773238106Sdes		free(c);
1774238106Sdes		return NULL;
1775238106Sdes	}
1776238106Sdes
1777238106Sdes	return c;
1778238106Sdes}
1779238106Sdes
1780238106Sdesstruct comm_point*
1781238106Sdescomm_point_create_local(struct comm_base *base, int fd, size_t bufsize,
1782238106Sdes        comm_point_callback_t* callback, void* callback_arg)
1783238106Sdes{
1784238106Sdes	struct comm_point* c = (struct comm_point*)calloc(1,
1785238106Sdes		sizeof(struct comm_point));
1786238106Sdes	short evbits;
1787238106Sdes	if(!c)
1788238106Sdes		return NULL;
1789238106Sdes	c->ev = (struct internal_event*)calloc(1,
1790238106Sdes		sizeof(struct internal_event));
1791238106Sdes	if(!c->ev) {
1792238106Sdes		free(c);
1793238106Sdes		return NULL;
1794238106Sdes	}
1795238106Sdes	c->ev->base = base;
1796238106Sdes	c->fd = fd;
1797269257Sdes	c->buffer = sldns_buffer_new(bufsize);
1798238106Sdes	if(!c->buffer) {
1799238106Sdes		free(c->ev);
1800238106Sdes		free(c);
1801238106Sdes		return NULL;
1802238106Sdes	}
1803238106Sdes	c->timeout = NULL;
1804238106Sdes	c->tcp_is_reading = 1;
1805238106Sdes	c->tcp_byte_count = 0;
1806238106Sdes	c->tcp_parent = NULL;
1807238106Sdes	c->max_tcp_count = 0;
1808238106Sdes	c->tcp_handlers = NULL;
1809238106Sdes	c->tcp_free = NULL;
1810238106Sdes	c->type = comm_local;
1811238106Sdes	c->tcp_do_close = 0;
1812238106Sdes	c->do_not_close = 1;
1813238106Sdes	c->tcp_do_toggle_rw = 0;
1814238106Sdes	c->tcp_check_nb_connect = 0;
1815238106Sdes	c->callback = callback;
1816238106Sdes	c->cb_arg = callback_arg;
1817238106Sdes	/* libevent stuff */
1818238106Sdes	evbits = EV_PERSIST | EV_READ;
1819238106Sdes	event_set(&c->ev->ev, c->fd, evbits, comm_point_local_handle_callback,
1820238106Sdes		c);
1821238106Sdes	if(event_base_set(base->eb->base, &c->ev->ev) != 0 ||
1822238106Sdes		event_add(&c->ev->ev, c->timeout) != 0 )
1823238106Sdes	{
1824238106Sdes		log_err("could not add localhdl event");
1825238106Sdes		free(c->ev);
1826238106Sdes		free(c);
1827238106Sdes		return NULL;
1828238106Sdes	}
1829238106Sdes	return c;
1830238106Sdes}
1831238106Sdes
1832238106Sdesstruct comm_point*
1833238106Sdescomm_point_create_raw(struct comm_base* base, int fd, int writing,
1834238106Sdes	comm_point_callback_t* callback, void* callback_arg)
1835238106Sdes{
1836238106Sdes	struct comm_point* c = (struct comm_point*)calloc(1,
1837238106Sdes		sizeof(struct comm_point));
1838238106Sdes	short evbits;
1839238106Sdes	if(!c)
1840238106Sdes		return NULL;
1841238106Sdes	c->ev = (struct internal_event*)calloc(1,
1842238106Sdes		sizeof(struct internal_event));
1843238106Sdes	if(!c->ev) {
1844238106Sdes		free(c);
1845238106Sdes		return NULL;
1846238106Sdes	}
1847238106Sdes	c->ev->base = base;
1848238106Sdes	c->fd = fd;
1849238106Sdes	c->buffer = NULL;
1850238106Sdes	c->timeout = NULL;
1851238106Sdes	c->tcp_is_reading = 0;
1852238106Sdes	c->tcp_byte_count = 0;
1853238106Sdes	c->tcp_parent = NULL;
1854238106Sdes	c->max_tcp_count = 0;
1855238106Sdes	c->tcp_handlers = NULL;
1856238106Sdes	c->tcp_free = NULL;
1857238106Sdes	c->type = comm_raw;
1858238106Sdes	c->tcp_do_close = 0;
1859238106Sdes	c->do_not_close = 1;
1860238106Sdes	c->tcp_do_toggle_rw = 0;
1861238106Sdes	c->tcp_check_nb_connect = 0;
1862238106Sdes	c->callback = callback;
1863238106Sdes	c->cb_arg = callback_arg;
1864238106Sdes	/* libevent stuff */
1865238106Sdes	if(writing)
1866238106Sdes		evbits = EV_PERSIST | EV_WRITE;
1867238106Sdes	else 	evbits = EV_PERSIST | EV_READ;
1868238106Sdes	event_set(&c->ev->ev, c->fd, evbits, comm_point_raw_handle_callback,
1869238106Sdes		c);
1870238106Sdes	if(event_base_set(base->eb->base, &c->ev->ev) != 0 ||
1871238106Sdes		event_add(&c->ev->ev, c->timeout) != 0 )
1872238106Sdes	{
1873238106Sdes		log_err("could not add rawhdl event");
1874238106Sdes		free(c->ev);
1875238106Sdes		free(c);
1876238106Sdes		return NULL;
1877238106Sdes	}
1878238106Sdes	return c;
1879238106Sdes}
1880238106Sdes
1881238106Sdesvoid
1882238106Sdescomm_point_close(struct comm_point* c)
1883238106Sdes{
1884238106Sdes	if(!c)
1885238106Sdes		return;
1886238106Sdes	if(c->fd != -1)
1887238106Sdes		if(event_del(&c->ev->ev) != 0) {
1888238106Sdes			log_err("could not event_del on close");
1889238106Sdes		}
1890238106Sdes	/* close fd after removing from event lists, or epoll.. is messed up */
1891238106Sdes	if(c->fd != -1 && !c->do_not_close) {
1892238106Sdes		verbose(VERB_ALGO, "close fd %d", c->fd);
1893238106Sdes#ifndef USE_WINSOCK
1894238106Sdes		close(c->fd);
1895238106Sdes#else
1896238106Sdes		closesocket(c->fd);
1897238106Sdes#endif
1898238106Sdes	}
1899238106Sdes	c->fd = -1;
1900238106Sdes}
1901238106Sdes
1902238106Sdesvoid
1903238106Sdescomm_point_delete(struct comm_point* c)
1904238106Sdes{
1905238106Sdes	if(!c)
1906238106Sdes		return;
1907238106Sdes	if(c->type == comm_tcp && c->ssl) {
1908249141Sdes#ifdef HAVE_SSL
1909238106Sdes		SSL_shutdown(c->ssl);
1910238106Sdes		SSL_free(c->ssl);
1911249141Sdes#endif
1912238106Sdes	}
1913238106Sdes	comm_point_close(c);
1914238106Sdes	if(c->tcp_handlers) {
1915238106Sdes		int i;
1916238106Sdes		for(i=0; i<c->max_tcp_count; i++)
1917238106Sdes			comm_point_delete(c->tcp_handlers[i]);
1918238106Sdes		free(c->tcp_handlers);
1919238106Sdes	}
1920238106Sdes	free(c->timeout);
1921238106Sdes	if(c->type == comm_tcp || c->type == comm_local)
1922269257Sdes		sldns_buffer_free(c->buffer);
1923238106Sdes	free(c->ev);
1924238106Sdes	free(c);
1925238106Sdes}
1926238106Sdes
1927238106Sdesvoid
1928238106Sdescomm_point_send_reply(struct comm_reply *repinfo)
1929238106Sdes{
1930238106Sdes	log_assert(repinfo && repinfo->c);
1931238106Sdes	if(repinfo->c->type == comm_udp) {
1932238106Sdes		if(repinfo->srctype)
1933238106Sdes			comm_point_send_udp_msg_if(repinfo->c,
1934238106Sdes			repinfo->c->buffer, (struct sockaddr*)&repinfo->addr,
1935238106Sdes			repinfo->addrlen, repinfo);
1936238106Sdes		else
1937238106Sdes			comm_point_send_udp_msg(repinfo->c, repinfo->c->buffer,
1938238106Sdes			(struct sockaddr*)&repinfo->addr, repinfo->addrlen);
1939238106Sdes	} else {
1940238106Sdes		comm_point_start_listening(repinfo->c, -1, TCP_QUERY_TIMEOUT);
1941238106Sdes	}
1942238106Sdes}
1943238106Sdes
1944238106Sdesvoid
1945238106Sdescomm_point_drop_reply(struct comm_reply* repinfo)
1946238106Sdes{
1947238106Sdes	if(!repinfo)
1948238106Sdes		return;
1949238106Sdes	log_assert(repinfo && repinfo->c);
1950238106Sdes	log_assert(repinfo->c->type != comm_tcp_accept);
1951238106Sdes	if(repinfo->c->type == comm_udp)
1952238106Sdes		return;
1953238106Sdes	reclaim_tcp_handler(repinfo->c);
1954238106Sdes}
1955238106Sdes
1956238106Sdesvoid
1957238106Sdescomm_point_stop_listening(struct comm_point* c)
1958238106Sdes{
1959238106Sdes	verbose(VERB_ALGO, "comm point stop listening %d", c->fd);
1960238106Sdes	if(event_del(&c->ev->ev) != 0) {
1961238106Sdes		log_err("event_del error to stoplisten");
1962238106Sdes	}
1963238106Sdes}
1964238106Sdes
1965238106Sdesvoid
1966238106Sdescomm_point_start_listening(struct comm_point* c, int newfd, int sec)
1967238106Sdes{
1968238106Sdes	verbose(VERB_ALGO, "comm point start listening %d",
1969238106Sdes		c->fd==-1?newfd:c->fd);
1970238106Sdes	if(c->type == comm_tcp_accept && !c->tcp_free) {
1971238106Sdes		/* no use to start listening no free slots. */
1972238106Sdes		return;
1973238106Sdes	}
1974238106Sdes	if(sec != -1 && sec != 0) {
1975238106Sdes		if(!c->timeout) {
1976238106Sdes			c->timeout = (struct timeval*)malloc(sizeof(
1977238106Sdes				struct timeval));
1978238106Sdes			if(!c->timeout) {
1979238106Sdes				log_err("cpsl: malloc failed. No net read.");
1980238106Sdes				return;
1981238106Sdes			}
1982238106Sdes		}
1983238106Sdes		c->ev->ev.ev_events |= EV_TIMEOUT;
1984238106Sdes#ifndef S_SPLINT_S /* splint fails on struct timeval. */
1985238106Sdes		c->timeout->tv_sec = sec;
1986238106Sdes		c->timeout->tv_usec = 0;
1987238106Sdes#endif /* S_SPLINT_S */
1988238106Sdes	}
1989238106Sdes	if(c->type == comm_tcp) {
1990238106Sdes		c->ev->ev.ev_events &= ~(EV_READ|EV_WRITE);
1991238106Sdes		if(c->tcp_is_reading)
1992238106Sdes			c->ev->ev.ev_events |= EV_READ;
1993238106Sdes		else	c->ev->ev.ev_events |= EV_WRITE;
1994238106Sdes	}
1995238106Sdes	if(newfd != -1) {
1996238106Sdes		if(c->fd != -1) {
1997238106Sdes#ifndef USE_WINSOCK
1998238106Sdes			close(c->fd);
1999238106Sdes#else
2000238106Sdes			closesocket(c->fd);
2001238106Sdes#endif
2002238106Sdes		}
2003238106Sdes		c->fd = newfd;
2004238106Sdes		c->ev->ev.ev_fd = c->fd;
2005238106Sdes	}
2006238106Sdes	if(event_add(&c->ev->ev, sec==0?NULL:c->timeout) != 0) {
2007238106Sdes		log_err("event_add failed. in cpsl.");
2008238106Sdes	}
2009238106Sdes}
2010238106Sdes
2011238106Sdesvoid comm_point_listen_for_rw(struct comm_point* c, int rd, int wr)
2012238106Sdes{
2013238106Sdes	verbose(VERB_ALGO, "comm point listen_for_rw %d %d", c->fd, wr);
2014238106Sdes	if(event_del(&c->ev->ev) != 0) {
2015238106Sdes		log_err("event_del error to cplf");
2016238106Sdes	}
2017238106Sdes	c->ev->ev.ev_events &= ~(EV_READ|EV_WRITE);
2018238106Sdes	if(rd) c->ev->ev.ev_events |= EV_READ;
2019238106Sdes	if(wr) c->ev->ev.ev_events |= EV_WRITE;
2020238106Sdes	if(event_add(&c->ev->ev, c->timeout) != 0) {
2021238106Sdes		log_err("event_add failed. in cplf.");
2022238106Sdes	}
2023238106Sdes}
2024238106Sdes
2025238106Sdessize_t comm_point_get_mem(struct comm_point* c)
2026238106Sdes{
2027238106Sdes	size_t s;
2028238106Sdes	if(!c)
2029238106Sdes		return 0;
2030238106Sdes	s = sizeof(*c) + sizeof(*c->ev);
2031238106Sdes	if(c->timeout)
2032238106Sdes		s += sizeof(*c->timeout);
2033238106Sdes	if(c->type == comm_tcp || c->type == comm_local)
2034269257Sdes		s += sizeof(*c->buffer) + sldns_buffer_capacity(c->buffer);
2035238106Sdes	if(c->type == comm_tcp_accept) {
2036238106Sdes		int i;
2037238106Sdes		for(i=0; i<c->max_tcp_count; i++)
2038238106Sdes			s += comm_point_get_mem(c->tcp_handlers[i]);
2039238106Sdes	}
2040238106Sdes	return s;
2041238106Sdes}
2042238106Sdes
2043238106Sdesstruct comm_timer*
2044238106Sdescomm_timer_create(struct comm_base* base, void (*cb)(void*), void* cb_arg)
2045238106Sdes{
2046238106Sdes	struct comm_timer *tm = (struct comm_timer*)calloc(1,
2047238106Sdes		sizeof(struct comm_timer));
2048238106Sdes	if(!tm)
2049238106Sdes		return NULL;
2050238106Sdes	tm->ev_timer = (struct internal_timer*)calloc(1,
2051238106Sdes		sizeof(struct internal_timer));
2052238106Sdes	if(!tm->ev_timer) {
2053238106Sdes		log_err("malloc failed");
2054238106Sdes		free(tm);
2055238106Sdes		return NULL;
2056238106Sdes	}
2057238106Sdes	tm->ev_timer->base = base;
2058238106Sdes	tm->callback = cb;
2059238106Sdes	tm->cb_arg = cb_arg;
2060238106Sdes	event_set(&tm->ev_timer->ev, -1, EV_TIMEOUT,
2061238106Sdes		comm_timer_callback, tm);
2062238106Sdes	if(event_base_set(base->eb->base, &tm->ev_timer->ev) != 0) {
2063238106Sdes		log_err("timer_create: event_base_set failed.");
2064238106Sdes		free(tm->ev_timer);
2065238106Sdes		free(tm);
2066238106Sdes		return NULL;
2067238106Sdes	}
2068238106Sdes	return tm;
2069238106Sdes}
2070238106Sdes
2071238106Sdesvoid
2072238106Sdescomm_timer_disable(struct comm_timer* timer)
2073238106Sdes{
2074238106Sdes	if(!timer)
2075238106Sdes		return;
2076238106Sdes	evtimer_del(&timer->ev_timer->ev);
2077238106Sdes	timer->ev_timer->enabled = 0;
2078238106Sdes}
2079238106Sdes
2080238106Sdesvoid
2081238106Sdescomm_timer_set(struct comm_timer* timer, struct timeval* tv)
2082238106Sdes{
2083238106Sdes	log_assert(tv);
2084238106Sdes	if(timer->ev_timer->enabled)
2085238106Sdes		comm_timer_disable(timer);
2086238106Sdes	event_set(&timer->ev_timer->ev, -1, EV_TIMEOUT,
2087238106Sdes		comm_timer_callback, timer);
2088238106Sdes	if(event_base_set(timer->ev_timer->base->eb->base,
2089238106Sdes		&timer->ev_timer->ev) != 0)
2090238106Sdes		log_err("comm_timer_set: set_base failed.");
2091238106Sdes	if(evtimer_add(&timer->ev_timer->ev, tv) != 0)
2092238106Sdes		log_err("comm_timer_set: evtimer_add failed.");
2093238106Sdes	timer->ev_timer->enabled = 1;
2094238106Sdes}
2095238106Sdes
2096238106Sdesvoid
2097238106Sdescomm_timer_delete(struct comm_timer* timer)
2098238106Sdes{
2099238106Sdes	if(!timer)
2100238106Sdes		return;
2101238106Sdes	comm_timer_disable(timer);
2102238106Sdes	free(timer->ev_timer);
2103238106Sdes	free(timer);
2104238106Sdes}
2105238106Sdes
2106238106Sdesvoid
2107238106Sdescomm_timer_callback(int ATTR_UNUSED(fd), short event, void* arg)
2108238106Sdes{
2109238106Sdes	struct comm_timer* tm = (struct comm_timer*)arg;
2110238106Sdes	if(!(event&EV_TIMEOUT))
2111238106Sdes		return;
2112238106Sdes	comm_base_now(tm->ev_timer->base);
2113238106Sdes	tm->ev_timer->enabled = 0;
2114238106Sdes	fptr_ok(fptr_whitelist_comm_timer(tm->callback));
2115238106Sdes	(*tm->callback)(tm->cb_arg);
2116238106Sdes}
2117238106Sdes
2118238106Sdesint
2119238106Sdescomm_timer_is_set(struct comm_timer* timer)
2120238106Sdes{
2121238106Sdes	return (int)timer->ev_timer->enabled;
2122238106Sdes}
2123238106Sdes
2124238106Sdessize_t
2125238106Sdescomm_timer_get_mem(struct comm_timer* timer)
2126238106Sdes{
2127238106Sdes	return sizeof(*timer) + sizeof(struct internal_timer);
2128238106Sdes}
2129238106Sdes
2130238106Sdesstruct comm_signal*
2131238106Sdescomm_signal_create(struct comm_base* base,
2132238106Sdes        void (*callback)(int, void*), void* cb_arg)
2133238106Sdes{
2134238106Sdes	struct comm_signal* com = (struct comm_signal*)malloc(
2135238106Sdes		sizeof(struct comm_signal));
2136238106Sdes	if(!com) {
2137238106Sdes		log_err("malloc failed");
2138238106Sdes		return NULL;
2139238106Sdes	}
2140238106Sdes	com->base = base;
2141238106Sdes	com->callback = callback;
2142238106Sdes	com->cb_arg = cb_arg;
2143238106Sdes	com->ev_signal = NULL;
2144238106Sdes	return com;
2145238106Sdes}
2146238106Sdes
2147238106Sdesvoid
2148238106Sdescomm_signal_callback(int sig, short event, void* arg)
2149238106Sdes{
2150238106Sdes	struct comm_signal* comsig = (struct comm_signal*)arg;
2151238106Sdes	if(!(event & EV_SIGNAL))
2152238106Sdes		return;
2153238106Sdes	comm_base_now(comsig->base);
2154238106Sdes	fptr_ok(fptr_whitelist_comm_signal(comsig->callback));
2155238106Sdes	(*comsig->callback)(sig, comsig->cb_arg);
2156238106Sdes}
2157238106Sdes
2158238106Sdesint
2159238106Sdescomm_signal_bind(struct comm_signal* comsig, int sig)
2160238106Sdes{
2161238106Sdes	struct internal_signal* entry = (struct internal_signal*)calloc(1,
2162238106Sdes		sizeof(struct internal_signal));
2163238106Sdes	if(!entry) {
2164238106Sdes		log_err("malloc failed");
2165238106Sdes		return 0;
2166238106Sdes	}
2167238106Sdes	log_assert(comsig);
2168238106Sdes	/* add signal event */
2169238106Sdes	signal_set(&entry->ev, sig, comm_signal_callback, comsig);
2170238106Sdes	if(event_base_set(comsig->base->eb->base, &entry->ev) != 0) {
2171238106Sdes		log_err("Could not set signal base");
2172238106Sdes		free(entry);
2173238106Sdes		return 0;
2174238106Sdes	}
2175238106Sdes	if(signal_add(&entry->ev, NULL) != 0) {
2176238106Sdes		log_err("Could not add signal handler");
2177238106Sdes		free(entry);
2178238106Sdes		return 0;
2179238106Sdes	}
2180238106Sdes	/* link into list */
2181238106Sdes	entry->next = comsig->ev_signal;
2182238106Sdes	comsig->ev_signal = entry;
2183238106Sdes	return 1;
2184238106Sdes}
2185238106Sdes
2186238106Sdesvoid
2187238106Sdescomm_signal_delete(struct comm_signal* comsig)
2188238106Sdes{
2189238106Sdes	struct internal_signal* p, *np;
2190238106Sdes	if(!comsig)
2191238106Sdes		return;
2192238106Sdes	p=comsig->ev_signal;
2193238106Sdes	while(p) {
2194238106Sdes		np = p->next;
2195238106Sdes		signal_del(&p->ev);
2196238106Sdes		free(p);
2197238106Sdes		p = np;
2198238106Sdes	}
2199238106Sdes	free(comsig);
2200238106Sdes}
2201