summaryrefslogtreecommitdiffstats
path: root/openpgp-ffi
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2020-11-24 10:45:29 +0100
committerJustus Winter <justus@sequoia-pgp.org>2020-12-07 15:57:42 +0100
commit551f29499a3ca9c5b15692ac7877730808dda8cb (patch)
treee84fb3c3d3bb0390d248a874d1fdd192a64dd0d0 /openpgp-ffi
parente524ef5fbc97c0c54b8144aed81c383faa099173 (diff)
openpgp: Make serialize::stream::Message Send + Sync.
- See #615.
Diffstat (limited to 'openpgp-ffi')
-rw-r--r--openpgp-ffi/include/sequoia/io.h13
-rw-r--r--openpgp-ffi/src/io.rs49
-rw-r--r--openpgp-ffi/src/serialize.rs4
3 files changed, 51 insertions, 15 deletions
diff --git a/openpgp-ffi/include/sequoia/io.h b/openpgp-ffi/include/sequoia/io.h
index 81d0093a..e574aefb 100644
--- a/openpgp-ffi/include/sequoia/io.h
+++ b/openpgp-ffi/include/sequoia/io.h
@@ -92,6 +92,13 @@ pgp_writer_t pgp_writer_from_bytes (uint8_t *buf, size_t len);
/// reference a chunk of memory allocated using libc's heap allocator.
/// The caller is responsible to `free` it once the writer has been
/// destroyed.
+///
+/// # Sending objects across thread boundaries
+///
+/// If you send a Sequoia object (like a pgp_writer_stack_t) that
+/// serializes to an allocating writer across thread boundaries, you
+/// must make sure that the system's allocator (i.e. `realloc (3)`)
+/// supports reallocating memory allocated by another thread.
/*/
pgp_writer_t pgp_writer_alloc (void **buf, size_t *len);
@@ -104,6 +111,12 @@ typedef ssize_t (*pgp_writer_cb_t) (void *cookie, const void *buf, size_t len);
/// Creates an writer from a callback and cookie.
///
/// This writer calls the given callback to write data.
+///
+/// # Sending objects across thread boundaries
+///
+/// If you send a Sequoia object (like a pgp_writer_stack_t) that
+/// serializes to a callback-based writer across thread boundaries,
+/// you must make sure that the callback and cookie also support this.
/*/
pgp_writer_t pgp_writer_from_callback (pgp_writer_cb_t, void *);
diff --git a/openpgp-ffi/src/io.rs b/openpgp-ffi/src/io.rs
index 35e80c47..484615cf 100644
--- a/openpgp-ffi/src/io.rs
+++ b/openpgp-ffi/src/io.rs
@@ -4,6 +4,7 @@ use std::fs::File;
use std::io::{self, Read, Write, Cursor};
use std::path::Path;
use std::slice;
+use std::sync::Mutex;
use libc::{c_void, c_char, size_t, ssize_t, realloc};
#[cfg(unix)]
@@ -181,7 +182,7 @@ pub struct Writer(WriterKind);
/// In some cases, we want to call functions on concrete types. To
/// avoid nasty hacks, we have specialized variants for that.
pub(crate) enum WriterKind {
- Generic(Box<dyn io::Write>),
+ Generic(Box<dyn io::Write + Send + Sync>),
Armored(openpgp::armor::Writer<&'static mut WriterKind>),
}
@@ -247,6 +248,13 @@ fn pgp_writer_from_bytes(buf: *mut u8, len: size_t) -> *mut Writer {
/// The caller is responsible to `free` it once the writer has been
/// destroyed.
///
+/// # Sending objects across thread boundaries
+///
+/// If you send a Sequoia object (like a pgp_writer_stack_t) that
+/// serializes to an allocating writer across thread boundaries, you
+/// must make sure that the system's allocator (i.e. `realloc (3)`)
+/// supports reallocating memory allocated by another thread.
+///
/// # Examples
///
/// ```c
@@ -302,32 +310,36 @@ fn pgp_writer_alloc(buf: *mut *mut c_void, len: *mut size_t)
let buf = ffi_param_ref_mut!(buf);
let len = ffi_param_ref_mut!(len);
- let w = WriterKind::Generic(Box::new(WriterAlloc {
+ let w = WriterKind::Generic(Box::new(WriterAlloc(Mutex::new(Buffer {
buf: buf,
len: len,
- }));
+ }))));
w.move_into_raw()
}
-struct WriterAlloc {
+struct WriterAlloc(Mutex<Buffer>);
+struct Buffer {
buf: &'static mut *mut c_void,
len: &'static mut size_t,
}
+unsafe impl Send for Buffer {}
+
impl Write for WriterAlloc {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- let old_len = *self.len;
+ let buffer = self.0.get_mut().expect("Mutex not to be poisoned");
+ let old_len = *buffer.len;
let new_len = old_len + buf.len();
let new = unsafe {
- realloc(*self.buf, new_len)
+ realloc(*buffer.buf, new_len)
};
if new.is_null() {
return Err(io::Error::new(io::ErrorKind::Other, "out of memory"));
}
- *self.buf = new;
- *self.len = new_len;
+ *buffer.buf = new;
+ *buffer.len = new_len;
let sl = unsafe {
slice::from_raw_parts_mut(new as *mut u8, new_len)
@@ -348,26 +360,37 @@ type WriterCallbackFn = extern fn(*mut c_void, *const c_void, size_t) -> ssize_t
/// Creates an writer from a callback and cookie.
///
/// This writer calls the given callback to write data.
+///
+/// # Sending objects across thread boundaries
+///
+/// If you send a Sequoia object (like a pgp_writer_stack_t) that
+/// serializes to a callback-based writer across thread boundaries,
+/// you must make sure that the callback and cookie also support this.
#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C"
fn pgp_writer_from_callback(cb: WriterCallbackFn,
cookie: *mut c_void)
-> *mut Writer {
- let w = WriterKind::Generic(Box::new(WriterCallback {
- cb, cookie,
- }));
+ let w = WriterKind::Generic(Box::new(WriterCallback(Mutex::new(
+ WriterClosure { cb, cookie, }))));
w.move_into_raw()
}
/// A generic callback-based writer implementation.
-struct WriterCallback {
+struct WriterCallback(Mutex<WriterClosure>);
+
+struct WriterClosure {
cb: WriterCallbackFn,
cookie: *mut c_void,
}
+unsafe impl Send for WriterClosure {}
+
impl Write for WriterCallback {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ let closure = self.0.get_mut().expect("Mutex not to be poisoned");
let r =
- (self.cb)(self.cookie, buf.as_ptr() as *const c_void, buf.len());
+ (closure.cb)(closure.cookie,
+ buf.as_ptr() as *const c_void, buf.len());
if r < 0 {
use std::io as stdio;
Err(stdio::Error::new(stdio::ErrorKind::Other,
diff --git a/openpgp-ffi/src/serialize.rs b/openpgp-ffi/src/serialize.rs
index aecf1a0a..053fedbb 100644
--- a/openpgp-ffi/src/serialize.rs
+++ b/openpgp-ffi/src/serialize.rs
@@ -152,7 +152,7 @@ pub extern "C" fn pgp_arbitrary_writer_new
pub extern "C" fn pgp_signer_new
(errp: Option<&mut *mut crate::error::Error>,
inner: *mut Message<'static>,
- signers: *const *mut Box<dyn self::openpgp::crypto::Signer>,
+ signers: *const *mut Box<dyn self::openpgp::crypto::Signer + Send + Sync>,
signers_len: size_t,
hash_algo: u8)
-> *mut Message<'static>
@@ -189,7 +189,7 @@ pub extern "C" fn pgp_signer_new
pub extern "C" fn pgp_signer_new_detached
(errp: Option<&mut *mut crate::error::Error>,
inner: *mut Message<'static>,
- signers: *const *mut Box<dyn self::openpgp::crypto::Signer>,
+ signers: *const *mut Box<dyn self::openpgp::crypto::Signer + Send + Sync>,
signers_len: size_t,
hash_algo: u8)
-> *mut Message<'static>