quic 0.0.5 → 0.0.7

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.
@@ -14,6 +14,14 @@
14
14
  minimum destlen ngtcp2 accepts. Revisit when PMTUD is enabled (Phase 4+). */
15
15
  #define QUIC_WRITE_PKT_BUFLEN NGTCP2_MAX_UDP_PAYLOAD_SIZE
16
16
 
17
+ /* Whether the stream handler h has member, judged by the size it was built
18
+ with: a handler built against an older quic/ext.h is shorter, and its
19
+ memory ends before the members added since. Compared with the end of the
20
+ member, not the start of the next one, so trailing padding does not
21
+ count. */
22
+ #define QUIC_EXT_HANDLER_HAS(h, member) \
23
+ ((h)->size >= offsetof(quic_ext_stream_handler, member) + sizeof((h)->member))
24
+
17
25
  /* A QUIC::Endpoint (endpoint.c). */
18
26
  typedef struct quic_endpoint quic_endpoint_t;
19
27
 
@@ -57,11 +65,18 @@ typedef struct {
57
65
  ptls_get_data_ptr. The ref must outlive the ptls_t. */
58
66
  ngtcp2_crypto_conn_ref conn_ref;
59
67
  /* Back-reference to the Client or Server Ruby object that owns this
60
- struct. ngtcp2 stream callbacks receive a void* user_data equal to this
61
- struct, and they look up @streams via owner. We are stored INSIDE owner
62
- via TypedData_Wrap_Struct, so owner is guaranteed alive while we exist
63
- (no dmark needed). GC.compact may relocate owner, so quic_conn_compact
64
- updates this field via rb_gc_location. */
68
+ struct. ngtcp2 callbacks receive a void* user_data equal to this
69
+ struct, and reach @streams and @accept_queue via owner. We are stored
70
+ INSIDE owner via TypedData_Wrap_Struct, so owner is guaranteed alive
71
+ while we exist (no dmark needed). GC.compact may relocate owner, so
72
+ quic_conn_compact updates this field via rb_gc_location.
73
+
74
+ A stream's callbacks get its QUIC::Stream's quic_stream_t from
75
+ ngtcp2's stream_user_data, which is only safe while @streams keeps
76
+ that Stream alive. So a Stream goes into @streams before ngtcp2 is
77
+ given its struct, and leaves only at the end of the stream_close
78
+ callback, which must not fail after that: a failing stream_close
79
+ leaves the stream in ngtcp2, pointing at a struct GC may free. */
65
80
  VALUE owner;
66
81
  /* An exception raised by Ruby code inside an ngtcp2 callback, caught with
67
82
  rb_protect so that it does not unwind through ngtcp2's frames. #read_pkt,
@@ -86,6 +101,11 @@ typedef struct {
86
101
  /* Set by the constructor. Decides which peer-initiated streams
87
102
  recv_stream_data queues for #accept_stream. */
88
103
  bool is_server;
104
+ /* The bytes the QUIC::Streams of this connection have queued and not yet
105
+ handed to ngtcp2, stopped streams excepted. ngtcp2 takes off the
106
+ connection's flow control window only what it has sent, so #write and
107
+ #write_nonblock take this off as well. */
108
+ uint64_t stream_unsent;
89
109
  /* <qlog_dir>/<SCID>.sqlog while ngtcp2 writes qlog to it, else NULL.
90
110
  quic_conn_close_qlog closes it as soon as the connection ends;
91
111
  NGTCP2_QLOG_WRITE_FLAG_FIN, sent by ngtcp2_conn_del, closes one still
@@ -126,6 +146,12 @@ VALUE quic_conn_alloc(VALUE klass);
126
146
  /* CLOCK_MONOTONIC in ngtcp2's units (nanoseconds). */
127
147
  ngtcp2_tstamp quic_now(void);
128
148
 
149
+ /* Run body(arg), Ruby code an ngtcp2 callback of c calls, under rb_protect.
150
+ An exception is kept in c->pending_exc (the first one wins; ngtcp2 stops
151
+ at the first failing callback anyway) and turned into
152
+ NGTCP2_ERR_CALLBACK_FAILURE, so that it never unwinds through ngtcp2. */
153
+ int quic_conn_protect(quic_conn_t *c, VALUE (*body)(VALUE), void *arg);
154
+
129
155
  /* Build the next packet of the connection self (wrapping c) into dest of
130
156
  QUIC_WRITE_PKT_BUFLEN bytes, as #write_pkt does, and store its path in
131
157
  *path. Returns the packet's length, 0 when there is nothing to send, or a
data/ext/quic/ext_api.c CHANGED
@@ -15,14 +15,16 @@ static quic_ext_conn *quic_ext_conn_get(VALUE conn) {
15
15
 
16
16
  /* Hand every stream of the connection to h. Allowed once, and only before
17
17
  the connection has a QUIC::Stream: the two modes cannot share streams.
18
- Every member of the ABI 1.0 handler is called, so h must be at least that
19
- large. @stream_handler marks the connection for the Ruby side, which then
20
- refuses #accept_stream. */
18
+ Every member of the ABI 1.0 handler is called, so h must hold them all
19
+ (handshake_completed is the last). A handler built against an older
20
+ quic/ext.h than this one is shorter than sizeof(quic_ext_stream_handler),
21
+ and is called only for the members its size covers. @stream_handler marks
22
+ the connection for the Ruby side, which then refuses #accept_stream. */
21
23
  static int quic_ext_set_stream_handler(quic_ext_conn *ec,
22
24
  const quic_ext_stream_handler *h,
23
25
  void *ud, VALUE owner) {
24
26
  quic_conn_t *c = quic_ext_conn_struct(ec);
25
- if (h == NULL || h->size < sizeof(quic_ext_stream_handler))
27
+ if (h == NULL || !QUIC_EXT_HANDLER_HAS(h, handshake_completed))
26
28
  return QUIC_EXT_ERR_OTHER;
27
29
  if (c->handler != NULL)
28
30
  return QUIC_EXT_ERR_INVALID_STATE;
@@ -93,7 +95,7 @@ static int quic_ext_set_application_error(quic_ext_conn *ec,
93
95
 
94
96
  const quic_ext_api quic_ext_api_table = {
95
97
  .abi_major = QUIC_EXT_ABI_MAJOR,
96
- .abi_minor = 0,
98
+ .abi_minor = QUIC_EXT_ABI_MINOR,
97
99
  .size = sizeof(quic_ext_api),
98
100
  .conn_get = quic_ext_conn_get,
99
101
  .set_stream_handler = quic_ext_set_stream_handler,
data/ext/quic/extconf.rb CHANGED
@@ -5,11 +5,11 @@ require "mini_portile2"
5
5
  require "shellwords"
6
6
  require "fileutils"
7
7
 
8
- NGTCP2_VERSION = "1.25.0"
9
- NGTCP2_SHA256 = "1c0843076528a87b65e9a9d455100941f4cb65d44f96c5da6ae56df146043955"
10
- # The picotls revision that ngtcp2 1.25.0 is tested against (see ngtcp2's README).
11
- PICOTLS_COMMIT = "f07f1c8c68b237f1468bc1f1fe1b68aba3ff23b4"
12
- PICOTLS_SHA256 = "6ecb4f8d9946c2b9342300b29627dc34e746a551d438d35af325a4495d62a6e3"
8
+ NGTCP2_VERSION = "1.26.0"
9
+ NGTCP2_SHA256 = "85174d674e7f8fd911a827c6e483fd417b21b1f54d7853dac464cee446c8d35f"
10
+ # The picotls revision that ngtcp2 1.26.0 is tested against (see ngtcp2's README).
11
+ PICOTLS_COMMIT = "a2d95de4c875d6dcb27658e476e3b624f4381bf0"
12
+ PICOTLS_SHA256 = "d54263601c4652ef28451533bb2e2fae3f5f44aff54338cf5110b9c12c4bab3a"
13
13
  # Bump when ext/quic/patches/picotls/ or PicotlsRecipe::SOURCES changes;
14
14
  # installed? only checks for the archive.
15
15
  PICOTLS_PATCH_LEVEL = "p2"
@@ -14,7 +14,13 @@
14
14
  * the table's. The structs below grow only by appending, which bumps
15
15
  * abi_minor; reordering, removing or retyping a member bumps abi_major.
16
16
  * Check `size` before calling a member added after the version you were
17
- * built against. The handler struct follows the same rules.
17
+ * built against. The handler struct follows the same rules:
18
+ * set_stream_handler takes any handler at least as large as the ABI 1.0
19
+ * one, and quic.so calls a member added later only when the handler's
20
+ * `size` covers it. Every member `size` covers must be non-NULL.
21
+ * A member added after ABI 1.0 is marked with the minor that brought it
22
+ * (abi_minor N), and quic.so calls a handler member only when the table's
23
+ * abi_minor is at least that N: an older quic.so leaves it uncalled.
18
24
  * - Exceptions: no function in the table and no handler function raises a
19
25
  * Ruby exception; they return 0 or a negative error code. The one
20
26
  * exception is conn_get, which raises TypeError for a wrong object and is
@@ -37,6 +43,8 @@
37
43
  #include <stdint.h>
38
44
 
39
45
  #define QUIC_EXT_ABI_MAJOR 1
46
+ /* The abi_minor of the structs as this header declares them. */
47
+ #define QUIC_EXT_ABI_MINOR 1
40
48
 
41
49
  #define QUIC_EXT_ERR_INVALID_STATE (-1)
42
50
  #define QUIC_EXT_ERR_STREAM_ID_BLOCKED (-2)
@@ -67,6 +75,19 @@ typedef struct {
67
75
  int (*stream_close)(void *ud, int64_t id, int has_code,
68
76
  uint64_t app_error_code);
69
77
  int (*handshake_completed)(void *ud);
78
+ /* abi_minor 1 */
79
+ /* The peer sent STOP_SENDING on stream id, which this endpoint sends on
80
+ (stream_stop_sending is the other way: this endpoint stopped reading).
81
+ Called once per stream. Once it returns 0, ngtcp2 shuts the send side
82
+ and sends RESET_STREAM carrying app_error_code, unless all that was
83
+ sent, FIN included, has been acknowledged. next_stream_data should no
84
+ longer offer the stream; if it does, stream_shut_write follows. It can
85
+ come before any recv_stream_data, for a stream the peer has just
86
+ opened, and also comes for a unidirectional stream this endpoint
87
+ opened. stream_close may follow within the same #read_pkt. Calling
88
+ shutdown_stream_write here sends RESET_STREAM with that code instead,
89
+ but stream_close still reports app_error_code. */
90
+ int (*recv_stop_sending)(void *ud, int64_t id, uint64_t app_error_code);
70
91
  } quic_ext_stream_handler;
71
92
 
72
93
  typedef struct {