diff --git a/Jamfile b/Jamfile index 6639afc2b..917f10254 100644 --- a/Jamfile +++ b/Jamfile @@ -161,6 +161,7 @@ rule linking ( properties * ) } if darwin in $(properties) + || iphone in $(properties) { # for ip_notifier result += CoreFoundation SystemConfiguration ; diff --git a/include/libtorrent/config.hpp b/include/libtorrent/config.hpp index 5b16cbaec..9625d5049 100644 --- a/include/libtorrent/config.hpp +++ b/include/libtorrent/config.hpp @@ -153,6 +153,7 @@ POSSIBILITY OF SUCH DAMAGE. # define TORRENT_USE_LOCALE 0 # endif #include +#include #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 // on OSX, use the built-in common crypto for built-in @@ -168,6 +169,10 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_USE_SYSTEMCONFIGURATION 1 +#if TARGET_OS_IPHONE +#define TORRENT_USE_SC_NETWORK_REACHABILITY 1 +#endif + #else // __APPLE__ // FreeBSD has a reasonable iconv signature // unless we're on glibc @@ -442,6 +447,10 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_USE_SYSTEMCONFIGURATION 0 #endif +#ifndef TORRENT_USE_SC_NETWORK_REACHABILITY +#define TORRENT_USE_SC_NETWORK_REACHABILITY 0 +#endif + #ifndef TORRENT_USE_CRYPTOAPI #define TORRENT_USE_CRYPTOAPI 0 #endif diff --git a/src/assert.cpp b/src/assert.cpp index e4b114922..1f8f98ee8 100644 --- a/src/assert.cpp +++ b/src/assert.cpp @@ -262,7 +262,7 @@ TORRENT_EXPORT void print_backtrace(char* out, int len, int max_depth TORRENT_EXPORT void print_backtrace(char* out, int len, int /*max_depth*/, void* /* ctx */) { out[0] = 0; - strncat(out, "", len); + std::strncat(out, "", std::size_t(len)); } #endif diff --git a/src/ip_notifier.cpp b/src/ip_notifier.cpp index 904f41d14..d741cdea8 100644 --- a/src/ip_notifier.cpp +++ b/src/ip_notifier.cpp @@ -59,7 +59,6 @@ namespace #elif TORRENT_USE_NETLINK // TODO: ip_change_notifier_nl #elif TORRENT_USE_SYSTEMCONFIGURATION -// see https://developer.apple.com/library/content/technotes/tn1145/_index.html template void CFRefRetain(T h) { CFRetain(h); } template void CFRefRelease(T h) { CFRelease(h); } @@ -99,6 +98,86 @@ void CFDispatchRetain(dispatch_queue_t q) { dispatch_retain(q); } void CFDispatchRelease(dispatch_queue_t q) { dispatch_release(q); } using CFDispatchRef = CFRef; +#if TORRENT_USE_SC_NETWORK_REACHABILITY +CFRef create_reachability(SCNetworkReachabilityCallBack callback + , void* context_info) +{ + TORRENT_ASSERT(callback != nullptr); + + sockaddr_in addr = {}; + addr.sin_len = sizeof(addr); + addr.sin_family = AF_INET; + + CFRef reach{SCNetworkReachabilityCreateWithAddress(nullptr + , reinterpret_cast(&addr))}; + if (!reach) + return CFRef(); + + SCNetworkReachabilityContext context = {0, nullptr, nullptr, nullptr, nullptr}; + context.info = context_info; + + return SCNetworkReachabilitySetCallback(reach.get(), callback, &context) + ? reach : CFRef(); +} + +struct ip_change_notifier_impl final : ip_change_notifier +{ + explicit ip_change_notifier_impl(io_service& ios) + : m_ios(ios) + { + m_queue = dispatch_queue_create("libtorrent.IPChangeNotifierQueue", nullptr); + m_reach = create_reachability( + [](SCNetworkReachabilityRef /*target*/, SCNetworkReachabilityFlags /*flags*/, void *info) + { + auto obj = static_cast(info); + obj->m_ios.post([obj]() + { + if (!obj->m_cb) return; + auto cb = std::move(obj->m_cb); + obj->m_cb = nullptr; + cb(error_code()); + }); + }, this); + + if (!m_queue || !m_reach + || !SCNetworkReachabilitySetDispatchQueue(m_reach.get(), m_queue.get())) + cancel(); + } + + // noncopyable + ip_change_notifier_impl(ip_change_notifier_impl const&) = delete; + ip_change_notifier_impl& operator=(ip_change_notifier_impl const&) = delete; + + ~ip_change_notifier_impl() override + { cancel(); } + + void async_wait(std::function cb) override + { + if (m_queue) + m_cb = std::move(cb); + else + m_ios.post([cb]() + { cb(make_error_code(boost::system::errc::not_supported)); }); + } + + void cancel() override + { + if (m_reach) + SCNetworkReachabilitySetDispatchQueue(m_reach.get(), nullptr); + + m_cb = nullptr; + m_reach = nullptr; + m_queue = nullptr; + } + +private: + io_service& m_ios; + CFDispatchRef m_queue; + CFRef m_reach; + std::function m_cb = nullptr; +}; +#else +// see https://developer.apple.com/library/content/technotes/tn1145/_index.html CFRef create_keys_array() { CFRef keys{CFArrayCreateMutable(nullptr @@ -143,7 +222,13 @@ struct ip_change_notifier_impl final : ip_change_notifier [](SCDynamicStoreRef /*store*/, CFArrayRef /*changedKeys*/, void *info) { auto obj = static_cast(info); - obj->m_ios.post([obj]() { if (obj->m_cb) obj->m_cb(error_code()); }); + obj->m_ios.post([obj]() + { + if (!obj->m_cb) return; + auto cb = std::move(obj->m_cb); + obj->m_cb = nullptr; + cb(error_code()); + }); }, this); if (!m_queue || !m_store @@ -183,6 +268,8 @@ private: CFRef m_store; std::function m_cb = nullptr; }; +#endif // TORRENT_USE_SC_NETWORK_REACHABILITY + #elif defined TORRENT_WINDOWS // TODO: ip_change_notifier_win #else