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