implemented ip_change_notifier_macos (#1891)

implemented ip_change_notifier_macos
This commit is contained in:
Alden Torres 2017-04-07 17:53:12 -04:00 committed by Arvid Norberg
parent 51c42adc3e
commit e4bdd14ae7
7 changed files with 239 additions and 2 deletions

View File

@ -300,6 +300,11 @@ if (WIN32)
endif()
endif()
if(APPLE)
# for ip_notifier
target_link_libraries(torrent-rasterbar "-framework CoreFoundation" "-framework SystemConfiguration")
endif (APPLE)
if (encryption)
target_link_libraries(torrent-rasterbar ${OPENSSL_LIBRARIES})
endif()

View File

@ -160,6 +160,12 @@ rule linking ( properties * )
result += <library>libsocket <library>libnsl ;
}
if <target-os>darwin in $(properties)
{
# for ip_notifier
result += <framework>CoreFoundation <framework>SystemConfiguration ;
}
if <iconv>on in $(properties)
{
result += <library>libiconv ;

View File

@ -166,6 +166,8 @@ POSSIBILITY OF SUCH DAMAGE.
#define TORRENT_USE_EXECINFO 1
#endif
#define TORRENT_USE_SYSTEMCONFIGURATION 1
#else // __APPLE__
// FreeBSD has a reasonable iconv signature
// unless we're on glibc
@ -436,6 +438,10 @@ POSSIBILITY OF SUCH DAMAGE.
#define TORRENT_USE_COMMONCRYPTO 0
#endif
#ifndef TORRENT_USE_SYSTEMCONFIGURATION
#define TORRENT_USE_SYSTEMCONFIGURATION 0
#endif
#ifndef TORRENT_USE_CRYPTOAPI
#define TORRENT_USE_CRYPTOAPI 0
#endif

View File

@ -31,12 +31,15 @@ POSSIBILITY OF SUCH DAMAGE.
*/
#include "libtorrent/aux_/ip_notifier.hpp"
#include "libtorrent/assert.hpp"
#if defined TORRENT_BUILD_SIMULATOR
// TODO: simulator support
#elif TORRENT_USE_NETLINK
#include "libtorrent/netlink.hpp"
#include <array>
#elif TORRENT_USE_SYSTEMCONFIGURATION
#include <SystemConfiguration/SystemConfiguration.h>
#elif defined TORRENT_WINDOWS
#include "libtorrent/aux_/throw.hpp"
#include "libtorrent/aux_/disable_warnings_push.hpp"
@ -55,11 +58,139 @@ namespace
// TODO: ip_change_notifier_sim
#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); }
template <typename T
, void (*Retain)(T) = CFRefRetain<T>, void (*Release)(T) = CFRefRelease<T>>
struct CFRef
{
CFRef() {}
explicit CFRef(T h) : m_h(h) {} // take ownership
~CFRef() { release(); }
CFRef(CFRef const& rhs) : m_h(rhs.m_h) { retain(); }
CFRef& operator=(CFRef const& rhs)
{
if (m_h == rhs.m_h) return *this;
release();
m_h = rhs.m_h;
retain();
return *this;
}
CFRef& operator=(T h) { m_h = h; return *this;}
CFRef& operator=(std::nullptr_t) { release(); return *this;}
T get() const { return m_h; }
explicit operator bool() const { return m_h != nullptr; }
private:
T m_h = nullptr; // handle
void retain() { if (m_h != nullptr) Retain(m_h); }
void release() { if (m_h != nullptr) Release(m_h); m_h = nullptr; }
};
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>;
CFRef<CFMutableArrayRef> create_keys_array()
{
CFRef<CFMutableArrayRef> keys{CFArrayCreateMutable(nullptr
, 0, &kCFTypeArrayCallBacks)};
// "State:/Network/Interface/[^/]+/IPv4"
CFRef<CFStringRef> key{SCDynamicStoreKeyCreateNetworkInterfaceEntity(nullptr
, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4)};
CFArrayAppendValue(keys.get(), key.get());
// NOTE: for IPv6, you can replicate the above setup with kSCEntNetIPv6
// but due to the current state of most common configurations, where
// IPv4 is used alongside with IPv6, you will end up with twice the
// notifications for the same change
return keys;
}
CFRef<SCDynamicStoreRef> create_dynamic_store(SCDynamicStoreCallBack callback, void* context_info)
{
TORRENT_ASSERT(callback != nullptr);
SCDynamicStoreContext context = {0, nullptr, nullptr, nullptr, nullptr};
context.info = context_info;
CFRef<SCDynamicStoreRef> store{SCDynamicStoreCreate(nullptr
, CFSTR("libtorrent.IPChangeNotifierStore"), callback, &context)};
if (!store)
return CFRef<SCDynamicStoreRef>();
CFRef<CFMutableArrayRef> keys = create_keys_array();
return SCDynamicStoreSetNotificationKeys(store.get(), nullptr, keys.get())
? store : CFRef<SCDynamicStoreRef>();
}
struct ip_change_notifier_macos final : ip_change_notifier
{
explicit ip_change_notifier_macos(io_service& ios)
: m_ios(ios)
{
m_queue = dispatch_queue_create("libtorrent.IPChangeNotifierQueue", nullptr);
m_store = create_dynamic_store(
[](SCDynamicStoreRef /*store*/, CFArrayRef /*changedKeys*/, void *info)
{
auto obj = static_cast<ip_change_notifier_macos*>(info);
obj->m_ios.post([obj]() { if (obj->m_cb) obj->m_cb(error_code()); });
}, this);
if (!m_queue || !m_store
|| !SCDynamicStoreSetDispatchQueue(m_store.get(), m_queue.get()))
cancel();
}
// noncopyable
ip_change_notifier_macos(ip_change_notifier_macos const&) = delete;
ip_change_notifier_macos& operator=(ip_change_notifier_macos const&) = delete;
~ip_change_notifier_macos() 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_store)
SCDynamicStoreSetDispatchQueue(m_store.get(), nullptr);
m_cb = nullptr;
m_store = nullptr;
m_queue = nullptr;
}
private:
io_service& m_ios;
CFDispatchRef m_queue;
CFRef<SCDynamicStoreRef> m_store;
std::function<void(error_code const&)> m_cb = nullptr;
};
#elif defined TORRENT_WINDOWS
// TODO: ip_change_notifier_win
#else
// TODO: ip_change_notifier_default
#endif
// TODO: to remove when separated per platform
#if defined TORRENT_BUILD_SIMULATOR || TORRENT_USE_NETLINK || defined TORRENT_WINDOWS
struct ip_change_notifier_impl final : ip_change_notifier
{
explicit ip_change_notifier_impl(io_service& ios);
@ -170,11 +301,28 @@ namespace
else
cb(ec);
}
#endif // defined TORRENT_BUILD_SIMULATOR || TORRENT_USE_NETLINK || defined TORRENT_WINDOWS
} // anonymous namespace
std::unique_ptr<ip_change_notifier> create_ip_notifier(io_service& ios)
{
return std::unique_ptr<ip_change_notifier>(new ip_change_notifier_impl(ios));
return std::unique_ptr<ip_change_notifier>(
#if defined TORRENT_BUILD_SIMULATOR
// ip_change_notifier_sim
new ip_change_notifier_impl(ios)
#elif TORRENT_USE_NETLINK
// ip_change_notifier_nl
new ip_change_notifier_impl(ios)
#elif TORRENT_USE_SYSTEMCONFIGURATION
new ip_change_notifier_macos(ios)
#elif defined TORRENT_WINDOWS
// ip_change_notifier_win
new ip_change_notifier_impl(ios)
#else
// ip_change_notifier_default
new ip_change_notifier_impl(ios)
#endif
);
}
}}

