added reachability based ip_change_notifier_impl for iOS (#1902)

added reachability based ip_change_notifier_impl for iOS
This commit is contained in:
Alden Torres 2017-04-11 23:53:13 -04:00 committed by Arvid Norberg
parent 79d7ae3638
commit 81d669399b
4 changed files with 100 additions and 3 deletions

View File

@ -161,6 +161,7 @@ rule linking ( properties * )
}
if <target-os>darwin in $(properties)
|| <target-os>iphone in $(properties)
{
# for ip_notifier
result += <framework>CoreFoundation <framework>SystemConfiguration ;

View File

@ -153,6 +153,7 @@ POSSIBILITY OF SUCH DAMAGE.
# define TORRENT_USE_LOCALE 0
# endif
#include <AvailabilityMacros.h>
#include <TargetConditionals.h>
#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

View File

@ -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, "<not supported>", len);
std::strncat(out, "<not supported>", std::size_t(len));
}
#endif

View File

@ -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 <typename T> void CFRefRetain(T h) { CFRetain(h); }
template <typename T> 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<dispatch_queue_t, CFDispatchRetain, CFDispatchRelease>;
#if TORRENT_USE_SC_NETWORK_REACHABILITY
CFRef<SCNetworkReachabilityRef> 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<SCNetworkReachabilityRef> reach{SCNetworkReachabilityCreateWithAddress(nullptr
, reinterpret_cast<sockaddr const*>(&addr))};
if (!reach)
return CFRef<SCNetworkReachabilityRef>();
SCNetworkReachabilityContext context = {0, nullptr, nullptr, nullptr, nullptr};
context.info = context_info;
return SCNetworkReachabilitySetCallback(reach.get(), callback, &context)
? reach : CFRef<SCNetworkReachabilityRef>();
}
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<ip_change_notifier_impl*>(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<void(error_code const&)> 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<SCNetworkReachabilityRef> m_reach;
std::function<void(error_code const&)> m_cb = nullptr;
};
#else
// see https://developer.apple.com/library/content/technotes/tn1145/_index.html
CFRef<CFMutableArrayRef> create_keys_array()
{
CFRef<CFMutableArrayRef> 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<ip_change_notifier_impl*>(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<SCDynamicStoreRef> m_store;
std::function<void(error_code const&)> m_cb = nullptr;
};
#endif // TORRENT_USE_SC_NETWORK_REACHABILITY
#elif defined TORRENT_WINDOWS
// TODO: ip_change_notifier_win
#else