1/* 2 * 3 * Copyright 2016 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19#import "GRPCConnectivityMonitor.h" 20 21#include <netinet/in.h> 22 23NSString *kGRPCConnectivityNotification = @"kGRPCConnectivityNotification"; 24 25static SCNetworkReachabilityRef reachability; 26static GRPCConnectivityStatus currentStatus; 27 28// Aggregate information in flags into network status. 29GRPCConnectivityStatus CalculateConnectivityStatus(SCNetworkReachabilityFlags flags) { 30 GRPCConnectivityStatus result = GRPCConnectivityUnknown; 31 if (((flags & kSCNetworkReachabilityFlagsReachable) == 0) || 32 ((flags & kSCNetworkReachabilityFlagsConnectionRequired) != 0)) { 33 return GRPCConnectivityNoNetwork; 34 } 35 result = GRPCConnectivityWiFi; 36#if TARGET_OS_IPHONE 37 if (flags & kSCNetworkReachabilityFlagsIsWWAN) { 38 return result = GRPCConnectivityCellular; 39 } 40#endif 41 return result; 42} 43 44static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, 45 void *info) { 46 GRPCConnectivityStatus newStatus = CalculateConnectivityStatus(flags); 47 48 if (newStatus != currentStatus) { 49 [[NSNotificationCenter defaultCenter] postNotificationName:kGRPCConnectivityNotification 50 object:nil]; 51 currentStatus = newStatus; 52 } 53} 54 55@implementation GRPCConnectivityMonitor 56 57+ (void)initialize { 58 if (self == [GRPCConnectivityMonitor self]) { 59 struct sockaddr_in addr = {0}; 60 addr.sin_len = sizeof(addr); 61 addr.sin_family = AF_INET; 62 reachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&addr); 63 currentStatus = GRPCConnectivityUnknown; 64 65 SCNetworkConnectionFlags flags; 66 if (SCNetworkReachabilityGetFlags(reachability, &flags)) { 67 currentStatus = CalculateConnectivityStatus(flags); 68 } 69 70 SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL}; 71 if (!SCNetworkReachabilitySetCallback(reachability, ReachabilityCallback, &context) || 72 !SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetMain(), 73 kCFRunLoopCommonModes)) { 74 NSLog(@"gRPC connectivity monitor fail to set"); 75 } 76 } 77} 78 79+ (void)registerObserver:(_Nonnull id)observer selector:(SEL)selector { 80 [[NSNotificationCenter defaultCenter] addObserver:observer 81 selector:selector 82 name:kGRPCConnectivityNotification 83 object:nil]; 84} 85 86+ (void)unregisterObserver:(_Nonnull id)observer { 87 [[NSNotificationCenter defaultCenter] removeObserver:observer]; 88} 89 90@end 91