quic 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,31 @@
1
+ #ifndef QUIC_ENDPOINT_H
2
+ #define QUIC_ENDPOINT_H 1
3
+
4
+ #include "connection_common.h"
5
+
6
+ extern VALUE rb_cQUICEndpoint;
7
+
8
+ /* The CID table, for the get_new_connection_id2 and remove_connection_id
9
+ callbacks of a connection the Endpoint holds. conn is that connection's
10
+ object. Neither touches Ruby objects, so the callbacks need no
11
+ rb_protect. dissociate leaves an entry that maps to another connection
12
+ alone. */
13
+ void quic_endpoint_associate_cid(quic_endpoint_t *ep, const ngtcp2_cid *cid,
14
+ VALUE conn);
15
+ void quic_endpoint_dissociate_cid(quic_endpoint_t *ep, const ngtcp2_cid *cid,
16
+ VALUE conn);
17
+
18
+ /* The Stateless Reset token for cid, derived from the Endpoint's secret so
19
+ that it can be made again for a CID no longer in the table. token is
20
+ NGTCP2_STATELESS_RESET_TOKENLEN bytes. Returns 0, or -1 on failure. */
21
+ int quic_endpoint_generate_reset_token(const quic_endpoint_t *ep,
22
+ uint8_t *token, const ngtcp2_cid *cid);
23
+
24
+ /* Connection#close of a connection the Endpoint holds: build the
25
+ CONNECTION_CLOSE carrying ccerr, queue it for Endpoint#write_pkt and
26
+ start the closing period. When ngtcp2 cannot build the packet, the
27
+ connection leaves the table at once. */
28
+ void quic_endpoint_close_conn(quic_endpoint_t *ep, quic_conn_t *c,
29
+ const ngtcp2_ccerr *ccerr);
30
+
31
+ #endif /* QUIC_ENDPOINT_H */
@@ -0,0 +1,106 @@
1
+ #include "connection_common.h"
2
+
3
+ /* The quic_ext_api table of quic/ext.h. A quic_ext_conn * is a quic_conn_t *
4
+ behind the opaque type. None of these functions raises a Ruby exception
5
+ except quic_ext_conn_get; they return 0 or a QUIC_EXT_ERR_* code. */
6
+
7
+ static quic_conn_t *quic_ext_conn_struct(quic_ext_conn *ec) {
8
+ return (quic_conn_t *)ec;
9
+ }
10
+
11
+ /* Raises TypeError unless conn is a QUIC::Connection::Client or Server. */
12
+ static quic_ext_conn *quic_ext_conn_get(VALUE conn) {
13
+ return (quic_ext_conn *)rb_check_typeddata(conn, &quic_conn_data_type);
14
+ }
15
+
16
+ /* Hand every stream of the connection to h. Allowed once, and only before
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. */
21
+ static int quic_ext_set_stream_handler(quic_ext_conn *ec,
22
+ const quic_ext_stream_handler *h,
23
+ void *ud, VALUE owner) {
24
+ quic_conn_t *c = quic_ext_conn_struct(ec);
25
+ if (h == NULL || h->size < sizeof(quic_ext_stream_handler))
26
+ return QUIC_EXT_ERR_OTHER;
27
+ if (c->handler != NULL)
28
+ return QUIC_EXT_ERR_INVALID_STATE;
29
+ VALUE streams = rb_ivar_get(c->owner, rb_intern("@streams"));
30
+ if (RB_TYPE_P(streams, T_HASH) && RHASH_SIZE(streams) > 0)
31
+ return QUIC_EXT_ERR_INVALID_STATE;
32
+
33
+ c->handler = h;
34
+ c->handler_ud = ud;
35
+ c->handler_owner = owner;
36
+ rb_ivar_set(c->owner, rb_intern("@stream_handler"), Qtrue);
37
+ return 0;
38
+ }
39
+
40
+ static int quic_ext_open_uni_stream(quic_ext_conn *ec, int64_t *id) {
41
+ quic_conn_t *c = quic_ext_conn_struct(ec);
42
+ int rv = ngtcp2_conn_open_uni_stream(c->conn, id, NULL);
43
+ if (rv == NGTCP2_ERR_STREAM_ID_BLOCKED)
44
+ return QUIC_EXT_ERR_STREAM_ID_BLOCKED;
45
+ return rv == 0 ? 0 : QUIC_EXT_ERR_OTHER;
46
+ }
47
+
48
+ /* Give the peer n more bytes of credit on the stream and the connection,
49
+ for data the handler has now consumed (for HTTP/3, request body handed
50
+ to the application). */
51
+ static int quic_ext_consume(quic_ext_conn *ec, int64_t id, uint64_t n) {
52
+ quic_conn_t *c = quic_ext_conn_struct(ec);
53
+ if (ngtcp2_conn_extend_max_stream_offset(c->conn, id, n) != 0)
54
+ return QUIC_EXT_ERR_OTHER;
55
+ ngtcp2_conn_extend_max_offset(c->conn, n);
56
+ return 0;
57
+ }
58
+
59
+ /* Both return 0 for a stream ngtcp2 no longer knows. */
60
+ static int quic_ext_shutdown_stream_read(quic_ext_conn *ec, int64_t id,
61
+ uint64_t app_error_code) {
62
+ quic_conn_t *c = quic_ext_conn_struct(ec);
63
+ return ngtcp2_conn_shutdown_stream_read(c->conn, 0, id, app_error_code) == 0
64
+ ? 0
65
+ : QUIC_EXT_ERR_OTHER;
66
+ }
67
+
68
+ static int quic_ext_shutdown_stream_write(quic_ext_conn *ec, int64_t id,
69
+ uint64_t app_error_code) {
70
+ quic_conn_t *c = quic_ext_conn_struct(ec);
71
+ return ngtcp2_conn_shutdown_stream_write(c->conn, 0, id, app_error_code) == 0
72
+ ? 0
73
+ : QUIC_EXT_ERR_OTHER;
74
+ }
75
+
76
+ /* This endpoint's initial_max_streams_bidi. nghttp3 needs it at setup;
77
+ later raises arrive through the extend_max_remote_streams_bidi handler. */
78
+ static uint64_t quic_ext_local_max_streams_bidi(quic_ext_conn *ec) {
79
+ quic_conn_t *c = quic_ext_conn_struct(ec);
80
+ return ngtcp2_conn_get_local_transport_params2(c->conn)
81
+ ->initial_max_streams_bidi;
82
+ }
83
+
84
+ /* Remember the application error to close the connection with after the
85
+ handler reports a failure (for HTTP/3, the H3_* code nghttp3 gave). */
86
+ static int quic_ext_set_application_error(quic_ext_conn *ec,
87
+ uint64_t app_error_code) {
88
+ quic_conn_t *c = quic_ext_conn_struct(ec);
89
+ ngtcp2_ccerr_set_application_error(&c->close_error, app_error_code, NULL, 0);
90
+ c->close_error_set = true;
91
+ return 0;
92
+ }
93
+
94
+ const quic_ext_api quic_ext_api_table = {
95
+ .abi_major = QUIC_EXT_ABI_MAJOR,
96
+ .abi_minor = 0,
97
+ .size = sizeof(quic_ext_api),
98
+ .conn_get = quic_ext_conn_get,
99
+ .set_stream_handler = quic_ext_set_stream_handler,
100
+ .open_uni_stream = quic_ext_open_uni_stream,
101
+ .consume = quic_ext_consume,
102
+ .shutdown_stream_read = quic_ext_shutdown_stream_read,
103
+ .shutdown_stream_write = quic_ext_shutdown_stream_write,
104
+ .local_max_streams_bidi = quic_ext_local_max_streams_bidi,
105
+ .set_application_error = quic_ext_set_application_error,
106
+ };
data/ext/quic/extconf.rb CHANGED
@@ -10,8 +10,9 @@ NGTCP2_SHA256 = "1c0843076528a87b65e9a9d455100941f4cb65d44f96c5da6ae56df14604395
10
10
  # The picotls revision that ngtcp2 1.25.0 is tested against (see ngtcp2's README).
