1 #include <CoreFoundation/CoreFoundation.h>
2 #include <CoreFoundation/CFRuntime.h>
4 #include <SecureObjectSync/SOSAccount.h>
5 #include <SecureObjectSync/SOSAccountPriv.h>
6 #include <SecureObjectSync/SOSTransport.h>
7 #include <SecureObjectSync/SOSTransportKeyParameter.h>
8 #include <SecureObjectSync/SOSKVSKeys.h>
9 #include <SecureObjectSync/SOSPeerCoder.h>
10 #include <utilities/SecCFWrappers.h>
12 #include "SOSTransportTestTransports.h"
14 static bool sendToPeer(SOSTransportMessageRef transport
, CFStringRef circleName
, CFStringRef peerID
, CFDataRef message
, CFErrorRef
*error
);
15 static bool syncWithPeers(SOSTransportMessageRef transport
, CFDictionaryRef circleToPeerIDs
, CFErrorRef
*error
);
16 static bool sendMessages(SOSTransportMessageRef transport
, CFDictionaryRef circleToPeersToMessage
, CFErrorRef
*error
);
17 static bool cleanupAfterPeer(SOSTransportMessageRef transport
, CFDictionaryRef circle_to_peer_ids
, CFErrorRef
*error
);
18 static CF_RETURNS_RETAINED
19 CFDictionaryRef
handleMessages(SOSTransportMessageRef transport
, CFMutableDictionaryRef circle_peer_messages_table
, CFErrorRef
*error
);
20 static void destroyMessageTransport(SOSTransportMessageRef transport
);
21 static void SOSTransportMessageTestAddBulkToChanges(SOSTransportMessageTestRef transport
, CFDictionaryRef updates
);
23 static bool flushMessageChanges(SOSTransportMessageRef transport
, CFErrorRef
*error
);
24 static bool publishCloudParameters(SOSTransportKeyParameterRef transport
, CFDataRef data
, CFErrorRef
* error
);
25 static bool SOSTransportKeyParameterTestPublishCloudParameters(SOSTransportKeyParameterTestRef transport
, CFDataRef newParameters
, CFErrorRef
*error
);
27 static bool expireRetirementRecords(SOSTransportCircleRef transport
, CFDictionaryRef retirements
, CFErrorRef
*error
);
28 static void destroy(SOSTransportCircleRef transport
);
29 static inline bool flushChanges(SOSTransportCircleRef transport
, CFErrorRef
*error
);
30 static bool postCircle(SOSTransportCircleRef transport
, CFStringRef circleName
, CFDataRef circle_data
, CFErrorRef
*error
);
31 static inline bool postRetirement(SOSTransportCircleRef transport
, CFStringRef circleName
, CFStringRef peer_id
, CFDataRef retirement_data
, CFErrorRef
*error
);
32 static bool handleKeyParameterChanges(SOSTransportKeyParameterRef transport
, CFDataRef data
, CFErrorRef error
);
34 static CFArrayRef
handleCircleMessages(SOSTransportCircleRef transport
, CFMutableDictionaryRef circle_circle_messages_table
, CFErrorRef
*error
);
35 static CFDictionaryRef
handleRetirementMessages(SOSTransportCircleRef transport
, CFMutableDictionaryRef circle_retirement_messages_table
, CFErrorRef
*error
);
36 static bool setToNewAccount(SOSTransportKeyParameterRef transport
);
38 static void SOSTransportCircleTestAddBulkToChanges(SOSTransportCircleTestRef transport
, CFDictionaryRef updates
);
39 static void SOSTransportCircleTestAddToChanges(SOSTransportCircleTestRef transport
, CFStringRef message_key
, CFDataRef message_data
);
40 static bool SOSTransportCircleTestSendChanges(SOSTransportCircleTestRef transport
, CFDictionaryRef changes
, CFErrorRef
*error
);
43 void SOSAccountUpdateTestTransports(SOSAccountRef account
, CFDictionaryRef gestalt
){
44 CFStringRef new_name
= (CFStringRef
)CFDictionaryGetValue(gestalt
, kPIUserDefinedDeviceName
);
45 SOSTransportKeyParameterTestRef key
= (SOSTransportKeyParameterTestRef
)account
->key_transport
;
46 CFDictionaryRef circles
= account
->circle_transports
;
47 CFDictionaryRef messages
= account
->message_transports
;
49 SOSTransportKeyParameterTestSetName(key
, new_name
);
50 CFDictionaryForEach(circles
, ^(const void *key
, const void *value
) {
51 SOSTransportCircleTestSetName((SOSTransportCircleTestRef
)value
, new_name
);
53 CFDictionaryForEach(messages
, ^(const void *key
, const void *value
) {
54 SOSTransportMessageTestSetName((SOSTransportMessageTestRef
)value
, new_name
);
59 static SOSCircleRef
SOSAccountEnsureCircleTest(SOSAccountRef a
, CFStringRef name
, CFStringRef accountName
, CFErrorRef
*error
)
61 CFErrorRef localError
= NULL
;
63 SOSCircleRef circle
= SOSAccountFindCircle(a
, name
, &localError
);
65 require_action_quiet(circle
|| !isSOSErrorCoded(localError
, kSOSErrorIncompatibleCircle
), fail
,
66 if (error
) { *error
= localError
; localError
= NULL
; });
69 circle
= SOSCircleCreate(NULL
, name
, NULL
);
71 CFDictionaryAddValue(a
->circles
, name
, circle
);
73 circle
= SOSAccountFindCircle(a
, name
, &localError
);
76 require_quiet(SOSAccountInflateTestTransportsForCircle(a
, name
, accountName
, &localError
), fail
);
79 CFReleaseNull(localError
);
83 bool SOSAccountEnsureFactoryCirclesTest(SOSAccountRef a
, CFStringRef accountName
)
88 require(a
->factory
, xit
);
89 CFArrayRef circle_names
= a
->factory
->copy_names(a
->factory
);
90 require(circle_names
, xit
);
91 CFArrayForEach(circle_names
, ^(const void*name
) {
93 SOSAccountEnsureCircleTest(a
, (CFStringRef
)name
, accountName
, NULL
);
96 CFReleaseNull(circle_names
);
103 bool SOSAccountInflateTestTransportsForCircle(SOSAccountRef account
, CFStringRef circleName
, CFStringRef accountName
, CFErrorRef
*error
){
104 bool success
= false;
105 SOSTransportCircleTestRef tCircle
= NULL
;
106 SOSTransportMessageTestRef tMessage
= NULL
;
108 if(account
->key_transport
== NULL
){
109 account
->key_transport
= (SOSTransportKeyParameterRef
)SOSTransportTestCreateKeyParameter(account
, accountName
, circleName
);
110 require_quiet(account
->key_transport
, fail
);
112 if(account
->circle_transports
== NULL
){
113 account
->circle_transports
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
114 tCircle
= SOSTransportTestCreateCircle(account
, accountName
, circleName
);
115 require_quiet(tCircle
, fail
);
116 CFDictionarySetValue(account
->circle_transports
, circleName
, tCircle
);
118 else if(CFDictionaryGetCount(account
->circle_transports
) == 0){
119 tCircle
= SOSTransportTestCreateCircle(account
, accountName
, circleName
);
120 require_quiet(tCircle
, fail
);
121 CFDictionarySetValue(account
->circle_transports
, circleName
, tCircle
);
123 if(account
->message_transports
== NULL
){
124 account
->message_transports
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
125 tMessage
= SOSTransportTestCreateMessage(account
, accountName
, circleName
);
126 require_quiet(tMessage
, fail
);
127 CFDictionarySetValue(account
->message_transports
, circleName
, tMessage
);
129 else if(CFDictionaryGetCount(account
->message_transports
) == 0){
130 tMessage
= SOSTransportTestCreateMessage(account
, accountName
, circleName
);
131 require_quiet(tMessage
, fail
);
132 CFDictionarySetValue(account
->message_transports
, circleName
, tMessage
);
137 CFReleaseNull(tCircle
);
138 CFReleaseNull(tMessage
);
143 //Mark Test Key Parameter Transport
146 struct SOSTransportKeyParameterTest
{
147 struct __OpaqueSOSTransportKeyParameter k
;
148 CFMutableDictionaryRef changes
;
150 CFStringRef circleName
;
153 SOSTransportKeyParameterTestRef
SOSTransportTestCreateKeyParameter(SOSAccountRef account
, CFStringRef name
, CFStringRef circleName
){
155 SOSTransportKeyParameterTestRef tpt
= calloc(1, sizeof(struct SOSTransportKeyParameterTest
));
157 tpt
->name
= CFRetainSafe(name
);
158 tpt
->changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
159 tpt
->k
.account
= CFRetainSafe(account
);
160 tpt
->circleName
= CFRetainSafe(circleName
);
161 tpt
->k
.publishCloudParameters
= publishCloudParameters
;
162 tpt
->k
.handleKeyParameterChanges
= handleKeyParameterChanges
;
163 tpt
->k
.setToNewAccount
= setToNewAccount
;
165 key_transports
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
166 CFArrayAppendValue(key_transports
, (SOSTransportKeyParameterRef
)tpt
);
167 SOSRegisterTransportKeyParameter((SOSTransportKeyParameterRef
)tpt
);
171 static bool handleKeyParameterChanges(SOSTransportKeyParameterRef transport
, CFDataRef data
, CFErrorRef error
){
172 SOSAccountRef account
= transport
->account
;
173 return SOSAccountHandleParametersChange(account
, data
, &error
);
176 static bool setToNewAccount(SOSTransportKeyParameterRef transport
){
177 SOSTransportKeyParameterTestRef tpt
= (SOSTransportKeyParameterTestRef
)transport
;
178 SOSAccountRef a
= SOSTransportKeyParameterTestGetAccount(tpt
);
179 CFStringRef accountName
= SOSTransportKeyParameterTestGetName(tpt
);
180 CFAllocatorRef allocator
= CFGetAllocator(a
);
181 CFReleaseNull(a
->circle_identities
);
182 CFReleaseNull(a
->circles
);
183 CFReleaseNull(a
->retired_peers
);
185 CFReleaseNull(a
->user_key_parameters
);
186 CFReleaseNull(a
->user_public
);
187 CFReleaseNull(a
->previous_public
);
188 CFReleaseNull(a
->_user_private
);
190 a
->user_public_trusted
= false;
191 a
->departure_code
= kSOSNeverAppliedToCircle
;
192 a
->user_private_timer
= 0;
193 a
->lock_notification_token
= 0;
199 // update_interest_block;
202 a
->circles
= CFDictionaryCreateMutableForCFTypes(allocator
);
203 a
->circle_identities
= CFDictionaryCreateMutableForCFTypes(allocator
);
204 a
->retired_peers
= CFDictionaryCreateMutableForCFTypes(allocator
);
206 //unregister all the transports from the global transport queue
207 SOSUnregisterTransportKeyParameter(a
->key_transport
);
208 CFArrayForEach(circle_transports
, ^(const void *value
) {
209 SOSTransportCircleTestRef tpt
= (SOSTransportCircleTestRef
) value
;
210 if(CFStringCompare(SOSTransportCircleTestGetName(tpt
), accountName
, 0) == 0){
211 SOSUnregisterTransportCircle((SOSTransportCircleRef
)tpt
);
214 CFArrayForEach(message_transports
, ^(const void *value
) {
215 SOSTransportMessageTestRef tpt
= (SOSTransportMessageTestRef
) value
;
216 if(CFStringCompare(SOSTransportMessageTestGetName(tpt
), accountName
, 0) == 0){
217 SOSUnregisterTransportMessage((SOSTransportMessageRef
)tpt
);
222 CFReleaseNull(a
->key_transport
);
223 CFReleaseNull(a
->circle_transports
);
224 CFReleaseNull(a
->message_transports
);
226 SOSAccountEnsureFactoryCirclesTest(a
, accountName
);
230 CFStringRef
SOSTransportKeyParameterTestGetName(SOSTransportKeyParameterTestRef transport
){
231 return transport
->name
;
234 void SOSTransportKeyParameterTestSetName(SOSTransportKeyParameterTestRef transport
, CFStringRef accountName
){
235 CFReleaseNull(transport
->name
);
236 transport
->name
= CFRetain(accountName
);
239 SOSAccountRef
SOSTransportKeyParameterTestGetAccount(SOSTransportKeyParameterTestRef transport
){
240 return ((SOSTransportKeyParameterRef
)transport
)->account
;
243 CFMutableDictionaryRef
SOSTransportKeyParameterTestGetChanges(SOSTransportKeyParameterTestRef transport
){
244 return transport
->changes
;
246 static bool publishCloudParameters(SOSTransportKeyParameterRef transport
, CFDataRef data
, CFErrorRef
* error
)
248 return SOSTransportKeyParameterTestPublishCloudParameters((SOSTransportKeyParameterTestRef
)transport
, data
, error
);
251 static bool SOSTransportKeyParameterTestPublishCloudParameters(SOSTransportKeyParameterTestRef transport
, CFDataRef newParameters
, CFErrorRef
*error
)
253 if(!transport
->changes
)
254 transport
->changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
256 CFDictionarySetValue(transport
->changes
, kSOSKVSKeyParametersKey
, newParameters
);
262 //MARK: Test Circle Transport
264 struct SOSTransportCircleTest
{
265 struct __OpaqueSOSTransportCircle c
;
266 CFMutableDictionaryRef changes
;
268 CFStringRef circleName
;
270 static CFStringRef
SOSTransportCircleCopyDescription(SOSTransportCircleTestRef transport
) {
272 return CFStringCreateWithFormat(NULL
, NULL
, CFSTR("<SOSTransportCircle@%p\n>"), transport
);
275 static CFStringRef
copyDescription(SOSTransportCircleRef transport
){
276 return SOSTransportCircleCopyDescription((SOSTransportCircleTestRef
)transport
);
279 CFStringRef
SOSTransportCircleTestGetName(SOSTransportCircleTestRef transport
){
280 return transport
->name
;
282 void SOSTransportCircleTestSetName(SOSTransportCircleTestRef transport
, CFStringRef accountName
){
283 CFReleaseNull(transport
->name
);
284 transport
->name
= CFRetain(accountName
);
287 CFMutableDictionaryRef
SOSTransportCircleTestGetChanges(SOSTransportCircleTestRef transport
){
288 return transport
->changes
;
290 SOSTransportCircleTestRef
SOSTransportTestCreateCircle(SOSAccountRef account
, CFStringRef name
, CFStringRef circleName
){
291 SOSTransportCircleTestRef tpt
= calloc(1, sizeof(struct SOSTransportCircleTest
));
293 tpt
->c
.account
= CFRetainSafe(account
);
294 tpt
->c
.copyDescription
= copyDescription
;
295 tpt
->c
.expireRetirementRecords
= expireRetirementRecords
;
296 tpt
->c
.postCircle
= postCircle
;
297 tpt
->c
.postRetirement
= postRetirement
;
298 tpt
->c
.flushChanges
= flushChanges
;
299 tpt
->c
.handleRetirementMessages
= handleRetirementMessages
;
300 tpt
->c
.handleCircleMessages
= handleCircleMessages
;
301 tpt
->c
.destroy
= destroy
;
302 tpt
->changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
303 tpt
->name
= CFRetainSafe(name
);
304 tpt
->circleName
= CFRetainSafe(circleName
);
305 if(!circle_transports
)
306 circle_transports
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
307 CFArrayAppendValue(circle_transports
, (SOSTransportCircleRef
)tpt
);
308 SOSRegisterTransportCircle((SOSTransportCircleRef
)tpt
);
314 static void destroy(SOSTransportCircleRef transport
){
315 SOSTransportCircleTestRef tkvs
= (SOSTransportCircleTestRef
)transport
;
316 CFArrayRemoveAllValue(circle_transports
, tkvs
);
317 CFReleaseNull(tkvs
->changes
);
318 CFReleaseNull(tkvs
->name
);
319 CFReleaseNull(tkvs
->circleName
);
322 static inline bool postRetirement(SOSTransportCircleRef transport
, CFStringRef circleName
, CFStringRef peer_id
, CFDataRef retirement_data
, CFErrorRef
*error
)
324 CFStringRef retirement_key
= SOSRetirementKeyCreateWithCircleNameAndPeer(circleName
, peer_id
);
326 SOSTransportCircleTestAddToChanges((SOSTransportCircleTestRef
)transport
, retirement_key
, retirement_data
);
328 CFReleaseNull(retirement_key
);
332 static inline bool flushChanges(SOSTransportCircleRef transport
, CFErrorRef
*error
)
337 static void SOSTransportCircleTestAddToChanges(SOSTransportCircleTestRef transport
, CFStringRef message_key
, CFDataRef message_data
){
339 if (transport
->changes
== NULL
) {
340 transport
->changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
342 if (message_data
== NULL
) {
343 CFDictionarySetValue(transport
->changes
, message_key
, kCFNull
);
345 CFDictionarySetValue(transport
->changes
, message_key
, message_data
);
349 static void SOSTransportCircleTestAddBulkToChanges(SOSTransportCircleTestRef transport
, CFDictionaryRef updates
){
351 if (transport
->changes
== NULL
) {
352 transport
->changes
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, CFDictionaryGetCount(updates
), updates
);
356 CFDictionaryForEach(updates
, ^(const void *key
, const void *value
) {
357 CFDictionarySetValue(transport
->changes
, key
, value
);
363 static bool expireRetirementRecords(SOSTransportCircleRef transport
, CFDictionaryRef retirements
, CFErrorRef
*error
) {
366 SOSTransportCircleTestRef tpt
= (SOSTransportCircleTestRef
)transport
;
367 CFMutableDictionaryRef keysToWrite
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
369 CFDictionaryForEach(retirements
, ^(const void *key
, const void *value
) {
370 if (isString(key
) && isArray(value
)) {
371 CFStringRef circle_name
= (CFStringRef
) key
;
372 CFArrayRef retirees
= (CFArrayRef
) value
;
374 CFArrayForEach(retirees
, ^(const void *value
) {
375 if (isString(value
)) {
376 CFStringRef retiree_id
= (CFStringRef
) value
;
378 CFStringRef kvsKey
= SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name
, retiree_id
);
380 CFDictionaryAddValue(keysToWrite
, kvsKey
, kCFNull
);
382 CFReleaseSafe(kvsKey
);
388 if(CFDictionaryGetCount(keysToWrite
)) {
389 SOSTransportCircleTestAddBulkToChanges(tpt
, keysToWrite
);
391 CFReleaseNull(keysToWrite
);
396 __unused
static bool SOSTransportCircleTestUpdateRetirementRecords(SOSTransportCircleTestRef transport
, CFDictionaryRef updates
, CFErrorRef
* error
){
397 CFErrorRef updateError
= NULL
;
398 bool success
= false;
399 if (SOSTransportCircleTestSendChanges((SOSTransportCircleTestRef
)transport
, updates
, &updateError
)){
402 SOSCreateErrorWithFormat(kSOSErrorSendFailure
, updateError
, error
, NULL
,
403 CFSTR("update parameters key failed [%@]"), updates
);
408 static bool postCircle(SOSTransportCircleRef transport
, CFStringRef circleName
, CFDataRef circle_data
, CFErrorRef
*error
){
409 SOSTransportCircleTestRef tkvs
= (SOSTransportCircleTestRef
)transport
;
410 CFStringRef circle_key
= SOSCircleKeyCreateWithName(circleName
, error
);
412 SOSTransportCircleTestAddToChanges(tkvs
, circle_key
, circle_data
);
413 CFReleaseNull(circle_key
);
418 static CFDictionaryRef
handleRetirementMessages(SOSTransportCircleRef transport
, CFMutableDictionaryRef circle_retirement_messages_table
, CFErrorRef
*error
){
419 SOSAccountRef account
= transport
->account
;
420 CFMutableDictionaryRef handledRetirementMessages
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
421 CFDictionaryForEach(circle_retirement_messages_table
, ^(const void *key
, const void *value
) {
422 if (isString(key
) && isDictionary(value
)) {
423 CFStringRef circle_name
= (CFStringRef
) key
;
425 CFDictionaryRef retirment_dictionary
= (CFDictionaryRef
) value
;
426 CFDictionaryForEach(retirment_dictionary
, ^(const void *key
, const void *value
) {
428 SOSPeerInfoRef pi
= SOSPeerInfoCreateFromData(NULL
, error
, (CFDataRef
) value
);
429 if(pi
&& CFEqual(key
, SOSPeerInfoGetPeerID(pi
)) && SOSPeerInfoInspectRetirementTicket(pi
, error
)) {
430 CFMutableDictionaryRef circle_retirements
= CFDictionaryEnsureCFDictionaryAndGetCurrentValue(account
->retired_peers
, circle_name
);
431 CFDictionarySetValue(circle_retirements
, key
, value
);
433 SOSAccountRecordRetiredPeerInCircleNamed(account
, circle_name
, pi
);
435 CFMutableArrayRef handledRetirementIDs
= CFDictionaryEnsureCFArrayAndGetCurrentValue(handledRetirementMessages
, circle_name
);
436 CFArrayAppendValue(handledRetirementIDs
, SOSPeerInfoGetPeerID(pi
));
443 return handledRetirementMessages
;
446 static CFArrayRef
handleCircleMessages(SOSTransportCircleRef transport
, CFMutableDictionaryRef circle_circle_messages_table
, CFErrorRef
*error
){
447 CFMutableArrayRef handledKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
448 CFDictionaryForEach(circle_circle_messages_table
, ^(const void *key
, const void *value
) {
449 CFErrorRef circleMessageError
= NULL
;
450 if (!SOSAccountHandleCircleMessage(transport
->account
, key
, value
, &circleMessageError
)) {
451 secerror("Error handling circle message %@ (%@): %@", key
, value
, circleMessageError
);
454 CFStringRef circle_id
= (CFStringRef
) key
;
455 CFArrayAppendValue(handledKeys
, circle_id
);
457 CFReleaseNull(circleMessageError
);
463 static bool SOSTransportCircleTestSendChanges(SOSTransportCircleTestRef transport
, CFDictionaryRef changes
, CFErrorRef
*error
){
464 if(!transport
->changes
)
465 transport
->changes
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, CFDictionaryGetCount(changes
), changes
);
467 CFDictionaryForEach(changes
, ^(const void *key
, const void *value
) {
468 CFDictionarySetValue(transport
->changes
, key
, value
);
474 SOSAccountRef
SOSTransportCircleTestGetAccount(SOSTransportCircleTestRef transport
) {
475 return ((SOSTransportCircleRef
)transport
)->account
;
479 //MARK Message Test Transport
482 struct SOSTransportMessageTest
{
483 struct __OpaqueSOSTransportMessage m
;
484 CFMutableDictionaryRef changes
;
486 CFStringRef circleName
;
489 SOSTransportMessageTestRef
SOSTransportTestCreateMessage(SOSAccountRef account
, CFStringRef name
, CFStringRef circleName
){
490 SOSTransportMessageTestRef tpt
= calloc(1, sizeof(struct SOSTransportMessageTest
));
492 SOSEngineRef engine
= SOSDataSourceFactoryGetEngineForDataSourceName(account
->factory
, circleName
, NULL
);
494 tpt
->m
.engine
= CFRetainSafe(engine
);
496 tpt
->m
.sendMessages
= sendMessages
;
497 tpt
->m
.syncWithPeers
= syncWithPeers
;
498 tpt
->m
.flushChanges
= flushMessageChanges
;
499 tpt
->m
.cleanupAfterPeerMessages
= cleanupAfterPeer
;
500 tpt
->m
.destroy
= destroyMessageTransport
;
501 tpt
->m
.handleMessages
= handleMessages
;
502 // Initialize ourselves
503 tpt
->changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
504 tpt
->name
= CFRetainSafe(name
);
505 tpt
->circleName
= CFRetainSafe(circleName
);
506 if(!message_transports
)
507 message_transports
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
508 CFArrayAppendValue(message_transports
, (SOSTransportMessageRef
)tpt
);
509 SOSRegisterTransportMessage((SOSTransportMessageRef
)tpt
);
514 CFStringRef
SOSTransportMessageTestGetName(SOSTransportMessageTestRef transport
){
515 return transport
->name
;
518 void SOSTransportMessageTestSetName(SOSTransportMessageTestRef transport
, CFStringRef accountName
){
519 CFReleaseNull(transport
->name
);
520 transport
->name
= CFRetain(accountName
);
523 CFMutableDictionaryRef
SOSTransportMessageTestGetChanges(SOSTransportMessageTestRef transport
){
524 return transport
->changes
;
527 static void destroyMessageTransport(SOSTransportMessageRef transport
){
528 SOSTransportMessageTestRef tkvs
= (SOSTransportMessageTestRef
)transport
;
529 CFArrayRemoveAllValue(message_transports
, tkvs
);
530 CFReleaseNull(tkvs
->circleName
);
531 CFReleaseNull(tkvs
->changes
);
532 CFReleaseNull(tkvs
->name
);
536 static void SOSTransportMessageTestAddBulkToChanges(SOSTransportMessageTestRef transport
, CFDictionaryRef updates
){
538 if (transport
->changes
== NULL
) {
539 transport
->changes
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, CFDictionaryGetCount(updates
), updates
);
543 CFDictionaryForEach(updates
, ^(const void *key
, const void *value
) {
544 CFDictionarySetValue(transport
->changes
, key
, value
);
549 static void SOSTransportMessageTestAddToChanges(SOSTransportMessageTestRef transport
, CFStringRef message_key
, CFDataRef message_data
){
550 if (transport
->changes
== NULL
) {
551 transport
->changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
553 if (message_data
== NULL
) {
554 CFDictionarySetValue(transport
->changes
, message_key
, kCFNull
);
556 CFDictionarySetValue(transport
->changes
, message_key
, message_data
);
560 static bool SOSTransportMessageTestCleanupAfterPeerMessages(SOSTransportMessageTestRef transport
, CFDictionaryRef circle_to_peer_ids
, CFErrorRef
*error
)
562 SOSEngineRef engine
= SOSTransportMessageGetEngine((SOSTransportMessageRef
)transport
);
563 require_quiet(engine
, fail
);
565 CFArrayRef enginePeers
= SOSEngineGetPeerIDs(engine
);
567 CFDictionaryForEach(circle_to_peer_ids
, ^(const void *key
, const void *value
) {
568 if (isString(key
) && isArray(value
)) {
569 CFStringRef circle_name
= (CFStringRef
) key
;
570 CFArrayRef peers_to_cleanup_after
= (CFArrayRef
) value
;
572 CFArrayForEach(peers_to_cleanup_after
, ^(const void *value
) {
573 if (isString(value
)) {
574 CFStringRef cleanup_id
= (CFStringRef
) value
;
575 // TODO: Since the enginePeers list is not authorative (the Account is) this could inadvertently clean up active peers or leave behind stale peers
576 if (enginePeers
) CFArrayForEach(enginePeers
, ^(const void *value
) {
577 if (isString(value
)) {
578 CFStringRef in_circle_id
= (CFStringRef
) value
;
580 CFStringRef kvsKey
= SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name
, cleanup_id
, in_circle_id
);
581 SOSTransportMessageTestAddToChanges(transport
, kvsKey
, NULL
);
582 CFReleaseSafe(kvsKey
);
584 kvsKey
= SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name
, in_circle_id
, cleanup_id
);
585 SOSTransportMessageTestAddToChanges(transport
, kvsKey
, NULL
);
586 CFReleaseSafe(kvsKey
);
595 return SOSTransportMessageFlushChanges((SOSTransportMessageRef
)transport
, error
);
600 static bool sendToPeer(SOSTransportMessageRef transport
, CFStringRef circleName
, CFStringRef peerID
, CFDataRef message
, CFErrorRef
*error
) {
601 SOSTransportMessageTestRef testTransport
= (SOSTransportMessageTestRef
) transport
;
603 CFStringRef message_to_peer_key
= SOSMessageKeyCreateFromTransportToPeer((SOSTransportMessageKVSRef
)transport
, peerID
);
604 CFDictionaryRef a_message_to_a_peer
= CFDictionaryCreateForCFTypes(NULL
, message_to_peer_key
, message
, NULL
);
606 SOSTransportMessageTestAddBulkToChanges((SOSTransportMessageTestRef
)testTransport
, a_message_to_a_peer
);
607 CFReleaseNull(a_message_to_a_peer
);
608 CFReleaseNull(message_to_peer_key
);
613 static bool syncWithPeers(SOSTransportMessageRef transport
, CFDictionaryRef circleToPeerIDs
, CFErrorRef
*error
){
614 // Each entry is keyed by circle name and contains a list of peerIDs
616 __block
bool result
= true;
618 CFDictionaryForEach(circleToPeerIDs
, ^(const void *key
, const void *value
) {
619 if (isString(key
) && isArray(value
)) {
620 CFStringRef circleName
= (CFStringRef
) key
;
621 CFArrayForEach(value
, ^(const void *value
) {
622 if (isString(value
)) {
623 CFStringRef peerID
= (CFStringRef
) value
;
625 SOSEnginePeerMessageSentBlock sent
= NULL
;
626 CFDataRef message_to_send
= NULL
;
628 SOSPeerRef peer
= SOSPeerCreateWithEngine(SOSTransportMessageGetEngine(transport
), peerID
);
629 CFDataRef coderData
= SOSEngineGetCoderData(SOSTransportMessageGetEngine(transport
), peerID
);
631 SOSCoderRef coder
= SOSCoderCreateFromData(coderData
, error
);
632 SOSPeerSetCoder(peer
, coder
);
634 ok
= SOSPeerCoderSendMessageIfNeeded(peer
, &message_to_send
, circleName
, peerID
, &sent
, error
);
635 coder
= SOSPeerGetCoder(peer
);
637 if (message_to_send
) {
638 CFDictionaryRef peer_dict
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
639 peerID
, message_to_send
,
642 CFDictionarySetValue(SOSTransportMessageTestGetChanges((SOSTransportMessageTestRef
)transport
), circleName
, peer_dict
);
643 SOSPeerCoderConsume(&sent
, ok
);
645 CFReleaseSafe(peer_dict
);
652 CFReleaseSafe(message_to_send
);
654 coderData
= SOSCoderCopyDER(coder
, error
);
656 if(!SOSEngineSetCoderData(SOSTransportMessageGetEngine(transport
), peerID
, coderData
, error
)){
657 secerror("SOSTransportMessageSendMessageIfNeeded, Could not save peer state");
659 CFReleaseNull(coderData
);
662 SOSCoderDispose(coder
);
673 static bool sendMessages(SOSTransportMessageRef transport
, CFDictionaryRef circleToPeersToMessage
, CFErrorRef
*error
) {
674 __block
bool result
= true;
676 CFDictionaryForEach(circleToPeersToMessage
, ^(const void *key
, const void *value
) {
677 if (isString(key
) && isDictionary(value
)) {
678 CFStringRef circleName
= (CFStringRef
) key
;
679 CFDictionaryForEach(value
, ^(const void *key
, const void *value
) {
680 if (isString(key
) && isData(value
)) {
681 CFStringRef peerID
= (CFStringRef
) key
;
682 CFDataRef message
= (CFDataRef
) value
;
683 bool rx
= sendToPeer(transport
, circleName
, peerID
, message
, error
);
693 static CF_RETURNS_RETAINED
694 CFDictionaryRef
handleMessages(SOSTransportMessageRef transport
, CFMutableDictionaryRef circle_peer_messages_table
, CFErrorRef
*error
) {
695 SOSTransportMessageTestRef tpt
= (SOSTransportMessageTestRef
)transport
;
696 CFMutableDictionaryRef handled
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
697 CFDictionaryRef peerToMessage
= CFDictionaryGetValue(circle_peer_messages_table
, tpt
->circleName
);
698 CFMutableArrayRef handled_peers
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
699 CFDictionaryAddValue(handled
, tpt
->circleName
, handled_peers
);
702 CFDictionaryForEach(peerToMessage
, ^(const void *key
, const void *value
) {
703 CFStringRef peer_id
= (CFStringRef
) key
;
704 CFDataRef peer_message
= (CFDataRef
) value
;
705 CFErrorRef localError
= NULL
;
707 if (SOSTransportMessageHandlePeerMessage((SOSTransportMessageRef
) transport
, peer_id
, peer_message
, &localError
)) {
708 CFArrayAppendValue(handled_peers
, key
);
710 secdebug("transport", "%@ KVSTransport handle message failed: %@", peer_id
, localError
);
712 CFReleaseNull(localError
);
715 CFReleaseNull(handled_peers
);
720 static bool flushMessageChanges(SOSTransportMessageRef transport
, CFErrorRef
*error
)
725 static bool cleanupAfterPeer(SOSTransportMessageRef transport
, CFDictionaryRef circle_to_peer_ids
, CFErrorRef
*error
)
727 return SOSTransportMessageTestCleanupAfterPeerMessages((SOSTransportMessageTestRef
) transport
, circle_to_peer_ids
, error
);
730 SOSAccountRef
SOSTransportMessageTestGetAccount(SOSTransportMessageTestRef transport
) {
731 return ((SOSTransportMessageRef
)transport
)->account
;