Skip to main content

quiche/
ffi.rs

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
27use 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]
249/// Corresponds to the `Config::set_application_protos_wire_format` Rust
250/// function.
251pub 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/// Deprecated: this is now always enabled and this function is a no-op.
389#[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, // retry_cids
674            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    // It's always an error to call this function without the custom-client-dcid
697    // feature enabled.
698    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/// An iterator over connection ids.
1146#[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    // TODO: implement Instant conversion for systems that don't use timespec.
2212    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        // First CID.
2374        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        // Second CID.
2384        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        // Exhausted.
2394        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        // Retire the initial SCID by advertising a new one with
2426        // retire_prior_to.
2427        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        // Use the FFI iterator to collect retired SCIDs.
2432        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        // The initial SCID should have been retired.
2439        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        // No more retired SCIDs.
2444        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}