blob: 1f0ad0bb75f869e1ad51e3a7aef3d2a9e6700dc4 [file] [log] [blame]
// Copyright (C) 2019, Cloudflare, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use std::ffi;
use std::ptr;
use std::slice;
use std::str;
use libc::c_char;
use libc::c_int;
use libc::c_void;
use libc::size_t;
use libc::ssize_t;
use crate::*;
use crate::h3::NameValue;
#[no_mangle]
pub extern fn quiche_h3_config_new() -> *mut h3::Config {
match h3::Config::new() {
Ok(c) => Box::into_raw(Box::new(c)),
Err(_) => ptr::null_mut(),
}
}
#[no_mangle]
pub extern fn quiche_h3_config_set_max_header_list_size(
config: &mut h3::Config, v: u64,
) {
config.set_max_header_list_size(v);
}
#[no_mangle]
pub extern fn quiche_h3_config_set_qpack_max_table_capacity(
config: &mut h3::Config, v: u64,
) {
config.set_qpack_max_table_capacity(v);
}
#[no_mangle]
pub extern fn quiche_h3_config_set_qpack_blocked_streams(
config: &mut h3::Config, v: u64,
) {
config.set_qpack_blocked_streams(v);
}
#[no_mangle]
pub extern fn quiche_h3_config_set_dgram_poll_threshold(
config: &mut h3::Config, v: u64,
) {
config.set_dgram_poll_threshold(v);
}
#[no_mangle]
pub extern fn quiche_h3_config_set_stream_poll_threshold(
config: &mut h3::Config, v: u64,
) {
config.set_stream_poll_threshold(v);
}
#[no_mangle]
pub extern fn quiche_h3_config_free(config: *mut h3::Config) {
unsafe { Box::from_raw(config) };
}
#[no_mangle]
pub extern fn quiche_h3_conn_new_with_transport(
quic_conn: &mut Connection, config: &mut h3::Config,
) -> *mut h3::Connection {
match h3::Connection::with_transport(quic_conn, config) {
Ok(c) => Box::into_raw(Box::new(c)),
Err(_) => ptr::null_mut(),
}
}
#[no_mangle]
pub extern fn quiche_h3_conn_poll(
conn: &mut h3::Connection, quic_conn: &mut Connection,
ev: *mut *const h3::Event,
) -> i64 {
match conn.poll(quic_conn) {
Ok((id, v)) => {
unsafe {
*ev = Box::into_raw(Box::new(v));
}
id as i64
},
Err(e) => e.to_c() as i64,
}
}
#[no_mangle]
pub extern fn quiche_h3_event_type(ev: &h3::Event) -> u32 {
match ev {
h3::Event::Headers { .. } => 0,
h3::Event::Data { .. } => 1,
h3::Event::Finished { .. } => 2,
h3::Event::Datagram { .. } => 3,
h3::Event::GoAway { .. } => 4,
}
}
#[no_mangle]
pub extern fn 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_int {
match ev {
h3::Event::Headers { list, .. } =>
for h in list {
let rc = cb(
h.name().as_ptr(),
h.name().len(),
h.value().as_ptr(),
h.value().len(),
argp,
);
if rc != 0 {
return rc;
}
},
_ => unreachable!(),
}
0
}
#[no_mangle]
pub extern fn quiche_h3_event_headers_has_body(ev: &h3::Event) -> bool {
match ev {
h3::Event::Headers { has_body, .. } => *has_body,
_ => unreachable!(),
}
}
#[no_mangle]
pub extern fn quiche_h3_event_free(ev: *mut h3::Event) {
unsafe { Box::from_raw(ev) };
}
#[repr(C)]
pub struct Header {
name: *mut u8,
name_len: usize,
value: *mut u8,
value_len: usize,
}
#[no_mangle]
pub extern fn quiche_h3_send_request(
conn: &mut h3::Connection, quic_conn: &mut Connection,
headers: *const Header, headers_len: size_t, fin: bool,
) -> i64 {
let req_headers = headers_from_ptr(headers, headers_len);
match conn.send_request(quic_conn, &req_headers, fin) {
Ok(v) => v as i64,
Err(e) => e.to_c() as i64,
}
}
#[no_mangle]
pub extern fn 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_int {
let resp_headers = headers_from_ptr(headers, headers_len);
match conn.send_response(quic_conn, stream_id, &resp_headers, fin) {
Ok(_) => 0,
Err(e) => e.to_c() as c_int,
}
}
#[no_mangle]
pub extern fn 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_int {
let resp_headers = headers_from_ptr(headers, headers_len);
let priority = unsafe { ffi::CStr::from_ptr(priority).to_str().unwrap() };
match conn.send_response_with_priority(
quic_conn,
stream_id,
&resp_headers,
&priority,
fin,
) {
Ok(_) => 0,
Err(e) => e.to_c() as c_int,
}
}
#[no_mangle]
pub extern fn 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_t {
if body_len > <ssize_t>::max_value() as usize {
panic!("The provided buffer is too large");
}
let body = unsafe { slice::from_raw_parts(body, body_len) };
match conn.send_body(quic_conn, stream_id, body, fin) {
Ok(v) => v as ssize_t,
Err(e) => e.to_c(),
}
}
#[no_mangle]
pub extern fn quiche_h3_recv_body(
conn: &mut h3::Connection, quic_conn: &mut Connection, stream_id: u64,
out: *mut u8, out_len: size_t,
) -> ssize_t {
if out_len > <ssize_t>::max_value() as usize {
panic!("The provided buffer is too large");
}
let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
match conn.recv_body(quic_conn, stream_id, out) {
Ok(v) => v as ssize_t,
Err(e) => e.to_c(),
}
}
#[no_mangle]
pub extern fn quiche_h3_dgram_enabled_by_peer(
conn: &h3::Connection, quic_conn: &Connection,
) -> bool {
conn.dgram_enabled_by_peer(quic_conn)
}
#[no_mangle]
pub extern fn quiche_h3_send_dgram(
conn: &mut h3::Connection, quic_conn: &mut Connection, flow_id: u64,
data: *const u8, data_len: size_t,
) -> c_int {
if data_len > <ssize_t>::max_value() as usize {
panic!("The provided buffer is too large");
}
let data = unsafe { slice::from_raw_parts(data, data_len) };
match conn.send_dgram(quic_conn, flow_id, data) {
Ok(_) => 0,
Err(e) => e.to_c() as c_int,
}
}
#[no_mangle]
pub extern fn 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_t {
if out_len > <ssize_t>::max_value() as usize {
panic!("The provided buffer is too large");
}
let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
match conn.recv_dgram(quic_conn, out) {
Ok((len, id, id_len)) => {
unsafe { *flow_id = id };
unsafe { *flow_id_len = id_len };
len as ssize_t
},
Err(e) => e.to_c(),
}
}
#[no_mangle]
pub extern fn quiche_h3_conn_free(conn: *mut h3::Connection) {
unsafe { Box::from_raw(conn) };
}
fn headers_from_ptr<'a>(
ptr: *const Header, len: size_t,
) -> Vec<h3::HeaderRef<'a>> {
let headers = unsafe { slice::from_raw_parts(ptr, len) };
let mut out = Vec::new();
for h in headers {
out.push({
let name = unsafe {
let slice = slice::from_raw_parts(h.name, h.name_len);
str::from_utf8_unchecked(slice)
};
let value = unsafe {
let slice = slice::from_raw_parts(h.value, h.value_len);
str::from_utf8_unchecked(slice)
};
h3::HeaderRef::new(name, value)
});
}
out
}