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 CFMutableArrayRef key_transports
= NULL
;
52 CFMutableArrayRef circle_transports
= NULL
;
53 CFMutableArrayRef message_transports
= NULL
;
55 void SOSAccountUpdateTestTransports(SOSAccountRef account
, CFDictionaryRef gestalt
){
56 CFStringRef new_name
= (CFStringRef
)CFDictionaryGetValue(gestalt
, kPIUserDefinedDeviceNameKey
);
58 SOSTransportKeyParameterTestSetName((SOSTransportKeyParameterTestRef
)account
->key_transport
, new_name
);
59 SOSTransportCircleTestSetName((SOSTransportCircleTestRef
)account
->circle_transport
, new_name
);
60 SOSTransportMessageTestSetName((SOSTransportMessageTestRef
)account
->kvs_message_transport
, new_name
);
64 static SOSCircleRef
SOSAccountEnsureCircleTest(SOSAccountRef a
, CFStringRef name
, CFStringRef accountName
, CFErrorRef
*error
)
66 CFErrorRef localError
= NULL
;
68 SOSCircleRef circle
= SOSAccountGetCircle(a
, &localError
);
70 require_action_quiet(circle
|| !isSOSErrorCoded(localError
, kSOSErrorIncompatibleCircle
), fail
,
71 if (error
) { *error
= localError
; localError
= NULL
; });
74 circle
= SOSCircleCreate(NULL
, name
, NULL
);
76 CFRetainAssign(a
->trusted_circle
, circle
);
78 circle
= SOSAccountGetCircle(a
, &localError
);
81 require_quiet(SOSAccountInflateTestTransportsForCircle(a
, name
, accountName
, &localError
), fail
);
82 require_quiet(SOSAccountHasFullPeerInfo(a
, &localError
), fail
);
85 CFReleaseNull(localError
);
89 bool SOSAccountEnsureFactoryCirclesTest(SOSAccountRef a
, CFStringRef accountName
)
94 require(a
->factory
, xit
);
95 CFStringRef circle_name
= SOSDataSourceFactoryCopyName(a
->factory
);
96 require(circle_name
, xit
);
98 SOSAccountEnsureCircleTest(a
, (CFStringRef
)circle_name
, accountName
, NULL
);
100 CFReleaseNull(circle_name
);
107 bool SOSAccountInflateTestTransportsForCircle(SOSAccountRef account
, CFStringRef circleName
, CFStringRef accountName
, CFErrorRef
*error
){
108 bool success
= false;
109 SOSTransportCircleTestRef tCircle
= NULL
;
110 SOSTransportMessageTestRef tMessage
= NULL
;
112 if(account
->key_transport
== NULL
){
113 account
->key_transport
= (SOSTransportKeyParameterRef
)SOSTransportTestCreateKeyParameter(account
, accountName
, circleName
);
114 require_quiet(account
->key_transport
, fail
);
116 if(account
->circle_transport
== NULL
){
117 tCircle
= SOSTransportTestCreateCircle(account
, accountName
, circleName
);
118 require_quiet(tCircle
, fail
);
119 CFRetainAssign(account
->circle_transport
, (SOSTransportCircleRef
)tCircle
);
121 if(account
->kvs_message_transport
== NULL
){
122 tMessage
= SOSTransportTestCreateMessage(account
, accountName
, circleName
);
123 require_quiet(tMessage
, fail
);
124 CFRetainAssign(account
->kvs_message_transport
, (SOSTransportMessageRef
)tMessage
);
129 CFReleaseNull(tCircle
);
130 CFReleaseNull(tMessage
);
135 //Mark Test Key Parameter Transport
138 struct SOSTransportKeyParameterTest
{
139 struct __OpaqueSOSTransportKeyParameter k
;
140 CFMutableDictionaryRef changes
;
142 CFStringRef circleName
;
145 SOSTransportKeyParameterTestRef
SOSTransportTestCreateKeyParameter(SOSAccountRef account
, CFStringRef name
, CFStringRef circleName
){
147 SOSTransportKeyParameterTestRef tpt
= (SOSTransportKeyParameterTestRef
) SOSTransportKeyParameterCreateForSubclass(sizeof(struct SOSTransportKeyParameterTest
) - sizeof(CFRuntimeBase
), account
, NULL
);
149 tpt
->name
= CFRetainSafe(name
);
150 tpt
->changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
151 tpt
->k
.account
= CFRetainSafe(account
);
152 tpt
->k
.destroy
= destroyKeyParameters
;
153 tpt
->circleName
= CFRetainSafe(circleName
);
154 tpt
->k
.publishCloudParameters
= publishCloudParameters
;
155 tpt
->k
.handleKeyParameterChanges
= handleKeyParameterChanges
;
156 tpt
->k
.setToNewAccount
= setToNewAccount
;
158 key_transports
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, NULL
);
159 CFArrayAppendValue(key_transports
, (SOSTransportKeyParameterRef
)tpt
);
161 SOSRegisterTransportKeyParameter((SOSTransportKeyParameterRef
)tpt
);
165 static bool handleKeyParameterChanges(SOSTransportKeyParameterRef transport
, CFDataRef data
, CFErrorRef error
){
166 SOSAccountRef account
= transport
->account
;
167 return SOSAccountHandleParametersChange(account
, data
, &error
);
170 static void destroyKeyParameters(SOSTransportKeyParameterRef transport
){
171 SOSTransportKeyParameterTestRef tpt
= (SOSTransportKeyParameterTestRef
)transport
;
173 CFArrayRemoveAllValue(key_transports
, tpt
);
174 SOSUnregisterTransportKeyParameter(transport
);
176 CFReleaseNull(tpt
->changes
);
177 CFReleaseNull(tpt
->name
);
178 CFReleaseNull(tpt
->circleName
);
182 static bool setToNewAccount(SOSTransportKeyParameterRef transport
, SOSAccountRef a
){
183 SOSTransportKeyParameterTestRef tpt
= (SOSTransportKeyParameterTestRef
)transport
;
184 CFStringRef accountName
= SOSTransportKeyParameterTestGetName(tpt
);
186 SOSAccountSetToNew(a
);
188 CFReleaseNull(a
->key_transport
);
189 CFReleaseNull(a
->circle_transport
);
190 CFReleaseNull(a
->kvs_message_transport
);
191 CFReleaseNull(a
->ids_message_transport
);
193 SOSAccountEnsureFactoryCirclesTest(a
, accountName
);
197 CFStringRef
SOSTransportKeyParameterTestGetName(SOSTransportKeyParameterTestRef transport
){
198 return transport
->name
;
201 void SOSTransportKeyParameterTestSetName(SOSTransportKeyParameterTestRef transport
, CFStringRef accountName
){
202 CFReleaseNull(transport
->name
);
203 transport
->name
= CFRetain(accountName
);
206 SOSAccountRef
SOSTransportKeyParameterTestGetAccount(SOSTransportKeyParameterTestRef transport
){
207 return ((SOSTransportKeyParameterRef
)transport
)->account
;
210 CFMutableDictionaryRef
SOSTransportKeyParameterTestGetChanges(SOSTransportKeyParameterTestRef transport
){
211 return transport
->changes
;
214 void SOSTransportKeyParameterTestClearChanges(SOSTransportKeyParameterTestRef transport
){
215 CFReleaseNull(transport
->changes
);
216 transport
->changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
219 static bool publishCloudParameters(SOSTransportKeyParameterRef transport
, CFDataRef data
, CFErrorRef
* error
)
221 return SOSTransportKeyParameterTestPublishCloudParameters((SOSTransportKeyParameterTestRef
)transport
, data
, error
);
224 static bool SOSTransportKeyParameterTestPublishCloudParameters(SOSTransportKeyParameterTestRef transport
, CFDataRef newParameters
, CFErrorRef
*error
)
226 if(!transport
->changes
)
227 transport
->changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
229 CFDictionarySetValue(transport
->changes
, kSOSKVSKeyParametersKey
, newParameters
);
235 //MARK: Test Circle Transport
237 struct SOSTransportCircleTest
{
238 struct __OpaqueSOSTransportCircle c
;
239 CFMutableDictionaryRef changes
;
241 CFStringRef circleName
;
243 static CFStringRef
SOSTransportCircleCopyDescription(SOSTransportCircleTestRef transport
) {
245 return CFStringCreateWithFormat(NULL
, NULL
, CFSTR("<SOSTransportCircle@%p\n>"), transport
);
248 static CFStringRef
copyDescription(SOSTransportCircleRef transport
){
249 return SOSTransportCircleCopyDescription((SOSTransportCircleTestRef
)transport
);
252 CFStringRef
SOSTransportCircleTestGetName(SOSTransportCircleTestRef transport
){
253 return transport
->name
;
255 void SOSTransportCircleTestSetName(SOSTransportCircleTestRef transport
, CFStringRef accountName
){
256 CFReleaseNull(transport
->name
);
257 transport
->name
= CFRetain(accountName
);
260 CFMutableDictionaryRef
SOSTransportCircleTestGetChanges(SOSTransportCircleTestRef transport
){
261 return transport
->changes
;
264 void SOSTransportCircleTestClearChanges(SOSTransportCircleTestRef transport
){
265 CFReleaseNull(transport
->changes
);
266 transport
->changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
269 SOSTransportCircleTestRef
SOSTransportTestCreateCircle(SOSAccountRef account
, CFStringRef name
, CFStringRef circleName
){
270 SOSTransportCircleTestRef tpt
= (SOSTransportCircleTestRef
) SOSTransportCircleCreateForSubclass(sizeof(struct SOSTransportCircleTest
) - sizeof(CFRuntimeBase
), account
, NULL
);
273 tpt
->c
.account
= CFRetainSafe(account
);
274 tpt
->c
.copyDescription
= copyDescription
;
275 tpt
->c
.expireRetirementRecords
= expireRetirementRecords
;
276 tpt
->c
.postCircle
= postCircle
;
277 tpt
->c
.postRetirement
= postRetirement
;
278 tpt
->c
.flushChanges
= flushChanges
;
279 tpt
->c
.handleRetirementMessages
= handleRetirementMessages
;
280 tpt
->c
.handleCircleMessages
= handleCircleMessages
;
281 tpt
->c
.destroy
= destroy
;
282 tpt
->c
.flushRingChanges
= flushRingChanges
;
283 tpt
->c
.postRing
= postRing
;
284 tpt
->c
.sendDebugInfo
= sendDebugInfo
;
285 tpt
->c
.sendPeerInfo
= sendPeerInfo
;
286 tpt
->changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
287 tpt
->name
= CFRetainSafe(name
);
288 tpt
->circleName
= CFRetainSafe(circleName
);
289 if(!circle_transports
)
290 circle_transports
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, NULL
);
291 CFArrayAppendValue(circle_transports
, (SOSTransportCircleRef
)tpt
);
293 SOSRegisterTransportCircle((SOSTransportCircleRef
)tpt
);
299 static void destroy(SOSTransportCircleRef transport
){
300 SOSTransportCircleTestRef tkvs
= (SOSTransportCircleTestRef
)transport
;
301 CFArrayRemoveAllValue(circle_transports
, tkvs
);
303 SOSUnregisterTransportCircle(transport
);
305 CFReleaseNull(tkvs
->changes
);
306 CFReleaseNull(tkvs
->name
);
307 CFReleaseNull(tkvs
->circleName
);
310 static bool sendPeerInfo(SOSTransportCircleRef transport
, CFStringRef peerID
, CFDataRef peerInfoData
, CFErrorRef
*error
){
311 SOSTransportCircleTestRef testTransport
= (SOSTransportCircleTestRef
)transport
;
312 CFMutableDictionaryRef changes
= SOSTransportCircleTestGetChanges(testTransport
);
313 CFDictionaryAddValue(changes
, peerID
, peerInfoData
);
316 static bool flushRingChanges(SOSTransportCircleRef transport
, CFErrorRef
* error
){
319 static bool postRing(SOSTransportCircleRef transport
, CFStringRef ringName
, CFDataRef ring
, CFErrorRef
*error
){
320 SOSTransportCircleTestRef testTransport
= (SOSTransportCircleTestRef
)transport
;
321 CFStringRef ringKey
= SOSRingKeyCreateWithName(ringName
, error
);
322 CFMutableDictionaryRef changes
= SOSTransportCircleTestGetChanges(testTransport
);
323 CFDictionaryAddValue(changes
, ringKey
, ring
);
324 CFReleaseNull(ringKey
);
328 static bool sendDebugInfo(SOSTransportCircleRef transport
, CFStringRef type
, CFTypeRef debugInfo
, CFErrorRef
*error
){
329 SOSTransportCircleTestRef testTransport
= (SOSTransportCircleTestRef
)transport
;
330 CFMutableDictionaryRef changes
= SOSTransportCircleTestGetChanges(testTransport
);
331 CFDictionaryAddValue(changes
, type
, debugInfo
);
335 static inline bool postRetirement(SOSTransportCircleRef transport
, CFStringRef circleName
, CFStringRef peer_id
, CFDataRef retirement_data
, CFErrorRef
*error
)
337 CFStringRef retirement_key
= SOSRetirementKeyCreateWithCircleNameAndPeer(circleName
, peer_id
);
339 SOSTransportCircleTestAddToChanges((SOSTransportCircleTestRef
)transport
, retirement_key
, retirement_data
);
341 CFReleaseNull(retirement_key
);
345 static inline bool flushChanges(SOSTransportCircleRef transport
, CFErrorRef
*error
)
350 static void SOSTransportCircleTestAddToChanges(SOSTransportCircleTestRef transport
, CFStringRef message_key
, CFDataRef message_data
){
352 if (transport
->changes
== NULL
) {
353 transport
->changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
355 if (message_data
== NULL
) {
356 CFDictionarySetValue(transport
->changes
, message_key
, kCFNull
);
358 CFDictionarySetValue(transport
->changes
, message_key
, message_data
);
360 secnotice("circle-changes", "Adding circle change %@ %@->%@", transport
->name
, message_key
, message_data
);
363 static void SOSTransportCircleTestAddBulkToChanges(SOSTransportCircleTestRef transport
, CFDictionaryRef updates
){
365 if (transport
->changes
== NULL
) {
366 transport
->changes
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, CFDictionaryGetCount(updates
), updates
);
370 CFDictionaryForEach(updates
, ^(const void *key
, const void *value
) {
371 CFDictionarySetValue(transport
->changes
, key
, value
);
377 static bool expireRetirementRecords(SOSTransportCircleRef transport
, CFDictionaryRef retirements
, CFErrorRef
*error
) {
380 SOSTransportCircleTestRef tpt
= (SOSTransportCircleTestRef
)transport
;
381 CFMutableDictionaryRef keysToWrite
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
383 CFDictionaryForEach(retirements
, ^(const void *key
, const void *value
) {
384 if (isString(key
) && isArray(value
)) {
385 CFStringRef circle_name
= (CFStringRef
) key
;
386 CFArrayRef retirees
= (CFArrayRef
) value
;
388 CFArrayForEach(retirees
, ^(const void *value
) {
389 if (isString(value
)) {
390 CFStringRef retiree_id
= (CFStringRef
) value
;
392 CFStringRef kvsKey
= SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name
, retiree_id
);
394 CFDictionaryAddValue(keysToWrite
, kvsKey
, kCFNull
);
396 CFReleaseSafe(kvsKey
);
402 if(CFDictionaryGetCount(keysToWrite
)) {
403 SOSTransportCircleTestAddBulkToChanges(tpt
, keysToWrite
);
405 CFReleaseNull(keysToWrite
);
410 __unused
static bool SOSTransportCircleTestUpdateRetirementRecords(SOSTransportCircleTestRef transport
, CFDictionaryRef updates
, CFErrorRef
* error
){
411 CFErrorRef updateError
= NULL
;
412 bool success
= false;
413 if (SOSTransportCircleTestSendChanges((SOSTransportCircleTestRef
)transport
, updates
, &updateError
)){
416 SOSCreateErrorWithFormat(kSOSErrorSendFailure
, updateError
, error
, NULL
,
417 CFSTR("update parameters key failed [%@]"), updates
);
422 bool SOSTransportCircleTestRemovePendingChange(SOSTransportCircleRef transport
, CFStringRef circleName
, CFErrorRef
*error
){
423 SOSTransportCircleTestRef tkvs
= (SOSTransportCircleTestRef
)transport
;
424 CFStringRef circle_key
= SOSCircleKeyCreateWithName(circleName
, error
);
426 CFDictionaryRemoveValue(tkvs
->changes
, circle_key
);
427 CFReleaseNull(circle_key
);
431 static bool postCircle(SOSTransportCircleRef transport
, CFStringRef circleName
, CFDataRef circle_data
, CFErrorRef
*error
){
432 SOSTransportCircleTestRef tkvs
= (SOSTransportCircleTestRef
)transport
;
433 CFStringRef circle_key
= SOSCircleKeyCreateWithName(circleName
, error
);
435 SOSTransportCircleTestAddToChanges(tkvs
, circle_key
, circle_data
);
436 CFReleaseNull(circle_key
);
441 static CF_RETURNS_RETAINED CFDictionaryRef
handleRetirementMessages(SOSTransportCircleRef transport
, CFMutableDictionaryRef circle_retirement_messages_table
, CFErrorRef
*error
){
442 SOSAccountRef account
= transport
->account
;
444 return SOSAccountHandleRetirementMessages(account
, circle_retirement_messages_table
, error
);
447 static CFArrayRef
handleCircleMessages(SOSTransportCircleRef transport
, CFMutableDictionaryRef circle_circle_messages_table
, CFErrorRef
*error
){
448 CFMutableArrayRef handledKeys
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
449 CFDictionaryForEach(circle_circle_messages_table
, ^(const void *key
, const void *value
) {
450 CFErrorRef circleMessageError
= NULL
;
451 if (!SOSAccountHandleCircleMessage(transport
->account
, key
, value
, &circleMessageError
)) {
452 secerror("Error handling circle message %@ (%@): %@", key
, value
, circleMessageError
);
455 CFStringRef circle_id
= (CFStringRef
) key
;
456 CFArrayAppendValue(handledKeys
, circle_id
);
458 CFReleaseNull(circleMessageError
);
464 static bool SOSTransportCircleTestSendChanges(SOSTransportCircleTestRef transport
, CFDictionaryRef changes
, CFErrorRef
*error
){
465 if(!transport
->changes
)
466 transport
->changes
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, CFDictionaryGetCount(changes
), changes
);
468 CFDictionaryForEach(changes
, ^(const void *key
, const void *value
) {
469 CFDictionarySetValue(transport
->changes
, key
, value
);
475 SOSAccountRef
SOSTransportCircleTestGetAccount(SOSTransportCircleTestRef transport
) {
476 return ((SOSTransportCircleRef
)transport
)->account
;
480 //MARK Message Test Transport
483 static CFIndex
getKVSTestTransportType(SOSTransportMessageRef transport
, CFErrorRef
*error
);
486 struct SOSTransportMessageTest
{
487 struct __OpaqueSOSTransportMessage m
;
488 CFMutableDictionaryRef changes
;
490 CFStringRef circleName
;
493 SOSTransportMessageTestRef
SOSTransportTestCreateMessage(SOSAccountRef account
, CFStringRef name
, CFStringRef circleName
){
494 SOSTransportMessageTestRef tpt
= (SOSTransportMessageTestRef
) SOSTransportMessageCreateForSubclass(sizeof(struct SOSTransportMessageTest
) - sizeof(CFRuntimeBase
), account
, circleName
, NULL
);
496 SOSEngineRef engine
= SOSDataSourceFactoryGetEngineForDataSourceName(account
->factory
, circleName
, NULL
);
498 tpt
->m
.engine
= CFRetainSafe(engine
);
500 tpt
->m
.sendMessages
= sendMessages
;
501 tpt
->m
.syncWithPeers
= syncWithPeers
;
502 tpt
->m
.flushChanges
= flushMessageChanges
;
503 tpt
->m
.cleanupAfterPeerMessages
= cleanupAfterPeer
;
504 tpt
->m
.destroy
= destroyMessageTransport
;
505 tpt
->m
.handleMessages
= handleMessages
;
506 // Initialize ourselves
507 tpt
->changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
508 tpt
->m
.account
= CFRetainSafe(account
);
509 tpt
->name
= CFRetainSafe(name
);
510 tpt
->circleName
= CFRetainSafe(circleName
);
511 tpt
->m
.getTransportType
= getKVSTestTransportType
;
514 if(!message_transports
)
515 message_transports
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, NULL
);
516 CFArrayAppendValue(message_transports
, (SOSTransportMessageRef
)tpt
);
517 SOSRegisterTransportMessage((SOSTransportMessageRef
)tpt
);
523 static CFIndex
getKVSTestTransportType(SOSTransportMessageRef transport
, CFErrorRef
*error
){
526 CFStringRef
SOSTransportMessageTestGetName(SOSTransportMessageTestRef transport
){
527 return transport
->name
;
530 void SOSTransportMessageTestSetName(SOSTransportMessageTestRef transport
, CFStringRef accountName
){
531 CFReleaseNull(transport
->name
);
532 transport
->name
= CFRetain(accountName
);
535 CFMutableDictionaryRef
SOSTransportMessageTestGetChanges(SOSTransportMessageTestRef transport
){
536 return transport
->changes
;
539 void SOSTransportMessageTestClearChanges(SOSTransportMessageTestRef transport
){
540 CFReleaseNull(transport
->changes
);
541 transport
->changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
545 static void destroyMessageTransport(SOSTransportMessageRef transport
){
546 SOSTransportMessageTestRef tkvs
= (SOSTransportMessageTestRef
)transport
;
548 SOSUnregisterTransportMessage(transport
);
550 CFArrayRemoveAllValue(message_transports
, tkvs
);
552 CFReleaseNull(tkvs
->circleName
);
553 CFReleaseNull(tkvs
->changes
);
554 CFReleaseNull(tkvs
->name
);
558 static void SOSTransportMessageTestAddBulkToChanges(SOSTransportMessageTestRef transport
, CFDictionaryRef updates
){
560 if (transport
->changes
== NULL
) {
561 transport
->changes
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, CFDictionaryGetCount(updates
), updates
);
565 CFDictionaryForEach(updates
, ^(const void *key
, const void *value
) {
566 CFDictionarySetValue(transport
->changes
, key
, value
);
571 static void SOSTransportMessageTestAddToChanges(SOSTransportMessageTestRef transport
, CFStringRef message_key
, CFDataRef message_data
){
572 if (transport
->changes
== NULL
) {
573 transport
->changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
575 if (message_data
== NULL
) {
576 CFDictionarySetValue(transport
->changes
, message_key
, kCFNull
);
578 CFDictionarySetValue(transport
->changes
, message_key
, message_data
);
582 static bool SOSTransportMessageTestCleanupAfterPeerMessages(SOSTransportMessageTestRef transport
, CFDictionaryRef circle_to_peer_ids
, CFErrorRef
*error
)
584 SOSEngineRef engine
= SOSTransportMessageGetEngine((SOSTransportMessageRef
)transport
);
585 require_quiet(engine
, fail
);
587 CFArrayRef enginePeers
= SOSEngineGetPeerIDs(engine
);
589 CFDictionaryForEach(circle_to_peer_ids
, ^(const void *key
, const void *value
) {
590 if (isString(key
) && isArray(value
)) {
591 CFStringRef circle_name
= (CFStringRef
) key
;
592 CFArrayRef peers_to_cleanup_after
= (CFArrayRef
) value
;
594 CFArrayForEach(peers_to_cleanup_after
, ^(const void *value
) {
595 if (isString(value
)) {
596 CFStringRef cleanup_id
= (CFStringRef
) value
;
597 // TODO: Since the enginePeers list is not authorative (the Account is) this could inadvertently clean up active peers or leave behind stale peers
598 if (enginePeers
) CFArrayForEach(enginePeers
, ^(const void *value
) {
599 if (isString(value
)) {
600 CFStringRef in_circle_id
= (CFStringRef
) value
;
602 CFStringRef kvsKey
= SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name
, cleanup_id
, in_circle_id
);
603 SOSTransportMessageTestAddToChanges(transport
, kvsKey
, NULL
);
604 CFReleaseSafe(kvsKey
);
606 kvsKey
= SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name
, in_circle_id
, cleanup_id
);
607 SOSTransportMessageTestAddToChanges(transport
, kvsKey
, NULL
);
608 CFReleaseSafe(kvsKey
);
617 return SOSTransportMessageFlushChanges((SOSTransportMessageRef
)transport
, error
);
622 static bool sendToPeer(SOSTransportMessageRef transport
, CFStringRef circleName
, CFStringRef peerID
, CFDataRef message
, CFErrorRef
*error
) {
623 SOSTransportMessageTestRef testTransport
= (SOSTransportMessageTestRef
) transport
;
625 CFStringRef message_to_peer_key
= SOSMessageKeyCreateFromTransportToPeer(transport
, peerID
);
626 CFDictionaryRef a_message_to_a_peer
= CFDictionaryCreateForCFTypes(NULL
, message_to_peer_key
, message
, NULL
);
628 SOSTransportMessageTestAddBulkToChanges((SOSTransportMessageTestRef
)testTransport
, a_message_to_a_peer
);
629 CFReleaseNull(a_message_to_a_peer
);
630 CFReleaseNull(message_to_peer_key
);
635 static bool syncWithPeers(SOSTransportMessageRef transport
, CFDictionaryRef circleToPeerIDs
, CFErrorRef
*error
){
636 // Each entry is keyed by circle name and contains a list of peerIDs
638 __block
bool result
= true;
640 CFDictionaryForEach(circleToPeerIDs
, ^(const void *key
, const void *value
) {
641 if (isString(key
) && isArray(value
)) {
642 CFStringRef circleName
= (CFStringRef
) key
;
643 CFArrayForEach(value
, ^(const void *value
) {
644 if (isString(value
)) {
645 CFStringRef peerID
= (CFStringRef
) value
;
646 SOSEngineRef engine
= SOSTransportMessageGetEngine(transport
);
647 SOSEngineWithPeerID(engine
, peerID
, error
, ^(SOSPeerRef peer
, SOSCoderRef coder
, SOSDataSourceRef dataSource
, SOSTransactionRef txn
, bool *forceSaveState
) {
648 SOSEnginePeerMessageSentBlock sent
= NULL
;
649 CFDataRef message_to_send
= NULL
;
650 bool ok
= SOSPeerCoderSendMessageIfNeeded(engine
, txn
, peer
, coder
, &message_to_send
, circleName
, peerID
, &sent
, error
);
651 if (message_to_send
) {
652 CFDictionaryRef peer_dict
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
, peerID
, message_to_send
, NULL
);
653 CFDictionarySetValue(SOSTransportMessageTestGetChanges((SOSTransportMessageTestRef
)transport
), circleName
, peer_dict
);
654 SOSPeerCoderConsume(&sent
, ok
);
655 CFReleaseSafe(peer_dict
);
658 CFReleaseSafe(message_to_send
);
668 static bool sendMessages(SOSTransportMessageRef transport
, CFDictionaryRef circleToPeersToMessage
, CFErrorRef
*error
) {
669 __block
bool result
= true;
671 CFDictionaryForEach(circleToPeersToMessage
, ^(const void *key
, const void *value
) {
672 if (isString(key
) && isDictionary(value
)) {
673 CFStringRef circleName
= (CFStringRef
) key
;
674 CFDictionaryForEach(value
, ^(const void *key
, const void *value
) {
675 if (isString(key
) && isData(value
)) {
676 CFStringRef peerID
= (CFStringRef
) key
;
677 CFDataRef message
= (CFDataRef
) value
;
678 bool rx
= sendToPeer(transport
, circleName
, peerID
, message
, error
);
688 static CF_RETURNS_RETAINED
689 CFDictionaryRef
handleMessages(SOSTransportMessageRef transport
, CFMutableDictionaryRef circle_peer_messages_table
, CFErrorRef
*error
) {
690 SOSTransportMessageTestRef tpt
= (SOSTransportMessageTestRef
)transport
;
691 CFMutableDictionaryRef handled
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
692 CFDictionaryRef peerToMessage
= CFDictionaryGetValue(circle_peer_messages_table
, tpt
->circleName
);
693 CFMutableArrayRef handled_peers
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
694 CFDictionaryAddValue(handled
, tpt
->circleName
, handled_peers
);
697 CFDictionaryForEach(peerToMessage
, ^(const void *key
, const void *value
) {
698 CFStringRef peer_id
= (CFStringRef
) key
;
699 CFDataRef peer_message
= (CFDataRef
) value
;
700 CFErrorRef localError
= NULL
;
702 if (SOSTransportMessageHandlePeerMessage((SOSTransportMessageRef
) transport
, peer_id
, peer_message
, &localError
)) {
703 CFArrayAppendValue(handled_peers
, key
);
705 secdebug("transport", "%@ KVSTransport handle message failed: %@", peer_id
, localError
);
707 CFReleaseNull(localError
);
710 CFReleaseNull(handled_peers
);
715 static bool flushMessageChanges(SOSTransportMessageRef transport
, CFErrorRef
*error
)
720 static bool cleanupAfterPeer(SOSTransportMessageRef transport
, CFDictionaryRef circle_to_peer_ids
, CFErrorRef
*error
)
722 return SOSTransportMessageTestCleanupAfterPeerMessages((SOSTransportMessageTestRef
) transport
, circle_to_peer_ids
, error
);
725 SOSAccountRef
SOSTransportMessageTestGetAccount(SOSTransportMessageRef transport
) {
726 return ((SOSTransportMessageRef
)transport
)->account
;
731 //MARK Message Test Transport
734 struct SOSTransportMessageIDSTest
{
735 struct __OpaqueSOSTransportMessage m
;
736 CFBooleanRef useFragmentation
;
737 CFMutableDictionaryRef changes
;
739 CFStringRef circleName
;
743 // V-table implementation forward declarations
745 static bool sendDataToPeerIDSTest(SOSTransportMessageRef transport
, CFStringRef circleName
, CFStringRef deviceID
, CFStringRef peerID
, CFDataRef message
, CFErrorRef
*error
);
746 static bool sendDictionaryToPeerIDSTest(SOSTransportMessageRef transport
, CFStringRef circleName
, CFStringRef deviceID
, CFStringRef peerID
, CFDictionaryRef message
, CFErrorRef
*error
);
748 static bool syncWithPeersIDSTest(SOSTransportMessageRef transport
, CFDictionaryRef circleToPeerIDs
, CFErrorRef
*error
);
749 static bool sendMessagesIDSTest(SOSTransportMessageRef transport
, CFDictionaryRef circleToPeersToMessage
, CFErrorRef
*error
);
750 static void destroyIDSTest(SOSTransportMessageRef transport
);
751 static bool cleanupAfterPeerIDSTest(SOSTransportMessageRef transport
, CFDictionaryRef circle_to_peer_ids
, CFErrorRef
*error
);
752 static bool flushChangesIDSTest(SOSTransportMessageRef transport
, CFErrorRef
*error
);
753 static CF_RETURNS_RETAINED CFDictionaryRef
handleMessagesIDSTest(SOSTransportMessageRef transport
, CFMutableDictionaryRef circle_peer_messages_table
, CFErrorRef
*error
);
754 static CFStringRef
copyIDSTestDescription(SOSTransportMessageRef object
);
755 static CFIndex
getIDSTestTransportType(SOSTransportMessageRef transport
, CFErrorRef
*error
);
759 SOSTransportMessageIDSTestRef
SOSTransportMessageIDSTestCreate(SOSAccountRef account
, CFStringRef accountName
, CFStringRef circleName
, CFErrorRef
*error
)
762 SOSTransportMessageIDSTestRef ids
= (SOSTransportMessageIDSTestRef
) SOSTransportMessageCreateForSubclass(sizeof(struct SOSTransportMessageIDSTest
) - sizeof(CFRuntimeBase
), account
, circleName
, NULL
);
767 ids
->m
.sendMessages
= sendMessagesIDSTest
;
768 ids
->m
.syncWithPeers
= syncWithPeersIDSTest
;
769 ids
->m
.flushChanges
= flushChangesIDSTest
;
770 ids
->m
.cleanupAfterPeerMessages
= cleanupAfterPeerIDSTest
;
771 ids
->m
.destroy
= destroyIDSTest
;
772 ids
->m
.handleMessages
= handleMessagesIDSTest
;
773 ids
->m
.copyDescription
= copyIDSTestDescription
;
774 ids
->m
.getName
= SOSTransportMessageIDSTestGetName
;
775 ids
->m
.getTransportType
= getIDSTestTransportType
;
776 ids
->useFragmentation
= kCFBooleanTrue
;
778 // Initialize ourselves
779 ids
->changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
780 ids
->circleName
= CFRetainSafe(circleName
);
781 ids
->name
= CFRetainSafe(accountName
);
783 if(!message_transports
)
784 message_transports
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, NULL
);
785 CFArrayAppendValue(message_transports
, (SOSTransportMessageRef
)ids
);
786 SOSRegisterTransportMessage((SOSTransportMessageRef
)ids
);
791 CFMutableDictionaryRef
SOSTransportMessageIDSTestGetChanges(SOSTransportMessageRef transport
){
792 return ((SOSTransportMessageIDSTestRef
)transport
)->changes
;
795 static CFStringRef
copyIDSTestDescription(SOSTransportMessageRef transport
){
796 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%@,%@,%@,%ld"),transport
->circleName
, transport
->account
, transport
->getName(transport
), transport
->getTransportType(transport
, NULL
));
799 CFStringRef
SOSTransportMessageIDSTestGetName(SOSTransportMessageRef transport
){
800 return ((SOSTransportMessageIDSTestRef
)transport
)->name
;
803 static CFIndex
getIDSTestTransportType(SOSTransportMessageRef transport
, CFErrorRef
*error
){
807 static void destroyIDSTest(SOSTransportMessageRef transport
){
808 SOSUnregisterTransportMessage(transport
);
811 void SOSTransportMessageIDSTestSetName(SOSTransportMessageRef transport
, CFStringRef accountName
){
812 SOSTransportMessageIDSTestRef t
= (SOSTransportMessageIDSTestRef
)transport
;
813 t
->name
= accountName
;
816 static CF_RETURNS_RETAINED
817 CFDictionaryRef
handleMessagesIDSTest(SOSTransportMessageRef transport
, CFMutableDictionaryRef message
, CFErrorRef
*error
) {
819 CFMutableDictionaryRef handled
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
820 CFDictionaryRef peerToMessage
= CFDictionaryGetValue(message
, transport
->circleName
);
821 CFMutableArrayRef handled_peers
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
823 secerror("Received IDS message!");
825 CFDictionaryForEach(peerToMessage
, ^(const void *key
, const void *value
) {
826 CFStringRef peer_id
= asString(key
, NULL
);
827 CFDataRef peer_message
= asData(value
, NULL
);
828 CFErrorRef localError
= NULL
;
830 if (peer_id
&& peer_message
&& SOSTransportMessageHandlePeerMessage(transport
, peer_id
, peer_message
, &localError
)) {
831 CFArrayAppendValue(handled_peers
, key
);
833 secnotice("transport", "%@ KVSTransport handle message failed: %@", peer_id
, localError
);
835 CFReleaseNull(localError
);
838 CFDictionaryAddValue(handled
, transport
->circleName
, handled_peers
);
839 CFReleaseNull(handled_peers
);
844 static void SOSTransportMessageIDSTestAddBulkToChanges(SOSTransportMessageIDSTestRef transport
, CFDictionaryRef updates
){
846 if (transport
->changes
== NULL
) {
847 transport
->changes
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, CFDictionaryGetCount(updates
), updates
);
851 CFDictionaryForEach(updates
, ^(const void *key
, const void *value
) {
852 CFDictionaryAddValue(transport
->changes
, key
, value
);
856 static bool sendDataToPeerIDSTest(SOSTransportMessageRef transport
, CFStringRef circleName
, CFStringRef deviceID
, CFStringRef peerID
, CFDataRef message
, CFErrorRef
*error
)
858 SOSTransportMessageIDSTestRef testTransport
= (SOSTransportMessageIDSTestRef
)transport
;
860 secerror("sending message through test transport: %@", message
);
861 CFStringRef message_to_peer_key
= SOSMessageKeyCreateFromTransportToPeer(transport
, peerID
);
862 CFDictionaryRef a_message_to_a_peer
= CFDictionaryCreateForCFTypes(NULL
, message_to_peer_key
, message
, NULL
);
864 SOSTransportMessageIDSTestAddBulkToChanges(testTransport
, a_message_to_a_peer
);
866 CFReleaseNull(message_to_peer_key
);
867 CFReleaseNull(a_message_to_a_peer
);
871 static bool sendDictionaryToPeerIDSTest(SOSTransportMessageRef transport
, CFStringRef circleName
, CFStringRef deviceID
, CFStringRef peerID
, CFDictionaryRef message
, CFErrorRef
*error
)
873 SOSTransportMessageIDSTestRef testTransport
= (SOSTransportMessageIDSTestRef
)transport
;
875 secerror("sending message through test transport: %@", message
);
876 CFStringRef message_to_peer_key
= SOSMessageKeyCreateFromTransportToPeer(transport
, peerID
);
877 CFDictionaryRef a_message_to_a_peer
= CFDictionaryCreateForCFTypes(NULL
, message_to_peer_key
, message
, NULL
);
879 SOSTransportMessageIDSTestAddBulkToChanges(testTransport
, a_message_to_a_peer
);
881 CFReleaseNull(message_to_peer_key
);
882 CFReleaseNull(a_message_to_a_peer
);
887 static bool syncWithPeersIDSTest(SOSTransportMessageRef transport
, CFDictionaryRef circleToPeerIDs
, CFErrorRef
*error
){
888 // Each entry is keyed by circle name and contains a list of peerIDs
889 __block
bool result
= true;
891 CFDictionaryForEach(circleToPeerIDs
, ^(const void *key
, const void *value
) {
892 if (isString(key
) && isArray(value
)) {
893 CFStringRef circleName
= (CFStringRef
) key
;
894 CFArrayForEach(value
, ^(const void *value
) {
895 if (isString(value
)) {
896 CFStringRef peerID
= (CFStringRef
) value
;
897 secnotice("transport", "IDS sync with peerIDs %@", peerID
);
898 result
&= SOSTransportMessageSendMessageIfNeeded(transport
, circleName
, peerID
, error
);
907 static bool sendMessagesIDSTest(SOSTransportMessageRef transport
, CFDictionaryRef circleToPeersToMessage
, CFErrorRef
*error
) {
909 __block
bool result
= true;
910 SOSCircleRef circle
= SOSAccountGetCircle(transport
->account
, error
);
911 SOSPeerInfoRef myPeer
= SOSAccountGetMyPeerInfo(transport
->account
);
912 __block CFStringRef peerID
= NULL
;
913 require_quiet(myPeer
, fail
);
915 CFDictionaryForEach(circleToPeersToMessage
, ^(const void *key
, const void *value
) {
916 if (isString(key
) && isDictionary(value
)) {
917 CFStringRef circleName
= (CFStringRef
) key
;
919 CFDictionaryForEach(value
, ^(const void *key1
, const void *value1
) {
920 if (isString(key1
) && isDictionary(value1
)) {
921 peerID
= (CFStringRef
) key1
;
922 CFMutableDictionaryRef message
= CFRetainSafe((CFMutableDictionaryRef
) value1
);
923 SOSCircleForEachPeer(circle
, ^(SOSPeerInfoRef peer
) {
924 if(!CFEqualSafe(myPeer
, peer
)){
925 CFStringRef deviceID
= SOSPeerInfoCopyDeviceID(peer
);
926 if(CFStringCompare(SOSPeerInfoGetPeerID(peer
), peerID
, 0) == 0){
928 rx
= sendDictionaryToPeerIDSTest(transport
, circleName
, deviceID
, peerID
, message
, error
);
931 CFReleaseNull(deviceID
);
936 peerID
= (CFStringRef
) key1
;
937 CFDataRef message
= CFRetainSafe((CFDataRef
) value1
);
939 SOSCircleForEachPeer(circle
, ^(SOSPeerInfoRef peer
) {
940 if(!CFEqualSafe(myPeer
, peer
)){
942 CFStringRef deviceID
= SOSPeerInfoCopyDeviceID(peer
);
943 if(CFStringCompare(SOSPeerInfoGetPeerID(peer
), peerID
, 0) == 0){
945 rx
= sendDataToPeerIDSTest(transport
, circleName
, deviceID
, peerID
, message
, error
);
948 CFReleaseNull(deviceID
);
959 static bool flushChangesIDSTest(SOSTransportMessageRef transport
, CFErrorRef
*error
)
964 static bool cleanupAfterPeerIDSTest(SOSTransportMessageRef transport
, CFDictionaryRef circle_to_peer_ids
, CFErrorRef
*error
)
969 void SOSTransportMessageIDSTestClearChanges(SOSTransportMessageRef transport
){
970 SOSTransportMessageIDSTestRef ids
= (SOSTransportMessageIDSTestRef
)transport
;
971 CFReleaseNull(ids
->changes
);
973 ids
->changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);