Skip to content

Commit

Permalink
Implement SSL_read, SSL_write and associated
Browse files Browse the repository at this point in the history
  • Loading branch information
ctz committed Mar 26, 2024
1 parent 16e9387 commit 3032b3d
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 2 deletions.
5 changes: 5 additions & 0 deletions rustls-libssl/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,11 @@ const ENTRYPOINTS: &[&str] = &[
"SSL_free",
"SSL_get_options",
"SSL_get_shutdown",
"SSL_has_pending",
"SSL_is_server",
"SSL_new",
"SSL_pending",
"SSL_read",
"SSL_set0_rbio",
"SSL_set0_wbio",
"SSL_set1_host",
Expand All @@ -85,6 +88,8 @@ const ENTRYPOINTS: &[&str] = &[
"SSL_set_shutdown",
"SSL_shutdown",
"SSL_up_ref",
"SSL_want",
"SSL_write",
"TLS_client_method",
"TLS_method",
"TLS_server_method",
Expand Down
81 changes: 79 additions & 2 deletions rustls-libssl/src/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ use openssl_sys::{OPENSSL_malloc, X509_STORE, X509_STORE_CTX};
use crate::bio::{Bio, BIO};
use crate::error::{ffi_panic_boundary, Error, MysteriouslyOppositeReturnValue};
use crate::ffi::{
free_arc, str_from_cstring, to_arc_mut_ptr, try_clone_arc, try_from, try_ref_from_ptr,
try_slice, try_str, Castable, OwnershipArc, OwnershipRef,
free_arc, str_from_cstring, to_arc_mut_ptr, try_clone_arc, try_from, try_mut_slice_int,
try_ref_from_ptr, try_slice, try_slice_int, try_str, Castable, OwnershipArc, OwnershipRef,
};
use crate::ShutdownResult;

Expand Down Expand Up @@ -515,6 +515,65 @@ entry! {
}
}

entry! {
pub fn _SSL_write(ssl: *mut SSL, buf: *const c_void, num: c_int) -> c_int {
const ERROR: c_int = -1;
let ssl = try_clone_arc!(ssl, ERROR);
let slice = try_slice_int!(buf as *const u8, num, ERROR);

if slice.is_empty() {
return ERROR;
}

match ssl
.lock()
.map_err(|_| Error::cannot_lock())
.and_then(|mut ssl| ssl.write(slice))
.map_err(|err| err.raise())
{
Err(_e) => ERROR,
Ok(written) => written as c_int,
}
}
}

entry! {
pub fn _SSL_read(ssl: *mut SSL, buf: *mut c_void, num: c_int) -> c_int {
const ERROR: c_int = -1;
let ssl = try_clone_arc!(ssl, ERROR);
let slice = try_mut_slice_int!(buf as *mut u8, num, ERROR);

match ssl
.lock()
.map_err(|_| Error::cannot_lock())
.and_then(|mut ssl| ssl.read(slice))
.map_err(|err| err.raise())
{
Err(_e) => ERROR,
Ok(read) => read as c_int,
}
}
}

entry! {
pub fn _SSL_want(ssl: *const SSL) -> c_int {
let ssl = try_clone_arc!(ssl);
let want = ssl.lock().ok().map(|ssl| ssl.want()).unwrap_or_default();

if want.read {
SSL_READING
} else if want.write {
SSL_WRITING
} else {
SSL_NOTHING
}
}
}

pub const SSL_NOTHING: i32 = 1;
pub const SSL_WRITING: i32 = 2;
pub const SSL_READING: i32 = 3;

entry! {
pub fn _SSL_shutdown(ssl: *mut SSL) -> c_int {
const ERROR: c_int = -1;
Expand Down Expand Up @@ -555,6 +614,24 @@ entry! {
}
}

entry! {
pub fn _SSL_pending(ssl: *const SSL) -> c_int {
let ssl = try_clone_arc!(ssl);

ssl.lock()
.map_err(|_| Error::cannot_lock())
.map(|mut ssl| ssl.get_pending_plaintext() as c_int)
.map_err(|err| err.raise())
.unwrap_or_default()
}
}

entry! {
pub fn _SSL_has_pending(ssl: *const SSL) -> c_int {
(_SSL_pending(ssl) > 0) as c_int
}
}

impl Castable for SSL {
type Ownership = OwnershipArc;
type RustType = Mutex<SSL>;
Expand Down
64 changes: 64 additions & 0 deletions rustls-libssl/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use core::ffi::CStr;
use std::io::{ErrorKind, Read, Write};
use std::sync::{Arc, Mutex};

use openssl_sys::X509_STORE;
Expand Down Expand Up @@ -427,6 +428,53 @@ impl Ssl {
Ok(())
}

fn want(&self) -> Want {
match &self.conn {
Some(conn) => Want {
read: conn.wants_read(),
write: conn.wants_write(),
},
None => Want::default(),
}
}

fn write(&mut self, slice: &[u8]) -> Result<usize, error::Error> {
let written = match &mut self.conn {
Some(ref mut conn) => conn.writer().write(slice).map_err(error::Error::from_io)?,
None => 0,
};
self.try_io()?;
Ok(written)
}

fn read(&mut self, slice: &mut [u8]) -> Result<usize, error::Error> {
let (late_err, read_count) = loop {
let late_err = self.try_io();

match &mut self.conn {
Some(ref mut conn) => match conn.reader().read(slice) {
Ok(read) => break (late_err, read),
Err(err) if err.kind() == ErrorKind::WouldBlock && late_err.is_ok() => {
// no data available, go around again.
continue;
}
Err(err) => {
return Err(error::Error::from_io(err));
}
},
None => break (late_err, 0),
};
};

if read_count > 0 {
Ok(read_count)
} else {
// Only raise IO errors after all data has been read.
late_err?;
Ok(0)
}
}

fn try_io(&mut self) -> Result<(), error::Error> {
let bio = match self.bio.as_mut() {
Some(bio) => bio,
Expand Down Expand Up @@ -478,6 +526,22 @@ impl Ssl {
fn set_shutdown(&mut self, flags: i32) {
self.shutdown_flags.set(flags);
}

fn get_pending_plaintext(&mut self) -> usize {
self.conn
.as_mut()
.and_then(|conn| {
let io_state = conn.process_new_packets().ok()?;
Some(io_state.plaintext_bytes_to_read())
})
.unwrap_or_default()
}
}

#[derive(Default)]
struct Want {
read: bool,
write: bool,
}

#[derive(PartialEq)]
Expand Down

0 comments on commit 3032b3d

Please sign in to comment.