quicsilver 0.5.0-x86_64-linux

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.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ci.yml +49 -0
  3. data/.github/workflows/cibuildgem.yaml +117 -0
  4. data/.gitignore +21 -0
  5. data/.gitmodules +3 -0
  6. data/.ruby-version +1 -0
  7. data/CHANGELOG.md +175 -0
  8. data/Gemfile +6 -0
  9. data/Gemfile.lock +67 -0
  10. data/LICENSE +21 -0
  11. data/README.md +261 -0
  12. data/Rakefile +130 -0
  13. data/benchmarks/baseline.rb +175 -0
  14. data/benchmarks/compare.rb +398 -0
  15. data/benchmarks/components.rb +191 -0
  16. data/benchmarks/helpers.rb +162 -0
  17. data/benchmarks/latency.rb +128 -0
  18. data/benchmarks/loss.rb +193 -0
  19. data/benchmarks/mobile.rb +125 -0
  20. data/bin/console +14 -0
  21. data/bin/setup +8 -0
  22. data/docs/connection_identity.md +141 -0
  23. data/examples/README.md +58 -0
  24. data/examples/benchmark.rb +191 -0
  25. data/examples/connection_pool_demo.rb +47 -0
  26. data/examples/example_helper.rb +69 -0
  27. data/examples/falcon_middleware.rb +44 -0
  28. data/examples/feature_demo.rb +125 -0
  29. data/examples/grpc_style.rb +97 -0
  30. data/examples/latency_aware_routing.rb +382 -0
  31. data/examples/lifecycle_drain.rb +264 -0
  32. data/examples/minimal_http3_server.rb +14 -0
  33. data/examples/priorities.rb +60 -0
  34. data/examples/protocol_http_server.rb +31 -0
  35. data/examples/rack_http3_server.rb +42 -0
  36. data/examples/rails_feature_test.rb +280 -0
  37. data/examples/server_stats.rb +117 -0
  38. data/examples/simple_client_test.rb +26 -0
  39. data/examples/streaming_sse.rb +33 -0
  40. data/examples/trailers.rb +69 -0
  41. data/examples/webtransport_smoke.rb +546 -0
  42. data/examples/worker_load_balancing.rb +425 -0
  43. data/ext/quicsilver/extconf.rb +124 -0
  44. data/ext/quicsilver/include/msquic.h +2226 -0
  45. data/ext/quicsilver/include/msquic_posix.h +696 -0
  46. data/ext/quicsilver/include/quic_sal_stub.h +314 -0
  47. data/ext/quicsilver/msquic_patch.rb +68 -0
  48. data/ext/quicsilver/patches/reliable-reset.patch +723 -0
  49. data/ext/quicsilver/patches/stream-final-size.patch +47 -0
  50. data/ext/quicsilver/quicsilver.c +2741 -0
  51. data/lib/quicsilver/3.4/quicsilver.so +0 -0
  52. data/lib/quicsilver/4.0/quicsilver.so +0 -0
  53. data/lib/quicsilver/client/client.rb +708 -0
  54. data/lib/quicsilver/client/connection_pool.rb +202 -0
  55. data/lib/quicsilver/client/request.rb +190 -0
  56. data/lib/quicsilver/errors.rb +39 -0
  57. data/lib/quicsilver/libmsquic.so.2 +0 -0
  58. data/lib/quicsilver/protocol/adapter.rb +196 -0
  59. data/lib/quicsilver/protocol/capsule.rb +38 -0
  60. data/lib/quicsilver/protocol/connect_stream_decoder.rb +75 -0
  61. data/lib/quicsilver/protocol/control_stream_parser.rb +117 -0
  62. data/lib/quicsilver/protocol/datagram.rb +40 -0
  63. data/lib/quicsilver/protocol/frame_parser.rb +141 -0
  64. data/lib/quicsilver/protocol/frame_reader.rb +84 -0
  65. data/lib/quicsilver/protocol/frames.rb +454 -0
  66. data/lib/quicsilver/protocol/priority.rb +65 -0
  67. data/lib/quicsilver/protocol/qpack/decoder.rb +127 -0
  68. data/lib/quicsilver/protocol/qpack/encoder.rb +217 -0
  69. data/lib/quicsilver/protocol/qpack/header_block_decoder.rb +140 -0
  70. data/lib/quicsilver/protocol/qpack/huffman.rb +459 -0
  71. data/lib/quicsilver/protocol/request_encoder.rb +50 -0
  72. data/lib/quicsilver/protocol/request_parser.rb +289 -0
  73. data/lib/quicsilver/protocol/response_encoder.rb +107 -0
  74. data/lib/quicsilver/protocol/response_parser.rb +147 -0
  75. data/lib/quicsilver/protocol/stream_input.rb +98 -0
  76. data/lib/quicsilver/protocol/stream_output.rb +59 -0
  77. data/lib/quicsilver/protocol/unidirectional_stream.rb +12 -0
  78. data/lib/quicsilver/protocol/web_transport.rb +214 -0
  79. data/lib/quicsilver/rack/context.rb +33 -0
  80. data/lib/quicsilver/response.rb +40 -0
  81. data/lib/quicsilver/server/listener_data.rb +14 -0
  82. data/lib/quicsilver/server/rack_adapter.rb +77 -0
  83. data/lib/quicsilver/server/receive_queue.rb +106 -0
  84. data/lib/quicsilver/server/request_handler.rb +149 -0
  85. data/lib/quicsilver/server/request_registry.rb +63 -0
  86. data/lib/quicsilver/server/scheduler.rb +50 -0
  87. data/lib/quicsilver/server/schedulers/fiber_scheduler.rb +79 -0
  88. data/lib/quicsilver/server/schedulers/thread_scheduler.rb +76 -0
  89. data/lib/quicsilver/server/server.rb +1080 -0
  90. data/lib/quicsilver/server/web_transport_flow_control.rb +270 -0
  91. data/lib/quicsilver/server/web_transport_manager.rb +281 -0
  92. data/lib/quicsilver/server/web_transport_registry.rb +40 -0
  93. data/lib/quicsilver/server/web_transport_session.rb +812 -0
  94. data/lib/quicsilver/server/web_transport_stream.rb +326 -0
  95. data/lib/quicsilver/transport/configuration.rb +234 -0
  96. data/lib/quicsilver/transport/connection.rb +594 -0
  97. data/lib/quicsilver/transport/connection_stats.rb +53 -0
  98. data/lib/quicsilver/transport/event_loop.rb +74 -0
  99. data/lib/quicsilver/transport/inbound_stream.rb +53 -0
  100. data/lib/quicsilver/transport/stream.rb +43 -0
  101. data/lib/quicsilver/transport/stream_event.rb +49 -0
  102. data/lib/quicsilver/transport/stream_id.rb +26 -0
  103. data/lib/quicsilver/version.rb +3 -0
  104. data/lib/quicsilver.rb +96 -0
  105. data/lib/rackup/handler/quicsilver.rb +96 -0
  106. data/quicsilver.gemspec +66 -0
  107. metadata +362 -0
