1 // Copyright (C) 2018-2019, Cloudflare, Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 //
11 // * Redistributions in binary form must reproduce the above copyright
12 // notice, this list of conditions and the following disclaimer in the
13 // documentation and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
19 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27 use std::ffi;
28 use std::ptr;
29 use std::slice;
30 use std::sync::atomic;
31
32 use std::net::Ipv4Addr;
33 use std::net::Ipv6Addr;
34 use std::net::SocketAddr;
35 use std::net::SocketAddrV4;
36 use std::net::SocketAddrV6;
37
38 #[cfg(unix)]
39 use std::os::unix::io::FromRawFd;
40
41 use libc::c_char;
42 use libc::c_int;
43 use libc::c_void;
44 use libc::size_t;
45 use libc::sockaddr;
46 use libc::ssize_t;
47 use libc::timespec;
48
49 #[cfg(not(windows))]
50 use libc::AF_INET;
51 #[cfg(windows)]
52 use winapi::shared::ws2def::AF_INET;
53
54 #[cfg(not(windows))]
55 use libc::AF_INET6;
56 #[cfg(windows)]
57 use winapi::shared::ws2def::AF_INET6;
58
59 #[cfg(not(windows))]
60 use libc::in_addr;
61 #[cfg(windows)]
62 use winapi::shared::inaddr::IN_ADDR as in_addr;
63
64 #[cfg(not(windows))]
65 use libc::in6_addr;
66 #[cfg(windows)]
67 use winapi::shared::in6addr::IN6_ADDR as in6_addr;
68
69 #[cfg(not(windows))]
70 use libc::sa_family_t;
71 #[cfg(windows)]
72 use winapi::shared::ws2def::ADDRESS_FAMILY as sa_family_t;
73
74 #[cfg(not(windows))]
75 use libc::sockaddr_in;
76 #[cfg(windows)]
77 use winapi::shared::ws2def::SOCKADDR_IN as sockaddr_in;
78
79 #[cfg(not(windows))]
80 use libc::sockaddr_in6;
81 #[cfg(windows)]
82 use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH as sockaddr_in6;
83
84 #[cfg(not(windows))]
85 use libc::sockaddr_storage;
86 #[cfg(windows)]
87 use winapi::shared::ws2def::SOCKADDR_STORAGE_LH as sockaddr_storage;
88
89 #[cfg(windows)]
90 use libc::c_int as socklen_t;
91 #[cfg(not(windows))]
92 use libc::socklen_t;
93
94 #[cfg(windows)]
95 use winapi::shared::in6addr::in6_addr_u;
96 #[cfg(windows)]
97 use winapi::shared::inaddr::in_addr_S_un;
98 #[cfg(windows)]
99 use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH_u;
100
101 use crate::*;
102
103 #[no_mangle]
quiche_version() -> *const u8104 pub extern fn quiche_version() -> *const u8 {
105 //static VERSION: &str = concat!("0.17.1", "\0");
106 // ANDROID's build system doesn't support environment variables
107 // so we hardcode the package version here.
108 static VERSION: &str = concat!("0.6.0", "\0");
109 VERSION.as_ptr()
110 }
111
112 struct Logger {
113 cb: extern fn(line: *const u8, argp: *mut c_void),
114 argp: std::sync::atomic::AtomicPtr<c_void>,
115 }
116
117 impl log::Log for Logger {
enabled(&self, _metadata: &log::Metadata) -> bool118 fn enabled(&self, _metadata: &log::Metadata) -> bool {
119 true
120 }
121
log(&self, record: &log::Record)122 fn log(&self, record: &log::Record) {
123 let line = format!("{}: {}\0", record.target(), record.args());
124 (self.cb)(line.as_ptr(), self.argp.load(atomic::Ordering::Relaxed));
125 }
126
flush(&self)127 fn flush(&self) {}
128 }
129
130 #[no_mangle]
quiche_enable_debug_logging( cb: extern fn(line: *const u8, argp: *mut c_void), argp: *mut c_void, ) -> c_int131 pub extern fn quiche_enable_debug_logging(
132 cb: extern fn(line: *const u8, argp: *mut c_void), argp: *mut c_void,
133 ) -> c_int {
134 let argp = atomic::AtomicPtr::new(argp);
135 let logger = Box::new(Logger { cb, argp });
136
137 if log::set_boxed_logger(logger).is_err() {
138 return -1;
139 }
140
141 log::set_max_level(log::LevelFilter::Trace);
142
143 0
144 }
145
146 #[no_mangle]
quiche_config_new(version: u32) -> *mut Config147 pub extern fn quiche_config_new(version: u32) -> *mut Config {
148 match Config::new(version) {
149 Ok(c) => Box::into_raw(Box::new(c)),
150
151 Err(_) => ptr::null_mut(),
152 }
153 }
154
155 #[no_mangle]
quiche_config_load_cert_chain_from_pem_file( config: &mut Config, path: *const c_char, ) -> c_int156 pub extern fn quiche_config_load_cert_chain_from_pem_file(
157 config: &mut Config, path: *const c_char,
158 ) -> c_int {
159 let path = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
160
161 match config.load_cert_chain_from_pem_file(path) {
162 Ok(_) => 0,
163
164 Err(e) => e.to_c() as c_int,
165 }
166 }
167
168 #[no_mangle]
quiche_config_load_priv_key_from_pem_file( config: &mut Config, path: *const c_char, ) -> c_int169 pub extern fn quiche_config_load_priv_key_from_pem_file(
170 config: &mut Config, path: *const c_char,
171 ) -> c_int {
172 let path = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
173
174 match config.load_priv_key_from_pem_file(path) {
175 Ok(_) => 0,
176
177 Err(e) => e.to_c() as c_int,
178 }
179 }
180
181 #[no_mangle]
quiche_config_load_verify_locations_from_file( config: &mut Config, path: *const c_char, ) -> c_int182 pub extern fn quiche_config_load_verify_locations_from_file(
183 config: &mut Config, path: *const c_char,
184 ) -> c_int {
185 let path = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
186
187 match config.load_verify_locations_from_file(path) {
188 Ok(_) => 0,
189
190 Err(e) => e.to_c() as c_int,
191 }
192 }
193
194 #[no_mangle]
quiche_config_load_verify_locations_from_directory( config: &mut Config, path: *const c_char, ) -> c_int195 pub extern fn quiche_config_load_verify_locations_from_directory(
196 config: &mut Config, path: *const c_char,
197 ) -> c_int {
198 let path = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
199
200 match config.load_verify_locations_from_directory(path) {
201 Ok(_) => 0,
202
203 Err(e) => e.to_c() as c_int,
204 }
205 }
206
207 #[no_mangle]
quiche_config_verify_peer(config: &mut Config, v: bool)208 pub extern fn quiche_config_verify_peer(config: &mut Config, v: bool) {
209 config.verify_peer(v);
210 }
211
212 #[no_mangle]
quiche_config_grease(config: &mut Config, v: bool)213 pub extern fn quiche_config_grease(config: &mut Config, v: bool) {
214 config.grease(v);
215 }
216
217 #[no_mangle]
quiche_config_log_keys(config: &mut Config)218 pub extern fn quiche_config_log_keys(config: &mut Config) {
219 config.log_keys();
220 }
221
222 #[no_mangle]
quiche_config_enable_early_data(config: &mut Config)223 pub extern fn quiche_config_enable_early_data(config: &mut Config) {
224 config.enable_early_data();
225 }
226
227 #[no_mangle]
228 /// Corresponds to the `Config::set_application_protos_wire_format` Rust
229 /// function.
quiche_config_set_application_protos( config: &mut Config, protos: *const u8, protos_len: size_t, ) -> c_int230 pub extern fn quiche_config_set_application_protos(
231 config: &mut Config, protos: *const u8, protos_len: size_t,
232 ) -> c_int {
233 let protos = unsafe { slice::from_raw_parts(protos, protos_len) };
234
235 match config.set_application_protos_wire_format(protos) {
236 Ok(_) => 0,
237
238 Err(e) => e.to_c() as c_int,
239 }
240 }
241
242 #[no_mangle]
quiche_config_set_max_idle_timeout(config: &mut Config, v: u64)243 pub extern fn quiche_config_set_max_idle_timeout(config: &mut Config, v: u64) {
244 config.set_max_idle_timeout(v);
245 }
246
247 #[no_mangle]
quiche_config_set_max_recv_udp_payload_size( config: &mut Config, v: size_t, )248 pub extern fn quiche_config_set_max_recv_udp_payload_size(
249 config: &mut Config, v: size_t,
250 ) {
251 config.set_max_recv_udp_payload_size(v);
252 }
253
254 #[no_mangle]
quiche_config_set_initial_max_data(config: &mut Config, v: u64)255 pub extern fn quiche_config_set_initial_max_data(config: &mut Config, v: u64) {
256 config.set_initial_max_data(v);
257 }
258
259 #[no_mangle]
quiche_config_set_initial_max_stream_data_bidi_local( config: &mut Config, v: u64, )260 pub extern fn quiche_config_set_initial_max_stream_data_bidi_local(
261 config: &mut Config, v: u64,
262 ) {
263 config.set_initial_max_stream_data_bidi_local(v);
264 }
265
266 #[no_mangle]
quiche_config_set_initial_max_stream_data_bidi_remote( config: &mut Config, v: u64, )267 pub extern fn quiche_config_set_initial_max_stream_data_bidi_remote(
268 config: &mut Config, v: u64,
269 ) {
270 config.set_initial_max_stream_data_bidi_remote(v);
271 }
272
273 #[no_mangle]
quiche_config_set_initial_max_stream_data_uni( config: &mut Config, v: u64, )274 pub extern fn quiche_config_set_initial_max_stream_data_uni(
275 config: &mut Config, v: u64,
276 ) {
277 config.set_initial_max_stream_data_uni(v);
278 }
279
280 #[no_mangle]
quiche_config_set_initial_max_streams_bidi( config: &mut Config, v: u64, )281 pub extern fn quiche_config_set_initial_max_streams_bidi(
282 config: &mut Config, v: u64,
283 ) {
284 config.set_initial_max_streams_bidi(v);
285 }
286
287 #[no_mangle]
quiche_config_set_initial_max_streams_uni( config: &mut Config, v: u64, )288 pub extern fn quiche_config_set_initial_max_streams_uni(
289 config: &mut Config, v: u64,
290 ) {
291 config.set_initial_max_streams_uni(v);
292 }
293
294 #[no_mangle]
quiche_config_set_ack_delay_exponent(config: &mut Config, v: u64)295 pub extern fn quiche_config_set_ack_delay_exponent(config: &mut Config, v: u64) {
296 config.set_ack_delay_exponent(v);
297 }
298
299 #[no_mangle]
quiche_config_set_max_ack_delay(config: &mut Config, v: u64)300 pub extern fn quiche_config_set_max_ack_delay(config: &mut Config, v: u64) {
301 config.set_max_ack_delay(v);
302 }
303
304 #[no_mangle]
quiche_config_set_disable_active_migration( config: &mut Config, v: bool, )305 pub extern fn quiche_config_set_disable_active_migration(
306 config: &mut Config, v: bool,
307 ) {
308 config.set_disable_active_migration(v);
309 }
310
311 #[no_mangle]
quiche_config_set_cc_algorithm_name( config: &mut Config, name: *const c_char, ) -> c_int312 pub extern fn quiche_config_set_cc_algorithm_name(
313 config: &mut Config, name: *const c_char,
314 ) -> c_int {
315 let name = unsafe { ffi::CStr::from_ptr(name).to_str().unwrap() };
316 match config.set_cc_algorithm_name(name) {
317 Ok(_) => 0,
318
319 Err(e) => e.to_c() as c_int,
320 }
321 }
322
323 #[no_mangle]
quiche_config_set_cc_algorithm( config: &mut Config, algo: CongestionControlAlgorithm, )324 pub extern fn quiche_config_set_cc_algorithm(
325 config: &mut Config, algo: CongestionControlAlgorithm,
326 ) {
327 config.set_cc_algorithm(algo);
328 }
329
330 #[no_mangle]
quiche_config_enable_hystart(config: &mut Config, v: bool)331 pub extern fn quiche_config_enable_hystart(config: &mut Config, v: bool) {
332 config.enable_hystart(v);
333 }
334
335 #[no_mangle]
quiche_config_enable_pacing(config: &mut Config, v: bool)336 pub extern fn quiche_config_enable_pacing(config: &mut Config, v: bool) {
337 config.enable_pacing(v);
338 }
339
340 #[no_mangle]
quiche_config_enable_dgram( config: &mut Config, enabled: bool, recv_queue_len: size_t, send_queue_len: size_t, )341 pub extern fn quiche_config_enable_dgram(
342 config: &mut Config, enabled: bool, recv_queue_len: size_t,
343 send_queue_len: size_t,
344 ) {
345 config.enable_dgram(enabled, recv_queue_len, send_queue_len);
346 }
347
348 #[no_mangle]
quiche_config_set_max_send_udp_payload_size( config: &mut Config, v: size_t, )349 pub extern fn quiche_config_set_max_send_udp_payload_size(
350 config: &mut Config, v: size_t,
351 ) {
352 config.set_max_send_udp_payload_size(v);
353 }
354
355 #[no_mangle]
quiche_config_set_max_connection_window( config: &mut Config, v: u64, )356 pub extern fn quiche_config_set_max_connection_window(
357 config: &mut Config, v: u64,
358 ) {
359 config.set_max_connection_window(v);
360 }
361
362 #[no_mangle]
quiche_config_set_max_stream_window(config: &mut Config, v: u64)363 pub extern fn quiche_config_set_max_stream_window(config: &mut Config, v: u64) {
364 config.set_max_stream_window(v);
365 }
366
367 #[no_mangle]
quiche_config_set_active_connection_id_limit( config: &mut Config, v: u64, )368 pub extern fn quiche_config_set_active_connection_id_limit(
369 config: &mut Config, v: u64,
370 ) {
371 config.set_active_connection_id_limit(v);
372 }
373
374 #[no_mangle]
quiche_config_set_stateless_reset_token( config: &mut Config, v: *const u8, )375 pub extern fn quiche_config_set_stateless_reset_token(
376 config: &mut Config, v: *const u8,
377 ) {
378 let reset_token = unsafe { slice::from_raw_parts(v, 16) };
379 let reset_token = match reset_token.try_into() {
380 Ok(rt) => rt,
381 Err(_) => unreachable!(),
382 };
383 let reset_token = u128::from_be_bytes(reset_token);
384 config.set_stateless_reset_token(Some(reset_token));
385 }
386
387 #[no_mangle]
quiche_config_free(config: *mut Config)388 pub extern fn quiche_config_free(config: *mut Config) {
389 unsafe { Box::from_raw(config) };
390 }
391
392 #[no_mangle]
quiche_header_info( buf: *mut u8, buf_len: size_t, dcil: size_t, version: *mut u32, ty: *mut u8, scid: *mut u8, scid_len: *mut size_t, dcid: *mut u8, dcid_len: *mut size_t, token: *mut u8, token_len: *mut size_t, ) -> c_int393 pub extern fn quiche_header_info(
394 buf: *mut u8, buf_len: size_t, dcil: size_t, version: *mut u32, ty: *mut u8,
395 scid: *mut u8, scid_len: *mut size_t, dcid: *mut u8, dcid_len: *mut size_t,
396 token: *mut u8, token_len: *mut size_t,
397 ) -> c_int {
398 let buf = unsafe { slice::from_raw_parts_mut(buf, buf_len) };
399 let hdr = match Header::from_slice(buf, dcil) {
400 Ok(v) => v,
401
402 Err(e) => return e.to_c() as c_int,
403 };
404
405 unsafe {
406 *version = hdr.version;
407
408 *ty = match hdr.ty {
409 Type::Initial => 1,
410 Type::Retry => 2,
411 Type::Handshake => 3,
412 Type::ZeroRTT => 4,
413 Type::Short => 5,
414 Type::VersionNegotiation => 6,
415 };
416
417 if *scid_len < hdr.scid.len() {
418 return -1;
419 }
420
421 let scid = slice::from_raw_parts_mut(scid, *scid_len);
422 let scid = &mut scid[..hdr.scid.len()];
423 scid.copy_from_slice(&hdr.scid);
424
425 *scid_len = hdr.scid.len();
426
427 if *dcid_len < hdr.dcid.len() {
428 return -1;
429 }
430
431 let dcid = slice::from_raw_parts_mut(dcid, *dcid_len);
432 let dcid = &mut dcid[..hdr.dcid.len()];
433 dcid.copy_from_slice(&hdr.dcid);
434
435 *dcid_len = hdr.dcid.len();
436
437 match hdr.token {
438 Some(tok) => {
439 if *token_len < tok.len() {
440 return -1;
441 }
442
443 let token = slice::from_raw_parts_mut(token, *token_len);
444 let token = &mut token[..tok.len()];
445 token.copy_from_slice(&tok);
446
447 *token_len = tok.len();
448 },
449
450 None => *token_len = 0,
451 }
452 }
453
454 0
455 }
456
457 #[no_mangle]
quiche_accept( scid: *const u8, scid_len: size_t, odcid: *const u8, odcid_len: size_t, local: &sockaddr, local_len: socklen_t, peer: &sockaddr, peer_len: socklen_t, config: &mut Config, ) -> *mut Connection458 pub extern fn quiche_accept(
459 scid: *const u8, scid_len: size_t, odcid: *const u8, odcid_len: size_t,
460 local: &sockaddr, local_len: socklen_t, peer: &sockaddr, peer_len: socklen_t,
461 config: &mut Config,
462 ) -> *mut Connection {
463 let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
464 let scid = ConnectionId::from_ref(scid);
465
466 let odcid = if !odcid.is_null() && odcid_len > 0 {
467 Some(ConnectionId::from_ref(unsafe {
468 slice::from_raw_parts(odcid, odcid_len)
469 }))
470 } else {
471 None
472 };
473
474 let local = std_addr_from_c(local, local_len);
475 let peer = std_addr_from_c(peer, peer_len);
476
477 match accept(&scid, odcid.as_ref(), local, peer, config) {
478 Ok(c) => Box::into_raw(Box::new(c)),
479
480 Err(_) => ptr::null_mut(),
481 }
482 }
483
484 #[no_mangle]
quiche_connect( server_name: *const c_char, scid: *const u8, scid_len: size_t, local: &sockaddr, local_len: socklen_t, peer: &sockaddr, peer_len: socklen_t, config: &mut Config, ) -> *mut Connection485 pub extern fn quiche_connect(
486 server_name: *const c_char, scid: *const u8, scid_len: size_t,
487 local: &sockaddr, local_len: socklen_t, peer: &sockaddr, peer_len: socklen_t,
488 config: &mut Config,
489 ) -> *mut Connection {
490 let server_name = if server_name.is_null() {
491 None
492 } else {
493 Some(unsafe { ffi::CStr::from_ptr(server_name).to_str().unwrap() })
494 };
495
496 let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
497 let scid = ConnectionId::from_ref(scid);
498
499 let local = std_addr_from_c(local, local_len);
500 let peer = std_addr_from_c(peer, peer_len);
501
502 match connect(server_name, &scid, local, peer, config) {
503 Ok(c) => Box::into_raw(Box::new(c)),
504
505 Err(_) => ptr::null_mut(),
506 }
507 }
508
509 #[no_mangle]
quiche_negotiate_version( scid: *const u8, scid_len: size_t, dcid: *const u8, dcid_len: size_t, out: *mut u8, out_len: size_t, ) -> ssize_t510 pub extern fn quiche_negotiate_version(
511 scid: *const u8, scid_len: size_t, dcid: *const u8, dcid_len: size_t,
512 out: *mut u8, out_len: size_t,
513 ) -> ssize_t {
514 let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
515 let scid = ConnectionId::from_ref(scid);
516
517 let dcid = unsafe { slice::from_raw_parts(dcid, dcid_len) };
518 let dcid = ConnectionId::from_ref(dcid);
519
520 let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
521
522 match negotiate_version(&scid, &dcid, out) {
523 Ok(v) => v as ssize_t,
524
525 Err(e) => e.to_c(),
526 }
527 }
528
529 #[no_mangle]
quiche_version_is_supported(version: u32) -> bool530 pub extern fn quiche_version_is_supported(version: u32) -> bool {
531 version_is_supported(version)
532 }
533
534 #[no_mangle]
quiche_retry( scid: *const u8, scid_len: size_t, dcid: *const u8, dcid_len: size_t, new_scid: *const u8, new_scid_len: size_t, token: *const u8, token_len: size_t, version: u32, out: *mut u8, out_len: size_t, ) -> ssize_t535 pub extern fn quiche_retry(
536 scid: *const u8, scid_len: size_t, dcid: *const u8, dcid_len: size_t,
537 new_scid: *const u8, new_scid_len: size_t, token: *const u8,
538 token_len: size_t, version: u32, out: *mut u8, out_len: size_t,
539 ) -> ssize_t {
540 let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
541 let scid = ConnectionId::from_ref(scid);
542
543 let dcid = unsafe { slice::from_raw_parts(dcid, dcid_len) };
544 let dcid = ConnectionId::from_ref(dcid);
545
546 let new_scid = unsafe { slice::from_raw_parts(new_scid, new_scid_len) };
547 let new_scid = ConnectionId::from_ref(new_scid);
548
549 let token = unsafe { slice::from_raw_parts(token, token_len) };
550 let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
551
552 match retry(&scid, &dcid, &new_scid, token, version, out) {
553 Ok(v) => v as ssize_t,
554
555 Err(e) => e.to_c(),
556 }
557 }
558
559 #[no_mangle]
quiche_conn_new_with_tls( scid: *const u8, scid_len: size_t, odcid: *const u8, odcid_len: size_t, local: &sockaddr, local_len: socklen_t, peer: &sockaddr, peer_len: socklen_t, config: &mut Config, ssl: *mut c_void, is_server: bool, ) -> *mut Connection560 pub extern fn quiche_conn_new_with_tls(
561 scid: *const u8, scid_len: size_t, odcid: *const u8, odcid_len: size_t,
562 local: &sockaddr, local_len: socklen_t, peer: &sockaddr, peer_len: socklen_t,
563 config: &mut Config, ssl: *mut c_void, is_server: bool,
564 ) -> *mut Connection {
565 let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
566 let scid = ConnectionId::from_ref(scid);
567
568 let odcid = if !odcid.is_null() && odcid_len > 0 {
569 Some(ConnectionId::from_ref(unsafe {
570 slice::from_raw_parts(odcid, odcid_len)
571 }))
572 } else {
573 None
574 };
575
576 let local = std_addr_from_c(local, local_len);
577 let peer = std_addr_from_c(peer, peer_len);
578
579 let tls = unsafe { tls::Handshake::from_ptr(ssl) };
580
581 match Connection::with_tls(
582 &scid,
583 odcid.as_ref(),
584 local,
585 peer,
586 config,
587 tls,
588 is_server,
589 ) {
590 Ok(c) => Box::into_raw(Box::new(c)),
591
592 Err(_) => ptr::null_mut(),
593 }
594 }
595
596 #[no_mangle]
quiche_conn_set_keylog_path( conn: &mut Connection, path: *const c_char, ) -> bool597 pub extern fn quiche_conn_set_keylog_path(
598 conn: &mut Connection, path: *const c_char,
599 ) -> bool {
600 let filename = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
601
602 let file = std::fs::OpenOptions::new()
603 .create(true)
604 .append(true)
605 .open(filename);
606
607 let writer = match file {
608 Ok(f) => std::io::BufWriter::new(f),
609
610 Err(_) => return false,
611 };
612
613 conn.set_keylog(Box::new(writer));
614
615 true
616 }
617
618 #[no_mangle]
619 #[cfg(unix)]
quiche_conn_set_keylog_fd(conn: &mut Connection, fd: c_int)620 pub extern fn quiche_conn_set_keylog_fd(conn: &mut Connection, fd: c_int) {
621 let f = unsafe { std::fs::File::from_raw_fd(fd) };
622 let writer = std::io::BufWriter::new(f);
623
624 conn.set_keylog(Box::new(writer));
625 }
626
627 #[no_mangle]
628 #[cfg(feature = "qlog")]
quiche_conn_set_qlog_path( conn: &mut Connection, path: *const c_char, log_title: *const c_char, log_desc: *const c_char, ) -> bool629 pub extern fn quiche_conn_set_qlog_path(
630 conn: &mut Connection, path: *const c_char, log_title: *const c_char,
631 log_desc: *const c_char,
632 ) -> bool {
633 let filename = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
634
635 let file = std::fs::OpenOptions::new()
636 .write(true)
637 .create_new(true)
638 .open(filename);
639
640 let writer = match file {
641 Ok(f) => std::io::BufWriter::new(f),
642
643 Err(_) => return false,
644 };
645
646 let title = unsafe { ffi::CStr::from_ptr(log_title).to_str().unwrap() };
647 let description = unsafe { ffi::CStr::from_ptr(log_desc).to_str().unwrap() };
648
649 conn.set_qlog(
650 Box::new(writer),
651 title.to_string(),
652 format!("{} id={}", description, conn.trace_id),
653 );
654
655 true
656 }
657
658 #[no_mangle]
659 #[cfg(all(unix, feature = "qlog"))]
quiche_conn_set_qlog_fd( conn: &mut Connection, fd: c_int, log_title: *const c_char, log_desc: *const c_char, )660 pub extern fn quiche_conn_set_qlog_fd(
661 conn: &mut Connection, fd: c_int, log_title: *const c_char,
662 log_desc: *const c_char,
663 ) {
664 let f = unsafe { std::fs::File::from_raw_fd(fd) };
665 let writer = std::io::BufWriter::new(f);
666
667 let title = unsafe { ffi::CStr::from_ptr(log_title).to_str().unwrap() };
668 let description = unsafe { ffi::CStr::from_ptr(log_desc).to_str().unwrap() };
669
670 conn.set_qlog(
671 Box::new(writer),
672 title.to_string(),
673 format!("{} id={}", description, conn.trace_id),
674 );
675 }
676
677 #[no_mangle]
quiche_conn_set_session( conn: &mut Connection, buf: *const u8, buf_len: size_t, ) -> c_int678 pub extern fn quiche_conn_set_session(
679 conn: &mut Connection, buf: *const u8, buf_len: size_t,
680 ) -> c_int {
681 let buf = unsafe { slice::from_raw_parts(buf, buf_len) };
682
683 match conn.set_session(buf) {
684 Ok(_) => 0,
685
686 Err(e) => e.to_c() as c_int,
687 }
688 }
689
690 #[repr(C)]
691 pub struct RecvInfo<'a> {
692 from: &'a sockaddr,
693 from_len: socklen_t,
694 to: &'a sockaddr,
695 to_len: socklen_t,
696 }
697
698 impl<'a> From<&RecvInfo<'a>> for crate::RecvInfo {
from(info: &RecvInfo) -> crate::RecvInfo699 fn from(info: &RecvInfo) -> crate::RecvInfo {
700 crate::RecvInfo {
701 from: std_addr_from_c(info.from, info.from_len),
702 to: std_addr_from_c(info.to, info.to_len),
703 }
704 }
705 }
706
707 #[no_mangle]
quiche_conn_recv( conn: &mut Connection, buf: *mut u8, buf_len: size_t, info: &RecvInfo, ) -> ssize_t708 pub extern fn quiche_conn_recv(
709 conn: &mut Connection, buf: *mut u8, buf_len: size_t, info: &RecvInfo,
710 ) -> ssize_t {
711 if buf_len > <ssize_t>::max_value() as usize {
712 panic!("The provided buffer is too large");
713 }
714
715 let buf = unsafe { slice::from_raw_parts_mut(buf, buf_len) };
716
717 match conn.recv(buf, info.into()) {
718 Ok(v) => v as ssize_t,
719
720 Err(e) => e.to_c(),
721 }
722 }
723
724 #[repr(C)]
725 pub struct SendInfo {
726 from: sockaddr_storage,
727 from_len: socklen_t,
728 to: sockaddr_storage,
729 to_len: socklen_t,
730
731 at: timespec,
732 }
733
734 #[no_mangle]
quiche_conn_send( conn: &mut Connection, out: *mut u8, out_len: size_t, out_info: &mut SendInfo, ) -> ssize_t735 pub extern fn quiche_conn_send(
736 conn: &mut Connection, out: *mut u8, out_len: size_t, out_info: &mut SendInfo,
737 ) -> ssize_t {
738 if out_len > <ssize_t>::max_value() as usize {
739 panic!("The provided buffer is too large");
740 }
741
742 let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
743
744 match conn.send(out) {
745 Ok((v, info)) => {
746 out_info.from_len = std_addr_to_c(&info.from, &mut out_info.from);
747 out_info.to_len = std_addr_to_c(&info.to, &mut out_info.to);
748
749 std_time_to_c(&info.at, &mut out_info.at);
750
751 v as ssize_t
752 },
753
754 Err(e) => e.to_c(),
755 }
756 }
757
758 #[no_mangle]
quiche_conn_stream_recv( conn: &mut Connection, stream_id: u64, out: *mut u8, out_len: size_t, fin: &mut bool, ) -> ssize_t759 pub extern fn quiche_conn_stream_recv(
760 conn: &mut Connection, stream_id: u64, out: *mut u8, out_len: size_t,
761 fin: &mut bool,
762 ) -> ssize_t {
763 if out_len > <ssize_t>::max_value() as usize {
764 panic!("The provided buffer is too large");
765 }
766
767 let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
768
769 let (out_len, out_fin) = match conn.stream_recv(stream_id, out) {
770 Ok(v) => v,
771
772 Err(e) => return e.to_c(),
773 };
774
775 *fin = out_fin;
776
777 out_len as ssize_t
778 }
779
780 #[no_mangle]
quiche_conn_stream_send( conn: &mut Connection, stream_id: u64, buf: *const u8, buf_len: size_t, fin: bool, ) -> ssize_t781 pub extern fn quiche_conn_stream_send(
782 conn: &mut Connection, stream_id: u64, buf: *const u8, buf_len: size_t,
783 fin: bool,
784 ) -> ssize_t {
785 if buf_len > <ssize_t>::max_value() as usize {
786 panic!("The provided buffer is too large");
787 }
788
789 let buf = unsafe { slice::from_raw_parts(buf, buf_len) };
790
791 match conn.stream_send(stream_id, buf, fin) {
792 Ok(v) => v as ssize_t,
793
794 Err(e) => e.to_c(),
795 }
796 }
797
798 #[no_mangle]
quiche_conn_stream_priority( conn: &mut Connection, stream_id: u64, urgency: u8, incremental: bool, ) -> c_int799 pub extern fn quiche_conn_stream_priority(
800 conn: &mut Connection, stream_id: u64, urgency: u8, incremental: bool,
801 ) -> c_int {
802 match conn.stream_priority(stream_id, urgency, incremental) {
803 Ok(_) => 0,
804
805 Err(e) => e.to_c() as c_int,
806 }
807 }
808
809 #[no_mangle]
quiche_conn_stream_shutdown( conn: &mut Connection, stream_id: u64, direction: Shutdown, err: u64, ) -> c_int810 pub extern fn quiche_conn_stream_shutdown(
811 conn: &mut Connection, stream_id: u64, direction: Shutdown, err: u64,
812 ) -> c_int {
813 match conn.stream_shutdown(stream_id, direction, err) {
814 Ok(_) => 0,
815
816 Err(e) => e.to_c() as c_int,
817 }
818 }
819
820 #[no_mangle]
quiche_conn_stream_capacity( conn: &Connection, stream_id: u64, ) -> ssize_t821 pub extern fn quiche_conn_stream_capacity(
822 conn: &Connection, stream_id: u64,
823 ) -> ssize_t {
824 match conn.stream_capacity(stream_id) {
825 Ok(v) => v as ssize_t,
826
827 Err(e) => e.to_c(),
828 }
829 }
830
831 #[no_mangle]
quiche_conn_stream_readable( conn: &Connection, stream_id: u64, ) -> bool832 pub extern fn quiche_conn_stream_readable(
833 conn: &Connection, stream_id: u64,
834 ) -> bool {
835 conn.stream_readable(stream_id)
836 }
837
838 #[no_mangle]
quiche_conn_stream_readable_next(conn: &mut Connection) -> i64839 pub extern fn quiche_conn_stream_readable_next(conn: &mut Connection) -> i64 {
840 conn.stream_readable_next().map(|v| v as i64).unwrap_or(-1)
841 }
842
843 #[no_mangle]
quiche_conn_stream_writable( conn: &mut Connection, stream_id: u64, len: usize, ) -> c_int844 pub extern fn quiche_conn_stream_writable(
845 conn: &mut Connection, stream_id: u64, len: usize,
846 ) -> c_int {
847 match conn.stream_writable(stream_id, len) {
848 Ok(true) => 1,
849
850 Ok(false) => 0,
851
852 Err(e) => e.to_c() as c_int,
853 }
854 }
855
856 #[no_mangle]
quiche_conn_stream_writable_next(conn: &mut Connection) -> i64857 pub extern fn quiche_conn_stream_writable_next(conn: &mut Connection) -> i64 {
858 conn.stream_writable_next().map(|v| v as i64).unwrap_or(-1)
859 }
860
861 #[no_mangle]
quiche_conn_stream_finished( conn: &Connection, stream_id: u64, ) -> bool862 pub extern fn quiche_conn_stream_finished(
863 conn: &Connection, stream_id: u64,
864 ) -> bool {
865 conn.stream_finished(stream_id)
866 }
867
868 #[no_mangle]
quiche_conn_readable(conn: &Connection) -> *mut StreamIter869 pub extern fn quiche_conn_readable(conn: &Connection) -> *mut StreamIter {
870 Box::into_raw(Box::new(conn.readable()))
871 }
872
873 #[no_mangle]
quiche_conn_writable(conn: &Connection) -> *mut StreamIter874 pub extern fn quiche_conn_writable(conn: &Connection) -> *mut StreamIter {
875 Box::into_raw(Box::new(conn.writable()))
876 }
877
878 #[no_mangle]
quiche_conn_max_send_udp_payload_size(conn: &Connection) -> usize879 pub extern fn quiche_conn_max_send_udp_payload_size(conn: &Connection) -> usize {
880 conn.max_send_udp_payload_size()
881 }
882
883 #[no_mangle]
quiche_conn_is_readable(conn: &Connection) -> bool884 pub extern fn quiche_conn_is_readable(conn: &Connection) -> bool {
885 conn.is_readable()
886 }
887
888 struct AppData(*mut c_void);
889 unsafe impl Send for AppData {}
890 unsafe impl Sync for AppData {}
891
892 #[no_mangle]
quiche_conn_stream_init_application_data( conn: &mut Connection, stream_id: u64, data: *mut c_void, ) -> c_int893 pub extern fn quiche_conn_stream_init_application_data(
894 conn: &mut Connection, stream_id: u64, data: *mut c_void,
895 ) -> c_int {
896 match conn.stream_init_application_data(stream_id, AppData(data)) {
897 Ok(_) => 0,
898
899 Err(e) => e.to_c() as c_int,
900 }
901 }
902
903 #[no_mangle]
quiche_conn_stream_application_data( conn: &mut Connection, stream_id: u64, ) -> *mut c_void904 pub extern fn quiche_conn_stream_application_data(
905 conn: &mut Connection, stream_id: u64,
906 ) -> *mut c_void {
907 match conn.stream_application_data(stream_id) {
908 Some(v) => v.downcast_mut::<AppData>().unwrap().0,
909
910 None => ptr::null_mut(),
911 }
912 }
913
914 #[no_mangle]
quiche_conn_close( conn: &mut Connection, app: bool, err: u64, reason: *const u8, reason_len: size_t, ) -> c_int915 pub extern fn quiche_conn_close(
916 conn: &mut Connection, app: bool, err: u64, reason: *const u8,
917 reason_len: size_t,
918 ) -> c_int {
919 let reason = unsafe { slice::from_raw_parts(reason, reason_len) };
920
921 match conn.close(app, err, reason) {
922 Ok(_) => 0,
923
924 Err(e) => e.to_c() as c_int,
925 }
926 }
927
928 #[no_mangle]
quiche_conn_timeout_as_nanos(conn: &Connection) -> u64929 pub extern fn quiche_conn_timeout_as_nanos(conn: &Connection) -> u64 {
930 match conn.timeout() {
931 Some(timeout) => timeout.as_nanos() as u64,
932
933 None => u64::MAX,
934 }
935 }
936
937 #[no_mangle]
quiche_conn_timeout_as_millis(conn: &Connection) -> u64938 pub extern fn quiche_conn_timeout_as_millis(conn: &Connection) -> u64 {
939 match conn.timeout() {
940 Some(timeout) => timeout.as_millis() as u64,
941
942 None => u64::MAX,
943 }
944 }
945
946 #[no_mangle]
quiche_conn_on_timeout(conn: &mut Connection)947 pub extern fn quiche_conn_on_timeout(conn: &mut Connection) {
948 conn.on_timeout()
949 }
950
951 #[no_mangle]
quiche_conn_trace_id( conn: &Connection, out: &mut *const u8, out_len: &mut size_t, )952 pub extern fn quiche_conn_trace_id(
953 conn: &Connection, out: &mut *const u8, out_len: &mut size_t,
954 ) {
955 let trace_id = conn.trace_id();
956
957 *out = trace_id.as_ptr();
958 *out_len = trace_id.len();
959 }
960
961 #[no_mangle]
quiche_conn_source_id( conn: &Connection, out: &mut *const u8, out_len: &mut size_t, )962 pub extern fn quiche_conn_source_id(
963 conn: &Connection, out: &mut *const u8, out_len: &mut size_t,
964 ) {
965 let conn_id = conn.source_id();
966 let id = conn_id.as_ref();
967 *out = id.as_ptr();
968 *out_len = id.len();
969 }
970
971 #[no_mangle]
quiche_conn_destination_id( conn: &Connection, out: &mut *const u8, out_len: &mut size_t, )972 pub extern fn quiche_conn_destination_id(
973 conn: &Connection, out: &mut *const u8, out_len: &mut size_t,
974 ) {
975 let conn_id = conn.destination_id();
976 let id = conn_id.as_ref();
977
978 *out = id.as_ptr();
979 *out_len = id.len();
980 }
981
982 #[no_mangle]
quiche_conn_application_proto( conn: &Connection, out: &mut *const u8, out_len: &mut size_t, )983 pub extern fn quiche_conn_application_proto(
984 conn: &Connection, out: &mut *const u8, out_len: &mut size_t,
985 ) {
986 let proto = conn.application_proto();
987
988 *out = proto.as_ptr();
989 *out_len = proto.len();
990 }
991
992 #[no_mangle]
quiche_conn_peer_cert( conn: &Connection, out: &mut *const u8, out_len: &mut size_t, )993 pub extern fn quiche_conn_peer_cert(
994 conn: &Connection, out: &mut *const u8, out_len: &mut size_t,
995 ) {
996 match conn.peer_cert() {
997 Some(peer_cert) => {
998 *out = peer_cert.as_ptr();
999 *out_len = peer_cert.len();
1000 },
1001
1002 None => *out_len = 0,
1003 }
1004 }
1005
1006 #[no_mangle]
quiche_conn_session( conn: &Connection, out: &mut *const u8, out_len: &mut size_t, )1007 pub extern fn quiche_conn_session(
1008 conn: &Connection, out: &mut *const u8, out_len: &mut size_t,
1009 ) {
1010 match conn.session() {
1011 Some(session) => {
1012 *out = session.as_ptr();
1013 *out_len = session.len();
1014 },
1015
1016 None => *out_len = 0,
1017 }
1018 }
1019
1020 #[no_mangle]
quiche_conn_is_established(conn: &Connection) -> bool1021 pub extern fn quiche_conn_is_established(conn: &Connection) -> bool {
1022 conn.is_established()
1023 }
1024
1025 #[no_mangle]
quiche_conn_is_in_early_data(conn: &Connection) -> bool1026 pub extern fn quiche_conn_is_in_early_data(conn: &Connection) -> bool {
1027 conn.is_in_early_data()
1028 }
1029
1030 #[no_mangle]
quiche_conn_is_draining(conn: &Connection) -> bool1031 pub extern fn quiche_conn_is_draining(conn: &Connection) -> bool {
1032 conn.is_draining()
1033 }
1034
1035 #[no_mangle]
quiche_conn_is_closed(conn: &Connection) -> bool1036 pub extern fn quiche_conn_is_closed(conn: &Connection) -> bool {
1037 conn.is_closed()
1038 }
1039
1040 #[no_mangle]
quiche_conn_is_timed_out(conn: &Connection) -> bool1041 pub extern fn quiche_conn_is_timed_out(conn: &Connection) -> bool {
1042 conn.is_timed_out()
1043 }
1044
1045 #[no_mangle]
quiche_conn_peer_error( conn: &Connection, is_app: *mut bool, error_code: *mut u64, reason: &mut *const u8, reason_len: &mut size_t, ) -> bool1046 pub extern fn quiche_conn_peer_error(
1047 conn: &Connection, is_app: *mut bool, error_code: *mut u64,
1048 reason: &mut *const u8, reason_len: &mut size_t,
1049 ) -> bool {
1050 match &conn.peer_error {
1051 Some(conn_err) => unsafe {
1052 *is_app = conn_err.is_app;
1053 *error_code = conn_err.error_code;
1054 *reason = conn_err.reason.as_ptr();
1055 *reason_len = conn_err.reason.len();
1056
1057 true
1058 },
1059
1060 None => false,
1061 }
1062 }
1063
1064 #[no_mangle]
quiche_conn_local_error( conn: &Connection, is_app: *mut bool, error_code: *mut u64, reason: &mut *const u8, reason_len: &mut size_t, ) -> bool1065 pub extern fn quiche_conn_local_error(
1066 conn: &Connection, is_app: *mut bool, error_code: *mut u64,
1067 reason: &mut *const u8, reason_len: &mut size_t,
1068 ) -> bool {
1069 match &conn.local_error {
1070 Some(conn_err) => unsafe {
1071 *is_app = conn_err.is_app;
1072 *error_code = conn_err.error_code;
1073 *reason = conn_err.reason.as_ptr();
1074 *reason_len = conn_err.reason.len();
1075
1076 true
1077 },
1078
1079 None => false,
1080 }
1081 }
1082
1083 #[no_mangle]
quiche_stream_iter_next( iter: &mut StreamIter, stream_id: *mut u64, ) -> bool1084 pub extern fn quiche_stream_iter_next(
1085 iter: &mut StreamIter, stream_id: *mut u64,
1086 ) -> bool {
1087 if let Some(v) = iter.next() {
1088 unsafe { *stream_id = v };
1089 return true;
1090 }
1091
1092 false
1093 }
1094
1095 #[no_mangle]
quiche_stream_iter_free(iter: *mut StreamIter)1096 pub extern fn quiche_stream_iter_free(iter: *mut StreamIter) {
1097 unsafe { Box::from_raw(iter) };
1098 }
1099
1100 #[repr(C)]
1101 pub struct Stats {
1102 recv: usize,
1103 sent: usize,
1104 lost: usize,
1105 retrans: usize,
1106 sent_bytes: u64,
1107 recv_bytes: u64,
1108 lost_bytes: u64,
1109 stream_retrans_bytes: u64,
1110 paths_count: usize,
1111 peer_max_idle_timeout: u64,
1112 peer_max_udp_payload_size: u64,
1113 peer_initial_max_data: u64,
1114 peer_initial_max_stream_data_bidi_local: u64,
1115 peer_initial_max_stream_data_bidi_remote: u64,
1116 peer_initial_max_stream_data_uni: u64,
1117 peer_initial_max_streams_bidi: u64,
1118 peer_initial_max_streams_uni: u64,
1119 peer_ack_delay_exponent: u64,
1120 peer_max_ack_delay: u64,
1121 peer_disable_active_migration: bool,
1122 peer_active_conn_id_limit: u64,
1123 peer_max_datagram_frame_size: ssize_t,
1124 paths: [PathStats; 8],
1125 }
1126
1127 #[no_mangle]
quiche_conn_stats(conn: &Connection, out: &mut Stats)1128 pub extern fn quiche_conn_stats(conn: &Connection, out: &mut Stats) {
1129 let stats = conn.stats();
1130
1131 out.recv = stats.recv;
1132 out.sent = stats.sent;
1133 out.lost = stats.lost;
1134 out.retrans = stats.retrans;
1135 out.sent_bytes = stats.sent_bytes;
1136 out.recv_bytes = stats.recv_bytes;
1137 out.lost_bytes = stats.lost_bytes;
1138 out.stream_retrans_bytes = stats.stream_retrans_bytes;
1139 out.paths_count = stats.paths_count;
1140 out.peer_max_idle_timeout = stats.peer_max_idle_timeout;
1141 out.peer_max_udp_payload_size = stats.peer_max_udp_payload_size;
1142 out.peer_initial_max_data = stats.peer_initial_max_data;
1143 out.peer_initial_max_stream_data_bidi_local =
1144 stats.peer_initial_max_stream_data_bidi_local;
1145 out.peer_initial_max_stream_data_bidi_remote =
1146 stats.peer_initial_max_stream_data_bidi_remote;
1147 out.peer_initial_max_stream_data_uni = stats.peer_initial_max_stream_data_uni;
1148 out.peer_initial_max_streams_bidi = stats.peer_initial_max_streams_bidi;
1149 out.peer_initial_max_streams_uni = stats.peer_initial_max_streams_uni;
1150 out.peer_ack_delay_exponent = stats.peer_ack_delay_exponent;
1151 out.peer_max_ack_delay = stats.peer_max_ack_delay;
1152 out.peer_disable_active_migration = stats.peer_disable_active_migration;
1153 out.peer_active_conn_id_limit = stats.peer_active_conn_id_limit;
1154 out.peer_max_datagram_frame_size = match stats.peer_max_datagram_frame_size {
1155 None => Error::Done.to_c(),
1156
1157 Some(v) => v as ssize_t,
1158 };
1159 }
1160
1161 #[repr(C)]
1162 pub struct PathStats {
1163 local_addr: sockaddr_storage,
1164 local_addr_len: socklen_t,
1165 peer_addr: sockaddr_storage,
1166 peer_addr_len: socklen_t,
1167 validation_state: ssize_t,
1168 active: bool,
1169 recv: usize,
1170 sent: usize,
1171 lost: usize,
1172 retrans: usize,
1173 rtt: u64,
1174 cwnd: usize,
1175 sent_bytes: u64,
1176 recv_bytes: u64,
1177 lost_bytes: u64,
1178 stream_retrans_bytes: u64,
1179 pmtu: usize,
1180 delivery_rate: u64,
1181 }
1182
1183 #[no_mangle]
quiche_conn_path_stats( conn: &Connection, idx: usize, out: &mut PathStats, ) -> c_int1184 pub extern fn quiche_conn_path_stats(
1185 conn: &Connection, idx: usize, out: &mut PathStats,
1186 ) -> c_int {
1187 let stats = match conn.path_stats().nth(idx) {
1188 Some(p) => p,
1189 None => return Error::Done.to_c() as c_int,
1190 };
1191
1192 out.local_addr_len = std_addr_to_c(&stats.local_addr, &mut out.local_addr);
1193 out.peer_addr_len = std_addr_to_c(&stats.peer_addr, &mut out.peer_addr);
1194 out.validation_state = stats.validation_state.to_c();
1195 out.active = stats.active;
1196 out.recv = stats.recv;
1197 out.sent = stats.sent;
1198 out.lost = stats.lost;
1199 out.retrans = stats.retrans;
1200 out.rtt = stats.rtt.as_nanos() as u64;
1201 out.cwnd = stats.cwnd;
1202 out.sent_bytes = stats.sent_bytes;
1203 out.recv_bytes = stats.recv_bytes;
1204 out.lost_bytes = stats.lost_bytes;
1205 out.stream_retrans_bytes = stats.stream_retrans_bytes;
1206 out.pmtu = stats.pmtu;
1207 out.delivery_rate = stats.delivery_rate;
1208
1209 0
1210 }
1211
1212 #[no_mangle]
quiche_conn_dgram_max_writable_len(conn: &Connection) -> ssize_t1213 pub extern fn quiche_conn_dgram_max_writable_len(conn: &Connection) -> ssize_t {
1214 match conn.dgram_max_writable_len() {
1215 None => Error::Done.to_c(),
1216
1217 Some(v) => v as ssize_t,
1218 }
1219 }
1220
1221 #[no_mangle]
quiche_conn_dgram_recv_front_len(conn: &Connection) -> ssize_t1222 pub extern fn quiche_conn_dgram_recv_front_len(conn: &Connection) -> ssize_t {
1223 match conn.dgram_recv_front_len() {
1224 None => Error::Done.to_c(),
1225
1226 Some(v) => v as ssize_t,
1227 }
1228 }
1229
1230 #[no_mangle]
quiche_conn_dgram_recv_queue_len(conn: &Connection) -> ssize_t1231 pub extern fn quiche_conn_dgram_recv_queue_len(conn: &Connection) -> ssize_t {
1232 conn.dgram_recv_queue_len() as ssize_t
1233 }
1234
1235 #[no_mangle]
quiche_conn_dgram_recv_queue_byte_size( conn: &Connection, ) -> ssize_t1236 pub extern fn quiche_conn_dgram_recv_queue_byte_size(
1237 conn: &Connection,
1238 ) -> ssize_t {
1239 conn.dgram_recv_queue_byte_size() as ssize_t
1240 }
1241
1242 #[no_mangle]
quiche_conn_dgram_send_queue_len(conn: &Connection) -> ssize_t1243 pub extern fn quiche_conn_dgram_send_queue_len(conn: &Connection) -> ssize_t {
1244 conn.dgram_send_queue_len() as ssize_t
1245 }
1246
1247 #[no_mangle]
quiche_conn_dgram_send_queue_byte_size( conn: &Connection, ) -> ssize_t1248 pub extern fn quiche_conn_dgram_send_queue_byte_size(
1249 conn: &Connection,
1250 ) -> ssize_t {
1251 conn.dgram_send_queue_byte_size() as ssize_t
1252 }
1253
1254 #[no_mangle]
quiche_conn_dgram_send( conn: &mut Connection, buf: *const u8, buf_len: size_t, ) -> ssize_t1255 pub extern fn quiche_conn_dgram_send(
1256 conn: &mut Connection, buf: *const u8, buf_len: size_t,
1257 ) -> ssize_t {
1258 if buf_len > <ssize_t>::max_value() as usize {
1259 panic!("The provided buffer is too large");
1260 }
1261
1262 let buf = unsafe { slice::from_raw_parts(buf, buf_len) };
1263
1264 match conn.dgram_send(buf) {
1265 Ok(_) => buf_len as ssize_t,
1266
1267 Err(e) => e.to_c(),
1268 }
1269 }
1270
1271 #[no_mangle]
quiche_conn_dgram_recv( conn: &mut Connection, out: *mut u8, out_len: size_t, ) -> ssize_t1272 pub extern fn quiche_conn_dgram_recv(
1273 conn: &mut Connection, out: *mut u8, out_len: size_t,
1274 ) -> ssize_t {
1275 if out_len > <ssize_t>::max_value() as usize {
1276 panic!("The provided buffer is too large");
1277 }
1278
1279 let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
1280
1281 let out_len = match conn.dgram_recv(out) {
1282 Ok(v) => v,
1283
1284 Err(e) => return e.to_c(),
1285 };
1286
1287 out_len as ssize_t
1288 }
1289
1290 #[no_mangle]
quiche_conn_dgram_purge_outgoing( conn: &mut Connection, f: extern fn(*const u8, size_t) -> bool, )1291 pub extern fn quiche_conn_dgram_purge_outgoing(
1292 conn: &mut Connection, f: extern fn(*const u8, size_t) -> bool,
1293 ) {
1294 conn.dgram_purge_outgoing(|d: &[u8]| -> bool {
1295 let ptr: *const u8 = d.as_ptr();
1296 let len: size_t = d.len();
1297
1298 f(ptr, len)
1299 });
1300 }
1301
1302 #[no_mangle]
quiche_conn_send_ack_eliciting(conn: &mut Connection) -> ssize_t1303 pub extern fn quiche_conn_send_ack_eliciting(conn: &mut Connection) -> ssize_t {
1304 match conn.send_ack_eliciting() {
1305 Ok(()) => 0,
1306 Err(e) => e.to_c(),
1307 }
1308 }
1309
1310 #[no_mangle]
quiche_conn_send_ack_eliciting_on_path( conn: &mut Connection, local: &sockaddr, local_len: socklen_t, peer: &sockaddr, peer_len: socklen_t, ) -> ssize_t1311 pub extern fn quiche_conn_send_ack_eliciting_on_path(
1312 conn: &mut Connection, local: &sockaddr, local_len: socklen_t,
1313 peer: &sockaddr, peer_len: socklen_t,
1314 ) -> ssize_t {
1315 let local = std_addr_from_c(local, local_len);
1316 let peer = std_addr_from_c(peer, peer_len);
1317 match conn.send_ack_eliciting_on_path(local, peer) {
1318 Ok(()) => 0,
1319 Err(e) => e.to_c(),
1320 }
1321 }
1322
1323 #[no_mangle]
quiche_conn_free(conn: *mut Connection)1324 pub extern fn quiche_conn_free(conn: *mut Connection) {
1325 unsafe { Box::from_raw(conn) };
1326 }
1327
1328 #[no_mangle]
quiche_conn_peer_streams_left_bidi(conn: &Connection) -> u641329 pub extern fn quiche_conn_peer_streams_left_bidi(conn: &Connection) -> u64 {
1330 conn.peer_streams_left_bidi()
1331 }
1332
1333 #[no_mangle]
quiche_conn_peer_streams_left_uni(conn: &Connection) -> u641334 pub extern fn quiche_conn_peer_streams_left_uni(conn: &Connection) -> u64 {
1335 conn.peer_streams_left_uni()
1336 }
1337
1338 #[no_mangle]
quiche_conn_send_quantum(conn: &Connection) -> size_t1339 pub extern fn quiche_conn_send_quantum(conn: &Connection) -> size_t {
1340 conn.send_quantum() as size_t
1341 }
1342
std_addr_from_c(addr: &sockaddr, addr_len: socklen_t) -> SocketAddr1343 fn std_addr_from_c(addr: &sockaddr, addr_len: socklen_t) -> SocketAddr {
1344 match addr.sa_family as i32 {
1345 AF_INET => {
1346 assert!(addr_len as usize == std::mem::size_of::<sockaddr_in>());
1347
1348 let in4 = unsafe { *(addr as *const _ as *const sockaddr_in) };
1349
1350 #[cfg(not(windows))]
1351 let ip_addr = Ipv4Addr::from(u32::from_be(in4.sin_addr.s_addr));
1352 #[cfg(windows)]
1353 let ip_addr = {
1354 let ip_bytes = unsafe { in4.sin_addr.S_un.S_un_b() };
1355
1356 Ipv4Addr::from([
1357 ip_bytes.s_b1,
1358 ip_bytes.s_b2,
1359 ip_bytes.s_b3,
1360 ip_bytes.s_b4,
1361 ])
1362 };
1363
1364 let port = u16::from_be(in4.sin_port);
1365
1366 let out = SocketAddrV4::new(ip_addr, port);
1367
1368 out.into()
1369 },
1370
1371 AF_INET6 => {
1372 assert!(addr_len as usize == std::mem::size_of::<sockaddr_in6>());
1373
1374 let in6 = unsafe { *(addr as *const _ as *const sockaddr_in6) };
1375
1376 let ip_addr = Ipv6Addr::from(
1377 #[cfg(not(windows))]
1378 in6.sin6_addr.s6_addr,
1379 #[cfg(windows)]
1380 *unsafe { in6.sin6_addr.u.Byte() },
1381 );
1382
1383 let port = u16::from_be(in6.sin6_port);
1384
1385 #[cfg(not(windows))]
1386 let scope_id = in6.sin6_scope_id;
1387 #[cfg(windows)]
1388 let scope_id = unsafe { *in6.u.sin6_scope_id() };
1389
1390 let out =
1391 SocketAddrV6::new(ip_addr, port, in6.sin6_flowinfo, scope_id);
1392
1393 out.into()
1394 },
1395
1396 _ => unimplemented!("unsupported address type"),
1397 }
1398 }
1399
std_addr_to_c(addr: &SocketAddr, out: &mut sockaddr_storage) -> socklen_t1400 fn std_addr_to_c(addr: &SocketAddr, out: &mut sockaddr_storage) -> socklen_t {
1401 let sin_port = addr.port().to_be();
1402
1403 match addr {
1404 SocketAddr::V4(addr) => unsafe {
1405 let sa_len = std::mem::size_of::<sockaddr_in>();
1406 let out_in = out as *mut _ as *mut sockaddr_in;
1407
1408 let s_addr = u32::from_ne_bytes(addr.ip().octets());
1409
1410 #[cfg(not(windows))]
1411 let sin_addr = in_addr { s_addr };
1412 #[cfg(windows)]
1413 let sin_addr = {
1414 let mut s_un = std::mem::zeroed::<in_addr_S_un>();
1415 *s_un.S_addr_mut() = s_addr;
1416 in_addr { S_un: s_un }
1417 };
1418
1419 *out_in = sockaddr_in {
1420 sin_family: AF_INET as sa_family_t,
1421
1422 sin_addr,
1423
1424 #[cfg(any(
1425 target_os = "macos",
1426 target_os = "ios",
1427 target_os = "watchos",
1428 target_os = "freebsd",
1429 target_os = "dragonfly",
1430 target_os = "openbsd",
1431 target_os = "netbsd"
1432 ))]
1433 sin_len: sa_len as u8,
1434
1435 sin_port,
1436
1437 sin_zero: std::mem::zeroed(),
1438 };
1439
1440 sa_len as socklen_t
1441 },
1442
1443 SocketAddr::V6(addr) => unsafe {
1444 let sa_len = std::mem::size_of::<sockaddr_in6>();
1445 let out_in6 = out as *mut _ as *mut sockaddr_in6;
1446
1447 #[cfg(not(windows))]
1448 let sin6_addr = in6_addr {
1449 s6_addr: addr.ip().octets(),
1450 };
1451 #[cfg(windows)]
1452 let sin6_addr = {
1453 let mut u = std::mem::zeroed::<in6_addr_u>();
1454 *u.Byte_mut() = addr.ip().octets();
1455 in6_addr { u }
1456 };
1457
1458 #[cfg(windows)]
1459 let u = {
1460 let mut u = std::mem::zeroed::<SOCKADDR_IN6_LH_u>();
1461 *u.sin6_scope_id_mut() = addr.scope_id();
1462 u
1463 };
1464
1465 *out_in6 = sockaddr_in6 {
1466 sin6_family: AF_INET6 as sa_family_t,
1467
1468 sin6_addr,
1469
1470 #[cfg(any(
1471 target_os = "macos",
1472 target_os = "ios",
1473 target_os = "watchos",
1474 target_os = "freebsd",
1475 target_os = "dragonfly",
1476 target_os = "openbsd",
1477 target_os = "netbsd"
1478 ))]
1479 sin6_len: sa_len as u8,
1480
1481 sin6_port: sin_port,
1482
1483 sin6_flowinfo: addr.flowinfo(),
1484
1485 #[cfg(not(windows))]
1486 sin6_scope_id: addr.scope_id(),
1487 #[cfg(windows)]
1488 u,
1489 };
1490
1491 sa_len as socklen_t
1492 },
1493 }
1494 }
1495
1496 #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))]
std_time_to_c(time: &std::time::Instant, out: &mut timespec)1497 fn std_time_to_c(time: &std::time::Instant, out: &mut timespec) {
1498 unsafe {
1499 ptr::copy_nonoverlapping(time as *const _ as *const timespec, out, 1)
1500 }
1501 }
1502
1503 #[cfg(any(target_os = "macos", target_os = "ios", target_os = "windows"))]
std_time_to_c(_time: &std::time::Instant, out: &mut timespec)1504 fn std_time_to_c(_time: &std::time::Instant, out: &mut timespec) {
1505 // TODO: implement Instant conversion for systems that don't use timespec.
1506 out.tv_sec = 0;
1507 out.tv_nsec = 0;
1508 }
1509
1510 #[cfg(test)]
1511 mod tests {
1512 use super::*;
1513
1514 #[cfg(windows)]
1515 use winapi::um::ws2tcpip::inet_ntop;
1516
1517 #[test]
addr_v4()1518 fn addr_v4() {
1519 let addr = "127.0.0.1:8080".parse().unwrap();
1520
1521 let mut out: sockaddr_storage = unsafe { std::mem::zeroed() };
1522
1523 assert_eq!(
1524 std_addr_to_c(&addr, &mut out),
1525 std::mem::size_of::<sockaddr_in>() as socklen_t
1526 );
1527
1528 let s = std::ffi::CString::new("ddd.ddd.ddd.ddd").unwrap();
1529
1530 let s = unsafe {
1531 let in_addr = &out as *const _ as *const sockaddr_in;
1532 assert_eq!(u16::from_be((*in_addr).sin_port), addr.port());
1533
1534 let dst = s.into_raw();
1535
1536 inet_ntop(
1537 AF_INET,
1538 &((*in_addr).sin_addr) as *const _ as *const c_void,
1539 dst,
1540 16,
1541 );
1542
1543 std::ffi::CString::from_raw(dst).into_string().unwrap()
1544 };
1545
1546 assert_eq!(s, "127.0.0.1");
1547
1548 let addr = unsafe {
1549 std_addr_from_c(
1550 &*(&out as *const _ as *const sockaddr),
1551 std::mem::size_of::<sockaddr_in>() as socklen_t,
1552 )
1553 };
1554
1555 assert_eq!(addr, "127.0.0.1:8080".parse().unwrap());
1556 }
1557
1558 #[test]
addr_v6()1559 fn addr_v6() {
1560 let addr = "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8080"
1561 .parse()
1562 .unwrap();
1563
1564 let mut out: sockaddr_storage = unsafe { std::mem::zeroed() };
1565
1566 assert_eq!(
1567 std_addr_to_c(&addr, &mut out),
1568 std::mem::size_of::<sockaddr_in6>() as socklen_t
1569 );
1570
1571 let s = std::ffi::CString::new("dddd:dddd:dddd:dddd:dddd:dddd:dddd:dddd")
1572 .unwrap();
1573
1574 let s = unsafe {
1575 let in6_addr = &out as *const _ as *const sockaddr_in6;
1576 assert_eq!(u16::from_be((*in6_addr).sin6_port), addr.port());
1577
1578 let dst = s.into_raw();
1579
1580 inet_ntop(
1581 AF_INET6,
1582 &((*in6_addr).sin6_addr) as *const _ as *const c_void,
1583 dst,
1584 45,
1585 );
1586
1587 std::ffi::CString::from_raw(dst).into_string().unwrap()
1588 };
1589
1590 assert_eq!(s, "2001:db8:85a3::8a2e:370:7334");
1591
1592 let addr = unsafe {
1593 std_addr_from_c(
1594 &*(&out as *const _ as *const sockaddr),
1595 std::mem::size_of::<sockaddr_in6>() as socklen_t,
1596 )
1597 };
1598
1599 assert_eq!(
1600 addr,
1601 "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8080"
1602 .parse()
1603 .unwrap()
1604 );
1605 }
1606
1607 #[cfg(not(windows))]
1608 extern {
inet_ntop( af: c_int, src: *const c_void, dst: *mut c_char, size: socklen_t, ) -> *mut c_char1609 fn inet_ntop(
1610 af: c_int, src: *const c_void, dst: *mut c_char, size: socklen_t,
1611 ) -> *mut c_char;
1612 }
1613 }
1614