diff --git a/tests/unittests/obj-c/ODWReachabilityTests.mm b/tests/unittests/obj-c/ODWReachabilityTests.mm new file mode 100644 index 000000000..501a3be7a --- /dev/null +++ b/tests/unittests/obj-c/ODWReachabilityTests.mm @@ -0,0 +1,113 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 +// +// ODWReachabilityTests.mm +// Tests +// +// Created by Abu Sayem on 13/12/2024. +// + +#import +#import "ODWReachability.h" + +#import +#import +#import +#import +#import +#import +#import + +@interface ODWReachabilityTests : XCTestCase +@end + +@implementation ODWReachabilityTests + +- (void)testReachabilityWithHostname +{ + NSString *hostname = @"www.microsoft.com"; + ODWReachability *reachability = [ODWReachability reachabilityWithHostname:hostname]; + + XCTestExpectation *expectation = [self expectationWithDescription:@"Reachability check"]; + NSString *hostUrl = [NSString stringWithFormat:@"https://%@", hostname]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + XCTAssertNotNil(reachability); + XCTAssertEqualObjects(reachability.url.absoluteString, hostUrl); + [expectation fulfill]; + }); + [self waitForExpectationsWithTimeout:10.0 handler:nil]; +} + +- (void)testReachabilityWithInvalidHostname +{ + NSString *hostname = @"invalid.hostname"; + ODWReachability *reachability = [ODWReachability reachabilityWithHostname:hostname]; + + XCTestExpectation *expectation = [self expectationWithDescription:@"Reachability check"]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + XCTAssertNil(reachability); + [expectation fulfill]; + }); + [self waitForExpectationsWithTimeout:10.0 handler:nil]; +} + +- (void)testReachabilityWithAddress +{ + struct sockaddr_in address; + address.sin_family = AF_INET; + address.sin_addr.s_addr = inet_addr("8.8.8.8"); + ODWReachability *reachability = [ODWReachability reachabilityWithAddress:&address]; + + XCTestExpectation *expectation = [self expectationWithDescription:@"Reachability check"]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + XCTAssertNotNil(reachability); + XCTAssertEqualObjects(reachability.url.absoluteString, @"https://8.8.8.8"); + [expectation fulfill]; + }); + [self waitForExpectationsWithTimeout:10.0 handler:nil]; +} + +- (void)testReachabilityWithInvalidAddress +{ + struct sockaddr_in address; + address.sin_family = AF_INET; + address.sin_addr.s_addr = inet_addr("0.0.0.0"); + ODWReachability *reachability = [ODWReachability reachabilityWithAddress:&address]; + + XCTestExpectation *expectation = [self expectationWithDescription:@"Reachability check"]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + XCTAssertNil(reachability); + [expectation fulfill]; + }); + [self waitForExpectationsWithTimeout:10.0 handler:nil]; +} + +- (void)testReachabilityForInternetConnection +{ + ODWReachability *reachability = [ODWReachability reachabilityForInternetConnection]; + + XCTestExpectation *expectation = [self expectationWithDescription:@"Reachability check"]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + XCTAssertNotNil(reachability); + XCTAssertEqual(reachability.currentReachabilityStatus, ReachableViaWiFi); + [expectation fulfill]; + }); + [self waitForExpectationsWithTimeout:10.0 handler:nil]; +} + +- (void)testReachabilityForLocalWiFi +{ + ODWReachability *reachability = [ODWReachability reachabilityForLocalWiFi]; + + XCTestExpectation *expectation = [self expectationWithDescription:@"Reachability check"]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + XCTAssertNotNil(reachability); + XCTAssertEqual(reachability.currentReachabilityStatus, ReachableViaWiFi); + [expectation fulfill]; + }); + [self waitForExpectationsWithTimeout:10.0 handler:nil]; +} + +@end + diff --git a/tests/unittests/unittests-ios.xcodeproj/project.pbxproj b/tests/unittests/unittests-ios.xcodeproj/project.pbxproj index b17cd878a..5511210d4 100644 --- a/tests/unittests/unittests-ios.xcodeproj/project.pbxproj +++ b/tests/unittests/unittests-ios.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 16CC10702D4D58DA00C03295 /* ODWReachabilityTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 16CC106F2D4D58DA00C03295 /* ODWReachabilityTests.mm */; }; 430102E5235E660F00836D50 /* iOSWrapper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 430102E4235E660F00836D50 /* iOSWrapper.mm */; }; 431EFE50233EBE54002FCC18 /* HttpClientTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 431EFE2A233EBE53002FCC18 /* HttpClientTests.cpp */; }; 431EFE51233EBE54002FCC18 /* LoggerTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 431EFE2B233EBE53002FCC18 /* LoggerTests.cpp */; }; @@ -116,6 +117,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 16CC106F2D4D58DA00C03295 /* ODWReachabilityTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = ODWReachabilityTests.mm; path = "obj-c/ODWReachabilityTests.mm"; sourceTree = ""; }; 430102E4235E660F00836D50 /* iOSWrapper.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = iOSWrapper.mm; path = ../../common/iOSWrapper.mm; sourceTree = ""; }; 431EFE1E233EBDF2002FCC18 /* libunittests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libunittests.a; sourceTree = BUILT_PRODUCTS_DIR; }; 431EFE2A233EBE53002FCC18 /* HttpClientTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HttpClientTests.cpp; sourceTree = ""; }; @@ -201,6 +203,7 @@ 431EFE15233EBDF2002FCC18 = { isa = PBXGroup; children = ( + 16CC106F2D4D58DA00C03295 /* ODWReachabilityTests.mm */, 43BD496F26B8B0C300EC3C0C /* EventPropertiesDecoratorTests.cpp */, 437C72F024D2286F0046F545 /* ODWLogConfigurationTests.mm */, 437C72EE24D21ACE0046F545 /* ODWSemanticContextTests.mm */, @@ -433,6 +436,7 @@ 431EFEA7233EC590002FCC18 /* HttpDeflateCompressionTests.cpp in Sources */, 431EFEB3233EC590002FCC18 /* OfflineStorageTests.cpp in Sources */, 431EFEB8233EC590002FCC18 /* TaskDispatcherCAPITests.cpp in Sources */, + 16CC10712D4D58DA00C03295 /* ODWReachabilityTests.mm in Sources */, 437C72ED24D0C5D70046F545 /* ODWEventPropertiesTests.mm in Sources */, 431EFEB6233EC590002FCC18 /* RouteTests.cpp in Sources */, 431EFEA8233EC590002FCC18 /* HttpRequestEncoderTests.cpp in Sources */, diff --git a/third_party/Reachability/ODWReachability.h b/third_party/Reachability/ODWReachability.h index 185b5cf59..b2d218417 100644 --- a/third_party/Reachability/ODWReachability.h +++ b/third_party/Reachability/ODWReachability.h @@ -60,6 +60,7 @@ typedef void (^NetworkUnreachable)(ODWReachability * reachability); @property (nonatomic, assign) BOOL reachableOnWWAN; +@property (nonatomic, strong) NSURL *url; +(ODWReachability*)reachabilityWithHostname:(NSString*)hostname; // This is identical to the function above, but is here to maintain @@ -68,6 +69,7 @@ typedef void (^NetworkUnreachable)(ODWReachability * reachability); +(ODWReachability*)reachabilityForInternetConnection; +(ODWReachability*)reachabilityWithAddress:(void *)hostAddress; +(ODWReachability*)reachabilityForLocalWiFi; ++(void)setTimeoutDurationInSeconds:(int)timeoutDuration; -(ODWReachability *)initWithReachabilityRef:(SCNetworkReachabilityRef)ref; diff --git a/third_party/Reachability/ODWReachability.m b/third_party/Reachability/ODWReachability.m index c786c38b6..0e13591d5 100644 --- a/third_party/Reachability/ODWReachability.m +++ b/third_party/Reachability/ODWReachability.m @@ -33,6 +33,7 @@ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF #import #import #import +#import NSString *const kNetworkReachabilityChangedNotification = @"NetworkReachabilityChangedNotification"; @@ -53,7 +54,7 @@ -(BOOL)isReachableWithFlags:(SCNetworkReachabilityFlags)flags; static NSString *reachabilityFlags(SCNetworkReachabilityFlags flags) { return [NSString stringWithFormat:@"%c%c %c%c%c%c%c%c%c", -#if TARGET_OS_IPHONE +#if TARGET_OS_IPHONE (flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-', #else 'X', @@ -86,16 +87,46 @@ static void TMReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkRea @implementation ODWReachability +static int kTimeoutDurationInSeconds = 10; + #pragma mark - Class Constructor Methods +(ODWReachability*)reachabilityWithHostName:(NSString*)hostname { + if (hostname == nil || [hostname length] == 0) + { + NSLog(@"Invalid hostname"); + return nil; + } return [ODWReachability reachabilityWithHostname:hostname]; } -+(ODWReachability*)reachabilityWithHostname:(NSString*)hostname ++(instancetype)reachabilityWithHostname:(NSString*)hostname { + if (@available(macOS 10.14, iOS 12.0, *)) + { + // Use URLSession for macOS 10.14 or higher + NSString *formattedHostname = hostname; + if (![formattedHostname hasPrefix:@"https://"] && ![formattedHostname hasPrefix:@"http://"]) { + formattedHostname = [NSString stringWithFormat:@"https://%@", hostname]; + } + NSURL *url = [NSURL URLWithString:formattedHostname]; + + NSURLSession *session = [NSURLSession sharedSession]; + __block ODWReachability *reachabilityInstance = [[self alloc] init]; + reachabilityInstance.url = url; + NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + reachabilityInstance = [self handleReachabilityResponse:response error:error url:reachabilityInstance.url]; + }]; + [dataTask resume]; + return reachabilityInstance; + } + + // Use SCNetworkReachability for macOS 10.14 or lower +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithName(NULL, [hostname UTF8String]); +#pragma clang diagnostic pop if (ref) { id reachability = [[self alloc] initWithReachabilityRef:ref]; @@ -108,7 +139,31 @@ +(ODWReachability*)reachabilityWithHostname:(NSString*)hostname +(ODWReachability *)reachabilityWithAddress:(void *)hostAddress { + if (hostAddress == NULL) { + NSLog(@"Invalid address"); + return nil; + } + + if (@available(macOS 10.14, iOS 12.0, *)) + { + // Use URLSession for macOS 10.14 or higher + NSString *addressString = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)hostAddress)->sin_addr)]; + NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"https://%@", addressString]]; + NSURLSession *session = [NSURLSession sharedSession]; + __block ODWReachability *reachabilityInstance = [[self alloc] init]; + reachabilityInstance.url = url; + NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + reachabilityInstance = [self handleReachabilityResponse:response error:error url:reachabilityInstance.url]; + }]; + [dataTask resume]; + return reachabilityInstance; // Return the instance after resuming the data task + } + + // Use SCNetworkReachability for macOS 10.14 or lower +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress); +#pragma clang diagnostic pop if (ref) { id reachability = [[self alloc] initWithReachabilityRef:ref]; @@ -119,6 +174,33 @@ +(ODWReachability *)reachabilityWithAddress:(void *)hostAddress return nil; } ++(ODWReachability *)handleReachabilityResponse:(NSURLResponse *)response error:(NSError *)error url:(NSURL *)url +{ + __block ODWReachability *reachabilityInstance = nil; + + if (error == nil) { + // Handle successful reachability + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; + if (httpResponse.statusCode == 200) + { + NSLog(@"Reachability success: %@", url); + reachabilityInstance = [[self alloc] init]; + reachabilityInstance.url = url; + } + else + { + NSLog(@"Reachability failed with status code: %ld", (long)httpResponse.statusCode); + } + return reachabilityInstance; + } + + // Handle reachability failure + NSLog(@"Reachability error: %@", error.localizedDescription); + + return nil; +} + + +(ODWReachability *)reachabilityForInternetConnection { struct sockaddr_in zeroAddress; @@ -161,8 +243,20 @@ -(ODWReachability *)initWithReachabilityRef:(SCNetworkReachabilityRef)ref return self; } ++(void)setTimeoutDurationInSeconds:(int)timeoutDuration +{ + if (timeoutDuration >= kTimeoutDurationInSeconds) + { + kTimeoutDurationInSeconds = timeoutDuration; + } + else + { + NSLog(@"Timeout duration must be at least 10."); + } +} + #ifdef __clang__ -#pragma clang diagnostic push +#pragma clang diagnostic push #pragma clang diagnostic ignored "-Wobjc-missing-super-calls" // Not fixing third_party components. #endif @@ -176,13 +270,13 @@ -(void)dealloc self.reachabilityRef = nil; } - self.reachableBlock = nil; - self.unreachableBlock = nil; + self.reachableBlock = nil; + self.unreachableBlock = nil; self.reachabilitySerialQueue = nil; } - -#ifdef __clang__ -#pragma clang diagnostic pop + +#ifdef __clang__ +#pragma clang diagnostic pop #endif #pragma mark - Notifier Methods @@ -194,34 +288,56 @@ -(void)dealloc -(BOOL)startNotifier { + if (@available(macOS 10.14, iOS 12.0, *)) + { + // Use URLSession for macOS 10.14 or higher + NSURLSession *session = [NSURLSession sharedSession]; + NSURLSessionDataTask *task = [session dataTaskWithURL:[self url] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + if (error) { + NSLog(@"URLSession failed: %@", error.localizedDescription); + self.reachabilityObject = nil; + } else { + self.reachabilityObject = self; + [[NSNotificationCenter defaultCenter] postNotificationName:kNetworkReachabilityChangedNotification object:self]; + } + }]; + if (task) { + [task resume]; + return YES; + } else { + NSLog(@"Failed to create URLSessionDataTask"); + return NO; + } + } + + // Use SCNetworkReachability for macOS 10.14 or lower // allow start notifier to be called multiple times - if(self.reachabilityObject && (self.reachabilityObject == self)) + if (self.reachabilityObject && (self.reachabilityObject == self)) { return YES; } - - SCNetworkReachabilityContext context = { 0, NULL, NULL, NULL, NULL }; + SCNetworkReachabilityContext context = { 0, NULL, NULL, NULL, NULL }; context.info = (__bridge void *)self; - - if(SCNetworkReachabilitySetCallback(self.reachabilityRef, TMReachabilityCallback, &context)) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + if (SCNetworkReachabilitySetCallback(self.reachabilityRef, TMReachabilityCallback, &context)) { - // Set it as our reachability queue, which will retain the queue - if(SCNetworkReachabilitySetDispatchQueue(self.reachabilityRef, self.reachabilitySerialQueue)) + if (SCNetworkReachabilitySetDispatchQueue(self.reachabilityRef, self.reachabilitySerialQueue)) +#pragma clang diagnostic pop { - // this should do a retain on ourself, so as long as we're in notifier mode we shouldn't disappear out from under ourselves - // woah self.reachabilityObject = self; return YES; - } - else - { + } else { #ifdef DEBUG NSLog(@"SCNetworkReachabilitySetDispatchQueue() failed: %s", SCErrorString(SCError())); #endif - - // UH OH - FAILURE - stop any callbacks! - SCNetworkReachabilitySetCallback(self.reachabilityRef, NULL, NULL); + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + // UH OH - FAILURE - stop any callbacks! + SCNetworkReachabilitySetCallback(self.reachabilityRef, NULL, NULL); +#pragma clang diagnostic pop } } else @@ -238,15 +354,25 @@ -(BOOL)startNotifier -(void)stopNotifier { + if (@available(macOS 10.14, iOS 12.0, *)) + { + // Use URLSession for macOS 10.14 or higher, no specific action is needed for URLSession + self.reachabilityObject = nil; + } + + // Use SCNetworkReachability for macOS 10.14 or lower +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" // First stop, any callbacks! SCNetworkReachabilitySetCallback(self.reachabilityRef, NULL, NULL); // Unregister target from the GCD serial dispatch queue. SCNetworkReachabilitySetDispatchQueue(self.reachabilityRef, NULL); - +#pragma clang diagnostic pop self.reachabilityObject = nil; } + #pragma mark - reachability tests // This is for the case where you flick the airplane mode; @@ -269,7 +395,7 @@ -(BOOL)isReachableWithFlags:(SCNetworkReachabilityFlags)flags if( (flags & testcase) == testcase ) connectionUP = NO; -#if TARGET_OS_IPHONE +#if TARGET_OS_IPHONE if(flags & kSCNetworkReachabilityFlagsIsWWAN) { // We're on 3G. @@ -286,17 +412,27 @@ -(BOOL)isReachableWithFlags:(SCNetworkReachabilityFlags)flags -(BOOL)isReachable { - SCNetworkReachabilityFlags flags; + if (@available(macOS 10.14, iOS 12.0, *)) + { + return [self checkNetworkReachability:true]; + } + // for macOS 10.14 or lower + SCNetworkReachabilityFlags flags; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" if(!SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags)) return NO; +#pragma clang diagnostic pop return [self isReachableWithFlags:flags]; } + -(BOOL)isReachableViaWWAN { -#if TARGET_OS_IPHONE +#if TARGET_OS_IPHONE SCNetworkReachabilityFlags flags = 0; @@ -319,14 +455,23 @@ -(BOOL)isReachableViaWWAN -(BOOL)isReachableViaWiFi { + if (@available(macOS 10.14, iOS 12.0, *)) + { + return [self checkNetworkReachability:true]; + } + + // for macOS 10.14 or lower SCNetworkReachabilityFlags flags = 0; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" if(SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags)) +#pragma clang diagnostic pop { // Check we're reachable if((flags & kSCNetworkReachabilityFlagsReachable)) { -#if TARGET_OS_IPHONE +#if TARGET_OS_IPHONE // Check we're NOT on WWAN if((flags & kSCNetworkReachabilityFlagsIsWWAN)) { @@ -350,45 +495,75 @@ -(BOOL)isConnectionRequired -(BOOL)connectionRequired { + if (@available(macOS 10.14, iOS 12.0, *)) + { + return [self checkNetworkReachability:false]; + } + + // for macOS 10.14 or lower SCNetworkReachabilityFlags flags; - if(SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags)) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + if(SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags)) +#pragma clang diagnostic pop { - return (flags & kSCNetworkReachabilityFlagsConnectionRequired); - } + return (flags & kSCNetworkReachabilityFlagsConnectionRequired); + } return NO; } + // Dynamic, on demand connection? -(BOOL)isConnectionOnDemand { - SCNetworkReachabilityFlags flags; + if (@available(macOS 10.14, iOS 12.0, *)) + { + return [self checkNetworkReachability:true]; + } - if (SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags)) + // for macOS 10.14 or lower + SCNetworkReachabilityFlags flags; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + if (SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags)) +#pragma clang diagnostic pop { - return ((flags & kSCNetworkReachabilityFlagsConnectionRequired) && - (flags & (kSCNetworkReachabilityFlagsConnectionOnTraffic | kSCNetworkReachabilityFlagsConnectionOnDemand))); - } + return ((flags & kSCNetworkReachabilityFlagsConnectionRequired) && + (flags & (kSCNetworkReachabilityFlagsConnectionOnTraffic | kSCNetworkReachabilityFlagsConnectionOnDemand))); + } - return NO; + return NO; } + // Is user intervention required? -(BOOL)isInterventionRequired { + if (@available(macOS 10.14, iOS 12.0, *)) + { + return [self checkNetworkReachability:false]; + } + + // for macOS 10.14 or lower SCNetworkReachabilityFlags flags; - if (SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags)) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + if (SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags)) +#pragma clang diagnostic pop { - return ((flags & kSCNetworkReachabilityFlagsConnectionRequired) && - (flags & kSCNetworkReachabilityFlagsInterventionRequired)); - } + return ((flags & kSCNetworkReachabilityFlagsConnectionRequired) && + (flags & kSCNetworkReachabilityFlagsInterventionRequired)); + } - return NO; + return NO; } + #pragma mark - reachability status stuff -(ODWNetworkStatus)currentReachabilityStatus @@ -398,7 +573,7 @@ -(ODWNetworkStatus)currentReachabilityStatus if([self isReachableViaWiFi]) return ReachableViaWiFi; -#if TARGET_OS_IPHONE +#if TARGET_OS_IPHONE return ReachableViaWWAN; #endif } @@ -408,9 +583,32 @@ -(ODWNetworkStatus)currentReachabilityStatus -(SCNetworkReachabilityFlags)reachabilityFlags { + if (@available(macOS 10.14, iOS 12.0, *)) + { + __block SCNetworkReachabilityFlags flags = 0; + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + + NSURLSession *session = [NSURLSession sharedSession]; + NSURLSessionDataTask *task = [session dataTaskWithURL:[self url] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + if (error == nil && data != nil) { + flags = kSCNetworkReachabilityFlagsReachable; + } + dispatch_semaphore_signal(semaphore); + }]; + + [task resume]; + dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, kTimeoutDurationInSeconds * NSEC_PER_SEC)); + + return flags; + } + + // for macOS 10.14 or lower SCNetworkReachabilityFlags flags = 0; - if(SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags)) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + if (SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags)) +#pragma clang diagnostic pop { return flags; } @@ -420,19 +618,19 @@ -(SCNetworkReachabilityFlags)reachabilityFlags -(NSString*)currentReachabilityString { - ODWNetworkStatus temp = [self currentReachabilityStatus]; + ODWNetworkStatus temp = [self currentReachabilityStatus]; - if(temp == ReachableViaWWAN) - { + if(temp == ReachableViaWWAN) + { // Updated for the fact that we have CDMA phones now! - return NSLocalizedString(@"Cellular", @""); - } - if (temp == ReachableViaWiFi) - { - return NSLocalizedString(@"WiFi", @""); - } - - return NSLocalizedString(@"No Connection", @""); + return NSLocalizedString(@"Cellular", @""); + } + if (temp == ReachableViaWiFi) + { + return NSLocalizedString(@"WiFi", @""); + } + + return NSLocalizedString(@"No Connection", @""); } -(NSString*)currentReachabilityFlags @@ -440,6 +638,30 @@ -(NSString*)currentReachabilityFlags return reachabilityFlags([self reachabilityFlags]); } +- (SCNetworkReachabilityFlags)checkNetworkReachability:(BOOL)checkData +{ + __block BOOL connection = NO; + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + + NSURLSession *session = [NSURLSession sharedSession]; + NSURLSessionDataTask *task = [session dataTaskWithURL:[self url] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + if (error == nil && !checkData) + { + connection = YES; + } + else if (error == nil && checkData && data != nil) + { + connection = YES; + } + dispatch_semaphore_signal(semaphore); + }]; + + [task resume]; + dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, kTimeoutDurationInSeconds * NSEC_PER_SEC)); + + return connection; +} + #pragma mark - Callback function calls this method -(void)reachabilityChanged:(SCNetworkReachabilityFlags)flags