quic 0.0.3 → 0.0.5

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.
@@ -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
- &ptls_openssl_x25519,
17
- &ptls_openssl_secp256r1,
16
+ &ptls_openssl_x25519,
17
+ &ptls_openssl_secp256r1,
18
18
  #if PTLS_OPENSSL_HAVE_SECP384R1
19
- &ptls_openssl_secp384r1,
19
+ &ptls_openssl_secp384r1,
20
20
  #endif
21
- NULL,
21
+ NULL,
22
22
  };
23
23
 
24
24
  ptls_cipher_suite_t *quic_cipher_suites[] = {
25
- &ptls_openssl_aes128gcmsha256,
26
- &ptls_openssl_aes256gcmsha384,
25
+ &ptls_openssl_aes128gcmsha256,
26
+ &ptls_openssl_aes256gcmsha384,
27
27
  #if PTLS_OPENSSL_HAVE_CHACHA20_POLY1305
28
- &ptls_openssl_chacha20poly1305sha256,
28
+ &ptls_openssl_chacha20poly1305sha256,
29
29
  #endif
30
- NULL,
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) ngtcp2_conn_del(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) ptls_openssl_dispose_verify_certificate(&c->verify_cert);
49
- if (c->tls != NULL) quic_tls_ctx_unref(c->tls);
50
- /* Still open only when no ngtcp2_conn was made to finish it. */
51
- if (c->qlog != NULL) fclose(c->qlog);
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
- "QUIC::Connection",
94
- {quic_conn_mark, quic_conn_free, quic_conn_size, quic_conn_compact,},
95
- NULL, NULL,
96
- RUBY_TYPED_FREE_IMMEDIATELY,
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
- quic_conn_raise_pending(quic_conn_t *c)
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) return 0;
134
- if (NIL_P(c->pending_exc)) c->pending_exc = rb_errinfo();
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
- quic_rand_cb(uint8_t *dest, size_t destlen, const ngtcp2_rand_ctx *rand_ctx)
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
- quic_get_new_connection_id_cb(ngtcp2_conn *conn, ngtcp2_cid *cid,
173
- ngtcp2_stateless_reset_token *token, size_t cidlen,
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
- ? 0 : NGTCP2_ERR_CALLBACK_FAILURE;
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
- quic_remove_connection_id_cb(ngtcp2_conn *conn, const ngtcp2_cid *cid, void *user_data)
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) quic_endpoint_dissociate_cid(c->endpoint, cid, c->owner);
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), sizeof(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, "%s must be an AF_INET or AF_INET6 sockaddr (Addrinfo#to_sockaddr)", name);
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")) return NGTCP2_CC_ALGO_RENO;
247
- if (id == rb_intern("cubic")) return NGTCP2_CC_ALGO_CUBIC;
248
- if (id == rb_intern("bbr")) return NGTCP2_CC_ALGO_BBR;
249
- rb_raise(rb_eArgError, "unknown cc_algo: %"PRIsVALUE" (expected :reno, :cubic, or :bbr)", sym);
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
- quic_get_uint64_field(tp, "initial_max_stream_data_bidi_local");
244
+ quic_get_uint64_field(tp, "initial_max_stream_data_bidi_local");
258
245
  params->initial_max_stream_data_bidi_remote =
259
- quic_get_uint64_field(tp, "initial_max_stream_data_bidi_remote");
246
+ quic_get_uint64_field(tp, "initial_max_stream_data_bidi_remote");
260
247
  params->initial_max_stream_data_uni =
261
- quic_get_uint64_field(tp, "initial_max_stream_data_uni");
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
- quic_get_uint64_field(tp, "initial_max_streams_bidi");
251
+ quic_get_uint64_field(tp, "initial_max_streams_bidi");
266
252
  params->initial_max_streams_uni =
267
- quic_get_uint64_field(tp, "initial_max_streams_uni");
253
+ quic_get_uint64_field(tp, "initial_max_streams_uni");
268
254
  params->max_idle_timeout =
269
- (ngtcp2_duration)quic_get_uint64_field(tp, "max_idle_timeout");
255
+ (ngtcp2_duration)quic_get_uint64_field(tp, "max_idle_timeout");
270
256
  params->active_connection_id_limit =
271
- quic_get_uint64_field(tp, "active_connection_id_limit");
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 = quic_cc_algo_from_sym(rb_funcall(st, rb_intern("cc_algo"), 0));
263
+ settings->cc_algo =
264
+ quic_cc_algo_from_sym(rb_funcall(st, rb_intern("cc_algo"), 0));
280
265
  settings->initial_rtt =
281
- (ngtcp2_duration)quic_get_uint64_field(st, "initial_rtt");
282
- settings->max_window =
283
- quic_get_uint64_field(st, "max_window");
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
- (ngtcp2_duration)quic_get_uint64_field(st, "handshake_timeout");
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
- quic_qlog_write_cb(void *user_data, uint32_t flags, const void *data, size_t datalen)
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) return;
280
+ if (c->qlog == NULL)
281
+ return;
299
282
  fwrite(data, 1, datalen, c->qlog);
300
- if (flags & NGTCP2_QLOG_WRITE_FLAG_FIN) {
301
- fclose(c->qlog);
302
- c->qlog = NULL;
303
- }
283
+ if (flags & NGTCP2_QLOG_WRITE_FLAG_FIN)
284
+ quic_conn_close_qlog(c);
304
285
  }
305
286
 
306
- void
307
- quic_conn_open_qlog(quic_conn_t *c, VALUE settings_v, ngtcp2_settings *settings)
308
- {
309
- VALUE dir = quic_path_value(rb_funcall(settings_v, rb_intern("qlog_dir"), 0), "qlog_dir");
310
- if (NIL_P(dir)) return;
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;
292
+ }
293
+
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) settings->qlog_write = quic_qlog_write_cb;
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
- if (NIL_P(value)) return Qnil;
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, "%s must be a String or Pathname (got %"PRIsVALUE")",
337
- name, rb_obj_class(value));
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
- quic_copy_alpn(VALUE alpn_ary, ptls_iovec_t **list, size_t *count, uint8_t **buf)
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) return;
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
- quic_conn_copy_alpn(quic_conn_t *c, VALUE settings_v)
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; /* already known (opened by this endpoint) */
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
- quic_conn_give_back_peer_stream(ngtcp2_conn *conn, int64_t stream_id)
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
- quic_stream_open_cb(ngtcp2_conn *conn, int64_t stream_id, void *user_data)
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) return 0; /* the handler keeps its own stream state */
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)) return Qnil;
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 = c->is_server ? !(a->stream_id & 0x01) : (a->stream_id & 0x01);
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
- quic_recv_stream_data_cb(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id,
481
- uint64_t offset, const uint8_t *data, size_t datalen,
482
- void *user_data, void *stream_user_data)
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, fin,
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) != 0) {
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
- .c = c, .stream_id = stream_id, .flags = flags, .data = data, .datalen = datalen,
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)) return Qnil;
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);
@@ -521,7 +508,9 @@ quic_acked_stream_data_offset_body(VALUE arg)
521
508
  /* Shift any head Chunks of @pending_chunks whose end-offset is fully
522
509
  covered by acked_offset. Each Chunk's start-offset in the stream is
523
510
  pending_shifted (after previous shifts); its end-offset is
524
- pending_shifted + RSTRING_LEN(head). */
511
+ pending_shifted + RSTRING_LEN(head). A stopped stream's
512
+ @pending_chunks is empty, and acks for what it sent before shift
513
+ nothing. */
525
514
  VALUE pending = rb_ivar_get(stream, rb_intern("@pending_chunks"));
