X-Git-Url: https://git.mdrn.pl/wl-app.git/blobdiff_plain/53b27422d140022594fc241cca91c3183be57bca..48b2fe9f7c2dc3d9aeaaa6dbfb27c7da4f3235ff:/iOS/Pods/Realm/Realm/ObjectStore/src/sync/impl/apple/network_reachability_observer.cpp diff --git a/iOS/Pods/Realm/Realm/ObjectStore/src/sync/impl/apple/network_reachability_observer.cpp b/iOS/Pods/Realm/Realm/ObjectStore/src/sync/impl/apple/network_reachability_observer.cpp new file mode 100644 index 0000000..ad040a4 --- /dev/null +++ b/iOS/Pods/Realm/Realm/ObjectStore/src/sync/impl/apple/network_reachability_observer.cpp @@ -0,0 +1,127 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2016 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +#include "sync/impl/apple/network_reachability_observer.hpp" + +#if NETWORK_REACHABILITY_AVAILABLE + +using namespace realm; +using namespace realm::_impl; + +namespace { + +NetworkReachabilityStatus reachability_status_for_flags(SCNetworkReachabilityFlags flags) +{ + if (!(flags & kSCNetworkReachabilityFlagsReachable)) + return NotReachable; + + if (flags & kSCNetworkReachabilityFlagsConnectionRequired) { + if (!(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) || + (flags & kSCNetworkReachabilityFlagsInterventionRequired)) + return NotReachable; + } + + NetworkReachabilityStatus status = ReachableViaWiFi; + +#if TARGET_OS_IPHONE + if (flags & kSCNetworkReachabilityFlagsIsWWAN) + status = ReachableViaWWAN; +#endif + + return status; +} + +} // (anonymous namespace) + +NetworkReachabilityObserver::NetworkReachabilityObserver(util::Optional hostname, + std::function handler) +: m_callback_queue(dispatch_queue_create("io.realm.sync.reachability", DISPATCH_QUEUE_SERIAL)) +, m_change_handler(std::move(handler)) +{ + if (hostname) { + m_reachability_ref = util::adoptCF(SystemConfiguration::shared().network_reachability_create_with_name(nullptr, + hostname->c_str())); + } else { + struct sockaddr zeroAddress = {}; + zeroAddress.sa_len = sizeof(zeroAddress); + zeroAddress.sa_family = AF_INET; + + m_reachability_ref = util::adoptCF(SystemConfiguration::shared().network_reachability_create_with_address(nullptr, + &zeroAddress)); + } +} + +NetworkReachabilityObserver::~NetworkReachabilityObserver() +{ + stop_observing(); + dispatch_release(m_callback_queue); +} + +NetworkReachabilityStatus NetworkReachabilityObserver::reachability_status() const +{ + SCNetworkReachabilityFlags flags; + + if (SystemConfiguration::shared().network_reachability_get_flags(m_reachability_ref.get(), &flags)) + return reachability_status_for_flags(flags); + + return NotReachable; +} + +bool NetworkReachabilityObserver::start_observing() +{ + m_previous_status = reachability_status(); + + auto callback = [](SCNetworkReachabilityRef, SCNetworkReachabilityFlags, void* self) { + static_cast(self)->reachability_changed(); + }; + + SCNetworkReachabilityContext context = {0, this, nullptr, nullptr, nullptr}; + + if (!SystemConfiguration::shared().network_reachability_set_callback(m_reachability_ref.get(), callback, &context)) + return false; + + if (!SystemConfiguration::shared().network_reachability_set_dispatch_queue(m_reachability_ref.get(), m_callback_queue)) + return false; + + return true; +} + +void NetworkReachabilityObserver::stop_observing() +{ + SystemConfiguration::shared().network_reachability_set_dispatch_queue(m_reachability_ref.get(), nullptr); + SystemConfiguration::shared().network_reachability_set_callback(m_reachability_ref.get(), nullptr, nullptr); + + // Wait for all previously-enqueued blocks to execute to guarantee that + // no callback will be called after returning from this method + dispatch_sync(m_callback_queue, ^{}); +} + +void NetworkReachabilityObserver::reachability_changed() +{ + auto current_status = reachability_status(); + + // When observing reachability of the specific host the callback might be called + // several times (because of DNS queries) with the same reachability flags while + // the caller should be notified only when the reachability status is really changed. + if (current_status != m_previous_status) { + m_change_handler(current_status); + m_previous_status = current_status; + } +} + +#endif