From 2d93b8c6ec661048f53d6417dade293dbcfdcc59 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Thu, 6 Apr 2017 19:11:04 -0400 Subject: [PATCH] Handle mismatched/stale devices on session queue The session state should never be manipulated concurrently. // FREEBIE --- src/Messages/OWSMessageSender.m | 58 +++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/src/Messages/OWSMessageSender.m b/src/Messages/OWSMessageSender.m index 5d24eb9..bcd2217 100644 --- a/src/Messages/OWSMessageSender.m +++ b/src/Messages/OWSMessageSender.m @@ -42,6 +42,13 @@ NS_ASSUME_NONNULL_BEGIN +void AssertIsOnSendingQueue() +{ + if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(10, 0)) { + dispatch_assert_queue([OWSDispatch sendingQueue]); + } // else, skip assert as it's a development convenience. +} + /** * OWSSendMessageOperation encapsulates all the work associated with sending a message, e.g. uploading attachments, * getting proper keys, and retrying upon failure. @@ -724,6 +731,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; failure:(RetryableFailureHandler)failureHandler { DDLogDebug(@"%@ sending message to service: %@", self.tag, message.debugDescription); + AssertIsOnSendingQueue(); if ([TSPreKeyManager isAppLockedDueToPreKeyUpdateFailures]) { OWSAnalyticsError(@"Message send failed due to prekey update failures"); @@ -857,8 +865,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; return failureHandler(error, YES); } - [self handleMismatchedDevices:serializedResponse recipient:recipient]; - retrySend(); + [self handleMismatchedDevices:serializedResponse recipient:recipient completion:retrySend]; break; } case 410: { @@ -871,8 +878,9 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; return failureHandler(error, YES); } - [self handleStaleDevicesWithResponse:responseData recipientId:recipient.uniqueId]; - retrySend(); + [self handleStaleDevicesWithResponse:responseData + recipientId:recipient.uniqueId + completion:retrySend]; break; } default: @@ -882,24 +890,29 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; }]; } -- (void)handleMismatchedDevices:(NSDictionary *)dictionary recipient:(SignalRecipient *)recipient +- (void)handleMismatchedDevices:(NSDictionary *)dictionary + recipient:(SignalRecipient *)recipient + completion:(void (^)())completionHandler { NSArray *extraDevices = [dictionary objectForKey:@"extraDevices"]; NSArray *missingDevices = [dictionary objectForKey:@"missingDevices"]; - if (extraDevices && extraDevices.count > 0) { - for (NSNumber *extraDeviceId in extraDevices) { - [self.storageManager deleteSessionForContact:recipient.uniqueId deviceId:extraDeviceId.intValue]; + dispatch_async([OWSDispatch sessionStoreQueue], ^{ + if (extraDevices && extraDevices.count > 0) { + for (NSNumber *extraDeviceId in extraDevices) { + [self.storageManager deleteSessionForContact:recipient.uniqueId deviceId:extraDeviceId.intValue]; + } + + [recipient removeDevices:[NSSet setWithArray:extraDevices]]; } - [recipient removeDevices:[NSSet setWithArray:extraDevices]]; - } + if (missingDevices && missingDevices.count > 0) { + [recipient addDevices:[NSSet setWithArray:missingDevices]]; + } - if (missingDevices && missingDevices.count > 0) { - [recipient addDevices:[NSSet setWithArray:missingDevices]]; - } - - [recipient save]; + [recipient save]; + completionHandler(); + }); } - (void)handleMessageSentLocally:(TSOutgoingMessage *)message @@ -1173,7 +1186,9 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; } } -- (void)handleStaleDevicesWithResponse:(NSData *)responseData recipientId:(NSString *)identifier +- (void)handleStaleDevicesWithResponse:(NSData *)responseData + recipientId:(NSString *)identifier + completion:(void (^)())completionHandler { dispatch_async([OWSDispatch sendingQueue], ^{ NSDictionary *serialization = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:nil]; @@ -1183,10 +1198,13 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; return; } - for (NSUInteger i = 0; i < [devices count]; i++) { - int deviceNumber = [devices[i] intValue]; - [[TSStorageManager sharedManager] deleteSessionForContact:identifier deviceId:deviceNumber]; - } + dispatch_async([OWSDispatch sessionStoreQueue], ^{ + for (NSUInteger i = 0; i < [devices count]; i++) { + int deviceNumber = [devices[i] intValue]; + [[TSStorageManager sharedManager] deleteSessionForContact:identifier deviceId:deviceNumber]; + } + completionHandler(); + }); }); }