11
11
  PICOTLS_COMMIT = "f07f1c8c68b237f1468bc1f1fe1b68aba3ff23b4"
12
12
  PICOTLS_SHA256 = "6ecb4f8d9946c2b9342300b29627dc34e746a551d438d35af325a4495d62a6e3"
13
- # Bump when ext/quic/patches/picotls/ changes; installed? only checks for the archive.
14
- PICOTLS_PATCH_LEVEL = "p1"
13
+ # Bump when ext/quic/patches/picotls/ or PicotlsRecipe::SOURCES changes;
14
+ # installed? only checks for the archive.
15
+ PICOTLS_PATCH_LEVEL = "p2"
15
16
 
16
17
  # Locate the host's libcrypto. ngtcp2 and picotls are vendored and statically
17
18
  # linked, but the crypto primitives and X.509 come from whatever OpenSSL (or
@@ -39,10 +40,12 @@ end
39
40
  openssl_cflags = pkg_config("openssl", "cflags-only-I").to_s.strip
40
41
 
41
42
  # picotls has no release tarballs, and its CMake build needs the picotest
42
- # submodule, which GitHub archive tarballs do not contain. Build only the two
43
- # libraries we need (core + OpenSSL-API backend) into a single libpicotls.a.
43
+ # submodule, which GitHub archive tarballs do not contain. Build only what
44
+ # quic.so uses into a single libpicotls.a: the core and the OpenSSL-API
45
+ # backend. The core's lib/pembase64.c, a PEM loader, is left out; the server
46
+ # reads its certificates with libcrypto instead.
44
47
  class PicotlsRecipe < MiniPortile
