Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโ€™ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SM-1413] Resolve Concurrency Issues in C FFI #981

Merged
merged 4 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 26 additions & 11 deletions crates/bitwarden-c/src/c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,24 @@

use crate::{box_ptr, ffi_ref};

#[repr(C)]
pub struct CClient {
/// Associates the tokio runtime to the `Client`, ensuring the runtime has the same lifecycle
/// as the `Client`.
runtime: tokio::runtime::Runtime,
Hinton marked this conversation as resolved.
Show resolved Hide resolved
client: Client,
}

#[no_mangle]
#[tokio::main]
pub async extern "C" fn run_command(
c_str_ptr: *const c_char,
client_ptr: *const Client,
) -> *mut c_char {
pub extern "C" fn run_command(c_str_ptr: *const c_char, client_ptr: *const CClient) -> *mut c_char {

Check warning on line 16 in crates/bitwarden-c/src/c.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-c/src/c.rs#L16

Added line #L16 was not covered by tests
let client = unsafe { ffi_ref!(client_ptr) };
let input_str = str::from_utf8(unsafe { CStr::from_ptr(c_str_ptr) }.to_bytes())
.expect("Input should be a valid string");

let result = client.run_command(input_str).await;
let result = client
.runtime
.block_on(client.client.run_command(input_str));

Check warning on line 24 in crates/bitwarden-c/src/c.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-c/src/c.rs#L21-L24

Added lines #L21 - L24 were not covered by tests
match std::ffi::CString::new(result) {
Ok(cstr) => cstr.into_raw(),
Err(_) => panic!("failed to return command result: null encountered"),
Expand All @@ -23,17 +30,25 @@

// Init client, potential leak! You need to call free_mem after this!
#[no_mangle]
pub extern "C" fn init(c_str_ptr: *const c_char) -> *mut Client {
pub extern "C" fn init(c_str_ptr: *const c_char) -> *mut CClient {

Check warning on line 33 in crates/bitwarden-c/src/c.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-c/src/c.rs#L33

Added line #L33 was not covered by tests
// This will only fail if another logger was already initialized, so we can ignore the result
let _ = env_logger::try_init();
if c_str_ptr.is_null() {
box_ptr!(Client::new(None))

let runtime = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.expect("Failed to build tokio runtime");

Check warning on line 40 in crates/bitwarden-c/src/c.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-c/src/c.rs#L36-L40

Added lines #L36 - L40 were not covered by tests

let client = if c_str_ptr.is_null() {
Client::new(None)

Check warning on line 43 in crates/bitwarden-c/src/c.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-c/src/c.rs#L42-L43

Added lines #L42 - L43 were not covered by tests
} else {
let input_string = str::from_utf8(unsafe { CStr::from_ptr(c_str_ptr) }.to_bytes())
.expect("Input should be a valid string")
.to_owned();
box_ptr!(Client::new(Some(input_string)))
}
Client::new(Some(input_string))

Check warning on line 48 in crates/bitwarden-c/src/c.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-c/src/c.rs#L48

Added line #L48 was not covered by tests
};

box_ptr!(CClient { runtime, client })

Check warning on line 51 in crates/bitwarden-c/src/c.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-c/src/c.rs#L51

Added line #L51 was not covered by tests
}

// Free mem
Expand Down
16 changes: 8 additions & 8 deletions crates/bitwarden-py/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use pyo3::prelude::*;

#[pyclass]
pub struct BitwardenClient(JsonClient);
pub struct BitwardenClient(tokio::runtime::Runtime, JsonClient);

#[pymethods]
impl BitwardenClient {
Expand All @@ -13,16 +13,16 @@
// result
let _ = pyo3_log::try_init();

Self(JsonClient::new(settings_string))
let runtime = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.expect("Failed to build tokio runtime");

Self(runtime, JsonClient::new(settings_string))

Check warning on line 21 in crates/bitwarden-py/src/client.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-py/src/client.rs#L16-L21

Added lines #L16 - L21 were not covered by tests
}

#[pyo3(text_signature = "($self, command_input)")]
fn run_command(&self, command_input: String) -> String {
run_command(&self.0, &command_input)
self.0.block_on(self.1.run_command(&command_input))

Check warning on line 26 in crates/bitwarden-py/src/client.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-py/src/client.rs#L26

Added line #L26 was not covered by tests
}
}

#[tokio::main]
async fn run_command(client: &JsonClient, input_str: &str) -> String {
client.run_command(input_str).await
}
2 changes: 1 addition & 1 deletion languages/go/bitwarden_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func NewBitwardenClient(apiURL *string, identityURL *string) (BitwardenClientInt

func (c *BitwardenClient) AccessTokenLogin(accessToken string, stateFile *string) error {
req := AccessTokenLoginRequest{AccessToken: accessToken, StateFile: stateFile}
command := Command{AccessTokenLogin: &req}
command := Command{LoginAccessToken: &req}

responseStr, err := c.commandRunner.RunCommand(command)
if err != nil {
Expand Down
Loading