@@ -0,0 +1,696 @@
1
+ /*++
2
+
3
+ Copyright (c) Microsoft Corporation.
4
+ Licensed under the MIT License.
5
+
6
+ Abstract:
7
+
8
+ This file contains the platform specific definitions for MsQuic structures
9
+ and error codes.
10
+
11
+ Environment:
12
+
13
+ POSIX (Linux and macOS)
14
+
15
+ --*/
16
+
17
+ #ifdef _WIN32
18
+ #pragma once
19
+ #endif
20
+
21
+ #ifndef _MSQUIC_POSIX_
22
+ #define _MSQUIC_POSIX_
23
+
24
+ #include <stdlib.h>
25
+ #include <stdio.h>
26
+ #include <stdint.h>
27
+ #include <sys/types.h>
28
+ #include <string.h>
29
+ #include <assert.h>
30
+ #include <inttypes.h>
31
+ #include <stddef.h>
32
+ #include <netdb.h>
33
+ #include <netinet/ip.h>
34
+ #include <unistd.h>
35
+ #include <sys/socket.h>
36
+ #include <arpa/inet.h>
37
+ #include <netdb.h>
38
+ #include <errno.h>
39
+ #include "quic_sal_stub.h"
40
+
41
+ #define QUIC_INLINE static inline
42
+
43
+ #ifdef __cplusplus
44
+ extern "C++" {
45
+ template <size_t S> struct _ENUM_FLAG_INTEGER_FOR_SIZE;
46
+ template <> struct _ENUM_FLAG_INTEGER_FOR_SIZE<1> {
47
+ typedef uint8_t type;
48
+ };
49
+ template <> struct _ENUM_FLAG_INTEGER_FOR_SIZE<2> {
50
+ typedef uint16_t type;
51
+ };
52
+ template <> struct _ENUM_FLAG_INTEGER_FOR_SIZE<4> {
53
+ typedef uint32_t type;
54
+ };
55
+ template <> struct _ENUM_FLAG_INTEGER_FOR_SIZE<8> {
56
+ typedef uint64_t type;
57
+ };
58
+
59
+ // used as an approximation of std::underlying_type<T>
60
+ template <class T> struct _ENUM_FLAG_SIZED_INTEGER
61
+ {
62
+ typedef typename _ENUM_FLAG_INTEGER_FOR_SIZE<sizeof(T)>::type type;
63
+ };
64
+ }
65
+
66
+ #define DEFINE_ENUM_FLAG_OPERATORS(ENUMTYPE) \
67
+ extern "C++" { \
68
+ QUIC_INLINE ENUMTYPE operator | (ENUMTYPE a, ENUMTYPE b) throw() { return ENUMTYPE(((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)a) | ((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)b)); } \
69
+ QUIC_INLINE ENUMTYPE &operator |= (ENUMTYPE &a, ENUMTYPE b) throw() { return (ENUMTYPE &)(((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type &)a) |= ((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)b)); } \
70
+ QUIC_INLINE ENUMTYPE operator & (ENUMTYPE a, ENUMTYPE b) throw() { return ENUMTYPE(((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)a) & ((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)b)); } \
71
+ QUIC_INLINE ENUMTYPE &operator &= (ENUMTYPE &a, ENUMTYPE b) throw() { return (ENUMTYPE &)(((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type &)a) &= ((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)b)); } \
72
+ QUIC_INLINE ENUMTYPE operator ~ (ENUMTYPE a) throw() { return ENUMTYPE(~((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)a)); } \
73
+ QUIC_INLINE ENUMTYPE operator ^ (ENUMTYPE a, ENUMTYPE b) throw() { return ENUMTYPE(((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)a) ^ ((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)b)); } \
74
+ QUIC_INLINE ENUMTYPE &operator ^= (ENUMTYPE &a, ENUMTYPE b) throw() { return (ENUMTYPE &)(((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type &)a) ^= ((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)b)); } \
75
+ }
76
+ #else
77
+ #define DEFINE_ENUM_FLAG_OPERATORS(ENUMTYPE) // NOP, C allows these operators.
78
+ #endif
79
+
80
+ #define QUIC_API
81
+ #define QUIC_MAIN_EXPORT
82
+ #define QUIC_STATUS unsigned int
83
+ #ifdef __cplusplus
84
+ #define QUIC_FAILED(X) (static_cast<int>(X) > 0)
85
+ #define QUIC_SUCCEEDED(X) (static_cast<int>(X) <= 0)
86
+ #else
87
+ #define QUIC_FAILED(X) ((int)(X) > 0)
88
+ #define QUIC_SUCCEEDED(X) ((int)(X) <= 0)
89
+ #endif // __cplusplus
90
+
91
+ //
92
+ // The type of an error code generated by the system is mostly 'int'. In most
93
+ // situations, we use the value of a system-generated error code as the value
94
+ // of QUIC_STATUS. In some situations, we use a custom value for QUIC_STATUS.
95
+ // In order to ensure that custom values don't conflict with system-generated
96
+ // values, the custom values are all kept outside the range of any possible
97
+ // 'int' value. There are static asserts to ensure that QUIC_STATUS type is
98
+ // large enough for this purpose.
99
+ //
100
+
101
+ #ifndef ESTRPIPE // undefined on macOS
102
+ #define ESTRPIPE 86
103
+ #endif // ESTRPIPE
104
+
105
+ #ifndef ENOKEY // undefined om macOS
106
+ #define ENOKEY 126
107
+ #endif // ENOKEY
108
+
109
+ #define ERROR_BASE 200000000 // 0xBEBC200
110
+ #define TLS_ERROR_BASE 256 + ERROR_BASE // 0xBEBC300
111
+ #define CERT_ERROR_BASE 512 + ERROR_BASE // 0xBEBC400
112
+
113
+ #ifdef __cplusplus
114
+ #define QUIC_STATUS_DEF(x) (static_cast<QUIC_STATUS>(x))
115
+ #else
116
+ #define QUIC_STATUS_DEF(x) ((QUIC_STATUS)(x))
117
+ #endif
118
+
119
+ #define QUIC_STATUS_SUCCESS QUIC_STATUS_DEF(0) // 0
120
+ #define QUIC_STATUS_PENDING QUIC_STATUS_DEF(-2) // -2
121
+ #define QUIC_STATUS_CONTINUE QUIC_STATUS_DEF(-1) // -1
122
+ #define QUIC_STATUS_OUT_OF_MEMORY QUIC_STATUS_DEF(ENOMEM) // 12
123
+ #define QUIC_STATUS_INVALID_PARAMETER QUIC_STATUS_DEF(EINVAL) // 22
124
+ #define QUIC_STATUS_INVALID_STATE QUIC_STATUS_DEF(EPERM) // 1
125
+ #define QUIC_STATUS_NOT_SUPPORTED QUIC_STATUS_DEF(EOPNOTSUPP) // 95 (102 on macOS)
126
+ #define QUIC_STATUS_NOT_FOUND QUIC_STATUS_DEF(ENOENT) // 2
127
+ #define QUIC_STATUS_FILE_NOT_FOUND QUIC_STATUS_NOT_FOUND // 2
128
+ #define QUIC_STATUS_BUFFER_TOO_SMALL QUIC_STATUS_DEF(EOVERFLOW) // 75 (84 on macOS)
129
+ #define QUIC_STATUS_HANDSHAKE_FAILURE QUIC_STATUS_DEF(ECONNABORTED) // 103 (53 on macOS)
130
+ #define QUIC_STATUS_ABORTED QUIC_STATUS_DEF(ECANCELED) // 125 (89 on macOS)
131
+ #define QUIC_STATUS_ADDRESS_IN_USE QUIC_STATUS_DEF(EADDRINUSE) // 98 (48 on macOS)
132
+ #define QUIC_STATUS_INVALID_ADDRESS QUIC_STATUS_DEF(EAFNOSUPPORT) // 97 (47 on macOS)
133
+ #define QUIC_STATUS_CONNECTION_TIMEOUT QUIC_STATUS_DEF(ETIMEDOUT) // 110 (60 on macOS)
134
+ #define QUIC_STATUS_CONNECTION_IDLE QUIC_STATUS_DEF(ETIME) // 62 (101 on macOS)
135
+ #define QUIC_STATUS_INTERNAL_ERROR QUIC_STATUS_DEF(EIO) // 5
136
+ #define QUIC_STATUS_CONNECTION_REFUSED QUIC_STATUS_DEF(ECONNREFUSED) // 111 (61 on macOS)
137
+ #define QUIC_STATUS_PROTOCOL_ERROR QUIC_STATUS_DEF(EPROTO) // 71 (100 on macOS)
138
+ #define QUIC_STATUS_VER_NEG_ERROR QUIC_STATUS_DEF(EPROTONOSUPPORT) // 93 (43 on macOS)
139
+ #define QUIC_STATUS_UNREACHABLE QUIC_STATUS_DEF(EHOSTUNREACH) // 113 (65 on macOS)
140
+ #define QUIC_STATUS_TLS_ERROR QUIC_STATUS_DEF(ENOKEY) // 126
141
+ #define QUIC_STATUS_USER_CANCELED QUIC_STATUS_DEF(EOWNERDEAD) // 130 (105 on macOS)
142
+ #define QUIC_STATUS_ALPN_NEG_FAILURE QUIC_STATUS_DEF(ENOPROTOOPT) // 92 (42 on macOS)
143
+ #define QUIC_STATUS_STREAM_LIMIT_REACHED QUIC_STATUS_DEF(ESTRPIPE) // 86
144
+ #define QUIC_STATUS_ALPN_IN_USE QUIC_STATUS_DEF(EPROTOTYPE) // 91 (41 on macOS)
145
+ #define QUIC_STATUS_ADDRESS_NOT_AVAILABLE QUIC_STATUS_DEF(EADDRNOTAVAIL) // 99 (47 on macOS)
146
+
147
+ #define QUIC_STATUS_TLS_ALERT(Alert) QUIC_STATUS_DEF((0xff & Alert)+ TLS_ERROR_BASE)
148
+
149
+ #define QUIC_STATUS_CLOSE_NOTIFY QUIC_STATUS_TLS_ALERT(0) // 0xBEBC300 - Close notify
150
+ #define QUIC_STATUS_BAD_CERTIFICATE QUIC_STATUS_TLS_ALERT(42) // 0xBEBC32A - Bad Certificate
151
+ #define QUIC_STATUS_UNSUPPORTED_CERTIFICATE QUIC_STATUS_TLS_ALERT(43) // 0xBEBC32B - Unsupported Certficiate
152
+ #define QUIC_STATUS_REVOKED_CERTIFICATE QUIC_STATUS_TLS_ALERT(44) // 0xBEBC32C - Revoked Certificate
153
+ #define QUIC_STATUS_EXPIRED_CERTIFICATE QUIC_STATUS_TLS_ALERT(45) // 0xBEBC32D - Expired Certificate
154
+ #define QUIC_STATUS_UNKNOWN_CERTIFICATE QUIC_STATUS_TLS_ALERT(46) // 0xBEBC32E - Unknown Certificate
155
+ #define QUIC_STATUS_REQUIRED_CERTIFICATE QUIC_STATUS_TLS_ALERT(116) // 0xBEBC374 - Required Certificate
156
+
157
+ #define QUIC_STATUS_CERT_ERROR(Val) QUIC_STATUS_DEF(Val + CERT_ERROR_BASE)
158
+
159
+ #define QUIC_STATUS_CERT_EXPIRED QUIC_STATUS_CERT_ERROR(1) // 0xBEBC401
160
+ #define QUIC_STATUS_CERT_UNTRUSTED_ROOT QUIC_STATUS_CERT_ERROR(2) // 0xBEBC402
161
+ #define QUIC_STATUS_CERT_NO_CERT QUIC_STATUS_CERT_ERROR(3) // 0xBEBC403
162
+
163
+ typedef unsigned char BOOLEAN;
164
+ typedef struct in_addr IN_ADDR;
165
+ typedef struct in6_addr IN6_ADDR;
166
+ typedef struct addrinfo ADDRINFO;
167
+ typedef sa_family_t QUIC_ADDRESS_FAMILY;
168
+
169
+ #define QUIC_ADDRESS_FAMILY_UNSPEC AF_UNSPEC
170
+ #define QUIC_ADDRESS_FAMILY_INET AF_INET
171
+ #define QUIC_ADDRESS_FAMILY_INET6 AF_INET6
172
+
173
+ typedef union QUIC_ADDR {
174
+ struct sockaddr Ip;
175
+ struct sockaddr_in Ipv4;
176
+ struct sockaddr_in6 Ipv6;
177
+ } QUIC_ADDR;
178
+
179
+ #ifndef RTL_FIELD_SIZE
180
+ #define RTL_FIELD_SIZE(type, field) (sizeof(((type *)0)->field))
181
+ #endif
182
+
183
+ #define FIELD_OFFSET(type, field) offsetof(type, field)
184
+
185
+ #define QUIC_ADDR_V4_PORT_OFFSET FIELD_OFFSET(struct sockaddr_in, sin_port)
186
+ #define QUIC_ADDR_V4_IP_OFFSET FIELD_OFFSET(struct sockaddr_in, sin_addr)
187
+
188
+ #define QUIC_ADDR_V6_PORT_OFFSET FIELD_OFFSET(struct sockaddr_in6, sin6_port)
189
+ #define QUIC_ADDR_V6_IP_OFFSET FIELD_OFFSET(struct sockaddr_in6, sin6_addr)
190
+
191
+ #ifndef FALSE
192
+ #define FALSE 0
193
+ #define TRUE 1
194
+ #endif
195
+
196
+ #define INITCODE
197
+ #define PAGEDX
198
+ #define QUIC_CACHEALIGN
199
+
200
+ #if defined(__cplusplus)
201
+ extern "C" {
202
+ #endif
203
+
204
+ #if defined(CX_PLATFORM_DARWIN)
205
+ #define QUIC_LOCALHOST_FOR_AF(Af) ("localhost")
206
+ #else
207
+ #define QUIC_LOCALHOST_FOR_AF(Af) ((Af == QUIC_ADDRESS_FAMILY_INET) ? "localhost" : "ip6-localhost")
208
+ #endif
209
+
210
+ #define QUIC_CERTIFICATE_FLAG_IGNORE_REVOCATION 0x00000080
211
+ #define QUIC_CERTIFICATE_FLAG_IGNORE_UNKNOWN_CA 0x00000100
212
+ #define QUIC_CERTIFICATE_FLAG_IGNORE_WRONG_USAGE 0x00000200
213
+ #define QUIC_CERTIFICATE_FLAG_IGNORE_CERTIFICATE_CN_INVALID 0x00001000 // bad common name in X509 Cert.
214
+ #define QUIC_CERTIFICATE_FLAG_IGNORE_CERTIFICATE_DATE_INVALID 0x00002000 // expired X509 Cert.
215
+ #define QUIC_CERTIFICATE_FLAG_IGNORE_WEAK_SIGNATURE 0x00010000
216
+
217
+ #if defined(__clang__)
218
+ #define QUIC_NO_SANITIZE(X) __attribute__((no_sanitize(X)))
219
+ #else
220
+ #define QUIC_NO_SANITIZE(X)
221
+ #endif
222
+
223
+ //
224
+ // Helpers for Windows string functions.
225
+ //
226
+
227
+ #define _strnicmp strncasecmp
228
+ #define sprintf_s(dst, dst_len, format, ...) snprintf(dst, dst_len, format, __VA_ARGS__)
229
+ #define _vsnprintf_s(dst, dst_len, flag, format, ...) vsnprintf(dst, dst_len, format, __VA_ARGS__)
230
+
231
+ //
232
+ // IP Address Abstraction Helpers
233
+ //
234
+
235
+ QUIC_INLINE
236
+ BOOLEAN
237
+ QuicAddrFamilyIsValid(
238
+ _In_ QUIC_ADDRESS_FAMILY Family
239
+ )
240
+ {
241
+ return
242
+ Family == QUIC_ADDRESS_FAMILY_UNSPEC ||
243
+ Family == QUIC_ADDRESS_FAMILY_INET ||
244
+ Family == QUIC_ADDRESS_FAMILY_INET6;
245
+ }
246
+
247
+ QUIC_INLINE
248
+ BOOLEAN
249
+ QuicAddrIsValid(
250
+ _In_ const QUIC_ADDR* const Addr
251
+ )
252
+ {
253
+ return QuicAddrFamilyIsValid(Addr->Ip.sa_family);
254
+ }
255
+
256
+ QUIC_INLINE
257
+ BOOLEAN
258
+ QuicAddrCompareIp(
259
+ _In_ const QUIC_ADDR* const Addr1,
260
+ _In_ const QUIC_ADDR* const Addr2
261
+ )
262
+ {
263
+ if (QUIC_ADDRESS_FAMILY_INET == Addr1->Ip.sa_family) {
264
+ return memcmp(&Addr1->Ipv4.sin_addr, &Addr2->Ipv4.sin_addr, sizeof(IN_ADDR)) == 0;
265
+ } else {
266
+ return memcmp(&Addr1->Ipv6.sin6_addr, &Addr2->Ipv6.sin6_addr, sizeof(IN6_ADDR)) == 0;
267
+ }
268
+ }
269
+
270
+ QUIC_INLINE
271
+ BOOLEAN
272
+ QuicAddrCompare(
273
+ _In_ const QUIC_ADDR* const Addr1,
274
+ _In_ const QUIC_ADDR* const Addr2
275
+ )
276
+ {
277
+ if (Addr1->Ip.sa_family != Addr2->Ip.sa_family ||
278
+ Addr1->Ipv4.sin_port != Addr2->Ipv4.sin_port) {
279
+ return FALSE;
280
+ }
281
+
282
+ if (QUIC_ADDRESS_FAMILY_INET == Addr1->Ip.sa_family) {
283
+ return memcmp(&Addr1->Ipv4.sin_addr, &Addr2->Ipv4.sin_addr, sizeof(IN_ADDR)) == 0;
284
+ } else {
285
+ return memcmp(&Addr1->Ipv6.sin6_addr, &Addr2->Ipv6.sin6_addr, sizeof(IN6_ADDR)) == 0;
286
+ }
287
+ }
288
+
289
+ QUIC_INLINE
290
+ QUIC_ADDRESS_FAMILY
291
+ QuicAddrGetFamily(
292
+ _In_ const QUIC_ADDR* const Addr
293
+ )
294
+ {
295
+ return Addr->Ip.sa_family;
296
+ }
297
+
298
+ QUIC_INLINE
299
+ void
300
+ QuicAddrSetFamily(
301
+ _In_ QUIC_ADDR* Addr,
302
+ _In_ QUIC_ADDRESS_FAMILY Family
303
+ )
304
+ {
305
+ Addr->Ip.sa_family = Family;
306
+ }
307
+
308
+ QUIC_INLINE
309
+ uint16_t
310
+ QuicAddrGetPort(
311
+ _In_ const QUIC_ADDR* const Addr
312
+ )
313
+ {
314
+ if (QUIC_ADDRESS_FAMILY_INET == Addr->Ip.sa_family) {
315
+ return ntohs(Addr->Ipv4.sin_port);
316
+ } else {
317
+ return ntohs(Addr->Ipv6.sin6_port);
318
+ }
319
+ }
320
+
321
+ QUIC_INLINE
322
+ void
323
+ QuicAddrSetPort(
324
+ _Out_ QUIC_ADDR* Addr,
325
+ _In_ uint16_t Port
326
+ )
327
+ {
328
+ if (QUIC_ADDRESS_FAMILY_INET == Addr->Ip.sa_family) {
329
+ Addr->Ipv4.sin_port = htons(Port);
330
+ } else {
331
+ Addr->Ipv6.sin6_port = htons(Port);
332
+ }
333
+ }
334
+
335
+ //
336
+ // Test only API to increment the IP address value.
337
+ //
338
+ QUIC_INLINE
339
+ void
340
+ QuicAddrIncrement(
341
+ _Inout_ QUIC_ADDR* Addr
342
+ )
343
+ {
344
+ if (Addr->Ip.sa_family == QUIC_ADDRESS_FAMILY_INET) {
345
+ ((uint8_t*)&Addr->Ipv4.sin_addr)[3]++;
346
+ } else {
347
+ ((uint8_t*)&Addr->Ipv6.sin6_addr)[15]++;
348
+ }
349
+ }
350
+
351
+ QUIC_INLINE
352
+ void
353
+ QuicAddrSetToLoopback(
354
+ _Inout_ QUIC_ADDR* Addr
355
+ )
356
+ {
357
+ if (Addr->Ip.sa_family == QUIC_ADDRESS_FAMILY_INET) {
358
+ Addr->Ipv4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
359
+ } else {
360
+ Addr->Ipv6.sin6_addr = in6addr_loopback;
361
+ }
362
+ }
363
+
364
+ QUIC_INLINE
365
+ uint32_t
366
+ QUIC_NO_SANITIZE("unsigned-integer-overflow")
367
+ QuicAddrHash(
368
+ _In_ const QUIC_ADDR* Addr
369
+ )
370
+ {
371
+ uint32_t Hash = 5387; // A random prime number.
372
+ #define UPDATE_HASH(byte) Hash = ((Hash << 5) - Hash) + (byte)
373
+ if (Addr->Ip.sa_family == QUIC_ADDRESS_FAMILY_INET) {
374
+ UPDATE_HASH(Addr->Ipv4.sin_port & 0xFF);
375
+ UPDATE_HASH(Addr->Ipv4.sin_port >> 8);
376
+ for (uint8_t i = 0; i < sizeof(Addr->Ipv4.sin_addr); ++i) {
377
+ UPDATE_HASH(((uint8_t*)&Addr->Ipv4.sin_addr)[i]);
378
+ }
379
+ } else {
380
+ UPDATE_HASH(Addr->Ipv6.sin6_port & 0xFF);
381
+ UPDATE_HASH(Addr->Ipv6.sin6_port >> 8);
382
+ for (uint8_t i = 0; i < sizeof(Addr->Ipv6.sin6_addr); ++i) {
383
+ UPDATE_HASH(((uint8_t*)&Addr->Ipv6.sin6_addr)[i]);
384
+ }
385
+ }
386
+ return Hash;
387
+ }
388
+
389
+ QUIC_INLINE
390
+ BOOLEAN
391
+ QuicAddrIsWildCard(
392
+ _In_ const QUIC_ADDR* const Addr
393
+ )
394
+ {
395
+ if (Addr->Ip.sa_family == QUIC_ADDRESS_FAMILY_UNSPEC) {
396
+ return TRUE;
397
+ } else if (Addr->Ip.sa_family == QUIC_ADDRESS_FAMILY_INET) {
398
+ const IN_ADDR ZeroAddr = {0};
399
+ return memcmp(&Addr->Ipv4.sin_addr.s_addr, &ZeroAddr, sizeof(IN_ADDR)) == 0;
400
+ } else {
401
+ const IN6_ADDR ZeroAddr = {0};
402
+ return memcmp(&Addr->Ipv6.sin6_addr, &ZeroAddr, sizeof(IN6_ADDR)) == 0;
403
+ }
404
+ }
405
+
406
+ QUIC_INLINE
407
+ BOOLEAN
408
+ QuicAddr4FromString(
409
+ _In_z_ const char* AddrStr,
410
+ _Out_ QUIC_ADDR* Addr
411
+ )
412
+ {
413
+ if (AddrStr[0] == '[') {
414
+ return FALSE;
415
+ }
416
+
417
+ const char* PortStart = strchr(AddrStr, ':');
418
+ if (PortStart != NULL) {
419
+ if (strchr(PortStart+1, ':') != NULL) {
420
+ return FALSE;
421
+ }
422
+
423
+ char TmpAddrStr[16];
424
+ size_t AddrLength = PortStart - AddrStr;
425
+ if (AddrLength >= sizeof(TmpAddrStr)) {
426
+ return FALSE;
427
+ }
428
+ memcpy(TmpAddrStr, AddrStr, AddrLength);
429
+ TmpAddrStr[AddrLength] = '\0';
430
+
431
+ if (inet_pton(AF_INET, TmpAddrStr, &Addr->Ipv4.sin_addr) != 1) {
432
+ return FALSE;
433
+ }
434
+ Addr->Ipv4.sin_port = htons(atoi(PortStart+1));
435
+ } else {
436
+ if (inet_pton(AF_INET, AddrStr, &Addr->Ipv4.sin_addr) != 1) {
437
+ return FALSE;
438
+ }
439
+ }
440
+ Addr->Ip.sa_family = QUIC_ADDRESS_FAMILY_INET;
441
+ return TRUE;
442
+ }
443
+
444
+ QUIC_INLINE
445
+ BOOLEAN
446
+ QuicAddr6FromString(
447
+ _In_z_ const char* AddrStr,
448
+ _Out_ QUIC_ADDR* Addr
449
+ )
450
+ {
451
+ char TmpAddrStr[64];
452
+ if (AddrStr[0] == '[') {
453
+ const char* BracketEnd = strchr(AddrStr, ']');
454
+ if (BracketEnd == NULL || *(BracketEnd+1) != ':') {
455
+ return FALSE;
456
+ }
457
+
458
+ const size_t AddrLength = BracketEnd - AddrStr - 1;
459
+ if (AddrLength >= sizeof(TmpAddrStr)) {
460
+ return FALSE;
461
+ }
462
+ memcpy(TmpAddrStr, AddrStr + 1, AddrLength);
463
+ TmpAddrStr[AddrLength] = '\0';
464
+ Addr->Ipv6.sin6_port = htons(atoi(BracketEnd+2));
465
+ } else {
466
+ const size_t AddrLength = strlen(AddrStr);
467
+ if (AddrLength >= sizeof(TmpAddrStr)) {
468
+ return FALSE;
469
+ }
470
+ //
471
+ // Copy the string including the null terminator.
472
+ //
473
+ memcpy(TmpAddrStr, AddrStr, AddrLength + 1);
474
+ }
475
+
476
+ Addr->Ipv6.sin6_scope_id = 0;
477
+ char* ScopeStart = strchr(TmpAddrStr, '%');
478
+ if (ScopeStart != NULL) {
479
+ *ScopeStart++ = '\0';
480
+ if (*ScopeStart == '\0') {
481
+ return FALSE;
482
+ }
483
+ do {
484
+ if (*ScopeStart < '0' || *ScopeStart > '9' ||
485
+ Addr->Ipv6.sin6_scope_id > (UINT32_MAX - (*ScopeStart - '0')) / 10) {
486
+ return FALSE;
487
+ }
488
+ Addr->Ipv6.sin6_scope_id =
489
+ Addr->Ipv6.sin6_scope_id * 10 + (uint32_t)(*ScopeStart++ - '0');
490
+ } while (*ScopeStart != '\0');
491
+ }
492
+
493
+ if (inet_pton(AF_INET6, TmpAddrStr, &Addr->Ipv6.sin6_addr) != 1) {
494
+ return FALSE;
495
+ }
496
+ Addr->Ip.sa_family = QUIC_ADDRESS_FAMILY_INET6;
497
+ return TRUE;
498
+ }
499
+
500
+ QUIC_INLINE
501
+ BOOLEAN
502
+ QuicAddrFromString(
503
+ _In_z_ const char* AddrStr,
504
+ _In_ uint16_t Port, // Host byte order
505
+ _Out_ QUIC_ADDR* Addr
506
+ )
507
+ {
508
+ Addr->Ipv4.sin_port = htons(Port);
509
+ return
510
+ QuicAddr4FromString(AddrStr, Addr) ||
511
+ QuicAddr6FromString(AddrStr, Addr);
512
+ }
513
+
514
+ typedef int QUIC_XDP_MAP_HANDLE;
515
+
516
+ QUIC_INLINE
517
+ BOOLEAN
518
+ CxPlatIsIpLiteral(
519
+ _In_z_ const char* AddrStr
520
+ )
521
+ {
522
+ IN_ADDR Ipv4Addr = {0};
523
+ IN6_ADDR Ipv6Addr = {0};
524
+ return
525
+ inet_pton(AF_INET, AddrStr, &Ipv4Addr) == 1 ||
526
+ inet_pton(AF_INET6, AddrStr, &Ipv6Addr) == 1;
527
+ }
528
+
529
+ //
530
+ // Represents an IP address and (optionally) port number as a string.
531
+ //
532
+ typedef struct QUIC_ADDR_STR {
533
+ char Address[65];
534
+ } QUIC_ADDR_STR;
535
+
536
+ //
537
+ // Formats only the IP literal, excluding the port and IPv6 brackets. For
538
+ // example, an IPv6 address with port 443 is formatted as "2001:db8::1".
539
+ //
540
+ QUIC_INLINE
541
+ BOOLEAN
542
+ QuicAddrIpToString(
543
+ _In_ const QUIC_ADDR* Addr,
544
+ _Out_ QUIC_ADDR_STR* AddrStr
545
+ )
546
+ {
547
+ const void* IpAddress;
548
+ AddrStr->Address[0] = '\0';
549
+ if (Addr->Ip.sa_family == QUIC_ADDRESS_FAMILY_INET) {
550
+ IpAddress = &Addr->Ipv4.sin_addr;
551
+ } else if (Addr->Ip.sa_family == QUIC_ADDRESS_FAMILY_INET6) {
552
+ IpAddress = &Addr->Ipv6.sin6_addr;
553
+ } else {
554
+ return FALSE;
555
+ }
556
+ return
557
+ inet_ntop(
558
+ Addr->Ip.sa_family,
559
+ IpAddress,
560
+ AddrStr->Address,
561
+ sizeof(AddrStr->Address)) != NULL;
562
+ }
563
+
564
+ //
565
+ // Formats the complete endpoint, including a nonzero port and the brackets
566
+ // required around IPv6 when a port is present. For example, an IPv6 address
567
+ // with port 443 is formatted as "[2001:db8::1]:443".
568
+ //
569
+ QUIC_INLINE
570
+ BOOLEAN
571
+ QuicAddrToString(
572
+ _In_ const QUIC_ADDR* Addr,
573
+ _Out_ QUIC_ADDR_STR* AddrStr
574
+ )
575
+ {
576
+ size_t AvailSpace = sizeof(AddrStr->Address);
577
+ char* Address = AddrStr->Address;
578
+ if (Addr->Ip.sa_family == QUIC_ADDRESS_FAMILY_INET6 && Addr->Ipv6.sin6_port != 0) {
579
+ Address[0] = '[';
580
+ Address++;
581
+ AvailSpace--;
582
+ }
583
+ if (inet_ntop(
584
+ Addr->Ip.sa_family == QUIC_ADDRESS_FAMILY_INET ? AF_INET : AF_INET6,
585
+ Addr->Ip.sa_family == QUIC_ADDRESS_FAMILY_INET ? (void*)&Addr->Ipv4.sin_addr : (void*)&Addr->Ipv6.sin6_addr,
586
+ Address,
587
+ AvailSpace) == NULL) {
588
+ return FALSE;
589
+ }
590
+ if (Addr->Ipv4.sin_port != 0) {
591
+ Address += strlen(Address);
592
+ if (Addr->Ip.sa_family == QUIC_ADDRESS_FAMILY_INET6) {
593
+ Address[0] = ']';
594
+ Address++;
595
+ }
596
+ AvailSpace = sizeof(AddrStr->Address) - (Address - AddrStr->Address);
597
+ snprintf(Address, AvailSpace, ":%hu", ntohs(Addr->Ipv4.sin_port));
598
+ }
599
+ return TRUE;
600
+ }
601
+
602
+ //
603
+ // Event Queue Abstraction
604
+ //
605
+
606
+ #if __linux__
607
+
608
+ //
609
+ // TODO: build on other 64-bit architectures
610
+ //
611
+ #if CXPLAT_USE_IO_URING && (defined(__x86_64__) || defined(__aarch64__)) // liburing
612
+ #define LIBURING_INTERNAL
613
+
614
+ #if defined(__cplusplus)
615
+ extern "C++" {
616
+ #endif
617
+ #include <liburing.h>
618
+ #if defined(__cplusplus)
619
+ } // extern "C++"
620
+ #endif
621
+
622
+ typedef struct CXPLAT_EVENTQ QUIC_EVENTQ;
623
+ typedef struct io_uring_cqe* CXPLAT_CQE;
624
+ typedef
625
+ _IRQL_requires_max_(PASSIVE_LEVEL)
626
+ void
627
+ (CXPLAT_EVENT_COMPLETION)(
628
+ _In_ CXPLAT_CQE* Cqe
629
+ );
630
+ typedef CXPLAT_EVENT_COMPLETION *CXPLAT_EVENT_COMPLETION_HANDLER;
631
+ #define CXPLAT_USE_EVENT_BATCH_COMPLETION
632
+ typedef
633
+ _IRQL_requires_max_(PASSIVE_LEVEL)
634
+ void
635
+ (CXPLAT_EVENT_BATCH_COMPLETION)(
636
+ _Inout_ CXPLAT_CQE** Cqes,
637
+ _Inout_ uint32_t* Count
638
+ );
639
+ typedef CXPLAT_EVENT_BATCH_COMPLETION *CXPLAT_EVENT_BATCH_COMPLETION_HANDLER;
640
+ typedef struct CXPLAT_SQE QUIC_SQE;
641
+
642
+ #else // epoll
643
+
644
+ #include <sys/epoll.h>
645
+ #include <sys/eventfd.h>
646
+
647
+ typedef int QUIC_EVENTQ;
648
+
649
+ typedef struct epoll_event QUIC_CQE;
650
+
651
+ typedef
652
+ void
653
+ (QUIC_EVENT_COMPLETION)(
654
+ _In_ QUIC_CQE* Cqe
655
+ );
656
+ typedef QUIC_EVENT_COMPLETION *QUIC_EVENT_COMPLETION_HANDLER;
657
+
658
+ typedef struct QUIC_SQE {
659
+ int fd;
660
+ QUIC_EVENT_COMPLETION_HANDLER Completion;
661
+ } QUIC_SQE;
662
+
663
+ #endif // epoll
664
+
665
+ #elif __APPLE__ || __FreeBSD__ // kqueue
666
+
667
+ #include <sys/event.h>
668
+ #include <fcntl.h>
669
+
670
+ typedef int QUIC_EVENTQ;
671
+
672
+ typedef struct kevent QUIC_CQE;
673
+
674
+ typedef
675
+ void
676
+ (QUIC_EVENT_COMPLETION)(
677
+ _In_ QUIC_CQE* Cqe
678
+ );
679
+ typedef QUIC_EVENT_COMPLETION *QUIC_EVENT_COMPLETION_HANDLER;
680
+
681
+ typedef struct QUIC_SQE {
682
+ uintptr_t Handle;
683
+ QUIC_EVENT_COMPLETION_HANDLER Completion;
684
+ } QUIC_SQE;
685
+
686
+ #else
687
+
688
+ #error Unsupported Platform
689
+
690
+ #endif
691
+
692
+ #if defined(__cplusplus)
693
+ }
694
+ #endif
695
+
696
+ #endif