• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2018-2019, Cloudflare, Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //     * Redistributions of source code must retain the above copyright notice,
9 //       this list of conditions and the following disclaimer.
10 //
11 //     * Redistributions in binary form must reproduce the above copyright
12 //       notice, this list of conditions and the following disclaimer in the
13 //       documentation and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
19 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 
27 use std::ffi;
28 use std::ptr;
29 use std::slice;
30 use std::sync::atomic;
31 
32 use std::net::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