45
- SOURCES = %w[lib/picotls.c lib/hpke.c lib/pembase64.c lib/openssl.c].freeze
48
+ SOURCES = %w[lib/picotls.c lib/hpke.c lib/openssl.c].freeze
46
49
 
47
50
  attr_accessor :openssl_cflags
48
51
 
@@ -161,4 +164,8 @@ append_cflags("-DQUIC_PICOTLS_COMMIT=\\\"#{PICOTLS_COMMIT}\\\"")
161
164
  append_cflags("-fvisibility=hidden")
162
165
  append_ldflags("-Wl,--exclude-libs,ALL") # Unexport symbols from statically linked libraries
163
166
 
167
+ # quic/ext.h, the C function table other extensions (the http3 gem) build
168
+ # against. It ships in the gem; QUIC::EXT_INCLUDE_DIR points them here.
169
+ append_cppflags("-I#{File.expand_path("include", __dir__)}")
170
+
164
171
  create_makefile("quic/quic")
@@ -0,0 +1,91 @@
1
+ /* quic/ext.h — the C function table quic.so offers to other extensions.
2
+ *
3
+ * Another extension (the http3 gem) registers a stream handler on a
4
+ * connection and drives it through this table instead of QUIC::Stream.
5
+ * Obtain the table after rb_require("quic") with
6
+ *
7
+ * quic_ext_get_api_fn get = (quic_ext_get_api_fn)rb_ext_resolve_symbol(
8
+ * "quic/quic", "quic_ext_get_api");
9
+ * const quic_ext_api *api = get ? get(QUIC_EXT_ABI_MAJOR) : NULL;
10
+ *
11
+ * Rules:
12
+ *
13
+ * - Version: quic_ext_get_api(major) returns NULL when major differs from
14
+ * the table's. The structs below grow only by appending, which bumps
15
+ * abi_minor; reordering, removing or retyping a member bumps abi_major.
16
+ * Check `size` before calling a member added after the version you were
17
+ * built against. The handler struct follows the same rules.
18
+ * - Exceptions: no function in the table and no handler function raises a
19
+ * Ruby exception; they return 0 or a negative error code. The one
20
+ * exception is conn_get, which raises TypeError for a wrong object and is
21
+ * meant for initialization called from a Ruby method. A handler function
22
+ * returning a negative value makes the ngtcp2 callback fail with
23
+ * NGTCP2_ERR_CALLBACK_FAILURE.
24
+ * - Lifetime: `owner` passed to set_stream_handler is marked by the
25
+ * connection while it lives. `ud` must not move (allocate it with
26
+ * xmalloc, not as a Ruby object), and `h` must outlive the connection
27
+ * (a static const struct). quic.so never calls a handler from its dfree,
28
+ * and the owner's dfree must not touch the quic_ext_conn.
29
+ * - Where: table functions may be called from inside handler functions.
30
+ * Everything runs with the GVL held.
31
+ */
32
+ #ifndef QUIC_EXT_H
33
+ #define QUIC_EXT_H 1
34
+
35
+ #include <ruby.h>
36
+ #include <stddef.h>
37
+ #include <stdint.h>
38
+
39
+ #define QUIC_EXT_ABI_MAJOR 1
40
+
41
+ #define QUIC_EXT_ERR_INVALID_STATE (-1)
42
+ #define QUIC_EXT_ERR_STREAM_ID_BLOCKED (-2)
43
+ #define QUIC_EXT_ERR_STREAM_NOT_FOUND (-3)
44
+ #define QUIC_EXT_ERR_OTHER (-99)
45
+
46
+ typedef struct {
47
+ const uint8_t *base;
48
+ size_t len;
49
+ } quic_ext_vec; /* same layout as ngtcp2_vec */
50
+ typedef struct quic_ext_conn quic_ext_conn; /* opaque */
51
+
52
+ typedef struct {
53
+ size_t size; /* sizeof(quic_ext_stream_handler); tells which members exist */
54
+ int (*recv_stream_data)(void *ud, int64_t id, const uint8_t *data, size_t len,
55
+ int fin, uint64_t ts, size_t *consumed);
56
+ int (*next_stream_data)(void *ud, int64_t *id, int *fin, quic_ext_vec *vecs,
57
+ size_t cap, size_t *nvecs);
58
+ int (*stream_data_written)(void *ud, int64_t id, size_t n);
59
+ int (*stream_blocked)(void *ud, int64_t id);
60
+ int (*stream_shut_write)(void *ud, int64_t id);
61
+ int (*acked_stream_data)(void *ud, int64_t id, uint64_t n);
62
+ int (*extend_max_stream_data)(void *ud, int64_t id);
63
+ int (*extend_max_remote_streams_bidi)(void *ud, uint64_t max);
64
+ int (*stream_stop_sending)(void *ud, int64_t id, uint64_t app_error_code);
65
+ int (*stream_reset)(void *ud, int64_t id, uint64_t final_size,
66
+ uint64_t app_error_code);
67
+ int (*stream_close)(void *ud, int64_t id, int has_code,
68
+ uint64_t app_error_code);
69
+ int (*handshake_completed)(void *ud);
70
+ } quic_ext_stream_handler;
71
+
72
+ typedef struct {
73
+ uint32_t abi_major; /* bumped only to break compatibility */
74
+ uint32_t abi_minor; /* bumped whenever a member is appended */
75
+ size_t size; /* sizeof(quic_ext_api) */
76
+ quic_ext_conn *(*conn_get)(VALUE conn); /* TypeError for a wrong object */
77
+ int (*set_stream_handler)(quic_ext_conn *c, const quic_ext_stream_handler *h,
78
+ void *ud, VALUE owner);
79
+ int (*open_uni_stream)(quic_ext_conn *c, int64_t *id);
80
+ int (*consume)(quic_ext_conn *c, int64_t id, uint64_t n);
81
+ int (*shutdown_stream_read)(quic_ext_conn *c, int64_t id,
82
+ uint64_t app_error_code);
83
+ int (*shutdown_stream_write)(quic_ext_conn *c, int64_t id,
84
+ uint64_t app_error_code);
85
+ uint64_t (*local_max_streams_bidi)(quic_ext_conn *c);
86
+ int (*set_application_error)(quic_ext_conn *c, uint64_t app_error_code);
87
+ } quic_ext_api;
88
+
89
+ typedef const quic_ext_api *(*quic_ext_get_api_fn)(uint32_t abi_major);
90
+
91
+ #endif /* QUIC_EXT_H */
data/ext/quic/quic.c CHANGED
@@ -1,9 +1,11 @@
1
1
  #include "quic.h"
