1#[cfg(feature = "sfv")]
28use std::convert::TryFrom;
29
30use std::ptr;
31use std::slice;
32
33use libc::c_int;
34use libc::c_void;
35use libc::size_t;
36use libc::ssize_t;
37
38use crate::*;
39
40use crate::h3::NameValue;
41use crate::h3::Priority;
42
43#[no_mangle]
44pub extern "C" fn quiche_h3_config_new() -> *mut h3::Config {
45 match h3::Config::new() {
46 Ok(c) => Box::into_raw(Box::new(c)),
47
48 Err(_) => ptr::null_mut(),
49 }
50}
51
52#[no_mangle]
53pub extern "C" fn quiche_h3_config_set_max_field_section_size(
54 config: &mut h3::Config, v: u64,
55) {
56 config.set_max_field_section_size(v);
57}
58
59#[no_mangle]
60pub extern "C" fn quiche_h3_config_set_qpack_max_table_capacity(
61 config: &mut h3::Config, v: u64,
62) {
63 config.set_qpack_max_table_capacity(v);
64}
65
66#[no_mangle]
67pub extern "C" fn quiche_h3_config_set_qpack_blocked_streams(
68 config: &mut h3::Config, v: u64,
69) {
70 config.set_qpack_blocked_streams(v);
71}
72
73#[no_mangle]
74pub extern "C" fn quiche_h3_config_enable_extended_connect(
75 config: &mut h3::Config, enabled: bool,
76) {
77 config.enable_extended_connect(enabled);
78}
79
80#[no_mangle]
81pub extern "C" fn quiche_h3_config_set_max_priority_update_size(
82 config: &mut h3::Config, v: u64,
83) {
84 config.set_max_priority_update_size(v);
85}
86
87#[no_mangle]
88pub extern "C" fn quiche_h3_config_free(config: *mut h3::Config) {
89 if !config.is_null() {
90 drop(unsafe { Box::from_raw(config) });
91 }
92}
93
94#[no_mangle]
95pub extern "C" fn quiche_h3_conn_new_with_transport(
96 quic_conn: &mut Connection, config: &mut h3::Config,
97) -> *mut h3::Connection {
98 match h3::Connection::with_transport(quic_conn, config) {
99 Ok(c) => Box::into_raw(Box::new(c)),
100
101 Err(_) => ptr::null_mut(),
102 }
103}
104
105#[no_mangle]
106pub extern "C" fn quiche_h3_for_each_setting(
107 conn: &h3::Connection,
108 cb: extern "C" fn(identifier: u64, value: u64, argp: *mut c_void) -> c_int,
109 argp: *mut c_void,
110) -> c_int {
111 match conn.peer_settings_raw() {
112 Some(raw) => {
113 for setting in raw {
114 let rc = cb(setting.0, setting.1, argp);
115
116 if rc != 0 {
117 return rc;
118 }
119 }
120
121 0
122 },
123
124 None => -1,
125 }
126}
127
128#[no_mangle]
129pub extern "C" fn quiche_h3_conn_poll(
130 conn: &mut h3::Connection, quic_conn: &mut Connection,
131 ev: *mut *const h3::Event,
132) -> i64 {
133 match conn.poll(quic_conn) {
134 Ok((id, v)) => {
135 unsafe {
136 *ev = Box::into_raw(Box::new(v));
137 }
138
139 id as i64
140 },
141
142 Err(e) => e.to_c() as i64,
143 }
144}
145
146#[no_mangle]
147pub extern "C" fn quiche_h3_event_type(ev: &h3::Event) -> u32 {
148 match ev {
149 h3::Event::Headers { .. } => 0,
150
151 h3::Event::Data => 1,
152
153 h3::Event::Finished => 2,
154
155 h3::Event::GoAway => 3,
156
157 h3::Event::Reset { .. } => 4,
158
159 h3::Event::PriorityUpdate => 5,
160 }
161}
162
163#[no_mangle]
164pub extern "C" fn quiche_h3_event_for_each_header(
165 ev: &h3::Event,
166 cb: extern "C" fn(
167 name: *const u8,
168 name_len: size_t,
169
170 value: *const u8,
171 value_len: size_t,
172
173 argp: *mut c_void,
174 ) -> c_int,
175 argp: *mut c_void,
176) -> c_int {
177 match ev {
178 h3::Event::Headers { list, .. } =>
179 for h in list {
180 let rc = cb(
181 h.name().as_ptr(),
182 h.name().len(),
183 h.value().as_ptr(),
184 h.value().len(),
185 argp,
186 );
187
188 if rc != 0 {
189 return rc;
190 }
191 },
192
193 _ => unreachable!(),
194 }
195
196 0
197}
198
199#[no_mangle]
200pub extern "C" fn quiche_h3_event_headers_has_more_frames(
201 ev: &h3::Event,
202) -> bool {
203 match ev {
204 h3::Event::Headers { more_frames, .. } => *more_frames,
205
206 _ => unreachable!(),
207 }
208}
209
210#[no_mangle]
211pub extern "C" fn quiche_h3_extended_connect_enabled_by_peer(
212 conn: &h3::Connection,
213) -> bool {
214 conn.extended_connect_enabled_by_peer()
215}
216
217#[no_mangle]
218pub extern "C" fn quiche_h3_event_free(ev: *mut h3::Event) {
219 if !ev.is_null() {
220 drop(unsafe { Box::from_raw(ev) });
221 }
222}
223
224#[repr(C)]
225pub struct Header {
226 name: *mut u8,
227 name_len: usize,
228
229 value: *mut u8,
230 value_len: usize,
231}
232
233#[no_mangle]
234pub extern "C" fn quiche_h3_send_request(
235 conn: &mut h3::Connection, quic_conn: &mut Connection,
236 headers: *const Header, headers_len: size_t, fin: bool,
237) -> i64 {
238 let req_headers = headers_from_ptr(headers, headers_len);
239
240 match conn.send_request(quic_conn, &req_headers, fin) {
241 Ok(v) => v as i64,
242
243 Err(e) => e.to_c() as i64,
244 }
245}
246
247#[no_mangle]
248pub extern "C" fn quiche_h3_send_response(
249 conn: &mut h3::Connection, quic_conn: &mut Connection, stream_id: u64,
250 headers: *const Header, headers_len: size_t, fin: bool,
251) -> c_int {
252 let resp_headers = headers_from_ptr(headers, headers_len);
253
254 match conn.send_response(quic_conn, stream_id, &resp_headers, fin) {
255 Ok(_) => 0,
256
257 Err(e) => e.to_c() as c_int,
258 }
259}
260
261#[no_mangle]
262pub extern "C" fn quiche_h3_send_response_with_priority(
263 conn: &mut h3::Connection, quic_conn: &mut Connection, stream_id: u64,
264 headers: *const Header, headers_len: size_t, priority: &Priority, fin: bool,
265) -> c_int {
266 let resp_headers = headers_from_ptr(headers, headers_len);
267
268 match conn.send_response_with_priority(
269 quic_conn,
270 stream_id,
271 &resp_headers,
272 priority,
273 fin,
274 ) {
275 Ok(_) => 0,
276
277 Err(e) => e.to_c() as c_int,
278 }
279}
280
281#[no_mangle]
282pub extern "C" fn quiche_h3_send_additional_headers(
283 conn: &mut h3::Connection, quic_conn: &mut Connection, stream_id: u64,
284 headers: *const Header, headers_len: size_t, is_trailer_section: bool,
285 fin: bool,
286) -> c_int {
287 let headers = headers_from_ptr(headers, headers_len);
288
289 match conn.send_additional_headers(
290 quic_conn,
291 stream_id,
292 &headers,
293 is_trailer_section,
294 fin,
295 ) {
296 Ok(_) => 0,
297
298 Err(e) => e.to_c() as c_int,
299 }
300}
301
302#[no_mangle]
303pub extern "C" fn quiche_h3_send_body(
304 conn: &mut h3::Connection, quic_conn: &mut Connection, stream_id: u64,
305 body: *const u8, body_len: size_t, fin: bool,
306) -> ssize_t {
307 if body_len > <ssize_t>::MAX as usize {
308 panic!("The provided buffer is too large");
309 }
310
311 let body = unsafe { slice::from_raw_parts(body, body_len) };
312
313 match conn.send_body(quic_conn, stream_id, body, fin) {
314 Ok(v) => v as ssize_t,
315
316 Err(e) => e.to_c(),
317 }
318}
319
320#[no_mangle]
321pub extern "C" fn quiche_h3_recv_body(
322 conn: &mut h3::Connection, quic_conn: &mut Connection, stream_id: u64,
323 out: *mut u8, out_len: size_t,
324) -> ssize_t {
325 if out_len > <ssize_t>::MAX as usize {
326 panic!("The provided buffer is too large");
327 }
328
329 let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
330
331 match conn.recv_body(quic_conn, stream_id, out) {
332 Ok(v) => v as ssize_t,
333
334 Err(e) => e.to_c(),
335 }
336}
337
338#[no_mangle]
339pub extern "C" fn quiche_h3_send_goaway(
340 conn: &mut h3::Connection, quic_conn: &mut Connection, id: u64,
341) -> c_int {
342 match conn.send_goaway(quic_conn, id) {
343 Ok(()) => 0,
344
345 Err(e) => e.to_c() as c_int,
346 }
347}
348
349#[no_mangle]
350#[cfg(feature = "sfv")]
351pub extern "C" fn quiche_h3_parse_extensible_priority(
352 priority: *const u8, priority_len: size_t, parsed: &mut Priority,
353) -> c_int {
354 let priority = unsafe { slice::from_raw_parts(priority, priority_len) };
355
356 match Priority::try_from(priority) {
357 Ok(v) => {
358 parsed.urgency = v.urgency;
359 parsed.incremental = v.incremental;
360 0
361 },
362
363 Err(e) => e.to_c() as c_int,
364 }
365}
366
367#[no_mangle]
368pub extern "C" fn quiche_h3_send_priority_update_for_request(
369 conn: &mut h3::Connection, quic_conn: &mut Connection, stream_id: u64,
370 priority: &Priority,
371) -> c_int {
372 match conn.send_priority_update_for_request(quic_conn, stream_id, priority) {
373 Ok(()) => 0,
374
375 Err(e) => e.to_c() as c_int,
376 }
377}
378
379#[no_mangle]
380pub extern "C" fn quiche_h3_take_last_priority_update(
381 conn: &mut h3::Connection, prioritized_element_id: u64,
382 cb: extern "C" fn(
383 priority_field_value: *const u8,
384 priority_field_value_len: size_t,
385 argp: *mut c_void,
386 ) -> c_int,
387 argp: *mut c_void,
388) -> c_int {
389 match conn.take_last_priority_update(prioritized_element_id) {
390 Ok(priority) => {
391 let rc = cb(priority.as_ptr(), priority.len(), argp);
392
393 if rc != 0 {
394 return rc;
395 }
396
397 0
398 },
399
400 Err(e) => e.to_c() as c_int,
401 }
402}
403
404#[no_mangle]
405pub extern "C" fn quiche_h3_dgram_enabled_by_peer(
406 conn: &h3::Connection, quic_conn: &Connection,
407) -> bool {
408 conn.dgram_enabled_by_peer(quic_conn)
409}
410
411#[no_mangle]
412pub extern "C" fn quiche_h3_conn_free(conn: *mut h3::Connection) {
413 if !conn.is_null() {
414 drop(unsafe { Box::from_raw(conn) });
415 }
416}
417
418fn headers_from_ptr<'a>(
419 ptr: *const Header, len: size_t,
420) -> Vec<h3::HeaderRef<'a>> {
421 let headers = unsafe { slice::from_raw_parts(ptr, len) };
422
423 let mut out = Vec::new();
424
425 for h in headers {
426 out.push({
427 let name = unsafe { slice::from_raw_parts(h.name, h.name_len) };
428 let value = unsafe { slice::from_raw_parts(h.value, h.value_len) };
429
430 h3::HeaderRef::new(name, value)
431 });
432 }
433
434 out
435}
436
437#[repr(C)]
438pub struct Stats {
439 qpack_encoder_stream_recv_bytes: u64,
440 qpack_decoder_stream_recv_bytes: u64,
441}
442
443#[no_mangle]
444pub extern "C" fn quiche_h3_conn_stats(conn: &h3::Connection, out: &mut Stats) {
445 let stats = conn.stats();
446
447 out.qpack_encoder_stream_recv_bytes = stats.qpack_encoder_stream_recv_bytes;
448 out.qpack_decoder_stream_recv_bytes = stats.qpack_decoder_stream_recv_bytes;
449}