quic 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.clang-format +1 -0
- data/.git-blame-ignore-revs +2 -0
- data/CHANGELOG.md +9 -0
- data/README.md +76 -2
- data/examples/demo_certificates.rb +67 -0
- data/examples/echo_endpoint_demo.rb +170 -0
- data/examples/echo_server_demo.rb +2 -58
- data/ext/quic/connection_client.c +77 -59
- data/ext/quic/connection_common.c +358 -365
- data/ext/quic/connection_common.h +20 -11
- data/ext/quic/connection_server.c +67 -48
- data/ext/quic/endpoint.c +206 -200
- data/ext/quic/endpoint.h +8 -5
- data/ext/quic/ext_api.c +41 -47
- data/ext/quic/include/quic/ext.h +26 -19
- data/ext/quic/quic.c +75 -67
- data/ext/quic/quic.h +4 -2
- data/ext/quic/stream.c +55 -74
- data/ext/quic/stream.h +5 -5
- data/ext/quic/tls_context.c +79 -70
- data/ext/quic/tls_context.h +2 -1
- data/lib/quic/version.rb +1 -1
- metadata +5 -1
|
@@ -13,31 +13,30 @@
|
|
|
13
13
|
in supported_groups and reached via HelloRetryRequest. X25519 is first so
|
|
14
14
|
the common case stays 1-RTT. */
|
|
15
15
|
ptls_key_exchange_algorithm_t *quic_key_exchanges[] = {
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
&ptls_openssl_x25519,
|
|
17
|
+
&ptls_openssl_secp256r1,
|
|
18
18
|
#if PTLS_OPENSSL_HAVE_SECP384R1
|
|
19
|
-
|
|
19
|
+
&ptls_openssl_secp384r1,
|
|
20
20
|
#endif
|
|
21
|
-
|
|
21
|
+
NULL,
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
ptls_cipher_suite_t *quic_cipher_suites[] = {
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
&ptls_openssl_aes128gcmsha256,
|
|
26
|
+
&ptls_openssl_aes256gcmsha384,
|
|
27
27
|
#if PTLS_OPENSSL_HAVE_CHACHA20_POLY1305
|
|
28
|
-
|
|
28
|
+
&ptls_openssl_chacha20poly1305sha256,
|
|
29
29
|
#endif
|
|
30
|
-
|
|
30
|
+
NULL,
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
static void
|
|
34
|
-
quic_conn_free(void *ptr)
|
|
35
|
-
{
|
|
33
|
+
static void quic_conn_free(void *ptr) {
|
|
36
34
|
quic_conn_t *c = (quic_conn_t *)ptr;
|
|
37
35
|
/* The Endpoint may be swept in the same GC cycle and freed first; nothing
|
|
38
36
|
from here on may reach its CID table. */
|
|
39
37
|
c->endpoint = NULL;
|
|
40
|
-
if (c->conn)
|
|
38
|
+
if (c->conn)
|
|
39
|
+
ngtcp2_conn_del(c->conn);
|
|
41
40
|
if (c->cptls.ptls) {
|
|
42
41
|
/* Safe even when configure_client_session never ran or failed midway. */
|
|
43
42
|
ngtcp2_crypto_picotls_deconfigure_session(&c->cptls);
|
|
@@ -45,26 +44,25 @@ quic_conn_free(void *ptr)
|
|
|
45
44
|
}
|
|
46
45
|
/* After ptls_free: the ptls_t references verify_cert through tls_ctx, or
|
|
47
46
|
the shared context on a server. */
|
|
48
|
-
if (c->verify_cert_initialized)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
if (c->verify_cert_initialized)
|
|
48
|
+
ptls_openssl_dispose_verify_certificate(&c->verify_cert);
|
|
49
|
+
if (c->tls != NULL)
|
|
50
|
+
quic_tls_ctx_unref(c->tls);
|
|
51
|
+
/* Still open only if no ngtcp2_conn was made to finish it; the
|
|
52
|
+
constructors close it before raising, so this is a safety net. */
|
|
53
|
+
quic_conn_close_qlog(c);
|
|
52
54
|
xfree(c->alpn);
|
|
53
55
|
xfree(c->alpn_buf);
|
|
54
56
|
xfree(c);
|
|
55
57
|
}
|
|
56
58
|
|
|
57
|
-
static size_t
|
|
58
|
-
quic_conn_size(const void *ptr)
|
|
59
|
-
{
|
|
59
|
+
static size_t quic_conn_size(const void *ptr) {
|
|
60
60
|
(void)ptr;
|
|
61
61
|
return sizeof(quic_conn_t);
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
/* owner is the object wrapping this struct, so it needs no mark. */
|
|
65
|
-
static void
|
|
66
|
-
quic_conn_mark(void *ptr)
|
|
67
|
-
{
|
|
65
|
+
static void quic_conn_mark(void *ptr) {
|
|
68
66
|
quic_conn_t *c = (quic_conn_t *)ptr;
|
|
69
67
|
rb_gc_mark_movable(c->pending_exc);
|
|
70
68
|
rb_gc_mark_movable(c->handler_owner);
|
|
@@ -77,9 +75,7 @@ quic_conn_mark(void *ptr)
|
|
|
77
75
|
void* user_data ngtcp2 callbacks receive (which equals this struct,
|
|
78
76
|
stored inside owner) keeps resolving @streams / @accept_queue. The
|
|
79
77
|
raw ngtcp2/picotls pointers are outside Ruby's heap and are left alone. */
|
|
80
|
-
static void
|
|
81
|
-
quic_conn_compact(void *ptr)
|
|
82
|
-
{
|
|
78
|
+
static void quic_conn_compact(void *ptr) {
|
|
83
79
|
quic_conn_t *c = (quic_conn_t *)ptr;
|
|
84
80
|
c->owner = rb_gc_location(c->owner);
|
|
85
81
|
c->pending_exc = rb_gc_location(c->pending_exc);
|
|
@@ -90,15 +86,20 @@ quic_conn_compact(void *ptr)
|
|
|
90
86
|
}
|
|
91
87
|
|
|
92
88
|
const rb_data_type_t quic_conn_data_type = {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
89
|
+
"QUIC::Connection",
|
|
90
|
+
{
|
|
91
|
+
quic_conn_mark,
|
|
92
|
+
quic_conn_free,
|
|
93
|
+
quic_conn_size,
|
|
94
|
+
quic_conn_compact,
|
|
95
|
+
},
|
|
96
|
+
NULL,
|
|
97
|
+
NULL,
|
|
98
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
|
97
99
|
};
|
|
98
100
|
|
|
99
101
|
VALUE
|
|
100
|
-
quic_conn_alloc(VALUE klass)
|
|
101
|
-
{
|
|
102
|
+
quic_conn_alloc(VALUE klass) {
|
|
102
103
|
quic_conn_t *c = ALLOC(quic_conn_t);
|
|
103
104
|
memset(c, 0, sizeof(*c));
|
|
104
105
|
c->pending_exc = Qnil;
|
|
@@ -112,10 +113,9 @@ quic_conn_alloc(VALUE klass)
|
|
|
112
113
|
/* Re-raise the exception a callback left in c->pending_exc, if any. Called
|
|
113
114
|
right after ngtcp2 returns, before its return value is looked at: the
|
|
114
115
|
NGTCP2_ERR_CALLBACK_FAILURE it reports is the result of that exception. */
|
|
115
|
-
static void
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
if (NIL_P(c->pending_exc)) return;
|
|
116
|
+
static void quic_conn_raise_pending(quic_conn_t *c) {
|
|
117
|
+
if (NIL_P(c->pending_exc))
|
|
118
|
+
return;
|
|
119
119
|
VALUE exc = c->pending_exc;
|
|
120
120
|
c->pending_exc = Qnil;
|
|
121
121
|
rb_exc_raise(exc);
|
|
@@ -125,42 +125,33 @@ quic_conn_raise_pending(quic_conn_t *c)
|
|
|
125
125
|
(the first one wins; ngtcp2 stops at the first failing callback anyway)
|
|
126
126
|
and turned into NGTCP2_ERR_CALLBACK_FAILURE, so that it never unwinds
|
|
127
127
|
through ngtcp2. */
|
|
128
|
-
static int
|
|
129
|
-
quic_conn_protect(quic_conn_t *c, VALUE (*body)(VALUE), void *arg)
|
|
130
|
-
{
|
|
128
|
+
static int quic_conn_protect(quic_conn_t *c, VALUE (*body)(VALUE), void *arg) {
|
|
131
129
|
int state = 0;
|
|
132
130
|
rb_protect(body, (VALUE)arg, &state);
|
|
133
|
-
if (state == 0)
|
|
134
|
-
|
|
131
|
+
if (state == 0)
|
|
132
|
+
return 0;
|
|
133
|
+
if (NIL_P(c->pending_exc))
|
|
134
|
+
c->pending_exc = rb_errinfo();
|
|
135
135
|
rb_set_errinfo(Qnil);
|
|
136
136
|
return NGTCP2_ERR_CALLBACK_FAILURE;
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
-
quic_conn_t *
|
|
140
|
-
quic_conn_get(VALUE self)
|
|
141
|
-
{
|
|
139
|
+
quic_conn_t *quic_conn_get(VALUE self) {
|
|
142
140
|
quic_conn_t *c;
|
|
143
141
|
TypedData_Get_Struct(self, quic_conn_t, &quic_conn_data_type, c);
|
|
144
142
|
return c;
|
|
145
143
|
}
|
|
146
144
|
|
|
147
|
-
ngtcp2_conn *
|
|
148
|
-
quic_conn_ptr(VALUE owner)
|
|
149
|
-
{
|
|
150
|
-
return quic_conn_get(owner)->conn;
|
|
151
|
-
}
|
|
145
|
+
ngtcp2_conn *quic_conn_ptr(VALUE owner) { return quic_conn_get(owner)->conn; }
|
|
152
146
|
|
|
153
|
-
ngtcp2_tstamp
|
|
154
|
-
quic_now(void)
|
|
155
|
-
{
|
|
147
|
+
ngtcp2_tstamp quic_now(void) {
|
|
156
148
|
struct timespec ts;
|
|
157
149
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
158
150
|
return (ngtcp2_tstamp)ts.tv_sec * NGTCP2_SECONDS + (ngtcp2_tstamp)ts.tv_nsec;
|
|
159
151
|
}
|
|
160
152
|
|
|
161
|
-
static void
|
|
162
|
-
|
|
163
|
-
{
|
|
153
|
+
static void quic_rand_cb(uint8_t *dest, size_t destlen,
|
|
154
|
+
const ngtcp2_rand_ctx *rand_ctx) {
|
|
164
155
|
(void)rand_ctx;
|
|
165
156
|
RAND_bytes(dest, (int)destlen);
|
|
166
157
|
}
|
|
@@ -168,11 +159,9 @@ quic_rand_cb(uint8_t *dest, size_t destlen, const ngtcp2_rand_ctx *rand_ctx)
|
|
|
168
159
|
/* A connection an Endpoint holds derives the token from the Endpoint's
|
|
169
160
|
secret and enters the new CID in its table. Any other connection never
|
|
170
161
|
sends a Stateless Reset, so a random token does. */
|
|
171
|
-
static int
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
void *user_data)
|
|
175
|
-
{
|
|
162
|
+
static int quic_get_new_connection_id_cb(ngtcp2_conn *conn, ngtcp2_cid *cid,
|
|
163
|
+
ngtcp2_stateless_reset_token *token,
|
|
164
|
+
size_t cidlen, void *user_data) {
|
|
176
165
|
(void)conn;
|
|
177
166
|
quic_conn_t *c = (quic_conn_t *)user_data;
|
|
178
167
|
if (RAND_bytes(cid->data, (int)cidlen) != 1) {
|
|
@@ -181,7 +170,8 @@ quic_get_new_connection_id_cb(ngtcp2_conn *conn, ngtcp2_cid *cid,
|
|
|
181
170
|
cid->datalen = cidlen;
|
|
182
171
|
if (c->endpoint == NULL) {
|
|
183
172
|
return RAND_bytes(token->data, NGTCP2_STATELESS_RESET_TOKENLEN) == 1
|
|
184
|
-
|
|
173
|
+
? 0
|
|
174
|
+
: NGTCP2_ERR_CALLBACK_FAILURE;
|
|
185
175
|
}
|
|
186
176
|
if (quic_endpoint_generate_reset_token(c->endpoint, token->data, cid) != 0) {
|
|
187
177
|
return NGTCP2_ERR_CALLBACK_FAILURE;
|
|
@@ -190,142 +180,142 @@ quic_get_new_connection_id_cb(ngtcp2_conn *conn, ngtcp2_cid *cid,
|
|
|
190
180
|
return 0;
|
|
191
181
|
}
|
|
192
182
|
|
|
193
|
-
static int
|
|
194
|
-
|
|
195
|
-
{
|
|
183
|
+
static int quic_remove_connection_id_cb(ngtcp2_conn *conn,
|
|
184
|
+
const ngtcp2_cid *cid,
|
|
185
|
+
void *user_data) {
|
|
196
186
|
(void)conn;
|
|
197
187
|
quic_conn_t *c = (quic_conn_t *)user_data;
|
|
198
|
-
if (c->endpoint != NULL)
|
|
188
|
+
if (c->endpoint != NULL)
|
|
189
|
+
quic_endpoint_dissociate_cid(c->endpoint, cid, c->owner);
|
|
199
190
|
return 0;
|
|
200
191
|
}
|
|
201
192
|
|
|
202
|
-
ngtcp2_conn *
|
|
203
|
-
quic_conn_get_conn(ngtcp2_crypto_conn_ref *conn_ref)
|
|
204
|
-
{
|
|
193
|
+
ngtcp2_conn *quic_conn_get_conn(ngtcp2_crypto_conn_ref *conn_ref) {
|
|
205
194
|
return ((quic_conn_t *)conn_ref->user_data)->conn;
|
|
206
195
|
}
|
|
207
196
|
|
|
208
|
-
void
|
|
209
|
-
quic_require_binary(VALUE str, const char *name)
|
|
210
|
-
{
|
|
197
|
+
void quic_require_binary(VALUE str, const char *name) {
|
|
211
198
|
Check_Type(str, T_STRING);
|
|
212
199
|
if (rb_enc_get_index(str) != rb_ascii8bit_encindex()) {
|
|
213
200
|
rb_raise(rb_eArgError, "%s must be ASCII-8BIT (binary) encoding", name);
|
|
214
201
|
}
|
|
215
202
|
}
|
|
216
203
|
|
|
217
|
-
void
|
|
218
|
-
quic_require_sockaddr(VALUE str, const char *name)
|
|
219
|
-
{
|
|
204
|
+
void quic_require_sockaddr(VALUE str, const char *name) {
|
|
220
205
|
quic_require_binary(str, name);
|
|
221
206
|
|
|
222
207
|
long len = RSTRING_LEN(str);
|
|
223
208
|
sa_family_t family = AF_UNSPEC;
|
|
224
209
|
if (len >= (long)(offsetof(struct sockaddr, sa_family) + sizeof(family))) {
|
|
225
|
-
memcpy(&family, RSTRING_PTR(str) + offsetof(struct sockaddr, sa_family),
|
|
210
|
+
memcpy(&family, RSTRING_PTR(str) + offsetof(struct sockaddr, sa_family),
|
|
211
|
+
sizeof(family));
|
|
226
212
|
}
|
|
227
213
|
if ((family == AF_INET && len == (long)sizeof(struct sockaddr_in)) ||
|
|
228
214
|
(family == AF_INET6 && len == (long)sizeof(struct sockaddr_in6))) {
|
|
229
215
|
return;
|
|
230
216
|
}
|
|
231
|
-
rb_raise(rb_eArgError,
|
|
217
|
+
rb_raise(rb_eArgError,
|
|
218
|
+
"%s must be an AF_INET or AF_INET6 sockaddr (Addrinfo#to_sockaddr)",
|
|
219
|
+
name);
|
|
232
220
|
}
|
|
233
221
|
|
|
234
|
-
static uint64_t
|
|
235
|
-
quic_get_uint64_field(VALUE obj, const char *name)
|
|
236
|
-
{
|
|
222
|
+
static uint64_t quic_get_uint64_field(VALUE obj, const char *name) {
|
|
237
223
|
VALUE v = rb_funcall(obj, rb_intern(name), 0);
|
|
238
224
|
return (uint64_t)NUM2ULL(v);
|
|
239
225
|
}
|
|
240
226
|
|
|
241
|
-
static ngtcp2_cc_algo
|
|
242
|
-
quic_cc_algo_from_sym(VALUE sym)
|
|
243
|
-
{
|
|
227
|
+
static ngtcp2_cc_algo quic_cc_algo_from_sym(VALUE sym) {
|
|
244
228
|
Check_Type(sym, T_SYMBOL);
|
|
245
229
|
ID id = SYM2ID(sym);
|
|
246
|
-
if (id == rb_intern("reno"))
|
|
247
|
-
|
|
248
|
-
if (id == rb_intern("
|
|
249
|
-
|
|
230
|
+
if (id == rb_intern("reno"))
|
|
231
|
+
return NGTCP2_CC_ALGO_RENO;
|
|
232
|
+
if (id == rb_intern("cubic"))
|
|
233
|
+
return NGTCP2_CC_ALGO_CUBIC;
|
|
234
|
+
if (id == rb_intern("bbr"))
|
|
235
|
+
return NGTCP2_CC_ALGO_BBR;
|
|
236
|
+
rb_raise(rb_eArgError,
|
|
237
|
+
"unknown cc_algo: %" PRIsVALUE " (expected :reno, :cubic, or :bbr)",
|
|
238
|
+
sym);
|
|
250
239
|
}
|
|
251
240
|
|
|
252
|
-
void
|
|
253
|
-
quic_fill_transport_params(ngtcp2_transport_params *params, VALUE tp)
|
|
254
|
-
{
|
|
241
|
+
void quic_fill_transport_params(ngtcp2_transport_params *params, VALUE tp) {
|
|
255
242
|
ngtcp2_transport_params_default(params);
|
|
256
243
|
params->initial_max_stream_data_bidi_local =
|
|
257
|
-
|
|
244
|
+
quic_get_uint64_field(tp, "initial_max_stream_data_bidi_local");
|
|
258
245
|
params->initial_max_stream_data_bidi_remote =
|
|
259
|
-
|
|
246
|
+
quic_get_uint64_field(tp, "initial_max_stream_data_bidi_remote");
|
|
260
247
|
params->initial_max_stream_data_uni =
|
|
261
|
-
|
|
262
|
-
params->initial_max_data =
|
|
263
|
-
quic_get_uint64_field(tp, "initial_max_data");
|
|
248
|
+
quic_get_uint64_field(tp, "initial_max_stream_data_uni");
|
|
249
|
+
params->initial_max_data = quic_get_uint64_field(tp, "initial_max_data");
|
|
264
250
|
params->initial_max_streams_bidi =
|
|
265
|
-
|
|
251
|
+
quic_get_uint64_field(tp, "initial_max_streams_bidi");
|
|
266
252
|
params->initial_max_streams_uni =
|
|
267
|
-
|
|
253
|
+
quic_get_uint64_field(tp, "initial_max_streams_uni");
|
|
268
254
|
params->max_idle_timeout =
|
|
269
|
-
|
|
255
|
+
(ngtcp2_duration)quic_get_uint64_field(tp, "max_idle_timeout");
|
|
270
256
|
params->active_connection_id_limit =
|
|
271
|
-
|
|
257
|
+
quic_get_uint64_field(tp, "active_connection_id_limit");
|
|
272
258
|
}
|
|
273
259
|
|
|
274
|
-
void
|
|
275
|
-
quic_fill_settings(ngtcp2_settings *settings, VALUE st)
|
|
276
|
-
{
|
|
260
|
+
void quic_fill_settings(ngtcp2_settings *settings, VALUE st) {
|
|
277
261
|
ngtcp2_settings_default(settings);
|
|
278
262
|
settings->initial_ts = quic_now();
|
|
279
|
-
settings->cc_algo =
|
|
263
|
+
settings->cc_algo =
|
|
264
|
+
quic_cc_algo_from_sym(rb_funcall(st, rb_intern("cc_algo"), 0));
|
|
280
265
|
settings->initial_rtt =
|
|
281
|
-
|
|
282
|
-
settings->max_window =
|
|
283
|
-
|
|
284
|
-
settings->max_stream_window =
|
|
285
|
-
quic_get_uint64_field(st, "max_stream_window");
|
|
266
|
+
(ngtcp2_duration)quic_get_uint64_field(st, "initial_rtt");
|
|
267
|
+
settings->max_window = quic_get_uint64_field(st, "max_window");
|
|
268
|
+
settings->max_stream_window = quic_get_uint64_field(st, "max_stream_window");
|
|
286
269
|
settings->handshake_timeout =
|
|
287
|
-
|
|
270
|
+
(ngtcp2_duration)quic_get_uint64_field(st, "handshake_timeout");
|
|
288
271
|
VALUE no_pmtud = rb_funcall(st, rb_intern("no_pmtud"), 0);
|
|
289
272
|
settings->no_pmtud = RTEST(no_pmtud) ? 1 : 0;
|
|
290
273
|
}
|
|
291
274
|
|
|
292
275
|
/* ngtcp2_settings.qlog_write. Touches no Ruby object, so it needs no
|
|
293
276
|
rb_protect. A write error only costs qlog. */
|
|
294
|
-
static void
|
|
295
|
-
|
|
296
|
-
{
|
|
277
|
+
static void quic_qlog_write_cb(void *user_data, uint32_t flags,
|
|
278
|
+
const void *data, size_t datalen) {
|
|
297
279
|
quic_conn_t *c = (quic_conn_t *)user_data;
|
|
298
|
-
if (c->qlog == NULL)
|
|
280
|
+
if (c->qlog == NULL)
|
|
281
|
+
return;
|
|
299
282
|
fwrite(data, 1, datalen, c->qlog);
|
|
300
|
-
if (flags & NGTCP2_QLOG_WRITE_FLAG_FIN)
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
283
|
+
if (flags & NGTCP2_QLOG_WRITE_FLAG_FIN)
|
|
284
|
+
quic_conn_close_qlog(c);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
void quic_conn_close_qlog(quic_conn_t *c) {
|
|
288
|
+
if (c->qlog == NULL)
|
|
289
|
+
return;
|
|
290
|
+
fclose(c->qlog);
|
|
291
|
+
c->qlog = NULL;
|
|
304
292
|
}
|
|
305
293
|
|
|
306
|
-
void
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
if (NIL_P(dir))
|
|
294
|
+
void quic_conn_open_qlog(quic_conn_t *c, VALUE settings_v,
|
|
295
|
+
ngtcp2_settings *settings) {
|
|
296
|
+
VALUE dir = quic_path_value(rb_funcall(settings_v, rb_intern("qlog_dir"), 0),
|
|
297
|
+
"qlog_dir");
|
|
298
|
+
if (NIL_P(dir))
|
|
299
|
+
return;
|
|
311
300
|
|
|
312
301
|
char hex[NGTCP2_MAX_CIDLEN * 2 + 1];
|
|
313
302
|
for (size_t i = 0; i < c->scid.datalen; i++) {
|
|
314
303
|
snprintf(hex + i * 2, 3, "%02x", c->scid.data[i]);
|
|
315
304
|
}
|
|
316
305
|
hex[c->scid.datalen * 2] = '\0';
|
|
317
|
-
VALUE path = rb_sprintf("%"PRIsVALUE"/%s.sqlog", dir, hex);
|
|
306
|
+
VALUE path = rb_sprintf("%" PRIsVALUE "/%s.sqlog", dir, hex);
|
|
318
307
|
c->qlog = fopen(StringValueCStr(path), "w");
|
|
319
|
-
if (c->qlog != NULL)
|
|
308
|
+
if (c->qlog != NULL)
|
|
309
|
+
settings->qlog_write = quic_qlog_write_cb;
|
|
320
310
|
}
|
|
321
311
|
|
|
322
312
|
/* Validate a path setting (ca_file, ca_path, ...) and return it as a String,
|
|
323
313
|
or Qnil. Accepts a String or anything responding to #to_path. Every
|
|
324
314
|
misconfiguration raises ArgumentError, including a wrong type. */
|
|
325
315
|
VALUE
|
|
326
|
-
quic_path_value(VALUE value, const char *name)
|
|
327
|
-
|
|
328
|
-
|
|
316
|
+
quic_path_value(VALUE value, const char *name) {
|
|
317
|
+
if (NIL_P(value))
|
|
318
|
+
return Qnil;
|
|
329
319
|
|
|
330
320
|
VALUE path = value;
|
|
331
321
|
if (!RB_TYPE_P(path, T_STRING)) {
|
|
@@ -333,8 +323,9 @@ quic_path_value(VALUE value, const char *name)
|
|
|
333
323
|
path = rb_funcall(path, rb_intern("to_path"), 0);
|
|
334
324
|
}
|
|
335
325
|
if (!RB_TYPE_P(path, T_STRING)) {
|
|
336
|
-
rb_raise(rb_eArgError,
|
|
337
|
-
|
|
326
|
+
rb_raise(rb_eArgError,
|
|
327
|
+
"%s must be a String or Pathname (got %" PRIsVALUE ")", name,
|
|
328
|
+
rb_obj_class(value));
|
|
338
329
|
}
|
|
339
330
|
}
|
|
340
331
|
/* Raises ArgumentError when the path contains a NUL byte. */
|
|
@@ -344,13 +335,13 @@ quic_path_value(VALUE value, const char *name)
|
|
|
344
335
|
|
|
345
336
|
/* picotls keeps the pointers of an ALPN list for the whole handshake, so
|
|
346
337
|
ALLOCA_N would not survive. */
|
|
347
|
-
void
|
|
348
|
-
|
|
349
|
-
{
|
|
338
|
+
void quic_copy_alpn(VALUE alpn_ary, ptls_iovec_t **list, size_t *count,
|
|
339
|
+
uint8_t **buf) {
|
|
350
340
|
Check_Type(alpn_ary, T_ARRAY);
|
|
351
341
|
long n_alpn = RARRAY_LEN(alpn_ary);
|
|
352
342
|
*count = 0;
|
|
353
|
-
if (n_alpn <= 0)
|
|
343
|
+
if (n_alpn <= 0)
|
|
344
|
+
return;
|
|
354
345
|
|
|
355
346
|
size_t total = 0;
|
|
356
347
|
for (long i = 0; i < n_alpn; i++) {
|
|
@@ -377,20 +368,16 @@ quic_copy_alpn(VALUE alpn_ary, ptls_iovec_t **list, size_t *count, uint8_t **buf
|
|
|
377
368
|
|
|
378
369
|
/* An empty list leaves c->alpn NULL, which a client sends as no ALPN
|
|
379
370
|
extension at all. */
|
|
380
|
-
void
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
quic_copy_alpn(rb_funcall(settings_v, rb_intern("alpn"), 0), &c->alpn, &c->alpn_count,
|
|
384
|
-
&c->alpn_buf);
|
|
371
|
+
void quic_conn_copy_alpn(quic_conn_t *c, VALUE settings_v) {
|
|
372
|
+
quic_copy_alpn(rb_funcall(settings_v, rb_intern("alpn"), 0), &c->alpn,
|
|
373
|
+
&c->alpn_count, &c->alpn_buf);
|
|
385
374
|
}
|
|
386
375
|
|
|
387
376
|
/* Shared helper: look up the QUIC::Stream registered for stream_id in the
|
|
388
377
|
owner connection's @streams Hash. Returns Qnil if not found (which can
|
|
389
378
|
happen if the stream was already removed by a previous stream_close
|
|
390
379
|
callback). */
|
|
391
|
-
static VALUE
|
|
392
|
-
quic_conn_lookup_stream(quic_conn_t *c, int64_t stream_id)
|
|
393
|
-
{
|
|
380
|
+
static VALUE quic_conn_lookup_stream(quic_conn_t *c, int64_t stream_id) {
|
|
394
381
|
VALUE streams = rb_ivar_get(c->owner, rb_intern("@streams"));
|
|
395
382
|
return rb_hash_aref(streams, LL2NUM(stream_id));
|
|
396
383
|
}
|
|
@@ -413,44 +400,40 @@ struct quic_stream_cb_args {
|
|
|
413
400
|
uint64_t app_error_code;
|
|
414
401
|
};
|
|
415
402
|
|
|
416
|
-
static VALUE
|
|
417
|
-
quic_stream_open_body(VALUE arg)
|
|
418
|
-
{
|
|
403
|
+
static VALUE quic_stream_open_body(VALUE arg) {
|
|
419
404
|
struct quic_stream_cb_args *a = (struct quic_stream_cb_args *)arg;
|
|
420
405
|
VALUE streams = rb_ivar_get(a->c->owner, rb_intern("@streams"));
|
|
421
406
|
if (!NIL_P(rb_hash_aref(streams, LL2NUM(a->stream_id)))) {
|
|
422
|
-
return Qnil;
|
|
407
|
+
return Qnil; /* already known (opened by this endpoint) */
|
|
423
408
|
}
|
|
424
409
|
VALUE stream = quic_stream_new(a->stream_id, a->c->owner);
|
|
425
410
|
rb_hash_aset(streams, LL2NUM(a->stream_id), stream);
|
|
426
411
|
return Qnil;
|
|
427
412
|
}
|
|
428
413
|
|
|
429
|
-
void
|
|
430
|
-
|
|
431
|
-
{
|
|
432
|
-
if (!ngtcp2_conn_is_local_stream2(conn, stream_id) && ngtcp2_is_bidi_stream(stream_id)) {
|
|
414
|
+
void quic_conn_give_back_peer_stream(ngtcp2_conn *conn, int64_t stream_id) {
|
|
415
|
+
if (!ngtcp2_conn_is_local_stream2(conn, stream_id) &&
|
|
416
|
+
ngtcp2_is_bidi_stream(stream_id)) {
|
|
433
417
|
ngtcp2_conn_extend_max_streams_bidi(conn, 1);
|
|
434
418
|
}
|
|
435
419
|
}
|
|
436
420
|
|
|
437
|
-
static int
|
|
438
|
-
|
|
439
|
-
{
|
|
421
|
+
static int quic_stream_open_cb(ngtcp2_conn *conn, int64_t stream_id,
|
|
422
|
+
void *user_data) {
|
|
440
423
|
(void)conn;
|
|
441
424
|
quic_conn_t *c = (quic_conn_t *)user_data;
|
|
442
|
-
if (c->handler)
|
|
425
|
+
if (c->handler)
|
|
426
|
+
return 0; /* the handler keeps its own stream state */
|
|
443
427
|
struct quic_stream_cb_args a = {.c = c, .stream_id = stream_id};
|
|
444
428
|
return quic_conn_protect(c, quic_stream_open_body, &a);
|
|
445
429
|
}
|
|
446
430
|
|
|
447
|
-
static VALUE
|
|
448
|
-
quic_recv_stream_data_body(VALUE arg)
|
|
449
|
-
{
|
|
431
|
+
static VALUE quic_recv_stream_data_body(VALUE arg) {
|
|
450
432
|
struct quic_stream_cb_args *a = (struct quic_stream_cb_args *)arg;
|
|
451
433
|
quic_conn_t *c = a->c;
|
|
452
434
|
VALUE stream = quic_conn_lookup_stream(c, a->stream_id);
|
|
453
|
-
if (NIL_P(stream))
|
|
435
|
+
if (NIL_P(stream))
|
|
436
|
+
return Qnil;
|
|
454
437
|
|
|
455
438
|
quic_stream_t *s;
|
|
456
439
|
TypedData_Get_Struct(stream, quic_stream_t, &quic_stream_data_type, s);
|
|
@@ -459,7 +442,8 @@ quic_recv_stream_data_body(VALUE arg)
|
|
|
459
442
|
marks the initiator (0 == client, 1 == server), so a client queues the
|
|
460
443
|
odd ids and a server the even ones. Push once, on first data arrival,
|
|
461
444
|
then mark so later data does not re-enqueue. */
|
|
462
|
-
bool peer_initiated =
|
|
445
|
+
bool peer_initiated =
|
|
446
|
+
c->is_server ? !(a->stream_id & 0x01) : (a->stream_id & 0x01);
|
|
463
447
|
if (!s->accept_queued && peer_initiated) {
|
|
464
448
|
VALUE accept_queue = rb_ivar_get(c->owner, rb_intern("@accept_queue"));
|
|
465
449
|
rb_ary_push(accept_queue, stream);
|
|
@@ -476,25 +460,25 @@ quic_recv_stream_data_body(VALUE arg)
|
|
|
476
460
|
return Qnil;
|
|
477
461
|
}
|
|
478
462
|
|
|
479
|
-
static int
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
{
|
|
463
|
+
static int quic_recv_stream_data_cb(ngtcp2_conn *conn, uint32_t flags,
|
|
464
|
+
int64_t stream_id, uint64_t offset,
|
|
465
|
+
const uint8_t *data, size_t datalen,
|
|
466
|
+
void *user_data, void *stream_user_data) {
|
|
484
467
|
(void)offset;
|
|
485
468
|
(void)stream_user_data;
|
|
486
469
|
quic_conn_t *c = (quic_conn_t *)user_data;
|
|
487
470
|
if (c->handler) {
|
|
488
471
|
size_t consumed = 0;
|
|
489
472
|
int fin = (flags & NGTCP2_STREAM_DATA_FLAG_FIN) != 0;
|
|
490
|
-
if (c->handler->recv_stream_data(c->handler_ud, stream_id, data, datalen,
|
|
491
|
-
c->now, &consumed) < 0) {
|
|
473
|
+
if (c->handler->recv_stream_data(c->handler_ud, stream_id, data, datalen,
|
|
474
|
+
fin, c->now, &consumed) < 0) {
|
|
492
475
|
return NGTCP2_ERR_CALLBACK_FAILURE;
|
|
493
476
|
}
|
|
494
477
|
/* What the handler consumed outright (for HTTP/3, everything but the
|
|
495
478
|
request body) goes straight back to the peer as credit. */
|
|
496
479
|
if (consumed > 0) {
|
|
497
|
-
if (ngtcp2_conn_extend_max_stream_offset(conn, stream_id, consumed) !=
|
|
480
|
+
if (ngtcp2_conn_extend_max_stream_offset(conn, stream_id, consumed) !=
|
|
481
|
+
0) {
|
|
498
482
|
return NGTCP2_ERR_CALLBACK_FAILURE;
|
|
499
483
|
}
|
|
500
484
|
ngtcp2_conn_extend_max_offset(conn, consumed);
|
|
@@ -502,17 +486,20 @@ quic_recv_stream_data_cb(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id,
|
|
|
502
486
|
return 0;
|
|
503
487
|
}
|
|
504
488
|
struct quic_stream_cb_args a = {
|
|
505
|
-
|
|
489
|
+
.c = c,
|
|
490
|
+
.stream_id = stream_id,
|
|
491
|
+
.flags = flags,
|
|
492
|
+
.data = data,
|
|
493
|
+
.datalen = datalen,
|
|
506
494
|
};
|
|
507
495
|
return quic_conn_protect(c, quic_recv_stream_data_body, &a);
|
|
508
496
|
}
|
|
509
497
|
|
|
510
|
-
static VALUE
|
|
511
|
-
quic_acked_stream_data_offset_body(VALUE arg)
|
|
512
|
-
{
|
|
498
|
+
static VALUE quic_acked_stream_data_offset_body(VALUE arg) {
|
|
513
499
|
struct quic_stream_cb_args *a = (struct quic_stream_cb_args *)arg;
|
|
514
500
|
VALUE stream = quic_conn_lookup_stream(a->c, a->stream_id);
|
|
515
|
-
if (NIL_P(stream))
|
|
501
|
+
if (NIL_P(stream))
|
|
502
|
+
return Qnil;
|
|
516
503
|
|
|
517
504
|
quic_stream_t *s;
|
|
518
505
|
TypedData_Get_Struct(stream, quic_stream_t, &quic_stream_data_type, s);
|
|
@@ -536,26 +523,25 @@ quic_acked_stream_data_offset_body(VALUE arg)
|
|
|
536
523
|
return Qnil;
|
|
537
524
|
}
|
|
538
525
|
|
|
539
|
-
static int
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
{
|
|
526
|
+
static int quic_acked_stream_data_offset_cb(ngtcp2_conn *conn,
|
|
527
|
+
int64_t stream_id, uint64_t offset,
|
|
528
|
+
uint64_t datalen, void *user_data,
|
|
529
|
+
void *stream_user_data) {
|
|
544
530
|
(void)conn;
|
|
545
531
|
(void)offset;
|
|
546
532
|
(void)stream_user_data;
|
|
547
533
|
quic_conn_t *c = (quic_conn_t *)user_data;
|
|
548
534
|
if (c->handler) {
|
|
549
535
|
return c->handler->acked_stream_data(c->handler_ud, stream_id, datalen) < 0
|
|
550
|
-
|
|
536
|
+
? NGTCP2_ERR_CALLBACK_FAILURE
|
|
537
|
+
: 0;
|
|
551
538
|
}
|
|
552
|
-
struct quic_stream_cb_args a = {
|
|
539
|
+
struct quic_stream_cb_args a = {
|
|
540
|
+
.c = c, .stream_id = stream_id, .acked = datalen};
|
|
553
541
|
return quic_conn_protect(c, quic_acked_stream_data_offset_body, &a);
|
|
554
542
|
}
|
|
555
543
|
|
|
556
|
-
static VALUE
|
|
557
|
-
quic_stream_close_body(VALUE arg)
|
|
558
|
-
{
|
|
544
|
+
static VALUE quic_stream_close_body(VALUE arg) {
|
|
559
545
|
struct quic_stream_cb_args *a = (struct quic_stream_cb_args *)arg;
|
|
560
546
|
VALUE streams = rb_ivar_get(a->c->owner, rb_intern("@streams"));
|
|
561
547
|
VALUE stream = rb_hash_aref(streams, LL2NUM(a->stream_id));
|
|
@@ -585,11 +571,9 @@ quic_stream_close_body(VALUE arg)
|
|
|
585
571
|
return Qnil;
|
|
586
572
|
}
|
|
587
573
|
|
|
588
|
-
static int
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
void *stream_user_data)
|
|
592
|
-
{
|
|
574
|
+
static int quic_stream_close_cb(ngtcp2_conn *conn, uint32_t flags,
|
|
575
|
+
int64_t stream_id, uint64_t app_error_code,
|
|
576
|
+
void *user_data, void *stream_user_data) {
|
|
593
577
|
(void)stream_user_data;
|
|
594
578
|
quic_conn_t *c = (quic_conn_t *)user_data;
|
|
595
579
|
if (c->handler) {
|
|
@@ -597,21 +581,25 @@ quic_stream_close_cb(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id,
|
|
|
597
581
|
gets its stream back at once. */
|
|
598
582
|
quic_conn_give_back_peer_stream(conn, stream_id);
|
|
599
583
|
int has_code = (flags & NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET) != 0;
|
|
600
|
-
return c->handler->stream_close(c->handler_ud, stream_id, has_code,
|
|
601
|
-
|
|
584
|
+
return c->handler->stream_close(c->handler_ud, stream_id, has_code,
|
|
585
|
+
app_error_code) < 0
|
|
586
|
+
? NGTCP2_ERR_CALLBACK_FAILURE
|
|
587
|
+
: 0;
|
|
602
588
|
}
|
|
603
589
|
struct quic_stream_cb_args a = {
|
|
604
|
-
|
|
590
|
+
.c = c,
|
|
591
|
+
.stream_id = stream_id,
|
|
592
|
+
.flags = flags,
|
|
593
|
+
.app_error_code = app_error_code,
|
|
605
594
|
};
|
|
606
595
|
return quic_conn_protect(c, quic_stream_close_body, &a);
|
|
607
596
|
}
|
|
608
597
|
|
|
609
|
-
static VALUE
|
|
610
|
-
quic_stream_reset_body(VALUE arg)
|
|
611
|
-
{
|
|
598
|
+
static VALUE quic_stream_reset_body(VALUE arg) {
|
|
612
599
|
struct quic_stream_cb_args *a = (struct quic_stream_cb_args *)arg;
|
|
613
600
|
VALUE stream = quic_conn_lookup_stream(a->c, a->stream_id);
|
|
614
|
-
if (NIL_P(stream))
|
|
601
|
+
if (NIL_P(stream))
|
|
602
|
+
return Qnil;
|
|
615
603
|
|
|
616
604
|
quic_stream_t *s;
|
|
617
605
|
TypedData_Get_Struct(stream, quic_stream_t, &quic_stream_data_type, s);
|
|
@@ -621,76 +609,78 @@ quic_stream_reset_body(VALUE arg)
|
|
|
621
609
|
return Qnil;
|
|
622
610
|
}
|
|
623
611
|
|
|
624
|
-
static int
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
void *stream_user_data)
|
|
628
|
-
{
|
|
612
|
+
static int quic_stream_reset_cb(ngtcp2_conn *conn, int64_t stream_id,
|
|
613
|
+
uint64_t final_size, uint64_t app_error_code,
|
|
614
|
+
void *user_data, void *stream_user_data) {
|
|
629
615
|
(void)conn;
|
|
630
616
|
(void)stream_user_data;
|
|
631
617
|
quic_conn_t *c = (quic_conn_t *)user_data;
|
|
632
618
|
if (c->handler) {
|
|
633
|
-
return c->handler->stream_reset(c->handler_ud, stream_id, final_size,
|
|
634
|
-
|
|
619
|
+
return c->handler->stream_reset(c->handler_ud, stream_id, final_size,
|
|
620
|
+
app_error_code) < 0
|
|
621
|
+
? NGTCP2_ERR_CALLBACK_FAILURE
|
|
622
|
+
: 0;
|
|
635
623
|
}
|
|
636
|
-
struct quic_stream_cb_args a = {
|
|
624
|
+
struct quic_stream_cb_args a = {
|
|
625
|
+
.c = c, .stream_id = stream_id, .app_error_code = app_error_code};
|
|
637
626
|
return quic_conn_protect(c, quic_stream_reset_body, &a);
|
|
638
627
|
}
|
|
639
628
|
|
|
640
629
|
/* The callbacks below matter only to a stream handler. Without one, the
|
|
641
630
|
QUIC::Stream mode needs none of them. */
|
|
642
631
|
|
|
643
|
-
static int
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
void *stream_user_data)
|
|
647
|
-
{
|
|
632
|
+
static int quic_stream_stop_sending_cb(ngtcp2_conn *conn, int64_t stream_id,
|
|
633
|
+
uint64_t app_error_code, void *user_data,
|
|
634
|
+
void *stream_user_data) {
|
|
648
635
|
(void)conn;
|
|
649
636
|
(void)stream_user_data;
|
|
650
637
|
quic_conn_t *c = (quic_conn_t *)user_data;
|
|
651
|
-
if (!c->handler)
|
|
652
|
-
|
|
653
|
-
|
|
638
|
+
if (!c->handler)
|
|
639
|
+
return 0;
|
|
640
|
+
return c->handler->stream_stop_sending(c->handler_ud, stream_id,
|
|
641
|
+
app_error_code) < 0
|
|
642
|
+
? NGTCP2_ERR_CALLBACK_FAILURE
|
|
643
|
+
: 0;
|
|
654
644
|
}
|
|
655
645
|
|
|
656
|
-
static int
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
void *stream_user_data)
|
|
660
|
-
{
|
|
646
|
+
static int quic_extend_max_stream_data_cb(ngtcp2_conn *conn, int64_t stream_id,
|
|
647
|
+
uint64_t max_data, void *user_data,
|
|
648
|
+
void *stream_user_data) {
|
|
661
649
|
(void)conn;
|
|
662
650
|
(void)max_data;
|
|
663
651
|
(void)stream_user_data;
|
|
664
652
|
quic_conn_t *c = (quic_conn_t *)user_data;
|
|
665
|
-
if (!c->handler)
|
|
653
|
+
if (!c->handler)
|
|
654
|
+
return 0;
|
|
666
655
|
return c->handler->extend_max_stream_data(c->handler_ud, stream_id) < 0
|
|
667
|
-
|
|
656
|
+
? NGTCP2_ERR_CALLBACK_FAILURE
|
|
657
|
+
: 0;
|
|
668
658
|
}
|
|
669
659
|
|
|
670
|
-
static int
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
{
|
|
660
|
+
static int quic_extend_max_remote_streams_bidi_cb(ngtcp2_conn *conn,
|
|
661
|
+
uint64_t max_streams,
|
|
662
|
+
void *user_data) {
|
|
674
663
|
(void)conn;
|
|
675
664
|
quic_conn_t *c = (quic_conn_t *)user_data;
|
|
676
|
-
if (!c->handler)
|
|
677
|
-
|
|
678
|
-
|
|
665
|
+
if (!c->handler)
|
|
666
|
+
return 0;
|
|
667
|
+
return c->handler->extend_max_remote_streams_bidi(c->handler_ud,
|
|
668
|
+
max_streams) < 0
|
|
669
|
+
? NGTCP2_ERR_CALLBACK_FAILURE
|
|
670
|
+
: 0;
|
|
679
671
|
}
|
|
680
672
|
|
|
681
|
-
static int
|
|
682
|
-
quic_handshake_completed_cb(ngtcp2_conn *conn, void *user_data)
|
|
683
|
-
{
|
|
673
|
+
static int quic_handshake_completed_cb(ngtcp2_conn *conn, void *user_data) {
|
|
684
674
|
(void)conn;
|
|
685
675
|
quic_conn_t *c = (quic_conn_t *)user_data;
|
|
686
|
-
if (!c->handler)
|
|
676
|
+
if (!c->handler)
|
|
677
|
+
return 0;
|
|
687
678
|
return c->handler->handshake_completed(c->handler_ud) < 0
|
|
688
|
-
|
|
679
|
+
? NGTCP2_ERR_CALLBACK_FAILURE
|
|
680
|
+
: 0;
|
|
689
681
|
}
|
|
690
682
|
|
|
691
|
-
void
|
|
692
|
-
quic_conn_fill_common_callbacks(ngtcp2_callbacks *callbacks)
|
|
693
|
-
{
|
|
683
|
+
void quic_conn_fill_common_callbacks(ngtcp2_callbacks *callbacks) {
|
|
694
684
|
memset(callbacks, 0, sizeof(*callbacks));
|
|
695
685
|
callbacks->recv_crypto_data = ngtcp2_crypto_recv_crypto_data_cb;
|
|
696
686
|
callbacks->encrypt = ngtcp2_crypto_encrypt_cb;
|
|
@@ -698,8 +688,10 @@ quic_conn_fill_common_callbacks(ngtcp2_callbacks *callbacks)
|
|
|
698
688
|
callbacks->hp_mask = ngtcp2_crypto_hp_mask_cb;
|
|
699
689
|
callbacks->update_key = ngtcp2_crypto_update_key_cb;
|
|
700
690
|
callbacks->delete_crypto_aead_ctx = ngtcp2_crypto_delete_crypto_aead_ctx_cb;
|
|
701
|
-
callbacks->delete_crypto_cipher_ctx =
|
|
702
|
-
|
|
691
|
+
callbacks->delete_crypto_cipher_ctx =
|
|
692
|
+
ngtcp2_crypto_delete_crypto_cipher_ctx_cb;
|
|
693
|
+
callbacks->get_path_challenge_data2 =
|
|
694
|
+
ngtcp2_crypto_get_path_challenge_data2_cb;
|
|
703
695
|
callbacks->version_negotiation = ngtcp2_crypto_version_negotiation_cb;
|
|
704
696
|
callbacks->rand = quic_rand_cb;
|
|
705
697
|
callbacks->get_new_connection_id2 = quic_get_new_connection_id_cb;
|
|
@@ -711,7 +703,8 @@ quic_conn_fill_common_callbacks(ngtcp2_callbacks *callbacks)
|
|
|
711
703
|
callbacks->stream_reset = quic_stream_reset_cb;
|
|
712
704
|
callbacks->stream_stop_sending = quic_stream_stop_sending_cb;
|
|
713
705
|
callbacks->extend_max_stream_data = quic_extend_max_stream_data_cb;
|
|
714
|
-
callbacks->extend_max_remote_streams_bidi =
|
|
706
|
+
callbacks->extend_max_remote_streams_bidi =
|
|
707
|
+
quic_extend_max_remote_streams_bidi_cb;
|
|
715
708
|
callbacks->handshake_completed = quic_handshake_completed_cb;
|
|
716
709
|
}
|
|
717
710
|
|
|
@@ -720,11 +713,10 @@ quic_conn_fill_common_callbacks(ngtcp2_callbacks *callbacks)
|
|
|
720
713
|
(no round-robin). Sets *out_datav to the byte slice to send, *out_datavcnt
|
|
721
714
|
to 0 or 1, *out_flags to NGTCP2_WRITE_STREAM_FLAG_FIN when applicable.
|
|
722
715
|
Returns the stream's Ruby VALUE (or Qnil if no candidate). */
|
|
723
|
-
static VALUE
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
{
|
|
716
|
+
static VALUE quic_conn_pick_send_stream(VALUE self, ngtcp2_vec *out_datav,
|
|
717
|
+
size_t *out_datavcnt,
|
|
718
|
+
uint32_t *out_flags,
|
|
719
|
+
int64_t *out_stream_id) {
|
|
728
720
|
VALUE streams = rb_ivar_get(self, rb_intern("@streams"));
|
|
729
721
|
VALUE stream_values = rb_funcall(streams, rb_intern("values"), 0);
|
|
730
722
|
|
|
@@ -732,7 +724,8 @@ quic_conn_pick_send_stream(VALUE self, ngtcp2_vec *out_datav,
|
|
|
732
724
|
VALUE st = RARRAY_AREF(stream_values, i);
|
|
733
725
|
quic_stream_t *s;
|
|
734
726
|
TypedData_Get_Struct(st, quic_stream_t, &quic_stream_data_type, s);
|
|
735
|
-
if (s->fin_flushed)
|
|
727
|
+
if (s->fin_flushed)
|
|
728
|
+
continue;
|
|
736
729
|
|
|
737
730
|
VALUE pending = rb_ivar_get(st, rb_intern("@pending_chunks"));
|
|
738
731
|
uint64_t position = s->sent_offset - s->pending_shifted;
|
|
@@ -762,8 +755,8 @@ quic_conn_pick_send_stream(VALUE self, ngtcp2_vec *out_datav,
|
|
|
762
755
|
remaining bytes of it (ngtcp2 may encode less, in which case FIN
|
|
763
756
|
won't actually be flushed and we'll retry next call). */
|
|
764
757
|
*out_flags = (s->fin_sent && chunk_idx == chunks_count - 1)
|
|
765
|
-
|
|
766
|
-
|
|
758
|
+
? NGTCP2_WRITE_STREAM_FLAG_FIN
|
|
759
|
+
: 0;
|
|
767
760
|
return st;
|
|
768
761
|
}
|
|
769
762
|
|
|
@@ -785,21 +778,21 @@ quic_conn_pick_send_stream(VALUE self, ngtcp2_vec *out_datav,
|
|
|
785
778
|
a pending FIN, route the packet through ngtcp2_conn_writev_stream so the
|
|
786
779
|
stream data gets framed alongside connection-level frames. Falls back to
|
|
787
780
|
conn-only when no stream is queued. Returns what ngtcp2 returned. */
|
|
788
|
-
static ngtcp2_ssize
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
{
|
|
781
|
+
static ngtcp2_ssize quic_conn_write_pkt_streams(VALUE self, quic_conn_t *c,
|
|
782
|
+
ngtcp2_path *path,
|
|
783
|
+
ngtcp2_pkt_info *pi,
|
|
784
|
+
uint8_t *dest, size_t destlen) {
|
|
792
785
|
ngtcp2_vec datav;
|
|
793
786
|
size_t datavcnt = 0;
|
|
794
787
|
uint32_t writev_flags = 0;
|
|
795
788
|
int64_t send_stream_id = -1;
|
|
796
789
|
VALUE selected_stream = quic_conn_pick_send_stream(
|
|
797
|
-
|
|
790
|
+
self, &datav, &datavcnt, &writev_flags, &send_stream_id);
|
|
798
791
|
|
|
799
792
|
ngtcp2_ssize pdatalen = -1;
|
|
800
793
|
ngtcp2_ssize n = ngtcp2_conn_writev_stream(
|
|
801
|
-
|
|
802
|
-
|
|
794
|
+
c->conn, path, pi, dest, destlen, &pdatalen, writev_flags, send_stream_id,
|
|
795
|
+
&datav, datavcnt, c->now);
|
|
803
796
|
|
|
804
797
|
if (n == NGTCP2_ERR_STREAM_DATA_BLOCKED && NIL_P(c->pending_exc)) {
|
|
805
798
|
/* The stream's queued data is beyond what the peer's flow control lets
|
|
@@ -814,7 +807,8 @@ quic_conn_write_pkt_streams(VALUE self, quic_conn_t *c, ngtcp2_path *path,
|
|
|
814
807
|
0, -1, NULL, 0, c->now);
|
|
815
808
|
}
|
|
816
809
|
|
|
817
|
-
if (n < 0 || !NIL_P(c->pending_exc))
|
|
810
|
+
if (n < 0 || !NIL_P(c->pending_exc))
|
|
811
|
+
return n;
|
|
818
812
|
|
|
819
813
|
/* Update the selected stream's accounting only when we actually sent
|
|
820
814
|
bytes. pdatalen >= 0 means ngtcp2 framed that many data bytes into the
|
|
@@ -822,8 +816,8 @@ quic_conn_write_pkt_streams(VALUE self, quic_conn_t *c, ngtcp2_path *path,
|
|
|
822
816
|
or other frames). */
|
|
823
817
|
if (!NIL_P(selected_stream) && pdatalen > 0) {
|
|
824
818
|
quic_stream_t *s;
|
|
825
|
-
TypedData_Get_Struct(selected_stream, quic_stream_t,
|
|
826
|
-
|
|
819
|
+
TypedData_Get_Struct(selected_stream, quic_stream_t, &quic_stream_data_type,
|
|
820
|
+
s);
|
|
827
821
|
s->sent_offset += (uint64_t)pdatalen;
|
|
828
822
|
/* FIN is only actually written when all requested data fits in the
|
|
829
823
|
frame (see ngtcp2 docs on NGTCP2_WRITE_STREAM_FLAG_FIN). */
|
|
@@ -835,8 +829,8 @@ quic_conn_write_pkt_streams(VALUE self, quic_conn_t *c, ngtcp2_path *path,
|
|
|
835
829
|
(writev_flags & NGTCP2_WRITE_STREAM_FLAG_FIN)) {
|
|
836
830
|
/* FIN-only packet (no data) was successfully written. */
|
|
837
831
|
quic_stream_t *s;
|
|
838
|
-
TypedData_Get_Struct(selected_stream, quic_stream_t,
|
|
839
|
-
|
|
832
|
+
TypedData_Get_Struct(selected_stream, quic_stream_t, &quic_stream_data_type,
|
|
833
|
+
s);
|
|
840
834
|
s->fin_flushed = true;
|
|
841
835
|
}
|
|
842
836
|
return n;
|
|
@@ -857,10 +851,10 @@ _Static_assert(offsetof(quic_ext_vec, len) == offsetof(ngtcp2_vec, len),
|
|
|
857
851
|
nghttp3. NGTCP2_WRITE_STREAM_FLAG_MORE is not used, so a packet carries
|
|
858
852
|
data of one stream at most. A handler failure is reported as
|
|
859
853
|
NGTCP2_ERR_CALLBACK_FAILURE. */
|
|
860
|
-
static ngtcp2_ssize
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
{
|
|
854
|
+
static ngtcp2_ssize quic_conn_write_pkt_handler(quic_conn_t *c,
|
|
855
|
+
ngtcp2_path *path,
|
|
856
|
+
ngtcp2_pkt_info *pi,
|
|
857
|
+
uint8_t *dest, size_t destlen) {
|
|
864
858
|
const quic_ext_stream_handler *h = c->handler;
|
|
865
859
|
for (;;) {
|
|
866
860
|
int64_t sid = -1;
|
|
@@ -868,46 +862,49 @@ quic_conn_write_pkt_handler(quic_conn_t *c, ngtcp2_path *path, ngtcp2_pkt_info *
|
|
|
868
862
|
quic_ext_vec vec[QUIC_HANDLER_VECCNT];
|
|
869
863
|
size_t nvec = 0;
|
|
870
864
|
if (ngtcp2_conn_get_max_data_left2(c->conn) &&
|
|
871
|
-
h->next_stream_data(c->handler_ud, &sid, &fin, vec, QUIC_HANDLER_VECCNT,
|
|
865
|
+
h->next_stream_data(c->handler_ud, &sid, &fin, vec, QUIC_HANDLER_VECCNT,
|
|
866
|
+
&nvec) < 0) {
|
|
872
867
|
return NGTCP2_ERR_CALLBACK_FAILURE;
|
|
873
868
|
}
|
|
874
869
|
|
|
875
870
|
ngtcp2_ssize ndatalen = -1;
|
|
876
|
-
ngtcp2_ssize n =
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
871
|
+
ngtcp2_ssize n =
|
|
872
|
+
ngtcp2_conn_writev_stream(c->conn, path, pi, dest, destlen, &ndatalen,
|
|
873
|
+
fin ? NGTCP2_WRITE_STREAM_FLAG_FIN : 0, sid,
|
|
874
|
+
(const ngtcp2_vec *)vec, nvec, c->now);
|
|
880
875
|
if (n == NGTCP2_ERR_STREAM_DATA_BLOCKED) {
|
|
881
|
-
if (h->stream_blocked(c->handler_ud, sid) < 0)
|
|
876
|
+
if (h->stream_blocked(c->handler_ud, sid) < 0)
|
|
877
|
+
return NGTCP2_ERR_CALLBACK_FAILURE;
|
|
882
878
|
continue;
|
|
883
879
|
}
|
|
884
880
|
if (n == NGTCP2_ERR_STREAM_SHUT_WR) {
|
|
885
|
-
if (h->stream_shut_write(c->handler_ud, sid) < 0)
|
|
881
|
+
if (h->stream_shut_write(c->handler_ud, sid) < 0)
|
|
882
|
+
return NGTCP2_ERR_CALLBACK_FAILURE;
|
|
886
883
|
continue;
|
|
887
884
|
}
|
|
888
|
-
if (n < 0)
|
|
889
|
-
|
|
885
|
+
if (n < 0)
|
|
886
|
+
return n;
|
|
887
|
+
if (ndatalen >= 0 &&
|
|
888
|
+
h->stream_data_written(c->handler_ud, sid, (size_t)ndatalen) < 0) {
|
|
890
889
|
return NGTCP2_ERR_CALLBACK_FAILURE;
|
|
891
890
|
}
|
|
892
|
-
return n;
|
|
891
|
+
return n; /* 0: nothing to send */
|
|
893
892
|
}
|
|
894
893
|
}
|
|
895
894
|
|
|
896
|
-
ngtcp2_ssize
|
|
897
|
-
|
|
898
|
-
{
|
|
895
|
+
ngtcp2_ssize quic_conn_write_pkt_raw(VALUE self, quic_conn_t *c,
|
|
896
|
+
ngtcp2_path *path, uint8_t *dest) {
|
|
899
897
|
ngtcp2_pkt_info pi;
|
|
900
898
|
memset(&pi, 0, sizeof(pi));
|
|
901
899
|
|
|
902
900
|
c->now = quic_now();
|
|
903
|
-
return c->handler
|
|
904
|
-
|
|
905
|
-
|
|
901
|
+
return c->handler ? quic_conn_write_pkt_handler(c, path, &pi, dest,
|
|
902
|
+
QUIC_WRITE_PKT_BUFLEN)
|
|
903
|
+
: quic_conn_write_pkt_streams(self, c, path, &pi, dest,
|
|
904
|
+
QUIC_WRITE_PKT_BUFLEN);
|
|
906
905
|
}
|
|
907
906
|
|
|
908
|
-
static VALUE
|
|
909
|
-
quic_conn_write_pkt(int argc, VALUE *argv, VALUE self)
|
|
910
|
-
{
|
|
907
|
+
static VALUE quic_conn_write_pkt(int argc, VALUE *argv, VALUE self) {
|
|
911
908
|
VALUE buffer = Qnil;
|
|
912
909
|
rb_scan_args(argc, argv, "01", &buffer);
|
|
913
910
|
|
|
@@ -923,15 +920,16 @@ quic_conn_write_pkt(int argc, VALUE *argv, VALUE self)
|
|
|
923
920
|
rb_raise(rb_eArgError, "buffer must be ASCII-8BIT (binary) encoding");
|
|
924
921
|
}
|
|
925
922
|
if (RSTRING_LEN(buffer) < (long)QUIC_WRITE_PKT_BUFLEN) {
|
|
926
|
-
rb_str_modify_expand(buffer,
|
|
923
|
+
rb_str_modify_expand(buffer,
|
|
924
|
+
(long)QUIC_WRITE_PKT_BUFLEN - RSTRING_LEN(buffer));
|
|
927
925
|
}
|
|
928
926
|
}
|
|
929
927
|
|
|
930
928
|
ngtcp2_path_storage path_storage;
|
|
931
929
|
ngtcp2_path_storage_zero(&path_storage);
|
|
932
930
|
|
|
933
|
-
ngtcp2_ssize n =
|
|
934
|
-
|
|
931
|
+
ngtcp2_ssize n = quic_conn_write_pkt_raw(self, c, &path_storage.path,
|
|
932
|
+
(uint8_t *)RSTRING_PTR(buffer));
|
|
935
933
|
|
|
936
934
|
if (!NIL_P(c->pending_exc)) {
|
|
937
935
|
rb_str_set_len(buffer, 0);
|
|
@@ -958,19 +956,21 @@ quic_conn_write_pkt(int argc, VALUE *argv, VALUE self)
|
|
|
958
956
|
sent, and becomes CertificateVerifyFailed when the verifier rejected the
|
|
959
957
|
peer. */
|
|
960
958
|
VALUE
|
|
961
|
-
quic_conn_error_new(quic_conn_t *c, int rv)
|
|
962
|
-
|
|
963
|
-
|
|
959
|
+
quic_conn_error_new(quic_conn_t *c, int rv) {
|
|
960
|
+
if (rv != NGTCP2_ERR_CRYPTO)
|
|
961
|
+
return quic_ngtcp2_error_new(rv);
|
|
964
962
|
|
|
965
963
|
/* 0 means "not set" to ngtcp2; close_notify (0) is never sent for a
|
|
966
964
|
verification failure, so report it as nil. */
|
|
967
965
|
uint8_t alert = ngtcp2_conn_get_tls_alert2(c->conn);
|
|
968
966
|
VALUE exc;
|
|
969
967
|
if (c->verify_failed) {
|
|
970
|
-
VALUE msg =
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
968
|
+
VALUE msg =
|
|
969
|
+
c->verify_result
|
|
970
|
+
? rb_sprintf("certificate verify failed (%s)",
|
|
971
|
+
X509_verify_cert_error_string(c->verify_result))
|
|
972
|
+
: rb_str_new_cstr(
|
|
973
|
+
"certificate verify failed (server sent no certificate)");
|
|
974
974
|
exc = rb_exc_new_str(rb_eQUICErrorCertificateVerifyFailed, msg);
|
|
975
975
|
rb_ivar_set(exc, rb_intern("@verify_result"),
|
|
976
976
|
c->verify_result ? INT2NUM(c->verify_result) : Qnil);
|
|
@@ -982,10 +982,8 @@ quic_conn_error_new(quic_conn_t *c, int rv)
|
|
|
982
982
|
return exc;
|
|
983
983
|
}
|
|
984
984
|
|
|
985
|
-
int
|
|
986
|
-
|
|
987
|
-
size_t datalen)
|
|
988
|
-
{
|
|
985
|
+
int quic_conn_read_pkt_raw(quic_conn_t *c, const ngtcp2_path *path,
|
|
986
|
+
const uint8_t *data, size_t datalen) {
|
|
989
987
|
ngtcp2_pkt_info pi;
|
|
990
988
|
memset(&pi, 0, sizeof(pi));
|
|
991
989
|
|
|
@@ -999,12 +997,14 @@ struct quic_read_pkt_args {
|
|
|
999
997
|
ngtcp2_path path;
|
|
1000
998
|
};
|
|
1001
999
|
|
|
1002
|
-
static VALUE
|
|
1003
|
-
quic_read_pkt_body(VALUE arg)
|
|
1004
|
-
{
|
|
1000
|
+
static VALUE quic_read_pkt_body(VALUE arg) {
|
|
1005
1001
|
struct quic_read_pkt_args *a = (struct quic_read_pkt_args *)arg;
|
|
1006
|
-
int rv = quic_conn_read_pkt_raw(a->c, &a->path,
|
|
1002
|
+
int rv = quic_conn_read_pkt_raw(a->c, &a->path,
|
|
1003
|
+
(const uint8_t *)RSTRING_PTR(a->packet),
|
|
1007
1004
|
(size_t)RSTRING_LEN(a->packet));
|
|
1005
|
+
/* The peer closed or reset the connection; ngtcp2 logs nothing more. */
|
|
1006
|
+
if (ngtcp2_conn_in_draining_period2(a->c->conn))
|
|
1007
|
+
quic_conn_close_qlog(a->c);
|
|
1008
1008
|
quic_conn_raise_pending(a->c);
|
|
1009
1009
|
if (rv != 0) {
|
|
1010
1010
|
/* longjmp passes through rb_ensure so unlock still fires. */
|
|
@@ -1013,16 +1013,12 @@ quic_read_pkt_body(VALUE arg)
|
|
|
1013
1013
|
return Qnil;
|
|
1014
1014
|
}
|
|
1015
1015
|
|
|
1016
|
-
static VALUE
|
|
1017
|
-
quic_read_pkt_unlock(VALUE arg)
|
|
1018
|
-
{
|
|
1016
|
+
static VALUE quic_read_pkt_unlock(VALUE arg) {
|
|
1019
1017
|
rb_str_unlocktmp(((struct quic_read_pkt_args *)arg)->packet);
|
|
1020
1018
|
return Qnil;
|
|
1021
1019
|
}
|
|
1022
1020
|
|
|
1023
|
-
static VALUE
|
|
1024
|
-
quic_conn_read_pkt(int argc, VALUE *argv, VALUE self)
|
|
1025
|
-
{
|
|
1021
|
+
static VALUE quic_conn_read_pkt(int argc, VALUE *argv, VALUE self) {
|
|
1026
1022
|
VALUE packet = Qnil;
|
|
1027
1023
|
VALUE opts = Qnil;
|
|
1028
1024
|
rb_scan_args(argc, argv, "1:", &packet, &opts);
|
|
@@ -1031,15 +1027,17 @@ quic_conn_read_pkt(int argc, VALUE *argv, VALUE self)
|
|
|
1031
1027
|
rb_raise(rb_eArgError, "missing keywords: local_sockaddr, remote_sockaddr");
|
|
1032
1028
|
}
|
|
1033
1029
|
|
|
1034
|
-
VALUE local_sockaddr
|
|
1035
|
-
|
|
1030
|
+
VALUE local_sockaddr =
|
|
1031
|
+
rb_hash_aref(opts, ID2SYM(rb_intern("local_sockaddr")));
|
|
1032
|
+
VALUE remote_sockaddr =
|
|
1033
|
+
rb_hash_aref(opts, ID2SYM(rb_intern("remote_sockaddr")));
|
|
1036
1034
|
|
|
1037
1035
|
if (NIL_P(local_sockaddr) || NIL_P(remote_sockaddr)) {
|
|
1038
1036
|
rb_raise(rb_eArgError, "missing keywords: local_sockaddr, remote_sockaddr");
|
|
1039
1037
|
}
|
|
1040
1038
|
|
|
1041
|
-
quic_require_binary(packet,
|
|
1042
|
-
quic_require_sockaddr(local_sockaddr,
|
|
1039
|
+
quic_require_binary(packet, "packet");
|
|
1040
|
+
quic_require_sockaddr(local_sockaddr, "local_sockaddr");
|
|
1043
1041
|
quic_require_sockaddr(remote_sockaddr, "remote_sockaddr");
|
|
1044
1042
|
|
|
1045
1043
|
quic_conn_t *c = quic_conn_get(self);
|
|
@@ -1047,78 +1045,72 @@ quic_conn_read_pkt(int argc, VALUE *argv, VALUE self)
|
|
|
1047
1045
|
struct quic_read_pkt_args args;
|
|
1048
1046
|
args.c = c;
|
|
1049
1047
|
args.packet = packet;
|
|
1050
|
-
args.path.local.addr
|
|
1051
|
-
args.path.local.addrlen
|
|
1052
|
-
args.path.remote.addr
|
|
1048
|
+
args.path.local.addr = (struct sockaddr *)RSTRING_PTR(local_sockaddr);
|
|
1049
|
+
args.path.local.addrlen = (ngtcp2_socklen)RSTRING_LEN(local_sockaddr);
|
|
1050
|
+
args.path.remote.addr = (struct sockaddr *)RSTRING_PTR(remote_sockaddr);
|
|
1053
1051
|
args.path.remote.addrlen = (ngtcp2_socklen)RSTRING_LEN(remote_sockaddr);
|
|
1054
|
-
args.path.user_data
|
|
1052
|
+
args.path.user_data = NULL;
|
|
1055
1053
|
|
|
1056
1054
|
rb_str_locktmp(packet);
|
|
1057
|
-
return rb_ensure(quic_read_pkt_body, (VALUE)&args,
|
|
1058
|
-
|
|
1055
|
+
return rb_ensure(quic_read_pkt_body, (VALUE)&args, quic_read_pkt_unlock,
|
|
1056
|
+
(VALUE)&args);
|
|
1059
1057
|
}
|
|
1060
1058
|
|
|
1061
|
-
static VALUE
|
|
1062
|
-
quic_conn_handshake_completed_p(VALUE self)
|
|
1063
|
-
{
|
|
1059
|
+
static VALUE quic_conn_handshake_completed_p(VALUE self) {
|
|
1064
1060
|
quic_conn_t *c = quic_conn_get(self);
|
|
1065
1061
|
return ngtcp2_conn_get_handshake_completed2(c->conn) ? Qtrue : Qfalse;
|
|
1066
1062
|
}
|
|
1067
1063
|
|
|
1068
|
-
static VALUE
|
|
1069
|
-
quic_conn_in_closing_period_p(VALUE self)
|
|
1070
|
-
{
|
|
1064
|
+
static VALUE quic_conn_in_closing_period_p(VALUE self) {
|
|
1071
1065
|
quic_conn_t *c = quic_conn_get(self);
|
|
1072
1066
|
return ngtcp2_conn_in_closing_period2(c->conn) ? Qtrue : Qfalse;
|
|
1073
1067
|
}
|
|
1074
1068
|
|
|
1075
|
-
static VALUE
|
|
1076
|
-
quic_conn_in_draining_period_p(VALUE self)
|
|
1077
|
-
{
|
|
1069
|
+
static VALUE quic_conn_in_draining_period_p(VALUE self) {
|
|
1078
1070
|
quic_conn_t *c = quic_conn_get(self);
|
|
1079
1071
|
return ngtcp2_conn_in_draining_period2(c->conn) ? Qtrue : Qfalse;
|
|
1080
1072
|
}
|
|
1081
1073
|
|
|
1082
|
-
static VALUE
|
|
1083
|
-
quic_conn_expiry(VALUE self)
|
|
1084
|
-
{
|
|
1074
|
+
static VALUE quic_conn_expiry(VALUE self) {
|
|
1085
1075
|
quic_conn_t *c = quic_conn_get(self);
|
|
1086
1076
|
ngtcp2_tstamp t = ngtcp2_conn_get_expiry2(c->conn);
|
|
1087
|
-
if (t == UINT64_MAX)
|
|
1077
|
+
if (t == UINT64_MAX)
|
|
1078
|
+
return Qnil;
|
|
1088
1079
|
return ULL2NUM((unsigned long long)t);
|
|
1089
1080
|
}
|
|
1090
1081
|
|
|
1091
1082
|
/* Caller is responsible for ordering with #read_pkt / #write_pkt:
|
|
1092
|
-
read_pkt or handle_expiry to advance ngtcp2 state, then write_pkt to flush.
|
|
1093
|
-
|
|
1094
|
-
quic_conn_handle_expiry(VALUE self)
|
|
1095
|
-
{
|
|
1083
|
+
read_pkt or handle_expiry to advance ngtcp2 state, then write_pkt to flush.
|
|
1084
|
+
*/
|
|
1085
|
+
static VALUE quic_conn_handle_expiry(VALUE self) {
|
|
1096
1086
|
quic_conn_t *c = quic_conn_get(self);
|
|
1097
1087
|
c->now = quic_now();
|
|
1098
1088
|
int rv = ngtcp2_conn_handle_expiry(c->conn, c->now);
|
|
1089
|
+
/* Timed out idle: the connection ends without a CONNECTION_CLOSE. */
|
|
1090
|
+
if (rv == NGTCP2_ERR_IDLE_CLOSE)
|
|
1091
|
+
quic_conn_close_qlog(c);
|
|
1099
1092
|
quic_conn_raise_pending(c);
|
|
1100
|
-
if (rv != 0)
|
|
1093
|
+
if (rv != 0)
|
|
1094
|
+
quic_raise_ngtcp2_error(rv);
|
|
1101
1095
|
return Qnil;
|
|
1102
1096
|
}
|
|
1103
1097
|
|
|
1104
1098
|
/* QUIC::Stream objects exist only without a stream handler. */
|
|
1105
|
-
static void
|
|
1106
|
-
quic_conn_require_stream_mode(quic_conn_t *c)
|
|
1107
|
-
{
|
|
1099
|
+
static void quic_conn_require_stream_mode(quic_conn_t *c) {
|
|
1108
1100
|
if (c->handler) {
|
|
1109
|
-
rb_raise(rb_eQUICErrorInvalidState,
|
|
1101
|
+
rb_raise(rb_eQUICErrorInvalidState,
|
|
1102
|
+
"the connection's streams belong to a C stream handler");
|
|
1110
1103
|
}
|
|
1111
1104
|
}
|
|
1112
1105
|
|
|
1113
|
-
static VALUE
|
|
1114
|
-
quic_conn_open_bidi_stream(VALUE self)
|
|
1115
|
-
{
|
|
1106
|
+
static VALUE quic_conn_open_bidi_stream(VALUE self) {
|
|
1116
1107
|
quic_conn_t *c = quic_conn_get(self);
|
|
1117
1108
|
quic_conn_require_stream_mode(c);
|
|
1118
1109
|
|
|
1119
1110
|
int64_t stream_id;
|
|
1120
1111
|
int rv = ngtcp2_conn_open_bidi_stream(c->conn, &stream_id, NULL);
|
|
1121
|
-
if (rv != 0)
|
|
1112
|
+
if (rv != 0)
|
|
1113
|
+
quic_raise_ngtcp2_error(rv);
|
|
1122
1114
|
|
|
1123
1115
|
VALUE stream = quic_stream_new(stream_id, self);
|
|
1124
1116
|
VALUE streams = rb_ivar_get(self, rb_intern("@streams"));
|
|
@@ -1126,15 +1118,14 @@ quic_conn_open_bidi_stream(VALUE self)
|
|
|
1126
1118
|
return stream;
|
|
1127
1119
|
}
|
|
1128
1120
|
|
|
1129
|
-
static VALUE
|
|
1130
|
-
quic_conn_open_uni_stream(VALUE self)
|
|
1131
|
-
{
|
|
1121
|
+
static VALUE quic_conn_open_uni_stream(VALUE self) {
|
|
1132
1122
|
quic_conn_t *c = quic_conn_get(self);
|
|
1133
1123
|
quic_conn_require_stream_mode(c);
|
|
1134
1124
|
|
|
1135
1125
|
int64_t stream_id;
|
|
1136
1126
|
int rv = ngtcp2_conn_open_uni_stream(c->conn, &stream_id, NULL);
|
|
1137
|
-
if (rv != 0)
|
|
1127
|
+
if (rv != 0)
|
|
1128
|
+
quic_raise_ngtcp2_error(rv);
|
|
1138
1129
|
|
|
1139
1130
|
VALUE stream = quic_stream_new(stream_id, self);
|
|
1140
1131
|
VALUE streams = rb_ivar_get(self, rb_intern("@streams"));
|
|
@@ -1144,13 +1135,12 @@ quic_conn_open_uni_stream(VALUE self)
|
|
|
1144
1135
|
|
|
1145
1136
|
/* Send an application CONNECTION_CLOSE (frame type 0x1d) to the peer and
|
|
1146
1137
|
transition the underlying ngtcp2_conn to the closing period. One UDP
|
|
1147
|
-
datagram is written to the bound socket
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
quic_conn_close_m(int argc, VALUE *argv, VALUE self)
|
|
1153
|
-
{
|
|
1138
|
+
datagram is written to the bound socket, once: nothing sends it again
|
|
1139
|
+
for packets the peer keeps sending (an Endpoint does, for its own
|
|
1140
|
+
connections), and #write_pkt raises QUIC::Error::Closed from here on.
|
|
1141
|
+
Calling #close on a connection that is already in the closing or
|
|
1142
|
+
draining period is a no-op (= returns nil without doing any I/O). */
|
|
1143
|
+
static VALUE quic_conn_close_m(int argc, VALUE *argv, VALUE self) {
|
|
1154
1144
|
VALUE opts = Qnil;
|
|
1155
1145
|
rb_scan_args(argc, argv, "0:", &opts);
|
|
1156
1146
|
|
|
@@ -1184,24 +1174,25 @@ quic_conn_close_m(int argc, VALUE *argv, VALUE self)
|
|
|
1184
1174
|
out through Endpoint#write_pkt. Once it has left the Endpoint's table
|
|
1185
1175
|
it is finished, and #close does nothing. */
|
|
1186
1176
|
if (c->from_endpoint) {
|
|
1187
|
-
if (c->endpoint == NULL)
|
|
1177
|
+
if (c->endpoint == NULL)
|
|
1178
|
+
return Qnil;
|
|
1188
1179
|
ngtcp2_ccerr ccerr;
|
|
1189
|
-
ngtcp2_ccerr_set_application_error(
|
|
1190
|
-
|
|
1180
|
+
ngtcp2_ccerr_set_application_error(
|
|
1181
|
+
&ccerr, error_code, reason_len > 0 ? reason_ptr : NULL, reason_len);
|
|
1191
1182
|
quic_endpoint_close_conn(c->endpoint, c, &ccerr);
|
|
1192
1183
|
return Qnil;
|
|
1193
1184
|
}
|
|
1194
1185
|
|
|
1195
1186
|
VALUE sock = rb_ivar_get(self, rb_intern("@sock"));
|
|
1196
1187
|
if (NIL_P(sock)) {
|
|
1197
|
-
rb_raise(rb_eQUICErrorNotBound,
|
|
1188
|
+
rb_raise(rb_eQUICErrorNotBound,
|
|
1189
|
+
"%" PRIsVALUE "#bind(sock) has not been called",
|
|
1198
1190
|
rb_obj_class(self));
|
|
1199
1191
|
}
|
|
1200
1192
|
|
|
1201
1193
|
ngtcp2_ccerr ccerr;
|
|
1202
|
-
ngtcp2_ccerr_set_application_error(
|
|
1203
|
-
|
|
1204
|
-
reason_len);
|
|
1194
|
+
ngtcp2_ccerr_set_application_error(
|
|
1195
|
+
&ccerr, error_code, reason_len > 0 ? reason_ptr : NULL, reason_len);
|
|
1205
1196
|
|
|
1206
1197
|
ngtcp2_path_storage path_storage;
|
|
1207
1198
|
ngtcp2_path_storage_zero(&path_storage);
|
|
@@ -1212,8 +1203,11 @@ quic_conn_close_m(int argc, VALUE *argv, VALUE self)
|
|
|
1212
1203
|
uint8_t *dest = (uint8_t *)RSTRING_PTR(buffer);
|
|
1213
1204
|
|
|
1214
1205
|
ngtcp2_ssize n = ngtcp2_conn_write_connection_close(
|
|
1215
|
-
c->conn, &path_storage.path, &pi, dest,
|
|
1216
|
-
|
|
1206
|
+
c->conn, &path_storage.path, &pi, dest, (size_t)QUIC_WRITE_PKT_BUFLEN,
|
|
1207
|
+
&ccerr, quic_now());
|
|
1208
|
+
/* The connection ends here whatever ngtcp2 returned, and the
|
|
1209
|
+
CONNECTION_CLOSE, if one was built, is in the qlog already. */
|
|
1210
|
+
quic_conn_close_qlog(c);
|
|
1217
1211
|
|
|
1218
1212
|
/* Pre-handshake or otherwise not in a state where CONNECTION_CLOSE can be
|
|
1219
1213
|
emitted (ngtcp2 returns NGTCP2_ERR_INVALID_STATE). Spec treats this as
|
|
@@ -1239,22 +1233,21 @@ quic_conn_close_m(int argc, VALUE *argv, VALUE self)
|
|
|
1239
1233
|
|
|
1240
1234
|
/* Why an Endpoint closed this connection; see quic_conn_t.error. Always nil
|
|
1241
1235
|
for a connection no Endpoint made. */
|
|
1242
|
-
static VALUE
|
|
1243
|
-
quic_conn_error_m(VALUE self)
|
|
1244
|
-
{
|
|
1236
|
+
static VALUE quic_conn_error_m(VALUE self) {
|
|
1245
1237
|
return quic_conn_get(self)->error;
|
|
1246
1238
|
}
|
|
1247
1239
|
|
|
1248
|
-
void
|
|
1249
|
-
quic_conn_define_shared_methods(VALUE klass)
|
|
1250
|
-
{
|
|
1240
|
+
void quic_conn_define_shared_methods(VALUE klass) {
|
|
1251
1241
|
rb_define_method(klass, "write_pkt", quic_conn_write_pkt, -1);
|
|
1252
|
-
rb_define_method(klass, "read_pkt",
|
|
1242
|
+
rb_define_method(klass, "read_pkt", quic_conn_read_pkt, -1);
|
|
1253
1243
|
rb_define_method(klass, "expiry", quic_conn_expiry, 0);
|
|
1254
1244
|
rb_define_method(klass, "handle_expiry", quic_conn_handle_expiry, 0);
|
|
1255
|
-
rb_define_method(klass, "handshake_completed?",
|
|
1256
|
-
|
|
1257
|
-
rb_define_method(klass, "
|
|
1245
|
+
rb_define_method(klass, "handshake_completed?",
|
|
1246
|
+
quic_conn_handshake_completed_p, 0);
|
|
1247
|
+
rb_define_method(klass, "in_closing_period?", quic_conn_in_closing_period_p,
|
|
1248
|
+
0);
|
|
1249
|
+
rb_define_method(klass, "in_draining_period?", quic_conn_in_draining_period_p,
|
|
1250
|
+
0);
|
|
1258
1251
|
rb_define_method(klass, "open_bidi_stream", quic_conn_open_bidi_stream, 0);
|
|
1259
1252
|
rb_define_method(klass, "open_uni_stream", quic_conn_open_uni_stream, 0);
|
|
1260
1253
|
rb_define_method(klass, "close", quic_conn_close_m, -1);
|