2
+ #include "connection_common.h"
2
3
  #include "stream.h"
3
4
 
4
5
  VALUE rb_mQUIC;
5
6
  VALUE rb_mQUICConnection;
6
7
  VALUE rb_cQUICConnectionClient;
8
+ VALUE rb_cQUICConnectionServer;
7
9
 
8
10
  VALUE rb_eQUICError;
9
11
  VALUE rb_eQUICErrorProto;
@@ -20,10 +22,17 @@ VALUE rb_eQUICErrorWaitWritable;
20
22
  VALUE rb_eQUICErrorStreamClosed;
21
23
  VALUE rb_eQUICErrorStreamReset;
22
24
  VALUE rb_eQUICErrorNotBound;
25
+ VALUE rb_eQUICErrorInvalidState;
23
26
 
24
- static VALUE
25
- quic_library_versions(VALUE self)
26
- {
27
+ /* The one symbol besides Init_quic that quic.so exports: other extensions
28
+ look it up with rb_ext_resolve_symbol("quic/quic", "quic_ext_get_api")
29
+ and get the C function table declared in quic/ext.h. NULL means the
30
+ caller was built against an incompatible major version. */
31
+ RUBY_FUNC_EXPORTED const quic_ext_api *quic_ext_get_api(uint32_t abi_major) {
32
+ return abi_major == QUIC_EXT_ABI_MAJOR ? &quic_ext_api_table : NULL;
33
+ }
34
+
35
+ static VALUE quic_library_versions(VALUE self) {
27
36
  (void)self;
28
37
  VALUE h = rb_hash_new();
29
38
  rb_hash_aset(h, ID2SYM(rb_intern("ngtcp2")),
@@ -37,90 +46,114 @@ quic_library_versions(VALUE self)
37
46
  return h;
38
47
  }
39
48
 
40
- void
41
- quic_raise_ngtcp2_error(int rv)
42
- {
49
+ VALUE
50
+ quic_ngtcp2_error_new(int rv) {
43
51
  VALUE cls;
44
52
  switch (rv) {
45
- case NGTCP2_ERR_PROTO:
46
- cls = rb_eQUICErrorProto;
47
- break;
48
- case NGTCP2_ERR_DROP_CONN:
49
- cls = rb_eQUICErrorDropConn;
50
- break;
51
- case NGTCP2_ERR_RETRY:
52
- cls = rb_eQUICErrorRetry;
53
- break;
54
- case NGTCP2_ERR_CLOSING:
55
- case NGTCP2_ERR_DRAINING:
56
- cls = rb_eQUICErrorClosed;
57
- break;
58
- case NGTCP2_ERR_IDLE_CLOSE:
59
- cls = rb_eQUICErrorClosed;
60
- break;
61
- case NGTCP2_ERR_CRYPTO:
62
- cls = rb_eQUICErrorCryptoError;
63
- break;
64
- case NGTCP2_ERR_HANDSHAKE_TIMEOUT:
65
- cls = rb_eQUICErrorHandshakeTimeout;
66
- break;
67
- case NGTCP2_ERR_STREAM_DATA_BLOCKED:
68
- cls = rb_eQUICErrorFlowControl;
69
- break;
70
- case NGTCP2_ERR_STREAM_SHUT_WR:
71
- cls = rb_eQUICErrorStreamClosed;
72
- break;
73
- default:
74
- cls = rb_eQUICErrorUnknown;
75
- break;
53
+ case NGTCP2_ERR_PROTO:
54
+ cls = rb_eQUICErrorProto;
55
+ break;
56
+ case NGTCP2_ERR_DROP_CONN:
57
+ cls = rb_eQUICErrorDropConn;
58
+ break;
59
+ case NGTCP2_ERR_RETRY:
60
+ cls = rb_eQUICErrorRetry;
61
+ break;
62
+ case NGTCP2_ERR_CLOSING:
63
+ case NGTCP2_ERR_DRAINING:
64
+ cls = rb_eQUICErrorClosed;
65
+ break;
66
+ case NGTCP2_ERR_IDLE_CLOSE:
67
+ cls = rb_eQUICErrorClosed;
68
+ break;
69
+ case NGTCP2_ERR_CRYPTO:
70
+ cls = rb_eQUICErrorCryptoError;
71
+ break;
72
+ case NGTCP2_ERR_HANDSHAKE_TIMEOUT:
73
+ cls = rb_eQUICErrorHandshakeTimeout;
74
+ break;
75
+ case NGTCP2_ERR_STREAM_DATA_BLOCKED:
76
+ cls = rb_eQUICErrorFlowControl;
77
+ break;
78
+ case NGTCP2_ERR_STREAM_SHUT_WR:
79
+ cls = rb_eQUICErrorStreamClosed;
80
+ break;
81
+ default:
82
+ cls = rb_eQUICErrorUnknown;
83
+ break;
76
84
  }
77
85
 
78
86
  VALUE exc = rb_exc_new_cstr(cls, ngtcp2_strerror(rv));
79
87
  rb_ivar_set(exc, rb_intern("@code"), INT2NUM(rv));
80
- rb_exc_raise(exc);
88
+ return exc;
89
+ }
90
+
91
+ void quic_raise_ngtcp2_error(int rv) {
92
+ rb_exc_raise(quic_ngtcp2_error_new(rv));
81
93
  }
82
94
 
83
- RUBY_FUNC_EXPORTED void
84
- Init_quic(void)
85
- {
95
+ RUBY_FUNC_EXPORTED void Init_quic(void) {
86
96
  rb_mQUIC = rb_define_module("QUIC");
87
97
  rb_mQUICConnection = rb_define_module_under(rb_mQUIC, "Connection");
88
- rb_define_singleton_method(rb_mQUIC, "library_versions", quic_library_versions, 0);
98
+ rb_define_singleton_method(rb_mQUIC, "library_versions",
99
+ quic_library_versions, 0);
89
100
 
90
101
  /* QUIC::Error is defined in Ruby (lib/quic.rb) before this Init_quic runs,
91
102
  so rb_const_get retrieves the already-defined base class. Subclasses live
92
103
  under QUIC::Error::<Name>. */
93
104
  rb_eQUICError = rb_const_get(rb_mQUIC, rb_intern("Error"));
94
- rb_eQUICErrorProto = rb_define_class_under(rb_eQUICError, "Proto", rb_eQUICError);
95
- rb_eQUICErrorDropConn = rb_define_class_under(rb_eQUICError, "DropConn", rb_eQUICError);
96
- rb_eQUICErrorRetry = rb_define_class_under(rb_eQUICError, "Retry", rb_eQUICError);
97
- rb_eQUICErrorClosed = rb_define_class_under(rb_eQUICError, "Closed", rb_eQUICError);
98
- rb_eQUICErrorCryptoError = rb_define_class_under(rb_eQUICError, "CryptoError", rb_eQUICError);
99
- /* The TLS alert this client sent, when read_pkt fails in the handshake.
105
+ rb_eQUICErrorProto =
106
+ rb_define_class_under(rb_eQUICError, "Proto", rb_eQUICError);
107
+ rb_eQUICErrorDropConn =
108
+ rb_define_class_under(rb_eQUICError, "DropConn", rb_eQUICError);
109
+ rb_eQUICErrorRetry =
110
+ rb_define_class_under(rb_eQUICError, "Retry", rb_eQUICError);
111
+ rb_eQUICErrorClosed =
112
+ rb_define_class_under(rb_eQUICError, "Closed", rb_eQUICError);
113
+ rb_eQUICErrorCryptoError =
114
+ rb_define_class_under(rb_eQUICError, "CryptoError", rb_eQUICError);
115
+ /* The TLS alert this endpoint sent, when read_pkt fails in the handshake.
100
116
  Alerts received from the peer are not recorded by ngtcp2. */
101
117
  rb_define_attr(rb_eQUICErrorCryptoError, "tls_alert", 1, 0);
102
- rb_eQUICErrorCertificateVerifyFailed =
103
- rb_define_class_under(rb_eQUICError, "CertificateVerifyFailed", rb_eQUICErrorCryptoError);
104
- /* X509_V_ERR_* from the chain / name check, or nil when no certificate came. */
118
+ rb_eQUICErrorCertificateVerifyFailed = rb_define_class_under(
119
+ rb_eQUICError, "CertificateVerifyFailed", rb_eQUICErrorCryptoError);
120
+ /* X509_V_ERR_* from the chain / name check, or nil when no certificate came.
121
+ */
105
122
  rb_define_attr(rb_eQUICErrorCertificateVerifyFailed, "verify_result", 1, 0);
106
- rb_eQUICErrorHandshakeTimeout = rb_define_class_under(rb_eQUICError, "HandshakeTimeout", rb_eQUICError);
107
- rb_eQUICErrorFlowControl = rb_define_class_under(rb_eQUICError, "FlowControl", rb_eQUICError);
108
- rb_eQUICErrorUnknown = rb_define_class_under(rb_eQUICError, "Unknown", rb_eQUICError);
123
+ rb_eQUICErrorHandshakeTimeout =
124
+ rb_define_class_under(rb_eQUICError, "HandshakeTimeout", rb_eQUICError);
125
+ rb_eQUICErrorFlowControl =
126
+ rb_define_class_under(rb_eQUICError, "FlowControl", rb_eQUICError);
127
+ rb_eQUICErrorUnknown =
128
+ rb_define_class_under(rb_eQUICError, "Unknown", rb_eQUICError);
109
129
 
110
- /* IO-style non-blocking errors. Mix in the standard IO::Wait{Readable,Writable}
111
- modules so callers can `rescue IO::WaitReadable` (or the QUIC subclass)
112
- interchangeably with stdlib IO objects. */
130
+ /* IO-style non-blocking errors. Mix in the standard
131
+ IO::Wait{Readable,Writable} modules so callers can `rescue
132
+ IO::WaitReadable` (or the QUIC subclass) interchangeably with stdlib IO
133
+ objects. */
113
134
  VALUE io_wait_readable = rb_const_get(rb_cIO, rb_intern("WaitReadable"));
114
135
  VALUE io_wait_writable = rb_const_get(rb_cIO, rb_intern("WaitWritable"));
115
- rb_eQUICErrorWaitReadable = rb_define_class_under(rb_eQUICError, "WaitReadable", rb_eQUICError);
136
+ rb_eQUICErrorWaitReadable =
137
+ rb_define_class_under(rb_eQUICError, "WaitReadable", rb_eQUICError);
116
138
  rb_include_module(rb_eQUICErrorWaitReadable, io_wait_readable);
117
- rb_eQUICErrorWaitWritable = rb_define_class_under(rb_eQUICError, "WaitWritable", rb_eQUICError);
139
+ rb_eQUICErrorWaitWritable =
140
+ rb_define_class_under(rb_eQUICError, "WaitWritable", rb_eQUICError);
118
141
  rb_include_module(rb_eQUICErrorWaitWritable, io_wait_writable);
119
142
 
120
- rb_eQUICErrorStreamClosed = rb_define_class_under(rb_eQUICError, "StreamClosed", rb_eQUICError);
121
- rb_eQUICErrorStreamReset = rb_define_class_under(rb_eQUICError, "StreamReset", rb_eQUICError);
122
- rb_eQUICErrorNotBound = rb_define_class_under(rb_eQUICError, "NotBound", rb_eQUICError);
143
+ rb_eQUICErrorStreamClosed =
144
+ rb_define_class_under(rb_eQUICError, "StreamClosed", rb_eQUICError);
145
+ rb_eQUICErrorStreamReset =
146
+ rb_define_class_under(rb_eQUICError, "StreamReset", rb_eQUICError);
147
+ rb_eQUICErrorNotBound =
148
+ rb_define_class_under(rb_eQUICError, "NotBound", rb_eQUICError);
149
+ /* Raised by the QUIC::Stream methods of a connection whose streams a C
150
+ stream handler (quic/ext.h) owns. */
151
+ rb_eQUICErrorInvalidState =
152
+ rb_define_class_under(rb_eQUICError, "InvalidState", rb_eQUICError);
123
153
 
154
+ Init_quic_tls_context(rb_mQUIC);
124
155
  Init_quic_connection_client(rb_mQUICConnection);
156
+ Init_quic_connection_server(rb_mQUICConnection);
157
+ Init_quic_endpoint(rb_mQUIC);
125
158
  Init_quic_stream(rb_mQUIC);
126
159
  }
data/ext/quic/quic.h CHANGED
@@ -6,21 +6,24 @@
6
6
 
7
7
  #include <ngtcp2/ngtcp2.h>
8
8
  #include <ngtcp2/ngtcp2_crypto.h>
9
- #include <picotls.h>
10
- #include <picotls/openssl.h>
11
9
  #include <ngtcp2/ngtcp2_crypto_picotls.h>
12
10
  #include <openssl/crypto.h>
11
+ #include <picotls.h>
12
+ #include <picotls/openssl.h>
13
13
 
14
14
  /* picotls disables ptls_openssl_x25519 unless it is built with the patch in
15
15
  ext/quic/patches/picotls/. extconf.rb checks the same condition at configure
16
16
  time; this catches a prebuilt ports/ tree whose patch was swapped out. */
17
17
  #if !PTLS_OPENSSL_HAVE_X25519
18
+ /* clang-format off */
18
19
  #error "picotls was built without X25519; is ext/quic/patches/picotls/*.patch applied?"
20
+ /* clang-format on */
19
21
  #endif
20
22
 
21
23
  extern VALUE rb_mQUIC;
22
24
  extern VALUE rb_mQUICConnection;
23
25
  extern VALUE rb_cQUICConnectionClient;
26
+ extern VALUE rb_cQUICConnectionServer;
24
27
 
25
28
  extern VALUE rb_eQUICError;
26
29
  extern VALUE rb_eQUICErrorProto;
@@ -37,18 +40,17 @@ extern VALUE rb_eQUICErrorWaitWritable;
37
40
  extern VALUE rb_eQUICErrorStreamClosed;
38
41
  extern VALUE rb_eQUICErrorStreamReset;
39
42
  extern VALUE rb_eQUICErrorNotBound;
43
+ extern VALUE rb_eQUICErrorInvalidState;
40
44
 
41
45
  void Init_quic_connection_client(VALUE rb_mQUICConnection);
46
+ void Init_quic_connection_server(VALUE rb_mQUICConnection);
47
+ void Init_quic_endpoint(VALUE rb_mQUIC);
42
48
 
43
- /* Accessor used by stream.c to issue ngtcp2 calls (e.g.
44
- ngtcp2_conn_shutdown_stream_read) for streams that hold a back-reference
45
- to their parent QUIC::Connection::Client via @client. Returns the raw
46
- ngtcp2_conn pointer; the caller is responsible for ensuring the Ruby
47
- Client object is alive for the duration of the call. */
48
- ngtcp2_conn *quic_client_conn(VALUE client);
49
+ /* A QUIC::Error subclass instance mapped from an ngtcp2 negative error code,
50
+ with the code in #code. Made, not raised. */
51
+ VALUE quic_ngtcp2_error_new(int rv);
49
52
 
50
- /* Raise a QUIC::Error subclass mapped from an ngtcp2 negative error code.
51
- Never returns. */
53
+ /* Raise quic_ngtcp2_error_new(rv). Never returns. */
52
54
  NORETURN(void quic_raise_ngtcp2_error(int rv));
53
55
 
54
56
  #endif /* QUIC_H */