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