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