1 #include <Security/SecureObjectSync/SOSTransport.h>
2 #include <Security/SecureObjectSync/SOSTransportMessage.h>
3 #include <Security/SecureObjectSync/SOSTransportMessageIDS.h>
4 #include <Security/SecureObjectSync/SOSKVSKeys.h>
5 #include <Security/SecureObjectSync/SOSPeerCoder.h>
6 #include <Security/SecureObjectSync/SOSEngine.h>
7 #include <utilities/SecCFWrappers.h>
8 #include <SOSInternal.h>
9 #include <Security/SecureObjectSync/SOSAccountPriv.h>
10 #include <SOSCloudKeychainClient.h>
11 #include <securityd/SecItemServer.h> // TODO: Remove this layer violation.
13 CFGiblisWithHashFor(SOSTransportMessage
);
15 SOSTransportMessageRef
SOSTransportMessageCreateForSubclass(size_t size
,
16 SOSAccountRef account
, CFStringRef circleName
,
19 SOSTransportMessageRef tpt
= CFTypeAllocateWithSpace(SOSTransportMessage
, size
, kCFAllocatorDefault
);
21 SOSEngineRef engine
= SOSDataSourceFactoryGetEngineForDataSourceName(account
->factory
, circleName
, error
);
23 tpt
->engine
= CFRetainSafe(engine
);
24 tpt
->account
= CFRetainSafe(account
);
25 tpt
->circleName
= CFRetainSafe(circleName
);
30 static CFStringRef
SOSTransportMessageCopyFormatDescription(CFTypeRef aObj
, CFDictionaryRef formatOptions
){
31 SOSTransportMessageRef t
= (SOSTransportMessageRef
) aObj
;
33 return t
->copyDescription
? t
->copyDescription(t
)
34 : CFStringCreateWithFormat(NULL
, NULL
, CFSTR("<SOSTransportMessage@%p\n>"), t
);
37 static void SOSTransportMessageDestroy(CFTypeRef aObj
){
38 SOSTransportMessageRef transport
= (SOSTransportMessageRef
) aObj
;
40 if (transport
->destroy
)
41 transport
->destroy(transport
);
43 CFReleaseSafe(transport
->account
);
46 CFStringRef
SOSTransportMessageGetCircleName(SOSTransportMessageRef transport
){
47 return transport
->circleName
;
50 CFIndex
SOSTransportMessageGetTransportType(SOSTransportMessageRef transport
, CFErrorRef
*error
){
51 return transport
->getTransportType
? transport
->getTransportType(transport
, error
) : kUnknown
;
55 SOSAccountRef
SOSTransportMessageGetAccount(SOSTransportMessageRef transport
){
56 return transport
->account
;
59 static CFHashCode
SOSTransportMessageHash(CFTypeRef obj
){
60 return (intptr_t) obj
;
63 static Boolean
SOSTransportMessageCompare(CFTypeRef lhs
, CFTypeRef rhs
){
64 return SOSTransportMessageHash(lhs
) == SOSTransportMessageHash(rhs
);
67 bool SOSTransportMessageSendMessage(SOSTransportMessageRef transport
, CFStringRef peerID
, CFDataRef message
, CFErrorRef
*error
) {
68 CFDictionaryRef peerMessage
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
, peerID
, message
, NULL
);
70 bool result
= SOSTransportMessageSendMessages(transport
, peerMessage
, error
);
72 CFReleaseNull(peerMessage
);
76 bool SOSTransportMessageSendMessages(SOSTransportMessageRef transport
, CFDictionaryRef peer_messages
, CFErrorRef
*error
) {
77 return transport
->sendMessages(transport
, peer_messages
, error
);
80 bool SOSTransportMessageFlushChanges(SOSTransportMessageRef transport
, CFErrorRef
*error
){
81 return transport
->flushChanges(transport
, error
);
84 bool SOSTransportMessageSyncWithPeers(SOSTransportMessageRef transport
, CFSetRef peers
, CFErrorRef
*error
){
85 return transport
->syncWithPeers(transport
, peers
, error
);
88 bool SOSTransportMessageCleanupAfterPeerMessages(SOSTransportMessageRef transport
, CFDictionaryRef circleToPeerIDs
, CFErrorRef
* error
){
89 return transport
->cleanupAfterPeerMessages(transport
, circleToPeerIDs
, error
);
93 CFDictionaryRef
SOSTransportMessageHandleMessages(SOSTransportMessageRef transport
, CFMutableDictionaryRef circle_peer_messages_table
, CFErrorRef
*error
){
94 return transport
->handleMessages(transport
, circle_peer_messages_table
, error
);
97 SOSEngineRef
SOSTransportMessageGetEngine(SOSTransportMessageRef transport
) {
98 return transport
->engine
;
101 static bool SOSEngineHandleCodedMessage(SOSEngineRef engine
, CFStringRef peerID
, CFDataRef codedMessage
, CFErrorRef
*error
) {
102 __block
bool result
= true;
103 __block
bool somethingChanged
= false;
105 result
&= SOSEngineWithPeerID(engine
, peerID
, error
, ^(SOSPeerRef peer
, SOSCoderRef coder
, SOSDataSourceRef dataSource
, SOSTransactionRef txn
, bool *shouldSave
) {
106 CFDataRef decodedMessage
= NULL
;
107 enum SOSCoderUnwrapStatus uwstatus
= SOSPeerHandleCoderMessage(peer
, coder
, peerID
, codedMessage
, &decodedMessage
, shouldSave
, error
);
108 if (uwstatus
== SOSCoderUnwrapDecoded
) {
109 SOSMessageRef message
= NULL
;
110 if (decodedMessage
&& CFDataGetLength(decodedMessage
)) {
111 // Only hand non empty messages to the engine, empty messages are an artifact
113 message
= SOSMessageCreateWithData(kCFAllocatorDefault
, decodedMessage
, error
);
116 bool engineHandleMessageDoesNotGetToRollbackTransactions
= true;
117 result
= SOSEngineHandleMessage_locked(engine
, peerID
, message
, txn
, &engineHandleMessageDoesNotGetToRollbackTransactions
, &somethingChanged
, error
);
118 CFReleaseSafe(message
);
121 result
= uwstatus
!= SOSCoderUnwrapError
;
123 CFReleaseNull(decodedMessage
);
126 if (somethingChanged
) {
127 SecKeychainChanged();
131 SOSCCRequestSyncWithPeer(peerID
);
137 bool SOSTransportMessageHandlePeerMessage(SOSTransportMessageRef transport
, CFStringRef peerID
, CFDataRef codedMessage
, CFErrorRef
*error
) {
139 SOSEngineRef engine
= SOSTransportMessageGetEngine(transport
);
140 require_quiet(SecRequirementError(engine
!= NULL
, error
, CFSTR("Missing engine")), done
);
142 result
= SOSEngineHandleCodedMessage(engine
, peerID
, codedMessage
, error
);
148 bool SOSTransportMessageSendMessageIfNeeded(SOSTransportMessageRef transport
, CFStringRef circle_id
, CFStringRef peer_id
, CFErrorRef
*error
) {
149 __block
bool ok
= true;
150 SOSEngineRef engine
= SOSTransportMessageGetEngine(transport
);
152 ok
&= SOSEngineWithPeerID(engine
, peer_id
, error
, ^(SOSPeerRef peer
, SOSCoderRef coder
, SOSDataSourceRef dataSource
, SOSTransactionRef txn
, bool *forceSaveState
) {
153 // Now under engine lock do stuff
154 CFDataRef message_to_send
= NULL
;
155 SOSEnginePeerMessageSentBlock sent
= NULL
;
156 ok
= SOSPeerCoderSendMessageIfNeeded(engine
, txn
, peer
, coder
, &message_to_send
, peer_id
, &sent
, error
);
157 if (message_to_send
) {
158 ok
= ok
&& SOSTransportMessageSendMessage(transport
, peer_id
, message_to_send
, error
);
160 SOSPeerCoderConsume(&sent
, ok
);
162 secnotice("transport", "no message to send to peer: %@", peer_id
);
166 CFReleaseSafe(message_to_send
);
168 *forceSaveState
= ok
;