1 // Copyright (C) 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::str;
31 
32 use libc::c_char;
33 use libc::c_int;
34 use libc::c_void;
35 use libc::size_t;
36 use libc::ssize_t;
37 
38 use crate::*;
39 
40 use crate::h3::NameValue;
41 
42 #[no_mangle]
quiche_h3_config_new() -> *mut h3::Config43 pub extern fn quiche_h3_config_new() -> *mut h3::Config {
44     match h3::Config::new() {
45         Ok(c) => Box::into_raw(Box::new(c)),
46 
47         Err(_) => ptr::null_mut(),
48     }
49 }
50 
51 #[no_mangle]
quiche_h3_config_set_max_header_list_size( config: &mut h3::Config, v: u64, )52 pub extern fn quiche_h3_config_set_max_header_list_size(
53     config: &mut h3::Config, v: u64,
54 ) {
55     config.set_max_header_list_size(v);
56 }
57 
58 #[no_mangle]
quiche_h3_config_set_qpack_max_table_capacity( config: &mut h3::Config, v: u64, )59 pub extern fn quiche_h3_config_set_qpack_max_table_capacity(
60     config: &mut h3::Config, v: u64,
61 ) {
62     config.set_qpack_max_table_capacity(v);
63 }
64 
65 #[no_mangle]
quiche_h3_config_set_qpack_blocked_streams( config: &mut h3::Config, v: u64, )66 pub extern fn quiche_h3_config_set_qpack_blocked_streams(
67     config: &mut h3::Config, v: u64,
68 ) {
69     config.set_qpack_blocked_streams(v);
70 }
71 
72 #[no_mangle]
quiche_h3_config_free(config: *mut h3::Config)73 pub extern fn quiche_h3_config_free(config: *mut h3::Config) {
74     unsafe { Box::from_raw(config) };
75 }
76 
77 #[no_mangle]
quiche_h3_conn_new_with_transport( quic_conn: &mut Connection, config: &mut h3::Config, ) -> *mut h3::Connection78 pub extern fn quiche_h3_conn_new_with_transport(
79     quic_conn: &mut Connection, config: &mut h3::Config,
80 ) -> *mut h3::Connection {
81     match h3::Connection::with_transport(quic_conn, config) {
82         Ok(c) => Box::into_raw(Box::new(c)),
83 
84         Err(_) => ptr::null_mut(),
85     }
86 }
87 
88 #[no_mangle]
quiche_h3_conn_poll( conn: &mut h3::Connection, quic_conn: &mut Connection, ev: *mut *const h3::Event, ) -> i6489 pub extern fn quiche_h3_conn_poll(
90     conn: &mut h3::Connection, quic_conn: &mut Connection,
91     ev: *mut *const h3::Event,
92 ) -> i64 {
93     match conn.poll(quic_conn) {
94         Ok((id, v)) => {
95             unsafe {
96                 *ev = Box::into_raw(Box::new(v));
97             }
98 
99             id as i64
100         },
101 
102         Err(e) => e.to_c() as i64,
103     }
104 }
105 
106 #[no_mangle]
quiche_h3_event_type(ev: &h3::Event) -> u32107 pub extern fn quiche_h3_event_type(ev: &h3::Event) -> u32 {
108     match ev {
109         h3::Event::Headers { .. } => 0,
110 
111         h3::Event::Data { .. } => 1,
112 
113         h3::Event::Finished { .. } => 2,
114 
115         h3::Event::Datagram { .. } => 3,
116 
117         h3::Event::GoAway { .. } => 4,
118     }
119 }
120 
121 #[no_mangle]
quiche_h3_event_for_each_header( ev: &h3::Event, cb: extern fn( name: *const u8, name_len: size_t, value: *const u8, value_len: size_t, argp: *mut c_void, ) -> c_int, argp: *mut c_void, ) -> c_int122 pub extern fn quiche_h3_event_for_each_header(
123     ev: &h3::Event,
124     cb: extern fn(
125         name: *const u8,
126         name_len: size_t,
127 
128         value: *const u8,
129         value_len: size_t,
130 
131         argp: *mut c_void,
132     ) -> c_int,
133     argp: *mut c_void,
134 ) -> c_int {
135     match ev {
136         h3::Event::Headers { list, .. } =>
137             for h in list {
138                 let rc = cb(
139                     h.name().as_ptr(),
140                     h.name().len(),
141                     h.value().as_ptr(),
142                     h.value().len(),
143                     argp,
144                 );
145 
146                 if rc != 0 {
147                     return rc;
148                 }
149             },
150 
151         _ => unreachable!(),
152     }
153 
154     0
155 }
156 
157 #[no_mangle]
quiche_h3_event_headers_has_body(ev: &h3::Event) -> bool158 pub extern fn quiche_h3_event_headers_has_body(ev: &h3::Event) -> bool {
159     match ev {
160         h3::Event::Headers { has_body, .. } => *has_body,
161 
162         _ => unreachable!(),
163     }
164 }
165 
166 #[no_mangle]
quiche_h3_event_free(ev: *mut h3::Event)167 pub extern fn quiche_h3_event_free(ev: *mut h3::Event) {
168     unsafe { Box::from_raw(ev) };
169 }
170 
171 #[repr(C)]
172 pub struct Header {
173     name: *mut u8,
174     name_len: usize,
175 
176     value: *mut u8,
177     value_len: usize,
178 }
179 
180 #[no_mangle]
quiche_h3_send_request( conn: &mut h3::Connection, quic_conn: &mut Connection, headers: *const Header, headers_len: size_t, fin: bool, ) -> i64181 pub extern fn quiche_h3_send_request(
182     conn: &mut h3::Connection, quic_conn: &mut Connection,
183     headers: *const Header, headers_len: size_t, fin: bool,
184 ) -> i64 {
185     let req_headers = headers_from_ptr(headers, headers_len);
186 
187     match conn.send_request(quic_conn, &req_headers, fin) {
188         Ok(v) => v as i64,
189 
190         Err(e) => e.to_c() as i64,
191     }
192 }
193 
194 #[no_mangle]
quiche_h3_send_response( conn: &mut h3::Connection, quic_conn: &mut Connection, stream_id: u64, headers: *const Header, headers_len: size_t, fin: bool, ) -> c_int195 pub extern fn quiche_h3_send_response(
196     conn: &mut h3::Connection, quic_conn: &mut Connection, stream_id: u64,
197     headers: *const Header, headers_len: size_t, fin: bool,
198 ) -> c_int {
199     let resp_headers = headers_from_ptr(headers, headers_len);
200 
201     match conn.send_response(quic_conn, stream_id, &resp_headers, fin) {
202         Ok(_) => 0,
203 
204         Err(e) => e.to_c() as c_int,
205     }
206 }
207 
208 #[no_mangle]
quiche_h3_send_response_with_priority( conn: &mut h3::Connection, quic_conn: &mut Connection, stream_id: u64, headers: *const Header, headers_len: size_t, priority: *const c_char, fin: bool, ) -> c_int209 pub extern fn quiche_h3_send_response_with_priority(
210     conn: &mut h3::Connection, quic_conn: &mut Connection, stream_id: u64,
211     headers: *const Header, headers_len: size_t, priority: *const c_char,
212     fin: bool,
213 ) -> c_int {
214     let resp_headers = headers_from_ptr(headers, headers_len);
215     let priority = unsafe { ffi::CStr::from_ptr(priority).to_str().unwrap() };
216 
217     match conn.send_response_with_priority(
218         quic_conn,
219         stream_id,
220         &resp_headers,
221         &priority,
222         fin,
223     ) {
224         Ok(_) => 0,
225 
226         Err(e) => e.to_c() as c_int,
227     }
228 }
229 
230 #[no_mangle]
quiche_h3_send_body( conn: &mut h3::Connection, quic_conn: &mut Connection, stream_id: u64, body: *const u8, body_len: size_t, fin: bool, ) -> ssize_t231 pub extern fn quiche_h3_send_body(
232     conn: &mut h3::Connection, quic_conn: &mut Connection, stream_id: u64,
233     body: *const u8, body_len: size_t, fin: bool,
234 ) -> ssize_t {
235     if body_len > <ssize_t>::max_value() as usize {
236         panic!("The provided buffer is too large");
237     }
238 
239     let body = unsafe { slice::from_raw_parts(body, body_len) };
240 
241     match conn.send_body(quic_conn, stream_id, body, fin) {
242         Ok(v) => v as ssize_t,
243 
244         Err(e) => e.to_c(),
245     }
246 }
247 
248 #[no_mangle]
quiche_h3_recv_body( conn: &mut h3::Connection, quic_conn: &mut Connection, stream_id: u64, out: *mut u8, out_len: size_t, ) -> ssize_t249 pub extern fn quiche_h3_recv_body(
250     conn: &mut h3::Connection, quic_conn: &mut Connection, stream_id: u64,
251     out: *mut u8, out_len: size_t,
252 ) -> ssize_t {
253     if out_len > <ssize_t>::max_value() as usize {
254         panic!("The provided buffer is too large");
255     }
256 
257     let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
258 
259     match conn.recv_body(quic_conn, stream_id, out) {
260         Ok(v) => v as ssize_t,
261 
262         Err(e) => e.to_c(),
263     }
264 }
265 
266 #[no_mangle]
quiche_h3_send_dgram( conn: &mut h3::Connection, quic_conn: &mut Connection, flow_id: u64, data: *const u8, data_len: size_t, ) -> c_int267 pub extern fn quiche_h3_send_dgram(
268     conn: &mut h3::Connection, quic_conn: &mut Connection, flow_id: u64,
269     data: *const u8, data_len: size_t,
270 ) -> c_int {
271     if data_len > <ssize_t>::max_value() as usize {
272         panic!("The provided buffer is too large");
273     }
274 
275     let data = unsafe { slice::from_raw_parts(data, data_len) };
276 
277     match conn.send_dgram(quic_conn, flow_id, data) {
278         Ok(_) => 0,
279 
280         Err(e) => e.to_c() as c_int,
281     }
282 }
283 
284 #[no_mangle]
quiche_h3_recv_dgram( conn: &mut h3::Connection, quic_conn: &mut Connection, flow_id: *mut u64, flow_id_len: *mut usize, out: *mut u8, out_len: size_t, ) -> ssize_t285 pub extern fn quiche_h3_recv_dgram(
286     conn: &mut h3::Connection, quic_conn: &mut Connection, flow_id: *mut u64,
287     flow_id_len: *mut usize, out: *mut u8, out_len: size_t,
288 ) -> ssize_t {
289     if out_len > <ssize_t>::max_value() as usize {
290         panic!("The provided buffer is too large");
291     }
292 
293     let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
294 
295     match conn.recv_dgram(quic_conn, out) {
296         Ok((len, id, id_len)) => {
297             unsafe { *flow_id = id };
298             unsafe { *flow_id_len = id_len };
299             len as ssize_t
300         },
301 
302         Err(e) => e.to_c(),
303     }
304 }
305 
306 #[no_mangle]
quiche_h3_conn_free(conn: *mut h3::Connection)307 pub extern fn quiche_h3_conn_free(conn: *mut h3::Connection) {
308     unsafe { Box::from_raw(conn) };
309 }
310 
headers_from_ptr<'a>( ptr: *const Header, len: size_t, ) -> Vec<h3::HeaderRef<'a>>311 fn headers_from_ptr<'a>(
312     ptr: *const Header, len: size_t,
313 ) -> Vec<h3::HeaderRef<'a>> {
314     let headers = unsafe { slice::from_raw_parts(ptr, len) };
315 
316     let mut out = Vec::new();
317 
318     for h in headers {
319         out.push({
320             let name = unsafe {
321                 let slice = slice::from_raw_parts(h.name, h.name_len);
322                 str::from_utf8_unchecked(slice)
323             };
324 
325             let value = unsafe {
326                 let slice = slice::from_raw_parts(h.value, h.value_len);
327                 str::from_utf8_unchecked(slice)
328             };
329 
330             h3::HeaderRef::new(name, value)
331         });
332     }
333 
334     out
335 }
336