quic 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -1
- data/LICENSE-DEPENDENCIES.txt +101 -0
- data/README.md +69 -6
- data/examples/doq_demo.rb +122 -0
- data/examples/echo_demo.rb +23 -12
- data/examples/handshake_demo.rb +18 -20
- data/examples/io_loop_demo.rb +144 -0
- data/examples/verify_demo.rb +105 -0
- data/ext/quic/connection_client.c +403 -68
- data/ext/quic/extconf.rb +138 -28
- data/ext/quic/patches/picotls/0001-openssl-use-raw-public-key-api-for-X25519.patch +74 -0
- data/ext/quic/quic.c +63 -51
- data/ext/quic/quic.h +35 -25
- data/ext/quic/stream.c +59 -23
- data/ext/quic/stream.h +7 -3
- data/lib/quic/connection.rb +69 -9
- data/lib/quic/settings.rb +23 -3
- data/lib/quic/stream.rb +17 -14
- data/lib/quic/transport_params.rb +1 -1
- data/lib/quic/version.rb +2 -2
- data/lib/quic.rb +1 -1
- data/sig/quic.rbs +42 -5
- metadata +31 -9
data/ext/quic/extconf.rb
CHANGED
|
@@ -2,53 +2,163 @@
|
|
|
2
2
|
|
|
3
3
|
require "mkmf"
|
|
4
4
|
require "mini_portile2"
|
|
5
|
+
require "shellwords"
|
|
6
|
+
require "fileutils"
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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"
|
|
13
|
+
# Bump when ext/quic/patches/picotls/ changes; installed? only checks for the archive.
|
|
14
|
+
PICOTLS_PATCH_LEVEL = "p1"
|
|
10
15
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
# Locate the host's libcrypto. ngtcp2 and picotls are vendored and statically
|
|
17
|
+
# linked, but the crypto primitives and X.509 come from whatever OpenSSL (or
|
|
18
|
+
# LibreSSL) the system provides, linked dynamically. Sharing one libcrypto with
|
|
19
|
+
# Ruby's own openssl extension is the point: two copies in one process
|
|
20
|
+
# interpose on each other's global symbols.
|
|
21
|
+
#
|
|
22
|
+
# Everything downstream resolves OpenSSL through pkg-config -- this file,
|
|
23
|
+
# ngtcp2's configure, and the `openssl` entry in libngtcp2_crypto_picotls.pc's
|
|
24
|
+
# Requires.private -- so --with-openssl-dir is honoured by putting its prefix
|
|
25
|
+
# on PKG_CONFIG_PATH once, here. That keeps all three agreeing on one install
|
|
26
|
+
# instead of each making its own choice.
|
|
27
|
+
_openssl_incdir, openssl_libdir = dir_config("openssl")
|
|
28
|
+
if openssl_libdir
|
|
29
|
+
ENV["PKG_CONFIG_PATH"] =
|
|
30
|
+
[File.join(openssl_libdir, "pkgconfig"), ENV["PKG_CONFIG_PATH"]].compact.join(File::PATH_SEPARATOR)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
unless pkg_config("openssl")
|
|
34
|
+
abort "OpenSSL not found. Install its development package (libssl-dev, " \
|
|
35
|
+
"openssl-devel, ...), or point at a prefix whose lib/pkgconfig holds " \
|
|
36
|
+
"openssl.pc with --with-openssl-dir=/path."
|
|
37
|
+
end
|
|
38
|
+
# picotls is compiled by hand below and needs the include path on its own.
|
|
39
|
+
openssl_cflags = pkg_config("openssl", "cflags-only-I").to_s.strip
|
|
40
|
+
|
|
41
|
+
# 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.
|
|
44
|
+
class PicotlsRecipe < MiniPortile
|
|
45
|
+
SOURCES = %w[lib/picotls.c lib/hpke.c lib/pembase64.c lib/openssl.c].freeze
|
|
46
|
+
|
|
47
|
+
attr_accessor :openssl_cflags
|
|
48
|
+
|
|
49
|
+
def configure
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def configured?
|
|
53
|
+
true
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def compile
|
|
57
|
+
cflags = %w[-std=gnu99 -O2 -fPIC -fvisibility=hidden -Iinclude] + openssl_cflags.to_s.shellsplit
|
|
58
|
+
objects = SOURCES.map do |src|
|
|
59
|
+
obj = File.basename(src, ".c") + ".o"
|
|
60
|
+
execute("compile", [*cc_cmd.shellsplit, *cflags, "-c", src, "-o", obj])
|
|
61
|
+
obj
|
|
62
|
+
end
|
|
63
|
+
ar = (ENV["AR"] || RbConfig::CONFIG["AR"] || "ar").shellsplit
|
|
64
|
+
execute("compile", [*ar, "rcs", "libpicotls.a", *objects])
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def install
|
|
68
|
+
FileUtils.mkdir_p([lib_path, include_path])
|
|
69
|
+
FileUtils.cp(File.join(work_path, "libpicotls.a"), lib_path)
|
|
70
|
+
FileUtils.cp_r(Dir.glob(File.join(work_path, "include", "*")), include_path)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def installed?
|
|
74
|
+
File.exist?(File.join(lib_path, "libpicotls.a"))
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
picotls = PicotlsRecipe.new("picotls", "#{PICOTLS_COMMIT[0, 7]}-#{PICOTLS_PATCH_LEVEL}")
|
|
79
|
+
picotls.files = [{
|
|
80
|
+
url: "https://github.com/h2o/picotls/archive/#{PICOTLS_COMMIT}.tar.gz",
|
|
81
|
+
sha256: PICOTLS_SHA256
|
|
15
82
|
}]
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
83
|
+
picotls.patch_files = Dir.glob(File.join(__dir__, "patches", "picotls", "*.patch")).sort
|
|
84
|
+
picotls.openssl_cflags = openssl_cflags
|
|
85
|
+
picotls.cook
|
|
86
|
+
# Deliberately no picotls.activate: mkmf_config passes -I/-L below, and not
|
|
87
|
+
# activating keeps the extra directory out of CPATH.
|
|
19
88
|
|
|
20
89
|
ngtcp2 = MiniPortile.new("ngtcp2", NGTCP2_VERSION)
|
|
21
90
|
ngtcp2.files = [{
|
|
22
91
|
url: "https://github.com/ngtcp2/ngtcp2/releases/download/v#{NGTCP2_VERSION}/ngtcp2-#{NGTCP2_VERSION}.tar.gz",
|
|
23
92
|
sha256: NGTCP2_SHA256
|
|
24
93
|
}]
|
|
25
|
-
ngtcp2.configure_options =
|
|
26
|
-
--enable-lib-only
|
|
27
|
-
--disable-shared
|
|
28
|
-
--with-pic
|
|
29
|
-
|
|
94
|
+
ngtcp2.configure_options = [
|
|
95
|
+
"--enable-lib-only",
|
|
96
|
+
"--disable-shared",
|
|
97
|
+
"--with-pic",
|
|
98
|
+
# Skip the quictls/libressl/ossl helpers; only libngtcp2_crypto_picotls.
|
|
99
|
+
"--without-openssl",
|
|
100
|
+
"--with-picotls",
|
|
101
|
+
# crypto/picotls declares lib_LIBRARIES, not lib_LTLIBRARIES, so it is built
|
|
102
|
+
# by plain ar rather than libtool and --with-pic does not reach it. Without
|
|
103
|
+
# -fPIC the archive cannot be linked into quic.so.
|
|
104
|
+
"CFLAGS=-g -O2 -fPIC",
|
|
105
|
+
"PICOTLS_CFLAGS=-I#{picotls.include_path}",
|
|
106
|
+
"PICOTLS_LIBS=-L#{picotls.lib_path} -lpicotls"
|
|
30
107
|
]
|
|
108
|
+
# ngtcp2 still probes for OpenSSL under --without-openssl: its picotls check
|
|
109
|
+
# links the conftest against libcrypto. It finds it through the same
|
|
110
|
+
# PKG_CONFIG_PATH set above, which the configure subprocess inherits.
|
|
31
111
|
ngtcp2.cook
|
|
32
112
|
ngtcp2.activate
|
|
33
113
|
|
|
34
|
-
# Wire static archives into mkmf in reverse dependency order.
|
|
35
|
-
# prepends to $libs, so the leftmost entry on the final link line
|
|
36
|
-
# the last one
|
|
37
|
-
#
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
114
|
+
# Wire the vendored static archives into mkmf in reverse dependency order.
|
|
115
|
+
# mkmf_config prepends to $libs, so the leftmost entry on the final link line
|
|
116
|
+
# ends up being the last one added here, satisfying static-link ordering:
|
|
117
|
+
# ngtcp2_crypto_picotls -> ngtcp2 -> picotls -> the -lssl -lcrypto that
|
|
118
|
+
# pkg_config("openssl") already put there.
|
|
119
|
+
#
|
|
120
|
+
# Deliberately not the `pkg:` form. Resolving libngtcp2_crypto_picotls.pc
|
|
121
|
+
# would follow its `Requires.private: libngtcp2, openssl` with
|
|
122
|
+
# `pkg-config --static`, which drags in the host libcrypto's own static
|
|
123
|
+
# dependency list (on Ubuntu: -l:libjitterentropy.a -lz -lzstd). Those belong
|
|
124
|
+
# to a static libcrypto we are not linking, and the archives they name are
|
|
125
|
+
# often not even installed. The recipe's own include/lib paths are all we
|
|
126
|
+
# need.
|
|
127
|
+
picotls.mkmf_config(static: "picotls")
|
|
128
|
+
ngtcp2.mkmf_config(static: "ngtcp2")
|
|
129
|
+
ngtcp2.mkmf_config(static: "ngtcp2_crypto_picotls")
|
|
42
130
|
|
|
131
|
+
# picotls's OpenSSL backend, and the X25519 patch in ext/quic/patches/picotls/,
|
|
132
|
+
# both need the raw public key API introduced in OpenSSL 1.1.1. LibreSSL
|
|
133
|
+
# reports 0x20000000L here, so one check covers both.
|
|
134
|
+
abort "OpenSSL 1.1.1 or later is required" unless try_compile(<<~C)
|
|
135
|
+
#include <openssl/opensslv.h>
|
|
136
|
+
#if OPENSSL_VERSION_NUMBER < 0x10101000L
|
|
137
|
+
#error OpenSSL is too old
|
|
138
|
+
#endif
|
|
139
|
+
int main(void) { return 0; }
|
|
140
|
+
C
|
|
43
141
|
abort "ngtcp2 header missing" unless have_header("ngtcp2/ngtcp2.h")
|
|
44
|
-
abort "
|
|
45
|
-
abort "openssl
|
|
142
|
+
abort "picotls header missing" unless have_header("picotls.h")
|
|
143
|
+
abort "picotls/openssl.h missing" unless have_header("picotls/openssl.h")
|
|
144
|
+
abort "ngtcp2_crypto_picotls header missing" unless have_header("ngtcp2/ngtcp2_crypto_picotls.h")
|
|
145
|
+
abort "picotls was built without X25519 (patch not applied?)" unless try_compile(<<~C)
|
|
146
|
+
#include <picotls/openssl.h>
|
|
147
|
+
#if !PTLS_OPENSSL_HAVE_X25519
|
|
148
|
+
#error X25519 unavailable
|
|
149
|
+
#endif
|
|
150
|
+
C
|
|
46
151
|
# ngtcp2_conn_client_new and most other ngtcp2 entry points are exposed as
|
|
47
152
|
# ABI-versioned macros, so use non-macro symbols for link verification.
|
|
48
153
|
abort "libngtcp2 not linkable" unless have_func("ngtcp2_version", "ngtcp2/ngtcp2.h")
|
|
49
|
-
abort "
|
|
50
|
-
|
|
154
|
+
abort "libngtcp2_crypto_picotls not linkable" unless
|
|
155
|
+
have_func("ngtcp2_crypto_picotls_configure_client_context", %w[picotls.h ngtcp2/ngtcp2_crypto_picotls.h])
|
|
156
|
+
abort "libcrypto not linkable" unless have_func("OpenSSL_version", "openssl/crypto.h")
|
|
51
157
|
|
|
158
|
+
# picotls has neither a version macro nor releases, so QUIC.library_versions
|
|
159
|
+
# reports the commit the extension was built against.
|
|
160
|
+
append_cflags("-DQUIC_PICOTLS_COMMIT=\\\"#{PICOTLS_COMMIT}\\\"")
|
|
52
161
|
append_cflags("-fvisibility=hidden")
|
|
162
|
+
append_ldflags("-Wl,--exclude-libs,ALL") # Unexport symbols from statically linked libraries
|
|
53
163
|
|
|
54
164
|
create_makefile("quic/quic")
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
Subject: [PATCH] openssl: use the raw public key API for X25519
|
|
2
|
+
|
|
3
|
+
LibreSSL does not provide EVP_PKEY_get1_tls_encodedpoint() /
|
|
4
|
+
EVP_PKEY_set1_tls_encodedpoint(), so picotls disables ptls_openssl_x25519
|
|
5
|
+
when built against LibreSSL. Switch the EVP-based X25519 key exchange to
|
|
6
|
+
EVP_PKEY_get_raw_public_key() / EVP_PKEY_new_raw_public_key() and drop the
|
|
7
|
+
LibreSSL exclusion.
|
|
8
|
+
|
|
9
|
+
Verified with LibreSSL 4.3.1 and OpenSSL 3.5.7 (picotls test-openssl.t,
|
|
10
|
+
including x25519-to-minicrypto / x25519-from-minicrypto).
|
|
11
|
+
|
|
12
|
+
Not upstream. Requires OpenSSL >= 1.1.1 (1.1.0 lacks the raw key API).
|
|
13
|
+
Applies to h2o/picotls@b84869f41414b6d0148db7728f1cf12f5b544874.
|
|
14
|
+
|
|
15
|
+
diff --git a/include/picotls/openssl.h b/include/picotls/openssl.h
|
|
16
|
+
index 37a0740..04e4653 100644
|
|
17
|
+
--- a/include/picotls/openssl.h
|
|
18
|
+
+++ b/include/picotls/openssl.h
|
|
19
|
+
@@ -60,7 +60,7 @@ extern ptls_key_exchange_algorithm_t ptls_openssl_secp521r1;
|
|
20
|
+
#ifdef EVP_PKEY_ED25519
|
|
21
|
+
#define PTLS_OPENSSL_HAVE_ED25519 1
|
|
22
|
+
#endif
|
|
23
|
+
-#if defined(NID_X25519) && !defined(LIBRESSL_VERSION_NUMBER)
|
|
24
|
+
+#if defined(NID_X25519)
|
|
25
|
+
#define PTLS_OPENSSL_HAVE_X25519 1
|
|
26
|
+
#define PTLS_OPENSSL_HAS_X25519 1 /* deprecated; use HAVE_ */
|
|
27
|
+
extern ptls_key_exchange_algorithm_t ptls_openssl_x25519;
|
|
28
|
+
diff --git a/lib/openssl.c b/lib/openssl.c
|
|
29
|
+
index d6d073b..1c7e492 100644
|
|
30
|
+
--- a/lib/openssl.c
|
|
31
|
+
+++ b/lib/openssl.c
|
|
32
|
+
@@ -559,15 +559,7 @@ static int evp_keyex_on_exchange(ptls_key_exchange_context_t **_ctx, int release
|
|
33
|
+
#undef X25519_KEY_SIZE
|
|
34
|
+
#endif
|
|
35
|
+
|
|
36
|
+
- if ((evppeer = EVP_PKEY_new()) == NULL) {
|
|
37
|
+
- ret = PTLS_ERROR_NO_MEMORY;
|
|
38
|
+
- goto Exit;
|
|
39
|
+
- }
|
|
40
|
+
- if (EVP_PKEY_copy_parameters(evppeer, ctx->privkey) <= 0) {
|
|
41
|
+
- ret = PTLS_ERROR_LIBRARY;
|
|
42
|
+
- goto Exit;
|
|
43
|
+
- }
|
|
44
|
+
- if (EVP_PKEY_set1_tls_encodedpoint(evppeer, peerkey.base, peerkey.len) <= 0) {
|
|
45
|
+
+ if ((evppeer = EVP_PKEY_new_raw_public_key(EVP_PKEY_id(ctx->privkey), NULL, peerkey.base, peerkey.len)) == NULL) {
|
|
46
|
+
ret = PTLS_ERROR_LIBRARY;
|
|
47
|
+
goto Exit;
|
|
48
|
+
}
|
|
49
|
+
@@ -629,10 +621,21 @@ static int evp_keyex_init(ptls_key_exchange_algorithm_t *algo, ptls_key_exchange
|
|
50
|
+
*ctx = (struct st_evp_keyex_context_t){{algo, {NULL}, evp_keyex_on_exchange}, pkey};
|
|
51
|
+
|
|
52
|
+
/* set public key */
|
|
53
|
+
- if ((ctx->super.pubkey.len = EVP_PKEY_get1_tls_encodedpoint(ctx->privkey, &ctx->super.pubkey.base)) == 0) {
|
|
54
|
+
- ctx->super.pubkey.base = NULL;
|
|
55
|
+
- ret = PTLS_ERROR_NO_MEMORY;
|
|
56
|
+
- goto Exit;
|
|
57
|
+
+ {
|
|
58
|
+
+ size_t publen = 0;
|
|
59
|
+
+ if (EVP_PKEY_get_raw_public_key(ctx->privkey, NULL, &publen) != 1 || publen == 0) {
|
|
60
|
+
+ ret = PTLS_ERROR_LIBRARY;
|
|
61
|
+
+ goto Exit;
|
|
62
|
+
+ }
|
|
63
|
+
+ if ((ctx->super.pubkey.base = OPENSSL_malloc(publen)) == NULL) {
|
|
64
|
+
+ ret = PTLS_ERROR_NO_MEMORY;
|
|
65
|
+
+ goto Exit;
|
|
66
|
+
+ }
|
|
67
|
+
+ if (EVP_PKEY_get_raw_public_key(ctx->privkey, ctx->super.pubkey.base, &publen) != 1) {
|
|
68
|
+
+ ret = PTLS_ERROR_LIBRARY;
|
|
69
|
+
+ goto Exit;
|
|
70
|
+
+ }
|
|
71
|
+
+ ctx->super.pubkey.len = publen;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
*_ctx = &ctx->super;
|
data/ext/quic/quic.c
CHANGED
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
#include "quic.h"
|
|
2
2
|
#include "stream.h"
|
|
3
3
|
|
|
4
|
-
VALUE
|
|
5
|
-
VALUE
|
|
6
|
-
VALUE
|
|
4
|
+
VALUE rb_mQUIC;
|
|
5
|
+
VALUE rb_mQUICConnection;
|
|
6
|
+
VALUE rb_cQUICConnectionClient;
|
|
7
7
|
|
|
8
|
-
VALUE
|
|
9
|
-
VALUE
|
|
10
|
-
VALUE
|
|
11
|
-
VALUE
|
|
12
|
-
VALUE
|
|
13
|
-
VALUE
|
|
14
|
-
VALUE
|
|
15
|
-
VALUE
|
|
16
|
-
VALUE
|
|
17
|
-
VALUE
|
|
18
|
-
VALUE
|
|
19
|
-
VALUE
|
|
20
|
-
VALUE
|
|
21
|
-
VALUE
|
|
8
|
+
VALUE rb_eQUICError;
|
|
9
|
+
VALUE rb_eQUICErrorProto;
|
|
10
|
+
VALUE rb_eQUICErrorDropConn;
|
|
11
|
+
VALUE rb_eQUICErrorRetry;
|
|
12
|
+
VALUE rb_eQUICErrorClosed;
|
|
13
|
+
VALUE rb_eQUICErrorCryptoError;
|
|
14
|
+
VALUE rb_eQUICErrorCertificateVerifyFailed;
|
|
15
|
+
VALUE rb_eQUICErrorHandshakeTimeout;
|
|
16
|
+
VALUE rb_eQUICErrorFlowControl;
|
|
17
|
+
VALUE rb_eQUICErrorUnknown;
|
|
18
|
+
VALUE rb_eQUICErrorWaitReadable;
|
|
19
|
+
VALUE rb_eQUICErrorWaitWritable;
|
|
20
|
+
VALUE rb_eQUICErrorStreamClosed;
|
|
21
|
+
VALUE rb_eQUICErrorStreamReset;
|
|
22
|
+
VALUE rb_eQUICErrorNotBound;
|
|
22
23
|
|
|
23
24
|
static VALUE
|
|
24
25
|
quic_library_versions(VALUE self)
|
|
@@ -29,6 +30,10 @@ quic_library_versions(VALUE self)
|
|
|
29
30
|
rb_str_new_cstr(ngtcp2_version(0)->version_str));
|
|
30
31
|
rb_hash_aset(h, ID2SYM(rb_intern("openssl")),
|
|
31
32
|
rb_str_new_cstr(OpenSSL_version(OPENSSL_VERSION)));
|
|
33
|
+
/* picotls has neither a version macro nor releases, so report the commit
|
|
34
|
+
extconf.rb built against (passed in as -DQUIC_PICOTLS_COMMIT). */
|
|
35
|
+
rb_hash_aset(h, ID2SYM(rb_intern("picotls")),
|
|
36
|
+
rb_str_new_cstr(QUIC_PICOTLS_COMMIT));
|
|
32
37
|
return h;
|
|
33
38
|
}
|
|
34
39
|
|
|
@@ -38,35 +43,35 @@ quic_raise_ngtcp2_error(int rv)
|
|
|
38
43
|
VALUE cls;
|
|
39
44
|
switch (rv) {
|
|
40
45
|
case NGTCP2_ERR_PROTO:
|
|
41
|
-
cls =
|
|
46
|
+
cls = rb_eQUICErrorProto;
|
|
42
47
|
break;
|
|
43
48
|
case NGTCP2_ERR_DROP_CONN:
|
|
44
|
-
cls =
|
|
49
|
+
cls = rb_eQUICErrorDropConn;
|
|
45
50
|
break;
|
|
46
51
|
case NGTCP2_ERR_RETRY:
|
|
47
|
-
cls =
|
|
52
|
+
cls = rb_eQUICErrorRetry;
|
|
48
53
|
break;
|
|
49
54
|
case NGTCP2_ERR_CLOSING:
|
|
50
55
|
case NGTCP2_ERR_DRAINING:
|
|
51
|
-
cls =
|
|
56
|
+
cls = rb_eQUICErrorClosed;
|
|
52
57
|
break;
|
|
53
58
|
case NGTCP2_ERR_IDLE_CLOSE:
|
|
54
|
-
cls =
|
|
59
|
+
cls = rb_eQUICErrorClosed;
|
|
55
60
|
break;
|
|
56
61
|
case NGTCP2_ERR_CRYPTO:
|
|
57
|
-
cls =
|
|
62
|
+
cls = rb_eQUICErrorCryptoError;
|
|
58
63
|
break;
|
|
59
64
|
case NGTCP2_ERR_HANDSHAKE_TIMEOUT:
|
|
60
|
-
cls =
|
|
65
|
+
cls = rb_eQUICErrorHandshakeTimeout;
|
|
61
66
|
break;
|
|
62
67
|
case NGTCP2_ERR_STREAM_DATA_BLOCKED:
|
|
63
|
-
cls =
|
|
68
|
+
cls = rb_eQUICErrorFlowControl;
|
|
64
69
|
break;
|
|
65
70
|
case NGTCP2_ERR_STREAM_SHUT_WR:
|
|
66
|
-
cls =
|
|
71
|
+
cls = rb_eQUICErrorStreamClosed;
|
|
67
72
|
break;
|
|
68
73
|
default:
|
|
69
|
-
cls =
|
|
74
|
+
cls = rb_eQUICErrorUnknown;
|
|
70
75
|
break;
|
|
71
76
|
}
|
|
72
77
|
|
|
@@ -78,37 +83,44 @@ quic_raise_ngtcp2_error(int rv)
|
|
|
78
83
|
RUBY_FUNC_EXPORTED void
|
|
79
84
|
Init_quic(void)
|
|
80
85
|
{
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
rb_define_singleton_method(
|
|
86
|
+
rb_mQUIC = rb_define_module("QUIC");
|
|
87
|
+
rb_mQUICConnection = rb_define_module_under(rb_mQUIC, "Connection");
|
|
88
|
+
rb_define_singleton_method(rb_mQUIC, "library_versions", quic_library_versions, 0);
|
|
84
89
|
|
|
85
|
-
/*
|
|
90
|
+
/* QUIC::Error is defined in Ruby (lib/quic.rb) before this Init_quic runs,
|
|
86
91
|
so rb_const_get retrieves the already-defined base class. Subclasses live
|
|
87
|
-
under
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
92
|
+
under QUIC::Error::<Name>. */
|
|
93
|
+
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.
|
|
100
|
+
Alerts received from the peer are not recorded by ngtcp2. */
|
|
101
|
+
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. */
|
|
105
|
+
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);
|
|
97
109
|
|
|
98
110
|
/* IO-style non-blocking errors. Mix in the standard IO::Wait{Readable,Writable}
|
|
99
|
-
modules so callers can `rescue IO::WaitReadable` (or the
|
|
111
|
+
modules so callers can `rescue IO::WaitReadable` (or the QUIC subclass)
|
|
100
112
|
interchangeably with stdlib IO objects. */
|
|
101
113
|
VALUE io_wait_readable = rb_const_get(rb_cIO, rb_intern("WaitReadable"));
|
|
102
114
|
VALUE io_wait_writable = rb_const_get(rb_cIO, rb_intern("WaitWritable"));
|
|
103
|
-
|
|
104
|
-
rb_include_module(
|
|
105
|
-
|
|
106
|
-
rb_include_module(
|
|
115
|
+
rb_eQUICErrorWaitReadable = rb_define_class_under(rb_eQUICError, "WaitReadable", rb_eQUICError);
|
|
116
|
+
rb_include_module(rb_eQUICErrorWaitReadable, io_wait_readable);
|
|
117
|
+
rb_eQUICErrorWaitWritable = rb_define_class_under(rb_eQUICError, "WaitWritable", rb_eQUICError);
|
|
118
|
+
rb_include_module(rb_eQUICErrorWaitWritable, io_wait_writable);
|
|
107
119
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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);
|
|
111
123
|
|
|
112
|
-
Init_quic_connection_client(
|
|
113
|
-
Init_quic_stream(
|
|
124
|
+
Init_quic_connection_client(rb_mQUICConnection);
|
|
125
|
+
Init_quic_stream(rb_mQUIC);
|
|
114
126
|
}
|
data/ext/quic/quic.h
CHANGED
|
@@ -6,38 +6,48 @@
|
|
|
6
6
|
|
|
7
7
|
#include <ngtcp2/ngtcp2.h>
|
|
8
8
|
#include <ngtcp2/ngtcp2_crypto.h>
|
|
9
|
-
#include <
|
|
10
|
-
#include <openssl
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
extern VALUE
|
|
22
|
-
extern VALUE
|
|
23
|
-
extern VALUE
|
|
24
|
-
|
|
25
|
-
extern VALUE
|
|
26
|
-
extern VALUE
|
|
27
|
-
extern VALUE
|
|
28
|
-
extern VALUE
|
|
29
|
-
extern VALUE
|
|
30
|
-
|
|
31
|
-
|
|
9
|
+
#include <picotls.h>
|
|
10
|
+
#include <picotls/openssl.h>
|
|
11
|
+
#include <ngtcp2/ngtcp2_crypto_picotls.h>
|
|
12
|
+
#include <openssl/crypto.h>
|
|
13
|
+
|
|
14
|
+
/* picotls disables ptls_openssl_x25519 unless it is built with the patch in
|
|
15
|
+
ext/quic/patches/picotls/. extconf.rb checks the same condition at configure
|
|
16
|
+
time; this catches a prebuilt ports/ tree whose patch was swapped out. */
|
|
17
|
+
#if !PTLS_OPENSSL_HAVE_X25519
|
|
18
|
+
#error "picotls was built without X25519; is ext/quic/patches/picotls/*.patch applied?"
|
|
19
|
+
#endif
|
|
20
|
+
|
|
21
|
+
extern VALUE rb_mQUIC;
|
|
22
|
+
extern VALUE rb_mQUICConnection;
|
|
23
|
+
extern VALUE rb_cQUICConnectionClient;
|
|
24
|
+
|
|
25
|
+
extern VALUE rb_eQUICError;
|
|
26
|
+
extern VALUE rb_eQUICErrorProto;
|
|
27
|
+
extern VALUE rb_eQUICErrorDropConn;
|
|
28
|
+
extern VALUE rb_eQUICErrorRetry;
|
|
29
|
+
extern VALUE rb_eQUICErrorClosed;
|
|
30
|
+
extern VALUE rb_eQUICErrorCryptoError;
|
|
31
|
+
extern VALUE rb_eQUICErrorCertificateVerifyFailed;
|
|
32
|
+
extern VALUE rb_eQUICErrorHandshakeTimeout;
|
|
33
|
+
extern VALUE rb_eQUICErrorFlowControl;
|
|
34
|
+
extern VALUE rb_eQUICErrorUnknown;
|
|
35
|
+
extern VALUE rb_eQUICErrorWaitReadable;
|
|
36
|
+
extern VALUE rb_eQUICErrorWaitWritable;
|
|
37
|
+
extern VALUE rb_eQUICErrorStreamClosed;
|
|
38
|
+
extern VALUE rb_eQUICErrorStreamReset;
|
|
39
|
+
extern VALUE rb_eQUICErrorNotBound;
|
|
40
|
+
|
|
41
|
+
void Init_quic_connection_client(VALUE rb_mQUICConnection);
|
|
32
42
|
|
|
33
43
|
/* Accessor used by stream.c to issue ngtcp2 calls (e.g.
|
|
34
44
|
ngtcp2_conn_shutdown_stream_read) for streams that hold a back-reference
|
|
35
|
-
to their parent
|
|
45
|
+
to their parent QUIC::Connection::Client via @client. Returns the raw
|
|
36
46
|
ngtcp2_conn pointer; the caller is responsible for ensuring the Ruby
|
|
37
47
|
Client object is alive for the duration of the call. */
|
|
38
48
|
ngtcp2_conn *quic_client_conn(VALUE client);
|
|
39
49
|
|
|
40
|
-
/* Raise a
|
|
50
|
+
/* Raise a QUIC::Error subclass mapped from an ngtcp2 negative error code.
|
|
41
51
|
Never returns. */
|
|
42
52
|
NORETURN(void quic_raise_ngtcp2_error(int rv));
|
|
43
53
|
|