Skip to content

Commit

Permalink
sync: Upgrade from SCNetworkReachability -> nw_path_monitor (#1406)
Browse files Browse the repository at this point in the history
  • Loading branch information
russellhancox committed Jul 31, 2024
1 parent 1ce4756 commit 6719d4c
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 82 deletions.
3 changes: 2 additions & 1 deletion Source/santasyncservice/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ objc_library(
name = "FCM_lib",
srcs = ["SNTSyncFCM.m"],
hdrs = ["SNTSyncFCM.h"],
sdk_frameworks = ["SystemConfiguration"],
sdk_frameworks = ["Network"],
deps = [
"@MOLAuthenticatingURLSession",
],
Expand Down Expand Up @@ -55,6 +55,7 @@ objc_library(
],
hdrs = ["SNTSyncManager.h"],
sdk_dylibs = ["libz"],
sdk_frameworks = ["Network"],
deps = [
":FCM_lib",
":broadcaster_lib",
Expand Down
53 changes: 18 additions & 35 deletions Source/santasyncservice/SNTSyncFCM.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

#import "Source/santasyncservice/SNTSyncFCM.h"

#import <SystemConfiguration/SystemConfiguration.h>
#import <Network/Network.h>

#import <MOLAuthenticatingURLSession/MOLAuthenticatingURLSession.h>

Expand Down Expand Up @@ -80,7 +80,7 @@ @interface SNTSyncFCM () {
@property(copy, nonatomic) SNTSyncFCMMessageHandler messageHandler;

/** Is used throughout the class to reconnect to FCM after a connection loss. */
@property SCNetworkReachabilityRef reachability;
@property nw_path_monitor_t pathMonitor;

/** FCM client identities. */
@property(nonatomic, readonly) NSString *project;
Expand All @@ -97,21 +97,6 @@ - (void)reachabilityRestored;

@end

#pragma mark SCNetworkReachabilityCallBack

/** Called when the network state changes. */
static void reachabilityHandler(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags,
void *info) {
dispatch_async(dispatch_get_main_queue(), ^{
if (flags & kSCNetworkReachabilityFlagsReachable) {
SNTSyncFCM *FCMClient = (__bridge SNTSyncFCM *)info;
SEL s = @selector(reachabilityRestored);
[NSObject cancelPreviousPerformRequestsWithTarget:FCMClient selector:s object:nil];
[FCMClient performSelector:s withObject:nil afterDelay:1];
}
});
}

@implementation SNTSyncFCM

#pragma mark init/dealloc methods
Expand Down Expand Up @@ -184,11 +169,6 @@ - (instancetype)initWithProject:(NSString *)project
messageHandler:messageHandler];
}

/** Before this object is released ensure reachability release. */
- (void)dealloc {
[self stopReachability];
}

#pragma mark property methods

- (BOOL)isConnected {
Expand All @@ -212,24 +192,27 @@ - (void)reachabilityRestored {

/** Start listening for network state changes on a background thread. */
- (void)startReachability {
if (self.reachability) return;
if (self.pathMonitor) return;
self.pathMonitor = nw_path_monitor_create();
nw_path_monitor_set_queue(self.pathMonitor, dispatch_get_main_queue());
nw_path_monitor_set_update_handler(self.pathMonitor, ^(nw_path_t path) {
if (nw_path_get_status(path) == nw_path_status_satisfied) {
SEL s = @selector(reachabilityRestored);
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:s object:nil];
[self performSelector:s withObject:nil afterDelay:1];
}
});
nw_path_monitor_set_cancel_handler(self.pathMonitor, ^{
self.pathMonitor = nil;
});
nw_path_monitor_start(self.pathMonitor);
LOGD(@"Reachability started.");
self.reachability =
SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, _connectComponents.host.UTF8String);
SCNetworkReachabilityContext context = {.info = (__bridge void *)self};
if (SCNetworkReachabilitySetCallback(self.reachability, reachabilityHandler, &context)) {
SCNetworkReachabilitySetDispatchQueue(
self.reachability, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0));
}
}

/** Stop listening for network state changes. */
- (void)stopReachability {
if (self.reachability) {
SCNetworkReachabilitySetDispatchQueue(self.reachability, NULL);
if (self.reachability) CFRelease(self.reachability);
self.reachability = NULL;
}
if (!self.pathMonitor) return;
nw_path_monitor_cancel(self.pathMonitor);
}

#pragma mark message methods
Expand Down
66 changes: 20 additions & 46 deletions Source/santasyncservice/SNTSyncManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

#import <MOLAuthenticatingURLSession/MOLAuthenticatingURLSession.h>
#import <MOLXPCConnection/MOLXPCConnection.h>
#import <SystemConfiguration/SystemConfiguration.h>
#import <Network/Network.h>

#import "Source/common/SNTCommonEnums.h"
#import "Source/common/SNTConfigurator.h"
Expand All @@ -35,9 +35,7 @@

static const uint8_t kMaxEnqueuedSyncs = 2;

@interface SNTSyncManager () <SNTPushNotificationsDelegate> {
SCNetworkReachabilityRef _reachability;
}
@interface SNTSyncManager () <SNTPushNotificationsDelegate>

@property(nonatomic) dispatch_source_t fullSyncTimer;
@property(nonatomic) dispatch_source_t ruleSyncTimer;
Expand All @@ -48,6 +46,7 @@ @interface SNTSyncManager () <SNTPushNotificationsDelegate> {
@property(nonatomic) MOLXPCConnection *daemonConn;

@property(nonatomic) BOOL reachable;
@property nw_path_monitor_t pathMonitor;

@property SNTPushNotifications *pushNotifications;

Expand All @@ -58,22 +57,6 @@ @interface SNTSyncManager () <SNTPushNotificationsDelegate> {

@end

// Called when the network state changes
static void reachabilityHandler(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags,
void *info) {
// Put this check and set on the main thread to ensure serial access.
dispatch_async(dispatch_get_main_queue(), ^{
SNTSyncManager *commandSyncManager = (__bridge SNTSyncManager *)info;
// Only call the setter when there is a change. This will filter out the redundant calls to this
// callback whenever the network interface states change.
int reachable =
(flags & kSCNetworkReachabilityFlagsReachable) == kSCNetworkReachabilityFlagsReachable;
if (commandSyncManager.reachable != reachable) {
commandSyncManager.reachable = reachable;
}
});
}

@implementation SNTSyncManager

#pragma mark init
Expand Down Expand Up @@ -102,11 +85,6 @@ - (instancetype)initWithDaemonConnection:(MOLXPCConnection *)daemonConn {
return self;
}

- (void)dealloc {
// Ensure reachability is always stopped
[self stopReachability];
}

#pragma mark SNTSyncServiceXPC methods

- (void)postEventsToSyncServer:(NSArray<SNTStoredEvent *> *)events fromBundle:(BOOL)isFromBundle {
Expand Down Expand Up @@ -413,34 +391,30 @@ - (void)setReachable:(BOOL)reachable {
}
}

// Start listening for network state changes on a background thread
// Start listening for network state changes.
- (void)startReachability {
dispatch_async(dispatch_get_main_queue(), ^{
if (self->_reachability) return;
const char *nodename = [[SNTConfigurator configurator] syncBaseURL].host.UTF8String;
self->_reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, nodename);
SCNetworkReachabilityContext context = {
.info = (__bridge_retained void *)self,
.release = (void (*)(const void *))CFBridgingRelease,
};
if (SCNetworkReachabilitySetCallback(self->_reachability, reachabilityHandler, &context)) {
SCNetworkReachabilitySetDispatchQueue(
self->_reachability, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0));
} else {
[self stopReachability];
if (self.pathMonitor) return;
self.pathMonitor = nw_path_monitor_create();
// Put the callback on the main thread to ensure serial access.
nw_path_monitor_set_queue(self.pathMonitor, dispatch_get_main_queue());
nw_path_monitor_set_update_handler(self.pathMonitor, ^(nw_path_t path) {
// Only call the setter when there is a change. This will filter out the redundant calls to
// this callback whenever the network interface states change.
int reachable = nw_path_get_status(path) == nw_path_status_satisfied;
if (self.reachable != reachable) {
self.reachable = reachable;
}
});
nw_path_monitor_set_cancel_handler(self.pathMonitor, ^{
self.pathMonitor = nil;
});
nw_path_monitor_start(self.pathMonitor);
}

// Stop listening for network state changes
- (void)stopReachability {
dispatch_async(dispatch_get_main_queue(), ^{
if (self->_reachability) {
SCNetworkReachabilitySetDispatchQueue(self->_reachability, NULL);
if (self->_reachability) CFRelease(self->_reachability);
self->_reachability = NULL;
}
});
if (!self.pathMonitor) return;
nw_path_monitor_cancel(self.pathMonitor);
}

@end

0 comments on commit 6719d4c

Please sign in to comment.