]>
Commit | Line | Data |
---|---|---|
51a168b8 HL |
1 | /* |
2 | * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved. | |
3 | * | |
4 | * Licensed under the Apache License 2.0 (the "License"). You may not use | |
5 | * this file except in compliance with the License. You can obtain a copy | |
6 | * in the file LICENSE in the source distribution or at | |
7 | * https://www.openssl.org/source/license.html | |
8 | */ | |
9 | ||
10 | #include "internal/quic_tserver.h" | |
11 | #include "internal/quic_channel.h" | |
12 | #include "internal/quic_statm.h" | |
13 | #include "internal/common.h" | |
14 | ||
15 | /* | |
16 | * QUIC Test Server Module | |
17 | * ======================= | |
18 | */ | |
19 | struct quic_tserver_st { | |
20 | QUIC_TSERVER_ARGS args; | |
21 | ||
22 | /* | |
23 | * The QUIC channel providing the core QUIC connection implementation. | |
24 | */ | |
25 | QUIC_CHANNEL *ch; | |
26 | ||
4e3a55fd MC |
27 | /* SSL_CTX for creating the underlying TLS connection */ |
28 | SSL_CTX *ctx; | |
29 | ||
30 | /* SSL for the underlying TLS connection */ | |
31 | SSL *tls; | |
32 | ||
51a168b8 HL |
33 | /* Our single bidirectional application data stream. */ |
34 | QUIC_STREAM *stream0; | |
35 | ||
36 | /* The current peer L4 address. AF_UNSPEC if we do not have a peer yet. */ | |
37 | BIO_ADDR cur_peer_addr; | |
38 | ||
39 | /* Are we connected to a peer? */ | |
40 | unsigned int connected : 1; | |
41 | }; | |
42 | ||
4e3a55fd MC |
43 | static int alpn_select_cb(SSL *ssl, const unsigned char **out, |
44 | unsigned char *outlen, const unsigned char *in, | |
45 | unsigned int inlen, void *arg) | |
46 | { | |
47 | unsigned char alpn[] = { 8, 'o', 's', 's', 'l', 't', 'e', 's', 't' }; | |
48 | ||
49 | if (SSL_select_next_proto((unsigned char **)out, outlen, alpn, sizeof(alpn), | |
50 | in, inlen) != OPENSSL_NPN_NEGOTIATED) | |
51 | return SSL_TLSEXT_ERR_ALERT_FATAL; | |
52 | ||
53 | return SSL_TLSEXT_ERR_OK; | |
54 | } | |
55 | ||
56 | QUIC_TSERVER *ossl_quic_tserver_new(const QUIC_TSERVER_ARGS *args, | |
57 | const char *certfile, const char *keyfile) | |
51a168b8 HL |
58 | { |
59 | QUIC_TSERVER *srv = NULL; | |
60 | QUIC_CHANNEL_ARGS ch_args = {0}; | |
61 | ||
62 | if (args->net_rbio == NULL || args->net_wbio == NULL) | |
63 | goto err; | |
64 | ||
65 | if ((srv = OPENSSL_zalloc(sizeof(*srv))) == NULL) | |
66 | goto err; | |
67 | ||
68 | srv->args = *args; | |
69 | ||
4e3a55fd MC |
70 | srv->ctx = SSL_CTX_new_ex(srv->args.libctx, srv->args.propq, TLS_method()); |
71 | if (srv->ctx == NULL) | |
72 | goto err; | |
73 | ||
74 | if (SSL_CTX_use_certificate_file(srv->ctx, certfile, SSL_FILETYPE_PEM) <= 0) | |
75 | goto err; | |
76 | ||
77 | if (SSL_CTX_use_PrivateKey_file(srv->ctx, keyfile, SSL_FILETYPE_PEM) <= 0) | |
78 | goto err; | |
79 | ||
80 | SSL_CTX_set_alpn_select_cb(srv->ctx, alpn_select_cb, srv); | |
81 | ||
82 | srv->tls = SSL_new(srv->ctx); | |
83 | if (srv->tls == NULL) | |
84 | goto err; | |
85 | ||
51a168b8 HL |
86 | ch_args.libctx = srv->args.libctx; |
87 | ch_args.propq = srv->args.propq; | |
4e3a55fd | 88 | ch_args.tls = srv->tls; |
51a168b8 HL |
89 | ch_args.is_server = 1; |
90 | ||
91 | if ((srv->ch = ossl_quic_channel_new(&ch_args)) == NULL) | |
92 | goto err; | |
93 | ||
94 | if (!ossl_quic_channel_set_net_rbio(srv->ch, srv->args.net_rbio) | |
95 | || !ossl_quic_channel_set_net_wbio(srv->ch, srv->args.net_wbio)) | |
96 | goto err; | |
97 | ||
98 | srv->stream0 = ossl_quic_channel_get_stream_by_id(srv->ch, 0); | |
99 | if (srv->stream0 == NULL) | |
100 | goto err; | |
101 | ||
102 | return srv; | |
103 | ||
104 | err: | |
105 | if (srv != NULL) | |
106 | ossl_quic_channel_free(srv->ch); | |
107 | ||
108 | OPENSSL_free(srv); | |
109 | return NULL; | |
110 | } | |
111 | ||
112 | void ossl_quic_tserver_free(QUIC_TSERVER *srv) | |
113 | { | |
114 | if (srv == NULL) | |
115 | return; | |
116 | ||
117 | ossl_quic_channel_free(srv->ch); | |
118 | BIO_free(srv->args.net_rbio); | |
119 | BIO_free(srv->args.net_wbio); | |
4e3a55fd MC |
120 | SSL_free(srv->tls); |
121 | SSL_CTX_free(srv->ctx); | |
51a168b8 HL |
122 | OPENSSL_free(srv); |
123 | } | |
124 | ||
14e31409 MC |
125 | /* Set mutator callbacks for test framework support */ |
126 | int ossl_quic_tserver_set_mutator(QUIC_TSERVER *srv, | |
127 | ossl_mutate_packet_cb mutatecb, | |
128 | ossl_finish_mutate_cb finishmutatecb, | |
129 | void *mutatearg) | |
130 | { | |
131 | return ossl_quic_channel_set_mutator(srv->ch, mutatecb, finishmutatecb, | |
132 | mutatearg); | |
133 | } | |
134 | ||
51a168b8 HL |
135 | int ossl_quic_tserver_tick(QUIC_TSERVER *srv) |
136 | { | |
137 | ossl_quic_reactor_tick(ossl_quic_channel_get_reactor(srv->ch)); | |
138 | ||
139 | if (ossl_quic_channel_is_active(srv->ch)) | |
140 | srv->connected = 1; | |
141 | ||
142 | return 1; | |
143 | } | |
144 | ||
145 | int ossl_quic_tserver_is_connected(QUIC_TSERVER *srv) | |
146 | { | |
147 | return ossl_quic_channel_is_active(srv->ch); | |
148 | } | |
149 | ||
adef87a2 | 150 | /* Returns 1 if the server is in any terminating or terminated state */ |
149a8e6c MC |
151 | int ossl_quic_tserver_is_term_any(QUIC_TSERVER *srv, |
152 | QUIC_TERMINATE_CAUSE *cause) | |
adef87a2 | 153 | { |
149a8e6c MC |
154 | return ossl_quic_channel_is_term_any(srv->ch, cause); |
155 | } | |
156 | ||
157 | /* Returns 1 if the server is in a terminated state */ | |
158 | int ossl_quic_tserver_is_terminated(QUIC_TSERVER *srv, | |
159 | QUIC_TERMINATE_CAUSE *cause) | |
160 | { | |
161 | return ossl_quic_channel_is_terminated(srv->ch, cause); | |
adef87a2 MC |
162 | } |
163 | ||
51a168b8 HL |
164 | int ossl_quic_tserver_read(QUIC_TSERVER *srv, |
165 | unsigned char *buf, | |
166 | size_t buf_len, | |
167 | size_t *bytes_read) | |
168 | { | |
a9979965 | 169 | int is_fin = 0; |
51a168b8 HL |
170 | |
171 | if (!ossl_quic_channel_is_active(srv->ch)) | |
172 | return 0; | |
173 | ||
a9979965 HL |
174 | if (srv->stream0->recv_fin_retired) |
175 | return 0; | |
176 | ||
51a168b8 HL |
177 | if (!ossl_quic_rstream_read(srv->stream0->rstream, buf, buf_len, |
178 | bytes_read, &is_fin)) | |
179 | return 0; | |
180 | ||
181 | if (*bytes_read > 0) { | |
182 | /* | |
183 | * We have read at least one byte from the stream. Inform stream-level | |
184 | * RXFC of the retirement of controlled bytes. Update the active stream | |
185 | * status (the RXFC may now want to emit a frame granting more credit to | |
186 | * the peer). | |
187 | */ | |
188 | OSSL_RTT_INFO rtt_info; | |
091f532e | 189 | |
51a168b8 HL |
190 | ossl_statm_get_rtt_info(ossl_quic_channel_get_statm(srv->ch), &rtt_info); |
191 | ||
192 | if (!ossl_quic_rxfc_on_retire(&srv->stream0->rxfc, *bytes_read, | |
193 | rtt_info.smoothed_rtt)) | |
194 | return 0; | |
195 | } | |
196 | ||
197 | if (is_fin) | |
198 | srv->stream0->recv_fin_retired = 1; | |
199 | ||
200 | if (*bytes_read > 0) | |
201 | ossl_quic_stream_map_update_state(ossl_quic_channel_get_qsm(srv->ch), | |
202 | srv->stream0); | |
203 | ||
204 | return 1; | |
205 | } | |
206 | ||
a9979965 HL |
207 | int ossl_quic_tserver_has_read_ended(QUIC_TSERVER *srv) |
208 | { | |
209 | return srv->stream0->recv_fin_retired; | |
210 | } | |
211 | ||
51a168b8 HL |
212 | int ossl_quic_tserver_write(QUIC_TSERVER *srv, |
213 | const unsigned char *buf, | |
214 | size_t buf_len, | |
215 | size_t *bytes_written) | |
216 | { | |
217 | if (!ossl_quic_channel_is_active(srv->ch)) | |
218 | return 0; | |
219 | ||
220 | if (!ossl_quic_sstream_append(srv->stream0->sstream, | |
221 | buf, buf_len, bytes_written)) | |
222 | return 0; | |
223 | ||
224 | if (*bytes_written > 0) | |
225 | /* | |
226 | * We have appended at least one byte to the stream. Potentially mark | |
227 | * the stream as active, depending on FC. | |
228 | */ | |
229 | ossl_quic_stream_map_update_state(ossl_quic_channel_get_qsm(srv->ch), | |
230 | srv->stream0); | |
231 | ||
232 | /* Try and send. */ | |
233 | ossl_quic_tserver_tick(srv); | |
234 | return 1; | |
235 | } | |
a9979965 HL |
236 | |
237 | int ossl_quic_tserver_conclude(QUIC_TSERVER *srv) | |
238 | { | |
239 | if (!ossl_quic_channel_is_active(srv->ch)) | |
240 | return 0; | |
241 | ||
242 | if (!ossl_quic_sstream_get_final_size(srv->stream0->sstream, NULL)) { | |
243 | ossl_quic_sstream_fin(srv->stream0->sstream); | |
244 | ossl_quic_stream_map_update_state(ossl_quic_channel_get_qsm(srv->ch), | |
245 | srv->stream0); | |
246 | } | |
247 | ||
248 | ossl_quic_tserver_tick(srv); | |
249 | return 1; | |
250 | } |