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 <utilities/debugging.h>
15 #include <utilities/SecCFWrappers.h>
16 #include <CoreFoundation/CFBase.h>
18 CFStringRef kKeyParameter
= CFSTR("KeyParameter");
19 CFStringRef kCircle
= CFSTR("Circle");
20 CFStringRef kMessage
= CFSTR("Message");
21 CFStringRef kAlwaysKeys
= CFSTR("AlwaysKeys");
22 CFStringRef kFirstUnlocked
= CFSTR("FirstUnlockKeys");
23 CFStringRef kUnlocked
= CFSTR("UnlockedKeys");
24 extern CFStringRef kSOSAccountDebugScope
;
26 #define DATE_LENGTH 18
28 CFStringRef
SOSInterestListCopyDescription(CFArrayRef interests
)
30 CFMutableStringRef description
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
31 CFStringAppendFormat(description
, NULL
, CFSTR("<Interest: "));
34 CFArrayForEach(interests
, ^(const void* string
) {
37 CFStringAppendFormat(description
, NULL
, CFSTR(" '%@'"), string
);
40 CFStringAppend(description
, CFSTR(">"));
47 // MARK: Key Interest Processing
50 CFGiblisGetSingleton(CFMutableArrayRef
, SOSGetTransportMessages
, sTransportMessages
, ^{
51 *sTransportMessages
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, NULL
);
54 CFGiblisGetSingleton(CFMutableArrayRef
, SOSGetTransportKeyParameters
, sTransportKeyParameters
, ^{
55 *sTransportKeyParameters
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, NULL
);
58 CFGiblisGetSingleton(CFMutableArrayRef
, SOSGetTransportCircles
, sTransportCircles
, ^{
59 *sTransportCircles
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, NULL
);
63 void SOSRegisterTransportMessage(SOSTransportMessageRef additional
) {
64 CFArrayAppendValue(SOSGetTransportMessages(), additional
);
67 void SOSUnregisterTransportMessage(SOSTransportMessageRef removal
) {
68 CFArrayRemoveAllValue(SOSGetTransportMessages(), removal
);
71 void SOSUnregisterAllTransportMessages() {
72 CFArrayRemoveAllValues(SOSGetTransportMessages());
75 void SOSRegisterTransportCircle(SOSTransportCircleRef additional
) {
76 CFArrayAppendValue(SOSGetTransportCircles(), additional
);
79 void SOSUnregisterTransportCircle(SOSTransportCircleRef removal
) {
80 CFArrayRemoveAllValue(SOSGetTransportCircles(), removal
);
83 void SOSUnregisterAllTransportCircles() {
84 CFArrayRemoveAllValues(SOSGetTransportCircles());
87 void SOSRegisterTransportKeyParameter(SOSTransportKeyParameterRef additional
) {
88 CFArrayAppendValue(SOSGetTransportKeyParameters(), additional
);
91 void SOSUnregisterTransportKeyParameter(SOSTransportKeyParameterRef removal
) {
92 CFArrayRemoveAllValue(SOSGetTransportKeyParameters(), removal
);
95 void SOSUnregisterAllTransportKeyParameters() {
96 CFArrayRemoveAllValues(SOSGetTransportKeyParameters());
100 // Should we be dispatching back to our queue to handle later
102 void SOSUpdateKeyInterest(SOSAccountRef account
)
104 CFMutableArrayRef alwaysKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
105 CFMutableArrayRef afterFirstUnlockKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
106 CFMutableArrayRef whenUnlockedKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
107 CFMutableDictionaryRef keyDict
= CFDictionaryCreateMutableForCFTypes (kCFAllocatorDefault
);
109 CFArrayForEach(SOSGetTransportKeyParameters(), ^(const void *value
) {
110 SOSTransportKeyParameterRef tKP
= (SOSTransportKeyParameterRef
) value
;
111 if (SOSTransportKeyParameterGetAccount(tKP
) == account
&& SOSTransportKeyParameterGetTransportType(tKP
, NULL
) == kKVS
) {
112 SOSTransportKeyParameterKVSRef tkvs
= (SOSTransportKeyParameterKVSRef
) value
;
113 CFErrorRef localError
= NULL
;
115 if (!SOSTransportKeyParameterKVSAppendKeyInterests(tkvs
, alwaysKeys
, afterFirstUnlockKeys
, whenUnlockedKeys
, &localError
)) {
116 secerror("Error getting key parameters interests %@", localError
);
118 CFReleaseNull(localError
);
121 CFMutableDictionaryRef keyParamsDict
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
122 CFDictionarySetValue(keyParamsDict
, kAlwaysKeys
, alwaysKeys
);
123 CFDictionarySetValue(keyParamsDict
, kFirstUnlocked
, afterFirstUnlockKeys
);
124 CFDictionarySetValue(keyParamsDict
, kUnlocked
, whenUnlockedKeys
);
125 CFDictionarySetValue(keyDict
, kKeyParameter
, keyParamsDict
);
127 CFReleaseNull(alwaysKeys
);
128 CFReleaseNull(afterFirstUnlockKeys
);
129 CFReleaseNull(whenUnlockedKeys
);
130 alwaysKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
131 afterFirstUnlockKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
132 whenUnlockedKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
134 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value
) {
135 if (SOSTransportCircleGetAccount((SOSTransportCircleRef
)value
) == account
&& SOSTransportCircleGetTransportType((SOSTransportCircleRef
)value
, NULL
) == kKVS
) {
136 SOSTransportCircleKVSRef tkvs
= (SOSTransportCircleKVSRef
) value
;
137 CFErrorRef localError
= NULL
;
139 if(!SOSTransportCircleKVSAppendKeyInterest(tkvs
, alwaysKeys
, afterFirstUnlockKeys
, whenUnlockedKeys
, &localError
)){
140 secerror("Error getting circle interests %@", localError
);
142 if(!SOSTransportCircleKVSAppendPeerInfoKeyInterest(tkvs
, alwaysKeys
, afterFirstUnlockKeys
, whenUnlockedKeys
, &localError
)){
143 secerror("Error getting peer info interests %@", localError
);
145 if(!SOSTransportCircleKVSAppendRingKeyInterest(tkvs
, alwaysKeys
, afterFirstUnlockKeys
, whenUnlockedKeys
, &localError
)){
146 secerror("Error getting ring interests %@", localError
);
148 if(!SOSTransportCircleKVSAppendDebugKeyInterest(tkvs
, alwaysKeys
, afterFirstUnlockKeys
, whenUnlockedKeys
, &localError
)){
149 secerror("Error getting debug key interests %@", localError
);
151 CFReleaseNull(localError
);
155 CFMutableDictionaryRef circleDict
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
156 CFDictionarySetValue(circleDict
, kAlwaysKeys
, alwaysKeys
);
157 CFDictionarySetValue(circleDict
, kFirstUnlocked
, afterFirstUnlockKeys
);
158 CFDictionarySetValue(circleDict
, kUnlocked
, whenUnlockedKeys
);
159 CFDictionarySetValue(keyDict
, kCircle
, circleDict
);
161 CFReleaseNull(alwaysKeys
);
162 CFReleaseNull(afterFirstUnlockKeys
);
163 CFReleaseNull(whenUnlockedKeys
);
164 alwaysKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
165 afterFirstUnlockKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
166 whenUnlockedKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
168 CFArrayForEach(SOSGetTransportMessages(), ^(const void *value
) {
169 if (SOSTransportMessageGetAccount((SOSTransportMessageRef
) value
) == account
&& SOSTransportMessageGetTransportType((SOSTransportMessageRef
) value
, NULL
) == kKVS
) {
170 SOSTransportMessageKVSRef tkvs
= (SOSTransportMessageKVSRef
) value
;
171 CFErrorRef localError
= NULL
;
173 if(!SOSTransportMessageKVSAppendKeyInterest(tkvs
, alwaysKeys
, afterFirstUnlockKeys
, whenUnlockedKeys
, &localError
)){
174 secerror("Error getting message interests %@", localError
);
176 CFReleaseNull(localError
);
180 CFMutableDictionaryRef messageDict
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
181 CFDictionarySetValue(messageDict
, kAlwaysKeys
, alwaysKeys
);
182 CFDictionarySetValue(messageDict
, kFirstUnlocked
, afterFirstUnlockKeys
);
183 CFDictionarySetValue(messageDict
, kUnlocked
, whenUnlockedKeys
);
184 CFDictionarySetValue(keyDict
, kMessage
, messageDict
);
187 // Log what we are about to do.
189 secnotice("key-interests", "Updating interests: %@", keyDict
);
191 SOSCloudKeychainUpdateKeys(keyDict
, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^(CFDictionaryRef returnedValues
, CFErrorRef error
) {
193 secerror("Error updating keys: %@", error
);
197 CFReleaseNull(alwaysKeys
);
198 CFReleaseNull(afterFirstUnlockKeys
);
199 CFReleaseNull(whenUnlockedKeys
);
200 CFReleaseNull(keyParamsDict
);
201 CFReleaseNull(circleDict
);
202 CFReleaseNull(messageDict
);
203 CFReleaseNull(keyDict
);
207 static void showWhatWasHandled(CFDictionaryRef updates
, CFMutableArrayRef handledKeys
) {
209 CFMutableStringRef updateStr
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
210 CFMutableStringRef handledKeysStr
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
212 CFDictionaryForEach(updates
, ^(const void *key
, const void *value
) {
214 CFStringAppendFormat(updateStr
, NULL
, CFSTR("%@ "), (CFStringRef
)key
);
217 CFArrayForEach(handledKeys
, ^(const void *value
) {
218 if (isString(value
)) {
219 CFStringAppendFormat(handledKeysStr
, NULL
, CFSTR("%@ "), (CFStringRef
)value
);
222 secinfo("updates", "Updates [%ld]: %@", CFDictionaryGetCount(updates
), updateStr
);
223 secinfo("updates", "Handled [%ld]: %@", CFArrayGetCount(handledKeys
), handledKeysStr
);
225 CFReleaseSafe(updateStr
);
226 CFReleaseSafe(handledKeysStr
);
230 CFMutableArrayRef
SOSTransportDispatchMessages(SOSAccountRef account
, CFDictionaryRef updates
, CFErrorRef
*error
){
232 CFMutableArrayRef handledKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
234 if(CFDictionaryContainsKey(updates
, kSOSKVSAccountChangedKey
)){
235 secnotice("accountChange", "SOSTransportDispatchMessages received kSOSKVSAccountChangedKey");
236 // While changing accounts we may modify the key params array. To avoid stepping on ourselves we
237 // copy the list for iteration. Now modifying the transport outside of the list iteration.
238 __block SOSTransportKeyParameterRef tempTransport
= NULL
;
239 CFMutableArrayRef originalKeyParams
= CFArrayCreateMutableCopy(kCFAllocatorDefault
, CFArrayGetCount(SOSGetTransportKeyParameters()), SOSGetTransportKeyParameters());
241 tempTransport
= NULL
;
242 CFArrayForEach(originalKeyParams
, ^(const void *value
) {
243 SOSTransportKeyParameterRef transport
= (SOSTransportKeyParameterRef
) value
;
244 if(CFEqualSafe(SOSTransportKeyParameterGetAccount(transport
), account
)){
245 tempTransport
= transport
;
248 if(tempTransport
!= NULL
){
249 SOSTransportKeyParameterHandleNewAccount(tempTransport
, account
);
250 CFStringRef dsid
= NULL
;
251 if(CFDictionaryGetValueIfPresent(updates
, kSOSKVSAccountChangedKey
, (const void**)&dsid
)){
253 CFStringRef accountDSID
= (CFStringRef
)SOSAccountGetValue(account
, kSOSDSIDKey
, error
);
255 if(accountDSID
== NULL
){
256 SOSAccountSetValue(account
, kSOSDSIDKey
, dsid
, error
);
257 secdebug("dsid", "Assigning new DSID: %@", dsid
);
259 else if(accountDSID
!= NULL
&& CFStringCompare(accountDSID
, dsid
, 0) != 0 ){
260 SOSAccountSetValue(account
, kSOSDSIDKey
, dsid
, error
);
261 secdebug("dsid", "Assigning new DSID: %@", dsid
);
264 secdebug("dsid", "DSIDs are the same!");
267 CFArrayRemoveAllValue(originalKeyParams
, tempTransport
);
269 }while(tempTransport
!= NULL
);
270 CFArrayAppendValue(handledKeys
, kSOSKVSAccountChangedKey
);
271 CFReleaseNull(originalKeyParams
);
276 // Iterate through keys in updates. Perform circle change update.
277 // Then instantiate circles and engines and peers for all peers that
278 // are receiving a message in updates.
279 CFMutableDictionaryRef circle_peer_messages_table
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
280 CFMutableDictionaryRef circle_circle_messages_table
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
281 CFMutableDictionaryRef circle_retirement_messages_table
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
282 CFMutableDictionaryRef ring_update_message_table
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
283 CFMutableDictionaryRef peer_info_message_table
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
284 CFMutableDictionaryRef debug_info_message_table
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
286 __block CFDataRef newParameters
= NULL
;
287 __block
bool initial_sync
= false;
288 __block
bool new_account
= false;
290 CFDictionaryForEach(updates
, ^(const void *key
, const void *value
) {
291 CFErrorRef localError
= NULL
;
292 CFStringRef circle_name
= NULL
;
293 CFStringRef ring_name
= NULL
;
294 CFStringRef peer_info_name
= NULL
;
295 CFStringRef from_name
= NULL
;
296 CFStringRef to_name
= NULL
;
297 CFStringRef backup_name
= NULL
;
299 switch (SOSKVSKeyGetKeyTypeAndParse(key
, &circle_name
, &peer_info_name
, &ring_name
, &backup_name
, &from_name
, &to_name
)) {
301 CFDictionarySetValue(circle_circle_messages_table
, circle_name
, value
);
303 case kInitialSyncKey
:
308 newParameters
= (CFDataRef
) CFRetainSafe(value
);
312 CFMutableDictionaryRef circle_messages
= CFDictionaryEnsureCFDictionaryAndGetCurrentValue(circle_peer_messages_table
, circle_name
);
313 CFDictionarySetValue(circle_messages
, from_name
, value
);
316 case kRetirementKey
: {
317 CFMutableDictionaryRef circle_retirements
= CFDictionaryEnsureCFDictionaryAndGetCurrentValue(circle_retirement_messages_table
, circle_name
);
318 CFDictionarySetValue(circle_retirements
, from_name
, value
);
321 case kAccountChangedKey
:
325 CFDictionarySetValue(peer_info_message_table
, peer_info_name
, value
);
328 if(isString(ring_name
))
329 CFDictionarySetValue(ring_update_message_table
, ring_name
, value
);
332 CFDictionarySetValue(debug_info_message_table
, peer_info_name
, value
);
335 case kLastKeyParameterKey
:
337 secnotice("updates", "Unknown key '%@', ignoring", key
);
342 CFReleaseNull(circle_name
);
343 CFReleaseNull(from_name
);
344 CFReleaseNull(to_name
);
345 CFReleaseNull(ring_name
);
346 CFReleaseNull(peer_info_name
);
347 CFReleaseNull(backup_name
);
350 secerror("Peer message processing error for: %@ -> %@ (%@)", key
, value
, *error
);
352 secerror("Peer message local processing error for: %@ -> %@ (%@)", key
, value
, localError
);
354 CFReleaseNull(localError
);
359 CFArrayForEach(SOSGetTransportKeyParameters(), ^(const void *value
) {
360 SOSTransportKeyParameterRef tkvs
= (SOSTransportKeyParameterRef
) value
;
361 CFErrorRef localError
= NULL
;
362 if(CFEqualSafe(SOSTransportKeyParameterGetAccount(tkvs
), account
)){
363 if(!SOSTransportKeyParameterHandleKeyParameterChanges(tkvs
, newParameters
, localError
))
364 secerror("Transport failed to handle new key parameters: %@", localError
);
367 CFArrayAppendValue(handledKeys
, kSOSKVSKeyParametersKey
);
369 CFReleaseNull(newParameters
);
372 CFArrayAppendValue(handledKeys
, kSOSKVSInitialSyncKey
);
375 if(CFDictionaryGetCount(debug_info_message_table
)) {
376 /* check for a newly set circle debug scope */
377 CFTypeRef debugScope
= CFDictionaryGetValue(debug_info_message_table
, kSOSAccountDebugScope
);
379 if(isString(debugScope
)){
380 ApplyScopeListForID(debugScope
, kScopeIDCircle
);
381 }else if(isDictionary(debugScope
)){
382 ApplyScopeDictionaryForID(debugScope
, kScopeIDCircle
);
385 CFStringRef debugInfoKey
= SOSDebugInfoKeyCreateWithTypeName(kSOSAccountDebugScope
);
386 CFArrayAppendValue(handledKeys
, debugInfoKey
);
387 CFReleaseNull(debugInfoKey
);
390 if(CFDictionaryGetCount(circle_retirement_messages_table
)) {
391 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value
) {
392 SOSTransportCircleRef tkvs
= (SOSTransportCircleRef
) value
;
393 if(CFEqualSafe(SOSTransportCircleGetAccount((SOSTransportCircleRef
)value
), account
)){
394 CFErrorRef localError
= NULL
;
395 CFDictionaryRef handledRetirementKeys
= SOSTransportCircleHandleRetirementMessages(tkvs
, circle_retirement_messages_table
, error
);
396 if(handledRetirementKeys
== NULL
){
397 secerror("Transport failed to handle retirement messages: %@", localError
);
399 CFDictionaryForEach(handledRetirementKeys
, ^(const void *key
, const void *value
) {
400 CFStringRef circle_name
= (CFStringRef
)key
;
401 CFArrayRef handledPeerIDs
= (CFArrayRef
)value
;
402 CFArrayForEach(handledPeerIDs
, ^(const void *value
) {
403 CFStringRef peer_id
= (CFStringRef
)value
;
404 CFStringRef keyHandled
= SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name
, peer_id
);
405 CFArrayAppendValue(handledKeys
, keyHandled
);
406 CFReleaseNull(keyHandled
);
410 CFReleaseNull(handledRetirementKeys
);
411 CFReleaseNull(localError
);
415 if(CFDictionaryGetCount(peer_info_message_table
)){
416 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value
) {
417 SOSTransportCircleRef tkvs
= (SOSTransportCircleRef
) value
;
418 if(CFEqualSafe(SOSTransportCircleGetAccount((SOSTransportCircleRef
)value
), account
)){
419 CFErrorRef localError
= NULL
;
420 CFArrayRef handledPeerInfoMessages
= SOSTransportCircleKVSHandlePeerInfoV2Messages(tkvs
, peer_info_message_table
, error
);
421 if(handledPeerInfoMessages
== NULL
){
422 secerror("Transport failed to handle peer info messages: %@", localError
);
424 CFArrayForEach(handledPeerInfoMessages
, ^(const void *value
) {
425 CFStringRef peer_id
= (CFStringRef
)value
;
426 CFStringRef keyHandled
= SOSPeerInfoV2KeyCreateWithPeerName(peer_id
);
427 CFArrayAppendValue(handledKeys
, keyHandled
);
428 CFReleaseNull(keyHandled
);
431 CFReleaseNull(handledPeerInfoMessages
);
432 CFReleaseNull(localError
);
436 if(CFDictionaryGetCount(circle_peer_messages_table
)) {
437 CFArrayForEach(SOSGetTransportMessages(), ^(const void *value
) {
438 SOSTransportMessageRef tkvs
= (SOSTransportMessageRef
) value
;
439 if(SOSTransportMessageGetTransportType(tkvs
, error
) != kIDS
){
440 if(CFEqualSafe(SOSTransportMessageGetAccount((SOSTransportMessageRef
)value
), account
)){
441 CFErrorRef handleMessagesError
= NULL
;
442 CFDictionaryRef handledPeers
= SOSTransportMessageHandleMessages(account
->kvs_message_transport
, circle_peer_messages_table
, &handleMessagesError
);
445 // We need to look for and send responses.
446 SOSAccountSyncWithAllPeers(account
, error
);
448 CFDictionaryForEach(handledPeers
, ^(const void *key
, const void *value
) {
449 if (isString(key
) && isArray(value
)) {
450 CFArrayForEach(value
, ^(const void *value
) {
451 if (isString(value
)) {
452 CFStringRef peerID
= (CFStringRef
) value
;
454 CFStringRef kvsHandledKey
= SOSMessageKeyCreateFromPeerToTransport((SOSTransportMessageKVSRef
)account
->kvs_message_transport
, peerID
);
455 CFArrayAppendValue(handledKeys
, kvsHandledKey
);
456 CFReleaseSafe(kvsHandledKey
);
461 CFErrorRef flushError
= NULL
;
462 if (!SOSTransportMessageFlushChanges((SOSTransportMessageRef
)account
->kvs_message_transport
, &flushError
)) {
463 secerror("Flush failed: %@", flushError
);
467 secerror("Didn't handle? : %@", handleMessagesError
);
469 CFReleaseNull(handledPeers
);
470 CFReleaseNull(handleMessagesError
);
476 if(CFDictionaryGetCount(circle_circle_messages_table
)) {
477 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value
) {
478 SOSTransportCircleRef tkvs
= (SOSTransportCircleRef
) value
;
479 if(CFEqualSafe(SOSTransportCircleGetAccount((SOSTransportCircleRef
)value
), account
)){
480 CFArrayRef handleCircleMessages
= SOSTransportCircleHandleCircleMessages(tkvs
, circle_circle_messages_table
, error
);
481 CFErrorRef localError
= NULL
;
482 if(handleCircleMessages
== NULL
){
483 secerror("Transport failed to handle circle messages: %@", localError
);
484 } else if(CFArrayGetCount(handleCircleMessages
) == 0) {
485 if(CFDictionaryGetCount(circle_circle_messages_table
) != 0) {
486 secerror("Transport failed to process all circle messages: (%ld/%ld) %@",
487 CFArrayGetCount(handleCircleMessages
),
488 CFDictionaryGetCount(circle_circle_messages_table
), localError
);
490 secnotice("circle", "Transport handled no circle messages");
493 CFArrayForEach(handleCircleMessages
, ^(const void *value
) {
494 CFStringRef keyHandled
= SOSCircleKeyCreateWithName((CFStringRef
)value
, error
);
495 CFArrayAppendValue(handledKeys
, keyHandled
);
496 CFReleaseNull(keyHandled
);
500 CFReleaseNull(localError
);
501 CFReleaseNull(handleCircleMessages
);
506 if(CFDictionaryGetCount(ring_update_message_table
)){
507 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value
) {
508 if(CFEqualSafe(SOSTransportCircleGetAccount((SOSTransportCircleRef
)value
), account
)){
509 CFErrorRef localError
= NULL
;
510 CFMutableArrayRef handledRingMessages
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
512 CFDictionaryForEach(ring_update_message_table
, ^(const void *key
, const void *value
) {
513 CFDataRef ringData
= (CFDataRef
)value
;
514 SOSRingRef ring
= SOSRingCreateFromData(error
, ringData
);
516 if(SOSAccountUpdateRingFromRemote(account
, ring
, error
)){
517 CFArrayAppendValue(handledRingMessages
, key
);
521 if(CFArrayGetCount(handledRingMessages
) == 0){
522 secerror("Transport failed to handle ring messages: %@", localError
);
524 CFArrayForEach(handledRingMessages
, ^(const void *value
) {
525 CFStringRef ring_name
= (CFStringRef
)value
;
526 CFStringRef keyHandled
= SOSRingKeyCreateWithRingName(ring_name
);
527 CFArrayAppendValue(handledKeys
, keyHandled
);
528 CFReleaseNull(keyHandled
);
531 CFReleaseNull(handledRingMessages
);
532 CFReleaseNull(localError
);
537 CFReleaseNull(circle_retirement_messages_table
);
538 CFReleaseNull(circle_circle_messages_table
);
539 CFReleaseNull(circle_peer_messages_table
);
540 CFReleaseNull(debug_info_message_table
);
541 CFReleaseNull(ring_update_message_table
);
542 CFReleaseNull(peer_info_message_table
);
543 CFReleaseNull(debug_info_message_table
);
545 showWhatWasHandled(updates
, handledKeys
);