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