/* * * Copyright 2016 gRPC authors. * * 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. * */ #import "GRPCConnectivityMonitor.h" #include NSString *kGRPCConnectivityNotification = @"kGRPCConnectivityNotification"; static SCNetworkReachabilityRef reachability; static GRPCConnectivityStatus currentStatus; // Aggregate information in flags into network status. GRPCConnectivityStatus CalculateConnectivityStatus(SCNetworkReachabilityFlags flags) { GRPCConnectivityStatus result = GRPCConnectivityUnknown; if (((flags & kSCNetworkReachabilityFlagsReachable) == 0) || ((flags & kSCNetworkReachabilityFlagsConnectionRequired) != 0)) { return GRPCConnectivityNoNetwork; } result = GRPCConnectivityWiFi; #if TARGET_OS_IPHONE if (flags & kSCNetworkReachabilityFlagsIsWWAN) { return result = GRPCConnectivityCellular; } #endif return result; } static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info) { GRPCConnectivityStatus newStatus = CalculateConnectivityStatus(flags); if (newStatus != currentStatus) { [[NSNotificationCenter defaultCenter] postNotificationName:kGRPCConnectivityNotification object:nil]; currentStatus = newStatus; } } @implementation GRPCConnectivityMonitor + (void)initialize { if (self == [GRPCConnectivityMonitor self]) { struct sockaddr_in addr = {0}; addr.sin_len = sizeof(addr); addr.sin_family = AF_INET; reachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&addr); currentStatus = GRPCConnectivityUnknown; SCNetworkConnectionFlags flags; if (SCNetworkReachabilityGetFlags(reachability, &flags)) { currentStatus = CalculateConnectivityStatus(flags); } SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL}; if (!SCNetworkReachabilitySetCallback(reachability, ReachabilityCallback, &context) || !SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetMain(), kCFRunLoopCommonModes)) { NSLog(@"gRPC connectivity monitor fail to set"); } } } + (void)registerObserver:(id)observer selector:(SEL)selector { [[NSNotificationCenter defaultCenter] addObserver:observer selector:selector name:kGRPCConnectivityNotification object:nil]; } + (void)unregisterObserver:(id)observer { [[NSNotificationCenter defaultCenter] removeObserver:observer]; } @end