SOSPeerCoder.m
1 /* 2 * Copyright (c) 2012-2016 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 #include "keychain/SecureObjectSync/SOSPeer.h" 25 #include "keychain/SecureObjectSync/SOSPeerCoder.h" 26 #include "keychain/SecureObjectSync/SOSTransportMessage.h" 27 #include "keychain/SecureObjectSync/SOSAccount.h" 28 #include "keychain/SecureObjectSync/SOSCoder.h" 29 #include "keychain/SecureObjectSync/SOSEngine.h" 30 #include "keychain/SecureObjectSync/SOSDataSource.h" 31 #import "keychain/SecureObjectSync/SOSAccountTransaction.h" 32 #include "keychain/SecureObjectSync/SOSKVSKeys.h" 33 #include "keychain/SecureObjectSync/SOSPeerOTRTimer.h" 34 35 #include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h" 36 37 #include <utilities/debugging.h> 38 #include <utilities/SecCFWrappers.h> 39 40 #include <AssertMacros.h> 41 #include "keychain/SecureObjectSync/SOSInternal.h" 42 43 enum SOSCoderUnwrapStatus SOSPeerHandleCoderMessage(SOSPeerRef peer, SOSCoderRef coder, CFStringRef peer_id, CFDataRef codedMessage, CFDataRef *decodedMessage, bool *forceSave, CFErrorRef *error) { 44 45 enum SOSCoderUnwrapStatus result = SOSCoderUnwrapError; 46 CFMutableDataRef localDecodedMessage = NULL; 47 48 SOSCoderStatus coderStatus = kSOSCoderDataReturned; 49 require_action_quiet(coder, xit, secerror("%@ getCoder: %@", peer_id, error ? *error : NULL)); 50 CFErrorRef localError = NULL; 51 if (coder) { 52 coderStatus = SOSCoderUnwrap(coder, codedMessage, &localDecodedMessage, peer_id, error); 53 dispatch_source_t timer = SOSPeerGetOTRTimer(peer); 54 if(timer){ 55 secnotice("otrtimer","removing timer for peer: %@", peer); 56 SOSPeerRemoveOTRTimerEntry(peer); 57 dispatch_cancel(timer); 58 } 59 switch(coderStatus) { 60 case kSOSCoderDataReturned: { 61 //logRawMessage(localDecodedMessage, false, 0); 62 result = SOSCoderUnwrapDecoded; 63 break; 64 } 65 case kSOSCoderNegotiating: // Sent message already in Unwrap. 66 result = SOSCoderUnwrapHandled; 67 secnotice("engine", "%@ engine negotiating", peer_id); 68 break; 69 case kSOSCoderNegotiationCompleted: 70 SOSPeerDidConnect(peer); 71 result = SOSCoderUnwrapHandled; 72 *forceSave = true; 73 secnotice("engine", "%@ engine negotiation complete", peer_id); 74 break; 75 case kSOSCoderFailure: // Probably restart coder 76 secnotice("engine", "%@ engine failed handling message %@", peer_id, error ? *error : NULL); 77 SOSCoderReset(coder); 78 if(SOSCoderStart(coder, &localError) == kSOSCoderFailure){ 79 secerror("Attempt to recover coder failed to restart: %@", localError); 80 } 81 break; 82 case kSOSCoderStaleEvent: // We received an event we have already processed in the past. 83 secinfo("engine", "%@ engine stale event ignored", peer_id); 84 result = SOSCoderUnwrapHandled; 85 break; 86 case kSOSCoderForceMessage: 87 SOSPeerSetMustSendMessage(peer, true); 88 result = SOSCoderUnwrapHandled; 89 break; 90 case kSOSCoderTooNew: // We received an event from the future! 91 secnotice("engine", "%@ engine received a message too soon, time to restart", peer_id); 92 SOSCoderReset(coder); 93 if(SOSCoderStart(coder, &localError) == kSOSCoderFailure){ 94 secerror("Attempt to recover coder failed to restart: %@", localError); 95 } 96 break; 97 default: 98 secnotice("engine", "%@ engine unknown coder state: %d", peer_id, (int)coderStatus); 99 assert(false); 100 break; 101 } 102 if(decodedMessage) 103 *decodedMessage = CFRetainSafe(localDecodedMessage); 104 CFReleaseNull(localDecodedMessage); 105 } 106 107 CFReleaseNull(localError); 108 xit: 109 return result; 110 } 111 bool SOSPeerCoderSendMessageIfNeeded(SOSAccount* account, SOSEngineRef engine, SOSTransactionRef txn, SOSPeerRef peer, SOSCoderRef coder, CFDataRef *message_to_send, CFStringRef peer_id, CFMutableArrayRef *attributeList, SOSEnginePeerMessageSentCallback **sentCallback, CFErrorRef *error) { 112 bool ok = false; 113 114 if(!coder) { 115 account.engine_peer_state_needs_repair = true; 116 } 117 require_action_quiet(coder, xit, secnotice("transport", "%@ getCoder: %@", peer_id, error ? *error : NULL)); 118 secnotice("transport", "coder state: %@", coder); 119 120 if (SOSCoderCanWrap(coder)) { 121 secinfo("transport", "%@ Coder can wrap, getting message from engine", peer_id); 122 CFMutableDataRef codedMessage = NULL; 123 CFDataRef message = SOSEngineCreateMessage_locked(engine, txn, peer, attributeList, error, sentCallback); 124 if (!message) { 125 secnotice("transport", "%@ SOSEngineCreateMessage_locked failed: %@", peer_id, *error); 126 } else if (CFDataGetLength(message) || SOSPeerMustSendMessage(peer)) { 127 // TODO: Remove SOSPeerMustSendMessage from peer and move into coder/transport instead 128 ok = message && (SOSCoderWrap(coder, message, &codedMessage, peer_id, error) == kSOSCoderDataReturned); 129 if (!ok) { 130 secnotice("transport", "%@ SOSCoderWrap failed: %@", peer_id, *error); 131 } else { 132 CFRetainAssign(*message_to_send, codedMessage); 133 SOSEngineSetCodersNeedSaving(engine, true); 134 } 135 CFReleaseNull(codedMessage); 136 } else { 137 // Zero length message means we have no work to do. 138 ok = true; 139 } 140 CFReleaseNull(message); 141 142 } else { 143 *message_to_send = SOSCoderCopyPendingResponse(coder); 144 SOSEngineSetCodersNeedSaving(engine, true); 145 secinfo("transport", "%@ negotiating, %@", peer_id, (message_to_send && *message_to_send) ? CFSTR("sending negotiation message.") : CFSTR("waiting for negotiation message.")); 146 147 SOSEnginePeerMessageSentCallback* pmsc = malloc(sizeof(SOSEnginePeerMessageSentCallback)); 148 memset(pmsc, 0, sizeof(SOSEnginePeerMessageSentCallback)); 149 150 pmsc->coder = CFRetainSafe(coder); 151 SOSEngineMessageCallbackSetCallback(pmsc, ^(bool wasSent){ 152 if (wasSent) { 153 SOSCoderConsumeResponse(pmsc->coder); 154 } 155 }); 156 157 *sentCallback = pmsc; 158 ok = true; 159 } 160 /*if coder state is in awaiting for message, then set a timer and restart if failure*/ 161 BOOL initialSync = !SOSAccountHasCompletedInitialSync(account); 162 if(*message_to_send != NULL && initialSync && !SOSPeerOTRTimerHaveReachedMaxRetryAllowance(account, (__bridge NSString*)peer_id)){ 163 if(SOSCoderIsCoderInAwaitingState(coder) && !SOSPeerTimerForPeerExist(peer) && SOSPeerOTRTimerHaveAnRTTAvailable(account, (__bridge NSString*)peer_id)){ 164 secnotice("otrtimer", "coder is in awaiting state"); 165 SOSPeerOTRTimerSetupAwaitingTimer(account, peer, engine, coder); 166 } 167 else if(!SOSCoderIsCoderInAwaitingState(coder)){ 168 secnotice("otrtimer", "coder not in awaiting state: %@", coder); 169 } 170 else if (SOSPeerTimerForPeerExist(peer)){ 171 secnotice("otrtimer", "timer for coder already set: %@", coder); 172 } 173 } 174 xit: 175 return ok; 176 }