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"
464c75e3aaSDag-Erling Smørgrav #include "util/tcp_conn_limit.h"
47b7579f77SDag-Erling Smørgrav #include "util/fptr_wlist.h"
48865f46b2SCy Schubert #include "util/proxy_protocol.h"
498f76bb7dSCy Schubert #include "util/timeval_func.h"
5009a3aaf3SDag-Erling Smørgrav #include "sldns/pkthdr.h"
5109a3aaf3SDag-Erling Smørgrav #include "sldns/sbuffer.h"
520fb34990SDag-Erling Smørgrav #include "sldns/str2wire.h"
53ff825849SDag-Erling Smørgrav #include "dnstap/dnstap.h"
5465b390aaSDag-Erling Smørgrav #include "dnscrypt/dnscrypt.h"
55e86b9096SDag-Erling Smørgrav #include "services/listen_dnsport.h"
56*46d2f618SCy Schubert #include "util/random.h"
575469a995SCy Schubert #ifdef HAVE_SYS_TYPES_H
585469a995SCy Schubert #include <sys/types.h>
595469a995SCy Schubert #endif
605469a995SCy Schubert #ifdef HAVE_SYS_SOCKET_H
615469a995SCy Schubert #include <sys/socket.h>
625469a995SCy Schubert #endif
635469a995SCy Schubert #ifdef HAVE_NETDB_H
645469a995SCy Schubert #include <netdb.h>
655469a995SCy Schubert #endif
66865f46b2SCy Schubert #ifdef HAVE_POLL_H
67865f46b2SCy Schubert #include <poll.h>
68865f46b2SCy Schubert #endif
695469a995SCy Schubert
708ed2b524SDag-Erling Smørgrav #ifdef HAVE_OPENSSL_SSL_H
71b7579f77SDag-Erling Smørgrav #include <openssl/ssl.h>
728ed2b524SDag-Erling Smørgrav #endif
738ed2b524SDag-Erling Smørgrav #ifdef HAVE_OPENSSL_ERR_H
74b7579f77SDag-Erling Smørgrav #include <openssl/err.h>
758ed2b524SDag-Erling Smørgrav #endif
76*46d2f618SCy Schubert
77*46d2f618SCy Schubert #ifdef HAVE_NGTCP2
78*46d2f618SCy Schubert #include <ngtcp2/ngtcp2.h>
79*46d2f618SCy Schubert #include <ngtcp2/ngtcp2_crypto.h>
80*46d2f618SCy Schubert #endif
81*46d2f618SCy Schubert
828f76bb7dSCy Schubert #ifdef HAVE_LINUX_NET_TSTAMP_H
838f76bb7dSCy Schubert #include <linux/net_tstamp.h>
848f76bb7dSCy Schubert #endif
85*46d2f618SCy Schubert
86b7579f77SDag-Erling Smørgrav /* -------- Start of local definitions -------- */
87b7579f77SDag-Erling Smørgrav /** if CMSG_ALIGN is not defined on this platform, a workaround */
88b7579f77SDag-Erling Smørgrav #ifndef CMSG_ALIGN
89f61ef7f6SDag-Erling Smørgrav # ifdef __CMSG_ALIGN
90f61ef7f6SDag-Erling Smørgrav # define CMSG_ALIGN(n) __CMSG_ALIGN(n)
91f61ef7f6SDag-Erling Smørgrav # elif defined(CMSG_DATA_ALIGN)
92b7579f77SDag-Erling Smørgrav # define CMSG_ALIGN _CMSG_DATA_ALIGN
93b7579f77SDag-Erling Smørgrav # else
94b7579f77SDag-Erling Smørgrav # define CMSG_ALIGN(len) (((len)+sizeof(long)-1) & ~(sizeof(long)-1))
95b7579f77SDag-Erling Smørgrav # endif
96b7579f77SDag-Erling Smørgrav #endif
97b7579f77SDag-Erling Smørgrav
98b7579f77SDag-Erling Smørgrav /** if CMSG_LEN is not defined on this platform, a workaround */
99b7579f77SDag-Erling Smørgrav #ifndef CMSG_LEN
100b7579f77SDag-Erling Smørgrav # define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr))+(len))
101b7579f77SDag-Erling Smørgrav #endif
102b7579f77SDag-Erling Smørgrav
103b7579f77SDag-Erling Smørgrav /** if CMSG_SPACE is not defined on this platform, a workaround */
104b7579f77SDag-Erling Smørgrav #ifndef CMSG_SPACE
105b7579f77SDag-Erling Smørgrav # ifdef _CMSG_HDR_ALIGN
106b7579f77SDag-Erling Smørgrav # define CMSG_SPACE(l) (CMSG_ALIGN(l)+_CMSG_HDR_ALIGN(sizeof(struct cmsghdr)))
107b7579f77SDag-Erling Smørgrav # else
108b7579f77SDag-Erling Smørgrav # define CMSG_SPACE(l) (CMSG_ALIGN(l)+CMSG_ALIGN(sizeof(struct cmsghdr)))
109b7579f77SDag-Erling Smørgrav # endif
110b7579f77SDag-Erling Smørgrav #endif
111b7579f77SDag-Erling Smørgrav
1124c75e3aaSDag-Erling Smørgrav /** The TCP writing query timeout in milliseconds */
113b5663de9SDag-Erling Smørgrav #define TCP_QUERY_TIMEOUT 120000
1144c75e3aaSDag-Erling Smørgrav /** The minimum actual TCP timeout to use, regardless of what we advertise,
1154c75e3aaSDag-Erling Smørgrav * in msec */
1164c75e3aaSDag-Erling Smørgrav #define TCP_QUERY_TIMEOUT_MINIMUM 200
117b7579f77SDag-Erling Smørgrav
118b7579f77SDag-Erling Smørgrav #ifndef NONBLOCKING_IS_BROKEN
119b7579f77SDag-Erling Smørgrav /** number of UDP reads to perform per read indication from select */
120b7579f77SDag-Erling Smørgrav #define NUM_UDP_PER_SELECT 100
121b7579f77SDag-Erling Smørgrav #else
122b7579f77SDag-Erling Smørgrav #define NUM_UDP_PER_SELECT 1
123b7579f77SDag-Erling Smørgrav #endif
124b7579f77SDag-Erling Smørgrav
125865f46b2SCy Schubert /** timeout in millisec to wait for write to unblock, packets dropped after.*/
126865f46b2SCy Schubert #define SEND_BLOCKED_WAIT_TIMEOUT 200
1276e71235eSCy Schubert /** max number of times to wait for write to unblock, packets dropped after.*/
1286e71235eSCy Schubert #define SEND_BLOCKED_MAX_RETRY 5
129865f46b2SCy Schubert
1308f76bb7dSCy Schubert /** Let's make timestamping code cleaner and redefine SO_TIMESTAMP* */
1318f76bb7dSCy Schubert #ifndef SO_TIMESTAMP
1328f76bb7dSCy Schubert #define SO_TIMESTAMP 29
1338f76bb7dSCy Schubert #endif
1348f76bb7dSCy Schubert #ifndef SO_TIMESTAMPNS
1358f76bb7dSCy Schubert #define SO_TIMESTAMPNS 35
1368f76bb7dSCy Schubert #endif
1378f76bb7dSCy Schubert #ifndef SO_TIMESTAMPING
1388f76bb7dSCy Schubert #define SO_TIMESTAMPING 37
1398f76bb7dSCy Schubert #endif
140b7579f77SDag-Erling Smørgrav /**
141e2d15004SDag-Erling Smørgrav * The internal event structure for keeping ub_event info for the event.
142b7579f77SDag-Erling Smørgrav * Possibly other structures (list, tree) this is part of.
143b7579f77SDag-Erling Smørgrav */
144b7579f77SDag-Erling Smørgrav struct internal_event {
145b7579f77SDag-Erling Smørgrav /** the comm base */
146b7579f77SDag-Erling Smørgrav struct comm_base* base;
147e2d15004SDag-Erling Smørgrav /** ub_event event type */
148e2d15004SDag-Erling Smørgrav struct ub_event* ev;
149b7579f77SDag-Erling Smørgrav };
150b7579f77SDag-Erling Smørgrav
151b7579f77SDag-Erling Smørgrav /**
152b7579f77SDag-Erling Smørgrav * Internal base structure, so that every thread has its own events.
153b7579f77SDag-Erling Smørgrav */
154b7579f77SDag-Erling Smørgrav struct internal_base {
155e2d15004SDag-Erling Smørgrav /** ub_event event_base type. */
156e2d15004SDag-Erling Smørgrav struct ub_event_base* base;
157b7579f77SDag-Erling Smørgrav /** seconds time pointer points here */
15817d15b25SDag-Erling Smørgrav time_t secs;
159b7579f77SDag-Erling Smørgrav /** timeval with current time */
160b7579f77SDag-Erling Smørgrav struct timeval now;
161b7579f77SDag-Erling Smørgrav /** the event used for slow_accept timeouts */
162e2d15004SDag-Erling Smørgrav struct ub_event* slow_accept;
163b7579f77SDag-Erling Smørgrav /** true if slow_accept is enabled */
164b7579f77SDag-Erling Smørgrav int slow_accept_enabled;
165865f46b2SCy Schubert /** last log time for slow logging of file descriptor errors */
166865f46b2SCy Schubert time_t last_slow_log;
167865f46b2SCy Schubert /** last log time for slow logging of write wait failures */
168865f46b2SCy Schubert time_t last_writewait_log;
169b7579f77SDag-Erling Smørgrav };
170b7579f77SDag-Erling Smørgrav
171b7579f77SDag-Erling Smørgrav /**
172b7579f77SDag-Erling Smørgrav * Internal timer structure, to store timer event in.
173b7579f77SDag-Erling Smørgrav */
174b7579f77SDag-Erling Smørgrav struct internal_timer {
175e2d15004SDag-Erling Smørgrav /** the super struct from which derived */
176e2d15004SDag-Erling Smørgrav struct comm_timer super;
177b7579f77SDag-Erling Smørgrav /** the comm base */
178b7579f77SDag-Erling Smørgrav struct comm_base* base;
179e2d15004SDag-Erling Smørgrav /** ub_event event type */
180e2d15004SDag-Erling Smørgrav struct ub_event* ev;
181b7579f77SDag-Erling Smørgrav /** is timer enabled */
182b7579f77SDag-Erling Smørgrav uint8_t enabled;
183b7579f77SDag-Erling Smørgrav };
184b7579f77SDag-Erling Smørgrav
185b7579f77SDag-Erling Smørgrav /**
186b7579f77SDag-Erling Smørgrav * Internal signal structure, to store signal event in.
187b7579f77SDag-Erling Smørgrav */
188b7579f77SDag-Erling Smørgrav struct internal_signal {
189e2d15004SDag-Erling Smørgrav /** ub_event event type */
190e2d15004SDag-Erling Smørgrav struct ub_event* ev;
191b7579f77SDag-Erling Smørgrav /** next in signal list */
192b7579f77SDag-Erling Smørgrav struct internal_signal* next;
193b7579f77SDag-Erling Smørgrav };
194b7579f77SDag-Erling Smørgrav
195b7579f77SDag-Erling Smørgrav /** create a tcp handler with a parent */
196b7579f77SDag-Erling Smørgrav static struct comm_point* comm_point_create_tcp_handler(
197b7579f77SDag-Erling Smørgrav struct comm_base *base, struct comm_point* parent, size_t bufsize,
198e86b9096SDag-Erling Smørgrav struct sldns_buffer* spoolbuf, comm_point_callback_type* callback,
1995469a995SCy Schubert void* callback_arg, struct unbound_socket* socket);
200b7579f77SDag-Erling Smørgrav
201b7579f77SDag-Erling Smørgrav /* -------- End of local definitions -------- */
202b7579f77SDag-Erling Smørgrav
203b7579f77SDag-Erling Smørgrav struct comm_base*
comm_base_create(int sigs)204b7579f77SDag-Erling Smørgrav comm_base_create(int sigs)
205b7579f77SDag-Erling Smørgrav {
206b7579f77SDag-Erling Smørgrav struct comm_base* b = (struct comm_base*)calloc(1,
207b7579f77SDag-Erling Smørgrav sizeof(struct comm_base));
208e2d15004SDag-Erling Smørgrav const char *evnm="event", *evsys="", *evmethod="";
209e2d15004SDag-Erling Smørgrav
210b7579f77SDag-Erling Smørgrav if(!b)
211b7579f77SDag-Erling Smørgrav return NULL;
212b7579f77SDag-Erling Smørgrav b->eb = (struct internal_base*)calloc(1, sizeof(struct internal_base));
213b7579f77SDag-Erling Smørgrav if(!b->eb) {
214b7579f77SDag-Erling Smørgrav free(b);
215b7579f77SDag-Erling Smørgrav return NULL;
216b7579f77SDag-Erling Smørgrav }
217e2d15004SDag-Erling Smørgrav b->eb->base = ub_default_event_base(sigs, &b->eb->secs, &b->eb->now);
218b7579f77SDag-Erling Smørgrav if(!b->eb->base) {
219b7579f77SDag-Erling Smørgrav free(b->eb);
220b7579f77SDag-Erling Smørgrav free(b);
221b7579f77SDag-Erling Smørgrav return NULL;
222b7579f77SDag-Erling Smørgrav }
223e2d15004SDag-Erling Smørgrav ub_comm_base_now(b);
224e2d15004SDag-Erling Smørgrav ub_get_event_sys(b->eb->base, &evnm, &evsys, &evmethod);
225e86b9096SDag-Erling Smørgrav verbose(VERB_ALGO, "%s %s uses %s method.", evnm, evsys, evmethod);
226b7579f77SDag-Erling Smørgrav return b;
227b7579f77SDag-Erling Smørgrav }
228b7579f77SDag-Erling Smørgrav
22917d15b25SDag-Erling Smørgrav struct comm_base*
comm_base_create_event(struct ub_event_base * base)230e2d15004SDag-Erling Smørgrav comm_base_create_event(struct ub_event_base* base)
23117d15b25SDag-Erling Smørgrav {
23217d15b25SDag-Erling Smørgrav struct comm_base* b = (struct comm_base*)calloc(1,
23317d15b25SDag-Erling Smørgrav sizeof(struct comm_base));
23417d15b25SDag-Erling Smørgrav if(!b)
23517d15b25SDag-Erling Smørgrav return NULL;
23617d15b25SDag-Erling Smørgrav b->eb = (struct internal_base*)calloc(1, sizeof(struct internal_base));
23717d15b25SDag-Erling Smørgrav if(!b->eb) {
23817d15b25SDag-Erling Smørgrav free(b);
23917d15b25SDag-Erling Smørgrav return NULL;
24017d15b25SDag-Erling Smørgrav }
24117d15b25SDag-Erling Smørgrav b->eb->base = base;
242e2d15004SDag-Erling Smørgrav ub_comm_base_now(b);
24317d15b25SDag-Erling Smørgrav return b;
24417d15b25SDag-Erling Smørgrav }
24517d15b25SDag-Erling Smørgrav
246b7579f77SDag-Erling Smørgrav void
comm_base_delete(struct comm_base * b)247b7579f77SDag-Erling Smørgrav comm_base_delete(struct comm_base* b)
248b7579f77SDag-Erling Smørgrav {
249b7579f77SDag-Erling Smørgrav if(!b)
250b7579f77SDag-Erling Smørgrav return;
251b7579f77SDag-Erling Smørgrav if(b->eb->slow_accept_enabled) {
252e2d15004SDag-Erling Smørgrav if(ub_event_del(b->eb->slow_accept) != 0) {
253b7579f77SDag-Erling Smørgrav log_err("could not event_del slow_accept");
254b7579f77SDag-Erling Smørgrav }
255e2d15004SDag-Erling Smørgrav ub_event_free(b->eb->slow_accept);
256b7579f77SDag-Erling Smørgrav }
257e2d15004SDag-Erling Smørgrav ub_event_base_free(b->eb->base);
258b7579f77SDag-Erling Smørgrav b->eb->base = NULL;
259b7579f77SDag-Erling Smørgrav free(b->eb);
260b7579f77SDag-Erling Smørgrav free(b);
261b7579f77SDag-Erling Smørgrav }
262b7579f77SDag-Erling Smørgrav
263b7579f77SDag-Erling Smørgrav void
comm_base_delete_no_base(struct comm_base * b)26417d15b25SDag-Erling Smørgrav comm_base_delete_no_base(struct comm_base* b)
26517d15b25SDag-Erling Smørgrav {
26617d15b25SDag-Erling Smørgrav if(!b)
26717d15b25SDag-Erling Smørgrav return;
26817d15b25SDag-Erling Smørgrav if(b->eb->slow_accept_enabled) {
269e2d15004SDag-Erling Smørgrav if(ub_event_del(b->eb->slow_accept) != 0) {
27017d15b25SDag-Erling Smørgrav log_err("could not event_del slow_accept");
27117d15b25SDag-Erling Smørgrav }
272e2d15004SDag-Erling Smørgrav ub_event_free(b->eb->slow_accept);
27317d15b25SDag-Erling Smørgrav }
27417d15b25SDag-Erling Smørgrav b->eb->base = NULL;
27517d15b25SDag-Erling Smørgrav free(b->eb);
27617d15b25SDag-Erling Smørgrav free(b);
27717d15b25SDag-Erling Smørgrav }
27817d15b25SDag-Erling Smørgrav
27917d15b25SDag-Erling Smørgrav void
comm_base_timept(struct comm_base * b,time_t ** tt,struct timeval ** tv)28017d15b25SDag-Erling Smørgrav comm_base_timept(struct comm_base* b, time_t** tt, struct timeval** tv)
281b7579f77SDag-Erling Smørgrav {
282b7579f77SDag-Erling Smørgrav *tt = &b->eb->secs;
283b7579f77SDag-Erling Smørgrav *tv = &b->eb->now;
284b7579f77SDag-Erling Smørgrav }
285b7579f77SDag-Erling Smørgrav
286b7579f77SDag-Erling Smørgrav void
comm_base_dispatch(struct comm_base * b)287b7579f77SDag-Erling Smørgrav comm_base_dispatch(struct comm_base* b)
288b7579f77SDag-Erling Smørgrav {
289b7579f77SDag-Erling Smørgrav int retval;
290e2d15004SDag-Erling Smørgrav retval = ub_event_base_dispatch(b->eb->base);
291e2d15004SDag-Erling Smørgrav if(retval < 0) {
292b7579f77SDag-Erling Smørgrav fatal_exit("event_dispatch returned error %d, "
293b7579f77SDag-Erling Smørgrav "errno is %s", retval, strerror(errno));
294b7579f77SDag-Erling Smørgrav }
295b7579f77SDag-Erling Smørgrav }
296b7579f77SDag-Erling Smørgrav
comm_base_exit(struct comm_base * b)297b7579f77SDag-Erling Smørgrav void comm_base_exit(struct comm_base* b)
298b7579f77SDag-Erling Smørgrav {
299e2d15004SDag-Erling Smørgrav if(ub_event_base_loopexit(b->eb->base) != 0) {
300b7579f77SDag-Erling Smørgrav log_err("Could not loopexit");
301b7579f77SDag-Erling Smørgrav }
302b7579f77SDag-Erling Smørgrav }
303b7579f77SDag-Erling Smørgrav
comm_base_set_slow_accept_handlers(struct comm_base * b,void (* stop_acc)(void *),void (* start_acc)(void *),void * arg)304b7579f77SDag-Erling Smørgrav void comm_base_set_slow_accept_handlers(struct comm_base* b,
305b7579f77SDag-Erling Smørgrav void (*stop_acc)(void*), void (*start_acc)(void*), void* arg)
306b7579f77SDag-Erling Smørgrav {
307b7579f77SDag-Erling Smørgrav b->stop_accept = stop_acc;
308b7579f77SDag-Erling Smørgrav b->start_accept = start_acc;
309b7579f77SDag-Erling Smørgrav b->cb_arg = arg;
310b7579f77SDag-Erling Smørgrav }
311b7579f77SDag-Erling Smørgrav
comm_base_internal(struct comm_base * b)312e2d15004SDag-Erling Smørgrav struct ub_event_base* comm_base_internal(struct comm_base* b)
313b7579f77SDag-Erling Smørgrav {
314b7579f77SDag-Erling Smørgrav return b->eb->base;
315b7579f77SDag-Erling Smørgrav }
316b7579f77SDag-Erling Smørgrav
317b7579f77SDag-Erling Smørgrav /** see if errno for udp has to be logged or not uses globals */
318b7579f77SDag-Erling Smørgrav static int
udp_send_errno_needs_log(struct sockaddr * addr,socklen_t addrlen)319b7579f77SDag-Erling Smørgrav udp_send_errno_needs_log(struct sockaddr* addr, socklen_t addrlen)
320b7579f77SDag-Erling Smørgrav {
321b7579f77SDag-Erling Smørgrav /* do not log transient errors (unless high verbosity) */
322b7579f77SDag-Erling Smørgrav #if defined(ENETUNREACH) || defined(EHOSTDOWN) || defined(EHOSTUNREACH) || defined(ENETDOWN)
323b7579f77SDag-Erling Smørgrav switch(errno) {
324b7579f77SDag-Erling Smørgrav # ifdef ENETUNREACH
325b7579f77SDag-Erling Smørgrav case ENETUNREACH:
326b7579f77SDag-Erling Smørgrav # endif
327b7579f77SDag-Erling Smørgrav # ifdef EHOSTDOWN
328b7579f77SDag-Erling Smørgrav case EHOSTDOWN:
329b7579f77SDag-Erling Smørgrav # endif
330b7579f77SDag-Erling Smørgrav # ifdef EHOSTUNREACH
331b7579f77SDag-Erling Smørgrav case EHOSTUNREACH:
332b7579f77SDag-Erling Smørgrav # endif
333b7579f77SDag-Erling Smørgrav # ifdef ENETDOWN
334b7579f77SDag-Erling Smørgrav case ENETDOWN:
335b7579f77SDag-Erling Smørgrav # endif
3365469a995SCy Schubert case EPERM:
33724e36522SCy Schubert case EACCES:
338b7579f77SDag-Erling Smørgrav if(verbosity < VERB_ALGO)
339b7579f77SDag-Erling Smørgrav return 0;
34056850988SCy Schubert break;
341b7579f77SDag-Erling Smørgrav default:
342b7579f77SDag-Erling Smørgrav break;
343b7579f77SDag-Erling Smørgrav }
344b7579f77SDag-Erling Smørgrav #endif
34517d15b25SDag-Erling Smørgrav /* permission denied is gotten for every send if the
34617d15b25SDag-Erling Smørgrav * network is disconnected (on some OS), squelch it */
347f61ef7f6SDag-Erling Smørgrav if( ((errno == EPERM)
348f61ef7f6SDag-Erling Smørgrav # ifdef EADDRNOTAVAIL
349f61ef7f6SDag-Erling Smørgrav /* 'Cannot assign requested address' also when disconnected */
350f61ef7f6SDag-Erling Smørgrav || (errno == EADDRNOTAVAIL)
351f61ef7f6SDag-Erling Smørgrav # endif
3525469a995SCy Schubert ) && verbosity < VERB_ALGO)
35317d15b25SDag-Erling Smørgrav return 0;
35457bddd21SDag-Erling Smørgrav # ifdef EADDRINUSE
35557bddd21SDag-Erling Smørgrav /* If SO_REUSEADDR is set, we could try to connect to the same server
35657bddd21SDag-Erling Smørgrav * from the same source port twice. */
35757bddd21SDag-Erling Smørgrav if(errno == EADDRINUSE && verbosity < VERB_DETAIL)
35857bddd21SDag-Erling Smørgrav return 0;
35957bddd21SDag-Erling Smørgrav # endif
360b7579f77SDag-Erling Smørgrav /* squelch errors where people deploy AAAA ::ffff:bla for
361b7579f77SDag-Erling Smørgrav * authority servers, which we try for intranets. */
362b7579f77SDag-Erling Smørgrav if(errno == EINVAL && addr_is_ip4mapped(
363b7579f77SDag-Erling Smørgrav (struct sockaddr_storage*)addr, addrlen) &&
364b7579f77SDag-Erling Smørgrav verbosity < VERB_DETAIL)
365b7579f77SDag-Erling Smørgrav return 0;
366b7579f77SDag-Erling Smørgrav /* SO_BROADCAST sockopt can give access to 255.255.255.255,
367b7579f77SDag-Erling Smørgrav * but a dns cache does not need it. */
368b7579f77SDag-Erling Smørgrav if(errno == EACCES && addr_is_broadcast(
369b7579f77SDag-Erling Smørgrav (struct sockaddr_storage*)addr, addrlen) &&
370b7579f77SDag-Erling Smørgrav verbosity < VERB_DETAIL)
371b7579f77SDag-Erling Smørgrav return 0;
372b7579f77SDag-Erling Smørgrav return 1;
373b7579f77SDag-Erling Smørgrav }
374b7579f77SDag-Erling Smørgrav
tcp_connect_errno_needs_log(struct sockaddr * addr,socklen_t addrlen)375b7579f77SDag-Erling Smørgrav int tcp_connect_errno_needs_log(struct sockaddr* addr, socklen_t addrlen)
376b7579f77SDag-Erling Smørgrav {
377b7579f77SDag-Erling Smørgrav return udp_send_errno_needs_log(addr, addrlen);
378b7579f77SDag-Erling Smørgrav }
379b7579f77SDag-Erling Smørgrav
380b7579f77SDag-Erling Smørgrav /* send a UDP reply */
381b7579f77SDag-Erling Smørgrav int
comm_point_send_udp_msg(struct comm_point * c,sldns_buffer * packet,struct sockaddr * addr,socklen_t addrlen,int is_connected)38217d15b25SDag-Erling Smørgrav comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet,
3837341cb0cSXin LI struct sockaddr* addr, socklen_t addrlen, int is_connected)
384b7579f77SDag-Erling Smørgrav {
385b7579f77SDag-Erling Smørgrav ssize_t sent;
386b7579f77SDag-Erling Smørgrav log_assert(c->fd != -1);
387b7579f77SDag-Erling Smørgrav #ifdef UNBOUND_DEBUG
38817d15b25SDag-Erling Smørgrav if(sldns_buffer_remaining(packet) == 0)
389b7579f77SDag-Erling Smørgrav log_err("error: send empty UDP packet");
390b7579f77SDag-Erling Smørgrav #endif
391b7579f77SDag-Erling Smørgrav log_assert(addr && addrlen > 0);
3927341cb0cSXin LI if(!is_connected) {
39317d15b25SDag-Erling Smørgrav sent = sendto(c->fd, (void*)sldns_buffer_begin(packet),
39417d15b25SDag-Erling Smørgrav sldns_buffer_remaining(packet), 0,
395b7579f77SDag-Erling Smørgrav addr, addrlen);
396369c6923SCy Schubert } else {
397369c6923SCy Schubert sent = send(c->fd, (void*)sldns_buffer_begin(packet),
398369c6923SCy Schubert sldns_buffer_remaining(packet), 0);
399369c6923SCy Schubert }
400b7579f77SDag-Erling Smørgrav if(sent == -1) {
401f61ef7f6SDag-Erling Smørgrav /* try again and block, waiting for IO to complete,
402f61ef7f6SDag-Erling Smørgrav * we want to send the answer, and we will wait for
403f61ef7f6SDag-Erling Smørgrav * the ethernet interface buffer to have space. */
404f61ef7f6SDag-Erling Smørgrav #ifndef USE_WINSOCK
405865f46b2SCy Schubert if(errno == EAGAIN || errno == EINTR ||
406f61ef7f6SDag-Erling Smørgrav # ifdef EWOULDBLOCK
407f61ef7f6SDag-Erling Smørgrav errno == EWOULDBLOCK ||
408f61ef7f6SDag-Erling Smørgrav # endif
409f61ef7f6SDag-Erling Smørgrav errno == ENOBUFS) {
410f61ef7f6SDag-Erling Smørgrav #else
411f61ef7f6SDag-Erling Smørgrav if(WSAGetLastError() == WSAEINPROGRESS ||
412865f46b2SCy Schubert WSAGetLastError() == WSAEINTR ||
413f61ef7f6SDag-Erling Smørgrav WSAGetLastError() == WSAENOBUFS ||
414f61ef7f6SDag-Erling Smørgrav WSAGetLastError() == WSAEWOULDBLOCK) {
415f61ef7f6SDag-Erling Smørgrav #endif
4166e71235eSCy Schubert int retries = 0;
417865f46b2SCy Schubert /* if we set the fd blocking, other threads suddenly
418865f46b2SCy Schubert * have a blocking fd that they operate on */
4196e71235eSCy Schubert while(sent == -1 && retries < SEND_BLOCKED_MAX_RETRY && (
420865f46b2SCy Schubert #ifndef USE_WINSOCK
421865f46b2SCy Schubert errno == EAGAIN || errno == EINTR ||
422865f46b2SCy Schubert # ifdef EWOULDBLOCK
423865f46b2SCy Schubert errno == EWOULDBLOCK ||
424865f46b2SCy Schubert # endif
425865f46b2SCy Schubert errno == ENOBUFS
426865f46b2SCy Schubert #else
427865f46b2SCy Schubert WSAGetLastError() == WSAEINPROGRESS ||
428865f46b2SCy Schubert WSAGetLastError() == WSAEINTR ||
429865f46b2SCy Schubert WSAGetLastError() == WSAENOBUFS ||
430865f46b2SCy Schubert WSAGetLastError() == WSAEWOULDBLOCK
431865f46b2SCy Schubert #endif
432865f46b2SCy Schubert )) {
433865f46b2SCy Schubert #if defined(HAVE_POLL) || defined(USE_WINSOCK)
4346e71235eSCy Schubert int send_nobufs = (
4356e71235eSCy Schubert #ifndef USE_WINSOCK
4366e71235eSCy Schubert errno == ENOBUFS
4376e71235eSCy Schubert #else
4386e71235eSCy Schubert WSAGetLastError() == WSAENOBUFS
4396e71235eSCy Schubert #endif
4406e71235eSCy Schubert );
441865f46b2SCy Schubert struct pollfd p;
442865f46b2SCy Schubert int pret;
443865f46b2SCy Schubert memset(&p, 0, sizeof(p));
444865f46b2SCy Schubert p.fd = c->fd;
445865f46b2SCy Schubert p.events = POLLOUT | POLLERR | POLLHUP;
446865f46b2SCy Schubert # ifndef USE_WINSOCK
447865f46b2SCy Schubert pret = poll(&p, 1, SEND_BLOCKED_WAIT_TIMEOUT);
448865f46b2SCy Schubert # else
449865f46b2SCy Schubert pret = WSAPoll(&p, 1,
450865f46b2SCy Schubert SEND_BLOCKED_WAIT_TIMEOUT);
451865f46b2SCy Schubert # endif
452865f46b2SCy Schubert if(pret == 0) {
453865f46b2SCy Schubert /* timer expired */
454865f46b2SCy Schubert struct comm_base* b = c->ev->base;
455865f46b2SCy Schubert if(b->eb->last_writewait_log+SLOW_LOG_TIME <=
456865f46b2SCy Schubert b->eb->secs) {
457865f46b2SCy Schubert b->eb->last_writewait_log = b->eb->secs;
458865f46b2SCy Schubert verbose(VERB_OPS, "send udp blocked "
459865f46b2SCy Schubert "for long, dropping packet.");
460865f46b2SCy Schubert }
461865f46b2SCy Schubert return 0;
462865f46b2SCy Schubert } else if(pret < 0 &&
463865f46b2SCy Schubert #ifndef USE_WINSOCK
464865f46b2SCy Schubert errno != EAGAIN && errno != EINTR &&
465865f46b2SCy Schubert # ifdef EWOULDBLOCK
466865f46b2SCy Schubert errno != EWOULDBLOCK &&
467865f46b2SCy Schubert # endif
468865f46b2SCy Schubert errno != ENOBUFS
469865f46b2SCy Schubert #else
470865f46b2SCy Schubert WSAGetLastError() != WSAEINPROGRESS &&
471865f46b2SCy Schubert WSAGetLastError() != WSAEINTR &&
472865f46b2SCy Schubert WSAGetLastError() != WSAENOBUFS &&
473865f46b2SCy Schubert WSAGetLastError() != WSAEWOULDBLOCK
474865f46b2SCy Schubert #endif
475865f46b2SCy Schubert ) {
476865f46b2SCy Schubert log_err("poll udp out failed: %s",
477865f46b2SCy Schubert sock_strerror(errno));
478865f46b2SCy Schubert return 0;
4796e71235eSCy Schubert } else if((pret < 0 &&
4806e71235eSCy Schubert #ifndef USE_WINSOCK
4816e71235eSCy Schubert errno == ENOBUFS
4826e71235eSCy Schubert #else
4836e71235eSCy Schubert WSAGetLastError() == WSAENOBUFS
4846e71235eSCy Schubert #endif
4856e71235eSCy Schubert ) || (send_nobufs && retries > 0)) {
4866e71235eSCy Schubert /* ENOBUFS, and poll returned without
4876e71235eSCy Schubert * a timeout. Or the retried send call
4886e71235eSCy Schubert * returned ENOBUFS. It is good to
4896e71235eSCy Schubert * wait a bit for the error to clear. */
4906e71235eSCy Schubert /* The timeout is 20*(2^(retries+1)),
4916e71235eSCy Schubert * it increases exponentially, starting
4926e71235eSCy Schubert * at 40 msec. After 5 tries, 1240 msec
4936e71235eSCy Schubert * have passed in total, when poll
4946e71235eSCy Schubert * returned the error, and 1200 msec
4956e71235eSCy Schubert * when send returned the errors. */
4966e71235eSCy Schubert #ifndef USE_WINSOCK
4976e71235eSCy Schubert pret = poll(NULL, 0, (SEND_BLOCKED_WAIT_TIMEOUT/10)<<(retries+1));
4986e71235eSCy Schubert #else
4996e71235eSCy Schubert pret = WSAPoll(NULL, 0, (SEND_BLOCKED_WAIT_TIMEOUT/10)<<(retries+1));
5006e71235eSCy Schubert #endif
5016e71235eSCy Schubert if(pret < 0 &&
5026e71235eSCy Schubert #ifndef USE_WINSOCK
5036e71235eSCy Schubert errno != EAGAIN && errno != EINTR &&
5046e71235eSCy Schubert # ifdef EWOULDBLOCK
5056e71235eSCy Schubert errno != EWOULDBLOCK &&
5066e71235eSCy Schubert # endif
5076e71235eSCy Schubert errno != ENOBUFS
5086e71235eSCy Schubert #else
5096e71235eSCy Schubert WSAGetLastError() != WSAEINPROGRESS &&
5106e71235eSCy Schubert WSAGetLastError() != WSAEINTR &&
5116e71235eSCy Schubert WSAGetLastError() != WSAENOBUFS &&
5126e71235eSCy Schubert WSAGetLastError() != WSAEWOULDBLOCK
5136e71235eSCy Schubert #endif
5146e71235eSCy Schubert ) {
5156e71235eSCy Schubert log_err("poll udp out timer failed: %s",
5166e71235eSCy Schubert sock_strerror(errno));
5176e71235eSCy Schubert }
518865f46b2SCy Schubert }
519865f46b2SCy Schubert #endif /* defined(HAVE_POLL) || defined(USE_WINSOCK) */
5206e71235eSCy Schubert retries++;
5217341cb0cSXin LI if (!is_connected) {
522f61ef7f6SDag-Erling Smørgrav sent = sendto(c->fd, (void*)sldns_buffer_begin(packet),
523f61ef7f6SDag-Erling Smørgrav sldns_buffer_remaining(packet), 0,
524f61ef7f6SDag-Erling Smørgrav addr, addrlen);
5257341cb0cSXin LI } else {
5267341cb0cSXin LI sent = send(c->fd, (void*)sldns_buffer_begin(packet),
5277341cb0cSXin LI sldns_buffer_remaining(packet), 0);
5287341cb0cSXin LI }
529865f46b2SCy Schubert }
530f61ef7f6SDag-Erling Smørgrav }
531f61ef7f6SDag-Erling Smørgrav }
532f61ef7f6SDag-Erling Smørgrav if(sent == -1) {
533b7579f77SDag-Erling Smørgrav if(!udp_send_errno_needs_log(addr, addrlen))
534b7579f77SDag-Erling Smørgrav return 0;
5357341cb0cSXin LI if (!is_connected) {
536c0caa2e2SCy Schubert verbose(VERB_OPS, "sendto failed: %s", sock_strerror(errno));
5377341cb0cSXin LI } else {
5387341cb0cSXin LI verbose(VERB_OPS, "send failed: %s", sock_strerror(errno));
5397341cb0cSXin LI }
540f44e67d1SCy Schubert if(addr)
541b7579f77SDag-Erling Smørgrav log_addr(VERB_OPS, "remote address is",
542b7579f77SDag-Erling Smørgrav (struct sockaddr_storage*)addr, addrlen);
543b7579f77SDag-Erling Smørgrav return 0;
54417d15b25SDag-Erling Smørgrav } else if((size_t)sent != sldns_buffer_remaining(packet)) {
545b7579f77SDag-Erling Smørgrav log_err("sent %d in place of %d bytes",
54617d15b25SDag-Erling Smørgrav (int)sent, (int)sldns_buffer_remaining(packet));
547b7579f77SDag-Erling Smørgrav return 0;
548b7579f77SDag-Erling Smørgrav }
549b7579f77SDag-Erling Smørgrav return 1;
550b7579f77SDag-Erling Smørgrav }
551b7579f77SDag-Erling Smørgrav
552b7579f77SDag-Erling Smørgrav #if defined(AF_INET6) && defined(IPV6_PKTINFO) && (defined(HAVE_RECVMSG) || defined(HAVE_SENDMSG))
553b7579f77SDag-Erling Smørgrav /** print debug ancillary info */
554b7579f77SDag-Erling Smørgrav static void p_ancil(const char* str, struct comm_reply* r)
555b7579f77SDag-Erling Smørgrav {
556b7579f77SDag-Erling Smørgrav if(r->srctype != 4 && r->srctype != 6) {
557b7579f77SDag-Erling Smørgrav log_info("%s: unknown srctype %d", str, r->srctype);
558b7579f77SDag-Erling Smørgrav return;
559b7579f77SDag-Erling Smørgrav }
5605469a995SCy Schubert
561b7579f77SDag-Erling Smørgrav if(r->srctype == 6) {
5625469a995SCy Schubert #ifdef IPV6_PKTINFO
563b7579f77SDag-Erling Smørgrav char buf[1024];
564b7579f77SDag-Erling Smørgrav if(inet_ntop(AF_INET6, &r->pktinfo.v6info.ipi6_addr,
565b7579f77SDag-Erling Smørgrav buf, (socklen_t)sizeof(buf)) == 0) {
56617d15b25SDag-Erling Smørgrav (void)strlcpy(buf, "(inet_ntop error)", sizeof(buf));
567b7579f77SDag-Erling Smørgrav }
568b7579f77SDag-Erling Smørgrav buf[sizeof(buf)-1]=0;
569b7579f77SDag-Erling Smørgrav log_info("%s: %s %d", str, buf, r->pktinfo.v6info.ipi6_ifindex);
5705469a995SCy Schubert #endif
571b7579f77SDag-Erling Smørgrav } else if(r->srctype == 4) {
572b7579f77SDag-Erling Smørgrav #ifdef IP_PKTINFO
573b7579f77SDag-Erling Smørgrav char buf1[1024], buf2[1024];
574b7579f77SDag-Erling Smørgrav if(inet_ntop(AF_INET, &r->pktinfo.v4info.ipi_addr,
575b7579f77SDag-Erling Smørgrav buf1, (socklen_t)sizeof(buf1)) == 0) {
57617d15b25SDag-Erling Smørgrav (void)strlcpy(buf1, "(inet_ntop error)", sizeof(buf1));
577b7579f77SDag-Erling Smørgrav }
578b7579f77SDag-Erling Smørgrav buf1[sizeof(buf1)-1]=0;
579b7579f77SDag-Erling Smørgrav #ifdef HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST
580b7579f77SDag-Erling Smørgrav if(inet_ntop(AF_INET, &r->pktinfo.v4info.ipi_spec_dst,
581b7579f77SDag-Erling Smørgrav buf2, (socklen_t)sizeof(buf2)) == 0) {
58217d15b25SDag-Erling Smørgrav (void)strlcpy(buf2, "(inet_ntop error)", sizeof(buf2));
583b7579f77SDag-Erling Smørgrav }
584b7579f77SDag-Erling Smørgrav buf2[sizeof(buf2)-1]=0;
585b7579f77SDag-Erling Smørgrav #else
586b7579f77SDag-Erling Smørgrav buf2[0]=0;
587b7579f77SDag-Erling Smørgrav #endif
588b7579f77SDag-Erling Smørgrav log_info("%s: %d %s %s", str, r->pktinfo.v4info.ipi_ifindex,
589b7579f77SDag-Erling Smørgrav buf1, buf2);
590b7579f77SDag-Erling Smørgrav #elif defined(IP_RECVDSTADDR)
591b7579f77SDag-Erling Smørgrav char buf1[1024];
592b7579f77SDag-Erling Smørgrav if(inet_ntop(AF_INET, &r->pktinfo.v4addr,
593b7579f77SDag-Erling Smørgrav buf1, (socklen_t)sizeof(buf1)) == 0) {
59417d15b25SDag-Erling Smørgrav (void)strlcpy(buf1, "(inet_ntop error)", sizeof(buf1));
595b7579f77SDag-Erling Smørgrav }
596b7579f77SDag-Erling Smørgrav buf1[sizeof(buf1)-1]=0;
597b7579f77SDag-Erling Smørgrav log_info("%s: %s", str, buf1);
598b7579f77SDag-Erling Smørgrav #endif /* IP_PKTINFO or PI_RECVDSTDADDR */
599b7579f77SDag-Erling Smørgrav }
600b7579f77SDag-Erling Smørgrav }
601b7579f77SDag-Erling Smørgrav #endif /* AF_INET6 && IPV6_PKTINFO && HAVE_RECVMSG||HAVE_SENDMSG */
602b7579f77SDag-Erling Smørgrav
603b7579f77SDag-Erling Smørgrav /** send a UDP reply over specified interface*/
604b7579f77SDag-Erling Smørgrav static int
60517d15b25SDag-Erling Smørgrav comm_point_send_udp_msg_if(struct comm_point *c, sldns_buffer* packet,
606b7579f77SDag-Erling Smørgrav struct sockaddr* addr, socklen_t addrlen, struct comm_reply* r)
607b7579f77SDag-Erling Smørgrav {
608b7579f77SDag-Erling Smørgrav #if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_SENDMSG)
609b7579f77SDag-Erling Smørgrav ssize_t sent;
610b7579f77SDag-Erling Smørgrav struct msghdr msg;
611b7579f77SDag-Erling Smørgrav struct iovec iov[1];
61225039b37SCy Schubert union {
61325039b37SCy Schubert struct cmsghdr hdr;
61425039b37SCy Schubert char buf[256];
61525039b37SCy Schubert } control;
616b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S
617b7579f77SDag-Erling Smørgrav struct cmsghdr *cmsg;
618b7579f77SDag-Erling Smørgrav #endif /* S_SPLINT_S */
619b7579f77SDag-Erling Smørgrav
620b7579f77SDag-Erling Smørgrav log_assert(c->fd != -1);
621b7579f77SDag-Erling Smørgrav #ifdef UNBOUND_DEBUG
62217d15b25SDag-Erling Smørgrav if(sldns_buffer_remaining(packet) == 0)
623b7579f77SDag-Erling Smørgrav log_err("error: send empty UDP packet");
624b7579f77SDag-Erling Smørgrav #endif
625b7579f77SDag-Erling Smørgrav log_assert(addr && addrlen > 0);
626b7579f77SDag-Erling Smørgrav
627b7579f77SDag-Erling Smørgrav msg.msg_name = addr;
628b7579f77SDag-Erling Smørgrav msg.msg_namelen = addrlen;
62917d15b25SDag-Erling Smørgrav iov[0].iov_base = sldns_buffer_begin(packet);
63017d15b25SDag-Erling Smørgrav iov[0].iov_len = sldns_buffer_remaining(packet);
631b7579f77SDag-Erling Smørgrav msg.msg_iov = iov;
632b7579f77SDag-Erling Smørgrav msg.msg_iovlen = 1;
63325039b37SCy Schubert msg.msg_control = control.buf;
634b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S
63525039b37SCy Schubert msg.msg_controllen = sizeof(control.buf);
636b7579f77SDag-Erling Smørgrav #endif /* S_SPLINT_S */
637b7579f77SDag-Erling Smørgrav msg.msg_flags = 0;
638b7579f77SDag-Erling Smørgrav
639b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S
640b7579f77SDag-Erling Smørgrav cmsg = CMSG_FIRSTHDR(&msg);
641b7579f77SDag-Erling Smørgrav if(r->srctype == 4) {
642b7579f77SDag-Erling Smørgrav #ifdef IP_PKTINFO
64309a3aaf3SDag-Erling Smørgrav void* cmsg_data;
644b7579f77SDag-Erling Smørgrav msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
64525039b37SCy Schubert log_assert(msg.msg_controllen <= sizeof(control.buf));
646b7579f77SDag-Erling Smørgrav cmsg->cmsg_level = IPPROTO_IP;
647b7579f77SDag-Erling Smørgrav cmsg->cmsg_type = IP_PKTINFO;
648b7579f77SDag-Erling Smørgrav memmove(CMSG_DATA(cmsg), &r->pktinfo.v4info,
649b7579f77SDag-Erling Smørgrav sizeof(struct in_pktinfo));
65009a3aaf3SDag-Erling Smørgrav /* unset the ifindex to not bypass the routing tables */
65109a3aaf3SDag-Erling Smørgrav cmsg_data = CMSG_DATA(cmsg);
65209a3aaf3SDag-Erling Smørgrav ((struct in_pktinfo *) cmsg_data)->ipi_ifindex = 0;
653b7579f77SDag-Erling Smørgrav cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
6548f76bb7dSCy Schubert /* zero the padding bytes inserted by the CMSG_LEN */
6558f76bb7dSCy Schubert if(sizeof(struct in_pktinfo) < cmsg->cmsg_len)
6568f76bb7dSCy Schubert memset(((uint8_t*)(CMSG_DATA(cmsg))) +
6578f76bb7dSCy Schubert sizeof(struct in_pktinfo), 0, cmsg->cmsg_len
6588f76bb7dSCy Schubert - sizeof(struct in_pktinfo));
659b7579f77SDag-Erling Smørgrav #elif defined(IP_SENDSRCADDR)
660b7579f77SDag-Erling Smørgrav msg.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
66125039b37SCy Schubert log_assert(msg.msg_controllen <= sizeof(control.buf));
662b7579f77SDag-Erling Smørgrav cmsg->cmsg_level = IPPROTO_IP;
663b7579f77SDag-Erling Smørgrav cmsg->cmsg_type = IP_SENDSRCADDR;
664b7579f77SDag-Erling Smørgrav memmove(CMSG_DATA(cmsg), &r->pktinfo.v4addr,
665b7579f77SDag-Erling Smørgrav sizeof(struct in_addr));
666b7579f77SDag-Erling Smørgrav cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
6678f76bb7dSCy Schubert /* zero the padding bytes inserted by the CMSG_LEN */
6688f76bb7dSCy Schubert if(sizeof(struct in_addr) < cmsg->cmsg_len)
6698f76bb7dSCy Schubert memset(((uint8_t*)(CMSG_DATA(cmsg))) +
6708f76bb7dSCy Schubert sizeof(struct in_addr), 0, cmsg->cmsg_len
6718f76bb7dSCy Schubert - sizeof(struct in_addr));
672b7579f77SDag-Erling Smørgrav #else
673b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "no IP_PKTINFO or IP_SENDSRCADDR");
674b7579f77SDag-Erling Smørgrav msg.msg_control = NULL;
675b7579f77SDag-Erling Smørgrav #endif /* IP_PKTINFO or IP_SENDSRCADDR */
676b7579f77SDag-Erling Smørgrav } else if(r->srctype == 6) {
67709a3aaf3SDag-Erling Smørgrav void* cmsg_data;
678b7579f77SDag-Erling Smørgrav msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
67925039b37SCy Schubert log_assert(msg.msg_controllen <= sizeof(control.buf));
680b7579f77SDag-Erling Smørgrav cmsg->cmsg_level = IPPROTO_IPV6;
681b7579f77SDag-Erling Smørgrav cmsg->cmsg_type = IPV6_PKTINFO;
682b7579f77SDag-Erling Smørgrav memmove(CMSG_DATA(cmsg), &r->pktinfo.v6info,
683b7579f77SDag-Erling Smørgrav sizeof(struct in6_pktinfo));
68409a3aaf3SDag-Erling Smørgrav /* unset the ifindex to not bypass the routing tables */
68509a3aaf3SDag-Erling Smørgrav cmsg_data = CMSG_DATA(cmsg);
68609a3aaf3SDag-Erling Smørgrav ((struct in6_pktinfo *) cmsg_data)->ipi6_ifindex = 0;
687b7579f77SDag-Erling Smørgrav cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
6888f76bb7dSCy Schubert /* zero the padding bytes inserted by the CMSG_LEN */
6898f76bb7dSCy Schubert if(sizeof(struct in6_pktinfo) < cmsg->cmsg_len)
6908f76bb7dSCy Schubert memset(((uint8_t*)(CMSG_DATA(cmsg))) +
6918f76bb7dSCy Schubert sizeof(struct in6_pktinfo), 0, cmsg->cmsg_len
6928f76bb7dSCy Schubert - sizeof(struct in6_pktinfo));
693b7579f77SDag-Erling Smørgrav } else {
694b7579f77SDag-Erling Smørgrav /* try to pass all 0 to use default route */
695b7579f77SDag-Erling Smørgrav msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
69625039b37SCy Schubert log_assert(msg.msg_controllen <= sizeof(control.buf));
697b7579f77SDag-Erling Smørgrav cmsg->cmsg_level = IPPROTO_IPV6;
698b7579f77SDag-Erling Smørgrav cmsg->cmsg_type = IPV6_PKTINFO;
699b7579f77SDag-Erling Smørgrav memset(CMSG_DATA(cmsg), 0, sizeof(struct in6_pktinfo));
700b7579f77SDag-Erling Smørgrav cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
7018f76bb7dSCy Schubert /* zero the padding bytes inserted by the CMSG_LEN */
7028f76bb7dSCy Schubert if(sizeof(struct in6_pktinfo) < cmsg->cmsg_len)
7038f76bb7dSCy Schubert memset(((uint8_t*)(CMSG_DATA(cmsg))) +
7048f76bb7dSCy Schubert sizeof(struct in6_pktinfo), 0, cmsg->cmsg_len
7058f76bb7dSCy Schubert - sizeof(struct in6_pktinfo));
706b7579f77SDag-Erling Smørgrav }
707b7579f77SDag-Erling Smørgrav #endif /* S_SPLINT_S */
7088f76bb7dSCy Schubert if(verbosity >= VERB_ALGO && r->srctype != 0)
709b7579f77SDag-Erling Smørgrav p_ancil("send_udp over interface", r);
710b7579f77SDag-Erling Smørgrav sent = sendmsg(c->fd, &msg, 0);
711b7579f77SDag-Erling Smørgrav if(sent == -1) {
712f61ef7f6SDag-Erling Smørgrav /* try again and block, waiting for IO to complete,
713f61ef7f6SDag-Erling Smørgrav * we want to send the answer, and we will wait for
714f61ef7f6SDag-Erling Smørgrav * the ethernet interface buffer to have space. */
715f61ef7f6SDag-Erling Smørgrav #ifndef USE_WINSOCK
716865f46b2SCy Schubert if(errno == EAGAIN || errno == EINTR ||
717f61ef7f6SDag-Erling Smørgrav # ifdef EWOULDBLOCK
718f61ef7f6SDag-Erling Smørgrav errno == EWOULDBLOCK ||
719f61ef7f6SDag-Erling Smørgrav # endif
720f61ef7f6SDag-Erling Smørgrav errno == ENOBUFS) {
721f61ef7f6SDag-Erling Smørgrav #else
722f61ef7f6SDag-Erling Smørgrav if(WSAGetLastError() == WSAEINPROGRESS ||
723865f46b2SCy Schubert WSAGetLastError() == WSAEINTR ||
724f61ef7f6SDag-Erling Smørgrav WSAGetLastError() == WSAENOBUFS ||
725f61ef7f6SDag-Erling Smørgrav WSAGetLastError() == WSAEWOULDBLOCK) {
726f61ef7f6SDag-Erling Smørgrav #endif
7276e71235eSCy Schubert int retries = 0;
7286e71235eSCy Schubert while(sent == -1 && retries < SEND_BLOCKED_MAX_RETRY && (
729865f46b2SCy Schubert #ifndef USE_WINSOCK
730865f46b2SCy Schubert errno == EAGAIN || errno == EINTR ||
731865f46b2SCy Schubert # ifdef EWOULDBLOCK
732865f46b2SCy Schubert errno == EWOULDBLOCK ||
733865f46b2SCy Schubert # endif
734865f46b2SCy Schubert errno == ENOBUFS
735865f46b2SCy Schubert #else
736865f46b2SCy Schubert WSAGetLastError() == WSAEINPROGRESS ||
737865f46b2SCy Schubert WSAGetLastError() == WSAEINTR ||
738865f46b2SCy Schubert WSAGetLastError() == WSAENOBUFS ||
739865f46b2SCy Schubert WSAGetLastError() == WSAEWOULDBLOCK
740865f46b2SCy Schubert #endif
741865f46b2SCy Schubert )) {
742865f46b2SCy Schubert #if defined(HAVE_POLL) || defined(USE_WINSOCK)
7436e71235eSCy Schubert int send_nobufs = (
7446e71235eSCy Schubert #ifndef USE_WINSOCK
7456e71235eSCy Schubert errno == ENOBUFS
7466e71235eSCy Schubert #else
7476e71235eSCy Schubert WSAGetLastError() == WSAENOBUFS
7486e71235eSCy Schubert #endif
7496e71235eSCy Schubert );
750865f46b2SCy Schubert struct pollfd p;
751865f46b2SCy Schubert int pret;
752865f46b2SCy Schubert memset(&p, 0, sizeof(p));
753865f46b2SCy Schubert p.fd = c->fd;
754865f46b2SCy Schubert p.events = POLLOUT | POLLERR | POLLHUP;
755865f46b2SCy Schubert # ifndef USE_WINSOCK
756865f46b2SCy Schubert pret = poll(&p, 1, SEND_BLOCKED_WAIT_TIMEOUT);
757865f46b2SCy Schubert # else
758865f46b2SCy Schubert pret = WSAPoll(&p, 1,
759865f46b2SCy Schubert SEND_BLOCKED_WAIT_TIMEOUT);
760865f46b2SCy Schubert # endif
761865f46b2SCy Schubert if(pret == 0) {
762865f46b2SCy Schubert /* timer expired */
763865f46b2SCy Schubert struct comm_base* b = c->ev->base;
764865f46b2SCy Schubert if(b->eb->last_writewait_log+SLOW_LOG_TIME <=
765865f46b2SCy Schubert b->eb->secs) {
766865f46b2SCy Schubert b->eb->last_writewait_log = b->eb->secs;
767865f46b2SCy Schubert verbose(VERB_OPS, "send udp blocked "
768865f46b2SCy Schubert "for long, dropping packet.");
769865f46b2SCy Schubert }
770865f46b2SCy Schubert return 0;
771865f46b2SCy Schubert } else if(pret < 0 &&
772865f46b2SCy Schubert #ifndef USE_WINSOCK
773865f46b2SCy Schubert errno != EAGAIN && errno != EINTR &&
774865f46b2SCy Schubert # ifdef EWOULDBLOCK
775865f46b2SCy Schubert errno != EWOULDBLOCK &&
776865f46b2SCy Schubert # endif
777865f46b2SCy Schubert errno != ENOBUFS
778865f46b2SCy Schubert #else
779865f46b2SCy Schubert WSAGetLastError() != WSAEINPROGRESS &&
780865f46b2SCy Schubert WSAGetLastError() != WSAEINTR &&
781865f46b2SCy Schubert WSAGetLastError() != WSAENOBUFS &&
782865f46b2SCy Schubert WSAGetLastError() != WSAEWOULDBLOCK
783865f46b2SCy Schubert #endif
784865f46b2SCy Schubert ) {
785865f46b2SCy Schubert log_err("poll udp out failed: %s",
786865f46b2SCy Schubert sock_strerror(errno));
787865f46b2SCy Schubert return 0;
7886e71235eSCy Schubert } else if((pret < 0 &&
7896e71235eSCy Schubert #ifndef USE_WINSOCK
7906e71235eSCy Schubert errno == ENOBUFS
7916e71235eSCy Schubert #else
7926e71235eSCy Schubert WSAGetLastError() == WSAENOBUFS
7936e71235eSCy Schubert #endif
7946e71235eSCy Schubert ) || (send_nobufs && retries > 0)) {
7956e71235eSCy Schubert /* ENOBUFS, and poll returned without
7966e71235eSCy Schubert * a timeout. Or the retried send call
7976e71235eSCy Schubert * returned ENOBUFS. It is good to
7986e71235eSCy Schubert * wait a bit for the error to clear. */
7996e71235eSCy Schubert /* The timeout is 20*(2^(retries+1)),
8006e71235eSCy Schubert * it increases exponentially, starting
8016e71235eSCy Schubert * at 40 msec. After 5 tries, 1240 msec
8026e71235eSCy Schubert * have passed in total, when poll
8036e71235eSCy Schubert * returned the error, and 1200 msec
8046e71235eSCy Schubert * when send returned the errors. */
8056e71235eSCy Schubert #ifndef USE_WINSOCK
8066e71235eSCy Schubert pret = poll(NULL, 0, (SEND_BLOCKED_WAIT_TIMEOUT/10)<<(retries+1));
8076e71235eSCy Schubert #else
8086e71235eSCy Schubert pret = WSAPoll(NULL, 0, (SEND_BLOCKED_WAIT_TIMEOUT/10)<<(retries+1));
8096e71235eSCy Schubert #endif
8106e71235eSCy Schubert if(pret < 0 &&
8116e71235eSCy Schubert #ifndef USE_WINSOCK
8126e71235eSCy Schubert errno != EAGAIN && errno != EINTR &&
8136e71235eSCy Schubert # ifdef EWOULDBLOCK
8146e71235eSCy Schubert errno != EWOULDBLOCK &&
8156e71235eSCy Schubert # endif
8166e71235eSCy Schubert errno != ENOBUFS
8176e71235eSCy Schubert #else
8186e71235eSCy Schubert WSAGetLastError() != WSAEINPROGRESS &&
8196e71235eSCy Schubert WSAGetLastError() != WSAEINTR &&
8206e71235eSCy Schubert WSAGetLastError() != WSAENOBUFS &&
8216e71235eSCy Schubert WSAGetLastError() != WSAEWOULDBLOCK
8226e71235eSCy Schubert #endif
8236e71235eSCy Schubert ) {
8246e71235eSCy Schubert log_err("poll udp out timer failed: %s",
8256e71235eSCy Schubert sock_strerror(errno));
8266e71235eSCy Schubert }
827865f46b2SCy Schubert }
828865f46b2SCy Schubert #endif /* defined(HAVE_POLL) || defined(USE_WINSOCK) */
8296e71235eSCy Schubert retries++;
830f61ef7f6SDag-Erling Smørgrav sent = sendmsg(c->fd, &msg, 0);
831865f46b2SCy Schubert }
832f61ef7f6SDag-Erling Smørgrav }
833f61ef7f6SDag-Erling Smørgrav }
834f61ef7f6SDag-Erling Smørgrav if(sent == -1) {
835b7579f77SDag-Erling Smørgrav if(!udp_send_errno_needs_log(addr, addrlen))
836b7579f77SDag-Erling Smørgrav return 0;
837b7579f77SDag-Erling Smørgrav verbose(VERB_OPS, "sendmsg failed: %s", strerror(errno));
838b7579f77SDag-Erling Smørgrav log_addr(VERB_OPS, "remote address is",
839b7579f77SDag-Erling Smørgrav (struct sockaddr_storage*)addr, addrlen);
840f61ef7f6SDag-Erling Smørgrav #ifdef __NetBSD__
841f61ef7f6SDag-Erling Smørgrav /* netbsd 7 has IP_PKTINFO for recv but not send */
842f61ef7f6SDag-Erling Smørgrav if(errno == EINVAL && r->srctype == 4)
843f61ef7f6SDag-Erling Smørgrav log_err("sendmsg: No support for sendmsg(IP_PKTINFO). "
844f61ef7f6SDag-Erling Smørgrav "Please disable interface-automatic");
845f61ef7f6SDag-Erling Smørgrav #endif
846b7579f77SDag-Erling Smørgrav return 0;
84717d15b25SDag-Erling Smørgrav } else if((size_t)sent != sldns_buffer_remaining(packet)) {
848b7579f77SDag-Erling Smørgrav log_err("sent %d in place of %d bytes",
84917d15b25SDag-Erling Smørgrav (int)sent, (int)sldns_buffer_remaining(packet));
850b7579f77SDag-Erling Smørgrav return 0;
851b7579f77SDag-Erling Smørgrav }
852b7579f77SDag-Erling Smørgrav return 1;
853b7579f77SDag-Erling Smørgrav #else
854b7579f77SDag-Erling Smørgrav (void)c;
855b7579f77SDag-Erling Smørgrav (void)packet;
856b7579f77SDag-Erling Smørgrav (void)addr;
857b7579f77SDag-Erling Smørgrav (void)addrlen;
858b7579f77SDag-Erling Smørgrav (void)r;
859b7579f77SDag-Erling Smørgrav log_err("sendmsg: IPV6_PKTINFO not supported");
860b7579f77SDag-Erling Smørgrav return 0;
861b7579f77SDag-Erling Smørgrav #endif /* AF_INET6 && IPV6_PKTINFO && HAVE_SENDMSG */
862b7579f77SDag-Erling Smørgrav }
863b7579f77SDag-Erling Smørgrav
864369c6923SCy Schubert /** return true is UDP receive error needs to be logged */
865369c6923SCy Schubert static int udp_recv_needs_log(int err)
866369c6923SCy Schubert {
867369c6923SCy Schubert switch(err) {
868f44e67d1SCy Schubert case EACCES: /* some hosts send ICMP 'Permission Denied' */
869f44e67d1SCy Schubert #ifndef USE_WINSOCK
870369c6923SCy Schubert case ECONNREFUSED:
871369c6923SCy Schubert # ifdef ENETUNREACH
872369c6923SCy Schubert case ENETUNREACH:
873369c6923SCy Schubert # endif
874369c6923SCy Schubert # ifdef EHOSTDOWN
875369c6923SCy Schubert case EHOSTDOWN:
876369c6923SCy Schubert # endif
877369c6923SCy Schubert # ifdef EHOSTUNREACH
878369c6923SCy Schubert case EHOSTUNREACH:
879369c6923SCy Schubert # endif
880369c6923SCy Schubert # ifdef ENETDOWN
881369c6923SCy Schubert case ENETDOWN:
882369c6923SCy Schubert # endif
883f44e67d1SCy Schubert #else /* USE_WINSOCK */
884f44e67d1SCy Schubert case WSAECONNREFUSED:
885f44e67d1SCy Schubert case WSAENETUNREACH:
886f44e67d1SCy Schubert case WSAEHOSTDOWN:
887f44e67d1SCy Schubert case WSAEHOSTUNREACH:
888f44e67d1SCy Schubert case WSAENETDOWN:
889f44e67d1SCy Schubert #endif
890369c6923SCy Schubert if(verbosity >= VERB_ALGO)
891369c6923SCy Schubert return 1;
892369c6923SCy Schubert return 0;
893369c6923SCy Schubert default:
894369c6923SCy Schubert break;
895369c6923SCy Schubert }
896369c6923SCy Schubert return 1;
897369c6923SCy Schubert }
898369c6923SCy Schubert
899865f46b2SCy Schubert /** Parses the PROXYv2 header from buf and updates the comm_reply struct.
900865f46b2SCy Schubert * Returns 1 on success, 0 on failure. */
901865f46b2SCy Schubert static int consume_pp2_header(struct sldns_buffer* buf, struct comm_reply* rep,
902865f46b2SCy Schubert int stream) {
903865f46b2SCy Schubert size_t size;
904103ba509SCy Schubert struct pp2_header *header;
905103ba509SCy Schubert int err = pp2_read_header(sldns_buffer_begin(buf),
906103ba509SCy Schubert sldns_buffer_remaining(buf));
907103ba509SCy Schubert if(err) return 0;
908103ba509SCy Schubert header = (struct pp2_header*)sldns_buffer_begin(buf);
909865f46b2SCy Schubert size = PP2_HEADER_SIZE + ntohs(header->len);
910865f46b2SCy Schubert if((header->ver_cmd & 0xF) == PP2_CMD_LOCAL) {
911865f46b2SCy Schubert /* A connection from the proxy itself.
912865f46b2SCy Schubert * No need to do anything with addresses. */
913865f46b2SCy Schubert goto done;
914865f46b2SCy Schubert }
915103ba509SCy Schubert if(header->fam_prot == PP2_UNSPEC_UNSPEC) {
916865f46b2SCy Schubert /* Unspecified family and protocol. This could be used for
917865f46b2SCy Schubert * health checks by proxies.
918865f46b2SCy Schubert * No need to do anything with addresses. */
919865f46b2SCy Schubert goto done;
920865f46b2SCy Schubert }
921865f46b2SCy Schubert /* Read the proxied address */
922865f46b2SCy Schubert switch(header->fam_prot) {
923103ba509SCy Schubert case PP2_INET_STREAM:
924103ba509SCy Schubert case PP2_INET_DGRAM:
925865f46b2SCy Schubert {
926865f46b2SCy Schubert struct sockaddr_in* addr =
927865f46b2SCy Schubert (struct sockaddr_in*)&rep->client_addr;
928865f46b2SCy Schubert addr->sin_family = AF_INET;
929865f46b2SCy Schubert addr->sin_addr.s_addr = header->addr.addr4.src_addr;
930865f46b2SCy Schubert addr->sin_port = header->addr.addr4.src_port;
931865f46b2SCy Schubert rep->client_addrlen = (socklen_t)sizeof(struct sockaddr_in);
932865f46b2SCy Schubert }
933865f46b2SCy Schubert /* Ignore the destination address; it should be us. */
934865f46b2SCy Schubert break;
935103ba509SCy Schubert case PP2_INET6_STREAM:
936103ba509SCy Schubert case PP2_INET6_DGRAM:
937865f46b2SCy Schubert {
938865f46b2SCy Schubert struct sockaddr_in6* addr =
939865f46b2SCy Schubert (struct sockaddr_in6*)&rep->client_addr;
940865f46b2SCy Schubert memset(addr, 0, sizeof(*addr));
941865f46b2SCy Schubert addr->sin6_family = AF_INET6;
942865f46b2SCy Schubert memcpy(&addr->sin6_addr,
943865f46b2SCy Schubert header->addr.addr6.src_addr, 16);
944865f46b2SCy Schubert addr->sin6_port = header->addr.addr6.src_port;
945865f46b2SCy Schubert rep->client_addrlen = (socklen_t)sizeof(struct sockaddr_in6);
946865f46b2SCy Schubert }
947865f46b2SCy Schubert /* Ignore the destination address; it should be us. */
948865f46b2SCy Schubert break;
949103ba509SCy Schubert default:
950103ba509SCy Schubert log_err("proxy_protocol: unsupported family and "
951103ba509SCy Schubert "protocol 0x%x", (int)header->fam_prot);
952103ba509SCy Schubert return 0;
953865f46b2SCy Schubert }
954865f46b2SCy Schubert rep->is_proxied = 1;
955865f46b2SCy Schubert done:
956865f46b2SCy Schubert if(!stream) {
957865f46b2SCy Schubert /* We are reading a whole packet;
958865f46b2SCy Schubert * Move the rest of the data to overwrite the PROXYv2 header */
959865f46b2SCy Schubert /* XXX can we do better to avoid memmove? */
9601838dec3SCy Schubert memmove(header, ((char*)header)+size,
961865f46b2SCy Schubert sldns_buffer_limit(buf)-size);
962865f46b2SCy Schubert sldns_buffer_set_limit(buf, sldns_buffer_limit(buf)-size);
963865f46b2SCy Schubert }
964865f46b2SCy Schubert return 1;
965865f46b2SCy Schubert }
966865f46b2SCy Schubert
967103ba509SCy Schubert #if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG)
968b7579f77SDag-Erling Smørgrav void
969b7579f77SDag-Erling Smørgrav comm_point_udp_ancil_callback(int fd, short event, void* arg)
970b7579f77SDag-Erling Smørgrav {
971b7579f77SDag-Erling Smørgrav struct comm_reply rep;
972b7579f77SDag-Erling Smørgrav struct msghdr msg;
973b7579f77SDag-Erling Smørgrav struct iovec iov[1];
974b7579f77SDag-Erling Smørgrav ssize_t rcv;
97525039b37SCy Schubert union {
97625039b37SCy Schubert struct cmsghdr hdr;
97725039b37SCy Schubert char buf[256];
97825039b37SCy Schubert } ancil;
979b7579f77SDag-Erling Smørgrav int i;
980b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S
981b7579f77SDag-Erling Smørgrav struct cmsghdr* cmsg;
982b7579f77SDag-Erling Smørgrav #endif /* S_SPLINT_S */
9838f76bb7dSCy Schubert #ifdef HAVE_LINUX_NET_TSTAMP_H
9848f76bb7dSCy Schubert struct timespec *ts;
9858f76bb7dSCy Schubert #endif /* HAVE_LINUX_NET_TSTAMP_H */
986b7579f77SDag-Erling Smørgrav
987b7579f77SDag-Erling Smørgrav rep.c = (struct comm_point*)arg;
988b7579f77SDag-Erling Smørgrav log_assert(rep.c->type == comm_udp);
989b7579f77SDag-Erling Smørgrav
990e2d15004SDag-Erling Smørgrav if(!(event&UB_EV_READ))
991b7579f77SDag-Erling Smørgrav return;
992b7579f77SDag-Erling Smørgrav log_assert(rep.c && rep.c->buffer && rep.c->fd == fd);
993e2d15004SDag-Erling Smørgrav ub_comm_base_now(rep.c->ev->base);
994b7579f77SDag-Erling Smørgrav for(i=0; i<NUM_UDP_PER_SELECT; i++) {
99517d15b25SDag-Erling Smørgrav sldns_buffer_clear(rep.c->buffer);
9968f76bb7dSCy Schubert timeval_clear(&rep.c->recv_tv);
997865f46b2SCy Schubert rep.remote_addrlen = (socklen_t)sizeof(rep.remote_addr);
998b7579f77SDag-Erling Smørgrav log_assert(fd != -1);
99917d15b25SDag-Erling Smørgrav log_assert(sldns_buffer_remaining(rep.c->buffer) > 0);
1000865f46b2SCy Schubert msg.msg_name = &rep.remote_addr;
1001865f46b2SCy Schubert msg.msg_namelen = (socklen_t)sizeof(rep.remote_addr);
100217d15b25SDag-Erling Smørgrav iov[0].iov_base = sldns_buffer_begin(rep.c->buffer);
100317d15b25SDag-Erling Smørgrav iov[0].iov_len = sldns_buffer_remaining(rep.c->buffer);
1004b7579f77SDag-Erling Smørgrav msg.msg_iov = iov;
1005b7579f77SDag-Erling Smørgrav msg.msg_iovlen = 1;
100625039b37SCy Schubert msg.msg_control = ancil.buf;
1007b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S
100825039b37SCy Schubert msg.msg_controllen = sizeof(ancil.buf);
1009b7579f77SDag-Erling Smørgrav #endif /* S_SPLINT_S */
1010b7579f77SDag-Erling Smørgrav msg.msg_flags = 0;
1011865f46b2SCy Schubert rcv = recvmsg(fd, &msg, MSG_DONTWAIT);
1012b7579f77SDag-Erling Smørgrav if(rcv == -1) {
1013369c6923SCy Schubert if(errno != EAGAIN && errno != EINTR
1014369c6923SCy Schubert && udp_recv_needs_log(errno)) {
1015b7579f77SDag-Erling Smørgrav log_err("recvmsg failed: %s", strerror(errno));
1016b7579f77SDag-Erling Smørgrav }
1017b7579f77SDag-Erling Smørgrav return;
1018b7579f77SDag-Erling Smørgrav }
1019865f46b2SCy Schubert rep.remote_addrlen = msg.msg_namelen;
102017d15b25SDag-Erling Smørgrav sldns_buffer_skip(rep.c->buffer, rcv);
102117d15b25SDag-Erling Smørgrav sldns_buffer_flip(rep.c->buffer);
1022b7579f77SDag-Erling Smørgrav rep.srctype = 0;
1023865f46b2SCy Schubert rep.is_proxied = 0;
1024b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S
1025b7579f77SDag-Erling Smørgrav for(cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
1026b7579f77SDag-Erling Smørgrav cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1027b7579f77SDag-Erling Smørgrav if( cmsg->cmsg_level == IPPROTO_IPV6 &&
1028b7579f77SDag-Erling Smørgrav cmsg->cmsg_type == IPV6_PKTINFO) {
1029b7579f77SDag-Erling Smørgrav rep.srctype = 6;
1030b7579f77SDag-Erling Smørgrav memmove(&rep.pktinfo.v6info, CMSG_DATA(cmsg),
1031b7579f77SDag-Erling Smørgrav sizeof(struct in6_pktinfo));
1032b7579f77SDag-Erling Smørgrav break;
1033b7579f77SDag-Erling Smørgrav #ifdef IP_PKTINFO
1034b7579f77SDag-Erling Smørgrav } else if( cmsg->cmsg_level == IPPROTO_IP &&
1035b7579f77SDag-Erling Smørgrav cmsg->cmsg_type == IP_PKTINFO) {
1036b7579f77SDag-Erling Smørgrav rep.srctype = 4;
1037b7579f77SDag-Erling Smørgrav memmove(&rep.pktinfo.v4info, CMSG_DATA(cmsg),
1038b7579f77SDag-Erling Smørgrav sizeof(struct in_pktinfo));
1039b7579f77SDag-Erling Smørgrav break;
1040b7579f77SDag-Erling Smørgrav #elif defined(IP_RECVDSTADDR)
1041b7579f77SDag-Erling Smørgrav } else if( cmsg->cmsg_level == IPPROTO_IP &&
1042b7579f77SDag-Erling Smørgrav cmsg->cmsg_type == IP_RECVDSTADDR) {
1043b7579f77SDag-Erling Smørgrav rep.srctype = 4;
1044b7579f77SDag-Erling Smørgrav memmove(&rep.pktinfo.v4addr, CMSG_DATA(cmsg),
1045b7579f77SDag-Erling Smørgrav sizeof(struct in_addr));
1046b7579f77SDag-Erling Smørgrav break;
1047b7579f77SDag-Erling Smørgrav #endif /* IP_PKTINFO or IP_RECVDSTADDR */
10488f76bb7dSCy Schubert #ifdef HAVE_LINUX_NET_TSTAMP_H
10498f76bb7dSCy Schubert } else if( cmsg->cmsg_level == SOL_SOCKET &&
10508f76bb7dSCy Schubert cmsg->cmsg_type == SO_TIMESTAMPNS) {
10518f76bb7dSCy Schubert ts = (struct timespec *)CMSG_DATA(cmsg);
10528f76bb7dSCy Schubert TIMESPEC_TO_TIMEVAL(&rep.c->recv_tv, ts);
10538f76bb7dSCy Schubert } else if( cmsg->cmsg_level == SOL_SOCKET &&
10548f76bb7dSCy Schubert cmsg->cmsg_type == SO_TIMESTAMPING) {
10558f76bb7dSCy Schubert ts = (struct timespec *)CMSG_DATA(cmsg);
10568f76bb7dSCy Schubert TIMESPEC_TO_TIMEVAL(&rep.c->recv_tv, ts);
10578f76bb7dSCy Schubert } else if( cmsg->cmsg_level == SOL_SOCKET &&
10588f76bb7dSCy Schubert cmsg->cmsg_type == SO_TIMESTAMP) {
10598f76bb7dSCy Schubert memmove(&rep.c->recv_tv, CMSG_DATA(cmsg), sizeof(struct timeval));
10608f76bb7dSCy Schubert #endif /* HAVE_LINUX_NET_TSTAMP_H */
1061b7579f77SDag-Erling Smørgrav }
1062b7579f77SDag-Erling Smørgrav }
10638f76bb7dSCy Schubert
10648f76bb7dSCy Schubert if(verbosity >= VERB_ALGO && rep.srctype != 0)
1065b7579f77SDag-Erling Smørgrav p_ancil("receive_udp on interface", &rep);
1066b7579f77SDag-Erling Smørgrav #endif /* S_SPLINT_S */
1067865f46b2SCy Schubert
1068865f46b2SCy Schubert if(rep.c->pp2_enabled && !consume_pp2_header(rep.c->buffer,
1069865f46b2SCy Schubert &rep, 0)) {
1070865f46b2SCy Schubert log_err("proxy_protocol: could not consume PROXYv2 header");
1071865f46b2SCy Schubert return;
1072865f46b2SCy Schubert }
1073865f46b2SCy Schubert if(!rep.is_proxied) {
1074865f46b2SCy Schubert rep.client_addrlen = rep.remote_addrlen;
1075865f46b2SCy Schubert memmove(&rep.client_addr, &rep.remote_addr,
1076865f46b2SCy Schubert rep.remote_addrlen);
1077865f46b2SCy Schubert }
1078865f46b2SCy Schubert
1079b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point(rep.c->callback));
1080b7579f77SDag-Erling Smørgrav if((*rep.c->callback)(rep.c, rep.c->cb_arg, NETEVENT_NOERROR, &rep)) {
1081b7579f77SDag-Erling Smørgrav /* send back immediate reply */
1082103ba509SCy Schubert struct sldns_buffer *buffer;
1083103ba509SCy Schubert #ifdef USE_DNSCRYPT
1084103ba509SCy Schubert buffer = rep.c->dnscrypt_buffer;
1085103ba509SCy Schubert #else
1086103ba509SCy Schubert buffer = rep.c->buffer;
1087103ba509SCy Schubert #endif
1088103ba509SCy Schubert (void)comm_point_send_udp_msg_if(rep.c, buffer,
1089865f46b2SCy Schubert (struct sockaddr*)&rep.remote_addr,
1090865f46b2SCy Schubert rep.remote_addrlen, &rep);
1091b7579f77SDag-Erling Smørgrav }
109257bddd21SDag-Erling Smørgrav if(!rep.c || rep.c->fd == -1) /* commpoint closed */
1093b7579f77SDag-Erling Smørgrav break;
1094b7579f77SDag-Erling Smørgrav }
1095b7579f77SDag-Erling Smørgrav }
1096103ba509SCy Schubert #endif /* AF_INET6 && IPV6_PKTINFO && HAVE_RECVMSG */
1097b7579f77SDag-Erling Smørgrav
1098b7579f77SDag-Erling Smørgrav void
1099b7579f77SDag-Erling Smørgrav comm_point_udp_callback(int fd, short event, void* arg)
1100b7579f77SDag-Erling Smørgrav {
1101b7579f77SDag-Erling Smørgrav struct comm_reply rep;
1102b7579f77SDag-Erling Smørgrav ssize_t rcv;
1103b7579f77SDag-Erling Smørgrav int i;
110465b390aaSDag-Erling Smørgrav struct sldns_buffer *buffer;
1105b7579f77SDag-Erling Smørgrav
1106b7579f77SDag-Erling Smørgrav rep.c = (struct comm_point*)arg;
1107b7579f77SDag-Erling Smørgrav log_assert(rep.c->type == comm_udp);
1108b7579f77SDag-Erling Smørgrav
1109e2d15004SDag-Erling Smørgrav if(!(event&UB_EV_READ))
1110b7579f77SDag-Erling Smørgrav return;
1111b7579f77SDag-Erling Smørgrav log_assert(rep.c && rep.c->buffer && rep.c->fd == fd);
1112e2d15004SDag-Erling Smørgrav ub_comm_base_now(rep.c->ev->base);
1113b7579f77SDag-Erling Smørgrav for(i=0; i<NUM_UDP_PER_SELECT; i++) {
111417d15b25SDag-Erling Smørgrav sldns_buffer_clear(rep.c->buffer);
1115865f46b2SCy Schubert rep.remote_addrlen = (socklen_t)sizeof(rep.remote_addr);
1116b7579f77SDag-Erling Smørgrav log_assert(fd != -1);
111717d15b25SDag-Erling Smørgrav log_assert(sldns_buffer_remaining(rep.c->buffer) > 0);
111817d15b25SDag-Erling Smørgrav rcv = recvfrom(fd, (void*)sldns_buffer_begin(rep.c->buffer),
1119865f46b2SCy Schubert sldns_buffer_remaining(rep.c->buffer), MSG_DONTWAIT,
1120865f46b2SCy Schubert (struct sockaddr*)&rep.remote_addr, &rep.remote_addrlen);
1121b7579f77SDag-Erling Smørgrav if(rcv == -1) {
1122b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK
1123369c6923SCy Schubert if(errno != EAGAIN && errno != EINTR
1124369c6923SCy Schubert && udp_recv_needs_log(errno))
1125b7579f77SDag-Erling Smørgrav log_err("recvfrom %d failed: %s",
1126b7579f77SDag-Erling Smørgrav fd, strerror(errno));
1127b7579f77SDag-Erling Smørgrav #else
1128b7579f77SDag-Erling Smørgrav if(WSAGetLastError() != WSAEINPROGRESS &&
1129b7579f77SDag-Erling Smørgrav WSAGetLastError() != WSAECONNRESET &&
1130f44e67d1SCy Schubert WSAGetLastError()!= WSAEWOULDBLOCK &&
1131f44e67d1SCy Schubert udp_recv_needs_log(WSAGetLastError()))
1132b7579f77SDag-Erling Smørgrav log_err("recvfrom failed: %s",
1133b7579f77SDag-Erling Smørgrav wsa_strerror(WSAGetLastError()));
1134b7579f77SDag-Erling Smørgrav #endif
1135b7579f77SDag-Erling Smørgrav return;
1136b7579f77SDag-Erling Smørgrav }
113717d15b25SDag-Erling Smørgrav sldns_buffer_skip(rep.c->buffer, rcv);
113817d15b25SDag-Erling Smørgrav sldns_buffer_flip(rep.c->buffer);
1139b7579f77SDag-Erling Smørgrav rep.srctype = 0;
1140865f46b2SCy Schubert rep.is_proxied = 0;
1141865f46b2SCy Schubert
1142865f46b2SCy Schubert if(rep.c->pp2_enabled && !consume_pp2_header(rep.c->buffer,
1143865f46b2SCy Schubert &rep, 0)) {
1144865f46b2SCy Schubert log_err("proxy_protocol: could not consume PROXYv2 header");
1145865f46b2SCy Schubert return;
1146865f46b2SCy Schubert }
1147865f46b2SCy Schubert if(!rep.is_proxied) {
1148865f46b2SCy Schubert rep.client_addrlen = rep.remote_addrlen;
1149865f46b2SCy Schubert memmove(&rep.client_addr, &rep.remote_addr,
1150865f46b2SCy Schubert rep.remote_addrlen);
1151865f46b2SCy Schubert }
1152865f46b2SCy Schubert
1153b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point(rep.c->callback));
1154b7579f77SDag-Erling Smørgrav if((*rep.c->callback)(rep.c, rep.c->cb_arg, NETEVENT_NOERROR, &rep)) {
1155b7579f77SDag-Erling Smørgrav /* send back immediate reply */
115665b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT
115765b390aaSDag-Erling Smørgrav buffer = rep.c->dnscrypt_buffer;
115865b390aaSDag-Erling Smørgrav #else
115965b390aaSDag-Erling Smørgrav buffer = rep.c->buffer;
116065b390aaSDag-Erling Smørgrav #endif
116165b390aaSDag-Erling Smørgrav (void)comm_point_send_udp_msg(rep.c, buffer,
1162865f46b2SCy Schubert (struct sockaddr*)&rep.remote_addr,
1163865f46b2SCy Schubert rep.remote_addrlen, 0);
1164b7579f77SDag-Erling Smørgrav }
116557bddd21SDag-Erling Smørgrav if(!rep.c || rep.c->fd != fd) /* commpoint closed to -1 or reused for
1166b7579f77SDag-Erling Smørgrav another UDP port. Note rep.c cannot be reused with TCP fd. */
1167b7579f77SDag-Erling Smørgrav break;
1168b7579f77SDag-Erling Smørgrav }
1169b7579f77SDag-Erling Smørgrav }
1170b7579f77SDag-Erling Smørgrav
1171*46d2f618SCy Schubert #ifdef HAVE_NGTCP2
1172*46d2f618SCy Schubert void
1173*46d2f618SCy Schubert doq_pkt_addr_init(struct doq_pkt_addr* paddr)
1174*46d2f618SCy Schubert {
1175*46d2f618SCy Schubert paddr->addrlen = (socklen_t)sizeof(paddr->addr);
1176*46d2f618SCy Schubert paddr->localaddrlen = (socklen_t)sizeof(paddr->localaddr);
1177*46d2f618SCy Schubert paddr->ifindex = 0;
1178*46d2f618SCy Schubert }
1179*46d2f618SCy Schubert
1180*46d2f618SCy Schubert /** set the ecn on the transmission */
1181*46d2f618SCy Schubert static void
1182*46d2f618SCy Schubert doq_set_ecn(int fd, int family, uint32_t ecn)
1183*46d2f618SCy Schubert {
1184*46d2f618SCy Schubert unsigned int val = ecn;
1185*46d2f618SCy Schubert if(family == AF_INET6) {
1186*46d2f618SCy Schubert if(setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &val,
1187*46d2f618SCy Schubert (socklen_t)sizeof(val)) == -1) {
1188*46d2f618SCy Schubert log_err("setsockopt(.. IPV6_TCLASS ..): %s",
1189*46d2f618SCy Schubert strerror(errno));
1190*46d2f618SCy Schubert }
1191*46d2f618SCy Schubert return;
1192*46d2f618SCy Schubert }
1193*46d2f618SCy Schubert if(setsockopt(fd, IPPROTO_IP, IP_TOS, &val,
1194*46d2f618SCy Schubert (socklen_t)sizeof(val)) == -1) {
1195*46d2f618SCy Schubert log_err("setsockopt(.. IP_TOS ..): %s",
1196*46d2f618SCy Schubert strerror(errno));
1197*46d2f618SCy Schubert }
1198*46d2f618SCy Schubert }
1199*46d2f618SCy Schubert
1200*46d2f618SCy Schubert /** set the local address in the control ancillary data */
1201*46d2f618SCy Schubert static void
1202*46d2f618SCy Schubert doq_set_localaddr_cmsg(struct msghdr* msg, size_t control_size,
1203*46d2f618SCy Schubert struct doq_addr_storage* localaddr, socklen_t localaddrlen,
1204*46d2f618SCy Schubert int ifindex)
1205*46d2f618SCy Schubert {
1206*46d2f618SCy Schubert #ifndef S_SPLINT_S
1207*46d2f618SCy Schubert struct cmsghdr* cmsg;
1208*46d2f618SCy Schubert #endif /* S_SPLINT_S */
1209*46d2f618SCy Schubert #ifndef S_SPLINT_S
1210*46d2f618SCy Schubert cmsg = CMSG_FIRSTHDR(msg);
1211*46d2f618SCy Schubert if(localaddr->sockaddr.in.sin_family == AF_INET) {
1212*46d2f618SCy Schubert #ifdef IP_PKTINFO
1213*46d2f618SCy Schubert struct sockaddr_in* sa = (struct sockaddr_in*)localaddr;
1214*46d2f618SCy Schubert struct in_pktinfo v4info;
1215*46d2f618SCy Schubert log_assert(localaddrlen >= sizeof(struct sockaddr_in));
1216*46d2f618SCy Schubert msg->msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
1217*46d2f618SCy Schubert memset(msg->msg_control, 0, msg->msg_controllen);
1218*46d2f618SCy Schubert log_assert(msg->msg_controllen <= control_size);
1219*46d2f618SCy Schubert cmsg->cmsg_level = IPPROTO_IP;
1220*46d2f618SCy Schubert cmsg->cmsg_type = IP_PKTINFO;
1221*46d2f618SCy Schubert memset(&v4info, 0, sizeof(v4info));
1222*46d2f618SCy Schubert # ifdef HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST
1223*46d2f618SCy Schubert memmove(&v4info.ipi_spec_dst, &sa->sin_addr,
1224*46d2f618SCy Schubert sizeof(struct in_addr));
1225*46d2f618SCy Schubert # else
1226*46d2f618SCy Schubert memmove(&v4info.ipi_addr, &sa->sin_addr,
1227*46d2f618SCy Schubert sizeof(struct in_addr));
1228*46d2f618SCy Schubert # endif
1229*46d2f618SCy Schubert v4info.ipi_ifindex = ifindex;
1230*46d2f618SCy Schubert memmove(CMSG_DATA(cmsg), &v4info, sizeof(struct in_pktinfo));
1231*46d2f618SCy Schubert cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
1232*46d2f618SCy Schubert #elif defined(IP_SENDSRCADDR)
1233*46d2f618SCy Schubert struct sockaddr_in* sa= (struct sockaddr_in*)localaddr;
1234*46d2f618SCy Schubert log_assert(localaddrlen >= sizeof(struct sockaddr_in));
1235*46d2f618SCy Schubert msg->msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
1236*46d2f618SCy Schubert memset(msg->msg_control, 0, msg->msg_controllen);
1237*46d2f618SCy Schubert log_assert(msg->msg_controllen <= control_size);
1238*46d2f618SCy Schubert cmsg->cmsg_level = IPPROTO_IP;
1239*46d2f618SCy Schubert cmsg->cmsg_type = IP_SENDSRCADDR;
1240*46d2f618SCy Schubert memmove(CMSG_DATA(cmsg), &sa->sin_addr,
1241*46d2f618SCy Schubert sizeof(struct in_addr));
1242*46d2f618SCy Schubert cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
1243*46d2f618SCy Schubert #endif
1244*46d2f618SCy Schubert } else {
1245*46d2f618SCy Schubert struct sockaddr_in6* sa6 = (struct sockaddr_in6*)localaddr;
1246*46d2f618SCy Schubert struct in6_pktinfo v6info;
1247*46d2f618SCy Schubert log_assert(localaddrlen >= sizeof(struct sockaddr_in6));
1248*46d2f618SCy Schubert msg->msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
1249*46d2f618SCy Schubert memset(msg->msg_control, 0, msg->msg_controllen);
1250*46d2f618SCy Schubert log_assert(msg->msg_controllen <= control_size);
1251*46d2f618SCy Schubert cmsg->cmsg_level = IPPROTO_IPV6;
1252*46d2f618SCy Schubert cmsg->cmsg_type = IPV6_PKTINFO;
1253*46d2f618SCy Schubert memset(&v6info, 0, sizeof(v6info));
1254*46d2f618SCy Schubert memmove(&v6info.ipi6_addr, &sa6->sin6_addr,
1255*46d2f618SCy Schubert sizeof(struct in6_addr));
1256*46d2f618SCy Schubert v6info.ipi6_ifindex = ifindex;
1257*46d2f618SCy Schubert memmove(CMSG_DATA(cmsg), &v6info, sizeof(struct in6_pktinfo));
1258*46d2f618SCy Schubert cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
1259*46d2f618SCy Schubert }
1260*46d2f618SCy Schubert #endif /* S_SPLINT_S */
1261*46d2f618SCy Schubert /* Ignore unused variables, if no assertions are compiled. */
1262*46d2f618SCy Schubert (void)localaddrlen;
1263*46d2f618SCy Schubert (void)control_size;
1264*46d2f618SCy Schubert }
1265*46d2f618SCy Schubert
1266*46d2f618SCy Schubert /** write address and port into strings */
1267*46d2f618SCy Schubert static int
1268*46d2f618SCy Schubert doq_print_addr_port(struct doq_addr_storage* addr, socklen_t addrlen,
1269*46d2f618SCy Schubert char* host, size_t hostlen, char* port, size_t portlen)
1270*46d2f618SCy Schubert {
1271*46d2f618SCy Schubert if(addr->sockaddr.in.sin_family == AF_INET) {
1272*46d2f618SCy Schubert struct sockaddr_in* sa = (struct sockaddr_in*)addr;
1273*46d2f618SCy Schubert log_assert(addrlen >= sizeof(*sa));
1274*46d2f618SCy Schubert if(inet_ntop(sa->sin_family, &sa->sin_addr, host,
1275*46d2f618SCy Schubert (socklen_t)hostlen) == 0) {
1276*46d2f618SCy Schubert log_hex("inet_ntop error: address", &sa->sin_addr,
1277*46d2f618SCy Schubert sizeof(sa->sin_addr));
1278*46d2f618SCy Schubert return 0;
1279*46d2f618SCy Schubert }
1280*46d2f618SCy Schubert snprintf(port, portlen, "%u", (unsigned)ntohs(sa->sin_port));
1281*46d2f618SCy Schubert } else if(addr->sockaddr.in.sin_family == AF_INET6) {
1282*46d2f618SCy Schubert struct sockaddr_in6* sa6 = (struct sockaddr_in6*)addr;
1283*46d2f618SCy Schubert log_assert(addrlen >= sizeof(*sa6));
1284*46d2f618SCy Schubert if(inet_ntop(sa6->sin6_family, &sa6->sin6_addr, host,
1285*46d2f618SCy Schubert (socklen_t)hostlen) == 0) {
1286*46d2f618SCy Schubert log_hex("inet_ntop error: address", &sa6->sin6_addr,
1287*46d2f618SCy Schubert sizeof(sa6->sin6_addr));
1288*46d2f618SCy Schubert return 0;
1289*46d2f618SCy Schubert }
1290*46d2f618SCy Schubert snprintf(port, portlen, "%u", (unsigned)ntohs(sa6->sin6_port));
1291*46d2f618SCy Schubert }
1292*46d2f618SCy Schubert return 1;
1293*46d2f618SCy Schubert }
1294*46d2f618SCy Schubert
1295*46d2f618SCy Schubert /** doq store the blocked packet when write has blocked */
1296*46d2f618SCy Schubert static void
1297*46d2f618SCy Schubert doq_store_blocked_pkt(struct comm_point* c, struct doq_pkt_addr* paddr,
1298*46d2f618SCy Schubert uint32_t ecn)
1299*46d2f618SCy Schubert {
1300*46d2f618SCy Schubert if(c->doq_socket->have_blocked_pkt)
1301*46d2f618SCy Schubert return; /* should not happen that we write when there is
1302*46d2f618SCy Schubert already a blocked write, but if so, drop it. */
1303*46d2f618SCy Schubert if(sldns_buffer_limit(c->doq_socket->pkt_buf) >
1304*46d2f618SCy Schubert sldns_buffer_capacity(c->doq_socket->blocked_pkt))
1305*46d2f618SCy Schubert return; /* impossibly large, drop packet. impossible because
1306*46d2f618SCy Schubert pkt_buf and blocked_pkt are the same size. */
1307*46d2f618SCy Schubert c->doq_socket->have_blocked_pkt = 1;
1308*46d2f618SCy Schubert c->doq_socket->blocked_pkt_pi.ecn = ecn;
1309*46d2f618SCy Schubert memcpy(c->doq_socket->blocked_paddr, paddr,
1310*46d2f618SCy Schubert sizeof(*c->doq_socket->blocked_paddr));
1311*46d2f618SCy Schubert sldns_buffer_clear(c->doq_socket->blocked_pkt);
1312*46d2f618SCy Schubert sldns_buffer_write(c->doq_socket->blocked_pkt,
1313*46d2f618SCy Schubert sldns_buffer_begin(c->doq_socket->pkt_buf),
1314*46d2f618SCy Schubert sldns_buffer_limit(c->doq_socket->pkt_buf));
1315*46d2f618SCy Schubert sldns_buffer_flip(c->doq_socket->blocked_pkt);
1316*46d2f618SCy Schubert }
1317*46d2f618SCy Schubert
1318*46d2f618SCy Schubert void
1319*46d2f618SCy Schubert doq_send_pkt(struct comm_point* c, struct doq_pkt_addr* paddr, uint32_t ecn)
1320*46d2f618SCy Schubert {
1321*46d2f618SCy Schubert struct msghdr msg;
1322*46d2f618SCy Schubert struct iovec iov[1];
1323*46d2f618SCy Schubert union {
1324*46d2f618SCy Schubert struct cmsghdr hdr;
1325*46d2f618SCy Schubert char buf[256];
1326*46d2f618SCy Schubert } control;
1327*46d2f618SCy Schubert ssize_t ret;
1328*46d2f618SCy Schubert iov[0].iov_base = sldns_buffer_begin(c->doq_socket->pkt_buf);
1329*46d2f618SCy Schubert iov[0].iov_len = sldns_buffer_limit(c->doq_socket->pkt_buf);
1330*46d2f618SCy Schubert memset(&msg, 0, sizeof(msg));
1331*46d2f618SCy Schubert msg.msg_name = (void*)&paddr->addr;
1332*46d2f618SCy Schubert msg.msg_namelen = paddr->addrlen;
1333*46d2f618SCy Schubert msg.msg_iov = iov;
1334*46d2f618SCy Schubert msg.msg_iovlen = 1;
1335*46d2f618SCy Schubert msg.msg_control = control.buf;
1336*46d2f618SCy Schubert #ifndef S_SPLINT_S
1337*46d2f618SCy Schubert msg.msg_controllen = sizeof(control.buf);
1338*46d2f618SCy Schubert #endif /* S_SPLINT_S */
1339*46d2f618SCy Schubert msg.msg_flags = 0;
1340*46d2f618SCy Schubert
1341*46d2f618SCy Schubert doq_set_localaddr_cmsg(&msg, sizeof(control.buf), &paddr->localaddr,
1342*46d2f618SCy Schubert paddr->localaddrlen, paddr->ifindex);
1343*46d2f618SCy Schubert doq_set_ecn(c->fd, paddr->addr.sockaddr.in.sin_family, ecn);
1344*46d2f618SCy Schubert
1345*46d2f618SCy Schubert for(;;) {
1346*46d2f618SCy Schubert ret = sendmsg(c->fd, &msg, MSG_DONTWAIT);
1347*46d2f618SCy Schubert if(ret == -1 && errno == EINTR)
1348*46d2f618SCy Schubert continue;
1349*46d2f618SCy Schubert break;
1350*46d2f618SCy Schubert }
1351*46d2f618SCy Schubert if(ret == -1) {
1352*46d2f618SCy Schubert #ifndef USE_WINSOCK
1353*46d2f618SCy Schubert if(errno == EAGAIN ||
1354*46d2f618SCy Schubert # ifdef EWOULDBLOCK
1355*46d2f618SCy Schubert errno == EWOULDBLOCK ||
1356*46d2f618SCy Schubert # endif
1357*46d2f618SCy Schubert errno == ENOBUFS)
1358*46d2f618SCy Schubert #else
1359*46d2f618SCy Schubert if(WSAGetLastError() == WSAEINPROGRESS ||
1360*46d2f618SCy Schubert WSAGetLastError() == WSAENOBUFS ||
1361*46d2f618SCy Schubert WSAGetLastError() == WSAEWOULDBLOCK)
1362*46d2f618SCy Schubert #endif
1363*46d2f618SCy Schubert {
1364*46d2f618SCy Schubert /* udp send has blocked */
1365*46d2f618SCy Schubert doq_store_blocked_pkt(c, paddr, ecn);
1366*46d2f618SCy Schubert return;
1367*46d2f618SCy Schubert }
1368*46d2f618SCy Schubert if(!udp_send_errno_needs_log((void*)&paddr->addr,
1369*46d2f618SCy Schubert paddr->addrlen))
1370*46d2f618SCy Schubert return;
1371*46d2f618SCy Schubert if(verbosity >= VERB_OPS) {
1372*46d2f618SCy Schubert char host[256], port[32];
1373*46d2f618SCy Schubert if(doq_print_addr_port(&paddr->addr, paddr->addrlen,
1374*46d2f618SCy Schubert host, sizeof(host), port, sizeof(port))) {
1375*46d2f618SCy Schubert verbose(VERB_OPS, "doq sendmsg to %s %s "
1376*46d2f618SCy Schubert "failed: %s", host, port,
1377*46d2f618SCy Schubert strerror(errno));
1378*46d2f618SCy Schubert } else {
1379*46d2f618SCy Schubert verbose(VERB_OPS, "doq sendmsg failed: %s",
1380*46d2f618SCy Schubert strerror(errno));
1381*46d2f618SCy Schubert }
1382*46d2f618SCy Schubert }
1383*46d2f618SCy Schubert return;
1384*46d2f618SCy Schubert } else if(ret != (ssize_t)sldns_buffer_limit(c->doq_socket->pkt_buf)) {
1385*46d2f618SCy Schubert char host[256], port[32];
1386*46d2f618SCy Schubert if(doq_print_addr_port(&paddr->addr, paddr->addrlen, host,
1387*46d2f618SCy Schubert sizeof(host), port, sizeof(port))) {
1388*46d2f618SCy Schubert log_err("doq sendmsg to %s %s failed: "
1389*46d2f618SCy Schubert "sent %d in place of %d bytes",
1390*46d2f618SCy Schubert host, port, (int)ret,
1391*46d2f618SCy Schubert (int)sldns_buffer_limit(c->doq_socket->pkt_buf));
1392*46d2f618SCy Schubert } else {
1393*46d2f618SCy Schubert log_err("doq sendmsg failed: "
1394*46d2f618SCy Schubert "sent %d in place of %d bytes",
1395*46d2f618SCy Schubert (int)ret, (int)sldns_buffer_limit(c->doq_socket->pkt_buf));
1396*46d2f618SCy Schubert }
1397*46d2f618SCy Schubert return;
1398*46d2f618SCy Schubert }
1399*46d2f618SCy Schubert }
1400*46d2f618SCy Schubert
1401*46d2f618SCy Schubert /** fetch port number */
1402*46d2f618SCy Schubert static int
1403*46d2f618SCy Schubert doq_sockaddr_get_port(struct doq_addr_storage* addr)
1404*46d2f618SCy Schubert {
1405*46d2f618SCy Schubert if(addr->sockaddr.in.sin_family == AF_INET) {
1406*46d2f618SCy Schubert struct sockaddr_in* sa = (struct sockaddr_in*)addr;
1407*46d2f618SCy Schubert return ntohs(sa->sin_port);
1408*46d2f618SCy Schubert } else if(addr->sockaddr.in.sin_family == AF_INET6) {
1409*46d2f618SCy Schubert struct sockaddr_in6* sa6 = (struct sockaddr_in6*)addr;
1410*46d2f618SCy Schubert return ntohs(sa6->sin6_port);
1411*46d2f618SCy Schubert }
1412*46d2f618SCy Schubert return 0;
1413*46d2f618SCy Schubert }
1414*46d2f618SCy Schubert
1415*46d2f618SCy Schubert /** get local address from ancillary data headers */
1416*46d2f618SCy Schubert static int
1417*46d2f618SCy Schubert doq_get_localaddr_cmsg(struct comm_point* c, struct doq_pkt_addr* paddr,
1418*46d2f618SCy Schubert int* pkt_continue, struct msghdr* msg)
1419*46d2f618SCy Schubert {
1420*46d2f618SCy Schubert #ifndef S_SPLINT_S
1421*46d2f618SCy Schubert struct cmsghdr* cmsg;
1422*46d2f618SCy Schubert #endif /* S_SPLINT_S */
1423*46d2f618SCy Schubert
1424*46d2f618SCy Schubert memset(&paddr->localaddr, 0, sizeof(paddr->localaddr));
1425*46d2f618SCy Schubert #ifndef S_SPLINT_S
1426*46d2f618SCy Schubert for(cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
1427*46d2f618SCy Schubert cmsg = CMSG_NXTHDR(msg, cmsg)) {
1428*46d2f618SCy Schubert if( cmsg->cmsg_level == IPPROTO_IPV6 &&
1429*46d2f618SCy Schubert cmsg->cmsg_type == IPV6_PKTINFO) {
1430*46d2f618SCy Schubert struct in6_pktinfo* v6info =
1431*46d2f618SCy Schubert (struct in6_pktinfo*)CMSG_DATA(cmsg);
1432*46d2f618SCy Schubert struct sockaddr_in6* sa= (struct sockaddr_in6*)
1433*46d2f618SCy Schubert &paddr->localaddr;
1434*46d2f618SCy Schubert struct sockaddr_in6* rema = (struct sockaddr_in6*)
1435*46d2f618SCy Schubert &paddr->addr;
1436*46d2f618SCy Schubert if(rema->sin6_family != AF_INET6) {
1437*46d2f618SCy Schubert log_err("doq cmsg family mismatch cmsg is ip6");
1438*46d2f618SCy Schubert *pkt_continue = 1;
1439*46d2f618SCy Schubert return 0;
1440*46d2f618SCy Schubert }
1441*46d2f618SCy Schubert sa->sin6_family = AF_INET6;
1442*46d2f618SCy Schubert sa->sin6_port = htons(doq_sockaddr_get_port(
1443*46d2f618SCy Schubert (void*)c->socket->addr));
1444*46d2f618SCy Schubert paddr->ifindex = v6info->ipi6_ifindex;
1445*46d2f618SCy Schubert memmove(&sa->sin6_addr, &v6info->ipi6_addr,
1446*46d2f618SCy Schubert sizeof(struct in6_addr));
1447*46d2f618SCy Schubert paddr->localaddrlen = sizeof(struct sockaddr_in6);
1448*46d2f618SCy Schubert break;
1449*46d2f618SCy Schubert #ifdef IP_PKTINFO
1450*46d2f618SCy Schubert } else if( cmsg->cmsg_level == IPPROTO_IP &&
1451*46d2f618SCy Schubert cmsg->cmsg_type == IP_PKTINFO) {
1452*46d2f618SCy Schubert struct in_pktinfo* v4info =
1453*46d2f618SCy Schubert (struct in_pktinfo*)CMSG_DATA(cmsg);
1454*46d2f618SCy Schubert struct sockaddr_in* sa= (struct sockaddr_in*)
1455*46d2f618SCy Schubert &paddr->localaddr;
1456*46d2f618SCy Schubert struct sockaddr_in* rema = (struct sockaddr_in*)
1457*46d2f618SCy Schubert &paddr->addr;
1458*46d2f618SCy Schubert if(rema->sin_family != AF_INET) {
1459*46d2f618SCy Schubert log_err("doq cmsg family mismatch cmsg is ip4");
1460*46d2f618SCy Schubert *pkt_continue = 1;
1461*46d2f618SCy Schubert return 0;
1462*46d2f618SCy Schubert }
1463*46d2f618SCy Schubert sa->sin_family = AF_INET;
1464*46d2f618SCy Schubert sa->sin_port = htons(doq_sockaddr_get_port(
1465*46d2f618SCy Schubert (void*)c->socket->addr));
1466*46d2f618SCy Schubert paddr->ifindex = v4info->ipi_ifindex;
1467*46d2f618SCy Schubert memmove(&sa->sin_addr, &v4info->ipi_addr,
1468*46d2f618SCy Schubert sizeof(struct in_addr));
1469*46d2f618SCy Schubert paddr->localaddrlen = sizeof(struct sockaddr_in);
1470*46d2f618SCy Schubert break;
1471*46d2f618SCy Schubert #elif defined(IP_RECVDSTADDR)
1472*46d2f618SCy Schubert } else if( cmsg->cmsg_level == IPPROTO_IP &&
1473*46d2f618SCy Schubert cmsg->cmsg_type == IP_RECVDSTADDR) {
1474*46d2f618SCy Schubert struct sockaddr_in* sa= (struct sockaddr_in*)
1475*46d2f618SCy Schubert &paddr->localaddr;
1476*46d2f618SCy Schubert struct sockaddr_in* rema = (struct sockaddr_in*)
1477*46d2f618SCy Schubert &paddr->addr;
1478*46d2f618SCy Schubert if(rema->sin_family != AF_INET) {
1479*46d2f618SCy Schubert log_err("doq cmsg family mismatch cmsg is ip4");
1480*46d2f618SCy Schubert *pkt_continue = 1;
1481*46d2f618SCy Schubert return 0;
1482*46d2f618SCy Schubert }
1483*46d2f618SCy Schubert sa->sin_family = AF_INET;
1484*46d2f618SCy Schubert sa->sin_port = htons(doq_sockaddr_get_port(
1485*46d2f618SCy Schubert (void*)c->socket->addr));
1486*46d2f618SCy Schubert paddr->ifindex = 0;
1487*46d2f618SCy Schubert memmove(&sa.sin_addr, CMSG_DATA(cmsg),
1488*46d2f618SCy Schubert sizeof(struct in_addr));
1489*46d2f618SCy Schubert paddr->localaddrlen = sizeof(struct sockaddr_in);
1490*46d2f618SCy Schubert break;
1491*46d2f618SCy Schubert #endif /* IP_PKTINFO or IP_RECVDSTADDR */
1492*46d2f618SCy Schubert }
1493*46d2f618SCy Schubert }
1494*46d2f618SCy Schubert #endif /* S_SPLINT_S */
1495*46d2f618SCy Schubert
1496*46d2f618SCy Schubert return 1;
1497*46d2f618SCy Schubert }
1498*46d2f618SCy Schubert
1499*46d2f618SCy Schubert /** get packet ecn information */
1500*46d2f618SCy Schubert static uint32_t
1501*46d2f618SCy Schubert msghdr_get_ecn(struct msghdr* msg, int family)
1502*46d2f618SCy Schubert {
1503*46d2f618SCy Schubert #ifndef S_SPLINT_S
1504*46d2f618SCy Schubert struct cmsghdr* cmsg;
1505*46d2f618SCy Schubert if(family == AF_INET6) {
1506*46d2f618SCy Schubert for(cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
1507*46d2f618SCy Schubert cmsg = CMSG_NXTHDR(msg, cmsg)) {
1508*46d2f618SCy Schubert if(cmsg->cmsg_level == IPPROTO_IPV6 &&
1509*46d2f618SCy Schubert cmsg->cmsg_type == IPV6_TCLASS &&
1510*46d2f618SCy Schubert cmsg->cmsg_len != 0) {
1511*46d2f618SCy Schubert uint8_t* ecn = (uint8_t*)CMSG_DATA(cmsg);
1512*46d2f618SCy Schubert return *ecn;
1513*46d2f618SCy Schubert }
1514*46d2f618SCy Schubert }
1515*46d2f618SCy Schubert return 0;
1516*46d2f618SCy Schubert }
1517*46d2f618SCy Schubert for(cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
1518*46d2f618SCy Schubert cmsg = CMSG_NXTHDR(msg, cmsg)) {
1519*46d2f618SCy Schubert if(cmsg->cmsg_level == IPPROTO_IP &&
1520*46d2f618SCy Schubert cmsg->cmsg_type == IP_TOS &&
1521*46d2f618SCy Schubert cmsg->cmsg_len != 0) {
1522*46d2f618SCy Schubert uint8_t* ecn = (uint8_t*)CMSG_DATA(cmsg);
1523*46d2f618SCy Schubert return *ecn;
1524*46d2f618SCy Schubert }
1525*46d2f618SCy Schubert }
1526*46d2f618SCy Schubert #endif /* S_SPLINT_S */
1527*46d2f618SCy Schubert return 0;
1528*46d2f618SCy Schubert }
1529*46d2f618SCy Schubert
1530*46d2f618SCy Schubert /** receive packet for DoQ on UDP. get ancillary data for addresses,
1531*46d2f618SCy Schubert * return false if failed and the callback can stop receiving UDP packets
1532*46d2f618SCy Schubert * if pkt_continue is false. */
1533*46d2f618SCy Schubert static int
1534*46d2f618SCy Schubert doq_recv(struct comm_point* c, struct doq_pkt_addr* paddr, int* pkt_continue,
1535*46d2f618SCy Schubert struct ngtcp2_pkt_info* pi)
1536*46d2f618SCy Schubert {
1537*46d2f618SCy Schubert struct msghdr msg;
1538*46d2f618SCy Schubert struct iovec iov[1];
1539*46d2f618SCy Schubert ssize_t rcv;
1540*46d2f618SCy Schubert union {
1541*46d2f618SCy Schubert struct cmsghdr hdr;
1542*46d2f618SCy Schubert char buf[256];
1543*46d2f618SCy Schubert } ancil;
1544*46d2f618SCy Schubert
1545*46d2f618SCy Schubert msg.msg_name = &paddr->addr;
1546*46d2f618SCy Schubert msg.msg_namelen = (socklen_t)sizeof(paddr->addr);
1547*46d2f618SCy Schubert iov[0].iov_base = sldns_buffer_begin(c->doq_socket->pkt_buf);
1548*46d2f618SCy Schubert iov[0].iov_len = sldns_buffer_remaining(c->doq_socket->pkt_buf);
1549*46d2f618SCy Schubert msg.msg_iov = iov;
1550*46d2f618SCy Schubert msg.msg_iovlen = 1;
1551*46d2f618SCy Schubert msg.msg_control = ancil.buf;
1552*46d2f618SCy Schubert #ifndef S_SPLINT_S
1553*46d2f618SCy Schubert msg.msg_controllen = sizeof(ancil.buf);
1554*46d2f618SCy Schubert #endif /* S_SPLINT_S */
1555*46d2f618SCy Schubert msg.msg_flags = 0;
1556*46d2f618SCy Schubert
1557*46d2f618SCy Schubert rcv = recvmsg(c->fd, &msg, MSG_DONTWAIT);
1558*46d2f618SCy Schubert if(rcv == -1) {
1559*46d2f618SCy Schubert if(errno != EAGAIN && errno != EINTR
1560*46d2f618SCy Schubert && udp_recv_needs_log(errno)) {
1561*46d2f618SCy Schubert log_err("recvmsg failed for doq: %s", strerror(errno));
1562*46d2f618SCy Schubert }
1563*46d2f618SCy Schubert *pkt_continue = 0;
1564*46d2f618SCy Schubert return 0;
1565*46d2f618SCy Schubert }
1566*46d2f618SCy Schubert
1567*46d2f618SCy Schubert paddr->addrlen = msg.msg_namelen;
1568*46d2f618SCy Schubert sldns_buffer_skip(c->doq_socket->pkt_buf, rcv);
1569*46d2f618SCy Schubert sldns_buffer_flip(c->doq_socket->pkt_buf);
1570*46d2f618SCy Schubert if(!doq_get_localaddr_cmsg(c, paddr, pkt_continue, &msg))
1571*46d2f618SCy Schubert return 0;
1572*46d2f618SCy Schubert pi->ecn = msghdr_get_ecn(&msg, paddr->addr.sockaddr.in.sin_family);
1573*46d2f618SCy Schubert return 1;
1574*46d2f618SCy Schubert }
1575*46d2f618SCy Schubert
1576*46d2f618SCy Schubert /** send the version negotiation for doq. scid and dcid are flipped around
1577*46d2f618SCy Schubert * to send back to the client. */
1578*46d2f618SCy Schubert static void
1579*46d2f618SCy Schubert doq_send_version_negotiation(struct comm_point* c, struct doq_pkt_addr* paddr,
1580*46d2f618SCy Schubert const uint8_t* dcid, size_t dcidlen, const uint8_t* scid,
1581*46d2f618SCy Schubert size_t scidlen)
1582*46d2f618SCy Schubert {
1583*46d2f618SCy Schubert uint32_t versions[2];
1584*46d2f618SCy Schubert size_t versions_len = 0;
1585*46d2f618SCy Schubert ngtcp2_ssize ret;
1586*46d2f618SCy Schubert uint8_t unused_random;
1587*46d2f618SCy Schubert
1588*46d2f618SCy Schubert /* fill the array with supported versions */
1589*46d2f618SCy Schubert versions[0] = NGTCP2_PROTO_VER_V1;
1590*46d2f618SCy Schubert versions_len = 1;
1591*46d2f618SCy Schubert unused_random = ub_random_max(c->doq_socket->rnd, 256);
1592*46d2f618SCy Schubert sldns_buffer_clear(c->doq_socket->pkt_buf);
1593*46d2f618SCy Schubert ret = ngtcp2_pkt_write_version_negotiation(
1594*46d2f618SCy Schubert sldns_buffer_begin(c->doq_socket->pkt_buf),
1595*46d2f618SCy Schubert sldns_buffer_capacity(c->doq_socket->pkt_buf), unused_random,
1596*46d2f618SCy Schubert dcid, dcidlen, scid, scidlen, versions, versions_len);
1597*46d2f618SCy Schubert if(ret < 0) {
1598*46d2f618SCy Schubert log_err("ngtcp2_pkt_write_version_negotiation failed: %s",
1599*46d2f618SCy Schubert ngtcp2_strerror(ret));
1600*46d2f618SCy Schubert return;
1601*46d2f618SCy Schubert }
1602*46d2f618SCy Schubert sldns_buffer_set_position(c->doq_socket->pkt_buf, ret);
1603*46d2f618SCy Schubert sldns_buffer_flip(c->doq_socket->pkt_buf);
1604*46d2f618SCy Schubert doq_send_pkt(c, paddr, 0);
1605*46d2f618SCy Schubert }
1606*46d2f618SCy Schubert
1607*46d2f618SCy Schubert /** Find the doq_conn object by remote address and dcid */
1608*46d2f618SCy Schubert static struct doq_conn*
1609*46d2f618SCy Schubert doq_conn_find(struct doq_table* table, struct doq_addr_storage* addr,
1610*46d2f618SCy Schubert socklen_t addrlen, struct doq_addr_storage* localaddr,
1611*46d2f618SCy Schubert socklen_t localaddrlen, int ifindex, const uint8_t* dcid,
1612*46d2f618SCy Schubert size_t dcidlen)
1613*46d2f618SCy Schubert {
1614*46d2f618SCy Schubert struct rbnode_type* node;
1615*46d2f618SCy Schubert struct doq_conn key;
1616*46d2f618SCy Schubert memset(&key.node, 0, sizeof(key.node));
1617*46d2f618SCy Schubert key.node.key = &key;
1618*46d2f618SCy Schubert memmove(&key.key.paddr.addr, addr, addrlen);
1619*46d2f618SCy Schubert key.key.paddr.addrlen = addrlen;
1620*46d2f618SCy Schubert memmove(&key.key.paddr.localaddr, localaddr, localaddrlen);
1621*46d2f618SCy Schubert key.key.paddr.localaddrlen = localaddrlen;
1622*46d2f618SCy Schubert key.key.paddr.ifindex = ifindex;
1623*46d2f618SCy Schubert key.key.dcid = (void*)dcid;
1624*46d2f618SCy Schubert key.key.dcidlen = dcidlen;
1625*46d2f618SCy Schubert node = rbtree_search(table->conn_tree, &key);
1626*46d2f618SCy Schubert if(node)
1627*46d2f618SCy Schubert return (struct doq_conn*)node->key;
1628*46d2f618SCy Schubert return NULL;
1629*46d2f618SCy Schubert }
1630*46d2f618SCy Schubert
1631*46d2f618SCy Schubert /** find the doq_con by the connection id */
1632*46d2f618SCy Schubert static struct doq_conn*
1633*46d2f618SCy Schubert doq_conn_find_by_id(struct doq_table* table, const uint8_t* dcid,
1634*46d2f618SCy Schubert size_t dcidlen)
1635*46d2f618SCy Schubert {
1636*46d2f618SCy Schubert struct doq_conid* conid;
1637*46d2f618SCy Schubert lock_rw_rdlock(&table->conid_lock);
1638*46d2f618SCy Schubert conid = doq_conid_find(table, dcid, dcidlen);
1639*46d2f618SCy Schubert if(conid) {
1640*46d2f618SCy Schubert /* make a copy of the key */
1641*46d2f618SCy Schubert struct doq_conn* conn;
1642*46d2f618SCy Schubert struct doq_conn_key key = conid->key;
1643*46d2f618SCy Schubert uint8_t cid[NGTCP2_MAX_CIDLEN];
1644*46d2f618SCy Schubert log_assert(conid->key.dcidlen <= NGTCP2_MAX_CIDLEN);
1645*46d2f618SCy Schubert memcpy(cid, conid->key.dcid, conid->key.dcidlen);
1646*46d2f618SCy Schubert key.dcid = cid;
1647*46d2f618SCy Schubert lock_rw_unlock(&table->conid_lock);
1648*46d2f618SCy Schubert
1649*46d2f618SCy Schubert /* now that the conid lock is released, look up the conn */
1650*46d2f618SCy Schubert lock_rw_rdlock(&table->lock);
1651*46d2f618SCy Schubert conn = doq_conn_find(table, &key.paddr.addr,
1652*46d2f618SCy Schubert key.paddr.addrlen, &key.paddr.localaddr,
1653*46d2f618SCy Schubert key.paddr.localaddrlen, key.paddr.ifindex, key.dcid,
1654*46d2f618SCy Schubert key.dcidlen);
1655*46d2f618SCy Schubert if(!conn) {
1656*46d2f618SCy Schubert /* The connection got deleted between the conid lookup
1657*46d2f618SCy Schubert * and the connection lock grab, it no longer exists,
1658*46d2f618SCy Schubert * so return null. */
1659*46d2f618SCy Schubert lock_rw_unlock(&table->lock);
1660*46d2f618SCy Schubert return NULL;
1661*46d2f618SCy Schubert }
1662*46d2f618SCy Schubert lock_basic_lock(&conn->lock);
1663*46d2f618SCy Schubert if(conn->is_deleted) {
1664*46d2f618SCy Schubert lock_rw_unlock(&table->lock);
1665*46d2f618SCy Schubert lock_basic_unlock(&conn->lock);
1666*46d2f618SCy Schubert return NULL;
1667*46d2f618SCy Schubert }
1668*46d2f618SCy Schubert lock_rw_unlock(&table->lock);
1669*46d2f618SCy Schubert return conn;
1670*46d2f618SCy Schubert }
1671*46d2f618SCy Schubert lock_rw_unlock(&table->conid_lock);
1672*46d2f618SCy Schubert return NULL;
1673*46d2f618SCy Schubert }
1674*46d2f618SCy Schubert
1675*46d2f618SCy Schubert /** Find the doq_conn, by addr or by connection id */
1676*46d2f618SCy Schubert static struct doq_conn*
1677*46d2f618SCy Schubert doq_conn_find_by_addr_or_cid(struct doq_table* table,
1678*46d2f618SCy Schubert struct doq_pkt_addr* paddr, const uint8_t* dcid, size_t dcidlen)
1679*46d2f618SCy Schubert {
1680*46d2f618SCy Schubert struct doq_conn* conn;
1681*46d2f618SCy Schubert lock_rw_rdlock(&table->lock);
1682*46d2f618SCy Schubert conn = doq_conn_find(table, &paddr->addr, paddr->addrlen,
1683*46d2f618SCy Schubert &paddr->localaddr, paddr->localaddrlen, paddr->ifindex,
1684*46d2f618SCy Schubert dcid, dcidlen);
1685*46d2f618SCy Schubert if(conn && conn->is_deleted) {
1686*46d2f618SCy Schubert conn = NULL;
1687*46d2f618SCy Schubert }
1688*46d2f618SCy Schubert if(conn) {
1689*46d2f618SCy Schubert lock_basic_lock(&conn->lock);
1690*46d2f618SCy Schubert lock_rw_unlock(&table->lock);
1691*46d2f618SCy Schubert verbose(VERB_ALGO, "doq: found connection by address, dcid");
1692*46d2f618SCy Schubert } else {
1693*46d2f618SCy Schubert lock_rw_unlock(&table->lock);
1694*46d2f618SCy Schubert conn = doq_conn_find_by_id(table, dcid, dcidlen);
1695*46d2f618SCy Schubert if(conn) {
1696*46d2f618SCy Schubert verbose(VERB_ALGO, "doq: found connection by dcid");
1697*46d2f618SCy Schubert }
1698*46d2f618SCy Schubert }
1699*46d2f618SCy Schubert return conn;
1700*46d2f618SCy Schubert }
1701*46d2f618SCy Schubert
1702*46d2f618SCy Schubert /** decode doq packet header, false on handled or failure, true to continue
1703*46d2f618SCy Schubert * to process the packet */
1704*46d2f618SCy Schubert static int
1705*46d2f618SCy Schubert doq_decode_pkt_header_negotiate(struct comm_point* c,
1706*46d2f618SCy Schubert struct doq_pkt_addr* paddr, struct doq_conn** conn)
1707*46d2f618SCy Schubert {
1708*46d2f618SCy Schubert #ifdef HAVE_STRUCT_NGTCP2_VERSION_CID
1709*46d2f618SCy Schubert struct ngtcp2_version_cid vc;
1710*46d2f618SCy Schubert #else
1711*46d2f618SCy Schubert uint32_t version;
1712*46d2f618SCy Schubert const uint8_t *dcid, *scid;
1713*46d2f618SCy Schubert size_t dcidlen, scidlen;
1714*46d2f618SCy Schubert #endif
1715*46d2f618SCy Schubert int rv;
1716*46d2f618SCy Schubert
1717*46d2f618SCy Schubert #ifdef HAVE_STRUCT_NGTCP2_VERSION_CID
1718*46d2f618SCy Schubert rv = ngtcp2_pkt_decode_version_cid(&vc,
1719*46d2f618SCy Schubert sldns_buffer_begin(c->doq_socket->pkt_buf),
1720*46d2f618SCy Schubert sldns_buffer_limit(c->doq_socket->pkt_buf),
1721*46d2f618SCy Schubert c->doq_socket->sv_scidlen);
1722*46d2f618SCy Schubert #else
1723*46d2f618SCy Schubert rv = ngtcp2_pkt_decode_version_cid(&version, &dcid, &dcidlen,
1724*46d2f618SCy Schubert &scid, &scidlen, sldns_buffer_begin(c->doq_socket->pkt_buf),
1725*46d2f618SCy Schubert sldns_buffer_limit(c->doq_socket->pkt_buf), c->doq_socket->sv_scidlen);
1726*46d2f618SCy Schubert #endif
1727*46d2f618SCy Schubert if(rv != 0) {
1728*46d2f618SCy Schubert if(rv == NGTCP2_ERR_VERSION_NEGOTIATION) {
1729*46d2f618SCy Schubert /* send the version negotiation */
1730*46d2f618SCy Schubert doq_send_version_negotiation(c, paddr,
1731*46d2f618SCy Schubert #ifdef HAVE_STRUCT_NGTCP2_VERSION_CID
1732*46d2f618SCy Schubert vc.scid, vc.scidlen, vc.dcid, vc.dcidlen
1733*46d2f618SCy Schubert #else
1734*46d2f618SCy Schubert scid, scidlen, dcid, dcidlen
1735*46d2f618SCy Schubert #endif
1736*46d2f618SCy Schubert );
1737*46d2f618SCy Schubert return 0;
1738*46d2f618SCy Schubert }
1739*46d2f618SCy Schubert verbose(VERB_ALGO, "doq: could not decode version "
1740*46d2f618SCy Schubert "and CID from QUIC packet header: %s",
1741*46d2f618SCy Schubert ngtcp2_strerror(rv));
1742*46d2f618SCy Schubert return 0;
1743*46d2f618SCy Schubert }
1744*46d2f618SCy Schubert
1745*46d2f618SCy Schubert if(verbosity >= VERB_ALGO) {
1746*46d2f618SCy Schubert verbose(VERB_ALGO, "ngtcp2_pkt_decode_version_cid packet has "
1747*46d2f618SCy Schubert "QUIC protocol version %u", (unsigned)
1748*46d2f618SCy Schubert #ifdef HAVE_STRUCT_NGTCP2_VERSION_CID
1749*46d2f618SCy Schubert vc.
1750*46d2f618SCy Schubert #endif
1751*46d2f618SCy Schubert version
1752*46d2f618SCy Schubert );
1753*46d2f618SCy Schubert log_hex("dcid",
1754*46d2f618SCy Schubert #ifdef HAVE_STRUCT_NGTCP2_VERSION_CID
1755*46d2f618SCy Schubert (void*)vc.dcid, vc.dcidlen
1756*46d2f618SCy Schubert #else
1757*46d2f618SCy Schubert (void*)dcid, dcidlen
1758*46d2f618SCy Schubert #endif
1759*46d2f618SCy Schubert );
1760*46d2f618SCy Schubert log_hex("scid",
1761*46d2f618SCy Schubert #ifdef HAVE_STRUCT_NGTCP2_VERSION_CID
1762*46d2f618SCy Schubert (void*)vc.scid, vc.scidlen
1763*46d2f618SCy Schubert #else
1764*46d2f618SCy Schubert (void*)scid, scidlen
1765*46d2f618SCy Schubert #endif
1766*46d2f618SCy Schubert );
1767*46d2f618SCy Schubert }
1768*46d2f618SCy Schubert *conn = doq_conn_find_by_addr_or_cid(c->doq_socket->table, paddr,
1769*46d2f618SCy Schubert #ifdef HAVE_STRUCT_NGTCP2_VERSION_CID
1770*46d2f618SCy Schubert vc.dcid, vc.dcidlen
1771*46d2f618SCy Schubert #else
1772*46d2f618SCy Schubert dcid, dcidlen
1773*46d2f618SCy Schubert #endif
1774*46d2f618SCy Schubert );
1775*46d2f618SCy Schubert if(*conn)
1776*46d2f618SCy Schubert (*conn)->doq_socket = c->doq_socket;
1777*46d2f618SCy Schubert return 1;
1778*46d2f618SCy Schubert }
1779*46d2f618SCy Schubert
1780*46d2f618SCy Schubert /** fill cid structure with random data */
1781*46d2f618SCy Schubert static void doq_cid_randfill(struct ngtcp2_cid* cid, size_t datalen,
1782*46d2f618SCy Schubert struct ub_randstate* rnd)
1783*46d2f618SCy Schubert {
1784*46d2f618SCy Schubert uint8_t buf[32];
1785*46d2f618SCy Schubert if(datalen > sizeof(buf))
1786*46d2f618SCy Schubert datalen = sizeof(buf);
1787*46d2f618SCy Schubert doq_fill_rand(rnd, buf, datalen);
1788*46d2f618SCy Schubert ngtcp2_cid_init(cid, buf, datalen);
1789*46d2f618SCy Schubert }
1790*46d2f618SCy Schubert
1791*46d2f618SCy Schubert /** send retry packet for doq connection. */
1792*46d2f618SCy Schubert static void
1793*46d2f618SCy Schubert doq_send_retry(struct comm_point* c, struct doq_pkt_addr* paddr,
1794*46d2f618SCy Schubert struct ngtcp2_pkt_hd* hd)
1795*46d2f618SCy Schubert {
1796*46d2f618SCy Schubert char host[256], port[32];
1797*46d2f618SCy Schubert struct ngtcp2_cid scid;
1798*46d2f618SCy Schubert uint8_t token[NGTCP2_CRYPTO_MAX_RETRY_TOKENLEN];
1799*46d2f618SCy Schubert ngtcp2_tstamp ts;
1800*46d2f618SCy Schubert ngtcp2_ssize tokenlen, ret;
1801*46d2f618SCy Schubert
1802*46d2f618SCy Schubert if(!doq_print_addr_port(&paddr->addr, paddr->addrlen, host,
1803*46d2f618SCy Schubert sizeof(host), port, sizeof(port))) {
1804*46d2f618SCy Schubert log_err("doq_send_retry failed");
1805*46d2f618SCy Schubert return;
1806*46d2f618SCy Schubert }
1807*46d2f618SCy Schubert verbose(VERB_ALGO, "doq: sending retry packet to %s %s", host, port);
1808*46d2f618SCy Schubert
1809*46d2f618SCy Schubert /* the server chosen source connection ID */
1810*46d2f618SCy Schubert scid.datalen = c->doq_socket->sv_scidlen;
1811*46d2f618SCy Schubert doq_cid_randfill(&scid, scid.datalen, c->doq_socket->rnd);
1812*46d2f618SCy Schubert
1813*46d2f618SCy Schubert ts = doq_get_timestamp_nanosec();
1814*46d2f618SCy Schubert
1815*46d2f618SCy Schubert tokenlen = ngtcp2_crypto_generate_retry_token(token,
1816*46d2f618SCy Schubert c->doq_socket->static_secret, c->doq_socket->static_secret_len,
1817*46d2f618SCy Schubert hd->version, (void*)&paddr->addr, paddr->addrlen, &scid,
1818*46d2f618SCy Schubert &hd->dcid, ts);
1819*46d2f618SCy Schubert if(tokenlen < 0) {
1820*46d2f618SCy Schubert log_err("ngtcp2_crypto_generate_retry_token failed: %s",
1821*46d2f618SCy Schubert ngtcp2_strerror(tokenlen));
1822*46d2f618SCy Schubert return;
1823*46d2f618SCy Schubert }
1824*46d2f618SCy Schubert
1825*46d2f618SCy Schubert sldns_buffer_clear(c->doq_socket->pkt_buf);
1826*46d2f618SCy Schubert ret = ngtcp2_crypto_write_retry(sldns_buffer_begin(c->doq_socket->pkt_buf),
1827*46d2f618SCy Schubert sldns_buffer_capacity(c->doq_socket->pkt_buf), hd->version,
1828*46d2f618SCy Schubert &hd->scid, &scid, &hd->dcid, token, tokenlen);
1829*46d2f618SCy Schubert if(ret < 0) {
1830*46d2f618SCy Schubert log_err("ngtcp2_crypto_write_retry failed: %s",
1831*46d2f618SCy Schubert ngtcp2_strerror(ret));
1832*46d2f618SCy Schubert return;
1833*46d2f618SCy Schubert }
1834*46d2f618SCy Schubert sldns_buffer_set_position(c->doq_socket->pkt_buf, ret);
1835*46d2f618SCy Schubert sldns_buffer_flip(c->doq_socket->pkt_buf);
1836*46d2f618SCy Schubert doq_send_pkt(c, paddr, 0);
1837*46d2f618SCy Schubert }
1838*46d2f618SCy Schubert
1839*46d2f618SCy Schubert /** doq send stateless connection close */
1840*46d2f618SCy Schubert static void
1841*46d2f618SCy Schubert doq_send_stateless_connection_close(struct comm_point* c,
1842*46d2f618SCy Schubert struct doq_pkt_addr* paddr, struct ngtcp2_pkt_hd* hd,
1843*46d2f618SCy Schubert uint64_t error_code)
1844*46d2f618SCy Schubert {
1845*46d2f618SCy Schubert ngtcp2_ssize ret;
1846*46d2f618SCy Schubert sldns_buffer_clear(c->doq_socket->pkt_buf);
1847*46d2f618SCy Schubert ret = ngtcp2_crypto_write_connection_close(
1848*46d2f618SCy Schubert sldns_buffer_begin(c->doq_socket->pkt_buf),
1849*46d2f618SCy Schubert sldns_buffer_capacity(c->doq_socket->pkt_buf), hd->version, &hd->scid,
1850*46d2f618SCy Schubert &hd->dcid, error_code, NULL, 0);
1851*46d2f618SCy Schubert if(ret < 0) {
1852*46d2f618SCy Schubert log_err("ngtcp2_crypto_write_connection_close failed: %s",
1853*46d2f618SCy Schubert ngtcp2_strerror(ret));
1854*46d2f618SCy Schubert return;
1855*46d2f618SCy Schubert }
1856*46d2f618SCy Schubert sldns_buffer_set_position(c->doq_socket->pkt_buf, ret);
1857*46d2f618SCy Schubert sldns_buffer_flip(c->doq_socket->pkt_buf);
1858*46d2f618SCy Schubert doq_send_pkt(c, paddr, 0);
1859*46d2f618SCy Schubert }
1860*46d2f618SCy Schubert
1861*46d2f618SCy Schubert /** doq verify retry token, false on failure */
1862*46d2f618SCy Schubert static int
1863*46d2f618SCy Schubert doq_verify_retry_token(struct comm_point* c, struct doq_pkt_addr* paddr,
1864*46d2f618SCy Schubert struct ngtcp2_cid* ocid, struct ngtcp2_pkt_hd* hd)
1865*46d2f618SCy Schubert {
1866*46d2f618SCy Schubert char host[256], port[32];
1867*46d2f618SCy Schubert ngtcp2_tstamp ts;
1868*46d2f618SCy Schubert if(!doq_print_addr_port(&paddr->addr, paddr->addrlen, host,
1869*46d2f618SCy Schubert sizeof(host), port, sizeof(port))) {
1870*46d2f618SCy Schubert log_err("doq_verify_retry_token failed");
1871*46d2f618SCy Schubert return 0;
1872*46d2f618SCy Schubert }
1873*46d2f618SCy Schubert ts = doq_get_timestamp_nanosec();
1874*46d2f618SCy Schubert verbose(VERB_ALGO, "doq: verifying retry token from %s %s", host,
1875*46d2f618SCy Schubert port);
1876*46d2f618SCy Schubert if(ngtcp2_crypto_verify_retry_token(ocid,
1877*46d2f618SCy Schubert #ifdef HAVE_STRUCT_NGTCP2_PKT_HD_TOKENLEN
1878*46d2f618SCy Schubert hd->token, hd->tokenlen,
1879*46d2f618SCy Schubert #else
1880*46d2f618SCy Schubert hd->token.base, hd->token.len,
1881*46d2f618SCy Schubert #endif
1882*46d2f618SCy Schubert c->doq_socket->static_secret,
1883*46d2f618SCy Schubert c->doq_socket->static_secret_len, hd->version,
1884*46d2f618SCy Schubert (void*)&paddr->addr, paddr->addrlen, &hd->dcid,
1885*46d2f618SCy Schubert 10*NGTCP2_SECONDS, ts) != 0) {
1886*46d2f618SCy Schubert verbose(VERB_ALGO, "doq: could not verify retry token "
1887*46d2f618SCy Schubert "from %s %s", host, port);
1888*46d2f618SCy Schubert return 0;
1889*46d2f618SCy Schubert }
1890*46d2f618SCy Schubert verbose(VERB_ALGO, "doq: verified retry token from %s %s", host, port);
1891*46d2f618SCy Schubert return 1;
1892*46d2f618SCy Schubert }
1893*46d2f618SCy Schubert
1894*46d2f618SCy Schubert /** doq verify token, false on failure */
1895*46d2f618SCy Schubert static int
1896*46d2f618SCy Schubert doq_verify_token(struct comm_point* c, struct doq_pkt_addr* paddr,
1897*46d2f618SCy Schubert struct ngtcp2_pkt_hd* hd)
1898*46d2f618SCy Schubert {
1899*46d2f618SCy Schubert char host[256], port[32];
1900*46d2f618SCy Schubert ngtcp2_tstamp ts;
1901*46d2f618SCy Schubert if(!doq_print_addr_port(&paddr->addr, paddr->addrlen, host,
1902*46d2f618SCy Schubert sizeof(host), port, sizeof(port))) {
1903*46d2f618SCy Schubert log_err("doq_verify_token failed");
1904*46d2f618SCy Schubert return 0;
1905*46d2f618SCy Schubert }
1906*46d2f618SCy Schubert ts = doq_get_timestamp_nanosec();
1907*46d2f618SCy Schubert verbose(VERB_ALGO, "doq: verifying token from %s %s", host, port);
1908*46d2f618SCy Schubert if(ngtcp2_crypto_verify_regular_token(
1909*46d2f618SCy Schubert #ifdef HAVE_STRUCT_NGTCP2_PKT_HD_TOKENLEN
1910*46d2f618SCy Schubert hd->token, hd->tokenlen,
1911*46d2f618SCy Schubert #else
1912*46d2f618SCy Schubert hd->token.base, hd->token.len,
1913*46d2f618SCy Schubert #endif
1914*46d2f618SCy Schubert c->doq_socket->static_secret, c->doq_socket->static_secret_len,
1915*46d2f618SCy Schubert (void*)&paddr->addr, paddr->addrlen, 3600*NGTCP2_SECONDS,
1916*46d2f618SCy Schubert ts) != 0) {
1917*46d2f618SCy Schubert verbose(VERB_ALGO, "doq: could not verify token from %s %s",
1918*46d2f618SCy Schubert host, port);
1919*46d2f618SCy Schubert return 0;
1920*46d2f618SCy Schubert }
1921*46d2f618SCy Schubert verbose(VERB_ALGO, "doq: verified token from %s %s", host, port);
1922*46d2f618SCy Schubert return 1;
1923*46d2f618SCy Schubert }
1924*46d2f618SCy Schubert
1925*46d2f618SCy Schubert /** delete and remove from the lookup tree the doq_conn connection */
1926*46d2f618SCy Schubert static void
1927*46d2f618SCy Schubert doq_delete_connection(struct comm_point* c, struct doq_conn* conn)
1928*46d2f618SCy Schubert {
1929*46d2f618SCy Schubert struct doq_conn copy;
1930*46d2f618SCy Schubert uint8_t cid[NGTCP2_MAX_CIDLEN];
1931*46d2f618SCy Schubert rbnode_type* node;
1932*46d2f618SCy Schubert if(!conn)
1933*46d2f618SCy Schubert return;
1934*46d2f618SCy Schubert /* Copy the key and set it deleted. */
1935*46d2f618SCy Schubert conn->is_deleted = 1;
1936*46d2f618SCy Schubert doq_conn_write_disable(conn);
1937*46d2f618SCy Schubert copy.key = conn->key;
1938*46d2f618SCy Schubert log_assert(conn->key.dcidlen <= NGTCP2_MAX_CIDLEN);
1939*46d2f618SCy Schubert memcpy(cid, conn->key.dcid, conn->key.dcidlen);
1940*46d2f618SCy Schubert copy.key.dcid = cid;
1941*46d2f618SCy Schubert copy.node.key = ©
1942*46d2f618SCy Schubert lock_basic_unlock(&conn->lock);
1943*46d2f618SCy Schubert
1944*46d2f618SCy Schubert /* Now get the table lock to delete it from the tree */
1945*46d2f618SCy Schubert lock_rw_wrlock(&c->doq_socket->table->lock);
1946*46d2f618SCy Schubert node = rbtree_delete(c->doq_socket->table->conn_tree, copy.node.key);
1947*46d2f618SCy Schubert if(node) {
1948*46d2f618SCy Schubert conn = (struct doq_conn*)node->key;
1949*46d2f618SCy Schubert lock_basic_lock(&conn->lock);
1950*46d2f618SCy Schubert doq_conn_write_list_remove(c->doq_socket->table, conn);
1951*46d2f618SCy Schubert if(conn->timer.timer_in_list) {
1952*46d2f618SCy Schubert /* Remove timer from list first, because finding the
1953*46d2f618SCy Schubert * rbnode element of the setlist of same timeouts
1954*46d2f618SCy Schubert * needs tree lookup. Edit the tree structure after
1955*46d2f618SCy Schubert * that lookup. */
1956*46d2f618SCy Schubert doq_timer_list_remove(c->doq_socket->table,
1957*46d2f618SCy Schubert &conn->timer);
1958*46d2f618SCy Schubert }
1959*46d2f618SCy Schubert if(conn->timer.timer_in_tree)
1960*46d2f618SCy Schubert doq_timer_tree_remove(c->doq_socket->table,
1961*46d2f618SCy Schubert &conn->timer);
1962*46d2f618SCy Schubert }
1963*46d2f618SCy Schubert lock_rw_unlock(&c->doq_socket->table->lock);
1964*46d2f618SCy Schubert if(node) {
1965*46d2f618SCy Schubert lock_basic_unlock(&conn->lock);
1966*46d2f618SCy Schubert doq_table_quic_size_subtract(c->doq_socket->table,
1967*46d2f618SCy Schubert sizeof(*conn)+conn->key.dcidlen);
1968*46d2f618SCy Schubert doq_conn_delete(conn, c->doq_socket->table);
1969*46d2f618SCy Schubert }
1970*46d2f618SCy Schubert }
1971*46d2f618SCy Schubert
1972*46d2f618SCy Schubert /** create and setup a new doq connection, to a new destination, or with
1973*46d2f618SCy Schubert * a new dcid. It has a new set of streams. It is inserted in the lookup tree.
1974*46d2f618SCy Schubert * Returns NULL on failure. */
1975*46d2f618SCy Schubert static struct doq_conn*
1976*46d2f618SCy Schubert doq_setup_new_conn(struct comm_point* c, struct doq_pkt_addr* paddr,
1977*46d2f618SCy Schubert struct ngtcp2_pkt_hd* hd, struct ngtcp2_cid* ocid)
1978*46d2f618SCy Schubert {
1979*46d2f618SCy Schubert struct doq_conn* conn;
1980*46d2f618SCy Schubert if(!doq_table_quic_size_available(c->doq_socket->table,
1981*46d2f618SCy Schubert c->doq_socket->cfg, sizeof(*conn)+hd->dcid.datalen
1982*46d2f618SCy Schubert + sizeof(struct doq_stream)
1983*46d2f618SCy Schubert + 100 /* estimated input query */
1984*46d2f618SCy Schubert + 1200 /* estimated output query */)) {
1985*46d2f618SCy Schubert verbose(VERB_ALGO, "doq: no mem available for new connection");
1986*46d2f618SCy Schubert doq_send_stateless_connection_close(c, paddr, hd,
1987*46d2f618SCy Schubert NGTCP2_CONNECTION_REFUSED);
1988*46d2f618SCy Schubert return NULL;
1989*46d2f618SCy Schubert }
1990*46d2f618SCy Schubert conn = doq_conn_create(c, paddr, hd->dcid.data, hd->dcid.datalen,
1991*46d2f618SCy Schubert hd->version);
1992*46d2f618SCy Schubert if(!conn) {
1993*46d2f618SCy Schubert log_err("doq: could not allocate doq_conn");
1994*46d2f618SCy Schubert return NULL;
1995*46d2f618SCy Schubert }
1996*46d2f618SCy Schubert lock_rw_wrlock(&c->doq_socket->table->lock);
1997*46d2f618SCy Schubert lock_basic_lock(&conn->lock);
1998*46d2f618SCy Schubert if(!rbtree_insert(c->doq_socket->table->conn_tree, &conn->node)) {
1999*46d2f618SCy Schubert lock_rw_unlock(&c->doq_socket->table->lock);
2000*46d2f618SCy Schubert log_err("doq: duplicate connection");
2001*46d2f618SCy Schubert /* conn has no entry in writelist, and no timer yet. */
2002*46d2f618SCy Schubert lock_basic_unlock(&conn->lock);
2003*46d2f618SCy Schubert doq_conn_delete(conn, c->doq_socket->table);
2004*46d2f618SCy Schubert return NULL;
2005*46d2f618SCy Schubert }
2006*46d2f618SCy Schubert lock_rw_unlock(&c->doq_socket->table->lock);
2007*46d2f618SCy Schubert doq_table_quic_size_add(c->doq_socket->table,
2008*46d2f618SCy Schubert sizeof(*conn)+conn->key.dcidlen);
2009*46d2f618SCy Schubert verbose(VERB_ALGO, "doq: created new connection");
2010*46d2f618SCy Schubert
2011*46d2f618SCy Schubert /* the scid and dcid switch meaning from the accepted client
2012*46d2f618SCy Schubert * connection to the server connection. The 'source' and 'destination'
2013*46d2f618SCy Schubert * meaning is reversed. */
2014*46d2f618SCy Schubert if(!doq_conn_setup(conn, hd->scid.data, hd->scid.datalen,
2015*46d2f618SCy Schubert (ocid?ocid->data:NULL), (ocid?ocid->datalen:0),
2016*46d2f618SCy Schubert #ifdef HAVE_STRUCT_NGTCP2_PKT_HD_TOKENLEN
2017*46d2f618SCy Schubert hd->token, hd->tokenlen
2018*46d2f618SCy Schubert #else
2019*46d2f618SCy Schubert hd->token.base, hd->token.len
2020*46d2f618SCy Schubert #endif
2021*46d2f618SCy Schubert )) {
2022*46d2f618SCy Schubert log_err("doq: could not set up connection");
2023*46d2f618SCy Schubert doq_delete_connection(c, conn);
2024*46d2f618SCy Schubert return NULL;
2025*46d2f618SCy Schubert }
2026*46d2f618SCy Schubert return conn;
2027*46d2f618SCy Schubert }
2028*46d2f618SCy Schubert
2029*46d2f618SCy Schubert /** perform doq address validation */
2030*46d2f618SCy Schubert static int
2031*46d2f618SCy Schubert doq_address_validation(struct comm_point* c, struct doq_pkt_addr* paddr,
2032*46d2f618SCy Schubert struct ngtcp2_pkt_hd* hd, struct ngtcp2_cid* ocid,
2033*46d2f618SCy Schubert struct ngtcp2_cid** pocid)
2034*46d2f618SCy Schubert {
2035*46d2f618SCy Schubert #ifdef HAVE_STRUCT_NGTCP2_PKT_HD_TOKENLEN
2036*46d2f618SCy Schubert const uint8_t* token = hd->token;
2037*46d2f618SCy Schubert size_t tokenlen = hd->tokenlen;
2038*46d2f618SCy Schubert #else
2039*46d2f618SCy Schubert const uint8_t* token = hd->token.base;
2040*46d2f618SCy Schubert size_t tokenlen = hd->token.len;
2041*46d2f618SCy Schubert #endif
2042*46d2f618SCy Schubert verbose(VERB_ALGO, "doq stateless address validation");
2043*46d2f618SCy Schubert
2044*46d2f618SCy Schubert if(tokenlen == 0 || token == NULL) {
2045*46d2f618SCy Schubert doq_send_retry(c, paddr, hd);
2046*46d2f618SCy Schubert return 0;
2047*46d2f618SCy Schubert }
2048*46d2f618SCy Schubert if(token[0] != NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY &&
2049*46d2f618SCy Schubert hd->dcid.datalen < NGTCP2_MIN_INITIAL_DCIDLEN) {
2050*46d2f618SCy Schubert doq_send_stateless_connection_close(c, paddr, hd,
2051*46d2f618SCy Schubert NGTCP2_INVALID_TOKEN);
2052*46d2f618SCy Schubert return 0;
2053*46d2f618SCy Schubert }
2054*46d2f618SCy Schubert if(token[0] == NGTCP2_CRYPTO_TOKEN_MAGIC_RETRY) {
2055*46d2f618SCy Schubert if(!doq_verify_retry_token(c, paddr, ocid, hd)) {
2056*46d2f618SCy Schubert doq_send_stateless_connection_close(c, paddr, hd,
2057*46d2f618SCy Schubert NGTCP2_INVALID_TOKEN);
2058*46d2f618SCy Schubert return 0;
2059*46d2f618SCy Schubert }
2060*46d2f618SCy Schubert *pocid = ocid;
2061*46d2f618SCy Schubert } else if(token[0] == NGTCP2_CRYPTO_TOKEN_MAGIC_REGULAR) {
2062*46d2f618SCy Schubert if(!doq_verify_token(c, paddr, hd)) {
2063*46d2f618SCy Schubert doq_send_retry(c, paddr, hd);
2064*46d2f618SCy Schubert return 0;
2065*46d2f618SCy Schubert }
2066*46d2f618SCy Schubert #ifdef HAVE_STRUCT_NGTCP2_PKT_HD_TOKENLEN
2067*46d2f618SCy Schubert hd->token = NULL;
2068*46d2f618SCy Schubert hd->tokenlen = 0;
2069*46d2f618SCy Schubert #else
2070*46d2f618SCy Schubert hd->token.base = NULL;
2071*46d2f618SCy Schubert hd->token.len = 0;
2072*46d2f618SCy Schubert #endif
2073*46d2f618SCy Schubert } else {
2074*46d2f618SCy Schubert verbose(VERB_ALGO, "doq address validation: unrecognised "
2075*46d2f618SCy Schubert "token in hd.token.base with magic byte 0x%2.2x",
2076*46d2f618SCy Schubert (int)token[0]);
2077*46d2f618SCy Schubert if(c->doq_socket->validate_addr) {
2078*46d2f618SCy Schubert doq_send_retry(c, paddr, hd);
2079*46d2f618SCy Schubert return 0;
2080*46d2f618SCy Schubert }
2081*46d2f618SCy Schubert #ifdef HAVE_STRUCT_NGTCP2_PKT_HD_TOKENLEN
2082*46d2f618SCy Schubert hd->token = NULL;
2083*46d2f618SCy Schubert hd->tokenlen = 0;
2084*46d2f618SCy Schubert #else
2085*46d2f618SCy Schubert hd->token.base = NULL;
2086*46d2f618SCy Schubert hd->token.len = 0;
2087*46d2f618SCy Schubert #endif
2088*46d2f618SCy Schubert }
2089*46d2f618SCy Schubert return 1;
2090*46d2f618SCy Schubert }
2091*46d2f618SCy Schubert
2092*46d2f618SCy Schubert /** the doq accept, returns false if no further processing of content */
2093*46d2f618SCy Schubert static int
2094*46d2f618SCy Schubert doq_accept(struct comm_point* c, struct doq_pkt_addr* paddr,
2095*46d2f618SCy Schubert struct doq_conn** conn, struct ngtcp2_pkt_info* pi)
2096*46d2f618SCy Schubert {
2097*46d2f618SCy Schubert int rv;
2098*46d2f618SCy Schubert struct ngtcp2_pkt_hd hd;
2099*46d2f618SCy Schubert struct ngtcp2_cid ocid, *pocid=NULL;
2100*46d2f618SCy Schubert int err_retry;
2101*46d2f618SCy Schubert memset(&hd, 0, sizeof(hd));
2102*46d2f618SCy Schubert rv = ngtcp2_accept(&hd, sldns_buffer_begin(c->doq_socket->pkt_buf),
2103*46d2f618SCy Schubert sldns_buffer_limit(c->doq_socket->pkt_buf));
2104*46d2f618SCy Schubert if(rv != 0) {
2105*46d2f618SCy Schubert if(rv == NGTCP2_ERR_RETRY) {
2106*46d2f618SCy Schubert doq_send_retry(c, paddr, &hd);
2107*46d2f618SCy Schubert return 0;
2108*46d2f618SCy Schubert }
2109*46d2f618SCy Schubert log_err("doq: initial packet failed, ngtcp2_accept failed: %s",
2110*46d2f618SCy Schubert ngtcp2_strerror(rv));
2111*46d2f618SCy Schubert return 0;
2112*46d2f618SCy Schubert }
2113*46d2f618SCy Schubert if(c->doq_socket->validate_addr ||
2114*46d2f618SCy Schubert #ifdef HAVE_STRUCT_NGTCP2_PKT_HD_TOKENLEN
2115*46d2f618SCy Schubert hd.tokenlen
2116*46d2f618SCy Schubert #else
2117*46d2f618SCy Schubert hd.token.len
2118*46d2f618SCy Schubert #endif
2119*46d2f618SCy Schubert ) {
2120*46d2f618SCy Schubert if(!doq_address_validation(c, paddr, &hd, &ocid, &pocid))
2121*46d2f618SCy Schubert return 0;
2122*46d2f618SCy Schubert }
2123*46d2f618SCy Schubert *conn = doq_setup_new_conn(c, paddr, &hd, pocid);
2124*46d2f618SCy Schubert if(!*conn)
2125*46d2f618SCy Schubert return 0;
2126*46d2f618SCy Schubert (*conn)->doq_socket = c->doq_socket;
2127*46d2f618SCy Schubert if(!doq_conn_recv(c, paddr, *conn, pi, &err_retry, NULL)) {
2128*46d2f618SCy Schubert if(err_retry)
2129*46d2f618SCy Schubert doq_send_retry(c, paddr, &hd);
2130*46d2f618SCy Schubert doq_delete_connection(c, *conn);
2131*46d2f618SCy Schubert *conn = NULL;
2132*46d2f618SCy Schubert return 0;
2133*46d2f618SCy Schubert }
2134*46d2f618SCy Schubert return 1;
2135*46d2f618SCy Schubert }
2136*46d2f618SCy Schubert
2137*46d2f618SCy Schubert /** doq pickup a timer to wait for for the worker. If any timer exists. */
2138*46d2f618SCy Schubert static void
2139*46d2f618SCy Schubert doq_pickup_timer(struct comm_point* c)
2140*46d2f618SCy Schubert {
2141*46d2f618SCy Schubert struct doq_timer* t;
2142*46d2f618SCy Schubert struct timeval tv;
2143*46d2f618SCy Schubert int have_time = 0;
2144*46d2f618SCy Schubert memset(&tv, 0, sizeof(tv));
2145*46d2f618SCy Schubert
2146*46d2f618SCy Schubert lock_rw_wrlock(&c->doq_socket->table->lock);
2147*46d2f618SCy Schubert RBTREE_FOR(t, struct doq_timer*, c->doq_socket->table->timer_tree) {
2148*46d2f618SCy Schubert if(t->worker_doq_socket == NULL ||
2149*46d2f618SCy Schubert t->worker_doq_socket == c->doq_socket) {
2150*46d2f618SCy Schubert /* pick up this element */
2151*46d2f618SCy Schubert t->worker_doq_socket = c->doq_socket;
2152*46d2f618SCy Schubert have_time = 1;
2153*46d2f618SCy Schubert memcpy(&tv, &t->time, sizeof(tv));
2154*46d2f618SCy Schubert break;
2155*46d2f618SCy Schubert }
2156*46d2f618SCy Schubert }
2157*46d2f618SCy Schubert lock_rw_unlock(&c->doq_socket->table->lock);
2158*46d2f618SCy Schubert
2159*46d2f618SCy Schubert if(have_time) {
2160*46d2f618SCy Schubert struct timeval rel;
2161*46d2f618SCy Schubert timeval_subtract(&rel, &tv, c->doq_socket->now_tv);
2162*46d2f618SCy Schubert comm_timer_set(c->doq_socket->timer, &rel);
2163*46d2f618SCy Schubert memcpy(&c->doq_socket->marked_time, &tv,
2164*46d2f618SCy Schubert sizeof(c->doq_socket->marked_time));
2165*46d2f618SCy Schubert verbose(VERB_ALGO, "doq pickup timer at %d.%6.6d in %d.%6.6d",
2166*46d2f618SCy Schubert (int)tv.tv_sec, (int)tv.tv_usec, (int)rel.tv_sec,
2167*46d2f618SCy Schubert (int)rel.tv_usec);
2168*46d2f618SCy Schubert } else {
2169*46d2f618SCy Schubert if(comm_timer_is_set(c->doq_socket->timer))
2170*46d2f618SCy Schubert comm_timer_disable(c->doq_socket->timer);
2171*46d2f618SCy Schubert memset(&c->doq_socket->marked_time, 0,
2172*46d2f618SCy Schubert sizeof(c->doq_socket->marked_time));
2173*46d2f618SCy Schubert verbose(VERB_ALGO, "doq timer disabled");
2174*46d2f618SCy Schubert }
2175*46d2f618SCy Schubert }
2176*46d2f618SCy Schubert
2177*46d2f618SCy Schubert /** doq done with connection, release locks and setup timer and write */
2178*46d2f618SCy Schubert static void
2179*46d2f618SCy Schubert doq_done_setup_timer_and_write(struct comm_point* c, struct doq_conn* conn)
2180*46d2f618SCy Schubert {
2181*46d2f618SCy Schubert struct doq_conn copy;
2182*46d2f618SCy Schubert uint8_t cid[NGTCP2_MAX_CIDLEN];
2183*46d2f618SCy Schubert rbnode_type* node;
2184*46d2f618SCy Schubert struct timeval new_tv;
2185*46d2f618SCy Schubert int write_change = 0, timer_change = 0;
2186*46d2f618SCy Schubert
2187*46d2f618SCy Schubert /* No longer in callbacks, so the pointer to doq_socket is back
2188*46d2f618SCy Schubert * to NULL. */
2189*46d2f618SCy Schubert conn->doq_socket = NULL;
2190*46d2f618SCy Schubert
2191*46d2f618SCy Schubert if(doq_conn_check_timer(conn, &new_tv))
2192*46d2f618SCy Schubert timer_change = 1;
2193*46d2f618SCy Schubert if( (conn->write_interest && !conn->on_write_list) ||
2194*46d2f618SCy Schubert (!conn->write_interest && conn->on_write_list))
2195*46d2f618SCy Schubert write_change = 1;
2196*46d2f618SCy Schubert
2197*46d2f618SCy Schubert if(!timer_change && !write_change) {
2198*46d2f618SCy Schubert /* Nothing to do. */
2199*46d2f618SCy Schubert lock_basic_unlock(&conn->lock);
2200*46d2f618SCy Schubert return;
2201*46d2f618SCy Schubert }
2202*46d2f618SCy Schubert
2203*46d2f618SCy Schubert /* The table lock is needed to change the write list and timer tree.
2204*46d2f618SCy Schubert * So the connection lock is release and then the connection is
2205*46d2f618SCy Schubert * looked up again. */
2206*46d2f618SCy Schubert copy.key = conn->key;
2207*46d2f618SCy Schubert log_assert(conn->key.dcidlen <= NGTCP2_MAX_CIDLEN);
2208*46d2f618SCy Schubert memcpy(cid, conn->key.dcid, conn->key.dcidlen);
2209*46d2f618SCy Schubert copy.key.dcid = cid;
2210*46d2f618SCy Schubert copy.node.key = ©
2211*46d2f618SCy Schubert lock_basic_unlock(&conn->lock);
2212*46d2f618SCy Schubert
2213*46d2f618SCy Schubert lock_rw_wrlock(&c->doq_socket->table->lock);
2214*46d2f618SCy Schubert node = rbtree_search(c->doq_socket->table->conn_tree, copy.node.key);
2215*46d2f618SCy Schubert if(!node) {
2216*46d2f618SCy Schubert lock_rw_unlock(&c->doq_socket->table->lock);
2217*46d2f618SCy Schubert /* Must have been deleted in the mean time. */
2218*46d2f618SCy Schubert return;
2219*46d2f618SCy Schubert }
2220*46d2f618SCy Schubert conn = (struct doq_conn*)node->key;
2221*46d2f618SCy Schubert lock_basic_lock(&conn->lock);
2222*46d2f618SCy Schubert if(conn->is_deleted) {
2223*46d2f618SCy Schubert /* It is deleted now. */
2224*46d2f618SCy Schubert lock_rw_unlock(&c->doq_socket->table->lock);
2225*46d2f618SCy Schubert lock_basic_unlock(&conn->lock);
2226*46d2f618SCy Schubert return;
2227*46d2f618SCy Schubert }
2228*46d2f618SCy Schubert
2229*46d2f618SCy Schubert if(write_change) {
2230*46d2f618SCy Schubert /* Edit the write lists, we are holding the table.lock and can
2231*46d2f618SCy Schubert * edit the list first,last and also prev,next and on_list
2232*46d2f618SCy Schubert * elements in the doq_conn structures. */
2233*46d2f618SCy Schubert doq_conn_set_write_list(c->doq_socket->table, conn);
2234*46d2f618SCy Schubert }
2235*46d2f618SCy Schubert if(timer_change) {
2236*46d2f618SCy Schubert doq_timer_set(c->doq_socket->table, &conn->timer,
2237*46d2f618SCy Schubert c->doq_socket, &new_tv);
2238*46d2f618SCy Schubert }
2239*46d2f618SCy Schubert lock_rw_unlock(&c->doq_socket->table->lock);
2240*46d2f618SCy Schubert lock_basic_unlock(&conn->lock);
2241*46d2f618SCy Schubert }
2242*46d2f618SCy Schubert
2243*46d2f618SCy Schubert /** doq done with connection callbacks, release locks and setup write */
2244*46d2f618SCy Schubert static void
2245*46d2f618SCy Schubert doq_done_with_conn_cb(struct comm_point* c, struct doq_conn* conn)
2246*46d2f618SCy Schubert {
2247*46d2f618SCy Schubert struct doq_conn copy;
2248*46d2f618SCy Schubert uint8_t cid[NGTCP2_MAX_CIDLEN];
2249*46d2f618SCy Schubert rbnode_type* node;
2250*46d2f618SCy Schubert
2251*46d2f618SCy Schubert /* no longer in callbacks, so the pointer to doq_socket is back
2252*46d2f618SCy Schubert * to NULL. */
2253*46d2f618SCy Schubert conn->doq_socket = NULL;
2254*46d2f618SCy Schubert
2255*46d2f618SCy Schubert if( (conn->write_interest && conn->on_write_list) ||
2256*46d2f618SCy Schubert (!conn->write_interest && !conn->on_write_list)) {
2257*46d2f618SCy Schubert /* The connection already has the required write list
2258*46d2f618SCy Schubert * status. */
2259*46d2f618SCy Schubert lock_basic_unlock(&conn->lock);
2260*46d2f618SCy Schubert return;
2261*46d2f618SCy Schubert }
2262*46d2f618SCy Schubert
2263*46d2f618SCy Schubert /* To edit the write list of connections we have to hold the table
2264*46d2f618SCy Schubert * lock, so we release the connection and then look it up again. */
2265*46d2f618SCy Schubert copy.key = conn->key;
2266*46d2f618SCy Schubert log_assert(conn->key.dcidlen <= NGTCP2_MAX_CIDLEN);
2267*46d2f618SCy Schubert memcpy(cid, conn->key.dcid, conn->key.dcidlen);
2268*46d2f618SCy Schubert copy.key.dcid = cid;
2269*46d2f618SCy Schubert copy.node.key = ©
2270*46d2f618SCy Schubert lock_basic_unlock(&conn->lock);
2271*46d2f618SCy Schubert
2272*46d2f618SCy Schubert lock_rw_wrlock(&c->doq_socket->table->lock);
2273*46d2f618SCy Schubert node = rbtree_search(c->doq_socket->table->conn_tree, copy.node.key);
2274*46d2f618SCy Schubert if(!node) {
2275*46d2f618SCy Schubert lock_rw_unlock(&c->doq_socket->table->lock);
2276*46d2f618SCy Schubert /* must have been deleted in the mean time */
2277*46d2f618SCy Schubert return;
2278*46d2f618SCy Schubert }
2279*46d2f618SCy Schubert conn = (struct doq_conn*)node->key;
2280*46d2f618SCy Schubert lock_basic_lock(&conn->lock);
2281*46d2f618SCy Schubert if(conn->is_deleted) {
2282*46d2f618SCy Schubert /* it is deleted now. */
2283*46d2f618SCy Schubert lock_rw_unlock(&c->doq_socket->table->lock);
2284*46d2f618SCy Schubert lock_basic_unlock(&conn->lock);
2285*46d2f618SCy Schubert return;
2286*46d2f618SCy Schubert }
2287*46d2f618SCy Schubert
2288*46d2f618SCy Schubert /* edit the write lists, we are holding the table.lock and can
2289*46d2f618SCy Schubert * edit the list first,last and also prev,next and on_list elements
2290*46d2f618SCy Schubert * in the doq_conn structures. */
2291*46d2f618SCy Schubert doq_conn_set_write_list(c->doq_socket->table, conn);
2292*46d2f618SCy Schubert lock_rw_unlock(&c->doq_socket->table->lock);
2293*46d2f618SCy Schubert lock_basic_unlock(&conn->lock);
2294*46d2f618SCy Schubert }
2295*46d2f618SCy Schubert
2296*46d2f618SCy Schubert /** doq count the length of the write list */
2297*46d2f618SCy Schubert static size_t
2298*46d2f618SCy Schubert doq_write_list_length(struct comm_point* c)
2299*46d2f618SCy Schubert {
2300*46d2f618SCy Schubert size_t count = 0;
2301*46d2f618SCy Schubert struct doq_conn* conn;
2302*46d2f618SCy Schubert lock_rw_rdlock(&c->doq_socket->table->lock);
2303*46d2f618SCy Schubert conn = c->doq_socket->table->write_list_first;
2304*46d2f618SCy Schubert while(conn) {
2305*46d2f618SCy Schubert count++;
2306*46d2f618SCy Schubert conn = conn->write_next;
2307*46d2f618SCy Schubert }
2308*46d2f618SCy Schubert lock_rw_unlock(&c->doq_socket->table->lock);
2309*46d2f618SCy Schubert return count;
2310*46d2f618SCy Schubert }
2311*46d2f618SCy Schubert
2312*46d2f618SCy Schubert /** doq pop the first element from the write list to have write events */
2313*46d2f618SCy Schubert static struct doq_conn*
2314*46d2f618SCy Schubert doq_pop_write_conn(struct comm_point* c)
2315*46d2f618SCy Schubert {
2316*46d2f618SCy Schubert struct doq_conn* conn;
2317*46d2f618SCy Schubert lock_rw_wrlock(&c->doq_socket->table->lock);
2318*46d2f618SCy Schubert conn = doq_table_pop_first(c->doq_socket->table);
2319*46d2f618SCy Schubert while(conn && conn->is_deleted) {
2320*46d2f618SCy Schubert lock_basic_unlock(&conn->lock);
2321*46d2f618SCy Schubert conn = doq_table_pop_first(c->doq_socket->table);
2322*46d2f618SCy Schubert }
2323*46d2f618SCy Schubert lock_rw_unlock(&c->doq_socket->table->lock);
2324*46d2f618SCy Schubert if(conn)
2325*46d2f618SCy Schubert conn->doq_socket = c->doq_socket;
2326*46d2f618SCy Schubert return conn;
2327*46d2f618SCy Schubert }
2328*46d2f618SCy Schubert
2329*46d2f618SCy Schubert /** doq the connection is done with write callbacks, release it. */
2330*46d2f618SCy Schubert static void
2331*46d2f618SCy Schubert doq_done_with_write_cb(struct comm_point* c, struct doq_conn* conn,
2332*46d2f618SCy Schubert int delete_it)
2333*46d2f618SCy Schubert {
2334*46d2f618SCy Schubert if(delete_it) {
2335*46d2f618SCy Schubert doq_delete_connection(c, conn);
2336*46d2f618SCy Schubert return;
2337*46d2f618SCy Schubert }
2338*46d2f618SCy Schubert doq_done_setup_timer_and_write(c, conn);
2339*46d2f618SCy Schubert }
2340*46d2f618SCy Schubert
2341*46d2f618SCy Schubert /** see if the doq socket wants to write packets */
2342*46d2f618SCy Schubert static int
2343*46d2f618SCy Schubert doq_socket_want_write(struct comm_point* c)
2344*46d2f618SCy Schubert {
2345*46d2f618SCy Schubert int want_write = 0;
2346*46d2f618SCy Schubert if(c->doq_socket->have_blocked_pkt)
2347*46d2f618SCy Schubert return 1;
2348*46d2f618SCy Schubert lock_rw_rdlock(&c->doq_socket->table->lock);
2349*46d2f618SCy Schubert if(c->doq_socket->table->write_list_first)
2350*46d2f618SCy Schubert want_write = 1;
2351*46d2f618SCy Schubert lock_rw_unlock(&c->doq_socket->table->lock);
2352*46d2f618SCy Schubert return want_write;
2353*46d2f618SCy Schubert }
2354*46d2f618SCy Schubert
2355*46d2f618SCy Schubert /** enable write event for the doq server socket fd */
2356*46d2f618SCy Schubert static void
2357*46d2f618SCy Schubert doq_socket_write_enable(struct comm_point* c)
2358*46d2f618SCy Schubert {
2359*46d2f618SCy Schubert verbose(VERB_ALGO, "doq socket want write");
2360*46d2f618SCy Schubert if(c->doq_socket->event_has_write)
2361*46d2f618SCy Schubert return;
2362*46d2f618SCy Schubert comm_point_listen_for_rw(c, 1, 1);
2363*46d2f618SCy Schubert c->doq_socket->event_has_write = 1;
2364*46d2f618SCy Schubert }
2365*46d2f618SCy Schubert
2366*46d2f618SCy Schubert /** disable write event for the doq server socket fd */
2367*46d2f618SCy Schubert static void
2368*46d2f618SCy Schubert doq_socket_write_disable(struct comm_point* c)
2369*46d2f618SCy Schubert {
2370*46d2f618SCy Schubert verbose(VERB_ALGO, "doq socket want no write");
2371*46d2f618SCy Schubert if(!c->doq_socket->event_has_write)
2372*46d2f618SCy Schubert return;
2373*46d2f618SCy Schubert comm_point_listen_for_rw(c, 1, 0);
2374*46d2f618SCy Schubert c->doq_socket->event_has_write = 0;
2375*46d2f618SCy Schubert }
2376*46d2f618SCy Schubert
2377*46d2f618SCy Schubert /** write blocked packet, if possible. returns false if failed, again. */
2378*46d2f618SCy Schubert static int
2379*46d2f618SCy Schubert doq_write_blocked_pkt(struct comm_point* c)
2380*46d2f618SCy Schubert {
2381*46d2f618SCy Schubert struct doq_pkt_addr paddr;
2382*46d2f618SCy Schubert if(!c->doq_socket->have_blocked_pkt)
2383*46d2f618SCy Schubert return 1;
2384*46d2f618SCy Schubert c->doq_socket->have_blocked_pkt = 0;
2385*46d2f618SCy Schubert if(sldns_buffer_limit(c->doq_socket->blocked_pkt) >
2386*46d2f618SCy Schubert sldns_buffer_remaining(c->doq_socket->pkt_buf))
2387*46d2f618SCy Schubert return 1; /* impossibly large, drop it.
2388*46d2f618SCy Schubert impossible since pkt_buf is same size as blocked_pkt buf. */
2389*46d2f618SCy Schubert sldns_buffer_clear(c->doq_socket->pkt_buf);
2390*46d2f618SCy Schubert sldns_buffer_write(c->doq_socket->pkt_buf,
2391*46d2f618SCy Schubert sldns_buffer_begin(c->doq_socket->blocked_pkt),
2392*46d2f618SCy Schubert sldns_buffer_limit(c->doq_socket->blocked_pkt));
2393*46d2f618SCy Schubert sldns_buffer_flip(c->doq_socket->pkt_buf);
2394*46d2f618SCy Schubert memcpy(&paddr, c->doq_socket->blocked_paddr, sizeof(paddr));
2395*46d2f618SCy Schubert doq_send_pkt(c, &paddr, c->doq_socket->blocked_pkt_pi.ecn);
2396*46d2f618SCy Schubert if(c->doq_socket->have_blocked_pkt)
2397*46d2f618SCy Schubert return 0;
2398*46d2f618SCy Schubert return 1;
2399*46d2f618SCy Schubert }
2400*46d2f618SCy Schubert
2401*46d2f618SCy Schubert /** doq find a timer that timeouted and return the conn, locked. */
2402*46d2f618SCy Schubert static struct doq_conn*
2403*46d2f618SCy Schubert doq_timer_timeout_conn(struct doq_server_socket* doq_socket)
2404*46d2f618SCy Schubert {
2405*46d2f618SCy Schubert struct doq_conn* conn = NULL;
2406*46d2f618SCy Schubert struct rbnode_type* node;
2407*46d2f618SCy Schubert lock_rw_wrlock(&doq_socket->table->lock);
2408*46d2f618SCy Schubert node = rbtree_first(doq_socket->table->timer_tree);
2409*46d2f618SCy Schubert if(node && node != RBTREE_NULL) {
2410*46d2f618SCy Schubert struct doq_timer* t = (struct doq_timer*)node;
2411*46d2f618SCy Schubert conn = t->conn;
2412*46d2f618SCy Schubert
2413*46d2f618SCy Schubert /* If now < timer then no further timeouts in tree. */
2414*46d2f618SCy Schubert if(timeval_smaller(doq_socket->now_tv, &t->time)) {
2415*46d2f618SCy Schubert lock_rw_unlock(&doq_socket->table->lock);
2416*46d2f618SCy Schubert return NULL;
2417*46d2f618SCy Schubert }
2418*46d2f618SCy Schubert
2419*46d2f618SCy Schubert lock_basic_lock(&conn->lock);
2420*46d2f618SCy Schubert conn->doq_socket = doq_socket;
2421*46d2f618SCy Schubert
2422*46d2f618SCy Schubert /* Now that the timer is fired, remove it. */
2423*46d2f618SCy Schubert doq_timer_unset(doq_socket->table, t);
2424*46d2f618SCy Schubert lock_rw_unlock(&doq_socket->table->lock);
2425*46d2f618SCy Schubert return conn;
2426*46d2f618SCy Schubert }
2427*46d2f618SCy Schubert lock_rw_unlock(&doq_socket->table->lock);
2428*46d2f618SCy Schubert return NULL;
2429*46d2f618SCy Schubert }
2430*46d2f618SCy Schubert
2431*46d2f618SCy Schubert /** doq timer erase the marker that said which timer the worker uses. */
2432*46d2f618SCy Schubert static void
2433*46d2f618SCy Schubert doq_timer_erase_marker(struct doq_server_socket* doq_socket)
2434*46d2f618SCy Schubert {
2435*46d2f618SCy Schubert struct doq_timer* t;
2436*46d2f618SCy Schubert lock_rw_wrlock(&doq_socket->table->lock);
2437*46d2f618SCy Schubert t = doq_timer_find_time(doq_socket->table, &doq_socket->marked_time);
2438*46d2f618SCy Schubert if(t && t->worker_doq_socket == doq_socket)
2439*46d2f618SCy Schubert t->worker_doq_socket = NULL;
2440*46d2f618SCy Schubert lock_rw_unlock(&doq_socket->table->lock);
2441*46d2f618SCy Schubert memset(&doq_socket->marked_time, 0, sizeof(doq_socket->marked_time));
2442*46d2f618SCy Schubert }
2443*46d2f618SCy Schubert
2444*46d2f618SCy Schubert void
2445*46d2f618SCy Schubert doq_timer_cb(void* arg)
2446*46d2f618SCy Schubert {
2447*46d2f618SCy Schubert struct doq_server_socket* doq_socket = (struct doq_server_socket*)arg;
2448*46d2f618SCy Schubert struct doq_conn* conn;
2449*46d2f618SCy Schubert verbose(VERB_ALGO, "doq timer callback");
2450*46d2f618SCy Schubert
2451*46d2f618SCy Schubert doq_timer_erase_marker(doq_socket);
2452*46d2f618SCy Schubert
2453*46d2f618SCy Schubert while((conn = doq_timer_timeout_conn(doq_socket)) != NULL) {
2454*46d2f618SCy Schubert if(conn->is_deleted ||
2455*46d2f618SCy Schubert #ifdef HAVE_NGTCP2_CONN_IN_CLOSING_PERIOD
2456*46d2f618SCy Schubert ngtcp2_conn_in_closing_period(conn->conn) ||
2457*46d2f618SCy Schubert #else
2458*46d2f618SCy Schubert ngtcp2_conn_is_in_closing_period(conn->conn) ||
2459*46d2f618SCy Schubert #endif
2460*46d2f618SCy Schubert #ifdef HAVE_NGTCP2_CONN_IN_DRAINING_PERIOD
2461*46d2f618SCy Schubert ngtcp2_conn_in_draining_period(conn->conn)
2462*46d2f618SCy Schubert #else
2463*46d2f618SCy Schubert ngtcp2_conn_is_in_draining_period(conn->conn)
2464*46d2f618SCy Schubert #endif
2465*46d2f618SCy Schubert ) {
2466*46d2f618SCy Schubert if(verbosity >= VERB_ALGO) {
2467*46d2f618SCy Schubert char remotestr[256];
2468*46d2f618SCy Schubert addr_to_str((void*)&conn->key.paddr.addr,
2469*46d2f618SCy Schubert conn->key.paddr.addrlen, remotestr,
2470*46d2f618SCy Schubert sizeof(remotestr));
2471*46d2f618SCy Schubert verbose(VERB_ALGO, "doq conn %s is deleted "
2472*46d2f618SCy Schubert "after timeout", remotestr);
2473*46d2f618SCy Schubert }
2474*46d2f618SCy Schubert doq_delete_connection(doq_socket->cp, conn);
2475*46d2f618SCy Schubert continue;
2476*46d2f618SCy Schubert }
2477*46d2f618SCy Schubert if(!doq_conn_handle_timeout(conn))
2478*46d2f618SCy Schubert doq_delete_connection(doq_socket->cp, conn);
2479*46d2f618SCy Schubert else doq_done_setup_timer_and_write(doq_socket->cp, conn);
2480*46d2f618SCy Schubert }
2481*46d2f618SCy Schubert
2482*46d2f618SCy Schubert if(doq_socket_want_write(doq_socket->cp))
2483*46d2f618SCy Schubert doq_socket_write_enable(doq_socket->cp);
2484*46d2f618SCy Schubert else doq_socket_write_disable(doq_socket->cp);
2485*46d2f618SCy Schubert doq_pickup_timer(doq_socket->cp);
2486*46d2f618SCy Schubert }
2487*46d2f618SCy Schubert
2488*46d2f618SCy Schubert void
2489*46d2f618SCy Schubert comm_point_doq_callback(int fd, short event, void* arg)
2490*46d2f618SCy Schubert {
2491*46d2f618SCy Schubert struct comm_point* c;
2492*46d2f618SCy Schubert struct doq_pkt_addr paddr;
2493*46d2f618SCy Schubert int i, pkt_continue, err_drop;
2494*46d2f618SCy Schubert struct doq_conn* conn;
2495*46d2f618SCy Schubert struct ngtcp2_pkt_info pi;
2496*46d2f618SCy Schubert size_t count, num_len;
2497*46d2f618SCy Schubert
2498*46d2f618SCy Schubert c = (struct comm_point*)arg;
2499*46d2f618SCy Schubert log_assert(c->type == comm_doq);
2500*46d2f618SCy Schubert
2501*46d2f618SCy Schubert log_assert(c && c->doq_socket->pkt_buf && c->fd == fd);
2502*46d2f618SCy Schubert ub_comm_base_now(c->ev->base);
2503*46d2f618SCy Schubert
2504*46d2f618SCy Schubert /* see if there is a blocked packet, and send that if possible.
2505*46d2f618SCy Schubert * do not attempt to read yet, even if possible, that would just
2506*46d2f618SCy Schubert * push more answers in reply to those read packets onto the list
2507*46d2f618SCy Schubert * of written replies. First attempt to clear the write content out.
2508*46d2f618SCy Schubert * That keeps the memory usage from bloating up. */
2509*46d2f618SCy Schubert if(c->doq_socket->have_blocked_pkt) {
2510*46d2f618SCy Schubert if(!doq_write_blocked_pkt(c)) {
2511*46d2f618SCy Schubert /* this write has also blocked, attempt to write
2512*46d2f618SCy Schubert * later. Make sure the event listens to write
2513*46d2f618SCy Schubert * events. */
2514*46d2f618SCy Schubert if(!c->doq_socket->event_has_write)
2515*46d2f618SCy Schubert doq_socket_write_enable(c);
2516*46d2f618SCy Schubert doq_pickup_timer(c);
2517*46d2f618SCy Schubert return;
2518*46d2f618SCy Schubert }
2519*46d2f618SCy Schubert }
2520*46d2f618SCy Schubert
2521*46d2f618SCy Schubert /* see if there is write interest */
2522*46d2f618SCy Schubert count = 0;
2523*46d2f618SCy Schubert num_len = doq_write_list_length(c);
2524*46d2f618SCy Schubert while((conn = doq_pop_write_conn(c)) != NULL) {
2525*46d2f618SCy Schubert if(conn->is_deleted ||
2526*46d2f618SCy Schubert #ifdef HAVE_NGTCP2_CONN_IN_CLOSING_PERIOD
2527*46d2f618SCy Schubert ngtcp2_conn_in_closing_period(conn->conn) ||
2528*46d2f618SCy Schubert #else
2529*46d2f618SCy Schubert ngtcp2_conn_is_in_closing_period(conn->conn) ||
2530*46d2f618SCy Schubert #endif
2531*46d2f618SCy Schubert #ifdef HAVE_NGTCP2_CONN_IN_DRAINING_PERIOD
2532*46d2f618SCy Schubert ngtcp2_conn_in_draining_period(conn->conn)
2533*46d2f618SCy Schubert #else
2534*46d2f618SCy Schubert ngtcp2_conn_is_in_draining_period(conn->conn)
2535*46d2f618SCy Schubert #endif
2536*46d2f618SCy Schubert ) {
2537*46d2f618SCy Schubert conn->doq_socket = NULL;
2538*46d2f618SCy Schubert lock_basic_unlock(&conn->lock);
2539*46d2f618SCy Schubert if(c->doq_socket->have_blocked_pkt) {
2540*46d2f618SCy Schubert if(!c->doq_socket->event_has_write)
2541*46d2f618SCy Schubert doq_socket_write_enable(c);
2542*46d2f618SCy Schubert doq_pickup_timer(c);
2543*46d2f618SCy Schubert return;
2544*46d2f618SCy Schubert }
2545*46d2f618SCy Schubert if(++count > num_len*2)
2546*46d2f618SCy Schubert break;
2547*46d2f618SCy Schubert continue;
2548*46d2f618SCy Schubert }
2549*46d2f618SCy Schubert if(verbosity >= VERB_ALGO) {
2550*46d2f618SCy Schubert char remotestr[256];
2551*46d2f618SCy Schubert addr_to_str((void*)&conn->key.paddr.addr,
2552*46d2f618SCy Schubert conn->key.paddr.addrlen, remotestr,
2553*46d2f618SCy Schubert sizeof(remotestr));
2554*46d2f618SCy Schubert verbose(VERB_ALGO, "doq write connection %s %d",
2555*46d2f618SCy Schubert remotestr, doq_sockaddr_get_port(
2556*46d2f618SCy Schubert &conn->key.paddr.addr));
2557*46d2f618SCy Schubert }
2558*46d2f618SCy Schubert if(doq_conn_write_streams(c, conn, &err_drop))
2559*46d2f618SCy Schubert err_drop = 0;
2560*46d2f618SCy Schubert doq_done_with_write_cb(c, conn, err_drop);
2561*46d2f618SCy Schubert if(c->doq_socket->have_blocked_pkt) {
2562*46d2f618SCy Schubert if(!c->doq_socket->event_has_write)
2563*46d2f618SCy Schubert doq_socket_write_enable(c);
2564*46d2f618SCy Schubert doq_pickup_timer(c);
2565*46d2f618SCy Schubert return;
2566*46d2f618SCy Schubert }
2567*46d2f618SCy Schubert /* Stop overly long write lists that are created
2568*46d2f618SCy Schubert * while we are processing. Do those next time there
2569*46d2f618SCy Schubert * is a write callback. Stops long loops, and keeps
2570*46d2f618SCy Schubert * fair for other events. */
2571*46d2f618SCy Schubert if(++count > num_len*2)
2572*46d2f618SCy Schubert break;
2573*46d2f618SCy Schubert }
2574*46d2f618SCy Schubert
2575*46d2f618SCy Schubert /* check for data to read */
2576*46d2f618SCy Schubert if((event&UB_EV_READ)!=0)
2577*46d2f618SCy Schubert for(i=0; i<NUM_UDP_PER_SELECT; i++) {
2578*46d2f618SCy Schubert /* there may be a blocked write packet and if so, stop
2579*46d2f618SCy Schubert * reading because the reply cannot get written. The
2580*46d2f618SCy Schubert * blocked packet could be written during the conn_recv
2581*46d2f618SCy Schubert * handling of replies, or for a connection close. */
2582*46d2f618SCy Schubert if(c->doq_socket->have_blocked_pkt) {
2583*46d2f618SCy Schubert if(!c->doq_socket->event_has_write)
2584*46d2f618SCy Schubert doq_socket_write_enable(c);
2585*46d2f618SCy Schubert doq_pickup_timer(c);
2586*46d2f618SCy Schubert return;
2587*46d2f618SCy Schubert }
2588*46d2f618SCy Schubert sldns_buffer_clear(c->doq_socket->pkt_buf);
2589*46d2f618SCy Schubert doq_pkt_addr_init(&paddr);
2590*46d2f618SCy Schubert log_assert(fd != -1);
2591*46d2f618SCy Schubert log_assert(sldns_buffer_remaining(c->doq_socket->pkt_buf) > 0);
2592*46d2f618SCy Schubert if(!doq_recv(c, &paddr, &pkt_continue, &pi)) {
2593*46d2f618SCy Schubert if(pkt_continue)
2594*46d2f618SCy Schubert continue;
2595*46d2f618SCy Schubert break;
2596*46d2f618SCy Schubert }
2597*46d2f618SCy Schubert
2598*46d2f618SCy Schubert /* handle incoming packet from remote addr to localaddr */
2599*46d2f618SCy Schubert if(verbosity >= VERB_ALGO) {
2600*46d2f618SCy Schubert char remotestr[256], localstr[256];
2601*46d2f618SCy Schubert addr_to_str((void*)&paddr.addr, paddr.addrlen,
2602*46d2f618SCy Schubert remotestr, sizeof(remotestr));
2603*46d2f618SCy Schubert addr_to_str((void*)&paddr.localaddr,
2604*46d2f618SCy Schubert paddr.localaddrlen, localstr,
2605*46d2f618SCy Schubert sizeof(localstr));
2606*46d2f618SCy Schubert log_info("incoming doq packet from %s port %d on "
2607*46d2f618SCy Schubert "%s port %d ifindex %d",
2608*46d2f618SCy Schubert remotestr, doq_sockaddr_get_port(&paddr.addr),
2609*46d2f618SCy Schubert localstr,
2610*46d2f618SCy Schubert doq_sockaddr_get_port(&paddr.localaddr),
2611*46d2f618SCy Schubert paddr.ifindex);
2612*46d2f618SCy Schubert log_info("doq_recv length %d ecn 0x%x",
2613*46d2f618SCy Schubert (int)sldns_buffer_limit(c->doq_socket->pkt_buf),
2614*46d2f618SCy Schubert (int)pi.ecn);
2615*46d2f618SCy Schubert }
2616*46d2f618SCy Schubert
2617*46d2f618SCy Schubert if(sldns_buffer_limit(c->doq_socket->pkt_buf) == 0)
2618*46d2f618SCy Schubert continue;
2619*46d2f618SCy Schubert
2620*46d2f618SCy Schubert conn = NULL;
2621*46d2f618SCy Schubert if(!doq_decode_pkt_header_negotiate(c, &paddr, &conn))
2622*46d2f618SCy Schubert continue;
2623*46d2f618SCy Schubert if(!conn) {
2624*46d2f618SCy Schubert if(!doq_accept(c, &paddr, &conn, &pi))
2625*46d2f618SCy Schubert continue;
2626*46d2f618SCy Schubert if(!doq_conn_write_streams(c, conn, NULL)) {
2627*46d2f618SCy Schubert doq_delete_connection(c, conn);
2628*46d2f618SCy Schubert continue;
2629*46d2f618SCy Schubert }
2630*46d2f618SCy Schubert doq_done_setup_timer_and_write(c, conn);
2631*46d2f618SCy Schubert continue;
2632*46d2f618SCy Schubert }
2633*46d2f618SCy Schubert if(
2634*46d2f618SCy Schubert #ifdef HAVE_NGTCP2_CONN_IN_CLOSING_PERIOD
2635*46d2f618SCy Schubert ngtcp2_conn_in_closing_period(conn->conn)
2636*46d2f618SCy Schubert #else
2637*46d2f618SCy Schubert ngtcp2_conn_is_in_closing_period(conn->conn)
2638*46d2f618SCy Schubert #endif
2639*46d2f618SCy Schubert ) {
2640*46d2f618SCy Schubert if(!doq_conn_send_close(c, conn)) {
2641*46d2f618SCy Schubert doq_delete_connection(c, conn);
2642*46d2f618SCy Schubert } else {
2643*46d2f618SCy Schubert doq_done_setup_timer_and_write(c, conn);
2644*46d2f618SCy Schubert }
2645*46d2f618SCy Schubert continue;
2646*46d2f618SCy Schubert }
2647*46d2f618SCy Schubert if(
2648*46d2f618SCy Schubert #ifdef HAVE_NGTCP2_CONN_IN_DRAINING_PERIOD
2649*46d2f618SCy Schubert ngtcp2_conn_in_draining_period(conn->conn)
2650*46d2f618SCy Schubert #else
2651*46d2f618SCy Schubert ngtcp2_conn_is_in_draining_period(conn->conn)
2652*46d2f618SCy Schubert #endif
2653*46d2f618SCy Schubert ) {
2654*46d2f618SCy Schubert doq_done_setup_timer_and_write(c, conn);
2655*46d2f618SCy Schubert continue;
2656*46d2f618SCy Schubert }
2657*46d2f618SCy Schubert if(!doq_conn_recv(c, &paddr, conn, &pi, NULL, &err_drop)) {
2658*46d2f618SCy Schubert /* The receive failed, and if it also failed to send
2659*46d2f618SCy Schubert * a close, drop the connection. That means it is not
2660*46d2f618SCy Schubert * in the closing period. */
2661*46d2f618SCy Schubert if(err_drop) {
2662*46d2f618SCy Schubert doq_delete_connection(c, conn);
2663*46d2f618SCy Schubert } else {
2664*46d2f618SCy Schubert doq_done_setup_timer_and_write(c, conn);
2665*46d2f618SCy Schubert }
2666*46d2f618SCy Schubert continue;
2667*46d2f618SCy Schubert }
2668*46d2f618SCy Schubert if(!doq_conn_write_streams(c, conn, &err_drop)) {
2669*46d2f618SCy Schubert if(err_drop) {
2670*46d2f618SCy Schubert doq_delete_connection(c, conn);
2671*46d2f618SCy Schubert } else {
2672*46d2f618SCy Schubert doq_done_setup_timer_and_write(c, conn);
2673*46d2f618SCy Schubert }
2674*46d2f618SCy Schubert continue;
2675*46d2f618SCy Schubert }
2676*46d2f618SCy Schubert doq_done_setup_timer_and_write(c, conn);
2677*46d2f618SCy Schubert }
2678*46d2f618SCy Schubert
2679*46d2f618SCy Schubert /* see if we want to have more write events */
2680*46d2f618SCy Schubert verbose(VERB_ALGO, "doq check write enable");
2681*46d2f618SCy Schubert if(doq_socket_want_write(c))
2682*46d2f618SCy Schubert doq_socket_write_enable(c);
2683*46d2f618SCy Schubert else doq_socket_write_disable(c);
2684*46d2f618SCy Schubert doq_pickup_timer(c);
2685*46d2f618SCy Schubert }
2686*46d2f618SCy Schubert
2687*46d2f618SCy Schubert /** create new doq server socket structure */
2688*46d2f618SCy Schubert static struct doq_server_socket*
2689*46d2f618SCy Schubert doq_server_socket_create(struct doq_table* table, struct ub_randstate* rnd,
2690*46d2f618SCy Schubert const char* ssl_service_key, const char* ssl_service_pem,
2691*46d2f618SCy Schubert struct comm_point* c, struct comm_base* base, struct config_file* cfg)
2692*46d2f618SCy Schubert {
2693*46d2f618SCy Schubert size_t doq_buffer_size = 4096; /* bytes buffer size, for one packet. */
2694*46d2f618SCy Schubert struct doq_server_socket* doq_socket;
2695*46d2f618SCy Schubert doq_socket = calloc(1, sizeof(*doq_socket));
2696*46d2f618SCy Schubert if(!doq_socket) {
2697*46d2f618SCy Schubert return NULL;
2698*46d2f618SCy Schubert }
2699*46d2f618SCy Schubert doq_socket->table = table;
2700*46d2f618SCy Schubert doq_socket->rnd = rnd;
2701*46d2f618SCy Schubert doq_socket->validate_addr = 1;
2702*46d2f618SCy Schubert if(ssl_service_key == NULL || ssl_service_key[0]==0) {
2703*46d2f618SCy Schubert log_err("doq server socket create: no tls-service-key");
2704*46d2f618SCy Schubert free(doq_socket);
2705*46d2f618SCy Schubert return NULL;
2706*46d2f618SCy Schubert }
2707*46d2f618SCy Schubert if(ssl_service_pem == NULL || ssl_service_pem[0]==0) {
2708*46d2f618SCy Schubert log_err("doq server socket create: no tls-service-pem");
2709*46d2f618SCy Schubert free(doq_socket);
2710*46d2f618SCy Schubert return NULL;
2711*46d2f618SCy Schubert }
2712*46d2f618SCy Schubert doq_socket->ssl_service_key = strdup(ssl_service_key);
2713*46d2f618SCy Schubert if(!doq_socket->ssl_service_key) {
2714*46d2f618SCy Schubert free(doq_socket);
2715*46d2f618SCy Schubert return NULL;
2716*46d2f618SCy Schubert }
2717*46d2f618SCy Schubert doq_socket->ssl_service_pem = strdup(ssl_service_pem);
2718*46d2f618SCy Schubert if(!doq_socket->ssl_service_pem) {
2719*46d2f618SCy Schubert free(doq_socket->ssl_service_key);
2720*46d2f618SCy Schubert free(doq_socket);
2721*46d2f618SCy Schubert return NULL;
2722*46d2f618SCy Schubert }
2723*46d2f618SCy Schubert doq_socket->ssl_verify_pem = NULL;
2724*46d2f618SCy Schubert /* the doq_socket has its own copy of the static secret, as
2725*46d2f618SCy Schubert * well as other config values, so that they do not need table.lock */
2726*46d2f618SCy Schubert doq_socket->static_secret_len = table->static_secret_len;
2727*46d2f618SCy Schubert doq_socket->static_secret = memdup(table->static_secret,
2728*46d2f618SCy Schubert table->static_secret_len);
2729*46d2f618SCy Schubert if(!doq_socket->static_secret) {
2730*46d2f618SCy Schubert free(doq_socket->ssl_service_key);
2731*46d2f618SCy Schubert free(doq_socket->ssl_service_pem);
2732*46d2f618SCy Schubert free(doq_socket->ssl_verify_pem);
2733*46d2f618SCy Schubert free(doq_socket);
2734*46d2f618SCy Schubert return NULL;
2735*46d2f618SCy Schubert }
2736*46d2f618SCy Schubert if(!doq_socket_setup_ctx(doq_socket)) {
2737*46d2f618SCy Schubert free(doq_socket->ssl_service_key);
2738*46d2f618SCy Schubert free(doq_socket->ssl_service_pem);
2739*46d2f618SCy Schubert free(doq_socket->ssl_verify_pem);
2740*46d2f618SCy Schubert free(doq_socket->static_secret);
2741*46d2f618SCy Schubert free(doq_socket);
2742*46d2f618SCy Schubert return NULL;
2743*46d2f618SCy Schubert }
2744*46d2f618SCy Schubert doq_socket->idle_timeout = table->idle_timeout;
2745*46d2f618SCy Schubert doq_socket->sv_scidlen = table->sv_scidlen;
2746*46d2f618SCy Schubert doq_socket->cp = c;
2747*46d2f618SCy Schubert doq_socket->pkt_buf = sldns_buffer_new(doq_buffer_size);
2748*46d2f618SCy Schubert if(!doq_socket->pkt_buf) {
2749*46d2f618SCy Schubert free(doq_socket->ssl_service_key);
2750*46d2f618SCy Schubert free(doq_socket->ssl_service_pem);
2751*46d2f618SCy Schubert free(doq_socket->ssl_verify_pem);
2752*46d2f618SCy Schubert free(doq_socket->static_secret);
2753*46d2f618SCy Schubert SSL_CTX_free(doq_socket->ctx);
2754*46d2f618SCy Schubert free(doq_socket);
2755*46d2f618SCy Schubert return NULL;
2756*46d2f618SCy Schubert }
2757*46d2f618SCy Schubert doq_socket->blocked_pkt = sldns_buffer_new(
2758*46d2f618SCy Schubert sldns_buffer_capacity(doq_socket->pkt_buf));
2759*46d2f618SCy Schubert if(!doq_socket->pkt_buf) {
2760*46d2f618SCy Schubert free(doq_socket->ssl_service_key);
2761*46d2f618SCy Schubert free(doq_socket->ssl_service_pem);
2762*46d2f618SCy Schubert free(doq_socket->ssl_verify_pem);
2763*46d2f618SCy Schubert free(doq_socket->static_secret);
2764*46d2f618SCy Schubert SSL_CTX_free(doq_socket->ctx);
2765*46d2f618SCy Schubert sldns_buffer_free(doq_socket->pkt_buf);
2766*46d2f618SCy Schubert free(doq_socket);
2767*46d2f618SCy Schubert return NULL;
2768*46d2f618SCy Schubert }
2769*46d2f618SCy Schubert doq_socket->blocked_paddr = calloc(1,
2770*46d2f618SCy Schubert sizeof(*doq_socket->blocked_paddr));
2771*46d2f618SCy Schubert if(!doq_socket->blocked_paddr) {
2772*46d2f618SCy Schubert free(doq_socket->ssl_service_key);
2773*46d2f618SCy Schubert free(doq_socket->ssl_service_pem);
2774*46d2f618SCy Schubert free(doq_socket->ssl_verify_pem);
2775*46d2f618SCy Schubert free(doq_socket->static_secret);
2776*46d2f618SCy Schubert SSL_CTX_free(doq_socket->ctx);
2777*46d2f618SCy Schubert sldns_buffer_free(doq_socket->pkt_buf);
2778*46d2f618SCy Schubert sldns_buffer_free(doq_socket->blocked_pkt);
2779*46d2f618SCy Schubert free(doq_socket);
2780*46d2f618SCy Schubert return NULL;
2781*46d2f618SCy Schubert }
2782*46d2f618SCy Schubert doq_socket->timer = comm_timer_create(base, doq_timer_cb, doq_socket);
2783*46d2f618SCy Schubert if(!doq_socket->timer) {
2784*46d2f618SCy Schubert free(doq_socket->ssl_service_key);
2785*46d2f618SCy Schubert free(doq_socket->ssl_service_pem);
2786*46d2f618SCy Schubert free(doq_socket->ssl_verify_pem);
2787*46d2f618SCy Schubert free(doq_socket->static_secret);
2788*46d2f618SCy Schubert SSL_CTX_free(doq_socket->ctx);
2789*46d2f618SCy Schubert sldns_buffer_free(doq_socket->pkt_buf);
2790*46d2f618SCy Schubert sldns_buffer_free(doq_socket->blocked_pkt);
2791*46d2f618SCy Schubert free(doq_socket->blocked_paddr);
2792*46d2f618SCy Schubert free(doq_socket);
2793*46d2f618SCy Schubert return NULL;
2794*46d2f618SCy Schubert }
2795*46d2f618SCy Schubert memset(&doq_socket->marked_time, 0, sizeof(doq_socket->marked_time));
2796*46d2f618SCy Schubert comm_base_timept(base, &doq_socket->now_tt, &doq_socket->now_tv);
2797*46d2f618SCy Schubert doq_socket->cfg = cfg;
2798*46d2f618SCy Schubert return doq_socket;
2799*46d2f618SCy Schubert }
2800*46d2f618SCy Schubert
2801*46d2f618SCy Schubert /** delete doq server socket structure */
2802*46d2f618SCy Schubert static void
2803*46d2f618SCy Schubert doq_server_socket_delete(struct doq_server_socket* doq_socket)
2804*46d2f618SCy Schubert {
2805*46d2f618SCy Schubert if(!doq_socket)
2806*46d2f618SCy Schubert return;
2807*46d2f618SCy Schubert free(doq_socket->static_secret);
2808*46d2f618SCy Schubert SSL_CTX_free(doq_socket->ctx);
2809*46d2f618SCy Schubert #ifndef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_SERVER_CONTEXT
2810*46d2f618SCy Schubert free(doq_socket->quic_method);
2811*46d2f618SCy Schubert #endif
2812*46d2f618SCy Schubert free(doq_socket->ssl_service_key);
2813*46d2f618SCy Schubert free(doq_socket->ssl_service_pem);
2814*46d2f618SCy Schubert free(doq_socket->ssl_verify_pem);
2815*46d2f618SCy Schubert sldns_buffer_free(doq_socket->pkt_buf);
2816*46d2f618SCy Schubert sldns_buffer_free(doq_socket->blocked_pkt);
2817*46d2f618SCy Schubert free(doq_socket->blocked_paddr);
2818*46d2f618SCy Schubert comm_timer_delete(doq_socket->timer);
2819*46d2f618SCy Schubert free(doq_socket);
2820*46d2f618SCy Schubert }
2821*46d2f618SCy Schubert
2822*46d2f618SCy Schubert /** find repinfo in the doq table */
2823*46d2f618SCy Schubert static struct doq_conn*
2824*46d2f618SCy Schubert doq_lookup_repinfo(struct doq_table* table, struct comm_reply* repinfo)
2825*46d2f618SCy Schubert {
2826*46d2f618SCy Schubert struct doq_conn* conn;
2827*46d2f618SCy Schubert struct doq_conn_key key;
2828*46d2f618SCy Schubert doq_conn_key_from_repinfo(&key, repinfo);
2829*46d2f618SCy Schubert lock_rw_rdlock(&table->lock);
2830*46d2f618SCy Schubert conn = doq_conn_find(table, &key.paddr.addr,
2831*46d2f618SCy Schubert key.paddr.addrlen, &key.paddr.localaddr,
2832*46d2f618SCy Schubert key.paddr.localaddrlen, key.paddr.ifindex, key.dcid,
2833*46d2f618SCy Schubert key.dcidlen);
2834*46d2f618SCy Schubert if(conn) {
2835*46d2f618SCy Schubert lock_basic_lock(&conn->lock);
2836*46d2f618SCy Schubert lock_rw_unlock(&table->lock);
2837*46d2f618SCy Schubert return conn;
2838*46d2f618SCy Schubert }
2839*46d2f618SCy Schubert lock_rw_unlock(&table->lock);
2840*46d2f618SCy Schubert return NULL;
2841*46d2f618SCy Schubert }
2842*46d2f618SCy Schubert
2843*46d2f618SCy Schubert /** doq find connection and stream. From inside callbacks from worker. */
2844*46d2f618SCy Schubert static int
2845*46d2f618SCy Schubert doq_lookup_conn_stream(struct comm_reply* repinfo, struct comm_point* c,
2846*46d2f618SCy Schubert struct doq_conn** conn, struct doq_stream** stream)
2847*46d2f618SCy Schubert {
2848*46d2f618SCy Schubert if(c->doq_socket->current_conn) {
2849*46d2f618SCy Schubert *conn = c->doq_socket->current_conn;
2850*46d2f618SCy Schubert } else {
2851*46d2f618SCy Schubert *conn = doq_lookup_repinfo(c->doq_socket->table, repinfo);
2852*46d2f618SCy Schubert if((*conn) && (*conn)->is_deleted) {
2853*46d2f618SCy Schubert lock_basic_unlock(&(*conn)->lock);
2854*46d2f618SCy Schubert *conn = NULL;
2855*46d2f618SCy Schubert }
2856*46d2f618SCy Schubert if(*conn) {
2857*46d2f618SCy Schubert (*conn)->doq_socket = c->doq_socket;
2858*46d2f618SCy Schubert }
2859*46d2f618SCy Schubert }
2860*46d2f618SCy Schubert if(!*conn) {
2861*46d2f618SCy Schubert *stream = NULL;
2862*46d2f618SCy Schubert return 0;
2863*46d2f618SCy Schubert }
2864*46d2f618SCy Schubert *stream = doq_stream_find(*conn, repinfo->doq_streamid);
2865*46d2f618SCy Schubert if(!*stream) {
2866*46d2f618SCy Schubert if(!c->doq_socket->current_conn) {
2867*46d2f618SCy Schubert /* Not inside callbacks, we have our own lock on conn.
2868*46d2f618SCy Schubert * Release it. */
2869*46d2f618SCy Schubert lock_basic_unlock(&(*conn)->lock);
2870*46d2f618SCy Schubert }
2871*46d2f618SCy Schubert return 0;
2872*46d2f618SCy Schubert }
2873*46d2f618SCy Schubert if((*stream)->is_closed) {
2874*46d2f618SCy Schubert /* stream is closed, ignore reply or drop */
2875*46d2f618SCy Schubert if(!c->doq_socket->current_conn) {
2876*46d2f618SCy Schubert /* Not inside callbacks, we have our own lock on conn.
2877*46d2f618SCy Schubert * Release it. */
2878*46d2f618SCy Schubert lock_basic_unlock(&(*conn)->lock);
2879*46d2f618SCy Schubert }
2880*46d2f618SCy Schubert return 0;
2881*46d2f618SCy Schubert }
2882*46d2f618SCy Schubert return 1;
2883*46d2f618SCy Schubert }
2884*46d2f618SCy Schubert
2885*46d2f618SCy Schubert /** doq send a reply from a comm reply */
2886*46d2f618SCy Schubert static void
2887*46d2f618SCy Schubert doq_socket_send_reply(struct comm_reply* repinfo)
2888*46d2f618SCy Schubert {
2889*46d2f618SCy Schubert struct doq_conn* conn;
2890*46d2f618SCy Schubert struct doq_stream* stream;
2891*46d2f618SCy Schubert log_assert(repinfo->c->type == comm_doq);
2892*46d2f618SCy Schubert if(!doq_lookup_conn_stream(repinfo, repinfo->c, &conn, &stream)) {
2893*46d2f618SCy Schubert verbose(VERB_ALGO, "doq: send_reply but %s is gone",
2894*46d2f618SCy Schubert (conn?"stream":"connection"));
2895*46d2f618SCy Schubert /* No stream, it may have been closed. */
2896*46d2f618SCy Schubert /* Drop the reply, it cannot be sent. */
2897*46d2f618SCy Schubert return;
2898*46d2f618SCy Schubert }
2899*46d2f618SCy Schubert if(!doq_stream_send_reply(conn, stream, repinfo->c->buffer))
2900*46d2f618SCy Schubert doq_stream_close(conn, stream, 1);
2901*46d2f618SCy Schubert if(!repinfo->c->doq_socket->current_conn) {
2902*46d2f618SCy Schubert /* Not inside callbacks, we have our own lock on conn.
2903*46d2f618SCy Schubert * Release it. */
2904*46d2f618SCy Schubert doq_done_with_conn_cb(repinfo->c, conn);
2905*46d2f618SCy Schubert /* since we sent a reply, or closed it, the assumption is
2906*46d2f618SCy Schubert * that there is something to write, so enable write event.
2907*46d2f618SCy Schubert * It waits until the write event happens to write the
2908*46d2f618SCy Schubert * streams with answers, this allows some answers to be
2909*46d2f618SCy Schubert * answered before the event loop reaches the doq fd, in
2910*46d2f618SCy Schubert * repinfo->c->fd, and that collates answers. That would
2911*46d2f618SCy Schubert * not happen if we write doq packets right now. */
2912*46d2f618SCy Schubert doq_socket_write_enable(repinfo->c);
2913*46d2f618SCy Schubert }
2914*46d2f618SCy Schubert }
2915*46d2f618SCy Schubert
2916*46d2f618SCy Schubert /** doq drop a reply from a comm reply */
2917*46d2f618SCy Schubert static void
2918*46d2f618SCy Schubert doq_socket_drop_reply(struct comm_reply* repinfo)
2919*46d2f618SCy Schubert {
2920*46d2f618SCy Schubert struct doq_conn* conn;
2921*46d2f618SCy Schubert struct doq_stream* stream;
2922*46d2f618SCy Schubert log_assert(repinfo->c->type == comm_doq);
2923*46d2f618SCy Schubert if(!doq_lookup_conn_stream(repinfo, repinfo->c, &conn, &stream)) {
2924*46d2f618SCy Schubert verbose(VERB_ALGO, "doq: drop_reply but %s is gone",
2925*46d2f618SCy Schubert (conn?"stream":"connection"));
2926*46d2f618SCy Schubert /* The connection or stream is already gone. */
2927*46d2f618SCy Schubert return;
2928*46d2f618SCy Schubert }
2929*46d2f618SCy Schubert doq_stream_close(conn, stream, 1);
2930*46d2f618SCy Schubert if(!repinfo->c->doq_socket->current_conn) {
2931*46d2f618SCy Schubert /* Not inside callbacks, we have our own lock on conn.
2932*46d2f618SCy Schubert * Release it. */
2933*46d2f618SCy Schubert doq_done_with_conn_cb(repinfo->c, conn);
2934*46d2f618SCy Schubert doq_socket_write_enable(repinfo->c);
2935*46d2f618SCy Schubert }
2936*46d2f618SCy Schubert }
2937*46d2f618SCy Schubert #endif /* HAVE_NGTCP2 */
2938*46d2f618SCy Schubert
2939f44e67d1SCy Schubert int adjusted_tcp_timeout(struct comm_point* c)
2940f44e67d1SCy Schubert {
2941f44e67d1SCy Schubert if(c->tcp_timeout_msec < TCP_QUERY_TIMEOUT_MINIMUM)
2942f44e67d1SCy Schubert return TCP_QUERY_TIMEOUT_MINIMUM;
2943f44e67d1SCy Schubert return c->tcp_timeout_msec;
2944f44e67d1SCy Schubert }
2945f44e67d1SCy Schubert
2946b7579f77SDag-Erling Smørgrav /** Use a new tcp handler for new query fd, set to read query */
2947b7579f77SDag-Erling Smørgrav static void
2948b5663de9SDag-Erling Smørgrav setup_tcp_handler(struct comm_point* c, int fd, int cur, int max)
2949b7579f77SDag-Erling Smørgrav {
29504c75e3aaSDag-Erling Smørgrav int handler_usage;
2951c0caa2e2SCy Schubert log_assert(c->type == comm_tcp || c->type == comm_http);
2952b7579f77SDag-Erling Smørgrav log_assert(c->fd == -1);
295317d15b25SDag-Erling Smørgrav sldns_buffer_clear(c->buffer);
295465b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT
295565b390aaSDag-Erling Smørgrav if (c->dnscrypt)
295665b390aaSDag-Erling Smørgrav sldns_buffer_clear(c->dnscrypt_buffer);
295765b390aaSDag-Erling Smørgrav #endif
2958b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 1;
2959b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0;
296024e36522SCy Schubert c->tcp_keepalive = 0;
2961b5663de9SDag-Erling Smørgrav /* if more than half the tcp handlers are in use, use a shorter
2962b5663de9SDag-Erling Smørgrav * timeout for this TCP connection, we need to make space for
2963b5663de9SDag-Erling Smørgrav * other connections to be able to get attention */
29644c75e3aaSDag-Erling Smørgrav /* If > 50% TCP handler structures in use, set timeout to 1/100th
29654c75e3aaSDag-Erling Smørgrav * configured value.
29664c75e3aaSDag-Erling Smørgrav * If > 65%TCP handler structures in use, set to 1/500th configured
29674c75e3aaSDag-Erling Smørgrav * value.
29684c75e3aaSDag-Erling Smørgrav * If > 80% TCP handler structures in use, set to 0.
29694c75e3aaSDag-Erling Smørgrav *
29704c75e3aaSDag-Erling Smørgrav * If the timeout to use falls below 200 milliseconds, an actual
29714c75e3aaSDag-Erling Smørgrav * timeout of 200ms is used.
29724c75e3aaSDag-Erling Smørgrav */
29734c75e3aaSDag-Erling Smørgrav handler_usage = (cur * 100) / max;
29744c75e3aaSDag-Erling Smørgrav if(handler_usage > 50 && handler_usage <= 65)
29754c75e3aaSDag-Erling Smørgrav c->tcp_timeout_msec /= 100;
29764c75e3aaSDag-Erling Smørgrav else if (handler_usage > 65 && handler_usage <= 80)
29774c75e3aaSDag-Erling Smørgrav c->tcp_timeout_msec /= 500;
29784c75e3aaSDag-Erling Smørgrav else if (handler_usage > 80)
29794c75e3aaSDag-Erling Smørgrav c->tcp_timeout_msec = 0;
2980f44e67d1SCy Schubert comm_point_start_listening(c, fd, adjusted_tcp_timeout(c));
2981b7579f77SDag-Erling Smørgrav }
2982b7579f77SDag-Erling Smørgrav
2983b7579f77SDag-Erling Smørgrav void comm_base_handle_slow_accept(int ATTR_UNUSED(fd),
2984b7579f77SDag-Erling Smørgrav short ATTR_UNUSED(event), void* arg)
2985b7579f77SDag-Erling Smørgrav {
2986b7579f77SDag-Erling Smørgrav struct comm_base* b = (struct comm_base*)arg;
2987b7579f77SDag-Erling Smørgrav /* timeout for the slow accept, re-enable accepts again */
2988b7579f77SDag-Erling Smørgrav if(b->start_accept) {
2989b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "wait is over, slow accept disabled");
2990b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_start_accept(b->start_accept));
2991b7579f77SDag-Erling Smørgrav (*b->start_accept)(b->cb_arg);
2992b7579f77SDag-Erling Smørgrav b->eb->slow_accept_enabled = 0;
2993b7579f77SDag-Erling Smørgrav }
2994b7579f77SDag-Erling Smørgrav }
2995b7579f77SDag-Erling Smørgrav
2996b7579f77SDag-Erling Smørgrav int comm_point_perform_accept(struct comm_point* c,
2997b7579f77SDag-Erling Smørgrav struct sockaddr_storage* addr, socklen_t* addrlen)
2998b7579f77SDag-Erling Smørgrav {
2999b7579f77SDag-Erling Smørgrav int new_fd;
3000b7579f77SDag-Erling Smørgrav *addrlen = (socklen_t)sizeof(*addr);
30013bd4df0aSDag-Erling Smørgrav #ifndef HAVE_ACCEPT4
3002b7579f77SDag-Erling Smørgrav new_fd = accept(c->fd, (struct sockaddr*)addr, addrlen);
30033bd4df0aSDag-Erling Smørgrav #else
30043bd4df0aSDag-Erling Smørgrav /* SOCK_NONBLOCK saves extra calls to fcntl for the same result */
30053bd4df0aSDag-Erling Smørgrav new_fd = accept4(c->fd, (struct sockaddr*)addr, addrlen, SOCK_NONBLOCK);
30063bd4df0aSDag-Erling Smørgrav #endif
3007b7579f77SDag-Erling Smørgrav if(new_fd == -1) {
3008b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK
3009b7579f77SDag-Erling Smørgrav /* EINTR is signal interrupt. others are closed connection. */
3010b7579f77SDag-Erling Smørgrav if( errno == EINTR || errno == EAGAIN
3011b7579f77SDag-Erling Smørgrav #ifdef EWOULDBLOCK
3012b7579f77SDag-Erling Smørgrav || errno == EWOULDBLOCK
3013b7579f77SDag-Erling Smørgrav #endif
3014b7579f77SDag-Erling Smørgrav #ifdef ECONNABORTED
3015b7579f77SDag-Erling Smørgrav || errno == ECONNABORTED
3016b7579f77SDag-Erling Smørgrav #endif
3017b7579f77SDag-Erling Smørgrav #ifdef EPROTO
3018b7579f77SDag-Erling Smørgrav || errno == EPROTO
3019b7579f77SDag-Erling Smørgrav #endif /* EPROTO */
3020b7579f77SDag-Erling Smørgrav )
3021b7579f77SDag-Erling Smørgrav return -1;
3022b7579f77SDag-Erling Smørgrav #if defined(ENFILE) && defined(EMFILE)
3023b7579f77SDag-Erling Smørgrav if(errno == ENFILE || errno == EMFILE) {
3024b7579f77SDag-Erling Smørgrav /* out of file descriptors, likely outside of our
3025b7579f77SDag-Erling Smørgrav * control. stop accept() calls for some time */
3026b7579f77SDag-Erling Smørgrav if(c->ev->base->stop_accept) {
3027b7579f77SDag-Erling Smørgrav struct comm_base* b = c->ev->base;
3028b7579f77SDag-Erling Smørgrav struct timeval tv;
3029b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "out of file descriptors: "
3030b7579f77SDag-Erling Smørgrav "slow accept");
3031865f46b2SCy Schubert ub_comm_base_now(b);
3032865f46b2SCy Schubert if(b->eb->last_slow_log+SLOW_LOG_TIME <=
3033865f46b2SCy Schubert b->eb->secs) {
3034865f46b2SCy Schubert b->eb->last_slow_log = b->eb->secs;
3035865f46b2SCy Schubert verbose(VERB_OPS, "accept failed, "
3036865f46b2SCy Schubert "slow down accept for %d "
3037865f46b2SCy Schubert "msec: %s",
3038865f46b2SCy Schubert NETEVENT_SLOW_ACCEPT_TIME,
3039865f46b2SCy Schubert sock_strerror(errno));
3040865f46b2SCy Schubert }
3041b7579f77SDag-Erling Smørgrav b->eb->slow_accept_enabled = 1;
3042b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_stop_accept(
3043b7579f77SDag-Erling Smørgrav b->stop_accept));
3044b7579f77SDag-Erling Smørgrav (*b->stop_accept)(b->cb_arg);
3045b7579f77SDag-Erling Smørgrav /* set timeout, no mallocs */
3046b7579f77SDag-Erling Smørgrav tv.tv_sec = NETEVENT_SLOW_ACCEPT_TIME/1000;
3047b5663de9SDag-Erling Smørgrav tv.tv_usec = (NETEVENT_SLOW_ACCEPT_TIME%1000)*1000;
3048e2d15004SDag-Erling Smørgrav b->eb->slow_accept = ub_event_new(b->eb->base,
3049e2d15004SDag-Erling Smørgrav -1, UB_EV_TIMEOUT,
3050b7579f77SDag-Erling Smørgrav comm_base_handle_slow_accept, b);
3051e2d15004SDag-Erling Smørgrav if(b->eb->slow_accept == NULL) {
3052b7579f77SDag-Erling Smørgrav /* we do not want to log here, because
3053b7579f77SDag-Erling Smørgrav * that would spam the logfiles.
3054b7579f77SDag-Erling Smørgrav * error: "event_base_set failed." */
3055b7579f77SDag-Erling Smørgrav }
3056e2d15004SDag-Erling Smørgrav else if(ub_event_add(b->eb->slow_accept, &tv)
3057e2d15004SDag-Erling Smørgrav != 0) {
3058b7579f77SDag-Erling Smørgrav /* we do not want to log here,
3059b7579f77SDag-Erling Smørgrav * error: "event_add failed." */
3060b7579f77SDag-Erling Smørgrav }
3061865f46b2SCy Schubert } else {
3062865f46b2SCy Schubert log_err("accept, with no slow down, "
3063865f46b2SCy Schubert "failed: %s", sock_strerror(errno));
3064b7579f77SDag-Erling Smørgrav }
3065b7579f77SDag-Erling Smørgrav return -1;
3066b7579f77SDag-Erling Smørgrav }
3067b7579f77SDag-Erling Smørgrav #endif
3068b7579f77SDag-Erling Smørgrav #else /* USE_WINSOCK */
3069b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEINPROGRESS ||
3070b7579f77SDag-Erling Smørgrav WSAGetLastError() == WSAECONNRESET)
3071b7579f77SDag-Erling Smørgrav return -1;
3072b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEWOULDBLOCK) {
3073e2d15004SDag-Erling Smørgrav ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
3074b7579f77SDag-Erling Smørgrav return -1;
3075b7579f77SDag-Erling Smørgrav }
3076b7579f77SDag-Erling Smørgrav #endif
3077c0caa2e2SCy Schubert log_err_addr("accept failed", sock_strerror(errno), addr,
3078c0caa2e2SCy Schubert *addrlen);
3079b7579f77SDag-Erling Smørgrav return -1;
3080b7579f77SDag-Erling Smørgrav }
30814c75e3aaSDag-Erling Smørgrav if(c->tcp_conn_limit && c->type == comm_tcp_accept) {
30824c75e3aaSDag-Erling Smørgrav c->tcl_addr = tcl_addr_lookup(c->tcp_conn_limit, addr, *addrlen);
30834c75e3aaSDag-Erling Smørgrav if(!tcl_new_connection(c->tcl_addr)) {
30844c75e3aaSDag-Erling Smørgrav if(verbosity >= 3)
30854c75e3aaSDag-Erling Smørgrav log_err_addr("accept rejected",
30864c75e3aaSDag-Erling Smørgrav "connection limit exceeded", addr, *addrlen);
30874c75e3aaSDag-Erling Smørgrav close(new_fd);
30884c75e3aaSDag-Erling Smørgrav return -1;
30894c75e3aaSDag-Erling Smørgrav }
30904c75e3aaSDag-Erling Smørgrav }
30913bd4df0aSDag-Erling Smørgrav #ifndef HAVE_ACCEPT4
3092b7579f77SDag-Erling Smørgrav fd_set_nonblock(new_fd);
30933bd4df0aSDag-Erling Smørgrav #endif
3094b7579f77SDag-Erling Smørgrav return new_fd;
3095b7579f77SDag-Erling Smørgrav }
3096b7579f77SDag-Erling Smørgrav
3097b7579f77SDag-Erling Smørgrav #ifdef USE_WINSOCK
3098b7579f77SDag-Erling Smørgrav static long win_bio_cb(BIO *b, int oper, const char* ATTR_UNUSED(argp),
309924e36522SCy Schubert #ifdef HAVE_BIO_SET_CALLBACK_EX
310024e36522SCy Schubert size_t ATTR_UNUSED(len),
310124e36522SCy Schubert #endif
310224e36522SCy Schubert int ATTR_UNUSED(argi), long argl,
310324e36522SCy Schubert #ifndef HAVE_BIO_SET_CALLBACK_EX
310424e36522SCy Schubert long retvalue
310524e36522SCy Schubert #else
310624e36522SCy Schubert int retvalue, size_t* ATTR_UNUSED(processed)
310724e36522SCy Schubert #endif
310824e36522SCy Schubert )
3109b7579f77SDag-Erling Smørgrav {
31103bd4df0aSDag-Erling Smørgrav int wsa_err = WSAGetLastError(); /* store errcode before it is gone */
3111b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "bio_cb %d, %s %s %s", oper,
3112b7579f77SDag-Erling Smørgrav (oper&BIO_CB_RETURN)?"return":"before",
3113b7579f77SDag-Erling Smørgrav (oper&BIO_CB_READ)?"read":((oper&BIO_CB_WRITE)?"write":"other"),
31143bd4df0aSDag-Erling Smørgrav wsa_err==WSAEWOULDBLOCK?"wsawb":"");
3115b7579f77SDag-Erling Smørgrav /* on windows, check if previous operation caused EWOULDBLOCK */
3116b7579f77SDag-Erling Smørgrav if( (oper == (BIO_CB_READ|BIO_CB_RETURN) && argl == 0) ||
3117b7579f77SDag-Erling Smørgrav (oper == (BIO_CB_GETS|BIO_CB_RETURN) && argl == 0)) {
31183bd4df0aSDag-Erling Smørgrav if(wsa_err == WSAEWOULDBLOCK)
3119e2d15004SDag-Erling Smørgrav ub_winsock_tcp_wouldblock((struct ub_event*)
3120e2d15004SDag-Erling Smørgrav BIO_get_callback_arg(b), UB_EV_READ);
3121b7579f77SDag-Erling Smørgrav }
3122b7579f77SDag-Erling Smørgrav if( (oper == (BIO_CB_WRITE|BIO_CB_RETURN) && argl == 0) ||
3123b7579f77SDag-Erling Smørgrav (oper == (BIO_CB_PUTS|BIO_CB_RETURN) && argl == 0)) {
31243bd4df0aSDag-Erling Smørgrav if(wsa_err == WSAEWOULDBLOCK)
3125e2d15004SDag-Erling Smørgrav ub_winsock_tcp_wouldblock((struct ub_event*)
3126e2d15004SDag-Erling Smørgrav BIO_get_callback_arg(b), UB_EV_WRITE);
3127b7579f77SDag-Erling Smørgrav }
3128b7579f77SDag-Erling Smørgrav /* return original return value */
3129b7579f77SDag-Erling Smørgrav return retvalue;
3130b7579f77SDag-Erling Smørgrav }
3131b7579f77SDag-Erling Smørgrav
3132b7579f77SDag-Erling Smørgrav /** set win bio callbacks for nonblocking operations */
3133b7579f77SDag-Erling Smørgrav void
3134b7579f77SDag-Erling Smørgrav comm_point_tcp_win_bio_cb(struct comm_point* c, void* thessl)
3135b7579f77SDag-Erling Smørgrav {
3136b7579f77SDag-Erling Smørgrav SSL* ssl = (SSL*)thessl;
3137b7579f77SDag-Erling Smørgrav /* set them both just in case, but usually they are the same BIO */
313824e36522SCy Schubert #ifdef HAVE_BIO_SET_CALLBACK_EX
313924e36522SCy Schubert BIO_set_callback_ex(SSL_get_rbio(ssl), &win_bio_cb);
314024e36522SCy Schubert #else
3141b7579f77SDag-Erling Smørgrav BIO_set_callback(SSL_get_rbio(ssl), &win_bio_cb);
314224e36522SCy Schubert #endif
3143e2d15004SDag-Erling Smørgrav BIO_set_callback_arg(SSL_get_rbio(ssl), (char*)c->ev->ev);
314424e36522SCy Schubert #ifdef HAVE_BIO_SET_CALLBACK_EX
314524e36522SCy Schubert BIO_set_callback_ex(SSL_get_wbio(ssl), &win_bio_cb);
314624e36522SCy Schubert #else
3147b7579f77SDag-Erling Smørgrav BIO_set_callback(SSL_get_wbio(ssl), &win_bio_cb);
314824e36522SCy Schubert #endif
3149e2d15004SDag-Erling Smørgrav BIO_set_callback_arg(SSL_get_wbio(ssl), (char*)c->ev->ev);
3150b7579f77SDag-Erling Smørgrav }
3151b7579f77SDag-Erling Smørgrav #endif
3152b7579f77SDag-Erling Smørgrav
3153c0caa2e2SCy Schubert #ifdef HAVE_NGHTTP2
3154c0caa2e2SCy Schubert /** Create http2 session server. Per connection, after TCP accepted.*/
3155c0caa2e2SCy Schubert static int http2_session_server_create(struct http2_session* h2_session)
3156c0caa2e2SCy Schubert {
3157c0caa2e2SCy Schubert log_assert(h2_session->callbacks);
3158c0caa2e2SCy Schubert h2_session->is_drop = 0;
3159c0caa2e2SCy Schubert if(nghttp2_session_server_new(&h2_session->session,
3160c0caa2e2SCy Schubert h2_session->callbacks,
3161c0caa2e2SCy Schubert h2_session) == NGHTTP2_ERR_NOMEM) {
3162c0caa2e2SCy Schubert log_err("failed to create nghttp2 session server");
3163c0caa2e2SCy Schubert return 0;
3164c0caa2e2SCy Schubert }
3165c0caa2e2SCy Schubert
3166c0caa2e2SCy Schubert return 1;
3167c0caa2e2SCy Schubert }
3168c0caa2e2SCy Schubert
3169c0caa2e2SCy Schubert /** Submit http2 setting to session. Once per session. */
3170c0caa2e2SCy Schubert static int http2_submit_settings(struct http2_session* h2_session)
3171c0caa2e2SCy Schubert {
3172c0caa2e2SCy Schubert int ret;
3173c0caa2e2SCy Schubert nghttp2_settings_entry settings[1] = {
3174c0caa2e2SCy Schubert {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
3175c0caa2e2SCy Schubert h2_session->c->http2_max_streams}};
3176c0caa2e2SCy Schubert
3177c0caa2e2SCy Schubert ret = nghttp2_submit_settings(h2_session->session, NGHTTP2_FLAG_NONE,
3178c0caa2e2SCy Schubert settings, 1);
3179c0caa2e2SCy Schubert if(ret) {
3180c0caa2e2SCy Schubert verbose(VERB_QUERY, "http2: submit_settings failed, "
3181c0caa2e2SCy Schubert "error: %s", nghttp2_strerror(ret));
3182c0caa2e2SCy Schubert return 0;
3183c0caa2e2SCy Schubert }
3184c0caa2e2SCy Schubert return 1;
3185c0caa2e2SCy Schubert }
3186c0caa2e2SCy Schubert #endif /* HAVE_NGHTTP2 */
3187c0caa2e2SCy Schubert
3188c0caa2e2SCy Schubert
3189b7579f77SDag-Erling Smørgrav void
3190b7579f77SDag-Erling Smørgrav comm_point_tcp_accept_callback(int fd, short event, void* arg)
3191b7579f77SDag-Erling Smørgrav {
3192b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)arg, *c_hdl;
3193b7579f77SDag-Erling Smørgrav int new_fd;
3194b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_tcp_accept);
3195e2d15004SDag-Erling Smørgrav if(!(event & UB_EV_READ)) {
3196b7579f77SDag-Erling Smørgrav log_info("ignoring tcp accept event %d", (int)event);
3197b7579f77SDag-Erling Smørgrav return;
3198b7579f77SDag-Erling Smørgrav }
3199e2d15004SDag-Erling Smørgrav ub_comm_base_now(c->ev->base);
3200b7579f77SDag-Erling Smørgrav /* find free tcp handler. */
3201b7579f77SDag-Erling Smørgrav if(!c->tcp_free) {
3202b7579f77SDag-Erling Smørgrav log_warn("accepted too many tcp, connections full");
3203b7579f77SDag-Erling Smørgrav return;
3204b7579f77SDag-Erling Smørgrav }
3205b7579f77SDag-Erling Smørgrav /* accept incoming connection. */
3206b7579f77SDag-Erling Smørgrav c_hdl = c->tcp_free;
3207e86b9096SDag-Erling Smørgrav /* clear leftover flags from previous use, and then set the
3208e86b9096SDag-Erling Smørgrav * correct event base for the event structure for libevent */
3209e86b9096SDag-Erling Smørgrav ub_event_free(c_hdl->ev->ev);
321024e36522SCy Schubert c_hdl->ev->ev = NULL;
3211369c6923SCy Schubert if((c_hdl->type == comm_tcp && c_hdl->tcp_req_info) ||
3212369c6923SCy Schubert c_hdl->type == comm_local || c_hdl->type == comm_raw)
3213369c6923SCy Schubert c_hdl->tcp_do_toggle_rw = 0;
3214369c6923SCy Schubert else c_hdl->tcp_do_toggle_rw = 1;
3215c0caa2e2SCy Schubert
3216c0caa2e2SCy Schubert if(c_hdl->type == comm_http) {
3217c0caa2e2SCy Schubert #ifdef HAVE_NGHTTP2
3218c0caa2e2SCy Schubert if(!c_hdl->h2_session ||
3219c0caa2e2SCy Schubert !http2_session_server_create(c_hdl->h2_session)) {
3220c0caa2e2SCy Schubert log_warn("failed to create nghttp2");
3221c0caa2e2SCy Schubert return;
3222c0caa2e2SCy Schubert }
3223c0caa2e2SCy Schubert if(!c_hdl->h2_session ||
3224c0caa2e2SCy Schubert !http2_submit_settings(c_hdl->h2_session)) {
3225c0caa2e2SCy Schubert log_warn("failed to submit http2 settings");
3226c0caa2e2SCy Schubert return;
3227c0caa2e2SCy Schubert }
3228369c6923SCy Schubert if(!c->ssl) {
3229369c6923SCy Schubert c_hdl->tcp_do_toggle_rw = 0;
3230369c6923SCy Schubert c_hdl->use_h2 = 1;
3231369c6923SCy Schubert }
3232c0caa2e2SCy Schubert #endif
3233c0caa2e2SCy Schubert c_hdl->ev->ev = ub_event_new(c_hdl->ev->base->eb->base, -1,
3234c0caa2e2SCy Schubert UB_EV_PERSIST | UB_EV_READ | UB_EV_TIMEOUT,
3235c0caa2e2SCy Schubert comm_point_http_handle_callback, c_hdl);
3236c0caa2e2SCy Schubert } else {
3237c0caa2e2SCy Schubert c_hdl->ev->ev = ub_event_new(c_hdl->ev->base->eb->base, -1,
3238c0caa2e2SCy Schubert UB_EV_PERSIST | UB_EV_READ | UB_EV_TIMEOUT,
3239c0caa2e2SCy Schubert comm_point_tcp_handle_callback, c_hdl);
3240c0caa2e2SCy Schubert }
3241e86b9096SDag-Erling Smørgrav if(!c_hdl->ev->ev) {
3242e86b9096SDag-Erling Smørgrav log_warn("could not ub_event_new, dropped tcp");
3243e86b9096SDag-Erling Smørgrav return;
3244e86b9096SDag-Erling Smørgrav }
3245b7579f77SDag-Erling Smørgrav log_assert(fd != -1);
3246b5663de9SDag-Erling Smørgrav (void)fd;
3247865f46b2SCy Schubert new_fd = comm_point_perform_accept(c, &c_hdl->repinfo.remote_addr,
3248865f46b2SCy Schubert &c_hdl->repinfo.remote_addrlen);
3249b7579f77SDag-Erling Smørgrav if(new_fd == -1)
3250b7579f77SDag-Erling Smørgrav return;
3251865f46b2SCy Schubert /* Copy remote_address to client_address.
3252865f46b2SCy Schubert * Simplest way/time for streams to do that. */
3253865f46b2SCy Schubert c_hdl->repinfo.client_addrlen = c_hdl->repinfo.remote_addrlen;
3254865f46b2SCy Schubert memmove(&c_hdl->repinfo.client_addr,
3255865f46b2SCy Schubert &c_hdl->repinfo.remote_addr,
3256865f46b2SCy Schubert c_hdl->repinfo.remote_addrlen);
3257b7579f77SDag-Erling Smørgrav if(c->ssl) {
3258b7579f77SDag-Erling Smørgrav c_hdl->ssl = incoming_ssl_fd(c->ssl, new_fd);
3259b7579f77SDag-Erling Smørgrav if(!c_hdl->ssl) {
3260b7579f77SDag-Erling Smørgrav c_hdl->fd = new_fd;
3261b7579f77SDag-Erling Smørgrav comm_point_close(c_hdl);
3262b7579f77SDag-Erling Smørgrav return;
3263b7579f77SDag-Erling Smørgrav }
3264b7579f77SDag-Erling Smørgrav c_hdl->ssl_shake_state = comm_ssl_shake_read;
3265b7579f77SDag-Erling Smørgrav #ifdef USE_WINSOCK
3266b7579f77SDag-Erling Smørgrav comm_point_tcp_win_bio_cb(c_hdl, c_hdl->ssl);
3267b7579f77SDag-Erling Smørgrav #endif
3268b7579f77SDag-Erling Smørgrav }
3269b7579f77SDag-Erling Smørgrav
3270b7579f77SDag-Erling Smørgrav /* grab the tcp handler buffers */
327109a3aaf3SDag-Erling Smørgrav c->cur_tcp_count++;
3272b7579f77SDag-Erling Smørgrav c->tcp_free = c_hdl->tcp_free;
327324e36522SCy Schubert c_hdl->tcp_free = NULL;
3274b7579f77SDag-Erling Smørgrav if(!c->tcp_free) {
3275b7579f77SDag-Erling Smørgrav /* stop accepting incoming queries for now. */
3276b7579f77SDag-Erling Smørgrav comm_point_stop_listening(c);
3277b7579f77SDag-Erling Smørgrav }
3278b5663de9SDag-Erling Smørgrav setup_tcp_handler(c_hdl, new_fd, c->cur_tcp_count, c->max_tcp_count);
3279b7579f77SDag-Erling Smørgrav }
3280b7579f77SDag-Erling Smørgrav
3281b7579f77SDag-Erling Smørgrav /** Make tcp handler free for next assignment */
3282b7579f77SDag-Erling Smørgrav static void
3283b7579f77SDag-Erling Smørgrav reclaim_tcp_handler(struct comm_point* c)
3284b7579f77SDag-Erling Smørgrav {
3285b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_tcp);
3286b7579f77SDag-Erling Smørgrav if(c->ssl) {
32878ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL
3288b7579f77SDag-Erling Smørgrav SSL_shutdown(c->ssl);
3289b7579f77SDag-Erling Smørgrav SSL_free(c->ssl);
3290b7579f77SDag-Erling Smørgrav c->ssl = NULL;
32918ed2b524SDag-Erling Smørgrav #endif
3292b7579f77SDag-Erling Smørgrav }
3293b7579f77SDag-Erling Smørgrav comm_point_close(c);
3294b7579f77SDag-Erling Smørgrav if(c->tcp_parent) {
329524e36522SCy Schubert if(c != c->tcp_parent->tcp_free) {
329609a3aaf3SDag-Erling Smørgrav c->tcp_parent->cur_tcp_count--;
3297b7579f77SDag-Erling Smørgrav c->tcp_free = c->tcp_parent->tcp_free;
3298b7579f77SDag-Erling Smørgrav c->tcp_parent->tcp_free = c;
329924e36522SCy Schubert }
3300b7579f77SDag-Erling Smørgrav if(!c->tcp_free) {
3301b7579f77SDag-Erling Smørgrav /* re-enable listening on accept socket */
3302b7579f77SDag-Erling Smørgrav comm_point_start_listening(c->tcp_parent, -1, -1);
3303b7579f77SDag-Erling Smørgrav }
3304b7579f77SDag-Erling Smørgrav }
3305369c6923SCy Schubert c->tcp_more_read_again = NULL;
3306369c6923SCy Schubert c->tcp_more_write_again = NULL;
33079cf5bc93SCy Schubert c->tcp_byte_count = 0;
3308865f46b2SCy Schubert c->pp2_header_state = pp2_header_none;
33099cf5bc93SCy Schubert sldns_buffer_clear(c->buffer);
3310b7579f77SDag-Erling Smørgrav }
3311b7579f77SDag-Erling Smørgrav
3312b7579f77SDag-Erling Smørgrav /** do the callback when writing is done */
3313b7579f77SDag-Erling Smørgrav static void
3314b7579f77SDag-Erling Smørgrav tcp_callback_writer(struct comm_point* c)
3315b7579f77SDag-Erling Smørgrav {
3316b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_tcp);
3317369c6923SCy Schubert if(!c->tcp_write_and_read) {
331817d15b25SDag-Erling Smørgrav sldns_buffer_clear(c->buffer);
3319369c6923SCy Schubert c->tcp_byte_count = 0;
3320369c6923SCy Schubert }
3321b7579f77SDag-Erling Smørgrav if(c->tcp_do_toggle_rw)
3322b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 1;
3323b7579f77SDag-Erling Smørgrav /* switch from listening(write) to listening(read) */
3324e86b9096SDag-Erling Smørgrav if(c->tcp_req_info) {
3325e86b9096SDag-Erling Smørgrav tcp_req_info_handle_writedone(c->tcp_req_info);
3326e86b9096SDag-Erling Smørgrav } else {
3327b7579f77SDag-Erling Smørgrav comm_point_stop_listening(c);
3328369c6923SCy Schubert if(c->tcp_write_and_read) {
3329369c6923SCy Schubert fptr_ok(fptr_whitelist_comm_point(c->callback));
3330369c6923SCy Schubert if( (*c->callback)(c, c->cb_arg, NETEVENT_PKT_WRITTEN,
3331369c6923SCy Schubert &c->repinfo) ) {
3332369c6923SCy Schubert comm_point_start_listening(c, -1,
3333f44e67d1SCy Schubert adjusted_tcp_timeout(c));
3334369c6923SCy Schubert }
3335369c6923SCy Schubert } else {
3336f44e67d1SCy Schubert comm_point_start_listening(c, -1,
3337f44e67d1SCy Schubert adjusted_tcp_timeout(c));
3338b7579f77SDag-Erling Smørgrav }
3339e86b9096SDag-Erling Smørgrav }
3340369c6923SCy Schubert }
3341b7579f77SDag-Erling Smørgrav
3342b7579f77SDag-Erling Smørgrav /** do the callback when reading is done */
3343b7579f77SDag-Erling Smørgrav static void
3344b7579f77SDag-Erling Smørgrav tcp_callback_reader(struct comm_point* c)
3345b7579f77SDag-Erling Smørgrav {
3346b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_tcp || c->type == comm_local);
334717d15b25SDag-Erling Smørgrav sldns_buffer_flip(c->buffer);
3348b7579f77SDag-Erling Smørgrav if(c->tcp_do_toggle_rw)
3349b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 0;
3350b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0;
3351e86b9096SDag-Erling Smørgrav if(c->tcp_req_info) {
3352e86b9096SDag-Erling Smørgrav tcp_req_info_handle_readdone(c->tcp_req_info);
3353e86b9096SDag-Erling Smørgrav } else {
3354b7579f77SDag-Erling Smørgrav if(c->type == comm_tcp)
3355b7579f77SDag-Erling Smørgrav comm_point_stop_listening(c);
3356b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point(c->callback));
3357b7579f77SDag-Erling Smørgrav if( (*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, &c->repinfo) ) {
3358f44e67d1SCy Schubert comm_point_start_listening(c, -1,
3359f44e67d1SCy Schubert adjusted_tcp_timeout(c));
3360b7579f77SDag-Erling Smørgrav }
3361b7579f77SDag-Erling Smørgrav }
3362e86b9096SDag-Erling Smørgrav }
3363b7579f77SDag-Erling Smørgrav
336457bddd21SDag-Erling Smørgrav #ifdef HAVE_SSL
33650eefd307SCy Schubert /** true if the ssl handshake error has to be squelched from the logs */
336625039b37SCy Schubert int
33670eefd307SCy Schubert squelch_err_ssl_handshake(unsigned long err)
33680eefd307SCy Schubert {
33690eefd307SCy Schubert if(verbosity >= VERB_QUERY)
33700eefd307SCy Schubert return 0; /* only squelch on low verbosity */
3371a39a5a69SCy Schubert if(ERR_GET_LIB(err) == ERR_LIB_SSL &&
3372a39a5a69SCy Schubert (ERR_GET_REASON(err) == SSL_R_HTTPS_PROXY_REQUEST ||
3373a39a5a69SCy Schubert ERR_GET_REASON(err) == SSL_R_HTTP_REQUEST ||
3374a39a5a69SCy Schubert ERR_GET_REASON(err) == SSL_R_WRONG_VERSION_NUMBER ||
3375a39a5a69SCy Schubert ERR_GET_REASON(err) == SSL_R_SSLV3_ALERT_BAD_CERTIFICATE
33760eefd307SCy Schubert #ifdef SSL_F_TLS_POST_PROCESS_CLIENT_HELLO
3377a39a5a69SCy Schubert || ERR_GET_REASON(err) == SSL_R_NO_SHARED_CIPHER
33780eefd307SCy Schubert #endif
33790eefd307SCy Schubert #ifdef SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO
3380a39a5a69SCy Schubert || ERR_GET_REASON(err) == SSL_R_UNKNOWN_PROTOCOL
3381a39a5a69SCy Schubert || ERR_GET_REASON(err) == SSL_R_UNSUPPORTED_PROTOCOL
33820eefd307SCy Schubert # ifdef SSL_R_VERSION_TOO_LOW
3383a39a5a69SCy Schubert || ERR_GET_REASON(err) == SSL_R_VERSION_TOO_LOW
33840eefd307SCy Schubert # endif
33850eefd307SCy Schubert #endif
3386a39a5a69SCy Schubert ))
33870eefd307SCy Schubert return 1;
33880eefd307SCy Schubert return 0;
33890eefd307SCy Schubert }
33900eefd307SCy Schubert #endif /* HAVE_SSL */
33910eefd307SCy Schubert
3392b7579f77SDag-Erling Smørgrav /** continue ssl handshake */
33938ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL
3394b7579f77SDag-Erling Smørgrav static int
3395b7579f77SDag-Erling Smørgrav ssl_handshake(struct comm_point* c)
3396b7579f77SDag-Erling Smørgrav {
3397b7579f77SDag-Erling Smørgrav int r;
3398b7579f77SDag-Erling Smørgrav if(c->ssl_shake_state == comm_ssl_shake_hs_read) {
3399b7579f77SDag-Erling Smørgrav /* read condition satisfied back to writing */
34005469a995SCy Schubert comm_point_listen_for_rw(c, 0, 1);
3401b7579f77SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_none;
3402b7579f77SDag-Erling Smørgrav return 1;
3403b7579f77SDag-Erling Smørgrav }
3404b7579f77SDag-Erling Smørgrav if(c->ssl_shake_state == comm_ssl_shake_hs_write) {
3405b7579f77SDag-Erling Smørgrav /* write condition satisfied, back to reading */
3406b7579f77SDag-Erling Smørgrav comm_point_listen_for_rw(c, 1, 0);
3407b7579f77SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_none;
3408b7579f77SDag-Erling Smørgrav return 1;
3409b7579f77SDag-Erling Smørgrav }
3410b7579f77SDag-Erling Smørgrav
3411b7579f77SDag-Erling Smørgrav ERR_clear_error();
3412b7579f77SDag-Erling Smørgrav r = SSL_do_handshake(c->ssl);
3413b7579f77SDag-Erling Smørgrav if(r != 1) {
3414b7579f77SDag-Erling Smørgrav int want = SSL_get_error(c->ssl, r);
3415b7579f77SDag-Erling Smørgrav if(want == SSL_ERROR_WANT_READ) {
3416b7579f77SDag-Erling Smørgrav if(c->ssl_shake_state == comm_ssl_shake_read)
3417b7579f77SDag-Erling Smørgrav return 1;
3418b7579f77SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_read;
3419b7579f77SDag-Erling Smørgrav comm_point_listen_for_rw(c, 1, 0);
3420b7579f77SDag-Erling Smørgrav return 1;
3421b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_WRITE) {
3422b7579f77SDag-Erling Smørgrav if(c->ssl_shake_state == comm_ssl_shake_write)
3423b7579f77SDag-Erling Smørgrav return 1;
3424b7579f77SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_write;
3425b7579f77SDag-Erling Smørgrav comm_point_listen_for_rw(c, 0, 1);
3426b7579f77SDag-Erling Smørgrav return 1;
3427b7579f77SDag-Erling Smørgrav } else if(r == 0) {
3428b7579f77SDag-Erling Smørgrav return 0; /* closed */
3429b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_SYSCALL) {
3430b7579f77SDag-Erling Smørgrav /* SYSCALL and errno==0 means closed uncleanly */
3431091e9e46SCy Schubert #ifdef EPIPE
3432091e9e46SCy Schubert if(errno == EPIPE && verbosity < 2)
3433091e9e46SCy Schubert return 0; /* silence 'broken pipe' */
3434091e9e46SCy Schubert #endif
3435091e9e46SCy Schubert #ifdef ECONNRESET
3436091e9e46SCy Schubert if(errno == ECONNRESET && verbosity < 2)
3437091e9e46SCy Schubert return 0; /* silence reset by peer */
3438091e9e46SCy Schubert #endif
3439a39a5a69SCy Schubert if(!tcp_connect_errno_needs_log(
3440865f46b2SCy Schubert (struct sockaddr*)&c->repinfo.remote_addr,
3441865f46b2SCy Schubert c->repinfo.remote_addrlen))
3442a39a5a69SCy Schubert return 0; /* silence connect failures that
3443a39a5a69SCy Schubert show up because after connect this is the
3444a39a5a69SCy Schubert first system call that accesses the socket */
3445b7579f77SDag-Erling Smørgrav if(errno != 0)
3446b7579f77SDag-Erling Smørgrav log_err("SSL_handshake syscall: %s",
3447b7579f77SDag-Erling Smørgrav strerror(errno));
3448b7579f77SDag-Erling Smørgrav return 0;
3449b7579f77SDag-Erling Smørgrav } else {
34500eefd307SCy Schubert unsigned long err = ERR_get_error();
34510eefd307SCy Schubert if(!squelch_err_ssl_handshake(err)) {
3452b7c0c8c1SCy Schubert long vr;
3453103ba509SCy Schubert log_crypto_err_io_code("ssl handshake failed",
3454103ba509SCy Schubert want, err);
3455b7c0c8c1SCy Schubert if((vr=SSL_get_verify_result(c->ssl)) != 0)
3456b7c0c8c1SCy Schubert log_err("ssl handshake cert error: %s",
3457b7c0c8c1SCy Schubert X509_verify_cert_error_string(
3458b7c0c8c1SCy Schubert vr));
3459865f46b2SCy Schubert log_addr(VERB_OPS, "ssl handshake failed",
3460865f46b2SCy Schubert &c->repinfo.remote_addr,
3461865f46b2SCy Schubert c->repinfo.remote_addrlen);
34620eefd307SCy Schubert }
3463b7579f77SDag-Erling Smørgrav return 0;
3464b7579f77SDag-Erling Smørgrav }
3465b7579f77SDag-Erling Smørgrav }
3466b7579f77SDag-Erling Smørgrav /* this is where peer verification could take place */
346757bddd21SDag-Erling Smørgrav if((SSL_get_verify_mode(c->ssl)&SSL_VERIFY_PEER)) {
346857bddd21SDag-Erling Smørgrav /* verification */
346957bddd21SDag-Erling Smørgrav if(SSL_get_verify_result(c->ssl) == X509_V_OK) {
34705469a995SCy Schubert #ifdef HAVE_SSL_GET1_PEER_CERTIFICATE
34715469a995SCy Schubert X509* x = SSL_get1_peer_certificate(c->ssl);
34725469a995SCy Schubert #else
347357bddd21SDag-Erling Smørgrav X509* x = SSL_get_peer_certificate(c->ssl);
34745469a995SCy Schubert #endif
347557bddd21SDag-Erling Smørgrav if(!x) {
347657bddd21SDag-Erling Smørgrav log_addr(VERB_ALGO, "SSL connection failed: "
347757bddd21SDag-Erling Smørgrav "no certificate",
3478865f46b2SCy Schubert &c->repinfo.remote_addr,
3479865f46b2SCy Schubert c->repinfo.remote_addrlen);
348057bddd21SDag-Erling Smørgrav return 0;
348157bddd21SDag-Erling Smørgrav }
348257bddd21SDag-Erling Smørgrav log_cert(VERB_ALGO, "peer certificate", x);
348357bddd21SDag-Erling Smørgrav #ifdef HAVE_SSL_GET0_PEERNAME
348457bddd21SDag-Erling Smørgrav if(SSL_get0_peername(c->ssl)) {
348557bddd21SDag-Erling Smørgrav char buf[255];
348657bddd21SDag-Erling Smørgrav snprintf(buf, sizeof(buf), "SSL connection "
348757bddd21SDag-Erling Smørgrav "to %s authenticated",
348857bddd21SDag-Erling Smørgrav SSL_get0_peername(c->ssl));
3489865f46b2SCy Schubert log_addr(VERB_ALGO, buf, &c->repinfo.remote_addr,
3490865f46b2SCy Schubert c->repinfo.remote_addrlen);
349157bddd21SDag-Erling Smørgrav } else {
349257bddd21SDag-Erling Smørgrav #endif
349357bddd21SDag-Erling Smørgrav log_addr(VERB_ALGO, "SSL connection "
3494865f46b2SCy Schubert "authenticated", &c->repinfo.remote_addr,
3495865f46b2SCy Schubert c->repinfo.remote_addrlen);
349657bddd21SDag-Erling Smørgrav #ifdef HAVE_SSL_GET0_PEERNAME
349757bddd21SDag-Erling Smørgrav }
349857bddd21SDag-Erling Smørgrav #endif
349957bddd21SDag-Erling Smørgrav X509_free(x);
350057bddd21SDag-Erling Smørgrav } else {
35015469a995SCy Schubert #ifdef HAVE_SSL_GET1_PEER_CERTIFICATE
35025469a995SCy Schubert X509* x = SSL_get1_peer_certificate(c->ssl);
35035469a995SCy Schubert #else
350457bddd21SDag-Erling Smørgrav X509* x = SSL_get_peer_certificate(c->ssl);
35055469a995SCy Schubert #endif
350657bddd21SDag-Erling Smørgrav if(x) {
350757bddd21SDag-Erling Smørgrav log_cert(VERB_ALGO, "peer certificate", x);
350857bddd21SDag-Erling Smørgrav X509_free(x);
350957bddd21SDag-Erling Smørgrav }
351057bddd21SDag-Erling Smørgrav log_addr(VERB_ALGO, "SSL connection failed: "
351157bddd21SDag-Erling Smørgrav "failed to authenticate",
3512865f46b2SCy Schubert &c->repinfo.remote_addr,
3513865f46b2SCy Schubert c->repinfo.remote_addrlen);
351457bddd21SDag-Erling Smørgrav return 0;
351557bddd21SDag-Erling Smørgrav }
351657bddd21SDag-Erling Smørgrav } else {
351757bddd21SDag-Erling Smørgrav /* unauthenticated, the verify peer flag was not set
351857bddd21SDag-Erling Smørgrav * in c->ssl when the ssl object was created from ssl_ctx */
3519865f46b2SCy Schubert log_addr(VERB_ALGO, "SSL connection", &c->repinfo.remote_addr,
3520865f46b2SCy Schubert c->repinfo.remote_addrlen);
352157bddd21SDag-Erling Smørgrav }
3522b7579f77SDag-Erling Smørgrav
35235469a995SCy Schubert #ifdef HAVE_SSL_GET0_ALPN_SELECTED
3524c0caa2e2SCy Schubert /* check if http2 use is negotiated */
3525c0caa2e2SCy Schubert if(c->type == comm_http && c->h2_session) {
3526c0caa2e2SCy Schubert const unsigned char *alpn;
3527c0caa2e2SCy Schubert unsigned int alpnlen = 0;
3528c0caa2e2SCy Schubert SSL_get0_alpn_selected(c->ssl, &alpn, &alpnlen);
3529c0caa2e2SCy Schubert if(alpnlen == 2 && memcmp("h2", alpn, 2) == 0) {
3530c0caa2e2SCy Schubert /* connection upgraded to HTTP2 */
3531c0caa2e2SCy Schubert c->tcp_do_toggle_rw = 0;
3532c0caa2e2SCy Schubert c->use_h2 = 1;
3533b7c0c8c1SCy Schubert } else {
3534b7c0c8c1SCy Schubert verbose(VERB_ALGO, "client doesn't support HTTP/2");
3535b7c0c8c1SCy Schubert return 0;
3536c0caa2e2SCy Schubert }
3537c0caa2e2SCy Schubert }
35385469a995SCy Schubert #endif
3539c0caa2e2SCy Schubert
3540b7579f77SDag-Erling Smørgrav /* setup listen rw correctly */
3541b7579f77SDag-Erling Smørgrav if(c->tcp_is_reading) {
3542b7579f77SDag-Erling Smørgrav if(c->ssl_shake_state != comm_ssl_shake_read)
3543b7579f77SDag-Erling Smørgrav comm_point_listen_for_rw(c, 1, 0);
3544b7579f77SDag-Erling Smørgrav } else {
35455469a995SCy Schubert comm_point_listen_for_rw(c, 0, 1);
3546b7579f77SDag-Erling Smørgrav }
3547b7579f77SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_none;
3548b7579f77SDag-Erling Smørgrav return 1;
3549b7579f77SDag-Erling Smørgrav }
35508ed2b524SDag-Erling Smørgrav #endif /* HAVE_SSL */
3551b7579f77SDag-Erling Smørgrav
3552b7579f77SDag-Erling Smørgrav /** ssl read callback on TCP */
3553b7579f77SDag-Erling Smørgrav static int
3554b7579f77SDag-Erling Smørgrav ssl_handle_read(struct comm_point* c)
3555b7579f77SDag-Erling Smørgrav {
35568ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL
3557b7579f77SDag-Erling Smørgrav int r;
3558b7579f77SDag-Erling Smørgrav if(c->ssl_shake_state != comm_ssl_shake_none) {
3559b7579f77SDag-Erling Smørgrav if(!ssl_handshake(c))
3560b7579f77SDag-Erling Smørgrav return 0;
3561b7579f77SDag-Erling Smørgrav if(c->ssl_shake_state != comm_ssl_shake_none)
3562b7579f77SDag-Erling Smørgrav return 1;
3563b7579f77SDag-Erling Smørgrav }
3564865f46b2SCy Schubert if(c->pp2_enabled && c->pp2_header_state != pp2_header_done) {
3565865f46b2SCy Schubert struct pp2_header* header = NULL;
3566865f46b2SCy Schubert size_t want_read_size = 0;
3567865f46b2SCy Schubert size_t current_read_size = 0;
3568865f46b2SCy Schubert if(c->pp2_header_state == pp2_header_none) {
3569865f46b2SCy Schubert want_read_size = PP2_HEADER_SIZE;
3570865f46b2SCy Schubert if(sldns_buffer_remaining(c->buffer)<want_read_size) {
3571865f46b2SCy Schubert log_err_addr("proxy_protocol: not enough "
3572865f46b2SCy Schubert "buffer size to read PROXYv2 header", "",
3573865f46b2SCy Schubert &c->repinfo.remote_addr,
3574865f46b2SCy Schubert c->repinfo.remote_addrlen);
3575865f46b2SCy Schubert return 0;
3576865f46b2SCy Schubert }
3577865f46b2SCy Schubert verbose(VERB_ALGO, "proxy_protocol: reading fixed "
3578865f46b2SCy Schubert "part of PROXYv2 header (len %lu)",
3579865f46b2SCy Schubert (unsigned long)want_read_size);
3580865f46b2SCy Schubert current_read_size = want_read_size;
3581865f46b2SCy Schubert if(c->tcp_byte_count < current_read_size) {
3582865f46b2SCy Schubert ERR_clear_error();
3583865f46b2SCy Schubert if((r=SSL_read(c->ssl, (void*)sldns_buffer_at(
3584865f46b2SCy Schubert c->buffer, c->tcp_byte_count),
3585865f46b2SCy Schubert current_read_size -
3586865f46b2SCy Schubert c->tcp_byte_count)) <= 0) {
3587865f46b2SCy Schubert int want = SSL_get_error(c->ssl, r);
3588865f46b2SCy Schubert if(want == SSL_ERROR_ZERO_RETURN) {
3589865f46b2SCy Schubert if(c->tcp_req_info)
3590865f46b2SCy Schubert return tcp_req_info_handle_read_close(c->tcp_req_info);
3591865f46b2SCy Schubert return 0; /* shutdown, closed */
3592865f46b2SCy Schubert } else if(want == SSL_ERROR_WANT_READ) {
3593865f46b2SCy Schubert #ifdef USE_WINSOCK
3594865f46b2SCy Schubert ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
3595865f46b2SCy Schubert #endif
3596865f46b2SCy Schubert return 1; /* read more later */
3597865f46b2SCy Schubert } else if(want == SSL_ERROR_WANT_WRITE) {
3598865f46b2SCy Schubert c->ssl_shake_state = comm_ssl_shake_hs_write;
3599865f46b2SCy Schubert comm_point_listen_for_rw(c, 0, 1);
3600865f46b2SCy Schubert return 1;
3601865f46b2SCy Schubert } else if(want == SSL_ERROR_SYSCALL) {
3602865f46b2SCy Schubert #ifdef ECONNRESET
3603865f46b2SCy Schubert if(errno == ECONNRESET && verbosity < 2)
3604865f46b2SCy Schubert return 0; /* silence reset by peer */
3605865f46b2SCy Schubert #endif
3606865f46b2SCy Schubert if(errno != 0)
3607865f46b2SCy Schubert log_err("SSL_read syscall: %s",
3608865f46b2SCy Schubert strerror(errno));
3609865f46b2SCy Schubert return 0;
3610865f46b2SCy Schubert }
3611103ba509SCy Schubert log_crypto_err_io("could not SSL_read",
3612103ba509SCy Schubert want);
3613865f46b2SCy Schubert return 0;
3614865f46b2SCy Schubert }
3615865f46b2SCy Schubert c->tcp_byte_count += r;
3616103ba509SCy Schubert sldns_buffer_skip(c->buffer, r);
3617865f46b2SCy Schubert if(c->tcp_byte_count != current_read_size) return 1;
3618865f46b2SCy Schubert c->pp2_header_state = pp2_header_init;
3619865f46b2SCy Schubert }
3620865f46b2SCy Schubert }
3621865f46b2SCy Schubert if(c->pp2_header_state == pp2_header_init) {
3622103ba509SCy Schubert int err;
3623103ba509SCy Schubert err = pp2_read_header(
3624103ba509SCy Schubert sldns_buffer_begin(c->buffer),
3625103ba509SCy Schubert sldns_buffer_limit(c->buffer));
3626103ba509SCy Schubert if(err) {
3627865f46b2SCy Schubert log_err("proxy_protocol: could not parse "
3628103ba509SCy Schubert "PROXYv2 header (%s)",
3629103ba509SCy Schubert pp_lookup_error(err));
3630865f46b2SCy Schubert return 0;
3631865f46b2SCy Schubert }
3632103ba509SCy Schubert header = (struct pp2_header*)sldns_buffer_begin(c->buffer);
3633865f46b2SCy Schubert want_read_size = ntohs(header->len);
3634103ba509SCy Schubert if(sldns_buffer_limit(c->buffer) <
3635865f46b2SCy Schubert PP2_HEADER_SIZE + want_read_size) {
3636865f46b2SCy Schubert log_err_addr("proxy_protocol: not enough "
3637865f46b2SCy Schubert "buffer size to read PROXYv2 header", "",
3638865f46b2SCy Schubert &c->repinfo.remote_addr,
3639865f46b2SCy Schubert c->repinfo.remote_addrlen);
3640865f46b2SCy Schubert return 0;
3641865f46b2SCy Schubert }
3642865f46b2SCy Schubert verbose(VERB_ALGO, "proxy_protocol: reading variable "
3643865f46b2SCy Schubert "part of PROXYv2 header (len %lu)",
3644865f46b2SCy Schubert (unsigned long)want_read_size);
3645865f46b2SCy Schubert current_read_size = PP2_HEADER_SIZE + want_read_size;
3646865f46b2SCy Schubert if(want_read_size == 0) {
3647865f46b2SCy Schubert /* nothing more to read; header is complete */
3648865f46b2SCy Schubert c->pp2_header_state = pp2_header_done;
3649865f46b2SCy Schubert } else if(c->tcp_byte_count < current_read_size) {
3650865f46b2SCy Schubert ERR_clear_error();
3651865f46b2SCy Schubert if((r=SSL_read(c->ssl, (void*)sldns_buffer_at(
3652865f46b2SCy Schubert c->buffer, c->tcp_byte_count),
3653865f46b2SCy Schubert current_read_size -
3654865f46b2SCy Schubert c->tcp_byte_count)) <= 0) {
3655865f46b2SCy Schubert int want = SSL_get_error(c->ssl, r);
3656865f46b2SCy Schubert if(want == SSL_ERROR_ZERO_RETURN) {
3657865f46b2SCy Schubert if(c->tcp_req_info)
3658865f46b2SCy Schubert return tcp_req_info_handle_read_close(c->tcp_req_info);
3659865f46b2SCy Schubert return 0; /* shutdown, closed */
3660865f46b2SCy Schubert } else if(want == SSL_ERROR_WANT_READ) {
3661865f46b2SCy Schubert #ifdef USE_WINSOCK
3662865f46b2SCy Schubert ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
3663865f46b2SCy Schubert #endif
3664865f46b2SCy Schubert return 1; /* read more later */
3665865f46b2SCy Schubert } else if(want == SSL_ERROR_WANT_WRITE) {
3666865f46b2SCy Schubert c->ssl_shake_state = comm_ssl_shake_hs_write;
3667865f46b2SCy Schubert comm_point_listen_for_rw(c, 0, 1);
3668865f46b2SCy Schubert return 1;
3669865f46b2SCy Schubert } else if(want == SSL_ERROR_SYSCALL) {
3670865f46b2SCy Schubert #ifdef ECONNRESET
3671865f46b2SCy Schubert if(errno == ECONNRESET && verbosity < 2)
3672865f46b2SCy Schubert return 0; /* silence reset by peer */
3673865f46b2SCy Schubert #endif
3674865f46b2SCy Schubert if(errno != 0)
3675865f46b2SCy Schubert log_err("SSL_read syscall: %s",
3676865f46b2SCy Schubert strerror(errno));
3677865f46b2SCy Schubert return 0;
3678865f46b2SCy Schubert }
3679103ba509SCy Schubert log_crypto_err_io("could not SSL_read",
3680103ba509SCy Schubert want);
3681865f46b2SCy Schubert return 0;
3682865f46b2SCy Schubert }
3683865f46b2SCy Schubert c->tcp_byte_count += r;
3684103ba509SCy Schubert sldns_buffer_skip(c->buffer, r);
3685865f46b2SCy Schubert if(c->tcp_byte_count != current_read_size) return 1;
3686865f46b2SCy Schubert c->pp2_header_state = pp2_header_done;
3687865f46b2SCy Schubert }
3688865f46b2SCy Schubert }
3689865f46b2SCy Schubert if(c->pp2_header_state != pp2_header_done || !header) {
3690865f46b2SCy Schubert log_err_addr("proxy_protocol: wrong state for the "
3691865f46b2SCy Schubert "PROXYv2 header", "", &c->repinfo.remote_addr,
3692865f46b2SCy Schubert c->repinfo.remote_addrlen);
3693865f46b2SCy Schubert return 0;
3694865f46b2SCy Schubert }
3695103ba509SCy Schubert sldns_buffer_flip(c->buffer);
3696865f46b2SCy Schubert if(!consume_pp2_header(c->buffer, &c->repinfo, 1)) {
3697865f46b2SCy Schubert log_err_addr("proxy_protocol: could not consume "
3698865f46b2SCy Schubert "PROXYv2 header", "", &c->repinfo.remote_addr,
3699865f46b2SCy Schubert c->repinfo.remote_addrlen);
3700865f46b2SCy Schubert return 0;
3701865f46b2SCy Schubert }
3702865f46b2SCy Schubert verbose(VERB_ALGO, "proxy_protocol: successful read of "
3703865f46b2SCy Schubert "PROXYv2 header");
3704865f46b2SCy Schubert /* Clear and reset the buffer to read the following
3705865f46b2SCy Schubert * DNS packet(s). */
3706865f46b2SCy Schubert sldns_buffer_clear(c->buffer);
3707865f46b2SCy Schubert c->tcp_byte_count = 0;
3708865f46b2SCy Schubert return 1;
3709865f46b2SCy Schubert }
3710b7579f77SDag-Erling Smørgrav if(c->tcp_byte_count < sizeof(uint16_t)) {
3711b7579f77SDag-Erling Smørgrav /* read length bytes */
3712b7579f77SDag-Erling Smørgrav ERR_clear_error();
371317d15b25SDag-Erling Smørgrav if((r=SSL_read(c->ssl, (void*)sldns_buffer_at(c->buffer,
3714b7579f77SDag-Erling Smørgrav c->tcp_byte_count), (int)(sizeof(uint16_t) -
3715b7579f77SDag-Erling Smørgrav c->tcp_byte_count))) <= 0) {
3716b7579f77SDag-Erling Smørgrav int want = SSL_get_error(c->ssl, r);
3717b7579f77SDag-Erling Smørgrav if(want == SSL_ERROR_ZERO_RETURN) {
3718e86b9096SDag-Erling Smørgrav if(c->tcp_req_info)
3719e86b9096SDag-Erling Smørgrav return tcp_req_info_handle_read_close(c->tcp_req_info);
3720b7579f77SDag-Erling Smørgrav return 0; /* shutdown, closed */
3721b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_READ) {
37225469a995SCy Schubert #ifdef USE_WINSOCK
37233bd4df0aSDag-Erling Smørgrav ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
37245469a995SCy Schubert #endif
3725b7579f77SDag-Erling Smørgrav return 1; /* read more later */
3726b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_WRITE) {
3727b7579f77SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_hs_write;
3728b7579f77SDag-Erling Smørgrav comm_point_listen_for_rw(c, 0, 1);
3729b7579f77SDag-Erling Smørgrav return 1;
3730b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_SYSCALL) {
3731e86b9096SDag-Erling Smørgrav #ifdef ECONNRESET
3732e86b9096SDag-Erling Smørgrav if(errno == ECONNRESET && verbosity < 2)
3733e86b9096SDag-Erling Smørgrav return 0; /* silence reset by peer */
3734e86b9096SDag-Erling Smørgrav #endif
3735b7579f77SDag-Erling Smørgrav if(errno != 0)
3736b7579f77SDag-Erling Smørgrav log_err("SSL_read syscall: %s",
3737b7579f77SDag-Erling Smørgrav strerror(errno));
3738b7579f77SDag-Erling Smørgrav return 0;
3739b7579f77SDag-Erling Smørgrav }
3740103ba509SCy Schubert log_crypto_err_io("could not SSL_read", want);
3741b7579f77SDag-Erling Smørgrav return 0;
3742b7579f77SDag-Erling Smørgrav }
3743b7579f77SDag-Erling Smørgrav c->tcp_byte_count += r;
37443bd4df0aSDag-Erling Smørgrav if(c->tcp_byte_count < sizeof(uint16_t))
3745b7579f77SDag-Erling Smørgrav return 1;
374617d15b25SDag-Erling Smørgrav if(sldns_buffer_read_u16_at(c->buffer, 0) >
374717d15b25SDag-Erling Smørgrav sldns_buffer_capacity(c->buffer)) {
3748b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "ssl: dropped larger than buffer");
3749b7579f77SDag-Erling Smørgrav return 0;
3750b7579f77SDag-Erling Smørgrav }
375117d15b25SDag-Erling Smørgrav sldns_buffer_set_limit(c->buffer,
375217d15b25SDag-Erling Smørgrav sldns_buffer_read_u16_at(c->buffer, 0));
375317d15b25SDag-Erling Smørgrav if(sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE) {
3754b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "ssl: dropped bogus too short.");
3755b7579f77SDag-Erling Smørgrav return 0;
3756b7579f77SDag-Erling Smørgrav }
37573bd4df0aSDag-Erling Smørgrav sldns_buffer_skip(c->buffer, (ssize_t)(c->tcp_byte_count-sizeof(uint16_t)));
3758b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "Reading ssl tcp query of length %d",
375917d15b25SDag-Erling Smørgrav (int)sldns_buffer_limit(c->buffer));
3760b7579f77SDag-Erling Smørgrav }
37613bd4df0aSDag-Erling Smørgrav if(sldns_buffer_remaining(c->buffer) > 0) {
3762b7579f77SDag-Erling Smørgrav ERR_clear_error();
376317d15b25SDag-Erling Smørgrav r = SSL_read(c->ssl, (void*)sldns_buffer_current(c->buffer),
376417d15b25SDag-Erling Smørgrav (int)sldns_buffer_remaining(c->buffer));
3765b7579f77SDag-Erling Smørgrav if(r <= 0) {
3766b7579f77SDag-Erling Smørgrav int want = SSL_get_error(c->ssl, r);
3767b7579f77SDag-Erling Smørgrav if(want == SSL_ERROR_ZERO_RETURN) {
3768e86b9096SDag-Erling Smørgrav if(c->tcp_req_info)
3769e86b9096SDag-Erling Smørgrav return tcp_req_info_handle_read_close(c->tcp_req_info);
3770b7579f77SDag-Erling Smørgrav return 0; /* shutdown, closed */
3771b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_READ) {
37725469a995SCy Schubert #ifdef USE_WINSOCK
37733bd4df0aSDag-Erling Smørgrav ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
37745469a995SCy Schubert #endif
3775b7579f77SDag-Erling Smørgrav return 1; /* read more later */
3776b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_WRITE) {
3777b7579f77SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_hs_write;
3778b7579f77SDag-Erling Smørgrav comm_point_listen_for_rw(c, 0, 1);
3779b7579f77SDag-Erling Smørgrav return 1;
3780b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_SYSCALL) {
3781e86b9096SDag-Erling Smørgrav #ifdef ECONNRESET
3782e86b9096SDag-Erling Smørgrav if(errno == ECONNRESET && verbosity < 2)
3783e86b9096SDag-Erling Smørgrav return 0; /* silence reset by peer */
3784e86b9096SDag-Erling Smørgrav #endif
3785b7579f77SDag-Erling Smørgrav if(errno != 0)
3786b7579f77SDag-Erling Smørgrav log_err("SSL_read syscall: %s",
3787b7579f77SDag-Erling Smørgrav strerror(errno));
3788b7579f77SDag-Erling Smørgrav return 0;
3789b7579f77SDag-Erling Smørgrav }
3790103ba509SCy Schubert log_crypto_err_io("could not SSL_read", want);
3791b7579f77SDag-Erling Smørgrav return 0;
3792b7579f77SDag-Erling Smørgrav }
379317d15b25SDag-Erling Smørgrav sldns_buffer_skip(c->buffer, (ssize_t)r);
37943bd4df0aSDag-Erling Smørgrav }
379517d15b25SDag-Erling Smørgrav if(sldns_buffer_remaining(c->buffer) <= 0) {
3796b7579f77SDag-Erling Smørgrav tcp_callback_reader(c);
3797b7579f77SDag-Erling Smørgrav }
3798b7579f77SDag-Erling Smørgrav return 1;
37998ed2b524SDag-Erling Smørgrav #else
38008ed2b524SDag-Erling Smørgrav (void)c;
38018ed2b524SDag-Erling Smørgrav return 0;
38028ed2b524SDag-Erling Smørgrav #endif /* HAVE_SSL */
3803b7579f77SDag-Erling Smørgrav }
3804b7579f77SDag-Erling Smørgrav
3805b7579f77SDag-Erling Smørgrav /** ssl write callback on TCP */
3806b7579f77SDag-Erling Smørgrav static int
3807b7579f77SDag-Erling Smørgrav ssl_handle_write(struct comm_point* c)
3808b7579f77SDag-Erling Smørgrav {
38098ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL
3810b7579f77SDag-Erling Smørgrav int r;
3811b7579f77SDag-Erling Smørgrav if(c->ssl_shake_state != comm_ssl_shake_none) {
3812b7579f77SDag-Erling Smørgrav if(!ssl_handshake(c))
3813b7579f77SDag-Erling Smørgrav return 0;
3814b7579f77SDag-Erling Smørgrav if(c->ssl_shake_state != comm_ssl_shake_none)
3815b7579f77SDag-Erling Smørgrav return 1;
3816b7579f77SDag-Erling Smørgrav }
3817b7579f77SDag-Erling Smørgrav /* ignore return, if fails we may simply block */
38180eefd307SCy Schubert (void)SSL_set_mode(c->ssl, (long)SSL_MODE_ENABLE_PARTIAL_WRITE);
3819369c6923SCy Schubert if((c->tcp_write_and_read?c->tcp_write_byte_count:c->tcp_byte_count) < sizeof(uint16_t)) {
3820369c6923SCy Schubert uint16_t len = htons(c->tcp_write_and_read?c->tcp_write_pkt_len:sldns_buffer_limit(c->buffer));
3821b7579f77SDag-Erling Smørgrav ERR_clear_error();
3822369c6923SCy Schubert if(c->tcp_write_and_read) {
3823369c6923SCy Schubert if(c->tcp_write_pkt_len + 2 < LDNS_RR_BUF_SIZE) {
3824369c6923SCy Schubert /* combine the tcp length and the query for
3825369c6923SCy Schubert * write, this emulates writev */
3826369c6923SCy Schubert uint8_t buf[LDNS_RR_BUF_SIZE];
3827369c6923SCy Schubert memmove(buf, &len, sizeof(uint16_t));
3828369c6923SCy Schubert memmove(buf+sizeof(uint16_t),
3829369c6923SCy Schubert c->tcp_write_pkt,
3830369c6923SCy Schubert c->tcp_write_pkt_len);
3831369c6923SCy Schubert r = SSL_write(c->ssl,
3832369c6923SCy Schubert (void*)(buf+c->tcp_write_byte_count),
3833369c6923SCy Schubert c->tcp_write_pkt_len + 2 -
3834369c6923SCy Schubert c->tcp_write_byte_count);
3835369c6923SCy Schubert } else {
3836369c6923SCy Schubert r = SSL_write(c->ssl,
3837369c6923SCy Schubert (void*)(((uint8_t*)&len)+c->tcp_write_byte_count),
3838369c6923SCy Schubert (int)(sizeof(uint16_t)-c->tcp_write_byte_count));
3839369c6923SCy Schubert }
3840369c6923SCy Schubert } else if(sizeof(uint16_t)+sldns_buffer_remaining(c->buffer) <
38410fb34990SDag-Erling Smørgrav LDNS_RR_BUF_SIZE) {
38420fb34990SDag-Erling Smørgrav /* combine the tcp length and the query for write,
38430fb34990SDag-Erling Smørgrav * this emulates writev */
38440fb34990SDag-Erling Smørgrav uint8_t buf[LDNS_RR_BUF_SIZE];
38450fb34990SDag-Erling Smørgrav memmove(buf, &len, sizeof(uint16_t));
38460fb34990SDag-Erling Smørgrav memmove(buf+sizeof(uint16_t),
38470fb34990SDag-Erling Smørgrav sldns_buffer_current(c->buffer),
38480fb34990SDag-Erling Smørgrav sldns_buffer_remaining(c->buffer));
38490fb34990SDag-Erling Smørgrav r = SSL_write(c->ssl, (void*)(buf+c->tcp_byte_count),
38500fb34990SDag-Erling Smørgrav (int)(sizeof(uint16_t)+
38510fb34990SDag-Erling Smørgrav sldns_buffer_remaining(c->buffer)
38520fb34990SDag-Erling Smørgrav - c->tcp_byte_count));
38530fb34990SDag-Erling Smørgrav } else {
3854b7579f77SDag-Erling Smørgrav r = SSL_write(c->ssl,
3855b7579f77SDag-Erling Smørgrav (void*)(((uint8_t*)&len)+c->tcp_byte_count),
3856b7579f77SDag-Erling Smørgrav (int)(sizeof(uint16_t)-c->tcp_byte_count));
38570fb34990SDag-Erling Smørgrav }
3858b7579f77SDag-Erling Smørgrav if(r <= 0) {
3859b7579f77SDag-Erling Smørgrav int want = SSL_get_error(c->ssl, r);
3860b7579f77SDag-Erling Smørgrav if(want == SSL_ERROR_ZERO_RETURN) {
3861b7579f77SDag-Erling Smørgrav return 0; /* closed */
3862b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_READ) {
3863e86b9096SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_hs_read;
3864b7579f77SDag-Erling Smørgrav comm_point_listen_for_rw(c, 1, 0);
3865b7579f77SDag-Erling Smørgrav return 1; /* wait for read condition */
3866b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_WRITE) {
38675469a995SCy Schubert #ifdef USE_WINSOCK
38683bd4df0aSDag-Erling Smørgrav ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
38695469a995SCy Schubert #endif
3870b7579f77SDag-Erling Smørgrav return 1; /* write more later */
3871b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_SYSCALL) {
3872e86b9096SDag-Erling Smørgrav #ifdef EPIPE
3873e86b9096SDag-Erling Smørgrav if(errno == EPIPE && verbosity < 2)
3874e86b9096SDag-Erling Smørgrav return 0; /* silence 'broken pipe' */
3875e86b9096SDag-Erling Smørgrav #endif
3876b7579f77SDag-Erling Smørgrav if(errno != 0)
3877b7579f77SDag-Erling Smørgrav log_err("SSL_write syscall: %s",
3878b7579f77SDag-Erling Smørgrav strerror(errno));
3879b7579f77SDag-Erling Smørgrav return 0;
3880b7579f77SDag-Erling Smørgrav }
3881103ba509SCy Schubert log_crypto_err_io("could not SSL_write", want);
3882b7579f77SDag-Erling Smørgrav return 0;
3883b7579f77SDag-Erling Smørgrav }
3884369c6923SCy Schubert if(c->tcp_write_and_read) {
3885369c6923SCy Schubert c->tcp_write_byte_count += r;
3886369c6923SCy Schubert if(c->tcp_write_byte_count < sizeof(uint16_t))
3887369c6923SCy Schubert return 1;
3888369c6923SCy Schubert } else {
3889b7579f77SDag-Erling Smørgrav c->tcp_byte_count += r;
3890b7579f77SDag-Erling Smørgrav if(c->tcp_byte_count < sizeof(uint16_t))
3891b7579f77SDag-Erling Smørgrav return 1;
389217d15b25SDag-Erling Smørgrav sldns_buffer_set_position(c->buffer, c->tcp_byte_count -
3893b7579f77SDag-Erling Smørgrav sizeof(uint16_t));
3894369c6923SCy Schubert }
3895369c6923SCy Schubert if((!c->tcp_write_and_read && sldns_buffer_remaining(c->buffer) == 0) || (c->tcp_write_and_read && c->tcp_write_byte_count == c->tcp_write_pkt_len + 2)) {
3896b7579f77SDag-Erling Smørgrav tcp_callback_writer(c);
3897b7579f77SDag-Erling Smørgrav return 1;
3898b7579f77SDag-Erling Smørgrav }
3899b7579f77SDag-Erling Smørgrav }
3900369c6923SCy Schubert log_assert(c->tcp_write_and_read || sldns_buffer_remaining(c->buffer) > 0);
3901369c6923SCy Schubert log_assert(!c->tcp_write_and_read || c->tcp_write_byte_count < c->tcp_write_pkt_len + 2);
3902b7579f77SDag-Erling Smørgrav ERR_clear_error();
3903369c6923SCy Schubert if(c->tcp_write_and_read) {
3904369c6923SCy Schubert r = SSL_write(c->ssl, (void*)(c->tcp_write_pkt + c->tcp_write_byte_count - 2),
3905369c6923SCy Schubert (int)(c->tcp_write_pkt_len + 2 - c->tcp_write_byte_count));
3906369c6923SCy Schubert } else {
390717d15b25SDag-Erling Smørgrav r = SSL_write(c->ssl, (void*)sldns_buffer_current(c->buffer),
390817d15b25SDag-Erling Smørgrav (int)sldns_buffer_remaining(c->buffer));
3909369c6923SCy Schubert }
3910b7579f77SDag-Erling Smørgrav if(r <= 0) {
3911b7579f77SDag-Erling Smørgrav int want = SSL_get_error(c->ssl, r);
3912b7579f77SDag-Erling Smørgrav if(want == SSL_ERROR_ZERO_RETURN) {
3913b7579f77SDag-Erling Smørgrav return 0; /* closed */
3914b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_READ) {
3915e86b9096SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_hs_read;
3916b7579f77SDag-Erling Smørgrav comm_point_listen_for_rw(c, 1, 0);
3917b7579f77SDag-Erling Smørgrav return 1; /* wait for read condition */
3918b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_WRITE) {
39195469a995SCy Schubert #ifdef USE_WINSOCK
39203bd4df0aSDag-Erling Smørgrav ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
39215469a995SCy Schubert #endif
3922b7579f77SDag-Erling Smørgrav return 1; /* write more later */
3923b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_SYSCALL) {
3924e86b9096SDag-Erling Smørgrav #ifdef EPIPE
3925e86b9096SDag-Erling Smørgrav if(errno == EPIPE && verbosity < 2)
3926e86b9096SDag-Erling Smørgrav return 0; /* silence 'broken pipe' */
3927e86b9096SDag-Erling Smørgrav #endif
3928b7579f77SDag-Erling Smørgrav if(errno != 0)
3929b7579f77SDag-Erling Smørgrav log_err("SSL_write syscall: %s",
3930b7579f77SDag-Erling Smørgrav strerror(errno));
3931b7579f77SDag-Erling Smørgrav return 0;
3932b7579f77SDag-Erling Smørgrav }
3933103ba509SCy Schubert log_crypto_err_io("could not SSL_write", want);
3934b7579f77SDag-Erling Smørgrav return 0;
3935b7579f77SDag-Erling Smørgrav }
3936369c6923SCy Schubert if(c->tcp_write_and_read) {
3937369c6923SCy Schubert c->tcp_write_byte_count += r;
3938369c6923SCy Schubert } else {
393917d15b25SDag-Erling Smørgrav sldns_buffer_skip(c->buffer, (ssize_t)r);
3940369c6923SCy Schubert }
3941b7579f77SDag-Erling Smørgrav
3942369c6923SCy Schubert if((!c->tcp_write_and_read && sldns_buffer_remaining(c->buffer) == 0) || (c->tcp_write_and_read && c->tcp_write_byte_count == c->tcp_write_pkt_len + 2)) {
3943b7579f77SDag-Erling Smørgrav tcp_callback_writer(c);
3944b7579f77SDag-Erling Smørgrav }
3945b7579f77SDag-Erling Smørgrav return 1;
39468ed2b524SDag-Erling Smørgrav #else
39478ed2b524SDag-Erling Smørgrav (void)c;
39488ed2b524SDag-Erling Smørgrav return 0;
39498ed2b524SDag-Erling Smørgrav #endif /* HAVE_SSL */
3950b7579f77SDag-Erling Smørgrav }
3951b7579f77SDag-Erling Smørgrav
3952b7579f77SDag-Erling Smørgrav /** handle ssl tcp connection with dns contents */
3953b7579f77SDag-Erling Smørgrav static int
3954369c6923SCy Schubert ssl_handle_it(struct comm_point* c, int is_write)
3955b7579f77SDag-Erling Smørgrav {
3956369c6923SCy Schubert /* handle case where renegotiation wants read during write call
3957369c6923SCy Schubert * or write during read calls */
3958369c6923SCy Schubert if(is_write && c->ssl_shake_state == comm_ssl_shake_hs_write)
3959369c6923SCy Schubert return ssl_handle_read(c);
3960369c6923SCy Schubert else if(!is_write && c->ssl_shake_state == comm_ssl_shake_hs_read)
3961369c6923SCy Schubert return ssl_handle_write(c);
3962369c6923SCy Schubert /* handle read events for read operation and write events for a
3963369c6923SCy Schubert * write operation */
3964369c6923SCy Schubert else if(!is_write)
3965b7579f77SDag-Erling Smørgrav return ssl_handle_read(c);
3966b7579f77SDag-Erling Smørgrav return ssl_handle_write(c);
3967b7579f77SDag-Erling Smørgrav }
3968b7579f77SDag-Erling Smørgrav
3969865f46b2SCy Schubert /**
3970865f46b2SCy Schubert * Handle tcp reading callback.
3971b7579f77SDag-Erling Smørgrav * @param fd: file descriptor of socket.
3972b7579f77SDag-Erling Smørgrav * @param c: comm point to read from into buffer.
3973b7579f77SDag-Erling Smørgrav * @param short_ok: if true, very short packets are OK (for comm_local).
3974b7579f77SDag-Erling Smørgrav * @return: 0 on error
3975b7579f77SDag-Erling Smørgrav */
3976b7579f77SDag-Erling Smørgrav static int
3977b7579f77SDag-Erling Smørgrav comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok)
3978b7579f77SDag-Erling Smørgrav {
3979b7579f77SDag-Erling Smørgrav ssize_t r;
3980865f46b2SCy Schubert int recv_initial = 0;
3981b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_tcp || c->type == comm_local);
3982b7579f77SDag-Erling Smørgrav if(c->ssl)
3983369c6923SCy Schubert return ssl_handle_it(c, 0);
3984369c6923SCy Schubert if(!c->tcp_is_reading && !c->tcp_write_and_read)
3985b7579f77SDag-Erling Smørgrav return 0;
3986b7579f77SDag-Erling Smørgrav
3987b7579f77SDag-Erling Smørgrav log_assert(fd != -1);
3988865f46b2SCy Schubert if(c->pp2_enabled && c->pp2_header_state != pp2_header_done) {
3989865f46b2SCy Schubert struct pp2_header* header = NULL;
3990865f46b2SCy Schubert size_t want_read_size = 0;
3991865f46b2SCy Schubert size_t current_read_size = 0;
3992865f46b2SCy Schubert if(c->pp2_header_state == pp2_header_none) {
3993865f46b2SCy Schubert want_read_size = PP2_HEADER_SIZE;
3994865f46b2SCy Schubert if(sldns_buffer_remaining(c->buffer)<want_read_size) {
3995865f46b2SCy Schubert log_err_addr("proxy_protocol: not enough "
3996865f46b2SCy Schubert "buffer size to read PROXYv2 header", "",
3997865f46b2SCy Schubert &c->repinfo.remote_addr,
3998865f46b2SCy Schubert c->repinfo.remote_addrlen);
3999865f46b2SCy Schubert return 0;
4000865f46b2SCy Schubert }
4001865f46b2SCy Schubert verbose(VERB_ALGO, "proxy_protocol: reading fixed "
4002865f46b2SCy Schubert "part of PROXYv2 header (len %lu)",
4003865f46b2SCy Schubert (unsigned long)want_read_size);
4004865f46b2SCy Schubert current_read_size = want_read_size;
4005865f46b2SCy Schubert if(c->tcp_byte_count < current_read_size) {
4006865f46b2SCy Schubert r = recv(fd, (void*)sldns_buffer_at(c->buffer,
4007865f46b2SCy Schubert c->tcp_byte_count),
4008865f46b2SCy Schubert current_read_size-c->tcp_byte_count, MSG_DONTWAIT);
400964d318eaSCy Schubert if(r == 0) {
401064d318eaSCy Schubert if(c->tcp_req_info)
401164d318eaSCy Schubert return tcp_req_info_handle_read_close(c->tcp_req_info);
401264d318eaSCy Schubert return 0;
401364d318eaSCy Schubert } else if(r == -1) {
4014865f46b2SCy Schubert goto recv_error_initial;
4015865f46b2SCy Schubert }
4016865f46b2SCy Schubert c->tcp_byte_count += r;
4017103ba509SCy Schubert sldns_buffer_skip(c->buffer, r);
4018865f46b2SCy Schubert if(c->tcp_byte_count != current_read_size) return 1;
4019865f46b2SCy Schubert c->pp2_header_state = pp2_header_init;
4020865f46b2SCy Schubert }
4021865f46b2SCy Schubert }
4022865f46b2SCy Schubert if(c->pp2_header_state == pp2_header_init) {
4023103ba509SCy Schubert int err;
4024103ba509SCy Schubert err = pp2_read_header(
4025103ba509SCy Schubert sldns_buffer_begin(c->buffer),
4026103ba509SCy Schubert sldns_buffer_limit(c->buffer));
4027103ba509SCy Schubert if(err) {
4028865f46b2SCy Schubert log_err("proxy_protocol: could not parse "
4029103ba509SCy Schubert "PROXYv2 header (%s)",
4030103ba509SCy Schubert pp_lookup_error(err));
4031865f46b2SCy Schubert return 0;
4032865f46b2SCy Schubert }
4033103ba509SCy Schubert header = (struct pp2_header*)sldns_buffer_begin(c->buffer);
4034865f46b2SCy Schubert want_read_size = ntohs(header->len);
4035103ba509SCy Schubert if(sldns_buffer_limit(c->buffer) <
4036865f46b2SCy Schubert PP2_HEADER_SIZE + want_read_size) {
4037865f46b2SCy Schubert log_err_addr("proxy_protocol: not enough "
4038865f46b2SCy Schubert "buffer size to read PROXYv2 header", "",
4039865f46b2SCy Schubert &c->repinfo.remote_addr,
4040865f46b2SCy Schubert c->repinfo.remote_addrlen);
4041865f46b2SCy Schubert return 0;
4042865f46b2SCy Schubert }
4043865f46b2SCy Schubert verbose(VERB_ALGO, "proxy_protocol: reading variable "
4044865f46b2SCy Schubert "part of PROXYv2 header (len %lu)",
4045865f46b2SCy Schubert (unsigned long)want_read_size);
4046865f46b2SCy Schubert current_read_size = PP2_HEADER_SIZE + want_read_size;
4047865f46b2SCy Schubert if(want_read_size == 0) {
4048865f46b2SCy Schubert /* nothing more to read; header is complete */
4049865f46b2SCy Schubert c->pp2_header_state = pp2_header_done;
4050865f46b2SCy Schubert } else if(c->tcp_byte_count < current_read_size) {
4051865f46b2SCy Schubert r = recv(fd, (void*)sldns_buffer_at(c->buffer,
4052865f46b2SCy Schubert c->tcp_byte_count),
4053865f46b2SCy Schubert current_read_size-c->tcp_byte_count, MSG_DONTWAIT);
4054865f46b2SCy Schubert if(r == 0) {
4055865f46b2SCy Schubert if(c->tcp_req_info)
4056865f46b2SCy Schubert return tcp_req_info_handle_read_close(c->tcp_req_info);
4057865f46b2SCy Schubert return 0;
4058865f46b2SCy Schubert } else if(r == -1) {
4059865f46b2SCy Schubert goto recv_error;
4060865f46b2SCy Schubert }
4061865f46b2SCy Schubert c->tcp_byte_count += r;
4062103ba509SCy Schubert sldns_buffer_skip(c->buffer, r);
4063865f46b2SCy Schubert if(c->tcp_byte_count != current_read_size) return 1;
4064865f46b2SCy Schubert c->pp2_header_state = pp2_header_done;
4065865f46b2SCy Schubert }
4066865f46b2SCy Schubert }
4067865f46b2SCy Schubert if(c->pp2_header_state != pp2_header_done || !header) {
4068865f46b2SCy Schubert log_err_addr("proxy_protocol: wrong state for the "
4069865f46b2SCy Schubert "PROXYv2 header", "", &c->repinfo.remote_addr,
4070865f46b2SCy Schubert c->repinfo.remote_addrlen);
4071865f46b2SCy Schubert return 0;
4072865f46b2SCy Schubert }
4073103ba509SCy Schubert sldns_buffer_flip(c->buffer);
4074865f46b2SCy Schubert if(!consume_pp2_header(c->buffer, &c->repinfo, 1)) {
4075865f46b2SCy Schubert log_err_addr("proxy_protocol: could not consume "
4076865f46b2SCy Schubert "PROXYv2 header", "", &c->repinfo.remote_addr,
4077865f46b2SCy Schubert c->repinfo.remote_addrlen);
4078865f46b2SCy Schubert return 0;
4079865f46b2SCy Schubert }
4080865f46b2SCy Schubert verbose(VERB_ALGO, "proxy_protocol: successful read of "
4081865f46b2SCy Schubert "PROXYv2 header");
4082865f46b2SCy Schubert /* Clear and reset the buffer to read the following
4083865f46b2SCy Schubert * DNS packet(s). */
4084865f46b2SCy Schubert sldns_buffer_clear(c->buffer);
4085865f46b2SCy Schubert c->tcp_byte_count = 0;
4086865f46b2SCy Schubert return 1;
4087865f46b2SCy Schubert }
4088865f46b2SCy Schubert
4089865f46b2SCy Schubert if(c->tcp_byte_count < sizeof(uint16_t)) {
4090865f46b2SCy Schubert /* read length bytes */
4091865f46b2SCy Schubert r = recv(fd,(void*)sldns_buffer_at(c->buffer,c->tcp_byte_count),
4092865f46b2SCy Schubert sizeof(uint16_t)-c->tcp_byte_count, MSG_DONTWAIT);
4093865f46b2SCy Schubert if(r == 0) {
4094865f46b2SCy Schubert if(c->tcp_req_info)
4095865f46b2SCy Schubert return tcp_req_info_handle_read_close(c->tcp_req_info);
4096865f46b2SCy Schubert return 0;
4097865f46b2SCy Schubert } else if(r == -1) {
4098865f46b2SCy Schubert if(c->pp2_enabled) goto recv_error;
4099865f46b2SCy Schubert goto recv_error_initial;
4100865f46b2SCy Schubert }
4101865f46b2SCy Schubert c->tcp_byte_count += r;
4102865f46b2SCy Schubert if(c->tcp_byte_count != sizeof(uint16_t))
4103865f46b2SCy Schubert return 1;
4104865f46b2SCy Schubert if(sldns_buffer_read_u16_at(c->buffer, 0) >
4105865f46b2SCy Schubert sldns_buffer_capacity(c->buffer)) {
4106865f46b2SCy Schubert verbose(VERB_QUERY, "tcp: dropped larger than buffer");
4107865f46b2SCy Schubert return 0;
4108865f46b2SCy Schubert }
4109865f46b2SCy Schubert sldns_buffer_set_limit(c->buffer,
4110865f46b2SCy Schubert sldns_buffer_read_u16_at(c->buffer, 0));
4111865f46b2SCy Schubert if(!short_ok &&
4112865f46b2SCy Schubert sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE) {
4113865f46b2SCy Schubert verbose(VERB_QUERY, "tcp: dropped bogus too short.");
4114865f46b2SCy Schubert return 0;
4115865f46b2SCy Schubert }
4116865f46b2SCy Schubert verbose(VERB_ALGO, "Reading tcp query of length %d",
4117865f46b2SCy Schubert (int)sldns_buffer_limit(c->buffer));
4118865f46b2SCy Schubert }
4119865f46b2SCy Schubert
4120865f46b2SCy Schubert if(sldns_buffer_remaining(c->buffer) == 0)
4121865f46b2SCy Schubert log_err("in comm_point_tcp_handle_read buffer_remaining is "
4122865f46b2SCy Schubert "not > 0 as expected, continuing with (harmless) 0 "
4123865f46b2SCy Schubert "length recv");
4124865f46b2SCy Schubert r = recv(fd, (void*)sldns_buffer_current(c->buffer),
4125865f46b2SCy Schubert sldns_buffer_remaining(c->buffer), MSG_DONTWAIT);
4126865f46b2SCy Schubert if(r == 0) {
4127865f46b2SCy Schubert if(c->tcp_req_info)
4128865f46b2SCy Schubert return tcp_req_info_handle_read_close(c->tcp_req_info);
4129865f46b2SCy Schubert return 0;
4130865f46b2SCy Schubert } else if(r == -1) {
4131865f46b2SCy Schubert goto recv_error;
4132865f46b2SCy Schubert }
4133865f46b2SCy Schubert sldns_buffer_skip(c->buffer, r);
4134865f46b2SCy Schubert if(sldns_buffer_remaining(c->buffer) <= 0) {
4135865f46b2SCy Schubert tcp_callback_reader(c);
4136865f46b2SCy Schubert }
4137865f46b2SCy Schubert return 1;
4138865f46b2SCy Schubert
4139865f46b2SCy Schubert recv_error_initial:
4140865f46b2SCy Schubert recv_initial = 1;
4141865f46b2SCy Schubert recv_error:
4142b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK
4143b7579f77SDag-Erling Smørgrav if(errno == EINTR || errno == EAGAIN)
4144b7579f77SDag-Erling Smørgrav return 1;
4145b7579f77SDag-Erling Smørgrav #ifdef ECONNRESET
4146b7579f77SDag-Erling Smørgrav if(errno == ECONNRESET && verbosity < 2)
4147b7579f77SDag-Erling Smørgrav return 0; /* silence reset by peer */
4148b7579f77SDag-Erling Smørgrav #endif
414956850988SCy Schubert if(recv_initial) {
41505469a995SCy Schubert #ifdef ECONNREFUSED
41515469a995SCy Schubert if(errno == ECONNREFUSED && verbosity < 2)
41525469a995SCy Schubert return 0; /* silence reset by peer */
41535469a995SCy Schubert #endif
4154f44e67d1SCy Schubert #ifdef ENETUNREACH
4155f44e67d1SCy Schubert if(errno == ENETUNREACH && verbosity < 2)
4156f44e67d1SCy Schubert return 0; /* silence it */
4157f44e67d1SCy Schubert #endif
4158f44e67d1SCy Schubert #ifdef EHOSTDOWN
4159f44e67d1SCy Schubert if(errno == EHOSTDOWN && verbosity < 2)
4160f44e67d1SCy Schubert return 0; /* silence it */
4161f44e67d1SCy Schubert #endif
4162f44e67d1SCy Schubert #ifdef EHOSTUNREACH
4163f44e67d1SCy Schubert if(errno == EHOSTUNREACH && verbosity < 2)
4164f44e67d1SCy Schubert return 0; /* silence it */
4165f44e67d1SCy Schubert #endif
4166f44e67d1SCy Schubert #ifdef ENETDOWN
4167f44e67d1SCy Schubert if(errno == ENETDOWN && verbosity < 2)
4168f44e67d1SCy Schubert return 0; /* silence it */
4169f44e67d1SCy Schubert #endif
4170f44e67d1SCy Schubert #ifdef EACCES
4171f44e67d1SCy Schubert if(errno == EACCES && verbosity < 2)
4172f44e67d1SCy Schubert return 0; /* silence it */
4173f44e67d1SCy Schubert #endif
4174f44e67d1SCy Schubert #ifdef ENOTCONN
4175f44e67d1SCy Schubert if(errno == ENOTCONN) {
417656850988SCy Schubert log_err_addr("read (in tcp initial) failed and this "
4177865f46b2SCy Schubert "could be because TCP Fast Open is "
4178865f46b2SCy Schubert "enabled [--disable-tfo-client "
4179865f46b2SCy Schubert "--disable-tfo-server] but does not "
4180865f46b2SCy Schubert "work", sock_strerror(errno),
4181865f46b2SCy Schubert &c->repinfo.remote_addr,
4182865f46b2SCy Schubert c->repinfo.remote_addrlen);
4183f44e67d1SCy Schubert return 0;
4184f44e67d1SCy Schubert }
4185f44e67d1SCy Schubert #endif
4186865f46b2SCy Schubert }
4187b7579f77SDag-Erling Smørgrav #else /* USE_WINSOCK */
4188865f46b2SCy Schubert if(recv_initial) {
41895469a995SCy Schubert if(WSAGetLastError() == WSAECONNREFUSED && verbosity < 2)
41905469a995SCy Schubert return 0;
41915469a995SCy Schubert if(WSAGetLastError() == WSAEHOSTDOWN && verbosity < 2)
41925469a995SCy Schubert return 0;
41935469a995SCy Schubert if(WSAGetLastError() == WSAEHOSTUNREACH && verbosity < 2)
41945469a995SCy Schubert return 0;
41955469a995SCy Schubert if(WSAGetLastError() == WSAENETDOWN && verbosity < 2)
41965469a995SCy Schubert return 0;
41975469a995SCy Schubert if(WSAGetLastError() == WSAENETUNREACH && verbosity < 2)
41985469a995SCy Schubert return 0;
4199865f46b2SCy Schubert }
4200b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAECONNRESET)
4201b7579f77SDag-Erling Smørgrav return 0;
4202b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEINPROGRESS)
4203b7579f77SDag-Erling Smørgrav return 1;
4204b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEWOULDBLOCK) {
4205e2d15004SDag-Erling Smørgrav ub_winsock_tcp_wouldblock(c->ev->ev,
4206e2d15004SDag-Erling Smørgrav UB_EV_READ);
4207b7579f77SDag-Erling Smørgrav return 1;
4208b7579f77SDag-Erling Smørgrav }
4209b7579f77SDag-Erling Smørgrav #endif
421056850988SCy Schubert log_err_addr((recv_initial?"read (in tcp initial)":"read (in tcp)"),
421156850988SCy Schubert sock_strerror(errno), &c->repinfo.remote_addr,
421256850988SCy Schubert c->repinfo.remote_addrlen);
4213b7579f77SDag-Erling Smørgrav return 0;
4214b7579f77SDag-Erling Smørgrav }
4215b7579f77SDag-Erling Smørgrav
4216b7579f77SDag-Erling Smørgrav /**
4217b7579f77SDag-Erling Smørgrav * Handle tcp writing callback.
4218b7579f77SDag-Erling Smørgrav * @param fd: file descriptor of socket.
4219b7579f77SDag-Erling Smørgrav * @param c: comm point to write buffer out of.
4220b7579f77SDag-Erling Smørgrav * @return: 0 on error
4221b7579f77SDag-Erling Smørgrav */
4222b7579f77SDag-Erling Smørgrav static int
4223b7579f77SDag-Erling Smørgrav comm_point_tcp_handle_write(int fd, struct comm_point* c)
4224b7579f77SDag-Erling Smørgrav {
4225b7579f77SDag-Erling Smørgrav ssize_t r;
422665b390aaSDag-Erling Smørgrav struct sldns_buffer *buffer;
4227b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_tcp);
422865b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT
422965b390aaSDag-Erling Smørgrav buffer = c->dnscrypt_buffer;
423065b390aaSDag-Erling Smørgrav #else
423165b390aaSDag-Erling Smørgrav buffer = c->buffer;
423265b390aaSDag-Erling Smørgrav #endif
4233369c6923SCy Schubert if(c->tcp_is_reading && !c->ssl && !c->tcp_write_and_read)
4234b7579f77SDag-Erling Smørgrav return 0;
4235b7579f77SDag-Erling Smørgrav log_assert(fd != -1);
4236369c6923SCy Schubert if(((!c->tcp_write_and_read && c->tcp_byte_count == 0) || (c->tcp_write_and_read && c->tcp_write_byte_count == 0)) && c->tcp_check_nb_connect) {
4237b7579f77SDag-Erling Smørgrav /* check for pending error from nonblocking connect */
4238b7579f77SDag-Erling Smørgrav /* from Stevens, unix network programming, vol1, 3rd ed, p450*/
4239b7579f77SDag-Erling Smørgrav int error = 0;
4240b7579f77SDag-Erling Smørgrav socklen_t len = (socklen_t)sizeof(error);
4241b7579f77SDag-Erling Smørgrav if(getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&error,
4242b7579f77SDag-Erling Smørgrav &len) < 0){
4243b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK
4244b7579f77SDag-Erling Smørgrav error = errno; /* on solaris errno is error */
4245b7579f77SDag-Erling Smørgrav #else /* USE_WINSOCK */
4246b7579f77SDag-Erling Smørgrav error = WSAGetLastError();
4247b7579f77SDag-Erling Smørgrav #endif
4248b7579f77SDag-Erling Smørgrav }
4249b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK
4250b7579f77SDag-Erling Smørgrav #if defined(EINPROGRESS) && defined(EWOULDBLOCK)
4251b7579f77SDag-Erling Smørgrav if(error == EINPROGRESS || error == EWOULDBLOCK)
4252b7579f77SDag-Erling Smørgrav return 1; /* try again later */
4253b7579f77SDag-Erling Smørgrav else
4254b7579f77SDag-Erling Smørgrav #endif
4255b7579f77SDag-Erling Smørgrav if(error != 0 && verbosity < 2)
4256b7579f77SDag-Erling Smørgrav return 0; /* silence lots of chatter in the logs */
4257b7579f77SDag-Erling Smørgrav else if(error != 0) {
4258ff825849SDag-Erling Smørgrav log_err_addr("tcp connect", strerror(error),
4259865f46b2SCy Schubert &c->repinfo.remote_addr,
4260865f46b2SCy Schubert c->repinfo.remote_addrlen);
4261b7579f77SDag-Erling Smørgrav #else /* USE_WINSOCK */
4262b7579f77SDag-Erling Smørgrav /* examine error */
4263b7579f77SDag-Erling Smørgrav if(error == WSAEINPROGRESS)
4264b7579f77SDag-Erling Smørgrav return 1;
4265b7579f77SDag-Erling Smørgrav else if(error == WSAEWOULDBLOCK) {
4266e2d15004SDag-Erling Smørgrav ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
4267b7579f77SDag-Erling Smørgrav return 1;
4268b7579f77SDag-Erling Smørgrav } else if(error != 0 && verbosity < 2)
4269b7579f77SDag-Erling Smørgrav return 0;
4270b7579f77SDag-Erling Smørgrav else if(error != 0) {
4271ff825849SDag-Erling Smørgrav log_err_addr("tcp connect", wsa_strerror(error),
4272865f46b2SCy Schubert &c->repinfo.remote_addr,
4273865f46b2SCy Schubert c->repinfo.remote_addrlen);
4274b7579f77SDag-Erling Smørgrav #endif /* USE_WINSOCK */
4275b7579f77SDag-Erling Smørgrav return 0;
4276b7579f77SDag-Erling Smørgrav }
4277b7579f77SDag-Erling Smørgrav }
4278b7579f77SDag-Erling Smørgrav if(c->ssl)
4279369c6923SCy Schubert return ssl_handle_it(c, 1);
4280b7579f77SDag-Erling Smørgrav
4281b5663de9SDag-Erling Smørgrav #ifdef USE_MSG_FASTOPEN
4282b5663de9SDag-Erling Smørgrav /* Only try this on first use of a connection that uses tfo,
4283b5663de9SDag-Erling Smørgrav otherwise fall through to normal write */
4284b5663de9SDag-Erling Smørgrav /* Also, TFO support on WINDOWS not implemented at the moment */
4285b5663de9SDag-Erling Smørgrav if(c->tcp_do_fastopen == 1) {
4286b5663de9SDag-Erling Smørgrav /* this form of sendmsg() does both a connect() and send() so need to
4287b5663de9SDag-Erling Smørgrav look for various flavours of error*/
4288369c6923SCy Schubert uint16_t len = htons(c->tcp_write_and_read?c->tcp_write_pkt_len:sldns_buffer_limit(buffer));
4289b5663de9SDag-Erling Smørgrav struct msghdr msg;
4290b5663de9SDag-Erling Smørgrav struct iovec iov[2];
4291b5663de9SDag-Erling Smørgrav c->tcp_do_fastopen = 0;
4292b5663de9SDag-Erling Smørgrav memset(&msg, 0, sizeof(msg));
4293369c6923SCy Schubert if(c->tcp_write_and_read) {
4294369c6923SCy Schubert iov[0].iov_base = (uint8_t*)&len + c->tcp_write_byte_count;
4295369c6923SCy Schubert iov[0].iov_len = sizeof(uint16_t) - c->tcp_write_byte_count;
4296369c6923SCy Schubert iov[1].iov_base = c->tcp_write_pkt;
4297369c6923SCy Schubert iov[1].iov_len = c->tcp_write_pkt_len;
4298369c6923SCy Schubert } else {
4299b5663de9SDag-Erling Smørgrav iov[0].iov_base = (uint8_t*)&len + c->tcp_byte_count;
4300b5663de9SDag-Erling Smørgrav iov[0].iov_len = sizeof(uint16_t) - c->tcp_byte_count;
430165b390aaSDag-Erling Smørgrav iov[1].iov_base = sldns_buffer_begin(buffer);
430265b390aaSDag-Erling Smørgrav iov[1].iov_len = sldns_buffer_limit(buffer);
4303369c6923SCy Schubert }
4304b5663de9SDag-Erling Smørgrav log_assert(iov[0].iov_len > 0);
4305865f46b2SCy Schubert msg.msg_name = &c->repinfo.remote_addr;
4306865f46b2SCy Schubert msg.msg_namelen = c->repinfo.remote_addrlen;
4307b5663de9SDag-Erling Smørgrav msg.msg_iov = iov;
4308b5663de9SDag-Erling Smørgrav msg.msg_iovlen = 2;
4309b5663de9SDag-Erling Smørgrav r = sendmsg(fd, &msg, MSG_FASTOPEN);
4310b5663de9SDag-Erling Smørgrav if (r == -1) {
4311b5663de9SDag-Erling Smørgrav #if defined(EINPROGRESS) && defined(EWOULDBLOCK)
4312b5663de9SDag-Erling Smørgrav /* Handshake is underway, maybe because no TFO cookie available.
43138a384985SDag-Erling Smørgrav Come back to write the message*/
4314b5663de9SDag-Erling Smørgrav if(errno == EINPROGRESS || errno == EWOULDBLOCK)
4315b5663de9SDag-Erling Smørgrav return 1;
4316b5663de9SDag-Erling Smørgrav #endif
4317b5663de9SDag-Erling Smørgrav if(errno == EINTR || errno == EAGAIN)
4318b5663de9SDag-Erling Smørgrav return 1;
4319b5663de9SDag-Erling Smørgrav /* Not handling EISCONN here as shouldn't ever hit that case.*/
432024e36522SCy Schubert if(errno != EPIPE
432124e36522SCy Schubert #ifdef EOPNOTSUPP
432224e36522SCy Schubert /* if /proc/sys/net/ipv4/tcp_fastopen is
432324e36522SCy Schubert * disabled on Linux, sendmsg may return
432424e36522SCy Schubert * 'Operation not supported', if so
432524e36522SCy Schubert * fallthrough to ordinary connect. */
432624e36522SCy Schubert && errno != EOPNOTSUPP
432724e36522SCy Schubert #endif
432824e36522SCy Schubert && errno != 0) {
432924e36522SCy Schubert if(verbosity < 2)
4330b5663de9SDag-Erling Smørgrav return 0; /* silence lots of chatter in the logs */
4331b5663de9SDag-Erling Smørgrav log_err_addr("tcp sendmsg", strerror(errno),
4332865f46b2SCy Schubert &c->repinfo.remote_addr,
4333865f46b2SCy Schubert c->repinfo.remote_addrlen);
4334b5663de9SDag-Erling Smørgrav return 0;
4335c7f4d7adSDag-Erling Smørgrav }
433624e36522SCy Schubert verbose(VERB_ALGO, "tcp sendmsg for fastopen failed (with %s), try normal connect", strerror(errno));
4337c7f4d7adSDag-Erling Smørgrav /* fallthrough to nonFASTOPEN
4338c7f4d7adSDag-Erling Smørgrav * (MSG_FASTOPEN on Linux 3 produces EPIPE)
4339c7f4d7adSDag-Erling Smørgrav * we need to perform connect() */
4340865f46b2SCy Schubert if(connect(fd, (struct sockaddr *)&c->repinfo.remote_addr,
4341865f46b2SCy Schubert c->repinfo.remote_addrlen) == -1) {
4342c7f4d7adSDag-Erling Smørgrav #ifdef EINPROGRESS
4343c7f4d7adSDag-Erling Smørgrav if(errno == EINPROGRESS)
4344c7f4d7adSDag-Erling Smørgrav return 1; /* wait until connect done*/
4345c7f4d7adSDag-Erling Smørgrav #endif
4346c7f4d7adSDag-Erling Smørgrav #ifdef USE_WINSOCK
4347c7f4d7adSDag-Erling Smørgrav if(WSAGetLastError() == WSAEINPROGRESS ||
4348c7f4d7adSDag-Erling Smørgrav WSAGetLastError() == WSAEWOULDBLOCK)
4349c7f4d7adSDag-Erling Smørgrav return 1; /* wait until connect done*/
4350c7f4d7adSDag-Erling Smørgrav #endif
4351c7f4d7adSDag-Erling Smørgrav if(tcp_connect_errno_needs_log(
4352865f46b2SCy Schubert (struct sockaddr *)&c->repinfo.remote_addr,
4353865f46b2SCy Schubert c->repinfo.remote_addrlen)) {
4354c7f4d7adSDag-Erling Smørgrav log_err_addr("outgoing tcp: connect after EPIPE for fastopen",
4355865f46b2SCy Schubert strerror(errno),
4356865f46b2SCy Schubert &c->repinfo.remote_addr,
4357865f46b2SCy Schubert c->repinfo.remote_addrlen);
4358c7f4d7adSDag-Erling Smørgrav }
4359c7f4d7adSDag-Erling Smørgrav return 0;
4360c7f4d7adSDag-Erling Smørgrav }
4361c7f4d7adSDag-Erling Smørgrav
4362b5663de9SDag-Erling Smørgrav } else {
4363369c6923SCy Schubert if(c->tcp_write_and_read) {
4364369c6923SCy Schubert c->tcp_write_byte_count += r;
4365369c6923SCy Schubert if(c->tcp_write_byte_count < sizeof(uint16_t))
4366369c6923SCy Schubert return 1;
4367369c6923SCy Schubert } else {
4368b5663de9SDag-Erling Smørgrav c->tcp_byte_count += r;
4369b5663de9SDag-Erling Smørgrav if(c->tcp_byte_count < sizeof(uint16_t))
4370b5663de9SDag-Erling Smørgrav return 1;
437165b390aaSDag-Erling Smørgrav sldns_buffer_set_position(buffer, c->tcp_byte_count -
4372b5663de9SDag-Erling Smørgrav sizeof(uint16_t));
4373369c6923SCy Schubert }
4374369c6923SCy Schubert if((!c->tcp_write_and_read && sldns_buffer_remaining(buffer) == 0) || (c->tcp_write_and_read && c->tcp_write_byte_count == c->tcp_write_pkt_len + 2)) {
4375b5663de9SDag-Erling Smørgrav tcp_callback_writer(c);
4376b5663de9SDag-Erling Smørgrav return 1;
4377b5663de9SDag-Erling Smørgrav }
4378b5663de9SDag-Erling Smørgrav }
4379b5663de9SDag-Erling Smørgrav }
4380b5663de9SDag-Erling Smørgrav #endif /* USE_MSG_FASTOPEN */
4381b5663de9SDag-Erling Smørgrav
4382369c6923SCy Schubert if((c->tcp_write_and_read?c->tcp_write_byte_count:c->tcp_byte_count) < sizeof(uint16_t)) {
4383369c6923SCy Schubert uint16_t len = htons(c->tcp_write_and_read?c->tcp_write_pkt_len:sldns_buffer_limit(buffer));
4384b7579f77SDag-Erling Smørgrav #ifdef HAVE_WRITEV
4385b7579f77SDag-Erling Smørgrav struct iovec iov[2];
4386369c6923SCy Schubert if(c->tcp_write_and_read) {
4387369c6923SCy Schubert iov[0].iov_base = (uint8_t*)&len + c->tcp_write_byte_count;
4388369c6923SCy Schubert iov[0].iov_len = sizeof(uint16_t) - c->tcp_write_byte_count;
4389369c6923SCy Schubert iov[1].iov_base = c->tcp_write_pkt;
4390369c6923SCy Schubert iov[1].iov_len = c->tcp_write_pkt_len;
4391369c6923SCy Schubert } else {
4392b7579f77SDag-Erling Smørgrav iov[0].iov_base = (uint8_t*)&len + c->tcp_byte_count;
4393b7579f77SDag-Erling Smørgrav iov[0].iov_len = sizeof(uint16_t) - c->tcp_byte_count;
439465b390aaSDag-Erling Smørgrav iov[1].iov_base = sldns_buffer_begin(buffer);
439565b390aaSDag-Erling Smørgrav iov[1].iov_len = sldns_buffer_limit(buffer);
4396369c6923SCy Schubert }
4397b7579f77SDag-Erling Smørgrav log_assert(iov[0].iov_len > 0);
4398b7579f77SDag-Erling Smørgrav r = writev(fd, iov, 2);
4399b7579f77SDag-Erling Smørgrav #else /* HAVE_WRITEV */
4400369c6923SCy Schubert if(c->tcp_write_and_read) {
4401369c6923SCy Schubert r = send(fd, (void*)(((uint8_t*)&len)+c->tcp_write_byte_count),
4402369c6923SCy Schubert sizeof(uint16_t)-c->tcp_write_byte_count, 0);
4403369c6923SCy Schubert } else {
4404b7579f77SDag-Erling Smørgrav r = send(fd, (void*)(((uint8_t*)&len)+c->tcp_byte_count),
4405b7579f77SDag-Erling Smørgrav sizeof(uint16_t)-c->tcp_byte_count, 0);
4406369c6923SCy Schubert }
4407b7579f77SDag-Erling Smørgrav #endif /* HAVE_WRITEV */
4408b7579f77SDag-Erling Smørgrav if(r == -1) {
4409b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK
4410b7579f77SDag-Erling Smørgrav # ifdef EPIPE
4411b7579f77SDag-Erling Smørgrav if(errno == EPIPE && verbosity < 2)
4412b7579f77SDag-Erling Smørgrav return 0; /* silence 'broken pipe' */
4413b7579f77SDag-Erling Smørgrav #endif
4414b7579f77SDag-Erling Smørgrav if(errno == EINTR || errno == EAGAIN)
4415b7579f77SDag-Erling Smørgrav return 1;
4416e86b9096SDag-Erling Smørgrav #ifdef ECONNRESET
4417e86b9096SDag-Erling Smørgrav if(errno == ECONNRESET && verbosity < 2)
4418e86b9096SDag-Erling Smørgrav return 0; /* silence reset by peer */
4419e86b9096SDag-Erling Smørgrav #endif
4420ff825849SDag-Erling Smørgrav # ifdef HAVE_WRITEV
4421ff825849SDag-Erling Smørgrav log_err_addr("tcp writev", strerror(errno),
4422865f46b2SCy Schubert &c->repinfo.remote_addr,
4423865f46b2SCy Schubert c->repinfo.remote_addrlen);
4424ff825849SDag-Erling Smørgrav # else /* HAVE_WRITEV */
4425ff825849SDag-Erling Smørgrav log_err_addr("tcp send s", strerror(errno),
4426865f46b2SCy Schubert &c->repinfo.remote_addr,
4427865f46b2SCy Schubert c->repinfo.remote_addrlen);
4428ff825849SDag-Erling Smørgrav # endif /* HAVE_WRITEV */
4429b7579f77SDag-Erling Smørgrav #else
4430b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAENOTCONN)
4431b7579f77SDag-Erling Smørgrav return 1;
4432b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEINPROGRESS)
4433b7579f77SDag-Erling Smørgrav return 1;
4434b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEWOULDBLOCK) {
4435e2d15004SDag-Erling Smørgrav ub_winsock_tcp_wouldblock(c->ev->ev,
4436e2d15004SDag-Erling Smørgrav UB_EV_WRITE);
4437b7579f77SDag-Erling Smørgrav return 1;
4438b7579f77SDag-Erling Smørgrav }
4439e86b9096SDag-Erling Smørgrav if(WSAGetLastError() == WSAECONNRESET && verbosity < 2)
4440e86b9096SDag-Erling Smørgrav return 0; /* silence reset by peer */
4441ff825849SDag-Erling Smørgrav log_err_addr("tcp send s",
4442ff825849SDag-Erling Smørgrav wsa_strerror(WSAGetLastError()),
4443865f46b2SCy Schubert &c->repinfo.remote_addr,
4444865f46b2SCy Schubert c->repinfo.remote_addrlen);
4445b7579f77SDag-Erling Smørgrav #endif
4446b7579f77SDag-Erling Smørgrav return 0;
4447b7579f77SDag-Erling Smørgrav }
4448369c6923SCy Schubert if(c->tcp_write_and_read) {
4449369c6923SCy Schubert c->tcp_write_byte_count += r;
4450369c6923SCy Schubert if(c->tcp_write_byte_count < sizeof(uint16_t))
4451369c6923SCy Schubert return 1;
4452369c6923SCy Schubert } else {
4453b7579f77SDag-Erling Smørgrav c->tcp_byte_count += r;
4454b7579f77SDag-Erling Smørgrav if(c->tcp_byte_count < sizeof(uint16_t))
4455b7579f77SDag-Erling Smørgrav return 1;
445665b390aaSDag-Erling Smørgrav sldns_buffer_set_position(buffer, c->tcp_byte_count -
4457b7579f77SDag-Erling Smørgrav sizeof(uint16_t));
4458369c6923SCy Schubert }
4459369c6923SCy Schubert if((!c->tcp_write_and_read && sldns_buffer_remaining(buffer) == 0) || (c->tcp_write_and_read && c->tcp_write_byte_count == c->tcp_write_pkt_len + 2)) {
4460b7579f77SDag-Erling Smørgrav tcp_callback_writer(c);
4461b7579f77SDag-Erling Smørgrav return 1;
4462b7579f77SDag-Erling Smørgrav }
4463b7579f77SDag-Erling Smørgrav }
4464369c6923SCy Schubert log_assert(c->tcp_write_and_read || sldns_buffer_remaining(buffer) > 0);
4465369c6923SCy Schubert log_assert(!c->tcp_write_and_read || c->tcp_write_byte_count < c->tcp_write_pkt_len + 2);
4466369c6923SCy Schubert if(c->tcp_write_and_read) {
4467f44e67d1SCy Schubert r = send(fd, (void*)(c->tcp_write_pkt + c->tcp_write_byte_count - 2),
4468369c6923SCy Schubert c->tcp_write_pkt_len + 2 - c->tcp_write_byte_count, 0);
4469369c6923SCy Schubert } else {
447065b390aaSDag-Erling Smørgrav r = send(fd, (void*)sldns_buffer_current(buffer),
447165b390aaSDag-Erling Smørgrav sldns_buffer_remaining(buffer), 0);
4472369c6923SCy Schubert }
4473b7579f77SDag-Erling Smørgrav if(r == -1) {
4474b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK
4475b7579f77SDag-Erling Smørgrav if(errno == EINTR || errno == EAGAIN)
4476b7579f77SDag-Erling Smørgrav return 1;
4477e86b9096SDag-Erling Smørgrav #ifdef ECONNRESET
4478e86b9096SDag-Erling Smørgrav if(errno == ECONNRESET && verbosity < 2)
4479e86b9096SDag-Erling Smørgrav return 0; /* silence reset by peer */
4480e86b9096SDag-Erling Smørgrav #endif
4481b7579f77SDag-Erling Smørgrav #else
4482b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEINPROGRESS)
4483b7579f77SDag-Erling Smørgrav return 1;
4484b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEWOULDBLOCK) {
4485e2d15004SDag-Erling Smørgrav ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
4486b7579f77SDag-Erling Smørgrav return 1;
4487b7579f77SDag-Erling Smørgrav }
4488e86b9096SDag-Erling Smørgrav if(WSAGetLastError() == WSAECONNRESET && verbosity < 2)
4489e86b9096SDag-Erling Smørgrav return 0; /* silence reset by peer */
4490b7579f77SDag-Erling Smørgrav #endif
4491c0caa2e2SCy Schubert log_err_addr("tcp send r", sock_strerror(errno),
4492865f46b2SCy Schubert &c->repinfo.remote_addr,
4493865f46b2SCy Schubert c->repinfo.remote_addrlen);
4494b7579f77SDag-Erling Smørgrav return 0;
4495b7579f77SDag-Erling Smørgrav }
4496369c6923SCy Schubert if(c->tcp_write_and_read) {
4497369c6923SCy Schubert c->tcp_write_byte_count += r;
4498369c6923SCy Schubert } else {
449965b390aaSDag-Erling Smørgrav sldns_buffer_skip(buffer, r);
4500369c6923SCy Schubert }
4501b7579f77SDag-Erling Smørgrav
4502369c6923SCy Schubert if((!c->tcp_write_and_read && sldns_buffer_remaining(buffer) == 0) || (c->tcp_write_and_read && c->tcp_write_byte_count == c->tcp_write_pkt_len + 2)) {
4503b7579f77SDag-Erling Smørgrav tcp_callback_writer(c);
4504b7579f77SDag-Erling Smørgrav }
4505b7579f77SDag-Erling Smørgrav
4506b7579f77SDag-Erling Smørgrav return 1;
4507b7579f77SDag-Erling Smørgrav }
4508b7579f77SDag-Erling Smørgrav
45091838dec3SCy Schubert /** read again to drain buffers when there could be more to read, returns 0
45101838dec3SCy Schubert * on failure which means the comm point is closed. */
45111838dec3SCy Schubert static int
4512e86b9096SDag-Erling Smørgrav tcp_req_info_read_again(int fd, struct comm_point* c)
4513e86b9096SDag-Erling Smørgrav {
4514e86b9096SDag-Erling Smørgrav while(c->tcp_req_info->read_again) {
4515e86b9096SDag-Erling Smørgrav int r;
4516e86b9096SDag-Erling Smørgrav c->tcp_req_info->read_again = 0;
4517e86b9096SDag-Erling Smørgrav if(c->tcp_is_reading)
4518e86b9096SDag-Erling Smørgrav r = comm_point_tcp_handle_read(fd, c, 0);
4519e86b9096SDag-Erling Smørgrav else r = comm_point_tcp_handle_write(fd, c);
4520e86b9096SDag-Erling Smørgrav if(!r) {
4521e86b9096SDag-Erling Smørgrav reclaim_tcp_handler(c);
4522e86b9096SDag-Erling Smørgrav if(!c->tcp_do_close) {
4523e86b9096SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point(
4524e86b9096SDag-Erling Smørgrav c->callback));
4525e86b9096SDag-Erling Smørgrav (void)(*c->callback)(c, c->cb_arg,
4526e86b9096SDag-Erling Smørgrav NETEVENT_CLOSED, NULL);
4527e86b9096SDag-Erling Smørgrav }
45281838dec3SCy Schubert return 0;
4529e86b9096SDag-Erling Smørgrav }
4530e86b9096SDag-Erling Smørgrav }
45311838dec3SCy Schubert return 1;
4532e86b9096SDag-Erling Smørgrav }
4533e86b9096SDag-Erling Smørgrav
4534369c6923SCy Schubert /** read again to drain buffers when there could be more to read */
4535369c6923SCy Schubert static void
4536369c6923SCy Schubert tcp_more_read_again(int fd, struct comm_point* c)
4537369c6923SCy Schubert {
4538369c6923SCy Schubert /* if the packet is done, but another one could be waiting on
4539369c6923SCy Schubert * the connection, the callback signals this, and we try again */
4540369c6923SCy Schubert /* this continues until the read routines get EAGAIN or so,
4541369c6923SCy Schubert * and thus does not call the callback, and the bool is 0 */
4542369c6923SCy Schubert int* moreread = c->tcp_more_read_again;
4543369c6923SCy Schubert while(moreread && *moreread) {
4544369c6923SCy Schubert *moreread = 0;
4545369c6923SCy Schubert if(!comm_point_tcp_handle_read(fd, c, 0)) {
4546369c6923SCy Schubert reclaim_tcp_handler(c);
4547369c6923SCy Schubert if(!c->tcp_do_close) {
4548369c6923SCy Schubert fptr_ok(fptr_whitelist_comm_point(
4549369c6923SCy Schubert c->callback));
4550369c6923SCy Schubert (void)(*c->callback)(c, c->cb_arg,
4551369c6923SCy Schubert NETEVENT_CLOSED, NULL);
4552369c6923SCy Schubert }
4553369c6923SCy Schubert return;
4554369c6923SCy Schubert }
4555369c6923SCy Schubert }
4556369c6923SCy Schubert }
4557369c6923SCy Schubert
4558369c6923SCy Schubert /** write again to fill up when there could be more to write */
4559369c6923SCy Schubert static void
4560369c6923SCy Schubert tcp_more_write_again(int fd, struct comm_point* c)
4561369c6923SCy Schubert {
4562369c6923SCy Schubert /* if the packet is done, but another is waiting to be written,
4563369c6923SCy Schubert * the callback signals it and we try again. */
4564369c6923SCy Schubert /* this continues until the write routines get EAGAIN or so,
4565369c6923SCy Schubert * and thus does not call the callback, and the bool is 0 */
4566369c6923SCy Schubert int* morewrite = c->tcp_more_write_again;
4567369c6923SCy Schubert while(morewrite && *morewrite) {
4568369c6923SCy Schubert *morewrite = 0;
4569369c6923SCy Schubert if(!comm_point_tcp_handle_write(fd, c)) {
4570369c6923SCy Schubert reclaim_tcp_handler(c);
4571369c6923SCy Schubert if(!c->tcp_do_close) {
4572369c6923SCy Schubert fptr_ok(fptr_whitelist_comm_point(
4573369c6923SCy Schubert c->callback));
4574369c6923SCy Schubert (void)(*c->callback)(c, c->cb_arg,
4575369c6923SCy Schubert NETEVENT_CLOSED, NULL);
4576369c6923SCy Schubert }
4577369c6923SCy Schubert return;
4578369c6923SCy Schubert }
4579369c6923SCy Schubert }
4580369c6923SCy Schubert }
4581369c6923SCy Schubert
4582b7579f77SDag-Erling Smørgrav void
4583b7579f77SDag-Erling Smørgrav comm_point_tcp_handle_callback(int fd, short event, void* arg)
4584b7579f77SDag-Erling Smørgrav {
4585b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)arg;
4586b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_tcp);
4587e2d15004SDag-Erling Smørgrav ub_comm_base_now(c->ev->base);
4588b7579f77SDag-Erling Smørgrav
45891838dec3SCy Schubert if(c->fd == -1 || c->fd != fd)
45901838dec3SCy Schubert return; /* duplicate event, but commpoint closed. */
45911838dec3SCy Schubert
459265b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT
459365b390aaSDag-Erling Smørgrav /* Initialize if this is a dnscrypt socket */
459465b390aaSDag-Erling Smørgrav if(c->tcp_parent) {
459565b390aaSDag-Erling Smørgrav c->dnscrypt = c->tcp_parent->dnscrypt;
459665b390aaSDag-Erling Smørgrav }
459765b390aaSDag-Erling Smørgrav if(c->dnscrypt && c->dnscrypt_buffer == c->buffer) {
459865b390aaSDag-Erling Smørgrav c->dnscrypt_buffer = sldns_buffer_new(sldns_buffer_capacity(c->buffer));
459965b390aaSDag-Erling Smørgrav if(!c->dnscrypt_buffer) {
460065b390aaSDag-Erling Smørgrav log_err("Could not allocate dnscrypt buffer");
4601971980c3SDag-Erling Smørgrav reclaim_tcp_handler(c);
4602971980c3SDag-Erling Smørgrav if(!c->tcp_do_close) {
4603971980c3SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point(
4604971980c3SDag-Erling Smørgrav c->callback));
4605971980c3SDag-Erling Smørgrav (void)(*c->callback)(c, c->cb_arg,
4606971980c3SDag-Erling Smørgrav NETEVENT_CLOSED, NULL);
4607971980c3SDag-Erling Smørgrav }
460865b390aaSDag-Erling Smørgrav return;
460965b390aaSDag-Erling Smørgrav }
461065b390aaSDag-Erling Smørgrav }
461165b390aaSDag-Erling Smørgrav #endif
461265b390aaSDag-Erling Smørgrav
4613e86b9096SDag-Erling Smørgrav if(event&UB_EV_TIMEOUT) {
4614e86b9096SDag-Erling Smørgrav verbose(VERB_QUERY, "tcp took too long, dropped");
4615e86b9096SDag-Erling Smørgrav reclaim_tcp_handler(c);
4616e86b9096SDag-Erling Smørgrav if(!c->tcp_do_close) {
4617e86b9096SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point(c->callback));
4618e86b9096SDag-Erling Smørgrav (void)(*c->callback)(c, c->cb_arg,
4619e86b9096SDag-Erling Smørgrav NETEVENT_TIMEOUT, NULL);
4620e86b9096SDag-Erling Smørgrav }
4621e86b9096SDag-Erling Smørgrav return;
4622e86b9096SDag-Erling Smørgrav }
4623369c6923SCy Schubert if(event&UB_EV_READ
4624369c6923SCy Schubert #ifdef USE_MSG_FASTOPEN
4625369c6923SCy Schubert && !(c->tcp_do_fastopen && (event&UB_EV_WRITE))
4626369c6923SCy Schubert #endif
4627369c6923SCy Schubert ) {
4628e86b9096SDag-Erling Smørgrav int has_tcpq = (c->tcp_req_info != NULL);
4629369c6923SCy Schubert int* moreread = c->tcp_more_read_again;
4630b7579f77SDag-Erling Smørgrav if(!comm_point_tcp_handle_read(fd, c, 0)) {
4631b7579f77SDag-Erling Smørgrav reclaim_tcp_handler(c);
4632b7579f77SDag-Erling Smørgrav if(!c->tcp_do_close) {
4633b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point(
4634b7579f77SDag-Erling Smørgrav c->callback));
4635b7579f77SDag-Erling Smørgrav (void)(*c->callback)(c, c->cb_arg,
4636b7579f77SDag-Erling Smørgrav NETEVENT_CLOSED, NULL);
4637b7579f77SDag-Erling Smørgrav }
4638369c6923SCy Schubert return;
4639b7579f77SDag-Erling Smørgrav }
46401838dec3SCy Schubert if(has_tcpq && c->tcp_req_info && c->tcp_req_info->read_again) {
46411838dec3SCy Schubert if(!tcp_req_info_read_again(fd, c))
46421838dec3SCy Schubert return;
46431838dec3SCy Schubert }
4644369c6923SCy Schubert if(moreread && *moreread)
4645369c6923SCy Schubert tcp_more_read_again(fd, c);
4646b7579f77SDag-Erling Smørgrav return;
4647b7579f77SDag-Erling Smørgrav }
4648e2d15004SDag-Erling Smørgrav if(event&UB_EV_WRITE) {
4649e86b9096SDag-Erling Smørgrav int has_tcpq = (c->tcp_req_info != NULL);
4650369c6923SCy Schubert int* morewrite = c->tcp_more_write_again;
4651b7579f77SDag-Erling Smørgrav if(!comm_point_tcp_handle_write(fd, c)) {
4652b7579f77SDag-Erling Smørgrav reclaim_tcp_handler(c);
4653b7579f77SDag-Erling Smørgrav if(!c->tcp_do_close) {
4654b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point(
4655b7579f77SDag-Erling Smørgrav c->callback));
4656b7579f77SDag-Erling Smørgrav (void)(*c->callback)(c, c->cb_arg,
4657b7579f77SDag-Erling Smørgrav NETEVENT_CLOSED, NULL);
4658b7579f77SDag-Erling Smørgrav }
4659369c6923SCy Schubert return;
4660b7579f77SDag-Erling Smørgrav }
46611838dec3SCy Schubert if(has_tcpq && c->tcp_req_info && c->tcp_req_info->read_again) {
46621838dec3SCy Schubert if(!tcp_req_info_read_again(fd, c))
46631838dec3SCy Schubert return;
46641838dec3SCy Schubert }
4665369c6923SCy Schubert if(morewrite && *morewrite)
4666369c6923SCy Schubert tcp_more_write_again(fd, c);
4667b7579f77SDag-Erling Smørgrav return;
4668b7579f77SDag-Erling Smørgrav }
4669b7579f77SDag-Erling Smørgrav log_err("Ignored event %d for tcphdl.", event);
4670b7579f77SDag-Erling Smørgrav }
4671b7579f77SDag-Erling Smørgrav
467257bddd21SDag-Erling Smørgrav /** Make http handler free for next assignment */
467357bddd21SDag-Erling Smørgrav static void
467457bddd21SDag-Erling Smørgrav reclaim_http_handler(struct comm_point* c)
467557bddd21SDag-Erling Smørgrav {
467657bddd21SDag-Erling Smørgrav log_assert(c->type == comm_http);
467757bddd21SDag-Erling Smørgrav if(c->ssl) {
467857bddd21SDag-Erling Smørgrav #ifdef HAVE_SSL
467957bddd21SDag-Erling Smørgrav SSL_shutdown(c->ssl);
468057bddd21SDag-Erling Smørgrav SSL_free(c->ssl);
468157bddd21SDag-Erling Smørgrav c->ssl = NULL;
468257bddd21SDag-Erling Smørgrav #endif
468357bddd21SDag-Erling Smørgrav }
468457bddd21SDag-Erling Smørgrav comm_point_close(c);
468557bddd21SDag-Erling Smørgrav if(c->tcp_parent) {
468624e36522SCy Schubert if(c != c->tcp_parent->tcp_free) {
468757bddd21SDag-Erling Smørgrav c->tcp_parent->cur_tcp_count--;
468857bddd21SDag-Erling Smørgrav c->tcp_free = c->tcp_parent->tcp_free;
468957bddd21SDag-Erling Smørgrav c->tcp_parent->tcp_free = c;
469024e36522SCy Schubert }
469157bddd21SDag-Erling Smørgrav if(!c->tcp_free) {
469257bddd21SDag-Erling Smørgrav /* re-enable listening on accept socket */
469357bddd21SDag-Erling Smørgrav comm_point_start_listening(c->tcp_parent, -1, -1);
469457bddd21SDag-Erling Smørgrav }
469557bddd21SDag-Erling Smørgrav }
469657bddd21SDag-Erling Smørgrav }
469757bddd21SDag-Erling Smørgrav
469857bddd21SDag-Erling Smørgrav /** read more data for http (with ssl) */
469957bddd21SDag-Erling Smørgrav static int
470057bddd21SDag-Erling Smørgrav ssl_http_read_more(struct comm_point* c)
470157bddd21SDag-Erling Smørgrav {
470257bddd21SDag-Erling Smørgrav #ifdef HAVE_SSL
470357bddd21SDag-Erling Smørgrav int r;
470457bddd21SDag-Erling Smørgrav log_assert(sldns_buffer_remaining(c->buffer) > 0);
470557bddd21SDag-Erling Smørgrav ERR_clear_error();
470657bddd21SDag-Erling Smørgrav r = SSL_read(c->ssl, (void*)sldns_buffer_current(c->buffer),
470757bddd21SDag-Erling Smørgrav (int)sldns_buffer_remaining(c->buffer));
470857bddd21SDag-Erling Smørgrav if(r <= 0) {
470957bddd21SDag-Erling Smørgrav int want = SSL_get_error(c->ssl, r);
471057bddd21SDag-Erling Smørgrav if(want == SSL_ERROR_ZERO_RETURN) {
471157bddd21SDag-Erling Smørgrav return 0; /* shutdown, closed */
471257bddd21SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_READ) {
471357bddd21SDag-Erling Smørgrav return 1; /* read more later */
471457bddd21SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_WRITE) {
471557bddd21SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_hs_write;
471657bddd21SDag-Erling Smørgrav comm_point_listen_for_rw(c, 0, 1);
471757bddd21SDag-Erling Smørgrav return 1;
471857bddd21SDag-Erling Smørgrav } else if(want == SSL_ERROR_SYSCALL) {
4719e86b9096SDag-Erling Smørgrav #ifdef ECONNRESET
4720e86b9096SDag-Erling Smørgrav if(errno == ECONNRESET && verbosity < 2)
4721e86b9096SDag-Erling Smørgrav return 0; /* silence reset by peer */
4722e86b9096SDag-Erling Smørgrav #endif
472357bddd21SDag-Erling Smørgrav if(errno != 0)
472457bddd21SDag-Erling Smørgrav log_err("SSL_read syscall: %s",
472557bddd21SDag-Erling Smørgrav strerror(errno));
472657bddd21SDag-Erling Smørgrav return 0;
472757bddd21SDag-Erling Smørgrav }
4728103ba509SCy Schubert log_crypto_err_io("could not SSL_read", want);
472957bddd21SDag-Erling Smørgrav return 0;
473057bddd21SDag-Erling Smørgrav }
47315469a995SCy Schubert verbose(VERB_ALGO, "ssl http read more skip to %d + %d",
47325469a995SCy Schubert (int)sldns_buffer_position(c->buffer), (int)r);
473357bddd21SDag-Erling Smørgrav sldns_buffer_skip(c->buffer, (ssize_t)r);
473457bddd21SDag-Erling Smørgrav return 1;
473557bddd21SDag-Erling Smørgrav #else
473657bddd21SDag-Erling Smørgrav (void)c;
473757bddd21SDag-Erling Smørgrav return 0;
473857bddd21SDag-Erling Smørgrav #endif /* HAVE_SSL */
473957bddd21SDag-Erling Smørgrav }
474057bddd21SDag-Erling Smørgrav
474157bddd21SDag-Erling Smørgrav /** read more data for http */
474257bddd21SDag-Erling Smørgrav static int
474357bddd21SDag-Erling Smørgrav http_read_more(int fd, struct comm_point* c)
474457bddd21SDag-Erling Smørgrav {
474557bddd21SDag-Erling Smørgrav ssize_t r;
474657bddd21SDag-Erling Smørgrav log_assert(sldns_buffer_remaining(c->buffer) > 0);
474757bddd21SDag-Erling Smørgrav r = recv(fd, (void*)sldns_buffer_current(c->buffer),
4748865f46b2SCy Schubert sldns_buffer_remaining(c->buffer), MSG_DONTWAIT);
474957bddd21SDag-Erling Smørgrav if(r == 0) {
475057bddd21SDag-Erling Smørgrav return 0;
475157bddd21SDag-Erling Smørgrav } else if(r == -1) {
475257bddd21SDag-Erling Smørgrav #ifndef USE_WINSOCK
475357bddd21SDag-Erling Smørgrav if(errno == EINTR || errno == EAGAIN)
475457bddd21SDag-Erling Smørgrav return 1;
475557bddd21SDag-Erling Smørgrav #else /* USE_WINSOCK */
475657bddd21SDag-Erling Smørgrav if(WSAGetLastError() == WSAECONNRESET)
475757bddd21SDag-Erling Smørgrav return 0;
475857bddd21SDag-Erling Smørgrav if(WSAGetLastError() == WSAEINPROGRESS)
475957bddd21SDag-Erling Smørgrav return 1;
476057bddd21SDag-Erling Smørgrav if(WSAGetLastError() == WSAEWOULDBLOCK) {
476157bddd21SDag-Erling Smørgrav ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
476257bddd21SDag-Erling Smørgrav return 1;
476357bddd21SDag-Erling Smørgrav }
476457bddd21SDag-Erling Smørgrav #endif
4765c0caa2e2SCy Schubert log_err_addr("read (in http r)", sock_strerror(errno),
4766865f46b2SCy Schubert &c->repinfo.remote_addr, c->repinfo.remote_addrlen);
476757bddd21SDag-Erling Smørgrav return 0;
476857bddd21SDag-Erling Smørgrav }
47695469a995SCy Schubert verbose(VERB_ALGO, "http read more skip to %d + %d",
47705469a995SCy Schubert (int)sldns_buffer_position(c->buffer), (int)r);
477157bddd21SDag-Erling Smørgrav sldns_buffer_skip(c->buffer, r);
477257bddd21SDag-Erling Smørgrav return 1;
477357bddd21SDag-Erling Smørgrav }
477457bddd21SDag-Erling Smørgrav
477557bddd21SDag-Erling Smørgrav /** return true if http header has been read (one line complete) */
477657bddd21SDag-Erling Smørgrav static int
477757bddd21SDag-Erling Smørgrav http_header_done(sldns_buffer* buf)
477857bddd21SDag-Erling Smørgrav {
477957bddd21SDag-Erling Smørgrav size_t i;
478057bddd21SDag-Erling Smørgrav for(i=sldns_buffer_position(buf); i<sldns_buffer_limit(buf); i++) {
478157bddd21SDag-Erling Smørgrav /* there was a \r before the \n, but we ignore that */
478257bddd21SDag-Erling Smørgrav if((char)sldns_buffer_read_u8_at(buf, i) == '\n')
478357bddd21SDag-Erling Smørgrav return 1;
478457bddd21SDag-Erling Smørgrav }
478557bddd21SDag-Erling Smørgrav return 0;
478657bddd21SDag-Erling Smørgrav }
478757bddd21SDag-Erling Smørgrav
478857bddd21SDag-Erling Smørgrav /** return character string into buffer for header line, moves buffer
478957bddd21SDag-Erling Smørgrav * past that line and puts zero terminator into linefeed-newline */
479057bddd21SDag-Erling Smørgrav static char*
479157bddd21SDag-Erling Smørgrav http_header_line(sldns_buffer* buf)
479257bddd21SDag-Erling Smørgrav {
479357bddd21SDag-Erling Smørgrav char* result = (char*)sldns_buffer_current(buf);
479457bddd21SDag-Erling Smørgrav size_t i;
479557bddd21SDag-Erling Smørgrav for(i=sldns_buffer_position(buf); i<sldns_buffer_limit(buf); i++) {
479657bddd21SDag-Erling Smørgrav /* terminate the string on the \r */
479757bddd21SDag-Erling Smørgrav if((char)sldns_buffer_read_u8_at(buf, i) == '\r')
479857bddd21SDag-Erling Smørgrav sldns_buffer_write_u8_at(buf, i, 0);
479957bddd21SDag-Erling Smørgrav /* terminate on the \n and skip past the it and done */
480057bddd21SDag-Erling Smørgrav if((char)sldns_buffer_read_u8_at(buf, i) == '\n') {
480157bddd21SDag-Erling Smørgrav sldns_buffer_write_u8_at(buf, i, 0);
480257bddd21SDag-Erling Smørgrav sldns_buffer_set_position(buf, i+1);
480357bddd21SDag-Erling Smørgrav return result;
480457bddd21SDag-Erling Smørgrav }
480557bddd21SDag-Erling Smørgrav }
480657bddd21SDag-Erling Smørgrav return NULL;
480757bddd21SDag-Erling Smørgrav }
480857bddd21SDag-Erling Smørgrav
480957bddd21SDag-Erling Smørgrav /** move unread buffer to start and clear rest for putting the rest into it */
481057bddd21SDag-Erling Smørgrav static void
481157bddd21SDag-Erling Smørgrav http_moveover_buffer(sldns_buffer* buf)
481257bddd21SDag-Erling Smørgrav {
481357bddd21SDag-Erling Smørgrav size_t pos = sldns_buffer_position(buf);
481457bddd21SDag-Erling Smørgrav size_t len = sldns_buffer_remaining(buf);
481557bddd21SDag-Erling Smørgrav sldns_buffer_clear(buf);
481657bddd21SDag-Erling Smørgrav memmove(sldns_buffer_begin(buf), sldns_buffer_at(buf, pos), len);
481757bddd21SDag-Erling Smørgrav sldns_buffer_set_position(buf, len);
481857bddd21SDag-Erling Smørgrav }
481957bddd21SDag-Erling Smørgrav
482057bddd21SDag-Erling Smørgrav /** a http header is complete, process it */
482157bddd21SDag-Erling Smørgrav static int
482257bddd21SDag-Erling Smørgrav http_process_initial_header(struct comm_point* c)
482357bddd21SDag-Erling Smørgrav {
482457bddd21SDag-Erling Smørgrav char* line = http_header_line(c->buffer);
482557bddd21SDag-Erling Smørgrav if(!line) return 1;
482657bddd21SDag-Erling Smørgrav verbose(VERB_ALGO, "http header: %s", line);
482757bddd21SDag-Erling Smørgrav if(strncasecmp(line, "HTTP/1.1 ", 9) == 0) {
482857bddd21SDag-Erling Smørgrav /* check returncode */
482957bddd21SDag-Erling Smørgrav if(line[9] != '2') {
483057bddd21SDag-Erling Smørgrav verbose(VERB_ALGO, "http bad status %s", line+9);
483157bddd21SDag-Erling Smørgrav return 0;
483257bddd21SDag-Erling Smørgrav }
483357bddd21SDag-Erling Smørgrav } else if(strncasecmp(line, "Content-Length: ", 16) == 0) {
483457bddd21SDag-Erling Smørgrav if(!c->http_is_chunked)
483557bddd21SDag-Erling Smørgrav c->tcp_byte_count = (size_t)atoi(line+16);
483657bddd21SDag-Erling Smørgrav } else if(strncasecmp(line, "Transfer-Encoding: chunked", 19+7) == 0) {
483757bddd21SDag-Erling Smørgrav c->tcp_byte_count = 0;
483857bddd21SDag-Erling Smørgrav c->http_is_chunked = 1;
483957bddd21SDag-Erling Smørgrav } else if(line[0] == 0) {
484057bddd21SDag-Erling Smørgrav /* end of initial headers */
484157bddd21SDag-Erling Smørgrav c->http_in_headers = 0;
484257bddd21SDag-Erling Smørgrav if(c->http_is_chunked)
484357bddd21SDag-Erling Smørgrav c->http_in_chunk_headers = 1;
484457bddd21SDag-Erling Smørgrav /* remove header text from front of buffer
484557bddd21SDag-Erling Smørgrav * the buffer is going to be used to return the data segment
484657bddd21SDag-Erling Smørgrav * itself and we don't want the header to get returned
484757bddd21SDag-Erling Smørgrav * prepended with it */
484857bddd21SDag-Erling Smørgrav http_moveover_buffer(c->buffer);
484957bddd21SDag-Erling Smørgrav sldns_buffer_flip(c->buffer);
485057bddd21SDag-Erling Smørgrav return 1;
485157bddd21SDag-Erling Smørgrav }
485257bddd21SDag-Erling Smørgrav /* ignore other headers */
485357bddd21SDag-Erling Smørgrav return 1;
485457bddd21SDag-Erling Smørgrav }
485557bddd21SDag-Erling Smørgrav
485657bddd21SDag-Erling Smørgrav /** a chunk header is complete, process it, return 0=fail, 1=continue next
485757bddd21SDag-Erling Smørgrav * header line, 2=done with chunked transfer*/
485857bddd21SDag-Erling Smørgrav static int
485957bddd21SDag-Erling Smørgrav http_process_chunk_header(struct comm_point* c)
486057bddd21SDag-Erling Smørgrav {
486157bddd21SDag-Erling Smørgrav char* line = http_header_line(c->buffer);
486257bddd21SDag-Erling Smørgrav if(!line) return 1;
486357bddd21SDag-Erling Smørgrav if(c->http_in_chunk_headers == 3) {
486457bddd21SDag-Erling Smørgrav verbose(VERB_ALGO, "http chunk trailer: %s", line);
486557bddd21SDag-Erling Smørgrav /* are we done ? */
486657bddd21SDag-Erling Smørgrav if(line[0] == 0 && c->tcp_byte_count == 0) {
486757bddd21SDag-Erling Smørgrav /* callback of http reader when NETEVENT_DONE,
486857bddd21SDag-Erling Smørgrav * end of data, with no data in buffer */
486957bddd21SDag-Erling Smørgrav sldns_buffer_set_position(c->buffer, 0);
487057bddd21SDag-Erling Smørgrav sldns_buffer_set_limit(c->buffer, 0);
487157bddd21SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point(c->callback));
487257bddd21SDag-Erling Smørgrav (void)(*c->callback)(c, c->cb_arg, NETEVENT_DONE, NULL);
487357bddd21SDag-Erling Smørgrav /* return that we are done */
487457bddd21SDag-Erling Smørgrav return 2;
487557bddd21SDag-Erling Smørgrav }
487657bddd21SDag-Erling Smørgrav if(line[0] == 0) {
487757bddd21SDag-Erling Smørgrav /* continue with header of the next chunk */
487857bddd21SDag-Erling Smørgrav c->http_in_chunk_headers = 1;
487957bddd21SDag-Erling Smørgrav /* remove header text from front of buffer */
488057bddd21SDag-Erling Smørgrav http_moveover_buffer(c->buffer);
488157bddd21SDag-Erling Smørgrav sldns_buffer_flip(c->buffer);
488257bddd21SDag-Erling Smørgrav return 1;
488357bddd21SDag-Erling Smørgrav }
488457bddd21SDag-Erling Smørgrav /* ignore further trail headers */
488557bddd21SDag-Erling Smørgrav return 1;
488657bddd21SDag-Erling Smørgrav }
488757bddd21SDag-Erling Smørgrav verbose(VERB_ALGO, "http chunk header: %s", line);
488857bddd21SDag-Erling Smørgrav if(c->http_in_chunk_headers == 1) {
488957bddd21SDag-Erling Smørgrav /* read chunked start line */
489057bddd21SDag-Erling Smørgrav char* end = NULL;
489157bddd21SDag-Erling Smørgrav c->tcp_byte_count = (size_t)strtol(line, &end, 16);
489257bddd21SDag-Erling Smørgrav if(end == line)
489357bddd21SDag-Erling Smørgrav return 0;
489457bddd21SDag-Erling Smørgrav c->http_in_chunk_headers = 0;
489557bddd21SDag-Erling Smørgrav /* remove header text from front of buffer */
489657bddd21SDag-Erling Smørgrav http_moveover_buffer(c->buffer);
489757bddd21SDag-Erling Smørgrav sldns_buffer_flip(c->buffer);
489857bddd21SDag-Erling Smørgrav if(c->tcp_byte_count == 0) {
489957bddd21SDag-Erling Smørgrav /* done with chunks, process chunk_trailer lines */
490057bddd21SDag-Erling Smørgrav c->http_in_chunk_headers = 3;
490157bddd21SDag-Erling Smørgrav }
490257bddd21SDag-Erling Smørgrav return 1;
490357bddd21SDag-Erling Smørgrav }
490457bddd21SDag-Erling Smørgrav /* ignore other headers */
490557bddd21SDag-Erling Smørgrav return 1;
490657bddd21SDag-Erling Smørgrav }
490757bddd21SDag-Erling Smørgrav
49085469a995SCy Schubert /** handle nonchunked data segment, 0=fail, 1=wait */
490957bddd21SDag-Erling Smørgrav static int
491057bddd21SDag-Erling Smørgrav http_nonchunk_segment(struct comm_point* c)
491157bddd21SDag-Erling Smørgrav {
491257bddd21SDag-Erling Smørgrav /* c->buffer at position..limit has new data we read in.
491357bddd21SDag-Erling Smørgrav * the buffer itself is full of nonchunked data.
491457bddd21SDag-Erling Smørgrav * we are looking to read tcp_byte_count more data
491557bddd21SDag-Erling Smørgrav * and then the transfer is done. */
491657bddd21SDag-Erling Smørgrav size_t remainbufferlen;
49175469a995SCy Schubert size_t got_now = sldns_buffer_limit(c->buffer);
491857bddd21SDag-Erling Smørgrav if(c->tcp_byte_count <= got_now) {
491957bddd21SDag-Erling Smørgrav /* done, this is the last data fragment */
492057bddd21SDag-Erling Smørgrav c->http_stored = 0;
492157bddd21SDag-Erling Smørgrav sldns_buffer_set_position(c->buffer, 0);
492257bddd21SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point(c->callback));
492357bddd21SDag-Erling Smørgrav (void)(*c->callback)(c, c->cb_arg, NETEVENT_DONE, NULL);
492457bddd21SDag-Erling Smørgrav return 1;
492557bddd21SDag-Erling Smørgrav }
492657bddd21SDag-Erling Smørgrav /* if we have the buffer space,
492757bddd21SDag-Erling Smørgrav * read more data collected into the buffer */
492857bddd21SDag-Erling Smørgrav remainbufferlen = sldns_buffer_capacity(c->buffer) -
492957bddd21SDag-Erling Smørgrav sldns_buffer_limit(c->buffer);
49305469a995SCy Schubert if(remainbufferlen+got_now >= c->tcp_byte_count ||
4931a39a5a69SCy Schubert remainbufferlen >= (size_t)(c->ssl?16384:2048)) {
493257bddd21SDag-Erling Smørgrav size_t total = sldns_buffer_limit(c->buffer);
493357bddd21SDag-Erling Smørgrav sldns_buffer_clear(c->buffer);
493457bddd21SDag-Erling Smørgrav sldns_buffer_set_position(c->buffer, total);
493557bddd21SDag-Erling Smørgrav c->http_stored = total;
493657bddd21SDag-Erling Smørgrav /* return and wait to read more */
493757bddd21SDag-Erling Smørgrav return 1;
493857bddd21SDag-Erling Smørgrav }
493957bddd21SDag-Erling Smørgrav /* call callback with this data amount, then
494057bddd21SDag-Erling Smørgrav * wait for more */
49415469a995SCy Schubert c->tcp_byte_count -= got_now;
494257bddd21SDag-Erling Smørgrav c->http_stored = 0;
494357bddd21SDag-Erling Smørgrav sldns_buffer_set_position(c->buffer, 0);
494457bddd21SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point(c->callback));
494557bddd21SDag-Erling Smørgrav (void)(*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, NULL);
494657bddd21SDag-Erling Smørgrav /* c->callback has to buffer_clear(c->buffer). */
494757bddd21SDag-Erling Smørgrav /* return and wait to read more */
494857bddd21SDag-Erling Smørgrav return 1;
494957bddd21SDag-Erling Smørgrav }
495057bddd21SDag-Erling Smørgrav
4951f44e67d1SCy Schubert /** handle chunked data segment, return 0=fail, 1=wait, 2=process more */
495257bddd21SDag-Erling Smørgrav static int
495357bddd21SDag-Erling Smørgrav http_chunked_segment(struct comm_point* c)
495457bddd21SDag-Erling Smørgrav {
495557bddd21SDag-Erling Smørgrav /* the c->buffer has from position..limit new data we read. */
495657bddd21SDag-Erling Smørgrav /* the current chunk has length tcp_byte_count.
495757bddd21SDag-Erling Smørgrav * once we read that read more chunk headers.
495857bddd21SDag-Erling Smørgrav */
495957bddd21SDag-Erling Smørgrav size_t remainbufferlen;
496057bddd21SDag-Erling Smørgrav size_t got_now = sldns_buffer_limit(c->buffer) - c->http_stored;
4961f44e67d1SCy Schubert verbose(VERB_ALGO, "http_chunked_segment: got now %d, tcpbytcount %d, http_stored %d, buffer pos %d, buffer limit %d", (int)got_now, (int)c->tcp_byte_count, (int)c->http_stored, (int)sldns_buffer_position(c->buffer), (int)sldns_buffer_limit(c->buffer));
496257bddd21SDag-Erling Smørgrav if(c->tcp_byte_count <= got_now) {
496357bddd21SDag-Erling Smørgrav /* the chunk has completed (with perhaps some extra data
496457bddd21SDag-Erling Smørgrav * from next chunk header and next chunk) */
496557bddd21SDag-Erling Smørgrav /* save too much info into temp buffer */
496657bddd21SDag-Erling Smørgrav size_t fraglen;
496757bddd21SDag-Erling Smørgrav struct comm_reply repinfo;
496857bddd21SDag-Erling Smørgrav c->http_stored = 0;
496957bddd21SDag-Erling Smørgrav sldns_buffer_skip(c->buffer, (ssize_t)c->tcp_byte_count);
497057bddd21SDag-Erling Smørgrav sldns_buffer_clear(c->http_temp);
497157bddd21SDag-Erling Smørgrav sldns_buffer_write(c->http_temp,
497257bddd21SDag-Erling Smørgrav sldns_buffer_current(c->buffer),
497357bddd21SDag-Erling Smørgrav sldns_buffer_remaining(c->buffer));
497457bddd21SDag-Erling Smørgrav sldns_buffer_flip(c->http_temp);
497557bddd21SDag-Erling Smørgrav
497657bddd21SDag-Erling Smørgrav /* callback with this fragment */
497757bddd21SDag-Erling Smørgrav fraglen = sldns_buffer_position(c->buffer);
497857bddd21SDag-Erling Smørgrav sldns_buffer_set_position(c->buffer, 0);
497957bddd21SDag-Erling Smørgrav sldns_buffer_set_limit(c->buffer, fraglen);
498057bddd21SDag-Erling Smørgrav repinfo = c->repinfo;
498157bddd21SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point(c->callback));
498257bddd21SDag-Erling Smørgrav (void)(*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, &repinfo);
498357bddd21SDag-Erling Smørgrav /* c->callback has to buffer_clear(). */
498457bddd21SDag-Erling Smørgrav
498557bddd21SDag-Erling Smørgrav /* is commpoint deleted? */
498657bddd21SDag-Erling Smørgrav if(!repinfo.c) {
498757bddd21SDag-Erling Smørgrav return 1;
498857bddd21SDag-Erling Smørgrav }
498957bddd21SDag-Erling Smørgrav /* copy waiting info */
499057bddd21SDag-Erling Smørgrav sldns_buffer_clear(c->buffer);
499157bddd21SDag-Erling Smørgrav sldns_buffer_write(c->buffer,
499257bddd21SDag-Erling Smørgrav sldns_buffer_begin(c->http_temp),
499357bddd21SDag-Erling Smørgrav sldns_buffer_remaining(c->http_temp));
499457bddd21SDag-Erling Smørgrav sldns_buffer_flip(c->buffer);
499557bddd21SDag-Erling Smørgrav /* process end of chunk trailer header lines, until
499657bddd21SDag-Erling Smørgrav * an empty line */
499757bddd21SDag-Erling Smørgrav c->http_in_chunk_headers = 3;
499857bddd21SDag-Erling Smørgrav /* process more data in buffer (if any) */
499957bddd21SDag-Erling Smørgrav return 2;
500057bddd21SDag-Erling Smørgrav }
500157bddd21SDag-Erling Smørgrav c->tcp_byte_count -= got_now;
500257bddd21SDag-Erling Smørgrav
500357bddd21SDag-Erling Smørgrav /* if we have the buffer space,
500457bddd21SDag-Erling Smørgrav * read more data collected into the buffer */
500557bddd21SDag-Erling Smørgrav remainbufferlen = sldns_buffer_capacity(c->buffer) -
500657bddd21SDag-Erling Smørgrav sldns_buffer_limit(c->buffer);
500757bddd21SDag-Erling Smørgrav if(remainbufferlen >= c->tcp_byte_count ||
500857bddd21SDag-Erling Smørgrav remainbufferlen >= 2048) {
500957bddd21SDag-Erling Smørgrav size_t total = sldns_buffer_limit(c->buffer);
501057bddd21SDag-Erling Smørgrav sldns_buffer_clear(c->buffer);
501157bddd21SDag-Erling Smørgrav sldns_buffer_set_position(c->buffer, total);
501257bddd21SDag-Erling Smørgrav c->http_stored = total;
501357bddd21SDag-Erling Smørgrav /* return and wait to read more */
501457bddd21SDag-Erling Smørgrav return 1;
501557bddd21SDag-Erling Smørgrav }
501657bddd21SDag-Erling Smørgrav
501757bddd21SDag-Erling Smørgrav /* callback of http reader for a new part of the data */
501857bddd21SDag-Erling Smørgrav c->http_stored = 0;
501957bddd21SDag-Erling Smørgrav sldns_buffer_set_position(c->buffer, 0);
502057bddd21SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point(c->callback));
502157bddd21SDag-Erling Smørgrav (void)(*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, NULL);
502257bddd21SDag-Erling Smørgrav /* c->callback has to buffer_clear(c->buffer). */
502357bddd21SDag-Erling Smørgrav /* return and wait to read more */
502457bddd21SDag-Erling Smørgrav return 1;
502557bddd21SDag-Erling Smørgrav }
502657bddd21SDag-Erling Smørgrav
5027c0caa2e2SCy Schubert #ifdef HAVE_NGHTTP2
5028c0caa2e2SCy Schubert /** Create new http2 session. Called when creating handling comm point. */
5029f44e67d1SCy Schubert static struct http2_session* http2_session_create(struct comm_point* c)
5030c0caa2e2SCy Schubert {
5031c0caa2e2SCy Schubert struct http2_session* session = calloc(1, sizeof(*session));
5032c0caa2e2SCy Schubert if(!session) {
5033c0caa2e2SCy Schubert log_err("malloc failure while creating http2 session");
5034c0caa2e2SCy Schubert return NULL;
5035c0caa2e2SCy Schubert }
5036c0caa2e2SCy Schubert session->c = c;
5037c0caa2e2SCy Schubert
5038c0caa2e2SCy Schubert return session;
5039c0caa2e2SCy Schubert }
5040c0caa2e2SCy Schubert #endif
5041c0caa2e2SCy Schubert
5042c0caa2e2SCy Schubert /** Delete http2 session. After closing connection or on error */
5043f44e67d1SCy Schubert static void http2_session_delete(struct http2_session* h2_session)
5044c0caa2e2SCy Schubert {
5045c0caa2e2SCy Schubert #ifdef HAVE_NGHTTP2
5046c0caa2e2SCy Schubert if(h2_session->callbacks)
5047c0caa2e2SCy Schubert nghttp2_session_callbacks_del(h2_session->callbacks);
5048c0caa2e2SCy Schubert free(h2_session);
5049c0caa2e2SCy Schubert #else
5050c0caa2e2SCy Schubert (void)h2_session;
5051c0caa2e2SCy Schubert #endif
5052c0caa2e2SCy Schubert }
5053c0caa2e2SCy Schubert
5054c0caa2e2SCy Schubert #ifdef HAVE_NGHTTP2
5055c0caa2e2SCy Schubert struct http2_stream* http2_stream_create(int32_t stream_id)
5056c0caa2e2SCy Schubert {
5057c0caa2e2SCy Schubert struct http2_stream* h2_stream = calloc(1, sizeof(*h2_stream));
5058c0caa2e2SCy Schubert if(!h2_stream) {
5059c0caa2e2SCy Schubert log_err("malloc failure while creating http2 stream");
5060c0caa2e2SCy Schubert return NULL;
5061c0caa2e2SCy Schubert }
5062c0caa2e2SCy Schubert h2_stream->stream_id = stream_id;
5063c0caa2e2SCy Schubert return h2_stream;
5064c0caa2e2SCy Schubert }
5065c0caa2e2SCy Schubert
5066c0caa2e2SCy Schubert /** Delete http2 stream. After session delete or stream close callback */
5067c0caa2e2SCy Schubert static void http2_stream_delete(struct http2_session* h2_session,
5068c0caa2e2SCy Schubert struct http2_stream* h2_stream)
5069c0caa2e2SCy Schubert {
5070c0caa2e2SCy Schubert if(h2_stream->mesh_state) {
5071c0caa2e2SCy Schubert mesh_state_remove_reply(h2_stream->mesh, h2_stream->mesh_state,
5072c0caa2e2SCy Schubert h2_session->c);
5073c0caa2e2SCy Schubert h2_stream->mesh_state = NULL;
5074c0caa2e2SCy Schubert }
5075c0caa2e2SCy Schubert http2_req_stream_clear(h2_stream);
5076c0caa2e2SCy Schubert free(h2_stream);
5077c0caa2e2SCy Schubert }
5078c0caa2e2SCy Schubert #endif
5079c0caa2e2SCy Schubert
5080c0caa2e2SCy Schubert void http2_stream_add_meshstate(struct http2_stream* h2_stream,
5081c0caa2e2SCy Schubert struct mesh_area* mesh, struct mesh_state* m)
5082c0caa2e2SCy Schubert {
5083c0caa2e2SCy Schubert h2_stream->mesh = mesh;
5084c0caa2e2SCy Schubert h2_stream->mesh_state = m;
5085c0caa2e2SCy Schubert }
5086c0caa2e2SCy Schubert
508756850988SCy Schubert void http2_stream_remove_mesh_state(struct http2_stream* h2_stream)
508856850988SCy Schubert {
508956850988SCy Schubert if(!h2_stream)
509056850988SCy Schubert return;
509156850988SCy Schubert h2_stream->mesh_state = NULL;
509256850988SCy Schubert }
509356850988SCy Schubert
5094c0caa2e2SCy Schubert /** delete http2 session server. After closing connection. */
5095c0caa2e2SCy Schubert static void http2_session_server_delete(struct http2_session* h2_session)
5096c0caa2e2SCy Schubert {
5097c0caa2e2SCy Schubert #ifdef HAVE_NGHTTP2
5098c0caa2e2SCy Schubert struct http2_stream* h2_stream, *next;
5099c0caa2e2SCy Schubert nghttp2_session_del(h2_session->session); /* NULL input is fine */
5100c0caa2e2SCy Schubert h2_session->session = NULL;
5101c0caa2e2SCy Schubert for(h2_stream = h2_session->first_stream; h2_stream;) {
5102c0caa2e2SCy Schubert next = h2_stream->next;
5103c0caa2e2SCy Schubert http2_stream_delete(h2_session, h2_stream);
5104c0caa2e2SCy Schubert h2_stream = next;
5105c0caa2e2SCy Schubert }
5106c0caa2e2SCy Schubert h2_session->first_stream = NULL;
5107c0caa2e2SCy Schubert h2_session->is_drop = 0;
5108c0caa2e2SCy Schubert h2_session->postpone_drop = 0;
5109c0caa2e2SCy Schubert h2_session->c->h2_stream = NULL;
5110c0caa2e2SCy Schubert #endif
5111c0caa2e2SCy Schubert (void)h2_session;
5112c0caa2e2SCy Schubert }
5113c0caa2e2SCy Schubert
5114c0caa2e2SCy Schubert #ifdef HAVE_NGHTTP2
5115c0caa2e2SCy Schubert void http2_session_add_stream(struct http2_session* h2_session,
5116c0caa2e2SCy Schubert struct http2_stream* h2_stream)
5117c0caa2e2SCy Schubert {
5118c0caa2e2SCy Schubert if(h2_session->first_stream)
5119c0caa2e2SCy Schubert h2_session->first_stream->prev = h2_stream;
5120c0caa2e2SCy Schubert h2_stream->next = h2_session->first_stream;
5121c0caa2e2SCy Schubert h2_session->first_stream = h2_stream;
5122c0caa2e2SCy Schubert }
5123c0caa2e2SCy Schubert
5124c0caa2e2SCy Schubert /** remove stream from session linked list. After stream close callback or
5125c0caa2e2SCy Schubert * closing connection */
5126f44e67d1SCy Schubert static void http2_session_remove_stream(struct http2_session* h2_session,
5127c0caa2e2SCy Schubert struct http2_stream* h2_stream)
5128c0caa2e2SCy Schubert {
5129c0caa2e2SCy Schubert if(h2_stream->prev)
5130c0caa2e2SCy Schubert h2_stream->prev->next = h2_stream->next;
5131c0caa2e2SCy Schubert else
5132c0caa2e2SCy Schubert h2_session->first_stream = h2_stream->next;
5133c0caa2e2SCy Schubert if(h2_stream->next)
5134c0caa2e2SCy Schubert h2_stream->next->prev = h2_stream->prev;
5135c0caa2e2SCy Schubert
5136c0caa2e2SCy Schubert }
5137c0caa2e2SCy Schubert
5138c0caa2e2SCy Schubert int http2_stream_close_cb(nghttp2_session* ATTR_UNUSED(session),
5139c0caa2e2SCy Schubert int32_t stream_id, uint32_t ATTR_UNUSED(error_code), void* cb_arg)
5140c0caa2e2SCy Schubert {
5141c0caa2e2SCy Schubert struct http2_stream* h2_stream;
5142c0caa2e2SCy Schubert struct http2_session* h2_session = (struct http2_session*)cb_arg;
5143c0caa2e2SCy Schubert if(!(h2_stream = nghttp2_session_get_stream_user_data(
5144c0caa2e2SCy Schubert h2_session->session, stream_id))) {
5145c0caa2e2SCy Schubert return 0;
5146c0caa2e2SCy Schubert }
5147c0caa2e2SCy Schubert http2_session_remove_stream(h2_session, h2_stream);
5148c0caa2e2SCy Schubert http2_stream_delete(h2_session, h2_stream);
5149c0caa2e2SCy Schubert return 0;
5150c0caa2e2SCy Schubert }
5151c0caa2e2SCy Schubert
5152c0caa2e2SCy Schubert ssize_t http2_recv_cb(nghttp2_session* ATTR_UNUSED(session), uint8_t* buf,
5153c0caa2e2SCy Schubert size_t len, int ATTR_UNUSED(flags), void* cb_arg)
5154c0caa2e2SCy Schubert {
5155c0caa2e2SCy Schubert struct http2_session* h2_session = (struct http2_session*)cb_arg;
5156369c6923SCy Schubert ssize_t ret;
5157c0caa2e2SCy Schubert
5158c0caa2e2SCy Schubert log_assert(h2_session->c->type == comm_http);
5159c0caa2e2SCy Schubert log_assert(h2_session->c->h2_session);
5160c0caa2e2SCy Schubert
5161369c6923SCy Schubert #ifdef HAVE_SSL
5162369c6923SCy Schubert if(h2_session->c->ssl) {
5163369c6923SCy Schubert int r;
5164c0caa2e2SCy Schubert ERR_clear_error();
5165c0caa2e2SCy Schubert r = SSL_read(h2_session->c->ssl, buf, len);
5166c0caa2e2SCy Schubert if(r <= 0) {
5167c0caa2e2SCy Schubert int want = SSL_get_error(h2_session->c->ssl, r);
5168c0caa2e2SCy Schubert if(want == SSL_ERROR_ZERO_RETURN) {
5169c0caa2e2SCy Schubert return NGHTTP2_ERR_EOF;
5170c0caa2e2SCy Schubert } else if(want == SSL_ERROR_WANT_READ) {
5171c0caa2e2SCy Schubert return NGHTTP2_ERR_WOULDBLOCK;
5172c0caa2e2SCy Schubert } else if(want == SSL_ERROR_WANT_WRITE) {
5173c0caa2e2SCy Schubert h2_session->c->ssl_shake_state = comm_ssl_shake_hs_write;
5174c0caa2e2SCy Schubert comm_point_listen_for_rw(h2_session->c, 0, 1);
5175c0caa2e2SCy Schubert return NGHTTP2_ERR_WOULDBLOCK;
5176c0caa2e2SCy Schubert } else if(want == SSL_ERROR_SYSCALL) {
5177c0caa2e2SCy Schubert #ifdef ECONNRESET
5178c0caa2e2SCy Schubert if(errno == ECONNRESET && verbosity < 2)
5179c0caa2e2SCy Schubert return NGHTTP2_ERR_CALLBACK_FAILURE;
5180c0caa2e2SCy Schubert #endif
5181c0caa2e2SCy Schubert if(errno != 0)
5182c0caa2e2SCy Schubert log_err("SSL_read syscall: %s",
5183c0caa2e2SCy Schubert strerror(errno));
5184c0caa2e2SCy Schubert return NGHTTP2_ERR_CALLBACK_FAILURE;
5185c0caa2e2SCy Schubert }
5186103ba509SCy Schubert log_crypto_err_io("could not SSL_read", want);
5187c0caa2e2SCy Schubert return NGHTTP2_ERR_CALLBACK_FAILURE;
5188c0caa2e2SCy Schubert }
5189c0caa2e2SCy Schubert return r;
5190369c6923SCy Schubert }
5191369c6923SCy Schubert #endif /* HAVE_SSL */
5192369c6923SCy Schubert
5193865f46b2SCy Schubert ret = recv(h2_session->c->fd, buf, len, MSG_DONTWAIT);
5194369c6923SCy Schubert if(ret == 0) {
5195369c6923SCy Schubert return NGHTTP2_ERR_EOF;
5196369c6923SCy Schubert } else if(ret < 0) {
5197369c6923SCy Schubert #ifndef USE_WINSOCK
5198369c6923SCy Schubert if(errno == EINTR || errno == EAGAIN)
5199369c6923SCy Schubert return NGHTTP2_ERR_WOULDBLOCK;
5200369c6923SCy Schubert #ifdef ECONNRESET
5201369c6923SCy Schubert if(errno == ECONNRESET && verbosity < 2)
5202369c6923SCy Schubert return NGHTTP2_ERR_CALLBACK_FAILURE;
5203c0caa2e2SCy Schubert #endif
5204369c6923SCy Schubert log_err_addr("could not http2 recv: %s", strerror(errno),
5205865f46b2SCy Schubert &h2_session->c->repinfo.remote_addr,
5206865f46b2SCy Schubert h2_session->c->repinfo.remote_addrlen);
5207369c6923SCy Schubert #else /* USE_WINSOCK */
5208369c6923SCy Schubert if(WSAGetLastError() == WSAECONNRESET)
5209369c6923SCy Schubert return NGHTTP2_ERR_CALLBACK_FAILURE;
5210369c6923SCy Schubert if(WSAGetLastError() == WSAEINPROGRESS)
5211369c6923SCy Schubert return NGHTTP2_ERR_WOULDBLOCK;
5212369c6923SCy Schubert if(WSAGetLastError() == WSAEWOULDBLOCK) {
5213369c6923SCy Schubert ub_winsock_tcp_wouldblock(h2_session->c->ev->ev,
5214369c6923SCy Schubert UB_EV_READ);
5215369c6923SCy Schubert return NGHTTP2_ERR_WOULDBLOCK;
5216369c6923SCy Schubert }
5217369c6923SCy Schubert log_err_addr("could not http2 recv: %s",
5218369c6923SCy Schubert wsa_strerror(WSAGetLastError()),
5219865f46b2SCy Schubert &h2_session->c->repinfo.remote_addr,
5220865f46b2SCy Schubert h2_session->c->repinfo.remote_addrlen);
5221369c6923SCy Schubert #endif
5222369c6923SCy Schubert return NGHTTP2_ERR_CALLBACK_FAILURE;
5223369c6923SCy Schubert }
5224369c6923SCy Schubert return ret;
5225c0caa2e2SCy Schubert }
5226c0caa2e2SCy Schubert #endif /* HAVE_NGHTTP2 */
5227c0caa2e2SCy Schubert
5228c0caa2e2SCy Schubert /** Handle http2 read */
5229c0caa2e2SCy Schubert static int
5230c0caa2e2SCy Schubert comm_point_http2_handle_read(int ATTR_UNUSED(fd), struct comm_point* c)
5231c0caa2e2SCy Schubert {
5232c0caa2e2SCy Schubert #ifdef HAVE_NGHTTP2
5233c0caa2e2SCy Schubert int ret;
5234c0caa2e2SCy Schubert log_assert(c->h2_session);
5235c0caa2e2SCy Schubert
5236c0caa2e2SCy Schubert /* reading until recv cb returns NGHTTP2_ERR_WOULDBLOCK */
5237c0caa2e2SCy Schubert ret = nghttp2_session_recv(c->h2_session->session);
5238c0caa2e2SCy Schubert if(ret) {
5239c0caa2e2SCy Schubert if(ret != NGHTTP2_ERR_EOF &&
5240c0caa2e2SCy Schubert ret != NGHTTP2_ERR_CALLBACK_FAILURE) {
5241369c6923SCy Schubert char a[256];
5242865f46b2SCy Schubert addr_to_str(&c->repinfo.remote_addr,
5243865f46b2SCy Schubert c->repinfo.remote_addrlen, a, sizeof(a));
5244369c6923SCy Schubert verbose(VERB_QUERY, "http2: session_recv from %s failed, "
5245369c6923SCy Schubert "error: %s", a, nghttp2_strerror(ret));
5246c0caa2e2SCy Schubert }
5247c0caa2e2SCy Schubert return 0;
5248c0caa2e2SCy Schubert }
5249c0caa2e2SCy Schubert if(nghttp2_session_want_write(c->h2_session->session)) {
5250c0caa2e2SCy Schubert c->tcp_is_reading = 0;
5251c0caa2e2SCy Schubert comm_point_stop_listening(c);
5252f44e67d1SCy Schubert comm_point_start_listening(c, -1, adjusted_tcp_timeout(c));
5253c0caa2e2SCy Schubert } else if(!nghttp2_session_want_read(c->h2_session->session))
5254c0caa2e2SCy Schubert return 0; /* connection can be closed */
5255c0caa2e2SCy Schubert return 1;
5256c0caa2e2SCy Schubert #else
5257c0caa2e2SCy Schubert (void)c;
5258c0caa2e2SCy Schubert return 0;
5259c0caa2e2SCy Schubert #endif
5260c0caa2e2SCy Schubert }
5261c0caa2e2SCy Schubert
526257bddd21SDag-Erling Smørgrav /**
526357bddd21SDag-Erling Smørgrav * Handle http reading callback.
526457bddd21SDag-Erling Smørgrav * @param fd: file descriptor of socket.
526557bddd21SDag-Erling Smørgrav * @param c: comm point to read from into buffer.
526657bddd21SDag-Erling Smørgrav * @return: 0 on error
526757bddd21SDag-Erling Smørgrav */
526857bddd21SDag-Erling Smørgrav static int
526957bddd21SDag-Erling Smørgrav comm_point_http_handle_read(int fd, struct comm_point* c)
527057bddd21SDag-Erling Smørgrav {
527157bddd21SDag-Erling Smørgrav log_assert(c->type == comm_http);
527257bddd21SDag-Erling Smørgrav log_assert(fd != -1);
527357bddd21SDag-Erling Smørgrav
527457bddd21SDag-Erling Smørgrav /* if we are in ssl handshake, handle SSL handshake */
527557bddd21SDag-Erling Smørgrav #ifdef HAVE_SSL
527657bddd21SDag-Erling Smørgrav if(c->ssl && c->ssl_shake_state != comm_ssl_shake_none) {
527757bddd21SDag-Erling Smørgrav if(!ssl_handshake(c))
527857bddd21SDag-Erling Smørgrav return 0;
527957bddd21SDag-Erling Smørgrav if(c->ssl_shake_state != comm_ssl_shake_none)
528057bddd21SDag-Erling Smørgrav return 1;
528157bddd21SDag-Erling Smørgrav }
528257bddd21SDag-Erling Smørgrav #endif /* HAVE_SSL */
528357bddd21SDag-Erling Smørgrav
528457bddd21SDag-Erling Smørgrav if(!c->tcp_is_reading)
528557bddd21SDag-Erling Smørgrav return 1;
5286c0caa2e2SCy Schubert
5287c0caa2e2SCy Schubert if(c->use_h2) {
5288c0caa2e2SCy Schubert return comm_point_http2_handle_read(fd, c);
5289c0caa2e2SCy Schubert }
5290c0caa2e2SCy Schubert
5291c0caa2e2SCy Schubert /* http version is <= http/1.1 */
5292c0caa2e2SCy Schubert
5293c0caa2e2SCy Schubert if(c->http_min_version >= http_version_2) {
5294c0caa2e2SCy Schubert /* HTTP/2 failed, not allowed to use lower version. */
5295c0caa2e2SCy Schubert return 0;
5296c0caa2e2SCy Schubert }
5297c0caa2e2SCy Schubert
529857bddd21SDag-Erling Smørgrav /* read more data */
529957bddd21SDag-Erling Smørgrav if(c->ssl) {
530057bddd21SDag-Erling Smørgrav if(!ssl_http_read_more(c))
530157bddd21SDag-Erling Smørgrav return 0;
530257bddd21SDag-Erling Smørgrav } else {
530357bddd21SDag-Erling Smørgrav if(!http_read_more(fd, c))
530457bddd21SDag-Erling Smørgrav return 0;
530557bddd21SDag-Erling Smørgrav }
530657bddd21SDag-Erling Smørgrav
53075469a995SCy Schubert if(c->http_stored >= sldns_buffer_position(c->buffer)) {
53085469a995SCy Schubert /* read did not work but we wanted more data, there is
53095469a995SCy Schubert * no bytes to process now. */
53105469a995SCy Schubert return 1;
53115469a995SCy Schubert }
531257bddd21SDag-Erling Smørgrav sldns_buffer_flip(c->buffer);
5313f44e67d1SCy Schubert /* if we are partway in a segment of data, position us at the point
5314f44e67d1SCy Schubert * where we left off previously */
5315f44e67d1SCy Schubert if(c->http_stored < sldns_buffer_limit(c->buffer))
5316f44e67d1SCy Schubert sldns_buffer_set_position(c->buffer, c->http_stored);
5317f44e67d1SCy Schubert else sldns_buffer_set_position(c->buffer, sldns_buffer_limit(c->buffer));
5318c0caa2e2SCy Schubert
531957bddd21SDag-Erling Smørgrav while(sldns_buffer_remaining(c->buffer) > 0) {
5320c0caa2e2SCy Schubert /* Handle HTTP/1.x data */
532157bddd21SDag-Erling Smørgrav /* if we are reading headers, read more headers */
532257bddd21SDag-Erling Smørgrav if(c->http_in_headers || c->http_in_chunk_headers) {
532357bddd21SDag-Erling Smørgrav /* if header is done, process the header */
532457bddd21SDag-Erling Smørgrav if(!http_header_done(c->buffer)) {
532557bddd21SDag-Erling Smørgrav /* copy remaining data to front of buffer
532657bddd21SDag-Erling Smørgrav * and set rest for writing into it */
532757bddd21SDag-Erling Smørgrav http_moveover_buffer(c->buffer);
532857bddd21SDag-Erling Smørgrav /* return and wait to read more */
532957bddd21SDag-Erling Smørgrav return 1;
533057bddd21SDag-Erling Smørgrav }
533157bddd21SDag-Erling Smørgrav if(!c->http_in_chunk_headers) {
533257bddd21SDag-Erling Smørgrav /* process initial headers */
533357bddd21SDag-Erling Smørgrav if(!http_process_initial_header(c))
533457bddd21SDag-Erling Smørgrav return 0;
533557bddd21SDag-Erling Smørgrav } else {
533657bddd21SDag-Erling Smørgrav /* process chunk headers */
533757bddd21SDag-Erling Smørgrav int r = http_process_chunk_header(c);
533857bddd21SDag-Erling Smørgrav if(r == 0) return 0;
533957bddd21SDag-Erling Smørgrav if(r == 2) return 1; /* done */
534057bddd21SDag-Erling Smørgrav /* r == 1, continue */
534157bddd21SDag-Erling Smørgrav }
534257bddd21SDag-Erling Smørgrav /* see if we have more to process */
534357bddd21SDag-Erling Smørgrav continue;
534457bddd21SDag-Erling Smørgrav }
534557bddd21SDag-Erling Smørgrav
534657bddd21SDag-Erling Smørgrav if(!c->http_is_chunked) {
534757bddd21SDag-Erling Smørgrav /* if we are reading nonchunks, process that*/
534857bddd21SDag-Erling Smørgrav return http_nonchunk_segment(c);
534957bddd21SDag-Erling Smørgrav } else {
535057bddd21SDag-Erling Smørgrav /* if we are reading chunks, read the chunk */
535157bddd21SDag-Erling Smørgrav int r = http_chunked_segment(c);
535257bddd21SDag-Erling Smørgrav if(r == 0) return 0;
535357bddd21SDag-Erling Smørgrav if(r == 1) return 1;
535457bddd21SDag-Erling Smørgrav continue;
535557bddd21SDag-Erling Smørgrav }
535657bddd21SDag-Erling Smørgrav }
535757bddd21SDag-Erling Smørgrav /* broke out of the loop; could not process header instead need
535857bddd21SDag-Erling Smørgrav * to read more */
535957bddd21SDag-Erling Smørgrav /* moveover any remaining data and read more data */
536057bddd21SDag-Erling Smørgrav http_moveover_buffer(c->buffer);
536157bddd21SDag-Erling Smørgrav /* return and wait to read more */
536257bddd21SDag-Erling Smørgrav return 1;
536357bddd21SDag-Erling Smørgrav }
536457bddd21SDag-Erling Smørgrav
536557bddd21SDag-Erling Smørgrav /** check pending connect for http */
536657bddd21SDag-Erling Smørgrav static int
536757bddd21SDag-Erling Smørgrav http_check_connect(int fd, struct comm_point* c)
536857bddd21SDag-Erling Smørgrav {
536957bddd21SDag-Erling Smørgrav /* check for pending error from nonblocking connect */
537057bddd21SDag-Erling Smørgrav /* from Stevens, unix network programming, vol1, 3rd ed, p450*/
537157bddd21SDag-Erling Smørgrav int error = 0;
537257bddd21SDag-Erling Smørgrav socklen_t len = (socklen_t)sizeof(error);
537357bddd21SDag-Erling Smørgrav if(getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&error,
537457bddd21SDag-Erling Smørgrav &len) < 0){
537557bddd21SDag-Erling Smørgrav #ifndef USE_WINSOCK
537657bddd21SDag-Erling Smørgrav error = errno; /* on solaris errno is error */
537757bddd21SDag-Erling Smørgrav #else /* USE_WINSOCK */
537857bddd21SDag-Erling Smørgrav error = WSAGetLastError();
537957bddd21SDag-Erling Smørgrav #endif
538057bddd21SDag-Erling Smørgrav }
538157bddd21SDag-Erling Smørgrav #ifndef USE_WINSOCK
538257bddd21SDag-Erling Smørgrav #if defined(EINPROGRESS) && defined(EWOULDBLOCK)
538357bddd21SDag-Erling Smørgrav if(error == EINPROGRESS || error == EWOULDBLOCK)
538457bddd21SDag-Erling Smørgrav return 1; /* try again later */
538557bddd21SDag-Erling Smørgrav else
538657bddd21SDag-Erling Smørgrav #endif
538757bddd21SDag-Erling Smørgrav if(error != 0 && verbosity < 2)
538857bddd21SDag-Erling Smørgrav return 0; /* silence lots of chatter in the logs */
538957bddd21SDag-Erling Smørgrav else if(error != 0) {
539057bddd21SDag-Erling Smørgrav log_err_addr("http connect", strerror(error),
5391865f46b2SCy Schubert &c->repinfo.remote_addr, c->repinfo.remote_addrlen);
539257bddd21SDag-Erling Smørgrav #else /* USE_WINSOCK */
539357bddd21SDag-Erling Smørgrav /* examine error */
539457bddd21SDag-Erling Smørgrav if(error == WSAEINPROGRESS)
539557bddd21SDag-Erling Smørgrav return 1;
539657bddd21SDag-Erling Smørgrav else if(error == WSAEWOULDBLOCK) {
539757bddd21SDag-Erling Smørgrav ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
539857bddd21SDag-Erling Smørgrav return 1;
539957bddd21SDag-Erling Smørgrav } else if(error != 0 && verbosity < 2)
540057bddd21SDag-Erling Smørgrav return 0;
540157bddd21SDag-Erling Smørgrav else if(error != 0) {
540257bddd21SDag-Erling Smørgrav log_err_addr("http connect", wsa_strerror(error),
5403865f46b2SCy Schubert &c->repinfo.remote_addr, c->repinfo.remote_addrlen);
540457bddd21SDag-Erling Smørgrav #endif /* USE_WINSOCK */
540557bddd21SDag-Erling Smørgrav return 0;
540657bddd21SDag-Erling Smørgrav }
540757bddd21SDag-Erling Smørgrav /* keep on processing this socket */
540857bddd21SDag-Erling Smørgrav return 2;
540957bddd21SDag-Erling Smørgrav }
541057bddd21SDag-Erling Smørgrav
541157bddd21SDag-Erling Smørgrav /** write more data for http (with ssl) */
541257bddd21SDag-Erling Smørgrav static int
541357bddd21SDag-Erling Smørgrav ssl_http_write_more(struct comm_point* c)
541457bddd21SDag-Erling Smørgrav {
541557bddd21SDag-Erling Smørgrav #ifdef HAVE_SSL
541657bddd21SDag-Erling Smørgrav int r;
541757bddd21SDag-Erling Smørgrav log_assert(sldns_buffer_remaining(c->buffer) > 0);
541857bddd21SDag-Erling Smørgrav ERR_clear_error();
541957bddd21SDag-Erling Smørgrav r = SSL_write(c->ssl, (void*)sldns_buffer_current(c->buffer),
542057bddd21SDag-Erling Smørgrav (int)sldns_buffer_remaining(c->buffer));
542157bddd21SDag-Erling Smørgrav if(r <= 0) {
542257bddd21SDag-Erling Smørgrav int want = SSL_get_error(c->ssl, r);
542357bddd21SDag-Erling Smørgrav if(want == SSL_ERROR_ZERO_RETURN) {
542457bddd21SDag-Erling Smørgrav return 0; /* closed */
542557bddd21SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_READ) {
5426e86b9096SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_hs_read;
542757bddd21SDag-Erling Smørgrav comm_point_listen_for_rw(c, 1, 0);
542857bddd21SDag-Erling Smørgrav return 1; /* wait for read condition */
542957bddd21SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_WRITE) {
543057bddd21SDag-Erling Smørgrav return 1; /* write more later */
543157bddd21SDag-Erling Smørgrav } else if(want == SSL_ERROR_SYSCALL) {
5432e86b9096SDag-Erling Smørgrav #ifdef EPIPE
5433e86b9096SDag-Erling Smørgrav if(errno == EPIPE && verbosity < 2)
5434e86b9096SDag-Erling Smørgrav return 0; /* silence 'broken pipe' */
5435e86b9096SDag-Erling Smørgrav #endif
543657bddd21SDag-Erling Smørgrav if(errno != 0)
543757bddd21SDag-Erling Smørgrav log_err("SSL_write syscall: %s",
543857bddd21SDag-Erling Smørgrav strerror(errno));
543957bddd21SDag-Erling Smørgrav return 0;
544057bddd21SDag-Erling Smørgrav }
5441103ba509SCy Schubert log_crypto_err_io("could not SSL_write", want);
544257bddd21SDag-Erling Smørgrav return 0;
544357bddd21SDag-Erling Smørgrav }
544457bddd21SDag-Erling Smørgrav sldns_buffer_skip(c->buffer, (ssize_t)r);
544557bddd21SDag-Erling Smørgrav return 1;
544657bddd21SDag-Erling Smørgrav #else
544757bddd21SDag-Erling Smørgrav (void)c;
544857bddd21SDag-Erling Smørgrav return 0;
544957bddd21SDag-Erling Smørgrav #endif /* HAVE_SSL */
545057bddd21SDag-Erling Smørgrav }
545157bddd21SDag-Erling Smørgrav
545257bddd21SDag-Erling Smørgrav /** write more data for http */
545357bddd21SDag-Erling Smørgrav static int
545457bddd21SDag-Erling Smørgrav http_write_more(int fd, struct comm_point* c)
545557bddd21SDag-Erling Smørgrav {
545657bddd21SDag-Erling Smørgrav ssize_t r;
545757bddd21SDag-Erling Smørgrav log_assert(sldns_buffer_remaining(c->buffer) > 0);
545857bddd21SDag-Erling Smørgrav r = send(fd, (void*)sldns_buffer_current(c->buffer),
545957bddd21SDag-Erling Smørgrav sldns_buffer_remaining(c->buffer), 0);
546057bddd21SDag-Erling Smørgrav if(r == -1) {
546157bddd21SDag-Erling Smørgrav #ifndef USE_WINSOCK
546257bddd21SDag-Erling Smørgrav if(errno == EINTR || errno == EAGAIN)
546357bddd21SDag-Erling Smørgrav return 1;
546457bddd21SDag-Erling Smørgrav #else
546557bddd21SDag-Erling Smørgrav if(WSAGetLastError() == WSAEINPROGRESS)
546657bddd21SDag-Erling Smørgrav return 1;
546757bddd21SDag-Erling Smørgrav if(WSAGetLastError() == WSAEWOULDBLOCK) {
546857bddd21SDag-Erling Smørgrav ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
546957bddd21SDag-Erling Smørgrav return 1;
547057bddd21SDag-Erling Smørgrav }
547157bddd21SDag-Erling Smørgrav #endif
5472c0caa2e2SCy Schubert log_err_addr("http send r", sock_strerror(errno),
5473865f46b2SCy Schubert &c->repinfo.remote_addr, c->repinfo.remote_addrlen);
547457bddd21SDag-Erling Smørgrav return 0;
547557bddd21SDag-Erling Smørgrav }
547657bddd21SDag-Erling Smørgrav sldns_buffer_skip(c->buffer, r);
547757bddd21SDag-Erling Smørgrav return 1;
547857bddd21SDag-Erling Smørgrav }
547957bddd21SDag-Erling Smørgrav
5480c0caa2e2SCy Schubert #ifdef HAVE_NGHTTP2
5481c0caa2e2SCy Schubert ssize_t http2_send_cb(nghttp2_session* ATTR_UNUSED(session), const uint8_t* buf,
5482c0caa2e2SCy Schubert size_t len, int ATTR_UNUSED(flags), void* cb_arg)
5483c0caa2e2SCy Schubert {
5484369c6923SCy Schubert ssize_t ret;
5485c0caa2e2SCy Schubert struct http2_session* h2_session = (struct http2_session*)cb_arg;
5486c0caa2e2SCy Schubert log_assert(h2_session->c->type == comm_http);
5487c0caa2e2SCy Schubert log_assert(h2_session->c->h2_session);
5488c0caa2e2SCy Schubert
5489369c6923SCy Schubert #ifdef HAVE_SSL
5490369c6923SCy Schubert if(h2_session->c->ssl) {
5491369c6923SCy Schubert int r;
5492c0caa2e2SCy Schubert ERR_clear_error();
5493c0caa2e2SCy Schubert r = SSL_write(h2_session->c->ssl, buf, len);
5494c0caa2e2SCy Schubert if(r <= 0) {
5495c0caa2e2SCy Schubert int want = SSL_get_error(h2_session->c->ssl, r);
5496c0caa2e2SCy Schubert if(want == SSL_ERROR_ZERO_RETURN) {
5497c0caa2e2SCy Schubert return NGHTTP2_ERR_CALLBACK_FAILURE;
5498c0caa2e2SCy Schubert } else if(want == SSL_ERROR_WANT_READ) {
5499c0caa2e2SCy Schubert h2_session->c->ssl_shake_state = comm_ssl_shake_hs_read;
5500c0caa2e2SCy Schubert comm_point_listen_for_rw(h2_session->c, 1, 0);
5501c0caa2e2SCy Schubert return NGHTTP2_ERR_WOULDBLOCK;
5502c0caa2e2SCy Schubert } else if(want == SSL_ERROR_WANT_WRITE) {
5503c0caa2e2SCy Schubert return NGHTTP2_ERR_WOULDBLOCK;
5504c0caa2e2SCy Schubert } else if(want == SSL_ERROR_SYSCALL) {
5505c0caa2e2SCy Schubert #ifdef EPIPE
5506c0caa2e2SCy Schubert if(errno == EPIPE && verbosity < 2)
5507c0caa2e2SCy Schubert return NGHTTP2_ERR_CALLBACK_FAILURE;
5508c0caa2e2SCy Schubert #endif
5509c0caa2e2SCy Schubert if(errno != 0)
5510c0caa2e2SCy Schubert log_err("SSL_write syscall: %s",
5511c0caa2e2SCy Schubert strerror(errno));
5512c0caa2e2SCy Schubert return NGHTTP2_ERR_CALLBACK_FAILURE;
5513c0caa2e2SCy Schubert }
5514103ba509SCy Schubert log_crypto_err_io("could not SSL_write", want);
5515c0caa2e2SCy Schubert return NGHTTP2_ERR_CALLBACK_FAILURE;
5516c0caa2e2SCy Schubert }
5517c0caa2e2SCy Schubert return r;
5518369c6923SCy Schubert }
5519369c6923SCy Schubert #endif /* HAVE_SSL */
5520369c6923SCy Schubert
5521369c6923SCy Schubert ret = send(h2_session->c->fd, buf, len, 0);
5522369c6923SCy Schubert if(ret == 0) {
5523369c6923SCy Schubert return NGHTTP2_ERR_CALLBACK_FAILURE;
5524369c6923SCy Schubert } else if(ret < 0) {
5525369c6923SCy Schubert #ifndef USE_WINSOCK
5526369c6923SCy Schubert if(errno == EINTR || errno == EAGAIN)
5527369c6923SCy Schubert return NGHTTP2_ERR_WOULDBLOCK;
5528369c6923SCy Schubert #ifdef EPIPE
5529369c6923SCy Schubert if(errno == EPIPE && verbosity < 2)
5530369c6923SCy Schubert return NGHTTP2_ERR_CALLBACK_FAILURE;
5531c0caa2e2SCy Schubert #endif
5532369c6923SCy Schubert #ifdef ECONNRESET
5533369c6923SCy Schubert if(errno == ECONNRESET && verbosity < 2)
5534369c6923SCy Schubert return NGHTTP2_ERR_CALLBACK_FAILURE;
5535369c6923SCy Schubert #endif
5536369c6923SCy Schubert log_err_addr("could not http2 write: %s", strerror(errno),
5537865f46b2SCy Schubert &h2_session->c->repinfo.remote_addr,
5538865f46b2SCy Schubert h2_session->c->repinfo.remote_addrlen);
5539369c6923SCy Schubert #else /* USE_WINSOCK */
5540369c6923SCy Schubert if(WSAGetLastError() == WSAENOTCONN)
5541369c6923SCy Schubert return NGHTTP2_ERR_WOULDBLOCK;
5542369c6923SCy Schubert if(WSAGetLastError() == WSAEINPROGRESS)
5543369c6923SCy Schubert return NGHTTP2_ERR_WOULDBLOCK;
5544369c6923SCy Schubert if(WSAGetLastError() == WSAEWOULDBLOCK) {
5545369c6923SCy Schubert ub_winsock_tcp_wouldblock(h2_session->c->ev->ev,
5546369c6923SCy Schubert UB_EV_WRITE);
5547369c6923SCy Schubert return NGHTTP2_ERR_WOULDBLOCK;
5548369c6923SCy Schubert }
5549369c6923SCy Schubert if(WSAGetLastError() == WSAECONNRESET && verbosity < 2)
5550369c6923SCy Schubert return NGHTTP2_ERR_CALLBACK_FAILURE;
5551369c6923SCy Schubert log_err_addr("could not http2 write: %s",
5552369c6923SCy Schubert wsa_strerror(WSAGetLastError()),
5553865f46b2SCy Schubert &h2_session->c->repinfo.remote_addr,
5554865f46b2SCy Schubert h2_session->c->repinfo.remote_addrlen);
5555369c6923SCy Schubert #endif
5556369c6923SCy Schubert return NGHTTP2_ERR_CALLBACK_FAILURE;
5557369c6923SCy Schubert }
5558369c6923SCy Schubert return ret;
5559c0caa2e2SCy Schubert }
5560c0caa2e2SCy Schubert #endif /* HAVE_NGHTTP2 */
5561c0caa2e2SCy Schubert
5562c0caa2e2SCy Schubert /** Handle http2 writing */
5563c0caa2e2SCy Schubert static int
5564c0caa2e2SCy Schubert comm_point_http2_handle_write(int ATTR_UNUSED(fd), struct comm_point* c)
5565c0caa2e2SCy Schubert {
5566c0caa2e2SCy Schubert #ifdef HAVE_NGHTTP2
5567c0caa2e2SCy Schubert int ret;
5568c0caa2e2SCy Schubert log_assert(c->h2_session);
5569c0caa2e2SCy Schubert
5570c0caa2e2SCy Schubert ret = nghttp2_session_send(c->h2_session->session);
5571c0caa2e2SCy Schubert if(ret) {
5572c0caa2e2SCy Schubert verbose(VERB_QUERY, "http2: session_send failed, "
5573c0caa2e2SCy Schubert "error: %s", nghttp2_strerror(ret));
5574c0caa2e2SCy Schubert return 0;
5575c0caa2e2SCy Schubert }
5576c0caa2e2SCy Schubert
5577c0caa2e2SCy Schubert if(nghttp2_session_want_read(c->h2_session->session)) {
5578c0caa2e2SCy Schubert c->tcp_is_reading = 1;
5579c0caa2e2SCy Schubert comm_point_stop_listening(c);
5580f44e67d1SCy Schubert comm_point_start_listening(c, -1, adjusted_tcp_timeout(c));
5581c0caa2e2SCy Schubert } else if(!nghttp2_session_want_write(c->h2_session->session))
5582c0caa2e2SCy Schubert return 0; /* connection can be closed */
5583c0caa2e2SCy Schubert return 1;
5584c0caa2e2SCy Schubert #else
5585c0caa2e2SCy Schubert (void)c;
5586c0caa2e2SCy Schubert return 0;
5587c0caa2e2SCy Schubert #endif
5588c0caa2e2SCy Schubert }
5589c0caa2e2SCy Schubert
559057bddd21SDag-Erling Smørgrav /**
559157bddd21SDag-Erling Smørgrav * Handle http writing callback.
559257bddd21SDag-Erling Smørgrav * @param fd: file descriptor of socket.
559357bddd21SDag-Erling Smørgrav * @param c: comm point to write buffer out of.
559457bddd21SDag-Erling Smørgrav * @return: 0 on error
559557bddd21SDag-Erling Smørgrav */
559657bddd21SDag-Erling Smørgrav static int
559757bddd21SDag-Erling Smørgrav comm_point_http_handle_write(int fd, struct comm_point* c)
559857bddd21SDag-Erling Smørgrav {
559957bddd21SDag-Erling Smørgrav log_assert(c->type == comm_http);
560057bddd21SDag-Erling Smørgrav log_assert(fd != -1);
560157bddd21SDag-Erling Smørgrav
560257bddd21SDag-Erling Smørgrav /* check pending connect errors, if that fails, we wait for more,
560357bddd21SDag-Erling Smørgrav * or we can continue to write contents */
560457bddd21SDag-Erling Smørgrav if(c->tcp_check_nb_connect) {
560557bddd21SDag-Erling Smørgrav int r = http_check_connect(fd, c);
560657bddd21SDag-Erling Smørgrav if(r == 0) return 0;
560757bddd21SDag-Erling Smørgrav if(r == 1) return 1;
560857bddd21SDag-Erling Smørgrav c->tcp_check_nb_connect = 0;
560957bddd21SDag-Erling Smørgrav }
561057bddd21SDag-Erling Smørgrav /* if we are in ssl handshake, handle SSL handshake */
561157bddd21SDag-Erling Smørgrav #ifdef HAVE_SSL
561257bddd21SDag-Erling Smørgrav if(c->ssl && c->ssl_shake_state != comm_ssl_shake_none) {
561357bddd21SDag-Erling Smørgrav if(!ssl_handshake(c))
561457bddd21SDag-Erling Smørgrav return 0;
561557bddd21SDag-Erling Smørgrav if(c->ssl_shake_state != comm_ssl_shake_none)
561657bddd21SDag-Erling Smørgrav return 1;
561757bddd21SDag-Erling Smørgrav }
561857bddd21SDag-Erling Smørgrav #endif /* HAVE_SSL */
561957bddd21SDag-Erling Smørgrav if(c->tcp_is_reading)
562057bddd21SDag-Erling Smørgrav return 1;
5621c0caa2e2SCy Schubert
5622c0caa2e2SCy Schubert if(c->use_h2) {
5623c0caa2e2SCy Schubert return comm_point_http2_handle_write(fd, c);
5624c0caa2e2SCy Schubert }
5625c0caa2e2SCy Schubert
5626c0caa2e2SCy Schubert /* http version is <= http/1.1 */
5627c0caa2e2SCy Schubert
5628c0caa2e2SCy Schubert if(c->http_min_version >= http_version_2) {
5629c0caa2e2SCy Schubert /* HTTP/2 failed, not allowed to use lower version. */
5630c0caa2e2SCy Schubert return 0;
5631c0caa2e2SCy Schubert }
5632c0caa2e2SCy Schubert
563357bddd21SDag-Erling Smørgrav /* if we are writing, write more */
563457bddd21SDag-Erling Smørgrav if(c->ssl) {
563557bddd21SDag-Erling Smørgrav if(!ssl_http_write_more(c))
563657bddd21SDag-Erling Smørgrav return 0;
563757bddd21SDag-Erling Smørgrav } else {
563857bddd21SDag-Erling Smørgrav if(!http_write_more(fd, c))
563957bddd21SDag-Erling Smørgrav return 0;
564057bddd21SDag-Erling Smørgrav }
564157bddd21SDag-Erling Smørgrav
564257bddd21SDag-Erling Smørgrav /* we write a single buffer contents, that can contain
564357bddd21SDag-Erling Smørgrav * the http request, and then flip to read the results */
564457bddd21SDag-Erling Smørgrav /* see if write is done */
564557bddd21SDag-Erling Smørgrav if(sldns_buffer_remaining(c->buffer) == 0) {
564657bddd21SDag-Erling Smørgrav sldns_buffer_clear(c->buffer);
564757bddd21SDag-Erling Smørgrav if(c->tcp_do_toggle_rw)
564857bddd21SDag-Erling Smørgrav c->tcp_is_reading = 1;
564957bddd21SDag-Erling Smørgrav c->tcp_byte_count = 0;
565057bddd21SDag-Erling Smørgrav /* switch from listening(write) to listening(read) */
565157bddd21SDag-Erling Smørgrav comm_point_stop_listening(c);
565257bddd21SDag-Erling Smørgrav comm_point_start_listening(c, -1, -1);
565357bddd21SDag-Erling Smørgrav }
565457bddd21SDag-Erling Smørgrav return 1;
565557bddd21SDag-Erling Smørgrav }
565657bddd21SDag-Erling Smørgrav
565757bddd21SDag-Erling Smørgrav void
565857bddd21SDag-Erling Smørgrav comm_point_http_handle_callback(int fd, short event, void* arg)
565957bddd21SDag-Erling Smørgrav {
566057bddd21SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)arg;
566157bddd21SDag-Erling Smørgrav log_assert(c->type == comm_http);
566257bddd21SDag-Erling Smørgrav ub_comm_base_now(c->ev->base);
566357bddd21SDag-Erling Smørgrav
5664e86b9096SDag-Erling Smørgrav if(event&UB_EV_TIMEOUT) {
5665e86b9096SDag-Erling Smørgrav verbose(VERB_QUERY, "http took too long, dropped");
5666e86b9096SDag-Erling Smørgrav reclaim_http_handler(c);
5667e86b9096SDag-Erling Smørgrav if(!c->tcp_do_close) {
5668e86b9096SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point(c->callback));
5669e86b9096SDag-Erling Smørgrav (void)(*c->callback)(c, c->cb_arg,
5670e86b9096SDag-Erling Smørgrav NETEVENT_TIMEOUT, NULL);
5671e86b9096SDag-Erling Smørgrav }
5672e86b9096SDag-Erling Smørgrav return;
5673e86b9096SDag-Erling Smørgrav }
567457bddd21SDag-Erling Smørgrav if(event&UB_EV_READ) {
567557bddd21SDag-Erling Smørgrav if(!comm_point_http_handle_read(fd, c)) {
567657bddd21SDag-Erling Smørgrav reclaim_http_handler(c);
567757bddd21SDag-Erling Smørgrav if(!c->tcp_do_close) {
567857bddd21SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point(
567957bddd21SDag-Erling Smørgrav c->callback));
568057bddd21SDag-Erling Smørgrav (void)(*c->callback)(c, c->cb_arg,
568157bddd21SDag-Erling Smørgrav NETEVENT_CLOSED, NULL);
568257bddd21SDag-Erling Smørgrav }
568357bddd21SDag-Erling Smørgrav }
568457bddd21SDag-Erling Smørgrav return;
568557bddd21SDag-Erling Smørgrav }
568657bddd21SDag-Erling Smørgrav if(event&UB_EV_WRITE) {
568757bddd21SDag-Erling Smørgrav if(!comm_point_http_handle_write(fd, c)) {
568857bddd21SDag-Erling Smørgrav reclaim_http_handler(c);
568957bddd21SDag-Erling Smørgrav if(!c->tcp_do_close) {
569057bddd21SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point(
569157bddd21SDag-Erling Smørgrav c->callback));
569257bddd21SDag-Erling Smørgrav (void)(*c->callback)(c, c->cb_arg,
569357bddd21SDag-Erling Smørgrav NETEVENT_CLOSED, NULL);
569457bddd21SDag-Erling Smørgrav }
569557bddd21SDag-Erling Smørgrav }
569657bddd21SDag-Erling Smørgrav return;
569757bddd21SDag-Erling Smørgrav }
569857bddd21SDag-Erling Smørgrav log_err("Ignored event %d for httphdl.", event);
569957bddd21SDag-Erling Smørgrav }
570057bddd21SDag-Erling Smørgrav
5701b7579f77SDag-Erling Smørgrav void comm_point_local_handle_callback(int fd, short event, void* arg)
5702b7579f77SDag-Erling Smørgrav {
5703b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)arg;
5704b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_local);
5705e2d15004SDag-Erling Smørgrav ub_comm_base_now(c->ev->base);
5706b7579f77SDag-Erling Smørgrav
5707e2d15004SDag-Erling Smørgrav if(event&UB_EV_READ) {
5708b7579f77SDag-Erling Smørgrav if(!comm_point_tcp_handle_read(fd, c, 1)) {
5709b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point(c->callback));
5710b7579f77SDag-Erling Smørgrav (void)(*c->callback)(c, c->cb_arg, NETEVENT_CLOSED,
5711b7579f77SDag-Erling Smørgrav NULL);
5712b7579f77SDag-Erling Smørgrav }
5713b7579f77SDag-Erling Smørgrav return;
5714b7579f77SDag-Erling Smørgrav }
5715b7579f77SDag-Erling Smørgrav log_err("Ignored event %d for localhdl.", event);
5716b7579f77SDag-Erling Smørgrav }
5717b7579f77SDag-Erling Smørgrav
5718b7579f77SDag-Erling Smørgrav void comm_point_raw_handle_callback(int ATTR_UNUSED(fd),
5719b7579f77SDag-Erling Smørgrav short event, void* arg)
5720b7579f77SDag-Erling Smørgrav {
5721b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)arg;
5722b7579f77SDag-Erling Smørgrav int err = NETEVENT_NOERROR;
5723b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_raw);
5724e2d15004SDag-Erling Smørgrav ub_comm_base_now(c->ev->base);
5725b7579f77SDag-Erling Smørgrav
5726e2d15004SDag-Erling Smørgrav if(event&UB_EV_TIMEOUT)
5727b7579f77SDag-Erling Smørgrav err = NETEVENT_TIMEOUT;
5728b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point_raw(c->callback));
5729b7579f77SDag-Erling Smørgrav (void)(*c->callback)(c, c->cb_arg, err, NULL);
5730b7579f77SDag-Erling Smørgrav }
5731b7579f77SDag-Erling Smørgrav
5732b7579f77SDag-Erling Smørgrav struct comm_point*
573317d15b25SDag-Erling Smørgrav comm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer,
5734865f46b2SCy Schubert int pp2_enabled, comm_point_callback_type* callback,
5735865f46b2SCy Schubert void* callback_arg, struct unbound_socket* socket)
5736b7579f77SDag-Erling Smørgrav {
5737b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)calloc(1,
5738b7579f77SDag-Erling Smørgrav sizeof(struct comm_point));
5739b7579f77SDag-Erling Smørgrav short evbits;
5740b7579f77SDag-Erling Smørgrav if(!c)
5741b7579f77SDag-Erling Smørgrav return NULL;
5742b7579f77SDag-Erling Smørgrav c->ev = (struct internal_event*)calloc(1,
5743b7579f77SDag-Erling Smørgrav sizeof(struct internal_event));
5744b7579f77SDag-Erling Smørgrav if(!c->ev) {
5745b7579f77SDag-Erling Smørgrav free(c);
5746b7579f77SDag-Erling Smørgrav return NULL;
5747b7579f77SDag-Erling Smørgrav }
5748b7579f77SDag-Erling Smørgrav c->ev->base = base;
5749b7579f77SDag-Erling Smørgrav c->fd = fd;
5750b7579f77SDag-Erling Smørgrav c->buffer = buffer;
5751b7579f77SDag-Erling Smørgrav c->timeout = NULL;
5752b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 0;
5753b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0;
5754b7579f77SDag-Erling Smørgrav c->tcp_parent = NULL;
5755b7579f77SDag-Erling Smørgrav c->max_tcp_count = 0;
575609a3aaf3SDag-Erling Smørgrav c->cur_tcp_count = 0;
5757b7579f77SDag-Erling Smørgrav c->tcp_handlers = NULL;
5758b7579f77SDag-Erling Smørgrav c->tcp_free = NULL;
5759b7579f77SDag-Erling Smørgrav c->type = comm_udp;
5760b7579f77SDag-Erling Smørgrav c->tcp_do_close = 0;
5761b7579f77SDag-Erling Smørgrav c->do_not_close = 0;
5762b7579f77SDag-Erling Smørgrav c->tcp_do_toggle_rw = 0;
5763b7579f77SDag-Erling Smørgrav c->tcp_check_nb_connect = 0;
5764b5663de9SDag-Erling Smørgrav #ifdef USE_MSG_FASTOPEN
5765b5663de9SDag-Erling Smørgrav c->tcp_do_fastopen = 0;
5766b5663de9SDag-Erling Smørgrav #endif
576765b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT
576865b390aaSDag-Erling Smørgrav c->dnscrypt = 0;
576965b390aaSDag-Erling Smørgrav c->dnscrypt_buffer = buffer;
577065b390aaSDag-Erling Smørgrav #endif
5771b7579f77SDag-Erling Smørgrav c->inuse = 0;
5772b7579f77SDag-Erling Smørgrav c->callback = callback;
5773b7579f77SDag-Erling Smørgrav c->cb_arg = callback_arg;
57745469a995SCy Schubert c->socket = socket;
5775865f46b2SCy Schubert c->pp2_enabled = pp2_enabled;
5776865f46b2SCy Schubert c->pp2_header_state = pp2_header_none;
5777e2d15004SDag-Erling Smørgrav evbits = UB_EV_READ | UB_EV_PERSIST;
5778e2d15004SDag-Erling Smørgrav /* ub_event stuff */
5779e2d15004SDag-Erling Smørgrav c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
5780e2d15004SDag-Erling Smørgrav comm_point_udp_callback, c);
5781e2d15004SDag-Erling Smørgrav if(c->ev->ev == NULL) {
5782b7579f77SDag-Erling Smørgrav log_err("could not baseset udp event");
5783b7579f77SDag-Erling Smørgrav comm_point_delete(c);
5784b7579f77SDag-Erling Smørgrav return NULL;
5785b7579f77SDag-Erling Smørgrav }
5786e2d15004SDag-Erling Smørgrav if(fd!=-1 && ub_event_add(c->ev->ev, c->timeout) != 0 ) {
5787b7579f77SDag-Erling Smørgrav log_err("could not add udp event");
5788b7579f77SDag-Erling Smørgrav comm_point_delete(c);
5789b7579f77SDag-Erling Smørgrav return NULL;
5790b7579f77SDag-Erling Smørgrav }
5791f44e67d1SCy Schubert c->event_added = 1;
5792b7579f77SDag-Erling Smørgrav return c;
5793b7579f77SDag-Erling Smørgrav }
5794b7579f77SDag-Erling Smørgrav
5795103ba509SCy Schubert #if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG)
5796b7579f77SDag-Erling Smørgrav struct comm_point*
5797b7579f77SDag-Erling Smørgrav comm_point_create_udp_ancil(struct comm_base *base, int fd,
5798865f46b2SCy Schubert sldns_buffer* buffer, int pp2_enabled,
57995469a995SCy Schubert comm_point_callback_type* callback, void* callback_arg, struct unbound_socket* socket)
5800b7579f77SDag-Erling Smørgrav {
5801b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)calloc(1,
5802b7579f77SDag-Erling Smørgrav sizeof(struct comm_point));
5803b7579f77SDag-Erling Smørgrav short evbits;
5804b7579f77SDag-Erling Smørgrav if(!c)
5805b7579f77SDag-Erling Smørgrav return NULL;
5806b7579f77SDag-Erling Smørgrav c->ev = (struct internal_event*)calloc(1,
5807b7579f77SDag-Erling Smørgrav sizeof(struct internal_event));
5808b7579f77SDag-Erling Smørgrav if(!c->ev) {
5809b7579f77SDag-Erling Smørgrav free(c);
5810b7579f77SDag-Erling Smørgrav return NULL;
5811b7579f77SDag-Erling Smørgrav }
5812b7579f77SDag-Erling Smørgrav c->ev->base = base;
5813b7579f77SDag-Erling Smørgrav c->fd = fd;
5814b7579f77SDag-Erling Smørgrav c->buffer = buffer;
5815b7579f77SDag-Erling Smørgrav c->timeout = NULL;
5816b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 0;
5817b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0;
5818b7579f77SDag-Erling Smørgrav c->tcp_parent = NULL;
5819b7579f77SDag-Erling Smørgrav c->max_tcp_count = 0;
582009a3aaf3SDag-Erling Smørgrav c->cur_tcp_count = 0;
5821b7579f77SDag-Erling Smørgrav c->tcp_handlers = NULL;
5822b7579f77SDag-Erling Smørgrav c->tcp_free = NULL;
5823b7579f77SDag-Erling Smørgrav c->type = comm_udp;
5824b7579f77SDag-Erling Smørgrav c->tcp_do_close = 0;
5825b7579f77SDag-Erling Smørgrav c->do_not_close = 0;
582665b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT
582765b390aaSDag-Erling Smørgrav c->dnscrypt = 0;
582865b390aaSDag-Erling Smørgrav c->dnscrypt_buffer = buffer;
582965b390aaSDag-Erling Smørgrav #endif
5830b7579f77SDag-Erling Smørgrav c->inuse = 0;
5831b7579f77SDag-Erling Smørgrav c->tcp_do_toggle_rw = 0;
5832b7579f77SDag-Erling Smørgrav c->tcp_check_nb_connect = 0;
5833b5663de9SDag-Erling Smørgrav #ifdef USE_MSG_FASTOPEN
5834b5663de9SDag-Erling Smørgrav c->tcp_do_fastopen = 0;
5835b5663de9SDag-Erling Smørgrav #endif
5836b7579f77SDag-Erling Smørgrav c->callback = callback;
5837b7579f77SDag-Erling Smørgrav c->cb_arg = callback_arg;
58385469a995SCy Schubert c->socket = socket;
5839865f46b2SCy Schubert c->pp2_enabled = pp2_enabled;
5840865f46b2SCy Schubert c->pp2_header_state = pp2_header_none;
5841e2d15004SDag-Erling Smørgrav evbits = UB_EV_READ | UB_EV_PERSIST;
5842e2d15004SDag-Erling Smørgrav /* ub_event stuff */
5843e2d15004SDag-Erling Smørgrav c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
5844e2d15004SDag-Erling Smørgrav comm_point_udp_ancil_callback, c);
5845e2d15004SDag-Erling Smørgrav if(c->ev->ev == NULL) {
5846b7579f77SDag-Erling Smørgrav log_err("could not baseset udp event");
5847b7579f77SDag-Erling Smørgrav comm_point_delete(c);
5848b7579f77SDag-Erling Smørgrav return NULL;
5849b7579f77SDag-Erling Smørgrav }
5850e2d15004SDag-Erling Smørgrav if(fd!=-1 && ub_event_add(c->ev->ev, c->timeout) != 0 ) {
5851b7579f77SDag-Erling Smørgrav log_err("could not add udp event");
5852b7579f77SDag-Erling Smørgrav comm_point_delete(c);
5853b7579f77SDag-Erling Smørgrav return NULL;
5854b7579f77SDag-Erling Smørgrav }
5855f44e67d1SCy Schubert c->event_added = 1;
5856b7579f77SDag-Erling Smørgrav return c;
5857b7579f77SDag-Erling Smørgrav }
5858103ba509SCy Schubert #endif
5859b7579f77SDag-Erling Smørgrav
5860*46d2f618SCy Schubert struct comm_point*
5861*46d2f618SCy Schubert comm_point_create_doq(struct comm_base *base, int fd, sldns_buffer* buffer,
5862*46d2f618SCy Schubert comm_point_callback_type* callback, void* callback_arg,
5863*46d2f618SCy Schubert struct unbound_socket* socket, struct doq_table* table,
5864*46d2f618SCy Schubert struct ub_randstate* rnd, const char* ssl_service_key,
5865*46d2f618SCy Schubert const char* ssl_service_pem, struct config_file* cfg)
5866*46d2f618SCy Schubert {
5867*46d2f618SCy Schubert #ifdef HAVE_NGTCP2
5868*46d2f618SCy Schubert struct comm_point* c = (struct comm_point*)calloc(1,
5869*46d2f618SCy Schubert sizeof(struct comm_point));
5870*46d2f618SCy Schubert short evbits;
5871*46d2f618SCy Schubert if(!c)
5872*46d2f618SCy Schubert return NULL;
5873*46d2f618SCy Schubert c->ev = (struct internal_event*)calloc(1,
5874*46d2f618SCy Schubert sizeof(struct internal_event));
5875*46d2f618SCy Schubert if(!c->ev) {
5876*46d2f618SCy Schubert free(c);
5877*46d2f618SCy Schubert return NULL;
5878*46d2f618SCy Schubert }
5879*46d2f618SCy Schubert c->ev->base = base;
5880*46d2f618SCy Schubert c->fd = fd;
5881*46d2f618SCy Schubert c->buffer = buffer;
5882*46d2f618SCy Schubert c->timeout = NULL;
5883*46d2f618SCy Schubert c->tcp_is_reading = 0;
5884*46d2f618SCy Schubert c->tcp_byte_count = 0;
5885*46d2f618SCy Schubert c->tcp_parent = NULL;
5886*46d2f618SCy Schubert c->max_tcp_count = 0;
5887*46d2f618SCy Schubert c->cur_tcp_count = 0;
5888*46d2f618SCy Schubert c->tcp_handlers = NULL;
5889*46d2f618SCy Schubert c->tcp_free = NULL;
5890*46d2f618SCy Schubert c->type = comm_doq;
5891*46d2f618SCy Schubert c->tcp_do_close = 0;
5892*46d2f618SCy Schubert c->do_not_close = 0;
5893*46d2f618SCy Schubert c->tcp_do_toggle_rw = 0;
5894*46d2f618SCy Schubert c->tcp_check_nb_connect = 0;
5895*46d2f618SCy Schubert #ifdef USE_MSG_FASTOPEN
5896*46d2f618SCy Schubert c->tcp_do_fastopen = 0;
5897*46d2f618SCy Schubert #endif
5898*46d2f618SCy Schubert #ifdef USE_DNSCRYPT
5899*46d2f618SCy Schubert c->dnscrypt = 0;
5900*46d2f618SCy Schubert c->dnscrypt_buffer = NULL;
5901*46d2f618SCy Schubert #endif
5902*46d2f618SCy Schubert #ifdef HAVE_NGTCP2
5903*46d2f618SCy Schubert c->doq_socket = doq_server_socket_create(table, rnd, ssl_service_key,
5904*46d2f618SCy Schubert ssl_service_pem, c, base, cfg);
5905*46d2f618SCy Schubert if(!c->doq_socket) {
5906*46d2f618SCy Schubert log_err("could not create doq comm_point");
5907*46d2f618SCy Schubert comm_point_delete(c);
5908*46d2f618SCy Schubert return NULL;
5909*46d2f618SCy Schubert }
5910*46d2f618SCy Schubert #endif
5911*46d2f618SCy Schubert c->inuse = 0;
5912*46d2f618SCy Schubert c->callback = callback;
5913*46d2f618SCy Schubert c->cb_arg = callback_arg;
5914*46d2f618SCy Schubert c->socket = socket;
5915*46d2f618SCy Schubert c->pp2_enabled = 0;
5916*46d2f618SCy Schubert c->pp2_header_state = pp2_header_none;
5917*46d2f618SCy Schubert evbits = UB_EV_READ | UB_EV_PERSIST;
5918*46d2f618SCy Schubert /* ub_event stuff */
5919*46d2f618SCy Schubert c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
5920*46d2f618SCy Schubert comm_point_doq_callback, c);
5921*46d2f618SCy Schubert if(c->ev->ev == NULL) {
5922*46d2f618SCy Schubert log_err("could not baseset udp event");
5923*46d2f618SCy Schubert comm_point_delete(c);
5924*46d2f618SCy Schubert return NULL;
5925*46d2f618SCy Schubert }
5926*46d2f618SCy Schubert if(fd!=-1 && ub_event_add(c->ev->ev, c->timeout) != 0 ) {
5927*46d2f618SCy Schubert log_err("could not add udp event");
5928*46d2f618SCy Schubert comm_point_delete(c);
5929*46d2f618SCy Schubert return NULL;
5930*46d2f618SCy Schubert }
5931*46d2f618SCy Schubert c->event_added = 1;
5932*46d2f618SCy Schubert return c;
5933*46d2f618SCy Schubert #else
5934*46d2f618SCy Schubert /* no libngtcp2, so no QUIC support */
5935*46d2f618SCy Schubert (void)base;
5936*46d2f618SCy Schubert (void)buffer;
5937*46d2f618SCy Schubert (void)callback;
5938*46d2f618SCy Schubert (void)callback_arg;
5939*46d2f618SCy Schubert (void)socket;
5940*46d2f618SCy Schubert (void)rnd;
5941*46d2f618SCy Schubert (void)table;
5942*46d2f618SCy Schubert (void)ssl_service_key;
5943*46d2f618SCy Schubert (void)ssl_service_pem;
5944*46d2f618SCy Schubert (void)cfg;
5945*46d2f618SCy Schubert sock_close(fd);
5946*46d2f618SCy Schubert return NULL;
5947*46d2f618SCy Schubert #endif /* HAVE_NGTCP2 */
5948*46d2f618SCy Schubert }
5949*46d2f618SCy Schubert
5950b7579f77SDag-Erling Smørgrav static struct comm_point*
5951b7579f77SDag-Erling Smørgrav comm_point_create_tcp_handler(struct comm_base *base,
5952b7579f77SDag-Erling Smørgrav struct comm_point* parent, size_t bufsize,
5953e86b9096SDag-Erling Smørgrav struct sldns_buffer* spoolbuf, comm_point_callback_type* callback,
59545469a995SCy Schubert void* callback_arg, struct unbound_socket* socket)
5955b7579f77SDag-Erling Smørgrav {
5956b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)calloc(1,
5957b7579f77SDag-Erling Smørgrav sizeof(struct comm_point));
5958b7579f77SDag-Erling Smørgrav short evbits;
5959b7579f77SDag-Erling Smørgrav if(!c)
5960b7579f77SDag-Erling Smørgrav return NULL;
5961b7579f77SDag-Erling Smørgrav c->ev = (struct internal_event*)calloc(1,
5962b7579f77SDag-Erling Smørgrav sizeof(struct internal_event));
5963b7579f77SDag-Erling Smørgrav if(!c->ev) {
5964b7579f77SDag-Erling Smørgrav free(c);
5965b7579f77SDag-Erling Smørgrav return NULL;
5966b7579f77SDag-Erling Smørgrav }
5967b7579f77SDag-Erling Smørgrav c->ev->base = base;
5968b7579f77SDag-Erling Smørgrav c->fd = -1;
596917d15b25SDag-Erling Smørgrav c->buffer = sldns_buffer_new(bufsize);
5970b7579f77SDag-Erling Smørgrav if(!c->buffer) {
5971b7579f77SDag-Erling Smørgrav free(c->ev);
5972b7579f77SDag-Erling Smørgrav free(c);
5973b7579f77SDag-Erling Smørgrav return NULL;
5974b7579f77SDag-Erling Smørgrav }
5975b7579f77SDag-Erling Smørgrav c->timeout = (struct timeval*)malloc(sizeof(struct timeval));
5976b7579f77SDag-Erling Smørgrav if(!c->timeout) {
597717d15b25SDag-Erling Smørgrav sldns_buffer_free(c->buffer);
5978b7579f77SDag-Erling Smørgrav free(c->ev);
5979b7579f77SDag-Erling Smørgrav free(c);
5980b7579f77SDag-Erling Smørgrav return NULL;
5981b7579f77SDag-Erling Smørgrav }
5982b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 0;
5983b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0;
5984b7579f77SDag-Erling Smørgrav c->tcp_parent = parent;
59854c75e3aaSDag-Erling Smørgrav c->tcp_timeout_msec = parent->tcp_timeout_msec;
59864c75e3aaSDag-Erling Smørgrav c->tcp_conn_limit = parent->tcp_conn_limit;
59874c75e3aaSDag-Erling Smørgrav c->tcl_addr = NULL;
59884c75e3aaSDag-Erling Smørgrav c->tcp_keepalive = 0;
5989b7579f77SDag-Erling Smørgrav c->max_tcp_count = 0;
599009a3aaf3SDag-Erling Smørgrav c->cur_tcp_count = 0;
5991b7579f77SDag-Erling Smørgrav c->tcp_handlers = NULL;
5992b7579f77SDag-Erling Smørgrav c->tcp_free = NULL;
5993b7579f77SDag-Erling Smørgrav c->type = comm_tcp;
5994b7579f77SDag-Erling Smørgrav c->tcp_do_close = 0;
5995b7579f77SDag-Erling Smørgrav c->do_not_close = 0;
5996b7579f77SDag-Erling Smørgrav c->tcp_do_toggle_rw = 1;
5997b7579f77SDag-Erling Smørgrav c->tcp_check_nb_connect = 0;
5998b5663de9SDag-Erling Smørgrav #ifdef USE_MSG_FASTOPEN
5999b5663de9SDag-Erling Smørgrav c->tcp_do_fastopen = 0;
6000b5663de9SDag-Erling Smørgrav #endif
600165b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT
600265b390aaSDag-Erling Smørgrav c->dnscrypt = 0;
6003c7f4d7adSDag-Erling Smørgrav /* We don't know just yet if this is a dnscrypt channel. Allocation
6004c7f4d7adSDag-Erling Smørgrav * will be done when handling the callback. */
600565b390aaSDag-Erling Smørgrav c->dnscrypt_buffer = c->buffer;
600665b390aaSDag-Erling Smørgrav #endif
6007b7579f77SDag-Erling Smørgrav c->repinfo.c = c;
6008b7579f77SDag-Erling Smørgrav c->callback = callback;
6009b7579f77SDag-Erling Smørgrav c->cb_arg = callback_arg;
60105469a995SCy Schubert c->socket = socket;
6011865f46b2SCy Schubert c->pp2_enabled = parent->pp2_enabled;
6012865f46b2SCy Schubert c->pp2_header_state = pp2_header_none;
6013e86b9096SDag-Erling Smørgrav if(spoolbuf) {
6014e86b9096SDag-Erling Smørgrav c->tcp_req_info = tcp_req_info_create(spoolbuf);
6015e86b9096SDag-Erling Smørgrav if(!c->tcp_req_info) {
6016e86b9096SDag-Erling Smørgrav log_err("could not create tcp commpoint");
6017e86b9096SDag-Erling Smørgrav sldns_buffer_free(c->buffer);
6018e86b9096SDag-Erling Smørgrav free(c->timeout);
6019e86b9096SDag-Erling Smørgrav free(c->ev);
6020e86b9096SDag-Erling Smørgrav free(c);
6021e86b9096SDag-Erling Smørgrav return NULL;
6022e86b9096SDag-Erling Smørgrav }
6023e86b9096SDag-Erling Smørgrav c->tcp_req_info->cp = c;
6024e86b9096SDag-Erling Smørgrav c->tcp_do_close = 1;
6025e86b9096SDag-Erling Smørgrav c->tcp_do_toggle_rw = 0;
6026e86b9096SDag-Erling Smørgrav }
6027b7579f77SDag-Erling Smørgrav /* add to parent free list */
6028b7579f77SDag-Erling Smørgrav c->tcp_free = parent->tcp_free;
6029b7579f77SDag-Erling Smørgrav parent->tcp_free = c;
6030e2d15004SDag-Erling Smørgrav /* ub_event stuff */
6031e2d15004SDag-Erling Smørgrav evbits = UB_EV_PERSIST | UB_EV_READ | UB_EV_TIMEOUT;
6032e2d15004SDag-Erling Smørgrav c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
6033e2d15004SDag-Erling Smørgrav comm_point_tcp_handle_callback, c);
6034e2d15004SDag-Erling Smørgrav if(c->ev->ev == NULL)
6035b7579f77SDag-Erling Smørgrav {
6036b7579f77SDag-Erling Smørgrav log_err("could not basetset tcphdl event");
6037b7579f77SDag-Erling Smørgrav parent->tcp_free = c->tcp_free;
6038e86b9096SDag-Erling Smørgrav tcp_req_info_delete(c->tcp_req_info);
6039e86b9096SDag-Erling Smørgrav sldns_buffer_free(c->buffer);
6040e86b9096SDag-Erling Smørgrav free(c->timeout);
6041b7579f77SDag-Erling Smørgrav free(c->ev);
6042b7579f77SDag-Erling Smørgrav free(c);
6043b7579f77SDag-Erling Smørgrav return NULL;
6044b7579f77SDag-Erling Smørgrav }
6045b7579f77SDag-Erling Smørgrav return c;
6046b7579f77SDag-Erling Smørgrav }
6047b7579f77SDag-Erling Smørgrav
6048c0caa2e2SCy Schubert static struct comm_point*
6049c0caa2e2SCy Schubert comm_point_create_http_handler(struct comm_base *base,
6050c0caa2e2SCy Schubert struct comm_point* parent, size_t bufsize, int harden_large_queries,
6051c0caa2e2SCy Schubert uint32_t http_max_streams, char* http_endpoint,
60525469a995SCy Schubert comm_point_callback_type* callback, void* callback_arg,
60535469a995SCy Schubert struct unbound_socket* socket)
6054c0caa2e2SCy Schubert {
6055c0caa2e2SCy Schubert struct comm_point* c = (struct comm_point*)calloc(1,
6056c0caa2e2SCy Schubert sizeof(struct comm_point));
6057c0caa2e2SCy Schubert short evbits;
6058c0caa2e2SCy Schubert if(!c)
6059c0caa2e2SCy Schubert return NULL;
6060c0caa2e2SCy Schubert c->ev = (struct internal_event*)calloc(1,
6061c0caa2e2SCy Schubert sizeof(struct internal_event));
6062c0caa2e2SCy Schubert if(!c->ev) {
6063c0caa2e2SCy Schubert free(c);
6064c0caa2e2SCy Schubert return NULL;
6065c0caa2e2SCy Schubert }
6066c0caa2e2SCy Schubert c->ev->base = base;
6067c0caa2e2SCy Schubert c->fd = -1;
6068c0caa2e2SCy Schubert c->buffer = sldns_buffer_new(bufsize);
6069c0caa2e2SCy Schubert if(!c->buffer) {
6070c0caa2e2SCy Schubert free(c->ev);
6071c0caa2e2SCy Schubert free(c);
6072c0caa2e2SCy Schubert return NULL;
6073c0caa2e2SCy Schubert }
6074c0caa2e2SCy Schubert c->timeout = (struct timeval*)malloc(sizeof(struct timeval));
6075c0caa2e2SCy Schubert if(!c->timeout) {
6076c0caa2e2SCy Schubert sldns_buffer_free(c->buffer);
6077c0caa2e2SCy Schubert free(c->ev);
6078c0caa2e2SCy Schubert free(c);
6079c0caa2e2SCy Schubert return NULL;
6080c0caa2e2SCy Schubert }
6081c0caa2e2SCy Schubert c->tcp_is_reading = 0;
6082c0caa2e2SCy Schubert c->tcp_byte_count = 0;
6083c0caa2e2SCy Schubert c->tcp_parent = parent;
6084c0caa2e2SCy Schubert c->tcp_timeout_msec = parent->tcp_timeout_msec;
6085c0caa2e2SCy Schubert c->tcp_conn_limit = parent->tcp_conn_limit;
6086c0caa2e2SCy Schubert c->tcl_addr = NULL;
6087c0caa2e2SCy Schubert c->tcp_keepalive = 0;
6088c0caa2e2SCy Schubert c->max_tcp_count = 0;
6089c0caa2e2SCy Schubert c->cur_tcp_count = 0;
6090c0caa2e2SCy Schubert c->tcp_handlers = NULL;
6091c0caa2e2SCy Schubert c->tcp_free = NULL;
6092c0caa2e2SCy Schubert c->type = comm_http;
6093c0caa2e2SCy Schubert c->tcp_do_close = 1;
6094c0caa2e2SCy Schubert c->do_not_close = 0;
6095c0caa2e2SCy Schubert c->tcp_do_toggle_rw = 1; /* will be set to 0 after http2 upgrade */
6096c0caa2e2SCy Schubert c->tcp_check_nb_connect = 0;
6097c0caa2e2SCy Schubert #ifdef USE_MSG_FASTOPEN
6098c0caa2e2SCy Schubert c->tcp_do_fastopen = 0;
6099c0caa2e2SCy Schubert #endif
6100c0caa2e2SCy Schubert #ifdef USE_DNSCRYPT
6101c0caa2e2SCy Schubert c->dnscrypt = 0;
6102c0caa2e2SCy Schubert c->dnscrypt_buffer = NULL;
6103c0caa2e2SCy Schubert #endif
6104c0caa2e2SCy Schubert c->repinfo.c = c;
6105c0caa2e2SCy Schubert c->callback = callback;
6106c0caa2e2SCy Schubert c->cb_arg = callback_arg;
61075469a995SCy Schubert c->socket = socket;
6108865f46b2SCy Schubert c->pp2_enabled = 0;
6109865f46b2SCy Schubert c->pp2_header_state = pp2_header_none;
6110c0caa2e2SCy Schubert
6111c0caa2e2SCy Schubert c->http_min_version = http_version_2;
6112c0caa2e2SCy Schubert c->http2_stream_max_qbuffer_size = bufsize;
6113c0caa2e2SCy Schubert if(harden_large_queries && bufsize > 512)
6114c0caa2e2SCy Schubert c->http2_stream_max_qbuffer_size = 512;
6115c0caa2e2SCy Schubert c->http2_max_streams = http_max_streams;
6116c0caa2e2SCy Schubert if(!(c->http_endpoint = strdup(http_endpoint))) {
6117c0caa2e2SCy Schubert log_err("could not strdup http_endpoint");
6118c0caa2e2SCy Schubert sldns_buffer_free(c->buffer);
6119c0caa2e2SCy Schubert free(c->timeout);
6120c0caa2e2SCy Schubert free(c->ev);
6121c0caa2e2SCy Schubert free(c);
6122c0caa2e2SCy Schubert return NULL;
6123c0caa2e2SCy Schubert }
6124c0caa2e2SCy Schubert c->use_h2 = 0;
6125c0caa2e2SCy Schubert #ifdef HAVE_NGHTTP2
6126c0caa2e2SCy Schubert if(!(c->h2_session = http2_session_create(c))) {
6127c0caa2e2SCy Schubert log_err("could not create http2 session");
6128c0caa2e2SCy Schubert free(c->http_endpoint);
6129c0caa2e2SCy Schubert sldns_buffer_free(c->buffer);
6130c0caa2e2SCy Schubert free(c->timeout);
6131c0caa2e2SCy Schubert free(c->ev);
6132c0caa2e2SCy Schubert free(c);
6133c0caa2e2SCy Schubert return NULL;
6134c0caa2e2SCy Schubert }
6135c0caa2e2SCy Schubert if(!(c->h2_session->callbacks = http2_req_callbacks_create())) {
6136c0caa2e2SCy Schubert log_err("could not create http2 callbacks");
6137c0caa2e2SCy Schubert http2_session_delete(c->h2_session);
6138c0caa2e2SCy Schubert free(c->http_endpoint);
6139c0caa2e2SCy Schubert sldns_buffer_free(c->buffer);
6140c0caa2e2SCy Schubert free(c->timeout);
6141c0caa2e2SCy Schubert free(c->ev);
6142c0caa2e2SCy Schubert free(c);
6143c0caa2e2SCy Schubert return NULL;
6144c0caa2e2SCy Schubert }
6145c0caa2e2SCy Schubert #endif
6146c0caa2e2SCy Schubert
6147c0caa2e2SCy Schubert /* add to parent free list */
6148c0caa2e2SCy Schubert c->tcp_free = parent->tcp_free;
6149c0caa2e2SCy Schubert parent->tcp_free = c;
6150c0caa2e2SCy Schubert /* ub_event stuff */
6151c0caa2e2SCy Schubert evbits = UB_EV_PERSIST | UB_EV_READ | UB_EV_TIMEOUT;
6152c0caa2e2SCy Schubert c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
6153c0caa2e2SCy Schubert comm_point_http_handle_callback, c);
6154c0caa2e2SCy Schubert if(c->ev->ev == NULL)
6155c0caa2e2SCy Schubert {
6156c0caa2e2SCy Schubert log_err("could not set http handler event");
6157c0caa2e2SCy Schubert parent->tcp_free = c->tcp_free;
6158c0caa2e2SCy Schubert http2_session_delete(c->h2_session);
6159c0caa2e2SCy Schubert sldns_buffer_free(c->buffer);
6160c0caa2e2SCy Schubert free(c->timeout);
6161c0caa2e2SCy Schubert free(c->ev);
6162c0caa2e2SCy Schubert free(c);
6163c0caa2e2SCy Schubert return NULL;
6164c0caa2e2SCy Schubert }
6165c0caa2e2SCy Schubert return c;
6166c0caa2e2SCy Schubert }
6167c0caa2e2SCy Schubert
6168b7579f77SDag-Erling Smørgrav struct comm_point*
61694c75e3aaSDag-Erling Smørgrav comm_point_create_tcp(struct comm_base *base, int fd, int num,
6170c0caa2e2SCy Schubert int idle_timeout, int harden_large_queries,
6171c0caa2e2SCy Schubert uint32_t http_max_streams, char* http_endpoint,
6172c0caa2e2SCy Schubert struct tcl_list* tcp_conn_limit, size_t bufsize,
6173c0caa2e2SCy Schubert struct sldns_buffer* spoolbuf, enum listen_type port_type,
6174865f46b2SCy Schubert int pp2_enabled, comm_point_callback_type* callback,
6175865f46b2SCy Schubert void* callback_arg, struct unbound_socket* socket)
6176b7579f77SDag-Erling Smørgrav {
6177b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)calloc(1,
6178b7579f77SDag-Erling Smørgrav sizeof(struct comm_point));
6179b7579f77SDag-Erling Smørgrav short evbits;
6180b7579f77SDag-Erling Smørgrav int i;
6181b7579f77SDag-Erling Smørgrav /* first allocate the TCP accept listener */
6182b7579f77SDag-Erling Smørgrav if(!c)
6183b7579f77SDag-Erling Smørgrav return NULL;
6184b7579f77SDag-Erling Smørgrav c->ev = (struct internal_event*)calloc(1,
6185b7579f77SDag-Erling Smørgrav sizeof(struct internal_event));
6186b7579f77SDag-Erling Smørgrav if(!c->ev) {
6187b7579f77SDag-Erling Smørgrav free(c);
6188b7579f77SDag-Erling Smørgrav return NULL;
6189b7579f77SDag-Erling Smørgrav }
6190b7579f77SDag-Erling Smørgrav c->ev->base = base;
6191b7579f77SDag-Erling Smørgrav c->fd = fd;
6192b7579f77SDag-Erling Smørgrav c->buffer = NULL;
6193b7579f77SDag-Erling Smørgrav c->timeout = NULL;
6194b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 0;
6195b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0;
61964c75e3aaSDag-Erling Smørgrav c->tcp_timeout_msec = idle_timeout;
61974c75e3aaSDag-Erling Smørgrav c->tcp_conn_limit = tcp_conn_limit;
61984c75e3aaSDag-Erling Smørgrav c->tcl_addr = NULL;
61994c75e3aaSDag-Erling Smørgrav c->tcp_keepalive = 0;
6200b7579f77SDag-Erling Smørgrav c->tcp_parent = NULL;
6201b7579f77SDag-Erling Smørgrav c->max_tcp_count = num;
620209a3aaf3SDag-Erling Smørgrav c->cur_tcp_count = 0;
6203b7579f77SDag-Erling Smørgrav c->tcp_handlers = (struct comm_point**)calloc((size_t)num,
6204b7579f77SDag-Erling Smørgrav sizeof(struct comm_point*));
6205b7579f77SDag-Erling Smørgrav if(!c->tcp_handlers) {
6206b7579f77SDag-Erling Smørgrav free(c->ev);
6207b7579f77SDag-Erling Smørgrav free(c);
6208b7579f77SDag-Erling Smørgrav return NULL;
6209b7579f77SDag-Erling Smørgrav }
6210b7579f77SDag-Erling Smørgrav c->tcp_free = NULL;
6211b7579f77SDag-Erling Smørgrav c->type = comm_tcp_accept;
6212b7579f77SDag-Erling Smørgrav c->tcp_do_close = 0;
6213b7579f77SDag-Erling Smørgrav c->do_not_close = 0;
6214b7579f77SDag-Erling Smørgrav c->tcp_do_toggle_rw = 0;
6215b7579f77SDag-Erling Smørgrav c->tcp_check_nb_connect = 0;
6216b5663de9SDag-Erling Smørgrav #ifdef USE_MSG_FASTOPEN
6217b5663de9SDag-Erling Smørgrav c->tcp_do_fastopen = 0;
6218b5663de9SDag-Erling Smørgrav #endif
621965b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT
622065b390aaSDag-Erling Smørgrav c->dnscrypt = 0;
622165b390aaSDag-Erling Smørgrav c->dnscrypt_buffer = NULL;
622265b390aaSDag-Erling Smørgrav #endif
6223b7579f77SDag-Erling Smørgrav c->callback = NULL;
6224b7579f77SDag-Erling Smørgrav c->cb_arg = NULL;
62255469a995SCy Schubert c->socket = socket;
6226865f46b2SCy Schubert c->pp2_enabled = (port_type==listen_type_http?0:pp2_enabled);
6227865f46b2SCy Schubert c->pp2_header_state = pp2_header_none;
6228e2d15004SDag-Erling Smørgrav evbits = UB_EV_READ | UB_EV_PERSIST;
6229e2d15004SDag-Erling Smørgrav /* ub_event stuff */
6230e2d15004SDag-Erling Smørgrav c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
6231e2d15004SDag-Erling Smørgrav comm_point_tcp_accept_callback, c);
6232e2d15004SDag-Erling Smørgrav if(c->ev->ev == NULL) {
6233e2d15004SDag-Erling Smørgrav log_err("could not baseset tcpacc event");
6234e2d15004SDag-Erling Smørgrav comm_point_delete(c);
6235e2d15004SDag-Erling Smørgrav return NULL;
6236e2d15004SDag-Erling Smørgrav }
6237e2d15004SDag-Erling Smørgrav if (ub_event_add(c->ev->ev, c->timeout) != 0) {
6238b7579f77SDag-Erling Smørgrav log_err("could not add tcpacc event");
6239b7579f77SDag-Erling Smørgrav comm_point_delete(c);
6240b7579f77SDag-Erling Smørgrav return NULL;
6241b7579f77SDag-Erling Smørgrav }
6242f44e67d1SCy Schubert c->event_added = 1;
6243c0caa2e2SCy Schubert /* now prealloc the handlers */
6244b7579f77SDag-Erling Smørgrav for(i=0; i<num; i++) {
6245c0caa2e2SCy Schubert if(port_type == listen_type_tcp ||
6246c0caa2e2SCy Schubert port_type == listen_type_ssl ||
6247c0caa2e2SCy Schubert port_type == listen_type_tcp_dnscrypt) {
6248b7579f77SDag-Erling Smørgrav c->tcp_handlers[i] = comm_point_create_tcp_handler(base,
62495469a995SCy Schubert c, bufsize, spoolbuf, callback, callback_arg, socket);
6250c0caa2e2SCy Schubert } else if(port_type == listen_type_http) {
6251c0caa2e2SCy Schubert c->tcp_handlers[i] = comm_point_create_http_handler(
6252c0caa2e2SCy Schubert base, c, bufsize, harden_large_queries,
6253c0caa2e2SCy Schubert http_max_streams, http_endpoint,
62545469a995SCy Schubert callback, callback_arg, socket);
6255c0caa2e2SCy Schubert }
6256c0caa2e2SCy Schubert else {
6257c0caa2e2SCy Schubert log_err("could not create tcp handler, unknown listen "
6258c0caa2e2SCy Schubert "type");
6259c0caa2e2SCy Schubert return NULL;
6260c0caa2e2SCy Schubert }
6261b7579f77SDag-Erling Smørgrav if(!c->tcp_handlers[i]) {
6262b7579f77SDag-Erling Smørgrav comm_point_delete(c);
6263b7579f77SDag-Erling Smørgrav return NULL;
6264b7579f77SDag-Erling Smørgrav }
6265b7579f77SDag-Erling Smørgrav }
6266b7579f77SDag-Erling Smørgrav
6267b7579f77SDag-Erling Smørgrav return c;
6268b7579f77SDag-Erling Smørgrav }
6269b7579f77SDag-Erling Smørgrav
6270b7579f77SDag-Erling Smørgrav struct comm_point*
6271b7579f77SDag-Erling Smørgrav comm_point_create_tcp_out(struct comm_base *base, size_t bufsize,
62723005e0a3SDag-Erling Smørgrav comm_point_callback_type* callback, void* callback_arg)
6273b7579f77SDag-Erling Smørgrav {
6274b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)calloc(1,
6275b7579f77SDag-Erling Smørgrav sizeof(struct comm_point));
6276b7579f77SDag-Erling Smørgrav short evbits;
6277b7579f77SDag-Erling Smørgrav if(!c)
6278b7579f77SDag-Erling Smørgrav return NULL;
6279b7579f77SDag-Erling Smørgrav c->ev = (struct internal_event*)calloc(1,
6280b7579f77SDag-Erling Smørgrav sizeof(struct internal_event));
6281b7579f77SDag-Erling Smørgrav if(!c->ev) {
6282b7579f77SDag-Erling Smørgrav free(c);
6283b7579f77SDag-Erling Smørgrav return NULL;
6284b7579f77SDag-Erling Smørgrav }
6285b7579f77SDag-Erling Smørgrav c->ev->base = base;
6286b7579f77SDag-Erling Smørgrav c->fd = -1;
628717d15b25SDag-Erling Smørgrav c->buffer = sldns_buffer_new(bufsize);
6288b7579f77SDag-Erling Smørgrav if(!c->buffer) {
6289b7579f77SDag-Erling Smørgrav free(c->ev);
6290b7579f77SDag-Erling Smørgrav free(c);
6291b7579f77SDag-Erling Smørgrav return NULL;
6292b7579f77SDag-Erling Smørgrav }
6293b7579f77SDag-Erling Smørgrav c->timeout = NULL;
6294b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 0;
6295b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0;
62964c75e3aaSDag-Erling Smørgrav c->tcp_timeout_msec = TCP_QUERY_TIMEOUT;
62974c75e3aaSDag-Erling Smørgrav c->tcp_conn_limit = NULL;
62984c75e3aaSDag-Erling Smørgrav c->tcl_addr = NULL;
62994c75e3aaSDag-Erling Smørgrav c->tcp_keepalive = 0;
6300b7579f77SDag-Erling Smørgrav c->tcp_parent = NULL;
6301b7579f77SDag-Erling Smørgrav c->max_tcp_count = 0;
630209a3aaf3SDag-Erling Smørgrav c->cur_tcp_count = 0;
6303b7579f77SDag-Erling Smørgrav c->tcp_handlers = NULL;
6304b7579f77SDag-Erling Smørgrav c->tcp_free = NULL;
6305b7579f77SDag-Erling Smørgrav c->type = comm_tcp;
6306b7579f77SDag-Erling Smørgrav c->tcp_do_close = 0;
6307b7579f77SDag-Erling Smørgrav c->do_not_close = 0;
6308b7579f77SDag-Erling Smørgrav c->tcp_do_toggle_rw = 1;
6309b7579f77SDag-Erling Smørgrav c->tcp_check_nb_connect = 1;
6310b5663de9SDag-Erling Smørgrav #ifdef USE_MSG_FASTOPEN
6311b5663de9SDag-Erling Smørgrav c->tcp_do_fastopen = 1;
6312b5663de9SDag-Erling Smørgrav #endif
631365b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT
631465b390aaSDag-Erling Smørgrav c->dnscrypt = 0;
631565b390aaSDag-Erling Smørgrav c->dnscrypt_buffer = c->buffer;
631665b390aaSDag-Erling Smørgrav #endif
6317b7579f77SDag-Erling Smørgrav c->repinfo.c = c;
6318b7579f77SDag-Erling Smørgrav c->callback = callback;
6319b7579f77SDag-Erling Smørgrav c->cb_arg = callback_arg;
6320865f46b2SCy Schubert c->pp2_enabled = 0;
6321865f46b2SCy Schubert c->pp2_header_state = pp2_header_none;
6322e2d15004SDag-Erling Smørgrav evbits = UB_EV_PERSIST | UB_EV_WRITE;
6323e2d15004SDag-Erling Smørgrav c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
6324e2d15004SDag-Erling Smørgrav comm_point_tcp_handle_callback, c);
6325e2d15004SDag-Erling Smørgrav if(c->ev->ev == NULL)
6326b7579f77SDag-Erling Smørgrav {
6327e2d15004SDag-Erling Smørgrav log_err("could not baseset tcpout event");
632817d15b25SDag-Erling Smørgrav sldns_buffer_free(c->buffer);
6329b7579f77SDag-Erling Smørgrav free(c->ev);
6330b7579f77SDag-Erling Smørgrav free(c);
6331b7579f77SDag-Erling Smørgrav return NULL;
6332b7579f77SDag-Erling Smørgrav }
6333b7579f77SDag-Erling Smørgrav
6334b7579f77SDag-Erling Smørgrav return c;
6335b7579f77SDag-Erling Smørgrav }
6336b7579f77SDag-Erling Smørgrav
6337b7579f77SDag-Erling Smørgrav struct comm_point*
633857bddd21SDag-Erling Smørgrav comm_point_create_http_out(struct comm_base *base, size_t bufsize,
633957bddd21SDag-Erling Smørgrav comm_point_callback_type* callback, void* callback_arg,
634057bddd21SDag-Erling Smørgrav sldns_buffer* temp)
634157bddd21SDag-Erling Smørgrav {
634257bddd21SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)calloc(1,
634357bddd21SDag-Erling Smørgrav sizeof(struct comm_point));
634457bddd21SDag-Erling Smørgrav short evbits;
634557bddd21SDag-Erling Smørgrav if(!c)
634657bddd21SDag-Erling Smørgrav return NULL;
634757bddd21SDag-Erling Smørgrav c->ev = (struct internal_event*)calloc(1,
634857bddd21SDag-Erling Smørgrav sizeof(struct internal_event));
634957bddd21SDag-Erling Smørgrav if(!c->ev) {
635057bddd21SDag-Erling Smørgrav free(c);
635157bddd21SDag-Erling Smørgrav return NULL;
635257bddd21SDag-Erling Smørgrav }
635357bddd21SDag-Erling Smørgrav c->ev->base = base;
635457bddd21SDag-Erling Smørgrav c->fd = -1;
635557bddd21SDag-Erling Smørgrav c->buffer = sldns_buffer_new(bufsize);
635657bddd21SDag-Erling Smørgrav if(!c->buffer) {
635757bddd21SDag-Erling Smørgrav free(c->ev);
635857bddd21SDag-Erling Smørgrav free(c);
635957bddd21SDag-Erling Smørgrav return NULL;
636057bddd21SDag-Erling Smørgrav }
636157bddd21SDag-Erling Smørgrav c->timeout = NULL;
636257bddd21SDag-Erling Smørgrav c->tcp_is_reading = 0;
636357bddd21SDag-Erling Smørgrav c->tcp_byte_count = 0;
636457bddd21SDag-Erling Smørgrav c->tcp_parent = NULL;
636557bddd21SDag-Erling Smørgrav c->max_tcp_count = 0;
636657bddd21SDag-Erling Smørgrav c->cur_tcp_count = 0;
636757bddd21SDag-Erling Smørgrav c->tcp_handlers = NULL;
636857bddd21SDag-Erling Smørgrav c->tcp_free = NULL;
636957bddd21SDag-Erling Smørgrav c->type = comm_http;
637057bddd21SDag-Erling Smørgrav c->tcp_do_close = 0;
637157bddd21SDag-Erling Smørgrav c->do_not_close = 0;
637257bddd21SDag-Erling Smørgrav c->tcp_do_toggle_rw = 1;
637357bddd21SDag-Erling Smørgrav c->tcp_check_nb_connect = 1;
637457bddd21SDag-Erling Smørgrav c->http_in_headers = 1;
637557bddd21SDag-Erling Smørgrav c->http_in_chunk_headers = 0;
637657bddd21SDag-Erling Smørgrav c->http_is_chunked = 0;
637757bddd21SDag-Erling Smørgrav c->http_temp = temp;
637857bddd21SDag-Erling Smørgrav #ifdef USE_MSG_FASTOPEN
637957bddd21SDag-Erling Smørgrav c->tcp_do_fastopen = 1;
638057bddd21SDag-Erling Smørgrav #endif
638157bddd21SDag-Erling Smørgrav #ifdef USE_DNSCRYPT
638257bddd21SDag-Erling Smørgrav c->dnscrypt = 0;
638357bddd21SDag-Erling Smørgrav c->dnscrypt_buffer = c->buffer;
638457bddd21SDag-Erling Smørgrav #endif
638557bddd21SDag-Erling Smørgrav c->repinfo.c = c;
638657bddd21SDag-Erling Smørgrav c->callback = callback;
638757bddd21SDag-Erling Smørgrav c->cb_arg = callback_arg;
6388865f46b2SCy Schubert c->pp2_enabled = 0;
6389865f46b2SCy Schubert c->pp2_header_state = pp2_header_none;
639057bddd21SDag-Erling Smørgrav evbits = UB_EV_PERSIST | UB_EV_WRITE;
639157bddd21SDag-Erling Smørgrav c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
639257bddd21SDag-Erling Smørgrav comm_point_http_handle_callback, c);
639357bddd21SDag-Erling Smørgrav if(c->ev->ev == NULL)
639457bddd21SDag-Erling Smørgrav {
639557bddd21SDag-Erling Smørgrav log_err("could not baseset tcpout event");
639657bddd21SDag-Erling Smørgrav #ifdef HAVE_SSL
639757bddd21SDag-Erling Smørgrav SSL_free(c->ssl);
639857bddd21SDag-Erling Smørgrav #endif
639957bddd21SDag-Erling Smørgrav sldns_buffer_free(c->buffer);
640057bddd21SDag-Erling Smørgrav free(c->ev);
640157bddd21SDag-Erling Smørgrav free(c);
640257bddd21SDag-Erling Smørgrav return NULL;
640357bddd21SDag-Erling Smørgrav }
640457bddd21SDag-Erling Smørgrav
640557bddd21SDag-Erling Smørgrav return c;
640657bddd21SDag-Erling Smørgrav }
640757bddd21SDag-Erling Smørgrav
640857bddd21SDag-Erling Smørgrav struct comm_point*
6409b7579f77SDag-Erling Smørgrav comm_point_create_local(struct comm_base *base, int fd, size_t bufsize,
64103005e0a3SDag-Erling Smørgrav comm_point_callback_type* callback, void* callback_arg)
6411b7579f77SDag-Erling Smørgrav {
6412b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)calloc(1,
6413b7579f77SDag-Erling Smørgrav sizeof(struct comm_point));
6414b7579f77SDag-Erling Smørgrav short evbits;
6415b7579f77SDag-Erling Smørgrav if(!c)
6416b7579f77SDag-Erling Smørgrav return NULL;
6417b7579f77SDag-Erling Smørgrav c->ev = (struct internal_event*)calloc(1,
6418b7579f77SDag-Erling Smørgrav sizeof(struct internal_event));
6419b7579f77SDag-Erling Smørgrav if(!c->ev) {
6420b7579f77SDag-Erling Smørgrav free(c);
6421b7579f77SDag-Erling Smørgrav return NULL;
6422b7579f77SDag-Erling Smørgrav }
6423b7579f77SDag-Erling Smørgrav c->ev->base = base;
6424b7579f77SDag-Erling Smørgrav c->fd = fd;
642517d15b25SDag-Erling Smørgrav c->buffer = sldns_buffer_new(bufsize);
6426b7579f77SDag-Erling Smørgrav if(!c->buffer) {
6427b7579f77SDag-Erling Smørgrav free(c->ev);
6428b7579f77SDag-Erling Smørgrav free(c);
6429b7579f77SDag-Erling Smørgrav return NULL;
6430b7579f77SDag-Erling Smørgrav }
6431b7579f77SDag-Erling Smørgrav c->timeout = NULL;
6432b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 1;
6433b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0;
6434b7579f77SDag-Erling Smørgrav c->tcp_parent = NULL;
6435b7579f77SDag-Erling Smørgrav c->max_tcp_count = 0;
643609a3aaf3SDag-Erling Smørgrav c->cur_tcp_count = 0;
6437b7579f77SDag-Erling Smørgrav c->tcp_handlers = NULL;
6438b7579f77SDag-Erling Smørgrav c->tcp_free = NULL;
6439b7579f77SDag-Erling Smørgrav c->type = comm_local;
6440b7579f77SDag-Erling Smørgrav c->tcp_do_close = 0;
6441b7579f77SDag-Erling Smørgrav c->do_not_close = 1;
6442b7579f77SDag-Erling Smørgrav c->tcp_do_toggle_rw = 0;
6443b7579f77SDag-Erling Smørgrav c->tcp_check_nb_connect = 0;
6444b5663de9SDag-Erling Smørgrav #ifdef USE_MSG_FASTOPEN
6445b5663de9SDag-Erling Smørgrav c->tcp_do_fastopen = 0;
6446b5663de9SDag-Erling Smørgrav #endif
644765b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT
644865b390aaSDag-Erling Smørgrav c->dnscrypt = 0;
644965b390aaSDag-Erling Smørgrav c->dnscrypt_buffer = c->buffer;
645065b390aaSDag-Erling Smørgrav #endif
6451b7579f77SDag-Erling Smørgrav c->callback = callback;
6452b7579f77SDag-Erling Smørgrav c->cb_arg = callback_arg;
6453865f46b2SCy Schubert c->pp2_enabled = 0;
6454865f46b2SCy Schubert c->pp2_header_state = pp2_header_none;
6455e2d15004SDag-Erling Smørgrav /* ub_event stuff */
6456e2d15004SDag-Erling Smørgrav evbits = UB_EV_PERSIST | UB_EV_READ;
6457e2d15004SDag-Erling Smørgrav c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
6458e2d15004SDag-Erling Smørgrav comm_point_local_handle_callback, c);
6459e2d15004SDag-Erling Smørgrav if(c->ev->ev == NULL) {
6460e2d15004SDag-Erling Smørgrav log_err("could not baseset localhdl event");
6461e2d15004SDag-Erling Smørgrav free(c->ev);
6462e2d15004SDag-Erling Smørgrav free(c);
6463e2d15004SDag-Erling Smørgrav return NULL;
6464e2d15004SDag-Erling Smørgrav }
6465e2d15004SDag-Erling Smørgrav if (ub_event_add(c->ev->ev, c->timeout) != 0) {
6466b7579f77SDag-Erling Smørgrav log_err("could not add localhdl event");
6467e2d15004SDag-Erling Smørgrav ub_event_free(c->ev->ev);
6468b7579f77SDag-Erling Smørgrav free(c->ev);
6469b7579f77SDag-Erling Smørgrav free(c);
6470b7579f77SDag-Erling Smørgrav return NULL;
6471b7579f77SDag-Erling Smørgrav }
6472f44e67d1SCy Schubert c->event_added = 1;
6473b7579f77SDag-Erling Smørgrav return c;
6474b7579f77SDag-Erling Smørgrav }
6475b7579f77SDag-Erling Smørgrav
6476b7579f77SDag-Erling Smørgrav struct comm_point*
6477b7579f77SDag-Erling Smørgrav comm_point_create_raw(struct comm_base* base, int fd, int writing,
64783005e0a3SDag-Erling Smørgrav comm_point_callback_type* callback, void* callback_arg)
6479b7579f77SDag-Erling Smørgrav {
6480b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)calloc(1,
6481b7579f77SDag-Erling Smørgrav sizeof(struct comm_point));
6482b7579f77SDag-Erling Smørgrav short evbits;
6483b7579f77SDag-Erling Smørgrav if(!c)
6484b7579f77SDag-Erling Smørgrav return NULL;
6485b7579f77SDag-Erling Smørgrav c->ev = (struct internal_event*)calloc(1,
6486b7579f77SDag-Erling Smørgrav sizeof(struct internal_event));
6487b7579f77SDag-Erling Smørgrav if(!c->ev) {
6488b7579f77SDag-Erling Smørgrav free(c);
6489b7579f77SDag-Erling Smørgrav return NULL;
6490b7579f77SDag-Erling Smørgrav }
6491b7579f77SDag-Erling Smørgrav c->ev->base = base;
6492b7579f77SDag-Erling Smørgrav c->fd = fd;
6493b7579f77SDag-Erling Smørgrav c->buffer = NULL;
6494b7579f77SDag-Erling Smørgrav c->timeout = NULL;
6495b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 0;
6496b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0;
6497b7579f77SDag-Erling Smørgrav c->tcp_parent = NULL;
6498b7579f77SDag-Erling Smørgrav c->max_tcp_count = 0;
649909a3aaf3SDag-Erling Smørgrav c->cur_tcp_count = 0;
6500b7579f77SDag-Erling Smørgrav c->tcp_handlers = NULL;
6501b7579f77SDag-Erling Smørgrav c->tcp_free = NULL;
6502b7579f77SDag-Erling Smørgrav c->type = comm_raw;
6503b7579f77SDag-Erling Smørgrav c->tcp_do_close = 0;
6504b7579f77SDag-Erling Smørgrav c->do_not_close = 1;
6505b7579f77SDag-Erling Smørgrav c->tcp_do_toggle_rw = 0;
6506b7579f77SDag-Erling Smørgrav c->tcp_check_nb_connect = 0;
6507b5663de9SDag-Erling Smørgrav #ifdef USE_MSG_FASTOPEN
6508b5663de9SDag-Erling Smørgrav c->tcp_do_fastopen = 0;
6509b5663de9SDag-Erling Smørgrav #endif
651065b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT
651165b390aaSDag-Erling Smørgrav c->dnscrypt = 0;
651265b390aaSDag-Erling Smørgrav c->dnscrypt_buffer = c->buffer;
651365b390aaSDag-Erling Smørgrav #endif
6514b7579f77SDag-Erling Smørgrav c->callback = callback;
6515b7579f77SDag-Erling Smørgrav c->cb_arg = callback_arg;
6516865f46b2SCy Schubert c->pp2_enabled = 0;
6517865f46b2SCy Schubert c->pp2_header_state = pp2_header_none;
6518e2d15004SDag-Erling Smørgrav /* ub_event stuff */
6519b7579f77SDag-Erling Smørgrav if(writing)
6520e2d15004SDag-Erling Smørgrav evbits = UB_EV_PERSIST | UB_EV_WRITE;
6521e2d15004SDag-Erling Smørgrav else evbits = UB_EV_PERSIST | UB_EV_READ;
6522e2d15004SDag-Erling Smørgrav c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
6523e2d15004SDag-Erling Smørgrav comm_point_raw_handle_callback, c);
6524e2d15004SDag-Erling Smørgrav if(c->ev->ev == NULL) {
6525e2d15004SDag-Erling Smørgrav log_err("could not baseset rawhdl event");
6526e2d15004SDag-Erling Smørgrav free(c->ev);
6527e2d15004SDag-Erling Smørgrav free(c);
6528e2d15004SDag-Erling Smørgrav return NULL;
6529e2d15004SDag-Erling Smørgrav }
6530e2d15004SDag-Erling Smørgrav if (ub_event_add(c->ev->ev, c->timeout) != 0) {
6531b7579f77SDag-Erling Smørgrav log_err("could not add rawhdl event");
6532e2d15004SDag-Erling Smørgrav ub_event_free(c->ev->ev);
6533b7579f77SDag-Erling Smørgrav free(c->ev);
6534b7579f77SDag-Erling Smørgrav free(c);
6535b7579f77SDag-Erling Smørgrav return NULL;
6536b7579f77SDag-Erling Smørgrav }
6537f44e67d1SCy Schubert c->event_added = 1;
6538b7579f77SDag-Erling Smørgrav return c;
6539b7579f77SDag-Erling Smørgrav }
6540b7579f77SDag-Erling Smørgrav
6541b7579f77SDag-Erling Smørgrav void
6542b7579f77SDag-Erling Smørgrav comm_point_close(struct comm_point* c)
6543b7579f77SDag-Erling Smørgrav {
6544b7579f77SDag-Erling Smørgrav if(!c)
6545b7579f77SDag-Erling Smørgrav return;
65463bd4df0aSDag-Erling Smørgrav if(c->fd != -1) {
6547369c6923SCy Schubert verbose(5, "comm_point_close of %d: event_del", c->fd);
6548f44e67d1SCy Schubert if(c->event_added) {
6549e2d15004SDag-Erling Smørgrav if(ub_event_del(c->ev->ev) != 0) {
6550b7579f77SDag-Erling Smørgrav log_err("could not event_del on close");
6551b7579f77SDag-Erling Smørgrav }
6552f44e67d1SCy Schubert c->event_added = 0;
6553f44e67d1SCy Schubert }
65543bd4df0aSDag-Erling Smørgrav }
65554c75e3aaSDag-Erling Smørgrav tcl_close_connection(c->tcl_addr);
6556e86b9096SDag-Erling Smørgrav if(c->tcp_req_info)
6557e86b9096SDag-Erling Smørgrav tcp_req_info_clear(c->tcp_req_info);
6558c0caa2e2SCy Schubert if(c->h2_session)
6559c0caa2e2SCy Schubert http2_session_server_delete(c->h2_session);
65601838dec3SCy Schubert /* stop the comm point from reading or writing after it is closed. */
65611838dec3SCy Schubert if(c->tcp_more_read_again && *c->tcp_more_read_again)
65621838dec3SCy Schubert *c->tcp_more_read_again = 0;
65631838dec3SCy Schubert if(c->tcp_more_write_again && *c->tcp_more_write_again)
65641838dec3SCy Schubert *c->tcp_more_write_again = 0;
6565c0caa2e2SCy Schubert
6566b7579f77SDag-Erling Smørgrav /* close fd after removing from event lists, or epoll.. is messed up */
6567b7579f77SDag-Erling Smørgrav if(c->fd != -1 && !c->do_not_close) {
65685469a995SCy Schubert #ifdef USE_WINSOCK
65693bd4df0aSDag-Erling Smørgrav if(c->type == comm_tcp || c->type == comm_http) {
65703bd4df0aSDag-Erling Smørgrav /* delete sticky events for the fd, it gets closed */
65713bd4df0aSDag-Erling Smørgrav ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ);
65723bd4df0aSDag-Erling Smørgrav ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE);
65733bd4df0aSDag-Erling Smørgrav }
65745469a995SCy Schubert #endif
6575b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "close fd %d", c->fd);
6576c0caa2e2SCy Schubert sock_close(c->fd);
6577b7579f77SDag-Erling Smørgrav }
6578b7579f77SDag-Erling Smørgrav c->fd = -1;
6579b7579f77SDag-Erling Smørgrav }
6580b7579f77SDag-Erling Smørgrav
6581b7579f77SDag-Erling Smørgrav void
6582b7579f77SDag-Erling Smørgrav comm_point_delete(struct comm_point* c)
6583b7579f77SDag-Erling Smørgrav {
6584b7579f77SDag-Erling Smørgrav if(!c)
6585b7579f77SDag-Erling Smørgrav return;
658657bddd21SDag-Erling Smørgrav if((c->type == comm_tcp || c->type == comm_http) && c->ssl) {
65878ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL
6588b7579f77SDag-Erling Smørgrav SSL_shutdown(c->ssl);
6589b7579f77SDag-Erling Smørgrav SSL_free(c->ssl);
65908ed2b524SDag-Erling Smørgrav #endif
6591b7579f77SDag-Erling Smørgrav }
6592c0caa2e2SCy Schubert if(c->type == comm_http && c->http_endpoint) {
6593c0caa2e2SCy Schubert free(c->http_endpoint);
6594c0caa2e2SCy Schubert c->http_endpoint = NULL;
6595c0caa2e2SCy Schubert }
6596b7579f77SDag-Erling Smørgrav comm_point_close(c);
6597b7579f77SDag-Erling Smørgrav if(c->tcp_handlers) {
6598b7579f77SDag-Erling Smørgrav int i;
6599b7579f77SDag-Erling Smørgrav for(i=0; i<c->max_tcp_count; i++)
6600b7579f77SDag-Erling Smørgrav comm_point_delete(c->tcp_handlers[i]);
6601b7579f77SDag-Erling Smørgrav free(c->tcp_handlers);
6602b7579f77SDag-Erling Smørgrav }
6603b7579f77SDag-Erling Smørgrav free(c->timeout);
660457bddd21SDag-Erling Smørgrav if(c->type == comm_tcp || c->type == comm_local || c->type == comm_http) {
660517d15b25SDag-Erling Smørgrav sldns_buffer_free(c->buffer);
660665b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT
660765b390aaSDag-Erling Smørgrav if(c->dnscrypt && c->dnscrypt_buffer != c->buffer) {
660865b390aaSDag-Erling Smørgrav sldns_buffer_free(c->dnscrypt_buffer);
660965b390aaSDag-Erling Smørgrav }
661065b390aaSDag-Erling Smørgrav #endif
6611e86b9096SDag-Erling Smørgrav if(c->tcp_req_info) {
6612e86b9096SDag-Erling Smørgrav tcp_req_info_delete(c->tcp_req_info);
6613e86b9096SDag-Erling Smørgrav }
6614c0caa2e2SCy Schubert if(c->h2_session) {
6615c0caa2e2SCy Schubert http2_session_delete(c->h2_session);
6616c0caa2e2SCy Schubert }
661765b390aaSDag-Erling Smørgrav }
6618*46d2f618SCy Schubert #ifdef HAVE_NGTCP2
6619*46d2f618SCy Schubert if(c->doq_socket)
6620*46d2f618SCy Schubert doq_server_socket_delete(c->doq_socket);
6621*46d2f618SCy Schubert #endif
6622e2d15004SDag-Erling Smørgrav ub_event_free(c->ev->ev);
6623b7579f77SDag-Erling Smørgrav free(c->ev);
6624b7579f77SDag-Erling Smørgrav free(c);
6625b7579f77SDag-Erling Smørgrav }
6626b7579f77SDag-Erling Smørgrav
6627*46d2f618SCy Schubert #ifdef USE_DNSTAP
6628*46d2f618SCy Schubert static void
6629*46d2f618SCy Schubert send_reply_dnstap(struct dt_env* dtenv,
6630*46d2f618SCy Schubert struct sockaddr* addr, socklen_t addrlen,
6631*46d2f618SCy Schubert struct sockaddr_storage* client_addr, socklen_t client_addrlen,
6632*46d2f618SCy Schubert enum comm_point_type type, void* ssl, sldns_buffer* buffer)
6633*46d2f618SCy Schubert {
6634*46d2f618SCy Schubert log_addr(VERB_ALGO, "from local addr", (void*)addr, addrlen);
6635*46d2f618SCy Schubert log_addr(VERB_ALGO, "response to client", client_addr, client_addrlen);
6636*46d2f618SCy Schubert dt_msg_send_client_response(dtenv, client_addr,
6637*46d2f618SCy Schubert (struct sockaddr_storage*)addr, type, ssl, buffer);
6638*46d2f618SCy Schubert }
6639*46d2f618SCy Schubert #endif
6640*46d2f618SCy Schubert
6641b7579f77SDag-Erling Smørgrav void
6642b7579f77SDag-Erling Smørgrav comm_point_send_reply(struct comm_reply *repinfo)
6643b7579f77SDag-Erling Smørgrav {
664465b390aaSDag-Erling Smørgrav struct sldns_buffer* buffer;
6645b7579f77SDag-Erling Smørgrav log_assert(repinfo && repinfo->c);
664665b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT
664765b390aaSDag-Erling Smørgrav buffer = repinfo->c->dnscrypt_buffer;
664865b390aaSDag-Erling Smørgrav if(!dnsc_handle_uncurved_request(repinfo)) {
664965b390aaSDag-Erling Smørgrav return;
665065b390aaSDag-Erling Smørgrav }
665165b390aaSDag-Erling Smørgrav #else
665265b390aaSDag-Erling Smørgrav buffer = repinfo->c->buffer;
665365b390aaSDag-Erling Smørgrav #endif
6654b7579f77SDag-Erling Smørgrav if(repinfo->c->type == comm_udp) {
6655b7579f77SDag-Erling Smørgrav if(repinfo->srctype)
6656865f46b2SCy Schubert comm_point_send_udp_msg_if(repinfo->c, buffer,
6657865f46b2SCy Schubert (struct sockaddr*)&repinfo->remote_addr,
6658865f46b2SCy Schubert repinfo->remote_addrlen, repinfo);
6659b7579f77SDag-Erling Smørgrav else
666065b390aaSDag-Erling Smørgrav comm_point_send_udp_msg(repinfo->c, buffer,
6661865f46b2SCy Schubert (struct sockaddr*)&repinfo->remote_addr,
6662865f46b2SCy Schubert repinfo->remote_addrlen, 0);
6663ff825849SDag-Erling Smørgrav #ifdef USE_DNSTAP
66645469a995SCy Schubert /*
6665*46d2f618SCy Schubert * sending src (client)/dst (local service) addresses over
6666*46d2f618SCy Schubert * DNSTAP from udp callback
66675469a995SCy Schubert */
66685469a995SCy Schubert if(repinfo->c->dtenv != NULL && repinfo->c->dtenv->log_client_response_messages) {
6669*46d2f618SCy Schubert send_reply_dnstap(repinfo->c->dtenv,
6670*46d2f618SCy Schubert repinfo->c->socket->addr,
6671*46d2f618SCy Schubert repinfo->c->socket->addrlen,
6672*46d2f618SCy Schubert &repinfo->client_addr, repinfo->client_addrlen,
6673*46d2f618SCy Schubert repinfo->c->type, repinfo->c->ssl,
6674*46d2f618SCy Schubert repinfo->c->buffer);
66755469a995SCy Schubert }
6676ff825849SDag-Erling Smørgrav #endif
6677b7579f77SDag-Erling Smørgrav } else {
6678ff825849SDag-Erling Smørgrav #ifdef USE_DNSTAP
6679*46d2f618SCy Schubert struct dt_env* dtenv =
6680*46d2f618SCy Schubert #ifdef HAVE_NGTCP2
6681*46d2f618SCy Schubert repinfo->c->doq_socket
6682*46d2f618SCy Schubert ?repinfo->c->dtenv:
6683*46d2f618SCy Schubert #endif
6684*46d2f618SCy Schubert repinfo->c->tcp_parent->dtenv;
6685*46d2f618SCy Schubert struct sldns_buffer* dtbuffer = repinfo->c->tcp_req_info
6686*46d2f618SCy Schubert ?repinfo->c->tcp_req_info->spool_buffer
6687*46d2f618SCy Schubert :repinfo->c->buffer;
6688*46d2f618SCy Schubert #ifdef USE_DNSCRYPT
6689*46d2f618SCy Schubert if(repinfo->c->dnscrypt && repinfo->is_dnscrypted)
6690*46d2f618SCy Schubert dtbuffer = repinfo->c->buffer;
6691*46d2f618SCy Schubert #endif
66925469a995SCy Schubert /*
6693*46d2f618SCy Schubert * sending src (client)/dst (local service) addresses over
6694*46d2f618SCy Schubert * DNSTAP from other callbacks
66955469a995SCy Schubert */
6696*46d2f618SCy Schubert if(dtenv != NULL && dtenv->log_client_response_messages) {
6697*46d2f618SCy Schubert send_reply_dnstap(dtenv,
6698*46d2f618SCy Schubert repinfo->c->socket->addr,
6699*46d2f618SCy Schubert repinfo->c->socket->addrlen,
6700*46d2f618SCy Schubert &repinfo->client_addr, repinfo->client_addrlen,
6701*46d2f618SCy Schubert repinfo->c->type, repinfo->c->ssl,
6702*46d2f618SCy Schubert dtbuffer);
67035469a995SCy Schubert }
6704ff825849SDag-Erling Smørgrav #endif
6705e86b9096SDag-Erling Smørgrav if(repinfo->c->tcp_req_info) {
6706e86b9096SDag-Erling Smørgrav tcp_req_info_send_reply(repinfo->c->tcp_req_info);
6707c0caa2e2SCy Schubert } else if(repinfo->c->use_h2) {
6708c0caa2e2SCy Schubert if(!http2_submit_dns_response(repinfo->c->h2_session)) {
6709c0caa2e2SCy Schubert comm_point_drop_reply(repinfo);
6710c0caa2e2SCy Schubert return;
6711c0caa2e2SCy Schubert }
6712c0caa2e2SCy Schubert repinfo->c->h2_stream = NULL;
6713c0caa2e2SCy Schubert repinfo->c->tcp_is_reading = 0;
6714c0caa2e2SCy Schubert comm_point_stop_listening(repinfo->c);
6715c0caa2e2SCy Schubert comm_point_start_listening(repinfo->c, -1,
6716f44e67d1SCy Schubert adjusted_tcp_timeout(repinfo->c));
6717c0caa2e2SCy Schubert return;
6718*46d2f618SCy Schubert #ifdef HAVE_NGTCP2
6719*46d2f618SCy Schubert } else if(repinfo->c->doq_socket) {
6720*46d2f618SCy Schubert doq_socket_send_reply(repinfo);
6721*46d2f618SCy Schubert #endif
6722e86b9096SDag-Erling Smørgrav } else {
6723b5663de9SDag-Erling Smørgrav comm_point_start_listening(repinfo->c, -1,
6724f44e67d1SCy Schubert adjusted_tcp_timeout(repinfo->c));
6725b7579f77SDag-Erling Smørgrav }
6726b7579f77SDag-Erling Smørgrav }
6727e86b9096SDag-Erling Smørgrav }
6728b7579f77SDag-Erling Smørgrav
6729b7579f77SDag-Erling Smørgrav void
6730b7579f77SDag-Erling Smørgrav comm_point_drop_reply(struct comm_reply* repinfo)
6731b7579f77SDag-Erling Smørgrav {
6732b7579f77SDag-Erling Smørgrav if(!repinfo)
6733b7579f77SDag-Erling Smørgrav return;
67340eefd307SCy Schubert log_assert(repinfo->c);
6735b7579f77SDag-Erling Smørgrav log_assert(repinfo->c->type != comm_tcp_accept);
6736b7579f77SDag-Erling Smørgrav if(repinfo->c->type == comm_udp)
6737b7579f77SDag-Erling Smørgrav return;
6738e86b9096SDag-Erling Smørgrav if(repinfo->c->tcp_req_info)
6739e86b9096SDag-Erling Smørgrav repinfo->c->tcp_req_info->is_drop = 1;
6740c0caa2e2SCy Schubert if(repinfo->c->type == comm_http) {
6741c0caa2e2SCy Schubert if(repinfo->c->h2_session) {
6742c0caa2e2SCy Schubert repinfo->c->h2_session->is_drop = 1;
6743c0caa2e2SCy Schubert if(!repinfo->c->h2_session->postpone_drop)
6744c0caa2e2SCy Schubert reclaim_http_handler(repinfo->c);
6745c0caa2e2SCy Schubert return;
6746c0caa2e2SCy Schubert }
6747c0caa2e2SCy Schubert reclaim_http_handler(repinfo->c);
6748c0caa2e2SCy Schubert return;
6749*46d2f618SCy Schubert #ifdef HAVE_NGTCP2
6750*46d2f618SCy Schubert } else if(repinfo->c->type == comm_doq) {
6751*46d2f618SCy Schubert doq_socket_drop_reply(repinfo);
6752*46d2f618SCy Schubert return;
6753*46d2f618SCy Schubert #endif
6754c0caa2e2SCy Schubert }
6755b7579f77SDag-Erling Smørgrav reclaim_tcp_handler(repinfo->c);
6756b7579f77SDag-Erling Smørgrav }
6757b7579f77SDag-Erling Smørgrav
6758b7579f77SDag-Erling Smørgrav void
6759b7579f77SDag-Erling Smørgrav comm_point_stop_listening(struct comm_point* c)
6760b7579f77SDag-Erling Smørgrav {
6761b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "comm point stop listening %d", c->fd);
6762f44e67d1SCy Schubert if(c->event_added) {
6763e2d15004SDag-Erling Smørgrav if(ub_event_del(c->ev->ev) != 0) {
6764b7579f77SDag-Erling Smørgrav log_err("event_del error to stoplisten");
6765b7579f77SDag-Erling Smørgrav }
6766f44e67d1SCy Schubert c->event_added = 0;
6767f44e67d1SCy Schubert }
6768b7579f77SDag-Erling Smørgrav }
6769b7579f77SDag-Erling Smørgrav
6770b7579f77SDag-Erling Smørgrav void
6771b5663de9SDag-Erling Smørgrav comm_point_start_listening(struct comm_point* c, int newfd, int msec)
6772b7579f77SDag-Erling Smørgrav {
6773e86b9096SDag-Erling Smørgrav verbose(VERB_ALGO, "comm point start listening %d (%d msec)",
6774e86b9096SDag-Erling Smørgrav c->fd==-1?newfd:c->fd, msec);
6775b7579f77SDag-Erling Smørgrav if(c->type == comm_tcp_accept && !c->tcp_free) {
6776b7579f77SDag-Erling Smørgrav /* no use to start listening no free slots. */
6777b7579f77SDag-Erling Smørgrav return;
6778b7579f77SDag-Erling Smørgrav }
6779f44e67d1SCy Schubert if(c->event_added) {
6780f44e67d1SCy Schubert if(ub_event_del(c->ev->ev) != 0) {
6781f44e67d1SCy Schubert log_err("event_del error to startlisten");
6782f44e67d1SCy Schubert }
6783f44e67d1SCy Schubert c->event_added = 0;
6784f44e67d1SCy Schubert }
6785b5663de9SDag-Erling Smørgrav if(msec != -1 && msec != 0) {
6786b7579f77SDag-Erling Smørgrav if(!c->timeout) {
6787b7579f77SDag-Erling Smørgrav c->timeout = (struct timeval*)malloc(sizeof(
6788b7579f77SDag-Erling Smørgrav struct timeval));
6789b7579f77SDag-Erling Smørgrav if(!c->timeout) {
6790b7579f77SDag-Erling Smørgrav log_err("cpsl: malloc failed. No net read.");
6791b7579f77SDag-Erling Smørgrav return;
6792b7579f77SDag-Erling Smørgrav }
6793b7579f77SDag-Erling Smørgrav }
6794e2d15004SDag-Erling Smørgrav ub_event_add_bits(c->ev->ev, UB_EV_TIMEOUT);
6795b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S /* splint fails on struct timeval. */
6796b5663de9SDag-Erling Smørgrav c->timeout->tv_sec = msec/1000;
6797b5663de9SDag-Erling Smørgrav c->timeout->tv_usec = (msec%1000)*1000;
6798b7579f77SDag-Erling Smørgrav #endif /* S_SPLINT_S */
679924e36522SCy Schubert } else {
680024e36522SCy Schubert if(msec == 0 || !c->timeout) {
680124e36522SCy Schubert ub_event_del_bits(c->ev->ev, UB_EV_TIMEOUT);
680224e36522SCy Schubert }
6803b7579f77SDag-Erling Smørgrav }
680457bddd21SDag-Erling Smørgrav if(c->type == comm_tcp || c->type == comm_http) {
6805e2d15004SDag-Erling Smørgrav ub_event_del_bits(c->ev->ev, UB_EV_READ|UB_EV_WRITE);
6806369c6923SCy Schubert if(c->tcp_write_and_read) {
6807369c6923SCy Schubert verbose(5, "startlistening %d mode rw", (newfd==-1?c->fd:newfd));
6808369c6923SCy Schubert ub_event_add_bits(c->ev->ev, UB_EV_READ|UB_EV_WRITE);
6809369c6923SCy Schubert } else if(c->tcp_is_reading) {
6810369c6923SCy Schubert verbose(5, "startlistening %d mode r", (newfd==-1?c->fd:newfd));
6811e2d15004SDag-Erling Smørgrav ub_event_add_bits(c->ev->ev, UB_EV_READ);
6812369c6923SCy Schubert } else {
6813369c6923SCy Schubert verbose(5, "startlistening %d mode w", (newfd==-1?c->fd:newfd));
6814369c6923SCy Schubert ub_event_add_bits(c->ev->ev, UB_EV_WRITE);
6815369c6923SCy Schubert }
6816b7579f77SDag-Erling Smørgrav }
6817b7579f77SDag-Erling Smørgrav if(newfd != -1) {
6818369c6923SCy Schubert if(c->fd != -1 && c->fd != newfd) {
6819369c6923SCy Schubert verbose(5, "cpsl close of fd %d for %d", c->fd, newfd);
6820c0caa2e2SCy Schubert sock_close(c->fd);
6821b7579f77SDag-Erling Smørgrav }
6822b7579f77SDag-Erling Smørgrav c->fd = newfd;
6823e2d15004SDag-Erling Smørgrav ub_event_set_fd(c->ev->ev, c->fd);
6824b7579f77SDag-Erling Smørgrav }
6825b5663de9SDag-Erling Smørgrav if(ub_event_add(c->ev->ev, msec==0?NULL:c->timeout) != 0) {
6826b7579f77SDag-Erling Smørgrav log_err("event_add failed. in cpsl.");
682724e36522SCy Schubert return;
6828b7579f77SDag-Erling Smørgrav }
6829f44e67d1SCy Schubert c->event_added = 1;
6830b7579f77SDag-Erling Smørgrav }
6831b7579f77SDag-Erling Smørgrav
6832b7579f77SDag-Erling Smørgrav void comm_point_listen_for_rw(struct comm_point* c, int rd, int wr)
6833b7579f77SDag-Erling Smørgrav {
6834b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "comm point listen_for_rw %d %d", c->fd, wr);
6835f44e67d1SCy Schubert if(c->event_added) {
6836e2d15004SDag-Erling Smørgrav if(ub_event_del(c->ev->ev) != 0) {
6837b7579f77SDag-Erling Smørgrav log_err("event_del error to cplf");
6838b7579f77SDag-Erling Smørgrav }
6839f44e67d1SCy Schubert c->event_added = 0;
6840f44e67d1SCy Schubert }
684124e36522SCy Schubert if(!c->timeout) {
684224e36522SCy Schubert ub_event_del_bits(c->ev->ev, UB_EV_TIMEOUT);
684324e36522SCy Schubert }
6844e2d15004SDag-Erling Smørgrav ub_event_del_bits(c->ev->ev, UB_EV_READ|UB_EV_WRITE);
6845e2d15004SDag-Erling Smørgrav if(rd) ub_event_add_bits(c->ev->ev, UB_EV_READ);
6846e2d15004SDag-Erling Smørgrav if(wr) ub_event_add_bits(c->ev->ev, UB_EV_WRITE);
6847e2d15004SDag-Erling Smørgrav if(ub_event_add(c->ev->ev, c->timeout) != 0) {
6848b7579f77SDag-Erling Smørgrav log_err("event_add failed. in cplf.");
684924e36522SCy Schubert return;
6850b7579f77SDag-Erling Smørgrav }
6851f44e67d1SCy Schubert c->event_added = 1;
6852b7579f77SDag-Erling Smørgrav }
6853b7579f77SDag-Erling Smørgrav
6854b7579f77SDag-Erling Smørgrav size_t comm_point_get_mem(struct comm_point* c)
6855b7579f77SDag-Erling Smørgrav {
6856b7579f77SDag-Erling Smørgrav size_t s;
6857b7579f77SDag-Erling Smørgrav if(!c)
6858b7579f77SDag-Erling Smørgrav return 0;
6859b7579f77SDag-Erling Smørgrav s = sizeof(*c) + sizeof(*c->ev);
6860b7579f77SDag-Erling Smørgrav if(c->timeout)
6861b7579f77SDag-Erling Smørgrav s += sizeof(*c->timeout);
686265b390aaSDag-Erling Smørgrav if(c->type == comm_tcp || c->type == comm_local) {
686317d15b25SDag-Erling Smørgrav s += sizeof(*c->buffer) + sldns_buffer_capacity(c->buffer);
686465b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT
686565b390aaSDag-Erling Smørgrav s += sizeof(*c->dnscrypt_buffer);
686665b390aaSDag-Erling Smørgrav if(c->buffer != c->dnscrypt_buffer) {
686765b390aaSDag-Erling Smørgrav s += sldns_buffer_capacity(c->dnscrypt_buffer);
686865b390aaSDag-Erling Smørgrav }
686965b390aaSDag-Erling Smørgrav #endif
687065b390aaSDag-Erling Smørgrav }
6871b7579f77SDag-Erling Smørgrav if(c->type == comm_tcp_accept) {
6872b7579f77SDag-Erling Smørgrav int i;
6873b7579f77SDag-Erling Smørgrav for(i=0; i<c->max_tcp_count; i++)
6874b7579f77SDag-Erling Smørgrav s += comm_point_get_mem(c->tcp_handlers[i]);
6875b7579f77SDag-Erling Smørgrav }
6876b7579f77SDag-Erling Smørgrav return s;
6877b7579f77SDag-Erling Smørgrav }
6878b7579f77SDag-Erling Smørgrav
6879b7579f77SDag-Erling Smørgrav struct comm_timer*
6880b7579f77SDag-Erling Smørgrav comm_timer_create(struct comm_base* base, void (*cb)(void*), void* cb_arg)
6881b7579f77SDag-Erling Smørgrav {
6882e2d15004SDag-Erling Smørgrav struct internal_timer *tm = (struct internal_timer*)calloc(1,
6883b7579f77SDag-Erling Smørgrav sizeof(struct internal_timer));
6884e2d15004SDag-Erling Smørgrav if(!tm) {
6885b7579f77SDag-Erling Smørgrav log_err("malloc failed");
6886b7579f77SDag-Erling Smørgrav return NULL;
6887b7579f77SDag-Erling Smørgrav }
6888e2d15004SDag-Erling Smørgrav tm->super.ev_timer = tm;
6889e2d15004SDag-Erling Smørgrav tm->base = base;
6890e2d15004SDag-Erling Smørgrav tm->super.callback = cb;
6891e2d15004SDag-Erling Smørgrav tm->super.cb_arg = cb_arg;
6892e2d15004SDag-Erling Smørgrav tm->ev = ub_event_new(base->eb->base, -1, UB_EV_TIMEOUT,
6893e2d15004SDag-Erling Smørgrav comm_timer_callback, &tm->super);
6894e2d15004SDag-Erling Smørgrav if(tm->ev == NULL) {
6895b7579f77SDag-Erling Smørgrav log_err("timer_create: event_base_set failed.");
6896b7579f77SDag-Erling Smørgrav free(tm);
6897b7579f77SDag-Erling Smørgrav return NULL;
6898b7579f77SDag-Erling Smørgrav }
6899e2d15004SDag-Erling Smørgrav return &tm->super;
6900b7579f77SDag-Erling Smørgrav }
6901b7579f77SDag-Erling Smørgrav
6902b7579f77SDag-Erling Smørgrav void
6903b7579f77SDag-Erling Smørgrav comm_timer_disable(struct comm_timer* timer)
6904b7579f77SDag-Erling Smørgrav {
6905b7579f77SDag-Erling Smørgrav if(!timer)
6906b7579f77SDag-Erling Smørgrav return;
6907e2d15004SDag-Erling Smørgrav ub_timer_del(timer->ev_timer->ev);
6908b7579f77SDag-Erling Smørgrav timer->ev_timer->enabled = 0;
6909b7579f77SDag-Erling Smørgrav }
6910b7579f77SDag-Erling Smørgrav
6911b7579f77SDag-Erling Smørgrav void
6912b7579f77SDag-Erling Smørgrav comm_timer_set(struct comm_timer* timer, struct timeval* tv)
6913b7579f77SDag-Erling Smørgrav {
6914b7579f77SDag-Erling Smørgrav log_assert(tv);
6915b7579f77SDag-Erling Smørgrav if(timer->ev_timer->enabled)
6916b7579f77SDag-Erling Smørgrav comm_timer_disable(timer);
6917e2d15004SDag-Erling Smørgrav if(ub_timer_add(timer->ev_timer->ev, timer->ev_timer->base->eb->base,
6918e2d15004SDag-Erling Smørgrav comm_timer_callback, timer, tv) != 0)
6919b7579f77SDag-Erling Smørgrav log_err("comm_timer_set: evtimer_add failed.");
6920b7579f77SDag-Erling Smørgrav timer->ev_timer->enabled = 1;
6921b7579f77SDag-Erling Smørgrav }
6922b7579f77SDag-Erling Smørgrav
6923b7579f77SDag-Erling Smørgrav void
6924b7579f77SDag-Erling Smørgrav comm_timer_delete(struct comm_timer* timer)
6925b7579f77SDag-Erling Smørgrav {
6926b7579f77SDag-Erling Smørgrav if(!timer)
6927b7579f77SDag-Erling Smørgrav return;
6928b7579f77SDag-Erling Smørgrav comm_timer_disable(timer);
6929e2d15004SDag-Erling Smørgrav /* Free the sub struct timer->ev_timer derived from the super struct timer.
6930e2d15004SDag-Erling Smørgrav * i.e. assert(timer == timer->ev_timer)
6931e2d15004SDag-Erling Smørgrav */
6932e2d15004SDag-Erling Smørgrav ub_event_free(timer->ev_timer->ev);
6933b7579f77SDag-Erling Smørgrav free(timer->ev_timer);
6934b7579f77SDag-Erling Smørgrav }
6935b7579f77SDag-Erling Smørgrav
6936b7579f77SDag-Erling Smørgrav void
6937b7579f77SDag-Erling Smørgrav comm_timer_callback(int ATTR_UNUSED(fd), short event, void* arg)
6938b7579f77SDag-Erling Smørgrav {
6939b7579f77SDag-Erling Smørgrav struct comm_timer* tm = (struct comm_timer*)arg;
6940e2d15004SDag-Erling Smørgrav if(!(event&UB_EV_TIMEOUT))
6941b7579f77SDag-Erling Smørgrav return;
6942e2d15004SDag-Erling Smørgrav ub_comm_base_now(tm->ev_timer->base);
6943b7579f77SDag-Erling Smørgrav tm->ev_timer->enabled = 0;
6944b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_timer(tm->callback));
6945b7579f77SDag-Erling Smørgrav (*tm->callback)(tm->cb_arg);
6946b7579f77SDag-Erling Smørgrav }
6947b7579f77SDag-Erling Smørgrav
6948b7579f77SDag-Erling Smørgrav int
6949b7579f77SDag-Erling Smørgrav comm_timer_is_set(struct comm_timer* timer)
6950b7579f77SDag-Erling Smørgrav {
6951b7579f77SDag-Erling Smørgrav return (int)timer->ev_timer->enabled;
6952b7579f77SDag-Erling Smørgrav }
6953b7579f77SDag-Erling Smørgrav
6954b7579f77SDag-Erling Smørgrav size_t
6955e2d15004SDag-Erling Smørgrav comm_timer_get_mem(struct comm_timer* ATTR_UNUSED(timer))
6956b7579f77SDag-Erling Smørgrav {
6957e2d15004SDag-Erling Smørgrav return sizeof(struct internal_timer);
6958b7579f77SDag-Erling Smørgrav }
6959b7579f77SDag-Erling Smørgrav
6960b7579f77SDag-Erling Smørgrav struct comm_signal*
6961b7579f77SDag-Erling Smørgrav comm_signal_create(struct comm_base* base,
6962b7579f77SDag-Erling Smørgrav void (*callback)(int, void*), void* cb_arg)
6963b7579f77SDag-Erling Smørgrav {
6964b7579f77SDag-Erling Smørgrav struct comm_signal* com = (struct comm_signal*)malloc(
6965b7579f77SDag-Erling Smørgrav sizeof(struct comm_signal));
6966b7579f77SDag-Erling Smørgrav if(!com) {
6967b7579f77SDag-Erling Smørgrav log_err("malloc failed");
6968b7579f77SDag-Erling Smørgrav return NULL;
6969b7579f77SDag-Erling Smørgrav }
6970b7579f77SDag-Erling Smørgrav com->base = base;
6971b7579f77SDag-Erling Smørgrav com->callback = callback;
6972b7579f77SDag-Erling Smørgrav com->cb_arg = cb_arg;
6973b7579f77SDag-Erling Smørgrav com->ev_signal = NULL;
6974b7579f77SDag-Erling Smørgrav return com;
6975b7579f77SDag-Erling Smørgrav }
6976b7579f77SDag-Erling Smørgrav
6977b7579f77SDag-Erling Smørgrav void
6978b7579f77SDag-Erling Smørgrav comm_signal_callback(int sig, short event, void* arg)
6979b7579f77SDag-Erling Smørgrav {
6980b7579f77SDag-Erling Smørgrav struct comm_signal* comsig = (struct comm_signal*)arg;
6981e2d15004SDag-Erling Smørgrav if(!(event & UB_EV_SIGNAL))
6982b7579f77SDag-Erling Smørgrav return;
6983e2d15004SDag-Erling Smørgrav ub_comm_base_now(comsig->base);
6984b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_signal(comsig->callback));
6985b7579f77SDag-Erling Smørgrav (*comsig->callback)(sig, comsig->cb_arg);
6986b7579f77SDag-Erling Smørgrav }
6987b7579f77SDag-Erling Smørgrav
6988b7579f77SDag-Erling Smørgrav int
6989b7579f77SDag-Erling Smørgrav comm_signal_bind(struct comm_signal* comsig, int sig)
6990b7579f77SDag-Erling Smørgrav {
6991b7579f77SDag-Erling Smørgrav struct internal_signal* entry = (struct internal_signal*)calloc(1,
6992b7579f77SDag-Erling Smørgrav sizeof(struct internal_signal));
6993b7579f77SDag-Erling Smørgrav if(!entry) {
6994b7579f77SDag-Erling Smørgrav log_err("malloc failed");
6995b7579f77SDag-Erling Smørgrav return 0;
6996b7579f77SDag-Erling Smørgrav }
6997b7579f77SDag-Erling Smørgrav log_assert(comsig);
6998b7579f77SDag-Erling Smørgrav /* add signal event */
6999e2d15004SDag-Erling Smørgrav entry->ev = ub_signal_new(comsig->base->eb->base, sig,
7000e2d15004SDag-Erling Smørgrav comm_signal_callback, comsig);
7001e2d15004SDag-Erling Smørgrav if(entry->ev == NULL) {
7002e2d15004SDag-Erling Smørgrav log_err("Could not create signal event");
7003b7579f77SDag-Erling Smørgrav free(entry);
7004b7579f77SDag-Erling Smørgrav return 0;
7005b7579f77SDag-Erling Smørgrav }
7006e2d15004SDag-Erling Smørgrav if(ub_signal_add(entry->ev, NULL) != 0) {
7007b7579f77SDag-Erling Smørgrav log_err("Could not add signal handler");
7008e2d15004SDag-Erling Smørgrav ub_event_free(entry->ev);
7009b7579f77SDag-Erling Smørgrav free(entry);
7010b7579f77SDag-Erling Smørgrav return 0;
7011b7579f77SDag-Erling Smørgrav }
7012b7579f77SDag-Erling Smørgrav /* link into list */
7013b7579f77SDag-Erling Smørgrav entry->next = comsig->ev_signal;
7014b7579f77SDag-Erling Smørgrav comsig->ev_signal = entry;
7015b7579f77SDag-Erling Smørgrav return 1;
7016b7579f77SDag-Erling Smørgrav }
7017b7579f77SDag-Erling Smørgrav
7018b7579f77SDag-Erling Smørgrav void
7019b7579f77SDag-Erling Smørgrav comm_signal_delete(struct comm_signal* comsig)
7020b7579f77SDag-Erling Smørgrav {
7021b7579f77SDag-Erling Smørgrav struct internal_signal* p, *np;
7022b7579f77SDag-Erling Smørgrav if(!comsig)
7023b7579f77SDag-Erling Smørgrav return;
7024b7579f77SDag-Erling Smørgrav p=comsig->ev_signal;
7025b7579f77SDag-Erling Smørgrav while(p) {
7026b7579f77SDag-Erling Smørgrav np = p->next;
7027e2d15004SDag-Erling Smørgrav ub_signal_del(p->ev);
7028e2d15004SDag-Erling Smørgrav ub_event_free(p->ev);
7029b7579f77SDag-Erling Smørgrav free(p);
7030b7579f77SDag-Erling Smørgrav p = np;
7031b7579f77SDag-Erling Smørgrav }
7032b7579f77SDag-Erling Smørgrav free(comsig);
7033b7579f77SDag-Erling Smørgrav }
7034