2 #include <Security/SecureObjectSync/SOSInternal.h>
3 #include <Security/SecureObjectSync/SOSKVSKeys.h>
4 #include <Security/SecureObjectSync/SOSAccountPriv.h>
5 #include <Security/SecureObjectSync/SOSTransport.h>
6 #include <Security/SecureObjectSync/SOSTransportKeyParameterKVS.h>
7 #include <Security/SecureObjectSync/SOSTransportCircleKVS.h>
8 #include <Security/SecureObjectSync/SOSTransportMessageKVS.h>
9 #include <Security/SecureObjectSync/SOSTransportMessageIDS.h>
10 #include <Security/SecureObjectSync/SOSTransportMessage.h>
11 #include <Security/SecureObjectSync/SOSRing.h>
13 #include <SOSCloudKeychainClient.h>
14 #include <SOSCloudKeychainLogging.h>
15 #include <utilities/debugging.h>
16 #include <utilities/SecCFWrappers.h>
17 #include <CoreFoundation/CFBase.h>
19 CFStringRef kKeyParameter
= CFSTR("KeyParameter");
20 CFStringRef kCircle
= CFSTR("Circle");
21 CFStringRef kMessage
= CFSTR("Message");
22 CFStringRef kAlwaysKeys
= CFSTR("AlwaysKeys");
23 CFStringRef kFirstUnlocked
= CFSTR("FirstUnlockKeys");
24 CFStringRef kUnlocked
= CFSTR("UnlockedKeys");
25 extern CFStringRef kSOSAccountDebugScope
;
27 #define DATE_LENGTH 18
29 CFStringRef
SOSInterestListCopyDescription(CFArrayRef interests
)
31 CFMutableStringRef description
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
32 CFStringAppendFormat(description
, NULL
, CFSTR("<Interest: "));
35 CFArrayForEach(interests
, ^(const void* string
) {
38 CFStringAppendFormat(description
, NULL
, CFSTR(" '%@'"), string
);
41 CFStringAppend(description
, CFSTR(">"));
48 // MARK: Key Interest Processing
51 CFGiblisGetSingleton(CFMutableArrayRef
, SOSGetTransportMessages
, sTransportMessages
, ^{
52 *sTransportMessages
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, NULL
);
55 CFGiblisGetSingleton(CFMutableArrayRef
, SOSGetTransportKeyParameters
, sTransportKeyParameters
, ^{
56 *sTransportKeyParameters
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, NULL
);
59 CFGiblisGetSingleton(CFMutableArrayRef
, SOSGetTransportCircles
, sTransportCircles
, ^{
60 *sTransportCircles
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, NULL
);
64 void SOSRegisterTransportMessage(SOSTransportMessageRef additional
) {
65 CFArrayAppendValue(SOSGetTransportMessages(), additional
);
68 void SOSUnregisterTransportMessage(SOSTransportMessageRef removal
) {
69 CFArrayRemoveAllValue(SOSGetTransportMessages(), removal
);
72 void SOSUnregisterAllTransportMessages() {
73 CFArrayRemoveAllValues(SOSGetTransportMessages());
76 void SOSRegisterTransportCircle(SOSTransportCircleRef additional
) {
77 CFArrayAppendValue(SOSGetTransportCircles(), additional
);
80 void SOSUnregisterTransportCircle(SOSTransportCircleRef removal
) {
81 CFArrayRemoveAllValue(SOSGetTransportCircles(), removal
);
84 void SOSUnregisterAllTransportCircles() {
85 CFArrayRemoveAllValues(SOSGetTransportCircles());
88 void SOSRegisterTransportKeyParameter(SOSTransportKeyParameterRef additional
) {
89 CFArrayAppendValue(SOSGetTransportKeyParameters(), additional
);
92 void SOSUnregisterTransportKeyParameter(SOSTransportKeyParameterRef removal
) {
93 CFArrayRemoveAllValue(SOSGetTransportKeyParameters(), removal
);
96 void SOSUnregisterAllTransportKeyParameters() {
97 CFArrayRemoveAllValues(SOSGetTransportKeyParameters());
101 // Should we be dispatching back to our queue to handle later
103 void SOSUpdateKeyInterest(SOSAccountRef account
)
105 CFMutableArrayRef alwaysKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
106 CFMutableArrayRef afterFirstUnlockKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
107 CFMutableArrayRef whenUnlockedKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
108 CFMutableDictionaryRef keyDict
= CFDictionaryCreateMutableForCFTypes (kCFAllocatorDefault
);
110 CFArrayForEach(SOSGetTransportKeyParameters(), ^(const void *value
) {
111 SOSTransportKeyParameterRef tKP
= (SOSTransportKeyParameterRef
) value
;
112 if (SOSTransportKeyParameterGetAccount(tKP
) == account
&& SOSTransportKeyParameterGetTransportType(tKP
, NULL
) == kKVS
) {
113 SOSTransportKeyParameterKVSRef tkvs
= (SOSTransportKeyParameterKVSRef
) value
;
114 CFErrorRef localError
= NULL
;
116 if (!SOSTransportKeyParameterKVSAppendKeyInterests(tkvs
, alwaysKeys
, afterFirstUnlockKeys
, whenUnlockedKeys
, &localError
)) {
117 secerror("Error getting key parameters interests %@", localError
);
119 CFReleaseNull(localError
);
122 CFMutableDictionaryRef keyParamsDict
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
123 CFDictionarySetValue(keyParamsDict
, kAlwaysKeys
, alwaysKeys
);
124 CFDictionarySetValue(keyParamsDict
, kFirstUnlocked
, afterFirstUnlockKeys
);
125 CFDictionarySetValue(keyParamsDict
, kUnlocked
, whenUnlockedKeys
);
126 CFDictionarySetValue(keyDict
, kKeyParameter
, keyParamsDict
);
128 CFReleaseNull(alwaysKeys
);
129 CFReleaseNull(afterFirstUnlockKeys
);
130 CFReleaseNull(whenUnlockedKeys
);
131 alwaysKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
132 afterFirstUnlockKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
133 whenUnlockedKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
135 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value
) {
136 if (SOSTransportCircleGetAccount((SOSTransportCircleRef
)value
) == account
&& SOSTransportCircleGetTransportType((SOSTransportCircleRef
)value
, NULL
) == kKVS
) {
137 SOSTransportCircleKVSRef tkvs
= (SOSTransportCircleKVSRef
) value
;
138 CFErrorRef localError
= NULL
;
140 if(!SOSTransportCircleKVSAppendKeyInterest(tkvs
, alwaysKeys
, afterFirstUnlockKeys
, whenUnlockedKeys
, &localError
)){
141 secerror("Error getting circle interests %@", localError
);
143 if(!SOSTransportCircleKVSAppendPeerInfoKeyInterest(tkvs
, alwaysKeys
, afterFirstUnlockKeys
, whenUnlockedKeys
, &localError
)){
144 secerror("Error getting peer info interests %@", localError
);
146 if(!SOSTransportCircleKVSAppendRingKeyInterest(tkvs
, alwaysKeys
, afterFirstUnlockKeys
, whenUnlockedKeys
, &localError
)){
147 secerror("Error getting ring interests %@", localError
);
149 if(!SOSTransportCircleKVSAppendDebugKeyInterest(tkvs
, alwaysKeys
, afterFirstUnlockKeys
, whenUnlockedKeys
, &localError
)){
150 secerror("Error getting debug key interests %@", localError
);
152 CFReleaseNull(localError
);
156 CFMutableDictionaryRef circleDict
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
157 CFDictionarySetValue(circleDict
, kAlwaysKeys
, alwaysKeys
);
158 CFDictionarySetValue(circleDict
, kFirstUnlocked
, afterFirstUnlockKeys
);
159 CFDictionarySetValue(circleDict
, kUnlocked
, whenUnlockedKeys
);
160 CFDictionarySetValue(keyDict
, kCircle
, circleDict
);
162 CFReleaseNull(alwaysKeys
);
163 CFReleaseNull(afterFirstUnlockKeys
);
164 CFReleaseNull(whenUnlockedKeys
);
165 alwaysKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
166 afterFirstUnlockKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
167 whenUnlockedKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
169 CFArrayForEach(SOSGetTransportMessages(), ^(const void *value
) {
170 if (SOSTransportMessageGetAccount((SOSTransportMessageRef
) value
) == account
&& SOSTransportMessageGetTransportType((SOSTransportMessageRef
) value
, NULL
) == kKVS
) {
171 SOSTransportMessageKVSRef tkvs
= (SOSTransportMessageKVSRef
) value
;
172 CFErrorRef localError
= NULL
;
174 if(!SOSTransportMessageKVSAppendKeyInterest(tkvs
, alwaysKeys
, afterFirstUnlockKeys
, whenUnlockedKeys
, &localError
)){
175 secerror("Error getting message interests %@", localError
);
177 CFReleaseNull(localError
);
181 CFMutableDictionaryRef messageDict
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
182 CFDictionarySetValue(messageDict
, kAlwaysKeys
, alwaysKeys
);
183 CFDictionarySetValue(messageDict
, kFirstUnlocked
, afterFirstUnlockKeys
);
184 CFDictionarySetValue(messageDict
, kUnlocked
, whenUnlockedKeys
);
185 CFDictionarySetValue(keyDict
, kMessage
, messageDict
);
188 // Log what we are about to do.
190 secnotice("key-interests", "Updating interests: %@", keyDict
);
192 SOSCloudKeychainUpdateKeys(keyDict
, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^(CFDictionaryRef returnedValues
, CFErrorRef error
) {
194 secerror("Error updating keys: %@", error
);
198 CFReleaseNull(alwaysKeys
);
199 CFReleaseNull(afterFirstUnlockKeys
);
200 CFReleaseNull(whenUnlockedKeys
);
201 CFReleaseNull(keyParamsDict
);
202 CFReleaseNull(circleDict
);
203 CFReleaseNull(messageDict
);
204 CFReleaseNull(keyDict
);
208 static void showWhatWasHandled(CFDictionaryRef updates
, CFMutableArrayRef handledKeys
) {
210 CFMutableStringRef updateStr
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
211 CFMutableStringRef handledKeysStr
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
213 CFDictionaryForEach(updates
, ^(const void *key
, const void *value
) {
215 CFStringAppendFormat(updateStr
, NULL
, CFSTR("%@ "), (CFStringRef
)key
);
218 CFArrayForEach(handledKeys
, ^(const void *value
) {
219 if (isString(value
)) {
220 CFStringAppendFormat(handledKeysStr
, NULL
, CFSTR("%@ "), (CFStringRef
)value
);
223 secinfo("updates", "Updates [%ld]: %@", CFDictionaryGetCount(updates
), updateStr
);
224 secinfo("updates", "Handled [%ld]: %@", CFArrayGetCount(handledKeys
), handledKeysStr
);
226 CFReleaseSafe(updateStr
);
227 CFReleaseSafe(handledKeysStr
);
230 #define KVS_STATE_INTERVAL 50
233 CFMutableArrayRef
SOSTransportDispatchMessages(SOSAccountRef account
, CFDictionaryRef updates
, CFErrorRef
*error
){
234 static int KVSLogCountDown
= 0;
236 CFMutableArrayRef handledKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
237 CFStringRef dsid
= NULL
;
239 if(CFDictionaryGetValueIfPresent(updates
, kSOSKVSAccountChangedKey
, (const void**)&dsid
)){
240 secnotice("accountChange", "SOSTransportDispatchMessages received kSOSKVSAccountChangedKey");
241 KVSLogCountDown
= 0; // Get an initial check on KVS values
242 // While changing accounts we may modify the key params array. To avoid stepping on ourselves we
243 // copy the list for iteration. Now modifying the transport outside of the list iteration.
244 CFMutableArrayRef transportsToUse
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
246 CFArrayForEach(SOSGetTransportKeyParameters(), ^(const void *value
) {
247 SOSTransportKeyParameterRef transport
= (SOSTransportKeyParameterRef
) value
;
248 if(CFEqualSafe(SOSTransportKeyParameterGetAccount(transport
), account
)){
249 CFArrayAppendValue(transportsToUse
, transport
);
254 CFArrayForEach(transportsToUse
, ^(const void *value
) {
255 SOSTransportKeyParameterRef tempTransport
= (SOSTransportKeyParameterRef
) value
;
257 CFStringRef accountDSID
= (CFStringRef
)SOSAccountGetValue(account
, kSOSDSIDKey
, error
);
259 if(accountDSID
== NULL
){
260 SOSTransportKeyParameterHandleNewAccount(tempTransport
, account
);
261 SOSAccountSetValue(account
, kSOSDSIDKey
, dsid
, error
);
262 secdebug("dsid", "Assigning new DSID: %@", dsid
);
263 } else if(accountDSID
!= NULL
&& CFStringCompare(accountDSID
, dsid
, 0) != 0 ) {
264 SOSTransportKeyParameterHandleNewAccount(tempTransport
, account
);
265 SOSAccountSetValue(account
, kSOSDSIDKey
, dsid
, error
);
266 secdebug("dsid", "Assigning new DSID: %@", dsid
);
268 secdebug("dsid", "DSIDs are the same!");
272 CFReleaseNull(transportsToUse
);
274 CFArrayAppendValue(handledKeys
, kSOSKVSAccountChangedKey
);
278 // Iterate through keys in updates. Perform circle change update.
279 // Then instantiate circles and engines and peers for all peers that
280 // are receiving a message in updates.
281 CFMutableDictionaryRef circle_peer_messages_table
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
282 CFMutableDictionaryRef circle_circle_messages_table
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
283 CFMutableDictionaryRef circle_retirement_messages_table
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
284 CFMutableDictionaryRef ring_update_message_table
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
285 CFMutableDictionaryRef peer_info_message_table
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
286 CFMutableDictionaryRef debug_info_message_table
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
288 __block CFDataRef newParameters
= NULL
;
289 __block
bool initial_sync
= false;
290 __block
bool new_account
= false;
292 CFDictionaryForEach(updates
, ^(const void *key
, const void *value
) {
293 CFErrorRef localError
= NULL
;
294 CFStringRef circle_name
= NULL
;
295 CFStringRef ring_name
= NULL
;
296 CFStringRef peer_info_name
= NULL
;
297 CFStringRef from_name
= NULL
;
298 CFStringRef to_name
= NULL
;
299 CFStringRef backup_name
= NULL
;
301 require_quiet(isString(key
), errOut
);
302 switch (SOSKVSKeyGetKeyTypeAndParse(key
, &circle_name
, &peer_info_name
, &ring_name
, &backup_name
, &from_name
, &to_name
)) {
304 CFDictionarySetValue(circle_circle_messages_table
, circle_name
, value
);
306 case kInitialSyncKey
:
311 newParameters
= (CFDataRef
) CFRetainSafe(value
);
315 CFMutableDictionaryRef circle_messages
= CFDictionaryEnsureCFDictionaryAndGetCurrentValue(circle_peer_messages_table
, circle_name
);
316 CFDictionarySetValue(circle_messages
, from_name
, value
);
319 case kRetirementKey
: {
320 CFMutableDictionaryRef circle_retirements
= CFDictionaryEnsureCFDictionaryAndGetCurrentValue(circle_retirement_messages_table
, circle_name
);
321 CFDictionarySetValue(circle_retirements
, from_name
, value
);
324 case kAccountChangedKey
:
328 CFDictionarySetValue(peer_info_message_table
, peer_info_name
, value
);
331 if(isString(ring_name
))
332 CFDictionarySetValue(ring_update_message_table
, ring_name
, value
);
335 CFDictionarySetValue(debug_info_message_table
, peer_info_name
, value
);
338 case kLastKeyParameterKey
:
340 secnotice("updates", "Unknown key '%@', ignoring", key
);
346 CFReleaseNull(circle_name
);
347 CFReleaseNull(from_name
);
348 CFReleaseNull(to_name
);
349 CFReleaseNull(ring_name
);
350 CFReleaseNull(peer_info_name
);
351 CFReleaseNull(backup_name
);
354 secerror("Peer message processing error for: %@ -> %@ (%@)", key
, value
, *error
);
356 secerror("Peer message local processing error for: %@ -> %@ (%@)", key
, value
, localError
);
358 CFReleaseNull(localError
);
363 CFArrayForEach(SOSGetTransportKeyParameters(), ^(const void *value
) {
364 SOSTransportKeyParameterRef tkvs
= (SOSTransportKeyParameterRef
) value
;
365 CFErrorRef localError
= NULL
;
366 if(CFEqualSafe(SOSTransportKeyParameterGetAccount(tkvs
), account
)){
367 if(!SOSTransportKeyParameterHandleKeyParameterChanges(tkvs
, newParameters
, localError
))
368 secerror("Transport failed to handle new key parameters: %@", localError
);
371 CFArrayAppendValue(handledKeys
, kSOSKVSKeyParametersKey
);
373 CFReleaseNull(newParameters
);
376 CFArrayAppendValue(handledKeys
, kSOSKVSInitialSyncKey
);
379 if(CFDictionaryGetCount(debug_info_message_table
)) {
380 /* check for a newly set circle debug scope */
381 CFTypeRef debugScope
= CFDictionaryGetValue(debug_info_message_table
, kSOSAccountDebugScope
);
383 if(isString(debugScope
)){
384 ApplyScopeListForID(debugScope
, kScopeIDCircle
);
385 }else if(isDictionary(debugScope
)){
386 ApplyScopeDictionaryForID(debugScope
, kScopeIDCircle
);
389 CFStringRef debugInfoKey
= SOSDebugInfoKeyCreateWithTypeName(kSOSAccountDebugScope
);
390 CFArrayAppendValue(handledKeys
, debugInfoKey
);
391 CFReleaseNull(debugInfoKey
);
394 if(CFDictionaryGetCount(circle_retirement_messages_table
)) {
395 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value
) {
396 SOSTransportCircleRef tkvs
= (SOSTransportCircleRef
) value
;
397 if(CFEqualSafe(SOSTransportCircleGetAccount((SOSTransportCircleRef
)value
), account
)){
398 CFErrorRef localError
= NULL
;
399 CFDictionaryRef handledRetirementKeys
= SOSTransportCircleHandleRetirementMessages(tkvs
, circle_retirement_messages_table
, error
);
400 if(handledRetirementKeys
== NULL
){
401 secerror("Transport failed to handle retirement messages: %@", localError
);
403 CFDictionaryForEach(handledRetirementKeys
, ^(const void *key
, const void *value
) {
404 CFStringRef circle_name
= (CFStringRef
)key
;
405 CFArrayRef handledPeerIDs
= (CFArrayRef
)value
;
406 CFArrayForEach(handledPeerIDs
, ^(const void *value
) {
407 CFStringRef peer_id
= (CFStringRef
)value
;
408 CFStringRef keyHandled
= SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name
, peer_id
);
409 CFArrayAppendValue(handledKeys
, keyHandled
);
410 CFReleaseNull(keyHandled
);
414 CFReleaseNull(handledRetirementKeys
);
415 CFReleaseNull(localError
);
419 if(CFDictionaryGetCount(peer_info_message_table
)){
420 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value
) {
421 SOSTransportCircleRef tkvs
= (SOSTransportCircleRef
) value
;
422 if(CFEqualSafe(SOSTransportCircleGetAccount((SOSTransportCircleRef
)value
), account
)){
423 CFErrorRef localError
= NULL
;
424 CFArrayRef handledPeerInfoMessages
= SOSTransportCircleKVSHandlePeerInfoV2Messages(tkvs
, peer_info_message_table
, error
);
425 if(handledPeerInfoMessages
== NULL
){
426 secerror("Transport failed to handle peer info messages: %@", localError
);
428 CFArrayForEach(handledPeerInfoMessages
, ^(const void *value
) {
429 CFStringRef peer_id
= (CFStringRef
)value
;
430 CFStringRef keyHandled
= SOSPeerInfoV2KeyCreateWithPeerName(peer_id
);
431 CFArrayAppendValue(handledKeys
, keyHandled
);
432 CFReleaseNull(keyHandled
);
435 CFReleaseNull(handledPeerInfoMessages
);
436 CFReleaseNull(localError
);
440 if(CFDictionaryGetCount(circle_peer_messages_table
)) {
441 CFArrayForEach(SOSGetTransportMessages(), ^(const void *value
) {
442 SOSTransportMessageRef tkvs
= (SOSTransportMessageRef
) value
;
444 if(SOSTransportMessageGetTransportType(tkvs
, error
) == kIDSTest
){ //this case is for the IDS test transport
445 if(CFEqualSafe(SOSTransportMessageGetAccount((SOSTransportMessageRef
)value
), account
)){
446 CFErrorRef handleMessagesError
= NULL
;
447 CFDictionaryRef handledPeers
= SOSTransportMessageHandleMessages(account
->ids_message_transport
, circle_peer_messages_table
, &handleMessagesError
);
450 // We need to look for and send responses.
451 SOSAccountSendIKSPSyncList(account
, error
);
452 SOSAccountSyncWithAllKVSPeers(account
, error
);
454 CFDictionaryForEach(handledPeers
, ^(const void *key
, const void *value
) {
455 if (isString(key
) && isArray(value
)) {
456 CFArrayForEach(value
, ^(const void *value
) {
457 if (isString(value
)) {
458 CFStringRef peerID
= (CFStringRef
) value
;
459 CFStringRef kvsHandledKey
= SOSMessageKeyCreateFromPeerToTransport(account
->ids_message_transport
, peerID
);
460 CFArrayAppendValue(handledKeys
, kvsHandledKey
);
461 CFReleaseSafe(kvsHandledKey
);
466 CFErrorRef flushError
= NULL
;
467 if (!SOSTransportMessageFlushChanges((SOSTransportMessageRef
)account
->kvs_message_transport
, &flushError
)) {
468 secerror("Flush failed: %@", flushError
);
472 secerror("Didn't handle? : %@", handleMessagesError
);
474 CFReleaseNull(handledPeers
);
475 CFReleaseNull(handleMessagesError
);
479 else if(SOSTransportMessageGetTransportType(tkvs
, error
) != kIDS
){
480 if(CFEqualSafe(SOSTransportMessageGetAccount((SOSTransportMessageRef
)value
), account
)){
481 CFErrorRef handleMessagesError
= NULL
;
482 CFDictionaryRef handledPeers
= SOSTransportMessageHandleMessages(account
->kvs_message_transport
, circle_peer_messages_table
, &handleMessagesError
);
485 // We need to look for and send responses.
486 SOSAccountSendIKSPSyncList(account
, error
);
487 SOSAccountSyncWithAllKVSPeers(account
, error
);
489 CFDictionaryForEach(handledPeers
, ^(const void *key
, const void *value
) {
490 if (isString(key
) && isArray(value
)) {
491 CFArrayForEach(value
, ^(const void *value
) {
492 if (isString(value
)) {
493 CFStringRef peerID
= (CFStringRef
) value
;
495 CFStringRef kvsHandledKey
= SOSMessageKeyCreateFromPeerToTransport(account
->kvs_message_transport
, peerID
);
496 if(kvsHandledKey
!= NULL
)
497 CFArrayAppendValue(handledKeys
, kvsHandledKey
);
498 CFReleaseSafe(kvsHandledKey
);
503 CFErrorRef flushError
= NULL
;
504 if (!SOSTransportMessageFlushChanges((SOSTransportMessageRef
)account
->kvs_message_transport
, &flushError
)) {
505 secerror("Flush failed: %@", flushError
);
509 secerror("Didn't handle? : %@", handleMessagesError
);
511 CFReleaseNull(handledPeers
);
512 CFReleaseNull(handleMessagesError
);
518 if(CFDictionaryGetCount(circle_circle_messages_table
)) {
519 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value
) {
520 SOSTransportCircleRef tkvs
= (SOSTransportCircleRef
) value
;
521 if(CFEqualSafe(SOSTransportCircleGetAccount((SOSTransportCircleRef
)value
), account
)){
522 CFArrayRef handleCircleMessages
= SOSTransportCircleHandleCircleMessages(tkvs
, circle_circle_messages_table
, error
);
523 CFErrorRef localError
= NULL
;
524 if(handleCircleMessages
== NULL
){
525 secerror("Transport failed to handle circle messages: %@", localError
);
526 } else if(CFArrayGetCount(handleCircleMessages
) == 0) {
527 if(CFDictionaryGetCount(circle_circle_messages_table
) != 0) {
528 secerror("Transport failed to process all circle messages: (%ld/%ld) %@",
529 CFArrayGetCount(handleCircleMessages
),
530 CFDictionaryGetCount(circle_circle_messages_table
), localError
);
532 secnotice("circle", "Transport handled no circle messages");
535 CFArrayForEach(handleCircleMessages
, ^(const void *value
) {
536 CFStringRef keyHandled
= SOSCircleKeyCreateWithName((CFStringRef
)value
, error
);
537 CFArrayAppendValue(handledKeys
, keyHandled
);
538 CFReleaseNull(keyHandled
);
542 CFReleaseNull(localError
);
543 CFReleaseNull(handleCircleMessages
);
548 if(CFDictionaryGetCount(ring_update_message_table
)){
549 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value
) {
550 if(CFEqualSafe(SOSTransportCircleGetAccount((SOSTransportCircleRef
)value
), account
)){
551 CFErrorRef localError
= NULL
;
552 CFMutableArrayRef handledRingMessages
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
554 CFDictionaryForEach(ring_update_message_table
, ^(const void *key
, const void *value
) {
555 CFDataRef ringData
= asData(value
, NULL
);
556 SOSRingRef ring
= SOSRingCreateFromData(error
, ringData
);
558 if(SOSAccountUpdateRingFromRemote(account
, ring
, error
)){
559 CFArrayAppendValue(handledRingMessages
, key
);
563 if(CFArrayGetCount(handledRingMessages
) == 0){
564 secerror("Transport failed to handle ring messages: %@", localError
);
566 CFArrayForEach(handledRingMessages
, ^(const void *value
) {
567 CFStringRef ring_name
= (CFStringRef
)value
;
568 CFStringRef keyHandled
= SOSRingKeyCreateWithRingName(ring_name
);
569 CFArrayAppendValue(handledKeys
, keyHandled
);
570 CFReleaseNull(keyHandled
);
573 CFReleaseNull(handledRingMessages
);
574 CFReleaseNull(localError
);
579 CFReleaseNull(circle_retirement_messages_table
);
580 CFReleaseNull(circle_circle_messages_table
);
581 CFReleaseNull(circle_peer_messages_table
);
582 CFReleaseNull(debug_info_message_table
);
583 CFReleaseNull(ring_update_message_table
);
584 CFReleaseNull(peer_info_message_table
);
585 CFReleaseNull(debug_info_message_table
);
587 if(KVSLogCountDown
<= 0) {
588 SOSCloudKVSLogState();
589 KVSLogCountDown
= KVS_STATE_INTERVAL
;
590 } else KVSLogCountDown
--;
592 showWhatWasHandled(updates
, handledKeys
);