1#include <SecureObjectSync/SOSPeer.h> 2#include <SecureObjectSync/SOSPeerCoder.h> 3#include <SecureObjectSync/SOSTransportMessage.h> 4#include <SecureObjectSync/SOSCoder.h> 5#include <SecureObjectSync/SOSAccount.h> 6#include <SecureObjectSync/SOSEngine.h> 7 8#include <utilities/debugging.h> 9#include <utilities/SecCFWrappers.h> 10 11#include <AssertMacros.h> 12#include "SOSInternal.h" 13 14static CFStringRef kSOSPeerCoderKey = CFSTR("coder"); 15 16bool SOSPeerCoderInitializeForPeer(SOSTransportMessageRef transport, SOSFullPeerInfoRef myPeerInfo, SOSPeerInfoRef peerInfo, CFErrorRef *error){ 17 CFErrorRef coderError = NULL; 18 19 CFStringRef peer_id = SOSPeerInfoGetPeerID(peerInfo); 20 SOSCoderRef coder = NULL; 21 CFDataRef coderData = NULL; 22 bool haveGoodCoder = false; 23 CFMutableDictionaryRef peerState = SOSEngineGetPeerState(SOSTransportMessageGetEngine(transport), peer_id); 24 25 if(peerState){ 26 coderData = CFDictionaryGetValue(peerState, kSOSPeerCoderKey); 27 if(coderData){ 28 coder = SOSCoderCreateFromData(coderData, &coderError); 29 if (!coder) { 30 secerror("Found data but couldn't make coder for %@: %@", peer_id, coderError); 31 } 32 haveGoodCoder = coder; 33 SOSCoderDispose(coder); 34 coder = NULL; 35 } 36 } 37 38 if (!haveGoodCoder) { 39 secnotice("peer", "New coder for id %@.", peer_id); 40 CFReleaseNull(coder); 41 coder = SOSCoderCreate(peerInfo, myPeerInfo, error); 42 if (coder) { 43 coderData = SOSCoderCopyDER(coder, error); 44 if(coderData){ 45 if(!(haveGoodCoder = SOSEngineSetCoderData(SOSTransportMessageGetEngine(transport), peer_id, coderData, error))){ 46 secerror("SOSPeerCoderInitializeForPeer, Could not save coder data"); 47 } 48 } 49 CFReleaseNull(coderData); 50 SOSCoderDispose(coder); 51 } else { 52 secerror("Couldn't make coder for %@", peer_id); 53 } 54 } 55 CFReleaseNull(coderError); 56 return haveGoodCoder; 57} 58 59void SOSPeerCoderConsume(SOSEnginePeerMessageSentBlock *sent, bool ok){ 60 if (*sent) 61 (*sent)(ok); 62} 63 64enum SOSCoderUnwrapStatus SOSPeerHandleCoderMessage(SOSPeerRef peer, CFStringRef peer_id, CFDataRef codedMessage, CFDataRef *decodedMessage, CFErrorRef *error){ 65 66 enum SOSCoderUnwrapStatus result = SOSCoderUnwrapError; 67 CFMutableDataRef localDecodedMessage = NULL; 68 69 SOSCoderStatus coderStatus = kSOSCoderDataReturned; 70 CFDataRef coderData = SOSEngineGetCoderData(SOSPeerGetEngine(peer), SOSPeerGetID(peer)); 71 require_quiet(coderData, fail); 72 SOSCoderRef coder = SOSCoderCreateFromData(coderData, error); 73 require(coder, fail); 74 CFErrorRef localError = NULL; 75 if (coder) { 76 coderStatus = SOSCoderUnwrap(coder, codedMessage, &localDecodedMessage, peer_id, error); 77 78 switch(coderStatus) { 79 case kSOSCoderDataReturned: { 80 logRawMessage(localDecodedMessage, false, 0); 81 result = SOSCoderUnwrapDecoded; 82 break; 83 } 84 case kSOSCoderNegotiating: // Sent message already in Unwrap. 85 result = SOSCoderUnwrapHandled; 86 secnotice("engine", "%@ engine negotiating", peer_id); 87 break; 88 case kSOSCoderNegotiationCompleted: 89 if(SOSEnginePeerDidConnect(SOSPeerGetEngine(peer), peer_id, error)) 90 result = SOSCoderUnwrapHandled; 91 secnotice("engine", "%@ engine negotiation complete", peer_id); 92 break; 93 case kSOSCoderFailure: // Probably restart coder 94 secnotice("engine", "%@ engine failed handling message %@", peer_id, error ? *error : NULL); 95 SOSCoderReset(coder); 96 if(SOSCoderStart(coder, &localError) == kSOSCoderFailure){ 97 secerror("Attempt to recover coder failed to restart: %@", localError); 98 } 99 break; 100 case kSOSCoderStaleEvent: // We received an event we have already processed in the past. 101 secnotice("engine", "%@ engine stale event ignored", peer_id); 102 break; 103 default: 104 assert(false); 105 break; 106 } 107 if(decodedMessage) 108 *decodedMessage = CFRetainSafe(localDecodedMessage); 109 CFReleaseNull(localDecodedMessage); 110 111 coderData = SOSCoderCopyDER(coder, error); 112 if(!SOSEngineSetCoderData(SOSPeerGetEngine(peer), peer_id, coderData, error)){ 113 secerror("SOSTransportMessageSendMessageIfNeeded, Could not save peer state"); 114 } 115 CFReleaseNull(coderData); 116 SOSCoderDispose(coder); 117 } 118 119 CFReleaseNull(localError); 120fail: 121 return result; 122 123} 124 125bool SOSPeerCoderSendMessageIfNeeded(SOSPeerRef peer, CFDataRef *message_to_send, CFStringRef circle_id, CFStringRef peer_id, SOSEnginePeerMessageSentBlock *sent, CFErrorRef *error){ 126 SOSCoderRef coder = SOSPeerGetCoder(peer); 127 128 bool ok = false; 129 require_quiet(coder, fail); 130 131 if (SOSCoderCanWrap(coder)) { 132 secnotice("transport", "%@ Coder can wrap, getting message from engine", peer_id); 133 CFMutableDataRef codedMessage = NULL; 134 CFDataRef message = SOSEngineCreateMessageToSyncToPeer(SOSPeerGetEngine(peer), peer_id, sent, error); 135 if (!message) { 136 secnotice("transport", "%@ SOSEngineCreateMessageToSyncToPeer failed: %@",peer_id, *error); 137 } 138 ok = message && (SOSCoderWrap(coder, message, &codedMessage, peer_id, error) == kSOSCoderDataReturned); 139 if (!ok) { 140 secnotice("transport", "%@ SOSCoderWrap failed: %@",peer_id, *error); 141 } 142 143 if (ok) 144 CFRetainAssign(*message_to_send, codedMessage); 145 146 CFReleaseNull(codedMessage); 147 CFReleaseNull(message); 148 } else { 149 *message_to_send = SOSCoderCopyPendingResponse(coder); 150 secnotice("transport", "%@ Negotiating, %@", peer_id, message_to_send ? CFSTR("Sending negotiation message.") : CFSTR("waiting for negotiation message.")); 151 *sent = Block_copy(^(bool wasSent){ 152 if (wasSent) 153 SOSCoderConsumeResponse(coder); 154 }); 155 ok = true; 156 } 157 158fail: 159 return ok; 160} 161