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 #[cfg(unix)]
33 use std::os::unix::io::FromRawFd;
34 
35 use libc::c_char;
36 use libc::c_int;
37 use libc::c_void;
38 use libc::size_t;
39 use libc::ssize_t;
40 
41 use crate::*;
42 
43 #[no_mangle]
quiche_version() -> *const u844 pub extern fn quiche_version() -> *const u8 {
45     //static VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), "\0");
46     // ANDROID's build system doesn't support environment variables
47     // so we hardcode the package version here.
48     static VERSION: &str = concat!("0.6.0", "\0");
49     VERSION.as_ptr()
50 }
51 
52 struct Logger {
53     cb: extern fn(line: *const u8, argp: *mut c_void),
54     argp: std::sync::atomic::AtomicPtr<c_void>,
55 }
56 
57 impl log::Log for Logger {
enabled(&self, _metadata: &log::Metadata) -> bool58     fn enabled(&self, _metadata: &log::Metadata) -> bool {
59         true
60     }
61 
log(&self, record: &log::Record)62     fn log(&self, record: &log::Record) {
63         let line = format!("{}: {}\0", record.target(), record.args());
64         (self.cb)(line.as_ptr(), self.argp.load(atomic::Ordering::Relaxed));
65     }
66 
flush(&self)67     fn flush(&self) {}
68 }
69 
70 #[no_mangle]
quiche_enable_debug_logging( cb: extern fn(line: *const u8, argp: *mut c_void), argp: *mut c_void, ) -> c_int71 pub extern fn quiche_enable_debug_logging(
72     cb: extern fn(line: *const u8, argp: *mut c_void), argp: *mut c_void,
73 ) -> c_int {
74     let argp = atomic::AtomicPtr::new(argp);
75     let logger = Box::new(Logger { cb, argp });
76 
77     if log::set_boxed_logger(logger).is_err() {
78         return -1;
79     }
80 
81     log::set_max_level(log::LevelFilter::Trace);
82 
83     0
84 }
85 
86 #[no_mangle]
quiche_config_new(version: u32) -> *mut Config87 pub extern fn quiche_config_new(version: u32) -> *mut Config {
88     match Config::new(version) {
89         Ok(c) => Box::into_raw(Box::new(c)),
90 
91         Err(_) => ptr::null_mut(),
92     }
93 }
94 
95 #[no_mangle]
quiche_config_load_cert_chain_from_pem_file( config: &mut Config, path: *const c_char, ) -> c_int96 pub extern fn quiche_config_load_cert_chain_from_pem_file(
97     config: &mut Config, path: *const c_char,
98 ) -> c_int {
99     let path = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
100 
101     match config.load_cert_chain_from_pem_file(path) {
102         Ok(_) => 0,
103 
104         Err(e) => e.to_c() as c_int,
105     }
106 }
107 
108 #[no_mangle]
quiche_config_load_priv_key_from_pem_file( config: &mut Config, path: *const c_char, ) -> c_int109 pub extern fn quiche_config_load_priv_key_from_pem_file(
110     config: &mut Config, path: *const c_char,
111 ) -> c_int {
112     let path = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
113 
114     match config.load_priv_key_from_pem_file(path) {
115         Ok(_) => 0,
116 
117         Err(e) => e.to_c() as c_int,
118     }
119 }
120 
121 #[no_mangle]
quiche_config_verify_peer(config: &mut Config, v: bool)122 pub extern fn quiche_config_verify_peer(config: &mut Config, v: bool) {
123     config.verify_peer(v);
124 }
125 
126 #[no_mangle]
quiche_config_grease(config: &mut Config, v: bool)127 pub extern fn quiche_config_grease(config: &mut Config, v: bool) {
128     config.grease(v);
129 }
130 
131 #[no_mangle]
quiche_config_log_keys(config: &mut Config)132 pub extern fn quiche_config_log_keys(config: &mut Config) {
133     config.log_keys();
134 }
135 
136 #[no_mangle]
quiche_config_enable_early_data(config: &mut Config)137 pub extern fn quiche_config_enable_early_data(config: &mut Config) {
138     config.enable_early_data();
139 }
140 
141 #[no_mangle]
quiche_config_set_application_protos( config: &mut Config, protos: *const u8, protos_len: size_t, ) -> c_int142 pub extern fn quiche_config_set_application_protos(
143     config: &mut Config, protos: *const u8, protos_len: size_t,
144 ) -> c_int {
145     let protos = unsafe { slice::from_raw_parts(protos, protos_len) };
146 
147     match config.set_application_protos(protos) {
148         Ok(_) => 0,
149 
150         Err(e) => e.to_c() as c_int,
151     }
152 }
153 
154 #[no_mangle]
quiche_config_set_max_idle_timeout(config: &mut Config, v: u64)155 pub extern fn quiche_config_set_max_idle_timeout(config: &mut Config, v: u64) {
156     config.set_max_idle_timeout(v);
157 }
158 
159 #[no_mangle]
quiche_config_set_max_udp_payload_size( config: &mut Config, v: u64, )160 pub extern fn quiche_config_set_max_udp_payload_size(
161     config: &mut Config, v: u64,
162 ) {
163     config.set_max_udp_payload_size(v);
164 }
165 
166 #[no_mangle]
quiche_config_set_initial_max_data(config: &mut Config, v: u64)167 pub extern fn quiche_config_set_initial_max_data(config: &mut Config, v: u64) {
168     config.set_initial_max_data(v);
169 }
170 
171 #[no_mangle]
quiche_config_set_initial_max_stream_data_bidi_local( config: &mut Config, v: u64, )172 pub extern fn quiche_config_set_initial_max_stream_data_bidi_local(
173     config: &mut Config, v: u64,
174 ) {
175     config.set_initial_max_stream_data_bidi_local(v);
176 }
177 
178 #[no_mangle]
quiche_config_set_initial_max_stream_data_bidi_remote( config: &mut Config, v: u64, )179 pub extern fn quiche_config_set_initial_max_stream_data_bidi_remote(
180     config: &mut Config, v: u64,
181 ) {
182     config.set_initial_max_stream_data_bidi_remote(v);
183 }
184 
185 #[no_mangle]
quiche_config_set_initial_max_stream_data_uni( config: &mut Config, v: u64, )186 pub extern fn quiche_config_set_initial_max_stream_data_uni(
187     config: &mut Config, v: u64,
188 ) {
189     config.set_initial_max_stream_data_uni(v);
190 }
191 
192 #[no_mangle]
quiche_config_set_initial_max_streams_bidi( config: &mut Config, v: u64, )193 pub extern fn quiche_config_set_initial_max_streams_bidi(
194     config: &mut Config, v: u64,
195 ) {
196     config.set_initial_max_streams_bidi(v);
197 }
198 
199 #[no_mangle]
quiche_config_set_initial_max_streams_uni( config: &mut Config, v: u64, )200 pub extern fn quiche_config_set_initial_max_streams_uni(
201     config: &mut Config, v: u64,
202 ) {
203     config.set_initial_max_streams_uni(v);
204 }
205 
206 #[no_mangle]
quiche_config_set_ack_delay_exponent(config: &mut Config, v: u64)207 pub extern fn quiche_config_set_ack_delay_exponent(config: &mut Config, v: u64) {
208     config.set_ack_delay_exponent(v);
209 }
210 
211 #[no_mangle]
quiche_config_set_max_ack_delay(config: &mut Config, v: u64)212 pub extern fn quiche_config_set_max_ack_delay(config: &mut Config, v: u64) {
213     config.set_max_ack_delay(v);
214 }
215 
216 #[no_mangle]
quiche_config_set_disable_active_migration( config: &mut Config, v: bool, )217 pub extern fn quiche_config_set_disable_active_migration(
218     config: &mut Config, v: bool,
219 ) {
220     config.set_disable_active_migration(v);
221 }
222 
223 #[no_mangle]
quiche_config_set_cc_algorithm_name( config: &mut Config, name: *const c_char, ) -> c_int224 pub extern fn quiche_config_set_cc_algorithm_name(
225     config: &mut Config, name: *const c_char,
226 ) -> c_int {
227     let name = unsafe { ffi::CStr::from_ptr(name).to_str().unwrap() };
228     match config.set_cc_algorithm_name(name) {
229         Ok(_) => 0,
230 
231         Err(e) => e.to_c() as c_int,
232     }
233 }
234 
235 #[no_mangle]
quiche_config_set_cc_algorithm( config: &mut Config, algo: CongestionControlAlgorithm, )236 pub extern fn quiche_config_set_cc_algorithm(
237     config: &mut Config, algo: CongestionControlAlgorithm,
238 ) {
239     config.set_cc_algorithm(algo);
240 }
241 
242 #[no_mangle]
quiche_config_enable_hystart(config: &mut Config, v: bool)243 pub extern fn quiche_config_enable_hystart(config: &mut Config, v: bool) {
244     config.enable_hystart(v);
245 }
246 
247 #[no_mangle]
quiche_config_enable_dgram( config: &mut Config, enabled: bool, recv_queue_len: size_t, send_queue_len: size_t, )248 pub extern fn quiche_config_enable_dgram(
249     config: &mut Config, enabled: bool, recv_queue_len: size_t,
250     send_queue_len: size_t,
251 ) {
252     config.enable_dgram(enabled, recv_queue_len, send_queue_len);
253 }
254 
255 #[no_mangle]
quiche_config_free(config: *mut Config)256 pub extern fn quiche_config_free(config: *mut Config) {
257     unsafe { Box::from_raw(config) };
258 }
259 
260 #[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_int261 pub extern fn quiche_header_info(
262     buf: *mut u8, buf_len: size_t, dcil: size_t, version: *mut u32, ty: *mut u8,
263     scid: *mut u8, scid_len: *mut size_t, dcid: *mut u8, dcid_len: *mut size_t,
264     token: *mut u8, token_len: *mut size_t,
265 ) -> c_int {
266     let buf = unsafe { slice::from_raw_parts_mut(buf, buf_len) };
267     let hdr = match Header::from_slice(buf, dcil) {
268         Ok(v) => v,
269 
270         Err(e) => return e.to_c() as c_int,
271     };
272 
273     unsafe {
274         *version = hdr.version;
275 
276         *ty = match hdr.ty {
277             Type::Initial => 1,
278             Type::Retry => 2,
279             Type::Handshake => 3,
280             Type::ZeroRTT => 4,
281             Type::Short => 5,
282             Type::VersionNegotiation => 6,
283         };
284 
285         if *scid_len < hdr.scid.len() {
286             return -1;
287         }
288 
289         let scid = slice::from_raw_parts_mut(scid, *scid_len);
290         let scid = &mut scid[..hdr.scid.len()];
291         scid.copy_from_slice(&hdr.scid);
292 
293         *scid_len = hdr.scid.len();
294 
295         if *dcid_len < hdr.dcid.len() {
296             return -1;
297         }
298 
299         let dcid = slice::from_raw_parts_mut(dcid, *dcid_len);
300         let dcid = &mut dcid[..hdr.dcid.len()];
301         dcid.copy_from_slice(&hdr.dcid);
302 
303         *dcid_len = hdr.dcid.len();
304 
305         match hdr.token {
306             Some(tok) => {
307                 if *token_len < tok.len() {
308                     return -1;
309                 }
310 
311                 let token = slice::from_raw_parts_mut(token, *token_len);
312                 let token = &mut token[..tok.len()];
313                 token.copy_from_slice(&tok);
314 
315                 *token_len = tok.len();
316             },
317 
318             None => *token_len = 0,
319         }
320     }
321 
322     0
323 }
324 
325 #[no_mangle]
quiche_accept( scid: *const u8, scid_len: size_t, odcid: *const u8, odcid_len: size_t, config: &mut Config, ) -> *mut Connection326 pub extern fn quiche_accept(
327     scid: *const u8, scid_len: size_t, odcid: *const u8, odcid_len: size_t,
328     config: &mut Config,
329 ) -> *mut Connection {
330     let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
331 
332     let odcid = if !odcid.is_null() || odcid_len == 0 {
333         Some(unsafe { slice::from_raw_parts(odcid, odcid_len) })
334     } else {
335         None
336     };
337 
338     match accept(scid, odcid, config) {
339         Ok(c) => Box::into_raw(Pin::into_inner(c)),
340 
341         Err(_) => ptr::null_mut(),
342     }
343 }
344 
345 #[no_mangle]
quiche_connect( server_name: *const c_char, scid: *const u8, scid_len: size_t, config: &mut Config, ) -> *mut Connection346 pub extern fn quiche_connect(
347     server_name: *const c_char, scid: *const u8, scid_len: size_t,
348     config: &mut Config,
349 ) -> *mut Connection {
350     let server_name = if server_name.is_null() {
351         None
352     } else {
353         Some(unsafe { ffi::CStr::from_ptr(server_name).to_str().unwrap() })
354     };
355 
356     let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
357 
358     match connect(server_name, scid, config) {
359         Ok(c) => Box::into_raw(Pin::into_inner(c)),
360 
361         Err(_) => ptr::null_mut(),
362     }
363 }
364 
365 #[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_t366 pub extern fn quiche_negotiate_version(
367     scid: *const u8, scid_len: size_t, dcid: *const u8, dcid_len: size_t,
368     out: *mut u8, out_len: size_t,
369 ) -> ssize_t {
370     let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
371     let dcid = unsafe { slice::from_raw_parts(dcid, dcid_len) };
372     let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
373 
374     match negotiate_version(scid, dcid, out) {
375         Ok(v) => v as ssize_t,
376 
377         Err(e) => e.to_c(),
378     }
379 }
380 
381 #[no_mangle]
quiche_version_is_supported(version: u32) -> bool382 pub extern fn quiche_version_is_supported(version: u32) -> bool {
383     version_is_supported(version)
384 }
385 
386 #[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_t387 pub extern fn quiche_retry(
388     scid: *const u8, scid_len: size_t, dcid: *const u8, dcid_len: size_t,
389     new_scid: *const u8, new_scid_len: size_t, token: *const u8,
390     token_len: size_t, version: u32, out: *mut u8, out_len: size_t,
391 ) -> ssize_t {
392     let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
393     let dcid = unsafe { slice::from_raw_parts(dcid, dcid_len) };
394     let new_scid = unsafe { slice::from_raw_parts(new_scid, new_scid_len) };
395     let token = unsafe { slice::from_raw_parts(token, token_len) };
396     let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
397 
398     match retry(scid, dcid, new_scid, token, version, out) {
399         Ok(v) => v as ssize_t,
400 
401         Err(e) => e.to_c(),
402     }
403 }
404 
405 #[no_mangle]
quiche_conn_new_with_tls( scid: *const u8, scid_len: size_t, odcid: *const u8, odcid_len: size_t, config: &mut Config, ssl: *mut c_void, is_server: bool, ) -> *mut Connection406 pub extern fn quiche_conn_new_with_tls(
407     scid: *const u8, scid_len: size_t, odcid: *const u8, odcid_len: size_t,
408     config: &mut Config, ssl: *mut c_void, is_server: bool,
409 ) -> *mut Connection {
410     let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
411 
412     let odcid = if !odcid.is_null() || odcid_len == 0 {
413         Some(unsafe { slice::from_raw_parts(odcid, odcid_len) })
414     } else {
415         None
416     };
417 
418     let tls = unsafe { tls::Handshake::from_ptr(ssl) };
419 
420     match Connection::with_tls(scid, odcid, config, tls, is_server) {
421         Ok(c) => Box::into_raw(Pin::into_inner(c)),
422 
423         Err(_) => ptr::null_mut(),
424     }
425 }
426 
427 #[no_mangle]
quiche_conn_set_keylog_path( conn: &mut Connection, path: *const c_char, ) -> bool428 pub extern fn quiche_conn_set_keylog_path(
429     conn: &mut Connection, path: *const c_char,
430 ) -> bool {
431     let filename = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
432 
433     let file = std::fs::OpenOptions::new()
434         .create(true)
435         .append(true)
436         .open(filename);
437 
438     let writer = match file {
439         Ok(f) => std::io::BufWriter::new(f),
440 
441         Err(_) => return false,
442     };
443 
444     conn.set_keylog(Box::new(writer));
445 
446     true
447 }
448 
449 #[no_mangle]
450 #[cfg(unix)]
quiche_conn_set_keylog_fd(conn: &mut Connection, fd: c_int)451 pub extern fn quiche_conn_set_keylog_fd(conn: &mut Connection, fd: c_int) {
452     let f = unsafe { std::fs::File::from_raw_fd(fd) };
453     let writer = std::io::BufWriter::new(f);
454 
455     conn.set_keylog(Box::new(writer));
456 }
457 
458 #[no_mangle]
459 #[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, ) -> bool460 pub extern fn quiche_conn_set_qlog_path(
461     conn: &mut Connection, path: *const c_char, log_title: *const c_char,
462     log_desc: *const c_char,
463 ) -> bool {
464     let filename = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
465 
466     let file = std::fs::OpenOptions::new()
467         .write(true)
468         .create_new(true)
469         .open(filename);
470 
471     let writer = match file {
472         Ok(f) => std::io::BufWriter::new(f),
473 
474         Err(_) => return false,
475     };
476 
477     let title = unsafe { ffi::CStr::from_ptr(log_title).to_str().unwrap() };
478     let description = unsafe { ffi::CStr::from_ptr(log_desc).to_str().unwrap() };
479 
480     conn.set_qlog(
481         Box::new(writer),
482         title.to_string(),
483         format!("{} id={}", description, conn.trace_id),
484     );
485 
486     true
487 }
488 
489 #[no_mangle]
490 #[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, )491 pub extern fn quiche_conn_set_qlog_fd(
492     conn: &mut Connection, fd: c_int, log_title: *const c_char,
493     log_desc: *const c_char,
494 ) {
495     let f = unsafe { std::fs::File::from_raw_fd(fd) };
496     let writer = std::io::BufWriter::new(f);
497 
498     let title = unsafe { ffi::CStr::from_ptr(log_title).to_str().unwrap() };
499     let description = unsafe { ffi::CStr::from_ptr(log_desc).to_str().unwrap() };
500 
501     conn.set_qlog(
502         Box::new(writer),
503         title.to_string(),
504         format!("{} id={}", description, conn.trace_id),
505     );
506 }
507 
508 #[no_mangle]
quiche_conn_recv( conn: &mut Connection, buf: *mut u8, buf_len: size_t, ) -> ssize_t509 pub extern fn quiche_conn_recv(
510     conn: &mut Connection, buf: *mut u8, buf_len: size_t,
511 ) -> ssize_t {
512     if buf_len > <ssize_t>::max_value() as usize {
513         panic!("The provided buffer is too large");
514     }
515 
516     let buf = unsafe { slice::from_raw_parts_mut(buf, buf_len) };
517 
518     match conn.recv(buf) {
519         Ok(v) => v as ssize_t,
520 
521         Err(e) => e.to_c(),
522     }
523 }
524 
525 #[no_mangle]
quiche_conn_send( conn: &mut Connection, out: *mut u8, out_len: size_t, ) -> ssize_t526 pub extern fn quiche_conn_send(
527     conn: &mut Connection, out: *mut u8, out_len: size_t,
528 ) -> ssize_t {
529     if out_len > <ssize_t>::max_value() as usize {
530         panic!("The provided buffer is too large");
531     }
532 
533     let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
534 
535     match conn.send(out) {
536         Ok(v) => v as ssize_t,
537 
538         Err(e) => e.to_c(),
539     }
540 }
541 
542 #[no_mangle]
quiche_conn_stream_recv( conn: &mut Connection, stream_id: u64, out: *mut u8, out_len: size_t, fin: &mut bool, ) -> ssize_t543 pub extern fn quiche_conn_stream_recv(
544     conn: &mut Connection, stream_id: u64, out: *mut u8, out_len: size_t,
545     fin: &mut bool,
546 ) -> ssize_t {
547     if out_len > <ssize_t>::max_value() as usize {
548         panic!("The provided buffer is too large");
549     }
550 
551     let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
552 
553     let (out_len, out_fin) = match conn.stream_recv(stream_id, out) {
554         Ok(v) => v,
555 
556         Err(e) => return e.to_c(),
557     };
558 
559     *fin = out_fin;
560 
561     out_len as ssize_t
562 }
563 
564 #[no_mangle]
quiche_conn_stream_send( conn: &mut Connection, stream_id: u64, buf: *const u8, buf_len: size_t, fin: bool, ) -> ssize_t565 pub extern fn quiche_conn_stream_send(
566     conn: &mut Connection, stream_id: u64, buf: *const u8, buf_len: size_t,
567     fin: bool,
568 ) -> ssize_t {
569     if buf_len > <ssize_t>::max_value() as usize {
570         panic!("The provided buffer is too large");
571     }
572 
573     let buf = unsafe { slice::from_raw_parts(buf, buf_len) };
574 
575     match conn.stream_send(stream_id, buf, fin) {
576         Ok(v) => v as ssize_t,
577 
578         Err(e) => e.to_c(),
579     }
580 }
581 
582 #[no_mangle]
quiche_conn_stream_shutdown( conn: &mut Connection, stream_id: u64, direction: Shutdown, err: u64, ) -> c_int583 pub extern fn quiche_conn_stream_shutdown(
584     conn: &mut Connection, stream_id: u64, direction: Shutdown, err: u64,
585 ) -> c_int {
586     match conn.stream_shutdown(stream_id, direction, err) {
587         Ok(_) => 0,
588 
589         Err(e) => e.to_c() as c_int,
590     }
591 }
592 
593 #[no_mangle]
quiche_conn_stream_capacity( conn: &mut Connection, stream_id: u64, ) -> ssize_t594 pub extern fn quiche_conn_stream_capacity(
595     conn: &mut Connection, stream_id: u64,
596 ) -> ssize_t {
597     match conn.stream_capacity(stream_id) {
598         Ok(v) => v as ssize_t,
599 
600         Err(e) => e.to_c(),
601     }
602 }
603 
604 #[no_mangle]
quiche_conn_stream_finished( conn: &mut Connection, stream_id: u64, ) -> bool605 pub extern fn quiche_conn_stream_finished(
606     conn: &mut Connection, stream_id: u64,
607 ) -> bool {
608     conn.stream_finished(stream_id)
609 }
610 
611 #[no_mangle]
quiche_conn_readable(conn: &Connection) -> *mut StreamIter612 pub extern fn quiche_conn_readable(conn: &Connection) -> *mut StreamIter {
613     Box::into_raw(Box::new(conn.readable()))
614 }
615 
616 #[no_mangle]
quiche_conn_writable(conn: &Connection) -> *mut StreamIter617 pub extern fn quiche_conn_writable(conn: &Connection) -> *mut StreamIter {
618     Box::into_raw(Box::new(conn.writable()))
619 }
620 
621 struct AppData(*mut c_void);
622 unsafe impl Send for AppData {}
623 
624 #[no_mangle]
quiche_conn_stream_init_application_data( conn: &mut Connection, stream_id: u64, data: *mut c_void, ) -> c_int625 pub extern fn quiche_conn_stream_init_application_data(
626     conn: &mut Connection, stream_id: u64, data: *mut c_void,
627 ) -> c_int {
628     match conn.stream_init_application_data(stream_id, AppData(data)) {
629         Ok(_) => 0,
630 
631         Err(e) => e.to_c() as c_int,
632     }
633 }
634 
635 #[no_mangle]
quiche_conn_stream_application_data( conn: &mut Connection, stream_id: u64, ) -> *mut c_void636 pub extern fn quiche_conn_stream_application_data(
637     conn: &mut Connection, stream_id: u64,
638 ) -> *mut c_void {
639     match conn.stream_application_data(stream_id) {
640         Some(v) => v.downcast_mut::<AppData>().unwrap().0,
641 
642         None => ptr::null_mut(),
643     }
644 }
645 
646 #[no_mangle]
quiche_conn_close( conn: &mut Connection, app: bool, err: u64, reason: *const u8, reason_len: size_t, ) -> c_int647 pub extern fn quiche_conn_close(
648     conn: &mut Connection, app: bool, err: u64, reason: *const u8,
649     reason_len: size_t,
650 ) -> c_int {
651     let reason = unsafe { slice::from_raw_parts(reason, reason_len) };
652 
653     match conn.close(app, err, reason) {
654         Ok(_) => 0,
655 
656         Err(e) => e.to_c() as c_int,
657     }
658 }
659 
660 #[no_mangle]
quiche_conn_timeout_as_nanos(conn: &mut Connection) -> u64661 pub extern fn quiche_conn_timeout_as_nanos(conn: &mut Connection) -> u64 {
662     match conn.timeout() {
663         Some(timeout) => timeout.as_nanos() as u64,
664 
665         None => std::u64::MAX,
666     }
667 }
668 
669 #[no_mangle]
quiche_conn_timeout_as_millis(conn: &mut Connection) -> u64670 pub extern fn quiche_conn_timeout_as_millis(conn: &mut Connection) -> u64 {
671     match conn.timeout() {
672         Some(timeout) => timeout.as_millis() as u64,
673 
674         None => std::u64::MAX,
675     }
676 }
677 
678 #[no_mangle]
quiche_conn_on_timeout(conn: &mut Connection)679 pub extern fn quiche_conn_on_timeout(conn: &mut Connection) {
680     conn.on_timeout()
681 }
682 
683 #[no_mangle]
quiche_conn_application_proto( conn: &mut Connection, out: &mut *const u8, out_len: &mut size_t, )684 pub extern fn quiche_conn_application_proto(
685     conn: &mut Connection, out: &mut *const u8, out_len: &mut size_t,
686 ) {
687     let proto = conn.application_proto();
688 
689     *out = proto.as_ptr();
690     *out_len = proto.len();
691 }
692 
693 #[no_mangle]
quiche_conn_is_established(conn: &mut Connection) -> bool694 pub extern fn quiche_conn_is_established(conn: &mut Connection) -> bool {
695     conn.is_established()
696 }
697 
698 #[no_mangle]
quiche_conn_is_in_early_data(conn: &mut Connection) -> bool699 pub extern fn quiche_conn_is_in_early_data(conn: &mut Connection) -> bool {
700     conn.is_in_early_data()
701 }
702 
703 #[no_mangle]
quiche_conn_is_closed(conn: &mut Connection) -> bool704 pub extern fn quiche_conn_is_closed(conn: &mut Connection) -> bool {
705     conn.is_closed()
706 }
707 
708 #[no_mangle]
quiche_stream_iter_next( iter: &mut StreamIter, stream_id: *mut u64, ) -> bool709 pub extern fn quiche_stream_iter_next(
710     iter: &mut StreamIter, stream_id: *mut u64,
711 ) -> bool {
712     if let Some(v) = iter.next() {
713         unsafe { *stream_id = v };
714         return true;
715     }
716 
717     false
718 }
719 
720 #[no_mangle]
quiche_stream_iter_free(iter: *mut StreamIter)721 pub extern fn quiche_stream_iter_free(iter: *mut StreamIter) {
722     unsafe { Box::from_raw(iter) };
723 }
724 
725 #[repr(C)]
726 pub struct Stats {
727     pub recv: usize,
728     pub sent: usize,
729     pub lost: usize,
730     pub rtt: u64,
731     pub cwnd: usize,
732     pub delivery_rate: u64,
733 }
734 
735 #[no_mangle]
quiche_conn_stats(conn: &Connection, out: &mut Stats)736 pub extern fn quiche_conn_stats(conn: &Connection, out: &mut Stats) {
737     let stats = conn.stats();
738 
739     out.recv = stats.recv;
740     out.sent = stats.sent;
741     out.lost = stats.lost;
742     out.rtt = stats.rtt.as_nanos() as u64;
743     out.cwnd = stats.cwnd;
744     out.delivery_rate = stats.delivery_rate;
745 }
746 
747 #[no_mangle]
quiche_conn_dgram_max_writable_len(conn: &Connection) -> ssize_t748 pub extern fn quiche_conn_dgram_max_writable_len(conn: &Connection) -> ssize_t {
749     match conn.dgram_max_writable_len() {
750         None => Error::Done.to_c(),
751 
752         Some(v) => v as ssize_t,
753     }
754 }
755 
756 #[no_mangle]
quiche_conn_dgram_send( conn: &mut Connection, buf: *const u8, buf_len: size_t, ) -> ssize_t757 pub extern fn quiche_conn_dgram_send(
758     conn: &mut Connection, buf: *const u8, buf_len: size_t,
759 ) -> ssize_t {
760     if buf_len > <ssize_t>::max_value() as usize {
761         panic!("The provided buffer is too large");
762     }
763 
764     let buf = unsafe { slice::from_raw_parts(buf, buf_len) };
765 
766     match conn.dgram_send(buf) {
767         Ok(_) => buf_len as ssize_t,
768 
769         Err(e) => e.to_c(),
770     }
771 }
772 
773 #[no_mangle]
quiche_conn_dgram_recv( conn: &mut Connection, out: *mut u8, out_len: size_t, ) -> ssize_t774 pub extern fn quiche_conn_dgram_recv(
775     conn: &mut Connection, out: *mut u8, out_len: size_t,
776 ) -> ssize_t {
777     if out_len > <ssize_t>::max_value() as usize {
778         panic!("The provided buffer is too large");
779     }
780 
781     let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
782 
783     let out_len = match conn.dgram_recv(out) {
784         Ok(v) => v,
785 
786         Err(e) => return e.to_c(),
787     };
788 
789     out_len as ssize_t
790 }
791 
792 #[no_mangle]
quiche_conn_dgram_purge_outgoing( conn: &mut Connection, f: extern fn(*const u8, size_t) -> bool, )793 pub extern fn quiche_conn_dgram_purge_outgoing(
794     conn: &mut Connection, f: extern fn(*const u8, size_t) -> bool,
795 ) {
796     conn.dgram_purge_outgoing(|d: &[u8]| -> bool {
797         let ptr: *const u8 = d.as_ptr();
798         let len: size_t = d.len();
799 
800         f(ptr, len)
801     });
802 }
803 
804 #[no_mangle]
quiche_conn_free(conn: *mut Connection)805 pub extern fn quiche_conn_free(conn: *mut Connection) {
806     unsafe { Box::from_raw(conn) };
807 }
808