Skip to content

build(ios): error on iOS with libp2p 0.56 using quic feature and if-watch 3.2.1 #6161

@sando38

Description

@sando38

Hello,

I tried to build an application with the latest libp2p version 0.56 including quic features on iOS, however, I have the below compiler errors, which seem to be related to the issue #5628 and #5679. I see that if-watch v3.2.1 was used in the compilation.

Undefined symbols for architecture arm64:
  "_SCDynamicStoreCreateRunLoopSource", referenced from:
      system_configuration::dynamic_store::SCDynamicStore::create_run_loop_source::hc606d8191d1eee96 in libapp.a[1330](system_configuration-ef8f09e6c16c7e34.system_configuration.a183a244f0552131-cgu.0.rcgu.o)
  "_SCDynamicStoreCreateWithOptions", referenced from:
      system_configuration::dynamic_store::SCDynamicStore::create::h7b8d644247fa5cbe in libapp.a[1330](system_configuration-ef8f09e6c16c7e34.system_configuration.a183a244f0552131-cgu.0.rcgu.o)
  "_SCDynamicStoreSetNotificationKeys", referenced from:
      std::sys::backtrace::__rust_begin_short_backtrace::h50d2f1a25ee701a8 in libapp.a[1329](if_watch-7a230dd48f870c3b.if_watch.56977769d1be1092-cgu.0.rcgu.o)
  "_kSCDynamicStoreUseSessionKeys", referenced from:
      system_configuration::dynamic_store::SCDynamicStoreBuilder$LT$T$GT$::create_store_options::h88a4075b4fa8049f in libapp.a[1329](if_watch-7a230dd48f870c3b.if_watch.56977769d1be1092-cgu.0.rcgu.o)

I am not experienced with iOS internals, but from the errors above I suspect that i.e. SCDynamicStore does not exist in the iOS world.

I checked with Claude LLM the apple.rs module in if-watch and it suggested to patch it this way (if it makes sense), practically using the fallback polling on iOS which is also described in the if-watch README.md file.

--- a/src/apple.rs
+++ b/src/apple.rs
@@ -1,11 +1,17 @@
 use crate::{IfEvent, IpNet, Ipv4Net, Ipv6Net};
+#[cfg(target_os = "macos")]
 use core_foundation::array::CFArray;
+#[cfg(target_os = "macos")]
 use core_foundation::runloop::{kCFRunLoopCommonModes, CFRunLoop};
+#[cfg(target_os = "macos")]
 use core_foundation::string::CFString;
 use fnv::FnvHashSet;
 use futures::channel::mpsc;
 use futures::stream::{FusedStream, Stream};
 use if_addrs::IfAddr;
 use std::collections::VecDeque;
 use std::io::Result;
 use std::pin::Pin;
 use std::task::{Context, Poll};
+#[cfg(target_os = "macos")]
 use system_configuration::dynamic_store::{
     SCDynamicStore, SCDynamicStoreBuilder, SCDynamicStoreCallBackContext,
 };
@@ -40,7 +46,12 @@ pub struct IfWatcher {
 impl IfWatcher {
     pub fn new() -> Result<Self> {
         let (tx, rx) = mpsc::channel(1);
-        std::thread::spawn(|| background_task(tx));
+        
+        #[cfg(target_os = "macos")]
+        std::thread::spawn(move || background_task_macos(tx));
+        
+        #[cfg(not(target_os = "macos"))]
+        std::thread::spawn(move || background_task_ios(tx));
+        
         let mut watcher = Self {
             addrs: Default::default(),
             queue: Default::default(),
@@ -119,6 +130,7 @@ fn ifaddr_to_ipnet(addr: IfAddr) -> IpNet {
     }
 }
 
+#[cfg(target_os = "macos")]
 fn callback(_store: SCDynamicStore, _changed_keys: CFArray<CFString>, info: &mut mpsc::Sender<()>) {
     match info.try_send(()) {
         Err(err) if err.is_disconnected() => CFRunLoop::get_current().stop(),
@@ -126,7 +138,8 @@ fn callback(_store: SCDynamicStore, _changed_keys: CFArray<CFString>, info: &mu
     }
 }
 
-fn background_task(tx: mpsc::Sender<()>) {
+#[cfg(target_os = "macos")]
+fn background_task_macos(tx: mpsc::Sender<()>) {
     let store = SCDynamicStoreBuilder::new("global-network-watcher")
         .callback_context(SCDynamicStoreCallBackContext {
             callout: callback,
@@ -140,4 +153,24 @@ fn background_task(tx: mpsc::Sender<()>) {
     let source = store.create_run_loop_source();
     let run_loop = CFRunLoop::get_current();
     run_loop.add_source(&source, unsafe { kCFRunLoopCommonModes });
     CFRunLoop::run_current();
-}
\ No newline at end of file
+}
+
+#[cfg(not(target_os = "macos"))]
+fn background_task_ios(mut tx: mpsc::Sender<()>) {
+    // On iOS, tvOS, and watchOS, we use a polling approach
+    // Poll every 2 seconds for network interface changes
+    loop {
+        std::thread::sleep(std::time::Duration::from_secs(2));
+        
+        // Send a notification to trigger a resync
+        match tx.try_send(()) {
+            Ok(_) => {},
+            Err(err) => {
+                if err.is_disconnected() {
+                    // Receiver has been dropped, exit the thread
+                    break;
+                }
+                // If the channel is full, skip this notification
+            }
+        }
+    }
+}

Any feedback appreciated! Thanks

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions