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 CFStringRef uuid
= SOSAccountCopyUUID(account
);
192 SOSCloudKeychainUpdateKeys(keyDict
, uuid
, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0), ^(CFDictionaryRef returnedValues
, CFErrorRef error
) {
194 secerror("Error updating keys: %@", error
);
199 CFReleaseNull(alwaysKeys
);
200 CFReleaseNull(afterFirstUnlockKeys
);
201 CFReleaseNull(whenUnlockedKeys
);
202 CFReleaseNull(keyParamsDict
);
203 CFReleaseNull(circleDict
);
204 CFReleaseNull(messageDict
);
205 CFReleaseNull(keyDict
);
209 static void showWhatWasHandled(CFDictionaryRef updates
, CFMutableArrayRef handledKeys
) {
211 CFMutableStringRef updateStr
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
212 CFMutableStringRef handledKeysStr
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
214 CFDictionaryForEach(updates
, ^(const void *key
, const void *value
) {
216 CFStringAppendFormat(updateStr
, NULL
, CFSTR("%@ "), (CFStringRef
)key
);
219 CFArrayForEach(handledKeys
, ^(const void *value
) {
220 if (isString(value
)) {
221 CFStringAppendFormat(handledKeysStr
, NULL
, CFSTR("%@ "), (CFStringRef
)value
);
224 secinfo("updates", "Updates [%ld]: %@", CFDictionaryGetCount(updates
), updateStr
);
225 secinfo("updates", "Handled [%ld]: %@", CFArrayGetCount(handledKeys
), handledKeysStr
);
227 CFReleaseSafe(updateStr
);
228 CFReleaseSafe(handledKeysStr
);
231 #define KVS_STATE_INTERVAL 50
234 CFMutableArrayRef
SOSTransportDispatchMessages(SOSAccountTransactionRef txn
, CFDictionaryRef updates
, CFErrorRef
*error
){
235 SOSAccountRef account
= txn
->account
;
237 CFMutableArrayRef handledKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
238 CFStringRef dsid
= NULL
;
240 if(CFDictionaryGetValueIfPresent(updates
, kSOSKVSAccountChangedKey
, (const void**)&dsid
)){
241 secnotice("accountChange", "SOSTransportDispatchMessages received kSOSKVSAccountChangedKey");
243 // While changing accounts we may modify the key params array. To avoid stepping on ourselves we
244 // copy the list for iteration. Now modifying the transport outside of the list iteration.
245 CFMutableArrayRef transportsToUse
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
247 CFArrayForEach(SOSGetTransportKeyParameters(), ^(const void *value
) {
248 SOSTransportKeyParameterRef transport
= (SOSTransportKeyParameterRef
) value
;
249 if(CFEqualSafe(SOSTransportKeyParameterGetAccount(transport
), account
)){
250 CFArrayAppendValue(transportsToUse
, transport
);
255 CFArrayForEach(transportsToUse
, ^(const void *value
) {
256 SOSTransportKeyParameterRef tempTransport
= (SOSTransportKeyParameterRef
) value
;
258 CFStringRef accountDSID
= (CFStringRef
)SOSAccountGetValue(account
, kSOSDSIDKey
, error
);
260 if(accountDSID
== NULL
){
261 SOSTransportKeyParameterHandleNewAccount(tempTransport
, account
);
262 SOSAccountSetValue(account
, kSOSDSIDKey
, dsid
, error
);
263 secdebug("dsid", "Assigning new DSID: %@", dsid
);
264 } else if(accountDSID
!= NULL
&& CFStringCompare(accountDSID
, dsid
, 0) != 0 ) {
265 SOSTransportKeyParameterHandleNewAccount(tempTransport
, account
);
266 SOSAccountSetValue(account
, kSOSDSIDKey
, dsid
, error
);
267 secdebug("dsid", "Assigning new DSID: %@", dsid
);
269 secdebug("dsid", "DSIDs are the same!");
273 CFReleaseNull(transportsToUse
);
275 CFArrayAppendValue(handledKeys
, kSOSKVSAccountChangedKey
);
279 // Iterate through keys in updates. Perform circle change update.
280 // Then instantiate circles and engines and peers for all peers that
281 // are receiving a message in updates.
282 CFMutableDictionaryRef circle_peer_messages_table
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
283 CFMutableDictionaryRef circle_circle_messages_table
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
284 CFMutableDictionaryRef circle_retirement_messages_table
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
285 CFMutableDictionaryRef ring_update_message_table
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
286 CFMutableDictionaryRef peer_info_message_table
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
287 CFMutableDictionaryRef debug_info_message_table
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
289 __block CFDataRef newParameters
= NULL
;
290 __block
bool initial_sync
= false;
291 __block
bool new_account
= false;
293 CFDictionaryForEach(updates
, ^(const void *key
, const void *value
) {
294 CFErrorRef localError
= NULL
;
295 CFStringRef circle_name
= NULL
;
296 CFStringRef ring_name
= NULL
;
297 CFStringRef peer_info_name
= NULL
;
298 CFStringRef from_name
= NULL
;
299 CFStringRef to_name
= NULL
;
300 CFStringRef backup_name
= NULL
;
302 require_quiet(isString(key
), errOut
);
303 switch (SOSKVSKeyGetKeyTypeAndParse(key
, &circle_name
, &peer_info_name
, &ring_name
, &backup_name
, &from_name
, &to_name
)) {
305 CFDictionarySetValue(circle_circle_messages_table
, circle_name
, value
);
307 case kInitialSyncKey
:
312 newParameters
= (CFDataRef
) CFRetainSafe(value
);
316 CFMutableDictionaryRef circle_messages
= CFDictionaryEnsureCFDictionaryAndGetCurrentValue(circle_peer_messages_table
, circle_name
);
317 CFDictionarySetValue(circle_messages
, from_name
, value
);
320 case kRetirementKey
: {
321 CFMutableDictionaryRef circle_retirements
= CFDictionaryEnsureCFDictionaryAndGetCurrentValue(circle_retirement_messages_table
, circle_name
);
322 CFDictionarySetValue(circle_retirements
, from_name
, value
);
325 case kAccountChangedKey
:
329 CFDictionarySetValue(peer_info_message_table
, peer_info_name
, value
);
332 if(isString(ring_name
))
333 CFDictionarySetValue(ring_update_message_table
, ring_name
, value
);
336 CFDictionarySetValue(debug_info_message_table
, peer_info_name
, value
);
339 case kLastKeyParameterKey
:
341 secnotice("updates", "Unknown key '%@', ignoring", key
);
347 CFReleaseNull(circle_name
);
348 CFReleaseNull(from_name
);
349 CFReleaseNull(to_name
);
350 CFReleaseNull(ring_name
);
351 CFReleaseNull(peer_info_name
);
352 CFReleaseNull(backup_name
);
355 secerror("Peer message processing error for: %@ -> %@ (%@)", key
, value
, *error
);
357 secerror("Peer message local processing error for: %@ -> %@ (%@)", key
, value
, localError
);
359 CFReleaseNull(localError
);
364 CFArrayForEach(SOSGetTransportKeyParameters(), ^(const void *value
) {
365 SOSTransportKeyParameterRef tkvs
= (SOSTransportKeyParameterRef
) value
;
366 CFErrorRef localError
= NULL
;
367 if(CFEqualSafe(SOSTransportKeyParameterGetAccount(tkvs
), account
)){
368 if(!SOSTransportKeyParameterHandleKeyParameterChanges(tkvs
, newParameters
, localError
))
369 secerror("Transport failed to handle new key parameters: %@", localError
);
372 CFArrayAppendValue(handledKeys
, kSOSKVSKeyParametersKey
);
374 CFReleaseNull(newParameters
);
377 CFArrayAppendValue(handledKeys
, kSOSKVSInitialSyncKey
);
380 if(CFDictionaryGetCount(debug_info_message_table
)) {
381 /* check for a newly set circle debug scope */
382 CFTypeRef debugScope
= CFDictionaryGetValue(debug_info_message_table
, kSOSAccountDebugScope
);
384 if(isString(debugScope
)){
385 ApplyScopeListForID(debugScope
, kScopeIDCircle
);
386 }else if(isDictionary(debugScope
)){
387 ApplyScopeDictionaryForID(debugScope
, kScopeIDCircle
);
390 CFStringRef debugInfoKey
= SOSDebugInfoKeyCreateWithTypeName(kSOSAccountDebugScope
);
391 CFArrayAppendValue(handledKeys
, debugInfoKey
);
392 CFReleaseNull(debugInfoKey
);
395 if(CFDictionaryGetCount(circle_retirement_messages_table
)) {
396 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value
) {
397 SOSTransportCircleRef tkvs
= (SOSTransportCircleRef
) value
;
398 if(CFEqualSafe(SOSTransportCircleGetAccount((SOSTransportCircleRef
)value
), account
)){
399 CFErrorRef localError
= NULL
;
400 CFDictionaryRef handledRetirementKeys
= SOSTransportCircleHandleRetirementMessages(tkvs
, circle_retirement_messages_table
, error
);
401 if(handledRetirementKeys
== NULL
){
402 secerror("Transport failed to handle retirement messages: %@", localError
);
404 CFDictionaryForEach(handledRetirementKeys
, ^(const void *key
, const void *value
) {
405 CFStringRef circle_name
= (CFStringRef
)key
;
406 CFArrayRef handledPeerIDs
= (CFArrayRef
)value
;
407 CFArrayForEach(handledPeerIDs
, ^(const void *value
) {
408 CFStringRef peer_id
= (CFStringRef
)value
;
409 CFStringRef keyHandled
= SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name
, peer_id
);
410 CFArrayAppendValue(handledKeys
, keyHandled
);
411 CFReleaseNull(keyHandled
);
415 CFReleaseNull(handledRetirementKeys
);
416 CFReleaseNull(localError
);
420 if(CFDictionaryGetCount(peer_info_message_table
)){
421 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value
) {
422 SOSTransportCircleRef tkvs
= (SOSTransportCircleRef
) value
;
423 if(CFEqualSafe(SOSTransportCircleGetAccount((SOSTransportCircleRef
)value
), account
)){
424 CFErrorRef localError
= NULL
;
425 CFArrayRef handledPeerInfoMessages
= SOSTransportCircleKVSHandlePeerInfoV2Messages(tkvs
, peer_info_message_table
, error
);
426 if(handledPeerInfoMessages
== NULL
){
427 secerror("Transport failed to handle peer info messages: %@", localError
);
429 CFArrayForEach(handledPeerInfoMessages
, ^(const void *value
) {
430 CFStringRef peer_id
= (CFStringRef
)value
;
431 CFStringRef keyHandled
= SOSPeerInfoV2KeyCreateWithPeerName(peer_id
);
432 CFArrayAppendValue(handledKeys
, keyHandled
);
433 CFReleaseNull(keyHandled
);
436 CFReleaseNull(handledPeerInfoMessages
);
437 CFReleaseNull(localError
);
441 if(CFDictionaryGetCount(circle_peer_messages_table
)) {
442 CFArrayForEach(SOSGetTransportMessages(), ^(const void *value
) {
443 SOSTransportMessageRef tmsg
= (SOSTransportMessageRef
) value
;
444 CFDictionaryRef circleToPeersHandled
= NULL
;
445 CFErrorRef handleMessagesError
= NULL
;
446 CFErrorRef flushError
= NULL
;
448 require_quiet(CFEqualSafe(SOSTransportMessageGetAccount(tmsg
), account
), done
);
450 circleToPeersHandled
= SOSTransportMessageHandleMessages(tmsg
, circle_peer_messages_table
, &handleMessagesError
);
451 require_action_quiet(circleToPeersHandled
, done
, secnotice("msg", "No messages handled: %@", handleMessagesError
));
453 CFArrayRef handledPeers
= asArray(CFDictionaryGetValue(circleToPeersHandled
, SOSTransportMessageGetCircleName(tmsg
)), NULL
);
456 CFArrayForEach(handledPeers
, ^(const void *value
) {
457 CFStringRef peerID
= asString(value
, NULL
);
460 CFStringRef kvsHandledKey
= SOSMessageKeyCreateFromPeerToTransport(tmsg
, peerID
);
462 CFArrayAppendValue(handledKeys
, kvsHandledKey
);
464 CFReleaseNull(kvsHandledKey
);
469 require_action_quiet(SOSTransportMessageFlushChanges(tmsg
, &flushError
), done
, secnotice("msg", "Flush failed: %@", flushError
););
472 CFReleaseNull(flushError
);
473 CFReleaseNull(circleToPeersHandled
);
474 CFReleaseNull(handleMessagesError
);
477 if(CFDictionaryGetCount(circle_circle_messages_table
)) {
478 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value
) {
479 SOSTransportCircleRef tkvs
= (SOSTransportCircleRef
) value
;
480 if(CFEqualSafe(SOSTransportCircleGetAccount((SOSTransportCircleRef
)value
), account
)){
481 CFArrayRef handleCircleMessages
= SOSTransportCircleHandleCircleMessages(tkvs
, circle_circle_messages_table
, error
);
482 CFErrorRef localError
= NULL
;
483 if(handleCircleMessages
== NULL
){
484 secerror("Transport failed to handle circle messages: %@", localError
);
485 } else if(CFArrayGetCount(handleCircleMessages
) == 0) {
486 if(CFDictionaryGetCount(circle_circle_messages_table
) != 0) {
487 secerror("Transport failed to process all circle messages: (%ld/%ld) %@",
488 CFArrayGetCount(handleCircleMessages
),
489 CFDictionaryGetCount(circle_circle_messages_table
), localError
);
491 secnotice("circle", "Transport handled no circle messages");
494 CFArrayForEach(handleCircleMessages
, ^(const void *value
) {
495 CFStringRef keyHandled
= SOSCircleKeyCreateWithName((CFStringRef
)value
, error
);
496 CFArrayAppendValue(handledKeys
, keyHandled
);
497 CFReleaseNull(keyHandled
);
501 CFReleaseNull(localError
);
502 CFReleaseNull(handleCircleMessages
);
507 if(CFDictionaryGetCount(ring_update_message_table
)){
508 CFArrayForEach(SOSGetTransportCircles(), ^(const void *value
) {
509 if(CFEqualSafe(SOSTransportCircleGetAccount((SOSTransportCircleRef
)value
), account
)){
510 CFErrorRef localError
= NULL
;
511 CFMutableArrayRef handledRingMessages
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
513 CFDictionaryForEach(ring_update_message_table
, ^(const void *key
, const void *value
) {
514 CFDataRef ringData
= asData(value
, NULL
);
515 SOSRingRef ring
= SOSRingCreateFromData(error
, ringData
);
517 if(SOSAccountUpdateRingFromRemote(account
, ring
, error
)){
518 CFArrayAppendValue(handledRingMessages
, key
);
522 if(CFArrayGetCount(handledRingMessages
) == 0){
523 secerror("Transport failed to handle ring messages: %@", localError
);
525 CFArrayForEach(handledRingMessages
, ^(const void *value
) {
526 CFStringRef ring_name
= (CFStringRef
)value
;
527 CFStringRef keyHandled
= SOSRingKeyCreateWithRingName(ring_name
);
528 CFArrayAppendValue(handledKeys
, keyHandled
);
529 CFReleaseNull(keyHandled
);
532 CFReleaseNull(handledRingMessages
);
533 CFReleaseNull(localError
);
538 CFReleaseNull(circle_retirement_messages_table
);
539 CFReleaseNull(circle_circle_messages_table
);
540 CFReleaseNull(circle_peer_messages_table
);
541 CFReleaseNull(debug_info_message_table
);
542 CFReleaseNull(ring_update_message_table
);
543 CFReleaseNull(peer_info_message_table
);
544 CFReleaseNull(debug_info_message_table
);
546 showWhatWasHandled(updates
, handledKeys
);