summaryrefslogtreecommitdiffhomepage
path: root/mullvad-ios/src/api_client/shadowsocks_loader.rs
blob: 2d63b179d350b37585fdc8123b85855849f1a859 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
use std::ffi::c_void;
use talpid_types::net::proxy::Shadowsocks;

unsafe extern "C" {
    /// Creates a `Shadowsocks` configuration.
    ///
    /// # SAFETY
    /// `rawBridgeProvider` **must** be provided by a call to `init_swift_shadowsocks_loader_wrapper`
    /// It is okay to persist it, and use it across multiple threads.
    pub fn swift_get_shadowsocks_bridges(rawBridgeProvider: *const c_void) -> *const c_void;
}

#[derive(Debug)]
#[repr(C)]
pub struct SwiftShadowsocksLoaderWrapper(SwiftShadowsocksLoaderWrapperContext);
impl SwiftShadowsocksLoaderWrapper {
    pub fn new(context: SwiftShadowsocksLoaderWrapperContext) -> SwiftShadowsocksLoaderWrapper {
        SwiftShadowsocksLoaderWrapper(context)
    }

    pub fn get_bridges(&self) -> Option<Shadowsocks> {
        self.context_ref().get_bridges()
    }

    fn context_ref(&self) -> &SwiftShadowsocksLoaderWrapperContext {
        &self.0
    }
}

// SAFETY: The context stored inside `SwiftShadowsocksLoaderWrapper` points to an object that is guaranteed to be thread safe
unsafe impl Sync for SwiftShadowsocksLoaderWrapper {}
// SAFETY: The context stored inside `SwiftShadowsocksLoaderWrapper` points to an object that is guaranteed to be Sendable
unsafe impl Send for SwiftShadowsocksLoaderWrapper {}

#[derive(Debug)]
#[repr(C)]
pub struct SwiftShadowsocksLoaderWrapperContext {
    // This pointer is a reference to a Swift object, and is only ever read by Rust.
    // It is used to call that Swift object across the FFI
    shadowsocks_loader: *const c_void,
}

// SAFETY: `shadowsocks_loader` inside the `SwiftShadowsocksLoaderWrapperContext ` points to an object that is guaranteed to be thread safe
unsafe impl Sync for SwiftShadowsocksLoaderWrapperContext {}
// SAFETY: `shadowsocks_loader` inside the `SwiftShadowsocksLoaderWrapperContext ` points to an object that is guaranteed to be Sendable
unsafe impl Send for SwiftShadowsocksLoaderWrapperContext {}

impl SwiftShadowsocksLoaderWrapperContext {
    pub fn get_bridges(&self) -> Option<Shadowsocks> {
        // SAFETY: See notice for `swift_get_shadowsocks_bridges`
        let raw_configuration = unsafe { swift_get_shadowsocks_bridges(self.shadowsocks_loader) };
        if raw_configuration.is_null() {
            return None;
        }
        // SAFETY: The pointer returned by `swift_get_shadowsocks_bridges` is guaranteed
        // to point to a valid `Shadowsocks` configuration, and has been null-checked
        let bridges: Shadowsocks = unsafe { *Box::from_raw(raw_configuration as *mut _) };
        Some(bridges)
    }
}

/// Called by the Swift side in order to provide an object to rust that can create
/// Shadowsocks configurations
///
/// # SAFETY
/// `shadowsocks_loader` **must be** pointing to a valid instance of a `SwiftShadowsocksBridgeProvider`
/// That instance's lifetime has to be equivalent to a `'static` lifetime in Rust
/// This function does not take ownership of `shadowsocks_loader`
#[unsafe(no_mangle)]
pub unsafe extern "C" fn init_swift_shadowsocks_loader_wrapper(
    shadowsocks_loader: *const c_void,
) -> SwiftShadowsocksLoaderWrapper {
    let context = SwiftShadowsocksLoaderWrapperContext { shadowsocks_loader };
    SwiftShadowsocksLoaderWrapper::new(context)
}