UNPKG

7.57 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 "RNCNetInfo.h"
9#import "RNCConnectionStateWatcher.h"
10
11#include <ifaddrs.h>
12#include <arpa/inet.h>
13
14#if !TARGET_OS_TV
15#import <CoreTelephony/CTCarrier.h>
16#import <CoreTelephony/CTTelephonyNetworkInfo.h>
17#endif
18@import SystemConfiguration.CaptiveNetwork;
19
20#import <React/RCTAssert.h>
21#import <React/RCTBridge.h>
22#import <React/RCTEventDispatcher.h>
23
24@interface RNCNetInfo () <RNCConnectionStateWatcherDelegate>
25
26@property (nonatomic, strong) RNCConnectionStateWatcher *connectionStateWatcher;
27@property (nonatomic) BOOL isObserving;
28
29@end
30
31@implementation RNCNetInfo
32
33#pragma mark - Module setup
34
35RCT_EXPORT_MODULE()
36
37// We need RNCReachabilityCallback's and module methods to be called on the same thread so that we can have
38// guarantees about when we mess with the reachability callbacks.
39- (dispatch_queue_t)methodQueue
40{
41 return dispatch_get_main_queue();
42}
43
44+ (BOOL)requiresMainQueueSetup
45{
46 return YES;
47}
48
49#pragma mark - Lifecycle
50
51- (NSArray *)supportedEvents
52{
53 return @[@"netInfo.networkStatusDidChange"];
54}
55
56- (void)startObserving
57{
58 self.isObserving = YES;
59}
60
61- (void)stopObserving
62{
63 self.isObserving = NO;
64}
65
66- (instancetype)init
67{
68 self = [super init];
69 if (self) {
70 _connectionStateWatcher = [[RNCConnectionStateWatcher alloc] initWithDelegate:self];
71 }
72 return self;
73}
74
75- (void)dealloc
76{
77 self.connectionStateWatcher = nil;
78}
79
80#pragma mark - RNCConnectionStateWatcherDelegate
81
82- (void)connectionStateWatcher:(RNCConnectionStateWatcher *)connectionStateWatcher didUpdateState:(RNCConnectionState *)state
83{
84 if (self.isObserving) {
85 NSDictionary *dictionary = [self currentDictionaryFromUpdateState:state withInterface:NULL];
86 [self sendEventWithName:@"netInfo.networkStatusDidChange" body:dictionary];
87 }
88}
89
90#pragma mark - Public API
91
92RCT_EXPORT_METHOD(getCurrentState:(nullable NSString *)requestedInterface resolve:(RCTPromiseResolveBlock)resolve
93 reject:(__unused RCTPromiseRejectBlock)reject)
94{
95 RNCConnectionState *state = [self.connectionStateWatcher currentState];
96 resolve([self currentDictionaryFromUpdateState:state withInterface:requestedInterface]);
97}
98
99#pragma mark - Utilities
100
101// Converts the state into a dictionary to send over the bridge
102- (NSDictionary *)currentDictionaryFromUpdateState:(RNCConnectionState *)state withInterface:(nullable NSString *)requestedInterface
103{
104 NSString *selectedInterface = requestedInterface ?: state.type;
105 NSMutableDictionary *details = [self detailsFromInterface:selectedInterface withState:state];
106 bool connected = [state.type isEqualToString:selectedInterface] && state.connected;
107 if (connected) {
108 details[@"isConnectionExpensive"] = @(state.expensive);
109 }
110
111 return @{
112 @"type": selectedInterface,
113 @"isConnected": @(connected),
114 @"details": details ?: NSNull.null
115 };
116}
117
118- (NSMutableDictionary *)detailsFromInterface:(nonnull NSString *)requestedInterface withState:(RNCConnectionState *)state
119{
120 NSMutableDictionary *details = [NSMutableDictionary new];
121 if ([requestedInterface isEqualToString: RNCConnectionTypeCellular]) {
122 details[@"cellularGeneration"] = state.cellularGeneration ?: NSNull.null;
123 details[@"carrier"] = [self carrier] ?: NSNull.null;
124 } else if ([requestedInterface isEqualToString: RNCConnectionTypeWifi] || [requestedInterface isEqualToString: RNCConnectionTypeEthernet]) {
125 details[@"ipAddress"] = [self ipAddress] ?: NSNull.null;
126 details[@"subnet"] = [self subnet] ?: NSNull.null;
127 #if !TARGET_OS_TV && !TARGET_OS_OSX
128 details[@"ssid"] = [self ssid] ?: NSNull.null;
129 details[@"bssid"] = [self bssid] ?: NSNull.null;
130 #endif
131 }
132 return details;
133}
134
135- (NSString *)carrier
136{
137#if (TARGET_OS_TV || TARGET_OS_OSX)
138 return nil;
139#else
140 CTTelephonyNetworkInfo *netinfo = [[CTTelephonyNetworkInfo alloc] init];
141 CTCarrier *carrier = [netinfo subscriberCellularProvider];
142 return carrier.carrierName;
143#endif
144}
145
146- (NSString *)ipAddress
147{
148 NSString *address = @"0.0.0.0";
149 struct ifaddrs *interfaces = NULL;
150 struct ifaddrs *temp_addr = NULL;
151 int success = 0;
152 // retrieve the current interfaces - returns 0 on success
153 success = getifaddrs(&interfaces);
154 if (success == 0) {
155 // Loop through linked list of interfaces
156 temp_addr = interfaces;
157 while (temp_addr != NULL) {
158 if (temp_addr->ifa_addr->sa_family == AF_INET) {
159 NSString* ifname = [NSString stringWithUTF8String:temp_addr->ifa_name];
160 if (
161 // Check if interface is en0 which is the wifi connection on the iPhone
162 // and the ethernet connection on the Apple TV
163 [ifname isEqualToString:@"en0"] ||
164 // Check if interface is en1 which is the wifi connection on the Apple TV
165 [ifname isEqualToString:@"en1"]
166 ) {
167 // Get NSString from C String
168 char str[INET_ADDRSTRLEN];
169 inet_ntop(AF_INET, &((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr, str, INET_ADDRSTRLEN);
170 address = [NSString stringWithUTF8String:str];
171 }
172 }
173
174 temp_addr = temp_addr->ifa_next;
175 }
176 }
177 // Free memory
178 freeifaddrs(interfaces);
179 return address;
180}
181
182- (NSString *)subnet
183{
184 NSString *subnet = @"0.0.0.0";
185 struct ifaddrs *interfaces = NULL;
186 struct ifaddrs *temp_addr = NULL;
187 int success = 0;
188 // retrieve the current interfaces - returns 0 on success
189 success = getifaddrs(&interfaces);
190 if (success == 0) {
191 // Loop through linked list of interfaces
192 temp_addr = interfaces;
193 while (temp_addr != NULL) {
194 if (temp_addr->ifa_addr->sa_family == AF_INET) {
195 NSString* ifname = [NSString stringWithUTF8String:temp_addr->ifa_name];
196 if (
197 // Check if interface is en0 which is the wifi connection on the iPhone
198 // and the ethernet connection on the Apple TV
199 [ifname isEqualToString:@"en0"] ||
200 // Check if interface is en1 which is the wifi connection on the Apple TV
201 [ifname isEqualToString:@"en1"]
202 ) {
203 // Get NSString from C String
204 char str[INET_ADDRSTRLEN];
205 inet_ntop(AF_INET, &((struct sockaddr_in *)temp_addr->ifa_netmask)->sin_addr, str, INET_ADDRSTRLEN);
206 subnet = [NSString stringWithUTF8String:str];
207 }
208 }
209
210 temp_addr = temp_addr->ifa_next;
211 }
212 }
213 // Free memory
214 freeifaddrs(interfaces);
215 return subnet;
216}
217
218#if !TARGET_OS_TV && !TARGET_OS_OSX
219- (NSString *)ssid
220{
221 NSArray *interfaceNames = CFBridgingRelease(CNCopySupportedInterfaces());
222 NSDictionary *SSIDInfo;
223 NSString *SSID = NULL;
224 for (NSString *interfaceName in interfaceNames) {
225 SSIDInfo = CFBridgingRelease(CNCopyCurrentNetworkInfo((__bridge CFStringRef)interfaceName));
226 if (SSIDInfo.count > 0) {
227 SSID = SSIDInfo[@"SSID"];
228 if ([SSID isEqualToString:@"Wi-Fi"] || [SSID isEqualToString:@"WLAN"]){
229 SSID = NULL;
230 }
231 break;
232 }
233 }
234 return SSID;
235}
236
237- (NSString *)bssid
238{
239 NSArray *interfaceNames = CFBridgingRelease(CNCopySupportedInterfaces());
240 NSDictionary *networkDetails;
241 NSString *BSSID = NULL;
242 for (NSString *interfaceName in interfaceNames) {
243 networkDetails = CFBridgingRelease(CNCopyCurrentNetworkInfo((__bridge CFStringRef)interfaceName));
244 if (networkDetails.count > 0)
245 {
246 BSSID = networkDetails[(NSString *) kCNNetworkInfoKeyBSSID];
247 break;
248 }
249 }
250 return BSSID;
251}
252#endif
253
254@end