xref: /freebsd/contrib/unbound/testcode/doqclient.c (revision be771a7b7f4580a30d99e41a5bb1b93a385a119d)
1*be771a7bSCy Schubert /*
2*be771a7bSCy Schubert  * testcode/doqclient.c - debug program. Perform multiple DNS queries using DoQ.
3*be771a7bSCy Schubert  *
4*be771a7bSCy Schubert  * Copyright (c) 2022, NLnet Labs. All rights reserved.
5*be771a7bSCy Schubert  *
6*be771a7bSCy Schubert  * This software is open source.
7*be771a7bSCy Schubert  *
8*be771a7bSCy Schubert  * Redistribution and use in source and binary forms, with or without
9*be771a7bSCy Schubert  * modification, are permitted provided that the following conditions
10*be771a7bSCy Schubert  * are met:
11*be771a7bSCy Schubert  *
12*be771a7bSCy Schubert  * Redistributions of source code must retain the above copyright notice,
13*be771a7bSCy Schubert  * this list of conditions and the following disclaimer.
14*be771a7bSCy Schubert  *
15*be771a7bSCy Schubert  * Redistributions in binary form must reproduce the above copyright notice,
16*be771a7bSCy Schubert  * this list of conditions and the following disclaimer in the documentation
17*be771a7bSCy Schubert  * and/or other materials provided with the distribution.
18*be771a7bSCy Schubert  *
19*be771a7bSCy Schubert  * Neither the name of the NLNET LABS nor the names of its contributors may
20*be771a7bSCy Schubert  * be used to endorse or promote products derived from this software without
21*be771a7bSCy Schubert  * specific prior written permission.
22*be771a7bSCy Schubert  *
23*be771a7bSCy Schubert  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24*be771a7bSCy Schubert  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25*be771a7bSCy Schubert  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26*be771a7bSCy Schubert  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27*be771a7bSCy Schubert  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28*be771a7bSCy Schubert  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29*be771a7bSCy Schubert  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30*be771a7bSCy Schubert  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31*be771a7bSCy Schubert  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32*be771a7bSCy Schubert  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33*be771a7bSCy Schubert  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34*be771a7bSCy Schubert  */
35*be771a7bSCy Schubert 
36*be771a7bSCy Schubert /**
37*be771a7bSCy Schubert  * \file
38*be771a7bSCy Schubert  *
39*be771a7bSCy Schubert  * Simple DNS-over-QUIC client. For testing and debugging purposes.
40*be771a7bSCy Schubert  * No authentication of TLS cert.
41*be771a7bSCy Schubert  */
42*be771a7bSCy Schubert 
43*be771a7bSCy Schubert #include "config.h"
44*be771a7bSCy Schubert #ifdef HAVE_GETOPT_H
45*be771a7bSCy Schubert #include <getopt.h>
46*be771a7bSCy Schubert #endif
47*be771a7bSCy Schubert 
48*be771a7bSCy Schubert #ifdef HAVE_NGTCP2
49*be771a7bSCy Schubert #include <ngtcp2/ngtcp2.h>
50*be771a7bSCy Schubert #include <ngtcp2/ngtcp2_crypto.h>
51*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_NGTCP2_CRYPTO_QUICTLS_H
52*be771a7bSCy Schubert #include <ngtcp2/ngtcp2_crypto_quictls.h>
53*be771a7bSCy Schubert #else
54*be771a7bSCy Schubert #include <ngtcp2/ngtcp2_crypto_openssl.h>
55*be771a7bSCy Schubert #endif
56*be771a7bSCy Schubert #include <openssl/ssl.h>
57*be771a7bSCy Schubert #include <openssl/rand.h>
58*be771a7bSCy Schubert #ifdef HAVE_TIME_H
59*be771a7bSCy Schubert #include <time.h>
60*be771a7bSCy Schubert #endif
61*be771a7bSCy Schubert #include <sys/time.h>
62*be771a7bSCy Schubert #include "util/locks.h"
63*be771a7bSCy Schubert #include "util/net_help.h"
64*be771a7bSCy Schubert #include "sldns/sbuffer.h"
65*be771a7bSCy Schubert #include "sldns/str2wire.h"
66*be771a7bSCy Schubert #include "sldns/wire2str.h"
67*be771a7bSCy Schubert #include "util/data/msgreply.h"
68*be771a7bSCy Schubert #include "util/data/msgencode.h"
69*be771a7bSCy Schubert #include "util/data/msgparse.h"
70*be771a7bSCy Schubert #include "util/data/dname.h"
71*be771a7bSCy Schubert #include "util/random.h"
72*be771a7bSCy Schubert #include "util/ub_event.h"
73*be771a7bSCy Schubert struct doq_client_stream_list;
74*be771a7bSCy Schubert struct doq_client_stream;
75*be771a7bSCy Schubert 
76*be771a7bSCy Schubert /** the local client data for the DoQ connection */
77*be771a7bSCy Schubert struct doq_client_data {
78*be771a7bSCy Schubert 	/** file descriptor */
79*be771a7bSCy Schubert 	int fd;
80*be771a7bSCy Schubert 	/** the event base for the events */
81*be771a7bSCy Schubert 	struct ub_event_base* base;
82*be771a7bSCy Schubert 	/** the ub event */
83*be771a7bSCy Schubert 	struct ub_event* ev;
84*be771a7bSCy Schubert 	/** the expiry timer */
85*be771a7bSCy Schubert 	struct ub_event* expire_timer;
86*be771a7bSCy Schubert 	/** is the expire_timer added */
87*be771a7bSCy Schubert 	int expire_timer_added;
88*be771a7bSCy Schubert 	/** the ngtcp2 connection information */
89*be771a7bSCy Schubert 	struct ngtcp2_conn* conn;
90*be771a7bSCy Schubert 	/** random state */
91*be771a7bSCy Schubert 	struct ub_randstate* rnd;
92*be771a7bSCy Schubert 	/** server connected to as a string */
93*be771a7bSCy Schubert 	const char* svr;
94*be771a7bSCy Schubert 	/** the static secret */
95*be771a7bSCy Schubert 	uint8_t* static_secret_data;
96*be771a7bSCy Schubert 	/** the static secret size */
97*be771a7bSCy Schubert 	size_t static_secret_size;
98*be771a7bSCy Schubert 	/** destination address sockaddr */
99*be771a7bSCy Schubert 	struct sockaddr_storage dest_addr;
100*be771a7bSCy Schubert 	/** length of dest addr */
101*be771a7bSCy Schubert 	socklen_t dest_addr_len;
102*be771a7bSCy Schubert 	/** local address sockaddr */
103*be771a7bSCy Schubert 	struct sockaddr_storage local_addr;
104*be771a7bSCy Schubert 	/** length of local addr */
105*be771a7bSCy Schubert 	socklen_t local_addr_len;
106*be771a7bSCy Schubert 	/** SSL context */
107*be771a7bSCy Schubert 	SSL_CTX* ctx;
108*be771a7bSCy Schubert 	/** SSL object */
109*be771a7bSCy Schubert 	SSL* ssl;
110*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_CLIENT_CONTEXT
111*be771a7bSCy Schubert 	/** the connection reference for ngtcp2_conn and userdata in ssl */
112*be771a7bSCy Schubert 	struct ngtcp2_crypto_conn_ref conn_ref;
113*be771a7bSCy Schubert #endif
114*be771a7bSCy Schubert 	/** the quic version to use */
115*be771a7bSCy Schubert 	uint32_t quic_version;
116*be771a7bSCy Schubert 	/** the last error */
117*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CCERR_DEFAULT
118*be771a7bSCy Schubert 	struct ngtcp2_ccerr ccerr;
119*be771a7bSCy Schubert #else
120*be771a7bSCy Schubert 	struct ngtcp2_connection_close_error last_error;
121*be771a7bSCy Schubert #endif
122*be771a7bSCy Schubert 	/** the recent tls alert error code */
123*be771a7bSCy Schubert 	uint8_t tls_alert;
124*be771a7bSCy Schubert 	/** the buffer for packet operations */
125*be771a7bSCy Schubert 	struct sldns_buffer* pkt_buf;
126*be771a7bSCy Schubert 	/** The list of queries to start. They have no stream associated.
127*be771a7bSCy Schubert 	 * Once they do, they move to the send list. */
128*be771a7bSCy Schubert 	struct doq_client_stream_list* query_list_start;
129*be771a7bSCy Schubert 	/** The list of queries to send. They have a stream, and they are
130*be771a7bSCy Schubert 	 * sending data. Data could also be received, like errors. */
131*be771a7bSCy Schubert 	struct doq_client_stream_list* query_list_send;
132*be771a7bSCy Schubert 	/** The list of queries to receive. They have a stream, and the
133*be771a7bSCy Schubert 	 * send is done, it is possible to read data. */
134*be771a7bSCy Schubert 	struct doq_client_stream_list* query_list_receive;
135*be771a7bSCy Schubert 	/** The list of queries that are stopped. They have no stream
136*be771a7bSCy Schubert 	 * active any more. Write and read are done. The query is done,
137*be771a7bSCy Schubert 	 * and it may be in error and then have no answer or partial answer. */
138*be771a7bSCy Schubert 	struct doq_client_stream_list* query_list_stop;
139*be771a7bSCy Schubert 	/** is there a blocked packet in the blocked_pkt buffer */
140*be771a7bSCy Schubert 	int have_blocked_pkt;
141*be771a7bSCy Schubert 	/** store blocked packet, a packet that could not be sent on the
142*be771a7bSCy Schubert 	 * nonblocking socket. */
143*be771a7bSCy Schubert 	struct sldns_buffer* blocked_pkt;
144*be771a7bSCy Schubert 	/** ecn info for the blocked packet */
145*be771a7bSCy Schubert 	struct ngtcp2_pkt_info blocked_pkt_pi;
146*be771a7bSCy Schubert 	/** the congestion control algorithm */
147*be771a7bSCy Schubert 	ngtcp2_cc_algo cc_algo;
148*be771a7bSCy Schubert 	/** the transport parameters file, for early data transmission */
149*be771a7bSCy Schubert 	const char* transport_file;
150*be771a7bSCy Schubert 	/** the tls session file, for session resumption */
151*be771a7bSCy Schubert 	const char* session_file;
152*be771a7bSCy Schubert 	/** if early data is enabled for the connection */
153*be771a7bSCy Schubert 	int early_data_enabled;
154*be771a7bSCy Schubert 	/** how quiet is the output */
155*be771a7bSCy Schubert 	int quiet;
156*be771a7bSCy Schubert 	/** the configured port for the destination */
157*be771a7bSCy Schubert 	int port;
158*be771a7bSCy Schubert };
159*be771a7bSCy Schubert 
160*be771a7bSCy Schubert /** the local client stream list, for appending streams to */
161*be771a7bSCy Schubert struct doq_client_stream_list {
162*be771a7bSCy Schubert 	/** first and last members of the list */
163*be771a7bSCy Schubert 	struct doq_client_stream* first, *last;
164*be771a7bSCy Schubert };
165*be771a7bSCy Schubert 
166*be771a7bSCy Schubert /** the local client data for a DoQ stream */
167*be771a7bSCy Schubert struct doq_client_stream {
168*be771a7bSCy Schubert 	/** next stream in list, and prev in list */
169*be771a7bSCy Schubert 	struct doq_client_stream* next, *prev;
170*be771a7bSCy Schubert 	/** the data buffer */
171*be771a7bSCy Schubert 	uint8_t* data;
172*be771a7bSCy Schubert 	/** length of the data buffer */
173*be771a7bSCy Schubert 	size_t data_len;
174*be771a7bSCy Schubert 	/** if the client query has a stream, that is active, associated with
175*be771a7bSCy Schubert 	 * it. The stream_id is in stream_id. */
176*be771a7bSCy Schubert 	int has_stream;
177*be771a7bSCy Schubert 	/** the stream id */
178*be771a7bSCy Schubert 	int64_t stream_id;
179*be771a7bSCy Schubert 	/** data written position */
180*be771a7bSCy Schubert 	size_t nwrite;
181*be771a7bSCy Schubert 	/** the data length for write, in network format */
182*be771a7bSCy Schubert 	uint16_t data_tcplen;
183*be771a7bSCy Schubert 	/** if the write of the query data is done. That means the
184*be771a7bSCy Schubert 	 * write channel has FIN, is closed for writing. */
185*be771a7bSCy Schubert 	int write_is_done;
186*be771a7bSCy Schubert 	/** data read position */
187*be771a7bSCy Schubert 	size_t nread;
188*be771a7bSCy Schubert 	/** the answer length, in network byte order */
189*be771a7bSCy Schubert 	uint16_t answer_len;
190*be771a7bSCy Schubert 	/** the answer buffer */
191*be771a7bSCy Schubert 	struct sldns_buffer* answer;
192*be771a7bSCy Schubert 	/** the answer is complete */
193*be771a7bSCy Schubert 	int answer_is_complete;
194*be771a7bSCy Schubert 	/** the query has an error, it has no answer, or no complete answer */
195*be771a7bSCy Schubert 	int query_has_error;
196*be771a7bSCy Schubert 	/** if the query is done */
197*be771a7bSCy Schubert 	int query_is_done;
198*be771a7bSCy Schubert };
199*be771a7bSCy Schubert 
200*be771a7bSCy Schubert #ifndef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_CLIENT_CONTEXT
201*be771a7bSCy Schubert /** the quic method struct, must remain valid during the QUIC connection. */
202*be771a7bSCy Schubert static SSL_QUIC_METHOD quic_method;
203*be771a7bSCy Schubert #endif
204*be771a7bSCy Schubert 
205*be771a7bSCy Schubert /** Get the connection ngtcp2_conn from the ssl app data
206*be771a7bSCy Schubert  * ngtcp2_crypto_conn_ref */
207*be771a7bSCy Schubert static ngtcp2_conn* conn_ref_get_conn(ngtcp2_crypto_conn_ref* conn_ref)
208*be771a7bSCy Schubert {
209*be771a7bSCy Schubert 	struct doq_client_data* data = (struct doq_client_data*)
210*be771a7bSCy Schubert 		conn_ref->user_data;
211*be771a7bSCy Schubert 	return data->conn;
212*be771a7bSCy Schubert }
213*be771a7bSCy Schubert 
214*be771a7bSCy Schubert static void
215*be771a7bSCy Schubert set_app_data(SSL* ssl, struct doq_client_data* data)
216*be771a7bSCy Schubert {
217*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_CLIENT_CONTEXT
218*be771a7bSCy Schubert 	data->conn_ref.get_conn = &conn_ref_get_conn;
219*be771a7bSCy Schubert 	data->conn_ref.user_data = data;
220*be771a7bSCy Schubert 	SSL_set_app_data(ssl, &data->conn_ref);
221*be771a7bSCy Schubert #else
222*be771a7bSCy Schubert 	SSL_set_app_data(ssl, data);
223*be771a7bSCy Schubert #endif
224*be771a7bSCy Schubert }
225*be771a7bSCy Schubert 
226*be771a7bSCy Schubert static struct doq_client_data*
227*be771a7bSCy Schubert get_app_data(SSL* ssl)
228*be771a7bSCy Schubert {
229*be771a7bSCy Schubert 	struct doq_client_data* data;
230*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_CLIENT_CONTEXT
231*be771a7bSCy Schubert 	data = (struct doq_client_data*)((struct ngtcp2_crypto_conn_ref*)
232*be771a7bSCy Schubert 		SSL_get_app_data(ssl))->user_data;
233*be771a7bSCy Schubert #else
234*be771a7bSCy Schubert 	data = (struct doq_client_data*) SSL_get_app_data(ssl);
235*be771a7bSCy Schubert #endif
236*be771a7bSCy Schubert 	return data;
237*be771a7bSCy Schubert }
238*be771a7bSCy Schubert 
239*be771a7bSCy Schubert 
240*be771a7bSCy Schubert 
241*be771a7bSCy Schubert /** write handle routine */
242*be771a7bSCy Schubert static void on_write(struct doq_client_data* data);
243*be771a7bSCy Schubert /** update the timer */
244*be771a7bSCy Schubert static void update_timer(struct doq_client_data* data);
245*be771a7bSCy Schubert /** disconnect we are done */
246*be771a7bSCy Schubert static void disconnect(struct doq_client_data* data);
247*be771a7bSCy Schubert /** fetch and write the transport file */
248*be771a7bSCy Schubert static void early_data_write_transport(struct doq_client_data* data);
249*be771a7bSCy Schubert 
250*be771a7bSCy Schubert /** usage of doqclient */
251*be771a7bSCy Schubert static void usage(char* argv[])
252*be771a7bSCy Schubert {
253*be771a7bSCy Schubert 	printf("usage: %s [options] name type class ...\n", argv[0]);
254*be771a7bSCy Schubert 	printf("	sends the name-type-class queries over "
255*be771a7bSCy Schubert 			"DNS-over-QUIC.\n");
256*be771a7bSCy Schubert 	printf("-s server	IP address to send the queries to, "
257*be771a7bSCy Schubert 			"default: 127.0.0.1\n");
258*be771a7bSCy Schubert 	printf("-p		Port to connect to, default: %d\n",
259*be771a7bSCy Schubert 		UNBOUND_DNS_OVER_QUIC_PORT);
260*be771a7bSCy Schubert 	printf("-v 		verbose output\n");
261*be771a7bSCy Schubert 	printf("-q 		quiet, short output of answer\n");
262*be771a7bSCy Schubert 	printf("-x file		transport file, for read/write of transport parameters.\n\t\tIf it exists, it is used to send early data. It is then\n\t\twritten to contain the last used transport parameters.\n\t\tAlso -y must be enabled for early data to succeed.\n");
263*be771a7bSCy Schubert 	printf("-y file		session file, for read/write of TLS session. If it exists,\n\t\tit is used for TLS session resumption. It is then written\n\t\tto contain the last session used.\n\t\tOn its own, without also -x, resumes TLS session.\n");
264*be771a7bSCy Schubert 	printf("-h 		This help text\n");
265*be771a7bSCy Schubert 	exit(1);
266*be771a7bSCy Schubert }
267*be771a7bSCy Schubert 
268*be771a7bSCy Schubert /** get the dest address */
269*be771a7bSCy Schubert static void
270*be771a7bSCy Schubert get_dest_addr(struct doq_client_data* data, const char* svr, int port)
271*be771a7bSCy Schubert {
272*be771a7bSCy Schubert 	if(!ipstrtoaddr(svr, port, &data->dest_addr, &data->dest_addr_len)) {
273*be771a7bSCy Schubert 		printf("fatal: bad server specs '%s'\n", svr);
274*be771a7bSCy Schubert 		exit(1);
275*be771a7bSCy Schubert 	}
276*be771a7bSCy Schubert }
277*be771a7bSCy Schubert 
278*be771a7bSCy Schubert /** open UDP socket to svr */
279*be771a7bSCy Schubert static int
280*be771a7bSCy Schubert open_svr_udp(struct doq_client_data* data)
281*be771a7bSCy Schubert {
282*be771a7bSCy Schubert 	int fd = -1;
283*be771a7bSCy Schubert 	int r;
284*be771a7bSCy Schubert 	fd = socket(addr_is_ip6(&data->dest_addr, data->dest_addr_len)?
285*be771a7bSCy Schubert 		PF_INET6:PF_INET, SOCK_DGRAM, 0);
286*be771a7bSCy Schubert 	if(fd == -1) {
287*be771a7bSCy Schubert 		perror("socket() error");
288*be771a7bSCy Schubert 		exit(1);
289*be771a7bSCy Schubert 	}
290*be771a7bSCy Schubert 	r = connect(fd, (struct sockaddr*)&data->dest_addr,
291*be771a7bSCy Schubert 		data->dest_addr_len);
292*be771a7bSCy Schubert 	if(r < 0 && r != EINPROGRESS) {
293*be771a7bSCy Schubert 		perror("connect() error");
294*be771a7bSCy Schubert 		exit(1);
295*be771a7bSCy Schubert 	}
296*be771a7bSCy Schubert 	fd_set_nonblock(fd);
297*be771a7bSCy Schubert 	return fd;
298*be771a7bSCy Schubert }
299*be771a7bSCy Schubert 
300*be771a7bSCy Schubert /** get the local address of the connection */
301*be771a7bSCy Schubert static void
302*be771a7bSCy Schubert get_local_addr(struct doq_client_data* data)
303*be771a7bSCy Schubert {
304*be771a7bSCy Schubert 	memset(&data->local_addr, 0, sizeof(data->local_addr));
305*be771a7bSCy Schubert 	data->local_addr_len = (socklen_t)sizeof(data->local_addr);
306*be771a7bSCy Schubert 	if(getsockname(data->fd, (struct sockaddr*)&data->local_addr,
307*be771a7bSCy Schubert 		&data->local_addr_len) == -1) {
308*be771a7bSCy Schubert 		perror("getsockname() error");
309*be771a7bSCy Schubert 		exit(1);
310*be771a7bSCy Schubert 	}
311*be771a7bSCy Schubert 	log_addr(1, "local_addr", &data->local_addr, data->local_addr_len);
312*be771a7bSCy Schubert 	log_addr(1, "dest_addr", &data->dest_addr, data->dest_addr_len);
313*be771a7bSCy Schubert }
314*be771a7bSCy Schubert 
315*be771a7bSCy Schubert static sldns_buffer*
316*be771a7bSCy Schubert make_query(char* qname, char* qtype, char* qclass)
317*be771a7bSCy Schubert {
318*be771a7bSCy Schubert 	struct query_info qinfo;
319*be771a7bSCy Schubert 	struct edns_data edns;
320*be771a7bSCy Schubert 	sldns_buffer* buf = sldns_buffer_new(65553);
321*be771a7bSCy Schubert 	if(!buf) fatal_exit("out of memory");
322*be771a7bSCy Schubert 	qinfo.qname = sldns_str2wire_dname(qname, &qinfo.qname_len);
323*be771a7bSCy Schubert 	if(!qinfo.qname) {
324*be771a7bSCy Schubert 		printf("cannot parse query name: '%s'\n", qname);
325*be771a7bSCy Schubert 		exit(1);
326*be771a7bSCy Schubert 	}
327*be771a7bSCy Schubert 
328*be771a7bSCy Schubert 	qinfo.qtype = sldns_get_rr_type_by_name(qtype);
329*be771a7bSCy Schubert 	qinfo.qclass = sldns_get_rr_class_by_name(qclass);
330*be771a7bSCy Schubert 	qinfo.local_alias = NULL;
331*be771a7bSCy Schubert 
332*be771a7bSCy Schubert 	qinfo_query_encode(buf, &qinfo); /* flips buffer */
333*be771a7bSCy Schubert 	free(qinfo.qname);
334*be771a7bSCy Schubert 	sldns_buffer_write_u16_at(buf, 0, 0x0000);
335*be771a7bSCy Schubert 	sldns_buffer_write_u16_at(buf, 2, BIT_RD);
336*be771a7bSCy Schubert 	memset(&edns, 0, sizeof(edns));
337*be771a7bSCy Schubert 	edns.edns_present = 1;
338*be771a7bSCy Schubert 	edns.bits = EDNS_DO;
339*be771a7bSCy Schubert 	edns.udp_size = 4096;
340*be771a7bSCy Schubert 	if(sldns_buffer_capacity(buf) >=
341*be771a7bSCy Schubert 		sldns_buffer_limit(buf)+calc_edns_field_size(&edns))
342*be771a7bSCy Schubert 		attach_edns_record(buf, &edns);
343*be771a7bSCy Schubert 	return buf;
344*be771a7bSCy Schubert }
345*be771a7bSCy Schubert 
346*be771a7bSCy Schubert /** create client stream structure */
347*be771a7bSCy Schubert static struct doq_client_stream*
348*be771a7bSCy Schubert client_stream_create(struct sldns_buffer* query_data)
349*be771a7bSCy Schubert {
350*be771a7bSCy Schubert 	struct doq_client_stream* str = calloc(1, sizeof(*str));
351*be771a7bSCy Schubert 	if(!str)
352*be771a7bSCy Schubert 		fatal_exit("calloc failed: out of memory");
353*be771a7bSCy Schubert 	str->data = memdup(sldns_buffer_begin(query_data),
354*be771a7bSCy Schubert 		sldns_buffer_limit(query_data));
355*be771a7bSCy Schubert 	if(!str->data)
356*be771a7bSCy Schubert 		fatal_exit("alloc data failed: out of memory");
357*be771a7bSCy Schubert 	str->data_len = sldns_buffer_limit(query_data);
358*be771a7bSCy Schubert 	str->stream_id = -1;
359*be771a7bSCy Schubert 	return str;
360*be771a7bSCy Schubert }
361*be771a7bSCy Schubert 
362*be771a7bSCy Schubert /** free client stream structure */
363*be771a7bSCy Schubert static void
364*be771a7bSCy Schubert client_stream_free(struct doq_client_stream* str)
365*be771a7bSCy Schubert {
366*be771a7bSCy Schubert 	if(!str)
367*be771a7bSCy Schubert 		return;
368*be771a7bSCy Schubert 	free(str->data);
369*be771a7bSCy Schubert 	sldns_buffer_free(str->answer);
370*be771a7bSCy Schubert 	free(str);
371*be771a7bSCy Schubert }
372*be771a7bSCy Schubert 
373*be771a7bSCy Schubert /** setup the stream to start the write process */
374*be771a7bSCy Schubert static void
375*be771a7bSCy Schubert client_stream_start_setup(struct doq_client_stream* str, int64_t stream_id)
376*be771a7bSCy Schubert {
377*be771a7bSCy Schubert 	str->has_stream = 1;
378*be771a7bSCy Schubert 	str->stream_id = stream_id;
379*be771a7bSCy Schubert 	str->nwrite = 0;
380*be771a7bSCy Schubert 	str->nread = 0;
381*be771a7bSCy Schubert 	str->answer_len = 0;
382*be771a7bSCy Schubert 	str->query_is_done = 0;
383*be771a7bSCy Schubert 	str->answer_is_complete = 0;
384*be771a7bSCy Schubert 	str->query_has_error = 0;
385*be771a7bSCy Schubert 	if(str->answer) {
386*be771a7bSCy Schubert 		sldns_buffer_free(str->answer);
387*be771a7bSCy Schubert 		str->answer = NULL;
388*be771a7bSCy Schubert 	}
389*be771a7bSCy Schubert }
390*be771a7bSCy Schubert 
391*be771a7bSCy Schubert /** Return string for log purposes with query name. */
392*be771a7bSCy Schubert static char*
393*be771a7bSCy Schubert client_stream_string(struct doq_client_stream* str)
394*be771a7bSCy Schubert {
395*be771a7bSCy Schubert 	char* s;
396*be771a7bSCy Schubert 	size_t dname_len;
397*be771a7bSCy Schubert 	char dname[256], tpstr[32], result[256+32+16];
398*be771a7bSCy Schubert 	uint16_t tp;
399*be771a7bSCy Schubert 	if(str->data_len <= LDNS_HEADER_SIZE) {
400*be771a7bSCy Schubert 		s = strdup("query_with_no_question");
401*be771a7bSCy Schubert 		if(!s)
402*be771a7bSCy Schubert 			fatal_exit("strdup failed: out of memory");
403*be771a7bSCy Schubert 		return s;
404*be771a7bSCy Schubert 	}
405*be771a7bSCy Schubert 	dname_len = dname_valid(str->data+LDNS_HEADER_SIZE,
406*be771a7bSCy Schubert 		str->data_len-LDNS_HEADER_SIZE);
407*be771a7bSCy Schubert 	if(!dname_len) {
408*be771a7bSCy Schubert 		s = strdup("query_dname_not_valid");
409*be771a7bSCy Schubert 		if(!s)
410*be771a7bSCy Schubert 			fatal_exit("strdup failed: out of memory");
411*be771a7bSCy Schubert 		return s;
412*be771a7bSCy Schubert 	}
413*be771a7bSCy Schubert 	(void)sldns_wire2str_dname_buf(str->data+LDNS_HEADER_SIZE, dname_len,
414*be771a7bSCy Schubert 		dname, sizeof(dname));
415*be771a7bSCy Schubert 	tp = sldns_wirerr_get_type(str->data+LDNS_HEADER_SIZE,
416*be771a7bSCy Schubert 		str->data_len-LDNS_HEADER_SIZE, dname_len);
417*be771a7bSCy Schubert 	(void)sldns_wire2str_type_buf(tp, tpstr, sizeof(tpstr));
418*be771a7bSCy Schubert 	snprintf(result, sizeof(result), "%s %s", dname, tpstr);
419*be771a7bSCy Schubert 	s = strdup(result);
420*be771a7bSCy Schubert 	if(!s)
421*be771a7bSCy Schubert 		fatal_exit("strdup failed: out of memory");
422*be771a7bSCy Schubert 	return s;
423*be771a7bSCy Schubert }
424*be771a7bSCy Schubert 
425*be771a7bSCy Schubert /** create query stream list */
426*be771a7bSCy Schubert static struct doq_client_stream_list*
427*be771a7bSCy Schubert stream_list_create(void)
428*be771a7bSCy Schubert {
429*be771a7bSCy Schubert 	struct doq_client_stream_list* list = calloc(1, sizeof(*list));
430*be771a7bSCy Schubert 	if(!list)
431*be771a7bSCy Schubert 		fatal_exit("calloc failed: out of memory");
432*be771a7bSCy Schubert 	return list;
433*be771a7bSCy Schubert }
434*be771a7bSCy Schubert 
435*be771a7bSCy Schubert /** free the query stream list */
436*be771a7bSCy Schubert static void
437*be771a7bSCy Schubert stream_list_free(struct doq_client_stream_list* list)
438*be771a7bSCy Schubert {
439*be771a7bSCy Schubert 	struct doq_client_stream* str;
440*be771a7bSCy Schubert 	if(!list)
441*be771a7bSCy Schubert 		return;
442*be771a7bSCy Schubert 	str = list->first;
443*be771a7bSCy Schubert 	while(str) {
444*be771a7bSCy Schubert 		struct doq_client_stream* next = str->next;
445*be771a7bSCy Schubert 		client_stream_free(str);
446*be771a7bSCy Schubert 		str = next;
447*be771a7bSCy Schubert 	}
448*be771a7bSCy Schubert 	free(list);
449*be771a7bSCy Schubert }
450*be771a7bSCy Schubert 
451*be771a7bSCy Schubert /** append item to list */
452*be771a7bSCy Schubert static void
453*be771a7bSCy Schubert stream_list_append(struct doq_client_stream_list* list,
454*be771a7bSCy Schubert 	struct doq_client_stream* str)
455*be771a7bSCy Schubert {
456*be771a7bSCy Schubert 	if(list->last) {
457*be771a7bSCy Schubert 		str->prev = list->last;
458*be771a7bSCy Schubert 		list->last->next = str;
459*be771a7bSCy Schubert 	} else {
460*be771a7bSCy Schubert 		str->prev = NULL;
461*be771a7bSCy Schubert 		list->first = str;
462*be771a7bSCy Schubert 	}
463*be771a7bSCy Schubert 	str->next = NULL;
464*be771a7bSCy Schubert 	list->last = str;
465*be771a7bSCy Schubert }
466*be771a7bSCy Schubert 
467*be771a7bSCy Schubert /** delete the item from the list */
468*be771a7bSCy Schubert static void
469*be771a7bSCy Schubert stream_list_delete(struct doq_client_stream_list* list,
470*be771a7bSCy Schubert 	struct doq_client_stream* str)
471*be771a7bSCy Schubert {
472*be771a7bSCy Schubert 	if(str->next) {
473*be771a7bSCy Schubert 		str->next->prev = str->prev;
474*be771a7bSCy Schubert 	} else {
475*be771a7bSCy Schubert 		list->last = str->prev;
476*be771a7bSCy Schubert 	}
477*be771a7bSCy Schubert 	if(str->prev) {
478*be771a7bSCy Schubert 		str->prev->next = str->next;
479*be771a7bSCy Schubert 	} else {
480*be771a7bSCy Schubert 		list->first = str->next;
481*be771a7bSCy Schubert 	}
482*be771a7bSCy Schubert 	str->prev = NULL;
483*be771a7bSCy Schubert 	str->next = NULL;
484*be771a7bSCy Schubert }
485*be771a7bSCy Schubert 
486*be771a7bSCy Schubert /** move the item from list1 to list2 */
487*be771a7bSCy Schubert static void
488*be771a7bSCy Schubert stream_list_move(struct doq_client_stream* str,
489*be771a7bSCy Schubert 	struct doq_client_stream_list* list1,
490*be771a7bSCy Schubert 	struct doq_client_stream_list* list2)
491*be771a7bSCy Schubert {
492*be771a7bSCy Schubert 	stream_list_delete(list1, str);
493*be771a7bSCy Schubert 	stream_list_append(list2, str);
494*be771a7bSCy Schubert }
495*be771a7bSCy Schubert 
496*be771a7bSCy Schubert /** allocate stream data buffer, then answer length is complete */
497*be771a7bSCy Schubert static void
498*be771a7bSCy Schubert client_stream_datalen_complete(struct doq_client_stream* str)
499*be771a7bSCy Schubert {
500*be771a7bSCy Schubert 	verbose(1, "answer length %d", (int)ntohs(str->answer_len));
501*be771a7bSCy Schubert 	str->answer = sldns_buffer_new(ntohs(str->answer_len));
502*be771a7bSCy Schubert 	if(!str->answer)
503*be771a7bSCy Schubert 		fatal_exit("sldns_buffer_new failed: out of memory");
504*be771a7bSCy Schubert 	sldns_buffer_set_limit(str->answer, ntohs(str->answer_len));
505*be771a7bSCy Schubert }
506*be771a7bSCy Schubert 
507*be771a7bSCy Schubert /** print the answer rrs */
508*be771a7bSCy Schubert static void
509*be771a7bSCy Schubert print_answer_rrs(uint8_t* pkt, size_t pktlen)
510*be771a7bSCy Schubert {
511*be771a7bSCy Schubert 	char buf[65535];
512*be771a7bSCy Schubert 	char* str;
513*be771a7bSCy Schubert 	size_t str_len;
514*be771a7bSCy Schubert 	int i, qdcount, ancount;
515*be771a7bSCy Schubert 	uint8_t* data = pkt;
516*be771a7bSCy Schubert 	size_t data_len = pktlen;
517*be771a7bSCy Schubert 	int comprloop = 0;
518*be771a7bSCy Schubert 	if(data_len < LDNS_HEADER_SIZE)
519*be771a7bSCy Schubert 		return;
520*be771a7bSCy Schubert 	qdcount = LDNS_QDCOUNT(data);
521*be771a7bSCy Schubert 	ancount = LDNS_ANCOUNT(data);
522*be771a7bSCy Schubert 	data += LDNS_HEADER_SIZE;
523*be771a7bSCy Schubert 	data_len -= LDNS_HEADER_SIZE;
524*be771a7bSCy Schubert 
525*be771a7bSCy Schubert 	for(i=0; i<qdcount; i++) {
526*be771a7bSCy Schubert 		str = buf;
527*be771a7bSCy Schubert 		str_len = sizeof(buf);
528*be771a7bSCy Schubert 		(void)sldns_wire2str_rrquestion_scan(&data, &data_len,
529*be771a7bSCy Schubert 			&str, &str_len, pkt, pktlen, &comprloop);
530*be771a7bSCy Schubert 	}
531*be771a7bSCy Schubert 	for(i=0; i<ancount; i++) {
532*be771a7bSCy Schubert 		str = buf;
533*be771a7bSCy Schubert 		str_len = sizeof(buf);
534*be771a7bSCy Schubert 		(void)sldns_wire2str_rr_scan(&data, &data_len, &str, &str_len,
535*be771a7bSCy Schubert 			pkt, pktlen, &comprloop);
536*be771a7bSCy Schubert 		/* terminate string */
537*be771a7bSCy Schubert 		if(str_len == 0)
538*be771a7bSCy Schubert 			buf[sizeof(buf)-1] = 0;
539*be771a7bSCy Schubert 		else	*str = 0;
540*be771a7bSCy Schubert 		printf("%s", buf);
541*be771a7bSCy Schubert 	}
542*be771a7bSCy Schubert }
543*be771a7bSCy Schubert 
544*be771a7bSCy Schubert /** short output of answer, short error or rcode or answer section RRs. */
545*be771a7bSCy Schubert static void
546*be771a7bSCy Schubert client_stream_print_short(struct doq_client_stream* str)
547*be771a7bSCy Schubert {
548*be771a7bSCy Schubert 	int rcode, ancount;
549*be771a7bSCy Schubert 	if(str->query_has_error) {
550*be771a7bSCy Schubert 		char* logs = client_stream_string(str);
551*be771a7bSCy Schubert 		printf("%s has error, there is no answer\n", logs);
552*be771a7bSCy Schubert 		free(logs);
553*be771a7bSCy Schubert 		return;
554*be771a7bSCy Schubert 	}
555*be771a7bSCy Schubert 	if(sldns_buffer_limit(str->answer) < LDNS_HEADER_SIZE) {
556*be771a7bSCy Schubert 		char* logs = client_stream_string(str);
557*be771a7bSCy Schubert 		printf("%s received short packet, smaller than header\n",
558*be771a7bSCy Schubert 			logs);
559*be771a7bSCy Schubert 		free(logs);
560*be771a7bSCy Schubert 		return;
561*be771a7bSCy Schubert 	}
562*be771a7bSCy Schubert 	rcode = LDNS_RCODE_WIRE(sldns_buffer_begin(str->answer));
563*be771a7bSCy Schubert 	if(rcode != 0) {
564*be771a7bSCy Schubert 		char* logs = client_stream_string(str);
565*be771a7bSCy Schubert 		char rc[16];
566*be771a7bSCy Schubert 		(void)sldns_wire2str_rcode_buf(rcode, rc, sizeof(rc));
567*be771a7bSCy Schubert 		printf("%s rcode %s\n", logs, rc);
568*be771a7bSCy Schubert 		free(logs);
569*be771a7bSCy Schubert 		return;
570*be771a7bSCy Schubert 	}
571*be771a7bSCy Schubert 	ancount = LDNS_ANCOUNT(sldns_buffer_begin(str->answer));
572*be771a7bSCy Schubert 	if(ancount == 0) {
573*be771a7bSCy Schubert 		char* logs = client_stream_string(str);
574*be771a7bSCy Schubert 		printf("%s nodata answer\n", logs);
575*be771a7bSCy Schubert 		free(logs);
576*be771a7bSCy Schubert 		return;
577*be771a7bSCy Schubert 	}
578*be771a7bSCy Schubert 	print_answer_rrs(sldns_buffer_begin(str->answer),
579*be771a7bSCy Schubert 		sldns_buffer_limit(str->answer));
580*be771a7bSCy Schubert }
581*be771a7bSCy Schubert 
582*be771a7bSCy Schubert /** print the stream output answer */
583*be771a7bSCy Schubert static void
584*be771a7bSCy Schubert client_stream_print_long(struct doq_client_data* data,
585*be771a7bSCy Schubert 	struct doq_client_stream* str)
586*be771a7bSCy Schubert {
587*be771a7bSCy Schubert 	char* s;
588*be771a7bSCy Schubert 	if(str->query_has_error) {
589*be771a7bSCy Schubert 		char* logs = client_stream_string(str);
590*be771a7bSCy Schubert 		printf("%s has error, there is no answer\n", logs);
591*be771a7bSCy Schubert 		free(logs);
592*be771a7bSCy Schubert 		return;
593*be771a7bSCy Schubert 	}
594*be771a7bSCy Schubert 	s = sldns_wire2str_pkt(sldns_buffer_begin(str->answer),
595*be771a7bSCy Schubert 		sldns_buffer_limit(str->answer));
596*be771a7bSCy Schubert 	printf("%s", (s?s:";sldns_wire2str_pkt failed\n"));
597*be771a7bSCy Schubert 	printf(";; SERVER: %s %d\n", data->svr, data->port);
598*be771a7bSCy Schubert 	free(s);
599*be771a7bSCy Schubert }
600*be771a7bSCy Schubert 
601*be771a7bSCy Schubert /** the stream has completed the data */
602*be771a7bSCy Schubert static void
603*be771a7bSCy Schubert client_stream_data_complete(struct doq_client_stream* str)
604*be771a7bSCy Schubert {
605*be771a7bSCy Schubert 	verbose(1, "received all answer content");
606*be771a7bSCy Schubert 	if(verbosity > 0) {
607*be771a7bSCy Schubert 		char* logs = client_stream_string(str);
608*be771a7bSCy Schubert 		char* s;
609*be771a7bSCy Schubert 		log_buf(1, "received answer", str->answer);
610*be771a7bSCy Schubert 		s = sldns_wire2str_pkt(sldns_buffer_begin(str->answer),
611*be771a7bSCy Schubert 			sldns_buffer_limit(str->answer));
612*be771a7bSCy Schubert 		if(!s) verbose(1, "could not sldns_wire2str_pkt");
613*be771a7bSCy Schubert 		else verbose(1, "query %s received:\n%s", logs, s);
614*be771a7bSCy Schubert 		free(s);
615*be771a7bSCy Schubert 		free(logs);
616*be771a7bSCy Schubert 	}
617*be771a7bSCy Schubert 	str->answer_is_complete = 1;
618*be771a7bSCy Schubert }
619*be771a7bSCy Schubert 
620*be771a7bSCy Schubert /** the stream has completed but with an error */
621*be771a7bSCy Schubert static void
622*be771a7bSCy Schubert client_stream_answer_error(struct doq_client_stream* str)
623*be771a7bSCy Schubert {
624*be771a7bSCy Schubert 	if(verbosity > 0) {
625*be771a7bSCy Schubert 		char* logs = client_stream_string(str);
626*be771a7bSCy Schubert 		if(str->answer)
627*be771a7bSCy Schubert 			verbose(1, "query %s has an error. received %d/%d bytes.",
628*be771a7bSCy Schubert 				logs, (int)sldns_buffer_position(str->answer),
629*be771a7bSCy Schubert 				(int)sldns_buffer_limit(str->answer));
630*be771a7bSCy Schubert 		else
631*be771a7bSCy Schubert 			verbose(1, "query %s has an error. received no data.",
632*be771a7bSCy Schubert 				logs);
633*be771a7bSCy Schubert 		free(logs);
634*be771a7bSCy Schubert 	}
635*be771a7bSCy Schubert 	str->query_has_error = 1;
636*be771a7bSCy Schubert }
637*be771a7bSCy Schubert 
638*be771a7bSCy Schubert /** receive data for a stream */
639*be771a7bSCy Schubert static void
640*be771a7bSCy Schubert client_stream_recv_data(struct doq_client_stream* str, const uint8_t* data,
641*be771a7bSCy Schubert 	size_t datalen)
642*be771a7bSCy Schubert {
643*be771a7bSCy Schubert 	int got_data = 0;
644*be771a7bSCy Schubert 	/* read the tcplength uint16_t at the start of the DNS message */
645*be771a7bSCy Schubert 	if(str->nread < 2) {
646*be771a7bSCy Schubert 		size_t to_move = datalen;
647*be771a7bSCy Schubert 		if(datalen > 2-str->nread)
648*be771a7bSCy Schubert 			to_move = 2-str->nread;
649*be771a7bSCy Schubert 		memmove(((uint8_t*)&str->answer_len)+str->nread, data,
650*be771a7bSCy Schubert 			to_move);
651*be771a7bSCy Schubert 		str->nread += to_move;
652*be771a7bSCy Schubert 		data += to_move;
653*be771a7bSCy Schubert 		datalen -= to_move;
654*be771a7bSCy Schubert 		if(str->nread == 2) {
655*be771a7bSCy Schubert 			/* we can allocate the data buffer */
656*be771a7bSCy Schubert 			client_stream_datalen_complete(str);
657*be771a7bSCy Schubert 		}
658*be771a7bSCy Schubert 	}
659*be771a7bSCy Schubert 	/* if we have data bytes */
660*be771a7bSCy Schubert 	if(datalen > 0) {
661*be771a7bSCy Schubert 		size_t to_write = datalen;
662*be771a7bSCy Schubert 		if(datalen > sldns_buffer_remaining(str->answer))
663*be771a7bSCy Schubert 			to_write = sldns_buffer_remaining(str->answer);
664*be771a7bSCy Schubert 		if(to_write > 0) {
665*be771a7bSCy Schubert 			sldns_buffer_write(str->answer, data, to_write);
666*be771a7bSCy Schubert 			str->nread += to_write;
667*be771a7bSCy Schubert 			data += to_write;
668*be771a7bSCy Schubert 			datalen -= to_write;
669*be771a7bSCy Schubert 			got_data = 1;
670*be771a7bSCy Schubert 		}
671*be771a7bSCy Schubert 	}
672*be771a7bSCy Schubert 	/* extra received bytes after end? */
673*be771a7bSCy Schubert 	if(datalen > 0) {
674*be771a7bSCy Schubert 		verbose(1, "extra bytes after end of DNS length");
675*be771a7bSCy Schubert 		if(verbosity > 0)
676*be771a7bSCy Schubert 			log_hex("extradata", (void*)data, datalen);
677*be771a7bSCy Schubert 	}
678*be771a7bSCy Schubert 	/* are we done with it? */
679*be771a7bSCy Schubert 	if(got_data && str->nread >= (size_t)(ntohs(str->answer_len))+2) {
680*be771a7bSCy Schubert 		client_stream_data_complete(str);
681*be771a7bSCy Schubert 	}
682*be771a7bSCy Schubert }
683*be771a7bSCy Schubert 
684*be771a7bSCy Schubert /** receive FIN from remote end on client stream, no more data to be
685*be771a7bSCy Schubert  * received on the stream. */
686*be771a7bSCy Schubert static void
687*be771a7bSCy Schubert client_stream_recv_fin(struct doq_client_data* data,
688*be771a7bSCy Schubert 	struct doq_client_stream* str, int is_fin)
689*be771a7bSCy Schubert {
690*be771a7bSCy Schubert 	if(verbosity > 0) {
691*be771a7bSCy Schubert 		char* logs = client_stream_string(str);
692*be771a7bSCy Schubert 		if(is_fin)
693*be771a7bSCy Schubert 			verbose(1, "query %s: received FIN from remote", logs);
694*be771a7bSCy Schubert 		else
695*be771a7bSCy Schubert 			verbose(1, "query %s: stream reset from remote", logs);
696*be771a7bSCy Schubert 		free(logs);
697*be771a7bSCy Schubert 	}
698*be771a7bSCy Schubert 	if(str->write_is_done)
699*be771a7bSCy Schubert 		stream_list_move(str, data->query_list_receive,
700*be771a7bSCy Schubert 			data->query_list_stop);
701*be771a7bSCy Schubert 	else
702*be771a7bSCy Schubert 		stream_list_move(str, data->query_list_send,
703*be771a7bSCy Schubert 			data->query_list_stop);
704*be771a7bSCy Schubert 	if(!str->answer_is_complete) {
705*be771a7bSCy Schubert 		client_stream_answer_error(str);
706*be771a7bSCy Schubert 	}
707*be771a7bSCy Schubert 	str->query_is_done = 1;
708*be771a7bSCy Schubert 	if(data->quiet)
709*be771a7bSCy Schubert 		client_stream_print_short(str);
710*be771a7bSCy Schubert 	else client_stream_print_long(data, str);
711*be771a7bSCy Schubert 	if(data->query_list_send->first==NULL &&
712*be771a7bSCy Schubert 		data->query_list_receive->first==NULL)
713*be771a7bSCy Schubert 		disconnect(data);
714*be771a7bSCy Schubert }
715*be771a7bSCy Schubert 
716*be771a7bSCy Schubert /** fill a buffer with random data */
717*be771a7bSCy Schubert static void fill_rand(struct ub_randstate* rnd, uint8_t* buf, size_t len)
718*be771a7bSCy Schubert {
719*be771a7bSCy Schubert 	if(RAND_bytes(buf, len) != 1) {
720*be771a7bSCy Schubert 		size_t i;
721*be771a7bSCy Schubert 		for(i=0; i<len; i++)
722*be771a7bSCy Schubert 			buf[i] = ub_random(rnd)&0xff;
723*be771a7bSCy Schubert 	}
724*be771a7bSCy Schubert }
725*be771a7bSCy Schubert 
726*be771a7bSCy Schubert /** create the static secret */
727*be771a7bSCy Schubert static void generate_static_secret(struct doq_client_data* data, size_t len)
728*be771a7bSCy Schubert {
729*be771a7bSCy Schubert 	data->static_secret_data = malloc(len);
730*be771a7bSCy Schubert 	if(!data->static_secret_data)
731*be771a7bSCy Schubert 		fatal_exit("malloc failed: out of memory");
732*be771a7bSCy Schubert 	data->static_secret_size = len;
733*be771a7bSCy Schubert 	fill_rand(data->rnd, data->static_secret_data, len);
734*be771a7bSCy Schubert }
735*be771a7bSCy Schubert 
736*be771a7bSCy Schubert /** fill cid structure with random data */
737*be771a7bSCy Schubert static void cid_randfill(struct ngtcp2_cid* cid, size_t datalen,
738*be771a7bSCy Schubert 	struct ub_randstate* rnd)
739*be771a7bSCy Schubert {
740*be771a7bSCy Schubert 	uint8_t buf[32];
741*be771a7bSCy Schubert 	if(datalen > sizeof(buf))
742*be771a7bSCy Schubert 		datalen = sizeof(buf);
743*be771a7bSCy Schubert 	fill_rand(rnd, buf, datalen);
744*be771a7bSCy Schubert 	ngtcp2_cid_init(cid, buf, datalen);
745*be771a7bSCy Schubert }
746*be771a7bSCy Schubert 
747*be771a7bSCy Schubert /** send buf on the client stream */
748*be771a7bSCy Schubert static int
749*be771a7bSCy Schubert client_bidi_stream(struct doq_client_data* data, int64_t* ret_stream_id,
750*be771a7bSCy Schubert 	void* stream_user_data)
751*be771a7bSCy Schubert {
752*be771a7bSCy Schubert 	int64_t stream_id;
753*be771a7bSCy Schubert 	int rv;
754*be771a7bSCy Schubert 
755*be771a7bSCy Schubert 	/* open new bidirectional stream */
756*be771a7bSCy Schubert 	rv = ngtcp2_conn_open_bidi_stream(data->conn, &stream_id,
757*be771a7bSCy Schubert 		stream_user_data);
758*be771a7bSCy Schubert 	if(rv != 0) {
759*be771a7bSCy Schubert 		if(rv == NGTCP2_ERR_STREAM_ID_BLOCKED) {
760*be771a7bSCy Schubert 			/* no bidi stream count for this new stream */
761*be771a7bSCy Schubert 			return 0;
762*be771a7bSCy Schubert 		}
763*be771a7bSCy Schubert 		fatal_exit("could not ngtcp2_conn_open_bidi_stream: %s",
764*be771a7bSCy Schubert 			ngtcp2_strerror(rv));
765*be771a7bSCy Schubert 	}
766*be771a7bSCy Schubert 	*ret_stream_id = stream_id;
767*be771a7bSCy Schubert 	return 1;
768*be771a7bSCy Schubert }
769*be771a7bSCy Schubert 
770*be771a7bSCy Schubert /** See if we can start query streams, by creating bidirectional streams
771*be771a7bSCy Schubert  * on the QUIC transport for them. */
772*be771a7bSCy Schubert static void
773*be771a7bSCy Schubert query_streams_start(struct doq_client_data* data)
774*be771a7bSCy Schubert {
775*be771a7bSCy Schubert 	while(data->query_list_start->first) {
776*be771a7bSCy Schubert 		struct doq_client_stream* str = data->query_list_start->first;
777*be771a7bSCy Schubert 		int64_t stream_id = 0;
778*be771a7bSCy Schubert 		if(!client_bidi_stream(data, &stream_id, str)) {
779*be771a7bSCy Schubert 			/* no more bidi streams allowed */
780*be771a7bSCy Schubert 			break;
781*be771a7bSCy Schubert 		}
782*be771a7bSCy Schubert 		if(verbosity > 0) {
783*be771a7bSCy Schubert 			char* logs = client_stream_string(str);
784*be771a7bSCy Schubert 			verbose(1, "query %s start on bidi stream id %lld",
785*be771a7bSCy Schubert 				logs, (long long int)stream_id);
786*be771a7bSCy Schubert 			free(logs);
787*be771a7bSCy Schubert 		}
788*be771a7bSCy Schubert 		/* setup the stream to start */
789*be771a7bSCy Schubert 		client_stream_start_setup(str, stream_id);
790*be771a7bSCy Schubert 		/* move the query entry to the send list to write it */
791*be771a7bSCy Schubert 		stream_list_move(str, data->query_list_start,
792*be771a7bSCy Schubert 			data->query_list_send);
793*be771a7bSCy Schubert 	}
794*be771a7bSCy Schubert }
795*be771a7bSCy Schubert 
796*be771a7bSCy Schubert /** the rand callback routine from ngtcp2 */
797*be771a7bSCy Schubert static void rand_cb(uint8_t* dest, size_t destlen,
798*be771a7bSCy Schubert 	const ngtcp2_rand_ctx* rand_ctx)
799*be771a7bSCy Schubert {
800*be771a7bSCy Schubert 	struct ub_randstate* rnd = (struct ub_randstate*)
801*be771a7bSCy Schubert 		rand_ctx->native_handle;
802*be771a7bSCy Schubert 	fill_rand(rnd, dest, destlen);
803*be771a7bSCy Schubert }
804*be771a7bSCy Schubert 
805*be771a7bSCy Schubert /** the get_new_connection_id callback routine from ngtcp2 */
806*be771a7bSCy Schubert static int get_new_connection_id_cb(struct ngtcp2_conn* ATTR_UNUSED(conn),
807*be771a7bSCy Schubert 	struct ngtcp2_cid* cid, uint8_t* token, size_t cidlen, void* user_data)
808*be771a7bSCy Schubert {
809*be771a7bSCy Schubert 	struct doq_client_data* data = (struct doq_client_data*)user_data;
810*be771a7bSCy Schubert 	cid_randfill(cid, cidlen, data->rnd);
811*be771a7bSCy Schubert 	if(ngtcp2_crypto_generate_stateless_reset_token(token,
812*be771a7bSCy Schubert 		data->static_secret_data, data->static_secret_size, cid) != 0)
813*be771a7bSCy Schubert 		return NGTCP2_ERR_CALLBACK_FAILURE;
814*be771a7bSCy Schubert 	return 0;
815*be771a7bSCy Schubert }
816*be771a7bSCy Schubert 
817*be771a7bSCy Schubert /** handle that early data is rejected */
818*be771a7bSCy Schubert static void
819*be771a7bSCy Schubert early_data_is_rejected(struct doq_client_data* data)
820*be771a7bSCy Schubert {
821*be771a7bSCy Schubert 	int rv;
822*be771a7bSCy Schubert 	verbose(1, "early data was rejected by the server");
823*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CONN_TLS_EARLY_DATA_REJECTED
824*be771a7bSCy Schubert 	rv = ngtcp2_conn_tls_early_data_rejected(data->conn);
825*be771a7bSCy Schubert #else
826*be771a7bSCy Schubert 	rv = ngtcp2_conn_early_data_rejected(data->conn);
827*be771a7bSCy Schubert #endif
828*be771a7bSCy Schubert 	if(rv != 0) {
829*be771a7bSCy Schubert 		log_err("ngtcp2_conn_early_data_rejected failed: %s",
830*be771a7bSCy Schubert 			ngtcp2_strerror(rv));
831*be771a7bSCy Schubert 		return;
832*be771a7bSCy Schubert 	}
833*be771a7bSCy Schubert 	/* move the streams back to the start state */
834*be771a7bSCy Schubert 	while(data->query_list_send->first) {
835*be771a7bSCy Schubert 		struct doq_client_stream* str = data->query_list_send->first;
836*be771a7bSCy Schubert 		/* move it back to the start list */
837*be771a7bSCy Schubert 		stream_list_move(str, data->query_list_send,
838*be771a7bSCy Schubert 			data->query_list_start);
839*be771a7bSCy Schubert 		str->has_stream = 0;
840*be771a7bSCy Schubert 		/* remove stream id */
841*be771a7bSCy Schubert 		str->stream_id = 0;
842*be771a7bSCy Schubert 		/* initialise other members, in case they are altered,
843*be771a7bSCy Schubert 		 * but unlikely, because early streams are rejected. */
844*be771a7bSCy Schubert 		str->nwrite = 0;
845*be771a7bSCy Schubert 		str->nread = 0;
846*be771a7bSCy Schubert 		str->answer_len = 0;
847*be771a7bSCy Schubert 		str->query_is_done = 0;
848*be771a7bSCy Schubert 		str->answer_is_complete = 0;
849*be771a7bSCy Schubert 		str->query_has_error = 0;
850*be771a7bSCy Schubert 		if(str->answer) {
851*be771a7bSCy Schubert 			sldns_buffer_free(str->answer);
852*be771a7bSCy Schubert 			str->answer = NULL;
853*be771a7bSCy Schubert 		}
854*be771a7bSCy Schubert 	}
855*be771a7bSCy Schubert }
856*be771a7bSCy Schubert 
857*be771a7bSCy Schubert /** the handshake completed callback from ngtcp2 */
858*be771a7bSCy Schubert static int
859*be771a7bSCy Schubert handshake_completed(ngtcp2_conn* ATTR_UNUSED(conn), void* user_data)
860*be771a7bSCy Schubert {
861*be771a7bSCy Schubert 	struct doq_client_data* data = (struct doq_client_data*)user_data;
862*be771a7bSCy Schubert 	verbose(1, "handshake_completed callback");
863*be771a7bSCy Schubert 	verbose(1, "ngtcp2_conn_get_max_data_left is %d",
864*be771a7bSCy Schubert 		(int)ngtcp2_conn_get_max_data_left(data->conn));
865*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CONN_GET_MAX_LOCAL_STREAMS_UNI
866*be771a7bSCy Schubert 	verbose(1, "ngtcp2_conn_get_max_local_streams_uni is %d",
867*be771a7bSCy Schubert 		(int)ngtcp2_conn_get_max_local_streams_uni(data->conn));
868*be771a7bSCy Schubert #endif
869*be771a7bSCy Schubert 	verbose(1, "ngtcp2_conn_get_streams_uni_left is %d",
870*be771a7bSCy Schubert 		(int)ngtcp2_conn_get_streams_uni_left(data->conn));
871*be771a7bSCy Schubert 	verbose(1, "ngtcp2_conn_get_streams_bidi_left is %d",
872*be771a7bSCy Schubert 		(int)ngtcp2_conn_get_streams_bidi_left(data->conn));
873*be771a7bSCy Schubert 	verbose(1, "negotiated cipher name is %s",
874*be771a7bSCy Schubert 		SSL_get_cipher_name(data->ssl));
875*be771a7bSCy Schubert 	if(verbosity > 0) {
876*be771a7bSCy Schubert 		const unsigned char* alpn = NULL;
877*be771a7bSCy Schubert 		unsigned int alpnlen = 0;
878*be771a7bSCy Schubert 		char alpnstr[128];
879*be771a7bSCy Schubert 		SSL_get0_alpn_selected(data->ssl, &alpn, &alpnlen);
880*be771a7bSCy Schubert 		if(alpnlen > sizeof(alpnstr)-1)
881*be771a7bSCy Schubert 			alpnlen = sizeof(alpnstr)-1;
882*be771a7bSCy Schubert 		memmove(alpnstr, alpn, alpnlen);
883*be771a7bSCy Schubert 		alpnstr[alpnlen]=0;
884*be771a7bSCy Schubert 		verbose(1, "negotiated ALPN is '%s'", alpnstr);
885*be771a7bSCy Schubert 	}
886*be771a7bSCy Schubert 	/* The SSL_get_early_data_status call works after the handshake
887*be771a7bSCy Schubert 	 * completes. */
888*be771a7bSCy Schubert 	if(data->early_data_enabled) {
889*be771a7bSCy Schubert 		if(SSL_get_early_data_status(data->ssl) !=
890*be771a7bSCy Schubert 			SSL_EARLY_DATA_ACCEPTED) {
891*be771a7bSCy Schubert 			early_data_is_rejected(data);
892*be771a7bSCy Schubert 		} else {
893*be771a7bSCy Schubert 			verbose(1, "early data was accepted by the server");
894*be771a7bSCy Schubert 		}
895*be771a7bSCy Schubert 	}
896*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_CLIENT_CONTEXT
897*be771a7bSCy Schubert 	if(data->transport_file) {
898*be771a7bSCy Schubert 		early_data_write_transport(data);
899*be771a7bSCy Schubert 	}
900*be771a7bSCy Schubert #endif
901*be771a7bSCy Schubert 	return 0;
902*be771a7bSCy Schubert }
903*be771a7bSCy Schubert 
904*be771a7bSCy Schubert /** the extend_max_local_streams_bidi callback from ngtcp2 */
905*be771a7bSCy Schubert static int
906*be771a7bSCy Schubert extend_max_local_streams_bidi(ngtcp2_conn* ATTR_UNUSED(conn),
907*be771a7bSCy Schubert 	uint64_t max_streams, void* user_data)
908*be771a7bSCy Schubert {
909*be771a7bSCy Schubert 	struct doq_client_data* data = (struct doq_client_data*)user_data;
910*be771a7bSCy Schubert 	verbose(1, "extend_max_local_streams_bidi callback, %d max_streams",
911*be771a7bSCy Schubert 		(int)max_streams);
912*be771a7bSCy Schubert 	verbose(1, "ngtcp2_conn_get_max_data_left is %d",
913*be771a7bSCy Schubert 		(int)ngtcp2_conn_get_max_data_left(data->conn));
914*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CONN_GET_MAX_LOCAL_STREAMS_UNI
915*be771a7bSCy Schubert 	verbose(1, "ngtcp2_conn_get_max_local_streams_uni is %d",
916*be771a7bSCy Schubert 		(int)ngtcp2_conn_get_max_local_streams_uni(data->conn));
917*be771a7bSCy Schubert #endif
918*be771a7bSCy Schubert 	verbose(1, "ngtcp2_conn_get_streams_uni_left is %d",
919*be771a7bSCy Schubert 		(int)ngtcp2_conn_get_streams_uni_left(data->conn));
920*be771a7bSCy Schubert 	verbose(1, "ngtcp2_conn_get_streams_bidi_left is %d",
921*be771a7bSCy Schubert 		(int)ngtcp2_conn_get_streams_bidi_left(data->conn));
922*be771a7bSCy Schubert 	query_streams_start(data);
923*be771a7bSCy Schubert 	return 0;
924*be771a7bSCy Schubert }
925*be771a7bSCy Schubert 
926*be771a7bSCy Schubert /** the recv_stream_data callback from ngtcp2 */
927*be771a7bSCy Schubert static int
928*be771a7bSCy Schubert recv_stream_data(ngtcp2_conn* ATTR_UNUSED(conn), uint32_t flags,
929*be771a7bSCy Schubert 	int64_t stream_id, uint64_t offset, const uint8_t* data,
930*be771a7bSCy Schubert 	size_t datalen, void* user_data, void* stream_user_data)
931*be771a7bSCy Schubert {
932*be771a7bSCy Schubert 	struct doq_client_data* doqdata = (struct doq_client_data*)user_data;
933*be771a7bSCy Schubert 	struct doq_client_stream* str = (struct doq_client_stream*)
934*be771a7bSCy Schubert 		stream_user_data;
935*be771a7bSCy Schubert 	verbose(1, "recv_stream_data stream %d offset %d datalen %d%s%s",
936*be771a7bSCy Schubert 		(int)stream_id, (int)offset, (int)datalen,
937*be771a7bSCy Schubert 		((flags&NGTCP2_STREAM_DATA_FLAG_FIN)!=0?" FIN":""),
938*be771a7bSCy Schubert #ifdef NGTCP2_STREAM_DATA_FLAG_0RTT
939*be771a7bSCy Schubert 		((flags&NGTCP2_STREAM_DATA_FLAG_0RTT)!=0?" 0RTT":"")
940*be771a7bSCy Schubert #else
941*be771a7bSCy Schubert 		((flags&NGTCP2_STREAM_DATA_FLAG_EARLY)!=0?" EARLY":"")
942*be771a7bSCy Schubert #endif
943*be771a7bSCy Schubert 		);
944*be771a7bSCy Schubert 	if(verbosity > 0)
945*be771a7bSCy Schubert 		log_hex("data", (void*)data, datalen);
946*be771a7bSCy Schubert 	if(verbosity > 0) {
947*be771a7bSCy Schubert 		char* logs = client_stream_string(str);
948*be771a7bSCy Schubert 		verbose(1, "the stream_user_data is %s stream id %d, nread %d",
949*be771a7bSCy Schubert 			logs, (int)str->stream_id, (int)str->nread);
950*be771a7bSCy Schubert 		free(logs);
951*be771a7bSCy Schubert 	}
952*be771a7bSCy Schubert 
953*be771a7bSCy Schubert 	/* append the data, if there is data */
954*be771a7bSCy Schubert 	if(datalen > 0) {
955*be771a7bSCy Schubert 		client_stream_recv_data(str, data, datalen);
956*be771a7bSCy Schubert 	}
957*be771a7bSCy Schubert 	if((flags&NGTCP2_STREAM_DATA_FLAG_FIN)!=0) {
958*be771a7bSCy Schubert 		client_stream_recv_fin(doqdata, str, 1);
959*be771a7bSCy Schubert 	}
960*be771a7bSCy Schubert 	ngtcp2_conn_extend_max_stream_offset(doqdata->conn, stream_id, datalen);
961*be771a7bSCy Schubert 	ngtcp2_conn_extend_max_offset(doqdata->conn, datalen);
962*be771a7bSCy Schubert 	return 0;
963*be771a7bSCy Schubert }
964*be771a7bSCy Schubert 
965*be771a7bSCy Schubert /** the stream reset callback from ngtcp2 */
966*be771a7bSCy Schubert static int
967*be771a7bSCy Schubert stream_reset(ngtcp2_conn* ATTR_UNUSED(conn), int64_t stream_id,
968*be771a7bSCy Schubert 	uint64_t final_size, uint64_t app_error_code, void* user_data,
969*be771a7bSCy Schubert 	void* stream_user_data)
970*be771a7bSCy Schubert {
971*be771a7bSCy Schubert 	struct doq_client_data* doqdata = (struct doq_client_data*)user_data;
972*be771a7bSCy Schubert 	struct doq_client_stream* str = (struct doq_client_stream*)
973*be771a7bSCy Schubert 		stream_user_data;
974*be771a7bSCy Schubert 	verbose(1, "stream reset for stream %d final size %d app error code %d",
975*be771a7bSCy Schubert 		(int)stream_id, (int)final_size, (int)app_error_code);
976*be771a7bSCy Schubert 	client_stream_recv_fin(doqdata, str, 0);
977*be771a7bSCy Schubert 	return 0;
978*be771a7bSCy Schubert }
979*be771a7bSCy Schubert 
980*be771a7bSCy Schubert /** copy sockaddr into ngtcp2 addr */
981*be771a7bSCy Schubert static void
982*be771a7bSCy Schubert copy_ngaddr(struct ngtcp2_addr* ngaddr, struct sockaddr_storage* addr,
983*be771a7bSCy Schubert 	socklen_t addrlen)
984*be771a7bSCy Schubert {
985*be771a7bSCy Schubert 	if(addr_is_ip6(addr, addrlen)) {
986*be771a7bSCy Schubert #if defined(NGTCP2_USE_GENERIC_SOCKADDR) || defined(NGTCP2_USE_GENERIC_IPV6_SOCKADDR)
987*be771a7bSCy Schubert 		struct sockaddr_in* i6 = (struct sockaddr_in6*)addr;
988*be771a7bSCy Schubert 		struct ngtcp2_sockaddr_in6 a6;
989*be771a7bSCy Schubert 		ngaddr->addr = calloc(1, sizeof(a6));
990*be771a7bSCy Schubert 		if(!ngaddr->addr) fatal_exit("calloc failed: out of memory");
991*be771a7bSCy Schubert 		ngaddr->addrlen = sizeof(a6);
992*be771a7bSCy Schubert 		memset(&a6, 0, sizeof(a6));
993*be771a7bSCy Schubert 		a6.sin6_family = i6->sin6_family;
994*be771a7bSCy Schubert 		a6.sin6_port = i6->sin6_port;
995*be771a7bSCy Schubert 		a6.sin6_flowinfo = i6->sin6_flowinfo;
996*be771a7bSCy Schubert 		memmove(&a6.sin6_addr, i6->sin6_addr, sizeof(a6.sin6_addr);
997*be771a7bSCy Schubert 		a6.sin6_scope_id = i6->sin6_scope_id;
998*be771a7bSCy Schubert 		memmove(ngaddr->addr, &a6, sizeof(a6));
999*be771a7bSCy Schubert #else
1000*be771a7bSCy Schubert 		ngaddr->addr = (ngtcp2_sockaddr*)addr;
1001*be771a7bSCy Schubert 		ngaddr->addrlen = addrlen;
1002*be771a7bSCy Schubert #endif
1003*be771a7bSCy Schubert 	} else {
1004*be771a7bSCy Schubert #ifdef NGTCP2_USE_GENERIC_SOCKADDR
1005*be771a7bSCy Schubert 		struct sockaddr_in* i4 = (struct sockaddr_in*)addr;
1006*be771a7bSCy Schubert 		struct ngtcp2_sockaddr_in a4;
1007*be771a7bSCy Schubert 		ngaddr->addr = calloc(1, sizeof(a4));
1008*be771a7bSCy Schubert 		if(!ngaddr->addr) fatal_exit("calloc failed: out of memory");
1009*be771a7bSCy Schubert 		ngaddr->addrlen = sizeof(a4);
1010*be771a7bSCy Schubert 		memset(&a4, 0, sizeof(a4));
1011*be771a7bSCy Schubert 		a4.sin_family = i4->sin_family;
1012*be771a7bSCy Schubert 		a4.sin_port = i4->sin_port;
1013*be771a7bSCy Schubert 		memmove(&a4.sin_addr, i4->sin_addr, sizeof(a4.sin_addr);
1014*be771a7bSCy Schubert 		memmove(ngaddr->addr, &a4, sizeof(a4));
1015*be771a7bSCy Schubert #else
1016*be771a7bSCy Schubert 		ngaddr->addr = (ngtcp2_sockaddr*)addr;
1017*be771a7bSCy Schubert 		ngaddr->addrlen = addrlen;
1018*be771a7bSCy Schubert #endif
1019*be771a7bSCy Schubert 	}
1020*be771a7bSCy Schubert }
1021*be771a7bSCy Schubert 
1022*be771a7bSCy Schubert /** debug log printf for ngtcp2 connections */
1023*be771a7bSCy Schubert static void log_printf_for_doq(void* ATTR_UNUSED(user_data),
1024*be771a7bSCy Schubert 	const char* fmt, ...)
1025*be771a7bSCy Schubert {
1026*be771a7bSCy Schubert 	va_list ap;
1027*be771a7bSCy Schubert 	va_start(ap, fmt);
1028*be771a7bSCy Schubert 	fprintf(stderr, "libngtcp2: ");
1029*be771a7bSCy Schubert 	vfprintf(stderr, fmt, ap);
1030*be771a7bSCy Schubert 	va_end(ap);
1031*be771a7bSCy Schubert 	fprintf(stderr, "\n");
1032*be771a7bSCy Schubert }
1033*be771a7bSCy Schubert 
1034*be771a7bSCy Schubert /** get a timestamp in nanoseconds */
1035*be771a7bSCy Schubert static ngtcp2_tstamp get_timestamp_nanosec(void)
1036*be771a7bSCy Schubert {
1037*be771a7bSCy Schubert #ifdef CLOCK_REALTIME
1038*be771a7bSCy Schubert 	struct timespec tp;
1039*be771a7bSCy Schubert 	memset(&tp, 0, sizeof(tp));
1040*be771a7bSCy Schubert #ifdef CLOCK_MONOTONIC
1041*be771a7bSCy Schubert 	if(clock_gettime(CLOCK_MONOTONIC, &tp) == -1) {
1042*be771a7bSCy Schubert #endif
1043*be771a7bSCy Schubert 		if(clock_gettime(CLOCK_REALTIME, &tp) == -1) {
1044*be771a7bSCy Schubert 			log_err("clock_gettime failed: %s", strerror(errno));
1045*be771a7bSCy Schubert 		}
1046*be771a7bSCy Schubert #ifdef CLOCK_MONOTONIC
1047*be771a7bSCy Schubert 	}
1048*be771a7bSCy Schubert #endif
1049*be771a7bSCy Schubert 	return ((uint64_t)tp.tv_sec)*((uint64_t)1000000000) +
1050*be771a7bSCy Schubert 		((uint64_t)tp.tv_nsec);
1051*be771a7bSCy Schubert #else
1052*be771a7bSCy Schubert 	struct timeval tv;
1053*be771a7bSCy Schubert 	if(gettimeofday(&tv, NULL) < 0) {
1054*be771a7bSCy Schubert 		log_err("gettimeofday failed: %s", strerror(errno));
1055*be771a7bSCy Schubert 	}
1056*be771a7bSCy Schubert 	return ((uint64_t)tv.tv_sec)*((uint64_t)1000000000) +
1057*be771a7bSCy Schubert 		((uint64_t)tv.tv_usec)*((uint64_t)1000);
1058*be771a7bSCy Schubert #endif /* CLOCK_REALTIME */
1059*be771a7bSCy Schubert }
1060*be771a7bSCy Schubert 
1061*be771a7bSCy Schubert /** create ngtcp2 client connection and set up. */
1062*be771a7bSCy Schubert static struct ngtcp2_conn* conn_client_setup(struct doq_client_data* data)
1063*be771a7bSCy Schubert {
1064*be771a7bSCy Schubert 	struct ngtcp2_conn* conn = NULL;
1065*be771a7bSCy Schubert 	int rv;
1066*be771a7bSCy Schubert 	struct ngtcp2_cid dcid, scid;
1067*be771a7bSCy Schubert 	struct ngtcp2_path path;
1068*be771a7bSCy Schubert 	uint32_t client_chosen_version = NGTCP2_PROTO_VER_V1;
1069*be771a7bSCy Schubert 	struct ngtcp2_callbacks cbs;
1070*be771a7bSCy Schubert 	struct ngtcp2_settings settings;
1071*be771a7bSCy Schubert 	struct ngtcp2_transport_params params;
1072*be771a7bSCy Schubert 
1073*be771a7bSCy Schubert 	memset(&cbs, 0, sizeof(cbs));
1074*be771a7bSCy Schubert 	memset(&settings, 0, sizeof(settings));
1075*be771a7bSCy Schubert 	memset(&params, 0, sizeof(params));
1076*be771a7bSCy Schubert 	memset(&dcid, 0, sizeof(dcid));
1077*be771a7bSCy Schubert 	memset(&scid, 0, sizeof(scid));
1078*be771a7bSCy Schubert 	memset(&path, 0, sizeof(path));
1079*be771a7bSCy Schubert 
1080*be771a7bSCy Schubert 	data->quic_version = client_chosen_version;
1081*be771a7bSCy Schubert 	ngtcp2_settings_default(&settings);
1082*be771a7bSCy Schubert 	if(str_is_ip6(data->svr)) {
1083*be771a7bSCy Schubert #ifdef HAVE_STRUCT_NGTCP2_SETTINGS_MAX_TX_UDP_PAYLOAD_SIZE
1084*be771a7bSCy Schubert 		settings.max_tx_udp_payload_size = 1232;
1085*be771a7bSCy Schubert #else
1086*be771a7bSCy Schubert 		settings.max_udp_payload_size = 1232;
1087*be771a7bSCy Schubert #endif
1088*be771a7bSCy Schubert 	}
1089*be771a7bSCy Schubert 	settings.rand_ctx.native_handle = data->rnd;
1090*be771a7bSCy Schubert 	if(verbosity > 0) {
1091*be771a7bSCy Schubert 		/* make debug logs */
1092*be771a7bSCy Schubert 		settings.log_printf = log_printf_for_doq;
1093*be771a7bSCy Schubert 	}
1094*be771a7bSCy Schubert 	settings.initial_ts = get_timestamp_nanosec();
1095*be771a7bSCy Schubert 	ngtcp2_transport_params_default(&params);
1096*be771a7bSCy Schubert 	params.initial_max_stream_data_bidi_local = 256*1024;
1097*be771a7bSCy Schubert 	params.initial_max_stream_data_bidi_remote = 256*1024;
1098*be771a7bSCy Schubert 	params.initial_max_stream_data_uni = 256*1024;
1099*be771a7bSCy Schubert 	params.initial_max_data = 1024*1024;
1100*be771a7bSCy Schubert 	params.initial_max_streams_bidi = 0;
1101*be771a7bSCy Schubert 	params.initial_max_streams_uni = 100;
1102*be771a7bSCy Schubert 	params.max_idle_timeout = 30*NGTCP2_SECONDS;
1103*be771a7bSCy Schubert 	params.active_connection_id_limit = 7;
1104*be771a7bSCy Schubert 	cid_randfill(&dcid, 16, data->rnd);
1105*be771a7bSCy Schubert 	cid_randfill(&scid, 16, data->rnd);
1106*be771a7bSCy Schubert 	cbs.client_initial = ngtcp2_crypto_client_initial_cb;
1107*be771a7bSCy Schubert 	cbs.recv_crypto_data = ngtcp2_crypto_recv_crypto_data_cb;
1108*be771a7bSCy Schubert 	cbs.encrypt = ngtcp2_crypto_encrypt_cb;
1109*be771a7bSCy Schubert 	cbs.decrypt = ngtcp2_crypto_decrypt_cb;
1110*be771a7bSCy Schubert 	cbs.hp_mask = ngtcp2_crypto_hp_mask_cb;
1111*be771a7bSCy Schubert 	cbs.recv_retry = ngtcp2_crypto_recv_retry_cb;
1112*be771a7bSCy Schubert 	cbs.update_key = ngtcp2_crypto_update_key_cb;
1113*be771a7bSCy Schubert 	cbs.delete_crypto_aead_ctx = ngtcp2_crypto_delete_crypto_aead_ctx_cb;
1114*be771a7bSCy Schubert 	cbs.delete_crypto_cipher_ctx =
1115*be771a7bSCy Schubert 		ngtcp2_crypto_delete_crypto_cipher_ctx_cb;
1116*be771a7bSCy Schubert 	cbs.get_path_challenge_data = ngtcp2_crypto_get_path_challenge_data_cb;
1117*be771a7bSCy Schubert 	cbs.version_negotiation = ngtcp2_crypto_version_negotiation_cb;
1118*be771a7bSCy Schubert 	cbs.get_new_connection_id = get_new_connection_id_cb;
1119*be771a7bSCy Schubert 	cbs.handshake_completed = handshake_completed;
1120*be771a7bSCy Schubert 	cbs.extend_max_local_streams_bidi = extend_max_local_streams_bidi;
1121*be771a7bSCy Schubert 	cbs.rand = rand_cb;
1122*be771a7bSCy Schubert 	cbs.recv_stream_data = recv_stream_data;
1123*be771a7bSCy Schubert 	cbs.stream_reset = stream_reset;
1124*be771a7bSCy Schubert 	copy_ngaddr(&path.local, &data->local_addr, data->local_addr_len);
1125*be771a7bSCy Schubert 	copy_ngaddr(&path.remote, &data->dest_addr, data->dest_addr_len);
1126*be771a7bSCy Schubert 
1127*be771a7bSCy Schubert 	rv = ngtcp2_conn_client_new(&conn, &dcid, &scid, &path,
1128*be771a7bSCy Schubert 		client_chosen_version, &cbs, &settings, &params,
1129*be771a7bSCy Schubert 		NULL, /* ngtcp2_mem allocator, use default */
1130*be771a7bSCy Schubert 		data /* callback argument */);
1131*be771a7bSCy Schubert 	if(!conn) fatal_exit("could not ngtcp2_conn_client_new: %s",
1132*be771a7bSCy Schubert 		ngtcp2_strerror(rv));
1133*be771a7bSCy Schubert 	data->cc_algo = settings.cc_algo;
1134*be771a7bSCy Schubert 	return conn;
1135*be771a7bSCy Schubert }
1136*be771a7bSCy Schubert 
1137*be771a7bSCy Schubert #ifndef HAVE_NGTCP2_CONN_ENCODE_0RTT_TRANSPORT_PARAMS
1138*be771a7bSCy Schubert /** write the transport file */
1139*be771a7bSCy Schubert static void
1140*be771a7bSCy Schubert transport_file_write(const char* file, struct ngtcp2_transport_params* params)
1141*be771a7bSCy Schubert {
1142*be771a7bSCy Schubert 	FILE* out;
1143*be771a7bSCy Schubert 	out = fopen(file, "w");
1144*be771a7bSCy Schubert 	if(!out) {
1145*be771a7bSCy Schubert 		perror(file);
1146*be771a7bSCy Schubert 		return;
1147*be771a7bSCy Schubert 	}
1148*be771a7bSCy Schubert 	fprintf(out, "initial_max_streams_bidi=%u\n",
1149*be771a7bSCy Schubert 		(unsigned)params->initial_max_streams_bidi);
1150*be771a7bSCy Schubert 	fprintf(out, "initial_max_streams_uni=%u\n",
1151*be771a7bSCy Schubert 		(unsigned)params->initial_max_streams_uni);
1152*be771a7bSCy Schubert 	fprintf(out, "initial_max_stream_data_bidi_local=%u\n",
1153*be771a7bSCy Schubert 		(unsigned)params->initial_max_stream_data_bidi_local);
1154*be771a7bSCy Schubert 	fprintf(out, "initial_max_stream_data_bidi_remote=%u\n",
1155*be771a7bSCy Schubert 		(unsigned)params->initial_max_stream_data_bidi_remote);
1156*be771a7bSCy Schubert 	fprintf(out, "initial_max_stream_data_uni=%u\n",
1157*be771a7bSCy Schubert 		(unsigned)params->initial_max_stream_data_uni);
1158*be771a7bSCy Schubert 	fprintf(out, "initial_max_data=%u\n",
1159*be771a7bSCy Schubert 		(unsigned)params->initial_max_data);
1160*be771a7bSCy Schubert 	fprintf(out, "active_connection_id_limit=%u\n",
1161*be771a7bSCy Schubert 		(unsigned)params->active_connection_id_limit);
1162*be771a7bSCy Schubert 	fprintf(out, "max_datagram_frame_size=%u\n",
1163*be771a7bSCy Schubert 		(unsigned)params->max_datagram_frame_size);
1164*be771a7bSCy Schubert 	if(ferror(out)) {
1165*be771a7bSCy Schubert 		verbose(1, "There was an error writing %s: %s",
1166*be771a7bSCy Schubert 			file, strerror(errno));
1167*be771a7bSCy Schubert 		fclose(out);
1168*be771a7bSCy Schubert 		return;
1169*be771a7bSCy Schubert 	}
1170*be771a7bSCy Schubert 	fclose(out);
1171*be771a7bSCy Schubert }
1172*be771a7bSCy Schubert #endif /* HAVE_NGTCP2_CONN_ENCODE_0RTT_TRANSPORT_PARAMS */
1173*be771a7bSCy Schubert 
1174*be771a7bSCy Schubert /** fetch and write the transport file */
1175*be771a7bSCy Schubert static void
1176*be771a7bSCy Schubert early_data_write_transport(struct doq_client_data* data)
1177*be771a7bSCy Schubert {
1178*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CONN_ENCODE_0RTT_TRANSPORT_PARAMS
1179*be771a7bSCy Schubert 	FILE* out;
1180*be771a7bSCy Schubert 	uint8_t buf[1024];
1181*be771a7bSCy Schubert 	ngtcp2_ssize len = ngtcp2_conn_encode_0rtt_transport_params(data->conn,
1182*be771a7bSCy Schubert 		buf, sizeof(buf));
1183*be771a7bSCy Schubert 	if(len < 0) {
1184*be771a7bSCy Schubert 		log_err("ngtcp2_conn_encode_0rtt_transport_params failed: %s",
1185*be771a7bSCy Schubert 			ngtcp2_strerror(len));
1186*be771a7bSCy Schubert 		return;
1187*be771a7bSCy Schubert 	}
1188*be771a7bSCy Schubert 	out = fopen(data->transport_file, "w");
1189*be771a7bSCy Schubert 	if(!out) {
1190*be771a7bSCy Schubert 		perror(data->transport_file);
1191*be771a7bSCy Schubert 		return;
1192*be771a7bSCy Schubert 	}
1193*be771a7bSCy Schubert 	if(fwrite(buf, 1, len, out) != (size_t)len) {
1194*be771a7bSCy Schubert 		log_err("fwrite %s failed: %s", data->transport_file,
1195*be771a7bSCy Schubert 			strerror(errno));
1196*be771a7bSCy Schubert 	}
1197*be771a7bSCy Schubert 	if(ferror(out)) {
1198*be771a7bSCy Schubert 		verbose(1, "There was an error writing %s: %s",
1199*be771a7bSCy Schubert 			data->transport_file, strerror(errno));
1200*be771a7bSCy Schubert 	}
1201*be771a7bSCy Schubert 	fclose(out);
1202*be771a7bSCy Schubert #else
1203*be771a7bSCy Schubert 	struct ngtcp2_transport_params params;
1204*be771a7bSCy Schubert 	memset(&params, 0, sizeof(params));
1205*be771a7bSCy Schubert 	ngtcp2_conn_get_remote_transport_params(data->conn, &params);
1206*be771a7bSCy Schubert 	transport_file_write(data->transport_file, &params);
1207*be771a7bSCy Schubert #endif
1208*be771a7bSCy Schubert }
1209*be771a7bSCy Schubert 
1210*be771a7bSCy Schubert #ifndef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_CLIENT_CONTEXT
1211*be771a7bSCy Schubert /** applicatation rx key callback, this is where the rx key is set,
1212*be771a7bSCy Schubert  * and streams can be opened, like http3 unidirectional streams, like
1213*be771a7bSCy Schubert  * the http3 control and http3 qpack encode and decoder streams. */
1214*be771a7bSCy Schubert static int
1215*be771a7bSCy Schubert application_rx_key_cb(struct doq_client_data* data)
1216*be771a7bSCy Schubert {
1217*be771a7bSCy Schubert 	verbose(1, "application_rx_key_cb callback");
1218*be771a7bSCy Schubert 	verbose(1, "ngtcp2_conn_get_max_data_left is %d",
1219*be771a7bSCy Schubert 		(int)ngtcp2_conn_get_max_data_left(data->conn));
1220*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CONN_GET_MAX_LOCAL_STREAMS_UNI
1221*be771a7bSCy Schubert 	verbose(1, "ngtcp2_conn_get_max_local_streams_uni is %d",
1222*be771a7bSCy Schubert 		(int)ngtcp2_conn_get_max_local_streams_uni(data->conn));
1223*be771a7bSCy Schubert #endif
1224*be771a7bSCy Schubert 	verbose(1, "ngtcp2_conn_get_streams_uni_left is %d",
1225*be771a7bSCy Schubert 		(int)ngtcp2_conn_get_streams_uni_left(data->conn));
1226*be771a7bSCy Schubert 	verbose(1, "ngtcp2_conn_get_streams_bidi_left is %d",
1227*be771a7bSCy Schubert 		(int)ngtcp2_conn_get_streams_bidi_left(data->conn));
1228*be771a7bSCy Schubert 	if(data->transport_file) {
1229*be771a7bSCy Schubert 		early_data_write_transport(data);
1230*be771a7bSCy Schubert 	}
1231*be771a7bSCy Schubert 	return 1;
1232*be771a7bSCy Schubert }
1233*be771a7bSCy Schubert 
1234*be771a7bSCy Schubert /** quic_method set_encryption_secrets function */
1235*be771a7bSCy Schubert static int
1236*be771a7bSCy Schubert set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level,
1237*be771a7bSCy Schubert 	const uint8_t *read_secret, const uint8_t *write_secret,
1238*be771a7bSCy Schubert 	size_t secret_len)
1239*be771a7bSCy Schubert {
1240*be771a7bSCy Schubert 	struct doq_client_data* data = get_app_data(ssl);
1241*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_ENCRYPTION_LEVEL
1242*be771a7bSCy Schubert 	ngtcp2_encryption_level
1243*be771a7bSCy Schubert #else
1244*be771a7bSCy Schubert 	ngtcp2_crypto_level
1245*be771a7bSCy Schubert #endif
1246*be771a7bSCy Schubert 		level =
1247*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CRYPTO_QUICTLS_FROM_OSSL_ENCRYPTION_LEVEL
1248*be771a7bSCy Schubert 		ngtcp2_crypto_quictls_from_ossl_encryption_level(ossl_level);
1249*be771a7bSCy Schubert #else
1250*be771a7bSCy Schubert 		ngtcp2_crypto_openssl_from_ossl_encryption_level(ossl_level);
1251*be771a7bSCy Schubert #endif
1252*be771a7bSCy Schubert 
1253*be771a7bSCy Schubert 	if(read_secret) {
1254*be771a7bSCy Schubert 		if(ngtcp2_crypto_derive_and_install_rx_key(data->conn, NULL,
1255*be771a7bSCy Schubert 			NULL, NULL, level, read_secret, secret_len) != 0) {
1256*be771a7bSCy Schubert 			log_err("ngtcp2_crypto_derive_and_install_rx_key failed");
1257*be771a7bSCy Schubert 			return 0;
1258*be771a7bSCy Schubert 		}
1259*be771a7bSCy Schubert 		if(level == NGTCP2_CRYPTO_LEVEL_APPLICATION) {
1260*be771a7bSCy Schubert 			if(!application_rx_key_cb(data))
1261*be771a7bSCy Schubert 				return 0;
1262*be771a7bSCy Schubert 		}
1263*be771a7bSCy Schubert 	}
1264*be771a7bSCy Schubert 
1265*be771a7bSCy Schubert 	if(write_secret) {
1266*be771a7bSCy Schubert 		if(ngtcp2_crypto_derive_and_install_tx_key(data->conn, NULL,
1267*be771a7bSCy Schubert 			NULL, NULL, level, write_secret, secret_len) != 0) {
1268*be771a7bSCy Schubert 			log_err("ngtcp2_crypto_derive_and_install_tx_key failed");
1269*be771a7bSCy Schubert 			return 0;
1270*be771a7bSCy Schubert 		}
1271*be771a7bSCy Schubert 	}
1272*be771a7bSCy Schubert 	return 1;
1273*be771a7bSCy Schubert }
1274*be771a7bSCy Schubert 
1275*be771a7bSCy Schubert /** quic_method add_handshake_data function */
1276*be771a7bSCy Schubert static int
1277*be771a7bSCy Schubert add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level,
1278*be771a7bSCy Schubert 	const uint8_t *data, size_t len)
1279*be771a7bSCy Schubert {
1280*be771a7bSCy Schubert 	struct doq_client_data* doqdata = get_app_data(ssl);
1281*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_ENCRYPTION_LEVEL
1282*be771a7bSCy Schubert 	ngtcp2_encryption_level
1283*be771a7bSCy Schubert #else
1284*be771a7bSCy Schubert 	ngtcp2_crypto_level
1285*be771a7bSCy Schubert #endif
1286*be771a7bSCy Schubert 		level =
1287*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CRYPTO_QUICTLS_FROM_OSSL_ENCRYPTION_LEVEL
1288*be771a7bSCy Schubert 		ngtcp2_crypto_quictls_from_ossl_encryption_level(ossl_level);
1289*be771a7bSCy Schubert #else
1290*be771a7bSCy Schubert 		ngtcp2_crypto_openssl_from_ossl_encryption_level(ossl_level);
1291*be771a7bSCy Schubert #endif
1292*be771a7bSCy Schubert 	int rv;
1293*be771a7bSCy Schubert 
1294*be771a7bSCy Schubert 	rv = ngtcp2_conn_submit_crypto_data(doqdata->conn, level, data, len);
1295*be771a7bSCy Schubert 	if(rv != 0) {
1296*be771a7bSCy Schubert 		log_err("ngtcp2_conn_submit_crypto_data failed: %s",
1297*be771a7bSCy Schubert 			ngtcp2_strerror(rv));
1298*be771a7bSCy Schubert 		ngtcp2_conn_set_tls_error(doqdata->conn, rv);
1299*be771a7bSCy Schubert 		return 0;
1300*be771a7bSCy Schubert 	}
1301*be771a7bSCy Schubert 	return 1;
1302*be771a7bSCy Schubert }
1303*be771a7bSCy Schubert 
1304*be771a7bSCy Schubert /** quic_method flush_flight function */
1305*be771a7bSCy Schubert static int
1306*be771a7bSCy Schubert flush_flight(SSL* ATTR_UNUSED(ssl))
1307*be771a7bSCy Schubert {
1308*be771a7bSCy Schubert 	return 1;
1309*be771a7bSCy Schubert }
1310*be771a7bSCy Schubert 
1311*be771a7bSCy Schubert /** quic_method send_alert function */
1312*be771a7bSCy Schubert static int
1313*be771a7bSCy Schubert send_alert(SSL *ssl, enum ssl_encryption_level_t ATTR_UNUSED(level),
1314*be771a7bSCy Schubert 	uint8_t alert)
1315*be771a7bSCy Schubert {
1316*be771a7bSCy Schubert 	struct doq_client_data* data = get_app_data(ssl);
1317*be771a7bSCy Schubert 	data->tls_alert = alert;
1318*be771a7bSCy Schubert 	return 1;
1319*be771a7bSCy Schubert }
1320*be771a7bSCy Schubert #endif /* HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_CLIENT_CONTEXT */
1321*be771a7bSCy Schubert 
1322*be771a7bSCy Schubert /** new session callback. We can write it to file for resumption later. */
1323*be771a7bSCy Schubert static int
1324*be771a7bSCy Schubert new_session_cb(SSL* ssl, SSL_SESSION* session)
1325*be771a7bSCy Schubert {
1326*be771a7bSCy Schubert 	struct doq_client_data* data = get_app_data(ssl);
1327*be771a7bSCy Schubert 	BIO *f;
1328*be771a7bSCy Schubert 	log_assert(data->session_file);
1329*be771a7bSCy Schubert 	verbose(1, "new session cb: the ssl session max_early_data_size is %u",
1330*be771a7bSCy Schubert 		(unsigned)SSL_SESSION_get_max_early_data(session));
1331*be771a7bSCy Schubert 	f = BIO_new_file(data->session_file, "w");
1332*be771a7bSCy Schubert 	if(!f) {
1333*be771a7bSCy Schubert 		log_err("Could not open %s: %s", data->session_file,
1334*be771a7bSCy Schubert 			strerror(errno));
1335*be771a7bSCy Schubert 		return 0;
1336*be771a7bSCy Schubert 	}
1337*be771a7bSCy Schubert 	PEM_write_bio_SSL_SESSION(f, session);
1338*be771a7bSCy Schubert 	BIO_free(f);
1339*be771a7bSCy Schubert 	verbose(1, "written tls session to %s", data->session_file);
1340*be771a7bSCy Schubert 	return 0;
1341*be771a7bSCy Schubert }
1342*be771a7bSCy Schubert 
1343*be771a7bSCy Schubert /** setup the TLS context */
1344*be771a7bSCy Schubert static SSL_CTX*
1345*be771a7bSCy Schubert ctx_client_setup(void)
1346*be771a7bSCy Schubert {
1347*be771a7bSCy Schubert 	SSL_CTX* ctx = SSL_CTX_new(TLS_client_method());
1348*be771a7bSCy Schubert 	if(!ctx) {
1349*be771a7bSCy Schubert 		log_crypto_err("Could not SSL_CTX_new");
1350*be771a7bSCy Schubert 		exit(1);
1351*be771a7bSCy Schubert 	}
1352*be771a7bSCy Schubert 	SSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION);
1353*be771a7bSCy Schubert 	SSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION);
1354*be771a7bSCy Schubert 	SSL_CTX_set_default_verify_paths(ctx);
1355*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CRYPTO_QUICTLS_CONFIGURE_CLIENT_CONTEXT
1356*be771a7bSCy Schubert 	if(ngtcp2_crypto_quictls_configure_client_context(ctx) != 0) {
1357*be771a7bSCy Schubert 		log_err("ngtcp2_crypto_quictls_configure_client_context failed");
1358*be771a7bSCy Schubert 		exit(1);
1359*be771a7bSCy Schubert 	}
1360*be771a7bSCy Schubert #else
1361*be771a7bSCy Schubert 	memset(&quic_method, 0, sizeof(quic_method));
1362*be771a7bSCy Schubert 	quic_method.set_encryption_secrets = &set_encryption_secrets;
1363*be771a7bSCy Schubert 	quic_method.add_handshake_data = &add_handshake_data;
1364*be771a7bSCy Schubert 	quic_method.flush_flight = &flush_flight;
1365*be771a7bSCy Schubert 	quic_method.send_alert = &send_alert;
1366*be771a7bSCy Schubert 	SSL_CTX_set_quic_method(ctx, &quic_method);
1367*be771a7bSCy Schubert #endif
1368*be771a7bSCy Schubert 	return ctx;
1369*be771a7bSCy Schubert }
1370*be771a7bSCy Schubert 
1371*be771a7bSCy Schubert 
1372*be771a7bSCy Schubert /* setup the TLS object */
1373*be771a7bSCy Schubert static SSL*
1374*be771a7bSCy Schubert ssl_client_setup(struct doq_client_data* data)
1375*be771a7bSCy Schubert {
1376*be771a7bSCy Schubert 	SSL* ssl = SSL_new(data->ctx);
1377*be771a7bSCy Schubert 	if(!ssl) {
1378*be771a7bSCy Schubert 		log_crypto_err("Could not SSL_new");
1379*be771a7bSCy Schubert 		exit(1);
1380*be771a7bSCy Schubert 	}
1381*be771a7bSCy Schubert 	set_app_data(ssl, data);
1382*be771a7bSCy Schubert 	SSL_set_connect_state(ssl);
1383*be771a7bSCy Schubert 	if(!SSL_set_fd(ssl, data->fd)) {
1384*be771a7bSCy Schubert 		log_crypto_err("Could not SSL_set_fd");
1385*be771a7bSCy Schubert 		exit(1);
1386*be771a7bSCy Schubert 	}
1387*be771a7bSCy Schubert 	if((data->quic_version & 0xff000000) == 0xff000000) {
1388*be771a7bSCy Schubert 		SSL_set_quic_use_legacy_codepoint(ssl, 1);
1389*be771a7bSCy Schubert 	} else {
1390*be771a7bSCy Schubert 		SSL_set_quic_use_legacy_codepoint(ssl, 0);
1391*be771a7bSCy Schubert 	}
1392*be771a7bSCy Schubert 	SSL_set_alpn_protos(ssl, (const unsigned char *)"\x03""doq", 4);
1393*be771a7bSCy Schubert 	/* send the SNI host name */
1394*be771a7bSCy Schubert 	SSL_set_tlsext_host_name(ssl, "localhost");
1395*be771a7bSCy Schubert 	return ssl;
1396*be771a7bSCy Schubert }
1397*be771a7bSCy Schubert 
1398*be771a7bSCy Schubert /** get packet ecn information */
1399*be771a7bSCy Schubert static uint32_t
1400*be771a7bSCy Schubert msghdr_get_ecn(struct msghdr* msg, int family)
1401*be771a7bSCy Schubert {
1402*be771a7bSCy Schubert #ifndef S_SPLINT_S
1403*be771a7bSCy Schubert 	struct cmsghdr* cmsg;
1404*be771a7bSCy Schubert 	if(family == AF_INET6) {
1405*be771a7bSCy Schubert 		for(cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
1406*be771a7bSCy Schubert 			cmsg = CMSG_NXTHDR(msg, cmsg)) {
1407*be771a7bSCy Schubert 			if(cmsg->cmsg_level == IPPROTO_IPV6 &&
1408*be771a7bSCy Schubert 				cmsg->cmsg_type == IPV6_TCLASS &&
1409*be771a7bSCy Schubert 				cmsg->cmsg_len != 0) {
1410*be771a7bSCy Schubert 				uint8_t* ecn = (uint8_t*)CMSG_DATA(cmsg);
1411*be771a7bSCy Schubert 				return *ecn;
1412*be771a7bSCy Schubert 			}
1413*be771a7bSCy Schubert 		}
1414*be771a7bSCy Schubert 		return 0;
1415*be771a7bSCy Schubert 	}
1416*be771a7bSCy Schubert 	for(cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
1417*be771a7bSCy Schubert 		cmsg = CMSG_NXTHDR(msg, cmsg)) {
1418*be771a7bSCy Schubert 		if(cmsg->cmsg_level == IPPROTO_IP &&
1419*be771a7bSCy Schubert 			cmsg->cmsg_type == IP_TOS &&
1420*be771a7bSCy Schubert 			cmsg->cmsg_len != 0) {
1421*be771a7bSCy Schubert 			uint8_t* ecn = (uint8_t*)CMSG_DATA(cmsg);
1422*be771a7bSCy Schubert 			return *ecn;
1423*be771a7bSCy Schubert 		}
1424*be771a7bSCy Schubert 	}
1425*be771a7bSCy Schubert 	return 0;
1426*be771a7bSCy Schubert #endif /* S_SPLINT_S */
1427*be771a7bSCy Schubert }
1428*be771a7bSCy Schubert 
1429*be771a7bSCy Schubert /** set the ecn on the transmission */
1430*be771a7bSCy Schubert static void
1431*be771a7bSCy Schubert set_ecn(int fd, int family, uint32_t ecn)
1432*be771a7bSCy Schubert {
1433*be771a7bSCy Schubert 	unsigned int val = ecn;
1434*be771a7bSCy Schubert 	if(family == AF_INET6) {
1435*be771a7bSCy Schubert 		if(setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &val,
1436*be771a7bSCy Schubert 			(socklen_t)sizeof(val)) == -1) {
1437*be771a7bSCy Schubert 			log_err("setsockopt(.. IPV6_TCLASS ..): %s",
1438*be771a7bSCy Schubert 				strerror(errno));
1439*be771a7bSCy Schubert 		}
1440*be771a7bSCy Schubert 		return;
1441*be771a7bSCy Schubert 	}
1442*be771a7bSCy Schubert 	if(setsockopt(fd, IPPROTO_IP, IP_TOS, &val,
1443*be771a7bSCy Schubert 		(socklen_t)sizeof(val)) == -1) {
1444*be771a7bSCy Schubert 		log_err("setsockopt(.. IP_TOS ..): %s",
1445*be771a7bSCy Schubert 			strerror(errno));
1446*be771a7bSCy Schubert 	}
1447*be771a7bSCy Schubert }
1448*be771a7bSCy Schubert 
1449*be771a7bSCy Schubert /** send a packet */
1450*be771a7bSCy Schubert static int
1451*be771a7bSCy Schubert doq_client_send_pkt(struct doq_client_data* data, uint32_t ecn, uint8_t* buf,
1452*be771a7bSCy Schubert 	size_t buf_len, int is_blocked_pkt, int* send_is_blocked)
1453*be771a7bSCy Schubert {
1454*be771a7bSCy Schubert 	struct msghdr msg;
1455*be771a7bSCy Schubert 	struct iovec iov[1];
1456*be771a7bSCy Schubert 	ssize_t ret;
1457*be771a7bSCy Schubert 	iov[0].iov_base = buf;
1458*be771a7bSCy Schubert 	iov[0].iov_len = buf_len;
1459*be771a7bSCy Schubert 	memset(&msg, 0, sizeof(msg));
1460*be771a7bSCy Schubert 	msg.msg_name = (void*)&data->dest_addr;
1461*be771a7bSCy Schubert 	msg.msg_namelen = data->dest_addr_len;
1462*be771a7bSCy Schubert 	msg.msg_iov = iov;
1463*be771a7bSCy Schubert 	msg.msg_iovlen = 1;
1464*be771a7bSCy Schubert 	set_ecn(data->fd, data->dest_addr.ss_family, ecn);
1465*be771a7bSCy Schubert 
1466*be771a7bSCy Schubert 	for(;;) {
1467*be771a7bSCy Schubert 		ret = sendmsg(data->fd, &msg, MSG_DONTWAIT);
1468*be771a7bSCy Schubert 		if(ret == -1 && errno == EINTR)
1469*be771a7bSCy Schubert 			continue;
1470*be771a7bSCy Schubert 		break;
1471*be771a7bSCy Schubert 	}
1472*be771a7bSCy Schubert 	if(ret == -1) {
1473*be771a7bSCy Schubert 		if(errno == EAGAIN) {
1474*be771a7bSCy Schubert 			if(buf_len >
1475*be771a7bSCy Schubert 				sldns_buffer_capacity(data->blocked_pkt))
1476*be771a7bSCy Schubert 				return 0; /* Cannot store it, but the buffers
1477*be771a7bSCy Schubert 				are equal length and large enough, so this
1478*be771a7bSCy Schubert 				should not happen. */
1479*be771a7bSCy Schubert 			data->have_blocked_pkt = 1;
1480*be771a7bSCy Schubert 			if(send_is_blocked)
1481*be771a7bSCy Schubert 				*send_is_blocked = 1;
1482*be771a7bSCy Schubert 			/* If we already send the previously blocked packet,
1483*be771a7bSCy Schubert 			 * no need to copy it, otherwise store the packet for
1484*be771a7bSCy Schubert 			 * later. */
1485*be771a7bSCy Schubert 			if(!is_blocked_pkt) {
1486*be771a7bSCy Schubert 				data->blocked_pkt_pi.ecn = ecn;
1487*be771a7bSCy Schubert 				sldns_buffer_clear(data->blocked_pkt);
1488*be771a7bSCy Schubert 				sldns_buffer_write(data->blocked_pkt, buf,
1489*be771a7bSCy Schubert 					buf_len);
1490*be771a7bSCy Schubert 				sldns_buffer_flip(data->blocked_pkt);
1491*be771a7bSCy Schubert 			}
1492*be771a7bSCy Schubert 			return 0;
1493*be771a7bSCy Schubert 		}
1494*be771a7bSCy Schubert 		log_err("doq sendmsg: %s", strerror(errno));
1495*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CCERR_DEFAULT
1496*be771a7bSCy Schubert 		ngtcp2_ccerr_set_application_error(&data->ccerr, -1, NULL, 0);
1497*be771a7bSCy Schubert #else
1498*be771a7bSCy Schubert 		ngtcp2_connection_close_error_set_application_error(&data->last_error, -1, NULL, 0);
1499*be771a7bSCy Schubert #endif
1500*be771a7bSCy Schubert 		return 0;
1501*be771a7bSCy Schubert 	}
1502*be771a7bSCy Schubert 	return 1;
1503*be771a7bSCy Schubert }
1504*be771a7bSCy Schubert 
1505*be771a7bSCy Schubert /** change event write on fd to when we have data or when congested */
1506*be771a7bSCy Schubert static void
1507*be771a7bSCy Schubert event_change_write(struct doq_client_data* data, int do_write)
1508*be771a7bSCy Schubert {
1509*be771a7bSCy Schubert 	ub_event_del(data->ev);
1510*be771a7bSCy Schubert 	if(do_write) {
1511*be771a7bSCy Schubert 		ub_event_add_bits(data->ev, UB_EV_WRITE);
1512*be771a7bSCy Schubert 	} else {
1513*be771a7bSCy Schubert 		ub_event_del_bits(data->ev, UB_EV_WRITE);
1514*be771a7bSCy Schubert 	}
1515*be771a7bSCy Schubert 	if(ub_event_add(data->ev, NULL) != 0) {
1516*be771a7bSCy Schubert 		fatal_exit("could not ub_event_add");
1517*be771a7bSCy Schubert 	}
1518*be771a7bSCy Schubert }
1519*be771a7bSCy Schubert 
1520*be771a7bSCy Schubert /** write the connection close, with possible error */
1521*be771a7bSCy Schubert static void
1522*be771a7bSCy Schubert write_conn_close(struct doq_client_data* data)
1523*be771a7bSCy Schubert {
1524*be771a7bSCy Schubert 	struct ngtcp2_path_storage ps;
1525*be771a7bSCy Schubert 	struct ngtcp2_pkt_info pi;
1526*be771a7bSCy Schubert 	ngtcp2_ssize ret;
1527*be771a7bSCy Schubert 	if(!data->conn ||
1528*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CONN_IN_CLOSING_PERIOD
1529*be771a7bSCy Schubert 		ngtcp2_conn_in_closing_period(data->conn) ||
1530*be771a7bSCy Schubert #else
1531*be771a7bSCy Schubert 		ngtcp2_conn_is_in_closing_period(data->conn) ||
1532*be771a7bSCy Schubert #endif
1533*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CONN_IN_DRAINING_PERIOD
1534*be771a7bSCy Schubert 		ngtcp2_conn_in_draining_period(data->conn)
1535*be771a7bSCy Schubert #else
1536*be771a7bSCy Schubert 		ngtcp2_conn_is_in_draining_period(data->conn)
1537*be771a7bSCy Schubert #endif
1538*be771a7bSCy Schubert 		)
1539*be771a7bSCy Schubert 		return;
1540*be771a7bSCy Schubert 	/* Drop blocked packet if there is one, the connection is being
1541*be771a7bSCy Schubert 	 * closed. And thus no further data traffic. */
1542*be771a7bSCy Schubert 	data->have_blocked_pkt = 0;
1543*be771a7bSCy Schubert 	if(
1544*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CCERR_DEFAULT
1545*be771a7bSCy Schubert 		data->ccerr.type == NGTCP2_CCERR_TYPE_IDLE_CLOSE
1546*be771a7bSCy Schubert #else
1547*be771a7bSCy Schubert 		data->last_error.type ==
1548*be771a7bSCy Schubert 		NGTCP2_CONNECTION_CLOSE_ERROR_CODE_TYPE_TRANSPORT_IDLE_CLOSE
1549*be771a7bSCy Schubert #endif
1550*be771a7bSCy Schubert 		) {
1551*be771a7bSCy Schubert 		/* do not call ngtcp2_conn_write_connection_close on the
1552*be771a7bSCy Schubert 		 * connection because the ngtcp2_conn_handle_expiry call
1553*be771a7bSCy Schubert 		 * has returned NGTCP2_ERR_IDLE_CLOSE. But continue to close
1554*be771a7bSCy Schubert 		 * the connection. */
1555*be771a7bSCy Schubert 		return;
1556*be771a7bSCy Schubert 	}
1557*be771a7bSCy Schubert 	verbose(1, "write connection close");
1558*be771a7bSCy Schubert 	ngtcp2_path_storage_zero(&ps);
1559*be771a7bSCy Schubert 	sldns_buffer_clear(data->pkt_buf);
1560*be771a7bSCy Schubert 	ret = ngtcp2_conn_write_connection_close(
1561*be771a7bSCy Schubert 		data->conn, &ps.path, &pi, sldns_buffer_begin(data->pkt_buf),
1562*be771a7bSCy Schubert 		sldns_buffer_remaining(data->pkt_buf),
1563*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CCERR_DEFAULT
1564*be771a7bSCy Schubert 		&data->ccerr
1565*be771a7bSCy Schubert #else
1566*be771a7bSCy Schubert 		&data->last_error
1567*be771a7bSCy Schubert #endif
1568*be771a7bSCy Schubert 		, get_timestamp_nanosec());
1569*be771a7bSCy Schubert 	if(ret < 0) {
1570*be771a7bSCy Schubert 		log_err("ngtcp2_conn_write_connection_close failed: %s",
1571*be771a7bSCy Schubert 			ngtcp2_strerror(ret));
1572*be771a7bSCy Schubert 		return;
1573*be771a7bSCy Schubert 	}
1574*be771a7bSCy Schubert 	verbose(1, "write connection close packet length %d", (int)ret);
1575*be771a7bSCy Schubert 	if(ret == 0)
1576*be771a7bSCy Schubert 		return;
1577*be771a7bSCy Schubert 	doq_client_send_pkt(data, pi.ecn, sldns_buffer_begin(data->pkt_buf),
1578*be771a7bSCy Schubert 		ret, 0, NULL);
1579*be771a7bSCy Schubert }
1580*be771a7bSCy Schubert 
1581*be771a7bSCy Schubert /** disconnect we are done */
1582*be771a7bSCy Schubert static void
1583*be771a7bSCy Schubert disconnect(struct doq_client_data* data)
1584*be771a7bSCy Schubert {
1585*be771a7bSCy Schubert 	verbose(1, "disconnect");
1586*be771a7bSCy Schubert 	write_conn_close(data);
1587*be771a7bSCy Schubert 	ub_event_base_loopexit(data->base);
1588*be771a7bSCy Schubert }
1589*be771a7bSCy Schubert 
1590*be771a7bSCy Schubert /** the expire timer callback */
1591*be771a7bSCy Schubert void doq_client_timer_cb(int ATTR_UNUSED(fd),
1592*be771a7bSCy Schubert 	short ATTR_UNUSED(bits), void* arg)
1593*be771a7bSCy Schubert {
1594*be771a7bSCy Schubert 	struct doq_client_data* data = (struct doq_client_data*)arg;
1595*be771a7bSCy Schubert 	ngtcp2_tstamp now = get_timestamp_nanosec();
1596*be771a7bSCy Schubert 	int rv;
1597*be771a7bSCy Schubert 
1598*be771a7bSCy Schubert 	verbose(1, "doq expire_timer");
1599*be771a7bSCy Schubert 	data->expire_timer_added = 0;
1600*be771a7bSCy Schubert 	rv = ngtcp2_conn_handle_expiry(data->conn, now);
1601*be771a7bSCy Schubert 	if(rv != 0) {
1602*be771a7bSCy Schubert 		log_err("ngtcp2_conn_handle_expiry failed: %s",
1603*be771a7bSCy Schubert 			ngtcp2_strerror(rv));
1604*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CCERR_DEFAULT
1605*be771a7bSCy Schubert 		ngtcp2_ccerr_set_liberr(&data->ccerr, rv, NULL, 0);
1606*be771a7bSCy Schubert #else
1607*be771a7bSCy Schubert 		ngtcp2_connection_close_error_set_transport_error_liberr(
1608*be771a7bSCy Schubert 			&data->last_error, rv, NULL, 0);
1609*be771a7bSCy Schubert #endif
1610*be771a7bSCy Schubert 		disconnect(data);
1611*be771a7bSCy Schubert 		return;
1612*be771a7bSCy Schubert 	}
1613*be771a7bSCy Schubert 	update_timer(data);
1614*be771a7bSCy Schubert 	on_write(data);
1615*be771a7bSCy Schubert }
1616*be771a7bSCy Schubert 
1617*be771a7bSCy Schubert /** update the timers */
1618*be771a7bSCy Schubert static void
1619*be771a7bSCy Schubert update_timer(struct doq_client_data* data)
1620*be771a7bSCy Schubert {
1621*be771a7bSCy Schubert 	ngtcp2_tstamp expiry = ngtcp2_conn_get_expiry(data->conn);
1622*be771a7bSCy Schubert 	ngtcp2_tstamp now = get_timestamp_nanosec();
1623*be771a7bSCy Schubert 	ngtcp2_tstamp t;
1624*be771a7bSCy Schubert 	struct timeval tv;
1625*be771a7bSCy Schubert 
1626*be771a7bSCy Schubert 	if(expiry <= now) {
1627*be771a7bSCy Schubert 		/* the timer has already expired, add with zero timeout */
1628*be771a7bSCy Schubert 		t = 0;
1629*be771a7bSCy Schubert 	} else {
1630*be771a7bSCy Schubert 		t = expiry - now;
1631*be771a7bSCy Schubert 	}
1632*be771a7bSCy Schubert 
1633*be771a7bSCy Schubert 	/* set the timer */
1634*be771a7bSCy Schubert 	if(data->expire_timer_added) {
1635*be771a7bSCy Schubert 		ub_timer_del(data->expire_timer);
1636*be771a7bSCy Schubert 		data->expire_timer_added = 0;
1637*be771a7bSCy Schubert 	}
1638*be771a7bSCy Schubert 	memset(&tv, 0, sizeof(tv));
1639*be771a7bSCy Schubert 	tv.tv_sec = t / NGTCP2_SECONDS;
1640*be771a7bSCy Schubert 	tv.tv_usec = (t / NGTCP2_MICROSECONDS)%1000000;
1641*be771a7bSCy Schubert 	verbose(1, "update_timer in %d.%6.6d secs", (int)tv.tv_sec,
1642*be771a7bSCy Schubert 		(int)tv.tv_usec);
1643*be771a7bSCy Schubert 	if(ub_timer_add(data->expire_timer, data->base,
1644*be771a7bSCy Schubert 		&doq_client_timer_cb, data, &tv) != 0) {
1645*be771a7bSCy Schubert 		log_err("timer_add failed: could not add expire timer");
1646*be771a7bSCy Schubert 		return;
1647*be771a7bSCy Schubert 	}
1648*be771a7bSCy Schubert 	data->expire_timer_added = 1;
1649*be771a7bSCy Schubert }
1650*be771a7bSCy Schubert 
1651*be771a7bSCy Schubert /** perform read operations on fd */
1652*be771a7bSCy Schubert static void
1653*be771a7bSCy Schubert on_read(struct doq_client_data* data)
1654*be771a7bSCy Schubert {
1655*be771a7bSCy Schubert 	struct sockaddr_storage addr;
1656*be771a7bSCy Schubert 	struct iovec iov[1];
1657*be771a7bSCy Schubert 	struct msghdr msg;
1658*be771a7bSCy Schubert 	union {
1659*be771a7bSCy Schubert 		struct cmsghdr hdr;
1660*be771a7bSCy Schubert 		char buf[256];
1661*be771a7bSCy Schubert 	} ancil;
1662*be771a7bSCy Schubert 	int i;
1663*be771a7bSCy Schubert 	ssize_t rcv;
1664*be771a7bSCy Schubert 	ngtcp2_pkt_info pi;
1665*be771a7bSCy Schubert 	int rv;
1666*be771a7bSCy Schubert 	struct ngtcp2_path path;
1667*be771a7bSCy Schubert 
1668*be771a7bSCy Schubert 	for(i=0; i<10; i++) {
1669*be771a7bSCy Schubert 		msg.msg_name = &addr;
1670*be771a7bSCy Schubert 		msg.msg_namelen = (socklen_t)sizeof(addr);
1671*be771a7bSCy Schubert 		iov[0].iov_base = sldns_buffer_begin(data->pkt_buf);
1672*be771a7bSCy Schubert 		iov[0].iov_len = sldns_buffer_remaining(data->pkt_buf);
1673*be771a7bSCy Schubert 		msg.msg_iov = iov;
1674*be771a7bSCy Schubert 		msg.msg_iovlen = 1;
1675*be771a7bSCy Schubert 		msg.msg_control = ancil.buf;
1676*be771a7bSCy Schubert #ifndef S_SPLINT_S
1677*be771a7bSCy Schubert 		msg.msg_controllen = sizeof(ancil.buf);
1678*be771a7bSCy Schubert #endif /* S_SPLINT_S */
1679*be771a7bSCy Schubert 		msg.msg_flags = 0;
1680*be771a7bSCy Schubert 
1681*be771a7bSCy Schubert 		rcv = recvmsg(data->fd, &msg, MSG_DONTWAIT);
1682*be771a7bSCy Schubert 		if(rcv == -1) {
1683*be771a7bSCy Schubert 			if(errno == EINTR || errno == EAGAIN)
1684*be771a7bSCy Schubert 				break;
1685*be771a7bSCy Schubert 			log_err_addr("doq recvmsg", strerror(errno),
1686*be771a7bSCy Schubert 				&data->dest_addr, sizeof(data->dest_addr_len));
1687*be771a7bSCy Schubert 			break;
1688*be771a7bSCy Schubert 		}
1689*be771a7bSCy Schubert 
1690*be771a7bSCy Schubert 		pi.ecn = msghdr_get_ecn(&msg, addr.ss_family);
1691*be771a7bSCy Schubert 		verbose(1, "recvmsg %d ecn=0x%x", (int)rcv, (int)pi.ecn);
1692*be771a7bSCy Schubert 
1693*be771a7bSCy Schubert 		memset(&path, 0, sizeof(path));
1694*be771a7bSCy Schubert 		path.local.addr = (void*)&data->local_addr;
1695*be771a7bSCy Schubert 		path.local.addrlen = data->local_addr_len;
1696*be771a7bSCy Schubert 		path.remote.addr = (void*)msg.msg_name;
1697*be771a7bSCy Schubert 		path.remote.addrlen = msg.msg_namelen;
1698*be771a7bSCy Schubert 		rv = ngtcp2_conn_read_pkt(data->conn, &path, &pi,
1699*be771a7bSCy Schubert 			iov[0].iov_base, rcv, get_timestamp_nanosec());
1700*be771a7bSCy Schubert 		if(rv != 0) {
1701*be771a7bSCy Schubert 			log_err("ngtcp2_conn_read_pkt failed: %s",
1702*be771a7bSCy Schubert 				ngtcp2_strerror(rv));
1703*be771a7bSCy Schubert 			if(
1704*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CCERR_DEFAULT
1705*be771a7bSCy Schubert 				data->ccerr.error_code == 0
1706*be771a7bSCy Schubert #else
1707*be771a7bSCy Schubert 				data->last_error.error_code == 0
1708*be771a7bSCy Schubert #endif
1709*be771a7bSCy Schubert 				) {
1710*be771a7bSCy Schubert 				if(rv == NGTCP2_ERR_CRYPTO) {
1711*be771a7bSCy Schubert 					/* in picotls the tls alert may need
1712*be771a7bSCy Schubert 					 * to be copied, but this is with
1713*be771a7bSCy Schubert 					 * openssl. And we have the value
1714*be771a7bSCy Schubert 					 * data.tls_alert. */
1715*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CCERR_DEFAULT
1716*be771a7bSCy Schubert 					ngtcp2_ccerr_set_tls_alert(
1717*be771a7bSCy Schubert 						&data->ccerr, data->tls_alert,
1718*be771a7bSCy Schubert 						NULL, 0);
1719*be771a7bSCy Schubert #else
1720*be771a7bSCy Schubert 					ngtcp2_connection_close_error_set_transport_error_tls_alert(
1721*be771a7bSCy Schubert 						&data->last_error,
1722*be771a7bSCy Schubert 						data->tls_alert, NULL, 0);
1723*be771a7bSCy Schubert #endif
1724*be771a7bSCy Schubert 				} else {
1725*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CCERR_DEFAULT
1726*be771a7bSCy Schubert 					ngtcp2_ccerr_set_liberr(&data->ccerr,
1727*be771a7bSCy Schubert 						rv, NULL, 0);
1728*be771a7bSCy Schubert #else
1729*be771a7bSCy Schubert 					ngtcp2_connection_close_error_set_transport_error_liberr(
1730*be771a7bSCy Schubert 						&data->last_error, rv, NULL,
1731*be771a7bSCy Schubert 						0);
1732*be771a7bSCy Schubert #endif
1733*be771a7bSCy Schubert 				}
1734*be771a7bSCy Schubert 			}
1735*be771a7bSCy Schubert 			disconnect(data);
1736*be771a7bSCy Schubert 			return;
1737*be771a7bSCy Schubert 		}
1738*be771a7bSCy Schubert 	}
1739*be771a7bSCy Schubert 
1740*be771a7bSCy Schubert 	update_timer(data);
1741*be771a7bSCy Schubert }
1742*be771a7bSCy Schubert 
1743*be771a7bSCy Schubert /** the write of this query has completed, it has spooled to packets,
1744*be771a7bSCy Schubert  * set it to have the write done and move it to the list of receive streams. */
1745*be771a7bSCy Schubert static void
1746*be771a7bSCy Schubert query_write_is_done(struct doq_client_data* data,
1747*be771a7bSCy Schubert 	struct doq_client_stream* str)
1748*be771a7bSCy Schubert {
1749*be771a7bSCy Schubert 	if(verbosity > 0) {
1750*be771a7bSCy Schubert 		char* logs = client_stream_string(str);
1751*be771a7bSCy Schubert 		verbose(1, "query %s write is done", logs);
1752*be771a7bSCy Schubert 		free(logs);
1753*be771a7bSCy Schubert 	}
1754*be771a7bSCy Schubert 	str->write_is_done = 1;
1755*be771a7bSCy Schubert 	stream_list_move(str, data->query_list_send, data->query_list_receive);
1756*be771a7bSCy Schubert }
1757*be771a7bSCy Schubert 
1758*be771a7bSCy Schubert /** write the data streams, if possible */
1759*be771a7bSCy Schubert static int
1760*be771a7bSCy Schubert write_streams(struct doq_client_data* data)
1761*be771a7bSCy Schubert {
1762*be771a7bSCy Schubert 	ngtcp2_path_storage ps;
1763*be771a7bSCy Schubert 	ngtcp2_tstamp ts = get_timestamp_nanosec();
1764*be771a7bSCy Schubert 	struct doq_client_stream* str, *next;
1765*be771a7bSCy Schubert 	uint32_t flags;
1766*be771a7bSCy Schubert 	/* number of bytes that can be sent without packet pacing */
1767*be771a7bSCy Schubert 	size_t send_quantum = ngtcp2_conn_get_send_quantum(data->conn);
1768*be771a7bSCy Schubert 	/* Overhead is the stream overhead of adding a header onto the data,
1769*be771a7bSCy Schubert 	 * this make sure the number of bytes to send in data bytes plus
1770*be771a7bSCy Schubert 	 * the overhead overshoots the target quantum by a smaller margin,
1771*be771a7bSCy Schubert 	 * and then it stops sending more bytes. With zero it would overshoot
1772*be771a7bSCy Schubert 	 * more, an accurate number would not overshoot. It is based on the
1773*be771a7bSCy Schubert 	 * stream frame header size. */
1774*be771a7bSCy Schubert 	size_t accumulated_send = 0, overhead_stream = 24, overhead_pkt = 60,
1775*be771a7bSCy Schubert 		max_packet_size = 1200;
1776*be771a7bSCy Schubert 	size_t num_packets = 0, max_packets = 65535;
1777*be771a7bSCy Schubert 	ngtcp2_path_storage_zero(&ps);
1778*be771a7bSCy Schubert 	str = data->query_list_send->first;
1779*be771a7bSCy Schubert 
1780*be771a7bSCy Schubert 	if(data->cc_algo != NGTCP2_CC_ALGO_BBR
1781*be771a7bSCy Schubert #ifdef NGTCP2_CC_ALGO_BBR_V2
1782*be771a7bSCy Schubert 		&& data->cc_algo != NGTCP2_CC_ALGO_BBR_V2
1783*be771a7bSCy Schubert #endif
1784*be771a7bSCy Schubert #ifdef NGTCP2_CC_ALGO_BBR2
1785*be771a7bSCy Schubert 		&& data->cc_algo != NGTCP2_CC_ALGO_BBR2
1786*be771a7bSCy Schubert #endif
1787*be771a7bSCy Schubert 		) {
1788*be771a7bSCy Schubert 		/* If we do not have a packet pacing congestion control
1789*be771a7bSCy Schubert 		 * algorithm, limit the number of packets. */
1790*be771a7bSCy Schubert 		max_packets = 10;
1791*be771a7bSCy Schubert 	}
1792*be771a7bSCy Schubert 
1793*be771a7bSCy Schubert 	/* loop like this, because at the start, the send list is empty,
1794*be771a7bSCy Schubert 	 * and we want to send handshake packets. But when there is a
1795*be771a7bSCy Schubert 	 * send_list, loop through that. */
1796*be771a7bSCy Schubert 	for(;;) {
1797*be771a7bSCy Schubert 		int64_t stream_id;
1798*be771a7bSCy Schubert 		ngtcp2_pkt_info pi;
1799*be771a7bSCy Schubert 		ngtcp2_vec datav[2];
1800*be771a7bSCy Schubert 		size_t datav_count = 0;
1801*be771a7bSCy Schubert 		int fin;
1802*be771a7bSCy Schubert 		ngtcp2_ssize ret;
1803*be771a7bSCy Schubert 		ngtcp2_ssize ndatalen = 0;
1804*be771a7bSCy Schubert 		int send_is_blocked = 0;
1805*be771a7bSCy Schubert 
1806*be771a7bSCy Schubert 		if(str) {
1807*be771a7bSCy Schubert 			/* pick up next in case this one is deleted */
1808*be771a7bSCy Schubert 			next = str->next;
1809*be771a7bSCy Schubert 			if(verbosity > 0) {
1810*be771a7bSCy Schubert 				char* logs = client_stream_string(str);
1811*be771a7bSCy Schubert 				verbose(1, "query %s write stream", logs);
1812*be771a7bSCy Schubert 				free(logs);
1813*be771a7bSCy Schubert 			}
1814*be771a7bSCy Schubert 			stream_id = str->stream_id;
1815*be771a7bSCy Schubert 			fin = 1;
1816*be771a7bSCy Schubert 			if(str->nwrite < 2) {
1817*be771a7bSCy Schubert 				str->data_tcplen = htons(str->data_len);
1818*be771a7bSCy Schubert 				datav[0].base = ((uint8_t*)&str->data_tcplen)+str->nwrite;
1819*be771a7bSCy Schubert 				datav[0].len = 2-str->nwrite;
1820*be771a7bSCy Schubert 				datav[1].base = str->data;
1821*be771a7bSCy Schubert 				datav[1].len = str->data_len;
1822*be771a7bSCy Schubert 				datav_count = 2;
1823*be771a7bSCy Schubert 			} else {
1824*be771a7bSCy Schubert 				datav[0].base = str->data + (str->nwrite-2);
1825*be771a7bSCy Schubert 				datav[0].len = str->data_len - (str->nwrite-2);
1826*be771a7bSCy Schubert 				datav_count = 1;
1827*be771a7bSCy Schubert 			}
1828*be771a7bSCy Schubert 		} else {
1829*be771a7bSCy Schubert 			next = NULL;
1830*be771a7bSCy Schubert 			verbose(1, "write stream -1.");
1831*be771a7bSCy Schubert 			stream_id = -1;
1832*be771a7bSCy Schubert 			fin = 0;
1833*be771a7bSCy Schubert 			datav[0].base = NULL;
1834*be771a7bSCy Schubert 			datav[0].len = 0;
1835*be771a7bSCy Schubert 			datav_count = 1;
1836*be771a7bSCy Schubert 		}
1837*be771a7bSCy Schubert 
1838*be771a7bSCy Schubert 		/* Does the first data entry fit into the send quantum? */
1839*be771a7bSCy Schubert 		/* Check if the data size sent, with a max of one full packet,
1840*be771a7bSCy Schubert 		 * with added stream header and packet header is allowed
1841*be771a7bSCy Schubert 		 * within the send quantum number of bytes. If not, it does
1842*be771a7bSCy Schubert 		 * not fit, and wait. */
1843*be771a7bSCy Schubert 		if(accumulated_send == 0 && ((datav_count == 1 &&
1844*be771a7bSCy Schubert 			(datav[0].len>max_packet_size?max_packet_size:
1845*be771a7bSCy Schubert 			datav[0].len)+overhead_stream+overhead_pkt >
1846*be771a7bSCy Schubert 			send_quantum) ||
1847*be771a7bSCy Schubert 			(datav_count == 2 &&
1848*be771a7bSCy Schubert 			(datav[0].len+datav[1].len>max_packet_size?
1849*be771a7bSCy Schubert 			max_packet_size:datav[0].len+datav[1].len)
1850*be771a7bSCy Schubert 			+overhead_stream+overhead_pkt > send_quantum))) {
1851*be771a7bSCy Schubert 			/* congestion limited */
1852*be771a7bSCy Schubert 			ngtcp2_conn_update_pkt_tx_time(data->conn, ts);
1853*be771a7bSCy Schubert 			event_change_write(data, 0);
1854*be771a7bSCy Schubert 			/* update the timer to wait until it is possible to
1855*be771a7bSCy Schubert 			 * write again */
1856*be771a7bSCy Schubert 			update_timer(data);
1857*be771a7bSCy Schubert 			return 0;
1858*be771a7bSCy Schubert 		}
1859*be771a7bSCy Schubert 		flags = 0;
1860*be771a7bSCy Schubert 		if(str && str->next != NULL) {
1861*be771a7bSCy Schubert 			/* Coalesce more data from more streams into this
1862*be771a7bSCy Schubert 			 * packet, if possible */
1863*be771a7bSCy Schubert 			/* There is more than one data entry in this send
1864*be771a7bSCy Schubert 			 * quantum, does the next one fit in the quantum? */
1865*be771a7bSCy Schubert 			size_t this_send, possible_next_send;
1866*be771a7bSCy Schubert 			if(datav_count == 1)
1867*be771a7bSCy Schubert 				this_send = datav[0].len;
1868*be771a7bSCy Schubert 			else	this_send = datav[0].len + datav[1].len;
1869*be771a7bSCy Schubert 			if(this_send > max_packet_size)
1870*be771a7bSCy Schubert 				this_send = max_packet_size;
1871*be771a7bSCy Schubert 			if(str->next->nwrite < 2)
1872*be771a7bSCy Schubert 				possible_next_send = (2-str->next->nwrite) +
1873*be771a7bSCy Schubert 					str->next->data_len;
1874*be771a7bSCy Schubert 			else	possible_next_send = str->next->data_len -
1875*be771a7bSCy Schubert 					(str->next->nwrite - 2);
1876*be771a7bSCy Schubert 			if(possible_next_send > max_packet_size)
1877*be771a7bSCy Schubert 				possible_next_send = max_packet_size;
1878*be771a7bSCy Schubert 			/* Check if the data lengths that writev returned
1879*be771a7bSCy Schubert 			 * with stream headers added up so far, in
1880*be771a7bSCy Schubert 			 * accumulated_send, with added the data length
1881*be771a7bSCy Schubert 			 * of this send, with a max of one full packet, and
1882*be771a7bSCy Schubert 			 * the data length of the next possible send, with
1883*be771a7bSCy Schubert 			 * a max of one full packet, with a stream header for
1884*be771a7bSCy Schubert 			 * this_send and a stream header for the next possible
1885*be771a7bSCy Schubert 			 * send and a packet header, fit in the send quantum
1886*be771a7bSCy Schubert 			 * number of bytes. If so, ask to add more content
1887*be771a7bSCy Schubert 			 * to the packet with the more flag. */
1888*be771a7bSCy Schubert 			if(accumulated_send + this_send + possible_next_send
1889*be771a7bSCy Schubert 				+2*overhead_stream+ overhead_pkt < send_quantum)
1890*be771a7bSCy Schubert 				flags |= NGTCP2_WRITE_STREAM_FLAG_MORE;
1891*be771a7bSCy Schubert 		}
1892*be771a7bSCy Schubert 		if(fin) {
1893*be771a7bSCy Schubert 			/* This is the final part of data for this stream */
1894*be771a7bSCy Schubert 			flags |= NGTCP2_WRITE_STREAM_FLAG_FIN;
1895*be771a7bSCy Schubert 		}
1896*be771a7bSCy Schubert 		sldns_buffer_clear(data->pkt_buf);
1897*be771a7bSCy Schubert 		ret = ngtcp2_conn_writev_stream(data->conn, &ps.path, &pi,
1898*be771a7bSCy Schubert 			sldns_buffer_begin(data->pkt_buf),
1899*be771a7bSCy Schubert 			sldns_buffer_remaining(data->pkt_buf), &ndatalen,
1900*be771a7bSCy Schubert 			flags, stream_id, datav, datav_count, ts);
1901*be771a7bSCy Schubert 		if(ret < 0) {
1902*be771a7bSCy Schubert 			if(ret == NGTCP2_ERR_WRITE_MORE) {
1903*be771a7bSCy Schubert 				if(str) {
1904*be771a7bSCy Schubert 					str->nwrite += ndatalen;
1905*be771a7bSCy Schubert 					if(str->nwrite >= str->data_len+2)
1906*be771a7bSCy Schubert 						query_write_is_done(data, str);
1907*be771a7bSCy Schubert 					str = next;
1908*be771a7bSCy Schubert 					accumulated_send += ndatalen + overhead_stream;
1909*be771a7bSCy Schubert 					continue;
1910*be771a7bSCy Schubert 				}
1911*be771a7bSCy Schubert 			}
1912*be771a7bSCy Schubert 			log_err("ngtcp2_conn_writev_stream failed: %s",
1913*be771a7bSCy Schubert 				ngtcp2_strerror(ret));
1914*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CCERR_DEFAULT
1915*be771a7bSCy Schubert 			ngtcp2_ccerr_set_liberr(&data->ccerr, ret, NULL, 0);
1916*be771a7bSCy Schubert #else
1917*be771a7bSCy Schubert 			ngtcp2_connection_close_error_set_transport_error_liberr(
1918*be771a7bSCy Schubert 				&data->last_error, ret, NULL, 0);
1919*be771a7bSCy Schubert #endif
1920*be771a7bSCy Schubert 			disconnect(data);
1921*be771a7bSCy Schubert 			return 0;
1922*be771a7bSCy Schubert 		}
1923*be771a7bSCy Schubert 		verbose(1, "writev_stream pkt size %d ndatawritten %d",
1924*be771a7bSCy Schubert 			(int)ret, (int)ndatalen);
1925*be771a7bSCy Schubert 		if(ndatalen >= 0 && str) {
1926*be771a7bSCy Schubert 			/* add the new write offset */
1927*be771a7bSCy Schubert 			str->nwrite += ndatalen;
1928*be771a7bSCy Schubert 			if(str->nwrite >= str->data_len+2)
1929*be771a7bSCy Schubert 				query_write_is_done(data, str);
1930*be771a7bSCy Schubert 		}
1931*be771a7bSCy Schubert 		if(ret == 0) {
1932*be771a7bSCy Schubert 			/* congestion limited */
1933*be771a7bSCy Schubert 			ngtcp2_conn_update_pkt_tx_time(data->conn, ts);
1934*be771a7bSCy Schubert 			event_change_write(data, 0);
1935*be771a7bSCy Schubert 			/* update the timer to wait until it is possible to
1936*be771a7bSCy Schubert 			 * write again */
1937*be771a7bSCy Schubert 			update_timer(data);
1938*be771a7bSCy Schubert 			return 0;
1939*be771a7bSCy Schubert 		}
1940*be771a7bSCy Schubert 		if(!doq_client_send_pkt(data, pi.ecn,
1941*be771a7bSCy Schubert 			sldns_buffer_begin(data->pkt_buf), ret, 0,
1942*be771a7bSCy Schubert 			&send_is_blocked)) {
1943*be771a7bSCy Schubert 			if(send_is_blocked) {
1944*be771a7bSCy Schubert 				/* Blocked packet, wait until it is possible
1945*be771a7bSCy Schubert 				 * to write again and also set a timer. */
1946*be771a7bSCy Schubert 				event_change_write(data, 1);
1947*be771a7bSCy Schubert 				update_timer(data);
1948*be771a7bSCy Schubert 				return 0;
1949*be771a7bSCy Schubert 			}
1950*be771a7bSCy Schubert 			/* Packet could not be sent. Like lost and timeout. */
1951*be771a7bSCy Schubert 			ngtcp2_conn_update_pkt_tx_time(data->conn, ts);
1952*be771a7bSCy Schubert 			event_change_write(data, 0);
1953*be771a7bSCy Schubert 			update_timer(data);
1954*be771a7bSCy Schubert 			return 0;
1955*be771a7bSCy Schubert 		}
1956*be771a7bSCy Schubert 		/* continue */
1957*be771a7bSCy Schubert 		if((size_t)ret >= send_quantum)
1958*be771a7bSCy Schubert 			break;
1959*be771a7bSCy Schubert 		send_quantum -= ret;
1960*be771a7bSCy Schubert 		accumulated_send = 0;
1961*be771a7bSCy Schubert 		str = next;
1962*be771a7bSCy Schubert 		if(str == NULL)
1963*be771a7bSCy Schubert 			break;
1964*be771a7bSCy Schubert 		if(++num_packets == max_packets)
1965*be771a7bSCy Schubert 			break;
1966*be771a7bSCy Schubert 	}
1967*be771a7bSCy Schubert 	ngtcp2_conn_update_pkt_tx_time(data->conn, ts);
1968*be771a7bSCy Schubert 	event_change_write(data, 1);
1969*be771a7bSCy Schubert 	return 1;
1970*be771a7bSCy Schubert }
1971*be771a7bSCy Schubert 
1972*be771a7bSCy Schubert /** send the blocked packet now that the stream is writable again. */
1973*be771a7bSCy Schubert static int
1974*be771a7bSCy Schubert send_blocked_pkt(struct doq_client_data* data)
1975*be771a7bSCy Schubert {
1976*be771a7bSCy Schubert 	ngtcp2_tstamp ts = get_timestamp_nanosec();
1977*be771a7bSCy Schubert 	int send_is_blocked = 0;
1978*be771a7bSCy Schubert 	if(!doq_client_send_pkt(data, data->blocked_pkt_pi.ecn,
1979*be771a7bSCy Schubert 		sldns_buffer_begin(data->pkt_buf),
1980*be771a7bSCy Schubert 		sldns_buffer_limit(data->pkt_buf), 1, &send_is_blocked)) {
1981*be771a7bSCy Schubert 		if(send_is_blocked) {
1982*be771a7bSCy Schubert 			/* Send was blocked, again. Wait, again to retry. */
1983*be771a7bSCy Schubert 			event_change_write(data, 1);
1984*be771a7bSCy Schubert 			/* make sure the timer is set while waiting */
1985*be771a7bSCy Schubert 			update_timer(data);
1986*be771a7bSCy Schubert 			return 0;
1987*be771a7bSCy Schubert 		}
1988*be771a7bSCy Schubert 		/* The packed could not be sent. Like it was lost, timeout. */
1989*be771a7bSCy Schubert 		data->have_blocked_pkt = 0;
1990*be771a7bSCy Schubert 		ngtcp2_conn_update_pkt_tx_time(data->conn, ts);
1991*be771a7bSCy Schubert 		event_change_write(data, 0);
1992*be771a7bSCy Schubert 		update_timer(data);
1993*be771a7bSCy Schubert 		return 0;
1994*be771a7bSCy Schubert 	}
1995*be771a7bSCy Schubert 	/* The blocked packet has been sent, the holding buffer can be
1996*be771a7bSCy Schubert 	 * cleared. */
1997*be771a7bSCy Schubert 	data->have_blocked_pkt = 0;
1998*be771a7bSCy Schubert 	ngtcp2_conn_update_pkt_tx_time(data->conn, ts);
1999*be771a7bSCy Schubert 	return 1;
2000*be771a7bSCy Schubert }
2001*be771a7bSCy Schubert 
2002*be771a7bSCy Schubert /** perform write operations, if any, on fd */
2003*be771a7bSCy Schubert static void
2004*be771a7bSCy Schubert on_write(struct doq_client_data* data)
2005*be771a7bSCy Schubert {
2006*be771a7bSCy Schubert 	if(data->have_blocked_pkt) {
2007*be771a7bSCy Schubert 		if(!send_blocked_pkt(data))
2008*be771a7bSCy Schubert 			return;
2009*be771a7bSCy Schubert 	}
2010*be771a7bSCy Schubert 	if(
2011*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CONN_IN_CLOSING_PERIOD
2012*be771a7bSCy Schubert 		ngtcp2_conn_in_closing_period(data->conn)
2013*be771a7bSCy Schubert #else
2014*be771a7bSCy Schubert 		ngtcp2_conn_is_in_closing_period(data->conn)
2015*be771a7bSCy Schubert #endif
2016*be771a7bSCy Schubert 		)
2017*be771a7bSCy Schubert 		return;
2018*be771a7bSCy Schubert 	if(!write_streams(data))
2019*be771a7bSCy Schubert 		return;
2020*be771a7bSCy Schubert 	update_timer(data);
2021*be771a7bSCy Schubert }
2022*be771a7bSCy Schubert 
2023*be771a7bSCy Schubert /** callback for main listening file descriptor */
2024*be771a7bSCy Schubert void
2025*be771a7bSCy Schubert doq_client_event_cb(int ATTR_UNUSED(fd), short bits, void* arg)
2026*be771a7bSCy Schubert {
2027*be771a7bSCy Schubert 	struct doq_client_data* data = (struct doq_client_data*)arg;
2028*be771a7bSCy Schubert 	verbose(1, "doq_client_event_cb %s%s%s",
2029*be771a7bSCy Schubert 		((bits&UB_EV_READ)!=0?"EV_READ":""),
2030*be771a7bSCy Schubert 		((bits&(UB_EV_READ|UB_EV_WRITE))==(UB_EV_READ|UB_EV_WRITE)?
2031*be771a7bSCy Schubert 		" ":""),
2032*be771a7bSCy Schubert 		((bits&UB_EV_WRITE)!=0?"EV_WRITE":""));
2033*be771a7bSCy Schubert 	if((bits&UB_EV_READ)) {
2034*be771a7bSCy Schubert 		on_read(data);
2035*be771a7bSCy Schubert 	}
2036*be771a7bSCy Schubert 	/* Perform the write operation anyway. The read operation may
2037*be771a7bSCy Schubert 	 * have produced data, or there is content waiting and it is possible
2038*be771a7bSCy Schubert 	 * to write that. */
2039*be771a7bSCy Schubert 	on_write(data);
2040*be771a7bSCy Schubert }
2041*be771a7bSCy Schubert 
2042*be771a7bSCy Schubert /** read the TLS session from file */
2043*be771a7bSCy Schubert static int
2044*be771a7bSCy Schubert early_data_setup_session(struct doq_client_data* data)
2045*be771a7bSCy Schubert {
2046*be771a7bSCy Schubert 	SSL_SESSION* session;
2047*be771a7bSCy Schubert 	BIO* f = BIO_new_file(data->session_file, "r");
2048*be771a7bSCy Schubert 	if(f == NULL) {
2049*be771a7bSCy Schubert 		if(errno == ENOENT) {
2050*be771a7bSCy Schubert 			verbose(1, "session file %s does not exist",
2051*be771a7bSCy Schubert 				data->session_file);
2052*be771a7bSCy Schubert 			return 0;
2053*be771a7bSCy Schubert 		}
2054*be771a7bSCy Schubert 		log_err("Could not read %s: %s", data->session_file,
2055*be771a7bSCy Schubert 			strerror(errno));
2056*be771a7bSCy Schubert 		return 0;
2057*be771a7bSCy Schubert 	}
2058*be771a7bSCy Schubert 	session = PEM_read_bio_SSL_SESSION(f, NULL, 0, NULL);
2059*be771a7bSCy Schubert 	if(session == NULL) {
2060*be771a7bSCy Schubert 		log_crypto_err("Could not read session file with PEM_read_bio_SSL_SESSION");
2061*be771a7bSCy Schubert 		BIO_free(f);
2062*be771a7bSCy Schubert 		return 0;
2063*be771a7bSCy Schubert 	}
2064*be771a7bSCy Schubert 	BIO_free(f);
2065*be771a7bSCy Schubert 	if(!SSL_set_session(data->ssl, session)) {
2066*be771a7bSCy Schubert 		log_crypto_err("Could not SSL_set_session");
2067*be771a7bSCy Schubert 		SSL_SESSION_free(session);
2068*be771a7bSCy Schubert 		return 0;
2069*be771a7bSCy Schubert 	}
2070*be771a7bSCy Schubert 	if(SSL_SESSION_get_max_early_data(session) == 0) {
2071*be771a7bSCy Schubert 		log_err("TLS session early data is 0");
2072*be771a7bSCy Schubert 		SSL_SESSION_free(session);
2073*be771a7bSCy Schubert 		return 0;
2074*be771a7bSCy Schubert 	}
2075*be771a7bSCy Schubert 	SSL_set_quic_early_data_enabled(data->ssl, 1);
2076*be771a7bSCy Schubert 	SSL_SESSION_free(session);
2077*be771a7bSCy Schubert 	return 1;
2078*be771a7bSCy Schubert }
2079*be771a7bSCy Schubert 
2080*be771a7bSCy Schubert #ifndef HAVE_NGTCP2_CONN_ENCODE_0RTT_TRANSPORT_PARAMS
2081*be771a7bSCy Schubert /** parse one line from the transport file */
2082*be771a7bSCy Schubert static int
2083*be771a7bSCy Schubert transport_parse_line(struct ngtcp2_transport_params* params, char* line)
2084*be771a7bSCy Schubert {
2085*be771a7bSCy Schubert 	if(strncmp(line, "initial_max_streams_bidi=", 25) == 0) {
2086*be771a7bSCy Schubert 		params->initial_max_streams_bidi = atoi(line+25);
2087*be771a7bSCy Schubert 		return 1;
2088*be771a7bSCy Schubert 	}
2089*be771a7bSCy Schubert 	if(strncmp(line, "initial_max_streams_uni=", 24) == 0) {
2090*be771a7bSCy Schubert 		params->initial_max_streams_uni = atoi(line+24);
2091*be771a7bSCy Schubert 		return 1;
2092*be771a7bSCy Schubert 	}
2093*be771a7bSCy Schubert 	if(strncmp(line, "initial_max_stream_data_bidi_local=", 35) == 0) {
2094*be771a7bSCy Schubert 		params->initial_max_stream_data_bidi_local = atoi(line+35);
2095*be771a7bSCy Schubert 		return 1;
2096*be771a7bSCy Schubert 	}
2097*be771a7bSCy Schubert 	if(strncmp(line, "initial_max_stream_data_bidi_remote=", 36) == 0) {
2098*be771a7bSCy Schubert 		params->initial_max_stream_data_bidi_remote = atoi(line+36);
2099*be771a7bSCy Schubert 		return 1;
2100*be771a7bSCy Schubert 	}
2101*be771a7bSCy Schubert 	if(strncmp(line, "initial_max_stream_data_uni=", 28) == 0) {
2102*be771a7bSCy Schubert 		params->initial_max_stream_data_uni = atoi(line+28);
2103*be771a7bSCy Schubert 		return 1;
2104*be771a7bSCy Schubert 	}
2105*be771a7bSCy Schubert 	if(strncmp(line, "initial_max_data=", 17) == 0) {
2106*be771a7bSCy Schubert 		params->initial_max_data = atoi(line+17);
2107*be771a7bSCy Schubert 		return 1;
2108*be771a7bSCy Schubert 	}
2109*be771a7bSCy Schubert 	if(strncmp(line, "active_connection_id_limit=", 27) == 0) {
2110*be771a7bSCy Schubert 		params->active_connection_id_limit = atoi(line+27);
2111*be771a7bSCy Schubert 		return 1;
2112*be771a7bSCy Schubert 	}
2113*be771a7bSCy Schubert 	if(strncmp(line, "max_datagram_frame_size=", 24) == 0) {
2114*be771a7bSCy Schubert 		params->max_datagram_frame_size = atoi(line+24);
2115*be771a7bSCy Schubert 		return 1;
2116*be771a7bSCy Schubert 	}
2117*be771a7bSCy Schubert 	return 0;
2118*be771a7bSCy Schubert }
2119*be771a7bSCy Schubert #endif /* HAVE_NGTCP2_CONN_ENCODE_0RTT_TRANSPORT_PARAMS */
2120*be771a7bSCy Schubert 
2121*be771a7bSCy Schubert /** setup the early data transport file and read it */
2122*be771a7bSCy Schubert static int
2123*be771a7bSCy Schubert early_data_setup_transport(struct doq_client_data* data)
2124*be771a7bSCy Schubert {
2125*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CONN_ENCODE_0RTT_TRANSPORT_PARAMS
2126*be771a7bSCy Schubert 	FILE* in;
2127*be771a7bSCy Schubert 	uint8_t buf[1024];
2128*be771a7bSCy Schubert 	size_t len;
2129*be771a7bSCy Schubert 	int rv;
2130*be771a7bSCy Schubert 	in = fopen(data->transport_file, "r");
2131*be771a7bSCy Schubert 	if(!in) {
2132*be771a7bSCy Schubert 		if(errno == ENOENT) {
2133*be771a7bSCy Schubert 			verbose(1, "transport file %s does not exist",
2134*be771a7bSCy Schubert 				data->transport_file);
2135*be771a7bSCy Schubert 			return 0;
2136*be771a7bSCy Schubert 		}
2137*be771a7bSCy Schubert 		perror(data->transport_file);
2138*be771a7bSCy Schubert 		return 0;
2139*be771a7bSCy Schubert 	}
2140*be771a7bSCy Schubert 	len = fread(buf, 1, sizeof(buf), in);
2141*be771a7bSCy Schubert 	if(ferror(in)) {
2142*be771a7bSCy Schubert 		log_err("%s: read failed: %s", data->transport_file,
2143*be771a7bSCy Schubert 			strerror(errno));
2144*be771a7bSCy Schubert 		fclose(in);
2145*be771a7bSCy Schubert 		return 0;
2146*be771a7bSCy Schubert 	}
2147*be771a7bSCy Schubert 	fclose(in);
2148*be771a7bSCy Schubert 	rv = ngtcp2_conn_decode_and_set_0rtt_transport_params(data->conn,
2149*be771a7bSCy Schubert 		buf, len);
2150*be771a7bSCy Schubert 	if(rv != 0) {
2151*be771a7bSCy Schubert 		log_err("ngtcp2_conn_decode_and_set_0rtt_transport_params failed: %s",
2152*be771a7bSCy Schubert 			ngtcp2_strerror(rv));
2153*be771a7bSCy Schubert 		return 0;
2154*be771a7bSCy Schubert 	}
2155*be771a7bSCy Schubert 	return 1;
2156*be771a7bSCy Schubert #else
2157*be771a7bSCy Schubert 	FILE* in;
2158*be771a7bSCy Schubert 	char buf[1024];
2159*be771a7bSCy Schubert 	struct ngtcp2_transport_params params;
2160*be771a7bSCy Schubert 	memset(&params, 0, sizeof(params));
2161*be771a7bSCy Schubert 	in = fopen(data->transport_file, "r");
2162*be771a7bSCy Schubert 	if(!in) {
2163*be771a7bSCy Schubert 		if(errno == ENOENT) {
2164*be771a7bSCy Schubert 			verbose(1, "transport file %s does not exist",
2165*be771a7bSCy Schubert 				data->transport_file);
2166*be771a7bSCy Schubert 			return 0;
2167*be771a7bSCy Schubert 		}
2168*be771a7bSCy Schubert 		perror(data->transport_file);
2169*be771a7bSCy Schubert 		return 0;
2170*be771a7bSCy Schubert 	}
2171*be771a7bSCy Schubert 	while(!feof(in)) {
2172*be771a7bSCy Schubert 		if(!fgets(buf, sizeof(buf), in)) {
2173*be771a7bSCy Schubert 			log_err("%s: read failed: %s", data->transport_file,
2174*be771a7bSCy Schubert 				strerror(errno));
2175*be771a7bSCy Schubert 			fclose(in);
2176*be771a7bSCy Schubert 			return 0;
2177*be771a7bSCy Schubert 		}
2178*be771a7bSCy Schubert 		if(!transport_parse_line(&params, buf)) {
2179*be771a7bSCy Schubert 			log_err("%s: could not parse line '%s'",
2180*be771a7bSCy Schubert 				data->transport_file, buf);
2181*be771a7bSCy Schubert 			fclose(in);
2182*be771a7bSCy Schubert 			return 0;
2183*be771a7bSCy Schubert 		}
2184*be771a7bSCy Schubert 	}
2185*be771a7bSCy Schubert 	fclose(in);
2186*be771a7bSCy Schubert 	ngtcp2_conn_set_early_remote_transport_params(data->conn, &params);
2187*be771a7bSCy Schubert #endif
2188*be771a7bSCy Schubert 	return 1;
2189*be771a7bSCy Schubert }
2190*be771a7bSCy Schubert 
2191*be771a7bSCy Schubert /** setup for early data, read the transport file and session file */
2192*be771a7bSCy Schubert static void
2193*be771a7bSCy Schubert early_data_setup(struct doq_client_data* data)
2194*be771a7bSCy Schubert {
2195*be771a7bSCy Schubert 	if(!early_data_setup_session(data)) {
2196*be771a7bSCy Schubert 		verbose(1, "TLS session resumption failed, early data is disabled");
2197*be771a7bSCy Schubert 		data->early_data_enabled = 0;
2198*be771a7bSCy Schubert 		return;
2199*be771a7bSCy Schubert 	}
2200*be771a7bSCy Schubert 	if(!early_data_setup_transport(data)) {
2201*be771a7bSCy Schubert 		verbose(1, "Transport parameters set failed, early data is disabled");
2202*be771a7bSCy Schubert 		data->early_data_enabled = 0;
2203*be771a7bSCy Schubert 		return;
2204*be771a7bSCy Schubert 	}
2205*be771a7bSCy Schubert }
2206*be771a7bSCy Schubert 
2207*be771a7bSCy Schubert /** start the early data transmission */
2208*be771a7bSCy Schubert static void
2209*be771a7bSCy Schubert early_data_start(struct doq_client_data* data)
2210*be771a7bSCy Schubert {
2211*be771a7bSCy Schubert 	query_streams_start(data);
2212*be771a7bSCy Schubert 	on_write(data);
2213*be771a7bSCy Schubert }
2214*be771a7bSCy Schubert 
2215*be771a7bSCy Schubert /** create doq_client_data */
2216*be771a7bSCy Schubert static struct doq_client_data*
2217*be771a7bSCy Schubert create_doq_client_data(const char* svr, int port, struct ub_event_base* base,
2218*be771a7bSCy Schubert 	const char* transport_file, const char* session_file, int quiet)
2219*be771a7bSCy Schubert {
2220*be771a7bSCy Schubert 	struct doq_client_data* data;
2221*be771a7bSCy Schubert 	data = calloc(1, sizeof(*data));
2222*be771a7bSCy Schubert 	if(!data) fatal_exit("calloc failed: out of memory");
2223*be771a7bSCy Schubert 	data->base = base;
2224*be771a7bSCy Schubert 	data->rnd = ub_initstate(NULL);
2225*be771a7bSCy Schubert 	if(!data->rnd) fatal_exit("ub_initstate failed: out of memory");
2226*be771a7bSCy Schubert 	data->svr = svr;
2227*be771a7bSCy Schubert 	get_dest_addr(data, svr, port);
2228*be771a7bSCy Schubert 	data->port = port;
2229*be771a7bSCy Schubert 	data->quiet = quiet;
2230*be771a7bSCy Schubert 	data->pkt_buf = sldns_buffer_new(65552);
2231*be771a7bSCy Schubert 	if(!data->pkt_buf)
2232*be771a7bSCy Schubert 		fatal_exit("sldns_buffer_new failed: out of memory");
2233*be771a7bSCy Schubert 	data->blocked_pkt = sldns_buffer_new(65552);
2234*be771a7bSCy Schubert 	if(!data->blocked_pkt)
2235*be771a7bSCy Schubert 		fatal_exit("sldns_buffer_new failed: out of memory");
2236*be771a7bSCy Schubert 	data->fd = open_svr_udp(data);
2237*be771a7bSCy Schubert 	get_local_addr(data);
2238*be771a7bSCy Schubert 	data->conn = conn_client_setup(data);
2239*be771a7bSCy Schubert #ifdef HAVE_NGTCP2_CCERR_DEFAULT
2240*be771a7bSCy Schubert 	ngtcp2_ccerr_default(&data->ccerr);
2241*be771a7bSCy Schubert #else
2242*be771a7bSCy Schubert 	ngtcp2_connection_close_error_default(&data->last_error);
2243*be771a7bSCy Schubert #endif
2244*be771a7bSCy Schubert 	data->transport_file = transport_file;
2245*be771a7bSCy Schubert 	data->session_file = session_file;
2246*be771a7bSCy Schubert 	if(data->transport_file && data->session_file)
2247*be771a7bSCy Schubert 		data->early_data_enabled = 1;
2248*be771a7bSCy Schubert 
2249*be771a7bSCy Schubert 	generate_static_secret(data, 32);
2250*be771a7bSCy Schubert 	data->ctx = ctx_client_setup();
2251*be771a7bSCy Schubert 	if(data->session_file) {
2252*be771a7bSCy Schubert 		SSL_CTX_set_session_cache_mode(data->ctx,
2253*be771a7bSCy Schubert 			SSL_SESS_CACHE_CLIENT |
2254*be771a7bSCy Schubert 			SSL_SESS_CACHE_NO_INTERNAL_STORE);
2255*be771a7bSCy Schubert 		SSL_CTX_sess_set_new_cb(data->ctx, new_session_cb);
2256*be771a7bSCy Schubert 	}
2257*be771a7bSCy Schubert 	data->ssl = ssl_client_setup(data);
2258*be771a7bSCy Schubert 	ngtcp2_conn_set_tls_native_handle(data->conn, data->ssl);
2259*be771a7bSCy Schubert 	if(data->early_data_enabled)
2260*be771a7bSCy Schubert 		early_data_setup(data);
2261*be771a7bSCy Schubert 
2262*be771a7bSCy Schubert 	data->ev = ub_event_new(base, data->fd, UB_EV_READ | UB_EV_WRITE |
2263*be771a7bSCy Schubert 		UB_EV_PERSIST, doq_client_event_cb, data);
2264*be771a7bSCy Schubert 	if(!data->ev) {
2265*be771a7bSCy Schubert 		fatal_exit("could not ub_event_new");
2266*be771a7bSCy Schubert 	}
2267*be771a7bSCy Schubert 	if(ub_event_add(data->ev, NULL) != 0) {
2268*be771a7bSCy Schubert 		fatal_exit("could not ub_event_add");
2269*be771a7bSCy Schubert 	}
2270*be771a7bSCy Schubert 	data->expire_timer = ub_event_new(data->base, -1,
2271*be771a7bSCy Schubert 		UB_EV_TIMEOUT, &doq_client_timer_cb, data);
2272*be771a7bSCy Schubert 	if(!data->expire_timer)
2273*be771a7bSCy Schubert 		fatal_exit("could not ub_event_new");
2274*be771a7bSCy Schubert 	data->query_list_start = stream_list_create();
2275*be771a7bSCy Schubert 	data->query_list_send = stream_list_create();
2276*be771a7bSCy Schubert 	data->query_list_receive = stream_list_create();
2277*be771a7bSCy Schubert 	data->query_list_stop = stream_list_create();
2278*be771a7bSCy Schubert 	return data;
2279*be771a7bSCy Schubert }
2280*be771a7bSCy Schubert 
2281*be771a7bSCy Schubert /** delete doq_client_data */
2282*be771a7bSCy Schubert static void
2283*be771a7bSCy Schubert delete_doq_client_data(struct doq_client_data* data)
2284*be771a7bSCy Schubert {
2285*be771a7bSCy Schubert 	if(!data)
2286*be771a7bSCy Schubert 		return;
2287*be771a7bSCy Schubert #if defined(NGTCP2_USE_GENERIC_SOCKADDR) || defined(NGTCP2_USE_GENERIC_IPV6_SOCKADDR)
2288*be771a7bSCy Schubert 	if(data->conn && data->dest_addr_len != 0) {
2289*be771a7bSCy Schubert 		if(addr_is_ip6(&data->dest_addr, data->dest_addr_len)) {
2290*be771a7bSCy Schubert #  if defined(NGTCP2_USE_GENERIC_SOCKADDR) || defined(NGTCP2_USE_GENERIC_IPV6_SOCKADDR)
2291*be771a7bSCy Schubert 			const struct ngtcp2_path* path6 = ngtcp2_conn_get_path(data->conn);
2292*be771a7bSCy Schubert 			free(path6->local.addr);
2293*be771a7bSCy Schubert 			free(path6->remote.addr);
2294*be771a7bSCy Schubert #  endif
2295*be771a7bSCy Schubert 		} else {
2296*be771a7bSCy Schubert #  if defined(NGTCP2_USE_GENERIC_SOCKADDR)
2297*be771a7bSCy Schubert 			const struct ngtcp2_path* path = ngtcp2_conn_get_path(data->conn);
2298*be771a7bSCy Schubert 			free(path->local.addr);
2299*be771a7bSCy Schubert 			free(path->remote.addr);
2300*be771a7bSCy Schubert #  endif
2301*be771a7bSCy Schubert 		}
2302*be771a7bSCy Schubert 	}
2303*be771a7bSCy Schubert #endif
2304*be771a7bSCy Schubert 	ngtcp2_conn_del(data->conn);
2305*be771a7bSCy Schubert 	SSL_free(data->ssl);
2306*be771a7bSCy Schubert 	sldns_buffer_free(data->pkt_buf);
2307*be771a7bSCy Schubert 	sldns_buffer_free(data->blocked_pkt);
2308*be771a7bSCy Schubert 	if(data->fd != -1)
2309*be771a7bSCy Schubert 		sock_close(data->fd);
2310*be771a7bSCy Schubert 	SSL_CTX_free(data->ctx);
2311*be771a7bSCy Schubert 	stream_list_free(data->query_list_start);
2312*be771a7bSCy Schubert 	stream_list_free(data->query_list_send);
2313*be771a7bSCy Schubert 	stream_list_free(data->query_list_receive);
2314*be771a7bSCy Schubert 	stream_list_free(data->query_list_stop);
2315*be771a7bSCy Schubert 	ub_randfree(data->rnd);
2316*be771a7bSCy Schubert 	if(data->ev) {
2317*be771a7bSCy Schubert 		ub_event_del(data->ev);
2318*be771a7bSCy Schubert 		ub_event_free(data->ev);
2319*be771a7bSCy Schubert 	}
2320*be771a7bSCy Schubert 	if(data->expire_timer_added)
2321*be771a7bSCy Schubert 		ub_timer_del(data->expire_timer);
2322*be771a7bSCy Schubert 	ub_event_free(data->expire_timer);
2323*be771a7bSCy Schubert 	free(data->static_secret_data);
2324*be771a7bSCy Schubert 	free(data);
2325*be771a7bSCy Schubert }
2326*be771a7bSCy Schubert 
2327*be771a7bSCy Schubert /** create the event base that registers events and timers */
2328*be771a7bSCy Schubert static struct ub_event_base*
2329*be771a7bSCy Schubert create_event_base(time_t* secs, struct timeval* now)
2330*be771a7bSCy Schubert {
2331*be771a7bSCy Schubert 	struct ub_event_base* base;
2332*be771a7bSCy Schubert 	const char *evnm="event", *evsys="", *evmethod="";
2333*be771a7bSCy Schubert 
2334*be771a7bSCy Schubert 	memset(now, 0, sizeof(*now));
2335*be771a7bSCy Schubert 	base = ub_default_event_base(1, secs, now);
2336*be771a7bSCy Schubert 	if(!base) fatal_exit("could not create ub_event base");
2337*be771a7bSCy Schubert 
2338*be771a7bSCy Schubert 	ub_get_event_sys(base, &evnm, &evsys, &evmethod);
2339*be771a7bSCy Schubert 	if(verbosity) log_info("%s %s uses %s method", evnm, evsys, evmethod);
2340*be771a7bSCy Schubert 
2341*be771a7bSCy Schubert 	return base;
2342*be771a7bSCy Schubert }
2343*be771a7bSCy Schubert 
2344*be771a7bSCy Schubert /** enter a query into the query list */
2345*be771a7bSCy Schubert static void
2346*be771a7bSCy Schubert client_enter_query_buf(struct doq_client_data* data, struct sldns_buffer* buf)
2347*be771a7bSCy Schubert {
2348*be771a7bSCy Schubert 	struct doq_client_stream* str;
2349*be771a7bSCy Schubert 	str = client_stream_create(buf);
2350*be771a7bSCy Schubert 	if(!str)
2351*be771a7bSCy Schubert 		fatal_exit("client_stream_create failed: out of memory");
2352*be771a7bSCy Schubert 	stream_list_append(data->query_list_start, str);
2353*be771a7bSCy Schubert }
2354*be771a7bSCy Schubert 
2355*be771a7bSCy Schubert /** enter the queries into the query list */
2356*be771a7bSCy Schubert static void
2357*be771a7bSCy Schubert client_enter_queries(struct doq_client_data* data, char** qs, int count)
2358*be771a7bSCy Schubert {
2359*be771a7bSCy Schubert 	int i;
2360*be771a7bSCy Schubert 	for(i=0; i<count; i+=3) {
2361*be771a7bSCy Schubert 		struct sldns_buffer* buf = NULL;
2362*be771a7bSCy Schubert 		buf = make_query(qs[i], qs[i+1], qs[i+2]);
2363*be771a7bSCy Schubert 		if(verbosity > 0) {
2364*be771a7bSCy Schubert 			char* str;
2365*be771a7bSCy Schubert 			log_buf(1, "send query", buf);
2366*be771a7bSCy Schubert 			str = sldns_wire2str_pkt(sldns_buffer_begin(buf),
2367*be771a7bSCy Schubert 				sldns_buffer_limit(buf));
2368*be771a7bSCy Schubert 			if(!str) verbose(1, "could not sldns_wire2str_pkt");
2369*be771a7bSCy Schubert 			else verbose(1, "send query:\n%s", str);
2370*be771a7bSCy Schubert 			free(str);
2371*be771a7bSCy Schubert 		}
2372*be771a7bSCy Schubert 		client_enter_query_buf(data, buf);
2373*be771a7bSCy Schubert 		sldns_buffer_free(buf);
2374*be771a7bSCy Schubert 	}
2375*be771a7bSCy Schubert }
2376*be771a7bSCy Schubert 
2377*be771a7bSCy Schubert /** run the dohclient queries */
2378*be771a7bSCy Schubert static void run(const char* svr, int port, char** qs, int count,
2379*be771a7bSCy Schubert 	const char* transport_file, const char* session_file, int quiet)
2380*be771a7bSCy Schubert {
2381*be771a7bSCy Schubert 	time_t secs = 0;
2382*be771a7bSCy Schubert 	struct timeval now;
2383*be771a7bSCy Schubert 	struct ub_event_base* base;
2384*be771a7bSCy Schubert 	struct doq_client_data* data;
2385*be771a7bSCy Schubert 
2386*be771a7bSCy Schubert 	/* setup */
2387*be771a7bSCy Schubert 	base = create_event_base(&secs, &now);
2388*be771a7bSCy Schubert 	data = create_doq_client_data(svr, port, base, transport_file,
2389*be771a7bSCy Schubert 		session_file, quiet);
2390*be771a7bSCy Schubert 	client_enter_queries(data, qs, count);
2391*be771a7bSCy Schubert 	if(data->early_data_enabled)
2392*be771a7bSCy Schubert 		early_data_start(data);
2393*be771a7bSCy Schubert 
2394*be771a7bSCy Schubert 	/* run the queries */
2395*be771a7bSCy Schubert 	ub_event_base_dispatch(base);
2396*be771a7bSCy Schubert 
2397*be771a7bSCy Schubert 	/* cleanup */
2398*be771a7bSCy Schubert 	delete_doq_client_data(data);
2399*be771a7bSCy Schubert 	ub_event_base_free(base);
2400*be771a7bSCy Schubert }
2401*be771a7bSCy Schubert #endif /* HAVE_NGTCP2 */
2402*be771a7bSCy Schubert 
2403*be771a7bSCy Schubert #ifdef HAVE_NGTCP2
2404*be771a7bSCy Schubert /** getopt global, in case header files fail to declare it. */
2405*be771a7bSCy Schubert extern int optind;
2406*be771a7bSCy Schubert /** getopt global, in case header files fail to declare it. */
2407*be771a7bSCy Schubert extern char* optarg;
2408*be771a7bSCy Schubert int main(int ATTR_UNUSED(argc), char** ATTR_UNUSED(argv))
2409*be771a7bSCy Schubert {
2410*be771a7bSCy Schubert 	int c;
2411*be771a7bSCy Schubert 	int port = UNBOUND_DNS_OVER_QUIC_PORT, quiet = 0;
2412*be771a7bSCy Schubert 	const char* svr = "127.0.0.1", *transport_file = NULL,
2413*be771a7bSCy Schubert 		*session_file = NULL;
2414*be771a7bSCy Schubert #ifdef USE_WINSOCK
2415*be771a7bSCy Schubert 	WSADATA wsa_data;
2416*be771a7bSCy Schubert 	if(WSAStartup(MAKEWORD(2,2), &wsa_data) != 0) {
2417*be771a7bSCy Schubert 		printf("WSAStartup failed\n");
2418*be771a7bSCy Schubert 		return 1;
2419*be771a7bSCy Schubert 	}
2420*be771a7bSCy Schubert #endif
2421*be771a7bSCy Schubert 	checklock_set_output_name("ublocktrace-doqclient");
2422*be771a7bSCy Schubert 	checklock_start();
2423*be771a7bSCy Schubert 	log_init(0, 0, 0);
2424*be771a7bSCy Schubert 	log_ident_set("doqclient");
2425*be771a7bSCy Schubert 
2426*be771a7bSCy Schubert 	while((c=getopt(argc, argv, "hp:qs:vx:y:")) != -1) {
2427*be771a7bSCy Schubert 		switch(c) {
2428*be771a7bSCy Schubert 			case 'p':
2429*be771a7bSCy Schubert 				if(atoi(optarg)==0 && strcmp(optarg,"0")!=0) {
2430*be771a7bSCy Schubert 					printf("error parsing port, "
2431*be771a7bSCy Schubert 					    "number expected: %s\n", optarg);
2432*be771a7bSCy Schubert 					return 1;
2433*be771a7bSCy Schubert 				}
2434*be771a7bSCy Schubert 				port = atoi(optarg);
2435*be771a7bSCy Schubert 				break;
2436*be771a7bSCy Schubert 			case 'q':
2437*be771a7bSCy Schubert 				quiet++;
2438*be771a7bSCy Schubert 				break;
2439*be771a7bSCy Schubert 			case 's':
2440*be771a7bSCy Schubert 				svr = optarg;
2441*be771a7bSCy Schubert 				break;
2442*be771a7bSCy Schubert 			case 'v':
2443*be771a7bSCy Schubert 				verbosity++;
2444*be771a7bSCy Schubert 				break;
2445*be771a7bSCy Schubert 			case 'x':
2446*be771a7bSCy Schubert 				transport_file = optarg;
2447*be771a7bSCy Schubert 				break;
2448*be771a7bSCy Schubert 			case 'y':
2449*be771a7bSCy Schubert 				session_file = optarg;
2450*be771a7bSCy Schubert 				break;
2451*be771a7bSCy Schubert 			case 'h':
2452*be771a7bSCy Schubert 			case '?':
2453*be771a7bSCy Schubert 			default:
2454*be771a7bSCy Schubert 				usage(argv);
2455*be771a7bSCy Schubert 		}
2456*be771a7bSCy Schubert 	}
2457*be771a7bSCy Schubert 
2458*be771a7bSCy Schubert 	argc -= optind;
2459*be771a7bSCy Schubert 	argv += optind;
2460*be771a7bSCy Schubert 
2461*be771a7bSCy Schubert 	if(argc%3!=0) {
2462*be771a7bSCy Schubert 		printf("Invalid input. Specify qname, qtype, and qclass.\n");
2463*be771a7bSCy Schubert 		return 1;
2464*be771a7bSCy Schubert 	}
2465*be771a7bSCy Schubert 	if(port == 53) {
2466*be771a7bSCy Schubert 		printf("Error: port number 53 not for DNS over QUIC. Port number 53 is not allowed to be used with DNS over QUIC. It is used for DNS datagrams.\n");
2467*be771a7bSCy Schubert 		return 1;
2468*be771a7bSCy Schubert 	}
2469*be771a7bSCy Schubert 
2470*be771a7bSCy Schubert 	run(svr, port, argv, argc, transport_file, session_file, quiet);
2471*be771a7bSCy Schubert 
2472*be771a7bSCy Schubert 	checklock_stop();
2473*be771a7bSCy Schubert #ifdef USE_WINSOCK
2474*be771a7bSCy Schubert 	WSACleanup();
2475*be771a7bSCy Schubert #endif
2476*be771a7bSCy Schubert 	return 0;
2477*be771a7bSCy Schubert }
2478*be771a7bSCy Schubert #else /* HAVE_NGTCP2 */
2479*be771a7bSCy Schubert int main(int ATTR_UNUSED(argc), char** ATTR_UNUSED(argv))
2480*be771a7bSCy Schubert {
2481*be771a7bSCy Schubert 	printf("Compiled without ngtcp2 for QUIC, cannot run doqclient.\n");
2482*be771a7bSCy Schubert 	return 1;
2483*be771a7bSCy Schubert }
2484*be771a7bSCy Schubert #endif /* HAVE_NGTCP2 */
2485*be771a7bSCy Schubert 
2486*be771a7bSCy Schubert /***--- definitions to make fptr_wlist work. ---***/
2487*be771a7bSCy Schubert /* These are callbacks, similar to smallapp callbacks, except the debug
2488*be771a7bSCy Schubert  * tool callbacks are not in it */
2489*be771a7bSCy Schubert struct tube;
2490*be771a7bSCy Schubert struct query_info;
2491*be771a7bSCy Schubert #include "util/data/packed_rrset.h"
2492*be771a7bSCy Schubert #include "daemon/worker.h"
2493*be771a7bSCy Schubert #include "daemon/remote.h"
2494*be771a7bSCy Schubert #include "util/fptr_wlist.h"
2495*be771a7bSCy Schubert #include "libunbound/context.h"
2496*be771a7bSCy Schubert 
2497*be771a7bSCy Schubert void worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube),
2498*be771a7bSCy Schubert 	uint8_t* ATTR_UNUSED(buffer), size_t ATTR_UNUSED(len),
2499*be771a7bSCy Schubert 	int ATTR_UNUSED(error), void* ATTR_UNUSED(arg))
2500*be771a7bSCy Schubert {
2501*be771a7bSCy Schubert 	log_assert(0);
2502*be771a7bSCy Schubert }
2503*be771a7bSCy Schubert 
2504*be771a7bSCy Schubert int worker_handle_request(struct comm_point* ATTR_UNUSED(c),
2505*be771a7bSCy Schubert 	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
2506*be771a7bSCy Schubert         struct comm_reply* ATTR_UNUSED(repinfo))
2507*be771a7bSCy Schubert {
2508*be771a7bSCy Schubert 	log_assert(0);
2509*be771a7bSCy Schubert 	return 0;
2510*be771a7bSCy Schubert }
2511*be771a7bSCy Schubert 
2512*be771a7bSCy Schubert int worker_handle_service_reply(struct comm_point* ATTR_UNUSED(c),
2513*be771a7bSCy Schubert 	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
2514*be771a7bSCy Schubert         struct comm_reply* ATTR_UNUSED(reply_info))
2515*be771a7bSCy Schubert {
2516*be771a7bSCy Schubert 	log_assert(0);
2517*be771a7bSCy Schubert 	return 0;
2518*be771a7bSCy Schubert }
2519*be771a7bSCy Schubert 
2520*be771a7bSCy Schubert int remote_accept_callback(struct comm_point* ATTR_UNUSED(c),
2521*be771a7bSCy Schubert 	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
2522*be771a7bSCy Schubert         struct comm_reply* ATTR_UNUSED(repinfo))
2523*be771a7bSCy Schubert {
2524*be771a7bSCy Schubert 	log_assert(0);
2525*be771a7bSCy Schubert 	return 0;
2526*be771a7bSCy Schubert }
2527*be771a7bSCy Schubert 
2528*be771a7bSCy Schubert int remote_control_callback(struct comm_point* ATTR_UNUSED(c),
2529*be771a7bSCy Schubert 	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
2530*be771a7bSCy Schubert         struct comm_reply* ATTR_UNUSED(repinfo))
2531*be771a7bSCy Schubert {
2532*be771a7bSCy Schubert 	log_assert(0);
2533*be771a7bSCy Schubert 	return 0;
2534*be771a7bSCy Schubert }
2535*be771a7bSCy Schubert 
2536*be771a7bSCy Schubert void worker_sighandler(int ATTR_UNUSED(sig), void* ATTR_UNUSED(arg))
2537*be771a7bSCy Schubert {
2538*be771a7bSCy Schubert 	log_assert(0);
2539*be771a7bSCy Schubert }
2540*be771a7bSCy Schubert 
2541*be771a7bSCy Schubert struct outbound_entry* worker_send_query(
2542*be771a7bSCy Schubert 	struct query_info* ATTR_UNUSED(qinfo), uint16_t ATTR_UNUSED(flags),
2543*be771a7bSCy Schubert 	int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec),
2544*be771a7bSCy Schubert 	int ATTR_UNUSED(nocaps), int ATTR_UNUSED(check_ratelimit),
2545*be771a7bSCy Schubert 	struct sockaddr_storage* ATTR_UNUSED(addr),
2546*be771a7bSCy Schubert 	socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
2547*be771a7bSCy Schubert 	size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
2548*be771a7bSCy Schubert 	int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
2549*be771a7bSCy Schubert 	struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited))
2550*be771a7bSCy Schubert {
2551*be771a7bSCy Schubert 	log_assert(0);
2552*be771a7bSCy Schubert 	return 0;
2553*be771a7bSCy Schubert }
2554*be771a7bSCy Schubert 
2555*be771a7bSCy Schubert #ifdef UB_ON_WINDOWS
2556*be771a7bSCy Schubert void
2557*be771a7bSCy Schubert worker_win_stop_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), void*
2558*be771a7bSCy Schubert 	ATTR_UNUSED(arg)) {
2559*be771a7bSCy Schubert 	log_assert(0);
2560*be771a7bSCy Schubert }
2561*be771a7bSCy Schubert 
2562*be771a7bSCy Schubert void
2563*be771a7bSCy Schubert wsvc_cron_cb(void* ATTR_UNUSED(arg))
2564*be771a7bSCy Schubert {
2565*be771a7bSCy Schubert 	log_assert(0);
2566*be771a7bSCy Schubert }
2567*be771a7bSCy Schubert #endif /* UB_ON_WINDOWS */
2568*be771a7bSCy Schubert 
2569*be771a7bSCy Schubert void
2570*be771a7bSCy Schubert worker_alloc_cleanup(void* ATTR_UNUSED(arg))
2571*be771a7bSCy Schubert {
2572*be771a7bSCy Schubert 	log_assert(0);
2573*be771a7bSCy Schubert }
2574*be771a7bSCy Schubert 
2575*be771a7bSCy Schubert struct outbound_entry* libworker_send_query(
2576*be771a7bSCy Schubert 	struct query_info* ATTR_UNUSED(qinfo), uint16_t ATTR_UNUSED(flags),
2577*be771a7bSCy Schubert 	int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec),
2578*be771a7bSCy Schubert 	int ATTR_UNUSED(nocaps), int ATTR_UNUSED(check_ratelimit),
2579*be771a7bSCy Schubert 	struct sockaddr_storage* ATTR_UNUSED(addr),
2580*be771a7bSCy Schubert 	socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
2581*be771a7bSCy Schubert 	size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
2582*be771a7bSCy Schubert 	int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
2583*be771a7bSCy Schubert 	struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited))
2584*be771a7bSCy Schubert {
2585*be771a7bSCy Schubert 	log_assert(0);
2586*be771a7bSCy Schubert 	return 0;
2587*be771a7bSCy Schubert }
2588*be771a7bSCy Schubert 
2589*be771a7bSCy Schubert int libworker_handle_service_reply(struct comm_point* ATTR_UNUSED(c),
2590*be771a7bSCy Schubert 	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
2591*be771a7bSCy Schubert         struct comm_reply* ATTR_UNUSED(reply_info))
2592*be771a7bSCy Schubert {
2593*be771a7bSCy Schubert 	log_assert(0);
2594*be771a7bSCy Schubert 	return 0;
2595*be771a7bSCy Schubert }
2596*be771a7bSCy Schubert 
2597*be771a7bSCy Schubert void libworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube),
2598*be771a7bSCy Schubert         uint8_t* ATTR_UNUSED(buffer), size_t ATTR_UNUSED(len),
2599*be771a7bSCy Schubert         int ATTR_UNUSED(error), void* ATTR_UNUSED(arg))
2600*be771a7bSCy Schubert {
2601*be771a7bSCy Schubert         log_assert(0);
2602*be771a7bSCy Schubert }
2603*be771a7bSCy Schubert 
2604*be771a7bSCy Schubert void libworker_fg_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
2605*be771a7bSCy Schubert 	struct sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s),
2606*be771a7bSCy Schubert 	char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited))
2607*be771a7bSCy Schubert {
2608*be771a7bSCy Schubert 	log_assert(0);
2609*be771a7bSCy Schubert }
2610*be771a7bSCy Schubert 
2611*be771a7bSCy Schubert void libworker_bg_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
2612*be771a7bSCy Schubert 	struct sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s),
2613*be771a7bSCy Schubert 	char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited))
2614*be771a7bSCy Schubert {
2615*be771a7bSCy Schubert 	log_assert(0);
2616*be771a7bSCy Schubert }
2617*be771a7bSCy Schubert 
2618*be771a7bSCy Schubert void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
2619*be771a7bSCy Schubert 	struct sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s),
2620*be771a7bSCy Schubert 	char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited))
2621*be771a7bSCy Schubert {
2622*be771a7bSCy Schubert 	log_assert(0);
2623*be771a7bSCy Schubert }
2624*be771a7bSCy Schubert 
2625*be771a7bSCy Schubert int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
2626*be771a7bSCy Schubert {
2627*be771a7bSCy Schubert 	log_assert(0);
2628*be771a7bSCy Schubert 	return 0;
2629*be771a7bSCy Schubert }
2630*be771a7bSCy Schubert 
2631*be771a7bSCy Schubert void worker_stat_timer_cb(void* ATTR_UNUSED(arg))
2632*be771a7bSCy Schubert {
2633*be771a7bSCy Schubert 	log_assert(0);
2634*be771a7bSCy Schubert }
2635*be771a7bSCy Schubert 
2636*be771a7bSCy Schubert void worker_probe_timer_cb(void* ATTR_UNUSED(arg))
2637*be771a7bSCy Schubert {
2638*be771a7bSCy Schubert 	log_assert(0);
2639*be771a7bSCy Schubert }
2640*be771a7bSCy Schubert 
2641*be771a7bSCy Schubert void worker_start_accept(void* ATTR_UNUSED(arg))
2642*be771a7bSCy Schubert {
2643*be771a7bSCy Schubert 	log_assert(0);
2644*be771a7bSCy Schubert }
2645*be771a7bSCy Schubert 
2646*be771a7bSCy Schubert void worker_stop_accept(void* ATTR_UNUSED(arg))
2647*be771a7bSCy Schubert {
2648*be771a7bSCy Schubert 	log_assert(0);
2649*be771a7bSCy Schubert }
2650*be771a7bSCy Schubert 
2651*be771a7bSCy Schubert /** keep track of lock id in lock-verify application */
2652*be771a7bSCy Schubert struct order_id {
2653*be771a7bSCy Schubert         /** the thread id that created it */
2654*be771a7bSCy Schubert         int thr;
2655*be771a7bSCy Schubert         /** the instance number of creation */
2656*be771a7bSCy Schubert         int instance;
2657*be771a7bSCy Schubert };
2658*be771a7bSCy Schubert 
2659*be771a7bSCy Schubert int order_lock_cmp(const void* e1, const void* e2)
2660*be771a7bSCy Schubert {
2661*be771a7bSCy Schubert         const struct order_id* o1 = e1;
2662*be771a7bSCy Schubert         const struct order_id* o2 = e2;
2663*be771a7bSCy Schubert         if(o1->thr < o2->thr) return -1;
2664*be771a7bSCy Schubert         if(o1->thr > o2->thr) return 1;
2665*be771a7bSCy Schubert         if(o1->instance < o2->instance) return -1;
2666*be771a7bSCy Schubert         if(o1->instance > o2->instance) return 1;
2667*be771a7bSCy Schubert         return 0;
2668*be771a7bSCy Schubert }
2669*be771a7bSCy Schubert 
2670*be771a7bSCy Schubert int
2671*be771a7bSCy Schubert codeline_cmp(const void* a, const void* b)
2672*be771a7bSCy Schubert {
2673*be771a7bSCy Schubert         return strcmp(a, b);
2674*be771a7bSCy Schubert }
2675*be771a7bSCy Schubert 
2676*be771a7bSCy Schubert int replay_var_compare(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
2677*be771a7bSCy Schubert {
2678*be771a7bSCy Schubert         log_assert(0);
2679*be771a7bSCy Schubert         return 0;
2680*be771a7bSCy Schubert }
2681*be771a7bSCy Schubert 
2682*be771a7bSCy Schubert void remote_get_opt_ssl(char* ATTR_UNUSED(str), void* ATTR_UNUSED(arg))
2683*be771a7bSCy Schubert {
2684*be771a7bSCy Schubert         log_assert(0);
2685*be771a7bSCy Schubert }
2686*be771a7bSCy Schubert 
2687*be771a7bSCy Schubert #ifdef USE_DNSTAP
2688*be771a7bSCy Schubert void dtio_tap_callback(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
2689*be771a7bSCy Schubert 	void* ATTR_UNUSED(arg))
2690*be771a7bSCy Schubert {
2691*be771a7bSCy Schubert 	log_assert(0);
2692*be771a7bSCy Schubert }
2693*be771a7bSCy Schubert #endif
2694*be771a7bSCy Schubert 
2695*be771a7bSCy Schubert #ifdef USE_DNSTAP
2696*be771a7bSCy Schubert void dtio_mainfdcallback(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
2697*be771a7bSCy Schubert 	void* ATTR_UNUSED(arg))
2698*be771a7bSCy Schubert {
2699*be771a7bSCy Schubert 	log_assert(0);
2700*be771a7bSCy Schubert }
2701*be771a7bSCy Schubert #endif
2702*be771a7bSCy Schubert 
2703*be771a7bSCy Schubert void fast_reload_service_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
2704*be771a7bSCy Schubert 	void* ATTR_UNUSED(arg))
2705*be771a7bSCy Schubert {
2706*be771a7bSCy Schubert 	log_assert(0);
2707*be771a7bSCy Schubert }
2708*be771a7bSCy Schubert 
2709*be771a7bSCy Schubert int fast_reload_client_callback(struct comm_point* ATTR_UNUSED(c),
2710*be771a7bSCy Schubert 	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
2711*be771a7bSCy Schubert         struct comm_reply* ATTR_UNUSED(repinfo))
2712*be771a7bSCy Schubert {
2713*be771a7bSCy Schubert 	log_assert(0);
2714*be771a7bSCy Schubert 	return 0;
2715*be771a7bSCy Schubert }
2716