1 2#include <SecureObjectSync/SOSPeer.h> 3#include <SecureObjectSync/SOSTransportCoder.h> 4#include <SecureObjectSync/SOSTransportMessage.h> 5#include <SecureObjectSync/SOSCoder.h> 6#include <SecureObjectSync/SOSAccount.h> 7#include <SecureObjectSync/SOSAccountPriv.h> 8#include <SecureObjectSync/SOSEngine.h> 9 10#include <utilities/debugging.h> 11#include <utilities/SecCFWrappers.h> 12 13#include <AssertMacros.h> 14#include <SOSInternal.h> 15 16 17// For now transport (the abstract class) consumes the Transport data in engine to hold 18// coder state. 19static SOSCoderRef SOSTransportMessageCopyPeerCoder(SOSTransportMessageRef transport, CFStringRef peer_id){ 20 SOSCoderRef coder = NULL; 21 22 CFDataRef coderData = SOSEngineGetTransportData(SOSTransportMessageGetEngine(transport), peer_id); 23 24 if (coderData) { 25 CFErrorRef localError = NULL; 26 coder = SOSCoderCreateFromData(coderData, &localError); 27 28 if (!coder) { 29 secerror("Failed to make coder from valid data for peer %@ (%@). THIS IS FATAL, WE CAN'T COMMUNICATE.", peer_id, localError); 30 } 31 32 CFReleaseNull(localError); 33 } 34 else 35 secerror("Failed to get coderData from engine for peer %@. THIS IS FATAL, WE CAN'T COMMUNICATE.", peer_id); 36 37 return coder; 38} 39 40bool SOSTransportMessageSavePeerCoderData(SOSTransportMessageRef transport, SOSCoderRef coder, CFStringRef peer_id, CFErrorRef *error) { 41 CFDataRef coderData = NULL; 42 bool ok = true; 43 44 if (coder) { 45 coderData = SOSCoderCopyDER(coder, error); 46 if (coderData == NULL) { 47 secerror("%@ coder data failed to export %@, zapping data", transport, error ? *error : 0); 48 } 49 } 50 require_action_quiet(coderData, exit, ok = SOSErrorCreate(kSOSErrorAllocationFailure, error, NULL, CFSTR("Creation of coder data failed"))); 51 52 ok = SOSEngineSetTransportData(SOSTransportMessageGetEngine(transport), peer_id, coderData, error); 53 54exit: 55 CFReleaseNull(coderData); 56 return ok; 57} 58 59bool SOSTransportCoderInitializeForPeer(SOSTransportMessageRef transport, SOSFullPeerInfoRef myPeerInfo, SOSPeerInfoRef peerInfo, CFErrorRef *error){ 60 SOSCoderRef coder = NULL; 61 CFStringRef peer_id = SOSPeerInfoGetPeerID(peerInfo); 62 CFDataRef coderData = SOSEngineGetTransportData(SOSTransportMessageGetEngine(transport), peer_id); 63 if(coderData != NULL) { 64 CFErrorRef coderError = NULL; 65 coder = SOSCoderCreateFromData(coderData, &coderError); 66 67 if (!coder) { 68 secerror("Found data but couldn't make coder for %@: %@", peer_id, coderError); 69 } 70 CFReleaseNull(coderError); 71 } 72 73 bool haveGoodCoder = coder; 74 if (!haveGoodCoder) { 75 secnotice("transport", "New coder for id %@.", peer_id); 76 coder = SOSCoderCreate(peerInfo, myPeerInfo, error); 77 78 if (coder) { 79 haveGoodCoder = SOSTransportMessageSavePeerCoderData(transport, coder, peer_id, error); 80 } else { 81 secerror("Couldn't make coder for %@", peer_id); 82 } 83 } 84 85 if (coder) 86 SOSCoderDispose(coder); 87 return haveGoodCoder; 88} 89 90enum SOSCoderUnwrapStatus SOSTransportMessageHandleCoderMessage(SOSTransportMessageRef transport, CFStringRef peer_id, CFDataRef codedMessage, CFDataRef *decodedMessage, CFErrorRef *error){ 91 92 enum SOSCoderUnwrapStatus result = SOSCoderUnwrapError; 93 CFMutableDataRef localDecodedMessage = NULL; 94 95 SOSCoderStatus coderStatus = kSOSCoderDataReturned; 96 SOSCoderRef coder = SOSTransportMessageCopyPeerCoder(transport, peer_id); 97 if(!coder){ 98 SOSAccountEnsurePeerRegistration(SOSTransportMessageGetAccount(transport), error); 99 coder = SOSTransportMessageCopyPeerCoder(transport, peer_id); 100 secnotice("transport", "Building new coder!"); 101 } 102 CFErrorRef localError = NULL; 103 if (coder) { 104 coderStatus = SOSCoderUnwrap(coder, codedMessage, &localDecodedMessage, peer_id, error); 105 106 switch(coderStatus) { 107 case kSOSCoderDataReturned: { 108 logRawMessage(localDecodedMessage, false, 0); 109 result = SOSCoderUnwrapDecoded; 110 break; 111 } 112 case kSOSCoderNegotiating: // Sent message already in Unwrap. 113 result = SOSCoderUnwrapHandled; 114 secnotice("transport", "%@ transport negotiating", peer_id); 115 break; 116 case kSOSCoderNegotiationCompleted: 117 if(SOSEnginePeerDidConnect(SOSTransportMessageGetEngine(transport), peer_id, error)) 118 result = SOSCoderUnwrapHandled; 119 secnotice("transport", "%@ transport negotiation complete", peer_id); 120 break; 121 case kSOSCoderFailure: // Probably restart coder 122 secnotice("transport", "%@ transport failed handling message %@", peer_id, error ? *error : NULL); 123 SOSCoderReset(coder); 124 if(SOSCoderStart(coder, &localError) == kSOSCoderFailure){ 125 secerror("Attempt to recover coder failed to restart: %@", localError); 126 } 127 break; 128 case kSOSCoderStaleEvent: // We received an event we have already processed in the past. 129 secnotice("transport", "%@ transport stale event ignored", peer_id); 130 break; 131 default: 132 assert(false); 133 break; 134 } 135 if(decodedMessage) 136 *decodedMessage = CFRetainSafe(localDecodedMessage); 137 CFReleaseNull(localDecodedMessage); 138 139 SOSTransportMessageSavePeerCoderData(transport, coder, peer_id, NULL); 140 SOSCoderDispose(coder); 141 } 142 else{ 143 secerror("SOSTransportMessageHandleCoderMessage: Could not make a new coder!"); 144 } 145 146 CFReleaseNull(localError); 147 148 return result; 149 150} 151 152#warning this should be SOSTransportMessage and be split up into coder/message pieces 153/* Send a message to peer if needed. Return false if there was an error, true otherwise. */ 154bool SOSTransportMessageSendMessageIfNeeded(SOSTransportMessageRef transport, CFStringRef circle_id, CFStringRef peer_id, CFErrorRef *error) { 155 SOSCoderRef coder = SOSTransportMessageCopyPeerCoder(transport, peer_id); 156 157 if(!coder){ 158 SOSAccountEnsurePeerRegistration(SOSTransportMessageGetAccount(transport), error); 159 coder = SOSTransportMessageCopyPeerCoder(transport, peer_id); 160 } 161 CFDataRef message_to_send = NULL; 162 bool ok = false; 163 SOSEnginePeerMessageSentBlock sent = NULL; 164 165 require_action_quiet(coder, fail, SOSCreateError(kSOSErrorAllocationFailure, CFSTR("SOSTransportMessageCopyPeerCoder failed"), *error, error)); 166 167 if (SOSCoderCanWrap(coder)) { 168 secnotice("transport", "%@ Coder can wrap, getting message from engine", peer_id); 169 CFMutableDataRef codedMessage = NULL; 170 CFDataRef message = SOSEngineCreateMessageToSyncToPeer(SOSTransportMessageGetEngine(transport), peer_id, &sent, error); 171 if (!message) { 172 secnotice("transport", "%@ SOSEngineCreateMessageToSyncToPeer failed: %@",peer_id, *error); 173 } 174 ok = message && (SOSCoderWrap(coder, message, &codedMessage, peer_id, error) == kSOSCoderDataReturned); 175 if (!ok) { 176 secnotice("transport", "%@ SOSCoderWrap failed: %@",peer_id, *error); 177 } 178 179 if (ok) 180 CFRetainAssign(message_to_send, codedMessage); 181 182 CFReleaseNull(codedMessage); 183 CFReleaseNull(message); 184 } else { 185 message_to_send = SOSCoderCopyPendingResponse(coder); 186 secnotice("transport", "%@ Negotiating, %@", peer_id, message_to_send ? CFSTR("Sending negotiation message.") : CFSTR("waiting for negotiation message.")); 187 sent = Block_copy(^(bool wasSent){ 188 if (wasSent) 189 SOSCoderConsumeResponse(coder); 190 }); 191 ok = true; 192 } 193 194 if (message_to_send) { 195 CFDictionaryRef peer_dict = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, 196 peer_id, message_to_send, 197 NULL); 198 CFDictionaryRef circle_peers = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, 199 circle_id, peer_dict, 200 NULL); 201 202 ok = ok && SOSTransportMessageSendMessages(transport, circle_peers, error); 203 204 if (sent) 205 sent(ok); 206 207 CFReleaseSafe(peer_dict); 208 CFReleaseSafe(circle_peers); 209 } 210 211 Block_release(sent); 212 213 CFReleaseSafe(message_to_send); 214 215 SOSTransportMessageSavePeerCoderData(transport, coder, peer_id, NULL); 216 217fail: 218 if (coder) 219 SOSCoderDispose(coder); 220 return ok; 221} 222