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.
data/ext/quic/stream.c CHANGED
@@ -5,37 +5,33 @@
5
5
 
6
6
  VALUE rb_cQUICStream;
7
7
 
8
- static void
9
- quic_stream_free(void *ptr)
10
- {
11
- xfree(ptr);
12
- }
8
+ static void quic_stream_free(void *ptr) { xfree(ptr); }
13
9
 
14
- static size_t
15
- quic_stream_size(const void *ptr)
16
- {
10
+ static size_t quic_stream_size(const void *ptr) {
17
11
  (void)ptr;
18
12
  return sizeof(quic_stream_t);
19
13
  }
20
14
 
21
15
  const rb_data_type_t quic_stream_data_type = {
22
- "QUIC::Stream",
23
- {NULL, quic_stream_free, quic_stream_size,},
24
- NULL, NULL,
25
- RUBY_TYPED_FREE_IMMEDIATELY,
16
+ "QUIC::Stream",
17
+ {
18
+ NULL,
19
+ quic_stream_free,
20
+ quic_stream_size,
21
+ },
22
+ NULL,
23
+ NULL,
24
+ RUBY_TYPED_FREE_IMMEDIATELY,
26
25
  };
27
26
 
28
- static VALUE
29
- quic_stream_alloc(VALUE klass)
30
- {
27
+ static VALUE quic_stream_alloc(VALUE klass) {
31
28
  quic_stream_t *s = ALLOC(quic_stream_t);
32
29
  memset(s, 0, sizeof(*s));
33
30
  return TypedData_Wrap_Struct(klass, &quic_stream_data_type, s);
34
31
  }
35
32
 
36
33
  VALUE
37
- quic_stream_new(int64_t stream_id, VALUE owner)
38
- {
34
+ quic_stream_new(int64_t stream_id, VALUE owner) {
39
35
  VALUE self = quic_stream_alloc(rb_cQUICStream);
40
36
  quic_stream_t *s;
41
37
  TypedData_Get_Struct(self, quic_stream_t, &quic_stream_data_type, s);
@@ -49,21 +45,30 @@ quic_stream_new(int64_t stream_id, VALUE owner)
49
45
  return self;
50
46
  }
51
47
 
48
+ /* Raise QUIC::Error::StreamClosed if nothing more can be written to the
49
+ stream: it was reset or has closed, or the peer sent STOP_SENDING. */
50
+ static void quic_stream_check_writable(quic_stream_t *s) {
51
+ if (s->reset || s->closed) {
52
+ rb_raise(rb_eQUICErrorStreamClosed, "stream is closed");
53
+ }
54
+ if (s->stopped) {
55
+ rb_raise(rb_eQUICErrorStreamClosed,
56
+ "the peer asked to stop sending (error code %llu)",
57
+ (unsigned long long)s->stop_app_error_code);
58
+ }
59
+ }
60
+
52
61
  /* Append a binary copy of |data| to @pending_chunks and optionally set the
53
62
  fin_sent flag. Flow control is the caller's concern (#write blocks in
54
63
  quic_stream_write_m and #write_nonblock returns a partial byte count in
55
64
  quic_stream_write_nonblock_m). This helper is reached only after the
56
65
  caller has confirmed the bytes fit in the current send window, so it
57
66
  never raises QUIC::Error::WaitWritable on its own. */
58
- static VALUE
59
- quic_stream_enqueue(VALUE self, VALUE data, bool fin)
60
- {
67
+ static VALUE quic_stream_enqueue(VALUE self, VALUE data, bool fin) {
61
68
  quic_stream_t *s;
62
69
  TypedData_Get_Struct(self, quic_stream_t, &quic_stream_data_type, s);
63
70
 
64
- if (s->reset || s->closed) {
65
- rb_raise(rb_eQUICErrorStreamClosed, "stream is closed");
66
- }
71
+ quic_stream_check_writable(s);
67
72
  if (s->fin_sent) {
68
73
  rb_raise(rb_eQUICErrorStreamClosed, "stream FIN already sent");
69
74
  }
@@ -87,12 +92,11 @@ quic_stream_enqueue(VALUE self, VALUE data, bool fin)
87
92
  return LONG2NUM(len);
88
93
  }
89
94
 
90
- static bool
91
- quic_stream_fin_kwarg(int argc, VALUE *argv, VALUE *data)
92
- {
95
+ static bool quic_stream_fin_kwarg(int argc, VALUE *argv, VALUE *data) {
93
96
  VALUE opts = Qnil;
94
97
  rb_scan_args(argc, argv, "1:", data, &opts);
95
- if (NIL_P(opts)) return false;
98
+ if (NIL_P(opts))
99
+ return false;
96
100
  VALUE fin = rb_hash_lookup(opts, ID2SYM(rb_intern("fin")));
97
101
  return RTEST(fin);
98
102
  }
@@ -101,12 +105,14 @@ quic_stream_fin_kwarg(int argc, VALUE *argv, VALUE *data)
101
105
  per-stream and the per-connection flow control limits ngtcp2 tracks, less
102
106
  the bytes already queued in @pending_chunks but not yet handed to ngtcp2.
103
107
  ngtcp2 only counts what it has sent, so without the subtraction a run of
104
- writes could queue far more than the peer allows. */
105
- static uint64_t
106
- quic_stream_window_left(VALUE self, VALUE client_v, quic_stream_t *s)
107
- {
108
+ writes could queue far more than the peer allows. Callers check the
109
+ stream is writable first: a stopped stream's @pending_chunks no longer
110
+ matches its offsets. */
111
+ static uint64_t quic_stream_window_left(VALUE self, VALUE client_v,
112
+ quic_stream_t *s) {
108
113
  ngtcp2_conn *conn = quic_conn_ptr(client_v);
109
- uint64_t stream_left = ngtcp2_conn_get_max_stream_data_left2(conn, s->stream_id);
114
+ uint64_t stream_left =
115
+ ngtcp2_conn_get_max_stream_data_left2(conn, s->stream_id);
110
116
  uint64_t conn_left = ngtcp2_conn_get_max_data_left2(conn);
111
117
  uint64_t left = stream_left < conn_left ? stream_left : conn_left;
112
118
 
@@ -124,17 +130,17 @@ quic_stream_window_left(VALUE self, VALUE client_v, quic_stream_t *s)
124
130
  /* Blocking write: block by repeatedly invoking #pump_once on the owning
125
131
  connection (@client) until the peer's flow control window has enough room
126
132
  for the full payload, then enqueue. IO#write-compatible: always queues all
127
- of `data`. Bare Streams (built via QUIC::Stream.allocate for unit tests,
128
- with @client = nil) skip the window check entirely. */
129
- static VALUE
130
- quic_stream_write_m(int argc, VALUE *argv, VALUE self)
131
- {
133
+ of `data`. A window that can no longer open, because the peer sent
134
+ STOP_SENDING or the stream ended meanwhile, raises
135
+ QUIC::Error::StreamClosed. Bare Streams (built via QUIC::Stream.allocate
136
+ for unit tests, with @client = nil) skip the window check entirely. */
137
+ static VALUE quic_stream_write_m(int argc, VALUE *argv, VALUE self) {
132
138
  VALUE data;
133
139
  bool fin = quic_stream_fin_kwarg(argc, argv, &data);
134
140
 
135
141
  VALUE client_v = rb_ivar_get(self, rb_intern("@client"));
136
142
  if (NIL_P(client_v)) {
137
- return quic_stream_enqueue(self, data, fin); /* bare-Stream test escape */
143
+ return quic_stream_enqueue(self, data, fin); /* bare-Stream test escape */
138
144
  }
139
145
 
140
146
  /* These will be re-validated by quic_stream_enqueue, but we need the
@@ -148,8 +154,10 @@ quic_stream_write_m(int argc, VALUE *argv, VALUE self)
148
154
  /* Loop until the full payload would fit in the current window. pump_once
149
155
  raises QUIC::Error::NotBound if the connection has not been #bind'ed;
150
156
  that error surfaces verbatim. */
157
+ quic_stream_check_writable(s);
151
158
  while ((uint64_t)needed > quic_stream_window_left(self, client_v, s)) {
152
159
  rb_funcall(client_v, rb_intern("pump_once"), 0);
160
+ quic_stream_check_writable(s);
153
161
  }
154
162
  }
155
163
 
@@ -162,15 +170,13 @@ quic_stream_write_m(int argc, VALUE *argv, VALUE self)
162
170
  prefix fits, FIN is NOT set on this call (caller re-issues with
163
171
  `fin: true` once the remainder is accepted) so we don't half-commit FIN.
164
172
  Bare Streams with @client = nil skip the window check entirely. */
165
- static VALUE
166
- quic_stream_write_nonblock_m(int argc, VALUE *argv, VALUE self)
167
- {
173
+ static VALUE quic_stream_write_nonblock_m(int argc, VALUE *argv, VALUE self) {
168
174
  VALUE data;
169
175
  bool fin = quic_stream_fin_kwarg(argc, argv, &data);
170
176
 
171
177
  VALUE client_v = rb_ivar_get(self, rb_intern("@client"));
172
178
  if (NIL_P(client_v)) {
173
- return quic_stream_enqueue(self, data, fin); /* bare-Stream test escape */
179
+ return quic_stream_enqueue(self, data, fin); /* bare-Stream test escape */
174
180
  }
175
181
 
176
182
  Check_Type(data, T_STRING);
@@ -183,6 +189,8 @@ quic_stream_write_nonblock_m(int argc, VALUE *argv, VALUE self)
183
189
 
184
190
  quic_stream_t *s;
185
191
  TypedData_Get_Struct(self, quic_stream_t, &quic_stream_data_type, s);
192
+ /* Before the window: a stream that cannot be written to never gets one. */
193
+ quic_stream_check_writable(s);
186
194
  uint64_t avail = quic_stream_window_left(self, client_v, s);
187
195
 
188
196
  if (avail == 0) {
@@ -195,12 +203,11 @@ quic_stream_write_nonblock_m(int argc, VALUE *argv, VALUE self)
195
203
  return quic_stream_enqueue(self, slice, effective_fin);
196
204
  }
197
205
 
198
- static VALUE
199
- quic_stream_close_write_m(VALUE self)
200
- {
206
+ static VALUE quic_stream_close_write_m(VALUE self) {
201
207
  quic_stream_t *s;
202
208
  TypedData_Get_Struct(self, quic_stream_t, &quic_stream_data_type, s);
203
- if (s->fin_sent) return Qnil; /* idempotent */
209
+ if (s->fin_sent)
210
+ return Qnil; /* idempotent */
204
211
  VALUE empty = rb_str_new("", 0);
205
212
  rb_enc_associate_index(empty, rb_ascii8bit_encindex());
206
213
  quic_stream_enqueue(self, empty, true);
@@ -215,9 +222,7 @@ quic_stream_close_write_m(VALUE self)
215
222
  - buffer empty + !fin_received: raise QUIC::Error::WaitReadable
216
223
  - buffer non-empty: return min(length, buffer.bytesize) bytes
217
224
  */
218
- static VALUE
219
- quic_stream_read_nonblock_m(VALUE self, VALUE length_v)
220
- {
225
+ static VALUE quic_stream_read_nonblock_m(VALUE self, VALUE length_v) {
221
226
  quic_stream_t *s;
222
227
  TypedData_Get_Struct(self, quic_stream_t, &quic_stream_data_type, s);
223
228
 
@@ -241,7 +246,8 @@ quic_stream_read_nonblock_m(VALUE self, VALUE length_v)
241
246
 
242
247
  /* Drop the first |take| bytes from buffer by memmove + truncate. */
243
248
  if (take < have) {
244
- memmove(RSTRING_PTR(buffer), RSTRING_PTR(buffer) + take, (size_t)(have - take));
249
+ memmove(RSTRING_PTR(buffer), RSTRING_PTR(buffer) + take,
250
+ (size_t)(have - take));
245
251
  }
246
252
  rb_str_set_len(buffer, have - take);
247
253
 
@@ -253,17 +259,17 @@ quic_stream_read_nonblock_m(VALUE self, VALUE length_v)
253
259
  VALUE client_v = rb_ivar_get(self, rb_intern("@client"));
254
260
  if (!NIL_P(client_v)) {
255
261
  ngtcp2_conn *conn = quic_conn_ptr(client_v);
256
- int rv = ngtcp2_conn_extend_max_stream_offset(conn, s->stream_id, (uint64_t)take);
257
- if (rv != 0) quic_raise_ngtcp2_error(rv);
262
+ int rv = ngtcp2_conn_extend_max_stream_offset(conn, s->stream_id,
263
+ (uint64_t)take);
264
+ if (rv != 0)
265
+ quic_raise_ngtcp2_error(rv);
258
266
  ngtcp2_conn_extend_max_offset(conn, (uint64_t)take);
259
267
  }
260
268
 
261
269
  return out;
262
270
  }
263
271
 
264
- static VALUE
265
- quic_stream_eof_p(VALUE self)
266
- {
272
+ static VALUE quic_stream_eof_p(VALUE self) {
267
273
  quic_stream_t *s;
268
274
  TypedData_Get_Struct(self, quic_stream_t, &quic_stream_data_type, s);
269
275
  VALUE buffer = rb_ivar_get(self, rb_intern("@recv_buffer"));
@@ -275,17 +281,13 @@ quic_stream_eof_p(VALUE self)
275
281
  connection closes first, since ngtcp2 does not report stream closure then.
276
282
  Keeps returning true after the stream has left the connection's @streams.
277
283
  A bare Stream is never closed. */
278
- static VALUE
279
- quic_stream_closed_p(VALUE self)
280
- {
284
+ static VALUE quic_stream_closed_p(VALUE self) {
281
285
  quic_stream_t *s;
282
286
  TypedData_Get_Struct(self, quic_stream_t, &quic_stream_data_type, s);
283
287
  return s->closed ? Qtrue : Qfalse;
284
288
  }
285
289
 
286
- static VALUE
287
- quic_stream_close_read_m(VALUE self)
288
- {
290
+ static VALUE quic_stream_close_read_m(VALUE self) {
289
291
  quic_stream_t *s;
290
292
  TypedData_Get_Struct(self, quic_stream_t, &quic_stream_data_type, s);
291
293
 
@@ -295,13 +297,12 @@ quic_stream_close_read_m(VALUE self)
295
297
  /* ngtcp2_conn_shutdown_stream_read sends STOP_SENDING. app_error_code 0
296
298
  since no QUIC-level error API is exposed yet. */
297
299
  int rv = ngtcp2_conn_shutdown_stream_read(conn, 0, s->stream_id, 0);
298
- if (rv != 0) quic_raise_ngtcp2_error(rv);
300
+ if (rv != 0)
301
+ quic_raise_ngtcp2_error(rv);
299
302
  return Qnil;
300
303
  }
301
304
 
302
- static VALUE
303
- quic_stream_close_m(VALUE self)
304
- {
305
+ static VALUE quic_stream_close_m(VALUE self) {
305
306
  /* Send FIN (if not yet) then STOP_SENDING. Idempotent on each leg. */
306
307
  quic_stream_close_write_m(self);
307
308
  quic_stream_close_read_m(self);
@@ -318,9 +319,7 @@ quic_stream_close_m(VALUE self)
318
319
  A bare Stream (@client == nil, used by unit-test fixtures) skips the
319
320
  ngtcp2 call and only flips s->reset, mirroring the #write / #close_write
320
321
  bare-Stream escapes. */
321
- static VALUE
322
- quic_stream_reset_m(int argc, VALUE *argv, VALUE self)
323
- {
322
+ static VALUE quic_stream_reset_m(int argc, VALUE *argv, VALUE self) {
324
323
  VALUE error_code_v = Qnil;
325
324
  rb_scan_args(argc, argv, "01", &error_code_v);
326
325
  uint64_t error_code = NIL_P(error_code_v) ? 0 : NUM2ULL(error_code_v);
@@ -328,17 +327,19 @@ quic_stream_reset_m(int argc, VALUE *argv, VALUE self)
328
327
  quic_stream_t *s;
329
328
  TypedData_Get_Struct(self, quic_stream_t, &quic_stream_data_type, s);
330
329
 
331
- if (s->reset) return Qnil; /* idempotent */
330
+ if (s->reset)
331
+ return Qnil; /* idempotent */
332
332
 
333
333
  VALUE client_v = rb_ivar_get(self, rb_intern("@client"));
334
334
  if (NIL_P(client_v)) {
335
- s->reset = true; /* bare Stream escape */
335
+ s->reset = true; /* bare Stream escape */
336
336
  return Qnil;
337
337
  }
338
338
 
339
339
  ngtcp2_conn *conn = quic_conn_ptr(client_v);
340
340
  int rv = ngtcp2_conn_shutdown_stream_write(conn, 0, s->stream_id, error_code);
341
- if (rv != 0) quic_raise_ngtcp2_error(rv);
341
+ if (rv != 0)
342
+ quic_raise_ngtcp2_error(rv);
342
343
  s->reset = true;
343
344
  return Qnil;
344
345
  }
@@ -346,9 +347,7 @@ quic_stream_reset_m(int argc, VALUE *argv, VALUE self)
346
347
  /* Called by #accept_stream / #accept_stream_nonblock for the stream they
347
348
  take off @accept_queue. A stream that closed while it waited there gives
348
349
  the peer back the stream it used up now (see quic_stream_close_body). */
349
- static VALUE
350
- quic_stream_accepted_m(VALUE self)
351
- {
350
+ static VALUE quic_stream_accepted_m(VALUE self) {
352
351
  quic_stream_t *s;
353
352
  TypedData_Get_Struct(self, quic_stream_t, &quic_stream_data_type, s);
354
353
  s->accepted = true;
@@ -362,20 +361,21 @@ quic_stream_accepted_m(VALUE self)
362
361
  return Qnil;
363
362
  }
364
363
 
365
- void
366
- Init_quic_stream(VALUE rb_mQUICArg)
367
- {
364
+ void Init_quic_stream(VALUE rb_mQUICArg) {
368
365
  rb_cQUICStream = rb_define_class_under(rb_mQUICArg, "Stream", rb_cObject);
369
366
  rb_define_alloc_func(rb_cQUICStream, quic_stream_alloc);
370
367
  rb_define_method(rb_cQUICStream, "write", quic_stream_write_m, -1);
371
- rb_define_method(rb_cQUICStream, "write_nonblock", quic_stream_write_nonblock_m, -1);
368
+ rb_define_method(rb_cQUICStream, "write_nonblock",
369
+ quic_stream_write_nonblock_m, -1);
372
370
  rb_define_method(rb_cQUICStream, "close_write", quic_stream_close_write_m, 0);
373
- rb_define_method(rb_cQUICStream, "read_nonblock", quic_stream_read_nonblock_m, 1);
371
+ rb_define_method(rb_cQUICStream, "read_nonblock", quic_stream_read_nonblock_m,
372
+ 1);
374
373
  rb_define_method(rb_cQUICStream, "eof?", quic_stream_eof_p, 0);
375
374
  rb_define_method(rb_cQUICStream, "closed?", quic_stream_closed_p, 0);
376
375
  rb_define_method(rb_cQUICStream, "close_read", quic_stream_close_read_m, 0);
377
376
  rb_define_method(rb_cQUICStream, "close", quic_stream_close_m, 0);
378
377
  rb_define_method(rb_cQUICStream, "reset", quic_stream_reset_m, -1);
379
- rb_define_private_method(rb_cQUICStream, "_accepted", quic_stream_accepted_m, 0);
378
+ rb_define_private_method(rb_cQUICStream, "_accepted", quic_stream_accepted_m,
379
+ 0);
380
380
  /* #read (blocking) and #initiator are defined in lib/quic/stream.rb. */
381
381
  }
data/ext/quic/stream.h CHANGED
@@ -22,13 +22,19 @@ typedef struct {
22
22
  /* Cumulative bytes shifted out of @pending_chunks. Always
23
23
  <= acked_offset (we only shift a Chunk after its end is acked). */
24
24
  uint64_t pending_shifted;
25
- bool fin_received; /* recv_stream_data delivered FIN */
26
- bool fin_sent; /* #write(fin: true) queued FIN */
27
- bool fin_flushed; /* write_pkt actually wrote the FIN frame */
28
- bool reset; /* stream_reset callback fired */
29
- bool closed; /* stream_close callback fired */
25
+ bool fin_received; /* recv_stream_data delivered FIN */
26
+ bool fin_sent; /* #write(fin: true) queued FIN */
27
+ bool fin_flushed; /* write_pkt actually wrote the FIN frame */
28
+ bool reset; /* stream_reset callback fired */
29
+ bool closed; /* stream_close callback fired */
30
30
  uint64_t close_app_error_code;
31
31
  bool close_has_app_error_code;
32
+ /* The send side is shut: the peer's STOP_SENDING arrived, or ngtcp2
33
+ reported the send side shut while writing. @pending_chunks has been
34
+ emptied, so the offsets above no longer describe it, and #write_pkt
35
+ skips the stream. */
36
+ bool stopped;
37
+ uint64_t stop_app_error_code; /* the STOP_SENDING's, 0 if none arrived */
32
38
  /* Set once a peer-initiated stream has been pushed onto the owning
33
39
  connection's @accept_queue, so recv_stream_data does not enqueue it
34
40
  again on subsequent data arrivals. */
@@ -11,20 +11,17 @@
11
11
 
12
12
  VALUE rb_cQUICTLSContext;
13
13
 
14
- void
15
- quic_tls_ctx_ref(quic_tls_ctx_t *t)
16
- {
17
- t->refcnt++;
18
- }
14
+ void quic_tls_ctx_ref(quic_tls_ctx_t *t) { t->refcnt++; }
19
15
 
20
- void
21
- quic_tls_ctx_unref(quic_tls_ctx_t *t)
22
- {
23
- if (--t->refcnt > 0) return;
24
- if (t->sign_cert_initialized) ptls_openssl_dispose_sign_certificate(&t->sign_cert);
16
+ void quic_tls_ctx_unref(quic_tls_ctx_t *t) {
17
+ if (--t->refcnt > 0)
18
+ return;
19
+ if (t->sign_cert_initialized)
20
+ ptls_openssl_dispose_sign_certificate(&t->sign_cert);
25
21
  /* picotls malloc()ed the list and each entry, so free(), not xfree(). */
26
22
  if (t->ctx.certificates.list != NULL) {
27
- for (size_t i = 0; i < t->ctx.certificates.count; i++) free(t->ctx.certificates.list[i].base);
23
+ for (size_t i = 0; i < t->ctx.certificates.count; i++)
24
+ free(t->ctx.certificates.list[i].base);
28
25
  free(t->ctx.certificates.list);
29
26
  }
30
27
  xfree(t->alpn);
@@ -34,30 +31,31 @@ quic_tls_ctx_unref(quic_tls_ctx_t *t)
34
31
 
35
32
  /* The QUIC::TLSContext object holds one reference. A context it never
36
33
  finished building (an exception mid-way) is released the same way. */
37
- static void
38
- quic_tls_context_free(void *ptr)
39
- {
40
- if (ptr != NULL) quic_tls_ctx_unref((quic_tls_ctx_t *)ptr);
34
+ static void quic_tls_context_free(void *ptr) {
35
+ if (ptr != NULL)
36
+ quic_tls_ctx_unref((quic_tls_ctx_t *)ptr);
41
37
  }
42
38
 
43
- static size_t
44
- quic_tls_context_size(const void *ptr)
45
- {
39
+ static size_t quic_tls_context_size(const void *ptr) {
46
40
  (void)ptr;
47
41
  return sizeof(quic_tls_ctx_t);
48
42
  }
49
43
 
50
44
  static const rb_data_type_t quic_tls_context_type = {
51
- "QUIC::TLSContext",
52
- {NULL, quic_tls_context_free, quic_tls_context_size,},
53
- NULL, NULL,
54
- RUBY_TYPED_FREE_IMMEDIATELY,
45
+ "QUIC::TLSContext",
46
+ {
47
+ NULL,
48
+ quic_tls_context_free,
49
+ quic_tls_context_size,
50
+ },
51
+ NULL,
52
+ NULL,
53
+ RUBY_TYPED_FREE_IMMEDIATELY,
55
54
  };
56
55
 
57
- quic_tls_ctx_t *
58
- quic_tls_context_get(VALUE tls_context)
59
- {
60
- return (quic_tls_ctx_t *)rb_check_typeddata(tls_context, &quic_tls_context_type);
56
+ quic_tls_ctx_t *quic_tls_context_get(VALUE tls_context) {
57
+ return (quic_tls_ctx_t *)rb_check_typeddata(tls_context,
58
+ &quic_tls_context_type);
61
59
  }
62
60
 
63
61
  /* Pick the first of the server's ALPN protocols, in the server's order of
@@ -65,16 +63,19 @@ quic_tls_context_get(VALUE tls_context)
65
63
  held and never touches Ruby objects. */
66
64
  static int
67
65
  quic_tls_on_client_hello_cb(ptls_on_client_hello_t *self, ptls_t *tls,
68
- ptls_on_client_hello_parameters_t *params)
69
- {
70
- quic_tls_ctx_t *t = (quic_tls_ctx_t *)((char *)self - offsetof(quic_tls_ctx_t, on_client_hello));
66
+ ptls_on_client_hello_parameters_t *params) {
67
+ quic_tls_ctx_t *t =
68
+ (quic_tls_ctx_t *)((char *)self -
69
+ offsetof(quic_tls_ctx_t, on_client_hello));
71
70
  for (size_t i = 0; i < t->alpn_count; i++) {
72
71
  for (size_t j = 0; j < params->negotiated_protocols.count; j++) {
73
72
  ptls_iovec_t offered = params->negotiated_protocols.list[j];
74
73
  if (offered.len == t->alpn[i].len &&
75
74
  memcmp(offered.base, t->alpn[i].base, offered.len) == 0) {
76
- return ptls_set_negotiated_protocol(tls, (const char *)offered.base, offered.len) == 0
77
- ? 0 : PTLS_ERROR_NO_MEMORY;
75
+ return ptls_set_negotiated_protocol(tls, (const char *)offered.base,
76
+ offered.len) == 0
77
+ ? 0
78
+ : PTLS_ERROR_NO_MEMORY;
78
79
  }
79
80
  }
80
81
  }
@@ -84,9 +85,8 @@ quic_tls_on_client_hello_cb(ptls_on_client_hello_t *self, ptls_t *tls,
84
85
  /* Never supply a passphrase. Without a callback, PEM_read_bio_PrivateKey
85
86
  falls back to PEM_def_callback, which prompts on the controlling terminal;
86
87
  this way an encrypted key fails to load like any other unreadable one. */
87
- static int
88
- quic_tls_no_passphrase_cb(char *buf, int size, int rwflag, void *userdata)
89
- {
88
+ static int quic_tls_no_passphrase_cb(char *buf, int size, int rwflag,
89
+ void *userdata) {
90
90
  (void)buf;
91
91
  (void)size;
92
92
  (void)rwflag;
@@ -100,10 +100,9 @@ quic_tls_no_passphrase_cb(char *buf, int size, int rwflag, void *userdata)
100
100
  raises ArgumentError naming the step that failed. Everything allocated
101
101
  here is released before raising, and libcrypto's error queue, which is
102
102
  shared with Ruby's openssl extension, is left empty on every return. */
103
- static void
104
- quic_tls_ctx_load_certificate_and_key(quic_tls_ctx_t *t, VALUE certificate_path,
105
- VALUE private_key_path)
106
- {
103
+ static void quic_tls_ctx_load_certificate_and_key(quic_tls_ctx_t *t,
104
+ VALUE certificate_path,
105
+ VALUE private_key_path) {
107
106
  VALUE failure_class = rb_eArgError;
108
107
  const char *failure = NULL;
109
108
  VALUE failed_path = Qnil;
@@ -118,7 +117,8 @@ quic_tls_ctx_load_certificate_and_key(quic_tls_ctx_t *t, VALUE certificate_path,
118
117
  ERR_clear_error();
119
118
 
120
119
  cert_bio = BIO_new_file(RSTRING_PTR(certificate_path), "r");
121
- if (cert_bio == NULL || (leaf = PEM_read_bio_X509(cert_bio, NULL, NULL, NULL)) == NULL) {
120
+ if (cert_bio == NULL ||
121
+ (leaf = PEM_read_bio_X509(cert_bio, NULL, NULL, NULL)) == NULL) {
122
122
  failure = "failed to load certificate";
123
123
  failed_path = certificate_path;
124
124
  goto done;
@@ -138,9 +138,11 @@ quic_tls_ctx_load_certificate_and_key(quic_tls_ctx_t *t, VALUE certificate_path,
138
138
  }
139
139
  }
140
140
  /* The loop ends with PEM_R_NO_START_LINE once no PEM block is left. Any
141
- other error means a broken block, as in SSL_CTX_use_certificate_chain_file. */
141
+ other error means a broken block, as in SSL_CTX_use_certificate_chain_file.
142
+ */
142
143
  err = ERR_peek_last_error();
143
- if (ERR_GET_LIB(err) != ERR_LIB_PEM || ERR_GET_REASON(err) != PEM_R_NO_START_LINE) {
144
+ if (ERR_GET_LIB(err) != ERR_LIB_PEM ||
145
+ ERR_GET_REASON(err) != PEM_R_NO_START_LINE) {
144
146
  failure = "failed to load certificate";
145
147
  failed_path = certificate_path;
146
148
  goto done;
@@ -148,7 +150,8 @@ quic_tls_ctx_load_certificate_and_key(quic_tls_ctx_t *t, VALUE certificate_path,
148
150
 
149
151
  key_bio = BIO_new_file(RSTRING_PTR(private_key_path), "r");
150
152
  if (key_bio == NULL ||
151
- (pkey = PEM_read_bio_PrivateKey(key_bio, NULL, quic_tls_no_passphrase_cb, NULL)) == NULL) {
153
+ (pkey = PEM_read_bio_PrivateKey(key_bio, NULL, quic_tls_no_passphrase_cb,
154
+ NULL)) == NULL) {
152
155
  failure = "failed to load private key";
153
156
  failed_path = private_key_path;
154
157
  goto done;
@@ -186,22 +189,27 @@ done:
186
189
  BIO_free(key_bio);
187
190
  ERR_clear_error();
188
191
 
189
- if (failure == NULL) return;
190
- if (NIL_P(failed_path)) rb_raise(failure_class, "%s", failure);
191
- rb_raise(failure_class, "%s: %"PRIsVALUE, failure, failed_path);
192
+ if (failure == NULL)
193
+ return;
194
+ if (NIL_P(failed_path))
195
+ rb_raise(failure_class, "%s", failure);
196
+ rb_raise(failure_class, "%s: %" PRIsVALUE, failure, failed_path);
192
197
  }
193
198
 
194
199
  VALUE
195
- quic_tls_context_server_new(VALUE certificate_path, VALUE private_key_path, VALUE alpn_ary)
196
- {
200
+ quic_tls_context_server_new(VALUE certificate_path, VALUE private_key_path,
201
+ VALUE alpn_ary) {
197
202
  certificate_path = quic_path_value(certificate_path, "certificate_path");
198
203
  private_key_path = quic_path_value(private_key_path, "private_key_path");
199
- if (NIL_P(certificate_path)) rb_raise(rb_eArgError, "certificate_path must not be nil");
200
- if (NIL_P(private_key_path)) rb_raise(rb_eArgError, "private_key_path must not be nil");
204
+ if (NIL_P(certificate_path))
205
+ rb_raise(rb_eArgError, "certificate_path must not be nil");
206
+ if (NIL_P(private_key_path))
207
+ rb_raise(rb_eArgError, "private_key_path must not be nil");
201
208
 
202
209
  /* The object owns the context from the start, so that an exception below
203
210
  releases whatever was built so far. */
204
- VALUE self = TypedData_Wrap_Struct(rb_cQUICTLSContext, &quic_tls_context_type, NULL);
211
+ VALUE self =
212
+ TypedData_Wrap_Struct(rb_cQUICTLSContext, &quic_tls_context_type, NULL);
205
213
  quic_tls_ctx_t *t = ZALLOC(quic_tls_ctx_t);
206
214
  t->refcnt = 1;
207
215
  DATA_PTR(self) = t;
@@ -209,21 +217,23 @@ quic_tls_context_server_new(VALUE certificate_path, VALUE private_key_path, VALU
209
217
  /* Without an ALPN to pick, every handshake would end in
210
218
  no_application_protocol. */
211
219
  quic_copy_alpn(alpn_ary, &t->alpn, &t->alpn_count, &t->alpn_buf);
212
- if (t->alpn_count == 0) rb_raise(rb_eArgError, "alpn must not be empty for a server");
220
+ if (t->alpn_count == 0)
221
+ rb_raise(rb_eArgError, "alpn must not be empty for a server");
213
222
 
214
223
  t->ctx = (ptls_context_t){
215
- .random_bytes = ptls_openssl_random_bytes,
216
- .get_time = &ptls_get_time,
217
- .key_exchanges = quic_key_exchanges,
218
- .cipher_suites = quic_cipher_suites,
219
- /* No session resumption: encrypt_ticket stays NULL, so no ticket is
220
- ever issued. Keep this so that PSK-only resumption is refused once
221
- resumption is added. */
222
- .require_dhe_on_psk = 1,
223
- .server_cipher_preference = 1,
224
+ .random_bytes = ptls_openssl_random_bytes,
225
+ .get_time = &ptls_get_time,
226
+ .key_exchanges = quic_key_exchanges,
227
+ .cipher_suites = quic_cipher_suites,
228
+ /* No session resumption: encrypt_ticket stays NULL, so no ticket is
229
+ ever issued. Keep this so that PSK-only resumption is refused once
230
+ resumption is added. */
231
+ .require_dhe_on_psk = 1,
232
+ .server_cipher_preference = 1,
224
233
  };
225
234
  if (ngtcp2_crypto_picotls_configure_server_context(&t->ctx) != 0) {
226
- rb_raise(rb_eRuntimeError, "ngtcp2_crypto_picotls_configure_server_context failed");
235
+ rb_raise(rb_eRuntimeError,
236
+ "ngtcp2_crypto_picotls_configure_server_context failed");
227
237
  }
228
238
  /* verify_certificate stays NULL: no client certificate is requested. */
229
239
  quic_tls_ctx_load_certificate_and_key(t, certificate_path, private_key_path);
@@ -234,13 +244,12 @@ quic_tls_context_server_new(VALUE certificate_path, VALUE private_key_path, VALU
234
244
 
235
245
  /* QUIC::TLSContext.server(certificate_path:, private_key_path:, alpn:). A
236
246
  missing or unknown keyword raises ArgumentError as a Ruby method would. */
237
- static VALUE
238
- quic_tls_context_s_server(int argc, VALUE *argv, VALUE klass)
239
- {
247
+ static VALUE quic_tls_context_s_server(int argc, VALUE *argv, VALUE klass) {
240
248
  (void)klass;
241
249
  VALUE opts = Qnil;
242
250
  rb_scan_args(argc, argv, "0:", &opts);
243
- if (NIL_P(opts)) opts = rb_hash_new();
251
+ if (NIL_P(opts))
252
+ opts = rb_hash_new();
244
253
 
245
254
  ID keywords[3];
246
255
  VALUE values[3];
@@ -251,10 +260,10 @@ quic_tls_context_s_server(int argc, VALUE *argv, VALUE klass)
251
260
  return quic_tls_context_server_new(values[0], values[1], values[2]);
252
261
  }
253
262
 
254
- void
255
- Init_quic_tls_context(VALUE rb_mQUICArg)
256
- {
257
- rb_cQUICTLSContext = rb_define_class_under(rb_mQUICArg, "TLSContext", rb_cObject);
263
+ void Init_quic_tls_context(VALUE rb_mQUICArg) {
264
+ rb_cQUICTLSContext =
265
+ rb_define_class_under(rb_mQUICArg, "TLSContext", rb_cObject);
258
266
  rb_undef_alloc_func(rb_cQUICTLSContext);
259
- rb_define_singleton_method(rb_cQUICTLSContext, "server", quic_tls_context_s_server, -1);
267
+ rb_define_singleton_method(rb_cQUICTLSContext, "server",
268
+ quic_tls_context_s_server, -1);
260
269
  }
@@ -34,7 +34,8 @@ void Init_quic_tls_context(VALUE rb_mQUICArg);
34
34
  holding the one reference to a new context. alpn_ary must be a non-empty
35
35
  Array of 1-255 byte Strings. Raises ArgumentError naming what could not
36
36
  be loaded or used. */
37
- VALUE quic_tls_context_server_new(VALUE certificate_path, VALUE private_key_path, VALUE alpn_ary);
37
+ VALUE quic_tls_context_server_new(VALUE certificate_path,
38
+ VALUE private_key_path, VALUE alpn_ary);
38
39
 
39
40
  /* The context behind a QUIC::TLSContext object. Raises TypeError for any
40
41
  other object. */
data/lib/quic/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module QUIC
4
- VERSION = "0.0.3"
4
+ VERSION = "0.0.5"
5
5
  end