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::SocketAddr;
33
34 #[cfg(unix)]
35 use std::os::unix::io::FromRawFd;
36
37 use libc::c_char;
38 use libc::c_int;
39 use libc::c_void;
40 use libc::size_t;
41 use libc::sockaddr;
42 use libc::ssize_t;
43 use libc::timespec;
44
45 #[cfg(not(windows))]
46 use libc::sockaddr_in;
47 #[cfg(windows)]
48 use winapi::shared::ws2def::SOCKADDR_IN as sockaddr_in;
49
50 #[cfg(not(windows))]
51 use libc::sockaddr_in6;
52 #[cfg(windows)]
53 use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH as sockaddr_in6;
54
55 #[cfg(not(windows))]
56 use libc::sockaddr_storage;
57 #[cfg(windows)]
58 use winapi::shared::ws2def::SOCKADDR_STORAGE_LH as sockaddr_storage;
59
60 #[cfg(windows)]
61 use libc::c_int as socklen_t;
62 #[cfg(not(windows))]
63 use libc::socklen_t;
64
65 #[cfg(not(windows))]
66 use libc::AF_INET;
67 #[cfg(windows)]
68 use winapi::shared::ws2def::AF_INET;
69
70 #[cfg(not(windows))]
71 use libc::AF_INET6;
72 #[cfg(windows)]
73 use winapi::shared::ws2def::AF_INET6;
74
75 use crate::*;
76
77 #[no_mangle]
quiche_version() -> *const u878 pub extern fn quiche_version() -> *const u8 {
79 //static VERSION: &str = concat!("0.9.0", "\0");
80 // ANDROID's build system doesn't support environment variables
81 // so we hardcode the package version here.
82 static VERSION: &str = concat!("0.6.0", "\0");
83 VERSION.as_ptr()
84 }
85
86 struct Logger {
87 cb: extern fn(line: *const u8, argp: *mut c_void),
88 argp: std::sync::atomic::AtomicPtr<c_void>,
89 }
90
91 impl log::Log for Logger {
enabled(&self, _metadata: &log::Metadata) -> bool92 fn enabled(&self, _metadata: &log::Metadata) -> bool {
93 true
94 }
95
log(&self, record: &log::Record)96 fn log(&self, record: &log::Record) {
97 let line = format!("{}: {}\0", record.target(), record.args());
98 (self.cb)(line.as_ptr(), self.argp.load(atomic::Ordering::Relaxed));
99 }
100
flush(&self)101 fn flush(&self) {}
102 }
103
104 #[no_mangle]
quiche_enable_debug_logging( cb: extern fn(line: *const u8, argp: *mut c_void), argp: *mut c_void, ) -> c_int105 pub extern fn quiche_enable_debug_logging(
106 cb: extern fn(line: *const u8, argp: *mut c_void), argp: *mut c_void,
107 ) -> c_int {
108 let argp = atomic::AtomicPtr::new(argp);
109 let logger = Box::new(Logger { cb, argp });
110
111 if log::set_boxed_logger(logger).is_err() {
112 return -1;
113 }
114
115 log::set_max_level(log::LevelFilter::Trace);
116
117 0
118 }
119
120 #[no_mangle]
quiche_config_new(version: u32) -> *mut Config121 pub extern fn quiche_config_new(version: u32) -> *mut Config {
122 match Config::new(version) {
123 Ok(c) => Box::into_raw(Box::new(c)),
124
125 Err(_) => ptr::null_mut(),
126 }
127 }
128
129 #[no_mangle]
quiche_config_load_cert_chain_from_pem_file( config: &mut Config, path: *const c_char, ) -> c_int130 pub extern fn quiche_config_load_cert_chain_from_pem_file(
131 config: &mut Config, path: *const c_char,
132 ) -> c_int {
133 let path = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
134
135 match config.load_cert_chain_from_pem_file(path) {
136 Ok(_) => 0,
137
138 Err(e) => e.to_c() as c_int,
139 }
140 }
141
142 #[no_mangle]
quiche_config_load_priv_key_from_pem_file( config: &mut Config, path: *const c_char, ) -> c_int143 pub extern fn quiche_config_load_priv_key_from_pem_file(
144 config: &mut Config, path: *const c_char,
145 ) -> c_int {
146 let path = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
147
148 match config.load_priv_key_from_pem_file(path) {
149 Ok(_) => 0,
150
151 Err(e) => e.to_c() as c_int,
152 }
153 }
154
155 #[no_mangle]
quiche_config_load_verify_locations_from_file( config: &mut Config, path: *const c_char, ) -> c_int156 pub extern fn quiche_config_load_verify_locations_from_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_verify_locations_from_file(path) {
162 Ok(_) => 0,
163
164 Err(e) => e.to_c() as c_int,
165 }
166 }
167
168 #[no_mangle]
quiche_config_verify_peer(config: &mut Config, v: bool)169 pub extern fn quiche_config_verify_peer(config: &mut Config, v: bool) {
170 config.verify_peer(v);
171 }
172
173 #[no_mangle]
quiche_config_grease(config: &mut Config, v: bool)174 pub extern fn quiche_config_grease(config: &mut Config, v: bool) {
175 config.grease(v);
176 }
177
178 #[no_mangle]
quiche_config_log_keys(config: &mut Config)179 pub extern fn quiche_config_log_keys(config: &mut Config) {
180 config.log_keys();
181 }
182
183 #[no_mangle]
quiche_config_enable_early_data(config: &mut Config)184 pub extern fn quiche_config_enable_early_data(config: &mut Config) {
185 config.enable_early_data();
186 }
187
188 #[no_mangle]
quiche_config_set_application_protos( config: &mut Config, protos: *const u8, protos_len: size_t, ) -> c_int189 pub extern fn quiche_config_set_application_protos(
190 config: &mut Config, protos: *const u8, protos_len: size_t,
191 ) -> c_int {
192 let protos = unsafe { slice::from_raw_parts(protos, protos_len) };
193
194 match config.set_application_protos(protos) {
195 Ok(_) => 0,
196
197 Err(e) => e.to_c() as c_int,
198 }
199 }
200
201 #[no_mangle]
quiche_config_set_max_idle_timeout(config: &mut Config, v: u64)202 pub extern fn quiche_config_set_max_idle_timeout(config: &mut Config, v: u64) {
203 config.set_max_idle_timeout(v);
204 }
205
206 #[no_mangle]
quiche_config_set_max_recv_udp_payload_size( config: &mut Config, v: size_t, )207 pub extern fn quiche_config_set_max_recv_udp_payload_size(
208 config: &mut Config, v: size_t,
209 ) {
210 config.set_max_recv_udp_payload_size(v);
211 }
212
213 #[no_mangle]
quiche_config_set_initial_max_data(config: &mut Config, v: u64)214 pub extern fn quiche_config_set_initial_max_data(config: &mut Config, v: u64) {
215 config.set_initial_max_data(v);
216 }
217
218 #[no_mangle]
quiche_config_set_initial_max_stream_data_bidi_local( config: &mut Config, v: u64, )219 pub extern fn quiche_config_set_initial_max_stream_data_bidi_local(
220 config: &mut Config, v: u64,
221 ) {
222 config.set_initial_max_stream_data_bidi_local(v);
223 }
224
225 #[no_mangle]
quiche_config_set_initial_max_stream_data_bidi_remote( config: &mut Config, v: u64, )226 pub extern fn quiche_config_set_initial_max_stream_data_bidi_remote(
227 config: &mut Config, v: u64,
228 ) {
229 config.set_initial_max_stream_data_bidi_remote(v);
230 }
231
232 #[no_mangle]
quiche_config_set_initial_max_stream_data_uni( config: &mut Config, v: u64, )233 pub extern fn quiche_config_set_initial_max_stream_data_uni(
234 config: &mut Config, v: u64,
235 ) {
236 config.set_initial_max_stream_data_uni(v);
237 }
238
239 #[no_mangle]
quiche_config_set_initial_max_streams_bidi( config: &mut Config, v: u64, )240 pub extern fn quiche_config_set_initial_max_streams_bidi(
241 config: &mut Config, v: u64,
242 ) {
243 config.set_initial_max_streams_bidi(v);
244 }
245
246 #[no_mangle]
quiche_config_set_initial_max_streams_uni( config: &mut Config, v: u64, )247 pub extern fn quiche_config_set_initial_max_streams_uni(
248 config: &mut Config, v: u64,
249 ) {
250 config.set_initial_max_streams_uni(v);
251 }
252
253 #[no_mangle]
quiche_config_set_ack_delay_exponent(config: &mut Config, v: u64)254 pub extern fn quiche_config_set_ack_delay_exponent(config: &mut Config, v: u64) {
255 config.set_ack_delay_exponent(v);
256 }
257
258 #[no_mangle]
quiche_config_set_max_ack_delay(config: &mut Config, v: u64)259 pub extern fn quiche_config_set_max_ack_delay(config: &mut Config, v: u64) {
260 config.set_max_ack_delay(v);
261 }
262
263 #[no_mangle]
quiche_config_set_disable_active_migration( config: &mut Config, v: bool, )264 pub extern fn quiche_config_set_disable_active_migration(
265 config: &mut Config, v: bool,
266 ) {
267 config.set_disable_active_migration(v);
268 }
269
270 #[no_mangle]
quiche_config_set_cc_algorithm_name( config: &mut Config, name: *const c_char, ) -> c_int271 pub extern fn quiche_config_set_cc_algorithm_name(
272 config: &mut Config, name: *const c_char,
273 ) -> c_int {
274 let name = unsafe { ffi::CStr::from_ptr(name).to_str().unwrap() };
275 match config.set_cc_algorithm_name(name) {
276 Ok(_) => 0,
277
278 Err(e) => e.to_c() as c_int,
279 }
280 }
281
282 #[no_mangle]
quiche_config_set_cc_algorithm( config: &mut Config, algo: CongestionControlAlgorithm, )283 pub extern fn quiche_config_set_cc_algorithm(
284 config: &mut Config, algo: CongestionControlAlgorithm,
285 ) {
286 config.set_cc_algorithm(algo);
287 }
288
289 #[no_mangle]
quiche_config_enable_hystart(config: &mut Config, v: bool)290 pub extern fn quiche_config_enable_hystart(config: &mut Config, v: bool) {
291 config.enable_hystart(v);
292 }
293
294 #[no_mangle]
quiche_config_enable_dgram( config: &mut Config, enabled: bool, recv_queue_len: size_t, send_queue_len: size_t, )295 pub extern fn quiche_config_enable_dgram(
296 config: &mut Config, enabled: bool, recv_queue_len: size_t,
297 send_queue_len: size_t,
298 ) {
299 config.enable_dgram(enabled, recv_queue_len, send_queue_len);
300 }
301
302 #[no_mangle]
quiche_config_set_max_send_udp_payload_size( config: &mut Config, v: size_t, )303 pub extern fn quiche_config_set_max_send_udp_payload_size(
304 config: &mut Config, v: size_t,
305 ) {
306 config.set_max_send_udp_payload_size(v);
307 }
308
309 #[no_mangle]
quiche_config_free(config: *mut Config)310 pub extern fn quiche_config_free(config: *mut Config) {
311 unsafe { Box::from_raw(config) };
312 }
313
314 #[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_int315 pub extern fn quiche_header_info(
316 buf: *mut u8, buf_len: size_t, dcil: size_t, version: *mut u32, ty: *mut u8,
317 scid: *mut u8, scid_len: *mut size_t, dcid: *mut u8, dcid_len: *mut size_t,
318 token: *mut u8, token_len: *mut size_t,
319 ) -> c_int {
320 let buf = unsafe { slice::from_raw_parts_mut(buf, buf_len) };
321 let hdr = match Header::from_slice(buf, dcil) {
322 Ok(v) => v,
323
324 Err(e) => return e.to_c() as c_int,
325 };
326
327 unsafe {
328 *version = hdr.version;
329
330 *ty = match hdr.ty {
331 Type::Initial => 1,
332 Type::Retry => 2,
333 Type::Handshake => 3,
334 Type::ZeroRTT => 4,
335 Type::Short => 5,
336 Type::VersionNegotiation => 6,
337 };
338
339 if *scid_len < hdr.scid.len() {
340 return -1;
341 }
342
343 let scid = slice::from_raw_parts_mut(scid, *scid_len);
344 let scid = &mut scid[..hdr.scid.len()];
345 scid.copy_from_slice(&hdr.scid);
346
347 *scid_len = hdr.scid.len();
348
349 if *dcid_len < hdr.dcid.len() {
350 return -1;
351 }
352
353 let dcid = slice::from_raw_parts_mut(dcid, *dcid_len);
354 let dcid = &mut dcid[..hdr.dcid.len()];
355 dcid.copy_from_slice(&hdr.dcid);
356
357 *dcid_len = hdr.dcid.len();
358
359 match hdr.token {
360 Some(tok) => {
361 if *token_len < tok.len() {
362 return -1;
363 }
364
365 let token = slice::from_raw_parts_mut(token, *token_len);
366 let token = &mut token[..tok.len()];
367 token.copy_from_slice(&tok);
368
369 *token_len = tok.len();
370 },
371
372 None => *token_len = 0,
373 }
374 }
375
376 0
377 }
378
379 #[no_mangle]
quiche_accept( scid: *const u8, scid_len: size_t, odcid: *const u8, odcid_len: size_t, from: &sockaddr, from_len: socklen_t, config: &mut Config, ) -> *mut Connection380 pub extern fn quiche_accept(
381 scid: *const u8, scid_len: size_t, odcid: *const u8, odcid_len: size_t,
382 from: &sockaddr, from_len: socklen_t, config: &mut Config,
383 ) -> *mut Connection {
384 let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
385 let scid = ConnectionId::from_ref(scid);
386
387 let odcid = if !odcid.is_null() && odcid_len > 0 {
388 Some(ConnectionId::from_ref(unsafe {
389 slice::from_raw_parts(odcid, odcid_len)
390 }))
391 } else {
392 None
393 };
394
395 let from = std_addr_from_c(from, from_len);
396
397 match accept(&scid, odcid.as_ref(), from, config) {
398 Ok(c) => Box::into_raw(Pin::into_inner(c)),
399
400 Err(_) => ptr::null_mut(),
401 }
402 }
403
404 #[no_mangle]
quiche_connect( server_name: *const c_char, scid: *const u8, scid_len: size_t, to: &sockaddr, to_len: socklen_t, config: &mut Config, ) -> *mut Connection405 pub extern fn quiche_connect(
406 server_name: *const c_char, scid: *const u8, scid_len: size_t, to: &sockaddr,
407 to_len: socklen_t, config: &mut Config,
408 ) -> *mut Connection {
409 let server_name = if server_name.is_null() {
410 None
411 } else {
412 Some(unsafe { ffi::CStr::from_ptr(server_name).to_str().unwrap() })
413 };
414
415 let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
416 let scid = ConnectionId::from_ref(scid);
417
418 let to = std_addr_from_c(to, to_len);
419
420 match connect(server_name, &scid, to, config) {
421 Ok(c) => Box::into_raw(Pin::into_inner(c)),
422
423 Err(_) => ptr::null_mut(),
424 }
425 }
426
427 #[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_t428 pub extern fn quiche_negotiate_version(
429 scid: *const u8, scid_len: size_t, dcid: *const u8, dcid_len: size_t,
430 out: *mut u8, out_len: size_t,
431 ) -> ssize_t {
432 let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
433 let scid = ConnectionId::from_ref(scid);
434
435 let dcid = unsafe { slice::from_raw_parts(dcid, dcid_len) };
436 let dcid = ConnectionId::from_ref(dcid);
437
438 let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
439
440 match negotiate_version(&scid, &dcid, out) {
441 Ok(v) => v as ssize_t,
442
443 Err(e) => e.to_c(),
444 }
445 }
446
447 #[no_mangle]
quiche_version_is_supported(version: u32) -> bool448 pub extern fn quiche_version_is_supported(version: u32) -> bool {
449 version_is_supported(version)
450 }
451
452 #[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_t453 pub extern fn quiche_retry(
454 scid: *const u8, scid_len: size_t, dcid: *const u8, dcid_len: size_t,
455 new_scid: *const u8, new_scid_len: size_t, token: *const u8,
456 token_len: size_t, version: u32, out: *mut u8, out_len: size_t,
457 ) -> ssize_t {
458 let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
459 let scid = ConnectionId::from_ref(scid);
460
461 let dcid = unsafe { slice::from_raw_parts(dcid, dcid_len) };
462 let dcid = ConnectionId::from_ref(dcid);
463
464 let new_scid = unsafe { slice::from_raw_parts(new_scid, new_scid_len) };
465 let new_scid = ConnectionId::from_ref(new_scid);
466
467 let token = unsafe { slice::from_raw_parts(token, token_len) };
468 let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
469
470 match retry(&scid, &dcid, &new_scid, token, version, out) {
471 Ok(v) => v as ssize_t,
472
473 Err(e) => e.to_c(),
474 }
475 }
476
477 #[no_mangle]
quiche_conn_new_with_tls( scid: *const u8, scid_len: size_t, odcid: *const u8, odcid_len: size_t, peer: &sockaddr, peer_len: socklen_t, config: &mut Config, ssl: *mut c_void, is_server: bool, ) -> *mut Connection478 pub extern fn quiche_conn_new_with_tls(
479 scid: *const u8, scid_len: size_t, odcid: *const u8, odcid_len: size_t,
480 peer: &sockaddr, peer_len: socklen_t, config: &mut Config, ssl: *mut c_void,
481 is_server: bool,
482 ) -> *mut Connection {
483 let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
484 let scid = ConnectionId::from_ref(scid);
485
486 let odcid = if !odcid.is_null() && odcid_len > 0 {
487 Some(ConnectionId::from_ref(unsafe {
488 slice::from_raw_parts(odcid, odcid_len)
489 }))
490 } else {
491 None
492 };
493
494 let peer = std_addr_from_c(peer, peer_len);
495
496 let tls = unsafe { tls::Handshake::from_ptr(ssl) };
497
498 match Connection::with_tls(
499 &scid,
500 odcid.as_ref(),
501 peer,
502 config,
503 tls,
504 is_server,
505 ) {
506 Ok(c) => Box::into_raw(Pin::into_inner(c)),
507
508 Err(_) => ptr::null_mut(),
509 }
510 }
511
512 #[no_mangle]
quiche_conn_set_keylog_path( conn: &mut Connection, path: *const c_char, ) -> bool513 pub extern fn quiche_conn_set_keylog_path(
514 conn: &mut Connection, path: *const c_char,
515 ) -> bool {
516 let filename = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
517
518 let file = std::fs::OpenOptions::new()
519 .create(true)
520 .append(true)
521 .open(filename);
522
523 let writer = match file {
524 Ok(f) => std::io::BufWriter::new(f),
525
526 Err(_) => return false,
527 };
528
529 conn.set_keylog(Box::new(writer));
530
531 true
532 }
533
534 #[no_mangle]
535 #[cfg(unix)]
quiche_conn_set_keylog_fd(conn: &mut Connection, fd: c_int)536 pub extern fn quiche_conn_set_keylog_fd(conn: &mut Connection, fd: c_int) {
537 let f = unsafe { std::fs::File::from_raw_fd(fd) };
538 let writer = std::io::BufWriter::new(f);
539
540 conn.set_keylog(Box::new(writer));
541 }
542
543 #[no_mangle]
544 #[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, ) -> bool545 pub extern fn quiche_conn_set_qlog_path(
546 conn: &mut Connection, path: *const c_char, log_title: *const c_char,
547 log_desc: *const c_char,
548 ) -> bool {
549 let filename = unsafe { ffi::CStr::from_ptr(path).to_str().unwrap() };
550
551 let file = std::fs::OpenOptions::new()
552 .write(true)
553 .create_new(true)
554 .open(filename);
555
556 let writer = match file {
557 Ok(f) => std::io::BufWriter::new(f),
558
559 Err(_) => return false,
560 };
561
562 let title = unsafe { ffi::CStr::from_ptr(log_title).to_str().unwrap() };
563 let description = unsafe { ffi::CStr::from_ptr(log_desc).to_str().unwrap() };
564
565 conn.set_qlog(
566 Box::new(writer),
567 title.to_string(),
568 format!("{} id={}", description, conn.trace_id),
569 );
570
571 true
572 }
573
574 #[no_mangle]
575 #[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, )576 pub extern fn quiche_conn_set_qlog_fd(
577 conn: &mut Connection, fd: c_int, log_title: *const c_char,
578 log_desc: *const c_char,
579 ) {
580 let f = unsafe { std::fs::File::from_raw_fd(fd) };
581 let writer = std::io::BufWriter::new(f);
582
583 let title = unsafe { ffi::CStr::from_ptr(log_title).to_str().unwrap() };
584 let description = unsafe { ffi::CStr::from_ptr(log_desc).to_str().unwrap() };
585
586 conn.set_qlog(
587 Box::new(writer),
588 title.to_string(),
589 format!("{} id={}", description, conn.trace_id),
590 );
591 }
592
593 #[no_mangle]
quiche_conn_set_session( conn: &mut Connection, buf: *const u8, buf_len: size_t, ) -> c_int594 pub extern fn quiche_conn_set_session(
595 conn: &mut Connection, buf: *const u8, buf_len: size_t,
596 ) -> c_int {
597 let buf = unsafe { slice::from_raw_parts(buf, buf_len) };
598
599 match conn.set_session(buf) {
600 Ok(_) => 0,
601
602 Err(e) => e.to_c() as c_int,
603 }
604 }
605
606 #[repr(C)]
607 pub struct RecvInfo<'a> {
608 from: &'a sockaddr,
609 from_len: socklen_t,
610 }
611
612 impl<'a> From<&RecvInfo<'a>> for crate::RecvInfo {
from(info: &RecvInfo) -> crate::RecvInfo613 fn from(info: &RecvInfo) -> crate::RecvInfo {
614 crate::RecvInfo {
615 from: std_addr_from_c(info.from, info.from_len),
616 }
617 }
618 }
619
620 #[no_mangle]
quiche_conn_recv( conn: &mut Connection, buf: *mut u8, buf_len: size_t, info: &RecvInfo, ) -> ssize_t621 pub extern fn quiche_conn_recv(
622 conn: &mut Connection, buf: *mut u8, buf_len: size_t, info: &RecvInfo,
623 ) -> ssize_t {
624 if buf_len > <ssize_t>::max_value() as usize {
625 panic!("The provided buffer is too large");
626 }
627
628 let buf = unsafe { slice::from_raw_parts_mut(buf, buf_len) };
629
630 match conn.recv(buf, info.into()) {
631 Ok(v) => v as ssize_t,
632
633 Err(e) => e.to_c(),
634 }
635 }
636
637 #[repr(C)]
638 pub struct SendInfo {
639 to: sockaddr_storage,
640 to_len: socklen_t,
641
642 at: timespec,
643 }
644
645 #[no_mangle]
quiche_conn_send( conn: &mut Connection, out: *mut u8, out_len: size_t, out_info: &mut SendInfo, ) -> ssize_t646 pub extern fn quiche_conn_send(
647 conn: &mut Connection, out: *mut u8, out_len: size_t, out_info: &mut SendInfo,
648 ) -> ssize_t {
649 if out_len > <ssize_t>::max_value() as usize {
650 panic!("The provided buffer is too large");
651 }
652
653 let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
654
655 match conn.send(out) {
656 Ok((v, info)) => {
657 out_info.to_len = std_addr_to_c(&info.to, &mut out_info.to);
658
659 std_time_to_c(&info.at, &mut out_info.at);
660
661 v as ssize_t
662 },
663
664 Err(e) => e.to_c(),
665 }
666 }
667
668 #[no_mangle]
quiche_conn_stream_recv( conn: &mut Connection, stream_id: u64, out: *mut u8, out_len: size_t, fin: &mut bool, ) -> ssize_t669 pub extern fn quiche_conn_stream_recv(
670 conn: &mut Connection, stream_id: u64, out: *mut u8, out_len: size_t,
671 fin: &mut bool,
672 ) -> ssize_t {
673 if out_len > <ssize_t>::max_value() as usize {
674 panic!("The provided buffer is too large");
675 }
676
677 let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
678
679 let (out_len, out_fin) = match conn.stream_recv(stream_id, out) {
680 Ok(v) => v,
681
682 Err(e) => return e.to_c(),
683 };
684
685 *fin = out_fin;
686
687 out_len as ssize_t
688 }
689
690 #[no_mangle]
quiche_conn_stream_send( conn: &mut Connection, stream_id: u64, buf: *const u8, buf_len: size_t, fin: bool, ) -> ssize_t691 pub extern fn quiche_conn_stream_send(
692 conn: &mut Connection, stream_id: u64, buf: *const u8, buf_len: size_t,
693 fin: bool,
694 ) -> ssize_t {
695 if buf_len > <ssize_t>::max_value() as usize {
696 panic!("The provided buffer is too large");
697 }
698
699 let buf = unsafe { slice::from_raw_parts(buf, buf_len) };
700
701 match conn.stream_send(stream_id, buf, fin) {
702 Ok(v) => v as ssize_t,
703
704 Err(e) => e.to_c(),
705 }
706 }
707
708 #[no_mangle]
quiche_conn_stream_priority( conn: &mut Connection, stream_id: u64, urgency: u8, incremental: bool, ) -> c_int709 pub extern fn quiche_conn_stream_priority(
710 conn: &mut Connection, stream_id: u64, urgency: u8, incremental: bool,
711 ) -> c_int {
712 match conn.stream_priority(stream_id, urgency, incremental) {
713 Ok(_) => 0,
714
715 Err(e) => e.to_c() as c_int,
716 }
717 }
718
719 #[no_mangle]
quiche_conn_stream_shutdown( conn: &mut Connection, stream_id: u64, direction: Shutdown, err: u64, ) -> c_int720 pub extern fn quiche_conn_stream_shutdown(
721 conn: &mut Connection, stream_id: u64, direction: Shutdown, err: u64,
722 ) -> c_int {
723 match conn.stream_shutdown(stream_id, direction, err) {
724 Ok(_) => 0,
725
726 Err(e) => e.to_c() as c_int,
727 }
728 }
729
730 #[no_mangle]
quiche_conn_stream_capacity( conn: &mut Connection, stream_id: u64, ) -> ssize_t731 pub extern fn quiche_conn_stream_capacity(
732 conn: &mut Connection, stream_id: u64,
733 ) -> ssize_t {
734 match conn.stream_capacity(stream_id) {
735 Ok(v) => v as ssize_t,
736
737 Err(e) => e.to_c(),
738 }
739 }
740
741 #[no_mangle]
quiche_conn_stream_readable( conn: &mut Connection, stream_id: u64, ) -> bool742 pub extern fn quiche_conn_stream_readable(
743 conn: &mut Connection, stream_id: u64,
744 ) -> bool {
745 conn.stream_readable(stream_id)
746 }
747
748 #[no_mangle]
quiche_conn_stream_finished( conn: &mut Connection, stream_id: u64, ) -> bool749 pub extern fn quiche_conn_stream_finished(
750 conn: &mut Connection, stream_id: u64,
751 ) -> bool {
752 conn.stream_finished(stream_id)
753 }
754
755 #[no_mangle]
quiche_conn_readable(conn: &Connection) -> *mut StreamIter756 pub extern fn quiche_conn_readable(conn: &Connection) -> *mut StreamIter {
757 Box::into_raw(Box::new(conn.readable()))
758 }
759
760 #[no_mangle]
quiche_conn_writable(conn: &Connection) -> *mut StreamIter761 pub extern fn quiche_conn_writable(conn: &Connection) -> *mut StreamIter {
762 Box::into_raw(Box::new(conn.writable()))
763 }
764
765 #[no_mangle]
quiche_conn_max_send_udp_payload_size(conn: &Connection) -> usize766 pub extern fn quiche_conn_max_send_udp_payload_size(conn: &Connection) -> usize {
767 conn.max_send_udp_payload_size()
768 }
769
770 #[no_mangle]
quiche_conn_is_readable(conn: &Connection) -> bool771 pub extern fn quiche_conn_is_readable(conn: &Connection) -> bool {
772 conn.is_readable()
773 }
774
775 struct AppData(*mut c_void);
776 unsafe impl Send for AppData {}
777 unsafe impl Sync for AppData {}
778
779 #[no_mangle]
quiche_conn_stream_init_application_data( conn: &mut Connection, stream_id: u64, data: *mut c_void, ) -> c_int780 pub extern fn quiche_conn_stream_init_application_data(
781 conn: &mut Connection, stream_id: u64, data: *mut c_void,
782 ) -> c_int {
783 match conn.stream_init_application_data(stream_id, AppData(data)) {
784 Ok(_) => 0,
785
786 Err(e) => e.to_c() as c_int,
787 }
788 }
789
790 #[no_mangle]
quiche_conn_stream_application_data( conn: &mut Connection, stream_id: u64, ) -> *mut c_void791 pub extern fn quiche_conn_stream_application_data(
792 conn: &mut Connection, stream_id: u64,
793 ) -> *mut c_void {
794 match conn.stream_application_data(stream_id) {
795 Some(v) => v.downcast_mut::<AppData>().unwrap().0,
796
797 None => ptr::null_mut(),
798 }
799 }
800
801 #[no_mangle]
quiche_conn_close( conn: &mut Connection, app: bool, err: u64, reason: *const u8, reason_len: size_t, ) -> c_int802 pub extern fn quiche_conn_close(
803 conn: &mut Connection, app: bool, err: u64, reason: *const u8,
804 reason_len: size_t,
805 ) -> c_int {
806 let reason = unsafe { slice::from_raw_parts(reason, reason_len) };
807
808 match conn.close(app, err, reason) {
809 Ok(_) => 0,
810
811 Err(e) => e.to_c() as c_int,
812 }
813 }
814
815 #[no_mangle]
quiche_conn_timeout_as_nanos(conn: &mut Connection) -> u64816 pub extern fn quiche_conn_timeout_as_nanos(conn: &mut Connection) -> u64 {
817 match conn.timeout() {
818 Some(timeout) => timeout.as_nanos() as u64,
819
820 None => std::u64::MAX,
821 }
822 }
823
824 #[no_mangle]
quiche_conn_timeout_as_millis(conn: &mut Connection) -> u64825 pub extern fn quiche_conn_timeout_as_millis(conn: &mut Connection) -> u64 {
826 match conn.timeout() {
827 Some(timeout) => timeout.as_millis() as u64,
828
829 None => std::u64::MAX,
830 }
831 }
832
833 #[no_mangle]
quiche_conn_on_timeout(conn: &mut Connection)834 pub extern fn quiche_conn_on_timeout(conn: &mut Connection) {
835 conn.on_timeout()
836 }
837
838 #[no_mangle]
quiche_conn_trace_id( conn: &mut Connection, out: &mut *const u8, out_len: &mut size_t, )839 pub extern fn quiche_conn_trace_id(
840 conn: &mut Connection, out: &mut *const u8, out_len: &mut size_t,
841 ) {
842 let trace_id = conn.trace_id();
843
844 *out = trace_id.as_ptr();
845 *out_len = trace_id.len();
846 }
847
848 #[no_mangle]
quiche_conn_source_id( conn: &mut Connection, out: &mut *const u8, out_len: &mut size_t, )849 pub extern fn quiche_conn_source_id(
850 conn: &mut Connection, out: &mut *const u8, out_len: &mut size_t,
851 ) {
852 let conn_id = conn.source_id();
853 let id = conn_id.as_ref();
854 *out = id.as_ptr();
855 *out_len = id.len();
856 }
857
858 #[no_mangle]
quiche_conn_destination_id( conn: &mut Connection, out: &mut *const u8, out_len: &mut size_t, )859 pub extern fn quiche_conn_destination_id(
860 conn: &mut Connection, out: &mut *const u8, out_len: &mut size_t,
861 ) {
862 let conn_id = conn.destination_id();
863 let id = conn_id.as_ref();
864
865 *out = id.as_ptr();
866 *out_len = id.len();
867 }
868
869 #[no_mangle]
quiche_conn_application_proto( conn: &mut Connection, out: &mut *const u8, out_len: &mut size_t, )870 pub extern fn quiche_conn_application_proto(
871 conn: &mut Connection, out: &mut *const u8, out_len: &mut size_t,
872 ) {
873 let proto = conn.application_proto();
874
875 *out = proto.as_ptr();
876 *out_len = proto.len();
877 }
878
879 #[no_mangle]
quiche_conn_session( conn: &mut Connection, out: &mut *const u8, out_len: &mut size_t, )880 pub extern fn quiche_conn_session(
881 conn: &mut Connection, out: &mut *const u8, out_len: &mut size_t,
882 ) {
883 match conn.session() {
884 Some(session) => {
885 *out = session.as_ptr();
886 *out_len = session.len();
887 },
888
889 None => *out_len = 0,
890 }
891 }
892
893 #[no_mangle]
quiche_conn_is_established(conn: &mut Connection) -> bool894 pub extern fn quiche_conn_is_established(conn: &mut Connection) -> bool {
895 conn.is_established()
896 }
897
898 #[no_mangle]
quiche_conn_is_in_early_data(conn: &mut Connection) -> bool899 pub extern fn quiche_conn_is_in_early_data(conn: &mut Connection) -> bool {
900 conn.is_in_early_data()
901 }
902
903 #[no_mangle]
quiche_conn_is_draining(conn: &mut Connection) -> bool904 pub extern fn quiche_conn_is_draining(conn: &mut Connection) -> bool {
905 conn.is_draining()
906 }
907
908 #[no_mangle]
quiche_conn_is_closed(conn: &mut Connection) -> bool909 pub extern fn quiche_conn_is_closed(conn: &mut Connection) -> bool {
910 conn.is_closed()
911 }
912
913 #[no_mangle]
quiche_conn_peer_error( conn: &mut Connection, is_app: *mut bool, error_code: *mut u64, reason: &mut *const u8, reason_len: &mut size_t, ) -> bool914 pub extern fn quiche_conn_peer_error(
915 conn: &mut Connection, is_app: *mut bool, error_code: *mut u64,
916 reason: &mut *const u8, reason_len: &mut size_t,
917 ) -> bool {
918 match &conn.peer_error {
919 Some(conn_err) => unsafe {
920 *is_app = conn_err.is_app;
921 *error_code = conn_err.error_code;
922 *reason = conn_err.reason.as_ptr();
923 *reason_len = conn_err.reason.len();
924
925 true
926 },
927
928 None => false,
929 }
930 }
931
932 #[no_mangle]
quiche_stream_iter_next( iter: &mut StreamIter, stream_id: *mut u64, ) -> bool933 pub extern fn quiche_stream_iter_next(
934 iter: &mut StreamIter, stream_id: *mut u64,
935 ) -> bool {
936 if let Some(v) = iter.next() {
937 unsafe { *stream_id = v };
938 return true;
939 }
940
941 false
942 }
943
944 #[no_mangle]
quiche_stream_iter_free(iter: *mut StreamIter)945 pub extern fn quiche_stream_iter_free(iter: *mut StreamIter) {
946 unsafe { Box::from_raw(iter) };
947 }
948
949 #[repr(C)]
950 pub struct Stats {
951 recv: usize,
952 sent: usize,
953 lost: usize,
954 rtt: u64,
955 cwnd: usize,
956 delivery_rate: u64,
957 }
958
959 #[no_mangle]
quiche_conn_stats(conn: &Connection, out: &mut Stats)960 pub extern fn quiche_conn_stats(conn: &Connection, out: &mut Stats) {
961 let stats = conn.stats();
962
963 out.recv = stats.recv;
964 out.sent = stats.sent;
965 out.lost = stats.lost;
966 out.rtt = stats.rtt.as_nanos() as u64;
967 out.cwnd = stats.cwnd;
968 out.delivery_rate = stats.delivery_rate;
969 }
970
971 #[no_mangle]
quiche_conn_dgram_max_writable_len(conn: &Connection) -> ssize_t972 pub extern fn quiche_conn_dgram_max_writable_len(conn: &Connection) -> ssize_t {
973 match conn.dgram_max_writable_len() {
974 None => Error::Done.to_c(),
975
976 Some(v) => v as ssize_t,
977 }
978 }
979
980 #[no_mangle]
quiche_conn_dgram_recv_front_len(conn: &Connection) -> ssize_t981 pub extern fn quiche_conn_dgram_recv_front_len(conn: &Connection) -> ssize_t {
982 match conn.dgram_recv_front_len() {
983 None => Error::Done.to_c(),
984
985 Some(v) => v as ssize_t,
986 }
987 }
988
989 #[no_mangle]
quiche_conn_dgram_recv_queue_len(conn: &Connection) -> ssize_t990 pub extern fn quiche_conn_dgram_recv_queue_len(conn: &Connection) -> ssize_t {
991 conn.dgram_recv_queue_len() as ssize_t
992 }
993
994 #[no_mangle]
quiche_conn_dgram_recv_queue_byte_size( conn: &Connection, ) -> ssize_t995 pub extern fn quiche_conn_dgram_recv_queue_byte_size(
996 conn: &Connection,
997 ) -> ssize_t {
998 conn.dgram_recv_queue_byte_size() as ssize_t
999 }
1000
1001 #[no_mangle]
quiche_conn_dgram_send_queue_len(conn: &Connection) -> ssize_t1002 pub extern fn quiche_conn_dgram_send_queue_len(conn: &Connection) -> ssize_t {
1003 conn.dgram_send_queue_len() as ssize_t
1004 }
1005
1006 #[no_mangle]
quiche_conn_dgram_send_queue_byte_size( conn: &Connection, ) -> ssize_t1007 pub extern fn quiche_conn_dgram_send_queue_byte_size(
1008 conn: &Connection,
1009 ) -> ssize_t {
1010 conn.dgram_send_queue_byte_size() as ssize_t
1011 }
1012
1013 #[no_mangle]
quiche_conn_dgram_send( conn: &mut Connection, buf: *const u8, buf_len: size_t, ) -> ssize_t1014 pub extern fn quiche_conn_dgram_send(
1015 conn: &mut Connection, buf: *const u8, buf_len: size_t,
1016 ) -> ssize_t {
1017 if buf_len > <ssize_t>::max_value() as usize {
1018 panic!("The provided buffer is too large");
1019 }
1020
1021 let buf = unsafe { slice::from_raw_parts(buf, buf_len) };
1022
1023 match conn.dgram_send(buf) {
1024 Ok(_) => buf_len as ssize_t,
1025
1026 Err(e) => e.to_c(),
1027 }
1028 }
1029
1030 #[no_mangle]
quiche_conn_dgram_recv( conn: &mut Connection, out: *mut u8, out_len: size_t, ) -> ssize_t1031 pub extern fn quiche_conn_dgram_recv(
1032 conn: &mut Connection, out: *mut u8, out_len: size_t,
1033 ) -> ssize_t {
1034 if out_len > <ssize_t>::max_value() as usize {
1035 panic!("The provided buffer is too large");
1036 }
1037
1038 let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
1039
1040 let out_len = match conn.dgram_recv(out) {
1041 Ok(v) => v,
1042
1043 Err(e) => return e.to_c(),
1044 };
1045
1046 out_len as ssize_t
1047 }
1048
1049 #[no_mangle]
quiche_conn_dgram_purge_outgoing( conn: &mut Connection, f: extern fn(*const u8, size_t) -> bool, )1050 pub extern fn quiche_conn_dgram_purge_outgoing(
1051 conn: &mut Connection, f: extern fn(*const u8, size_t) -> bool,
1052 ) {
1053 conn.dgram_purge_outgoing(|d: &[u8]| -> bool {
1054 let ptr: *const u8 = d.as_ptr();
1055 let len: size_t = d.len();
1056
1057 f(ptr, len)
1058 });
1059 }
1060
1061 #[no_mangle]
quiche_conn_free(conn: *mut Connection)1062 pub extern fn quiche_conn_free(conn: *mut Connection) {
1063 unsafe { Box::from_raw(conn) };
1064 }
1065
1066 #[no_mangle]
quiche_conn_peer_streams_left_bidi(conn: &mut Connection) -> u641067 pub extern fn quiche_conn_peer_streams_left_bidi(conn: &mut Connection) -> u64 {
1068 conn.peer_streams_left_bidi()
1069 }
1070
1071 #[no_mangle]
quiche_conn_peer_streams_left_uni(conn: &mut Connection) -> u641072 pub extern fn quiche_conn_peer_streams_left_uni(conn: &mut Connection) -> u64 {
1073 conn.peer_streams_left_uni()
1074 }
1075
std_addr_from_c(addr: &sockaddr, addr_len: socklen_t) -> SocketAddr1076 fn std_addr_from_c(addr: &sockaddr, addr_len: socklen_t) -> SocketAddr {
1077 unsafe {
1078 match addr.sa_family as i32 {
1079 AF_INET => {
1080 assert!(addr_len as usize == std::mem::size_of::<sockaddr_in>());
1081
1082 SocketAddr::V4(
1083 *(addr as *const _ as *const sockaddr_in as *const _),
1084 )
1085 },
1086
1087 AF_INET6 => {
1088 assert!(addr_len as usize == std::mem::size_of::<sockaddr_in6>());
1089
1090 SocketAddr::V6(
1091 *(addr as *const _ as *const sockaddr_in6 as *const _),
1092 )
1093 },
1094
1095 _ => unimplemented!("unsupported address type"),
1096 }
1097 }
1098 }
1099
std_addr_to_c(addr: &SocketAddr, out: &mut sockaddr_storage) -> socklen_t1100 fn std_addr_to_c(addr: &SocketAddr, out: &mut sockaddr_storage) -> socklen_t {
1101 unsafe {
1102 match addr {
1103 SocketAddr::V4(addr) => {
1104 let sa_len = std::mem::size_of::<sockaddr_in>();
1105
1106 let src = addr as *const _ as *const u8;
1107 let dst = out as *mut _ as *mut u8;
1108
1109 std::ptr::copy_nonoverlapping(src, dst, sa_len);
1110
1111 sa_len as socklen_t
1112 },
1113
1114 SocketAddr::V6(addr) => {
1115 let sa_len = std::mem::size_of::<sockaddr_in6>();
1116
1117 let src = addr as *const _ as *const u8;
1118 let dst = out as *mut _ as *mut u8;
1119
1120 std::ptr::copy_nonoverlapping(src, dst, sa_len);
1121
1122 sa_len as socklen_t
1123 },
1124 }
1125 }
1126 }
1127
1128 #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))]
std_time_to_c(time: &std::time::Instant, out: &mut timespec)1129 fn std_time_to_c(time: &std::time::Instant, out: &mut timespec) {
1130 unsafe {
1131 ptr::copy_nonoverlapping(time as *const _ as *const timespec, out, 1)
1132 }
1133 }
1134
1135 #[cfg(any(target_os = "macos", target_os = "ios", target_os = "windows"))]
std_time_to_c(_time: &std::time::Instant, out: &mut timespec)1136 fn std_time_to_c(_time: &std::time::Instant, out: &mut timespec) {
1137 // TODO: implement Instant conversion for systems that don't use timespec.
1138 out.tv_sec = 0;
1139 out.tv_nsec = 0;
1140 }
1141