2 #include <Security/SecureObjectSync/SOSPeer.h>
3 #include <Security/SecureObjectSync/SOSTransportCoder.h>
4 #include <Security/SecureObjectSync/SOSTransportMessage.h>
5 #include <Security/SecureObjectSync/SOSCoder.h>
6 #include <Security/SecureObjectSync/SOSAccount.h>
7 #include <Security/SecureObjectSync/SOSAccountPriv.h>
8 #include <Security/SecureObjectSync/SOSEngine.h>
10 #include <utilities/debugging.h>
11 #include <utilities/SecCFWrappers.h>
13 #include <AssertMacros.h>
14 #include <SOSInternal.h>
17 // For now transport (the abstract class) consumes the Transport data in engine to hold
19 static SOSCoderRef
SOSTransportMessageCopyPeerCoder(SOSTransportMessageRef transport
, CFStringRef peer_id
){
20 SOSCoderRef coder
= NULL
;
22 CFDataRef coderData
= SOSEngineGetCoderData(SOSTransportMessageGetEngine(transport
), peer_id
);
25 CFErrorRef localError
= NULL
;
26 coder
= SOSCoderCreateFromData(coderData
, &localError
);
29 secerror("Failed to make coder from valid data for peer %@ (%@). THIS IS FATAL: WE CAN'T COMMUNICATE.", peer_id
, localError
);
32 CFReleaseNull(localError
);
35 secerror("Failed to get coderData from engine for peer %@. THIS IS FATAL: WE CAN'T COMMUNICATE.", peer_id
);
40 bool SOSTransportMessageSavePeerCoderData(SOSTransportMessageRef transport
, SOSCoderRef coder
, CFStringRef peer_id
, CFErrorRef
*error
) {
41 CFDataRef coderData
= NULL
;
45 coderData
= SOSCoderCopyDER(coder
, error
);
46 if (coderData
== NULL
) {
47 secerror("%@ coder data failed to export %@, zapping data", transport
, error
? *error
: 0);
50 require_action_quiet(coderData
, exit
, ok
= SOSErrorCreate(kSOSErrorAllocationFailure
, error
, NULL
, CFSTR("Creation of coder data failed")));
52 ok
= SOSEngineSetCoderData(SOSTransportMessageGetEngine(transport
), peer_id
, coderData
, error
);
55 CFReleaseNull(coderData
);
59 bool SOSTransportCoderInitializeForPeer(SOSTransportMessageRef transport
, SOSFullPeerInfoRef myPeerInfo
, SOSPeerInfoRef peerInfo
, CFErrorRef
*error
){
60 SOSCoderRef coder
= NULL
;
61 CFStringRef peer_id
= SOSPeerInfoGetPeerID(peerInfo
);
62 CFDataRef coderData
= SOSEngineGetCoderData(SOSTransportMessageGetEngine(transport
), peer_id
);
63 if(coderData
!= NULL
) {
64 CFErrorRef coderError
= NULL
;
65 coder
= SOSCoderCreateFromData(coderData
, &coderError
);
68 secerror("Found data but couldn't make coder for %@: %@", peer_id
, coderError
);
70 CFReleaseNull(coderError
);
73 bool haveGoodCoder
= coder
;
75 secnotice("transport", "New coder for id %@.", peer_id
);
76 if(SOSPeerInfoShouldUseIDSTransport(SOSFullPeerInfoGetPeerInfo(myPeerInfo
), peerInfo
))
77 coder
= SOSCoderCreate(peerInfo
, myPeerInfo
, kCFBooleanTrue
, error
);
79 coder
= SOSCoderCreate(peerInfo
, myPeerInfo
, kCFBooleanFalse
, error
);
81 haveGoodCoder
= SOSTransportMessageSavePeerCoderData(transport
, coder
, peer_id
, error
);
83 secerror("Couldn't make coder for %@", peer_id
);
88 SOSCoderDispose(coder
);
92 enum SOSCoderUnwrapStatus
SOSTransportMessageHandleCoderMessage(SOSTransportMessageRef transport
, CFStringRef peer_id
, CFDataRef codedMessage
, CFDataRef
*decodedMessage
, CFErrorRef
*error
){
94 enum SOSCoderUnwrapStatus result
= SOSCoderUnwrapError
;
95 CFMutableDataRef localDecodedMessage
= NULL
;
97 SOSCoderStatus coderStatus
= kSOSCoderDataReturned
;
98 SOSCoderRef coder
= SOSTransportMessageCopyPeerCoder(transport
, peer_id
);
100 SOSAccountEnsurePeerRegistration(SOSTransportMessageGetAccount(transport
), error
);
101 coder
= SOSTransportMessageCopyPeerCoder(transport
, peer_id
);
102 secnotice("transport", "Building new coder!");
104 CFErrorRef localError
= NULL
;
106 coderStatus
= SOSCoderUnwrap(coder
, codedMessage
, &localDecodedMessage
, peer_id
, error
);
108 switch(coderStatus
) {
109 case kSOSCoderDataReturned
: {
110 logRawMessage(localDecodedMessage
, false, 0);
111 result
= SOSCoderUnwrapDecoded
;
114 case kSOSCoderNegotiating
: // Sent message already in Unwrap.
115 result
= SOSCoderUnwrapHandled
;
116 secnotice("transport", "%@ transport negotiating", peer_id
);
118 case kSOSCoderNegotiationCompleted
:
119 if (SOSEnginePeerDidConnect(SOSTransportMessageGetEngine(transport
), peer_id
, error
))
120 result
= SOSCoderUnwrapHandled
;
121 secnotice("transport", "%@ transport negotiation complete", peer_id
);
123 case kSOSCoderFailure
: // Probably restart coder
124 secnotice("transport", "%@ transport failed handling message %@", peer_id
, error
? *error
: NULL
);
125 SOSCoderReset(coder
);
126 if (SOSCoderStart(coder
, &localError
) == kSOSCoderFailure
) {
127 secerror("Attempt to recover coder failed to restart: %@", localError
);
130 case kSOSCoderStaleEvent
: // We received an event we have already processed in the past.
131 result
= SOSCoderUnwrapHandled
;
132 secinfo("transport", "%@ transport stale event ignored", peer_id
);
134 case kSOSCoderTooNew
: //We received an event from the future!
135 secnotice("transport", "%@ transport received a message too soon, time to restart", peer_id
);
136 SOSCoderReset(coder
);
137 if(SOSCoderStart(coder
, &localError
) == kSOSCoderFailure
){
138 secerror("Attempt to recover coder failed to restart: %@", localError
);
146 *decodedMessage
= CFRetainSafe(localDecodedMessage
);
147 CFReleaseNull(localDecodedMessage
);
149 SOSTransportMessageSavePeerCoderData(transport
, coder
, peer_id
, NULL
);
150 SOSCoderDispose(coder
);
152 secerror("SOSTransportMessageHandleCoderMessage: Could not make a new coder!");
155 CFReleaseNull(localError
);
160 // TODO: This should be SOSTransportMessage and be split up into coder/message pieces
161 /* Send a message to peer if needed. Return false if there was an error, true otherwise. */
162 bool SOSTransportMessageSendMessageIfNeeded(SOSTransportMessageRef transport
, CFStringRef circle_id
, CFStringRef peer_id
, CFErrorRef
*error
) {
163 SOSCoderRef coder
= SOSTransportMessageCopyPeerCoder(transport
, peer_id
);
166 SOSAccountEnsurePeerRegistration(SOSTransportMessageGetAccount(transport
), error
);
167 coder
= SOSTransportMessageCopyPeerCoder(transport
, peer_id
);
169 CFDataRef message_to_send
= NULL
;
171 SOSEnginePeerMessageSentBlock sent
= NULL
;
173 require_action_quiet(coder
, fail
, SOSCreateError(kSOSErrorAllocationFailure
, CFSTR("SOSTransportMessageCopyPeerCoder failed"), *error
, error
));
175 if (SOSCoderCanWrap(coder
)) {
176 secinfo("transport", "%@ Coder can wrap, getting message from engine", peer_id
);
177 CFMutableDataRef codedMessage
= NULL
;
178 CFDataRef message
= SOSEngineCreateMessageToSyncToPeer(SOSTransportMessageGetEngine(transport
), peer_id
, &sent
, error
);
180 secnotice("transport", "%@ SOSEngineCreateMessageToSyncToPeer failed: %@",peer_id
, *error
);
182 ok
= message
&& (SOSCoderWrap(coder
, message
, &codedMessage
, peer_id
, error
) == kSOSCoderDataReturned
);
184 secnotice("transport", "%@ SOSCoderWrap failed: %@",peer_id
, *error
);
188 CFRetainAssign(message_to_send
, codedMessage
);
190 CFReleaseNull(codedMessage
);
191 CFReleaseNull(message
);
193 message_to_send
= SOSCoderCopyPendingResponse(coder
);
194 secinfo("transport", "%@ negotiating, %@", peer_id
, message_to_send
? CFSTR("sending negotiation message.") : CFSTR("waiting for negotiation message."));
195 sent
= Block_copy(^(bool wasSent
){
197 SOSCoderConsumeResponse(coder
);
202 if (message_to_send
) {
203 CFDictionaryRef peer_dict
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
204 peer_id
, message_to_send
,
206 CFDictionaryRef circle_peers
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
207 circle_id
, peer_dict
,
210 ok
= ok
&& SOSTransportMessageSendMessages(transport
, circle_peers
, error
);
215 CFReleaseSafe(peer_dict
);
216 CFReleaseSafe(circle_peers
);
221 CFReleaseSafe(message_to_send
);
223 SOSTransportMessageSavePeerCoderData(transport
, coder
, peer_id
, NULL
);
227 SOSCoderDispose(coder
);