• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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