1use std::ffi;
28use std::ptr;
29use std::slice;
30use std::sync::atomic;
31
32use std::net::Ipv4Addr;
33use std::net::Ipv6Addr;
34use std::net::SocketAddrV4;
35use std::net::SocketAddrV6;
36
37#[cfg(unix)]
38use std::os::unix::io::FromRawFd;
39
40use libc::c_char;
41use libc::c_int;
42use libc::c_void;
43use libc::size_t;
44use libc::sockaddr;
45use libc::ssize_t;
46use libc::timespec;
47
48#[cfg(not(windows))]
49use libc::AF_INET;
50#[cfg(windows)]
51use windows_sys::Win32::Networking::WinSock::AF_INET;
52
53#[cfg(not(windows))]
54use libc::AF_INET6;
55#[cfg(windows)]
56use windows_sys::Win32::Networking::WinSock::AF_INET6;
57
58#[cfg(not(windows))]
59use libc::in_addr;
60#[cfg(windows)]
61use windows_sys::Win32::Networking::WinSock::IN_ADDR as in_addr;
62
63#[cfg(not(windows))]
64use libc::in6_addr;
65#[cfg(windows)]
66use windows_sys::Win32::Networking::WinSock::IN6_ADDR as in6_addr;
67
68#[cfg(not(windows))]
69use libc::sa_family_t;
70#[cfg(windows)]
71use windows_sys::Win32::Networking::WinSock::ADDRESS_FAMILY as sa_family_t;
72
73#[cfg(not(windows))]
74use libc::sockaddr_in;
75#[cfg(windows)]
76use windows_sys::Win32::Networking::WinSock::SOCKADDR_IN as sockaddr_in;
77
78#[cfg(not(windows))]
79use libc::sockaddr_in6;
80#[cfg(windows)]
81use windows_sys::Win32::Networking::WinSock::SOCKADDR_IN6 as sockaddr_in6;
82
83#[cfg(not(windows))]
84use libc::sockaddr_storage;
85#[cfg(windows)]
86use windows_sys::Win32::Networking::WinSock::SOCKADDR_STORAGE as sockaddr_storage;
87
88#[cfg(windows)]
89use libc::c_int as socklen_t;
90#[cfg(not(windows))]
91use libc::socklen_t;
92
93#[cfg(windows)]
94use windows_sys::Win32::Networking::WinSock::IN6_ADDR_0;
95#[cfg(windows)]
96use windows_sys::Win32::Networking::WinSock::IN_ADDR_0;
97#[cfg(windows)]
98use windows_sys::Win32::Networking::WinSock::SOCKADDR_IN6_0;
99
100use crate::*;
101
102#[no_mangle]
103pub extern "C" fn quiche_version() -> *const u8 {
104 static VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), "\0");
105 VERSION.as_ptr()
106}
107
108struct Logger {
109 cb: extern "C" fn(line: *const u8, argp: *mut c_void),
110 argp: atomic::AtomicPtr<c_void>,
111}
112
113impl log::Log for Logger {
114 fn enabled(&self, _metadata: &log::Metadata) -> bool {
115 true
116 }
117
118 fn log(&self, record: &log::Record) {
119 let line = format!("{}: {}\0", record.target(), record.args());
120 (self.cb)(line.as_ptr(), self.argp.load(atomic::Ordering::Relaxed));
121 }
122
123 fn flush(&self) {}
124}
125
126#[no_mangle]
127pub extern "C" fn quiche_enable_debug_logging(
128 cb: extern "C" fn(line: *const u8, argp: *mut c_void), argp: *mut c_void,
129) -> c_int {
130 let argp = atomic::AtomicPtr::new(argp);
131 let logger = Box::new(Logger { cb, argp });
132
133 if log::set_boxed_logger(logger).is_err() {
134 return -1;
135 }
136
137 log::set_max_level(log::LevelFilter::Trace);
138
139 0
140}
141
142#[no_mangle]
143pub extern "C" fn quiche_config_new(version: u32) -> *mut Config {
144 match Config::new(version) {
145 Ok(c) => Box::into_raw(Box::new(c)),
146
147 Err(_) => ptr::null_mut(),
148 }
149}
150
151#[no_mangle]
152pub extern "C" fn quiche_config_load_cert_chain_from_pem_file(
153 config: &mut Config, path: *const c_char,
154) -> c_int {
155 let path = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
156
157 match config.load_cert_chain_from_pem_file(path) {
158 Ok(_) => 0,
159
160 Err(e) => e.to_c() as c_int,
161 }
162}
163
164#[no_mangle]
165pub extern "C" fn quiche_config_load_priv_key_from_pem_file(
166 config: &mut Config, path: *const c_char,
167) -> c_int {
168 let path = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
169
170 match config.load_priv_key_from_pem_file(path) {
171 Ok(_) => 0,
172
173 Err(e) => e.to_c() as c_int,
174 }
175}
176
177#[no_mangle]
178pub extern "C" fn quiche_config_load_verify_locations_from_file(
179 config: &mut Config, path: *const c_char,
180) -> c_int {
181 let path = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
182
183 match config.load_verify_locations_from_file(path) {
184 Ok(_) => 0,
185
186 Err(e) => e.to_c() as c_int,
187 }
188}
189
190#[no_mangle]
191pub extern "C" fn quiche_config_load_verify_locations_from_directory(
192 config: &mut Config, path: *const c_char,
193) -> c_int {
194 let path = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
195
196 match config.load_verify_locations_from_directory(path) {
197 Ok(_) => 0,
198
199 Err(e) => e.to_c() as c_int,
200 }
201}
202
203#[no_mangle]
204pub extern "C" fn quiche_config_set_curves_list(
205 config: &mut Config, curves: *const c_char,
206) -> c_int {
207 let curves = unsafe { ffi::CStr::from_ptr(curves).to_str().unwrap() };
208
209 match config.set_curves_list(curves) {
210 Ok(_) => 0,
211
212 Err(e) => e.to_c() as c_int,
213 }
214}
215
216#[no_mangle]
217pub extern "C" fn quiche_config_verify_peer(config: &mut Config, v: bool) {
218 config.verify_peer(v);
219}
220
221#[no_mangle]
222pub extern "C" fn quiche_config_grease(config: &mut Config, v: bool) {
223 config.grease(v);
224}
225
226#[no_mangle]
227pub extern "C" fn quiche_config_discover_pmtu(config: &mut Config, v: bool) {
228 config.discover_pmtu(v);
229}
230
231#[no_mangle]
232pub extern "C" fn quiche_config_set_pmtud_max_probes(
233 config: &mut Config, max_probes: u8,
234) {
235 config.set_pmtud_max_probes(max_probes);
236}
237
238#[no_mangle]
239pub extern "C" fn quiche_config_log_keys(config: &mut Config) {
240 config.log_keys();
241}
242
243#[no_mangle]
244pub extern "C" fn quiche_config_enable_early_data(config: &mut Config) {
245 config.enable_early_data();
246}
247
248#[no_mangle]
249pub extern "C" fn quiche_config_set_application_protos(
252 config: &mut Config, protos: *const u8, protos_len: size_t,
253) -> c_int {
254 let protos = unsafe { slice::from_raw_parts(protos, protos_len) };
255
256 match config.set_application_protos_wire_format(protos) {
257 Ok(_) => 0,
258
259 Err(e) => e.to_c() as c_int,
260 }
261}
262
263#[no_mangle]
264pub extern "C" fn quiche_config_set_max_amplification_factor(
265 config: &mut Config, v: usize,
266) {
267 config.set_max_amplification_factor(v);
268}
269
270#[no_mangle]
271pub extern "C" fn quiche_config_set_max_idle_timeout(
272 config: &mut Config, v: u64,
273) {
274 config.set_max_idle_timeout(v);
275}
276
277#[no_mangle]
278pub extern "C" fn quiche_config_set_max_recv_udp_payload_size(
279 config: &mut Config, v: size_t,
280) {
281 config.set_max_recv_udp_payload_size(v);
282}
283
284#[no_mangle]
285pub extern "C" fn quiche_config_set_initial_max_data(
286 config: &mut Config, v: u64,
287) {
288 config.set_initial_max_data(v);
289}
290
291#[no_mangle]
292pub extern "C" fn quiche_config_set_initial_max_stream_data_bidi_local(
293 config: &mut Config, v: u64,
294) {
295 config.set_initial_max_stream_data_bidi_local(v);
296}
297
298#[no_mangle]
299pub extern "C" fn quiche_config_set_initial_max_stream_data_bidi_remote(
300 config: &mut Config, v: u64,
301) {
302 config.set_initial_max_stream_data_bidi_remote(v);
303}
304
305#[no_mangle]
306pub extern "C" fn quiche_config_set_initial_max_stream_data_uni(
307 config: &mut Config, v: u64,
308) {
309 config.set_initial_max_stream_data_uni(v);
310}
311
312#[no_mangle]
313pub extern "C" fn quiche_config_set_initial_max_streams_bidi(
314 config: &mut Config, v: u64,
315) {
316 config.set_initial_max_streams_bidi(v);
317}
318
319#[no_mangle]
320pub extern "C" fn quiche_config_set_initial_max_streams_uni(
321 config: &mut Config, v: u64,
322) {
323 config.set_initial_max_streams_uni(v);
324}
325
326#[no_mangle]
327pub extern "C" fn quiche_config_set_ack_delay_exponent(
328 config: &mut Config, v: u64,
329) {
330 config.set_ack_delay_exponent(v);
331}
332
333#[no_mangle]
334pub extern "C" fn quiche_config_set_max_ack_delay(config: &mut Config, v: u64) {
335 config.set_max_ack_delay(v);
336}
337
338#[no_mangle]
339pub extern "C" fn quiche_config_set_disable_active_migration(
340 config: &mut Config, v: bool,
341) {
342 config.set_disable_active_migration(v);
343}
344
345#[no_mangle]
346pub extern "C" fn quiche_config_set_cc_algorithm_name(
347 config: &mut Config, name: *const c_char,
348) -> c_int {
349 let name = unsafe { ffi::CStr::from_ptr(name).to_str().unwrap() };
350 match config.set_cc_algorithm_name(name) {
351 Ok(_) => 0,
352
353 Err(e) => e.to_c() as c_int,
354 }
355}
356
357#[no_mangle]
358pub extern "C" fn quiche_config_set_cc_algorithm(
359 config: &mut Config, algo: CongestionControlAlgorithm,
360) {
361 config.set_cc_algorithm(algo);
362}
363
364#[no_mangle]
365pub extern "C" fn quiche_config_set_initial_congestion_window_packets(
366 config: &mut Config, packets: size_t,
367) {
368 config.set_initial_congestion_window_packets(packets);
369}
370
371#[no_mangle]
372pub extern "C" fn quiche_config_enable_hystart(config: &mut Config, v: bool) {
373 config.enable_hystart(v);
374}
375
376#[no_mangle]
377pub extern "C" fn quiche_config_enable_pacing(config: &mut Config, v: bool) {
378 config.enable_pacing(v);
379}
380
381#[no_mangle]
382pub extern "C" fn quiche_config_set_enable_cubic_idle_restart_fix(
383 config: &mut Config, v: bool,
384) {
385 config.set_enable_cubic_idle_restart_fix(v);
386}
387
388#[no_mangle]
390pub extern "C" fn quiche_config_set_use_initial_max_data_as_flow_control_win(
391 _config: &mut Config, _v: bool,
392) {
393}
394
395#[no_mangle]
396pub extern "C" fn quiche_config_set_max_pacing_rate(config: &mut Config, v: u64) {
397 config.set_max_pacing_rate(v);
398}
399
400#[no_mangle]
401pub extern "C" fn quiche_config_enable_dgram(
402 config: &mut Config, enabled: bool, recv_queue_len: size_t,
403 send_queue_len: size_t,
404) {
405 config.enable_dgram(enabled, recv_queue_len, send_queue_len);
406}
407
408#[no_mangle]
409pub extern "C" fn quiche_config_set_max_send_udp_payload_size(
410 config: &mut Config, v: size_t,
411) {
412 config.set_max_send_udp_payload_size(v);
413}
414
415#[no_mangle]
416pub extern "C" fn quiche_config_set_max_connection_window(
417 config: &mut Config, v: u64,
418) {
419 config.set_max_connection_window(v);
420}
421
422#[no_mangle]
423pub extern "C" fn quiche_config_set_max_stream_window(
424 config: &mut Config, v: u64,
425) {
426 config.set_max_stream_window(v);
427}
428
429#[no_mangle]
430pub extern "C" fn quiche_config_set_active_connection_id_limit(
431 config: &mut Config, v: u64,
432) {
433 config.set_active_connection_id_limit(v);
434}
435
436#[no_mangle]
437pub extern "C" fn quiche_config_set_stateless_reset_token(
438 config: &mut Config, v: *const u8,
439) {
440 let reset_token = unsafe { slice::from_raw_parts(v, 16) };
441 let reset_token = match reset_token.try_into() {
442 Ok(rt) => rt,
443 Err(_) => unreachable!(),
444 };
445 let reset_token = u128::from_be_bytes(reset_token);
446 config.set_stateless_reset_token(Some(reset_token));
447}
448
449#[no_mangle]
450pub extern "C" fn quiche_config_set_disable_dcid_reuse(
451 config: &mut Config, v: bool,
452) {
453 config.set_disable_dcid_reuse(v);
454}
455
456#[no_mangle]
457pub extern "C" fn quiche_config_set_ticket_key(
458 config: &mut Config, key: *const u8, key_len: size_t,
459) -> c_int {
460 let key = unsafe { slice::from_raw_parts(key, key_len) };
461
462 match config.set_ticket_key(key) {
463 Ok(_) => 0,
464
465 Err(e) => e.to_c() as c_int,
466 }
467}
468
469#[no_mangle]
470pub extern "C" fn quiche_config_free(config: *mut Config) {
471 if !config.is_null() {
472 drop(unsafe { Box::from_raw(config) });
473 }
474}
475
476#[no_mangle]
477pub extern "C" fn quiche_header_info(
478 buf: *mut u8, buf_len: size_t, dcil: size_t, version: *mut u32, ty: *mut u8,
479 scid: *mut u8, scid_len: *mut size_t, dcid: *mut u8, dcid_len: *mut size_t,
480 token: *mut u8, token_len: *mut size_t,
481) -> c_int {
482 let buf = unsafe { slice::from_raw_parts_mut(buf, buf_len) };
483 let hdr = match Header::from_slice(buf, dcil) {
484 Ok(v) => v,
485
486 Err(e) => return e.to_c() as c_int,
487 };
488
489 unsafe {
490 *version = hdr.version;
491
492 *ty = match hdr.ty {
493 Type::Initial => 1,
494 Type::Retry => 2,
495 Type::Handshake => 3,
496 Type::ZeroRTT => 4,
497 Type::Short => 5,
498 Type::VersionNegotiation => 6,
499 };
500
501 if *scid_len < hdr.scid.len() {
502 return -1;
503 }
504
505 let scid = slice::from_raw_parts_mut(scid, *scid_len);
506 let scid = &mut scid[..hdr.scid.len()];
507 scid.copy_from_slice(&hdr.scid);
508
509 *scid_len = hdr.scid.len();
510
511 if *dcid_len < hdr.dcid.len() {
512 return -1;
513 }
514
515 let dcid = slice::from_raw_parts_mut(dcid, *dcid_len);
516 let dcid = &mut dcid[..hdr.dcid.len()];
517 dcid.copy_from_slice(&hdr.dcid);
518
519 *dcid_len = hdr.dcid.len();
520
521 match hdr.token {
522 Some(tok) => {
523 if *token_len < tok.len() {
524 return -1;
525 }
526
527 let token = slice::from_raw_parts_mut(token, *token_len);
528 let token = &mut token[..tok.len()];
529 token.copy_from_slice(&tok);
530
531 *token_len = tok.len();
532 },
533
534 None => *token_len = 0,
535 }
536 }
537
538 0
539}
540
541#[no_mangle]
542pub extern "C" fn quiche_accept(
543 scid: *const u8, scid_len: size_t, odcid: *const u8, odcid_len: size_t,
544 local: &sockaddr, local_len: socklen_t, peer: &sockaddr, peer_len: socklen_t,
545 config: &mut Config,
546) -> *mut Connection {
547 let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
548 let scid = ConnectionId::from_ref(scid);
549
550 let odcid = if !odcid.is_null() && odcid_len > 0 {
551 Some(ConnectionId::from_ref(unsafe {
552 slice::from_raw_parts(odcid, odcid_len)
553 }))
554 } else {
555 None
556 };
557
558 let local = std_addr_from_c(local, local_len);
559 let peer = std_addr_from_c(peer, peer_len);
560
561 match accept(&scid, odcid.as_ref(), local, peer, config) {
562 Ok(c) => Box::into_raw(Box::new(c)),
563
564 Err(_) => ptr::null_mut(),
565 }
566}
567
568#[no_mangle]
569pub extern "C" fn quiche_connect(
570 server_name: *const c_char, scid: *const u8, scid_len: size_t,
571 local: &sockaddr, local_len: socklen_t, peer: &sockaddr, peer_len: socklen_t,
572 config: &mut Config,
573) -> *mut Connection {
574 let server_name = if server_name.is_null() {
575 None
576 } else {
577 Some(unsafe { ffi::CStr::from_ptr(server_name).to_str().unwrap() })
578 };
579
580 let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
581 let scid = ConnectionId::from_ref(scid);
582
583 let local = std_addr_from_c(local, local_len);
584 let peer = std_addr_from_c(peer, peer_len);
585
586 match connect(server_name, &scid, local, peer, config) {
587 Ok(c) => Box::into_raw(Box::new(c)),
588
589 Err(_) => ptr::null_mut(),
590 }
591}
592
593#[no_mangle]
594pub extern "C" fn quiche_negotiate_version(
595 scid: *const u8, scid_len: size_t, dcid: *const u8, dcid_len: size_t,
596 out: *mut u8, out_len: size_t,
597) -> ssize_t {
598 let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
599 let scid = ConnectionId::from_ref(scid);
600
601 let dcid = unsafe { slice::from_raw_parts(dcid, dcid_len) };
602 let dcid = ConnectionId::from_ref(dcid);
603
604 let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
605
606 match negotiate_version(&scid, &dcid, out) {
607 Ok(v) => v as ssize_t,
608
609 Err(e) => e.to_c(),
610 }
611}
612
613#[no_mangle]
614pub extern "C" fn quiche_version_is_supported(version: u32) -> bool {
615 version_is_supported(version)
616}
617
618#[no_mangle]
619pub extern "C" fn quiche_retry(
620 scid: *const u8, scid_len: size_t, dcid: *const u8, dcid_len: size_t,
621 new_scid: *const u8, new_scid_len: size_t, token: *const u8,
622 token_len: size_t, version: u32, out: *mut u8, out_len: size_t,
623) -> ssize_t {
624 let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
625 let scid = ConnectionId::from_ref(scid);
626
627 let dcid = unsafe { slice::from_raw_parts(dcid, dcid_len) };
628 let dcid = ConnectionId::from_ref(dcid);
629
630 let new_scid = unsafe { slice::from_raw_parts(new_scid, new_scid_len) };
631 let new_scid = ConnectionId::from_ref(new_scid);
632
633 let token = unsafe { slice::from_raw_parts(token, token_len) };
634 let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
635
636 match retry(&scid, &dcid, &new_scid, token, version, out) {
637 Ok(v) => v as ssize_t,
638
639 Err(e) => e.to_c(),
640 }
641}
642
643#[no_mangle]
644#[cfg(feature = "custom-client-dcid")]
645pub extern "C" fn quiche_conn_new_with_tls_and_client_dcid(
646 scid: *const u8, scid_len: size_t, dcid: *const u8, dcid_len: size_t,
647 local: &sockaddr, local_len: socklen_t, peer: &sockaddr, peer_len: socklen_t,
648 config: &Config, ssl: *mut c_void,
649) -> *mut Connection {
650 {
651 let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
652 let scid = ConnectionId::from_ref(scid);
653
654 let dcid = if !dcid.is_null() && dcid_len > 0 {
655 Some(ConnectionId::from_ref(unsafe {
656 slice::from_raw_parts(dcid, dcid_len)
657 }))
658 } else {
659 None
660 };
661
662 let local = std_addr_from_c(local, local_len);
663 let peer = std_addr_from_c(peer, peer_len);
664
665 let tls = match unsafe { tls::Handshake::from_ptr(ssl) } {
666 Ok(v) => v,
667
668 Err(_) => return ptr::null_mut(),
669 };
670
671 match Connection::with_tls(
672 &scid,
673 None, dcid.as_ref(),
675 local,
676 peer,
677 config,
678 tls,
679 false,
680 ) {
681 Ok(c) => Box::into_raw(Box::new(c)),
682
683 Err(_) => ptr::null_mut(),
684 }
685 }
686}
687
688#[no_mangle]
689#[cfg(not(feature = "custom-client-dcid"))]
690#[allow(unused_variables)]
691pub extern "C" fn quiche_conn_new_with_tls_and_client_dcid(
692 scid: *const u8, scid_len: size_t, dcid: *const u8, dcid_len: size_t,
693 local: &sockaddr, local_len: socklen_t, peer: &sockaddr, peer_len: socklen_t,
694 config: &Config, ssl: *mut c_void,
695) -> *mut Connection {
696 ptr::null_mut()
699}
700
701#[no_mangle]
702pub extern "C" fn quiche_conn_new_with_tls(
703 scid: *const u8, scid_len: size_t, odcid: *const u8, odcid_len: size_t,
704 local: &sockaddr, local_len: socklen_t, peer: &sockaddr, peer_len: socklen_t,
705 config: &Config, ssl: *mut c_void, is_server: bool,
706) -> *mut Connection {
707 let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
708 let scid = ConnectionId::from_ref(scid);
709
710 let odcid = if !odcid.is_null() && odcid_len > 0 {
711 Some(ConnectionId::from_ref(unsafe {
712 slice::from_raw_parts(odcid, odcid_len)
713 }))
714 } else {
715 None
716 };
717
718 let retry_cids = odcid.as_ref().map(|odcid| RetryConnectionIds {
719 original_destination_cid: odcid,
720 retry_source_cid: &scid,
721 });
722
723 let local = std_addr_from_c(local, local_len);
724 let peer = std_addr_from_c(peer, peer_len);
725
726 let tls = match unsafe { tls::Handshake::from_ptr(ssl) } {
727 Ok(v) => v,
728
729 Err(_) => return ptr::null_mut(),
730 };
731
732 match Connection::with_tls(
733 &scid, retry_cids, None, local, peer, config, tls, is_server,
734 ) {
735 Ok(c) => Box::into_raw(Box::new(c)),
736
737 Err(_) => ptr::null_mut(),
738 }
739}
740
741#[no_mangle]
742pub extern "C" fn quiche_conn_set_keylog_path(
743 conn: &mut Connection, path: *const c_char,
744) -> bool {
745 let filename = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
746
747 let file = std::fs::OpenOptions::new()
748 .create(true)
749 .append(true)
750 .open(filename);
751
752 let writer = match file {
753 Ok(f) => std::io::BufWriter::new(f),
754
755 Err(_) => return false,
756 };
757
758 conn.set_keylog(Box::new(writer));
759
760 true
761}
762
763#[no_mangle]
764#[cfg(unix)]
765pub extern "C" fn quiche_conn_set_keylog_fd(conn: &mut Connection, fd: c_int) {
766 let f = unsafe { std::fs::File::from_raw_fd(fd) };
767 let writer = std::io::BufWriter::new(f);
768
769 conn.set_keylog(Box::new(writer));
770}
771
772#[no_mangle]
773#[cfg(feature = "qlog")]
774pub extern "C" fn quiche_conn_set_qlog_path(
775 conn: &mut Connection, path: *const c_char, log_title: *const c_char,
776 log_desc: *const c_char,
777) -> bool {
778 let filename = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
779
780 let file = std::fs::OpenOptions::new()
781 .write(true)
782 .create_new(true)
783 .open(filename);
784
785 let writer = match file {
786 Ok(f) => std::io::BufWriter::new(f),
787
788 Err(_) => return false,
789 };
790
791 let title = unsafe { ffi::CStr::from_ptr(log_title).to_str().unwrap() };
792 let description = unsafe { ffi::CStr::from_ptr(log_desc).to_str().unwrap() };
793
794 conn.set_qlog(
795 Box::new(writer),
796 title.to_string(),
797 format!("{} id={}", description, conn.trace_id),
798 );
799
800 true
801}
802
803#[no_mangle]
804#[cfg(all(unix, feature = "qlog"))]
805pub extern "C" fn quiche_conn_set_qlog_fd(
806 conn: &mut Connection, fd: c_int, log_title: *const c_char,
807 log_desc: *const c_char,
808) {
809 let f = unsafe { std::fs::File::from_raw_fd(fd) };
810 let writer = std::io::BufWriter::new(f);
811
812 let title = unsafe { ffi::CStr::from_ptr(log_title).to_str().unwrap() };
813 let description = unsafe { ffi::CStr::from_ptr(log_desc).to_str().unwrap() };
814
815 conn.set_qlog(
816 Box::new(writer),
817 title.to_string(),
818 format!("{} id={}", description, conn.trace_id),
819 );
820}
821
822#[no_mangle]
823pub extern "C" fn quiche_conn_set_session(
824 conn: &mut Connection, buf: *const u8, buf_len: size_t,
825) -> c_int {
826 let buf = unsafe { slice::from_raw_parts(buf, buf_len) };
827
828 match conn.set_session(buf) {
829 Ok(_) => 0,
830
831 Err(e) => e.to_c() as c_int,
832 }
833}
834
835#[no_mangle]
836pub extern "C" fn quiche_conn_set_max_idle_timeout(
837 conn: &mut Connection, v: u64,
838) -> c_int {
839 match conn.set_max_idle_timeout(v) {
840 Ok(()) => 0,
841
842 Err(e) => e.to_c() as c_int,
843 }
844}
845
846#[repr(C)]
847pub struct RecvInfo<'a> {
848 from: &'a sockaddr,
849 from_len: socklen_t,
850 to: &'a sockaddr,
851 to_len: socklen_t,
852}
853
854impl From<&RecvInfo<'_>> for crate::RecvInfo {
855 fn from(info: &RecvInfo) -> crate::RecvInfo {
856 crate::RecvInfo {
857 from: std_addr_from_c(info.from, info.from_len),
858 to: std_addr_from_c(info.to, info.to_len),
859 }
860 }
861}
862
863#[no_mangle]
864pub extern "C" fn quiche_conn_recv(
865 conn: &mut Connection, buf: *mut u8, buf_len: size_t, info: &RecvInfo,
866) -> ssize_t {
867 if buf_len > <ssize_t>::MAX as usize {
868 panic!("The provided buffer is too large");
869 }
870
871 let buf = unsafe { slice::from_raw_parts_mut(buf, buf_len) };
872
873 match conn.recv(buf, info.into()) {
874 Ok(v) => v as ssize_t,
875
876 Err(e) => e.to_c(),
877 }
878}
879
880#[repr(C)]
881pub struct SendInfo {
882 from: sockaddr_storage,
883 from_len: socklen_t,
884 to: sockaddr_storage,
885 to_len: socklen_t,
886
887 at: timespec,
888}
889
890#[no_mangle]
891pub extern "C" fn quiche_conn_send(
892 conn: &mut Connection, out: *mut u8, out_len: size_t, out_info: &mut SendInfo,
893) -> ssize_t {
894 if out_len > <ssize_t>::MAX as usize {
895 panic!("The provided buffer is too large");
896 }
897
898 let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
899
900 match conn.send(out) {
901 Ok((v, info)) => {
902 out_info.from_len = std_addr_to_c(&info.from, &mut out_info.from);
903 out_info.to_len = std_addr_to_c(&info.to, &mut out_info.to);
904
905 std_time_to_c(&info.at, &mut out_info.at);
906
907 v as ssize_t
908 },
909
910 Err(e) => e.to_c(),
911 }
912}
913
914#[no_mangle]
915pub extern "C" fn quiche_conn_send_on_path(
916 conn: &mut Connection, out: *mut u8, out_len: size_t, from: *const sockaddr,
917 from_len: socklen_t, to: *const sockaddr, to_len: socklen_t,
918 out_info: &mut SendInfo,
919) -> ssize_t {
920 if out_len > <ssize_t>::MAX as usize {
921 panic!("The provided buffer is too large");
922 }
923
924 let from = optional_std_addr_from_c(from, from_len);
925 let to = optional_std_addr_from_c(to, to_len);
926 let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
927
928 match conn.send_on_path(out, from, to) {
929 Ok((v, info)) => {
930 out_info.from_len = std_addr_to_c(&info.from, &mut out_info.from);
931 out_info.to_len = std_addr_to_c(&info.to, &mut out_info.to);
932
933 std_time_to_c(&info.at, &mut out_info.at);
934
935 v as ssize_t
936 },
937
938 Err(e) => e.to_c(),
939 }
940}
941
942#[no_mangle]
943pub extern "C" fn quiche_conn_stream_recv(
944 conn: &mut Connection, stream_id: u64, out: *mut u8, out_len: size_t,
945 fin: &mut bool, out_error_code: &mut u64,
946) -> ssize_t {
947 if out_len > <ssize_t>::MAX as usize {
948 panic!("The provided buffer is too large");
949 }
950
951 let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
952
953 let (out_len, out_fin) = match conn.stream_recv(stream_id, out) {
954 Ok(v) => v,
955
956 Err(e) => {
957 match e {
958 Error::StreamReset(error) => *out_error_code = error,
959 Error::StreamStopped(error) => *out_error_code = error,
960 _ => {},
961 }
962 return e.to_c();
963 },
964 };
965
966 *fin = out_fin;
967
968 out_len as ssize_t
969}
970
971#[no_mangle]
972pub extern "C" fn quiche_conn_stream_send(
973 conn: &mut Connection, stream_id: u64, buf: *const u8, buf_len: size_t,
974 fin: bool, out_error_code: &mut u64,
975) -> ssize_t {
976 if buf_len > <ssize_t>::MAX as usize {
977 panic!("The provided buffer is too large");
978 }
979
980 let buf = if buf.is_null() {
981 assert_eq!(buf_len, 0);
982 &[]
983 } else {
984 unsafe { slice::from_raw_parts(buf, buf_len) }
985 };
986
987 match conn.stream_send(stream_id, buf, fin) {
988 Ok(v) => v as ssize_t,
989
990 Err(e) => {
991 match e {
992 Error::StreamReset(error) => *out_error_code = error,
993 Error::StreamStopped(error) => *out_error_code = error,
994 _ => {},
995 }
996 e.to_c()
997 },
998 }
999}
1000
1001#[no_mangle]
1002pub extern "C" fn quiche_conn_stream_priority(
1003 conn: &mut Connection, stream_id: u64, urgency: u8, incremental: bool,
1004) -> c_int {
1005 match conn.stream_priority(stream_id, urgency, incremental) {
1006 Ok(_) => 0,
1007
1008 Err(e) => e.to_c() as c_int,
1009 }
1010}
1011
1012#[no_mangle]
1013pub extern "C" fn quiche_conn_stream_shutdown(
1014 conn: &mut Connection, stream_id: u64, direction: Shutdown, err: u64,
1015) -> c_int {
1016 match conn.stream_shutdown(stream_id, direction, err) {
1017 Ok(_) => 0,
1018
1019 Err(e) => e.to_c() as c_int,
1020 }
1021}
1022
1023#[no_mangle]
1024pub extern "C" fn quiche_conn_stream_capacity(
1025 conn: &mut Connection, stream_id: u64,
1026) -> ssize_t {
1027 match conn.stream_capacity(stream_id) {
1028 Ok(v) => v as ssize_t,
1029
1030 Err(e) => e.to_c(),
1031 }
1032}
1033
1034#[no_mangle]
1035pub extern "C" fn quiche_conn_stream_readable(
1036 conn: &Connection, stream_id: u64,
1037) -> bool {
1038 conn.stream_readable(stream_id)
1039}
1040
1041#[no_mangle]
1042pub extern "C" fn quiche_conn_stream_readable_next(conn: &mut Connection) -> i64 {
1043 conn.stream_readable_next().map(|v| v as i64).unwrap_or(-1)
1044}
1045
1046#[no_mangle]
1047pub extern "C" fn quiche_conn_stream_writable(
1048 conn: &mut Connection, stream_id: u64, len: usize,
1049) -> c_int {
1050 match conn.stream_writable(stream_id, len) {
1051 Ok(true) => 1,
1052
1053 Ok(false) => 0,
1054
1055 Err(e) => e.to_c() as c_int,
1056 }
1057}
1058
1059#[no_mangle]
1060pub extern "C" fn quiche_conn_stream_writable_next(conn: &mut Connection) -> i64 {
1061 conn.stream_writable_next().map(|v| v as i64).unwrap_or(-1)
1062}
1063
1064#[no_mangle]
1065pub extern "C" fn quiche_conn_stream_finished(
1066 conn: &Connection, stream_id: u64,
1067) -> bool {
1068 conn.stream_finished(stream_id)
1069}
1070
1071#[no_mangle]
1072pub extern "C" fn quiche_conn_readable(conn: &Connection) -> *mut StreamIter {
1073 Box::into_raw(Box::new(conn.readable()))
1074}
1075
1076#[no_mangle]
1077pub extern "C" fn quiche_conn_writable(conn: &Connection) -> *mut StreamIter {
1078 Box::into_raw(Box::new(conn.writable()))
1079}
1080
1081#[no_mangle]
1082pub extern "C" fn quiche_conn_max_send_udp_payload_size(
1083 conn: &Connection,
1084) -> usize {
1085 conn.max_send_udp_payload_size()
1086}
1087
1088#[no_mangle]
1089pub extern "C" fn quiche_conn_is_readable(conn: &Connection) -> bool {
1090 conn.is_readable()
1091}
1092
1093#[no_mangle]
1094pub extern "C" fn quiche_conn_close(
1095 conn: &mut Connection, app: bool, err: u64, reason: *const u8,
1096 reason_len: size_t,
1097) -> c_int {
1098 let reason = if reason.is_null() {
1099 assert_eq!(reason_len, 0);
1100 &[]
1101 } else {
1102 unsafe { slice::from_raw_parts(reason, reason_len) }
1103 };
1104
1105 match conn.close(app, err, reason) {
1106 Ok(_) => 0,
1107
1108 Err(e) => e.to_c() as c_int,
1109 }
1110}
1111
1112#[no_mangle]
1113pub extern "C" fn quiche_conn_timeout_as_nanos(conn: &Connection) -> u64 {
1114 match conn.timeout() {
1115 Some(timeout) => timeout.as_nanos() as u64,
1116
1117 None => u64::MAX,
1118 }
1119}
1120
1121#[no_mangle]
1122pub extern "C" fn quiche_conn_timeout_as_millis(conn: &Connection) -> u64 {
1123 match conn.timeout() {
1124 Some(timeout) => timeout.as_millis() as u64,
1125
1126 None => u64::MAX,
1127 }
1128}
1129
1130#[no_mangle]
1131pub extern "C" fn quiche_conn_on_timeout(conn: &mut Connection) {
1132 conn.on_timeout()
1133}
1134
1135#[no_mangle]
1136pub extern "C" fn quiche_conn_trace_id(
1137 conn: &Connection, out: &mut *const u8, out_len: &mut size_t,
1138) {
1139 let trace_id = conn.trace_id();
1140
1141 *out = trace_id.as_ptr();
1142 *out_len = trace_id.len();
1143}
1144
1145#[derive(Default)]
1147pub struct ConnectionIdIter<'a> {
1148 cids: Vec<ConnectionId<'a>>,
1149 index: usize,
1150}
1151
1152#[no_mangle]
1153pub extern "C" fn quiche_conn_source_ids(
1154 conn: &Connection,
1155) -> *mut ConnectionIdIter<'_> {
1156 let vec = conn.source_ids().cloned().collect();
1157 Box::into_raw(Box::new(ConnectionIdIter {
1158 cids: vec,
1159 index: 0,
1160 }))
1161}
1162
1163#[no_mangle]
1164pub extern "C" fn quiche_connection_id_iter_next(
1165 iter: &mut ConnectionIdIter, out: &mut *const u8, out_len: &mut size_t,
1166) -> bool {
1167 if let Some(conn_id) = iter.cids.get(iter.index) {
1168 let id = conn_id.as_ref();
1169 *out = id.as_ptr();
1170 *out_len = id.len();
1171 iter.index += 1;
1172 return true;
1173 }
1174
1175 false
1176}
1177
1178#[no_mangle]
1179pub extern "C" fn quiche_connection_id_iter_free(iter: *mut ConnectionIdIter) {
1180 if !iter.is_null() {
1181 drop(unsafe { Box::from_raw(iter) });
1182 }
1183}
1184
1185#[no_mangle]
1186pub extern "C" fn quiche_conn_source_id(
1187 conn: &Connection, out: &mut *const u8, out_len: &mut size_t,
1188) {
1189 let conn_id = conn.source_id();
1190 let id = conn_id.as_ref();
1191 *out = id.as_ptr();
1192 *out_len = id.len();
1193}
1194
1195#[no_mangle]
1196pub extern "C" fn quiche_conn_destination_id(
1197 conn: &Connection, out: &mut *const u8, out_len: &mut size_t,
1198) {
1199 let conn_id = conn.destination_id();
1200 let id = conn_id.as_ref();
1201
1202 *out = id.as_ptr();
1203 *out_len = id.len();
1204}
1205
1206#[no_mangle]
1207pub extern "C" fn quiche_conn_application_proto(
1208 conn: &Connection, out: &mut *const u8, out_len: &mut size_t,
1209) {
1210 let proto = conn.application_proto();
1211
1212 *out = proto.as_ptr();
1213 *out_len = proto.len();
1214}
1215
1216#[no_mangle]
1217pub extern "C" fn quiche_conn_peer_cert(
1218 conn: &Connection, out: &mut *const u8, out_len: &mut size_t,
1219) {
1220 match conn.peer_cert() {
1221 Some(peer_cert) => {
1222 *out = peer_cert.as_ptr();
1223 *out_len = peer_cert.len();
1224 },
1225
1226 None => *out_len = 0,
1227 }
1228}
1229
1230#[no_mangle]
1231pub extern "C" fn quiche_conn_session(
1232 conn: &Connection, out: &mut *const u8, out_len: &mut size_t,
1233) {
1234 match conn.session() {
1235 Some(session) => {
1236 *out = session.as_ptr();
1237 *out_len = session.len();
1238 },
1239
1240 None => *out_len = 0,
1241 }
1242}
1243
1244#[no_mangle]
1245pub extern "C" fn quiche_conn_server_name(
1246 conn: &Connection, out: &mut *const u8, out_len: &mut size_t,
1247) {
1248 match conn.server_name() {
1249 Some(server_name) => {
1250 *out = server_name.as_ptr();
1251 *out_len = server_name.len();
1252 },
1253
1254 None => *out_len = 0,
1255 }
1256}
1257
1258#[no_mangle]
1259pub extern "C" fn quiche_conn_is_established(conn: &Connection) -> bool {
1260 conn.is_established()
1261}
1262
1263#[no_mangle]
1264pub extern "C" fn quiche_conn_is_resumed(conn: &Connection) -> bool {
1265 conn.is_resumed()
1266}
1267
1268#[no_mangle]
1269pub extern "C" fn quiche_conn_is_in_early_data(conn: &Connection) -> bool {
1270 conn.is_in_early_data()
1271}
1272
1273#[no_mangle]
1274pub extern "C" fn quiche_conn_is_draining(conn: &Connection) -> bool {
1275 conn.is_draining()
1276}
1277
1278#[no_mangle]
1279pub extern "C" fn quiche_conn_is_closed(conn: &Connection) -> bool {
1280 conn.is_closed()
1281}
1282
1283#[no_mangle]
1284pub extern "C" fn quiche_conn_is_timed_out(conn: &Connection) -> bool {
1285 conn.is_timed_out()
1286}
1287
1288#[no_mangle]
1289pub extern "C" fn quiche_conn_peer_error(
1290 conn: &Connection, is_app: *mut bool, error_code: *mut u64,
1291 reason: &mut *const u8, reason_len: &mut size_t,
1292) -> bool {
1293 match &conn.peer_error {
1294 Some(conn_err) => unsafe {
1295 *is_app = conn_err.is_app;
1296 *error_code = conn_err.error_code;
1297 *reason = conn_err.reason.as_ptr();
1298 *reason_len = conn_err.reason.len();
1299
1300 true
1301 },
1302
1303 None => false,
1304 }
1305}
1306
1307#[no_mangle]
1308pub extern "C" fn quiche_conn_local_error(
1309 conn: &Connection, is_app: *mut bool, error_code: *mut u64,
1310 reason: &mut *const u8, reason_len: &mut size_t,
1311) -> bool {
1312 match &conn.local_error {
1313 Some(conn_err) => unsafe {
1314 *is_app = conn_err.is_app;
1315 *error_code = conn_err.error_code;
1316 *reason = conn_err.reason.as_ptr();
1317 *reason_len = conn_err.reason.len();
1318
1319 true
1320 },
1321
1322 None => false,
1323 }
1324}
1325
1326#[no_mangle]
1327pub extern "C" fn quiche_stream_iter_next(
1328 iter: &mut StreamIter, stream_id: *mut u64,
1329) -> bool {
1330 if let Some(v) = iter.next() {
1331 unsafe { *stream_id = v };
1332 return true;
1333 }
1334
1335 false
1336}
1337
1338#[no_mangle]
1339pub extern "C" fn quiche_stream_iter_free(iter: *mut StreamIter) {
1340 if !iter.is_null() {
1341 drop(unsafe { Box::from_raw(iter) });
1342 }
1343}
1344
1345#[repr(C)]
1346pub struct Stats {
1347 recv: usize,
1348 sent: usize,
1349 lost: usize,
1350 spurious_lost: usize,
1351 retrans: usize,
1352 sent_bytes: u64,
1353 recv_bytes: u64,
1354 acked_bytes: u64,
1355 lost_bytes: u64,
1356 stream_retrans_bytes: u64,
1357 dgram_recv: usize,
1358 dgram_sent: usize,
1359 paths_count: usize,
1360 reset_stream_count_local: u64,
1361 stopped_stream_count_local: u64,
1362 reset_stream_count_remote: u64,
1363 stopped_stream_count_remote: u64,
1364 data_blocked_sent_count: u64,
1365 stream_data_blocked_sent_count: u64,
1366 data_blocked_recv_count: u64,
1367 stream_data_blocked_recv_count: u64,
1368 streams_blocked_bidi_recv_count: u64,
1369 streams_blocked_uni_recv_count: u64,
1370 path_challenge_rx_count: u64,
1371 bytes_in_flight_duration_msec: u64,
1372 tx_buffered_inconsistent: bool,
1373}
1374
1375pub struct TransportParams {
1376 max_idle_timeout: u64,
1377 max_udp_payload_size: u64,
1378 initial_max_data: u64,
1379 initial_max_stream_data_bidi_local: u64,
1380 initial_max_stream_data_bidi_remote: u64,
1381 initial_max_stream_data_uni: u64,
1382 initial_max_streams_bidi: u64,
1383 initial_max_streams_uni: u64,
1384 ack_delay_exponent: u64,
1385 max_ack_delay: u64,
1386 disable_active_migration: bool,
1387 active_conn_id_limit: u64,
1388 max_datagram_frame_size: ssize_t,
1389}
1390
1391#[no_mangle]
1392pub extern "C" fn quiche_conn_stats(conn: &Connection, out: &mut Stats) {
1393 let stats = conn.stats();
1394
1395 out.recv = stats.recv;
1396 out.sent = stats.sent;
1397 out.lost = stats.lost;
1398 out.spurious_lost = stats.spurious_lost;
1399 out.retrans = stats.retrans;
1400 out.sent_bytes = stats.sent_bytes;
1401 out.recv_bytes = stats.recv_bytes;
1402 out.acked_bytes = stats.acked_bytes;
1403 out.lost_bytes = stats.lost_bytes;
1404 out.stream_retrans_bytes = stats.stream_retrans_bytes;
1405 out.dgram_recv = stats.dgram_recv;
1406 out.dgram_sent = stats.dgram_sent;
1407 out.paths_count = stats.paths_count;
1408 out.reset_stream_count_local = stats.reset_stream_count_local;
1409 out.stopped_stream_count_local = stats.stopped_stream_count_local;
1410 out.reset_stream_count_remote = stats.reset_stream_count_remote;
1411 out.stopped_stream_count_remote = stats.stopped_stream_count_remote;
1412 out.data_blocked_sent_count = stats.data_blocked_sent_count;
1413 out.stream_data_blocked_sent_count = stats.stream_data_blocked_sent_count;
1414 out.data_blocked_recv_count = stats.data_blocked_recv_count;
1415 out.stream_data_blocked_recv_count = stats.stream_data_blocked_recv_count;
1416 out.streams_blocked_bidi_recv_count = stats.streams_blocked_bidi_recv_count;
1417 out.streams_blocked_uni_recv_count = stats.streams_blocked_uni_recv_count;
1418 out.path_challenge_rx_count = stats.path_challenge_rx_count;
1419 out.bytes_in_flight_duration_msec =
1420 stats.bytes_in_flight_duration.as_millis() as u64;
1421 out.tx_buffered_inconsistent =
1422 stats.tx_buffered_state != TxBufferTrackingState::Ok;
1423}
1424
1425#[no_mangle]
1426pub extern "C" fn quiche_conn_peer_transport_params(
1427 conn: &Connection, out: &mut TransportParams,
1428) -> bool {
1429 let tps = match conn.peer_transport_params() {
1430 Some(v) => v,
1431 None => return false,
1432 };
1433
1434 out.max_idle_timeout = tps.max_idle_timeout;
1435 out.max_udp_payload_size = tps.max_udp_payload_size;
1436 out.initial_max_data = tps.initial_max_data;
1437 out.initial_max_stream_data_bidi_local =
1438 tps.initial_max_stream_data_bidi_local;
1439 out.initial_max_stream_data_bidi_remote =
1440 tps.initial_max_stream_data_bidi_remote;
1441 out.initial_max_stream_data_uni = tps.initial_max_stream_data_uni;
1442 out.initial_max_streams_bidi = tps.initial_max_streams_bidi;
1443 out.initial_max_streams_uni = tps.initial_max_streams_uni;
1444 out.ack_delay_exponent = tps.ack_delay_exponent;
1445 out.max_ack_delay = tps.max_ack_delay;
1446 out.disable_active_migration = tps.disable_active_migration;
1447 out.active_conn_id_limit = tps.active_conn_id_limit;
1448 out.max_datagram_frame_size = match tps.max_datagram_frame_size {
1449 None => Error::Done.to_c(),
1450
1451 Some(v) => v as ssize_t,
1452 };
1453
1454 true
1455}
1456
1457#[repr(C)]
1458pub struct PathStats {
1459 local_addr: sockaddr_storage,
1460 local_addr_len: socklen_t,
1461 peer_addr: sockaddr_storage,
1462 peer_addr_len: socklen_t,
1463 validation_state: ssize_t,
1464 active: bool,
1465 recv: usize,
1466 sent: usize,
1467 lost: usize,
1468 retrans: usize,
1469 total_pto_count: usize,
1470 dgram_recv: usize,
1471 dgram_sent: usize,
1472 rtt: u64,
1473 min_rtt: u64,
1474 max_rtt: u64,
1475 rttvar: u64,
1476 cwnd: usize,
1477 sent_bytes: u64,
1478 recv_bytes: u64,
1479 lost_bytes: u64,
1480 stream_retrans_bytes: u64,
1481 pmtu: usize,
1482 delivery_rate: u64,
1483 max_bandwidth: u64,
1484 startup_exit_cwnd: u64,
1485}
1486
1487#[no_mangle]
1488pub extern "C" fn quiche_conn_path_stats(
1489 conn: &Connection, idx: usize, out: &mut PathStats,
1490) -> c_int {
1491 let stats = match conn.path_stats().nth(idx) {
1492 Some(p) => p,
1493 None => return Error::Done.to_c() as c_int,
1494 };
1495
1496 out.local_addr_len = std_addr_to_c(&stats.local_addr, &mut out.local_addr);
1497 out.peer_addr_len = std_addr_to_c(&stats.peer_addr, &mut out.peer_addr);
1498 out.validation_state = stats.validation_state.to_c();
1499 out.active = stats.active;
1500 out.recv = stats.recv;
1501 out.sent = stats.sent;
1502 out.lost = stats.lost;
1503 out.retrans = stats.retrans;
1504 out.total_pto_count = stats.total_pto_count;
1505 out.dgram_recv = stats.dgram_recv;
1506 out.dgram_sent = stats.dgram_sent;
1507 out.rtt = stats.rtt.as_nanos() as u64;
1508 out.min_rtt = stats.min_rtt.unwrap_or_default().as_nanos() as u64;
1509 out.max_rtt = stats.max_rtt.unwrap_or_default().as_nanos() as u64;
1510 out.rttvar = stats.rttvar.as_nanos() as u64;
1511 out.cwnd = stats.cwnd;
1512 out.sent_bytes = stats.sent_bytes;
1513 out.recv_bytes = stats.recv_bytes;
1514 out.lost_bytes = stats.lost_bytes;
1515 out.stream_retrans_bytes = stats.stream_retrans_bytes;
1516 out.pmtu = stats.pmtu;
1517 out.delivery_rate = stats.delivery_rate;
1518 out.max_bandwidth = stats.max_bandwidth.unwrap_or(0);
1519 out.startup_exit_cwnd =
1520 stats.startup_exit.map(|s| s.cwnd as u64).unwrap_or(0);
1521
1522 0
1523}
1524
1525#[no_mangle]
1526pub extern "C" fn quiche_conn_is_server(conn: &Connection) -> bool {
1527 conn.is_server()
1528}
1529
1530#[no_mangle]
1531pub extern "C" fn quiche_conn_dgram_max_writable_len(
1532 conn: &Connection,
1533) -> ssize_t {
1534 match conn.dgram_max_writable_len() {
1535 None => Error::Done.to_c(),
1536
1537 Some(v) => v as ssize_t,
1538 }
1539}
1540
1541#[no_mangle]
1542pub extern "C" fn quiche_conn_dgram_recv_front_len(conn: &Connection) -> ssize_t {
1543 match conn.dgram_recv_front_len() {
1544 None => Error::Done.to_c(),
1545
1546 Some(v) => v as ssize_t,
1547 }
1548}
1549
1550#[no_mangle]
1551pub extern "C" fn quiche_conn_dgram_recv_queue_len(conn: &Connection) -> ssize_t {
1552 conn.dgram_recv_queue_len() as ssize_t
1553}
1554
1555#[no_mangle]
1556pub extern "C" fn quiche_conn_dgram_recv_queue_byte_size(
1557 conn: &Connection,
1558) -> ssize_t {
1559 conn.dgram_recv_queue_byte_size() as ssize_t
1560}
1561
1562#[no_mangle]
1563pub extern "C" fn quiche_conn_dgram_send_queue_len(conn: &Connection) -> ssize_t {
1564 conn.dgram_send_queue_len() as ssize_t
1565}
1566
1567#[no_mangle]
1568pub extern "C" fn quiche_conn_dgram_send_queue_byte_size(
1569 conn: &Connection,
1570) -> ssize_t {
1571 conn.dgram_send_queue_byte_size() as ssize_t
1572}
1573
1574#[no_mangle]
1575pub extern "C" fn quiche_conn_dgram_send(
1576 conn: &mut Connection, buf: *const u8, buf_len: size_t,
1577) -> ssize_t {
1578 if buf_len > <ssize_t>::MAX as usize {
1579 panic!("The provided buffer is too large");
1580 }
1581
1582 let buf = unsafe { slice::from_raw_parts(buf, buf_len) };
1583
1584 match conn.dgram_send(buf) {
1585 Ok(_) => buf_len as ssize_t,
1586
1587 Err(e) => e.to_c(),
1588 }
1589}
1590
1591#[no_mangle]
1592pub extern "C" fn quiche_conn_dgram_recv(
1593 conn: &mut Connection, out: *mut u8, out_len: size_t,
1594) -> ssize_t {
1595 if out_len > <ssize_t>::MAX as usize {
1596 panic!("The provided buffer is too large");
1597 }
1598
1599 let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
1600
1601 let out_len = match conn.dgram_recv(out) {
1602 Ok(v) => v,
1603
1604 Err(e) => return e.to_c(),
1605 };
1606
1607 out_len as ssize_t
1608}
1609
1610#[no_mangle]
1611pub extern "C" fn quiche_conn_dgram_purge_outgoing(
1612 conn: &mut Connection, f: extern "C" fn(*const u8, size_t) -> bool,
1613) {
1614 conn.dgram_purge_outgoing(|d: &[u8]| -> bool {
1615 let ptr: *const u8 = d.as_ptr();
1616 let len: size_t = d.len();
1617
1618 f(ptr, len)
1619 });
1620}
1621
1622#[no_mangle]
1623pub extern "C" fn quiche_conn_is_dgram_send_queue_full(
1624 conn: &Connection,
1625) -> bool {
1626 conn.is_dgram_send_queue_full()
1627}
1628
1629#[no_mangle]
1630pub extern "C" fn quiche_conn_is_dgram_recv_queue_full(
1631 conn: &Connection,
1632) -> bool {
1633 conn.is_dgram_recv_queue_full()
1634}
1635
1636#[no_mangle]
1637pub extern "C" fn quiche_conn_send_ack_eliciting(
1638 conn: &mut Connection,
1639) -> ssize_t {
1640 match conn.send_ack_eliciting() {
1641 Ok(()) => 0,
1642 Err(e) => e.to_c(),
1643 }
1644}
1645
1646#[no_mangle]
1647pub extern "C" fn quiche_conn_send_ack_eliciting_on_path(
1648 conn: &mut Connection, local: &sockaddr, local_len: socklen_t,
1649 peer: &sockaddr, peer_len: socklen_t,
1650) -> ssize_t {
1651 let local = std_addr_from_c(local, local_len);
1652 let peer = std_addr_from_c(peer, peer_len);
1653 match conn.send_ack_eliciting_on_path(local, peer) {
1654 Ok(()) => 0,
1655 Err(e) => e.to_c(),
1656 }
1657}
1658
1659#[no_mangle]
1660pub extern "C" fn quiche_conn_free(conn: *mut Connection) {
1661 if !conn.is_null() {
1662 drop(unsafe { Box::from_raw(conn) });
1663 }
1664}
1665
1666#[no_mangle]
1667pub extern "C" fn quiche_conn_peer_streams_left_bidi(conn: &Connection) -> u64 {
1668 conn.peer_streams_left_bidi()
1669}
1670
1671#[no_mangle]
1672pub extern "C" fn quiche_conn_peer_streams_left_uni(conn: &Connection) -> u64 {
1673 conn.peer_streams_left_uni()
1674}
1675
1676#[no_mangle]
1677pub extern "C" fn quiche_conn_send_quantum(conn: &Connection) -> size_t {
1678 conn.send_quantum() as size_t
1679}
1680
1681#[no_mangle]
1682pub extern "C" fn quiche_conn_active_scids(conn: &Connection) -> size_t {
1683 conn.active_scids() as size_t
1684}
1685
1686#[no_mangle]
1687pub extern "C" fn quiche_conn_scids_left(conn: &Connection) -> size_t {
1688 conn.scids_left() as size_t
1689}
1690
1691#[no_mangle]
1692pub extern "C" fn quiche_conn_new_scid(
1693 conn: &mut Connection, scid: *const u8, scid_len: size_t,
1694 reset_token: *const u8, retire_if_needed: bool, scid_seq: *mut u64,
1695) -> c_int {
1696 let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
1697 let scid = ConnectionId::from_ref(scid);
1698
1699 let reset_token = unsafe { slice::from_raw_parts(reset_token, 16) };
1700 let reset_token = match reset_token.try_into() {
1701 Ok(rt) => rt,
1702 Err(_) => unreachable!(),
1703 };
1704 let reset_token = u128::from_be_bytes(reset_token);
1705
1706 match conn.new_scid(&scid, reset_token, retire_if_needed) {
1707 Ok(c) => {
1708 unsafe { *scid_seq = c }
1709 0
1710 },
1711 Err(e) => e.to_c() as c_int,
1712 }
1713}
1714
1715#[no_mangle]
1716pub extern "C" fn quiche_conn_retire_dcid(
1717 conn: &mut Connection, dcid_seq: u64,
1718) -> c_int {
1719 match conn.retire_dcid(dcid_seq) {
1720 Ok(_) => 0,
1721 Err(e) => e.to_c() as c_int,
1722 }
1723}
1724
1725#[no_mangle]
1726pub extern "C" fn quiche_conn_available_dcids(conn: &Connection) -> size_t {
1727 conn.available_dcids() as size_t
1728}
1729
1730#[no_mangle]
1731pub extern "C" fn quiche_conn_retired_scids(conn: &Connection) -> size_t {
1732 conn.retired_scids() as size_t
1733}
1734
1735#[no_mangle]
1736pub extern "C" fn quiche_conn_retired_scid_iter(
1737 conn: &mut Connection,
1738) -> *mut ConnectionIdIter<'_> {
1739 let mut cids = Vec::with_capacity(conn.retired_scids());
1740 while let Some(cid) = conn.retired_scid_next() {
1741 cids.push(cid);
1742 }
1743 Box::into_raw(Box::new(ConnectionIdIter { cids, index: 0 }))
1744}
1745
1746#[no_mangle]
1747pub extern "C" fn quiche_conn_send_quantum_on_path(
1748 conn: &Connection, local: &sockaddr, local_len: socklen_t, peer: &sockaddr,
1749 peer_len: socklen_t,
1750) -> size_t {
1751 let local = std_addr_from_c(local, local_len);
1752 let peer = std_addr_from_c(peer, peer_len);
1753
1754 conn.send_quantum_on_path(local, peer) as size_t
1755}
1756
1757#[no_mangle]
1758pub extern "C" fn quiche_conn_paths_iter(
1759 conn: &Connection, from: &sockaddr, from_len: socklen_t,
1760) -> *mut SocketAddrIter {
1761 let addr = std_addr_from_c(from, from_len);
1762
1763 Box::into_raw(Box::new(conn.paths_iter(addr)))
1764}
1765
1766#[no_mangle]
1767pub extern "C" fn quiche_socket_addr_iter_next(
1768 iter: &mut SocketAddrIter, peer: &mut sockaddr_storage,
1769 peer_len: *mut socklen_t,
1770) -> bool {
1771 if let Some(v) = iter.next() {
1772 unsafe { *peer_len = std_addr_to_c(&v, peer) }
1773 return true;
1774 }
1775
1776 false
1777}
1778
1779#[no_mangle]
1780pub extern "C" fn quiche_socket_addr_iter_free(iter: *mut SocketAddrIter) {
1781 if !iter.is_null() {
1782 drop(unsafe { Box::from_raw(iter) });
1783 }
1784}
1785
1786#[no_mangle]
1787pub extern "C" fn quiche_conn_is_path_validated(
1788 conn: &Connection, from: &sockaddr, from_len: socklen_t, to: &sockaddr,
1789 to_len: socklen_t,
1790) -> c_int {
1791 let from = std_addr_from_c(from, from_len);
1792 let to = std_addr_from_c(to, to_len);
1793 match conn.is_path_validated(from, to) {
1794 Ok(v) => v as c_int,
1795 Err(e) => e.to_c() as c_int,
1796 }
1797}
1798
1799#[no_mangle]
1800pub extern "C" fn quiche_conn_probe_path(
1801 conn: &mut Connection, local: &sockaddr, local_len: socklen_t,
1802 peer: &sockaddr, peer_len: socklen_t, seq: *mut u64,
1803) -> c_int {
1804 let local = std_addr_from_c(local, local_len);
1805 let peer = std_addr_from_c(peer, peer_len);
1806 match conn.probe_path(local, peer) {
1807 Ok(v) => {
1808 unsafe { *seq = v }
1809 0
1810 },
1811 Err(e) => e.to_c() as c_int,
1812 }
1813}
1814
1815#[no_mangle]
1816pub extern "C" fn quiche_conn_migrate_source(
1817 conn: &mut Connection, local: &sockaddr, local_len: socklen_t, seq: *mut u64,
1818) -> c_int {
1819 let local = std_addr_from_c(local, local_len);
1820 match conn.migrate_source(local) {
1821 Ok(v) => {
1822 unsafe { *seq = v }
1823 0
1824 },
1825 Err(e) => e.to_c() as c_int,
1826 }
1827}
1828
1829#[no_mangle]
1830pub extern "C" fn quiche_conn_migrate(
1831 conn: &mut Connection, local: &sockaddr, local_len: socklen_t,
1832 peer: &sockaddr, peer_len: socklen_t, seq: *mut u64,
1833) -> c_int {
1834 let local = std_addr_from_c(local, local_len);
1835 let peer = std_addr_from_c(peer, peer_len);
1836 match conn.migrate(local, peer) {
1837 Ok(v) => {
1838 unsafe { *seq = v }
1839 0
1840 },
1841 Err(e) => e.to_c() as c_int,
1842 }
1843}
1844
1845#[no_mangle]
1846pub extern "C" fn quiche_conn_path_event_next(
1847 conn: &mut Connection,
1848) -> *mut PathEvent {
1849 match conn.path_event_next() {
1850 Some(v) => Box::into_raw(Box::new(v)),
1851 None => ptr::null_mut(),
1852 }
1853}
1854
1855#[no_mangle]
1856pub extern "C" fn quiche_path_event_type(ev: &PathEvent) -> u32 {
1857 match ev {
1858 PathEvent::New { .. } => 0,
1859
1860 PathEvent::Validated { .. } => 1,
1861
1862 PathEvent::FailedValidation { .. } => 2,
1863
1864 PathEvent::Closed { .. } => 3,
1865
1866 PathEvent::ReusedSourceConnectionId { .. } => 4,
1867
1868 PathEvent::PeerMigrated { .. } => 5,
1869
1870 PathEvent::PmtuUpdated { .. } => 6,
1871 }
1872}
1873
1874#[no_mangle]
1875pub extern "C" fn quiche_path_event_new(
1876 ev: &PathEvent, local_addr: &mut sockaddr_storage,
1877 local_addr_len: &mut socklen_t, peer_addr: &mut sockaddr_storage,
1878 peer_addr_len: &mut socklen_t,
1879) {
1880 match ev {
1881 PathEvent::New(local, peer) => {
1882 *local_addr_len = std_addr_to_c(local, local_addr);
1883 *peer_addr_len = std_addr_to_c(peer, peer_addr)
1884 },
1885
1886 _ => unreachable!(),
1887 }
1888}
1889
1890#[no_mangle]
1891pub extern "C" fn quiche_path_event_validated(
1892 ev: &PathEvent, local_addr: &mut sockaddr_storage,
1893 local_addr_len: &mut socklen_t, peer_addr: &mut sockaddr_storage,
1894 peer_addr_len: &mut socklen_t,
1895) {
1896 match ev {
1897 PathEvent::Validated(local, peer) => {
1898 *local_addr_len = std_addr_to_c(local, local_addr);
1899 *peer_addr_len = std_addr_to_c(peer, peer_addr)
1900 },
1901
1902 _ => unreachable!(),
1903 }
1904}
1905
1906#[no_mangle]
1907pub extern "C" fn quiche_path_event_failed_validation(
1908 ev: &PathEvent, local_addr: &mut sockaddr_storage,
1909 local_addr_len: &mut socklen_t, peer_addr: &mut sockaddr_storage,
1910 peer_addr_len: &mut socklen_t,
1911) {
1912 match ev {
1913 PathEvent::FailedValidation(local, peer) => {
1914 *local_addr_len = std_addr_to_c(local, local_addr);
1915 *peer_addr_len = std_addr_to_c(peer, peer_addr)
1916 },
1917
1918 _ => unreachable!(),
1919 }
1920}
1921
1922#[no_mangle]
1923pub extern "C" fn quiche_path_event_closed(
1924 ev: &PathEvent, local_addr: &mut sockaddr_storage,
1925 local_addr_len: &mut socklen_t, peer_addr: &mut sockaddr_storage,
1926 peer_addr_len: &mut socklen_t,
1927) {
1928 match ev {
1929 PathEvent::Closed(local, peer) => {
1930 *local_addr_len = std_addr_to_c(local, local_addr);
1931 *peer_addr_len = std_addr_to_c(peer, peer_addr)
1932 },
1933
1934 _ => unreachable!(),
1935 }
1936}
1937
1938#[no_mangle]
1939pub extern "C" fn quiche_path_event_reused_source_connection_id(
1940 ev: &PathEvent, cid_sequence_number: &mut u64,
1941 old_local_addr: &mut sockaddr_storage, old_local_addr_len: &mut socklen_t,
1942 old_peer_addr: &mut sockaddr_storage, old_peer_addr_len: &mut socklen_t,
1943 local_addr: &mut sockaddr_storage, local_addr_len: &mut socklen_t,
1944 peer_addr: &mut sockaddr_storage, peer_addr_len: &mut socklen_t,
1945) {
1946 match ev {
1947 PathEvent::ReusedSourceConnectionId(id, old, new) => {
1948 *cid_sequence_number = *id;
1949 *old_local_addr_len = std_addr_to_c(&old.0, old_local_addr);
1950 *old_peer_addr_len = std_addr_to_c(&old.1, old_peer_addr);
1951
1952 *local_addr_len = std_addr_to_c(&new.0, local_addr);
1953 *peer_addr_len = std_addr_to_c(&new.1, peer_addr)
1954 },
1955
1956 _ => unreachable!(),
1957 }
1958}
1959
1960#[no_mangle]
1961pub extern "C" fn quiche_path_event_peer_migrated(
1962 ev: &PathEvent, local_addr: &mut sockaddr_storage,
1963 local_addr_len: &mut socklen_t, peer_addr: &mut sockaddr_storage,
1964 peer_addr_len: &mut socklen_t,
1965) {
1966 match ev {
1967 PathEvent::PeerMigrated(local, peer) => {
1968 *local_addr_len = std_addr_to_c(local, local_addr);
1969 *peer_addr_len = std_addr_to_c(peer, peer_addr);
1970 },
1971
1972 _ => unreachable!(),
1973 }
1974}
1975
1976#[no_mangle]
1977pub extern "C" fn quiche_path_event_pmtu_updated(
1978 ev: &PathEvent, local_addr: &mut sockaddr_storage,
1979 local_addr_len: &mut socklen_t, peer_addr: &mut sockaddr_storage,
1980 peer_addr_len: &mut socklen_t, pmtu: &mut size_t,
1981) {
1982 match ev {
1983 PathEvent::PmtuUpdated {
1984 local,
1985 peer,
1986 pmtu: value,
1987 } => {
1988 *local_addr_len = std_addr_to_c(local, local_addr);
1989 *peer_addr_len = std_addr_to_c(peer, peer_addr);
1990 *pmtu = *value;
1991 },
1992
1993 _ => unreachable!(),
1994 }
1995}
1996
1997#[no_mangle]
1998pub extern "C" fn quiche_path_event_free(ev: *mut PathEvent) {
1999 if !ev.is_null() {
2000 drop(unsafe { Box::from_raw(ev) });
2001 }
2002}
2003
2004#[no_mangle]
2005pub extern "C" fn quiche_put_varint(
2006 buf: *mut u8, buf_len: size_t, val: u64,
2007) -> c_int {
2008 let buf = unsafe { slice::from_raw_parts_mut(buf, buf_len) };
2009
2010 let mut b = octets::OctetsMut::with_slice(buf);
2011 match b.put_varint(val) {
2012 Ok(_) => 0,
2013
2014 Err(e) => {
2015 let err: Error = e.into();
2016 err.to_c() as c_int
2017 },
2018 }
2019}
2020
2021#[no_mangle]
2022pub extern "C" fn quiche_get_varint(
2023 buf: *const u8, buf_len: size_t, val: *mut u64,
2024) -> ssize_t {
2025 let buf = unsafe { slice::from_raw_parts(buf, buf_len) };
2026
2027 let mut b = octets::Octets::with_slice(buf);
2028 match b.get_varint() {
2029 Ok(v) => unsafe { *val = v },
2030
2031 Err(e) => {
2032 let err: Error = e.into();
2033 return err.to_c();
2034 },
2035 };
2036
2037 b.off() as ssize_t
2038}
2039
2040fn optional_std_addr_from_c(
2041 addr: *const sockaddr, addr_len: socklen_t,
2042) -> Option<SocketAddr> {
2043 if addr.is_null() || addr_len == 0 {
2044 return None;
2045 }
2046
2047 Some(std_addr_from_c(unsafe { &*addr }, addr_len))
2048}
2049
2050fn std_addr_from_c(addr: &sockaddr, addr_len: socklen_t) -> SocketAddr {
2051 match addr.sa_family as _ {
2052 AF_INET => {
2053 assert!(addr_len as usize == size_of::<sockaddr_in>());
2054
2055 let in4 = unsafe { *(addr as *const _ as *const sockaddr_in) };
2056
2057 #[cfg(not(windows))]
2058 let ip_addr = Ipv4Addr::from(u32::from_be(in4.sin_addr.s_addr));
2059 #[cfg(windows)]
2060 let ip_addr = {
2061 let ip_bytes = unsafe { in4.sin_addr.S_un.S_un_b };
2062
2063 Ipv4Addr::from([
2064 ip_bytes.s_b1,
2065 ip_bytes.s_b2,
2066 ip_bytes.s_b3,
2067 ip_bytes.s_b4,
2068 ])
2069 };
2070
2071 let port = u16::from_be(in4.sin_port);
2072
2073 let out = SocketAddrV4::new(ip_addr, port);
2074
2075 out.into()
2076 },
2077
2078 AF_INET6 => {
2079 assert!(addr_len as usize == size_of::<sockaddr_in6>());
2080
2081 let in6 = unsafe { *(addr as *const _ as *const sockaddr_in6) };
2082
2083 let ip_addr = Ipv6Addr::from(
2084 #[cfg(not(windows))]
2085 in6.sin6_addr.s6_addr,
2086 #[cfg(windows)]
2087 unsafe {
2088 in6.sin6_addr.u.Byte
2089 },
2090 );
2091
2092 let port = u16::from_be(in6.sin6_port);
2093
2094 #[cfg(not(windows))]
2095 let scope_id = in6.sin6_scope_id;
2096 #[cfg(windows)]
2097 let scope_id = unsafe { in6.Anonymous.sin6_scope_id };
2098
2099 let out =
2100 SocketAddrV6::new(ip_addr, port, in6.sin6_flowinfo, scope_id);
2101
2102 out.into()
2103 },
2104
2105 _ => unimplemented!("unsupported address type"),
2106 }
2107}
2108
2109fn std_addr_to_c(addr: &SocketAddr, out: &mut sockaddr_storage) -> socklen_t {
2110 let sin_port = addr.port().to_be();
2111
2112 match addr {
2113 SocketAddr::V4(addr) => unsafe {
2114 let sa_len = size_of::<sockaddr_in>();
2115 let out_in = out as *mut _ as *mut sockaddr_in;
2116
2117 let s_addr = u32::from_ne_bytes(addr.ip().octets());
2118
2119 #[cfg(not(windows))]
2120 let sin_addr = in_addr { s_addr };
2121 #[cfg(windows)]
2122 let sin_addr = in_addr {
2123 S_un: IN_ADDR_0 { S_addr: s_addr },
2124 };
2125
2126 *out_in = sockaddr_in {
2127 sin_family: AF_INET as sa_family_t,
2128
2129 sin_addr,
2130
2131 #[cfg(any(
2132 target_os = "macos",
2133 target_os = "ios",
2134 target_os = "watchos",
2135 target_os = "freebsd",
2136 target_os = "dragonfly",
2137 target_os = "openbsd",
2138 target_os = "netbsd"
2139 ))]
2140 sin_len: sa_len as u8,
2141
2142 sin_port,
2143
2144 sin_zero: std::mem::zeroed(),
2145 };
2146
2147 sa_len as socklen_t
2148 },
2149
2150 SocketAddr::V6(addr) => unsafe {
2151 let sa_len = size_of::<sockaddr_in6>();
2152 let out_in6 = out as *mut _ as *mut sockaddr_in6;
2153
2154 #[cfg(not(windows))]
2155 let sin6_addr = in6_addr {
2156 s6_addr: addr.ip().octets(),
2157 };
2158 #[cfg(windows)]
2159 let sin6_addr = in6_addr {
2160 u: IN6_ADDR_0 {
2161 Byte: addr.ip().octets(),
2162 },
2163 };
2164
2165 *out_in6 = sockaddr_in6 {
2166 sin6_family: AF_INET6 as sa_family_t,
2167
2168 sin6_addr,
2169
2170 #[cfg(any(
2171 target_os = "macos",
2172 target_os = "ios",
2173 target_os = "watchos",
2174 target_os = "freebsd",
2175 target_os = "dragonfly",
2176 target_os = "openbsd",
2177 target_os = "netbsd"
2178 ))]
2179 sin6_len: sa_len as u8,
2180
2181 sin6_port: sin_port,
2182
2183 sin6_flowinfo: addr.flowinfo(),
2184
2185 #[cfg(not(windows))]
2186 sin6_scope_id: addr.scope_id(),
2187 #[cfg(windows)]
2188 Anonymous: SOCKADDR_IN6_0 {
2189 sin6_scope_id: addr.scope_id(),
2190 },
2191 };
2192
2193 sa_len as socklen_t
2194 },
2195 }
2196}
2197
2198#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))]
2199fn std_time_to_c(time: &Instant, out: &mut timespec) {
2200 const INSTANT_ZERO: Instant =
2201 unsafe { std::mem::transmute(std::time::UNIX_EPOCH) };
2202
2203 let raw_time = time.duration_since(INSTANT_ZERO);
2204
2205 out.tv_sec = raw_time.as_secs() as libc::time_t;
2206 out.tv_nsec = raw_time.subsec_nanos() as libc::c_long;
2207}
2208
2209#[cfg(any(target_os = "macos", target_os = "ios", target_os = "windows"))]
2210fn std_time_to_c(_time: &Instant, out: &mut timespec) {
2211 out.tv_sec = 0;
2213 out.tv_nsec = 0;
2214}
2215
2216#[cfg(test)]
2217mod tests {
2218 use super::*;
2219
2220 use libc::c_void;
2221 #[cfg(windows)]
2222 use windows_sys::Win32::Networking::WinSock::inet_ntop;
2223
2224 #[test]
2225 fn pmtu_updated_path_event() {
2226 let local = "127.0.0.1:8080".parse().unwrap();
2227 let peer = "127.0.0.2:443".parse().unwrap();
2228
2229 let event = PathEvent::PmtuUpdated {
2230 local,
2231 peer,
2232 pmtu: 1400,
2233 };
2234 assert_eq!(quiche_path_event_type(&event), 6);
2235
2236 let mut local_out: sockaddr_storage = unsafe { std::mem::zeroed() };
2237 let mut peer_out: sockaddr_storage = unsafe { std::mem::zeroed() };
2238 let mut local_len = 0;
2239 let mut peer_len = 0;
2240 let mut pmtu = usize::MAX;
2241
2242 quiche_path_event_pmtu_updated(
2243 &event,
2244 &mut local_out,
2245 &mut local_len,
2246 &mut peer_out,
2247 &mut peer_len,
2248 &mut pmtu,
2249 );
2250 assert_eq!(pmtu, 1400);
2251 assert_eq!(
2252 unsafe {
2253 std_addr_from_c(
2254 &*(&local_out as *const _ as *const sockaddr),
2255 local_len,
2256 )
2257 },
2258 local
2259 );
2260 assert_eq!(
2261 unsafe {
2262 std_addr_from_c(
2263 &*(&peer_out as *const _ as *const sockaddr),
2264 peer_len,
2265 )
2266 },
2267 peer
2268 );
2269 }
2270
2271 #[test]
2272 fn addr_v4() {
2273 let addr = "127.0.0.1:8080".parse().unwrap();
2274
2275 let mut out: sockaddr_storage = unsafe { std::mem::zeroed() };
2276
2277 assert_eq!(
2278 std_addr_to_c(&addr, &mut out),
2279 size_of::<sockaddr_in>() as socklen_t
2280 );
2281
2282 let s = ffi::CString::new("ddd.ddd.ddd.ddd").unwrap();
2283
2284 let s = unsafe {
2285 let in_addr = &out as *const _ as *const sockaddr_in;
2286 assert_eq!(u16::from_be((*in_addr).sin_port), addr.port());
2287
2288 let dst = s.into_raw();
2289
2290 inet_ntop(
2291 AF_INET as _,
2292 &((*in_addr).sin_addr) as *const _ as *const c_void,
2293 dst as _,
2294 16,
2295 );
2296
2297 ffi::CString::from_raw(dst).into_string().unwrap()
2298 };
2299
2300 assert_eq!(s, "127.0.0.1");
2301
2302 let addr = unsafe {
2303 std_addr_from_c(
2304 &*(&out as *const _ as *const sockaddr),
2305 size_of::<sockaddr_in>() as socklen_t,
2306 )
2307 };
2308
2309 assert_eq!(addr, "127.0.0.1:8080".parse().unwrap());
2310 }
2311
2312 #[test]
2313 fn addr_v6() {
2314 let addr = "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8080"
2315 .parse()
2316 .unwrap();
2317
2318 let mut out: sockaddr_storage = unsafe { std::mem::zeroed() };
2319
2320 assert_eq!(
2321 std_addr_to_c(&addr, &mut out),
2322 size_of::<sockaddr_in6>() as socklen_t
2323 );
2324
2325 let s =
2326 ffi::CString::new("dddd:dddd:dddd:dddd:dddd:dddd:dddd:dddd").unwrap();
2327
2328 let s = unsafe {
2329 let in6_addr = &out as *const _ as *const sockaddr_in6;
2330 assert_eq!(u16::from_be((*in6_addr).sin6_port), addr.port());
2331
2332 let dst = s.into_raw();
2333
2334 inet_ntop(
2335 AF_INET6 as _,
2336 &((*in6_addr).sin6_addr) as *const _ as *const c_void,
2337 dst as _,
2338 45,
2339 );
2340
2341 ffi::CString::from_raw(dst).into_string().unwrap()
2342 };
2343
2344 assert_eq!(s, "2001:db8:85a3::8a2e:370:7334");
2345
2346 let addr = unsafe {
2347 std_addr_from_c(
2348 &*(&out as *const _ as *const sockaddr),
2349 size_of::<sockaddr_in6>() as socklen_t,
2350 )
2351 };
2352
2353 assert_eq!(
2354 addr,
2355 "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8080"
2356 .parse()
2357 .unwrap()
2358 );
2359 }
2360
2361 #[test]
2362 fn connection_id_iter_next() {
2363 let cids = vec![
2364 ConnectionId::from_vec(vec![1, 2, 3, 4]),
2365 ConnectionId::from_vec(vec![5, 6]),
2366 ];
2367
2368 let mut iter = ConnectionIdIter { cids, index: 0 };
2369
2370 let mut out: *const u8 = ptr::null();
2371 let mut out_len: size_t = 0;
2372
2373 assert!(quiche_connection_id_iter_next(
2375 &mut iter,
2376 &mut out,
2377 &mut out_len
2378 ));
2379 assert_eq!(out_len, 4);
2380 let slice = unsafe { slice::from_raw_parts(out, out_len) };
2381 assert_eq!(slice, &[1, 2, 3, 4]);
2382
2383 assert!(quiche_connection_id_iter_next(
2385 &mut iter,
2386 &mut out,
2387 &mut out_len
2388 ));
2389 assert_eq!(out_len, 2);
2390 let slice = unsafe { slice::from_raw_parts(out, out_len) };
2391 assert_eq!(slice, &[5, 6]);
2392
2393 assert!(!quiche_connection_id_iter_next(
2395 &mut iter,
2396 &mut out,
2397 &mut out_len
2398 ));
2399 }
2400
2401 #[test]
2402 fn retired_scid_iter() {
2403 let mut config = Config::new(PROTOCOL_VERSION).unwrap();
2404 config
2405 .load_cert_chain_from_pem_file("examples/cert.crt")
2406 .unwrap();
2407 config
2408 .load_priv_key_from_pem_file("examples/cert.key")
2409 .unwrap();
2410 config
2411 .set_application_protos(&[b"proto1", b"proto2"])
2412 .unwrap();
2413 config.verify_peer(false);
2414 config.set_active_connection_id_limit(2);
2415
2416 let mut pipe = test_utils::Pipe::with_config(&mut config).unwrap();
2417 assert_eq!(pipe.handshake(), Ok(()));
2418
2419 let scid = pipe.client.source_id().into_owned();
2420
2421 let (scid_1, reset_token_1) = test_utils::create_cid_and_reset_token(16);
2422 assert_eq!(pipe.client.new_scid(&scid_1, reset_token_1, false), Ok(1));
2423 assert_eq!(pipe.advance(), Ok(()));
2424
2425 let (scid_2, reset_token_2) = test_utils::create_cid_and_reset_token(16);
2428 assert_eq!(pipe.client.new_scid(&scid_2, reset_token_2, true), Ok(2));
2429 assert_eq!(pipe.advance(), Ok(()));
2430
2431 let iter = quiche_conn_retired_scid_iter(&mut pipe.client);
2433 let iter = unsafe { &mut *iter };
2434
2435 let mut out: *const u8 = ptr::null();
2436 let mut out_len: size_t = 0;
2437
2438 assert!(quiche_connection_id_iter_next(iter, &mut out, &mut out_len));
2440 let slice = unsafe { slice::from_raw_parts(out, out_len) };
2441 assert_eq!(slice, scid.as_ref());
2442
2443 assert!(!quiche_connection_id_iter_next(
2445 iter,
2446 &mut out,
2447 &mut out_len
2448 ));
2449
2450 quiche_connection_id_iter_free(iter);
2451 }
2452
2453 #[cfg(not(windows))]
2454 extern "C" {
2455 fn inet_ntop(
2456 af: c_int, src: *const c_void, dst: *mut c_char, size: socklen_t,
2457 ) -> *mut c_char;
2458 }
2459}