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