Skip to content
Snippets Groups Projects
Commit e1443b19 authored by Muxi Yan's avatar Muxi Yan
Browse files

Flush host when network connectivity changes

parent a8d6681c
No related branches found
No related tags found
No related merge requests found
...@@ -375,20 +375,6 @@ static NSMutableDictionary *callFlags; ...@@ -375,20 +375,6 @@ static NSMutableDictionary *callFlags;
_state = GRXWriterStateStarted; _state = GRXWriterStateStarted;
} }
// Create a retain cycle so that this instance lives until the RPC finishes (or is cancelled).
// This makes RPCs in which the call isn't externally retained possible (as long as it is started
// before being autoreleased).
// Care is taken not to retain self strongly in any of the blocks used in this implementation, so
// that the life of the instance is determined by this retain cycle.
_retainSelf = self;
_responseWriteable = [[GRXConcurrentWriteable alloc] initWithWriteable:writeable];
_wrappedCall = [[GRPCWrappedCall alloc] initWithHost:_host path:_path];
NSAssert(_wrappedCall, @"Error allocating RPC objects. Low memory?");
[self sendHeaders:_requestHeaders];
[self invokeCall];
// TODO(jcanizales): Extract this logic somewhere common. // TODO(jcanizales): Extract this logic somewhere common.
NSString *host = [NSURL URLWithString:[@"https://" stringByAppendingString:_host]].host; NSString *host = [NSURL URLWithString:[@"https://" stringByAppendingString:_host]].host;
if (!host) { if (!host) {
...@@ -397,15 +383,35 @@ static NSMutableDictionary *callFlags; ...@@ -397,15 +383,35 @@ static NSMutableDictionary *callFlags;
} }
__weak typeof(self) weakSelf = self; __weak typeof(self) weakSelf = self;
_connectivityMonitor = [GRPCConnectivityMonitor monitorWithHost:host]; _connectivityMonitor = [GRPCConnectivityMonitor monitorWithHost:host];
[_connectivityMonitor handleLossWithHandler:^{ void (^handler)() = ^{
typeof(self) strongSelf = weakSelf; typeof(self) strongSelf = weakSelf;
if (strongSelf) { if (strongSelf) {
[strongSelf finishWithError:[NSError errorWithDomain:kGRPCErrorDomain [strongSelf finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
code:GRPCErrorCodeUnavailable code:GRPCErrorCodeUnavailable
userInfo:@{NSLocalizedDescriptionKey: @"Connectivity lost."}]]; userInfo:@{NSLocalizedDescriptionKey: @"Connectivity lost."}]];
[[GRPCHost hostWithAddress:strongSelf->_host] disconnect];
} }
}]; };
[_connectivityMonitor handleLossWithHandler:handler
wifiStatusChangeHandler:handler];
// Create a retain cycle so that this instance lives until the RPC finishes
// (or is cancelled).
// This makes RPCs in which the call isn't externally retained possible (as
// long as it is started
// before being autoreleased).
// Care is taken not to retain self strongly in any of the blocks used in this
// implementation, so
// that the life of the instance is determined by this retain cycle.
_retainSelf = self;
_responseWriteable =
[[GRXConcurrentWriteable alloc] initWithWriteable:writeable];
_wrappedCall = [[GRPCWrappedCall alloc] initWithHost:_host path:_path];
NSAssert(_wrappedCall, @"Error allocating RPC objects. Low memory?");
[self sendHeaders:_requestHeaders];
[self invokeCall];
} }
- (void)setState:(GRXWriterState)newState { - (void)setState:(GRXWriterState)newState {
......
...@@ -73,5 +73,6 @@ ...@@ -73,5 +73,6 @@
* Only one handler is active at a time, so if this method is called again before the previous * Only one handler is active at a time, so if this method is called again before the previous
* handler has been called, it might never be called at all (or yes, if it has already been queued). * handler has been called, it might never be called at all (or yes, if it has already been queued).
*/ */
- (void)handleLossWithHandler:(nonnull void (^)())handler; - (void)handleLossWithHandler:(void (^)())handler
wifiStatusChangeHandler:(void (^)())wifiStatusChangeHandler;
@end @end
...@@ -120,6 +120,7 @@ static void PassFlagsToContextInfoBlock(SCNetworkReachabilityRef target, ...@@ -120,6 +120,7 @@ static void PassFlagsToContextInfoBlock(SCNetworkReachabilityRef target,
@implementation GRPCConnectivityMonitor { @implementation GRPCConnectivityMonitor {
SCNetworkReachabilityRef _reachabilityRef; SCNetworkReachabilityRef _reachabilityRef;
GRPCReachabilityFlags *_previousReachabilityFlags;
} }
- (nullable instancetype)initWithReachability:(nullable SCNetworkReachabilityRef)reachability { - (nullable instancetype)initWithReachability:(nullable SCNetworkReachabilityRef)reachability {
...@@ -129,6 +130,13 @@ static void PassFlagsToContextInfoBlock(SCNetworkReachabilityRef target, ...@@ -129,6 +130,13 @@ static void PassFlagsToContextInfoBlock(SCNetworkReachabilityRef target,
if ((self = [super init])) { if ((self = [super init])) {
_reachabilityRef = CFRetain(reachability); _reachabilityRef = CFRetain(reachability);
_queue = dispatch_get_main_queue(); _queue = dispatch_get_main_queue();
SCNetworkReachabilityFlags flags;
if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags)) {
_previousReachabilityFlags =
[[GRPCReachabilityFlags alloc] initWithFlags:flags];
} else {
_previousReachabilityFlags = 0;
}
} }
return self; return self;
} }
...@@ -149,11 +157,16 @@ static void PassFlagsToContextInfoBlock(SCNetworkReachabilityRef target, ...@@ -149,11 +157,16 @@ static void PassFlagsToContextInfoBlock(SCNetworkReachabilityRef target,
return returnValue; return returnValue;
} }
- (void)handleLossWithHandler:(void (^)())handler { - (void)handleLossWithHandler:(void (^)())handler
wifiStatusChangeHandler:(nonnull void (^)())wifiStatusChangeHandler {
[self startListeningWithHandler:^(GRPCReachabilityFlags *flags) { [self startListeningWithHandler:^(GRPCReachabilityFlags *flags) {
if (!flags.isHostReachable) { if (!flags.reachable && handler) {
handler(); handler();
} else if (flags.isWWAN ^ _previousReachabilityFlags.isWWAN &&
wifiStatusChangeHandler) {
wifiStatusChangeHandler();
} }
_previousReachabilityFlags = flags;
}]; }];
} }
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#import "GRPCChannel.h" #import "GRPCChannel.h"
#import "GRPCCompletionQueue.h" #import "GRPCCompletionQueue.h"
#import "GRPCConnectivityMonitor.h"
#import "NSDictionary+GRPC.h" #import "NSDictionary+GRPC.h"
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
...@@ -52,6 +53,7 @@ NS_ASSUME_NONNULL_BEGIN ...@@ -52,6 +53,7 @@ NS_ASSUME_NONNULL_BEGIN
#define GRPC_OBJC_VERSION_STRING @"1.0.0" #define GRPC_OBJC_VERSION_STRING @"1.0.0"
static NSMutableDictionary *kHostCache; static NSMutableDictionary *kHostCache;
static GRPCConnectivityMonitor *connectivityMonitor = nil;
@implementation GRPCHost { @implementation GRPCHost {
// TODO(mlumish): Investigate whether caching channels with strong links is a good idea. // TODO(mlumish): Investigate whether caching channels with strong links is a good idea.
...@@ -98,6 +100,16 @@ static NSMutableDictionary *kHostCache; ...@@ -98,6 +100,16 @@ static NSMutableDictionary *kHostCache;
_address = address; _address = address;
_secure = YES; _secure = YES;
kHostCache[address] = self; kHostCache[address] = self;
if (!connectivityMonitor) {
connectivityMonitor =
[GRPCConnectivityMonitor monitorWithHost:hostURL.host];
void (^handler)() = ^{
[GRPCHost flushChannelCache];
};
[connectivityMonitor handleLossWithHandler:handler
wifiStatusChangeHandler:handler];
}
} }
} }
return self; return self;
...@@ -110,6 +122,7 @@ static NSMutableDictionary *kHostCache; ...@@ -110,6 +122,7 @@ static NSMutableDictionary *kHostCache;
BOOL * _Nonnull stop) { BOOL * _Nonnull stop) {
[host disconnect]; [host disconnect];
}]; }];
connectivityMonitor = nil;
} }
} }
......
...@@ -65,3 +65,4 @@ GRPC_XMACRO_ITEM(interventionRequired, InterventionRequired) ...@@ -65,3 +65,4 @@ GRPC_XMACRO_ITEM(interventionRequired, InterventionRequired)
GRPC_XMACRO_ITEM(connectionOnDemand, ConnectionOnDemand) GRPC_XMACRO_ITEM(connectionOnDemand, ConnectionOnDemand)
GRPC_XMACRO_ITEM(isLocalAddress, IsLocalAddress) GRPC_XMACRO_ITEM(isLocalAddress, IsLocalAddress)
GRPC_XMACRO_ITEM(isDirect, IsDirect) GRPC_XMACRO_ITEM(isDirect, IsDirect)
GRPC_XMACRO_ITEM(isWWAN, IsWWAN)
...@@ -156,7 +156,7 @@ ...@@ -156,7 +156,7 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
5347BF6C41E7888C1C05CD88 /* [CP] Copy Pods Resources */ = { 5347BF6C41E7888C1C05CD88 /* [CP] Copy Pods Resources */ = {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment