1 #include <CoreFoundation/CoreFoundation.h>
2 #include <CoreFoundation/CFRuntime.h>
4 #include <Security/SecureObjectSync/SOSAccount.h>
5 #include <Security/SecureObjectSync/SOSAccountPriv.h>
6 #include <Security/SecureObjectSync/SOSTransport.h>
7 #include <Security/SecureObjectSync/SOSTransportKeyParameter.h>
8 #include <Security/SecureObjectSync/SOSTransportCircle.h>
9 #include <Security/SecureObjectSync/SOSTransportMessage.h>
10 #include <Security/SecureObjectSync/SOSKVSKeys.h>
11 #include <Security/SecureObjectSync/SOSPeerCoder.h>
12 #include <utilities/SecCFWrappers.h>
13 #include <Security/SecureObjectSync/SOSPeerInfoV2.h>
15 #include "SOSTransportTestTransports.h"
17 static bool sendToPeer(SOSTransportMessageRef transport
, CFStringRef circleName
, CFStringRef peerID
, CFDataRef message
, CFErrorRef
*error
);
18 static bool syncWithPeers(SOSTransportMessageRef transport
, CFDictionaryRef circleToPeerIDs
, CFErrorRef
*error
);
19 static bool sendMessages(SOSTransportMessageRef transport
, CFDictionaryRef circleToPeersToMessage
, CFErrorRef
*error
);
20 static bool cleanupAfterPeer(SOSTransportMessageRef transport
, CFDictionaryRef circle_to_peer_ids
, CFErrorRef
*error
);
21 static CF_RETURNS_RETAINED
22 CFDictionaryRef
handleMessages(SOSTransportMessageRef transport
, CFMutableDictionaryRef circle_peer_messages_table
, CFErrorRef
*error
);
23 static void destroyMessageTransport(SOSTransportMessageRef transport
);
24 static void SOSTransportMessageTestAddBulkToChanges(SOSTransportMessageTestRef transport
, CFDictionaryRef updates
);
26 static bool flushMessageChanges(SOSTransportMessageRef transport
, CFErrorRef
*error
);
27 static bool publishCloudParameters(SOSTransportKeyParameterRef transport
, CFDataRef data
, CFErrorRef
* error
);
28 static bool SOSTransportKeyParameterTestPublishCloudParameters(SOSTransportKeyParameterTestRef transport
, CFDataRef newParameters
, CFErrorRef
*error
);
30 static bool expireRetirementRecords(SOSTransportCircleRef transport
, CFDictionaryRef retirements
, CFErrorRef
*error
);
31 static void destroy(SOSTransportCircleRef transport
);
32 static inline bool flushChanges(SOSTransportCircleRef transport
, CFErrorRef
*error
);
33 static bool postCircle(SOSTransportCircleRef transport
, CFStringRef circleName
, CFDataRef circle_data
, CFErrorRef
*error
);
34 static inline bool postRetirement(SOSTransportCircleRef transport
, CFStringRef circleName
, CFStringRef peer_id
, CFDataRef retirement_data
, CFErrorRef
*error
);
35 static bool handleKeyParameterChanges(SOSTransportKeyParameterRef transport
, CFDataRef data
, CFErrorRef error
);
37 static CFArrayRef
handleCircleMessages(SOSTransportCircleRef transport
, CFMutableDictionaryRef circle_circle_messages_table
, CFErrorRef
*error
);
38 static CFDictionaryRef
handleRetirementMessages(SOSTransportCircleRef transport
, CFMutableDictionaryRef circle_retirement_messages_table
, CFErrorRef
*error
);
39 static bool setToNewAccount(SOSTransportKeyParameterRef transport
, SOSAccountRef account
);
40 static void destroyKeyParameters(SOSTransportKeyParameterRef transport
);
42 static void SOSTransportCircleTestAddBulkToChanges(SOSTransportCircleTestRef transport
, CFDictionaryRef updates
);
43 static void SOSTransportCircleTestAddToChanges(SOSTransportCircleTestRef transport
, CFStringRef message_key
, CFDataRef message_data
);
44 static bool SOSTransportCircleTestSendChanges(SOSTransportCircleTestRef transport
, CFDictionaryRef changes
, CFErrorRef
*error
);
46 static bool sendPeerInfo(SOSTransportCircleRef transport
, CFStringRef peerID
, CFDataRef peerInfoData
, CFErrorRef
*error
);
47 static bool flushRingChanges(SOSTransportCircleRef transport
, CFErrorRef
* error
);
48 static bool postRing(SOSTransportCircleRef transport
, CFStringRef ringName
, CFDataRef ring
, CFErrorRef
*error
);
49 static bool sendDebugInfo(SOSTransportCircleRef transport
, CFStringRef type
, CFTypeRef debugInfo
, CFErrorRef
*error
);
51 void SOSAccountUpdateTestTransports(SOSAccountRef account
, CFDictionaryRef gestalt
){
52 CFStringRef new_name
= (CFStringRef
)CFDictionaryGetValue(gestalt
, kPIUserDefinedDeviceNameKey
);
54 SOSTransportKeyParameterTestSetName((SOSTransportKeyParameterTestRef
)account
->key_transport
, new_name
);
55 SOSTransportCircleTestSetName((SOSTransportCircleTestRef
)account
->circle_transport
, new_name
);
56 SOSTransportMessageTestSetName((SOSTransportMessageTestRef
)account
->kvs_message_transport
, new_name
);
60 static SOSCircleRef
SOSAccountEnsureCircleTest(SOSAccountRef a
, CFStringRef name
, CFStringRef accountName
, CFErrorRef
*error
)
62 CFErrorRef localError
= NULL
;
64 SOSCircleRef circle
= SOSAccountGetCircle(a
, &localError
);
66 require_action_quiet(circle
|| !isSOSErrorCoded(localError
, kSOSErrorIncompatibleCircle
), fail
,
67 if (error
) { *error
= localError
; localError
= NULL
; });
70 circle
= SOSCircleCreate(NULL
, name
, NULL
);
72 CFRetainAssign(a
->trusted_circle
, circle
);
74 circle
= SOSAccountGetCircle(a
, &localError
);
77 require_quiet(SOSAccountInflateTestTransportsForCircle(a
, name
, accountName
, &localError
), fail
);
78 require_quiet(SOSAccountHasFullPeerInfo(a
, &localError
), fail
);
81 CFReleaseNull(localError
);
85 bool SOSAccountEnsureFactoryCirclesTest(SOSAccountRef a
, CFStringRef accountName
)
90 require(a
->factory
, xit
);
91 CFStringRef circle_name
= SOSDataSourceFactoryCopyName(a
->factory
);
92 require(circle_name
, xit
);
94 SOSAccountEnsureCircleTest(a
, (CFStringRef
)circle_name
, accountName
, NULL
);
96 CFReleaseNull(circle_name
);
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_transport
== NULL
){
113 tCircle
= SOSTransportTestCreateCircle(account
, accountName
, circleName
);
114 require_quiet(tCircle
, fail
);
115 CFRetainAssign(account
->circle_transport
, (SOSTransportCircleRef
)tCircle
);
117 if(account
->kvs_message_transport
== NULL
){
118 tMessage
= SOSTransportTestCreateMessage(account
, accountName
, circleName
);
119 require_quiet(tMessage
, fail
);
120 CFRetainAssign(account
->kvs_message_transport
, (SOSTransportMessageRef
)tMessage
);
125 CFReleaseNull(tCircle
);
126 CFReleaseNull(tMessage
);
131 //Mark Test Key Parameter Transport
134 struct SOSTransportKeyParameterTest
{
135 struct __OpaqueSOSTransportKeyParameter k
;
136 CFMutableDictionaryRef changes
;
138 CFStringRef circleName
;
141 SOSTransportKeyParameterTestRef
SOSTransportTestCreateKeyParameter(SOSAccountRef account
, CFStringRef name
, CFStringRef circleName
){
143 SOSTransportKeyParameterTestRef tpt
= (SOSTransportKeyParameterTestRef
) SOSTransportKeyParameterCreateForSubclass(sizeof(struct SOSTransportKeyParameterTest
) - sizeof(CFRuntimeBase
), account
, NULL
);
145 tpt
->name
= CFRetainSafe(name
);
146 tpt
->changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
147 tpt
->k
.account
= CFRetainSafe(account
);
148 tpt
->k
.destroy
= destroyKeyParameters
;
149 tpt
->circleName
= CFRetainSafe(circleName
);
150 tpt
->k
.publishCloudParameters
= publishCloudParameters
;
151 tpt
->k
.handleKeyParameterChanges
= handleKeyParameterChanges
;
152 tpt
->k
.setToNewAccount
= setToNewAccount
;
154 key_transports
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, NULL
);
155 CFArrayAppendValue(key_transports
, (SOSTransportKeyParameterRef
)tpt
);
157 SOSRegisterTransportKeyParameter((SOSTransportKeyParameterRef
)tpt
);
161 static bool handleKeyParameterChanges(SOSTransportKeyParameterRef transport
, CFDataRef data
, CFErrorRef error
){
162 SOSAccountRef account
= transport
->account
;
163 return SOSAccountHandleParametersChange(account
, data
, &error
);
166 static void destroyKeyParameters(SOSTransportKeyParameterRef transport
){
167 SOSTransportKeyParameterTestRef tpt
= (SOSTransportKeyParameterTestRef
)transport
;
169 CFArrayRemoveAllValue(key_transports
, tpt
);
170 SOSUnregisterTransportKeyParameter(transport
);
172 CFReleaseNull(tpt
->changes
);
173 CFReleaseNull(tpt
->name
);
174 CFReleaseNull(tpt
->circleName
);
178 static bool setToNewAccount(SOSTransportKeyParameterRef transport
, SOSAccountRef a
){
179 SOSTransportKeyParameterTestRef tpt
= (SOSTransportKeyParameterTestRef
)transport
;
180 CFStringRef accountName
= SOSTransportKeyParameterTestGetName(tpt
);
182 SOSAccountSetToNew(a
);
184 CFReleaseNull(a
->key_transport
);
185 CFReleaseNull(a
->circle_transport
);
186 CFReleaseNull(a
->kvs_message_transport
);
187 CFReleaseNull(a
->ids_message_transport
);
189 SOSAccountEnsureFactoryCirclesTest(a
, accountName
);
193 CFStringRef
SOSTransportKeyParameterTestGetName(SOSTransportKeyParameterTestRef transport
){
194 return transport
->name
;
197 void SOSTransportKeyParameterTestSetName(SOSTransportKeyParameterTestRef transport
, CFStringRef accountName
){
198 CFReleaseNull(transport
->name
);
199 transport
->name
= CFRetain(accountName
);
202 SOSAccountRef
SOSTransportKeyParameterTestGetAccount(SOSTransportKeyParameterTestRef transport
){
203 return ((SOSTransportKeyParameterRef
)transport
)->account
;
206 CFMutableDictionaryRef
SOSTransportKeyParameterTestGetChanges(SOSTransportKeyParameterTestRef transport
){
207 return transport
->changes
;
210 void SOSTransportKeyParameterTestClearChanges(SOSTransportKeyParameterTestRef transport
){
211 CFReleaseNull(transport
->changes
);
212 transport
->changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
215 static bool publishCloudParameters(SOSTransportKeyParameterRef transport
, CFDataRef data
, CFErrorRef
* error
)
217 return SOSTransportKeyParameterTestPublishCloudParameters((SOSTransportKeyParameterTestRef
)transport
, data
, error
);
220 static bool SOSTransportKeyParameterTestPublishCloudParameters(SOSTransportKeyParameterTestRef transport
, CFDataRef newParameters
, CFErrorRef
*error
)
222 if(!transport
->changes
)
223 transport
->changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
225 CFDictionarySetValue(transport
->changes
, kSOSKVSKeyParametersKey
, newParameters
);
231 //MARK: Test Circle Transport
233 struct SOSTransportCircleTest
{
234 struct __OpaqueSOSTransportCircle c
;
235 CFMutableDictionaryRef changes
;
237 CFStringRef circleName
;
239 static CFStringRef
SOSTransportCircleCopyDescription(SOSTransportCircleTestRef transport
) {
241 return CFStringCreateWithFormat(NULL
, NULL
, CFSTR("<SOSTransportCircle@%p\n>"), transport
);
244 static CFStringRef
copyDescription(SOSTransportCircleRef transport
){
245 return SOSTransportCircleCopyDescription((SOSTransportCircleTestRef
)transport
);
248 CFStringRef
SOSTransportCircleTestGetName(SOSTransportCircleTestRef transport
){
249 return transport
->name
;
251 void SOSTransportCircleTestSetName(SOSTransportCircleTestRef transport
, CFStringRef accountName
){
252 CFReleaseNull(transport
->name
);
253 transport
->name
= CFRetain(accountName
);
256 CFMutableDictionaryRef
SOSTransportCircleTestGetChanges(SOSTransportCircleTestRef transport
){
257 return transport
->changes
;
260 void SOSTransportCircleTestClearChanges(SOSTransportCircleTestRef transport
){
261 CFReleaseNull(transport
->changes
);
262 transport
->changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
265 SOSTransportCircleTestRef
SOSTransportTestCreateCircle(SOSAccountRef account
, CFStringRef name
, CFStringRef circleName
){
266 SOSTransportCircleTestRef tpt
= (SOSTransportCircleTestRef
) SOSTransportCircleCreateForSubclass(sizeof(struct SOSTransportCircleTest
) - sizeof(CFRuntimeBase
), account
, NULL
);
269 tpt
->c
.account
= CFRetainSafe(account
);
270 tpt
->c
.copyDescription
= copyDescription
;
271 tpt
->c
.expireRetirementRecords
= expireRetirementRecords
;
272 tpt
->c
.postCircle
= postCircle
;
273 tpt
->c
.postRetirement
= postRetirement
;
274 tpt
->c
.flushChanges
= flushChanges
;
275 tpt
->c
.handleRetirementMessages
= handleRetirementMessages
;
276 tpt
->c
.handleCircleMessages
= handleCircleMessages
;
277 tpt
->c
.destroy
= destroy
;
278 tpt
->c
.flushRingChanges
= flushRingChanges
;
279 tpt
->c
.postRing
= postRing
;
280 tpt
->c
.sendDebugInfo
= sendDebugInfo
;
281 tpt
->c
.sendPeerInfo
= sendPeerInfo
;
282 tpt
->changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
283 tpt
->name
= CFRetainSafe(name
);
284 tpt
->circleName
= CFRetainSafe(circleName
);
285 if(!circle_transports
)
286 circle_transports
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, NULL
);
287 CFArrayAppendValue(circle_transports
, (SOSTransportCircleRef
)tpt
);
289 SOSRegisterTransportCircle((SOSTransportCircleRef
)tpt
);
295 static void destroy(SOSTransportCircleRef transport
){
296 SOSTransportCircleTestRef tkvs
= (SOSTransportCircleTestRef
)transport
;
297 CFArrayRemoveAllValue(circle_transports
, tkvs
);
299 SOSUnregisterTransportCircle(transport
);
301 CFReleaseNull(tkvs
->changes
);
302 CFReleaseNull(tkvs
->name
);
303 CFReleaseNull(tkvs
->circleName
);
306 static bool sendPeerInfo(SOSTransportCircleRef transport
, CFStringRef peerID
, CFDataRef peerInfoData
, CFErrorRef
*error
){
307 SOSTransportCircleTestRef testTransport
= (SOSTransportCircleTestRef
)transport
;
308 CFMutableDictionaryRef changes
= SOSTransportCircleTestGetChanges(testTransport
);
309 CFDictionaryAddValue(changes
, peerID
, peerInfoData
);
312 static bool flushRingChanges(SOSTransportCircleRef transport
, CFErrorRef
* error
){
315 static bool postRing(SOSTransportCircleRef transport
, CFStringRef ringName
, CFDataRef ring
, CFErrorRef
*error
){
316 SOSTransportCircleTestRef testTransport
= (SOSTransportCircleTestRef
)transport
;
317 CFStringRef ringKey
= SOSRingKeyCreateWithName(ringName
, error
);
318 CFMutableDictionaryRef changes
= SOSTransportCircleTestGetChanges(testTransport
);
319 CFDictionaryAddValue(changes
, ringKey
, ring
);
320 CFReleaseNull(ringKey
);
324 static bool sendDebugInfo(SOSTransportCircleRef transport
, CFStringRef type
, CFTypeRef debugInfo
, CFErrorRef
*error
){
325 SOSTransportCircleTestRef testTransport
= (SOSTransportCircleTestRef
)transport
;
326 CFMutableDictionaryRef changes
= SOSTransportCircleTestGetChanges(testTransport
);
327 CFDictionaryAddValue(changes
, type
, debugInfo
);
331 static inline bool postRetirement(SOSTransportCircleRef transport
, CFStringRef circleName
, CFStringRef peer_id
, CFDataRef retirement_data
, CFErrorRef
*error
)
333 CFStringRef retirement_key
= SOSRetirementKeyCreateWithCircleNameAndPeer(circleName
, peer_id
);
335 SOSTransportCircleTestAddToChanges((SOSTransportCircleTestRef
)transport
, retirement_key
, retirement_data
);
337 CFReleaseNull(retirement_key
);
341 static inline bool flushChanges(SOSTransportCircleRef transport
, CFErrorRef
*error
)
346 static void SOSTransportCircleTestAddToChanges(SOSTransportCircleTestRef transport
, CFStringRef message_key
, CFDataRef message_data
){
348 if (transport
->changes
== NULL
) {
349 transport
->changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
351 if (message_data
== NULL
) {
352 CFDictionarySetValue(transport
->changes
, message_key
, kCFNull
);
354 CFDictionarySetValue(transport
->changes
, message_key
, message_data
);
356 secnotice("circle-changes", "Adding circle change %@ %@->%@", transport
->name
, message_key
, message_data
);
359 static void SOSTransportCircleTestAddBulkToChanges(SOSTransportCircleTestRef transport
, CFDictionaryRef updates
){
361 if (transport
->changes
== NULL
) {
362 transport
->changes
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, CFDictionaryGetCount(updates
), updates
);
366 CFDictionaryForEach(updates
, ^(const void *key
, const void *value
) {
367 CFDictionarySetValue(transport
->changes
, key
, value
);
373 static bool expireRetirementRecords(SOSTransportCircleRef transport
, CFDictionaryRef retirements
, CFErrorRef
*error
) {
376 SOSTransportCircleTestRef tpt
= (SOSTransportCircleTestRef
)transport
;
377 CFMutableDictionaryRef keysToWrite
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
379 CFDictionaryForEach(retirements
, ^(const void *key
, const void *value
) {
380 if (isString(key
) && isArray(value
)) {
381 CFStringRef circle_name
= (CFStringRef
) key
;
382 CFArrayRef retirees
= (CFArrayRef
) value
;
384 CFArrayForEach(retirees
, ^(const void *value
) {
385 if (isString(value
)) {
386 CFStringRef retiree_id
= (CFStringRef
) value
;
388 CFStringRef kvsKey
= SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name
, retiree_id
);
390 CFDictionaryAddValue(keysToWrite
, kvsKey
, kCFNull
);
392 CFReleaseSafe(kvsKey
);
398 if(CFDictionaryGetCount(keysToWrite
)) {
399 SOSTransportCircleTestAddBulkToChanges(tpt
, keysToWrite
);
401 CFReleaseNull(keysToWrite
);
406 __unused
static bool SOSTransportCircleTestUpdateRetirementRecords(SOSTransportCircleTestRef transport
, CFDictionaryRef updates
, CFErrorRef
* error
){
407 CFErrorRef updateError
= NULL
;
408 bool success
= false;
409 if (SOSTransportCircleTestSendChanges((SOSTransportCircleTestRef
)transport
, updates
, &updateError
)){
412 SOSCreateErrorWithFormat(kSOSErrorSendFailure
, updateError
, error
, NULL
,
413 CFSTR("update parameters key failed [%@]"), updates
);
418 bool SOSTransportCircleTestRemovePendingChange(SOSTransportCircleRef transport
, CFStringRef circleName
, CFErrorRef
*error
){
419 SOSTransportCircleTestRef tkvs
= (SOSTransportCircleTestRef
)transport
;
420 CFStringRef circle_key
= SOSCircleKeyCreateWithName(circleName
, error
);
422 CFDictionaryRemoveValue(tkvs
->changes
, circle_key
);
423 CFReleaseNull(circle_key
);
427 static bool postCircle(SOSTransportCircleRef transport
, CFStringRef circleName
, CFDataRef circle_data
, CFErrorRef
*error
){
428 SOSTransportCircleTestRef tkvs
= (SOSTransportCircleTestRef
)transport
;
429 CFStringRef circle_key
= SOSCircleKeyCreateWithName(circleName
, error
);
431 SOSTransportCircleTestAddToChanges(tkvs
, circle_key
, circle_data
);
432 CFReleaseNull(circle_key
);
437 static CF_RETURNS_RETAINED CFDictionaryRef
handleRetirementMessages(SOSTransportCircleRef transport
, CFMutableDictionaryRef circle_retirement_messages_table
, CFErrorRef
*error
){
438 SOSAccountRef account
= transport
->account
;
440 return SOSAccountHandleRetirementMessages(account
, circle_retirement_messages_table
, error
);
443 static CFArrayRef
handleCircleMessages(SOSTransportCircleRef transport
, CFMutableDictionaryRef circle_circle_messages_table
, CFErrorRef
*error
){
444 CFMutableArrayRef handledKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
445 CFDictionaryForEach(circle_circle_messages_table
, ^(const void *key
, const void *value
) {
446 CFErrorRef circleMessageError
= NULL
;
447 if (!SOSAccountHandleCircleMessage(transport
->account
, key
, value
, &circleMessageError
)) {
448 secerror("Error handling circle message %@ (%@): %@", key
, value
, circleMessageError
);
451 CFStringRef circle_id
= (CFStringRef
) key
;
452 CFArrayAppendValue(handledKeys
, circle_id
);
454 CFReleaseNull(circleMessageError
);
460 static bool SOSTransportCircleTestSendChanges(SOSTransportCircleTestRef transport
, CFDictionaryRef changes
, CFErrorRef
*error
){
461 if(!transport
->changes
)
462 transport
->changes
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, CFDictionaryGetCount(changes
), changes
);
464 CFDictionaryForEach(changes
, ^(const void *key
, const void *value
) {
465 CFDictionarySetValue(transport
->changes
, key
, value
);
471 SOSAccountRef
SOSTransportCircleTestGetAccount(SOSTransportCircleTestRef transport
) {
472 return ((SOSTransportCircleRef
)transport
)->account
;
476 //MARK Message Test Transport
479 struct SOSTransportMessageTest
{
480 struct __OpaqueSOSTransportMessage m
;
481 CFMutableDictionaryRef changes
;
483 CFStringRef circleName
;
486 SOSTransportMessageTestRef
SOSTransportTestCreateMessage(SOSAccountRef account
, CFStringRef name
, CFStringRef circleName
){
487 SOSTransportMessageTestRef tpt
= (SOSTransportMessageTestRef
) SOSTransportMessageCreateForSubclass(sizeof(struct SOSTransportMessageTest
) - sizeof(CFRuntimeBase
), account
, circleName
, NULL
);
489 SOSEngineRef engine
= SOSDataSourceFactoryGetEngineForDataSourceName(account
->factory
, circleName
, NULL
);
491 tpt
->m
.engine
= CFRetainSafe(engine
);
493 tpt
->m
.sendMessages
= sendMessages
;
494 tpt
->m
.syncWithPeers
= syncWithPeers
;
495 tpt
->m
.flushChanges
= flushMessageChanges
;
496 tpt
->m
.cleanupAfterPeerMessages
= cleanupAfterPeer
;
497 tpt
->m
.destroy
= destroyMessageTransport
;
498 tpt
->m
.handleMessages
= handleMessages
;
499 // Initialize ourselves
500 tpt
->changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
501 tpt
->m
.account
= CFRetainSafe(account
);
502 tpt
->name
= CFRetainSafe(name
);
503 tpt
->circleName
= CFRetainSafe(circleName
);
504 if(!message_transports
)
505 message_transports
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, NULL
);
506 CFArrayAppendValue(message_transports
, (SOSTransportMessageRef
)tpt
);
507 SOSRegisterTransportMessage((SOSTransportMessageRef
)tpt
);
512 CFStringRef
SOSTransportMessageTestGetName(SOSTransportMessageTestRef transport
){
513 return transport
->name
;
516 void SOSTransportMessageTestSetName(SOSTransportMessageTestRef transport
, CFStringRef accountName
){
517 CFReleaseNull(transport
->name
);
518 transport
->name
= CFRetain(accountName
);
521 CFMutableDictionaryRef
SOSTransportMessageTestGetChanges(SOSTransportMessageTestRef transport
){
522 return transport
->changes
;
525 void SOSTransportMessageTestClearChanges(SOSTransportMessageTestRef transport
){
526 CFReleaseNull(transport
->changes
);
527 transport
->changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
531 static void destroyMessageTransport(SOSTransportMessageRef transport
){
532 SOSTransportMessageTestRef tkvs
= (SOSTransportMessageTestRef
)transport
;
534 SOSUnregisterTransportMessage(transport
);
536 CFArrayRemoveAllValue(message_transports
, tkvs
);
538 CFReleaseNull(tkvs
->circleName
);
539 CFReleaseNull(tkvs
->changes
);
540 CFReleaseNull(tkvs
->name
);
544 static void SOSTransportMessageTestAddBulkToChanges(SOSTransportMessageTestRef transport
, CFDictionaryRef updates
){
546 if (transport
->changes
== NULL
) {
547 transport
->changes
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, CFDictionaryGetCount(updates
), updates
);
551 CFDictionaryForEach(updates
, ^(const void *key
, const void *value
) {
552 CFDictionarySetValue(transport
->changes
, key
, value
);
557 static void SOSTransportMessageTestAddToChanges(SOSTransportMessageTestRef transport
, CFStringRef message_key
, CFDataRef message_data
){
558 if (transport
->changes
== NULL
) {
559 transport
->changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
561 if (message_data
== NULL
) {
562 CFDictionarySetValue(transport
->changes
, message_key
, kCFNull
);
564 CFDictionarySetValue(transport
->changes
, message_key
, message_data
);
568 static bool SOSTransportMessageTestCleanupAfterPeerMessages(SOSTransportMessageTestRef transport
, CFDictionaryRef circle_to_peer_ids
, CFErrorRef
*error
)
570 SOSEngineRef engine
= SOSTransportMessageGetEngine((SOSTransportMessageRef
)transport
);
571 require_quiet(engine
, fail
);
573 CFArrayRef enginePeers
= SOSEngineGetPeerIDs(engine
);
575 CFDictionaryForEach(circle_to_peer_ids
, ^(const void *key
, const void *value
) {
576 if (isString(key
) && isArray(value
)) {
577 CFStringRef circle_name
= (CFStringRef
) key
;
578 CFArrayRef peers_to_cleanup_after
= (CFArrayRef
) value
;
580 CFArrayForEach(peers_to_cleanup_after
, ^(const void *value
) {
581 if (isString(value
)) {
582 CFStringRef cleanup_id
= (CFStringRef
) value
;
583 // TODO: Since the enginePeers list is not authorative (the Account is) this could inadvertently clean up active peers or leave behind stale peers
584 if (enginePeers
) CFArrayForEach(enginePeers
, ^(const void *value
) {
585 if (isString(value
)) {
586 CFStringRef in_circle_id
= (CFStringRef
) value
;
588 CFStringRef kvsKey
= SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name
, cleanup_id
, in_circle_id
);
589 SOSTransportMessageTestAddToChanges(transport
, kvsKey
, NULL
);
590 CFReleaseSafe(kvsKey
);
592 kvsKey
= SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name
, in_circle_id
, cleanup_id
);
593 SOSTransportMessageTestAddToChanges(transport
, kvsKey
, NULL
);
594 CFReleaseSafe(kvsKey
);
603 return SOSTransportMessageFlushChanges((SOSTransportMessageRef
)transport
, error
);
608 static bool sendToPeer(SOSTransportMessageRef transport
, CFStringRef circleName
, CFStringRef peerID
, CFDataRef message
, CFErrorRef
*error
) {
609 SOSTransportMessageTestRef testTransport
= (SOSTransportMessageTestRef
) transport
;
611 CFStringRef message_to_peer_key
= SOSMessageKeyCreateFromTransportToPeer((SOSTransportMessageKVSRef
)transport
, peerID
);
612 CFDictionaryRef a_message_to_a_peer
= CFDictionaryCreateForCFTypes(NULL
, message_to_peer_key
, message
, NULL
);
614 SOSTransportMessageTestAddBulkToChanges((SOSTransportMessageTestRef
)testTransport
, a_message_to_a_peer
);
615 CFReleaseNull(a_message_to_a_peer
);
616 CFReleaseNull(message_to_peer_key
);
621 static bool syncWithPeers(SOSTransportMessageRef transport
, CFDictionaryRef circleToPeerIDs
, CFErrorRef
*error
){
622 // Each entry is keyed by circle name and contains a list of peerIDs
624 __block
bool result
= true;
626 CFDictionaryForEach(circleToPeerIDs
, ^(const void *key
, const void *value
) {
627 if (isString(key
) && isArray(value
)) {
628 CFStringRef circleName
= (CFStringRef
) key
;
629 CFArrayForEach(value
, ^(const void *value
) {
630 if (isString(value
)) {
631 CFStringRef peerID
= (CFStringRef
) value
;
632 SOSEngineRef engine
= SOSTransportMessageGetEngine(transport
);
633 SOSEngineWithPeerID(engine
, peerID
, error
, ^(SOSPeerRef peer
, SOSDataSourceRef dataSource
, SOSTransactionRef txn
, bool *forceSaveState
) {
634 SOSEnginePeerMessageSentBlock sent
= NULL
;
635 CFDataRef message_to_send
= NULL
;
636 bool ok
= SOSPeerCoderSendMessageIfNeeded(engine
, peer
, &message_to_send
, circleName
, peerID
, &sent
, error
);
637 if (message_to_send
) {
638 CFDictionaryRef peer_dict
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
, peerID
, message_to_send
, NULL
);
639 CFDictionarySetValue(SOSTransportMessageTestGetChanges((SOSTransportMessageTestRef
)transport
), circleName
, peer_dict
);
640 SOSPeerCoderConsume(&sent
, ok
);
641 CFReleaseSafe(peer_dict
);
644 CFReleaseSafe(message_to_send
);
654 static bool sendMessages(SOSTransportMessageRef transport
, CFDictionaryRef circleToPeersToMessage
, CFErrorRef
*error
) {
655 __block
bool result
= true;
657 CFDictionaryForEach(circleToPeersToMessage
, ^(const void *key
, const void *value
) {
658 if (isString(key
) && isDictionary(value
)) {
659 CFStringRef circleName
= (CFStringRef
) key
;
660 CFDictionaryForEach(value
, ^(const void *key
, const void *value
) {
661 if (isString(key
) && isData(value
)) {
662 CFStringRef peerID
= (CFStringRef
) key
;
663 CFDataRef message
= (CFDataRef
) value
;
664 bool rx
= sendToPeer(transport
, circleName
, peerID
, message
, error
);
674 static CF_RETURNS_RETAINED
675 CFDictionaryRef
handleMessages(SOSTransportMessageRef transport
, CFMutableDictionaryRef circle_peer_messages_table
, CFErrorRef
*error
) {
676 SOSTransportMessageTestRef tpt
= (SOSTransportMessageTestRef
)transport
;
677 CFMutableDictionaryRef handled
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
678 CFDictionaryRef peerToMessage
= CFDictionaryGetValue(circle_peer_messages_table
, tpt
->circleName
);
679 CFMutableArrayRef handled_peers
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
680 CFDictionaryAddValue(handled
, tpt
->circleName
, handled_peers
);
683 CFDictionaryForEach(peerToMessage
, ^(const void *key
, const void *value
) {
684 CFStringRef peer_id
= (CFStringRef
) key
;
685 CFDataRef peer_message
= (CFDataRef
) value
;
686 CFErrorRef localError
= NULL
;
688 if (SOSTransportMessageHandlePeerMessage((SOSTransportMessageRef
) transport
, peer_id
, peer_message
, &localError
)) {
689 CFArrayAppendValue(handled_peers
, key
);
691 secdebug("transport", "%@ KVSTransport handle message failed: %@", peer_id
, localError
);
693 CFReleaseNull(localError
);
696 CFReleaseNull(handled_peers
);
701 static bool flushMessageChanges(SOSTransportMessageRef transport
, CFErrorRef
*error
)
706 static bool cleanupAfterPeer(SOSTransportMessageRef transport
, CFDictionaryRef circle_to_peer_ids
, CFErrorRef
*error
)
708 return SOSTransportMessageTestCleanupAfterPeerMessages((SOSTransportMessageTestRef
) transport
, circle_to_peer_ids
, error
);
711 SOSAccountRef
SOSTransportMessageTestGetAccount(SOSTransportMessageTestRef transport
) {
712 return ((SOSTransportMessageRef
)transport
)->account
;
717 //MARK Message Test Transport
720 struct SOSTransportMessageIDSTest
{
721 struct __OpaqueSOSTransportMessage m
;
722 CFMutableDictionaryRef changes
;
724 CFStringRef circleName
;
729 // V-table implementation forward declarations
731 static bool sendToPeerIDSTest(SOSTransportMessageRef transport
, CFStringRef circleName
, CFStringRef deviceID
, CFStringRef peerID
, CFDataRef message
, CFErrorRef
*error
);
732 static bool syncWithPeersIDSTest(SOSTransportMessageRef transport
, CFDictionaryRef circleToPeerIDs
, CFErrorRef
*error
);
733 static bool sendMessagesIDSTest(SOSTransportMessageRef transport
, CFDictionaryRef circleToPeersToMessage
, CFErrorRef
*error
);
734 static void destroyIDSTest(SOSTransportMessageRef transport
);
735 static bool cleanupAfterPeerIDSTest(SOSTransportMessageRef transport
, CFDictionaryRef circle_to_peer_ids
, CFErrorRef
*error
);
736 static bool flushChangesIDSTest(SOSTransportMessageRef transport
, CFErrorRef
*error
);
737 static CF_RETURNS_RETAINED CFDictionaryRef
handleMessagesIDSTest(SOSTransportMessageRef transport
, CFMutableDictionaryRef circle_peer_messages_table
, CFErrorRef
*error
);
739 SOSTransportMessageIDSTestRef
SOSTransportMessageIDSTestCreate(SOSAccountRef account
, CFStringRef circleName
, CFErrorRef
*error
)
741 SOSTransportMessageIDSTestRef ids
= calloc(1, sizeof(struct SOSTransportMessageIDSTest
));
745 ids
->m
.sendMessages
= sendMessagesIDSTest
;
746 ids
->m
.syncWithPeers
= syncWithPeersIDSTest
;
747 ids
->m
.flushChanges
= flushChangesIDSTest
;
748 ids
->m
.cleanupAfterPeerMessages
= cleanupAfterPeerIDSTest
;
749 ids
->m
.destroy
= destroyIDSTest
;
750 ids
->m
.handleMessages
= handleMessagesIDSTest
;
751 // Initialize ourselves
753 SOSRegisterTransportMessage((SOSTransportMessageRef
)ids
);
757 static void destroyIDSTest(SOSTransportMessageRef transport
){
758 SOSUnregisterTransportMessage(transport
);
761 static CF_RETURNS_RETAINED
762 CFDictionaryRef
handleMessagesIDSTest(SOSTransportMessageRef transport
, CFMutableDictionaryRef message
, CFErrorRef
*error
) {
763 CFMutableDictionaryRef handled
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
764 CFMutableArrayRef handled_peers
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
767 CFDictionaryForEach(message
, ^(const void *key
, const void *value
) {
768 CFStringRef peer_id
= (CFStringRef
) key
;
769 CFDataRef peer_message
= (CFDataRef
) value
;
770 __block CFErrorRef localError
= NULL
;
772 //find the Peer ID if we are given a Device ID
773 SOSCircleRef circle
= SOSAccountGetCircle(transport
->account
, error
);
774 SOSCircleForEachPeer(circle
, ^(SOSPeerInfoRef peer
) {
775 CFStringRef deviceID
= SOSPeerInfoCopyDeviceID(peer
);
776 if(CFEqualSafe(deviceID
, peer_id
) || CFEqualSafe(SOSPeerInfoGetPeerID(peer
), peer_id
)){
777 CFStringRef peerID
= SOSPeerInfoGetPeerID(peer
);
779 if (SOSTransportMessageHandlePeerMessage(transport
, peerID
, peer_message
, &localError
)) {
780 CFArrayAppendValue(handled_peers
, key
);
782 secdebug("transport", "%@ IDSTransport handle message failed: %@", peer_id
, localError
);
785 CFReleaseNull(deviceID
);
787 CFReleaseNull(localError
);
790 CFDictionaryAddValue(handled
, transport
->circleName
, handled_peers
);
791 CFReleaseNull(handled_peers
);
796 static void SOSTransportMessageIDSTestAddBulkToChanges(SOSTransportMessageIDSTestRef transport
, CFDictionaryRef updates
){
798 if (transport
->changes
== NULL
) {
799 transport
->changes
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, CFDictionaryGetCount(updates
), updates
);
803 CFDictionaryForEach(updates
, ^(const void *key
, const void *value
) {
804 CFDictionarySetValue(transport
->changes
, key
, value
);
808 static bool sendToPeerIDSTest(SOSTransportMessageRef transport
, CFStringRef circleName
, CFStringRef deviceID
, CFStringRef peerID
, CFDataRef message
, CFErrorRef
*error
)
810 SOSTransportMessageIDSTestRef testTransport
= (SOSTransportMessageIDSTestRef
)transport
;
811 SOSEngineRef engine
= SOSTransportMessageGetEngine(transport
);
812 CFStringRef my_id
= SOSEngineGetMyID(engine
);
814 CFStringRef circle_to_transport_key
= SOSMessageKeyCreateWithCircleNameAndTransportType(circleName
, SOSTransportMessageTypeIDS
);
815 CFDictionaryRef a_message_to_a_peer
= CFDictionaryCreateForCFTypes(NULL
, my_id
, message
, NULL
);
817 CFDictionaryRef transport_to_messages
= CFDictionaryCreateForCFTypes(NULL
, circle_to_transport_key
, a_message_to_a_peer
, NULL
);
819 SOSTransportMessageIDSTestAddBulkToChanges(testTransport
, transport_to_messages
);
821 CFReleaseNull(a_message_to_a_peer
);
822 CFReleaseNull(transport_to_messages
);
823 CFReleaseNull(circle_to_transport_key
);
829 static bool syncWithPeersIDSTest(SOSTransportMessageRef transport
, CFDictionaryRef circleToPeerIDs
, CFErrorRef
*error
){
830 // Each entry is keyed by circle name and contains a list of peerIDs
831 __block
bool result
= true;
833 CFDictionaryForEach(circleToPeerIDs
, ^(const void *key
, const void *value
) {
834 if (isString(key
) && isArray(value
)) {
835 CFStringRef circleName
= (CFStringRef
) key
;
836 CFArrayForEach(value
, ^(const void *value
) {
837 if (isString(value
)) {
838 CFStringRef peerID
= (CFStringRef
) value
;
839 secnotice("transport", "IDS sync with peerIDs %@", peerID
);
840 result
&= SOSTransportMessageSendMessageIfNeeded(transport
, circleName
, peerID
, error
);
849 static bool sendMessagesIDSTest(SOSTransportMessageRef transport
, CFDictionaryRef circleToPeersToMessage
, CFErrorRef
*error
) {
850 __block
bool result
= true;
851 SOSCircleRef circle
= SOSAccountGetCircle(transport
->account
, error
);
853 CFDictionaryForEach(circleToPeersToMessage
, ^(const void *key
, const void *value
) {
854 if (isString(key
) && isDictionary(value
)) {
855 CFStringRef circleName
= (CFStringRef
) key
;
856 CFDictionaryForEach(value
, ^(const void *key
, const void *value
) {
857 if (isString(key
) && isData(value
)) {
858 CFStringRef peerID
= (CFStringRef
) key
;
859 CFDataRef message
= (CFDataRef
) value
;
860 SOSCircleForEachPeer(circle
, ^(SOSPeerInfoRef peer
) {
861 CFStringRef deviceID
= SOSPeerInfoCopyDeviceID(peer
);
862 if(CFEqualSafe(SOSPeerInfoGetPeerID(peer
), peerID
) || CFEqualSafe(deviceID
, peerID
)){
863 bool rx
= sendToPeerIDSTest(transport
, circleName
, deviceID
, peerID
, message
, error
);
865 CFReleaseNull(deviceID
);
867 CFReleaseNull(deviceID
);
877 static bool flushChangesIDSTest(SOSTransportMessageRef transport
, CFErrorRef
*error
)
882 static bool cleanupAfterPeerIDSTest(SOSTransportMessageRef transport
, CFDictionaryRef circle_to_peer_ids
, CFErrorRef
*error
)