526
515
  while (RARRAY_LEN(pending) > 0) {
527
516
  VALUE head = RARRAY_AREF(pending, 0);
@@ -536,26 +525,25 @@ quic_acked_stream_data_offset_body(VALUE arg)
536
525
  return Qnil;
537
526
  }
538
527
 
539
- static int
540
- quic_acked_stream_data_offset_cb(ngtcp2_conn *conn, int64_t stream_id,
541
- uint64_t offset, uint64_t datalen,
542
- void *user_data, void *stream_user_data)
543
- {
528
+ static int quic_acked_stream_data_offset_cb(ngtcp2_conn *conn,
529
+ int64_t stream_id, uint64_t offset,
530
+ uint64_t datalen, void *user_data,
531
+ void *stream_user_data) {
544
532
  (void)conn;
545
533
  (void)offset;
546
534
  (void)stream_user_data;
547
535
  quic_conn_t *c = (quic_conn_t *)user_data;
548
536
  if (c->handler) {
549
537
  return c->handler->acked_stream_data(c->handler_ud, stream_id, datalen) < 0
550
- ? NGTCP2_ERR_CALLBACK_FAILURE : 0;
538
+ ? NGTCP2_ERR_CALLBACK_FAILURE
539
+ : 0;
551
540
  }
552
- struct quic_stream_cb_args a = {.c = c, .stream_id = stream_id, .acked = datalen};
541
+ struct quic_stream_cb_args a = {
542
+ .c = c, .stream_id = stream_id, .acked = datalen};
553
543
  return quic_conn_protect(c, quic_acked_stream_data_offset_body, &a);
554
544
  }
555
545
 
556
- static VALUE
557
- quic_stream_close_body(VALUE arg)
558
- {
546
+ static VALUE quic_stream_close_body(VALUE arg) {
559
547
  struct quic_stream_cb_args *a = (struct quic_stream_cb_args *)arg;
560
548
  VALUE streams = rb_ivar_get(a->c->owner, rb_intern("@streams"));
561
549
  VALUE stream = rb_hash_aref(streams, LL2NUM(a->stream_id));
@@ -585,11 +573,9 @@ quic_stream_close_body(VALUE arg)
585
573
  return Qnil;
586
574
  }
587
575
 
588
- static int
589
- quic_stream_close_cb(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id,
590
- uint64_t app_error_code, void *user_data,
591
- void *stream_user_data)
592
- {
576
+ static int quic_stream_close_cb(ngtcp2_conn *conn, uint32_t flags,
577
+ int64_t stream_id, uint64_t app_error_code,
578
+ void *user_data, void *stream_user_data) {
593
579
  (void)stream_user_data;
594
580
  quic_conn_t *c = (quic_conn_t *)user_data;
595
581
  if (c->handler) {
@@ -597,21 +583,25 @@ quic_stream_close_cb(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id,
597
583
  gets its stream back at once. */
598
584
  quic_conn_give_back_peer_stream(conn, stream_id);
599
585
  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, app_error_code) < 0
601
- ? NGTCP2_ERR_CALLBACK_FAILURE : 0;
586
+ return c->handler->stream_close(c->handler_ud, stream_id, has_code,
587
+ app_error_code) < 0
588
+ ? NGTCP2_ERR_CALLBACK_FAILURE
589
+ : 0;
602
590
  }
603
591
  struct quic_stream_cb_args a = {
604
- .c = c, .stream_id = stream_id, .flags = flags, .app_error_code = app_error_code,
592
+ .c = c,
593
+ .stream_id = stream_id,
594
+ .flags = flags,
595
+ .app_error_code = app_error_code,
605
596
  };
606
597
  return quic_conn_protect(c, quic_stream_close_body, &a);
607
598
  }
608
599
 
609
- static VALUE
610
- quic_stream_reset_body(VALUE arg)
611
- {
600
+ static VALUE quic_stream_reset_body(VALUE arg) {
612
601
  struct quic_stream_cb_args *a = (struct quic_stream_cb_args *)arg;
613
602
  VALUE stream = quic_conn_lookup_stream(a->c, a->stream_id);
614
- if (NIL_P(stream)) return Qnil;
603
+ if (NIL_P(stream))
604
+ return Qnil;
615
605
 
616
606
  quic_stream_t *s;
617
607
  TypedData_Get_Struct(stream, quic_stream_t, &quic_stream_data_type, s);
@@ -621,76 +611,120 @@ quic_stream_reset_body(VALUE arg)
621
611
  return Qnil;
622
612
  }
623
613
 
624
- static int
625
- quic_stream_reset_cb(ngtcp2_conn *conn, int64_t stream_id, uint64_t final_size,
626
- uint64_t app_error_code, void *user_data,
627
- void *stream_user_data)
628
- {
614
+ static int quic_stream_reset_cb(ngtcp2_conn *conn, int64_t stream_id,
615
+ uint64_t final_size, uint64_t app_error_code,
616
+ void *user_data, void *stream_user_data) {
629
617
  (void)conn;
630
618
  (void)stream_user_data;
631
619
  quic_conn_t *c = (quic_conn_t *)user_data;
632
620
  if (c->handler) {
633
- return c->handler->stream_reset(c->handler_ud, stream_id, final_size, app_error_code) < 0
634
- ? NGTCP2_ERR_CALLBACK_FAILURE : 0;
621
+ return c->handler->stream_reset(c->handler_ud, stream_id, final_size,
622
+ app_error_code) < 0
623
+ ? NGTCP2_ERR_CALLBACK_FAILURE
624
+ : 0;
635
625
  }
636
- struct quic_stream_cb_args a = {.c = c, .stream_id = stream_id, .app_error_code = app_error_code};
626
+ struct quic_stream_cb_args a = {
627
+ .c = c, .stream_id = stream_id, .app_error_code = app_error_code};
637
628
  return quic_conn_protect(c, quic_stream_reset_body, &a);
638
629
  }
639
630
 
631
+ /* Nothing queued on stream can go out any more: drop it all, and have
632
+ #write_pkt skip the stream from now on. ngtcp2 retransmits no STREAM
633
+ frame of a stream it has reset, so it no longer reads the bytes it was
634
+ given either. */
635
+ static void quic_stream_stop(VALUE stream) {
636
+ quic_stream_t *s;
637
+ TypedData_Get_Struct(stream, quic_stream_t, &quic_stream_data_type, s);
638
+ s->stopped = true;
639
+ rb_ary_clear(rb_ivar_get(stream, rb_intern("@pending_chunks")));
640
+ }
641
+
642
+ static VALUE quic_recv_stop_sending_body(VALUE arg) {
643
+ struct quic_stream_cb_args *a = (struct quic_stream_cb_args *)arg;
644
+ VALUE stream = quic_conn_lookup_stream(a->c, a->stream_id);
645
+ if (NIL_P(stream))
646
+ return Qnil;
647
+
648
+ quic_stream_t *s;
649
+ TypedData_Get_Struct(stream, quic_stream_t, &quic_stream_data_type, s);
650
+ s->stop_app_error_code = a->app_error_code;
651
+ quic_stream_stop(stream);
652
+ return Qnil;
653
+ }
654
+
655
+ /* The peer sent STOP_SENDING. ngtcp2 shuts the send side and sends
656
+ RESET_STREAM itself once this returns. A stream handler learns of it when
657
+ #write_pkt finds the send side shut (stream_shut_write). */
658
+ static int quic_recv_stop_sending_cb(ngtcp2_conn *conn, int64_t stream_id,
659
+ uint64_t app_error_code, void *user_data,
660
+ void *stream_user_data) {
661
+ (void)conn;
662
+ (void)stream_user_data;
663
+ quic_conn_t *c = (quic_conn_t *)user_data;
664
+ if (c->handler)
665
+ return 0;
666
+ struct quic_stream_cb_args a = {
667
+ .c = c, .stream_id = stream_id, .app_error_code = app_error_code};
668
+ return quic_conn_protect(c, quic_recv_stop_sending_body, &a);
669
+ }
670
+
640
671
  /* The callbacks below matter only to a stream handler. Without one, the
641
672
  QUIC::Stream mode needs none of them. */
642
673
 
643
- static int
644
- quic_stream_stop_sending_cb(ngtcp2_conn *conn, int64_t stream_id,
645
- uint64_t app_error_code, void *user_data,
646
- void *stream_user_data)
647
- {
674
+ /* This endpoint stopped reading the stream, and STOP_SENDING is going out.
675
+ Not to be confused with recv_stop_sending above. */
676
+ static int quic_stream_stop_sending_cb(ngtcp2_conn *conn, int64_t stream_id,
677
+ uint64_t app_error_code, void *user_data,
678
+ void *stream_user_data) {
648
679
  (void)conn;
649
680
  (void)stream_user_data;
650
681
  quic_conn_t *c = (quic_conn_t *)user_data;
651
- if (!c->handler) return 0;
652
- return c->handler->stream_stop_sending(c->handler_ud, stream_id, app_error_code) < 0
653
- ? NGTCP2_ERR_CALLBACK_FAILURE : 0;
682
+ if (!c->handler)
683
+ return 0;
684
+ return c->handler->stream_stop_sending(c->handler_ud, stream_id,
685
+ app_error_code) < 0
686
+ ? NGTCP2_ERR_CALLBACK_FAILURE
687
+ : 0;
654
688
  }
655
689
 
656
- static int
657
- quic_extend_max_stream_data_cb(ngtcp2_conn *conn, int64_t stream_id,
658
- uint64_t max_data, void *user_data,
659
- void *stream_user_data)
660
- {
690
+ static int quic_extend_max_stream_data_cb(ngtcp2_conn *conn, int64_t stream_id,
691
+ uint64_t max_data, void *user_data,
692
+ void *stream_user_data) {
661
693
  (void)conn;
662
694
  (void)max_data;
663
695
  (void)stream_user_data;
664
696
  quic_conn_t *c = (quic_conn_t *)user_data;
665
- if (!c->handler) return 0;
697
+ if (!c->handler)
698
+ return 0;
666
699
  return c->handler->extend_max_stream_data(c->handler_ud, stream_id) < 0
667
- ? NGTCP2_ERR_CALLBACK_FAILURE : 0;
700
+ ? NGTCP2_ERR_CALLBACK_FAILURE
701
+ : 0;
668
702
  }
669
703
 
670
- static int
671
- quic_extend_max_remote_streams_bidi_cb(ngtcp2_conn *conn, uint64_t max_streams,
672
- void *user_data)
673
- {
704
+ static int quic_extend_max_remote_streams_bidi_cb(ngtcp2_conn *conn,
705
+ uint64_t max_streams,
706
+ void *user_data) {
674
707
  (void)conn;
675
708
  quic_conn_t *c = (quic_conn_t *)user_data;
676
- if (!c->handler) return 0;
677
- return c->handler->extend_max_remote_streams_bidi(c->handler_ud, max_streams) < 0
678
- ? NGTCP2_ERR_CALLBACK_FAILURE : 0;
709
+ if (!c->handler)
710
+ return 0;
711
+ return c->handler->extend_max_remote_streams_bidi(c->handler_ud,
712
+ max_streams) < 0
713
+ ? NGTCP2_ERR_CALLBACK_FAILURE
714
+ : 0;
679
715
  }
680
716
 
681
- static int
682
- quic_handshake_completed_cb(ngtcp2_conn *conn, void *user_data)
683
- {
717
+ static int quic_handshake_completed_cb(ngtcp2_conn *conn, void *user_data) {
684
718
  (void)conn;
685
719
  quic_conn_t *c = (quic_conn_t *)user_data;
686
- if (!c->handler) return 0;
720
+ if (!c->handler)
721
+ return 0;
687
722
  return c->handler->handshake_completed(c->handler_ud) < 0
688
- ? NGTCP2_ERR_CALLBACK_FAILURE : 0;
723
+ ? NGTCP2_ERR_CALLBACK_FAILURE
724
+ : 0;
689
725
  }
690
726
 
691
- void
692
- quic_conn_fill_common_callbacks(ngtcp2_callbacks *callbacks)
693
- {
727
+ void quic_conn_fill_common_callbacks(ngtcp2_callbacks *callbacks) {
694
728
  memset(callbacks, 0, sizeof(*callbacks));
695
729
  callbacks->recv_crypto_data = ngtcp2_crypto_recv_crypto_data_cb;
696
730
  callbacks->encrypt = ngtcp2_crypto_encrypt_cb;
@@ -698,8 +732,10 @@ quic_conn_fill_common_callbacks(ngtcp2_callbacks *callbacks)
698
732
  callbacks->hp_mask = ngtcp2_crypto_hp_mask_cb;
699
733
  callbacks->update_key = ngtcp2_crypto_update_key_cb;
700
734
  callbacks->delete_crypto_aead_ctx = ngtcp2_crypto_delete_crypto_aead_ctx_cb;
701
- callbacks->delete_crypto_cipher_ctx = ngtcp2_crypto_delete_crypto_cipher_ctx_cb;
702
- callbacks->get_path_challenge_data2 = ngtcp2_crypto_get_path_challenge_data2_cb;
735
+ callbacks->delete_crypto_cipher_ctx =
736
+ ngtcp2_crypto_delete_crypto_cipher_ctx_cb;
737
+ callbacks->get_path_challenge_data2 =
738
+ ngtcp2_crypto_get_path_challenge_data2_cb;
703
739
  callbacks->version_negotiation = ngtcp2_crypto_version_negotiation_cb;
704
740
  callbacks->rand = quic_rand_cb;
705
741
  callbacks->get_new_connection_id2 = quic_get_new_connection_id_cb;
@@ -709,22 +745,24 @@ quic_conn_fill_common_callbacks(ngtcp2_callbacks *callbacks)
709
745
  callbacks->acked_stream_data_offset = quic_acked_stream_data_offset_cb;
710
746
  callbacks->stream_close = quic_stream_close_cb;
711
747
  callbacks->stream_reset = quic_stream_reset_cb;
748
+ callbacks->recv_stop_sending = quic_recv_stop_sending_cb;
712
749
  callbacks->stream_stop_sending = quic_stream_stop_sending_cb;
713
750
  callbacks->extend_max_stream_data = quic_extend_max_stream_data_cb;
714
- callbacks->extend_max_remote_streams_bidi = quic_extend_max_remote_streams_bidi_cb;
751
+ callbacks->extend_max_remote_streams_bidi =
752
+ quic_extend_max_remote_streams_bidi_cb;
715
753
  callbacks->handshake_completed = quic_handshake_completed_cb;
716
754
  }
717
755
 
718
- /* Find the first stream in @streams that has either pending bytes or a
719
- pending FIN to flush. Phase 4 minimum: linear scan, take the first match
720
- (no round-robin). Sets *out_datav to the byte slice to send, *out_datavcnt
721
- to 0 or 1, *out_flags to NGTCP2_WRITE_STREAM_FLAG_FIN when applicable.
722
- Returns the stream's Ruby VALUE (or Qnil if no candidate). */
723
- static VALUE
724
- quic_conn_pick_send_stream(VALUE self, ngtcp2_vec *out_datav,
725
- size_t *out_datavcnt, uint32_t *out_flags,
726
- int64_t *out_stream_id)
727
- {
756
+ /* Find the first stream in @streams, stopped ones aside, that has either
757
+ pending bytes or a pending FIN to flush. Phase 4 minimum: linear scan,
758
+ take the first match (no round-robin). Sets *out_datav to the byte slice
759
+ to send, *out_datavcnt to 0 or 1, *out_flags to
760
+ NGTCP2_WRITE_STREAM_FLAG_FIN when applicable. Returns the stream's Ruby
761
+ VALUE (or Qnil if no candidate). */
762
+ static VALUE quic_conn_pick_send_stream(VALUE self, ngtcp2_vec *out_datav,
763
+ size_t *out_datavcnt,
764
+ uint32_t *out_flags,
765
+ int64_t *out_stream_id) {
728
766
  VALUE streams = rb_ivar_get(self, rb_intern("@streams"));
729
767
  VALUE stream_values = rb_funcall(streams, rb_intern("values"), 0);
730
768
 
@@ -732,7 +770,8 @@ quic_conn_pick_send_stream(VALUE self, ngtcp2_vec *out_datav,
732
770
  VALUE st = RARRAY_AREF(stream_values, i);
733
771
  quic_stream_t *s;
734
772
  TypedData_Get_Struct(st, quic_stream_t, &quic_stream_data_type, s);
735
- if (s->fin_flushed) continue;
773
+ if (s->fin_flushed || s->stopped)
774
+ continue;
736
775
 
737
776
  VALUE pending = rb_ivar_get(st, rb_intern("@pending_chunks"));
738
777
  uint64_t position = s->sent_offset - s->pending_shifted;
@@ -762,8 +801,8 @@ quic_conn_pick_send_stream(VALUE self, ngtcp2_vec *out_datav,
762
801
  remaining bytes of it (ngtcp2 may encode less, in which case FIN
763
802
  won't actually be flushed and we'll retry next call). */
764
803
  *out_flags = (s->fin_sent && chunk_idx == chunks_count - 1)
765
- ? NGTCP2_WRITE_STREAM_FLAG_FIN
766
- : 0;
804
+ ? NGTCP2_WRITE_STREAM_FLAG_FIN
805
+ : 0;
767
806
  return st;
768
807
  }
769
808
 
@@ -785,27 +824,34 @@ quic_conn_pick_send_stream(VALUE self, ngtcp2_vec *out_datav,
785
824
  a pending FIN, route the packet through ngtcp2_conn_writev_stream so the
786
825
  stream data gets framed alongside connection-level frames. Falls back to
787
826
  conn-only when no stream is queued. Returns what ngtcp2 returned. */
788
- static ngtcp2_ssize
789
- quic_conn_write_pkt_streams(VALUE self, quic_conn_t *c, ngtcp2_path *path,
790
- ngtcp2_pkt_info *pi, uint8_t *dest, size_t destlen)
791
- {
827
+ static ngtcp2_ssize quic_conn_write_pkt_streams(VALUE self, quic_conn_t *c,
828
+ ngtcp2_path *path,
829
+ ngtcp2_pkt_info *pi,
830
+ uint8_t *dest, size_t destlen) {
792
831
  ngtcp2_vec datav;
793
832
  size_t datavcnt = 0;
794
833
  uint32_t writev_flags = 0;
795
834
  int64_t send_stream_id = -1;
796
835
  VALUE selected_stream = quic_conn_pick_send_stream(
797
- self, &datav, &datavcnt, &writev_flags, &send_stream_id);
836
+ self, &datav, &datavcnt, &writev_flags, &send_stream_id);
798
837
 
799
838
  ngtcp2_ssize pdatalen = -1;
800
839
  ngtcp2_ssize n = ngtcp2_conn_writev_stream(
801
- c->conn, path, pi, dest, destlen, &pdatalen,
802
- writev_flags, send_stream_id, &datav, datavcnt, c->now);
803
-
804
- if (n == NGTCP2_ERR_STREAM_DATA_BLOCKED && NIL_P(c->pending_exc)) {
805
- /* The stream's queued data is beyond what the peer's flow control lets
806
- through right now. Keep it queued and build the packet without it, so
807
- that ACKs and other frames still go out; the data follows once the
808
- peer extends its window (MAX_STREAM_DATA / MAX_DATA). */
840
+ c->conn, path, pi, dest, destlen, &pdatalen, writev_flags, send_stream_id,
841
+ &datav, datavcnt, c->now);
842
+
843
+ if ((n == NGTCP2_ERR_STREAM_DATA_BLOCKED || n == NGTCP2_ERR_STREAM_SHUT_WR) &&
844
+ NIL_P(c->pending_exc)) {
845
+ /* DATA_BLOCKED: the stream's queued data is beyond what the peer's flow
846
+ control lets through right now. Keep it queued; it follows once the
847
+ peer extends its window (MAX_STREAM_DATA / MAX_DATA).
848
+ SHUT_WR: ngtcp2 shut the stream's send side without recv_stop_sending
849
+ marking the stream, as #reset does. What is queued can never go out,
850
+ so drop it.
851
+ Either way, build the packet without the stream's data, so that ACKs
852
+ and other frames still go out. */
853
+ if (n == NGTCP2_ERR_STREAM_SHUT_WR)
854
+ quic_stream_stop(selected_stream);
809
855
  selected_stream = Qnil;
810
856
  datavcnt = 0;
811
857
  writev_flags = 0;
@@ -814,7 +860,8 @@ quic_conn_write_pkt_streams(VALUE self, quic_conn_t *c, ngtcp2_path *path,
814
860
  0, -1, NULL, 0, c->now);
815
861
  }
816
862
 
817
- if (n < 0 || !NIL_P(c->pending_exc)) return n;
863
+ if (n < 0 || !NIL_P(c->pending_exc))
864
+ return n;
818
865
 
819
866
  /* Update the selected stream's accounting only when we actually sent
820
867
  bytes. pdatalen >= 0 means ngtcp2 framed that many data bytes into the
@@ -822,8 +869,8 @@ quic_conn_write_pkt_streams(VALUE self, quic_conn_t *c, ngtcp2_path *path,
822
869
  or other frames). */
823
870
  if (!NIL_P(selected_stream) && pdatalen > 0) {
824
871
  quic_stream_t *s;
825
- TypedData_Get_Struct(selected_stream, quic_stream_t,
826
- &quic_stream_data_type, s);
872
+ TypedData_Get_Struct(selected_stream, quic_stream_t, &quic_stream_data_type,
873
+ s);
827
874
  s->sent_offset += (uint64_t)pdatalen;
828
875
  /* FIN is only actually written when all requested data fits in the
829
876
  frame (see ngtcp2 docs on NGTCP2_WRITE_STREAM_FLAG_FIN). */
@@ -835,8 +882,8 @@ quic_conn_write_pkt_streams(VALUE self, quic_conn_t *c, ngtcp2_path *path,
835
882
  (writev_flags & NGTCP2_WRITE_STREAM_FLAG_FIN)) {
836
883
  /* FIN-only packet (no data) was successfully written. */
837
884
  quic_stream_t *s;
838
- TypedData_Get_Struct(selected_stream, quic_stream_t,
839
- &quic_stream_data_type, s);
885
+ TypedData_Get_Struct(selected_stream, quic_stream_t, &quic_stream_data_type,
886
+ s);
840
887
  s->fin_flushed = true;
841
888
  }
842
889
  return n;
@@ -857,10 +904,10 @@ _Static_assert(offsetof(quic_ext_vec, len) == offsetof(ngtcp2_vec, len),
857
904
  nghttp3. NGTCP2_WRITE_STREAM_FLAG_MORE is not used, so a packet carries
858
905
  data of one stream at most. A handler failure is reported as
859
906
  NGTCP2_ERR_CALLBACK_FAILURE. */
860
- static ngtcp2_ssize
861
- quic_conn_write_pkt_handler(quic_conn_t *c, ngtcp2_path *path, ngtcp2_pkt_info *pi,
862
- uint8_t *dest, size_t destlen)
863
- {
907
+ static ngtcp2_ssize quic_conn_write_pkt_handler(quic_conn_t *c,
908
+ ngtcp2_path *path,
909
+ ngtcp2_pkt_info *pi,
910
+ uint8_t *dest, size_t destlen) {
864
911
  const quic_ext_stream_handler *h = c->handler;
865
912
  for (;;) {
866
913
  int64_t sid = -1;
@@ -868,46 +915,49 @@ quic_conn_write_pkt_handler(quic_conn_t *c, ngtcp2_path *path, ngtcp2_pkt_info *
868
915
  quic_ext_vec vec[QUIC_HANDLER_VECCNT];
869
916
  size_t nvec = 0;
870
917
  if (ngtcp2_conn_get_max_data_left2(c->conn) &&
871
- h->next_stream_data(c->handler_ud, &sid, &fin, vec, QUIC_HANDLER_VECCNT, &nvec) < 0) {
918
+ h->next_stream_data(c->handler_ud, &sid, &fin, vec, QUIC_HANDLER_VECCNT,
919
+ &nvec) < 0) {
872
920
  return NGTCP2_ERR_CALLBACK_FAILURE;
873
921
  }
874
922
 
875
923
  ngtcp2_ssize ndatalen = -1;
876
- ngtcp2_ssize n = ngtcp2_conn_writev_stream(
877
- c->conn, path, pi, dest, destlen, &ndatalen,
878
- fin ? NGTCP2_WRITE_STREAM_FLAG_FIN : 0, sid,
879
- (const ngtcp2_vec *)vec, nvec, c->now);
924
+ ngtcp2_ssize n =
925
+ ngtcp2_conn_writev_stream(c->conn, path, pi, dest, destlen, &ndatalen,
926
+ fin ? NGTCP2_WRITE_STREAM_FLAG_FIN : 0, sid,
927
+ (const ngtcp2_vec *)vec, nvec, c->now);
880
928
  if (n == NGTCP2_ERR_STREAM_DATA_BLOCKED) {
881
- if (h->stream_blocked(c->handler_ud, sid) < 0) return NGTCP2_ERR_CALLBACK_FAILURE;
929
+ if (h->stream_blocked(c->handler_ud, sid) < 0)
930
+ return NGTCP2_ERR_CALLBACK_FAILURE;
882
931
  continue;
883
932
  }
884
933
  if (n == NGTCP2_ERR_STREAM_SHUT_WR) {
885
- if (h->stream_shut_write(c->handler_ud, sid) < 0) return NGTCP2_ERR_CALLBACK_FAILURE;
934
+ if (h->stream_shut_write(c->handler_ud, sid) < 0)
935
+ return NGTCP2_ERR_CALLBACK_FAILURE;
886
936
  continue;
887
937
  }
888
- if (n < 0) return n;
889
- if (ndatalen >= 0 && h->stream_data_written(c->handler_ud, sid, (size_t)ndatalen) < 0) {
938
+ if (n < 0)
939
+ return n;
940
+ if (ndatalen >= 0 &&
941
+ h->stream_data_written(c->handler_ud, sid, (size_t)ndatalen) < 0) {
890
942
  return NGTCP2_ERR_CALLBACK_FAILURE;
891
943
  }
892
- return n; /* 0: nothing to send */
944
+ return n; /* 0: nothing to send */
893
945
  }
894
946
  }
895
947
 
896
- ngtcp2_ssize
897
- quic_conn_write_pkt_raw(VALUE self, quic_conn_t *c, ngtcp2_path *path, uint8_t *dest)
898
- {
948
+ ngtcp2_ssize quic_conn_write_pkt_raw(VALUE self, quic_conn_t *c,
949
+ ngtcp2_path *path, uint8_t *dest) {
899
950
  ngtcp2_pkt_info pi;
900
951
  memset(&pi, 0, sizeof(pi));
901
952
 
902
953
  c->now = quic_now();
903
- return c->handler
904
- ? quic_conn_write_pkt_handler(c, path, &pi, dest, QUIC_WRITE_PKT_BUFLEN)
905
- : quic_conn_write_pkt_streams(self, c, path, &pi, dest, QUIC_WRITE_PKT_BUFLEN);
954
+ return c->handler ? quic_conn_write_pkt_handler(c, path, &pi, dest,
955
+ QUIC_WRITE_PKT_BUFLEN)
956
+ : quic_conn_write_pkt_streams(self, c, path, &pi, dest,
957
+ QUIC_WRITE_PKT_BUFLEN);
906
958
  }
907
959
 
908
- static VALUE
909
- quic_conn_write_pkt(int argc, VALUE *argv, VALUE self)
910
- {
960
+ static VALUE quic_conn_write_pkt(int argc, VALUE *argv, VALUE self) {
911
961
  VALUE buffer = Qnil;
912
962
  rb_scan_args(argc, argv, "01", &buffer);
913
963
 
@@ -923,15 +973,16 @@ quic_conn_write_pkt(int argc, VALUE *argv, VALUE self)
923
973
  rb_raise(rb_eArgError, "buffer must be ASCII-8BIT (binary) encoding");
924
974
  }
925
975
  if (RSTRING_LEN(buffer) < (long)QUIC_WRITE_PKT_BUFLEN) {
926
- rb_str_modify_expand(buffer, (long)QUIC_WRITE_PKT_BUFLEN - RSTRING_LEN(buffer));
976
+ rb_str_modify_expand(buffer,
977
+ (long)QUIC_WRITE_PKT_BUFLEN - RSTRING_LEN(buffer));
927
978
  }
928
979
  }
929
980
 
930
981
  ngtcp2_path_storage path_storage;
931
982
  ngtcp2_path_storage_zero(&path_storage);
932
983
 
933
- ngtcp2_ssize n =
934
- quic_conn_write_pkt_raw(self, c, &path_storage.path, (uint8_t *)RSTRING_PTR(buffer));
984
+ ngtcp2_ssize n = quic_conn_write_pkt_raw(self, c, &path_storage.path,
985
+ (uint8_t *)RSTRING_PTR(buffer));
935
986
 
936
987
  if (!NIL_P(c->pending_exc)) {
937
988
  rb_str_set_len(buffer, 0);
@@ -958,19 +1009,21 @@ quic_conn_write_pkt(int argc, VALUE *argv, VALUE self)
958
1009
  sent, and becomes CertificateVerifyFailed when the verifier rejected the
959
1010
  peer. */
960
1011
  VALUE
961
- quic_conn_error_new(quic_conn_t *c, int rv)
962
- {
963
- if (rv != NGTCP2_ERR_CRYPTO) return quic_ngtcp2_error_new(rv);
1012
+ quic_conn_error_new(quic_conn_t *c, int rv) {
1013
+ if (rv != NGTCP2_ERR_CRYPTO)
1014
+ return quic_ngtcp2_error_new(rv);
964
1015
 
965
1016
  /* 0 means "not set" to ngtcp2; close_notify (0) is never sent for a
966
1017
  verification failure, so report it as nil. */
967
1018
  uint8_t alert = ngtcp2_conn_get_tls_alert2(c->conn);
968
1019
  VALUE exc;
969
1020
  if (c->verify_failed) {
970
- VALUE msg = c->verify_result
971
- ? rb_sprintf("certificate verify failed (%s)",
972
- X509_verify_cert_error_string(c->verify_result))
973
- : rb_str_new_cstr("certificate verify failed (server sent no certificate)");
1021
+ VALUE msg =
1022
+ c->verify_result
1023
+ ? rb_sprintf("certificate verify failed (%s)",
1024
+ X509_verify_cert_error_string(c->verify_result))
1025
+ : rb_str_new_cstr(
1026
+ "certificate verify failed (server sent no certificate)");
974
1027
  exc = rb_exc_new_str(rb_eQUICErrorCertificateVerifyFailed, msg);
975
1028
  rb_ivar_set(exc, rb_intern("@verify_result"),
976
1029
  c->verify_result ? INT2NUM(c->verify_result) : Qnil);
@@ -982,10 +1035,8 @@ quic_conn_error_new(quic_conn_t *c, int rv)
982
1035
  return exc;
983
1036
  }
984
1037
 
985
- int
986
- quic_conn_read_pkt_raw(quic_conn_t *c, const ngtcp2_path *path, const uint8_t *data,
987
- size_t datalen)
988
- {
1038
+ int quic_conn_read_pkt_raw(quic_conn_t *c, const ngtcp2_path *path,
1039
+ const uint8_t *data, size_t datalen) {
989
1040
  ngtcp2_pkt_info pi;
990
1041
  memset(&pi, 0, sizeof(pi));
991
1042
 
@@ -999,12 +1050,14 @@ struct quic_read_pkt_args {
999
1050
  ngtcp2_path path;
1000
1051
  };
1001
1052
 
1002
- static VALUE
1003
- quic_read_pkt_body(VALUE arg)
1004
- {
1053
+ static VALUE quic_read_pkt_body(VALUE arg) {
1005
1054
  struct quic_read_pkt_args *a = (struct quic_read_pkt_args *)arg;
1006
- int rv = quic_conn_read_pkt_raw(a->c, &a->path, (const uint8_t *)RSTRING_PTR(a->packet),
1055
+ int rv = quic_conn_read_pkt_raw(a->c, &a->path,
1056
+ (const uint8_t *)RSTRING_PTR(a->packet),
1007
1057
  (size_t)RSTRING_LEN(a->packet));
1058
+ /* The peer closed or reset the connection; ngtcp2 logs nothing more. */
1059
+ if (ngtcp2_conn_in_draining_period2(a->c->conn))
1060
+ quic_conn_close_qlog(a->c);
1008
1061
  quic_conn_raise_pending(a->c);
1009
1062
  if (rv != 0) {
1010
1063
  /* longjmp passes through rb_ensure so unlock still fires. */
@@ -1013,16 +1066,12 @@ quic_read_pkt_body(VALUE arg)
1013
1066
  return Qnil;
1014
1067
  }
1015
1068
 
1016
- static VALUE
1017
- quic_read_pkt_unlock(VALUE arg)
1018
- {
1069
+ static VALUE quic_read_pkt_unlock(VALUE arg) {
1019
1070
  rb_str_unlocktmp(((struct quic_read_pkt_args *)arg)->packet);
1020
1071
  return Qnil;
1021
1072
  }
1022
1073
 
1023
- static VALUE
1024
- quic_conn_read_pkt(int argc, VALUE *argv, VALUE self)
1025
- {
1074
+ static VALUE quic_conn_read_pkt(int argc, VALUE *argv, VALUE self) {
1026
1075
  VALUE packet = Qnil;
1027
1076
  VALUE opts = Qnil;
1028
1077
  rb_scan_args(argc, argv, "1:", &packet, &opts);
@@ -1031,15 +1080,17 @@ quic_conn_read_pkt(int argc, VALUE *argv, VALUE self)
1031
1080
  rb_raise(rb_eArgError, "missing keywords: local_sockaddr, remote_sockaddr");
1032
1081
  }
1033
1082
 
1034
- VALUE local_sockaddr = rb_hash_aref(opts, ID2SYM(rb_intern("local_sockaddr")));
1035
- VALUE remote_sockaddr = rb_hash_aref(opts, ID2SYM(rb_intern("remote_sockaddr")));
1083
+ VALUE local_sockaddr =
1084
+ rb_hash_aref(opts, ID2SYM(rb_intern("local_sockaddr")));
1085
+ VALUE remote_sockaddr =
1086
+ rb_hash_aref(opts, ID2SYM(rb_intern("remote_sockaddr")));
1036
1087
 
1037
1088
  if (NIL_P(local_sockaddr) || NIL_P(remote_sockaddr)) {
1038
1089
  rb_raise(rb_eArgError, "missing keywords: local_sockaddr, remote_sockaddr");
1039
1090
  }
1040
1091
 
1041
- quic_require_binary(packet, "packet");
1042
- quic_require_sockaddr(local_sockaddr, "local_sockaddr");
1092
+ quic_require_binary(packet, "packet");
1093
+ quic_require_sockaddr(local_sockaddr, "local_sockaddr");
1043
1094
  quic_require_sockaddr(remote_sockaddr, "remote_sockaddr");
1044
1095
 
1045
1096
  quic_conn_t *c = quic_conn_get(self);
@@ -1047,78 +1098,72 @@ quic_conn_read_pkt(int argc, VALUE *argv, VALUE self)
1047
1098
  struct quic_read_pkt_args args;
1048
1099
  args.c = c;
1049
1100
  args.packet = packet;
1050
- args.path.local.addr = (struct sockaddr *)RSTRING_PTR(local_sockaddr);
1051
- args.path.local.addrlen = (ngtcp2_socklen)RSTRING_LEN(local_sockaddr);
1052
- args.path.remote.addr = (struct sockaddr *)RSTRING_PTR(remote_sockaddr);
1101
+ args.path.local.addr = (struct sockaddr *)RSTRING_PTR(local_sockaddr);
1102
+ args.path.local.addrlen = (ngtcp2_socklen)RSTRING_LEN(local_sockaddr);
1103
+ args.path.remote.addr = (struct sockaddr *)RSTRING_PTR(remote_sockaddr);
1053
1104
  args.path.remote.addrlen = (ngtcp2_socklen)RSTRING_LEN(remote_sockaddr);
1054
- args.path.user_data = NULL;
1105
+ args.path.user_data = NULL;
1055
1106
 
1056
1107
  rb_str_locktmp(packet);
1057
- return rb_ensure(quic_read_pkt_body, (VALUE)&args,
1058
- quic_read_pkt_unlock, (VALUE)&args);
1108
+ return rb_ensure(quic_read_pkt_body, (VALUE)&args, quic_read_pkt_unlock,
1109
+ (VALUE)&args);
1059
1110
  }
1060
1111
 
1061
- static VALUE
1062
- quic_conn_handshake_completed_p(VALUE self)
1063
- {
1112
+ static VALUE quic_conn_handshake_completed_p(VALUE self) {
1064
1113
  quic_conn_t *c = quic_conn_get(self);
1065
1114
  return ngtcp2_conn_get_handshake_completed2(c->conn) ? Qtrue : Qfalse;
1066
1115
  }
1067
1116
 
1068
- static VALUE
1069
- quic_conn_in_closing_period_p(VALUE self)
1070
- {
1117
+ static VALUE quic_conn_in_closing_period_p(VALUE self) {
1071
1118
  quic_conn_t *c = quic_conn_get(self);
1072
1119
  return ngtcp2_conn_in_closing_period2(c->conn) ? Qtrue : Qfalse;
1073
1120
  }
1074
1121
 
1075
- static VALUE
1076
- quic_conn_in_draining_period_p(VALUE self)
1077
- {
1122
+ static VALUE quic_conn_in_draining_period_p(VALUE self) {
1078
1123
  quic_conn_t *c = quic_conn_get(self);
1079
1124
  return ngtcp2_conn_in_draining_period2(c->conn) ? Qtrue : Qfalse;
1080
1125
  }
1081
1126
 
1082
- static VALUE
1083
- quic_conn_expiry(VALUE self)
1084
- {
1127
+ static VALUE quic_conn_expiry(VALUE self) {
1085
1128
  quic_conn_t *c = quic_conn_get(self);
1086
1129
  ngtcp2_tstamp t = ngtcp2_conn_get_expiry2(c->conn);
1087
- if (t == UINT64_MAX) return Qnil;
1130
+ if (t == UINT64_MAX)
1131
+ return Qnil;
1088
1132
  return ULL2NUM((unsigned long long)t);
1089
1133
  }
1090
1134
 
1091
1135
  /* 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
- static VALUE
1094
- quic_conn_handle_expiry(VALUE self)
1095
- {
1136
+ read_pkt or handle_expiry to advance ngtcp2 state, then write_pkt to flush.
1137
+ */
1138
+ static VALUE quic_conn_handle_expiry(VALUE self) {
1096
1139
  quic_conn_t *c = quic_conn_get(self);
1097
1140
  c->now = quic_now();
1098
1141
  int rv = ngtcp2_conn_handle_expiry(c->conn, c->now);
1142
+ /* Timed out idle: the connection ends without a CONNECTION_CLOSE. */
1143
+ if (rv == NGTCP2_ERR_IDLE_CLOSE)
1144
+ quic_conn_close_qlog(c);
1099
1145
  quic_conn_raise_pending(c);
1100
- if (rv != 0) quic_raise_ngtcp2_error(rv);
1146
+ if (rv != 0)
1147
+ quic_raise_ngtcp2_error(rv);
1101
1148
  return Qnil;
1102
1149
  }
1103
1150
 
1104
1151
  /* QUIC::Stream objects exist only without a stream handler. */
1105
- static void
1106
- quic_conn_require_stream_mode(quic_conn_t *c)
1107
- {
1152
+ static void quic_conn_require_stream_mode(quic_conn_t *c) {
1108
1153
  if (c->handler) {
1109
- rb_raise(rb_eQUICErrorInvalidState, "the connection's streams belong to a C stream handler");
1154
+ rb_raise(rb_eQUICErrorInvalidState,
1155
+ "the connection's streams belong to a C stream handler");
1110
1156
  }
1111
1157
  }
1112
1158
 
1113
- static VALUE
1114
- quic_conn_open_bidi_stream(VALUE self)
1115
- {
1159
+ static VALUE quic_conn_open_bidi_stream(VALUE self) {
1116
1160
  quic_conn_t *c = quic_conn_get(self);
1117
1161
  quic_conn_require_stream_mode(c);
1118
1162
 
1119
1163
  int64_t stream_id;
1120
1164
  int rv = ngtcp2_conn_open_bidi_stream(c->conn, &stream_id, NULL);
1121
- if (rv != 0) quic_raise_ngtcp2_error(rv);
1165
+ if (rv != 0)
1166
+ quic_raise_ngtcp2_error(rv);
1122
1167
 
1123
1168
  VALUE stream = quic_stream_new(stream_id, self);
1124
1169
  VALUE streams = rb_ivar_get(self, rb_intern("@streams"));
@@ -1126,15 +1171,14 @@ quic_conn_open_bidi_stream(VALUE self)
1126
1171
  return stream;
1127
1172
  }
1128
1173
 
1129
- static VALUE
1130
- quic_conn_open_uni_stream(VALUE self)
1131
- {
1174
+ static VALUE quic_conn_open_uni_stream(VALUE self) {
1132
1175
  quic_conn_t *c = quic_conn_get(self);
1133
1176
  quic_conn_require_stream_mode(c);
1134
1177
 
1135
1178
  int64_t stream_id;
1136
1179
  int rv = ngtcp2_conn_open_uni_stream(c->conn, &stream_id, NULL);
1137
- if (rv != 0) quic_raise_ngtcp2_error(rv);
1180
+ if (rv != 0)
1181
+ quic_raise_ngtcp2_error(rv);
1138
1182
 
1139
1183
  VALUE stream = quic_stream_new(stream_id, self);
1140
1184
  VALUE streams = rb_ivar_get(self, rb_intern("@streams"));
@@ -1144,13 +1188,12 @@ quic_conn_open_uni_stream(VALUE self)
1144
1188
 
1145
1189
  /* Send an application CONNECTION_CLOSE (frame type 0x1d) to the peer and
1146
1190
  transition the underlying ngtcp2_conn to the closing period. One UDP
1147
- datagram is written to the bound socket; ngtcp2 handles closing-period
1148
- retransmits via the caller's pump loop. Calling #close on a connection
1149
- that is already in the closing or draining period is a no-op (= returns
1150
- nil without doing any I/O). */
1151
- static VALUE
1152
- quic_conn_close_m(int argc, VALUE *argv, VALUE self)
1153
- {
1191
+ datagram is written to the bound socket, once: nothing sends it again
1192
+ for packets the peer keeps sending (an Endpoint does, for its own
1193
+ connections), and #write_pkt raises QUIC::Error::Closed from here on.
1194
+ Calling #close on a connection that is already in the closing or
1195
+ draining period is a no-op (= returns nil without doing any I/O). */
1196
+ static VALUE quic_conn_close_m(int argc, VALUE *argv, VALUE self) {
1154
1197
  VALUE opts = Qnil;
1155
1198
  rb_scan_args(argc, argv, "0:", &opts);
1156
1199
 
@@ -1184,24 +1227,25 @@ quic_conn_close_m(int argc, VALUE *argv, VALUE self)
1184
1227
  out through Endpoint#write_pkt. Once it has left the Endpoint's table
1185
1228
  it is finished, and #close does nothing. */
1186
1229
  if (c->from_endpoint) {
1187
- if (c->endpoint == NULL) return Qnil;
1230
+ if (c->endpoint == NULL)
1231
+ return Qnil;
1188
1232
  ngtcp2_ccerr ccerr;
1189
- ngtcp2_ccerr_set_application_error(&ccerr, error_code, reason_len > 0 ? reason_ptr : NULL,
1190
- reason_len);
1233
+ ngtcp2_ccerr_set_application_error(
1234
+ &ccerr, error_code, reason_len > 0 ? reason_ptr : NULL, reason_len);
1191
1235
  quic_endpoint_close_conn(c->endpoint, c, &ccerr);
1192
1236
  return Qnil;
1193
1237
  }
1194
1238
 
1195
1239
  VALUE sock = rb_ivar_get(self, rb_intern("@sock"));
1196
1240
  if (NIL_P(sock)) {
1197
- rb_raise(rb_eQUICErrorNotBound, "%"PRIsVALUE"#bind(sock) has not been called",
1241
+ rb_raise(rb_eQUICErrorNotBound,
1242
+ "%" PRIsVALUE "#bind(sock) has not been called",
1198
1243
  rb_obj_class(self));
1199
1244
  }
1200
1245
 
1201
1246
  ngtcp2_ccerr ccerr;
1202
- ngtcp2_ccerr_set_application_error(&ccerr, error_code,
1203
- reason_len > 0 ? reason_ptr : NULL,
1204
- reason_len);
1247
+ ngtcp2_ccerr_set_application_error(
1248
+ &ccerr, error_code, reason_len > 0 ? reason_ptr : NULL, reason_len);
1205
1249
 
1206
1250
  ngtcp2_path_storage path_storage;
1207
1251
  ngtcp2_path_storage_zero(&path_storage);
@@ -1212,8 +1256,11 @@ quic_conn_close_m(int argc, VALUE *argv, VALUE self)
1212
1256
  uint8_t *dest = (uint8_t *)RSTRING_PTR(buffer);
1213
1257
 
1214
1258
  ngtcp2_ssize n = ngtcp2_conn_write_connection_close(
1215
- c->conn, &path_storage.path, &pi, dest,
1216
- (size_t)QUIC_WRITE_PKT_BUFLEN, &ccerr, quic_now());
1259
+ c->conn, &path_storage.path, &pi, dest, (size_t)QUIC_WRITE_PKT_BUFLEN,
1260
+ &ccerr, quic_now());
1261
+ /* The connection ends here whatever ngtcp2 returned, and the
1262
+ CONNECTION_CLOSE, if one was built, is in the qlog already. */
1263
+ quic_conn_close_qlog(c);
1217
1264
 
1218
1265
  /* Pre-handshake or otherwise not in a state where CONNECTION_CLOSE can be
1219
1266
  emitted (ngtcp2 returns NGTCP2_ERR_INVALID_STATE). Spec treats this as
@@ -1239,22 +1286,21 @@ quic_conn_close_m(int argc, VALUE *argv, VALUE self)
1239
1286
 
1240
1287
  /* Why an Endpoint closed this connection; see quic_conn_t.error. Always nil
1241
1288
  for a connection no Endpoint made. */
1242
- static VALUE
1243
- quic_conn_error_m(VALUE self)
1244
- {
1289
+ static VALUE quic_conn_error_m(VALUE self) {
1245
1290
  return quic_conn_get(self)->error;
1246
1291
  }
1247
1292
 
1248
- void
1249
- quic_conn_define_shared_methods(VALUE klass)
1250
- {
1293
+ void quic_conn_define_shared_methods(VALUE klass) {
1251
1294
  rb_define_method(klass, "write_pkt", quic_conn_write_pkt, -1);
1252
- rb_define_method(klass, "read_pkt", quic_conn_read_pkt, -1);
1295
+ rb_define_method(klass, "read_pkt", quic_conn_read_pkt, -1);
1253
1296
  rb_define_method(klass, "expiry", quic_conn_expiry, 0);
1254
1297
  rb_define_method(klass, "handle_expiry", quic_conn_handle_expiry, 0);
1255
- rb_define_method(klass, "handshake_completed?", quic_conn_handshake_completed_p, 0);
1256
- rb_define_method(klass, "in_closing_period?", quic_conn_in_closing_period_p, 0);
1257
- rb_define_method(klass, "in_draining_period?", quic_conn_in_draining_period_p, 0);
1298
+ rb_define_method(klass, "handshake_completed?",
1299
+ quic_conn_handshake_completed_p, 0);
1300
+ rb_define_method(klass, "in_closing_period?", quic_conn_in_closing_period_p,
1301
+ 0);
1302
+ rb_define_method(klass, "in_draining_period?", quic_conn_in_draining_period_p,
1303
+ 0);
1258
1304
  rb_define_method(klass, "open_bidi_stream", quic_conn_open_bidi_stream, 0);
1259
1305
  rb_define_method(klass, "open_uni_stream", quic_conn_open_uni_stream, 0);
1260
1306
  rb_define_method(klass, "close", quic_conn_close_m, -1);