• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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!("0.17.1", "\0");
106     // ANDROID's build system doesn't support environment variables
107     // so we hardcode the package version here.
108     static VERSION: &str = concat!("0.6.0", "\0");
109     VERSION.as_ptr()
110 }
111 
112 struct Logger {
113     cb: extern fn(line: *const u8, argp: *mut c_void),
114     argp: std::sync::atomic::AtomicPtr<c_void>,
115 }
116 
117 impl log::Log for Logger {
enabled(&self, _metadata: &log::Metadata) -> bool118     fn enabled(&self, _metadata: &log::Metadata) -> bool {
119         true
120     }
121 
log(&self, record: &log::Record)122     fn log(&self, record: &log::Record) {
123         let line = format!("{}: {}\0", record.target(), record.args());
124         (self.cb)(line.as_ptr(), self.argp.load(atomic::Ordering::Relaxed));
125     }
126 
flush(&self)127     fn flush(&self) {}
128 }
129 
130 #[no_mangle]
quiche_enable_debug_logging( cb: extern fn(line: *const u8, argp: *mut c_void), argp: *mut c_void, ) -> c_int131 pub extern fn quiche_enable_debug_logging(
132     cb: extern fn(line: *const u8, argp: *mut c_void), argp: *mut c_void,
133 ) -> c_int {
134     let argp = atomic::AtomicPtr::new(argp);
135     let logger = Box::new(Logger { cb, argp });
136 
137     if log::set_boxed_logger(logger).is_err() {
138         return -1;
139     }
140 
141     log::set_max_level(log::LevelFilter::Trace);
142 
143     0
144 }
145 
146 #[no_mangle]
quiche_config_new(version: u32) -> *mut Config147 pub extern fn quiche_config_new(version: u32) -> *mut Config {
148     match Config::new(version) {
149         Ok(c) => Box::into_raw(Box::new(c)),
150 
151         Err(_) => ptr::null_mut(),
152     }
153 }
154 
155 #[no_mangle]
quiche_config_load_cert_chain_from_pem_file( config: &mut Config, path: *const c_char, ) -> c_int156 pub extern fn quiche_config_load_cert_chain_from_pem_file(
157     config: &mut Config, path: *const c_char,
158 ) -> c_int {
159     let path = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
160 
161     match config.load_cert_chain_from_pem_file(path) {
162         Ok(_) => 0,
163 
164         Err(e) => e.to_c() as c_int,
165     }
166 }
167 
168 #[no_mangle]
quiche_config_load_priv_key_from_pem_file( config: &mut Config, path: *const c_char, ) -> c_int169 pub extern fn quiche_config_load_priv_key_from_pem_file(
170     config: &mut Config, path: *const c_char,
171 ) -> c_int {
172     let path = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
173 
174     match config.load_priv_key_from_pem_file(path) {
175         Ok(_) => 0,
176 
177         Err(e) => e.to_c() as c_int,
178     }
179 }
180 
181 #[no_mangle]
quiche_config_load_verify_locations_from_file( config: &mut Config, path: *const c_char, ) -> c_int182 pub extern fn quiche_config_load_verify_locations_from_file(
183     config: &mut Config, path: *const c_char,
184 ) -> c_int {
185     let path = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
186 
187     match config.load_verify_locations_from_file(path) {
188         Ok(_) => 0,
189 
190         Err(e) => e.to_c() as c_int,
191     }
192 }
193 
194 #[no_mangle]
quiche_config_load_verify_locations_from_directory( config: &mut Config, path: *const c_char, ) -> c_int195 pub extern fn quiche_config_load_verify_locations_from_directory(
196     config: &mut Config, path: *const c_char,
197 ) -> c_int {
198     let path = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
199 
200     match config.load_verify_locations_from_directory(path) {
201         Ok(_) => 0,
202 
203         Err(e) => e.to_c() as c_int,
204     }
205 }
206 
207 #[no_mangle]
quiche_config_verify_peer(config: &mut Config, v: bool)208 pub extern fn quiche_config_verify_peer(config: &mut Config, v: bool) {
209     config.verify_peer(v);
210 }
211 
212 #[no_mangle]
quiche_config_grease(config: &mut Config, v: bool)213 pub extern fn quiche_config_grease(config: &mut Config, v: bool) {
214     config.grease(v);
215 }
216 
217 #[no_mangle]
quiche_config_log_keys(config: &mut Config)218 pub extern fn quiche_config_log_keys(config: &mut Config) {
219     config.log_keys();
220 }
221 
222 #[no_mangle]
quiche_config_enable_early_data(config: &mut Config)223 pub extern fn quiche_config_enable_early_data(config: &mut Config) {
224     config.enable_early_data();
225 }
226 
227 #[no_mangle]
228 /// Corresponds to the `Config::set_application_protos_wire_format` Rust
229 /// function.
quiche_config_set_application_protos( config: &mut Config, protos: *const u8, protos_len: size_t, ) -> c_int230 pub extern fn quiche_config_set_application_protos(
231     config: &mut Config, protos: *const u8, protos_len: size_t,
232 ) -> c_int {
233     let protos = unsafe { slice::from_raw_parts(protos, protos_len) };
234 
235     match config.set_application_protos_wire_format(protos) {
236         Ok(_) => 0,
237 
238         Err(e) => e.to_c() as c_int,
239     }
240 }
241 
242 #[no_mangle]
quiche_config_set_max_idle_timeout(config: &mut Config, v: u64)243 pub extern fn quiche_config_set_max_idle_timeout(config: &mut Config, v: u64) {
244     config.set_max_idle_timeout(v);
245 }
246 
247 #[no_mangle]
quiche_config_set_max_recv_udp_payload_size( config: &mut Config, v: size_t, )248 pub extern fn quiche_config_set_max_recv_udp_payload_size(
249     config: &mut Config, v: size_t,
250 ) {
251     config.set_max_recv_udp_payload_size(v);
252 }
253 
254 #[no_mangle]
quiche_config_set_initial_max_data(config: &mut Config, v: u64)255 pub extern fn quiche_config_set_initial_max_data(config: &mut Config, v: u64) {
256     config.set_initial_max_data(v);
257 }
258 
259 #[no_mangle]
quiche_config_set_initial_max_stream_data_bidi_local( config: &mut Config, v: u64, )260 pub extern fn quiche_config_set_initial_max_stream_data_bidi_local(
261     config: &mut Config, v: u64,
262 ) {
263     config.set_initial_max_stream_data_bidi_local(v);
264 }
265 
266 #[no_mangle]
quiche_config_set_initial_max_stream_data_bidi_remote( config: &mut Config, v: u64, )267 pub extern fn quiche_config_set_initial_max_stream_data_bidi_remote(
268     config: &mut Config, v: u64,
269 ) {
270     config.set_initial_max_stream_data_bidi_remote(v);
271 }
272 
273 #[no_mangle]
quiche_config_set_initial_max_stream_data_uni( config: &mut Config, v: u64, )274 pub extern fn quiche_config_set_initial_max_stream_data_uni(
275     config: &mut Config, v: u64,
276 ) {
277     config.set_initial_max_stream_data_uni(v);
278 }
279 
280 #[no_mangle]
quiche_config_set_initial_max_streams_bidi( config: &mut Config, v: u64, )281 pub extern fn quiche_config_set_initial_max_streams_bidi(
282     config: &mut Config, v: u64,
283 ) {
284     config.set_initial_max_streams_bidi(v);
285 }
286 
287 #[no_mangle]
quiche_config_set_initial_max_streams_uni( config: &mut Config, v: u64, )288 pub extern fn quiche_config_set_initial_max_streams_uni(
289     config: &mut Config, v: u64,
290 ) {
291     config.set_initial_max_streams_uni(v);
292 }
293 
294 #[no_mangle]
quiche_config_set_ack_delay_exponent(config: &mut Config, v: u64)295 pub extern fn quiche_config_set_ack_delay_exponent(config: &mut Config, v: u64) {
296     config.set_ack_delay_exponent(v);
297 }
298 
299 #[no_mangle]
quiche_config_set_max_ack_delay(config: &mut Config, v: u64)300 pub extern fn quiche_config_set_max_ack_delay(config: &mut Config, v: u64) {
301     config.set_max_ack_delay(v);
302 }
303 
304 #[no_mangle]
quiche_config_set_disable_active_migration( config: &mut Config, v: bool, )305 pub extern fn quiche_config_set_disable_active_migration(
306     config: &mut Config, v: bool,
307 ) {
308     config.set_disable_active_migration(v);
309 }
310 
311 #[no_mangle]
quiche_config_set_cc_algorithm_name( config: &mut Config, name: *const c_char, ) -> c_int312 pub extern fn quiche_config_set_cc_algorithm_name(
313     config: &mut Config, name: *const c_char,
314 ) -> c_int {
315     let name = unsafe { ffi::CStr::from_ptr(name).to_str().unwrap() };
316     match config.set_cc_algorithm_name(name) {
317         Ok(_) => 0,
318 
319         Err(e) => e.to_c() as c_int,
320     }
321 }
322 
323 #[no_mangle]
quiche_config_set_cc_algorithm( config: &mut Config, algo: CongestionControlAlgorithm, )324 pub extern fn quiche_config_set_cc_algorithm(
325     config: &mut Config, algo: CongestionControlAlgorithm,
326 ) {
327     config.set_cc_algorithm(algo);
328 }
329 
330 #[no_mangle]
quiche_config_enable_hystart(config: &mut Config, v: bool)331 pub extern fn quiche_config_enable_hystart(config: &mut Config, v: bool) {
332     config.enable_hystart(v);
333 }
334 
335 #[no_mangle]
quiche_config_enable_pacing(config: &mut Config, v: bool)336 pub extern fn quiche_config_enable_pacing(config: &mut Config, v: bool) {
337     config.enable_pacing(v);
338 }
339 
340 #[no_mangle]
quiche_config_enable_dgram( config: &mut Config, enabled: bool, recv_queue_len: size_t, send_queue_len: size_t, )341 pub extern fn quiche_config_enable_dgram(
342     config: &mut Config, enabled: bool, recv_queue_len: size_t,
343     send_queue_len: size_t,
344 ) {
345     config.enable_dgram(enabled, recv_queue_len, send_queue_len);
346 }
347 
348 #[no_mangle]
quiche_config_set_max_send_udp_payload_size( config: &mut Config, v: size_t, )349 pub extern fn quiche_config_set_max_send_udp_payload_size(
350     config: &mut Config, v: size_t,
351 ) {
352     config.set_max_send_udp_payload_size(v);
353 }
354 
355 #[no_mangle]
quiche_config_set_max_connection_window( config: &mut Config, v: u64, )356 pub extern fn quiche_config_set_max_connection_window(
357     config: &mut Config, v: u64,
358 ) {
359     config.set_max_connection_window(v);
360 }
361 
362 #[no_mangle]
quiche_config_set_max_stream_window(config: &mut Config, v: u64)363 pub extern fn quiche_config_set_max_stream_window(config: &mut Config, v: u64) {
364     config.set_max_stream_window(v);
365 }
366 
367 #[no_mangle]
quiche_config_set_active_connection_id_limit( config: &mut Config, v: u64, )368 pub extern fn quiche_config_set_active_connection_id_limit(
369     config: &mut Config, v: u64,
370 ) {
371     config.set_active_connection_id_limit(v);
372 }
373 
374 #[no_mangle]
quiche_config_set_stateless_reset_token( config: &mut Config, v: *const u8, )375 pub extern fn quiche_config_set_stateless_reset_token(
376     config: &mut Config, v: *const u8,
377 ) {
378     let reset_token = unsafe { slice::from_raw_parts(v, 16) };
379     let reset_token = match reset_token.try_into() {
380         Ok(rt) => rt,
381         Err(_) => unreachable!(),
382     };
383     let reset_token = u128::from_be_bytes(reset_token);
384     config.set_stateless_reset_token(Some(reset_token));
385 }
386 
387 #[no_mangle]
quiche_config_free(config: *mut Config)388 pub extern fn quiche_config_free(config: *mut Config) {
389     unsafe { Box::from_raw(config) };
390 }
391 
392 #[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_int393 pub extern fn quiche_header_info(
394     buf: *mut u8, buf_len: size_t, dcil: size_t, version: *mut u32, ty: *mut u8,
395     scid: *mut u8, scid_len: *mut size_t, dcid: *mut u8, dcid_len: *mut size_t,
396     token: *mut u8, token_len: *mut size_t,
397 ) -> c_int {
398     let buf = unsafe { slice::from_raw_parts_mut(buf, buf_len) };
399     let hdr = match Header::from_slice(buf, dcil) {
400         Ok(v) => v,
401 
402         Err(e) => return e.to_c() as c_int,
403     };
404 
405     unsafe {
406         *version = hdr.version;
407 
408         *ty = match hdr.ty {
409             Type::Initial => 1,
410             Type::Retry => 2,
411             Type::Handshake => 3,
412             Type::ZeroRTT => 4,
413             Type::Short => 5,
414             Type::VersionNegotiation => 6,
415         };
416 
417         if *scid_len < hdr.scid.len() {
418             return -1;
419         }
420 
421         let scid = slice::from_raw_parts_mut(scid, *scid_len);
422         let scid = &mut scid[..hdr.scid.len()];
423         scid.copy_from_slice(&hdr.scid);
424 
425         *scid_len = hdr.scid.len();
426 
427         if *dcid_len < hdr.dcid.len() {
428             return -1;
429         }
430 
431         let dcid = slice::from_raw_parts_mut(dcid, *dcid_len);
432         let dcid = &mut dcid[..hdr.dcid.len()];
433         dcid.copy_from_slice(&hdr.dcid);
434 
435         *dcid_len = hdr.dcid.len();
436 
437         match hdr.token {
438             Some(tok) => {
439                 if *token_len < tok.len() {
440                     return -1;
441                 }
442 
443                 let token = slice::from_raw_parts_mut(token, *token_len);
444                 let token = &mut token[..tok.len()];
445                 token.copy_from_slice(&tok);
446 
447                 *token_len = tok.len();
448             },
449 
450             None => *token_len = 0,
451         }
452     }
453 
454     0
455 }
456 
457 #[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 Connection458 pub extern fn quiche_accept(
459     scid: *const u8, scid_len: size_t, odcid: *const u8, odcid_len: size_t,
460     local: &sockaddr, local_len: socklen_t, peer: &sockaddr, peer_len: socklen_t,
461     config: &mut Config,
462 ) -> *mut Connection {
463     let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
464     let scid = ConnectionId::from_ref(scid);
465 
466     let odcid = if !odcid.is_null() && odcid_len > 0 {
467         Some(ConnectionId::from_ref(unsafe {
468             slice::from_raw_parts(odcid, odcid_len)
469         }))
470     } else {
471         None
472     };
473 
474     let local = std_addr_from_c(local, local_len);
475     let peer = std_addr_from_c(peer, peer_len);
476 
477     match accept(&scid, odcid.as_ref(), local, peer, config) {
478         Ok(c) => Box::into_raw(Box::new(c)),
479 
480         Err(_) => ptr::null_mut(),
481     }
482 }
483 
484 #[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 Connection485 pub extern fn quiche_connect(
486     server_name: *const c_char, scid: *const u8, scid_len: size_t,
487     local: &sockaddr, local_len: socklen_t, peer: &sockaddr, peer_len: socklen_t,
488     config: &mut Config,
489 ) -> *mut Connection {
490     let server_name = if server_name.is_null() {
491         None
492     } else {
493         Some(unsafe { ffi::CStr::from_ptr(server_name).to_str().unwrap() })
494     };
495 
496     let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
497     let scid = ConnectionId::from_ref(scid);
498 
499     let local = std_addr_from_c(local, local_len);
500     let peer = std_addr_from_c(peer, peer_len);
501 
502     match connect(server_name, &scid, local, peer, config) {
503         Ok(c) => Box::into_raw(Box::new(c)),
504 
505         Err(_) => ptr::null_mut(),
506     }
507 }
508 
509 #[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_t510 pub extern fn quiche_negotiate_version(
511     scid: *const u8, scid_len: size_t, dcid: *const u8, dcid_len: size_t,
512     out: *mut u8, out_len: size_t,
513 ) -> ssize_t {
514     let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
515     let scid = ConnectionId::from_ref(scid);
516 
517     let dcid = unsafe { slice::from_raw_parts(dcid, dcid_len) };
518     let dcid = ConnectionId::from_ref(dcid);
519 
520     let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
521 
522     match negotiate_version(&scid, &dcid, out) {
523         Ok(v) => v as ssize_t,
524 
525         Err(e) => e.to_c(),
526     }
527 }
528 
529 #[no_mangle]
quiche_version_is_supported(version: u32) -> bool530 pub extern fn quiche_version_is_supported(version: u32) -> bool {
531     version_is_supported(version)
532 }
533 
534 #[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_t535 pub extern fn quiche_retry(
536     scid: *const u8, scid_len: size_t, dcid: *const u8, dcid_len: size_t,
537     new_scid: *const u8, new_scid_len: size_t, token: *const u8,
538     token_len: size_t, version: u32, out: *mut u8, out_len: size_t,
539 ) -> ssize_t {
540     let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
541     let scid = ConnectionId::from_ref(scid);
542 
543     let dcid = unsafe { slice::from_raw_parts(dcid, dcid_len) };
544     let dcid = ConnectionId::from_ref(dcid);
545 
546     let new_scid = unsafe { slice::from_raw_parts(new_scid, new_scid_len) };
547     let new_scid = ConnectionId::from_ref(new_scid);
548 
549     let token = unsafe { slice::from_raw_parts(token, token_len) };
550     let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
551 
552     match retry(&scid, &dcid, &new_scid, token, version, out) {
553         Ok(v) => v as ssize_t,
554 
555         Err(e) => e.to_c(),
556     }
557 }
558 
559 #[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 Connection560 pub extern fn quiche_conn_new_with_tls(
561     scid: *const u8, scid_len: size_t, odcid: *const u8, odcid_len: size_t,
562     local: &sockaddr, local_len: socklen_t, peer: &sockaddr, peer_len: socklen_t,
563     config: &mut Config, ssl: *mut c_void, is_server: bool,
564 ) -> *mut Connection {
565     let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
566     let scid = ConnectionId::from_ref(scid);
567 
568     let odcid = if !odcid.is_null() && odcid_len > 0 {
569         Some(ConnectionId::from_ref(unsafe {
570             slice::from_raw_parts(odcid, odcid_len)
571         }))
572     } else {
573         None
574     };
575 
576     let local = std_addr_from_c(local, local_len);
577     let peer = std_addr_from_c(peer, peer_len);
578 
579     let tls = unsafe { tls::Handshake::from_ptr(ssl) };
580 
581     match Connection::with_tls(
582         &scid,
583         odcid.as_ref(),
584         local,
585         peer,
586         config,
587         tls,
588         is_server,
589     ) {
590         Ok(c) => Box::into_raw(Box::new(c)),
591 
592         Err(_) => ptr::null_mut(),
593     }
594 }
595 
596 #[no_mangle]
quiche_conn_set_keylog_path( conn: &mut Connection, path: *const c_char, ) -> bool597 pub extern fn quiche_conn_set_keylog_path(
598     conn: &mut Connection, path: *const c_char,
599 ) -> bool {
600     let filename = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
601 
602     let file = std::fs::OpenOptions::new()
603         .create(true)
604         .append(true)
605         .open(filename);
606 
607     let writer = match file {
608         Ok(f) => std::io::BufWriter::new(f),
609 
610         Err(_) => return false,
611     };
612 
613     conn.set_keylog(Box::new(writer));
614 
615     true
616 }
617 
618 #[no_mangle]
619 #[cfg(unix)]
quiche_conn_set_keylog_fd(conn: &mut Connection, fd: c_int)620 pub extern fn quiche_conn_set_keylog_fd(conn: &mut Connection, fd: c_int) {
621     let f = unsafe { std::fs::File::from_raw_fd(fd) };
622     let writer = std::io::BufWriter::new(f);
623 
624     conn.set_keylog(Box::new(writer));
625 }
626 
627 #[no_mangle]
628 #[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, ) -> bool629 pub extern fn quiche_conn_set_qlog_path(
630     conn: &mut Connection, path: *const c_char, log_title: *const c_char,
631     log_desc: *const c_char,
632 ) -> bool {
633     let filename = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
634 
635     let file = std::fs::OpenOptions::new()
636         .write(true)
637         .create_new(true)
638         .open(filename);
639 
640     let writer = match file {
641         Ok(f) => std::io::BufWriter::new(f),
642 
643         Err(_) => return false,
644     };
645 
646     let title = unsafe { ffi::CStr::from_ptr(log_title).to_str().unwrap() };
647     let description = unsafe { ffi::CStr::from_ptr(log_desc).to_str().unwrap() };
648 
649     conn.set_qlog(
650         Box::new(writer),
651         title.to_string(),
652         format!("{} id={}", description, conn.trace_id),
653     );
654 
655     true
656 }
657 
658 #[no_mangle]
659 #[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, )660 pub extern fn quiche_conn_set_qlog_fd(
661     conn: &mut Connection, fd: c_int, log_title: *const c_char,
662     log_desc: *const c_char,
663 ) {
664     let f = unsafe { std::fs::File::from_raw_fd(fd) };
665     let writer = std::io::BufWriter::new(f);
666 
667     let title = unsafe { ffi::CStr::from_ptr(log_title).to_str().unwrap() };
668     let description = unsafe { ffi::CStr::from_ptr(log_desc).to_str().unwrap() };
669 
670     conn.set_qlog(
671         Box::new(writer),
672         title.to_string(),
673         format!("{} id={}", description, conn.trace_id),
674     );
675 }
676 
677 #[no_mangle]
quiche_conn_set_session( conn: &mut Connection, buf: *const u8, buf_len: size_t, ) -> c_int678 pub extern fn quiche_conn_set_session(
679     conn: &mut Connection, buf: *const u8, buf_len: size_t,
680 ) -> c_int {
681     let buf = unsafe { slice::from_raw_parts(buf, buf_len) };
682 
683     match conn.set_session(buf) {
684         Ok(_) => 0,
685 
686         Err(e) => e.to_c() as c_int,
687     }
688 }
689 
690 #[repr(C)]
691 pub struct RecvInfo<'a> {
692     from: &'a sockaddr,
693     from_len: socklen_t,
694     to: &'a sockaddr,
695     to_len: socklen_t,
696 }
697 
698 impl<'a> From<&RecvInfo<'a>> for crate::RecvInfo {
from(info: &RecvInfo) -> crate::RecvInfo699     fn from(info: &RecvInfo) -> crate::RecvInfo {
700         crate::RecvInfo {
701             from: std_addr_from_c(info.from, info.from_len),
702             to: std_addr_from_c(info.to, info.to_len),
703         }
704     }
705 }
706 
707 #[no_mangle]
quiche_conn_recv( conn: &mut Connection, buf: *mut u8, buf_len: size_t, info: &RecvInfo, ) -> ssize_t708 pub extern fn quiche_conn_recv(
709     conn: &mut Connection, buf: *mut u8, buf_len: size_t, info: &RecvInfo,
710 ) -> ssize_t {
711     if buf_len > <ssize_t>::max_value() as usize {
712         panic!("The provided buffer is too large");
713     }
714 
715     let buf = unsafe { slice::from_raw_parts_mut(buf, buf_len) };
716 
717     match conn.recv(buf, info.into()) {
718         Ok(v) => v as ssize_t,
719 
720         Err(e) => e.to_c(),
721     }
722 }
723 
724 #[repr(C)]
725 pub struct SendInfo {
726     from: sockaddr_storage,
727     from_len: socklen_t,
728     to: sockaddr_storage,
729     to_len: socklen_t,
730 
731     at: timespec,
732 }
733 
734 #[no_mangle]
quiche_conn_send( conn: &mut Connection, out: *mut u8, out_len: size_t, out_info: &mut SendInfo, ) -> ssize_t735 pub extern fn quiche_conn_send(
736     conn: &mut Connection, out: *mut u8, out_len: size_t, out_info: &mut SendInfo,
737 ) -> ssize_t {
738     if out_len > <ssize_t>::max_value() as usize {
739         panic!("The provided buffer is too large");
740     }
741 
742     let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
743 
744     match conn.send(out) {
745         Ok((v, info)) => {
746             out_info.from_len = std_addr_to_c(&info.from, &mut out_info.from);
747             out_info.to_len = std_addr_to_c(&info.to, &mut out_info.to);
748 
749             std_time_to_c(&info.at, &mut out_info.at);
750 
751             v as ssize_t
752         },
753 
754         Err(e) => e.to_c(),
755     }
756 }
757 
758 #[no_mangle]
quiche_conn_stream_recv( conn: &mut Connection, stream_id: u64, out: *mut u8, out_len: size_t, fin: &mut bool, ) -> ssize_t759 pub extern fn quiche_conn_stream_recv(
760     conn: &mut Connection, stream_id: u64, out: *mut u8, out_len: size_t,
761     fin: &mut bool,
762 ) -> ssize_t {
763     if out_len > <ssize_t>::max_value() as usize {
764         panic!("The provided buffer is too large");
765     }
766 
767     let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
768 
769     let (out_len, out_fin) = match conn.stream_recv(stream_id, out) {
770         Ok(v) => v,
771 
772         Err(e) => return e.to_c(),
773     };
774 
775     *fin = out_fin;
776 
777     out_len as ssize_t
778 }
779 
780 #[no_mangle]
quiche_conn_stream_send( conn: &mut Connection, stream_id: u64, buf: *const u8, buf_len: size_t, fin: bool, ) -> ssize_t781 pub extern fn quiche_conn_stream_send(
782     conn: &mut Connection, stream_id: u64, buf: *const u8, buf_len: size_t,
783     fin: bool,
784 ) -> ssize_t {
785     if buf_len > <ssize_t>::max_value() as usize {
786         panic!("The provided buffer is too large");
787     }
788 
789     let buf = unsafe { slice::from_raw_parts(buf, buf_len) };
790 
791     match conn.stream_send(stream_id, buf, fin) {
792         Ok(v) => v as ssize_t,
793 
794         Err(e) => e.to_c(),
795     }
796 }
797 
798 #[no_mangle]
quiche_conn_stream_priority( conn: &mut Connection, stream_id: u64, urgency: u8, incremental: bool, ) -> c_int799 pub extern fn quiche_conn_stream_priority(
800     conn: &mut Connection, stream_id: u64, urgency: u8, incremental: bool,
801 ) -> c_int {
802     match conn.stream_priority(stream_id, urgency, incremental) {
803         Ok(_) => 0,
804 
805         Err(e) => e.to_c() as c_int,
806     }
807 }
808 
809 #[no_mangle]
quiche_conn_stream_shutdown( conn: &mut Connection, stream_id: u64, direction: Shutdown, err: u64, ) -> c_int810 pub extern fn quiche_conn_stream_shutdown(
811     conn: &mut Connection, stream_id: u64, direction: Shutdown, err: u64,
812 ) -> c_int {
813     match conn.stream_shutdown(stream_id, direction, err) {
814         Ok(_) => 0,
815 
816         Err(e) => e.to_c() as c_int,
817     }
818 }
819 
820 #[no_mangle]
quiche_conn_stream_capacity( conn: &Connection, stream_id: u64, ) -> ssize_t821 pub extern fn quiche_conn_stream_capacity(
822     conn: &Connection, stream_id: u64,
823 ) -> ssize_t {
824     match conn.stream_capacity(stream_id) {
825         Ok(v) => v as ssize_t,
826 
827         Err(e) => e.to_c(),
828     }
829 }
830 
831 #[no_mangle]
quiche_conn_stream_readable( conn: &Connection, stream_id: u64, ) -> bool832 pub extern fn quiche_conn_stream_readable(
833     conn: &Connection, stream_id: u64,
834 ) -> bool {
835     conn.stream_readable(stream_id)
836 }
837 
838 #[no_mangle]
quiche_conn_stream_readable_next(conn: &mut Connection) -> i64839 pub extern fn quiche_conn_stream_readable_next(conn: &mut Connection) -> i64 {
840     conn.stream_readable_next().map(|v| v as i64).unwrap_or(-1)
841 }
842 
843 #[no_mangle]
quiche_conn_stream_writable( conn: &mut Connection, stream_id: u64, len: usize, ) -> c_int844 pub extern fn quiche_conn_stream_writable(
845     conn: &mut Connection, stream_id: u64, len: usize,
846 ) -> c_int {
847     match conn.stream_writable(stream_id, len) {
848         Ok(true) => 1,
849 
850         Ok(false) => 0,
851 
852         Err(e) => e.to_c() as c_int,
853     }
854 }
855 
856 #[no_mangle]
quiche_conn_stream_writable_next(conn: &mut Connection) -> i64857 pub extern fn quiche_conn_stream_writable_next(conn: &mut Connection) -> i64 {
858     conn.stream_writable_next().map(|v| v as i64).unwrap_or(-1)
859 }
860 
861 #[no_mangle]
quiche_conn_stream_finished( conn: &Connection, stream_id: u64, ) -> bool862 pub extern fn quiche_conn_stream_finished(
863     conn: &Connection, stream_id: u64,
864 ) -> bool {
865     conn.stream_finished(stream_id)
866 }
867 
868 #[no_mangle]
quiche_conn_readable(conn: &Connection) -> *mut StreamIter869 pub extern fn quiche_conn_readable(conn: &Connection) -> *mut StreamIter {
870     Box::into_raw(Box::new(conn.readable()))
871 }
872 
873 #[no_mangle]
quiche_conn_writable(conn: &Connection) -> *mut StreamIter874 pub extern fn quiche_conn_writable(conn: &Connection) -> *mut StreamIter {
875     Box::into_raw(Box::new(conn.writable()))
876 }
877 
878 #[no_mangle]
quiche_conn_max_send_udp_payload_size(conn: &Connection) -> usize879 pub extern fn quiche_conn_max_send_udp_payload_size(conn: &Connection) -> usize {
880     conn.max_send_udp_payload_size()
881 }
882 
883 #[no_mangle]
quiche_conn_is_readable(conn: &Connection) -> bool884 pub extern fn quiche_conn_is_readable(conn: &Connection) -> bool {
885     conn.is_readable()
886 }
887 
888 struct AppData(*mut c_void);
889 unsafe impl Send for AppData {}
890 unsafe impl Sync for AppData {}
891 
892 #[no_mangle]
quiche_conn_stream_init_application_data( conn: &mut Connection, stream_id: u64, data: *mut c_void, ) -> c_int893 pub extern fn quiche_conn_stream_init_application_data(
894     conn: &mut Connection, stream_id: u64, data: *mut c_void,
895 ) -> c_int {
896     match conn.stream_init_application_data(stream_id, AppData(data)) {
897         Ok(_) => 0,
898 
899         Err(e) => e.to_c() as c_int,
900     }
901 }
902 
903 #[no_mangle]
quiche_conn_stream_application_data( conn: &mut Connection, stream_id: u64, ) -> *mut c_void904 pub extern fn quiche_conn_stream_application_data(
905     conn: &mut Connection, stream_id: u64,
906 ) -> *mut c_void {
907     match conn.stream_application_data(stream_id) {
908         Some(v) => v.downcast_mut::<AppData>().unwrap().0,
909 
910         None => ptr::null_mut(),
911     }
912 }
913 
914 #[no_mangle]
quiche_conn_close( conn: &mut Connection, app: bool, err: u64, reason: *const u8, reason_len: size_t, ) -> c_int915 pub extern fn quiche_conn_close(
916     conn: &mut Connection, app: bool, err: u64, reason: *const u8,
917     reason_len: size_t,
918 ) -> c_int {
919     let reason = unsafe { slice::from_raw_parts(reason, reason_len) };
920 
921     match conn.close(app, err, reason) {
922         Ok(_) => 0,
923 
924         Err(e) => e.to_c() as c_int,
925     }
926 }
927 
928 #[no_mangle]
quiche_conn_timeout_as_nanos(conn: &Connection) -> u64929 pub extern fn quiche_conn_timeout_as_nanos(conn: &Connection) -> u64 {
930     match conn.timeout() {
931         Some(timeout) => timeout.as_nanos() as u64,
932 
933         None => u64::MAX,
934     }
935 }
936 
937 #[no_mangle]
quiche_conn_timeout_as_millis(conn: &Connection) -> u64938 pub extern fn quiche_conn_timeout_as_millis(conn: &Connection) -> u64 {
939     match conn.timeout() {
940         Some(timeout) => timeout.as_millis() as u64,
941 
942         None => u64::MAX,
943     }
944 }
945 
946 #[no_mangle]
quiche_conn_on_timeout(conn: &mut Connection)947 pub extern fn quiche_conn_on_timeout(conn: &mut Connection) {
948     conn.on_timeout()
949 }
950 
951 #[no_mangle]
quiche_conn_trace_id( conn: &Connection, out: &mut *const u8, out_len: &mut size_t, )952 pub extern fn quiche_conn_trace_id(
953     conn: &Connection, out: &mut *const u8, out_len: &mut size_t,
954 ) {
955     let trace_id = conn.trace_id();
956 
957     *out = trace_id.as_ptr();
958     *out_len = trace_id.len();
959 }
960 
961 #[no_mangle]
quiche_conn_source_id( conn: &Connection, out: &mut *const u8, out_len: &mut size_t, )962 pub extern fn quiche_conn_source_id(
963     conn: &Connection, out: &mut *const u8, out_len: &mut size_t,
964 ) {
965     let conn_id = conn.source_id();
966     let id = conn_id.as_ref();
967     *out = id.as_ptr();
968     *out_len = id.len();
969 }
970 
971 #[no_mangle]
quiche_conn_destination_id( conn: &Connection, out: &mut *const u8, out_len: &mut size_t, )972 pub extern fn quiche_conn_destination_id(
973     conn: &Connection, out: &mut *const u8, out_len: &mut size_t,
974 ) {
975     let conn_id = conn.destination_id();
976     let id = conn_id.as_ref();
977 
978     *out = id.as_ptr();
979     *out_len = id.len();
980 }
981 
982 #[no_mangle]
quiche_conn_application_proto( conn: &Connection, out: &mut *const u8, out_len: &mut size_t, )983 pub extern fn quiche_conn_application_proto(
984     conn: &Connection, out: &mut *const u8, out_len: &mut size_t,
985 ) {
986     let proto = conn.application_proto();
987 
988     *out = proto.as_ptr();
989     *out_len = proto.len();
990 }
991 
992 #[no_mangle]
quiche_conn_peer_cert( conn: &Connection, out: &mut *const u8, out_len: &mut size_t, )993 pub extern fn quiche_conn_peer_cert(
994     conn: &Connection, out: &mut *const u8, out_len: &mut size_t,
995 ) {
996     match conn.peer_cert() {
997         Some(peer_cert) => {
998             *out = peer_cert.as_ptr();
999             *out_len = peer_cert.len();
1000         },
1001 
1002         None => *out_len = 0,
1003     }
1004 }
1005 
1006 #[no_mangle]
quiche_conn_session( conn: &Connection, out: &mut *const u8, out_len: &mut size_t, )1007 pub extern fn quiche_conn_session(
1008     conn: &Connection, out: &mut *const u8, out_len: &mut size_t,
1009 ) {
1010     match conn.session() {
1011         Some(session) => {
1012             *out = session.as_ptr();
1013             *out_len = session.len();
1014         },
1015 
1016         None => *out_len = 0,
1017     }
1018 }
1019 
1020 #[no_mangle]
quiche_conn_is_established(conn: &Connection) -> bool1021 pub extern fn quiche_conn_is_established(conn: &Connection) -> bool {
1022     conn.is_established()
1023 }
1024 
1025 #[no_mangle]
quiche_conn_is_in_early_data(conn: &Connection) -> bool1026 pub extern fn quiche_conn_is_in_early_data(conn: &Connection) -> bool {
1027     conn.is_in_early_data()
1028 }
1029 
1030 #[no_mangle]
quiche_conn_is_draining(conn: &Connection) -> bool1031 pub extern fn quiche_conn_is_draining(conn: &Connection) -> bool {
1032     conn.is_draining()
1033 }
1034 
1035 #[no_mangle]
quiche_conn_is_closed(conn: &Connection) -> bool1036 pub extern fn quiche_conn_is_closed(conn: &Connection) -> bool {
1037     conn.is_closed()
1038 }
1039 
1040 #[no_mangle]
quiche_conn_is_timed_out(conn: &Connection) -> bool1041 pub extern fn quiche_conn_is_timed_out(conn: &Connection) -> bool {
1042     conn.is_timed_out()
1043 }
1044 
1045 #[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, ) -> bool1046 pub extern fn quiche_conn_peer_error(
1047     conn: &Connection, is_app: *mut bool, error_code: *mut u64,
1048     reason: &mut *const u8, reason_len: &mut size_t,
1049 ) -> bool {
1050     match &conn.peer_error {
1051         Some(conn_err) => unsafe {
1052             *is_app = conn_err.is_app;
1053             *error_code = conn_err.error_code;
1054             *reason = conn_err.reason.as_ptr();
1055             *reason_len = conn_err.reason.len();
1056 
1057             true
1058         },
1059 
1060         None => false,
1061     }
1062 }
1063 
1064 #[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, ) -> bool1065 pub extern fn quiche_conn_local_error(
1066     conn: &Connection, is_app: *mut bool, error_code: *mut u64,
1067     reason: &mut *const u8, reason_len: &mut size_t,
1068 ) -> bool {
1069     match &conn.local_error {
1070         Some(conn_err) => unsafe {
1071             *is_app = conn_err.is_app;
1072             *error_code = conn_err.error_code;
1073             *reason = conn_err.reason.as_ptr();
1074             *reason_len = conn_err.reason.len();
1075 
1076             true
1077         },
1078 
1079         None => false,
1080     }
1081 }
1082 
1083 #[no_mangle]
quiche_stream_iter_next( iter: &mut StreamIter, stream_id: *mut u64, ) -> bool1084 pub extern fn quiche_stream_iter_next(
1085     iter: &mut StreamIter, stream_id: *mut u64,
1086 ) -> bool {
1087     if let Some(v) = iter.next() {
1088         unsafe { *stream_id = v };
1089         return true;
1090     }
1091 
1092     false
1093 }
1094 
1095 #[no_mangle]
quiche_stream_iter_free(iter: *mut StreamIter)1096 pub extern fn quiche_stream_iter_free(iter: *mut StreamIter) {
1097     unsafe { Box::from_raw(iter) };
1098 }
1099 
1100 #[repr(C)]
1101 pub struct Stats {
1102     recv: usize,
1103     sent: usize,
1104     lost: usize,
1105     retrans: usize,
1106     sent_bytes: u64,
1107     recv_bytes: u64,
1108     lost_bytes: u64,
1109     stream_retrans_bytes: u64,
1110     paths_count: usize,
1111     peer_max_idle_timeout: u64,
1112     peer_max_udp_payload_size: u64,
1113     peer_initial_max_data: u64,
1114     peer_initial_max_stream_data_bidi_local: u64,
1115     peer_initial_max_stream_data_bidi_remote: u64,
1116     peer_initial_max_stream_data_uni: u64,
1117     peer_initial_max_streams_bidi: u64,
1118     peer_initial_max_streams_uni: u64,
1119     peer_ack_delay_exponent: u64,
1120     peer_max_ack_delay: u64,
1121     peer_disable_active_migration: bool,
1122     peer_active_conn_id_limit: u64,
1123     peer_max_datagram_frame_size: ssize_t,
1124     paths: [PathStats; 8],
1125 }
1126 
1127 #[no_mangle]
quiche_conn_stats(conn: &Connection, out: &mut Stats)1128 pub extern fn quiche_conn_stats(conn: &Connection, out: &mut Stats) {
1129     let stats = conn.stats();
1130 
1131     out.recv = stats.recv;
1132     out.sent = stats.sent;
1133     out.lost = stats.lost;
1134     out.retrans = stats.retrans;
1135     out.sent_bytes = stats.sent_bytes;
1136     out.recv_bytes = stats.recv_bytes;
1137     out.lost_bytes = stats.lost_bytes;
1138     out.stream_retrans_bytes = stats.stream_retrans_bytes;
1139     out.paths_count = stats.paths_count;
1140     out.peer_max_idle_timeout = stats.peer_max_idle_timeout;
1141     out.peer_max_udp_payload_size = stats.peer_max_udp_payload_size;
1142     out.peer_initial_max_data = stats.peer_initial_max_data;
1143     out.peer_initial_max_stream_data_bidi_local =
1144         stats.peer_initial_max_stream_data_bidi_local;
1145     out.peer_initial_max_stream_data_bidi_remote =
1146         stats.peer_initial_max_stream_data_bidi_remote;
1147     out.peer_initial_max_stream_data_uni = stats.peer_initial_max_stream_data_uni;
1148     out.peer_initial_max_streams_bidi = stats.peer_initial_max_streams_bidi;
1149     out.peer_initial_max_streams_uni = stats.peer_initial_max_streams_uni;
1150     out.peer_ack_delay_exponent = stats.peer_ack_delay_exponent;
1151     out.peer_max_ack_delay = stats.peer_max_ack_delay;
1152     out.peer_disable_active_migration = stats.peer_disable_active_migration;
1153     out.peer_active_conn_id_limit = stats.peer_active_conn_id_limit;
1154     out.peer_max_datagram_frame_size = match stats.peer_max_datagram_frame_size {
1155         None => Error::Done.to_c(),
1156 
1157         Some(v) => v as ssize_t,
1158     };
1159 }
1160 
1161 #[repr(C)]
1162 pub struct PathStats {
1163     local_addr: sockaddr_storage,
1164     local_addr_len: socklen_t,
1165     peer_addr: sockaddr_storage,
1166     peer_addr_len: socklen_t,
1167     validation_state: ssize_t,
1168     active: bool,
1169     recv: usize,
1170     sent: usize,
1171     lost: usize,
1172     retrans: usize,
1173     rtt: u64,
1174     cwnd: usize,
1175     sent_bytes: u64,
1176     recv_bytes: u64,
1177     lost_bytes: u64,
1178     stream_retrans_bytes: u64,
1179     pmtu: usize,
1180     delivery_rate: u64,
1181 }
1182 
1183 #[no_mangle]
quiche_conn_path_stats( conn: &Connection, idx: usize, out: &mut PathStats, ) -> c_int1184 pub extern fn quiche_conn_path_stats(
1185     conn: &Connection, idx: usize, out: &mut PathStats,
1186 ) -> c_int {
1187     let stats = match conn.path_stats().nth(idx) {
1188         Some(p) => p,
1189         None => return Error::Done.to_c() as c_int,
1190     };
1191 
1192     out.local_addr_len = std_addr_to_c(&stats.local_addr, &mut out.local_addr);
1193     out.peer_addr_len = std_addr_to_c(&stats.peer_addr, &mut out.peer_addr);
1194     out.validation_state = stats.validation_state.to_c();
1195     out.active = stats.active;
1196     out.recv = stats.recv;
1197     out.sent = stats.sent;
1198     out.lost = stats.lost;
1199     out.retrans = stats.retrans;
1200     out.rtt = stats.rtt.as_nanos() as u64;
1201     out.cwnd = stats.cwnd;
1202     out.sent_bytes = stats.sent_bytes;
1203     out.recv_bytes = stats.recv_bytes;
1204     out.lost_bytes = stats.lost_bytes;
1205     out.stream_retrans_bytes = stats.stream_retrans_bytes;
1206     out.pmtu = stats.pmtu;
1207     out.delivery_rate = stats.delivery_rate;
1208 
1209     0
1210 }
1211 
1212 #[no_mangle]
quiche_conn_dgram_max_writable_len(conn: &Connection) -> ssize_t1213 pub extern fn quiche_conn_dgram_max_writable_len(conn: &Connection) -> ssize_t {
1214     match conn.dgram_max_writable_len() {
1215         None => Error::Done.to_c(),
1216 
1217         Some(v) => v as ssize_t,
1218     }
1219 }
1220 
1221 #[no_mangle]
quiche_conn_dgram_recv_front_len(conn: &Connection) -> ssize_t1222 pub extern fn quiche_conn_dgram_recv_front_len(conn: &Connection) -> ssize_t {
1223     match conn.dgram_recv_front_len() {
1224         None => Error::Done.to_c(),
1225 
1226         Some(v) => v as ssize_t,
1227     }
1228 }
1229 
1230 #[no_mangle]
quiche_conn_dgram_recv_queue_len(conn: &Connection) -> ssize_t1231 pub extern fn quiche_conn_dgram_recv_queue_len(conn: &Connection) -> ssize_t {
1232     conn.dgram_recv_queue_len() as ssize_t
1233 }
1234 
1235 #[no_mangle]
quiche_conn_dgram_recv_queue_byte_size( conn: &Connection, ) -> ssize_t1236 pub extern fn quiche_conn_dgram_recv_queue_byte_size(
1237     conn: &Connection,
1238 ) -> ssize_t {
1239     conn.dgram_recv_queue_byte_size() as ssize_t
1240 }
1241 
1242 #[no_mangle]
quiche_conn_dgram_send_queue_len(conn: &Connection) -> ssize_t1243 pub extern fn quiche_conn_dgram_send_queue_len(conn: &Connection) -> ssize_t {
1244     conn.dgram_send_queue_len() as ssize_t
1245 }
1246 
1247 #[no_mangle]
quiche_conn_dgram_send_queue_byte_size( conn: &Connection, ) -> ssize_t1248 pub extern fn quiche_conn_dgram_send_queue_byte_size(
1249     conn: &Connection,
1250 ) -> ssize_t {
1251     conn.dgram_send_queue_byte_size() as ssize_t
1252 }
1253 
1254 #[no_mangle]
quiche_conn_dgram_send( conn: &mut Connection, buf: *const u8, buf_len: size_t, ) -> ssize_t1255 pub extern fn quiche_conn_dgram_send(
1256     conn: &mut Connection, buf: *const u8, buf_len: size_t,
1257 ) -> ssize_t {
1258     if buf_len > <ssize_t>::max_value() as usize {
1259         panic!("The provided buffer is too large");
1260     }
1261 
1262     let buf = unsafe { slice::from_raw_parts(buf, buf_len) };
1263 
1264     match conn.dgram_send(buf) {
1265         Ok(_) => buf_len as ssize_t,
1266 
1267         Err(e) => e.to_c(),
1268     }
1269 }
1270 
1271 #[no_mangle]
quiche_conn_dgram_recv( conn: &mut Connection, out: *mut u8, out_len: size_t, ) -> ssize_t1272 pub extern fn quiche_conn_dgram_recv(
1273     conn: &mut Connection, out: *mut u8, out_len: size_t,
1274 ) -> ssize_t {
1275     if out_len > <ssize_t>::max_value() as usize {
1276         panic!("The provided buffer is too large");
1277     }
1278 
1279     let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
1280 
1281     let out_len = match conn.dgram_recv(out) {
1282         Ok(v) => v,
1283 
1284         Err(e) => return e.to_c(),
1285     };
1286 
1287     out_len as ssize_t
1288 }
1289 
1290 #[no_mangle]
quiche_conn_dgram_purge_outgoing( conn: &mut Connection, f: extern fn(*const u8, size_t) -> bool, )1291 pub extern fn quiche_conn_dgram_purge_outgoing(
1292     conn: &mut Connection, f: extern fn(*const u8, size_t) -> bool,
1293 ) {
1294     conn.dgram_purge_outgoing(|d: &[u8]| -> bool {
1295         let ptr: *const u8 = d.as_ptr();
1296         let len: size_t = d.len();
1297 
1298         f(ptr, len)
1299     });
1300 }
1301 
1302 #[no_mangle]
quiche_conn_send_ack_eliciting(conn: &mut Connection) -> ssize_t1303 pub extern fn quiche_conn_send_ack_eliciting(conn: &mut Connection) -> ssize_t {
1304     match conn.send_ack_eliciting() {
1305         Ok(()) => 0,
1306         Err(e) => e.to_c(),
1307     }
1308 }
1309 
1310 #[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_t1311 pub extern fn quiche_conn_send_ack_eliciting_on_path(
1312     conn: &mut Connection, local: &sockaddr, local_len: socklen_t,
1313     peer: &sockaddr, peer_len: socklen_t,
1314 ) -> ssize_t {
1315     let local = std_addr_from_c(local, local_len);
1316     let peer = std_addr_from_c(peer, peer_len);
1317     match conn.send_ack_eliciting_on_path(local, peer) {
1318         Ok(()) => 0,
1319         Err(e) => e.to_c(),
1320     }
1321 }
1322 
1323 #[no_mangle]
quiche_conn_free(conn: *mut Connection)1324 pub extern fn quiche_conn_free(conn: *mut Connection) {
1325     unsafe { Box::from_raw(conn) };
1326 }
1327 
1328 #[no_mangle]
quiche_conn_peer_streams_left_bidi(conn: &Connection) -> u641329 pub extern fn quiche_conn_peer_streams_left_bidi(conn: &Connection) -> u64 {
1330     conn.peer_streams_left_bidi()
1331 }
1332 
1333 #[no_mangle]
quiche_conn_peer_streams_left_uni(conn: &Connection) -> u641334 pub extern fn quiche_conn_peer_streams_left_uni(conn: &Connection) -> u64 {
1335     conn.peer_streams_left_uni()
1336 }
1337 
1338 #[no_mangle]
quiche_conn_send_quantum(conn: &Connection) -> size_t1339 pub extern fn quiche_conn_send_quantum(conn: &Connection) -> size_t {
1340     conn.send_quantum() as size_t
1341 }
1342 
std_addr_from_c(addr: &sockaddr, addr_len: socklen_t) -> SocketAddr1343 fn std_addr_from_c(addr: &sockaddr, addr_len: socklen_t) -> SocketAddr {
1344     match addr.sa_family as i32 {
1345         AF_INET => {
1346             assert!(addr_len as usize == std::mem::size_of::<sockaddr_in>());
1347 
1348             let in4 = unsafe { *(addr as *const _ as *const sockaddr_in) };
1349 
1350             #[cfg(not(windows))]
1351             let ip_addr = Ipv4Addr::from(u32::from_be(in4.sin_addr.s_addr));
1352             #[cfg(windows)]
1353             let ip_addr = {
1354                 let ip_bytes = unsafe { in4.sin_addr.S_un.S_un_b() };
1355 
1356                 Ipv4Addr::from([
1357                     ip_bytes.s_b1,
1358                     ip_bytes.s_b2,
1359                     ip_bytes.s_b3,
1360                     ip_bytes.s_b4,
1361                 ])
1362             };
1363 
1364             let port = u16::from_be(in4.sin_port);
1365 
1366             let out = SocketAddrV4::new(ip_addr, port);
1367 
1368             out.into()
1369         },
1370 
1371         AF_INET6 => {
1372             assert!(addr_len as usize == std::mem::size_of::<sockaddr_in6>());
1373 
1374             let in6 = unsafe { *(addr as *const _ as *const sockaddr_in6) };
1375 
1376             let ip_addr = Ipv6Addr::from(
1377                 #[cfg(not(windows))]
1378                 in6.sin6_addr.s6_addr,
1379                 #[cfg(windows)]
1380                 *unsafe { in6.sin6_addr.u.Byte() },
1381             );
1382 
1383             let port = u16::from_be(in6.sin6_port);
1384 
1385             #[cfg(not(windows))]
1386             let scope_id = in6.sin6_scope_id;
1387             #[cfg(windows)]
1388             let scope_id = unsafe { *in6.u.sin6_scope_id() };
1389 
1390             let out =
1391                 SocketAddrV6::new(ip_addr, port, in6.sin6_flowinfo, scope_id);
1392 
1393             out.into()
1394         },
1395 
1396         _ => unimplemented!("unsupported address type"),
1397     }
1398 }
1399 
std_addr_to_c(addr: &SocketAddr, out: &mut sockaddr_storage) -> socklen_t1400 fn std_addr_to_c(addr: &SocketAddr, out: &mut sockaddr_storage) -> socklen_t {
1401     let sin_port = addr.port().to_be();
1402 
1403     match addr {
1404         SocketAddr::V4(addr) => unsafe {
1405             let sa_len = std::mem::size_of::<sockaddr_in>();
1406             let out_in = out as *mut _ as *mut sockaddr_in;
1407 
1408             let s_addr = u32::from_ne_bytes(addr.ip().octets());
1409 
1410             #[cfg(not(windows))]
1411             let sin_addr = in_addr { s_addr };
1412             #[cfg(windows)]
1413             let sin_addr = {
1414                 let mut s_un = std::mem::zeroed::<in_addr_S_un>();
1415                 *s_un.S_addr_mut() = s_addr;
1416                 in_addr { S_un: s_un }
1417             };
1418 
1419             *out_in = sockaddr_in {
1420                 sin_family: AF_INET as sa_family_t,
1421 
1422                 sin_addr,
1423 
1424                 #[cfg(any(
1425                     target_os = "macos",
1426                     target_os = "ios",
1427                     target_os = "watchos",
1428                     target_os = "freebsd",
1429                     target_os = "dragonfly",
1430                     target_os = "openbsd",
1431                     target_os = "netbsd"
1432                 ))]
1433                 sin_len: sa_len as u8,
1434 
1435                 sin_port,
1436 
1437                 sin_zero: std::mem::zeroed(),
1438             };
1439 
1440             sa_len as socklen_t
1441         },
1442 
1443         SocketAddr::V6(addr) => unsafe {
1444             let sa_len = std::mem::size_of::<sockaddr_in6>();
1445             let out_in6 = out as *mut _ as *mut sockaddr_in6;
1446 
1447             #[cfg(not(windows))]
1448             let sin6_addr = in6_addr {
1449                 s6_addr: addr.ip().octets(),
1450             };
1451             #[cfg(windows)]
1452             let sin6_addr = {
1453                 let mut u = std::mem::zeroed::<in6_addr_u>();
1454                 *u.Byte_mut() = addr.ip().octets();
1455                 in6_addr { u }
1456             };
1457 
1458             #[cfg(windows)]
1459             let u = {
1460                 let mut u = std::mem::zeroed::<SOCKADDR_IN6_LH_u>();
1461                 *u.sin6_scope_id_mut() = addr.scope_id();
1462                 u
1463             };
1464 
1465             *out_in6 = sockaddr_in6 {
1466                 sin6_family: AF_INET6 as sa_family_t,
1467 
1468                 sin6_addr,
1469 
1470                 #[cfg(any(
1471                     target_os = "macos",
1472                     target_os = "ios",
1473                     target_os = "watchos",
1474                     target_os = "freebsd",
1475                     target_os = "dragonfly",
1476                     target_os = "openbsd",
1477                     target_os = "netbsd"
1478                 ))]
1479                 sin6_len: sa_len as u8,
1480 
1481                 sin6_port: sin_port,
1482 
1483                 sin6_flowinfo: addr.flowinfo(),
1484 
1485                 #[cfg(not(windows))]
1486                 sin6_scope_id: addr.scope_id(),
1487                 #[cfg(windows)]
1488                 u,
1489             };
1490 
1491             sa_len as socklen_t
1492         },
1493     }
1494 }
1495 
1496 #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))]
std_time_to_c(time: &std::time::Instant, out: &mut timespec)1497 fn std_time_to_c(time: &std::time::Instant, out: &mut timespec) {
1498     unsafe {
1499         ptr::copy_nonoverlapping(time as *const _ as *const timespec, out, 1)
1500     }
1501 }
1502 
1503 #[cfg(any(target_os = "macos", target_os = "ios", target_os = "windows"))]
std_time_to_c(_time: &std::time::Instant, out: &mut timespec)1504 fn std_time_to_c(_time: &std::time::Instant, out: &mut timespec) {
1505     // TODO: implement Instant conversion for systems that don't use timespec.
1506     out.tv_sec = 0;
1507     out.tv_nsec = 0;
1508 }
1509 
1510 #[cfg(test)]
1511 mod tests {
1512     use super::*;
1513 
1514     #[cfg(windows)]
1515     use winapi::um::ws2tcpip::inet_ntop;
1516 
1517     #[test]
addr_v4()1518     fn addr_v4() {
1519         let addr = "127.0.0.1:8080".parse().unwrap();
1520 
1521         let mut out: sockaddr_storage = unsafe { std::mem::zeroed() };
1522 
1523         assert_eq!(
1524             std_addr_to_c(&addr, &mut out),
1525             std::mem::size_of::<sockaddr_in>() as socklen_t
1526         );
1527 
1528         let s = std::ffi::CString::new("ddd.ddd.ddd.ddd").unwrap();
1529 
1530         let s = unsafe {
1531             let in_addr = &out as *const _ as *const sockaddr_in;
1532             assert_eq!(u16::from_be((*in_addr).sin_port), addr.port());
1533 
1534             let dst = s.into_raw();
1535 
1536             inet_ntop(
1537                 AF_INET,
1538                 &((*in_addr).sin_addr) as *const _ as *const c_void,
1539                 dst,
1540                 16,
1541             );
1542 
1543             std::ffi::CString::from_raw(dst).into_string().unwrap()
1544         };
1545 
1546         assert_eq!(s, "127.0.0.1");
1547 
1548         let addr = unsafe {
1549             std_addr_from_c(
1550                 &*(&out as *const _ as *const sockaddr),
1551                 std::mem::size_of::<sockaddr_in>() as socklen_t,
1552             )
1553         };
1554 
1555         assert_eq!(addr, "127.0.0.1:8080".parse().unwrap());
1556     }
1557 
1558     #[test]
addr_v6()1559     fn addr_v6() {
1560         let addr = "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8080"
1561             .parse()
1562             .unwrap();
1563 
1564         let mut out: sockaddr_storage = unsafe { std::mem::zeroed() };
1565 
1566         assert_eq!(
1567             std_addr_to_c(&addr, &mut out),
1568             std::mem::size_of::<sockaddr_in6>() as socklen_t
1569         );
1570 
1571         let s = std::ffi::CString::new("dddd:dddd:dddd:dddd:dddd:dddd:dddd:dddd")
1572             .unwrap();
1573 
1574         let s = unsafe {
1575             let in6_addr = &out as *const _ as *const sockaddr_in6;
1576             assert_eq!(u16::from_be((*in6_addr).sin6_port), addr.port());
1577 
1578             let dst = s.into_raw();
1579 
1580             inet_ntop(
1581                 AF_INET6,
1582                 &((*in6_addr).sin6_addr) as *const _ as *const c_void,
1583                 dst,
1584                 45,
1585             );
1586 
1587             std::ffi::CString::from_raw(dst).into_string().unwrap()
1588         };
1589 
1590         assert_eq!(s, "2001:db8:85a3::8a2e:370:7334");
1591 
1592         let addr = unsafe {
1593             std_addr_from_c(
1594                 &*(&out as *const _ as *const sockaddr),
1595                 std::mem::size_of::<sockaddr_in6>() as socklen_t,
1596             )
1597         };
1598 
1599         assert_eq!(
1600             addr,
1601             "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8080"
1602                 .parse()
1603                 .unwrap()
1604         );
1605     }
1606 
1607     #[cfg(not(windows))]
1608     extern {
inet_ntop( af: c_int, src: *const c_void, dst: *mut c_char, size: socklen_t, ) -> *mut c_char1609         fn inet_ntop(
1610             af: c_int, src: *const c_void, dst: *mut c_char, size: socklen_t,
1611         ) -> *mut c_char;
1612     }
1613 }
1614