View File

@ -38,4 +38,5 @@ project tools
exe fuzz_torrent : fuzz_torrent.cpp ;
exe parse_access_log : parse_access_log.cpp ;
exe dht : dht_put.cpp : <include>../ed25519/src ;
exe session_log_alerts : session_log_alerts.cpp ;

View File

@ -1,5 +1,6 @@
tool_programs = \
fuzz_torrent
fuzz_torrent \
session_log_alerts
if ENABLE_EXAMPLES
bin_PROGRAMS = $(tool_programs)
@ -20,6 +21,7 @@ EXTRA_DIST = Jamfile \
parse_utp_log.py
fuzz_torrent_SOURCES = fuzz_torrent.cpp
session_log_alerts_SOURCES = session_log_alerts.cpp
LDADD = $(top_builddir)/src/libtorrent-rasterbar.la

View File

@ -0,0 +1,69 @@
/*
Copyright (c) 2017, Arvid Norberg, Alden Torres
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "libtorrent/session.hpp"
#include "libtorrent/alert_types.hpp"
#include <cstdio>
#include <cinttypes>
#include <cstdlib>
using namespace libtorrent;
int main(int argc, char* argv[])
{
std::printf("press Ctrl+C, kill the process or wait for 1000 alerts\n");
settings_pack sett;
sett.set_int(settings_pack::alert_mask, 0xffffffff);
session s(sett);
int count = 0;
while (count <= 1000)
{
s.wait_for_alert(seconds(5));
std::vector<alert*> alerts;
s.pop_alerts(&alerts);
for (auto const a : alerts)
{
if (a->type() == log_alert::alert_type)
{
std::printf("log_alert - %s\n", a->message().c_str());
count++;
}
}
}
std::printf("\n");
return 0;
}