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
, CFSetRef peers
, 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
, CFSetRef peers
, CFErrorRef
*error
){
636 // Each entry is keyed by circle name and contains a list of peerIDs
638 __block
bool result
= true;
640 CFStringRef circleName
= transport
->circleName
;
641 CFSetForEach(peers
, ^(const void *value
) {
642 CFStringRef peerID
= asString(value
, NULL
);
645 SOSEngineRef engine
= SOSTransportMessageGetEngine(transport
);
646 SOSEngineWithPeerID(engine
, peerID
, error
, ^(SOSPeerRef peer
, SOSCoderRef coder
, SOSDataSourceRef dataSource
, SOSTransactionRef txn
, bool *forceSaveState
) {
647 SOSEnginePeerMessageSentBlock sent
= NULL
;
648 CFDataRef message_to_send
= NULL
;
649 bool ok
= SOSPeerCoderSendMessageIfNeeded(engine
, txn
, peer
, coder
, &message_to_send
, peerID
, &sent
, error
);
650 if (message_to_send
) {
651 CFDictionaryRef peer_dict
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
, peerID
, message_to_send
, NULL
);
652 CFDictionarySetValue(SOSTransportMessageTestGetChanges((SOSTransportMessageTestRef
)transport
), circleName
, peer_dict
);
653 SOSPeerCoderConsume(&sent
, ok
);
654 CFReleaseSafe(peer_dict
);
657 CFReleaseSafe(message_to_send
);
665 static bool sendMessages(SOSTransportMessageRef transport
, CFDictionaryRef peersToMessage
, CFErrorRef
*error
) {
666 __block
bool result
= true;
668 CFStringRef circleName
= transport
->circleName
;
669 CFDictionaryForEach(peersToMessage
, ^(const void *key
, const void *value
) {
670 if (isString(key
) && isData(value
)) {
671 CFStringRef peerID
= (CFStringRef
) key
;
672 CFDataRef message
= (CFDataRef
) value
;
673 bool rx
= sendToPeer(transport
, circleName
, peerID
, message
, error
);
681 static CF_RETURNS_RETAINED
682 CFDictionaryRef
handleMessages(SOSTransportMessageRef transport
, CFMutableDictionaryRef circle_peer_messages_table
, CFErrorRef
*error
) {
683 SOSTransportMessageTestRef tpt
= (SOSTransportMessageTestRef
)transport
;
684 CFMutableDictionaryRef handled
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
685 CFDictionaryRef peerToMessage
= CFDictionaryGetValue(circle_peer_messages_table
, tpt
->circleName
);
686 CFMutableArrayRef handled_peers
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
687 CFDictionaryAddValue(handled
, tpt
->circleName
, handled_peers
);
690 CFDictionaryForEach(peerToMessage
, ^(const void *key
, const void *value
) {
691 CFStringRef peer_id
= (CFStringRef
) key
;
692 CFDataRef peer_message
= (CFDataRef
) value
;
693 CFErrorRef localError
= NULL
;
695 if (SOSTransportMessageHandlePeerMessage((SOSTransportMessageRef
) transport
, peer_id
, peer_message
, &localError
)) {
696 CFArrayAppendValue(handled_peers
, key
);
698 secdebug("transport", "%@ KVSTransport handle message failed: %@", peer_id
, localError
);
700 CFReleaseNull(localError
);
703 CFReleaseNull(handled_peers
);
708 static bool flushMessageChanges(SOSTransportMessageRef transport
, CFErrorRef
*error
)
713 static bool cleanupAfterPeer(SOSTransportMessageRef transport
, CFDictionaryRef circle_to_peer_ids
, CFErrorRef
*error
)
715 return SOSTransportMessageTestCleanupAfterPeerMessages((SOSTransportMessageTestRef
) transport
, circle_to_peer_ids
, error
);
718 SOSAccountRef
SOSTransportMessageTestGetAccount(SOSTransportMessageRef transport
) {
719 return ((SOSTransportMessageRef
)transport
)->account
;
724 //MARK Message Test Transport
727 struct SOSTransportMessageIDSTest
{
728 struct __OpaqueSOSTransportMessage m
;
729 CFBooleanRef useFragmentation
;
730 CFMutableDictionaryRef changes
;
732 CFStringRef circleName
;
736 // V-table implementation forward declarations
738 static bool sendDataToPeerIDSTest(SOSTransportMessageRef transport
, CFStringRef circleName
, CFStringRef deviceID
, CFStringRef peerID
, CFDataRef message
, CFErrorRef
*error
);
739 static bool sendDictionaryToPeerIDSTest(SOSTransportMessageRef transport
, CFStringRef circleName
, CFStringRef deviceID
, CFStringRef peerID
, CFDictionaryRef message
, CFErrorRef
*error
);
741 static bool syncWithPeersIDSTest(SOSTransportMessageRef transport
, CFSetRef peers
, CFErrorRef
*error
);
742 static bool sendMessagesIDSTest(SOSTransportMessageRef transport
, CFDictionaryRef circleToPeersToMessage
, CFErrorRef
*error
);
743 static void destroyIDSTest(SOSTransportMessageRef transport
);
744 static bool cleanupAfterPeerIDSTest(SOSTransportMessageRef transport
, CFDictionaryRef circle_to_peer_ids
, CFErrorRef
*error
);
745 static bool flushChangesIDSTest(SOSTransportMessageRef transport
, CFErrorRef
*error
);
746 static CF_RETURNS_RETAINED CFDictionaryRef
handleMessagesIDSTest(SOSTransportMessageRef transport
, CFMutableDictionaryRef circle_peer_messages_table
, CFErrorRef
*error
);
747 static CFStringRef
copyIDSTestDescription(SOSTransportMessageRef object
);
748 static CFIndex
getIDSTestTransportType(SOSTransportMessageRef transport
, CFErrorRef
*error
);
752 SOSTransportMessageIDSTestRef
SOSTransportMessageIDSTestCreate(SOSAccountRef account
, CFStringRef accountName
, CFStringRef circleName
, CFErrorRef
*error
)
755 SOSTransportMessageIDSTestRef ids
= (SOSTransportMessageIDSTestRef
) SOSTransportMessageCreateForSubclass(sizeof(struct SOSTransportMessageIDSTest
) - sizeof(CFRuntimeBase
), account
, circleName
, NULL
);
760 ids
->m
.sendMessages
= sendMessagesIDSTest
;
761 ids
->m
.syncWithPeers
= syncWithPeersIDSTest
;
762 ids
->m
.flushChanges
= flushChangesIDSTest
;
763 ids
->m
.cleanupAfterPeerMessages
= cleanupAfterPeerIDSTest
;
764 ids
->m
.destroy
= destroyIDSTest
;
765 ids
->m
.handleMessages
= handleMessagesIDSTest
;
766 ids
->m
.copyDescription
= copyIDSTestDescription
;
767 ids
->m
.getName
= SOSTransportMessageIDSTestGetName
;
768 ids
->m
.getTransportType
= getIDSTestTransportType
;
769 ids
->useFragmentation
= kCFBooleanTrue
;
771 // Initialize ourselves
772 ids
->changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
773 ids
->circleName
= CFRetainSafe(circleName
);
774 ids
->name
= CFRetainSafe(accountName
);
776 if(!message_transports
)
777 message_transports
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, NULL
);
778 CFArrayAppendValue(message_transports
, (SOSTransportMessageRef
)ids
);
779 SOSRegisterTransportMessage((SOSTransportMessageRef
)ids
);
784 CFMutableDictionaryRef
SOSTransportMessageIDSTestGetChanges(SOSTransportMessageRef transport
){
785 return ((SOSTransportMessageIDSTestRef
)transport
)->changes
;
788 static CFStringRef
copyIDSTestDescription(SOSTransportMessageRef transport
){
789 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%@,%@,%@,%ld"),transport
->circleName
, transport
->account
, transport
->getName(transport
), transport
->getTransportType(transport
, NULL
));
792 CFStringRef
SOSTransportMessageIDSTestGetName(SOSTransportMessageRef transport
){
793 return ((SOSTransportMessageIDSTestRef
)transport
)->name
;
796 static CFIndex
getIDSTestTransportType(SOSTransportMessageRef transport
, CFErrorRef
*error
){
800 static void destroyIDSTest(SOSTransportMessageRef transport
){
801 SOSUnregisterTransportMessage(transport
);
804 void SOSTransportMessageIDSTestSetName(SOSTransportMessageRef transport
, CFStringRef accountName
){
805 SOSTransportMessageIDSTestRef t
= (SOSTransportMessageIDSTestRef
)transport
;
806 t
->name
= accountName
;
809 static CF_RETURNS_RETAINED
810 CFDictionaryRef
handleMessagesIDSTest(SOSTransportMessageRef transport
, CFMutableDictionaryRef message
, CFErrorRef
*error
) {
812 CFMutableDictionaryRef handled
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
813 CFDictionaryRef peerToMessage
= CFDictionaryGetValue(message
, transport
->circleName
);
814 CFMutableArrayRef handled_peers
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
816 secerror("Received IDS message!");
818 CFDictionaryForEach(peerToMessage
, ^(const void *key
, const void *value
) {
819 CFStringRef peer_id
= asString(key
, NULL
);
820 CFDataRef peer_message
= asData(value
, NULL
);
821 CFErrorRef localError
= NULL
;
823 if (peer_id
&& peer_message
&& SOSTransportMessageHandlePeerMessage(transport
, peer_id
, peer_message
, &localError
)) {
824 CFArrayAppendValue(handled_peers
, key
);
826 secnotice("transport", "%@ KVSTransport handle message failed: %@", peer_id
, localError
);
828 CFReleaseNull(localError
);
831 CFDictionaryAddValue(handled
, transport
->circleName
, handled_peers
);
832 CFReleaseNull(handled_peers
);
837 static void SOSTransportMessageIDSTestAddBulkToChanges(SOSTransportMessageIDSTestRef transport
, CFDictionaryRef updates
){
839 if (transport
->changes
== NULL
) {
840 transport
->changes
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, CFDictionaryGetCount(updates
), updates
);
844 CFDictionaryForEach(updates
, ^(const void *key
, const void *value
) {
845 CFDictionaryAddValue(transport
->changes
, key
, value
);
849 static bool sendDataToPeerIDSTest(SOSTransportMessageRef transport
, CFStringRef circleName
, CFStringRef deviceID
, CFStringRef peerID
, CFDataRef message
, CFErrorRef
*error
)
851 SOSTransportMessageIDSTestRef testTransport
= (SOSTransportMessageIDSTestRef
)transport
;
853 secerror("sending message through test transport: %@", message
);
854 CFStringRef message_to_peer_key
= SOSMessageKeyCreateFromTransportToPeer(transport
, peerID
);
855 CFDictionaryRef a_message_to_a_peer
= CFDictionaryCreateForCFTypes(NULL
, message_to_peer_key
, message
, NULL
);
857 SOSTransportMessageIDSTestAddBulkToChanges(testTransport
, a_message_to_a_peer
);
859 CFReleaseNull(message_to_peer_key
);
860 CFReleaseNull(a_message_to_a_peer
);
864 static bool sendDictionaryToPeerIDSTest(SOSTransportMessageRef transport
, CFStringRef circleName
, CFStringRef deviceID
, CFStringRef peerID
, CFDictionaryRef message
, CFErrorRef
*error
)
866 SOSTransportMessageIDSTestRef testTransport
= (SOSTransportMessageIDSTestRef
)transport
;
868 secerror("sending message through test transport: %@", message
);
869 CFStringRef message_to_peer_key
= SOSMessageKeyCreateFromTransportToPeer(transport
, peerID
);
870 CFDictionaryRef a_message_to_a_peer
= CFDictionaryCreateForCFTypes(NULL
, message_to_peer_key
, message
, NULL
);
872 SOSTransportMessageIDSTestAddBulkToChanges(testTransport
, a_message_to_a_peer
);
874 CFReleaseNull(message_to_peer_key
);
875 CFReleaseNull(a_message_to_a_peer
);
880 static bool syncWithPeersIDSTest(SOSTransportMessageRef transport
, CFSetRef peerIDs
, CFErrorRef
*error
){
881 // Each entry is keyed by circle name and contains a list of peerIDs
882 __block
bool result
= true;
884 CFSetForEach(peerIDs
, ^(const void *value
) {
885 CFStringRef peerID
= asString(value
, NULL
);
887 secnotice("transport", "IDS sync with peerIDs %@", peerID
);
888 result
&= SOSTransportMessageSendMessageIfNeeded(transport
, transport
->circleName
, peerID
, error
);
895 static bool sendMessagesIDSTest(SOSTransportMessageRef transport
, CFDictionaryRef peersToMessage
, CFErrorRef
*error
) {
897 __block
bool result
= true;
898 SOSAccountRef account
= transport
->account
;
900 CFDictionaryForEach(peersToMessage
, ^(const void *key
, const void *value
) {
901 CFStringRef idsDeviceID
= NULL
;;
902 CFStringRef peerID
= asString(key
, NULL
);
903 SOSPeerInfoRef pi
= NULL
;
904 require(peerID
, done
);
905 require(!CFEqualSafe(peerID
, SOSAccountGetMyPeerID(account
)), done
);
907 pi
= SOSAccountCopyPeerWithID(account
, peerID
, NULL
);
910 idsDeviceID
= SOSPeerInfoCopyDeviceID(pi
);
911 require(idsDeviceID
, done
);
913 CFDictionaryRef messageDictionary
= asDictionary(value
, NULL
);
914 if (messageDictionary
) {
915 result
&= sendDictionaryToPeerIDSTest(transport
, transport
->circleName
, idsDeviceID
, peerID
, messageDictionary
, error
);
917 CFDataRef messageData
= asData(value
, NULL
);
919 result
&= sendDataToPeerIDSTest(transport
, transport
->circleName
, idsDeviceID
, peerID
, messageData
, error
);
923 CFReleaseNull(idsDeviceID
);
931 static bool flushChangesIDSTest(SOSTransportMessageRef transport
, CFErrorRef
*error
)
936 static bool cleanupAfterPeerIDSTest(SOSTransportMessageRef transport
, CFDictionaryRef circle_to_peer_ids
, CFErrorRef
*error
)
941 void SOSTransportMessageIDSTestClearChanges(SOSTransportMessageRef transport
){
942 SOSTransportMessageIDSTestRef ids
= (SOSTransportMessageIDSTestRef
)transport
;
943 CFReleaseNull(ids
->changes
);
945 ids
->changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);