diff options
| author | mojganii <mojgan.jelodar@codic.se> | 2025-03-18 17:05:17 +0100 |
|---|---|---|
| committer | mojganii <mojgan.jelodar@codic.se> | 2025-04-15 15:38:45 +0200 |
| commit | 59f4f47a1ed3e89d6273ba1cb8a9749ef45e49b9 (patch) | |
| tree | a4acf78d94df4d9762d7713790122815e06a64ac | |
| parent | effafb699b8f6831cbc6df0bcaa51766d9a44718 (diff) | |
| download | mullvadvpn-59f4f47a1ed3e89d6273ba1cb8a9749ef45e49b9.tar.xz mullvadvpn-59f4f47a1ed3e89d6273ba1cb8a9749ef45e49b9.zip | |
Implement mullvad_api_send_problem_report in Rust
| -rw-r--r-- | ios/MullvadRustRuntime/include/mullvad_rust_runtime.h | 14 | ||||
| -rw-r--r-- | mullvad-api/src/lib.rs | 18 | ||||
| -rw-r--r-- | mullvad-ios/src/api_client/mod.rs | 1 | ||||
| -rw-r--r-- | mullvad-ios/src/api_client/response.rs | 1 | ||||
| -rw-r--r-- | mullvad-ios/src/api_client/send_problem_report.rs | 124 |
5 files changed, 156 insertions, 2 deletions
diff --git a/ios/MullvadRustRuntime/include/mullvad_rust_runtime.h b/ios/MullvadRustRuntime/include/mullvad_rust_runtime.h index 12ce0fd4c0..77dac6b4da 100644 --- a/ios/MullvadRustRuntime/include/mullvad_rust_runtime.h +++ b/ios/MullvadRustRuntime/include/mullvad_rust_runtime.h @@ -54,6 +54,15 @@ typedef struct CompletionCookie { void *inner; } CompletionCookie; +typedef struct SwiftProblemReportRequest { + const uint8_t *address; + uintptr_t address_len; + const uint8_t *message; + uintptr_t message_len; + const uint8_t *log; + uintptr_t log_len; +} SwiftProblemReportRequest; + typedef struct ProxyHandle { void *context; uint16_t port; @@ -258,6 +267,11 @@ struct SwiftRetryStrategy mullvad_api_retry_strategy_exponential(uintptr_t max_r uint32_t factor, uint64_t max_delay_sec); +struct SwiftCancelHandle mullvad_api_send_problem_report(struct SwiftApiContext api_context, + void *completion_cookie, + struct SwiftRetryStrategy retry_strategy, + const struct SwiftProblemReportRequest *request); + /** * Initializes a valid pointer to an instance of `EncryptedDnsProxyState`. * diff --git a/mullvad-api/src/lib.rs b/mullvad-api/src/lib.rs index 2d2814d099..987098c591 100644 --- a/mullvad-api/src/lib.rs +++ b/mullvad-api/src/lib.rs @@ -687,6 +687,21 @@ impl ProblemReportProxy { log: &str, metadata: &BTreeMap<String, String>, ) -> impl Future<Output = Result<(), rest::Error>> { + let future = self.porblem_report_response(email, message, log, metadata); + + async move { + future.await?; + Ok(()) + } + } + + pub fn porblem_report_response( + &self, + email: &str, + message: &str, + log: &str, + metadata: &BTreeMap<String, String>, + ) -> impl Future<Output = Result<rest::Response<Incoming>, rest::Error>> { #[derive(serde::Serialize)] struct ProblemReport { address: String, @@ -709,8 +724,7 @@ impl ProblemReportProxy { let request = factory .post_json(&format!("{APP_URL_PREFIX}/problem-report"), &report)? .expected_status(&[StatusCode::NO_CONTENT]); - service.request(request).await?; - Ok(()) + service.request(request).await } } } diff --git a/mullvad-ios/src/api_client/mod.rs b/mullvad-ios/src/api_client/mod.rs index fd9fde7aa7..234724530e 100644 --- a/mullvad-ios/src/api_client/mod.rs +++ b/mullvad-ios/src/api_client/mod.rs @@ -15,6 +15,7 @@ mod cancellation; mod completion; mod response; mod retry_strategy; +mod send_problem_report; #[repr(C)] pub struct SwiftApiContext(*const ApiContext); diff --git a/mullvad-ios/src/api_client/response.rs b/mullvad-ios/src/api_client/response.rs index 3b017e37c6..90f1552ffd 100644 --- a/mullvad-ios/src/api_client/response.rs +++ b/mullvad-ios/src/api_client/response.rs @@ -8,6 +8,7 @@ use mullvad_api::{ RelayListProxy, StatusCode, }; + #[repr(C)] pub struct SwiftMullvadApiResponse { body: *mut u8, diff --git a/mullvad-ios/src/api_client/send_problem_report.rs b/mullvad-ios/src/api_client/send_problem_report.rs new file mode 100644 index 0000000000..f96f8926d2 --- /dev/null +++ b/mullvad-ios/src/api_client/send_problem_report.rs @@ -0,0 +1,124 @@ +use mullvad_api::{ + rest::{self, MullvadRestHandle}, + ProblemReportProxy, +}; +use talpid_future::retry::retry_future; + +use super::{ + cancellation::{RequestCancelHandle, SwiftCancelHandle}, + completion::{CompletionCookie, SwiftCompletionHandler}, + response::SwiftMullvadApiResponse, + retry_strategy::{RetryStrategy, SwiftRetryStrategy}, + SwiftApiContext, +}; + +use mullvad_api::rest::Error; +use std::{collections::BTreeMap}; +use std::slice; +use tokio::task::JoinHandle; + +#[no_mangle] +pub unsafe extern "C" fn mullvad_api_send_problem_report( + api_context: SwiftApiContext, + completion_cookie: *mut libc::c_void, + retry_strategy: SwiftRetryStrategy, + request: *const SwiftProblemReportRequest, +) -> SwiftCancelHandle { + let completion_handler = SwiftCompletionHandler::new(CompletionCookie(completion_cookie)); + let completion = completion_handler.clone(); + + let Ok(tokio_handle) = crate::mullvad_ios_runtime() else { + completion_handler.finish(SwiftMullvadApiResponse::no_tokio_runtime()); + return SwiftCancelHandle::empty(); + }; + + let api_context = api_context.into_rust_context(); + let retry_strategy = unsafe { retry_strategy.into_rust() }; + + let problem_report_request = match unsafe { ProblemReportRequest::from_swift_parameters(request) } { + Some(req) => req, + None => { + let err = Error::ApiError(rest::StatusCode::BAD_REQUEST, "Failed to send problem report: invalid address, message, or log data.".to_string()); + log::error!("{err:?}"); + completion.finish(SwiftMullvadApiResponse::rest_error(err)); + return SwiftCancelHandle::empty(); + } + }; + + let task: JoinHandle<()> = tokio_handle.spawn(async move { + match mullvad_api_send_problem_report_inner( + api_context.rest_handle(), + retry_strategy, + problem_report_request, + ) + .await + { + Ok(response) => completion.finish(response), + Err(err) => { + log::error!("{err:?}"); + completion.finish(SwiftMullvadApiResponse::rest_error(err)); + } + } + }); + + RequestCancelHandle::new(task, completion_handler.clone()).into_swift() +} + +async fn mullvad_api_send_problem_report_inner( + rest_client: MullvadRestHandle, + retry_strategy: RetryStrategy, + problem_report_request: ProblemReportRequest, +) -> Result<SwiftMullvadApiResponse, rest::Error> { + let api = ProblemReportProxy::new(rest_client); + let empty_metadata: BTreeMap<String, String> = BTreeMap::new(); + + let future_factory = || api.porblem_report_response(&problem_report_request.address, &problem_report_request.message, &(String::from_utf8_lossy(&problem_report_request.log)), &empty_metadata); + + let should_retry = |result: &Result<_, rest::Error>| match result { + Err(err) => err.is_network_error(), + Ok(_) => false, + }; + + let response = retry_future(future_factory, should_retry, retry_strategy.delays()).await?; + SwiftMullvadApiResponse::with_body(response).await + +} + +#[repr(C)] +pub struct SwiftProblemReportRequest { + address: *const u8, + address_len: usize, + message: *const u8, + message_len: usize, + log: *const u8, + log_len: usize, +} + +struct ProblemReportRequest { + address: String, + message: String, + log: Vec<u8>, +} + + +unsafe impl Send for SwiftProblemReportRequest {} + +impl ProblemReportRequest { + unsafe fn from_swift_parameters(request: *const SwiftProblemReportRequest) -> Option<Self> { + if request.is_null() { + return None; + } + + let request = &*request; // Dereference the pointer + + let address_slice = slice::from_raw_parts(request.address, request.address_len); + let message_slice = slice::from_raw_parts(request.message, request.message_len); + let log_slice = slice::from_raw_parts(request.log, request.log_len); + + let address = String::from_utf8(address_slice.to_vec()).ok()?; + let message = String::from_utf8(message_slice.to_vec()).ok()?; + let log = log_slice.to_vec(); + + Some(Self { address, message, log }) + } +}
\ No newline at end of file |
