xref: /freebsd/contrib/unbound/util/netevent.c (revision 4c75e3aa0f1368f18240b8bfd0e1e88f64994a1c)
1b7579f77SDag-Erling Smørgrav /*
2b7579f77SDag-Erling Smørgrav  * util/netevent.c - event notification
3b7579f77SDag-Erling Smørgrav  *
4b7579f77SDag-Erling Smørgrav  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5b7579f77SDag-Erling Smørgrav  *
6b7579f77SDag-Erling Smørgrav  * This software is open source.
7b7579f77SDag-Erling Smørgrav  *
8b7579f77SDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
9b7579f77SDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
10b7579f77SDag-Erling Smørgrav  * are met:
11b7579f77SDag-Erling Smørgrav  *
12b7579f77SDag-Erling Smørgrav  * Redistributions of source code must retain the above copyright notice,
13b7579f77SDag-Erling Smørgrav  * this list of conditions and the following disclaimer.
14b7579f77SDag-Erling Smørgrav  *
15b7579f77SDag-Erling Smørgrav  * Redistributions in binary form must reproduce the above copyright notice,
16b7579f77SDag-Erling Smørgrav  * this list of conditions and the following disclaimer in the documentation
17b7579f77SDag-Erling Smørgrav  * and/or other materials provided with the distribution.
18b7579f77SDag-Erling Smørgrav  *
19b7579f77SDag-Erling Smørgrav  * Neither the name of the NLNET LABS nor the names of its contributors may
20b7579f77SDag-Erling Smørgrav  * be used to endorse or promote products derived from this software without
21b7579f77SDag-Erling Smørgrav  * specific prior written permission.
22b7579f77SDag-Erling Smørgrav  *
23b7579f77SDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2417d15b25SDag-Erling Smørgrav  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2517d15b25SDag-Erling Smørgrav  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2617d15b25SDag-Erling Smørgrav  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2717d15b25SDag-Erling Smørgrav  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2817d15b25SDag-Erling Smørgrav  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
2917d15b25SDag-Erling Smørgrav  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
3017d15b25SDag-Erling Smørgrav  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
3117d15b25SDag-Erling Smørgrav  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
3217d15b25SDag-Erling Smørgrav  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3317d15b25SDag-Erling Smørgrav  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34b7579f77SDag-Erling Smørgrav  */
35b7579f77SDag-Erling Smørgrav 
36b7579f77SDag-Erling Smørgrav /**
37b7579f77SDag-Erling Smørgrav  * \file
38b7579f77SDag-Erling Smørgrav  *
39b7579f77SDag-Erling Smørgrav  * This file contains event notification functions.
40b7579f77SDag-Erling Smørgrav  */
41b7579f77SDag-Erling Smørgrav #include "config.h"
42b7579f77SDag-Erling Smørgrav #include "util/netevent.h"
43e2d15004SDag-Erling Smørgrav #include "util/ub_event.h"
44b7579f77SDag-Erling Smørgrav #include "util/log.h"
45b7579f77SDag-Erling Smørgrav #include "util/net_help.h"
46*4c75e3aaSDag-Erling Smørgrav #include "util/tcp_conn_limit.h"
47b7579f77SDag-Erling Smørgrav #include "util/fptr_wlist.h"
4809a3aaf3SDag-Erling Smørgrav #include "sldns/pkthdr.h"
4909a3aaf3SDag-Erling Smørgrav #include "sldns/sbuffer.h"
500fb34990SDag-Erling Smørgrav #include "sldns/str2wire.h"
51ff825849SDag-Erling Smørgrav #include "dnstap/dnstap.h"
5265b390aaSDag-Erling Smørgrav #include "dnscrypt/dnscrypt.h"
538ed2b524SDag-Erling Smørgrav #ifdef HAVE_OPENSSL_SSL_H
54b7579f77SDag-Erling Smørgrav #include <openssl/ssl.h>
558ed2b524SDag-Erling Smørgrav #endif
568ed2b524SDag-Erling Smørgrav #ifdef HAVE_OPENSSL_ERR_H
57b7579f77SDag-Erling Smørgrav #include <openssl/err.h>
588ed2b524SDag-Erling Smørgrav #endif
59b7579f77SDag-Erling Smørgrav 
60b7579f77SDag-Erling Smørgrav /* -------- Start of local definitions -------- */
61b7579f77SDag-Erling Smørgrav /** if CMSG_ALIGN is not defined on this platform, a workaround */
62b7579f77SDag-Erling Smørgrav #ifndef CMSG_ALIGN
63f61ef7f6SDag-Erling Smørgrav #  ifdef __CMSG_ALIGN
64f61ef7f6SDag-Erling Smørgrav #    define CMSG_ALIGN(n) __CMSG_ALIGN(n)
65f61ef7f6SDag-Erling Smørgrav #  elif defined(CMSG_DATA_ALIGN)
66b7579f77SDag-Erling Smørgrav #    define CMSG_ALIGN _CMSG_DATA_ALIGN
67b7579f77SDag-Erling Smørgrav #  else
68b7579f77SDag-Erling Smørgrav #    define CMSG_ALIGN(len) (((len)+sizeof(long)-1) & ~(sizeof(long)-1))
69b7579f77SDag-Erling Smørgrav #  endif
70b7579f77SDag-Erling Smørgrav #endif
71b7579f77SDag-Erling Smørgrav 
72b7579f77SDag-Erling Smørgrav /** if CMSG_LEN is not defined on this platform, a workaround */
73b7579f77SDag-Erling Smørgrav #ifndef CMSG_LEN
74b7579f77SDag-Erling Smørgrav #  define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr))+(len))
75b7579f77SDag-Erling Smørgrav #endif
76b7579f77SDag-Erling Smørgrav 
77b7579f77SDag-Erling Smørgrav /** if CMSG_SPACE is not defined on this platform, a workaround */
78b7579f77SDag-Erling Smørgrav #ifndef CMSG_SPACE
79b7579f77SDag-Erling Smørgrav #  ifdef _CMSG_HDR_ALIGN
80b7579f77SDag-Erling Smørgrav #    define CMSG_SPACE(l) (CMSG_ALIGN(l)+_CMSG_HDR_ALIGN(sizeof(struct cmsghdr)))
81b7579f77SDag-Erling Smørgrav #  else
82b7579f77SDag-Erling Smørgrav #    define CMSG_SPACE(l) (CMSG_ALIGN(l)+CMSG_ALIGN(sizeof(struct cmsghdr)))
83b7579f77SDag-Erling Smørgrav #  endif
84b7579f77SDag-Erling Smørgrav #endif
85b7579f77SDag-Erling Smørgrav 
86*4c75e3aaSDag-Erling Smørgrav /** The TCP writing query timeout in milliseconds */
87b5663de9SDag-Erling Smørgrav #define TCP_QUERY_TIMEOUT 120000
88*4c75e3aaSDag-Erling Smørgrav /** The minimum actual TCP timeout to use, regardless of what we advertise,
89*4c75e3aaSDag-Erling Smørgrav  * in msec */
90*4c75e3aaSDag-Erling Smørgrav #define TCP_QUERY_TIMEOUT_MINIMUM 200
91b7579f77SDag-Erling Smørgrav 
92b7579f77SDag-Erling Smørgrav #ifndef NONBLOCKING_IS_BROKEN
93b7579f77SDag-Erling Smørgrav /** number of UDP reads to perform per read indication from select */
94b7579f77SDag-Erling Smørgrav #define NUM_UDP_PER_SELECT 100
95b7579f77SDag-Erling Smørgrav #else
96b7579f77SDag-Erling Smørgrav #define NUM_UDP_PER_SELECT 1
97b7579f77SDag-Erling Smørgrav #endif
98b7579f77SDag-Erling Smørgrav 
99b7579f77SDag-Erling Smørgrav /**
100e2d15004SDag-Erling Smørgrav  * The internal event structure for keeping ub_event info for the event.
101b7579f77SDag-Erling Smørgrav  * Possibly other structures (list, tree) this is part of.
102b7579f77SDag-Erling Smørgrav  */
103b7579f77SDag-Erling Smørgrav struct internal_event {
104b7579f77SDag-Erling Smørgrav 	/** the comm base */
105b7579f77SDag-Erling Smørgrav 	struct comm_base* base;
106e2d15004SDag-Erling Smørgrav 	/** ub_event event type */
107e2d15004SDag-Erling Smørgrav 	struct ub_event* ev;
108b7579f77SDag-Erling Smørgrav };
109b7579f77SDag-Erling Smørgrav 
110b7579f77SDag-Erling Smørgrav /**
111b7579f77SDag-Erling Smørgrav  * Internal base structure, so that every thread has its own events.
112b7579f77SDag-Erling Smørgrav  */
113b7579f77SDag-Erling Smørgrav struct internal_base {
114e2d15004SDag-Erling Smørgrav 	/** ub_event event_base type. */
115e2d15004SDag-Erling Smørgrav 	struct ub_event_base* base;
116b7579f77SDag-Erling Smørgrav 	/** seconds time pointer points here */
11717d15b25SDag-Erling Smørgrav 	time_t secs;
118b7579f77SDag-Erling Smørgrav 	/** timeval with current time */
119b7579f77SDag-Erling Smørgrav 	struct timeval now;
120b7579f77SDag-Erling Smørgrav 	/** the event used for slow_accept timeouts */
121e2d15004SDag-Erling Smørgrav 	struct ub_event* slow_accept;
122b7579f77SDag-Erling Smørgrav 	/** true if slow_accept is enabled */
123b7579f77SDag-Erling Smørgrav 	int slow_accept_enabled;
124b7579f77SDag-Erling Smørgrav };
125b7579f77SDag-Erling Smørgrav 
126b7579f77SDag-Erling Smørgrav /**
127b7579f77SDag-Erling Smørgrav  * Internal timer structure, to store timer event in.
128b7579f77SDag-Erling Smørgrav  */
129b7579f77SDag-Erling Smørgrav struct internal_timer {
130e2d15004SDag-Erling Smørgrav 	/** the super struct from which derived */
131e2d15004SDag-Erling Smørgrav 	struct comm_timer super;
132b7579f77SDag-Erling Smørgrav 	/** the comm base */
133b7579f77SDag-Erling Smørgrav 	struct comm_base* base;
134e2d15004SDag-Erling Smørgrav 	/** ub_event event type */
135e2d15004SDag-Erling Smørgrav 	struct ub_event* ev;
136b7579f77SDag-Erling Smørgrav 	/** is timer enabled */
137b7579f77SDag-Erling Smørgrav 	uint8_t enabled;
138b7579f77SDag-Erling Smørgrav };
139b7579f77SDag-Erling Smørgrav 
140b7579f77SDag-Erling Smørgrav /**
141b7579f77SDag-Erling Smørgrav  * Internal signal structure, to store signal event in.
142b7579f77SDag-Erling Smørgrav  */
143b7579f77SDag-Erling Smørgrav struct internal_signal {
144e2d15004SDag-Erling Smørgrav 	/** ub_event event type */
145e2d15004SDag-Erling Smørgrav 	struct ub_event* ev;
146b7579f77SDag-Erling Smørgrav 	/** next in signal list */
147b7579f77SDag-Erling Smørgrav 	struct internal_signal* next;
148b7579f77SDag-Erling Smørgrav };
149b7579f77SDag-Erling Smørgrav 
150b7579f77SDag-Erling Smørgrav /** create a tcp handler with a parent */
151b7579f77SDag-Erling Smørgrav static struct comm_point* comm_point_create_tcp_handler(
152b7579f77SDag-Erling Smørgrav 	struct comm_base *base, struct comm_point* parent, size_t bufsize,
1533005e0a3SDag-Erling Smørgrav         comm_point_callback_type* callback, void* callback_arg);
154b7579f77SDag-Erling Smørgrav 
155b7579f77SDag-Erling Smørgrav /* -------- End of local definitions -------- */
156b7579f77SDag-Erling Smørgrav 
157b7579f77SDag-Erling Smørgrav struct comm_base*
158b7579f77SDag-Erling Smørgrav comm_base_create(int sigs)
159b7579f77SDag-Erling Smørgrav {
160b7579f77SDag-Erling Smørgrav 	struct comm_base* b = (struct comm_base*)calloc(1,
161b7579f77SDag-Erling Smørgrav 		sizeof(struct comm_base));
162e2d15004SDag-Erling Smørgrav 	const char *evnm="event", *evsys="", *evmethod="";
163e2d15004SDag-Erling Smørgrav 
164b7579f77SDag-Erling Smørgrav 	if(!b)
165b7579f77SDag-Erling Smørgrav 		return NULL;
166b7579f77SDag-Erling Smørgrav 	b->eb = (struct internal_base*)calloc(1, sizeof(struct internal_base));
167b7579f77SDag-Erling Smørgrav 	if(!b->eb) {
168b7579f77SDag-Erling Smørgrav 		free(b);
169b7579f77SDag-Erling Smørgrav 		return NULL;
170b7579f77SDag-Erling Smørgrav 	}
171e2d15004SDag-Erling Smørgrav 	b->eb->base = ub_default_event_base(sigs, &b->eb->secs, &b->eb->now);
172b7579f77SDag-Erling Smørgrav 	if(!b->eb->base) {
173b7579f77SDag-Erling Smørgrav 		free(b->eb);
174b7579f77SDag-Erling Smørgrav 		free(b);
175b7579f77SDag-Erling Smørgrav 		return NULL;
176b7579f77SDag-Erling Smørgrav 	}
177e2d15004SDag-Erling Smørgrav 	ub_comm_base_now(b);
178e2d15004SDag-Erling Smørgrav 	ub_get_event_sys(b->eb->base, &evnm, &evsys, &evmethod);
179e2d15004SDag-Erling Smørgrav 	verbose(VERB_ALGO, "%s %s user %s method.", evnm, evsys, evmethod);
180b7579f77SDag-Erling Smørgrav 	return b;
181b7579f77SDag-Erling Smørgrav }
182b7579f77SDag-Erling Smørgrav 
18317d15b25SDag-Erling Smørgrav struct comm_base*
184e2d15004SDag-Erling Smørgrav comm_base_create_event(struct ub_event_base* base)
18517d15b25SDag-Erling Smørgrav {
18617d15b25SDag-Erling Smørgrav 	struct comm_base* b = (struct comm_base*)calloc(1,
18717d15b25SDag-Erling Smørgrav 		sizeof(struct comm_base));
18817d15b25SDag-Erling Smørgrav 	if(!b)
18917d15b25SDag-Erling Smørgrav 		return NULL;
19017d15b25SDag-Erling Smørgrav 	b->eb = (struct internal_base*)calloc(1, sizeof(struct internal_base));
19117d15b25SDag-Erling Smørgrav 	if(!b->eb) {
19217d15b25SDag-Erling Smørgrav 		free(b);
19317d15b25SDag-Erling Smørgrav 		return NULL;
19417d15b25SDag-Erling Smørgrav 	}
19517d15b25SDag-Erling Smørgrav 	b->eb->base = base;
196e2d15004SDag-Erling Smørgrav 	ub_comm_base_now(b);
19717d15b25SDag-Erling Smørgrav 	return b;
19817d15b25SDag-Erling Smørgrav }
19917d15b25SDag-Erling Smørgrav 
200b7579f77SDag-Erling Smørgrav void
201b7579f77SDag-Erling Smørgrav comm_base_delete(struct comm_base* b)
202b7579f77SDag-Erling Smørgrav {
203b7579f77SDag-Erling Smørgrav 	if(!b)
204b7579f77SDag-Erling Smørgrav 		return;
205b7579f77SDag-Erling Smørgrav 	if(b->eb->slow_accept_enabled) {
206e2d15004SDag-Erling Smørgrav 		if(ub_event_del(b->eb->slow_accept) != 0) {
207b7579f77SDag-Erling Smørgrav 			log_err("could not event_del slow_accept");
208b7579f77SDag-Erling Smørgrav 		}
209e2d15004SDag-Erling Smørgrav 		ub_event_free(b->eb->slow_accept);
210b7579f77SDag-Erling Smørgrav 	}
211e2d15004SDag-Erling Smørgrav 	ub_event_base_free(b->eb->base);
212b7579f77SDag-Erling Smørgrav 	b->eb->base = NULL;
213b7579f77SDag-Erling Smørgrav 	free(b->eb);
214b7579f77SDag-Erling Smørgrav 	free(b);
215b7579f77SDag-Erling Smørgrav }
216b7579f77SDag-Erling Smørgrav 
217b7579f77SDag-Erling Smørgrav void
21817d15b25SDag-Erling Smørgrav comm_base_delete_no_base(struct comm_base* b)
21917d15b25SDag-Erling Smørgrav {
22017d15b25SDag-Erling Smørgrav 	if(!b)
22117d15b25SDag-Erling Smørgrav 		return;
22217d15b25SDag-Erling Smørgrav 	if(b->eb->slow_accept_enabled) {
223e2d15004SDag-Erling Smørgrav 		if(ub_event_del(b->eb->slow_accept) != 0) {
22417d15b25SDag-Erling Smørgrav 			log_err("could not event_del slow_accept");
22517d15b25SDag-Erling Smørgrav 		}
226e2d15004SDag-Erling Smørgrav 		ub_event_free(b->eb->slow_accept);
22717d15b25SDag-Erling Smørgrav 	}
22817d15b25SDag-Erling Smørgrav 	b->eb->base = NULL;
22917d15b25SDag-Erling Smørgrav 	free(b->eb);
23017d15b25SDag-Erling Smørgrav 	free(b);
23117d15b25SDag-Erling Smørgrav }
23217d15b25SDag-Erling Smørgrav 
23317d15b25SDag-Erling Smørgrav void
23417d15b25SDag-Erling Smørgrav comm_base_timept(struct comm_base* b, time_t** tt, struct timeval** tv)
235b7579f77SDag-Erling Smørgrav {
236b7579f77SDag-Erling Smørgrav 	*tt = &b->eb->secs;
237b7579f77SDag-Erling Smørgrav 	*tv = &b->eb->now;
238b7579f77SDag-Erling Smørgrav }
239b7579f77SDag-Erling Smørgrav 
240b7579f77SDag-Erling Smørgrav void
241b7579f77SDag-Erling Smørgrav comm_base_dispatch(struct comm_base* b)
242b7579f77SDag-Erling Smørgrav {
243b7579f77SDag-Erling Smørgrav 	int retval;
244e2d15004SDag-Erling Smørgrav 	retval = ub_event_base_dispatch(b->eb->base);
245e2d15004SDag-Erling Smørgrav 	if(retval < 0) {
246b7579f77SDag-Erling Smørgrav 		fatal_exit("event_dispatch returned error %d, "
247b7579f77SDag-Erling Smørgrav 			"errno is %s", retval, strerror(errno));
248b7579f77SDag-Erling Smørgrav 	}
249b7579f77SDag-Erling Smørgrav }
250b7579f77SDag-Erling Smørgrav 
251b7579f77SDag-Erling Smørgrav void comm_base_exit(struct comm_base* b)
252b7579f77SDag-Erling Smørgrav {
253e2d15004SDag-Erling Smørgrav 	if(ub_event_base_loopexit(b->eb->base) != 0) {
254b7579f77SDag-Erling Smørgrav 		log_err("Could not loopexit");
255b7579f77SDag-Erling Smørgrav 	}
256b7579f77SDag-Erling Smørgrav }
257b7579f77SDag-Erling Smørgrav 
258b7579f77SDag-Erling Smørgrav void comm_base_set_slow_accept_handlers(struct comm_base* b,
259b7579f77SDag-Erling Smørgrav 	void (*stop_acc)(void*), void (*start_acc)(void*), void* arg)
260b7579f77SDag-Erling Smørgrav {
261b7579f77SDag-Erling Smørgrav 	b->stop_accept = stop_acc;
262b7579f77SDag-Erling Smørgrav 	b->start_accept = start_acc;
263b7579f77SDag-Erling Smørgrav 	b->cb_arg = arg;
264b7579f77SDag-Erling Smørgrav }
265b7579f77SDag-Erling Smørgrav 
266e2d15004SDag-Erling Smørgrav struct ub_event_base* comm_base_internal(struct comm_base* b)
267b7579f77SDag-Erling Smørgrav {
268b7579f77SDag-Erling Smørgrav 	return b->eb->base;
269b7579f77SDag-Erling Smørgrav }
270b7579f77SDag-Erling Smørgrav 
271b7579f77SDag-Erling Smørgrav /** see if errno for udp has to be logged or not uses globals */
272b7579f77SDag-Erling Smørgrav static int
273b7579f77SDag-Erling Smørgrav udp_send_errno_needs_log(struct sockaddr* addr, socklen_t addrlen)
274b7579f77SDag-Erling Smørgrav {
275b7579f77SDag-Erling Smørgrav 	/* do not log transient errors (unless high verbosity) */
276b7579f77SDag-Erling Smørgrav #if defined(ENETUNREACH) || defined(EHOSTDOWN) || defined(EHOSTUNREACH) || defined(ENETDOWN)
277b7579f77SDag-Erling Smørgrav 	switch(errno) {
278b7579f77SDag-Erling Smørgrav #  ifdef ENETUNREACH
279b7579f77SDag-Erling Smørgrav 		case ENETUNREACH:
280b7579f77SDag-Erling Smørgrav #  endif
281b7579f77SDag-Erling Smørgrav #  ifdef EHOSTDOWN
282b7579f77SDag-Erling Smørgrav 		case EHOSTDOWN:
283b7579f77SDag-Erling Smørgrav #  endif
284b7579f77SDag-Erling Smørgrav #  ifdef EHOSTUNREACH
285b7579f77SDag-Erling Smørgrav 		case EHOSTUNREACH:
286b7579f77SDag-Erling Smørgrav #  endif
287b7579f77SDag-Erling Smørgrav #  ifdef ENETDOWN
288b7579f77SDag-Erling Smørgrav 		case ENETDOWN:
289b7579f77SDag-Erling Smørgrav #  endif
290b7579f77SDag-Erling Smørgrav 			if(verbosity < VERB_ALGO)
291b7579f77SDag-Erling Smørgrav 				return 0;
292b7579f77SDag-Erling Smørgrav 		default:
293b7579f77SDag-Erling Smørgrav 			break;
294b7579f77SDag-Erling Smørgrav 	}
295b7579f77SDag-Erling Smørgrav #endif
29617d15b25SDag-Erling Smørgrav 	/* permission denied is gotten for every send if the
29717d15b25SDag-Erling Smørgrav 	 * network is disconnected (on some OS), squelch it */
298f61ef7f6SDag-Erling Smørgrav 	if( ((errno == EPERM)
299f61ef7f6SDag-Erling Smørgrav #  ifdef EADDRNOTAVAIL
300f61ef7f6SDag-Erling Smørgrav 		/* 'Cannot assign requested address' also when disconnected */
301f61ef7f6SDag-Erling Smørgrav 		|| (errno == EADDRNOTAVAIL)
302f61ef7f6SDag-Erling Smørgrav #  endif
303f61ef7f6SDag-Erling Smørgrav 		) && verbosity < VERB_DETAIL)
30417d15b25SDag-Erling Smørgrav 		return 0;
30557bddd21SDag-Erling Smørgrav #  ifdef EADDRINUSE
30657bddd21SDag-Erling Smørgrav 	/* If SO_REUSEADDR is set, we could try to connect to the same server
30757bddd21SDag-Erling Smørgrav 	 * from the same source port twice. */
30857bddd21SDag-Erling Smørgrav 	if(errno == EADDRINUSE && verbosity < VERB_DETAIL)
30957bddd21SDag-Erling Smørgrav 		return 0;
31057bddd21SDag-Erling Smørgrav #  endif
311b7579f77SDag-Erling Smørgrav 	/* squelch errors where people deploy AAAA ::ffff:bla for
312b7579f77SDag-Erling Smørgrav 	 * authority servers, which we try for intranets. */
313b7579f77SDag-Erling Smørgrav 	if(errno == EINVAL && addr_is_ip4mapped(
314b7579f77SDag-Erling Smørgrav 		(struct sockaddr_storage*)addr, addrlen) &&
315b7579f77SDag-Erling Smørgrav 		verbosity < VERB_DETAIL)
316b7579f77SDag-Erling Smørgrav 		return 0;
317b7579f77SDag-Erling Smørgrav 	/* SO_BROADCAST sockopt can give access to 255.255.255.255,
318b7579f77SDag-Erling Smørgrav 	 * but a dns cache does not need it. */
319b7579f77SDag-Erling Smørgrav 	if(errno == EACCES && addr_is_broadcast(
320b7579f77SDag-Erling Smørgrav 		(struct sockaddr_storage*)addr, addrlen) &&
321b7579f77SDag-Erling Smørgrav 		verbosity < VERB_DETAIL)
322b7579f77SDag-Erling Smørgrav 		return 0;
323b7579f77SDag-Erling Smørgrav 	return 1;
324b7579f77SDag-Erling Smørgrav }
325b7579f77SDag-Erling Smørgrav 
326b7579f77SDag-Erling Smørgrav int tcp_connect_errno_needs_log(struct sockaddr* addr, socklen_t addrlen)
327b7579f77SDag-Erling Smørgrav {
328b7579f77SDag-Erling Smørgrav 	return udp_send_errno_needs_log(addr, addrlen);
329b7579f77SDag-Erling Smørgrav }
330b7579f77SDag-Erling Smørgrav 
331b7579f77SDag-Erling Smørgrav /* send a UDP reply */
332b7579f77SDag-Erling Smørgrav int
33317d15b25SDag-Erling Smørgrav comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet,
334b7579f77SDag-Erling Smørgrav 	struct sockaddr* addr, socklen_t addrlen)
335b7579f77SDag-Erling Smørgrav {
336b7579f77SDag-Erling Smørgrav 	ssize_t sent;
337b7579f77SDag-Erling Smørgrav 	log_assert(c->fd != -1);
338b7579f77SDag-Erling Smørgrav #ifdef UNBOUND_DEBUG
33917d15b25SDag-Erling Smørgrav 	if(sldns_buffer_remaining(packet) == 0)
340b7579f77SDag-Erling Smørgrav 		log_err("error: send empty UDP packet");
341b7579f77SDag-Erling Smørgrav #endif
342b7579f77SDag-Erling Smørgrav 	log_assert(addr && addrlen > 0);
34317d15b25SDag-Erling Smørgrav 	sent = sendto(c->fd, (void*)sldns_buffer_begin(packet),
34417d15b25SDag-Erling Smørgrav 		sldns_buffer_remaining(packet), 0,
345b7579f77SDag-Erling Smørgrav 		addr, addrlen);
346b7579f77SDag-Erling Smørgrav 	if(sent == -1) {
347f61ef7f6SDag-Erling Smørgrav 		/* try again and block, waiting for IO to complete,
348f61ef7f6SDag-Erling Smørgrav 		 * we want to send the answer, and we will wait for
349f61ef7f6SDag-Erling Smørgrav 		 * the ethernet interface buffer to have space. */
350f61ef7f6SDag-Erling Smørgrav #ifndef USE_WINSOCK
351f61ef7f6SDag-Erling Smørgrav 		if(errno == EAGAIN ||
352f61ef7f6SDag-Erling Smørgrav #  ifdef EWOULDBLOCK
353f61ef7f6SDag-Erling Smørgrav 			errno == EWOULDBLOCK ||
354f61ef7f6SDag-Erling Smørgrav #  endif
355f61ef7f6SDag-Erling Smørgrav 			errno == ENOBUFS) {
356f61ef7f6SDag-Erling Smørgrav #else
357f61ef7f6SDag-Erling Smørgrav 		if(WSAGetLastError() == WSAEINPROGRESS ||
358f61ef7f6SDag-Erling Smørgrav 			WSAGetLastError() == WSAENOBUFS ||
359f61ef7f6SDag-Erling Smørgrav 			WSAGetLastError() == WSAEWOULDBLOCK) {
360f61ef7f6SDag-Erling Smørgrav #endif
361f61ef7f6SDag-Erling Smørgrav 			int e;
362f61ef7f6SDag-Erling Smørgrav 			fd_set_block(c->fd);
363f61ef7f6SDag-Erling Smørgrav 			sent = sendto(c->fd, (void*)sldns_buffer_begin(packet),
364f61ef7f6SDag-Erling Smørgrav 				sldns_buffer_remaining(packet), 0,
365f61ef7f6SDag-Erling Smørgrav 				addr, addrlen);
366f61ef7f6SDag-Erling Smørgrav 			e = errno;
367f61ef7f6SDag-Erling Smørgrav 			fd_set_nonblock(c->fd);
368f61ef7f6SDag-Erling Smørgrav 			errno = e;
369f61ef7f6SDag-Erling Smørgrav 		}
370f61ef7f6SDag-Erling Smørgrav 	}
371f61ef7f6SDag-Erling Smørgrav 	if(sent == -1) {
372b7579f77SDag-Erling Smørgrav 		if(!udp_send_errno_needs_log(addr, addrlen))
373b7579f77SDag-Erling Smørgrav 			return 0;
374b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK
375b7579f77SDag-Erling Smørgrav 		verbose(VERB_OPS, "sendto failed: %s", strerror(errno));
376b7579f77SDag-Erling Smørgrav #else
377b7579f77SDag-Erling Smørgrav 		verbose(VERB_OPS, "sendto failed: %s",
378b7579f77SDag-Erling Smørgrav 			wsa_strerror(WSAGetLastError()));
379b7579f77SDag-Erling Smørgrav #endif
380b7579f77SDag-Erling Smørgrav 		log_addr(VERB_OPS, "remote address is",
381b7579f77SDag-Erling Smørgrav 			(struct sockaddr_storage*)addr, addrlen);
382b7579f77SDag-Erling Smørgrav 		return 0;
38317d15b25SDag-Erling Smørgrav 	} else if((size_t)sent != sldns_buffer_remaining(packet)) {
384b7579f77SDag-Erling Smørgrav 		log_err("sent %d in place of %d bytes",
38517d15b25SDag-Erling Smørgrav 			(int)sent, (int)sldns_buffer_remaining(packet));
386b7579f77SDag-Erling Smørgrav 		return 0;
387b7579f77SDag-Erling Smørgrav 	}
388b7579f77SDag-Erling Smørgrav 	return 1;
389b7579f77SDag-Erling Smørgrav }
390b7579f77SDag-Erling Smørgrav 
391b7579f77SDag-Erling Smørgrav #if defined(AF_INET6) && defined(IPV6_PKTINFO) && (defined(HAVE_RECVMSG) || defined(HAVE_SENDMSG))
392b7579f77SDag-Erling Smørgrav /** print debug ancillary info */
393b7579f77SDag-Erling Smørgrav static void p_ancil(const char* str, struct comm_reply* r)
394b7579f77SDag-Erling Smørgrav {
395b7579f77SDag-Erling Smørgrav 	if(r->srctype != 4 && r->srctype != 6) {
396b7579f77SDag-Erling Smørgrav 		log_info("%s: unknown srctype %d", str, r->srctype);
397b7579f77SDag-Erling Smørgrav 		return;
398b7579f77SDag-Erling Smørgrav 	}
399b7579f77SDag-Erling Smørgrav 	if(r->srctype == 6) {
400b7579f77SDag-Erling Smørgrav 		char buf[1024];
401b7579f77SDag-Erling Smørgrav 		if(inet_ntop(AF_INET6, &r->pktinfo.v6info.ipi6_addr,
402b7579f77SDag-Erling Smørgrav 			buf, (socklen_t)sizeof(buf)) == 0) {
40317d15b25SDag-Erling Smørgrav 			(void)strlcpy(buf, "(inet_ntop error)", sizeof(buf));
404b7579f77SDag-Erling Smørgrav 		}
405b7579f77SDag-Erling Smørgrav 		buf[sizeof(buf)-1]=0;
406b7579f77SDag-Erling Smørgrav 		log_info("%s: %s %d", str, buf, r->pktinfo.v6info.ipi6_ifindex);
407b7579f77SDag-Erling Smørgrav 	} else if(r->srctype == 4) {
408b7579f77SDag-Erling Smørgrav #ifdef IP_PKTINFO
409b7579f77SDag-Erling Smørgrav 		char buf1[1024], buf2[1024];
410b7579f77SDag-Erling Smørgrav 		if(inet_ntop(AF_INET, &r->pktinfo.v4info.ipi_addr,
411b7579f77SDag-Erling Smørgrav 			buf1, (socklen_t)sizeof(buf1)) == 0) {
41217d15b25SDag-Erling Smørgrav 			(void)strlcpy(buf1, "(inet_ntop error)", sizeof(buf1));
413b7579f77SDag-Erling Smørgrav 		}
414b7579f77SDag-Erling Smørgrav 		buf1[sizeof(buf1)-1]=0;
415b7579f77SDag-Erling Smørgrav #ifdef HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST
416b7579f77SDag-Erling Smørgrav 		if(inet_ntop(AF_INET, &r->pktinfo.v4info.ipi_spec_dst,
417b7579f77SDag-Erling Smørgrav 			buf2, (socklen_t)sizeof(buf2)) == 0) {
41817d15b25SDag-Erling Smørgrav 			(void)strlcpy(buf2, "(inet_ntop error)", sizeof(buf2));
419b7579f77SDag-Erling Smørgrav 		}
420b7579f77SDag-Erling Smørgrav 		buf2[sizeof(buf2)-1]=0;
421b7579f77SDag-Erling Smørgrav #else
422b7579f77SDag-Erling Smørgrav 		buf2[0]=0;
423b7579f77SDag-Erling Smørgrav #endif
424b7579f77SDag-Erling Smørgrav 		log_info("%s: %d %s %s", str, r->pktinfo.v4info.ipi_ifindex,
425b7579f77SDag-Erling Smørgrav 			buf1, buf2);
426b7579f77SDag-Erling Smørgrav #elif defined(IP_RECVDSTADDR)
427b7579f77SDag-Erling Smørgrav 		char buf1[1024];
428b7579f77SDag-Erling Smørgrav 		if(inet_ntop(AF_INET, &r->pktinfo.v4addr,
429b7579f77SDag-Erling Smørgrav 			buf1, (socklen_t)sizeof(buf1)) == 0) {
43017d15b25SDag-Erling Smørgrav 			(void)strlcpy(buf1, "(inet_ntop error)", sizeof(buf1));
431b7579f77SDag-Erling Smørgrav 		}
432b7579f77SDag-Erling Smørgrav 		buf1[sizeof(buf1)-1]=0;
433b7579f77SDag-Erling Smørgrav 		log_info("%s: %s", str, buf1);
434b7579f77SDag-Erling Smørgrav #endif /* IP_PKTINFO or PI_RECVDSTDADDR */
435b7579f77SDag-Erling Smørgrav 	}
436b7579f77SDag-Erling Smørgrav }
437b7579f77SDag-Erling Smørgrav #endif /* AF_INET6 && IPV6_PKTINFO && HAVE_RECVMSG||HAVE_SENDMSG */
438b7579f77SDag-Erling Smørgrav 
439b7579f77SDag-Erling Smørgrav /** send a UDP reply over specified interface*/
440b7579f77SDag-Erling Smørgrav static int
44117d15b25SDag-Erling Smørgrav comm_point_send_udp_msg_if(struct comm_point *c, sldns_buffer* packet,
442b7579f77SDag-Erling Smørgrav 	struct sockaddr* addr, socklen_t addrlen, struct comm_reply* r)
443b7579f77SDag-Erling Smørgrav {
444b7579f77SDag-Erling Smørgrav #if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_SENDMSG)
445b7579f77SDag-Erling Smørgrav 	ssize_t sent;
446b7579f77SDag-Erling Smørgrav 	struct msghdr msg;
447b7579f77SDag-Erling Smørgrav 	struct iovec iov[1];
448b7579f77SDag-Erling Smørgrav 	char control[256];
449b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S
450b7579f77SDag-Erling Smørgrav 	struct cmsghdr *cmsg;
451b7579f77SDag-Erling Smørgrav #endif /* S_SPLINT_S */
452b7579f77SDag-Erling Smørgrav 
453b7579f77SDag-Erling Smørgrav 	log_assert(c->fd != -1);
454b7579f77SDag-Erling Smørgrav #ifdef UNBOUND_DEBUG
45517d15b25SDag-Erling Smørgrav 	if(sldns_buffer_remaining(packet) == 0)
456b7579f77SDag-Erling Smørgrav 		log_err("error: send empty UDP packet");
457b7579f77SDag-Erling Smørgrav #endif
458b7579f77SDag-Erling Smørgrav 	log_assert(addr && addrlen > 0);
459b7579f77SDag-Erling Smørgrav 
460b7579f77SDag-Erling Smørgrav 	msg.msg_name = addr;
461b7579f77SDag-Erling Smørgrav 	msg.msg_namelen = addrlen;
46217d15b25SDag-Erling Smørgrav 	iov[0].iov_base = sldns_buffer_begin(packet);
46317d15b25SDag-Erling Smørgrav 	iov[0].iov_len = sldns_buffer_remaining(packet);
464b7579f77SDag-Erling Smørgrav 	msg.msg_iov = iov;
465b7579f77SDag-Erling Smørgrav 	msg.msg_iovlen = 1;
466b7579f77SDag-Erling Smørgrav 	msg.msg_control = control;
467b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S
468b7579f77SDag-Erling Smørgrav 	msg.msg_controllen = sizeof(control);
469b7579f77SDag-Erling Smørgrav #endif /* S_SPLINT_S */
470b7579f77SDag-Erling Smørgrav 	msg.msg_flags = 0;
471b7579f77SDag-Erling Smørgrav 
472b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S
473b7579f77SDag-Erling Smørgrav 	cmsg = CMSG_FIRSTHDR(&msg);
474b7579f77SDag-Erling Smørgrav 	if(r->srctype == 4) {
475b7579f77SDag-Erling Smørgrav #ifdef IP_PKTINFO
47609a3aaf3SDag-Erling Smørgrav 		void* cmsg_data;
477b7579f77SDag-Erling Smørgrav 		msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
478b7579f77SDag-Erling Smørgrav 		log_assert(msg.msg_controllen <= sizeof(control));
479b7579f77SDag-Erling Smørgrav 		cmsg->cmsg_level = IPPROTO_IP;
480b7579f77SDag-Erling Smørgrav 		cmsg->cmsg_type = IP_PKTINFO;
481b7579f77SDag-Erling Smørgrav 		memmove(CMSG_DATA(cmsg), &r->pktinfo.v4info,
482b7579f77SDag-Erling Smørgrav 			sizeof(struct in_pktinfo));
48309a3aaf3SDag-Erling Smørgrav 		/* unset the ifindex to not bypass the routing tables */
48409a3aaf3SDag-Erling Smørgrav 		cmsg_data = CMSG_DATA(cmsg);
48509a3aaf3SDag-Erling Smørgrav 		((struct in_pktinfo *) cmsg_data)->ipi_ifindex = 0;
486b7579f77SDag-Erling Smørgrav 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
487b7579f77SDag-Erling Smørgrav #elif defined(IP_SENDSRCADDR)
488b7579f77SDag-Erling Smørgrav 		msg.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
489b7579f77SDag-Erling Smørgrav 		log_assert(msg.msg_controllen <= sizeof(control));
490b7579f77SDag-Erling Smørgrav 		cmsg->cmsg_level = IPPROTO_IP;
491b7579f77SDag-Erling Smørgrav 		cmsg->cmsg_type = IP_SENDSRCADDR;
492b7579f77SDag-Erling Smørgrav 		memmove(CMSG_DATA(cmsg), &r->pktinfo.v4addr,
493b7579f77SDag-Erling Smørgrav 			sizeof(struct in_addr));
494b7579f77SDag-Erling Smørgrav 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
495b7579f77SDag-Erling Smørgrav #else
496b7579f77SDag-Erling Smørgrav 		verbose(VERB_ALGO, "no IP_PKTINFO or IP_SENDSRCADDR");
497b7579f77SDag-Erling Smørgrav 		msg.msg_control = NULL;
498b7579f77SDag-Erling Smørgrav #endif /* IP_PKTINFO or IP_SENDSRCADDR */
499b7579f77SDag-Erling Smørgrav 	} else if(r->srctype == 6) {
50009a3aaf3SDag-Erling Smørgrav 		void* cmsg_data;
501b7579f77SDag-Erling Smørgrav 		msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
502b7579f77SDag-Erling Smørgrav 		log_assert(msg.msg_controllen <= sizeof(control));
503b7579f77SDag-Erling Smørgrav 		cmsg->cmsg_level = IPPROTO_IPV6;
504b7579f77SDag-Erling Smørgrav 		cmsg->cmsg_type = IPV6_PKTINFO;
505b7579f77SDag-Erling Smørgrav 		memmove(CMSG_DATA(cmsg), &r->pktinfo.v6info,
506b7579f77SDag-Erling Smørgrav 			sizeof(struct in6_pktinfo));
50709a3aaf3SDag-Erling Smørgrav 		/* unset the ifindex to not bypass the routing tables */
50809a3aaf3SDag-Erling Smørgrav 		cmsg_data = CMSG_DATA(cmsg);
50909a3aaf3SDag-Erling Smørgrav 		((struct in6_pktinfo *) cmsg_data)->ipi6_ifindex = 0;
510b7579f77SDag-Erling Smørgrav 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
511b7579f77SDag-Erling Smørgrav 	} else {
512b7579f77SDag-Erling Smørgrav 		/* try to pass all 0 to use default route */
513b7579f77SDag-Erling Smørgrav 		msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
514b7579f77SDag-Erling Smørgrav 		log_assert(msg.msg_controllen <= sizeof(control));
515b7579f77SDag-Erling Smørgrav 		cmsg->cmsg_level = IPPROTO_IPV6;
516b7579f77SDag-Erling Smørgrav 		cmsg->cmsg_type = IPV6_PKTINFO;
517b7579f77SDag-Erling Smørgrav 		memset(CMSG_DATA(cmsg), 0, sizeof(struct in6_pktinfo));
518b7579f77SDag-Erling Smørgrav 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
519b7579f77SDag-Erling Smørgrav 	}
520b7579f77SDag-Erling Smørgrav #endif /* S_SPLINT_S */
521b7579f77SDag-Erling Smørgrav 	if(verbosity >= VERB_ALGO)
522b7579f77SDag-Erling Smørgrav 		p_ancil("send_udp over interface", r);
523b7579f77SDag-Erling Smørgrav 	sent = sendmsg(c->fd, &msg, 0);
524b7579f77SDag-Erling Smørgrav 	if(sent == -1) {
525f61ef7f6SDag-Erling Smørgrav 		/* try again and block, waiting for IO to complete,
526f61ef7f6SDag-Erling Smørgrav 		 * we want to send the answer, and we will wait for
527f61ef7f6SDag-Erling Smørgrav 		 * the ethernet interface buffer to have space. */
528f61ef7f6SDag-Erling Smørgrav #ifndef USE_WINSOCK
529f61ef7f6SDag-Erling Smørgrav 		if(errno == EAGAIN ||
530f61ef7f6SDag-Erling Smørgrav #  ifdef EWOULDBLOCK
531f61ef7f6SDag-Erling Smørgrav 			errno == EWOULDBLOCK ||
532f61ef7f6SDag-Erling Smørgrav #  endif
533f61ef7f6SDag-Erling Smørgrav 			errno == ENOBUFS) {
534f61ef7f6SDag-Erling Smørgrav #else
535f61ef7f6SDag-Erling Smørgrav 		if(WSAGetLastError() == WSAEINPROGRESS ||
536f61ef7f6SDag-Erling Smørgrav 			WSAGetLastError() == WSAENOBUFS ||
537f61ef7f6SDag-Erling Smørgrav 			WSAGetLastError() == WSAEWOULDBLOCK) {
538f61ef7f6SDag-Erling Smørgrav #endif
539f61ef7f6SDag-Erling Smørgrav 			int e;
540f61ef7f6SDag-Erling Smørgrav 			fd_set_block(c->fd);
541f61ef7f6SDag-Erling Smørgrav 			sent = sendmsg(c->fd, &msg, 0);
542f61ef7f6SDag-Erling Smørgrav 			e = errno;
543f61ef7f6SDag-Erling Smørgrav 			fd_set_nonblock(c->fd);
544f61ef7f6SDag-Erling Smørgrav 			errno = e;
545f61ef7f6SDag-Erling Smørgrav 		}
546f61ef7f6SDag-Erling Smørgrav 	}
547f61ef7f6SDag-Erling Smørgrav 	if(sent == -1) {
548b7579f77SDag-Erling Smørgrav 		if(!udp_send_errno_needs_log(addr, addrlen))
549b7579f77SDag-Erling Smørgrav 			return 0;
550b7579f77SDag-Erling Smørgrav 		verbose(VERB_OPS, "sendmsg failed: %s", strerror(errno));
551b7579f77SDag-Erling Smørgrav 		log_addr(VERB_OPS, "remote address is",
552b7579f77SDag-Erling Smørgrav 			(struct sockaddr_storage*)addr, addrlen);
553f61ef7f6SDag-Erling Smørgrav #ifdef __NetBSD__
554f61ef7f6SDag-Erling Smørgrav 		/* netbsd 7 has IP_PKTINFO for recv but not send */
555f61ef7f6SDag-Erling Smørgrav 		if(errno == EINVAL && r->srctype == 4)
556f61ef7f6SDag-Erling Smørgrav 			log_err("sendmsg: No support for sendmsg(IP_PKTINFO). "
557f61ef7f6SDag-Erling Smørgrav 				"Please disable interface-automatic");
558f61ef7f6SDag-Erling Smørgrav #endif
559b7579f77SDag-Erling Smørgrav 		return 0;
56017d15b25SDag-Erling Smørgrav 	} else if((size_t)sent != sldns_buffer_remaining(packet)) {
561b7579f77SDag-Erling Smørgrav 		log_err("sent %d in place of %d bytes",
56217d15b25SDag-Erling Smørgrav 			(int)sent, (int)sldns_buffer_remaining(packet));
563b7579f77SDag-Erling Smørgrav 		return 0;
564b7579f77SDag-Erling Smørgrav 	}
565b7579f77SDag-Erling Smørgrav 	return 1;
566b7579f77SDag-Erling Smørgrav #else
567b7579f77SDag-Erling Smørgrav 	(void)c;
568b7579f77SDag-Erling Smørgrav 	(void)packet;
569b7579f77SDag-Erling Smørgrav 	(void)addr;
570b7579f77SDag-Erling Smørgrav 	(void)addrlen;
571b7579f77SDag-Erling Smørgrav 	(void)r;
572b7579f77SDag-Erling Smørgrav 	log_err("sendmsg: IPV6_PKTINFO not supported");
573b7579f77SDag-Erling Smørgrav 	return 0;
574b7579f77SDag-Erling Smørgrav #endif /* AF_INET6 && IPV6_PKTINFO && HAVE_SENDMSG */
575b7579f77SDag-Erling Smørgrav }
576b7579f77SDag-Erling Smørgrav 
577b7579f77SDag-Erling Smørgrav void
578b7579f77SDag-Erling Smørgrav comm_point_udp_ancil_callback(int fd, short event, void* arg)
579b7579f77SDag-Erling Smørgrav {
580b7579f77SDag-Erling Smørgrav #if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG)
581b7579f77SDag-Erling Smørgrav 	struct comm_reply rep;
582b7579f77SDag-Erling Smørgrav 	struct msghdr msg;
583b7579f77SDag-Erling Smørgrav 	struct iovec iov[1];
584b7579f77SDag-Erling Smørgrav 	ssize_t rcv;
585b7579f77SDag-Erling Smørgrav 	char ancil[256];
586b7579f77SDag-Erling Smørgrav 	int i;
587b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S
588b7579f77SDag-Erling Smørgrav 	struct cmsghdr* cmsg;
589b7579f77SDag-Erling Smørgrav #endif /* S_SPLINT_S */
590b7579f77SDag-Erling Smørgrav 
591b7579f77SDag-Erling Smørgrav 	rep.c = (struct comm_point*)arg;
592b7579f77SDag-Erling Smørgrav 	log_assert(rep.c->type == comm_udp);
593b7579f77SDag-Erling Smørgrav 
594e2d15004SDag-Erling Smørgrav 	if(!(event&UB_EV_READ))
595b7579f77SDag-Erling Smørgrav 		return;
596b7579f77SDag-Erling Smørgrav 	log_assert(rep.c && rep.c->buffer && rep.c->fd == fd);
597e2d15004SDag-Erling Smørgrav 	ub_comm_base_now(rep.c->ev->base);
598b7579f77SDag-Erling Smørgrav 	for(i=0; i<NUM_UDP_PER_SELECT; i++) {
59917d15b25SDag-Erling Smørgrav 		sldns_buffer_clear(rep.c->buffer);
600b7579f77SDag-Erling Smørgrav 		rep.addrlen = (socklen_t)sizeof(rep.addr);
601b7579f77SDag-Erling Smørgrav 		log_assert(fd != -1);
60217d15b25SDag-Erling Smørgrav 		log_assert(sldns_buffer_remaining(rep.c->buffer) > 0);
603b7579f77SDag-Erling Smørgrav 		msg.msg_name = &rep.addr;
604b7579f77SDag-Erling Smørgrav 		msg.msg_namelen = (socklen_t)sizeof(rep.addr);
60517d15b25SDag-Erling Smørgrav 		iov[0].iov_base = sldns_buffer_begin(rep.c->buffer);
60617d15b25SDag-Erling Smørgrav 		iov[0].iov_len = sldns_buffer_remaining(rep.c->buffer);
607b7579f77SDag-Erling Smørgrav 		msg.msg_iov = iov;
608b7579f77SDag-Erling Smørgrav 		msg.msg_iovlen = 1;
609b7579f77SDag-Erling Smørgrav 		msg.msg_control = ancil;
610b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S
611b7579f77SDag-Erling Smørgrav 		msg.msg_controllen = sizeof(ancil);
612b7579f77SDag-Erling Smørgrav #endif /* S_SPLINT_S */
613b7579f77SDag-Erling Smørgrav 		msg.msg_flags = 0;
614b7579f77SDag-Erling Smørgrav 		rcv = recvmsg(fd, &msg, 0);
615b7579f77SDag-Erling Smørgrav 		if(rcv == -1) {
616b7579f77SDag-Erling Smørgrav 			if(errno != EAGAIN && errno != EINTR) {
617b7579f77SDag-Erling Smørgrav 				log_err("recvmsg failed: %s", strerror(errno));
618b7579f77SDag-Erling Smørgrav 			}
619b7579f77SDag-Erling Smørgrav 			return;
620b7579f77SDag-Erling Smørgrav 		}
621b7579f77SDag-Erling Smørgrav 		rep.addrlen = msg.msg_namelen;
62217d15b25SDag-Erling Smørgrav 		sldns_buffer_skip(rep.c->buffer, rcv);
62317d15b25SDag-Erling Smørgrav 		sldns_buffer_flip(rep.c->buffer);
624b7579f77SDag-Erling Smørgrav 		rep.srctype = 0;
625b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S
626b7579f77SDag-Erling Smørgrav 		for(cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
627b7579f77SDag-Erling Smørgrav 			cmsg = CMSG_NXTHDR(&msg, cmsg)) {
628b7579f77SDag-Erling Smørgrav 			if( cmsg->cmsg_level == IPPROTO_IPV6 &&
629b7579f77SDag-Erling Smørgrav 				cmsg->cmsg_type == IPV6_PKTINFO) {
630b7579f77SDag-Erling Smørgrav 				rep.srctype = 6;
631b7579f77SDag-Erling Smørgrav 				memmove(&rep.pktinfo.v6info, CMSG_DATA(cmsg),
632b7579f77SDag-Erling Smørgrav 					sizeof(struct in6_pktinfo));
633b7579f77SDag-Erling Smørgrav 				break;
634b7579f77SDag-Erling Smørgrav #ifdef IP_PKTINFO
635b7579f77SDag-Erling Smørgrav 			} else if( cmsg->cmsg_level == IPPROTO_IP &&
636b7579f77SDag-Erling Smørgrav 				cmsg->cmsg_type == IP_PKTINFO) {
637b7579f77SDag-Erling Smørgrav 				rep.srctype = 4;
638b7579f77SDag-Erling Smørgrav 				memmove(&rep.pktinfo.v4info, CMSG_DATA(cmsg),
639b7579f77SDag-Erling Smørgrav 					sizeof(struct in_pktinfo));
640b7579f77SDag-Erling Smørgrav 				break;
641b7579f77SDag-Erling Smørgrav #elif defined(IP_RECVDSTADDR)
642b7579f77SDag-Erling Smørgrav 			} else if( cmsg->cmsg_level == IPPROTO_IP &&
643b7579f77SDag-Erling Smørgrav 				cmsg->cmsg_type == IP_RECVDSTADDR) {
644b7579f77SDag-Erling Smørgrav 				rep.srctype = 4;
645b7579f77SDag-Erling Smørgrav 				memmove(&rep.pktinfo.v4addr, CMSG_DATA(cmsg),
646b7579f77SDag-Erling Smørgrav 					sizeof(struct in_addr));
647b7579f77SDag-Erling Smørgrav 				break;
648b7579f77SDag-Erling Smørgrav #endif /* IP_PKTINFO or IP_RECVDSTADDR */
649b7579f77SDag-Erling Smørgrav 			}
650b7579f77SDag-Erling Smørgrav 		}
651b7579f77SDag-Erling Smørgrav 		if(verbosity >= VERB_ALGO)
652b7579f77SDag-Erling Smørgrav 			p_ancil("receive_udp on interface", &rep);
653b7579f77SDag-Erling Smørgrav #endif /* S_SPLINT_S */
654b7579f77SDag-Erling Smørgrav 		fptr_ok(fptr_whitelist_comm_point(rep.c->callback));
655b7579f77SDag-Erling Smørgrav 		if((*rep.c->callback)(rep.c, rep.c->cb_arg, NETEVENT_NOERROR, &rep)) {
656b7579f77SDag-Erling Smørgrav 			/* send back immediate reply */
657b7579f77SDag-Erling Smørgrav 			(void)comm_point_send_udp_msg_if(rep.c, rep.c->buffer,
658b7579f77SDag-Erling Smørgrav 				(struct sockaddr*)&rep.addr, rep.addrlen, &rep);
659b7579f77SDag-Erling Smørgrav 		}
66057bddd21SDag-Erling Smørgrav 		if(!rep.c || rep.c->fd == -1) /* commpoint closed */
661b7579f77SDag-Erling Smørgrav 			break;
662b7579f77SDag-Erling Smørgrav 	}
663b7579f77SDag-Erling Smørgrav #else
664b7579f77SDag-Erling Smørgrav 	(void)fd;
665b7579f77SDag-Erling Smørgrav 	(void)event;
666b7579f77SDag-Erling Smørgrav 	(void)arg;
6673005e0a3SDag-Erling Smørgrav 	fatal_exit("recvmsg: No support for IPV6_PKTINFO; IP_PKTINFO or IP_RECVDSTADDR. "
668b7579f77SDag-Erling Smørgrav 		"Please disable interface-automatic");
669b7579f77SDag-Erling Smørgrav #endif /* AF_INET6 && IPV6_PKTINFO && HAVE_RECVMSG */
670b7579f77SDag-Erling Smørgrav }
671b7579f77SDag-Erling Smørgrav 
672b7579f77SDag-Erling Smørgrav void
673b7579f77SDag-Erling Smørgrav comm_point_udp_callback(int fd, short event, void* arg)
674b7579f77SDag-Erling Smørgrav {
675b7579f77SDag-Erling Smørgrav 	struct comm_reply rep;
676b7579f77SDag-Erling Smørgrav 	ssize_t rcv;
677b7579f77SDag-Erling Smørgrav 	int i;
67865b390aaSDag-Erling Smørgrav 	struct sldns_buffer *buffer;
679b7579f77SDag-Erling Smørgrav 
680b7579f77SDag-Erling Smørgrav 	rep.c = (struct comm_point*)arg;
681b7579f77SDag-Erling Smørgrav 	log_assert(rep.c->type == comm_udp);
682b7579f77SDag-Erling Smørgrav 
683e2d15004SDag-Erling Smørgrav 	if(!(event&UB_EV_READ))
684b7579f77SDag-Erling Smørgrav 		return;
685b7579f77SDag-Erling Smørgrav 	log_assert(rep.c && rep.c->buffer && rep.c->fd == fd);
686e2d15004SDag-Erling Smørgrav 	ub_comm_base_now(rep.c->ev->base);
687b7579f77SDag-Erling Smørgrav 	for(i=0; i<NUM_UDP_PER_SELECT; i++) {
68817d15b25SDag-Erling Smørgrav 		sldns_buffer_clear(rep.c->buffer);
689b7579f77SDag-Erling Smørgrav 		rep.addrlen = (socklen_t)sizeof(rep.addr);
690b7579f77SDag-Erling Smørgrav 		log_assert(fd != -1);
69117d15b25SDag-Erling Smørgrav 		log_assert(sldns_buffer_remaining(rep.c->buffer) > 0);
69217d15b25SDag-Erling Smørgrav 		rcv = recvfrom(fd, (void*)sldns_buffer_begin(rep.c->buffer),
69317d15b25SDag-Erling Smørgrav 			sldns_buffer_remaining(rep.c->buffer), 0,
694b7579f77SDag-Erling Smørgrav 			(struct sockaddr*)&rep.addr, &rep.addrlen);
695b7579f77SDag-Erling Smørgrav 		if(rcv == -1) {
696b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK
697b7579f77SDag-Erling Smørgrav 			if(errno != EAGAIN && errno != EINTR)
698b7579f77SDag-Erling Smørgrav 				log_err("recvfrom %d failed: %s",
699b7579f77SDag-Erling Smørgrav 					fd, strerror(errno));
700b7579f77SDag-Erling Smørgrav #else
701b7579f77SDag-Erling Smørgrav 			if(WSAGetLastError() != WSAEINPROGRESS &&
702b7579f77SDag-Erling Smørgrav 				WSAGetLastError() != WSAECONNRESET &&
703b7579f77SDag-Erling Smørgrav 				WSAGetLastError()!= WSAEWOULDBLOCK)
704b7579f77SDag-Erling Smørgrav 				log_err("recvfrom failed: %s",
705b7579f77SDag-Erling Smørgrav 					wsa_strerror(WSAGetLastError()));
706b7579f77SDag-Erling Smørgrav #endif
707b7579f77SDag-Erling Smørgrav 			return;
708b7579f77SDag-Erling Smørgrav 		}
70917d15b25SDag-Erling Smørgrav 		sldns_buffer_skip(rep.c->buffer, rcv);
71017d15b25SDag-Erling Smørgrav 		sldns_buffer_flip(rep.c->buffer);
711b7579f77SDag-Erling Smørgrav 		rep.srctype = 0;
712b7579f77SDag-Erling Smørgrav 		fptr_ok(fptr_whitelist_comm_point(rep.c->callback));
713b7579f77SDag-Erling Smørgrav 		if((*rep.c->callback)(rep.c, rep.c->cb_arg, NETEVENT_NOERROR, &rep)) {
714b7579f77SDag-Erling Smørgrav 			/* send back immediate reply */
71565b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT
71665b390aaSDag-Erling Smørgrav 			buffer = rep.c->dnscrypt_buffer;
71765b390aaSDag-Erling Smørgrav #else
71865b390aaSDag-Erling Smørgrav 			buffer = rep.c->buffer;
71965b390aaSDag-Erling Smørgrav #endif
72065b390aaSDag-Erling Smørgrav 			(void)comm_point_send_udp_msg(rep.c, buffer,
721b7579f77SDag-Erling Smørgrav 				(struct sockaddr*)&rep.addr, rep.addrlen);
722b7579f77SDag-Erling Smørgrav 		}
72357bddd21SDag-Erling Smørgrav 		if(!rep.c || rep.c->fd != fd) /* commpoint closed to -1 or reused for
724b7579f77SDag-Erling Smørgrav 		another UDP port. Note rep.c cannot be reused with TCP fd. */
725b7579f77SDag-Erling Smørgrav 			break;
726b7579f77SDag-Erling Smørgrav 	}
727b7579f77SDag-Erling Smørgrav }
728b7579f77SDag-Erling Smørgrav 
729b7579f77SDag-Erling Smørgrav /** Use a new tcp handler for new query fd, set to read query */
730b7579f77SDag-Erling Smørgrav static void
731b5663de9SDag-Erling Smørgrav setup_tcp_handler(struct comm_point* c, int fd, int cur, int max)
732b7579f77SDag-Erling Smørgrav {
733*4c75e3aaSDag-Erling Smørgrav 	int handler_usage;
734b7579f77SDag-Erling Smørgrav 	log_assert(c->type == comm_tcp);
735b7579f77SDag-Erling Smørgrav 	log_assert(c->fd == -1);
73617d15b25SDag-Erling Smørgrav 	sldns_buffer_clear(c->buffer);
73765b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT
73865b390aaSDag-Erling Smørgrav 	if (c->dnscrypt)
73965b390aaSDag-Erling Smørgrav 		sldns_buffer_clear(c->dnscrypt_buffer);
74065b390aaSDag-Erling Smørgrav #endif
741b7579f77SDag-Erling Smørgrav 	c->tcp_is_reading = 1;
742b7579f77SDag-Erling Smørgrav 	c->tcp_byte_count = 0;
743b5663de9SDag-Erling Smørgrav 	/* if more than half the tcp handlers are in use, use a shorter
744b5663de9SDag-Erling Smørgrav 	 * timeout for this TCP connection, we need to make space for
745b5663de9SDag-Erling Smørgrav 	 * other connections to be able to get attention */
746*4c75e3aaSDag-Erling Smørgrav 	/* If > 50% TCP handler structures in use, set timeout to 1/100th
747*4c75e3aaSDag-Erling Smørgrav 	 * 	configured value.
748*4c75e3aaSDag-Erling Smørgrav 	 * If > 65%TCP handler structures in use, set to 1/500th configured
749*4c75e3aaSDag-Erling Smørgrav 	 * 	value.
750*4c75e3aaSDag-Erling Smørgrav 	 * If > 80% TCP handler structures in use, set to 0.
751*4c75e3aaSDag-Erling Smørgrav 	 *
752*4c75e3aaSDag-Erling Smørgrav 	 * If the timeout to use falls below 200 milliseconds, an actual
753*4c75e3aaSDag-Erling Smørgrav 	 * timeout of 200ms is used.
754*4c75e3aaSDag-Erling Smørgrav 	 */
755*4c75e3aaSDag-Erling Smørgrav 	handler_usage = (cur * 100) / max;
756*4c75e3aaSDag-Erling Smørgrav 	if(handler_usage > 50 && handler_usage <= 65)
757*4c75e3aaSDag-Erling Smørgrav 		c->tcp_timeout_msec /= 100;
758*4c75e3aaSDag-Erling Smørgrav 	else if (handler_usage > 65 && handler_usage <= 80)
759*4c75e3aaSDag-Erling Smørgrav 		c->tcp_timeout_msec /= 500;
760*4c75e3aaSDag-Erling Smørgrav 	else if (handler_usage > 80)
761*4c75e3aaSDag-Erling Smørgrav 		c->tcp_timeout_msec = 0;
762*4c75e3aaSDag-Erling Smørgrav 	comm_point_start_listening(c, fd,
763*4c75e3aaSDag-Erling Smørgrav 		c->tcp_timeout_msec < TCP_QUERY_TIMEOUT_MINIMUM
764*4c75e3aaSDag-Erling Smørgrav 			? TCP_QUERY_TIMEOUT_MINIMUM
765*4c75e3aaSDag-Erling Smørgrav 			: c->tcp_timeout_msec);
766b7579f77SDag-Erling Smørgrav }
767b7579f77SDag-Erling Smørgrav 
768b7579f77SDag-Erling Smørgrav void comm_base_handle_slow_accept(int ATTR_UNUSED(fd),
769b7579f77SDag-Erling Smørgrav 	short ATTR_UNUSED(event), void* arg)
770b7579f77SDag-Erling Smørgrav {
771b7579f77SDag-Erling Smørgrav 	struct comm_base* b = (struct comm_base*)arg;
772b7579f77SDag-Erling Smørgrav 	/* timeout for the slow accept, re-enable accepts again */
773b7579f77SDag-Erling Smørgrav 	if(b->start_accept) {
774b7579f77SDag-Erling Smørgrav 		verbose(VERB_ALGO, "wait is over, slow accept disabled");
775b7579f77SDag-Erling Smørgrav 		fptr_ok(fptr_whitelist_start_accept(b->start_accept));
776b7579f77SDag-Erling Smørgrav 		(*b->start_accept)(b->cb_arg);
777b7579f77SDag-Erling Smørgrav 		b->eb->slow_accept_enabled = 0;
778b7579f77SDag-Erling Smørgrav 	}
779b7579f77SDag-Erling Smørgrav }
780b7579f77SDag-Erling Smørgrav 
781b7579f77SDag-Erling Smørgrav int comm_point_perform_accept(struct comm_point* c,
782b7579f77SDag-Erling Smørgrav 	struct sockaddr_storage* addr, socklen_t* addrlen)
783b7579f77SDag-Erling Smørgrav {
784b7579f77SDag-Erling Smørgrav 	int new_fd;
785b7579f77SDag-Erling Smørgrav 	*addrlen = (socklen_t)sizeof(*addr);
7863bd4df0aSDag-Erling Smørgrav #ifndef HAVE_ACCEPT4
787b7579f77SDag-Erling Smørgrav 	new_fd = accept(c->fd, (struct sockaddr*)addr, addrlen);
7883bd4df0aSDag-Erling Smørgrav #else
7893bd4df0aSDag-Erling Smørgrav 	/* SOCK_NONBLOCK saves extra calls to fcntl for the same result */
7903bd4df0aSDag-Erling Smørgrav 	new_fd = accept4(c->fd, (struct sockaddr*)addr, addrlen, SOCK_NONBLOCK);
7913bd4df0aSDag-Erling Smørgrav #endif
792b7579f77SDag-Erling Smørgrav 	if(new_fd == -1) {
793b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK
794b7579f77SDag-Erling Smørgrav 		/* EINTR is signal interrupt. others are closed connection. */
795b7579f77SDag-Erling Smørgrav 		if(	errno == EINTR || errno == EAGAIN
796b7579f77SDag-Erling Smørgrav #ifdef EWOULDBLOCK
797b7579f77SDag-Erling Smørgrav 			|| errno == EWOULDBLOCK
798b7579f77SDag-Erling Smørgrav #endif
799b7579f77SDag-Erling Smørgrav #ifdef ECONNABORTED
800b7579f77SDag-Erling Smørgrav 			|| errno == ECONNABORTED
801b7579f77SDag-Erling Smørgrav #endif
802b7579f77SDag-Erling Smørgrav #ifdef EPROTO
803b7579f77SDag-Erling Smørgrav 			|| errno == EPROTO
804b7579f77SDag-Erling Smørgrav #endif /* EPROTO */
805b7579f77SDag-Erling Smørgrav 			)
806b7579f77SDag-Erling Smørgrav 			return -1;
807b7579f77SDag-Erling Smørgrav #if defined(ENFILE) && defined(EMFILE)
808b7579f77SDag-Erling Smørgrav 		if(errno == ENFILE || errno == EMFILE) {
809b7579f77SDag-Erling Smørgrav 			/* out of file descriptors, likely outside of our
810b7579f77SDag-Erling Smørgrav 			 * control. stop accept() calls for some time */
811b7579f77SDag-Erling Smørgrav 			if(c->ev->base->stop_accept) {
812b7579f77SDag-Erling Smørgrav 				struct comm_base* b = c->ev->base;
813b7579f77SDag-Erling Smørgrav 				struct timeval tv;
814b7579f77SDag-Erling Smørgrav 				verbose(VERB_ALGO, "out of file descriptors: "
815b7579f77SDag-Erling Smørgrav 					"slow accept");
816b7579f77SDag-Erling Smørgrav 				b->eb->slow_accept_enabled = 1;
817b7579f77SDag-Erling Smørgrav 				fptr_ok(fptr_whitelist_stop_accept(
818b7579f77SDag-Erling Smørgrav 					b->stop_accept));
819b7579f77SDag-Erling Smørgrav 				(*b->stop_accept)(b->cb_arg);
820b7579f77SDag-Erling Smørgrav 				/* set timeout, no mallocs */
821b7579f77SDag-Erling Smørgrav 				tv.tv_sec = NETEVENT_SLOW_ACCEPT_TIME/1000;
822b5663de9SDag-Erling Smørgrav 				tv.tv_usec = (NETEVENT_SLOW_ACCEPT_TIME%1000)*1000;
823e2d15004SDag-Erling Smørgrav 				b->eb->slow_accept = ub_event_new(b->eb->base,
824e2d15004SDag-Erling Smørgrav 					-1, UB_EV_TIMEOUT,
825b7579f77SDag-Erling Smørgrav 					comm_base_handle_slow_accept, b);
826e2d15004SDag-Erling Smørgrav 				if(b->eb->slow_accept == NULL) {
827b7579f77SDag-Erling Smørgrav 					/* we do not want to log here, because
828b7579f77SDag-Erling Smørgrav 					 * that would spam the logfiles.
829b7579f77SDag-Erling Smørgrav 					 * error: "event_base_set failed." */
830b7579f77SDag-Erling Smørgrav 				}
831e2d15004SDag-Erling Smørgrav 				else if(ub_event_add(b->eb->slow_accept, &tv)
832e2d15004SDag-Erling Smørgrav 					!= 0) {
833b7579f77SDag-Erling Smørgrav 					/* we do not want to log here,
834b7579f77SDag-Erling Smørgrav 					 * error: "event_add failed." */
835b7579f77SDag-Erling Smørgrav 				}
836b7579f77SDag-Erling Smørgrav 			}
837b7579f77SDag-Erling Smørgrav 			return -1;
838b7579f77SDag-Erling Smørgrav 		}
839b7579f77SDag-Erling Smørgrav #endif
840ff825849SDag-Erling Smørgrav 		log_err_addr("accept failed", strerror(errno), addr, *addrlen);
841b7579f77SDag-Erling Smørgrav #else /* USE_WINSOCK */
842b7579f77SDag-Erling Smørgrav 		if(WSAGetLastError() == WSAEINPROGRESS ||
843b7579f77SDag-Erling Smørgrav 			WSAGetLastError() == WSAECONNRESET)
844b7579f77SDag-Erling Smørgrav 			return -1;
845b7579f77SDag-Erling Smørgrav 		if(WSAGetLastError() == WSAEWOULDBLOCK) {
846e2d15004SDag-Erling Smørgrav 			ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
847b7579f77SDag-Erling Smørgrav 			return -1;
848b7579f77SDag-Erling Smørgrav 		}
849ff825849SDag-Erling Smørgrav 		log_err_addr("accept failed", wsa_strerror(WSAGetLastError()),
850ff825849SDag-Erling Smørgrav 			addr, *addrlen);
851b7579f77SDag-Erling Smørgrav #endif
852b7579f77SDag-Erling Smørgrav 		return -1;
853b7579f77SDag-Erling Smørgrav 	}
854*4c75e3aaSDag-Erling Smørgrav 	if(c->tcp_conn_limit && c->type == comm_tcp_accept) {
855*4c75e3aaSDag-Erling Smørgrav 		c->tcl_addr = tcl_addr_lookup(c->tcp_conn_limit, addr, *addrlen);
856*4c75e3aaSDag-Erling Smørgrav 		if(!tcl_new_connection(c->tcl_addr)) {
857*4c75e3aaSDag-Erling Smørgrav 			if(verbosity >= 3)
858*4c75e3aaSDag-Erling Smørgrav 				log_err_addr("accept rejected",
859*4c75e3aaSDag-Erling Smørgrav 				"connection limit exceeded", addr, *addrlen);
860*4c75e3aaSDag-Erling Smørgrav 			close(new_fd);
861*4c75e3aaSDag-Erling Smørgrav 			return -1;
862*4c75e3aaSDag-Erling Smørgrav 		}
863*4c75e3aaSDag-Erling Smørgrav 	}
8643bd4df0aSDag-Erling Smørgrav #ifndef HAVE_ACCEPT4
865b7579f77SDag-Erling Smørgrav 	fd_set_nonblock(new_fd);
8663bd4df0aSDag-Erling Smørgrav #endif
867b7579f77SDag-Erling Smørgrav 	return new_fd;
868b7579f77SDag-Erling Smørgrav }
869b7579f77SDag-Erling Smørgrav 
870b7579f77SDag-Erling Smørgrav #ifdef USE_WINSOCK
871b7579f77SDag-Erling Smørgrav static long win_bio_cb(BIO *b, int oper, const char* ATTR_UNUSED(argp),
872b7579f77SDag-Erling Smørgrav         int ATTR_UNUSED(argi), long argl, long retvalue)
873b7579f77SDag-Erling Smørgrav {
8743bd4df0aSDag-Erling Smørgrav 	int wsa_err = WSAGetLastError(); /* store errcode before it is gone */
875b7579f77SDag-Erling Smørgrav 	verbose(VERB_ALGO, "bio_cb %d, %s %s %s", oper,
876b7579f77SDag-Erling Smørgrav 		(oper&BIO_CB_RETURN)?"return":"before",
877b7579f77SDag-Erling Smørgrav 		(oper&BIO_CB_READ)?"read":((oper&BIO_CB_WRITE)?"write":"other"),
8783bd4df0aSDag-Erling Smørgrav 		wsa_err==WSAEWOULDBLOCK?"wsawb":"");
879b7579f77SDag-Erling Smørgrav 	/* on windows, check if previous operation caused EWOULDBLOCK */
880b7579f77SDag-Erling Smørgrav 	if( (oper == (BIO_CB_READ|BIO_CB_RETURN) && argl == 0) ||
881b7579f77SDag-Erling Smørgrav 		(oper == (BIO_CB_GETS|BIO_CB_RETURN) && argl == 0)) {
8823bd4df0aSDag-Erling Smørgrav 		if(wsa_err == WSAEWOULDBLOCK)
883e2d15004SDag-Erling Smørgrav 			ub_winsock_tcp_wouldblock((struct ub_event*)
884e2d15004SDag-Erling Smørgrav 				BIO_get_callback_arg(b), UB_EV_READ);
885b7579f77SDag-Erling Smørgrav 	}
886b7579f77SDag-Erling Smørgrav 	if( (oper == (BIO_CB_WRITE|BIO_CB_RETURN) && argl == 0) ||
887b7579f77SDag-Erling Smørgrav 		(oper == (BIO_CB_PUTS|BIO_CB_RETURN) && argl == 0)) {
8883bd4df0aSDag-Erling Smørgrav 		if(wsa_err == WSAEWOULDBLOCK)
889e2d15004SDag-Erling Smørgrav 			ub_winsock_tcp_wouldblock((struct ub_event*)
890e2d15004SDag-Erling Smørgrav 				BIO_get_callback_arg(b), UB_EV_WRITE);
891b7579f77SDag-Erling Smørgrav 	}
892b7579f77SDag-Erling Smørgrav 	/* return original return value */
893b7579f77SDag-Erling Smørgrav 	return retvalue;
894b7579f77SDag-Erling Smørgrav }
895b7579f77SDag-Erling Smørgrav 
896b7579f77SDag-Erling Smørgrav /** set win bio callbacks for nonblocking operations */
897b7579f77SDag-Erling Smørgrav void
898b7579f77SDag-Erling Smørgrav comm_point_tcp_win_bio_cb(struct comm_point* c, void* thessl)
899b7579f77SDag-Erling Smørgrav {
900b7579f77SDag-Erling Smørgrav 	SSL* ssl = (SSL*)thessl;
901b7579f77SDag-Erling Smørgrav 	/* set them both just in case, but usually they are the same BIO */
902b7579f77SDag-Erling Smørgrav 	BIO_set_callback(SSL_get_rbio(ssl), &win_bio_cb);
903e2d15004SDag-Erling Smørgrav 	BIO_set_callback_arg(SSL_get_rbio(ssl), (char*)c->ev->ev);
904b7579f77SDag-Erling Smørgrav 	BIO_set_callback(SSL_get_wbio(ssl), &win_bio_cb);
905e2d15004SDag-Erling Smørgrav 	BIO_set_callback_arg(SSL_get_wbio(ssl), (char*)c->ev->ev);
906b7579f77SDag-Erling Smørgrav }
907b7579f77SDag-Erling Smørgrav #endif
908b7579f77SDag-Erling Smørgrav 
909b7579f77SDag-Erling Smørgrav void
910b7579f77SDag-Erling Smørgrav comm_point_tcp_accept_callback(int fd, short event, void* arg)
911b7579f77SDag-Erling Smørgrav {
912b7579f77SDag-Erling Smørgrav 	struct comm_point* c = (struct comm_point*)arg, *c_hdl;
913b7579f77SDag-Erling Smørgrav 	int new_fd;
914b7579f77SDag-Erling Smørgrav 	log_assert(c->type == comm_tcp_accept);
915e2d15004SDag-Erling Smørgrav 	if(!(event & UB_EV_READ)) {
916b7579f77SDag-Erling Smørgrav 		log_info("ignoring tcp accept event %d", (int)event);
917b7579f77SDag-Erling Smørgrav 		return;
918b7579f77SDag-Erling Smørgrav 	}
919e2d15004SDag-Erling Smørgrav 	ub_comm_base_now(c->ev->base);
920b7579f77SDag-Erling Smørgrav 	/* find free tcp handler. */
921b7579f77SDag-Erling Smørgrav 	if(!c->tcp_free) {
922b7579f77SDag-Erling Smørgrav 		log_warn("accepted too many tcp, connections full");
923b7579f77SDag-Erling Smørgrav 		return;
924b7579f77SDag-Erling Smørgrav 	}
925b7579f77SDag-Erling Smørgrav 	/* accept incoming connection. */
926b7579f77SDag-Erling Smørgrav 	c_hdl = c->tcp_free;
927b7579f77SDag-Erling Smørgrav 	log_assert(fd != -1);
928b5663de9SDag-Erling Smørgrav 	(void)fd;
929b7579f77SDag-Erling Smørgrav 	new_fd = comm_point_perform_accept(c, &c_hdl->repinfo.addr,
930b7579f77SDag-Erling Smørgrav 		&c_hdl->repinfo.addrlen);
931b7579f77SDag-Erling Smørgrav 	if(new_fd == -1)
932b7579f77SDag-Erling Smørgrav 		return;
933b7579f77SDag-Erling Smørgrav 	if(c->ssl) {
934b7579f77SDag-Erling Smørgrav 		c_hdl->ssl = incoming_ssl_fd(c->ssl, new_fd);
935b7579f77SDag-Erling Smørgrav 		if(!c_hdl->ssl) {
936b7579f77SDag-Erling Smørgrav 			c_hdl->fd = new_fd;
937b7579f77SDag-Erling Smørgrav 			comm_point_close(c_hdl);
938b7579f77SDag-Erling Smørgrav 			return;
939b7579f77SDag-Erling Smørgrav 		}
940b7579f77SDag-Erling Smørgrav 		c_hdl->ssl_shake_state = comm_ssl_shake_read;
941b7579f77SDag-Erling Smørgrav #ifdef USE_WINSOCK
942b7579f77SDag-Erling Smørgrav 		comm_point_tcp_win_bio_cb(c_hdl, c_hdl->ssl);
943b7579f77SDag-Erling Smørgrav #endif
944b7579f77SDag-Erling Smørgrav 	}
945b7579f77SDag-Erling Smørgrav 
946b7579f77SDag-Erling Smørgrav 	/* grab the tcp handler buffers */
94709a3aaf3SDag-Erling Smørgrav 	c->cur_tcp_count++;
948b7579f77SDag-Erling Smørgrav 	c->tcp_free = c_hdl->tcp_free;
949b7579f77SDag-Erling Smørgrav 	if(!c->tcp_free) {
950b7579f77SDag-Erling Smørgrav 		/* stop accepting incoming queries for now. */
951b7579f77SDag-Erling Smørgrav 		comm_point_stop_listening(c);
952b7579f77SDag-Erling Smørgrav 	}
953b5663de9SDag-Erling Smørgrav 	setup_tcp_handler(c_hdl, new_fd, c->cur_tcp_count, c->max_tcp_count);
954b7579f77SDag-Erling Smørgrav }
955b7579f77SDag-Erling Smørgrav 
956b7579f77SDag-Erling Smørgrav /** Make tcp handler free for next assignment */
957b7579f77SDag-Erling Smørgrav static void
958b7579f77SDag-Erling Smørgrav reclaim_tcp_handler(struct comm_point* c)
959b7579f77SDag-Erling Smørgrav {
960b7579f77SDag-Erling Smørgrav 	log_assert(c->type == comm_tcp);
961b7579f77SDag-Erling Smørgrav 	if(c->ssl) {
9628ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL
963b7579f77SDag-Erling Smørgrav 		SSL_shutdown(c->ssl);
964b7579f77SDag-Erling Smørgrav 		SSL_free(c->ssl);
965b7579f77SDag-Erling Smørgrav 		c->ssl = NULL;
9668ed2b524SDag-Erling Smørgrav #endif
967b7579f77SDag-Erling Smørgrav 	}
968b7579f77SDag-Erling Smørgrav 	comm_point_close(c);
969b7579f77SDag-Erling Smørgrav 	if(c->tcp_parent) {
97009a3aaf3SDag-Erling Smørgrav 		c->tcp_parent->cur_tcp_count--;
971b7579f77SDag-Erling Smørgrav 		c->tcp_free = c->tcp_parent->tcp_free;
972b7579f77SDag-Erling Smørgrav 		c->tcp_parent->tcp_free = c;
973b7579f77SDag-Erling Smørgrav 		if(!c->tcp_free) {
974b7579f77SDag-Erling Smørgrav 			/* re-enable listening on accept socket */
975b7579f77SDag-Erling Smørgrav 			comm_point_start_listening(c->tcp_parent, -1, -1);
976b7579f77SDag-Erling Smørgrav 		}
977b7579f77SDag-Erling Smørgrav 	}
978b7579f77SDag-Erling Smørgrav }
979b7579f77SDag-Erling Smørgrav 
980b7579f77SDag-Erling Smørgrav /** do the callback when writing is done */
981b7579f77SDag-Erling Smørgrav static void
982b7579f77SDag-Erling Smørgrav tcp_callback_writer(struct comm_point* c)
983b7579f77SDag-Erling Smørgrav {
984b7579f77SDag-Erling Smørgrav 	log_assert(c->type == comm_tcp);
98517d15b25SDag-Erling Smørgrav 	sldns_buffer_clear(c->buffer);
986b7579f77SDag-Erling Smørgrav 	if(c->tcp_do_toggle_rw)
987b7579f77SDag-Erling Smørgrav 		c->tcp_is_reading = 1;
988b7579f77SDag-Erling Smørgrav 	c->tcp_byte_count = 0;
989b7579f77SDag-Erling Smørgrav 	/* switch from listening(write) to listening(read) */
990b7579f77SDag-Erling Smørgrav 	comm_point_stop_listening(c);
991b7579f77SDag-Erling Smørgrav 	comm_point_start_listening(c, -1, -1);
992b7579f77SDag-Erling Smørgrav }
993b7579f77SDag-Erling Smørgrav 
994b7579f77SDag-Erling Smørgrav /** do the callback when reading is done */
995b7579f77SDag-Erling Smørgrav static void
996b7579f77SDag-Erling Smørgrav tcp_callback_reader(struct comm_point* c)
997b7579f77SDag-Erling Smørgrav {
998b7579f77SDag-Erling Smørgrav 	log_assert(c->type == comm_tcp || c->type == comm_local);
99917d15b25SDag-Erling Smørgrav 	sldns_buffer_flip(c->buffer);
1000b7579f77SDag-Erling Smørgrav 	if(c->tcp_do_toggle_rw)
1001b7579f77SDag-Erling Smørgrav 		c->tcp_is_reading = 0;
1002b7579f77SDag-Erling Smørgrav 	c->tcp_byte_count = 0;
1003b7579f77SDag-Erling Smørgrav 	if(c->type == comm_tcp)
1004b7579f77SDag-Erling Smørgrav 		comm_point_stop_listening(c);
1005b7579f77SDag-Erling Smørgrav 	fptr_ok(fptr_whitelist_comm_point(c->callback));
1006b7579f77SDag-Erling Smørgrav 	if( (*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, &c->repinfo) ) {
1007b5663de9SDag-Erling Smørgrav 		comm_point_start_listening(c, -1, c->tcp_timeout_msec);
1008b7579f77SDag-Erling Smørgrav 	}
1009b7579f77SDag-Erling Smørgrav }
1010b7579f77SDag-Erling Smørgrav 
101157bddd21SDag-Erling Smørgrav #ifdef HAVE_SSL
101257bddd21SDag-Erling Smørgrav /** log certificate details */
101357bddd21SDag-Erling Smørgrav static void
101457bddd21SDag-Erling Smørgrav log_cert(unsigned level, const char* str, X509* cert)
101557bddd21SDag-Erling Smørgrav {
101657bddd21SDag-Erling Smørgrav 	BIO* bio;
101757bddd21SDag-Erling Smørgrav 	char nul = 0;
101857bddd21SDag-Erling Smørgrav 	char* pp = NULL;
101957bddd21SDag-Erling Smørgrav 	long len;
102057bddd21SDag-Erling Smørgrav 	if(verbosity < level) return;
102157bddd21SDag-Erling Smørgrav 	bio = BIO_new(BIO_s_mem());
102257bddd21SDag-Erling Smørgrav 	if(!bio) return;
102357bddd21SDag-Erling Smørgrav 	X509_print_ex(bio, cert, 0, (unsigned long)-1
102457bddd21SDag-Erling Smørgrav 		^(X509_FLAG_NO_SUBJECT
102557bddd21SDag-Erling Smørgrav                         |X509_FLAG_NO_ISSUER|X509_FLAG_NO_VALIDITY
102657bddd21SDag-Erling Smørgrav 			|X509_FLAG_NO_EXTENSIONS|X509_FLAG_NO_AUX
102757bddd21SDag-Erling Smørgrav 			|X509_FLAG_NO_ATTRIBUTES));
102857bddd21SDag-Erling Smørgrav 	BIO_write(bio, &nul, (int)sizeof(nul));
102957bddd21SDag-Erling Smørgrav 	len = BIO_get_mem_data(bio, &pp);
103057bddd21SDag-Erling Smørgrav 	if(len != 0 && pp) {
103157bddd21SDag-Erling Smørgrav 		verbose(level, "%s: \n%s", str, pp);
103257bddd21SDag-Erling Smørgrav 	}
103357bddd21SDag-Erling Smørgrav 	BIO_free(bio);
103457bddd21SDag-Erling Smørgrav }
103557bddd21SDag-Erling Smørgrav #endif /* HAVE_SSL */
103657bddd21SDag-Erling Smørgrav 
1037b7579f77SDag-Erling Smørgrav /** continue ssl handshake */
10388ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL
1039b7579f77SDag-Erling Smørgrav static int
1040b7579f77SDag-Erling Smørgrav ssl_handshake(struct comm_point* c)
1041b7579f77SDag-Erling Smørgrav {
1042b7579f77SDag-Erling Smørgrav 	int r;
1043b7579f77SDag-Erling Smørgrav 	if(c->ssl_shake_state == comm_ssl_shake_hs_read) {
1044b7579f77SDag-Erling Smørgrav 		/* read condition satisfied back to writing */
1045b7579f77SDag-Erling Smørgrav 		comm_point_listen_for_rw(c, 1, 1);
1046b7579f77SDag-Erling Smørgrav 		c->ssl_shake_state = comm_ssl_shake_none;
1047b7579f77SDag-Erling Smørgrav 		return 1;
1048b7579f77SDag-Erling Smørgrav 	}
1049b7579f77SDag-Erling Smørgrav 	if(c->ssl_shake_state == comm_ssl_shake_hs_write) {
1050b7579f77SDag-Erling Smørgrav 		/* write condition satisfied, back to reading */
1051b7579f77SDag-Erling Smørgrav 		comm_point_listen_for_rw(c, 1, 0);
1052b7579f77SDag-Erling Smørgrav 		c->ssl_shake_state = comm_ssl_shake_none;
1053b7579f77SDag-Erling Smørgrav 		return 1;
1054b7579f77SDag-Erling Smørgrav 	}
1055b7579f77SDag-Erling Smørgrav 
1056b7579f77SDag-Erling Smørgrav 	ERR_clear_error();
1057b7579f77SDag-Erling Smørgrav 	r = SSL_do_handshake(c->ssl);
1058b7579f77SDag-Erling Smørgrav 	if(r != 1) {
1059b7579f77SDag-Erling Smørgrav 		int want = SSL_get_error(c->ssl, r);
1060b7579f77SDag-Erling Smørgrav 		if(want == SSL_ERROR_WANT_READ) {
1061b7579f77SDag-Erling Smørgrav 			if(c->ssl_shake_state == comm_ssl_shake_read)
1062b7579f77SDag-Erling Smørgrav 				return 1;
1063b7579f77SDag-Erling Smørgrav 			c->ssl_shake_state = comm_ssl_shake_read;
1064b7579f77SDag-Erling Smørgrav 			comm_point_listen_for_rw(c, 1, 0);
1065b7579f77SDag-Erling Smørgrav 			return 1;
1066b7579f77SDag-Erling Smørgrav 		} else if(want == SSL_ERROR_WANT_WRITE) {
1067b7579f77SDag-Erling Smørgrav 			if(c->ssl_shake_state == comm_ssl_shake_write)
1068b7579f77SDag-Erling Smørgrav 				return 1;
1069b7579f77SDag-Erling Smørgrav 			c->ssl_shake_state = comm_ssl_shake_write;
1070b7579f77SDag-Erling Smørgrav 			comm_point_listen_for_rw(c, 0, 1);
1071b7579f77SDag-Erling Smørgrav 			return 1;
1072b7579f77SDag-Erling Smørgrav 		} else if(r == 0) {
1073b7579f77SDag-Erling Smørgrav 			return 0; /* closed */
1074b7579f77SDag-Erling Smørgrav 		} else if(want == SSL_ERROR_SYSCALL) {
1075b7579f77SDag-Erling Smørgrav 			/* SYSCALL and errno==0 means closed uncleanly */
1076b7579f77SDag-Erling Smørgrav 			if(errno != 0)
1077b7579f77SDag-Erling Smørgrav 				log_err("SSL_handshake syscall: %s",
1078b7579f77SDag-Erling Smørgrav 					strerror(errno));
1079b7579f77SDag-Erling Smørgrav 			return 0;
1080b7579f77SDag-Erling Smørgrav 		} else {
1081b7579f77SDag-Erling Smørgrav 			log_crypto_err("ssl handshake failed");
1082b7579f77SDag-Erling Smørgrav 			log_addr(1, "ssl handshake failed", &c->repinfo.addr,
1083b7579f77SDag-Erling Smørgrav 				c->repinfo.addrlen);
1084b7579f77SDag-Erling Smørgrav 			return 0;
1085b7579f77SDag-Erling Smørgrav 		}
1086b7579f77SDag-Erling Smørgrav 	}
1087b7579f77SDag-Erling Smørgrav 	/* this is where peer verification could take place */
108857bddd21SDag-Erling Smørgrav 	if((SSL_get_verify_mode(c->ssl)&SSL_VERIFY_PEER)) {
108957bddd21SDag-Erling Smørgrav 		/* verification */
109057bddd21SDag-Erling Smørgrav 		if(SSL_get_verify_result(c->ssl) == X509_V_OK) {
109157bddd21SDag-Erling Smørgrav 			X509* x = SSL_get_peer_certificate(c->ssl);
109257bddd21SDag-Erling Smørgrav 			if(!x) {
109357bddd21SDag-Erling Smørgrav 				log_addr(VERB_ALGO, "SSL connection failed: "
109457bddd21SDag-Erling Smørgrav 					"no certificate",
109557bddd21SDag-Erling Smørgrav 					&c->repinfo.addr, c->repinfo.addrlen);
109657bddd21SDag-Erling Smørgrav 				return 0;
109757bddd21SDag-Erling Smørgrav 			}
109857bddd21SDag-Erling Smørgrav 			log_cert(VERB_ALGO, "peer certificate", x);
109957bddd21SDag-Erling Smørgrav #ifdef HAVE_SSL_GET0_PEERNAME
110057bddd21SDag-Erling Smørgrav 			if(SSL_get0_peername(c->ssl)) {
110157bddd21SDag-Erling Smørgrav 				char buf[255];
110257bddd21SDag-Erling Smørgrav 				snprintf(buf, sizeof(buf), "SSL connection "
110357bddd21SDag-Erling Smørgrav 					"to %s authenticated",
110457bddd21SDag-Erling Smørgrav 					SSL_get0_peername(c->ssl));
110557bddd21SDag-Erling Smørgrav 				log_addr(VERB_ALGO, buf, &c->repinfo.addr,
1106b7579f77SDag-Erling Smørgrav 					c->repinfo.addrlen);
110757bddd21SDag-Erling Smørgrav 			} else {
110857bddd21SDag-Erling Smørgrav #endif
110957bddd21SDag-Erling Smørgrav 				log_addr(VERB_ALGO, "SSL connection "
111057bddd21SDag-Erling Smørgrav 					"authenticated", &c->repinfo.addr,
111157bddd21SDag-Erling Smørgrav 					c->repinfo.addrlen);
111257bddd21SDag-Erling Smørgrav #ifdef HAVE_SSL_GET0_PEERNAME
111357bddd21SDag-Erling Smørgrav 			}
111457bddd21SDag-Erling Smørgrav #endif
111557bddd21SDag-Erling Smørgrav 			X509_free(x);
111657bddd21SDag-Erling Smørgrav 		} else {
111757bddd21SDag-Erling Smørgrav 			X509* x = SSL_get_peer_certificate(c->ssl);
111857bddd21SDag-Erling Smørgrav 			if(x) {
111957bddd21SDag-Erling Smørgrav 				log_cert(VERB_ALGO, "peer certificate", x);
112057bddd21SDag-Erling Smørgrav 				X509_free(x);
112157bddd21SDag-Erling Smørgrav 			}
112257bddd21SDag-Erling Smørgrav 			log_addr(VERB_ALGO, "SSL connection failed: "
112357bddd21SDag-Erling Smørgrav 				"failed to authenticate",
112457bddd21SDag-Erling Smørgrav 				&c->repinfo.addr, c->repinfo.addrlen);
112557bddd21SDag-Erling Smørgrav 			return 0;
112657bddd21SDag-Erling Smørgrav 		}
112757bddd21SDag-Erling Smørgrav 	} else {
112857bddd21SDag-Erling Smørgrav 		/* unauthenticated, the verify peer flag was not set
112957bddd21SDag-Erling Smørgrav 		 * in c->ssl when the ssl object was created from ssl_ctx */
113057bddd21SDag-Erling Smørgrav 		log_addr(VERB_ALGO, "SSL connection", &c->repinfo.addr,
113157bddd21SDag-Erling Smørgrav 			c->repinfo.addrlen);
113257bddd21SDag-Erling Smørgrav 	}
1133b7579f77SDag-Erling Smørgrav 
1134b7579f77SDag-Erling Smørgrav 	/* setup listen rw correctly */
1135b7579f77SDag-Erling Smørgrav 	if(c->tcp_is_reading) {
1136b7579f77SDag-Erling Smørgrav 		if(c->ssl_shake_state != comm_ssl_shake_read)
1137b7579f77SDag-Erling Smørgrav 			comm_point_listen_for_rw(c, 1, 0);
1138b7579f77SDag-Erling Smørgrav 	} else {
1139b7579f77SDag-Erling Smørgrav 		comm_point_listen_for_rw(c, 1, 1);
1140b7579f77SDag-Erling Smørgrav 	}
1141b7579f77SDag-Erling Smørgrav 	c->ssl_shake_state = comm_ssl_shake_none;
1142b7579f77SDag-Erling Smørgrav 	return 1;
1143b7579f77SDag-Erling Smørgrav }
11448ed2b524SDag-Erling Smørgrav #endif /* HAVE_SSL */
1145b7579f77SDag-Erling Smørgrav 
1146b7579f77SDag-Erling Smørgrav /** ssl read callback on TCP */
1147b7579f77SDag-Erling Smørgrav static int
1148b7579f77SDag-Erling Smørgrav ssl_handle_read(struct comm_point* c)
1149b7579f77SDag-Erling Smørgrav {
11508ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL
1151b7579f77SDag-Erling Smørgrav 	int r;
1152b7579f77SDag-Erling Smørgrav 	if(c->ssl_shake_state != comm_ssl_shake_none) {
1153b7579f77SDag-Erling Smørgrav 		if(!ssl_handshake(c))
1154b7579f77SDag-Erling Smørgrav 			return 0;
1155b7579f77SDag-Erling Smørgrav 		if(c->ssl_shake_state != comm_ssl_shake_none)
1156b7579f77SDag-Erling Smørgrav 			return 1;
1157b7579f77SDag-Erling Smørgrav 	}
1158b7579f77SDag-Erling Smørgrav 	if(c->tcp_byte_count < sizeof(uint16_t)) {
1159b7579f77SDag-Erling Smørgrav 		/* read length bytes */
1160b7579f77SDag-Erling Smørgrav 		ERR_clear_error();
116117d15b25SDag-Erling Smørgrav 		if((r=SSL_read(c->ssl, (void*)sldns_buffer_at(c->buffer,
1162b7579f77SDag-Erling Smørgrav 			c->tcp_byte_count), (int)(sizeof(uint16_t) -
1163b7579f77SDag-Erling Smørgrav 			c->tcp_byte_count))) <= 0) {
1164b7579f77SDag-Erling Smørgrav 			int want = SSL_get_error(c->ssl, r);
1165b7579f77SDag-Erling Smørgrav 			if(want == SSL_ERROR_ZERO_RETURN) {
1166b7579f77SDag-Erling Smørgrav 				return 0; /* shutdown, closed */
1167b7579f77SDag-Erling Smørgrav 			} else if(want == SSL_ERROR_WANT_READ) {
11683bd4df0aSDag-Erling Smørgrav 				ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
1169b7579f77SDag-Erling Smørgrav 				return 1; /* read more later */
1170b7579f77SDag-Erling Smørgrav 			} else if(want == SSL_ERROR_WANT_WRITE) {
1171b7579f77SDag-Erling Smørgrav 				c->ssl_shake_state = comm_ssl_shake_hs_write;
1172b7579f77SDag-Erling Smørgrav 				comm_point_listen_for_rw(c, 0, 1);
1173b7579f77SDag-Erling Smørgrav 				return 1;
1174b7579f77SDag-Erling Smørgrav 			} else if(want == SSL_ERROR_SYSCALL) {
1175b7579f77SDag-Erling Smørgrav 				if(errno != 0)
1176b7579f77SDag-Erling Smørgrav 					log_err("SSL_read syscall: %s",
1177b7579f77SDag-Erling Smørgrav 						strerror(errno));
1178b7579f77SDag-Erling Smørgrav 				return 0;
1179b7579f77SDag-Erling Smørgrav 			}
1180b7579f77SDag-Erling Smørgrav 			log_crypto_err("could not SSL_read");
1181b7579f77SDag-Erling Smørgrav 			return 0;
1182b7579f77SDag-Erling Smørgrav 		}
1183b7579f77SDag-Erling Smørgrav 		c->tcp_byte_count += r;
11843bd4df0aSDag-Erling Smørgrav 		if(c->tcp_byte_count < sizeof(uint16_t))
1185b7579f77SDag-Erling Smørgrav 			return 1;
118617d15b25SDag-Erling Smørgrav 		if(sldns_buffer_read_u16_at(c->buffer, 0) >
118717d15b25SDag-Erling Smørgrav 			sldns_buffer_capacity(c->buffer)) {
1188b7579f77SDag-Erling Smørgrav 			verbose(VERB_QUERY, "ssl: dropped larger than buffer");
1189b7579f77SDag-Erling Smørgrav 			return 0;
1190b7579f77SDag-Erling Smørgrav 		}
119117d15b25SDag-Erling Smørgrav 		sldns_buffer_set_limit(c->buffer,
119217d15b25SDag-Erling Smørgrav 			sldns_buffer_read_u16_at(c->buffer, 0));
119317d15b25SDag-Erling Smørgrav 		if(sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE) {
1194b7579f77SDag-Erling Smørgrav 			verbose(VERB_QUERY, "ssl: dropped bogus too short.");
1195b7579f77SDag-Erling Smørgrav 			return 0;
1196b7579f77SDag-Erling Smørgrav 		}
11973bd4df0aSDag-Erling Smørgrav 		sldns_buffer_skip(c->buffer, (ssize_t)(c->tcp_byte_count-sizeof(uint16_t)));
1198b7579f77SDag-Erling Smørgrav 		verbose(VERB_ALGO, "Reading ssl tcp query of length %d",
119917d15b25SDag-Erling Smørgrav 			(int)sldns_buffer_limit(c->buffer));
1200b7579f77SDag-Erling Smørgrav 	}
12013bd4df0aSDag-Erling Smørgrav 	if(sldns_buffer_remaining(c->buffer) > 0) {
1202b7579f77SDag-Erling Smørgrav 		ERR_clear_error();
120317d15b25SDag-Erling Smørgrav 		r = SSL_read(c->ssl, (void*)sldns_buffer_current(c->buffer),
120417d15b25SDag-Erling Smørgrav 			(int)sldns_buffer_remaining(c->buffer));
1205b7579f77SDag-Erling Smørgrav 		if(r <= 0) {
1206b7579f77SDag-Erling Smørgrav 			int want = SSL_get_error(c->ssl, r);
1207b7579f77SDag-Erling Smørgrav 			if(want == SSL_ERROR_ZERO_RETURN) {
1208b7579f77SDag-Erling Smørgrav 				return 0; /* shutdown, closed */
1209b7579f77SDag-Erling Smørgrav 			} else if(want == SSL_ERROR_WANT_READ) {
12103bd4df0aSDag-Erling Smørgrav 				ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
1211b7579f77SDag-Erling Smørgrav 				return 1; /* read more later */
1212b7579f77SDag-Erling Smørgrav 			} else if(want == SSL_ERROR_WANT_WRITE) {
1213b7579f77SDag-Erling Smørgrav 				c->ssl_shake_state = comm_ssl_shake_hs_write;
1214b7579f77SDag-Erling Smørgrav 				comm_point_listen_for_rw(c, 0, 1);
1215b7579f77SDag-Erling Smørgrav 				return 1;
1216b7579f77SDag-Erling Smørgrav 			} else if(want == SSL_ERROR_SYSCALL) {
1217b7579f77SDag-Erling Smørgrav 				if(errno != 0)
1218b7579f77SDag-Erling Smørgrav 					log_err("SSL_read syscall: %s",
1219b7579f77SDag-Erling Smørgrav 						strerror(errno));
1220b7579f77SDag-Erling Smørgrav 				return 0;
1221b7579f77SDag-Erling Smørgrav 			}
1222b7579f77SDag-Erling Smørgrav 			log_crypto_err("could not SSL_read");
1223b7579f77SDag-Erling Smørgrav 			return 0;
1224b7579f77SDag-Erling Smørgrav 		}
122517d15b25SDag-Erling Smørgrav 		sldns_buffer_skip(c->buffer, (ssize_t)r);
12263bd4df0aSDag-Erling Smørgrav 	}
122717d15b25SDag-Erling Smørgrav 	if(sldns_buffer_remaining(c->buffer) <= 0) {
1228b7579f77SDag-Erling Smørgrav 		tcp_callback_reader(c);
1229b7579f77SDag-Erling Smørgrav 	}
1230b7579f77SDag-Erling Smørgrav 	return 1;
12318ed2b524SDag-Erling Smørgrav #else
12328ed2b524SDag-Erling Smørgrav 	(void)c;
12338ed2b524SDag-Erling Smørgrav 	return 0;
12348ed2b524SDag-Erling Smørgrav #endif /* HAVE_SSL */
1235b7579f77SDag-Erling Smørgrav }
1236b7579f77SDag-Erling Smørgrav 
1237b7579f77SDag-Erling Smørgrav /** ssl write callback on TCP */
1238b7579f77SDag-Erling Smørgrav static int
1239b7579f77SDag-Erling Smørgrav ssl_handle_write(struct comm_point* c)
1240b7579f77SDag-Erling Smørgrav {
12418ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL
1242b7579f77SDag-Erling Smørgrav 	int r;
1243b7579f77SDag-Erling Smørgrav 	if(c->ssl_shake_state != comm_ssl_shake_none) {
1244b7579f77SDag-Erling Smørgrav 		if(!ssl_handshake(c))
1245b7579f77SDag-Erling Smørgrav 			return 0;
1246b7579f77SDag-Erling Smørgrav 		if(c->ssl_shake_state != comm_ssl_shake_none)
1247b7579f77SDag-Erling Smørgrav 			return 1;
1248b7579f77SDag-Erling Smørgrav 	}
1249b7579f77SDag-Erling Smørgrav 	/* ignore return, if fails we may simply block */
1250b7579f77SDag-Erling Smørgrav 	(void)SSL_set_mode(c->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
1251b7579f77SDag-Erling Smørgrav 	if(c->tcp_byte_count < sizeof(uint16_t)) {
125217d15b25SDag-Erling Smørgrav 		uint16_t len = htons(sldns_buffer_limit(c->buffer));
1253b7579f77SDag-Erling Smørgrav 		ERR_clear_error();
12540fb34990SDag-Erling Smørgrav 		if(sizeof(uint16_t)+sldns_buffer_remaining(c->buffer) <
12550fb34990SDag-Erling Smørgrav 			LDNS_RR_BUF_SIZE) {
12560fb34990SDag-Erling Smørgrav 			/* combine the tcp length and the query for write,
12570fb34990SDag-Erling Smørgrav 			 * this emulates writev */
12580fb34990SDag-Erling Smørgrav 			uint8_t buf[LDNS_RR_BUF_SIZE];
12590fb34990SDag-Erling Smørgrav 			memmove(buf, &len, sizeof(uint16_t));
12600fb34990SDag-Erling Smørgrav 			memmove(buf+sizeof(uint16_t),
12610fb34990SDag-Erling Smørgrav 				sldns_buffer_current(c->buffer),
12620fb34990SDag-Erling Smørgrav 				sldns_buffer_remaining(c->buffer));
12630fb34990SDag-Erling Smørgrav 			r = SSL_write(c->ssl, (void*)(buf+c->tcp_byte_count),
12640fb34990SDag-Erling Smørgrav 				(int)(sizeof(uint16_t)+
12650fb34990SDag-Erling Smørgrav 				sldns_buffer_remaining(c->buffer)
12660fb34990SDag-Erling Smørgrav 				- c->tcp_byte_count));
12670fb34990SDag-Erling Smørgrav 		} else {
1268b7579f77SDag-Erling Smørgrav 			r = SSL_write(c->ssl,
1269b7579f77SDag-Erling Smørgrav 				(void*)(((uint8_t*)&len)+c->tcp_byte_count),
1270b7579f77SDag-Erling Smørgrav 				(int)(sizeof(uint16_t)-c->tcp_byte_count));
12710fb34990SDag-Erling Smørgrav 		}
1272b7579f77SDag-Erling Smørgrav 		if(r <= 0) {
1273b7579f77SDag-Erling Smørgrav 			int want = SSL_get_error(c->ssl, r);
1274b7579f77SDag-Erling Smørgrav 			if(want == SSL_ERROR_ZERO_RETURN) {
1275b7579f77SDag-Erling Smørgrav 				return 0; /* closed */
1276b7579f77SDag-Erling Smørgrav 			} else if(want == SSL_ERROR_WANT_READ) {
1277b7579f77SDag-Erling Smørgrav 				c->ssl_shake_state = comm_ssl_shake_read;
1278b7579f77SDag-Erling Smørgrav 				comm_point_listen_for_rw(c, 1, 0);
1279b7579f77SDag-Erling Smørgrav 				return 1; /* wait for read condition */
1280b7579f77SDag-Erling Smørgrav 			} else if(want == SSL_ERROR_WANT_WRITE) {
12813bd4df0aSDag-Erling Smørgrav 				ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
1282b7579f77SDag-Erling Smørgrav 				return 1; /* write more later */
1283b7579f77SDag-Erling Smørgrav 			} else if(want == SSL_ERROR_SYSCALL) {
1284b7579f77SDag-Erling Smørgrav 				if(errno != 0)
1285b7579f77SDag-Erling Smørgrav 					log_err("SSL_write syscall: %s",
1286b7579f77SDag-Erling Smørgrav 						strerror(errno));
1287b7579f77SDag-Erling Smørgrav 				return 0;
1288b7579f77SDag-Erling Smørgrav 			}
1289b7579f77SDag-Erling Smørgrav 			log_crypto_err("could not SSL_write");
1290b7579f77SDag-Erling Smørgrav 			return 0;
1291b7579f77SDag-Erling Smørgrav 		}
1292b7579f77SDag-Erling Smørgrav 		c->tcp_byte_count += r;
1293b7579f77SDag-Erling Smørgrav 		if(c->tcp_byte_count < sizeof(uint16_t))
1294b7579f77SDag-Erling Smørgrav 			return 1;
129517d15b25SDag-Erling Smørgrav 		sldns_buffer_set_position(c->buffer, c->tcp_byte_count -
1296b7579f77SDag-Erling Smørgrav 			sizeof(uint16_t));
129717d15b25SDag-Erling Smørgrav 		if(sldns_buffer_remaining(c->buffer) == 0) {
1298b7579f77SDag-Erling Smørgrav 			tcp_callback_writer(c);
1299b7579f77SDag-Erling Smørgrav 			return 1;
1300b7579f77SDag-Erling Smørgrav 		}
1301b7579f77SDag-Erling Smørgrav 	}
130217d15b25SDag-Erling Smørgrav 	log_assert(sldns_buffer_remaining(c->buffer) > 0);
1303b7579f77SDag-Erling Smørgrav 	ERR_clear_error();
130417d15b25SDag-Erling Smørgrav 	r = SSL_write(c->ssl, (void*)sldns_buffer_current(c->buffer),
130517d15b25SDag-Erling Smørgrav 		(int)sldns_buffer_remaining(c->buffer));
1306b7579f77SDag-Erling Smørgrav 	if(r <= 0) {
1307b7579f77SDag-Erling Smørgrav 		int want = SSL_get_error(c->ssl, r);
1308b7579f77SDag-Erling Smørgrav 		if(want == SSL_ERROR_ZERO_RETURN) {
1309b7579f77SDag-Erling Smørgrav 			return 0; /* closed */
1310b7579f77SDag-Erling Smørgrav 		} else if(want == SSL_ERROR_WANT_READ) {
1311b7579f77SDag-Erling Smørgrav 			c->ssl_shake_state = comm_ssl_shake_read;
1312b7579f77SDag-Erling Smørgrav 			comm_point_listen_for_rw(c, 1, 0);
1313b7579f77SDag-Erling Smørgrav 			return 1; /* wait for read condition */
1314b7579f77SDag-Erling Smørgrav 		} else if(want == SSL_ERROR_WANT_WRITE) {
13153bd4df0aSDag-Erling Smørgrav 			ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
1316b7579f77SDag-Erling Smørgrav 			return 1; /* write more later */
1317b7579f77SDag-Erling Smørgrav 		} else if(want == SSL_ERROR_SYSCALL) {
1318b7579f77SDag-Erling Smørgrav 			if(errno != 0)
1319b7579f77SDag-Erling Smørgrav 				log_err("SSL_write syscall: %s",
1320b7579f77SDag-Erling Smørgrav 					strerror(errno));
1321b7579f77SDag-Erling Smørgrav 			return 0;
1322b7579f77SDag-Erling Smørgrav 		}
1323b7579f77SDag-Erling Smørgrav 		log_crypto_err("could not SSL_write");
1324b7579f77SDag-Erling Smørgrav 		return 0;
1325b7579f77SDag-Erling Smørgrav 	}
132617d15b25SDag-Erling Smørgrav 	sldns_buffer_skip(c->buffer, (ssize_t)r);
1327b7579f77SDag-Erling Smørgrav 
132817d15b25SDag-Erling Smørgrav 	if(sldns_buffer_remaining(c->buffer) == 0) {
1329b7579f77SDag-Erling Smørgrav 		tcp_callback_writer(c);
1330b7579f77SDag-Erling Smørgrav 	}
1331b7579f77SDag-Erling Smørgrav 	return 1;
13328ed2b524SDag-Erling Smørgrav #else
13338ed2b524SDag-Erling Smørgrav 	(void)c;
13348ed2b524SDag-Erling Smørgrav 	return 0;
13358ed2b524SDag-Erling Smørgrav #endif /* HAVE_SSL */
1336b7579f77SDag-Erling Smørgrav }
1337b7579f77SDag-Erling Smørgrav 
1338b7579f77SDag-Erling Smørgrav /** handle ssl tcp connection with dns contents */
1339b7579f77SDag-Erling Smørgrav static int
1340b7579f77SDag-Erling Smørgrav ssl_handle_it(struct comm_point* c)
1341b7579f77SDag-Erling Smørgrav {
1342b7579f77SDag-Erling Smørgrav 	if(c->tcp_is_reading)
1343b7579f77SDag-Erling Smørgrav 		return ssl_handle_read(c);
1344b7579f77SDag-Erling Smørgrav 	return ssl_handle_write(c);
1345b7579f77SDag-Erling Smørgrav }
1346b7579f77SDag-Erling Smørgrav 
1347b7579f77SDag-Erling Smørgrav /** Handle tcp reading callback.
1348b7579f77SDag-Erling Smørgrav  * @param fd: file descriptor of socket.
1349b7579f77SDag-Erling Smørgrav  * @param c: comm point to read from into buffer.
1350b7579f77SDag-Erling Smørgrav  * @param short_ok: if true, very short packets are OK (for comm_local).
1351b7579f77SDag-Erling Smørgrav  * @return: 0 on error
1352b7579f77SDag-Erling Smørgrav  */
1353b7579f77SDag-Erling Smørgrav static int
1354b7579f77SDag-Erling Smørgrav comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok)
1355b7579f77SDag-Erling Smørgrav {
1356b7579f77SDag-Erling Smørgrav 	ssize_t r;
1357b7579f77SDag-Erling Smørgrav 	log_assert(c->type == comm_tcp || c->type == comm_local);
1358b7579f77SDag-Erling Smørgrav 	if(c->ssl)
1359b7579f77SDag-Erling Smørgrav 		return ssl_handle_it(c);
1360b7579f77SDag-Erling Smørgrav 	if(!c->tcp_is_reading)
1361b7579f77SDag-Erling Smørgrav 		return 0;
1362b7579f77SDag-Erling Smørgrav 
1363b7579f77SDag-Erling Smørgrav 	log_assert(fd != -1);
1364b7579f77SDag-Erling Smørgrav 	if(c->tcp_byte_count < sizeof(uint16_t)) {
1365b7579f77SDag-Erling Smørgrav 		/* read length bytes */
136617d15b25SDag-Erling Smørgrav 		r = recv(fd,(void*)sldns_buffer_at(c->buffer,c->tcp_byte_count),
1367b7579f77SDag-Erling Smørgrav 			sizeof(uint16_t)-c->tcp_byte_count, 0);
1368b7579f77SDag-Erling Smørgrav 		if(r == 0)
1369b7579f77SDag-Erling Smørgrav 			return 0;
1370b7579f77SDag-Erling Smørgrav 		else if(r == -1) {
1371b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK
1372b7579f77SDag-Erling Smørgrav 			if(errno == EINTR || errno == EAGAIN)
1373b7579f77SDag-Erling Smørgrav 				return 1;
1374b7579f77SDag-Erling Smørgrav #ifdef ECONNRESET
1375b7579f77SDag-Erling Smørgrav 			if(errno == ECONNRESET && verbosity < 2)
1376b7579f77SDag-Erling Smørgrav 				return 0; /* silence reset by peer */
1377b7579f77SDag-Erling Smørgrav #endif
1378ff825849SDag-Erling Smørgrav 			log_err_addr("read (in tcp s)", strerror(errno),
1379ff825849SDag-Erling Smørgrav 				&c->repinfo.addr, c->repinfo.addrlen);
1380b7579f77SDag-Erling Smørgrav #else /* USE_WINSOCK */
1381b7579f77SDag-Erling Smørgrav 			if(WSAGetLastError() == WSAECONNRESET)
1382b7579f77SDag-Erling Smørgrav 				return 0;
1383b7579f77SDag-Erling Smørgrav 			if(WSAGetLastError() == WSAEINPROGRESS)
1384b7579f77SDag-Erling Smørgrav 				return 1;
1385b7579f77SDag-Erling Smørgrav 			if(WSAGetLastError() == WSAEWOULDBLOCK) {
1386e2d15004SDag-Erling Smørgrav 				ub_winsock_tcp_wouldblock(c->ev->ev,
1387e2d15004SDag-Erling Smørgrav 					UB_EV_READ);
1388b7579f77SDag-Erling Smørgrav 				return 1;
1389b7579f77SDag-Erling Smørgrav 			}
1390ff825849SDag-Erling Smørgrav 			log_err_addr("read (in tcp s)",
1391ff825849SDag-Erling Smørgrav 				wsa_strerror(WSAGetLastError()),
1392ff825849SDag-Erling Smørgrav 				&c->repinfo.addr, c->repinfo.addrlen);
1393b7579f77SDag-Erling Smørgrav #endif
1394b7579f77SDag-Erling Smørgrav 			return 0;
1395b7579f77SDag-Erling Smørgrav 		}
1396b7579f77SDag-Erling Smørgrav 		c->tcp_byte_count += r;
1397b7579f77SDag-Erling Smørgrav 		if(c->tcp_byte_count != sizeof(uint16_t))
1398b7579f77SDag-Erling Smørgrav 			return 1;
139917d15b25SDag-Erling Smørgrav 		if(sldns_buffer_read_u16_at(c->buffer, 0) >
140017d15b25SDag-Erling Smørgrav 			sldns_buffer_capacity(c->buffer)) {
1401b7579f77SDag-Erling Smørgrav 			verbose(VERB_QUERY, "tcp: dropped larger than buffer");
1402b7579f77SDag-Erling Smørgrav 			return 0;
1403b7579f77SDag-Erling Smørgrav 		}
140417d15b25SDag-Erling Smørgrav 		sldns_buffer_set_limit(c->buffer,
140517d15b25SDag-Erling Smørgrav 			sldns_buffer_read_u16_at(c->buffer, 0));
1406b7579f77SDag-Erling Smørgrav 		if(!short_ok &&
140717d15b25SDag-Erling Smørgrav 			sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE) {
1408b7579f77SDag-Erling Smørgrav 			verbose(VERB_QUERY, "tcp: dropped bogus too short.");
1409b7579f77SDag-Erling Smørgrav 			return 0;
1410b7579f77SDag-Erling Smørgrav 		}
1411b7579f77SDag-Erling Smørgrav 		verbose(VERB_ALGO, "Reading tcp query of length %d",
141217d15b25SDag-Erling Smørgrav 			(int)sldns_buffer_limit(c->buffer));
1413b7579f77SDag-Erling Smørgrav 	}
1414b7579f77SDag-Erling Smørgrav 
141517d15b25SDag-Erling Smørgrav 	log_assert(sldns_buffer_remaining(c->buffer) > 0);
141617d15b25SDag-Erling Smørgrav 	r = recv(fd, (void*)sldns_buffer_current(c->buffer),
141717d15b25SDag-Erling Smørgrav 		sldns_buffer_remaining(c->buffer), 0);
1418b7579f77SDag-Erling Smørgrav 	if(r == 0) {
1419b7579f77SDag-Erling Smørgrav 		return 0;
1420b7579f77SDag-Erling Smørgrav 	} else if(r == -1) {
1421b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK
1422b7579f77SDag-Erling Smørgrav 		if(errno == EINTR || errno == EAGAIN)
1423b7579f77SDag-Erling Smørgrav 			return 1;
1424ff825849SDag-Erling Smørgrav 		log_err_addr("read (in tcp r)", strerror(errno),
1425ff825849SDag-Erling Smørgrav 			&c->repinfo.addr, c->repinfo.addrlen);
1426b7579f77SDag-Erling Smørgrav #else /* USE_WINSOCK */
1427b7579f77SDag-Erling Smørgrav 		if(WSAGetLastError() == WSAECONNRESET)
1428b7579f77SDag-Erling Smørgrav 			return 0;
1429b7579f77SDag-Erling Smørgrav 		if(WSAGetLastError() == WSAEINPROGRESS)
1430b7579f77SDag-Erling Smørgrav 			return 1;
1431b7579f77SDag-Erling Smørgrav 		if(WSAGetLastError() == WSAEWOULDBLOCK) {
1432e2d15004SDag-Erling Smørgrav 			ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
1433b7579f77SDag-Erling Smørgrav 			return 1;
1434b7579f77SDag-Erling Smørgrav 		}
1435ff825849SDag-Erling Smørgrav 		log_err_addr("read (in tcp r)",
1436ff825849SDag-Erling Smørgrav 			wsa_strerror(WSAGetLastError()),
1437ff825849SDag-Erling Smørgrav 			&c->repinfo.addr, c->repinfo.addrlen);
1438b7579f77SDag-Erling Smørgrav #endif
1439b7579f77SDag-Erling Smørgrav 		return 0;
1440b7579f77SDag-Erling Smørgrav 	}
144117d15b25SDag-Erling Smørgrav 	sldns_buffer_skip(c->buffer, r);
144217d15b25SDag-Erling Smørgrav 	if(sldns_buffer_remaining(c->buffer) <= 0) {
1443b7579f77SDag-Erling Smørgrav 		tcp_callback_reader(c);
1444b7579f77SDag-Erling Smørgrav 	}
1445b7579f77SDag-Erling Smørgrav 	return 1;
1446b7579f77SDag-Erling Smørgrav }
1447b7579f77SDag-Erling Smørgrav 
1448b7579f77SDag-Erling Smørgrav /**
1449b7579f77SDag-Erling Smørgrav  * Handle tcp writing callback.
1450b7579f77SDag-Erling Smørgrav  * @param fd: file descriptor of socket.
1451b7579f77SDag-Erling Smørgrav  * @param c: comm point to write buffer out of.
1452b7579f77SDag-Erling Smørgrav  * @return: 0 on error
1453b7579f77SDag-Erling Smørgrav  */
1454b7579f77SDag-Erling Smørgrav static int
1455b7579f77SDag-Erling Smørgrav comm_point_tcp_handle_write(int fd, struct comm_point* c)
1456b7579f77SDag-Erling Smørgrav {
1457b7579f77SDag-Erling Smørgrav 	ssize_t r;
145865b390aaSDag-Erling Smørgrav 	struct sldns_buffer *buffer;
1459b7579f77SDag-Erling Smørgrav 	log_assert(c->type == comm_tcp);
146065b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT
146165b390aaSDag-Erling Smørgrav 	buffer = c->dnscrypt_buffer;
146265b390aaSDag-Erling Smørgrav #else
146365b390aaSDag-Erling Smørgrav 	buffer = c->buffer;
146465b390aaSDag-Erling Smørgrav #endif
1465b7579f77SDag-Erling Smørgrav 	if(c->tcp_is_reading && !c->ssl)
1466b7579f77SDag-Erling Smørgrav 		return 0;
1467b7579f77SDag-Erling Smørgrav 	log_assert(fd != -1);
1468b7579f77SDag-Erling Smørgrav 	if(c->tcp_byte_count == 0 && c->tcp_check_nb_connect) {
1469b7579f77SDag-Erling Smørgrav 		/* check for pending error from nonblocking connect */
1470b7579f77SDag-Erling Smørgrav 		/* from Stevens, unix network programming, vol1, 3rd ed, p450*/
1471b7579f77SDag-Erling Smørgrav 		int error = 0;
1472b7579f77SDag-Erling Smørgrav 		socklen_t len = (socklen_t)sizeof(error);
1473b7579f77SDag-Erling Smørgrav 		if(getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&error,
1474b7579f77SDag-Erling Smørgrav 			&len) < 0){
1475b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK
1476b7579f77SDag-Erling Smørgrav 			error = errno; /* on solaris errno is error */
1477b7579f77SDag-Erling Smørgrav #else /* USE_WINSOCK */
1478b7579f77SDag-Erling Smørgrav 			error = WSAGetLastError();
1479b7579f77SDag-Erling Smørgrav #endif
1480b7579f77SDag-Erling Smørgrav 		}
1481b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK
1482b7579f77SDag-Erling Smørgrav #if defined(EINPROGRESS) && defined(EWOULDBLOCK)
1483b7579f77SDag-Erling Smørgrav 		if(error == EINPROGRESS || error == EWOULDBLOCK)
1484b7579f77SDag-Erling Smørgrav 			return 1; /* try again later */
1485b7579f77SDag-Erling Smørgrav 		else
1486b7579f77SDag-Erling Smørgrav #endif
1487b7579f77SDag-Erling Smørgrav 		if(error != 0 && verbosity < 2)
1488b7579f77SDag-Erling Smørgrav 			return 0; /* silence lots of chatter in the logs */
1489b7579f77SDag-Erling Smørgrav                 else if(error != 0) {
1490ff825849SDag-Erling Smørgrav 			log_err_addr("tcp connect", strerror(error),
1491ff825849SDag-Erling Smørgrav 				&c->repinfo.addr, c->repinfo.addrlen);
1492b7579f77SDag-Erling Smørgrav #else /* USE_WINSOCK */
1493b7579f77SDag-Erling Smørgrav 		/* examine error */
1494b7579f77SDag-Erling Smørgrav 		if(error == WSAEINPROGRESS)
1495b7579f77SDag-Erling Smørgrav 			return 1;
1496b7579f77SDag-Erling Smørgrav 		else if(error == WSAEWOULDBLOCK) {
1497e2d15004SDag-Erling Smørgrav 			ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
1498b7579f77SDag-Erling Smørgrav 			return 1;
1499b7579f77SDag-Erling Smørgrav 		} else if(error != 0 && verbosity < 2)
1500b7579f77SDag-Erling Smørgrav 			return 0;
1501b7579f77SDag-Erling Smørgrav 		else if(error != 0) {
1502ff825849SDag-Erling Smørgrav 			log_err_addr("tcp connect", wsa_strerror(error),
1503ff825849SDag-Erling Smørgrav 				&c->repinfo.addr, c->repinfo.addrlen);
1504b7579f77SDag-Erling Smørgrav #endif /* USE_WINSOCK */
1505b7579f77SDag-Erling Smørgrav 			return 0;
1506b7579f77SDag-Erling Smørgrav 		}
1507b7579f77SDag-Erling Smørgrav 	}
1508b7579f77SDag-Erling Smørgrav 	if(c->ssl)
1509b7579f77SDag-Erling Smørgrav 		return ssl_handle_it(c);
1510b7579f77SDag-Erling Smørgrav 
1511b5663de9SDag-Erling Smørgrav #ifdef USE_MSG_FASTOPEN
1512b5663de9SDag-Erling Smørgrav 	/* Only try this on first use of a connection that uses tfo,
1513b5663de9SDag-Erling Smørgrav 	   otherwise fall through to normal write */
1514b5663de9SDag-Erling Smørgrav 	/* Also, TFO support on WINDOWS not implemented at the moment */
1515b5663de9SDag-Erling Smørgrav 	if(c->tcp_do_fastopen == 1) {
1516b5663de9SDag-Erling Smørgrav 		/* this form of sendmsg() does both a connect() and send() so need to
1517b5663de9SDag-Erling Smørgrav 		   look for various flavours of error*/
151865b390aaSDag-Erling Smørgrav 		uint16_t len = htons(sldns_buffer_limit(buffer));
1519b5663de9SDag-Erling Smørgrav 		struct msghdr msg;
1520b5663de9SDag-Erling Smørgrav 		struct iovec iov[2];
1521b5663de9SDag-Erling Smørgrav 		c->tcp_do_fastopen = 0;
1522b5663de9SDag-Erling Smørgrav 		memset(&msg, 0, sizeof(msg));
1523b5663de9SDag-Erling Smørgrav 		iov[0].iov_base = (uint8_t*)&len + c->tcp_byte_count;
1524b5663de9SDag-Erling Smørgrav 		iov[0].iov_len = sizeof(uint16_t) - c->tcp_byte_count;
152565b390aaSDag-Erling Smørgrav 		iov[1].iov_base = sldns_buffer_begin(buffer);
152665b390aaSDag-Erling Smørgrav 		iov[1].iov_len = sldns_buffer_limit(buffer);
1527b5663de9SDag-Erling Smørgrav 		log_assert(iov[0].iov_len > 0);
1528b5663de9SDag-Erling Smørgrav 		log_assert(iov[1].iov_len > 0);
1529b5663de9SDag-Erling Smørgrav 		msg.msg_name = &c->repinfo.addr;
1530b5663de9SDag-Erling Smørgrav 		msg.msg_namelen = c->repinfo.addrlen;
1531b5663de9SDag-Erling Smørgrav 		msg.msg_iov = iov;
1532b5663de9SDag-Erling Smørgrav 		msg.msg_iovlen = 2;
1533b5663de9SDag-Erling Smørgrav 		r = sendmsg(fd, &msg, MSG_FASTOPEN);
1534b5663de9SDag-Erling Smørgrav 		if (r == -1) {
1535b5663de9SDag-Erling Smørgrav #if defined(EINPROGRESS) && defined(EWOULDBLOCK)
1536b5663de9SDag-Erling Smørgrav 			/* Handshake is underway, maybe because no TFO cookie available.
15378a384985SDag-Erling Smørgrav 			   Come back to write the message*/
1538b5663de9SDag-Erling Smørgrav 			if(errno == EINPROGRESS || errno == EWOULDBLOCK)
1539b5663de9SDag-Erling Smørgrav 				return 1;
1540b5663de9SDag-Erling Smørgrav #endif
1541b5663de9SDag-Erling Smørgrav 			if(errno == EINTR || errno == EAGAIN)
1542b5663de9SDag-Erling Smørgrav 				return 1;
1543b5663de9SDag-Erling Smørgrav 			/* Not handling EISCONN here as shouldn't ever hit that case.*/
1544c7f4d7adSDag-Erling Smørgrav 			if(errno != EPIPE && errno != 0 && verbosity < 2)
1545b5663de9SDag-Erling Smørgrav 				return 0; /* silence lots of chatter in the logs */
1546c7f4d7adSDag-Erling Smørgrav 			if(errno != EPIPE && errno != 0) {
1547b5663de9SDag-Erling Smørgrav 				log_err_addr("tcp sendmsg", strerror(errno),
1548b5663de9SDag-Erling Smørgrav 					&c->repinfo.addr, c->repinfo.addrlen);
1549b5663de9SDag-Erling Smørgrav 				return 0;
1550c7f4d7adSDag-Erling Smørgrav 			}
1551c7f4d7adSDag-Erling Smørgrav 			/* fallthrough to nonFASTOPEN
1552c7f4d7adSDag-Erling Smørgrav 			 * (MSG_FASTOPEN on Linux 3 produces EPIPE)
1553c7f4d7adSDag-Erling Smørgrav 			 * we need to perform connect() */
1554c7f4d7adSDag-Erling Smørgrav 			if(connect(fd, (struct sockaddr *)&c->repinfo.addr, c->repinfo.addrlen) == -1) {
1555c7f4d7adSDag-Erling Smørgrav #ifdef EINPROGRESS
1556c7f4d7adSDag-Erling Smørgrav 				if(errno == EINPROGRESS)
1557c7f4d7adSDag-Erling Smørgrav 					return 1; /* wait until connect done*/
1558c7f4d7adSDag-Erling Smørgrav #endif
1559c7f4d7adSDag-Erling Smørgrav #ifdef USE_WINSOCK
1560c7f4d7adSDag-Erling Smørgrav 				if(WSAGetLastError() == WSAEINPROGRESS ||
1561c7f4d7adSDag-Erling Smørgrav 					WSAGetLastError() == WSAEWOULDBLOCK)
1562c7f4d7adSDag-Erling Smørgrav 					return 1; /* wait until connect done*/
1563c7f4d7adSDag-Erling Smørgrav #endif
1564c7f4d7adSDag-Erling Smørgrav 				if(tcp_connect_errno_needs_log(
1565c7f4d7adSDag-Erling Smørgrav 					(struct sockaddr *)&c->repinfo.addr, c->repinfo.addrlen)) {
1566c7f4d7adSDag-Erling Smørgrav 					log_err_addr("outgoing tcp: connect after EPIPE for fastopen",
1567c7f4d7adSDag-Erling Smørgrav 						strerror(errno), &c->repinfo.addr, c->repinfo.addrlen);
1568c7f4d7adSDag-Erling Smørgrav 				}
1569c7f4d7adSDag-Erling Smørgrav 				return 0;
1570c7f4d7adSDag-Erling Smørgrav 			}
1571c7f4d7adSDag-Erling Smørgrav 
1572b5663de9SDag-Erling Smørgrav 		} else {
1573b5663de9SDag-Erling Smørgrav 			c->tcp_byte_count += r;
1574b5663de9SDag-Erling Smørgrav 			if(c->tcp_byte_count < sizeof(uint16_t))
1575b5663de9SDag-Erling Smørgrav 				return 1;
157665b390aaSDag-Erling Smørgrav 			sldns_buffer_set_position(buffer, c->tcp_byte_count -
1577b5663de9SDag-Erling Smørgrav 				sizeof(uint16_t));
157865b390aaSDag-Erling Smørgrav 			if(sldns_buffer_remaining(buffer) == 0) {
1579b5663de9SDag-Erling Smørgrav 				tcp_callback_writer(c);
1580b5663de9SDag-Erling Smørgrav 				return 1;
1581b5663de9SDag-Erling Smørgrav 			}
1582b5663de9SDag-Erling Smørgrav 		}
1583b5663de9SDag-Erling Smørgrav 	}
1584b5663de9SDag-Erling Smørgrav #endif /* USE_MSG_FASTOPEN */
1585b5663de9SDag-Erling Smørgrav 
1586b7579f77SDag-Erling Smørgrav 	if(c->tcp_byte_count < sizeof(uint16_t)) {
158765b390aaSDag-Erling Smørgrav 		uint16_t len = htons(sldns_buffer_limit(buffer));
1588b7579f77SDag-Erling Smørgrav #ifdef HAVE_WRITEV
1589b7579f77SDag-Erling Smørgrav 		struct iovec iov[2];
1590b7579f77SDag-Erling Smørgrav 		iov[0].iov_base = (uint8_t*)&len + c->tcp_byte_count;
1591b7579f77SDag-Erling Smørgrav 		iov[0].iov_len = sizeof(uint16_t) - c->tcp_byte_count;
159265b390aaSDag-Erling Smørgrav 		iov[1].iov_base = sldns_buffer_begin(buffer);
159365b390aaSDag-Erling Smørgrav 		iov[1].iov_len = sldns_buffer_limit(buffer);
1594b7579f77SDag-Erling Smørgrav 		log_assert(iov[0].iov_len > 0);
1595b7579f77SDag-Erling Smørgrav 		log_assert(iov[1].iov_len > 0);
1596b7579f77SDag-Erling Smørgrav 		r = writev(fd, iov, 2);
1597b7579f77SDag-Erling Smørgrav #else /* HAVE_WRITEV */
1598b7579f77SDag-Erling Smørgrav 		r = send(fd, (void*)(((uint8_t*)&len)+c->tcp_byte_count),
1599b7579f77SDag-Erling Smørgrav 			sizeof(uint16_t)-c->tcp_byte_count, 0);
1600b7579f77SDag-Erling Smørgrav #endif /* HAVE_WRITEV */
1601b7579f77SDag-Erling Smørgrav 		if(r == -1) {
1602b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK
1603b7579f77SDag-Erling Smørgrav #  ifdef EPIPE
1604b7579f77SDag-Erling Smørgrav                 	if(errno == EPIPE && verbosity < 2)
1605b7579f77SDag-Erling Smørgrav                         	return 0; /* silence 'broken pipe' */
1606b7579f77SDag-Erling Smørgrav   #endif
1607b7579f77SDag-Erling Smørgrav 			if(errno == EINTR || errno == EAGAIN)
1608b7579f77SDag-Erling Smørgrav 				return 1;
1609ff825849SDag-Erling Smørgrav #  ifdef HAVE_WRITEV
1610ff825849SDag-Erling Smørgrav 			log_err_addr("tcp writev", strerror(errno),
1611ff825849SDag-Erling Smørgrav 				&c->repinfo.addr, c->repinfo.addrlen);
1612ff825849SDag-Erling Smørgrav #  else /* HAVE_WRITEV */
1613ff825849SDag-Erling Smørgrav 			log_err_addr("tcp send s", strerror(errno),
1614ff825849SDag-Erling Smørgrav 				&c->repinfo.addr, c->repinfo.addrlen);
1615ff825849SDag-Erling Smørgrav #  endif /* HAVE_WRITEV */
1616b7579f77SDag-Erling Smørgrav #else
1617b7579f77SDag-Erling Smørgrav 			if(WSAGetLastError() == WSAENOTCONN)
1618b7579f77SDag-Erling Smørgrav 				return 1;
1619b7579f77SDag-Erling Smørgrav 			if(WSAGetLastError() == WSAEINPROGRESS)
1620b7579f77SDag-Erling Smørgrav 				return 1;
1621b7579f77SDag-Erling Smørgrav 			if(WSAGetLastError() == WSAEWOULDBLOCK) {
1622e2d15004SDag-Erling Smørgrav 				ub_winsock_tcp_wouldblock(c->ev->ev,
1623e2d15004SDag-Erling Smørgrav 					UB_EV_WRITE);
1624b7579f77SDag-Erling Smørgrav 				return 1;
1625b7579f77SDag-Erling Smørgrav 			}
1626ff825849SDag-Erling Smørgrav 			log_err_addr("tcp send s",
1627ff825849SDag-Erling Smørgrav 				wsa_strerror(WSAGetLastError()),
1628ff825849SDag-Erling Smørgrav 				&c->repinfo.addr, c->repinfo.addrlen);
1629b7579f77SDag-Erling Smørgrav #endif
1630b7579f77SDag-Erling Smørgrav 			return 0;
1631b7579f77SDag-Erling Smørgrav 		}
1632b7579f77SDag-Erling Smørgrav 		c->tcp_byte_count += r;
1633b7579f77SDag-Erling Smørgrav 		if(c->tcp_byte_count < sizeof(uint16_t))
1634b7579f77SDag-Erling Smørgrav 			return 1;
163565b390aaSDag-Erling Smørgrav 		sldns_buffer_set_position(buffer, c->tcp_byte_count -
1636b7579f77SDag-Erling Smørgrav 			sizeof(uint16_t));
163765b390aaSDag-Erling Smørgrav 		if(sldns_buffer_remaining(buffer) == 0) {
1638b7579f77SDag-Erling Smørgrav 			tcp_callback_writer(c);
1639b7579f77SDag-Erling Smørgrav 			return 1;
1640b7579f77SDag-Erling Smørgrav 		}
1641b7579f77SDag-Erling Smørgrav 	}
164265b390aaSDag-Erling Smørgrav 	log_assert(sldns_buffer_remaining(buffer) > 0);
164365b390aaSDag-Erling Smørgrav 	r = send(fd, (void*)sldns_buffer_current(buffer),
164465b390aaSDag-Erling Smørgrav 		sldns_buffer_remaining(buffer), 0);
1645b7579f77SDag-Erling Smørgrav 	if(r == -1) {
1646b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK
1647b7579f77SDag-Erling Smørgrav 		if(errno == EINTR || errno == EAGAIN)
1648b7579f77SDag-Erling Smørgrav 			return 1;
1649ff825849SDag-Erling Smørgrav 		log_err_addr("tcp send r", strerror(errno),
1650ff825849SDag-Erling Smørgrav 			&c->repinfo.addr, c->repinfo.addrlen);
1651b7579f77SDag-Erling Smørgrav #else
1652b7579f77SDag-Erling Smørgrav 		if(WSAGetLastError() == WSAEINPROGRESS)
1653b7579f77SDag-Erling Smørgrav 			return 1;
1654b7579f77SDag-Erling Smørgrav 		if(WSAGetLastError() == WSAEWOULDBLOCK) {
1655e2d15004SDag-Erling Smørgrav 			ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
1656b7579f77SDag-Erling Smørgrav 			return 1;
1657b7579f77SDag-Erling Smørgrav 		}
1658ff825849SDag-Erling Smørgrav 		log_err_addr("tcp send r", wsa_strerror(WSAGetLastError()),
1659ff825849SDag-Erling Smørgrav 			&c->repinfo.addr, c->repinfo.addrlen);
1660b7579f77SDag-Erling Smørgrav #endif
1661b7579f77SDag-Erling Smørgrav 		return 0;
1662b7579f77SDag-Erling Smørgrav 	}
166365b390aaSDag-Erling Smørgrav 	sldns_buffer_skip(buffer, r);
1664b7579f77SDag-Erling Smørgrav 
166565b390aaSDag-Erling Smørgrav 	if(sldns_buffer_remaining(buffer) == 0) {
1666b7579f77SDag-Erling Smørgrav 		tcp_callback_writer(c);
1667b7579f77SDag-Erling Smørgrav 	}
1668b7579f77SDag-Erling Smørgrav 
1669b7579f77SDag-Erling Smørgrav 	return 1;
1670b7579f77SDag-Erling Smørgrav }
1671b7579f77SDag-Erling Smørgrav 
1672b7579f77SDag-Erling Smørgrav void
1673b7579f77SDag-Erling Smørgrav comm_point_tcp_handle_callback(int fd, short event, void* arg)
1674b7579f77SDag-Erling Smørgrav {
1675b7579f77SDag-Erling Smørgrav 	struct comm_point* c = (struct comm_point*)arg;
1676b7579f77SDag-Erling Smørgrav 	log_assert(c->type == comm_tcp);
1677e2d15004SDag-Erling Smørgrav 	ub_comm_base_now(c->ev->base);
1678b7579f77SDag-Erling Smørgrav 
167965b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT
168065b390aaSDag-Erling Smørgrav 	/* Initialize if this is a dnscrypt socket */
168165b390aaSDag-Erling Smørgrav 	if(c->tcp_parent) {
168265b390aaSDag-Erling Smørgrav 		c->dnscrypt = c->tcp_parent->dnscrypt;
168365b390aaSDag-Erling Smørgrav 	}
168465b390aaSDag-Erling Smørgrav 	if(c->dnscrypt && c->dnscrypt_buffer == c->buffer) {
168565b390aaSDag-Erling Smørgrav 		c->dnscrypt_buffer = sldns_buffer_new(sldns_buffer_capacity(c->buffer));
168665b390aaSDag-Erling Smørgrav 		if(!c->dnscrypt_buffer) {
168765b390aaSDag-Erling Smørgrav 			log_err("Could not allocate dnscrypt buffer");
1688971980c3SDag-Erling Smørgrav 			reclaim_tcp_handler(c);
1689971980c3SDag-Erling Smørgrav 			if(!c->tcp_do_close) {
1690971980c3SDag-Erling Smørgrav 				fptr_ok(fptr_whitelist_comm_point(
1691971980c3SDag-Erling Smørgrav 					c->callback));
1692971980c3SDag-Erling Smørgrav 				(void)(*c->callback)(c, c->cb_arg,
1693971980c3SDag-Erling Smørgrav 					NETEVENT_CLOSED, NULL);
1694971980c3SDag-Erling Smørgrav 			}
169565b390aaSDag-Erling Smørgrav 			return;
169665b390aaSDag-Erling Smørgrav 		}
169765b390aaSDag-Erling Smørgrav 	}
169865b390aaSDag-Erling Smørgrav #endif
169965b390aaSDag-Erling Smørgrav 
1700e2d15004SDag-Erling Smørgrav 	if(event&UB_EV_READ) {
1701b7579f77SDag-Erling Smørgrav 		if(!comm_point_tcp_handle_read(fd, c, 0)) {
1702b7579f77SDag-Erling Smørgrav 			reclaim_tcp_handler(c);
1703b7579f77SDag-Erling Smørgrav 			if(!c->tcp_do_close) {
1704b7579f77SDag-Erling Smørgrav 				fptr_ok(fptr_whitelist_comm_point(
1705b7579f77SDag-Erling Smørgrav 					c->callback));
1706b7579f77SDag-Erling Smørgrav 				(void)(*c->callback)(c, c->cb_arg,
1707b7579f77SDag-Erling Smørgrav 					NETEVENT_CLOSED, NULL);
1708b7579f77SDag-Erling Smørgrav 			}
1709b7579f77SDag-Erling Smørgrav 		}
1710b7579f77SDag-Erling Smørgrav 		return;
1711b7579f77SDag-Erling Smørgrav 	}
1712e2d15004SDag-Erling Smørgrav 	if(event&UB_EV_WRITE) {
1713b7579f77SDag-Erling Smørgrav 		if(!comm_point_tcp_handle_write(fd, c)) {
1714b7579f77SDag-Erling Smørgrav 			reclaim_tcp_handler(c);
1715b7579f77SDag-Erling Smørgrav 			if(!c->tcp_do_close) {
1716b7579f77SDag-Erling Smørgrav 				fptr_ok(fptr_whitelist_comm_point(
1717b7579f77SDag-Erling Smørgrav 					c->callback));
1718b7579f77SDag-Erling Smørgrav 				(void)(*c->callback)(c, c->cb_arg,
1719b7579f77SDag-Erling Smørgrav 					NETEVENT_CLOSED, NULL);
1720b7579f77SDag-Erling Smørgrav 			}
1721b7579f77SDag-Erling Smørgrav 		}
1722b7579f77SDag-Erling Smørgrav 		return;
1723b7579f77SDag-Erling Smørgrav 	}
1724e2d15004SDag-Erling Smørgrav 	if(event&UB_EV_TIMEOUT) {
1725b7579f77SDag-Erling Smørgrav 		verbose(VERB_QUERY, "tcp took too long, dropped");
1726b7579f77SDag-Erling Smørgrav 		reclaim_tcp_handler(c);
1727b7579f77SDag-Erling Smørgrav 		if(!c->tcp_do_close) {
1728b7579f77SDag-Erling Smørgrav 			fptr_ok(fptr_whitelist_comm_point(c->callback));
1729b7579f77SDag-Erling Smørgrav 			(void)(*c->callback)(c, c->cb_arg,
1730b7579f77SDag-Erling Smørgrav 				NETEVENT_TIMEOUT, NULL);
1731b7579f77SDag-Erling Smørgrav 		}
1732b7579f77SDag-Erling Smørgrav 		return;
1733b7579f77SDag-Erling Smørgrav 	}
1734b7579f77SDag-Erling Smørgrav 	log_err("Ignored event %d for tcphdl.", event);
1735b7579f77SDag-Erling Smørgrav }
1736b7579f77SDag-Erling Smørgrav 
173757bddd21SDag-Erling Smørgrav /** Make http handler free for next assignment */
173857bddd21SDag-Erling Smørgrav static void
173957bddd21SDag-Erling Smørgrav reclaim_http_handler(struct comm_point* c)
174057bddd21SDag-Erling Smørgrav {
174157bddd21SDag-Erling Smørgrav 	log_assert(c->type == comm_http);
174257bddd21SDag-Erling Smørgrav 	if(c->ssl) {
174357bddd21SDag-Erling Smørgrav #ifdef HAVE_SSL
174457bddd21SDag-Erling Smørgrav 		SSL_shutdown(c->ssl);
174557bddd21SDag-Erling Smørgrav 		SSL_free(c->ssl);
174657bddd21SDag-Erling Smørgrav 		c->ssl = NULL;
174757bddd21SDag-Erling Smørgrav #endif
174857bddd21SDag-Erling Smørgrav 	}
174957bddd21SDag-Erling Smørgrav 	comm_point_close(c);
175057bddd21SDag-Erling Smørgrav 	if(c->tcp_parent) {
175157bddd21SDag-Erling Smørgrav 		c->tcp_parent->cur_tcp_count--;
175257bddd21SDag-Erling Smørgrav 		c->tcp_free = c->tcp_parent->tcp_free;
175357bddd21SDag-Erling Smørgrav 		c->tcp_parent->tcp_free = c;
175457bddd21SDag-Erling Smørgrav 		if(!c->tcp_free) {
175557bddd21SDag-Erling Smørgrav 			/* re-enable listening on accept socket */
175657bddd21SDag-Erling Smørgrav 			comm_point_start_listening(c->tcp_parent, -1, -1);
175757bddd21SDag-Erling Smørgrav 		}
175857bddd21SDag-Erling Smørgrav 	}
175957bddd21SDag-Erling Smørgrav }
176057bddd21SDag-Erling Smørgrav 
176157bddd21SDag-Erling Smørgrav /** read more data for http (with ssl) */
176257bddd21SDag-Erling Smørgrav static int
176357bddd21SDag-Erling Smørgrav ssl_http_read_more(struct comm_point* c)
176457bddd21SDag-Erling Smørgrav {
176557bddd21SDag-Erling Smørgrav #ifdef HAVE_SSL
176657bddd21SDag-Erling Smørgrav 	int r;
176757bddd21SDag-Erling Smørgrav 	log_assert(sldns_buffer_remaining(c->buffer) > 0);
176857bddd21SDag-Erling Smørgrav 	ERR_clear_error();
176957bddd21SDag-Erling Smørgrav 	r = SSL_read(c->ssl, (void*)sldns_buffer_current(c->buffer),
177057bddd21SDag-Erling Smørgrav 		(int)sldns_buffer_remaining(c->buffer));
177157bddd21SDag-Erling Smørgrav 	if(r <= 0) {
177257bddd21SDag-Erling Smørgrav 		int want = SSL_get_error(c->ssl, r);
177357bddd21SDag-Erling Smørgrav 		if(want == SSL_ERROR_ZERO_RETURN) {
177457bddd21SDag-Erling Smørgrav 			return 0; /* shutdown, closed */
177557bddd21SDag-Erling Smørgrav 		} else if(want == SSL_ERROR_WANT_READ) {
177657bddd21SDag-Erling Smørgrav 			return 1; /* read more later */
177757bddd21SDag-Erling Smørgrav 		} else if(want == SSL_ERROR_WANT_WRITE) {
177857bddd21SDag-Erling Smørgrav 			c->ssl_shake_state = comm_ssl_shake_hs_write;
177957bddd21SDag-Erling Smørgrav 			comm_point_listen_for_rw(c, 0, 1);
178057bddd21SDag-Erling Smørgrav 			return 1;
178157bddd21SDag-Erling Smørgrav 		} else if(want == SSL_ERROR_SYSCALL) {
178257bddd21SDag-Erling Smørgrav 			if(errno != 0)
178357bddd21SDag-Erling Smørgrav 				log_err("SSL_read syscall: %s",
178457bddd21SDag-Erling Smørgrav 					strerror(errno));
178557bddd21SDag-Erling Smørgrav 			return 0;
178657bddd21SDag-Erling Smørgrav 		}
178757bddd21SDag-Erling Smørgrav 		log_crypto_err("could not SSL_read");
178857bddd21SDag-Erling Smørgrav 		return 0;
178957bddd21SDag-Erling Smørgrav 	}
179057bddd21SDag-Erling Smørgrav 	sldns_buffer_skip(c->buffer, (ssize_t)r);
179157bddd21SDag-Erling Smørgrav 	return 1;
179257bddd21SDag-Erling Smørgrav #else
179357bddd21SDag-Erling Smørgrav 	(void)c;
179457bddd21SDag-Erling Smørgrav 	return 0;
179557bddd21SDag-Erling Smørgrav #endif /* HAVE_SSL */
179657bddd21SDag-Erling Smørgrav }
179757bddd21SDag-Erling Smørgrav 
179857bddd21SDag-Erling Smørgrav /** read more data for http */
179957bddd21SDag-Erling Smørgrav static int
180057bddd21SDag-Erling Smørgrav http_read_more(int fd, struct comm_point* c)
180157bddd21SDag-Erling Smørgrav {
180257bddd21SDag-Erling Smørgrav 	ssize_t r;
180357bddd21SDag-Erling Smørgrav 	log_assert(sldns_buffer_remaining(c->buffer) > 0);
180457bddd21SDag-Erling Smørgrav 	r = recv(fd, (void*)sldns_buffer_current(c->buffer),
180557bddd21SDag-Erling Smørgrav 		sldns_buffer_remaining(c->buffer), 0);
180657bddd21SDag-Erling Smørgrav 	if(r == 0) {
180757bddd21SDag-Erling Smørgrav 		return 0;
180857bddd21SDag-Erling Smørgrav 	} else if(r == -1) {
180957bddd21SDag-Erling Smørgrav #ifndef USE_WINSOCK
181057bddd21SDag-Erling Smørgrav 		if(errno == EINTR || errno == EAGAIN)
181157bddd21SDag-Erling Smørgrav 			return 1;
181257bddd21SDag-Erling Smørgrav 		log_err_addr("read (in http r)", strerror(errno),
181357bddd21SDag-Erling Smørgrav 			&c->repinfo.addr, c->repinfo.addrlen);
181457bddd21SDag-Erling Smørgrav #else /* USE_WINSOCK */
181557bddd21SDag-Erling Smørgrav 		if(WSAGetLastError() == WSAECONNRESET)
181657bddd21SDag-Erling Smørgrav 			return 0;
181757bddd21SDag-Erling Smørgrav 		if(WSAGetLastError() == WSAEINPROGRESS)
181857bddd21SDag-Erling Smørgrav 			return 1;
181957bddd21SDag-Erling Smørgrav 		if(WSAGetLastError() == WSAEWOULDBLOCK) {
182057bddd21SDag-Erling Smørgrav 			ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
182157bddd21SDag-Erling Smørgrav 			return 1;
182257bddd21SDag-Erling Smørgrav 		}
182357bddd21SDag-Erling Smørgrav 		log_err_addr("read (in http r)",
182457bddd21SDag-Erling Smørgrav 			wsa_strerror(WSAGetLastError()),
182557bddd21SDag-Erling Smørgrav 			&c->repinfo.addr, c->repinfo.addrlen);
182657bddd21SDag-Erling Smørgrav #endif
182757bddd21SDag-Erling Smørgrav 		return 0;
182857bddd21SDag-Erling Smørgrav 	}
182957bddd21SDag-Erling Smørgrav 	sldns_buffer_skip(c->buffer, r);
183057bddd21SDag-Erling Smørgrav 	return 1;
183157bddd21SDag-Erling Smørgrav }
183257bddd21SDag-Erling Smørgrav 
183357bddd21SDag-Erling Smørgrav /** return true if http header has been read (one line complete) */
183457bddd21SDag-Erling Smørgrav static int
183557bddd21SDag-Erling Smørgrav http_header_done(sldns_buffer* buf)
183657bddd21SDag-Erling Smørgrav {
183757bddd21SDag-Erling Smørgrav 	size_t i;
183857bddd21SDag-Erling Smørgrav 	for(i=sldns_buffer_position(buf); i<sldns_buffer_limit(buf); i++) {
183957bddd21SDag-Erling Smørgrav 		/* there was a \r before the \n, but we ignore that */
184057bddd21SDag-Erling Smørgrav 		if((char)sldns_buffer_read_u8_at(buf, i) == '\n')
184157bddd21SDag-Erling Smørgrav 			return 1;
184257bddd21SDag-Erling Smørgrav 	}
184357bddd21SDag-Erling Smørgrav 	return 0;
184457bddd21SDag-Erling Smørgrav }
184557bddd21SDag-Erling Smørgrav 
184657bddd21SDag-Erling Smørgrav /** return character string into buffer for header line, moves buffer
184757bddd21SDag-Erling Smørgrav  * past that line and puts zero terminator into linefeed-newline */
184857bddd21SDag-Erling Smørgrav static char*
184957bddd21SDag-Erling Smørgrav http_header_line(sldns_buffer* buf)
185057bddd21SDag-Erling Smørgrav {
185157bddd21SDag-Erling Smørgrav 	char* result = (char*)sldns_buffer_current(buf);
185257bddd21SDag-Erling Smørgrav 	size_t i;
185357bddd21SDag-Erling Smørgrav 	for(i=sldns_buffer_position(buf); i<sldns_buffer_limit(buf); i++) {
185457bddd21SDag-Erling Smørgrav 		/* terminate the string on the \r */
185557bddd21SDag-Erling Smørgrav 		if((char)sldns_buffer_read_u8_at(buf, i) == '\r')
185657bddd21SDag-Erling Smørgrav 			sldns_buffer_write_u8_at(buf, i, 0);
185757bddd21SDag-Erling Smørgrav 		/* terminate on the \n and skip past the it and done */
185857bddd21SDag-Erling Smørgrav 		if((char)sldns_buffer_read_u8_at(buf, i) == '\n') {
185957bddd21SDag-Erling Smørgrav 			sldns_buffer_write_u8_at(buf, i, 0);
186057bddd21SDag-Erling Smørgrav 			sldns_buffer_set_position(buf, i+1);
186157bddd21SDag-Erling Smørgrav 			return result;
186257bddd21SDag-Erling Smørgrav 		}
186357bddd21SDag-Erling Smørgrav 	}
186457bddd21SDag-Erling Smørgrav 	return NULL;
186557bddd21SDag-Erling Smørgrav }
186657bddd21SDag-Erling Smørgrav 
186757bddd21SDag-Erling Smørgrav /** move unread buffer to start and clear rest for putting the rest into it */
186857bddd21SDag-Erling Smørgrav static void
186957bddd21SDag-Erling Smørgrav http_moveover_buffer(sldns_buffer* buf)
187057bddd21SDag-Erling Smørgrav {
187157bddd21SDag-Erling Smørgrav 	size_t pos = sldns_buffer_position(buf);
187257bddd21SDag-Erling Smørgrav 	size_t len = sldns_buffer_remaining(buf);
187357bddd21SDag-Erling Smørgrav 	sldns_buffer_clear(buf);
187457bddd21SDag-Erling Smørgrav 	memmove(sldns_buffer_begin(buf), sldns_buffer_at(buf, pos), len);
187557bddd21SDag-Erling Smørgrav 	sldns_buffer_set_position(buf, len);
187657bddd21SDag-Erling Smørgrav }
187757bddd21SDag-Erling Smørgrav 
187857bddd21SDag-Erling Smørgrav /** a http header is complete, process it */
187957bddd21SDag-Erling Smørgrav static int
188057bddd21SDag-Erling Smørgrav http_process_initial_header(struct comm_point* c)
188157bddd21SDag-Erling Smørgrav {
188257bddd21SDag-Erling Smørgrav 	char* line = http_header_line(c->buffer);
188357bddd21SDag-Erling Smørgrav 	if(!line) return 1;
188457bddd21SDag-Erling Smørgrav 	verbose(VERB_ALGO, "http header: %s", line);
188557bddd21SDag-Erling Smørgrav 	if(strncasecmp(line, "HTTP/1.1 ", 9) == 0) {
188657bddd21SDag-Erling Smørgrav 		/* check returncode */
188757bddd21SDag-Erling Smørgrav 		if(line[9] != '2') {
188857bddd21SDag-Erling Smørgrav 			verbose(VERB_ALGO, "http bad status %s", line+9);
188957bddd21SDag-Erling Smørgrav 			return 0;
189057bddd21SDag-Erling Smørgrav 		}
189157bddd21SDag-Erling Smørgrav 	} else if(strncasecmp(line, "Content-Length: ", 16) == 0) {
189257bddd21SDag-Erling Smørgrav 		if(!c->http_is_chunked)
189357bddd21SDag-Erling Smørgrav 			c->tcp_byte_count = (size_t)atoi(line+16);
189457bddd21SDag-Erling Smørgrav 	} else if(strncasecmp(line, "Transfer-Encoding: chunked", 19+7) == 0) {
189557bddd21SDag-Erling Smørgrav 		c->tcp_byte_count = 0;
189657bddd21SDag-Erling Smørgrav 		c->http_is_chunked = 1;
189757bddd21SDag-Erling Smørgrav 	} else if(line[0] == 0) {
189857bddd21SDag-Erling Smørgrav 		/* end of initial headers */
189957bddd21SDag-Erling Smørgrav 		c->http_in_headers = 0;
190057bddd21SDag-Erling Smørgrav 		if(c->http_is_chunked)
190157bddd21SDag-Erling Smørgrav 			c->http_in_chunk_headers = 1;
190257bddd21SDag-Erling Smørgrav 		/* remove header text from front of buffer
190357bddd21SDag-Erling Smørgrav 		 * the buffer is going to be used to return the data segment
190457bddd21SDag-Erling Smørgrav 		 * itself and we don't want the header to get returned
190557bddd21SDag-Erling Smørgrav 		 * prepended with it */
190657bddd21SDag-Erling Smørgrav 		http_moveover_buffer(c->buffer);
190757bddd21SDag-Erling Smørgrav 		sldns_buffer_flip(c->buffer);
190857bddd21SDag-Erling Smørgrav 		return 1;
190957bddd21SDag-Erling Smørgrav 	}
191057bddd21SDag-Erling Smørgrav 	/* ignore other headers */
191157bddd21SDag-Erling Smørgrav 	return 1;
191257bddd21SDag-Erling Smørgrav }
191357bddd21SDag-Erling Smørgrav 
191457bddd21SDag-Erling Smørgrav /** a chunk header is complete, process it, return 0=fail, 1=continue next
191557bddd21SDag-Erling Smørgrav  * header line, 2=done with chunked transfer*/
191657bddd21SDag-Erling Smørgrav static int
191757bddd21SDag-Erling Smørgrav http_process_chunk_header(struct comm_point* c)
191857bddd21SDag-Erling Smørgrav {
191957bddd21SDag-Erling Smørgrav 	char* line = http_header_line(c->buffer);
192057bddd21SDag-Erling Smørgrav 	if(!line) return 1;
192157bddd21SDag-Erling Smørgrav 	if(c->http_in_chunk_headers == 3) {
192257bddd21SDag-Erling Smørgrav 		verbose(VERB_ALGO, "http chunk trailer: %s", line);
192357bddd21SDag-Erling Smørgrav 		/* are we done ? */
192457bddd21SDag-Erling Smørgrav 		if(line[0] == 0 && c->tcp_byte_count == 0) {
192557bddd21SDag-Erling Smørgrav 			/* callback of http reader when NETEVENT_DONE,
192657bddd21SDag-Erling Smørgrav 			 * end of data, with no data in buffer */
192757bddd21SDag-Erling Smørgrav 			sldns_buffer_set_position(c->buffer, 0);
192857bddd21SDag-Erling Smørgrav 			sldns_buffer_set_limit(c->buffer, 0);
192957bddd21SDag-Erling Smørgrav 			fptr_ok(fptr_whitelist_comm_point(c->callback));
193057bddd21SDag-Erling Smørgrav 			(void)(*c->callback)(c, c->cb_arg, NETEVENT_DONE, NULL);
193157bddd21SDag-Erling Smørgrav 			/* return that we are done */
193257bddd21SDag-Erling Smørgrav 			return 2;
193357bddd21SDag-Erling Smørgrav 		}
193457bddd21SDag-Erling Smørgrav 		if(line[0] == 0) {
193557bddd21SDag-Erling Smørgrav 			/* continue with header of the next chunk */
193657bddd21SDag-Erling Smørgrav 			c->http_in_chunk_headers = 1;
193757bddd21SDag-Erling Smørgrav 			/* remove header text from front of buffer */
193857bddd21SDag-Erling Smørgrav 			http_moveover_buffer(c->buffer);
193957bddd21SDag-Erling Smørgrav 			sldns_buffer_flip(c->buffer);
194057bddd21SDag-Erling Smørgrav 			return 1;
194157bddd21SDag-Erling Smørgrav 		}
194257bddd21SDag-Erling Smørgrav 		/* ignore further trail headers */
194357bddd21SDag-Erling Smørgrav 		return 1;
194457bddd21SDag-Erling Smørgrav 	}
194557bddd21SDag-Erling Smørgrav 	verbose(VERB_ALGO, "http chunk header: %s", line);
194657bddd21SDag-Erling Smørgrav 	if(c->http_in_chunk_headers == 1) {
194757bddd21SDag-Erling Smørgrav 		/* read chunked start line */
194857bddd21SDag-Erling Smørgrav 		char* end = NULL;
194957bddd21SDag-Erling Smørgrav 		c->tcp_byte_count = (size_t)strtol(line, &end, 16);
195057bddd21SDag-Erling Smørgrav 		if(end == line)
195157bddd21SDag-Erling Smørgrav 			return 0;
195257bddd21SDag-Erling Smørgrav 		c->http_in_chunk_headers = 0;
195357bddd21SDag-Erling Smørgrav 		/* remove header text from front of buffer */
195457bddd21SDag-Erling Smørgrav 		http_moveover_buffer(c->buffer);
195557bddd21SDag-Erling Smørgrav 		sldns_buffer_flip(c->buffer);
195657bddd21SDag-Erling Smørgrav 		if(c->tcp_byte_count == 0) {
195757bddd21SDag-Erling Smørgrav 			/* done with chunks, process chunk_trailer lines */
195857bddd21SDag-Erling Smørgrav 			c->http_in_chunk_headers = 3;
195957bddd21SDag-Erling Smørgrav 		}
196057bddd21SDag-Erling Smørgrav 		return 1;
196157bddd21SDag-Erling Smørgrav 	}
196257bddd21SDag-Erling Smørgrav 	/* ignore other headers */
196357bddd21SDag-Erling Smørgrav 	return 1;
196457bddd21SDag-Erling Smørgrav }
196557bddd21SDag-Erling Smørgrav 
196657bddd21SDag-Erling Smørgrav /** handle nonchunked data segment */
196757bddd21SDag-Erling Smørgrav static int
196857bddd21SDag-Erling Smørgrav http_nonchunk_segment(struct comm_point* c)
196957bddd21SDag-Erling Smørgrav {
197057bddd21SDag-Erling Smørgrav 	/* c->buffer at position..limit has new data we read in.
197157bddd21SDag-Erling Smørgrav 	 * the buffer itself is full of nonchunked data.
197257bddd21SDag-Erling Smørgrav 	 * we are looking to read tcp_byte_count more data
197357bddd21SDag-Erling Smørgrav 	 * and then the transfer is done. */
197457bddd21SDag-Erling Smørgrav 	size_t remainbufferlen;
197557bddd21SDag-Erling Smørgrav 	size_t got_now = sldns_buffer_limit(c->buffer) - c->http_stored;
197657bddd21SDag-Erling Smørgrav 	if(c->tcp_byte_count <= got_now) {
197757bddd21SDag-Erling Smørgrav 		/* done, this is the last data fragment */
197857bddd21SDag-Erling Smørgrav 		c->http_stored = 0;
197957bddd21SDag-Erling Smørgrav 		sldns_buffer_set_position(c->buffer, 0);
198057bddd21SDag-Erling Smørgrav 		fptr_ok(fptr_whitelist_comm_point(c->callback));
198157bddd21SDag-Erling Smørgrav 		(void)(*c->callback)(c, c->cb_arg, NETEVENT_DONE, NULL);
198257bddd21SDag-Erling Smørgrav 		return 1;
198357bddd21SDag-Erling Smørgrav 	}
198457bddd21SDag-Erling Smørgrav 	c->tcp_byte_count -= got_now;
198557bddd21SDag-Erling Smørgrav 	/* if we have the buffer space,
198657bddd21SDag-Erling Smørgrav 	 * read more data collected into the buffer */
198757bddd21SDag-Erling Smørgrav 	remainbufferlen = sldns_buffer_capacity(c->buffer) -
198857bddd21SDag-Erling Smørgrav 		sldns_buffer_limit(c->buffer);
198957bddd21SDag-Erling Smørgrav 	if(remainbufferlen >= c->tcp_byte_count ||
199057bddd21SDag-Erling Smørgrav 		remainbufferlen >= 2048) {
199157bddd21SDag-Erling Smørgrav 		size_t total = sldns_buffer_limit(c->buffer);
199257bddd21SDag-Erling Smørgrav 		sldns_buffer_clear(c->buffer);
199357bddd21SDag-Erling Smørgrav 		sldns_buffer_set_position(c->buffer, total);
199457bddd21SDag-Erling Smørgrav 		c->http_stored = total;
199557bddd21SDag-Erling Smørgrav 		/* return and wait to read more */
199657bddd21SDag-Erling Smørgrav 		return 1;
199757bddd21SDag-Erling Smørgrav 	}
199857bddd21SDag-Erling Smørgrav 	/* call callback with this data amount, then
199957bddd21SDag-Erling Smørgrav 	 * wait for more */
200057bddd21SDag-Erling Smørgrav 	c->http_stored = 0;
200157bddd21SDag-Erling Smørgrav 	sldns_buffer_set_position(c->buffer, 0);
200257bddd21SDag-Erling Smørgrav 	fptr_ok(fptr_whitelist_comm_point(c->callback));
200357bddd21SDag-Erling Smørgrav 	(void)(*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, NULL);
200457bddd21SDag-Erling Smørgrav 	/* c->callback has to buffer_clear(c->buffer). */
200557bddd21SDag-Erling Smørgrav 	/* return and wait to read more */
200657bddd21SDag-Erling Smørgrav 	return 1;
200757bddd21SDag-Erling Smørgrav }
200857bddd21SDag-Erling Smørgrav 
200957bddd21SDag-Erling Smørgrav /** handle nonchunked data segment, return 0=fail, 1=wait, 2=process more */
201057bddd21SDag-Erling Smørgrav static int
201157bddd21SDag-Erling Smørgrav http_chunked_segment(struct comm_point* c)
201257bddd21SDag-Erling Smørgrav {
201357bddd21SDag-Erling Smørgrav 	/* the c->buffer has from position..limit new data we read. */
201457bddd21SDag-Erling Smørgrav 	/* the current chunk has length tcp_byte_count.
201557bddd21SDag-Erling Smørgrav 	 * once we read that read more chunk headers.
201657bddd21SDag-Erling Smørgrav 	 */
201757bddd21SDag-Erling Smørgrav 	size_t remainbufferlen;
201857bddd21SDag-Erling Smørgrav 	size_t got_now = sldns_buffer_limit(c->buffer) - c->http_stored;
201957bddd21SDag-Erling Smørgrav 	if(c->tcp_byte_count <= got_now) {
202057bddd21SDag-Erling Smørgrav 		/* the chunk has completed (with perhaps some extra data
202157bddd21SDag-Erling Smørgrav 		 * from next chunk header and next chunk) */
202257bddd21SDag-Erling Smørgrav 		/* save too much info into temp buffer */
202357bddd21SDag-Erling Smørgrav 		size_t fraglen;
202457bddd21SDag-Erling Smørgrav 		struct comm_reply repinfo;
202557bddd21SDag-Erling Smørgrav 		c->http_stored = 0;
202657bddd21SDag-Erling Smørgrav 		sldns_buffer_skip(c->buffer, (ssize_t)c->tcp_byte_count);
202757bddd21SDag-Erling Smørgrav 		sldns_buffer_clear(c->http_temp);
202857bddd21SDag-Erling Smørgrav 		sldns_buffer_write(c->http_temp,
202957bddd21SDag-Erling Smørgrav 			sldns_buffer_current(c->buffer),
203057bddd21SDag-Erling Smørgrav 			sldns_buffer_remaining(c->buffer));
203157bddd21SDag-Erling Smørgrav 		sldns_buffer_flip(c->http_temp);
203257bddd21SDag-Erling Smørgrav 
203357bddd21SDag-Erling Smørgrav 		/* callback with this fragment */
203457bddd21SDag-Erling Smørgrav 		fraglen = sldns_buffer_position(c->buffer);
203557bddd21SDag-Erling Smørgrav 		sldns_buffer_set_position(c->buffer, 0);
203657bddd21SDag-Erling Smørgrav 		sldns_buffer_set_limit(c->buffer, fraglen);
203757bddd21SDag-Erling Smørgrav 		repinfo = c->repinfo;
203857bddd21SDag-Erling Smørgrav 		fptr_ok(fptr_whitelist_comm_point(c->callback));
203957bddd21SDag-Erling Smørgrav 		(void)(*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, &repinfo);
204057bddd21SDag-Erling Smørgrav 		/* c->callback has to buffer_clear(). */
204157bddd21SDag-Erling Smørgrav 
204257bddd21SDag-Erling Smørgrav 		/* is commpoint deleted? */
204357bddd21SDag-Erling Smørgrav 		if(!repinfo.c) {
204457bddd21SDag-Erling Smørgrav 			return 1;
204557bddd21SDag-Erling Smørgrav 		}
204657bddd21SDag-Erling Smørgrav 		/* copy waiting info */
204757bddd21SDag-Erling Smørgrav 		sldns_buffer_clear(c->buffer);
204857bddd21SDag-Erling Smørgrav 		sldns_buffer_write(c->buffer,
204957bddd21SDag-Erling Smørgrav 			sldns_buffer_begin(c->http_temp),
205057bddd21SDag-Erling Smørgrav 			sldns_buffer_remaining(c->http_temp));
205157bddd21SDag-Erling Smørgrav 		sldns_buffer_flip(c->buffer);
205257bddd21SDag-Erling Smørgrav 		/* process end of chunk trailer header lines, until
205357bddd21SDag-Erling Smørgrav 		 * an empty line */
205457bddd21SDag-Erling Smørgrav 		c->http_in_chunk_headers = 3;
205557bddd21SDag-Erling Smørgrav 		/* process more data in buffer (if any) */
205657bddd21SDag-Erling Smørgrav 		return 2;
205757bddd21SDag-Erling Smørgrav 	}
205857bddd21SDag-Erling Smørgrav 	c->tcp_byte_count -= got_now;
205957bddd21SDag-Erling Smørgrav 
206057bddd21SDag-Erling Smørgrav 	/* if we have the buffer space,
206157bddd21SDag-Erling Smørgrav 	 * read more data collected into the buffer */
206257bddd21SDag-Erling Smørgrav 	remainbufferlen = sldns_buffer_capacity(c->buffer) -
206357bddd21SDag-Erling Smørgrav 		sldns_buffer_limit(c->buffer);
206457bddd21SDag-Erling Smørgrav 	if(remainbufferlen >= c->tcp_byte_count ||
206557bddd21SDag-Erling Smørgrav 		remainbufferlen >= 2048) {
206657bddd21SDag-Erling Smørgrav 		size_t total = sldns_buffer_limit(c->buffer);
206757bddd21SDag-Erling Smørgrav 		sldns_buffer_clear(c->buffer);
206857bddd21SDag-Erling Smørgrav 		sldns_buffer_set_position(c->buffer, total);
206957bddd21SDag-Erling Smørgrav 		c->http_stored = total;
207057bddd21SDag-Erling Smørgrav 		/* return and wait to read more */
207157bddd21SDag-Erling Smørgrav 		return 1;
207257bddd21SDag-Erling Smørgrav 	}
207357bddd21SDag-Erling Smørgrav 
207457bddd21SDag-Erling Smørgrav 	/* callback of http reader for a new part of the data */
207557bddd21SDag-Erling Smørgrav 	c->http_stored = 0;
207657bddd21SDag-Erling Smørgrav 	sldns_buffer_set_position(c->buffer, 0);
207757bddd21SDag-Erling Smørgrav 	fptr_ok(fptr_whitelist_comm_point(c->callback));
207857bddd21SDag-Erling Smørgrav 	(void)(*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, NULL);
207957bddd21SDag-Erling Smørgrav 	/* c->callback has to buffer_clear(c->buffer). */
208057bddd21SDag-Erling Smørgrav 	/* return and wait to read more */
208157bddd21SDag-Erling Smørgrav 	return 1;
208257bddd21SDag-Erling Smørgrav }
208357bddd21SDag-Erling Smørgrav 
208457bddd21SDag-Erling Smørgrav /**
208557bddd21SDag-Erling Smørgrav  * Handle http reading callback.
208657bddd21SDag-Erling Smørgrav  * @param fd: file descriptor of socket.
208757bddd21SDag-Erling Smørgrav  * @param c: comm point to read from into buffer.
208857bddd21SDag-Erling Smørgrav  * @return: 0 on error
208957bddd21SDag-Erling Smørgrav  */
209057bddd21SDag-Erling Smørgrav static int
209157bddd21SDag-Erling Smørgrav comm_point_http_handle_read(int fd, struct comm_point* c)
209257bddd21SDag-Erling Smørgrav {
209357bddd21SDag-Erling Smørgrav 	log_assert(c->type == comm_http);
209457bddd21SDag-Erling Smørgrav 	log_assert(fd != -1);
209557bddd21SDag-Erling Smørgrav 
209657bddd21SDag-Erling Smørgrav 	/* if we are in ssl handshake, handle SSL handshake */
209757bddd21SDag-Erling Smørgrav #ifdef HAVE_SSL
209857bddd21SDag-Erling Smørgrav 	if(c->ssl && c->ssl_shake_state != comm_ssl_shake_none) {
209957bddd21SDag-Erling Smørgrav 		if(!ssl_handshake(c))
210057bddd21SDag-Erling Smørgrav 			return 0;
210157bddd21SDag-Erling Smørgrav 		if(c->ssl_shake_state != comm_ssl_shake_none)
210257bddd21SDag-Erling Smørgrav 			return 1;
210357bddd21SDag-Erling Smørgrav 	}
210457bddd21SDag-Erling Smørgrav #endif /* HAVE_SSL */
210557bddd21SDag-Erling Smørgrav 
210657bddd21SDag-Erling Smørgrav 	if(!c->tcp_is_reading)
210757bddd21SDag-Erling Smørgrav 		return 1;
210857bddd21SDag-Erling Smørgrav 	/* read more data */
210957bddd21SDag-Erling Smørgrav 	if(c->ssl) {
211057bddd21SDag-Erling Smørgrav 		if(!ssl_http_read_more(c))
211157bddd21SDag-Erling Smørgrav 			return 0;
211257bddd21SDag-Erling Smørgrav 	} else {
211357bddd21SDag-Erling Smørgrav 		if(!http_read_more(fd, c))
211457bddd21SDag-Erling Smørgrav 			return 0;
211557bddd21SDag-Erling Smørgrav 	}
211657bddd21SDag-Erling Smørgrav 
211757bddd21SDag-Erling Smørgrav 	sldns_buffer_flip(c->buffer);
211857bddd21SDag-Erling Smørgrav 	while(sldns_buffer_remaining(c->buffer) > 0) {
211957bddd21SDag-Erling Smørgrav 		/* if we are reading headers, read more headers */
212057bddd21SDag-Erling Smørgrav 		if(c->http_in_headers || c->http_in_chunk_headers) {
212157bddd21SDag-Erling Smørgrav 			/* if header is done, process the header */
212257bddd21SDag-Erling Smørgrav 			if(!http_header_done(c->buffer)) {
212357bddd21SDag-Erling Smørgrav 				/* copy remaining data to front of buffer
212457bddd21SDag-Erling Smørgrav 				 * and set rest for writing into it */
212557bddd21SDag-Erling Smørgrav 				http_moveover_buffer(c->buffer);
212657bddd21SDag-Erling Smørgrav 				/* return and wait to read more */
212757bddd21SDag-Erling Smørgrav 				return 1;
212857bddd21SDag-Erling Smørgrav 			}
212957bddd21SDag-Erling Smørgrav 			if(!c->http_in_chunk_headers) {
213057bddd21SDag-Erling Smørgrav 				/* process initial headers */
213157bddd21SDag-Erling Smørgrav 				if(!http_process_initial_header(c))
213257bddd21SDag-Erling Smørgrav 					return 0;
213357bddd21SDag-Erling Smørgrav 			} else {
213457bddd21SDag-Erling Smørgrav 				/* process chunk headers */
213557bddd21SDag-Erling Smørgrav 				int r = http_process_chunk_header(c);
213657bddd21SDag-Erling Smørgrav 				if(r == 0) return 0;
213757bddd21SDag-Erling Smørgrav 				if(r == 2) return 1; /* done */
213857bddd21SDag-Erling Smørgrav 				/* r == 1, continue */
213957bddd21SDag-Erling Smørgrav 			}
214057bddd21SDag-Erling Smørgrav 			/* see if we have more to process */
214157bddd21SDag-Erling Smørgrav 			continue;
214257bddd21SDag-Erling Smørgrav 		}
214357bddd21SDag-Erling Smørgrav 
214457bddd21SDag-Erling Smørgrav 		if(!c->http_is_chunked) {
214557bddd21SDag-Erling Smørgrav 			/* if we are reading nonchunks, process that*/
214657bddd21SDag-Erling Smørgrav 			return http_nonchunk_segment(c);
214757bddd21SDag-Erling Smørgrav 		} else {
214857bddd21SDag-Erling Smørgrav 			/* if we are reading chunks, read the chunk */
214957bddd21SDag-Erling Smørgrav 			int r = http_chunked_segment(c);
215057bddd21SDag-Erling Smørgrav 			if(r == 0) return 0;
215157bddd21SDag-Erling Smørgrav 			if(r == 1) return 1;
215257bddd21SDag-Erling Smørgrav 			continue;
215357bddd21SDag-Erling Smørgrav 		}
215457bddd21SDag-Erling Smørgrav 	}
215557bddd21SDag-Erling Smørgrav 	/* broke out of the loop; could not process header instead need
215657bddd21SDag-Erling Smørgrav 	 * to read more */
215757bddd21SDag-Erling Smørgrav 	/* moveover any remaining data and read more data */
215857bddd21SDag-Erling Smørgrav 	http_moveover_buffer(c->buffer);
215957bddd21SDag-Erling Smørgrav 	/* return and wait to read more */
216057bddd21SDag-Erling Smørgrav 	return 1;
216157bddd21SDag-Erling Smørgrav }
216257bddd21SDag-Erling Smørgrav 
216357bddd21SDag-Erling Smørgrav /** check pending connect for http */
216457bddd21SDag-Erling Smørgrav static int
216557bddd21SDag-Erling Smørgrav http_check_connect(int fd, struct comm_point* c)
216657bddd21SDag-Erling Smørgrav {
216757bddd21SDag-Erling Smørgrav 	/* check for pending error from nonblocking connect */
216857bddd21SDag-Erling Smørgrav 	/* from Stevens, unix network programming, vol1, 3rd ed, p450*/
216957bddd21SDag-Erling Smørgrav 	int error = 0;
217057bddd21SDag-Erling Smørgrav 	socklen_t len = (socklen_t)sizeof(error);
217157bddd21SDag-Erling Smørgrav 	if(getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&error,
217257bddd21SDag-Erling Smørgrav 		&len) < 0){
217357bddd21SDag-Erling Smørgrav #ifndef USE_WINSOCK
217457bddd21SDag-Erling Smørgrav 		error = errno; /* on solaris errno is error */
217557bddd21SDag-Erling Smørgrav #else /* USE_WINSOCK */
217657bddd21SDag-Erling Smørgrav 		error = WSAGetLastError();
217757bddd21SDag-Erling Smørgrav #endif
217857bddd21SDag-Erling Smørgrav 	}
217957bddd21SDag-Erling Smørgrav #ifndef USE_WINSOCK
218057bddd21SDag-Erling Smørgrav #if defined(EINPROGRESS) && defined(EWOULDBLOCK)
218157bddd21SDag-Erling Smørgrav 	if(error == EINPROGRESS || error == EWOULDBLOCK)
218257bddd21SDag-Erling Smørgrav 		return 1; /* try again later */
218357bddd21SDag-Erling Smørgrav 	else
218457bddd21SDag-Erling Smørgrav #endif
218557bddd21SDag-Erling Smørgrav 	if(error != 0 && verbosity < 2)
218657bddd21SDag-Erling Smørgrav 		return 0; /* silence lots of chatter in the logs */
218757bddd21SDag-Erling Smørgrav 	else if(error != 0) {
218857bddd21SDag-Erling Smørgrav 		log_err_addr("http connect", strerror(error),
218957bddd21SDag-Erling Smørgrav 			&c->repinfo.addr, c->repinfo.addrlen);
219057bddd21SDag-Erling Smørgrav #else /* USE_WINSOCK */
219157bddd21SDag-Erling Smørgrav 	/* examine error */
219257bddd21SDag-Erling Smørgrav 	if(error == WSAEINPROGRESS)
219357bddd21SDag-Erling Smørgrav 		return 1;
219457bddd21SDag-Erling Smørgrav 	else if(error == WSAEWOULDBLOCK) {
219557bddd21SDag-Erling Smørgrav 		ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
219657bddd21SDag-Erling Smørgrav 		return 1;
219757bddd21SDag-Erling Smørgrav 	} else if(error != 0 && verbosity < 2)
219857bddd21SDag-Erling Smørgrav 		return 0;
219957bddd21SDag-Erling Smørgrav 	else if(error != 0) {
220057bddd21SDag-Erling Smørgrav 		log_err_addr("http connect", wsa_strerror(error),
220157bddd21SDag-Erling Smørgrav 			&c->repinfo.addr, c->repinfo.addrlen);
220257bddd21SDag-Erling Smørgrav #endif /* USE_WINSOCK */
220357bddd21SDag-Erling Smørgrav 		return 0;
220457bddd21SDag-Erling Smørgrav 	}
220557bddd21SDag-Erling Smørgrav 	/* keep on processing this socket */
220657bddd21SDag-Erling Smørgrav 	return 2;
220757bddd21SDag-Erling Smørgrav }
220857bddd21SDag-Erling Smørgrav 
220957bddd21SDag-Erling Smørgrav /** write more data for http (with ssl) */
221057bddd21SDag-Erling Smørgrav static int
221157bddd21SDag-Erling Smørgrav ssl_http_write_more(struct comm_point* c)
221257bddd21SDag-Erling Smørgrav {
221357bddd21SDag-Erling Smørgrav #ifdef HAVE_SSL
221457bddd21SDag-Erling Smørgrav 	int r;
221557bddd21SDag-Erling Smørgrav 	log_assert(sldns_buffer_remaining(c->buffer) > 0);
221657bddd21SDag-Erling Smørgrav 	ERR_clear_error();
221757bddd21SDag-Erling Smørgrav 	r = SSL_write(c->ssl, (void*)sldns_buffer_current(c->buffer),
221857bddd21SDag-Erling Smørgrav 		(int)sldns_buffer_remaining(c->buffer));
221957bddd21SDag-Erling Smørgrav 	if(r <= 0) {
222057bddd21SDag-Erling Smørgrav 		int want = SSL_get_error(c->ssl, r);
222157bddd21SDag-Erling Smørgrav 		if(want == SSL_ERROR_ZERO_RETURN) {
222257bddd21SDag-Erling Smørgrav 			return 0; /* closed */
222357bddd21SDag-Erling Smørgrav 		} else if(want == SSL_ERROR_WANT_READ) {
222457bddd21SDag-Erling Smørgrav 			c->ssl_shake_state = comm_ssl_shake_read;
222557bddd21SDag-Erling Smørgrav 			comm_point_listen_for_rw(c, 1, 0);
222657bddd21SDag-Erling Smørgrav 			return 1; /* wait for read condition */
222757bddd21SDag-Erling Smørgrav 		} else if(want == SSL_ERROR_WANT_WRITE) {
222857bddd21SDag-Erling Smørgrav 			return 1; /* write more later */
222957bddd21SDag-Erling Smørgrav 		} else if(want == SSL_ERROR_SYSCALL) {
223057bddd21SDag-Erling Smørgrav 			if(errno != 0)
223157bddd21SDag-Erling Smørgrav 				log_err("SSL_write syscall: %s",
223257bddd21SDag-Erling Smørgrav 					strerror(errno));
223357bddd21SDag-Erling Smørgrav 			return 0;
223457bddd21SDag-Erling Smørgrav 		}
223557bddd21SDag-Erling Smørgrav 		log_crypto_err("could not SSL_write");
223657bddd21SDag-Erling Smørgrav 		return 0;
223757bddd21SDag-Erling Smørgrav 	}
223857bddd21SDag-Erling Smørgrav 	sldns_buffer_skip(c->buffer, (ssize_t)r);
223957bddd21SDag-Erling Smørgrav 	return 1;
224057bddd21SDag-Erling Smørgrav #else
224157bddd21SDag-Erling Smørgrav 	(void)c;
224257bddd21SDag-Erling Smørgrav 	return 0;
224357bddd21SDag-Erling Smørgrav #endif /* HAVE_SSL */
224457bddd21SDag-Erling Smørgrav }
224557bddd21SDag-Erling Smørgrav 
224657bddd21SDag-Erling Smørgrav /** write more data for http */
224757bddd21SDag-Erling Smørgrav static int
224857bddd21SDag-Erling Smørgrav http_write_more(int fd, struct comm_point* c)
224957bddd21SDag-Erling Smørgrav {
225057bddd21SDag-Erling Smørgrav 	ssize_t r;
225157bddd21SDag-Erling Smørgrav 	log_assert(sldns_buffer_remaining(c->buffer) > 0);
225257bddd21SDag-Erling Smørgrav 	r = send(fd, (void*)sldns_buffer_current(c->buffer),
225357bddd21SDag-Erling Smørgrav 		sldns_buffer_remaining(c->buffer), 0);
225457bddd21SDag-Erling Smørgrav 	if(r == -1) {
225557bddd21SDag-Erling Smørgrav #ifndef USE_WINSOCK
225657bddd21SDag-Erling Smørgrav 		if(errno == EINTR || errno == EAGAIN)
225757bddd21SDag-Erling Smørgrav 			return 1;
225857bddd21SDag-Erling Smørgrav 		log_err_addr("http send r", strerror(errno),
225957bddd21SDag-Erling Smørgrav 			&c->repinfo.addr, c->repinfo.addrlen);
226057bddd21SDag-Erling Smørgrav #else
226157bddd21SDag-Erling Smørgrav 		if(WSAGetLastError() == WSAEINPROGRESS)
226257bddd21SDag-Erling Smørgrav 			return 1;
226357bddd21SDag-Erling Smørgrav 		if(WSAGetLastError() == WSAEWOULDBLOCK) {
226457bddd21SDag-Erling Smørgrav 			ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
226557bddd21SDag-Erling Smørgrav 			return 1;
226657bddd21SDag-Erling Smørgrav 		}
226757bddd21SDag-Erling Smørgrav 		log_err_addr("http send r", wsa_strerror(WSAGetLastError()),
226857bddd21SDag-Erling Smørgrav 			&c->repinfo.addr, c->repinfo.addrlen);
226957bddd21SDag-Erling Smørgrav #endif
227057bddd21SDag-Erling Smørgrav 		return 0;
227157bddd21SDag-Erling Smørgrav 	}
227257bddd21SDag-Erling Smørgrav 	sldns_buffer_skip(c->buffer, r);
227357bddd21SDag-Erling Smørgrav 	return 1;
227457bddd21SDag-Erling Smørgrav }
227557bddd21SDag-Erling Smørgrav 
227657bddd21SDag-Erling Smørgrav /**
227757bddd21SDag-Erling Smørgrav  * Handle http writing callback.
227857bddd21SDag-Erling Smørgrav  * @param fd: file descriptor of socket.
227957bddd21SDag-Erling Smørgrav  * @param c: comm point to write buffer out of.
228057bddd21SDag-Erling Smørgrav  * @return: 0 on error
228157bddd21SDag-Erling Smørgrav  */
228257bddd21SDag-Erling Smørgrav static int
228357bddd21SDag-Erling Smørgrav comm_point_http_handle_write(int fd, struct comm_point* c)
228457bddd21SDag-Erling Smørgrav {
228557bddd21SDag-Erling Smørgrav 	log_assert(c->type == comm_http);
228657bddd21SDag-Erling Smørgrav 	log_assert(fd != -1);
228757bddd21SDag-Erling Smørgrav 
228857bddd21SDag-Erling Smørgrav 	/* check pending connect errors, if that fails, we wait for more,
228957bddd21SDag-Erling Smørgrav 	 * or we can continue to write contents */
229057bddd21SDag-Erling Smørgrav 	if(c->tcp_check_nb_connect) {
229157bddd21SDag-Erling Smørgrav 		int r = http_check_connect(fd, c);
229257bddd21SDag-Erling Smørgrav 		if(r == 0) return 0;
229357bddd21SDag-Erling Smørgrav 		if(r == 1) return 1;
229457bddd21SDag-Erling Smørgrav 		c->tcp_check_nb_connect = 0;
229557bddd21SDag-Erling Smørgrav 	}
229657bddd21SDag-Erling Smørgrav 	/* if we are in ssl handshake, handle SSL handshake */
229757bddd21SDag-Erling Smørgrav #ifdef HAVE_SSL
229857bddd21SDag-Erling Smørgrav 	if(c->ssl && c->ssl_shake_state != comm_ssl_shake_none) {
229957bddd21SDag-Erling Smørgrav 		if(!ssl_handshake(c))
230057bddd21SDag-Erling Smørgrav 			return 0;
230157bddd21SDag-Erling Smørgrav 		if(c->ssl_shake_state != comm_ssl_shake_none)
230257bddd21SDag-Erling Smørgrav 			return 1;
230357bddd21SDag-Erling Smørgrav 	}
230457bddd21SDag-Erling Smørgrav #endif /* HAVE_SSL */
230557bddd21SDag-Erling Smørgrav 	if(c->tcp_is_reading)
230657bddd21SDag-Erling Smørgrav 		return 1;
230757bddd21SDag-Erling Smørgrav 	/* if we are writing, write more */
230857bddd21SDag-Erling Smørgrav 	if(c->ssl) {
230957bddd21SDag-Erling Smørgrav 		if(!ssl_http_write_more(c))
231057bddd21SDag-Erling Smørgrav 			return 0;
231157bddd21SDag-Erling Smørgrav 	} else {
231257bddd21SDag-Erling Smørgrav 		if(!http_write_more(fd, c))
231357bddd21SDag-Erling Smørgrav 			return 0;
231457bddd21SDag-Erling Smørgrav 	}
231557bddd21SDag-Erling Smørgrav 
231657bddd21SDag-Erling Smørgrav 	/* we write a single buffer contents, that can contain
231757bddd21SDag-Erling Smørgrav 	 * the http request, and then flip to read the results */
231857bddd21SDag-Erling Smørgrav 	/* see if write is done */
231957bddd21SDag-Erling Smørgrav 	if(sldns_buffer_remaining(c->buffer) == 0) {
232057bddd21SDag-Erling Smørgrav 		sldns_buffer_clear(c->buffer);
232157bddd21SDag-Erling Smørgrav 		if(c->tcp_do_toggle_rw)
232257bddd21SDag-Erling Smørgrav 			c->tcp_is_reading = 1;
232357bddd21SDag-Erling Smørgrav 		c->tcp_byte_count = 0;
232457bddd21SDag-Erling Smørgrav 		/* switch from listening(write) to listening(read) */
232557bddd21SDag-Erling Smørgrav 		comm_point_stop_listening(c);
232657bddd21SDag-Erling Smørgrav 		comm_point_start_listening(c, -1, -1);
232757bddd21SDag-Erling Smørgrav 	}
232857bddd21SDag-Erling Smørgrav 	return 1;
232957bddd21SDag-Erling Smørgrav }
233057bddd21SDag-Erling Smørgrav 
233157bddd21SDag-Erling Smørgrav void
233257bddd21SDag-Erling Smørgrav comm_point_http_handle_callback(int fd, short event, void* arg)
233357bddd21SDag-Erling Smørgrav {
233457bddd21SDag-Erling Smørgrav 	struct comm_point* c = (struct comm_point*)arg;
233557bddd21SDag-Erling Smørgrav 	log_assert(c->type == comm_http);
233657bddd21SDag-Erling Smørgrav 	ub_comm_base_now(c->ev->base);
233757bddd21SDag-Erling Smørgrav 
233857bddd21SDag-Erling Smørgrav 	if(event&UB_EV_READ) {
233957bddd21SDag-Erling Smørgrav 		if(!comm_point_http_handle_read(fd, c)) {
234057bddd21SDag-Erling Smørgrav 			reclaim_http_handler(c);
234157bddd21SDag-Erling Smørgrav 			if(!c->tcp_do_close) {
234257bddd21SDag-Erling Smørgrav 				fptr_ok(fptr_whitelist_comm_point(
234357bddd21SDag-Erling Smørgrav 					c->callback));
234457bddd21SDag-Erling Smørgrav 				(void)(*c->callback)(c, c->cb_arg,
234557bddd21SDag-Erling Smørgrav 					NETEVENT_CLOSED, NULL);
234657bddd21SDag-Erling Smørgrav 			}
234757bddd21SDag-Erling Smørgrav 		}
234857bddd21SDag-Erling Smørgrav 		return;
234957bddd21SDag-Erling Smørgrav 	}
235057bddd21SDag-Erling Smørgrav 	if(event&UB_EV_WRITE) {
235157bddd21SDag-Erling Smørgrav 		if(!comm_point_http_handle_write(fd, c)) {
235257bddd21SDag-Erling Smørgrav 			reclaim_http_handler(c);
235357bddd21SDag-Erling Smørgrav 			if(!c->tcp_do_close) {
235457bddd21SDag-Erling Smørgrav 				fptr_ok(fptr_whitelist_comm_point(
235557bddd21SDag-Erling Smørgrav 					c->callback));
235657bddd21SDag-Erling Smørgrav 				(void)(*c->callback)(c, c->cb_arg,
235757bddd21SDag-Erling Smørgrav 					NETEVENT_CLOSED, NULL);
235857bddd21SDag-Erling Smørgrav 			}
235957bddd21SDag-Erling Smørgrav 		}
236057bddd21SDag-Erling Smørgrav 		return;
236157bddd21SDag-Erling Smørgrav 	}
236257bddd21SDag-Erling Smørgrav 	if(event&UB_EV_TIMEOUT) {
236357bddd21SDag-Erling Smørgrav 		verbose(VERB_QUERY, "http took too long, dropped");
236457bddd21SDag-Erling Smørgrav 		reclaim_http_handler(c);
236557bddd21SDag-Erling Smørgrav 		if(!c->tcp_do_close) {
236657bddd21SDag-Erling Smørgrav 			fptr_ok(fptr_whitelist_comm_point(c->callback));
236757bddd21SDag-Erling Smørgrav 			(void)(*c->callback)(c, c->cb_arg,
236857bddd21SDag-Erling Smørgrav 				NETEVENT_TIMEOUT, NULL);
236957bddd21SDag-Erling Smørgrav 		}
237057bddd21SDag-Erling Smørgrav 		return;
237157bddd21SDag-Erling Smørgrav 	}
237257bddd21SDag-Erling Smørgrav 	log_err("Ignored event %d for httphdl.", event);
237357bddd21SDag-Erling Smørgrav }
237457bddd21SDag-Erling Smørgrav 
2375b7579f77SDag-Erling Smørgrav void comm_point_local_handle_callback(int fd, short event, void* arg)
2376b7579f77SDag-Erling Smørgrav {
2377b7579f77SDag-Erling Smørgrav 	struct comm_point* c = (struct comm_point*)arg;
2378b7579f77SDag-Erling Smørgrav 	log_assert(c->type == comm_local);
2379e2d15004SDag-Erling Smørgrav 	ub_comm_base_now(c->ev->base);
2380b7579f77SDag-Erling Smørgrav 
2381e2d15004SDag-Erling Smørgrav 	if(event&UB_EV_READ) {
2382b7579f77SDag-Erling Smørgrav 		if(!comm_point_tcp_handle_read(fd, c, 1)) {
2383b7579f77SDag-Erling Smørgrav 			fptr_ok(fptr_whitelist_comm_point(c->callback));
2384b7579f77SDag-Erling Smørgrav 			(void)(*c->callback)(c, c->cb_arg, NETEVENT_CLOSED,
2385b7579f77SDag-Erling Smørgrav 				NULL);
2386b7579f77SDag-Erling Smørgrav 		}
2387b7579f77SDag-Erling Smørgrav 		return;
2388b7579f77SDag-Erling Smørgrav 	}
2389b7579f77SDag-Erling Smørgrav 	log_err("Ignored event %d for localhdl.", event);
2390b7579f77SDag-Erling Smørgrav }
2391b7579f77SDag-Erling Smørgrav 
2392b7579f77SDag-Erling Smørgrav void comm_point_raw_handle_callback(int ATTR_UNUSED(fd),
2393b7579f77SDag-Erling Smørgrav 	short event, void* arg)
2394b7579f77SDag-Erling Smørgrav {
2395b7579f77SDag-Erling Smørgrav 	struct comm_point* c = (struct comm_point*)arg;
2396b7579f77SDag-Erling Smørgrav 	int err = NETEVENT_NOERROR;
2397b7579f77SDag-Erling Smørgrav 	log_assert(c->type == comm_raw);
2398e2d15004SDag-Erling Smørgrav 	ub_comm_base_now(c->ev->base);
2399b7579f77SDag-Erling Smørgrav 
2400e2d15004SDag-Erling Smørgrav 	if(event&UB_EV_TIMEOUT)
2401b7579f77SDag-Erling Smørgrav 		err = NETEVENT_TIMEOUT;
2402b7579f77SDag-Erling Smørgrav 	fptr_ok(fptr_whitelist_comm_point_raw(c->callback));
2403b7579f77SDag-Erling Smørgrav 	(void)(*c->callback)(c, c->cb_arg, err, NULL);
2404b7579f77SDag-Erling Smørgrav }
2405b7579f77SDag-Erling Smørgrav 
2406b7579f77SDag-Erling Smørgrav struct comm_point*
240717d15b25SDag-Erling Smørgrav comm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer,
24083005e0a3SDag-Erling Smørgrav 	comm_point_callback_type* callback, void* callback_arg)
2409b7579f77SDag-Erling Smørgrav {
2410b7579f77SDag-Erling Smørgrav 	struct comm_point* c = (struct comm_point*)calloc(1,
2411b7579f77SDag-Erling Smørgrav 		sizeof(struct comm_point));
2412b7579f77SDag-Erling Smørgrav 	short evbits;
2413b7579f77SDag-Erling Smørgrav 	if(!c)
2414b7579f77SDag-Erling Smørgrav 		return NULL;
2415b7579f77SDag-Erling Smørgrav 	c->ev = (struct internal_event*)calloc(1,
2416b7579f77SDag-Erling Smørgrav 		sizeof(struct internal_event));
2417b7579f77SDag-Erling Smørgrav 	if(!c->ev) {
2418b7579f77SDag-Erling Smørgrav 		free(c);
2419b7579f77SDag-Erling Smørgrav 		return NULL;
2420b7579f77SDag-Erling Smørgrav 	}
2421b7579f77SDag-Erling Smørgrav 	c->ev->base = base;
2422b7579f77SDag-Erling Smørgrav 	c->fd = fd;
2423b7579f77SDag-Erling Smørgrav 	c->buffer = buffer;
2424b7579f77SDag-Erling Smørgrav 	c->timeout = NULL;
2425b7579f77SDag-Erling Smørgrav 	c->tcp_is_reading = 0;
2426b7579f77SDag-Erling Smørgrav 	c->tcp_byte_count = 0;
2427b7579f77SDag-Erling Smørgrav 	c->tcp_parent = NULL;
2428b7579f77SDag-Erling Smørgrav 	c->max_tcp_count = 0;
242909a3aaf3SDag-Erling Smørgrav 	c->cur_tcp_count = 0;
2430b7579f77SDag-Erling Smørgrav 	c->tcp_handlers = NULL;
2431b7579f77SDag-Erling Smørgrav 	c->tcp_free = NULL;
2432b7579f77SDag-Erling Smørgrav 	c->type = comm_udp;
2433b7579f77SDag-Erling Smørgrav 	c->tcp_do_close = 0;
2434b7579f77SDag-Erling Smørgrav 	c->do_not_close = 0;
2435b7579f77SDag-Erling Smørgrav 	c->tcp_do_toggle_rw = 0;
2436b7579f77SDag-Erling Smørgrav 	c->tcp_check_nb_connect = 0;
2437b5663de9SDag-Erling Smørgrav #ifdef USE_MSG_FASTOPEN
2438b5663de9SDag-Erling Smørgrav 	c->tcp_do_fastopen = 0;
2439b5663de9SDag-Erling Smørgrav #endif
244065b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT
244165b390aaSDag-Erling Smørgrav 	c->dnscrypt = 0;
244265b390aaSDag-Erling Smørgrav 	c->dnscrypt_buffer = buffer;
244365b390aaSDag-Erling Smørgrav #endif
2444b7579f77SDag-Erling Smørgrav 	c->inuse = 0;
2445b7579f77SDag-Erling Smørgrav 	c->callback = callback;
2446b7579f77SDag-Erling Smørgrav 	c->cb_arg = callback_arg;
2447e2d15004SDag-Erling Smørgrav 	evbits = UB_EV_READ | UB_EV_PERSIST;
2448e2d15004SDag-Erling Smørgrav 	/* ub_event stuff */
2449e2d15004SDag-Erling Smørgrav 	c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
2450e2d15004SDag-Erling Smørgrav 		comm_point_udp_callback, c);
2451e2d15004SDag-Erling Smørgrav 	if(c->ev->ev == NULL) {
2452b7579f77SDag-Erling Smørgrav 		log_err("could not baseset udp event");
2453b7579f77SDag-Erling Smørgrav 		comm_point_delete(c);
2454b7579f77SDag-Erling Smørgrav 		return NULL;
2455b7579f77SDag-Erling Smørgrav 	}
2456e2d15004SDag-Erling Smørgrav 	if(fd!=-1 && ub_event_add(c->ev->ev, c->timeout) != 0 ) {
2457b7579f77SDag-Erling Smørgrav 		log_err("could not add udp event");
2458b7579f77SDag-Erling Smørgrav 		comm_point_delete(c);
2459b7579f77SDag-Erling Smørgrav 		return NULL;
2460b7579f77SDag-Erling Smørgrav 	}
2461b7579f77SDag-Erling Smørgrav 	return c;
2462b7579f77SDag-Erling Smørgrav }
2463b7579f77SDag-Erling Smørgrav 
2464b7579f77SDag-Erling Smørgrav struct comm_point*
2465b7579f77SDag-Erling Smørgrav comm_point_create_udp_ancil(struct comm_base *base, int fd,
246617d15b25SDag-Erling Smørgrav 	sldns_buffer* buffer,
24673005e0a3SDag-Erling Smørgrav 	comm_point_callback_type* callback, void* callback_arg)
2468b7579f77SDag-Erling Smørgrav {
2469b7579f77SDag-Erling Smørgrav 	struct comm_point* c = (struct comm_point*)calloc(1,
2470b7579f77SDag-Erling Smørgrav 		sizeof(struct comm_point));
2471b7579f77SDag-Erling Smørgrav 	short evbits;
2472b7579f77SDag-Erling Smørgrav 	if(!c)
2473b7579f77SDag-Erling Smørgrav 		return NULL;
2474b7579f77SDag-Erling Smørgrav 	c->ev = (struct internal_event*)calloc(1,
2475b7579f77SDag-Erling Smørgrav 		sizeof(struct internal_event));
2476b7579f77SDag-Erling Smørgrav 	if(!c->ev) {
2477b7579f77SDag-Erling Smørgrav 		free(c);
2478b7579f77SDag-Erling Smørgrav 		return NULL;
2479b7579f77SDag-Erling Smørgrav 	}
2480b7579f77SDag-Erling Smørgrav 	c->ev->base = base;
2481b7579f77SDag-Erling Smørgrav 	c->fd = fd;
2482b7579f77SDag-Erling Smørgrav 	c->buffer = buffer;
2483b7579f77SDag-Erling Smørgrav 	c->timeout = NULL;
2484b7579f77SDag-Erling Smørgrav 	c->tcp_is_reading = 0;
2485b7579f77SDag-Erling Smørgrav 	c->tcp_byte_count = 0;
2486b7579f77SDag-Erling Smørgrav 	c->tcp_parent = NULL;
2487b7579f77SDag-Erling Smørgrav 	c->max_tcp_count = 0;
248809a3aaf3SDag-Erling Smørgrav 	c->cur_tcp_count = 0;
2489b7579f77SDag-Erling Smørgrav 	c->tcp_handlers = NULL;
2490b7579f77SDag-Erling Smørgrav 	c->tcp_free = NULL;
2491b7579f77SDag-Erling Smørgrav 	c->type = comm_udp;
2492b7579f77SDag-Erling Smørgrav 	c->tcp_do_close = 0;
2493b7579f77SDag-Erling Smørgrav 	c->do_not_close = 0;
249465b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT
249565b390aaSDag-Erling Smørgrav 	c->dnscrypt = 0;
249665b390aaSDag-Erling Smørgrav 	c->dnscrypt_buffer = buffer;
249765b390aaSDag-Erling Smørgrav #endif
2498b7579f77SDag-Erling Smørgrav 	c->inuse = 0;
2499b7579f77SDag-Erling Smørgrav 	c->tcp_do_toggle_rw = 0;
2500b7579f77SDag-Erling Smørgrav 	c->tcp_check_nb_connect = 0;
2501b5663de9SDag-Erling Smørgrav #ifdef USE_MSG_FASTOPEN
2502b5663de9SDag-Erling Smørgrav 	c->tcp_do_fastopen = 0;
2503b5663de9SDag-Erling Smørgrav #endif
2504b7579f77SDag-Erling Smørgrav 	c->callback = callback;
2505b7579f77SDag-Erling Smørgrav 	c->cb_arg = callback_arg;
2506e2d15004SDag-Erling Smørgrav 	evbits = UB_EV_READ | UB_EV_PERSIST;
2507e2d15004SDag-Erling Smørgrav 	/* ub_event stuff */
2508e2d15004SDag-Erling Smørgrav 	c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
2509e2d15004SDag-Erling Smørgrav 		comm_point_udp_ancil_callback, c);
2510e2d15004SDag-Erling Smørgrav 	if(c->ev->ev == NULL) {
2511b7579f77SDag-Erling Smørgrav 		log_err("could not baseset udp event");
2512b7579f77SDag-Erling Smørgrav 		comm_point_delete(c);
2513b7579f77SDag-Erling Smørgrav 		return NULL;
2514b7579f77SDag-Erling Smørgrav 	}
2515e2d15004SDag-Erling Smørgrav 	if(fd!=-1 && ub_event_add(c->ev->ev, c->timeout) != 0 ) {
2516b7579f77SDag-Erling Smørgrav 		log_err("could not add udp event");
2517b7579f77SDag-Erling Smørgrav 		comm_point_delete(c);
2518b7579f77SDag-Erling Smørgrav 		return NULL;
2519b7579f77SDag-Erling Smørgrav 	}
2520b7579f77SDag-Erling Smørgrav 	return c;
2521b7579f77SDag-Erling Smørgrav }
2522b7579f77SDag-Erling Smørgrav 
2523b7579f77SDag-Erling Smørgrav static struct comm_point*
2524b7579f77SDag-Erling Smørgrav comm_point_create_tcp_handler(struct comm_base *base,
2525b7579f77SDag-Erling Smørgrav 	struct comm_point* parent, size_t bufsize,
25263005e0a3SDag-Erling Smørgrav         comm_point_callback_type* callback, void* callback_arg)
2527b7579f77SDag-Erling Smørgrav {
2528b7579f77SDag-Erling Smørgrav 	struct comm_point* c = (struct comm_point*)calloc(1,
2529b7579f77SDag-Erling Smørgrav 		sizeof(struct comm_point));
2530b7579f77SDag-Erling Smørgrav 	short evbits;
2531b7579f77SDag-Erling Smørgrav 	if(!c)
2532b7579f77SDag-Erling Smørgrav 		return NULL;
2533b7579f77SDag-Erling Smørgrav 	c->ev = (struct internal_event*)calloc(1,
2534b7579f77SDag-Erling Smørgrav 		sizeof(struct internal_event));
2535b7579f77SDag-Erling Smørgrav 	if(!c->ev) {
2536b7579f77SDag-Erling Smørgrav 		free(c);
2537b7579f77SDag-Erling Smørgrav 		return NULL;
2538b7579f77SDag-Erling Smørgrav 	}
2539b7579f77SDag-Erling Smørgrav 	c->ev->base = base;
2540b7579f77SDag-Erling Smørgrav 	c->fd = -1;
254117d15b25SDag-Erling Smørgrav 	c->buffer = sldns_buffer_new(bufsize);
2542b7579f77SDag-Erling Smørgrav 	if(!c->buffer) {
2543b7579f77SDag-Erling Smørgrav 		free(c->ev);
2544b7579f77SDag-Erling Smørgrav 		free(c);
2545b7579f77SDag-Erling Smørgrav 		return NULL;
2546b7579f77SDag-Erling Smørgrav 	}
2547b7579f77SDag-Erling Smørgrav 	c->timeout = (struct timeval*)malloc(sizeof(struct timeval));
2548b7579f77SDag-Erling Smørgrav 	if(!c->timeout) {
254917d15b25SDag-Erling Smørgrav 		sldns_buffer_free(c->buffer);
2550b7579f77SDag-Erling Smørgrav 		free(c->ev);
2551b7579f77SDag-Erling Smørgrav 		free(c);
2552b7579f77SDag-Erling Smørgrav 		return NULL;
2553b7579f77SDag-Erling Smørgrav 	}
2554b7579f77SDag-Erling Smørgrav 	c->tcp_is_reading = 0;
2555b7579f77SDag-Erling Smørgrav 	c->tcp_byte_count = 0;
2556b7579f77SDag-Erling Smørgrav 	c->tcp_parent = parent;
2557*4c75e3aaSDag-Erling Smørgrav 	c->tcp_timeout_msec = parent->tcp_timeout_msec;
2558*4c75e3aaSDag-Erling Smørgrav 	c->tcp_conn_limit = parent->tcp_conn_limit;
2559*4c75e3aaSDag-Erling Smørgrav 	c->tcl_addr = NULL;
2560*4c75e3aaSDag-Erling Smørgrav 	c->tcp_keepalive = 0;
2561b7579f77SDag-Erling Smørgrav 	c->max_tcp_count = 0;
256209a3aaf3SDag-Erling Smørgrav 	c->cur_tcp_count = 0;
2563b7579f77SDag-Erling Smørgrav 	c->tcp_handlers = NULL;
2564b7579f77SDag-Erling Smørgrav 	c->tcp_free = NULL;
2565b7579f77SDag-Erling Smørgrav 	c->type = comm_tcp;
2566b7579f77SDag-Erling Smørgrav 	c->tcp_do_close = 0;
2567b7579f77SDag-Erling Smørgrav 	c->do_not_close = 0;
2568b7579f77SDag-Erling Smørgrav 	c->tcp_do_toggle_rw = 1;
2569b7579f77SDag-Erling Smørgrav 	c->tcp_check_nb_connect = 0;
2570b5663de9SDag-Erling Smørgrav #ifdef USE_MSG_FASTOPEN
2571b5663de9SDag-Erling Smørgrav 	c->tcp_do_fastopen = 0;
2572b5663de9SDag-Erling Smørgrav #endif
257365b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT
257465b390aaSDag-Erling Smørgrav 	c->dnscrypt = 0;
2575c7f4d7adSDag-Erling Smørgrav 	/* We don't know just yet if this is a dnscrypt channel. Allocation
2576c7f4d7adSDag-Erling Smørgrav 	 * will be done when handling the callback. */
257765b390aaSDag-Erling Smørgrav 	c->dnscrypt_buffer = c->buffer;
257865b390aaSDag-Erling Smørgrav #endif
2579b7579f77SDag-Erling Smørgrav 	c->repinfo.c = c;
2580b7579f77SDag-Erling Smørgrav 	c->callback = callback;
2581b7579f77SDag-Erling Smørgrav 	c->cb_arg = callback_arg;
2582b7579f77SDag-Erling Smørgrav 	/* add to parent free list */
2583b7579f77SDag-Erling Smørgrav 	c->tcp_free = parent->tcp_free;
2584b7579f77SDag-Erling Smørgrav 	parent->tcp_free = c;
2585e2d15004SDag-Erling Smørgrav 	/* ub_event stuff */
2586e2d15004SDag-Erling Smørgrav 	evbits = UB_EV_PERSIST | UB_EV_READ | UB_EV_TIMEOUT;
2587e2d15004SDag-Erling Smørgrav 	c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
2588e2d15004SDag-Erling Smørgrav 		comm_point_tcp_handle_callback, c);
2589e2d15004SDag-Erling Smørgrav 	if(c->ev->ev == NULL)
2590b7579f77SDag-Erling Smørgrav 	{
2591b7579f77SDag-Erling Smørgrav 		log_err("could not basetset tcphdl event");
2592b7579f77SDag-Erling Smørgrav 		parent->tcp_free = c->tcp_free;
2593b7579f77SDag-Erling Smørgrav 		free(c->ev);
2594b7579f77SDag-Erling Smørgrav 		free(c);
2595b7579f77SDag-Erling Smørgrav 		return NULL;
2596b7579f77SDag-Erling Smørgrav 	}
2597b7579f77SDag-Erling Smørgrav 	return c;
2598b7579f77SDag-Erling Smørgrav }
2599b7579f77SDag-Erling Smørgrav 
2600b7579f77SDag-Erling Smørgrav struct comm_point*
2601*4c75e3aaSDag-Erling Smørgrav comm_point_create_tcp(struct comm_base *base, int fd, int num,
2602*4c75e3aaSDag-Erling Smørgrav 	int idle_timeout, struct tcl_list* tcp_conn_limit, size_t bufsize,
26033005e0a3SDag-Erling Smørgrav         comm_point_callback_type* callback, void* callback_arg)
2604b7579f77SDag-Erling Smørgrav {
2605b7579f77SDag-Erling Smørgrav 	struct comm_point* c = (struct comm_point*)calloc(1,
2606b7579f77SDag-Erling Smørgrav 		sizeof(struct comm_point));
2607b7579f77SDag-Erling Smørgrav 	short evbits;
2608b7579f77SDag-Erling Smørgrav 	int i;
2609b7579f77SDag-Erling Smørgrav 	/* first allocate the TCP accept listener */
2610b7579f77SDag-Erling Smørgrav 	if(!c)
2611b7579f77SDag-Erling Smørgrav 		return NULL;
2612b7579f77SDag-Erling Smørgrav 	c->ev = (struct internal_event*)calloc(1,
2613b7579f77SDag-Erling Smørgrav 		sizeof(struct internal_event));
2614b7579f77SDag-Erling Smørgrav 	if(!c->ev) {
2615b7579f77SDag-Erling Smørgrav 		free(c);
2616b7579f77SDag-Erling Smørgrav 		return NULL;
2617b7579f77SDag-Erling Smørgrav 	}
2618b7579f77SDag-Erling Smørgrav 	c->ev->base = base;
2619b7579f77SDag-Erling Smørgrav 	c->fd = fd;
2620b7579f77SDag-Erling Smørgrav 	c->buffer = NULL;
2621b7579f77SDag-Erling Smørgrav 	c->timeout = NULL;
2622b7579f77SDag-Erling Smørgrav 	c->tcp_is_reading = 0;
2623b7579f77SDag-Erling Smørgrav 	c->tcp_byte_count = 0;
2624*4c75e3aaSDag-Erling Smørgrav 	c->tcp_timeout_msec = idle_timeout;
2625*4c75e3aaSDag-Erling Smørgrav 	c->tcp_conn_limit = tcp_conn_limit;
2626*4c75e3aaSDag-Erling Smørgrav 	c->tcl_addr = NULL;
2627*4c75e3aaSDag-Erling Smørgrav 	c->tcp_keepalive = 0;
2628b7579f77SDag-Erling Smørgrav 	c->tcp_parent = NULL;
2629b7579f77SDag-Erling Smørgrav 	c->max_tcp_count = num;
263009a3aaf3SDag-Erling Smørgrav 	c->cur_tcp_count = 0;
2631b7579f77SDag-Erling Smørgrav 	c->tcp_handlers = (struct comm_point**)calloc((size_t)num,
2632b7579f77SDag-Erling Smørgrav 		sizeof(struct comm_point*));
2633b7579f77SDag-Erling Smørgrav 	if(!c->tcp_handlers) {
2634b7579f77SDag-Erling Smørgrav 		free(c->ev);
2635b7579f77SDag-Erling Smørgrav 		free(c);
2636b7579f77SDag-Erling Smørgrav 		return NULL;
2637b7579f77SDag-Erling Smørgrav 	}
2638b7579f77SDag-Erling Smørgrav 	c->tcp_free = NULL;
2639b7579f77SDag-Erling Smørgrav 	c->type = comm_tcp_accept;
2640b7579f77SDag-Erling Smørgrav 	c->tcp_do_close = 0;
2641b7579f77SDag-Erling Smørgrav 	c->do_not_close = 0;
2642b7579f77SDag-Erling Smørgrav 	c->tcp_do_toggle_rw = 0;
2643b7579f77SDag-Erling Smørgrav 	c->tcp_check_nb_connect = 0;
2644b5663de9SDag-Erling Smørgrav #ifdef USE_MSG_FASTOPEN
2645b5663de9SDag-Erling Smørgrav 	c->tcp_do_fastopen = 0;
2646b5663de9SDag-Erling Smørgrav #endif
264765b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT
264865b390aaSDag-Erling Smørgrav 	c->dnscrypt = 0;
264965b390aaSDag-Erling Smørgrav 	c->dnscrypt_buffer = NULL;
265065b390aaSDag-Erling Smørgrav #endif
2651b7579f77SDag-Erling Smørgrav 	c->callback = NULL;
2652b7579f77SDag-Erling Smørgrav 	c->cb_arg = NULL;
2653e2d15004SDag-Erling Smørgrav 	evbits = UB_EV_READ | UB_EV_PERSIST;
2654e2d15004SDag-Erling Smørgrav 	/* ub_event stuff */
2655e2d15004SDag-Erling Smørgrav 	c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
2656e2d15004SDag-Erling Smørgrav 		comm_point_tcp_accept_callback, c);
2657e2d15004SDag-Erling Smørgrav 	if(c->ev->ev == NULL) {
2658e2d15004SDag-Erling Smørgrav 		log_err("could not baseset tcpacc event");
2659e2d15004SDag-Erling Smørgrav 		comm_point_delete(c);
2660e2d15004SDag-Erling Smørgrav 		return NULL;
2661e2d15004SDag-Erling Smørgrav 	}
2662e2d15004SDag-Erling Smørgrav 	if (ub_event_add(c->ev->ev, c->timeout) != 0) {
2663b7579f77SDag-Erling Smørgrav 		log_err("could not add tcpacc event");
2664b7579f77SDag-Erling Smørgrav 		comm_point_delete(c);
2665b7579f77SDag-Erling Smørgrav 		return NULL;
2666b7579f77SDag-Erling Smørgrav 	}
2667b7579f77SDag-Erling Smørgrav 	/* now prealloc the tcp handlers */
2668b7579f77SDag-Erling Smørgrav 	for(i=0; i<num; i++) {
2669b7579f77SDag-Erling Smørgrav 		c->tcp_handlers[i] = comm_point_create_tcp_handler(base,
2670b7579f77SDag-Erling Smørgrav 			c, bufsize, callback, callback_arg);
2671b7579f77SDag-Erling Smørgrav 		if(!c->tcp_handlers[i]) {
2672b7579f77SDag-Erling Smørgrav 			comm_point_delete(c);
2673b7579f77SDag-Erling Smørgrav 			return NULL;
2674b7579f77SDag-Erling Smørgrav 		}
2675b7579f77SDag-Erling Smørgrav 	}
2676b7579f77SDag-Erling Smørgrav 
2677b7579f77SDag-Erling Smørgrav 	return c;
2678b7579f77SDag-Erling Smørgrav }
2679b7579f77SDag-Erling Smørgrav 
2680b7579f77SDag-Erling Smørgrav struct comm_point*
2681b7579f77SDag-Erling Smørgrav comm_point_create_tcp_out(struct comm_base *base, size_t bufsize,
26823005e0a3SDag-Erling Smørgrav         comm_point_callback_type* callback, void* callback_arg)
2683b7579f77SDag-Erling Smørgrav {
2684b7579f77SDag-Erling Smørgrav 	struct comm_point* c = (struct comm_point*)calloc(1,
2685b7579f77SDag-Erling Smørgrav 		sizeof(struct comm_point));
2686b7579f77SDag-Erling Smørgrav 	short evbits;
2687b7579f77SDag-Erling Smørgrav 	if(!c)
2688b7579f77SDag-Erling Smørgrav 		return NULL;
2689b7579f77SDag-Erling Smørgrav 	c->ev = (struct internal_event*)calloc(1,
2690b7579f77SDag-Erling Smørgrav 		sizeof(struct internal_event));
2691b7579f77SDag-Erling Smørgrav 	if(!c->ev) {
2692b7579f77SDag-Erling Smørgrav 		free(c);
2693b7579f77SDag-Erling Smørgrav 		return NULL;
2694b7579f77SDag-Erling Smørgrav 	}
2695b7579f77SDag-Erling Smørgrav 	c->ev->base = base;
2696b7579f77SDag-Erling Smørgrav 	c->fd = -1;
269717d15b25SDag-Erling Smørgrav 	c->buffer = sldns_buffer_new(bufsize);
2698b7579f77SDag-Erling Smørgrav 	if(!c->buffer) {
2699b7579f77SDag-Erling Smørgrav 		free(c->ev);
2700b7579f77SDag-Erling Smørgrav 		free(c);
2701b7579f77SDag-Erling Smørgrav 		return NULL;
2702b7579f77SDag-Erling Smørgrav 	}
2703b7579f77SDag-Erling Smørgrav 	c->timeout = NULL;
2704b7579f77SDag-Erling Smørgrav 	c->tcp_is_reading = 0;
2705b7579f77SDag-Erling Smørgrav 	c->tcp_byte_count = 0;
2706*4c75e3aaSDag-Erling Smørgrav 	c->tcp_timeout_msec = TCP_QUERY_TIMEOUT;
2707*4c75e3aaSDag-Erling Smørgrav 	c->tcp_conn_limit = NULL;
2708*4c75e3aaSDag-Erling Smørgrav 	c->tcl_addr = NULL;
2709*4c75e3aaSDag-Erling Smørgrav 	c->tcp_keepalive = 0;
2710b7579f77SDag-Erling Smørgrav 	c->tcp_parent = NULL;
2711b7579f77SDag-Erling Smørgrav 	c->max_tcp_count = 0;
271209a3aaf3SDag-Erling Smørgrav 	c->cur_tcp_count = 0;
2713b7579f77SDag-Erling Smørgrav 	c->tcp_handlers = NULL;
2714b7579f77SDag-Erling Smørgrav 	c->tcp_free = NULL;
2715b7579f77SDag-Erling Smørgrav 	c->type = comm_tcp;
2716b7579f77SDag-Erling Smørgrav 	c->tcp_do_close = 0;
2717b7579f77SDag-Erling Smørgrav 	c->do_not_close = 0;
2718b7579f77SDag-Erling Smørgrav 	c->tcp_do_toggle_rw = 1;
2719b7579f77SDag-Erling Smørgrav 	c->tcp_check_nb_connect = 1;
2720b5663de9SDag-Erling Smørgrav #ifdef USE_MSG_FASTOPEN
2721b5663de9SDag-Erling Smørgrav 	c->tcp_do_fastopen = 1;
2722b5663de9SDag-Erling Smørgrav #endif
272365b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT
272465b390aaSDag-Erling Smørgrav 	c->dnscrypt = 0;
272565b390aaSDag-Erling Smørgrav 	c->dnscrypt_buffer = c->buffer;
272665b390aaSDag-Erling Smørgrav #endif
2727b7579f77SDag-Erling Smørgrav 	c->repinfo.c = c;
2728b7579f77SDag-Erling Smørgrav 	c->callback = callback;
2729b7579f77SDag-Erling Smørgrav 	c->cb_arg = callback_arg;
2730e2d15004SDag-Erling Smørgrav 	evbits = UB_EV_PERSIST | UB_EV_WRITE;
2731e2d15004SDag-Erling Smørgrav 	c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
2732e2d15004SDag-Erling Smørgrav 		comm_point_tcp_handle_callback, c);
2733e2d15004SDag-Erling Smørgrav 	if(c->ev->ev == NULL)
2734b7579f77SDag-Erling Smørgrav 	{
2735e2d15004SDag-Erling Smørgrav 		log_err("could not baseset tcpout event");
273617d15b25SDag-Erling Smørgrav 		sldns_buffer_free(c->buffer);
2737b7579f77SDag-Erling Smørgrav 		free(c->ev);
2738b7579f77SDag-Erling Smørgrav 		free(c);
2739b7579f77SDag-Erling Smørgrav 		return NULL;
2740b7579f77SDag-Erling Smørgrav 	}
2741b7579f77SDag-Erling Smørgrav 
2742b7579f77SDag-Erling Smørgrav 	return c;
2743b7579f77SDag-Erling Smørgrav }
2744b7579f77SDag-Erling Smørgrav 
2745b7579f77SDag-Erling Smørgrav struct comm_point*
274657bddd21SDag-Erling Smørgrav comm_point_create_http_out(struct comm_base *base, size_t bufsize,
274757bddd21SDag-Erling Smørgrav         comm_point_callback_type* callback, void* callback_arg,
274857bddd21SDag-Erling Smørgrav 	sldns_buffer* temp)
274957bddd21SDag-Erling Smørgrav {
275057bddd21SDag-Erling Smørgrav 	struct comm_point* c = (struct comm_point*)calloc(1,
275157bddd21SDag-Erling Smørgrav 		sizeof(struct comm_point));
275257bddd21SDag-Erling Smørgrav 	short evbits;
275357bddd21SDag-Erling Smørgrav 	if(!c)
275457bddd21SDag-Erling Smørgrav 		return NULL;
275557bddd21SDag-Erling Smørgrav 	c->ev = (struct internal_event*)calloc(1,
275657bddd21SDag-Erling Smørgrav 		sizeof(struct internal_event));
275757bddd21SDag-Erling Smørgrav 	if(!c->ev) {
275857bddd21SDag-Erling Smørgrav 		free(c);
275957bddd21SDag-Erling Smørgrav 		return NULL;
276057bddd21SDag-Erling Smørgrav 	}
276157bddd21SDag-Erling Smørgrav 	c->ev->base = base;
276257bddd21SDag-Erling Smørgrav 	c->fd = -1;
276357bddd21SDag-Erling Smørgrav 	c->buffer = sldns_buffer_new(bufsize);
276457bddd21SDag-Erling Smørgrav 	if(!c->buffer) {
276557bddd21SDag-Erling Smørgrav 		free(c->ev);
276657bddd21SDag-Erling Smørgrav 		free(c);
276757bddd21SDag-Erling Smørgrav 		return NULL;
276857bddd21SDag-Erling Smørgrav 	}
276957bddd21SDag-Erling Smørgrav 	c->timeout = NULL;
277057bddd21SDag-Erling Smørgrav 	c->tcp_is_reading = 0;
277157bddd21SDag-Erling Smørgrav 	c->tcp_byte_count = 0;
277257bddd21SDag-Erling Smørgrav 	c->tcp_parent = NULL;
277357bddd21SDag-Erling Smørgrav 	c->max_tcp_count = 0;
277457bddd21SDag-Erling Smørgrav 	c->cur_tcp_count = 0;
277557bddd21SDag-Erling Smørgrav 	c->tcp_handlers = NULL;
277657bddd21SDag-Erling Smørgrav 	c->tcp_free = NULL;
277757bddd21SDag-Erling Smørgrav 	c->type = comm_http;
277857bddd21SDag-Erling Smørgrav 	c->tcp_do_close = 0;
277957bddd21SDag-Erling Smørgrav 	c->do_not_close = 0;
278057bddd21SDag-Erling Smørgrav 	c->tcp_do_toggle_rw = 1;
278157bddd21SDag-Erling Smørgrav 	c->tcp_check_nb_connect = 1;
278257bddd21SDag-Erling Smørgrav 	c->http_in_headers = 1;
278357bddd21SDag-Erling Smørgrav 	c->http_in_chunk_headers = 0;
278457bddd21SDag-Erling Smørgrav 	c->http_is_chunked = 0;
278557bddd21SDag-Erling Smørgrav 	c->http_temp = temp;
278657bddd21SDag-Erling Smørgrav #ifdef USE_MSG_FASTOPEN
278757bddd21SDag-Erling Smørgrav 	c->tcp_do_fastopen = 1;
278857bddd21SDag-Erling Smørgrav #endif
278957bddd21SDag-Erling Smørgrav #ifdef USE_DNSCRYPT
279057bddd21SDag-Erling Smørgrav 	c->dnscrypt = 0;
279157bddd21SDag-Erling Smørgrav 	c->dnscrypt_buffer = c->buffer;
279257bddd21SDag-Erling Smørgrav #endif
279357bddd21SDag-Erling Smørgrav 	c->repinfo.c = c;
279457bddd21SDag-Erling Smørgrav 	c->callback = callback;
279557bddd21SDag-Erling Smørgrav 	c->cb_arg = callback_arg;
279657bddd21SDag-Erling Smørgrav 	evbits = UB_EV_PERSIST | UB_EV_WRITE;
279757bddd21SDag-Erling Smørgrav 	c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
279857bddd21SDag-Erling Smørgrav 		comm_point_http_handle_callback, c);
279957bddd21SDag-Erling Smørgrav 	if(c->ev->ev == NULL)
280057bddd21SDag-Erling Smørgrav 	{
280157bddd21SDag-Erling Smørgrav 		log_err("could not baseset tcpout event");
280257bddd21SDag-Erling Smørgrav #ifdef HAVE_SSL
280357bddd21SDag-Erling Smørgrav 		SSL_free(c->ssl);
280457bddd21SDag-Erling Smørgrav #endif
280557bddd21SDag-Erling Smørgrav 		sldns_buffer_free(c->buffer);
280657bddd21SDag-Erling Smørgrav 		free(c->ev);
280757bddd21SDag-Erling Smørgrav 		free(c);
280857bddd21SDag-Erling Smørgrav 		return NULL;
280957bddd21SDag-Erling Smørgrav 	}
281057bddd21SDag-Erling Smørgrav 
281157bddd21SDag-Erling Smørgrav 	return c;
281257bddd21SDag-Erling Smørgrav }
281357bddd21SDag-Erling Smørgrav 
281457bddd21SDag-Erling Smørgrav struct comm_point*
2815b7579f77SDag-Erling Smørgrav comm_point_create_local(struct comm_base *base, int fd, size_t bufsize,
28163005e0a3SDag-Erling Smørgrav         comm_point_callback_type* callback, void* callback_arg)
2817b7579f77SDag-Erling Smørgrav {
2818b7579f77SDag-Erling Smørgrav 	struct comm_point* c = (struct comm_point*)calloc(1,
2819b7579f77SDag-Erling Smørgrav 		sizeof(struct comm_point));
2820b7579f77SDag-Erling Smørgrav 	short evbits;
2821b7579f77SDag-Erling Smørgrav 	if(!c)
2822b7579f77SDag-Erling Smørgrav 		return NULL;
2823b7579f77SDag-Erling Smørgrav 	c->ev = (struct internal_event*)calloc(1,
2824b7579f77SDag-Erling Smørgrav 		sizeof(struct internal_event));
2825b7579f77SDag-Erling Smørgrav 	if(!c->ev) {
2826b7579f77SDag-Erling Smørgrav 		free(c);
2827b7579f77SDag-Erling Smørgrav 		return NULL;
2828b7579f77SDag-Erling Smørgrav 	}
2829b7579f77SDag-Erling Smørgrav 	c->ev->base = base;
2830b7579f77SDag-Erling Smørgrav 	c->fd = fd;
283117d15b25SDag-Erling Smørgrav 	c->buffer = sldns_buffer_new(bufsize);
2832b7579f77SDag-Erling Smørgrav 	if(!c->buffer) {
2833b7579f77SDag-Erling Smørgrav 		free(c->ev);
2834b7579f77SDag-Erling Smørgrav 		free(c);
2835b7579f77SDag-Erling Smørgrav 		return NULL;
2836b7579f77SDag-Erling Smørgrav 	}
2837b7579f77SDag-Erling Smørgrav 	c->timeout = NULL;
2838b7579f77SDag-Erling Smørgrav 	c->tcp_is_reading = 1;
2839b7579f77SDag-Erling Smørgrav 	c->tcp_byte_count = 0;
2840b7579f77SDag-Erling Smørgrav 	c->tcp_parent = NULL;
2841b7579f77SDag-Erling Smørgrav 	c->max_tcp_count = 0;
284209a3aaf3SDag-Erling Smørgrav 	c->cur_tcp_count = 0;
2843b7579f77SDag-Erling Smørgrav 	c->tcp_handlers = NULL;
2844b7579f77SDag-Erling Smørgrav 	c->tcp_free = NULL;
2845b7579f77SDag-Erling Smørgrav 	c->type = comm_local;
2846b7579f77SDag-Erling Smørgrav 	c->tcp_do_close = 0;
2847b7579f77SDag-Erling Smørgrav 	c->do_not_close = 1;
2848b7579f77SDag-Erling Smørgrav 	c->tcp_do_toggle_rw = 0;
2849b7579f77SDag-Erling Smørgrav 	c->tcp_check_nb_connect = 0;
2850b5663de9SDag-Erling Smørgrav #ifdef USE_MSG_FASTOPEN
2851b5663de9SDag-Erling Smørgrav 	c->tcp_do_fastopen = 0;
2852b5663de9SDag-Erling Smørgrav #endif
285365b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT
285465b390aaSDag-Erling Smørgrav 	c->dnscrypt = 0;
285565b390aaSDag-Erling Smørgrav 	c->dnscrypt_buffer = c->buffer;
285665b390aaSDag-Erling Smørgrav #endif
2857b7579f77SDag-Erling Smørgrav 	c->callback = callback;
2858b7579f77SDag-Erling Smørgrav 	c->cb_arg = callback_arg;
2859e2d15004SDag-Erling Smørgrav 	/* ub_event stuff */
2860e2d15004SDag-Erling Smørgrav 	evbits = UB_EV_PERSIST | UB_EV_READ;
2861e2d15004SDag-Erling Smørgrav 	c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
2862e2d15004SDag-Erling Smørgrav 		comm_point_local_handle_callback, c);
2863e2d15004SDag-Erling Smørgrav 	if(c->ev->ev == NULL) {
2864e2d15004SDag-Erling Smørgrav 		log_err("could not baseset localhdl event");
2865e2d15004SDag-Erling Smørgrav 		free(c->ev);
2866e2d15004SDag-Erling Smørgrav 		free(c);
2867e2d15004SDag-Erling Smørgrav 		return NULL;
2868e2d15004SDag-Erling Smørgrav 	}
2869e2d15004SDag-Erling Smørgrav 	if (ub_event_add(c->ev->ev, c->timeout) != 0) {
2870b7579f77SDag-Erling Smørgrav 		log_err("could not add localhdl event");
2871e2d15004SDag-Erling Smørgrav 		ub_event_free(c->ev->ev);
2872b7579f77SDag-Erling Smørgrav 		free(c->ev);
2873b7579f77SDag-Erling Smørgrav 		free(c);
2874b7579f77SDag-Erling Smørgrav 		return NULL;
2875b7579f77SDag-Erling Smørgrav 	}
2876b7579f77SDag-Erling Smørgrav 	return c;
2877b7579f77SDag-Erling Smørgrav }
2878b7579f77SDag-Erling Smørgrav 
2879b7579f77SDag-Erling Smørgrav struct comm_point*
2880b7579f77SDag-Erling Smørgrav comm_point_create_raw(struct comm_base* base, int fd, int writing,
28813005e0a3SDag-Erling Smørgrav 	comm_point_callback_type* callback, void* callback_arg)
2882b7579f77SDag-Erling Smørgrav {
2883b7579f77SDag-Erling Smørgrav 	struct comm_point* c = (struct comm_point*)calloc(1,
2884b7579f77SDag-Erling Smørgrav 		sizeof(struct comm_point));
2885b7579f77SDag-Erling Smørgrav 	short evbits;
2886b7579f77SDag-Erling Smørgrav 	if(!c)
2887b7579f77SDag-Erling Smørgrav 		return NULL;
2888b7579f77SDag-Erling Smørgrav 	c->ev = (struct internal_event*)calloc(1,
2889b7579f77SDag-Erling Smørgrav 		sizeof(struct internal_event));
2890b7579f77SDag-Erling Smørgrav 	if(!c->ev) {
2891b7579f77SDag-Erling Smørgrav 		free(c);
2892b7579f77SDag-Erling Smørgrav 		return NULL;
2893b7579f77SDag-Erling Smørgrav 	}
2894b7579f77SDag-Erling Smørgrav 	c->ev->base = base;
2895b7579f77SDag-Erling Smørgrav 	c->fd = fd;
2896b7579f77SDag-Erling Smørgrav 	c->buffer = NULL;
2897b7579f77SDag-Erling Smørgrav 	c->timeout = NULL;
2898b7579f77SDag-Erling Smørgrav 	c->tcp_is_reading = 0;
2899b7579f77SDag-Erling Smørgrav 	c->tcp_byte_count = 0;
2900b7579f77SDag-Erling Smørgrav 	c->tcp_parent = NULL;
2901b7579f77SDag-Erling Smørgrav 	c->max_tcp_count = 0;
290209a3aaf3SDag-Erling Smørgrav 	c->cur_tcp_count = 0;
2903b7579f77SDag-Erling Smørgrav 	c->tcp_handlers = NULL;
2904b7579f77SDag-Erling Smørgrav 	c->tcp_free = NULL;
2905b7579f77SDag-Erling Smørgrav 	c->type = comm_raw;
2906b7579f77SDag-Erling Smørgrav 	c->tcp_do_close = 0;
2907b7579f77SDag-Erling Smørgrav 	c->do_not_close = 1;
2908b7579f77SDag-Erling Smørgrav 	c->tcp_do_toggle_rw = 0;
2909b7579f77SDag-Erling Smørgrav 	c->tcp_check_nb_connect = 0;
2910b5663de9SDag-Erling Smørgrav #ifdef USE_MSG_FASTOPEN
2911b5663de9SDag-Erling Smørgrav 	c->tcp_do_fastopen = 0;
2912b5663de9SDag-Erling Smørgrav #endif
291365b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT
291465b390aaSDag-Erling Smørgrav 	c->dnscrypt = 0;
291565b390aaSDag-Erling Smørgrav 	c->dnscrypt_buffer = c->buffer;
291665b390aaSDag-Erling Smørgrav #endif
2917b7579f77SDag-Erling Smørgrav 	c->callback = callback;
2918b7579f77SDag-Erling Smørgrav 	c->cb_arg = callback_arg;
2919e2d15004SDag-Erling Smørgrav 	/* ub_event stuff */
2920b7579f77SDag-Erling Smørgrav 	if(writing)
2921e2d15004SDag-Erling Smørgrav 		evbits = UB_EV_PERSIST | UB_EV_WRITE;
2922e2d15004SDag-Erling Smørgrav 	else 	evbits = UB_EV_PERSIST | UB_EV_READ;
2923e2d15004SDag-Erling Smørgrav 	c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
2924e2d15004SDag-Erling Smørgrav 		comm_point_raw_handle_callback, c);
2925e2d15004SDag-Erling Smørgrav 	if(c->ev->ev == NULL) {
2926e2d15004SDag-Erling Smørgrav 		log_err("could not baseset rawhdl event");
2927e2d15004SDag-Erling Smørgrav 		free(c->ev);
2928e2d15004SDag-Erling Smørgrav 		free(c);
2929e2d15004SDag-Erling Smørgrav 		return NULL;
2930e2d15004SDag-Erling Smørgrav 	}
2931e2d15004SDag-Erling Smørgrav 	if (ub_event_add(c->ev->ev, c->timeout) != 0) {
2932b7579f77SDag-Erling Smørgrav 		log_err("could not add rawhdl event");
2933e2d15004SDag-Erling Smørgrav 		ub_event_free(c->ev->ev);
2934b7579f77SDag-Erling Smørgrav 		free(c->ev);
2935b7579f77SDag-Erling Smørgrav 		free(c);
2936b7579f77SDag-Erling Smørgrav 		return NULL;
2937b7579f77SDag-Erling Smørgrav 	}
2938b7579f77SDag-Erling Smørgrav 	return c;
2939b7579f77SDag-Erling Smørgrav }
2940b7579f77SDag-Erling Smørgrav 
2941b7579f77SDag-Erling Smørgrav void
2942b7579f77SDag-Erling Smørgrav comm_point_close(struct comm_point* c)
2943b7579f77SDag-Erling Smørgrav {
2944b7579f77SDag-Erling Smørgrav 	if(!c)
2945b7579f77SDag-Erling Smørgrav 		return;
29463bd4df0aSDag-Erling Smørgrav 	if(c->fd != -1) {
2947e2d15004SDag-Erling Smørgrav 		if(ub_event_del(c->ev->ev) != 0) {
2948b7579f77SDag-Erling Smørgrav 			log_err("could not event_del on close");
2949b7579f77SDag-Erling Smørgrav 		}
29503bd4df0aSDag-Erling Smørgrav 	}
2951*4c75e3aaSDag-Erling Smørgrav 	tcl_close_connection(c->tcl_addr);
2952b7579f77SDag-Erling Smørgrav 	/* close fd after removing from event lists, or epoll.. is messed up */
2953b7579f77SDag-Erling Smørgrav 	if(c->fd != -1 && !c->do_not_close) {
29543bd4df0aSDag-Erling Smørgrav 		if(c->type == comm_tcp || c->type == comm_http) {
29553bd4df0aSDag-Erling Smørgrav 			/* delete sticky events for the fd, it gets closed */
29563bd4df0aSDag-Erling Smørgrav 			ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
29573bd4df0aSDag-Erling Smørgrav 			ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
29583bd4df0aSDag-Erling Smørgrav 		}
2959b7579f77SDag-Erling Smørgrav 		verbose(VERB_ALGO, "close fd %d", c->fd);
2960b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK
2961b7579f77SDag-Erling Smørgrav 		close(c->fd);
2962b7579f77SDag-Erling Smørgrav #else
2963b7579f77SDag-Erling Smørgrav 		closesocket(c->fd);
2964b7579f77SDag-Erling Smørgrav #endif
2965b7579f77SDag-Erling Smørgrav 	}
2966b7579f77SDag-Erling Smørgrav 	c->fd = -1;
2967b7579f77SDag-Erling Smørgrav }
2968b7579f77SDag-Erling Smørgrav 
2969b7579f77SDag-Erling Smørgrav void
2970b7579f77SDag-Erling Smørgrav comm_point_delete(struct comm_point* c)
2971b7579f77SDag-Erling Smørgrav {
2972b7579f77SDag-Erling Smørgrav 	if(!c)
2973b7579f77SDag-Erling Smørgrav 		return;
297457bddd21SDag-Erling Smørgrav 	if((c->type == comm_tcp || c->type == comm_http) && c->ssl) {
29758ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL
2976b7579f77SDag-Erling Smørgrav 		SSL_shutdown(c->ssl);
2977b7579f77SDag-Erling Smørgrav 		SSL_free(c->ssl);
29788ed2b524SDag-Erling Smørgrav #endif
2979b7579f77SDag-Erling Smørgrav 	}
2980b7579f77SDag-Erling Smørgrav 	comm_point_close(c);
2981b7579f77SDag-Erling Smørgrav 	if(c->tcp_handlers) {
2982b7579f77SDag-Erling Smørgrav 		int i;
2983b7579f77SDag-Erling Smørgrav 		for(i=0; i<c->max_tcp_count; i++)
2984b7579f77SDag-Erling Smørgrav 			comm_point_delete(c->tcp_handlers[i]);
2985b7579f77SDag-Erling Smørgrav 		free(c->tcp_handlers);
2986b7579f77SDag-Erling Smørgrav 	}
2987b7579f77SDag-Erling Smørgrav 	free(c->timeout);
298857bddd21SDag-Erling Smørgrav 	if(c->type == comm_tcp || c->type == comm_local || c->type == comm_http) {
298917d15b25SDag-Erling Smørgrav 		sldns_buffer_free(c->buffer);
299065b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT
299165b390aaSDag-Erling Smørgrav 		if(c->dnscrypt && c->dnscrypt_buffer != c->buffer) {
299265b390aaSDag-Erling Smørgrav 			sldns_buffer_free(c->dnscrypt_buffer);
299365b390aaSDag-Erling Smørgrav 		}
299465b390aaSDag-Erling Smørgrav #endif
299565b390aaSDag-Erling Smørgrav 	}
2996e2d15004SDag-Erling Smørgrav 	ub_event_free(c->ev->ev);
2997b7579f77SDag-Erling Smørgrav 	free(c->ev);
2998b7579f77SDag-Erling Smørgrav 	free(c);
2999b7579f77SDag-Erling Smørgrav }
3000b7579f77SDag-Erling Smørgrav 
3001b7579f77SDag-Erling Smørgrav void
3002b7579f77SDag-Erling Smørgrav comm_point_send_reply(struct comm_reply *repinfo)
3003b7579f77SDag-Erling Smørgrav {
300465b390aaSDag-Erling Smørgrav 	struct sldns_buffer* buffer;
3005b7579f77SDag-Erling Smørgrav 	log_assert(repinfo && repinfo->c);
300665b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT
300765b390aaSDag-Erling Smørgrav 	buffer = repinfo->c->dnscrypt_buffer;
300865b390aaSDag-Erling Smørgrav 	if(!dnsc_handle_uncurved_request(repinfo)) {
300965b390aaSDag-Erling Smørgrav 		return;
301065b390aaSDag-Erling Smørgrav 	}
301165b390aaSDag-Erling Smørgrav #else
301265b390aaSDag-Erling Smørgrav 	buffer = repinfo->c->buffer;
301365b390aaSDag-Erling Smørgrav #endif
3014b7579f77SDag-Erling Smørgrav 	if(repinfo->c->type == comm_udp) {
3015b7579f77SDag-Erling Smørgrav 		if(repinfo->srctype)
3016b7579f77SDag-Erling Smørgrav 			comm_point_send_udp_msg_if(repinfo->c,
301765b390aaSDag-Erling Smørgrav 			buffer, (struct sockaddr*)&repinfo->addr,
3018b7579f77SDag-Erling Smørgrav 			repinfo->addrlen, repinfo);
3019b7579f77SDag-Erling Smørgrav 		else
302065b390aaSDag-Erling Smørgrav 			comm_point_send_udp_msg(repinfo->c, buffer,
3021b7579f77SDag-Erling Smørgrav 			(struct sockaddr*)&repinfo->addr, repinfo->addrlen);
3022ff825849SDag-Erling Smørgrav #ifdef USE_DNSTAP
3023ff825849SDag-Erling Smørgrav 		if(repinfo->c->dtenv != NULL &&
3024ff825849SDag-Erling Smørgrav 		   repinfo->c->dtenv->log_client_response_messages)
3025ff825849SDag-Erling Smørgrav 			dt_msg_send_client_response(repinfo->c->dtenv,
3026ff825849SDag-Erling Smørgrav 			&repinfo->addr, repinfo->c->type, repinfo->c->buffer);
3027ff825849SDag-Erling Smørgrav #endif
3028b7579f77SDag-Erling Smørgrav 	} else {
3029ff825849SDag-Erling Smørgrav #ifdef USE_DNSTAP
3030ff825849SDag-Erling Smørgrav 		if(repinfo->c->tcp_parent->dtenv != NULL &&
3031ff825849SDag-Erling Smørgrav 		   repinfo->c->tcp_parent->dtenv->log_client_response_messages)
3032ff825849SDag-Erling Smørgrav 			dt_msg_send_client_response(repinfo->c->tcp_parent->dtenv,
3033ff825849SDag-Erling Smørgrav 			&repinfo->addr, repinfo->c->type, repinfo->c->buffer);
3034ff825849SDag-Erling Smørgrav #endif
3035b5663de9SDag-Erling Smørgrav 		comm_point_start_listening(repinfo->c, -1,
3036b5663de9SDag-Erling Smørgrav 			repinfo->c->tcp_timeout_msec);
3037b7579f77SDag-Erling Smørgrav 	}
3038b7579f77SDag-Erling Smørgrav }
3039b7579f77SDag-Erling Smørgrav 
3040b7579f77SDag-Erling Smørgrav void
3041b7579f77SDag-Erling Smørgrav comm_point_drop_reply(struct comm_reply* repinfo)
3042b7579f77SDag-Erling Smørgrav {
3043b7579f77SDag-Erling Smørgrav 	if(!repinfo)
3044b7579f77SDag-Erling Smørgrav 		return;
3045b7579f77SDag-Erling Smørgrav 	log_assert(repinfo && repinfo->c);
3046b7579f77SDag-Erling Smørgrav 	log_assert(repinfo->c->type != comm_tcp_accept);
3047b7579f77SDag-Erling Smørgrav 	if(repinfo->c->type == comm_udp)
3048b7579f77SDag-Erling Smørgrav 		return;
3049b7579f77SDag-Erling Smørgrav 	reclaim_tcp_handler(repinfo->c);
3050b7579f77SDag-Erling Smørgrav }
3051b7579f77SDag-Erling Smørgrav 
3052b7579f77SDag-Erling Smørgrav void
3053b7579f77SDag-Erling Smørgrav comm_point_stop_listening(struct comm_point* c)
3054b7579f77SDag-Erling Smørgrav {
3055b7579f77SDag-Erling Smørgrav 	verbose(VERB_ALGO, "comm point stop listening %d", c->fd);
3056e2d15004SDag-Erling Smørgrav 	if(ub_event_del(c->ev->ev) != 0) {
3057b7579f77SDag-Erling Smørgrav 		log_err("event_del error to stoplisten");
3058b7579f77SDag-Erling Smørgrav 	}
3059b7579f77SDag-Erling Smørgrav }
3060b7579f77SDag-Erling Smørgrav 
3061b7579f77SDag-Erling Smørgrav void
3062b5663de9SDag-Erling Smørgrav comm_point_start_listening(struct comm_point* c, int newfd, int msec)
3063b7579f77SDag-Erling Smørgrav {
3064b7579f77SDag-Erling Smørgrav 	verbose(VERB_ALGO, "comm point start listening %d",
3065b7579f77SDag-Erling Smørgrav 		c->fd==-1?newfd:c->fd);
3066b7579f77SDag-Erling Smørgrav 	if(c->type == comm_tcp_accept && !c->tcp_free) {
3067b7579f77SDag-Erling Smørgrav 		/* no use to start listening no free slots. */
3068b7579f77SDag-Erling Smørgrav 		return;
3069b7579f77SDag-Erling Smørgrav 	}
3070b5663de9SDag-Erling Smørgrav 	if(msec != -1 && msec != 0) {
3071b7579f77SDag-Erling Smørgrav 		if(!c->timeout) {
3072b7579f77SDag-Erling Smørgrav 			c->timeout = (struct timeval*)malloc(sizeof(
3073b7579f77SDag-Erling Smørgrav 				struct timeval));
3074b7579f77SDag-Erling Smørgrav 			if(!c->timeout) {
3075b7579f77SDag-Erling Smørgrav 				log_err("cpsl: malloc failed. No net read.");
3076b7579f77SDag-Erling Smørgrav 				return;
3077b7579f77SDag-Erling Smørgrav 			}
3078b7579f77SDag-Erling Smørgrav 		}
3079e2d15004SDag-Erling Smørgrav 		ub_event_add_bits(c->ev->ev, UB_EV_TIMEOUT);
3080b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S /* splint fails on struct timeval. */
3081b5663de9SDag-Erling Smørgrav 		c->timeout->tv_sec = msec/1000;
3082b5663de9SDag-Erling Smørgrav 		c->timeout->tv_usec = (msec%1000)*1000;
3083b7579f77SDag-Erling Smørgrav #endif /* S_SPLINT_S */
3084b7579f77SDag-Erling Smørgrav 	}
308557bddd21SDag-Erling Smørgrav 	if(c->type == comm_tcp || c->type == comm_http) {
3086e2d15004SDag-Erling Smørgrav 		ub_event_del_bits(c->ev->ev, UB_EV_READ|UB_EV_WRITE);
3087b7579f77SDag-Erling Smørgrav 		if(c->tcp_is_reading)
3088e2d15004SDag-Erling Smørgrav 			ub_event_add_bits(c->ev->ev, UB_EV_READ);
3089e2d15004SDag-Erling Smørgrav 		else	ub_event_add_bits(c->ev->ev, UB_EV_WRITE);
3090b7579f77SDag-Erling Smørgrav 	}
3091b7579f77SDag-Erling Smørgrav 	if(newfd != -1) {
3092b7579f77SDag-Erling Smørgrav 		if(c->fd != -1) {
3093b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK
3094b7579f77SDag-Erling Smørgrav 			close(c->fd);
3095b7579f77SDag-Erling Smørgrav #else
3096b7579f77SDag-Erling Smørgrav 			closesocket(c->fd);
3097b7579f77SDag-Erling Smørgrav #endif
3098b7579f77SDag-Erling Smørgrav 		}
3099b7579f77SDag-Erling Smørgrav 		c->fd = newfd;
3100e2d15004SDag-Erling Smørgrav 		ub_event_set_fd(c->ev->ev, c->fd);
3101b7579f77SDag-Erling Smørgrav 	}
3102b5663de9SDag-Erling Smørgrav 	if(ub_event_add(c->ev->ev, msec==0?NULL:c->timeout) != 0) {
3103b7579f77SDag-Erling Smørgrav 		log_err("event_add failed. in cpsl.");
3104b7579f77SDag-Erling Smørgrav 	}
3105b7579f77SDag-Erling Smørgrav }
3106b7579f77SDag-Erling Smørgrav 
3107b7579f77SDag-Erling Smørgrav void comm_point_listen_for_rw(struct comm_point* c, int rd, int wr)
3108b7579f77SDag-Erling Smørgrav {
3109b7579f77SDag-Erling Smørgrav 	verbose(VERB_ALGO, "comm point listen_for_rw %d %d", c->fd, wr);
3110e2d15004SDag-Erling Smørgrav 	if(ub_event_del(c->ev->ev) != 0) {
3111b7579f77SDag-Erling Smørgrav 		log_err("event_del error to cplf");
3112b7579f77SDag-Erling Smørgrav 	}
3113e2d15004SDag-Erling Smørgrav 	ub_event_del_bits(c->ev->ev, UB_EV_READ|UB_EV_WRITE);
3114e2d15004SDag-Erling Smørgrav 	if(rd) ub_event_add_bits(c->ev->ev, UB_EV_READ);
3115e2d15004SDag-Erling Smørgrav 	if(wr) ub_event_add_bits(c->ev->ev, UB_EV_WRITE);
3116e2d15004SDag-Erling Smørgrav 	if(ub_event_add(c->ev->ev, c->timeout) != 0) {
3117b7579f77SDag-Erling Smørgrav 		log_err("event_add failed. in cplf.");
3118b7579f77SDag-Erling Smørgrav 	}
3119b7579f77SDag-Erling Smørgrav }
3120b7579f77SDag-Erling Smørgrav 
3121b7579f77SDag-Erling Smørgrav size_t comm_point_get_mem(struct comm_point* c)
3122b7579f77SDag-Erling Smørgrav {
3123b7579f77SDag-Erling Smørgrav 	size_t s;
3124b7579f77SDag-Erling Smørgrav 	if(!c)
3125b7579f77SDag-Erling Smørgrav 		return 0;
3126b7579f77SDag-Erling Smørgrav 	s = sizeof(*c) + sizeof(*c->ev);
3127b7579f77SDag-Erling Smørgrav 	if(c->timeout)
3128b7579f77SDag-Erling Smørgrav 		s += sizeof(*c->timeout);
312965b390aaSDag-Erling Smørgrav 	if(c->type == comm_tcp || c->type == comm_local) {
313017d15b25SDag-Erling Smørgrav 		s += sizeof(*c->buffer) + sldns_buffer_capacity(c->buffer);
313165b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT
313265b390aaSDag-Erling Smørgrav 		s += sizeof(*c->dnscrypt_buffer);
313365b390aaSDag-Erling Smørgrav 		if(c->buffer != c->dnscrypt_buffer) {
313465b390aaSDag-Erling Smørgrav 			s += sldns_buffer_capacity(c->dnscrypt_buffer);
313565b390aaSDag-Erling Smørgrav 		}
313665b390aaSDag-Erling Smørgrav #endif
313765b390aaSDag-Erling Smørgrav 	}
3138b7579f77SDag-Erling Smørgrav 	if(c->type == comm_tcp_accept) {
3139b7579f77SDag-Erling Smørgrav 		int i;
3140b7579f77SDag-Erling Smørgrav 		for(i=0; i<c->max_tcp_count; i++)
3141b7579f77SDag-Erling Smørgrav 			s += comm_point_get_mem(c->tcp_handlers[i]);
3142b7579f77SDag-Erling Smørgrav 	}
3143b7579f77SDag-Erling Smørgrav 	return s;
3144b7579f77SDag-Erling Smørgrav }
3145b7579f77SDag-Erling Smørgrav 
3146b7579f77SDag-Erling Smørgrav struct comm_timer*
3147b7579f77SDag-Erling Smørgrav comm_timer_create(struct comm_base* base, void (*cb)(void*), void* cb_arg)
3148b7579f77SDag-Erling Smørgrav {
3149e2d15004SDag-Erling Smørgrav 	struct internal_timer *tm = (struct internal_timer*)calloc(1,
3150b7579f77SDag-Erling Smørgrav 		sizeof(struct internal_timer));
3151e2d15004SDag-Erling Smørgrav 	if(!tm) {
3152b7579f77SDag-Erling Smørgrav 		log_err("malloc failed");
3153b7579f77SDag-Erling Smørgrav 		return NULL;
3154b7579f77SDag-Erling Smørgrav 	}
3155e2d15004SDag-Erling Smørgrav 	tm->super.ev_timer = tm;
3156e2d15004SDag-Erling Smørgrav 	tm->base = base;
3157e2d15004SDag-Erling Smørgrav 	tm->super.callback = cb;
3158e2d15004SDag-Erling Smørgrav 	tm->super.cb_arg = cb_arg;
3159e2d15004SDag-Erling Smørgrav 	tm->ev = ub_event_new(base->eb->base, -1, UB_EV_TIMEOUT,
3160e2d15004SDag-Erling Smørgrav 		comm_timer_callback, &tm->super);
3161e2d15004SDag-Erling Smørgrav 	if(tm->ev == NULL) {
3162b7579f77SDag-Erling Smørgrav 		log_err("timer_create: event_base_set failed.");
3163b7579f77SDag-Erling Smørgrav 		free(tm);
3164b7579f77SDag-Erling Smørgrav 		return NULL;
3165b7579f77SDag-Erling Smørgrav 	}
3166e2d15004SDag-Erling Smørgrav 	return &tm->super;
3167b7579f77SDag-Erling Smørgrav }
3168b7579f77SDag-Erling Smørgrav 
3169b7579f77SDag-Erling Smørgrav void
3170b7579f77SDag-Erling Smørgrav comm_timer_disable(struct comm_timer* timer)
3171b7579f77SDag-Erling Smørgrav {
3172b7579f77SDag-Erling Smørgrav 	if(!timer)
3173b7579f77SDag-Erling Smørgrav 		return;
3174e2d15004SDag-Erling Smørgrav 	ub_timer_del(timer->ev_timer->ev);
3175b7579f77SDag-Erling Smørgrav 	timer->ev_timer->enabled = 0;
3176b7579f77SDag-Erling Smørgrav }
3177b7579f77SDag-Erling Smørgrav 
3178b7579f77SDag-Erling Smørgrav void
3179b7579f77SDag-Erling Smørgrav comm_timer_set(struct comm_timer* timer, struct timeval* tv)
3180b7579f77SDag-Erling Smørgrav {
3181b7579f77SDag-Erling Smørgrav 	log_assert(tv);
3182b7579f77SDag-Erling Smørgrav 	if(timer->ev_timer->enabled)
3183b7579f77SDag-Erling Smørgrav 		comm_timer_disable(timer);
3184e2d15004SDag-Erling Smørgrav 	if(ub_timer_add(timer->ev_timer->ev, timer->ev_timer->base->eb->base,
3185e2d15004SDag-Erling Smørgrav 		comm_timer_callback, timer, tv) != 0)
3186b7579f77SDag-Erling Smørgrav 		log_err("comm_timer_set: evtimer_add failed.");
3187b7579f77SDag-Erling Smørgrav 	timer->ev_timer->enabled = 1;
3188b7579f77SDag-Erling Smørgrav }
3189b7579f77SDag-Erling Smørgrav 
3190b7579f77SDag-Erling Smørgrav void
3191b7579f77SDag-Erling Smørgrav comm_timer_delete(struct comm_timer* timer)
3192b7579f77SDag-Erling Smørgrav {
3193b7579f77SDag-Erling Smørgrav 	if(!timer)
3194b7579f77SDag-Erling Smørgrav 		return;
3195b7579f77SDag-Erling Smørgrav 	comm_timer_disable(timer);
3196e2d15004SDag-Erling Smørgrav 	/* Free the sub struct timer->ev_timer derived from the super struct timer.
3197e2d15004SDag-Erling Smørgrav 	 * i.e. assert(timer == timer->ev_timer)
3198e2d15004SDag-Erling Smørgrav 	 */
3199e2d15004SDag-Erling Smørgrav 	ub_event_free(timer->ev_timer->ev);
3200b7579f77SDag-Erling Smørgrav 	free(timer->ev_timer);
3201b7579f77SDag-Erling Smørgrav }
3202b7579f77SDag-Erling Smørgrav 
3203b7579f77SDag-Erling Smørgrav void
3204b7579f77SDag-Erling Smørgrav comm_timer_callback(int ATTR_UNUSED(fd), short event, void* arg)
3205b7579f77SDag-Erling Smørgrav {
3206b7579f77SDag-Erling Smørgrav 	struct comm_timer* tm = (struct comm_timer*)arg;
3207e2d15004SDag-Erling Smørgrav 	if(!(event&UB_EV_TIMEOUT))
3208b7579f77SDag-Erling Smørgrav 		return;
3209e2d15004SDag-Erling Smørgrav 	ub_comm_base_now(tm->ev_timer->base);
3210b7579f77SDag-Erling Smørgrav 	tm->ev_timer->enabled = 0;
3211b7579f77SDag-Erling Smørgrav 	fptr_ok(fptr_whitelist_comm_timer(tm->callback));
3212b7579f77SDag-Erling Smørgrav 	(*tm->callback)(tm->cb_arg);
3213b7579f77SDag-Erling Smørgrav }
3214b7579f77SDag-Erling Smørgrav 
3215b7579f77SDag-Erling Smørgrav int
3216b7579f77SDag-Erling Smørgrav comm_timer_is_set(struct comm_timer* timer)
3217b7579f77SDag-Erling Smørgrav {
3218b7579f77SDag-Erling Smørgrav 	return (int)timer->ev_timer->enabled;
3219b7579f77SDag-Erling Smørgrav }
3220b7579f77SDag-Erling Smørgrav 
3221b7579f77SDag-Erling Smørgrav size_t
3222e2d15004SDag-Erling Smørgrav comm_timer_get_mem(struct comm_timer* ATTR_UNUSED(timer))
3223b7579f77SDag-Erling Smørgrav {
3224e2d15004SDag-Erling Smørgrav 	return sizeof(struct internal_timer);
3225b7579f77SDag-Erling Smørgrav }
3226b7579f77SDag-Erling Smørgrav 
3227b7579f77SDag-Erling Smørgrav struct comm_signal*
3228b7579f77SDag-Erling Smørgrav comm_signal_create(struct comm_base* base,
3229b7579f77SDag-Erling Smørgrav         void (*callback)(int, void*), void* cb_arg)
3230b7579f77SDag-Erling Smørgrav {
3231b7579f77SDag-Erling Smørgrav 	struct comm_signal* com = (struct comm_signal*)malloc(
3232b7579f77SDag-Erling Smørgrav 		sizeof(struct comm_signal));
3233b7579f77SDag-Erling Smørgrav 	if(!com) {
3234b7579f77SDag-Erling Smørgrav 		log_err("malloc failed");
3235b7579f77SDag-Erling Smørgrav 		return NULL;
3236b7579f77SDag-Erling Smørgrav 	}
3237b7579f77SDag-Erling Smørgrav 	com->base = base;
3238b7579f77SDag-Erling Smørgrav 	com->callback = callback;
3239b7579f77SDag-Erling Smørgrav 	com->cb_arg = cb_arg;
3240b7579f77SDag-Erling Smørgrav 	com->ev_signal = NULL;
3241b7579f77SDag-Erling Smørgrav 	return com;
3242b7579f77SDag-Erling Smørgrav }
3243b7579f77SDag-Erling Smørgrav 
3244b7579f77SDag-Erling Smørgrav void
3245b7579f77SDag-Erling Smørgrav comm_signal_callback(int sig, short event, void* arg)
3246b7579f77SDag-Erling Smørgrav {
3247b7579f77SDag-Erling Smørgrav 	struct comm_signal* comsig = (struct comm_signal*)arg;
3248e2d15004SDag-Erling Smørgrav 	if(!(event & UB_EV_SIGNAL))
3249b7579f77SDag-Erling Smørgrav 		return;
3250e2d15004SDag-Erling Smørgrav 	ub_comm_base_now(comsig->base);
3251b7579f77SDag-Erling Smørgrav 	fptr_ok(fptr_whitelist_comm_signal(comsig->callback));
3252b7579f77SDag-Erling Smørgrav 	(*comsig->callback)(sig, comsig->cb_arg);
3253b7579f77SDag-Erling Smørgrav }
3254b7579f77SDag-Erling Smørgrav 
3255b7579f77SDag-Erling Smørgrav int
3256b7579f77SDag-Erling Smørgrav comm_signal_bind(struct comm_signal* comsig, int sig)
3257b7579f77SDag-Erling Smørgrav {
3258b7579f77SDag-Erling Smørgrav 	struct internal_signal* entry = (struct internal_signal*)calloc(1,
3259b7579f77SDag-Erling Smørgrav 		sizeof(struct internal_signal));
3260b7579f77SDag-Erling Smørgrav 	if(!entry) {
3261b7579f77SDag-Erling Smørgrav 		log_err("malloc failed");
3262b7579f77SDag-Erling Smørgrav 		return 0;
3263b7579f77SDag-Erling Smørgrav 	}
3264b7579f77SDag-Erling Smørgrav 	log_assert(comsig);
3265b7579f77SDag-Erling Smørgrav 	/* add signal event */
3266e2d15004SDag-Erling Smørgrav 	entry->ev = ub_signal_new(comsig->base->eb->base, sig,
3267e2d15004SDag-Erling Smørgrav 		comm_signal_callback, comsig);
3268e2d15004SDag-Erling Smørgrav 	if(entry->ev == NULL) {
3269e2d15004SDag-Erling Smørgrav 		log_err("Could not create signal event");
3270b7579f77SDag-Erling Smørgrav 		free(entry);
3271b7579f77SDag-Erling Smørgrav 		return 0;
3272b7579f77SDag-Erling Smørgrav 	}
3273e2d15004SDag-Erling Smørgrav 	if(ub_signal_add(entry->ev, NULL) != 0) {
3274b7579f77SDag-Erling Smørgrav 		log_err("Could not add signal handler");
3275e2d15004SDag-Erling Smørgrav 		ub_event_free(entry->ev);
3276b7579f77SDag-Erling Smørgrav 		free(entry);
3277b7579f77SDag-Erling Smørgrav 		return 0;
3278b7579f77SDag-Erling Smørgrav 	}
3279b7579f77SDag-Erling Smørgrav 	/* link into list */
3280b7579f77SDag-Erling Smørgrav 	entry->next = comsig->ev_signal;
3281b7579f77SDag-Erling Smørgrav 	comsig->ev_signal = entry;
3282b7579f77SDag-Erling Smørgrav 	return 1;
3283b7579f77SDag-Erling Smørgrav }
3284b7579f77SDag-Erling Smørgrav 
3285b7579f77SDag-Erling Smørgrav void
3286b7579f77SDag-Erling Smørgrav comm_signal_delete(struct comm_signal* comsig)
3287b7579f77SDag-Erling Smørgrav {
3288b7579f77SDag-Erling Smørgrav 	struct internal_signal* p, *np;
3289b7579f77SDag-Erling Smørgrav 	if(!comsig)
3290b7579f77SDag-Erling Smørgrav 		return;
3291b7579f77SDag-Erling Smørgrav 	p=comsig->ev_signal;
3292b7579f77SDag-Erling Smørgrav 	while(p) {
3293b7579f77SDag-Erling Smørgrav 		np = p->next;
3294e2d15004SDag-Erling Smørgrav 		ub_signal_del(p->ev);
3295e2d15004SDag-Erling Smørgrav 		ub_event_free(p->ev);
3296b7579f77SDag-Erling Smørgrav 		free(p);
3297b7579f77SDag-Erling Smørgrav 		p = np;
3298b7579f77SDag-Erling Smørgrav 	}
3299b7579f77SDag-Erling Smørgrav 	free(comsig);
3300b7579f77SDag-Erling Smørgrav }
3301