UNPKG

3.6 kBPlain TextView Raw
1/**
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8#import "RNCConnectionStateWatcher.h"
9#import <SystemConfiguration/SystemConfiguration.h>
10#import <netinet/in.h>
11
12@interface RNCConnectionStateWatcher () <NSURLSessionDataDelegate>
13
14@property (nonatomic) SCNetworkReachabilityRef reachabilityRef;
15@property (nullable, weak, nonatomic) id<RNCConnectionStateWatcherDelegate> delegate;
16@property (nonatomic) SCNetworkReachabilityFlags lastFlags;
17@property (nonnull, strong, nonatomic) RNCConnectionState *state;
18
19@end
20
21@implementation RNCConnectionStateWatcher
22
23#pragma mark - Lifecycle
24
25- (instancetype)initWithDelegate:(id<RNCConnectionStateWatcherDelegate>)delegate
26{
27 self = [self init];
28 if (self) {
29 _delegate = delegate;
30 _state = [[RNCConnectionState alloc] init];
31 _reachabilityRef = [self createReachabilityRef];
32 }
33 return self;
34}
35
36- (void)dealloc
37{
38 self.delegate = nil;
39
40 if (self.reachabilityRef != nil) {
41 SCNetworkReachabilityUnscheduleFromRunLoop(self.reachabilityRef, CFRunLoopGetMain(), kCFRunLoopCommonModes);
42 CFRelease(self.reachabilityRef);
43 self.reachabilityRef = nil;
44 }
45}
46
47#pragma mark - Public methods
48
49- (RNCConnectionState *)currentState
50{
51 return self.state;
52}
53
54#pragma mark - Callback
55
56typedef void (^RNCConnectionStateUpdater)(SCNetworkReachabilityFlags);
57
58static void RNCReachabilityCallback(__unused SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info)
59{
60 RNCConnectionStateUpdater block = (__bridge id)info;
61 if (block != nil) {
62 block(flags);
63 }
64}
65
66static void RNCReachabilityContextRelease(const void *info)
67{
68 Block_release(info);
69}
70
71static const void *RNCReachabilityContextRetain(const void *info)
72{
73 return Block_copy(info);
74}
75
76- (void)update:(SCNetworkReachabilityFlags)flags
77{
78 self.lastFlags = flags;
79 self.state = [[RNCConnectionState alloc] initWithReachabilityFlags:flags];
80}
81
82#pragma mark - Setters
83
84- (void)setState:(RNCConnectionState *)state
85{
86 if (![state isEqualToConnectionState:_state]) {
87 _state = state;
88
89 [self updateDelegate];
90 }
91}
92
93#pragma mark - Utilities
94
95- (void)updateDelegate
96{
97 [self.delegate connectionStateWatcher:self didUpdateState:self.state];
98}
99
100- (SCNetworkReachabilityRef)createReachabilityRef
101{
102 struct sockaddr_in zeroAddress;
103 bzero(&zeroAddress, sizeof(zeroAddress));
104 zeroAddress.sin_len = sizeof(zeroAddress);
105 zeroAddress.sin_family = AF_INET;
106
107 SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *) &zeroAddress);
108
109 __weak typeof(self) weakSelf = self;
110 RNCConnectionStateUpdater callback = ^(SCNetworkReachabilityFlags flags) {
111 __strong __typeof(weakSelf) strongSelf = weakSelf;
112 if (strongSelf != nil) {
113 [strongSelf update:flags];
114 }
115 };
116
117 SCNetworkReachabilityContext context = {
118 0,
119 (__bridge void *)callback,
120 RNCReachabilityContextRetain,
121 RNCReachabilityContextRelease,
122 NULL
123 };
124 SCNetworkReachabilitySetCallback(reachability, RNCReachabilityCallback, &context);
125 SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
126
127 // Set the state the first time
128 SCNetworkReachabilityFlags flags;
129 SCNetworkReachabilityGetFlags(reachability, &flags);
130 [self update:flags];
131
132 return reachability;
133}
134
135@end