]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/Regressions/SOSTransportTestTransports.c
Security-57337.20.44.tar.gz
[apple/security.git] / OSX / sec / securityd / Regressions / SOSTransportTestTransports.c
1 #include <CoreFoundation/CoreFoundation.h>
2 #include <CoreFoundation/CFRuntime.h>
3
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>
14
15 #include "SOSTransportTestTransports.h"
16
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);
25
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);
29
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);
36
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);
41
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);
45
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);
50
51 void SOSAccountUpdateTestTransports(SOSAccountRef account, CFDictionaryRef gestalt){
52 CFStringRef new_name = (CFStringRef)CFDictionaryGetValue(gestalt, kPIUserDefinedDeviceNameKey);
53
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);
57
58 }
59
60 static SOSCircleRef SOSAccountEnsureCircleTest(SOSAccountRef a, CFStringRef name, CFStringRef accountName, CFErrorRef *error)
61 {
62 CFErrorRef localError = NULL;
63
64 SOSCircleRef circle = SOSAccountGetCircle(a, &localError);
65
66 require_action_quiet(circle || !isSOSErrorCoded(localError, kSOSErrorIncompatibleCircle), fail,
67 if (error) { *error = localError; localError = NULL; });
68
69 if(NULL == circle){
70 circle = SOSCircleCreate(NULL, name, NULL);
71 if (circle){
72 CFRetainAssign(a->trusted_circle, circle);
73 CFRelease(circle);
74 circle = SOSAccountGetCircle(a, &localError);
75 }
76 }
77 require_quiet(SOSAccountInflateTestTransportsForCircle(a, name, accountName, &localError), fail);
78 require_quiet(SOSAccountHasFullPeerInfo(a, &localError), fail);
79
80 fail:
81 CFReleaseNull(localError);
82 return circle;
83 }
84
85 bool SOSAccountEnsureFactoryCirclesTest(SOSAccountRef a, CFStringRef accountName)
86 {
87 bool result = false;
88 if (a)
89 {
90 require(a->factory, xit);
91 CFStringRef circle_name = SOSDataSourceFactoryCopyName(a->factory);
92 require(circle_name, xit);
93
94 SOSAccountEnsureCircleTest(a, (CFStringRef)circle_name, accountName, NULL);
95
96 CFReleaseNull(circle_name);
97 result = true;
98 }
99 xit:
100 return result;
101 }
102
103 bool SOSAccountInflateTestTransportsForCircle(SOSAccountRef account, CFStringRef circleName, CFStringRef accountName, CFErrorRef *error){
104 bool success = false;
105 SOSTransportCircleTestRef tCircle = NULL;
106 SOSTransportMessageTestRef tMessage = NULL;
107
108 if(account->key_transport == NULL){
109 account->key_transport = (SOSTransportKeyParameterRef)SOSTransportTestCreateKeyParameter(account, accountName, circleName);
110 require_quiet(account->key_transport, fail);
111 }
112 if(account->circle_transport == NULL){
113 tCircle = SOSTransportTestCreateCircle(account, accountName, circleName);
114 require_quiet(tCircle, fail);
115 CFRetainAssign(account->circle_transport, (SOSTransportCircleRef)tCircle);
116 }
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);
121 }
122
123 success = true;
124 fail:
125 CFReleaseNull(tCircle);
126 CFReleaseNull(tMessage);
127 return success;
128 }
129
130 ///
131 //Mark Test Key Parameter Transport
132 ///
133
134 struct SOSTransportKeyParameterTest{
135 struct __OpaqueSOSTransportKeyParameter k;
136 CFMutableDictionaryRef changes;
137 CFStringRef name;
138 CFStringRef circleName;
139 };
140
141 SOSTransportKeyParameterTestRef SOSTransportTestCreateKeyParameter(SOSAccountRef account, CFStringRef name, CFStringRef circleName){
142
143 SOSTransportKeyParameterTestRef tpt = (SOSTransportKeyParameterTestRef) SOSTransportKeyParameterCreateForSubclass(sizeof(struct SOSTransportKeyParameterTest) - sizeof(CFRuntimeBase), account, NULL);
144
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;
153 if(!key_transports)
154 key_transports = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
155 CFArrayAppendValue(key_transports, (SOSTransportKeyParameterRef)tpt);
156
157 SOSRegisterTransportKeyParameter((SOSTransportKeyParameterRef)tpt);
158 return tpt;
159 }
160
161 static bool handleKeyParameterChanges(SOSTransportKeyParameterRef transport, CFDataRef data, CFErrorRef error){
162 SOSAccountRef account = transport->account;
163 return SOSAccountHandleParametersChange(account, data, &error);
164 }
165
166 static void destroyKeyParameters(SOSTransportKeyParameterRef transport){
167 SOSTransportKeyParameterTestRef tpt = (SOSTransportKeyParameterTestRef)transport;
168
169 CFArrayRemoveAllValue(key_transports, tpt);
170 SOSUnregisterTransportKeyParameter(transport);
171
172 CFReleaseNull(tpt->changes);
173 CFReleaseNull(tpt->name);
174 CFReleaseNull(tpt->circleName);
175 }
176
177
178 static bool setToNewAccount(SOSTransportKeyParameterRef transport, SOSAccountRef a){
179 SOSTransportKeyParameterTestRef tpt = (SOSTransportKeyParameterTestRef)transport;
180 CFStringRef accountName = SOSTransportKeyParameterTestGetName(tpt);
181
182 SOSAccountSetToNew(a);
183
184 CFReleaseNull(a->key_transport);
185 CFReleaseNull(a->circle_transport);
186 CFReleaseNull(a->kvs_message_transport);
187 CFReleaseNull(a->ids_message_transport);
188
189 SOSAccountEnsureFactoryCirclesTest(a, accountName);
190
191 return true;
192 }
193 CFStringRef SOSTransportKeyParameterTestGetName(SOSTransportKeyParameterTestRef transport){
194 return transport->name;
195 }
196
197 void SOSTransportKeyParameterTestSetName(SOSTransportKeyParameterTestRef transport, CFStringRef accountName){
198 CFReleaseNull(transport->name);
199 transport->name = CFRetain(accountName);
200 }
201
202 SOSAccountRef SOSTransportKeyParameterTestGetAccount(SOSTransportKeyParameterTestRef transport){
203 return ((SOSTransportKeyParameterRef)transport)->account;
204 }
205
206 CFMutableDictionaryRef SOSTransportKeyParameterTestGetChanges(SOSTransportKeyParameterTestRef transport){
207 return transport->changes;
208 }
209
210 void SOSTransportKeyParameterTestClearChanges(SOSTransportKeyParameterTestRef transport){
211 CFReleaseNull(transport->changes);
212 transport->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
213 }
214
215 static bool publishCloudParameters(SOSTransportKeyParameterRef transport, CFDataRef data, CFErrorRef* error)
216 {
217 return SOSTransportKeyParameterTestPublishCloudParameters((SOSTransportKeyParameterTestRef)transport, data, error);
218 }
219
220 static bool SOSTransportKeyParameterTestPublishCloudParameters(SOSTransportKeyParameterTestRef transport, CFDataRef newParameters, CFErrorRef *error)
221 {
222 if(!transport->changes)
223 transport->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
224
225 CFDictionarySetValue(transport->changes, kSOSKVSKeyParametersKey, newParameters);
226
227 return true;
228 }
229
230 ///
231 //MARK: Test Circle Transport
232 ///
233 struct SOSTransportCircleTest{
234 struct __OpaqueSOSTransportCircle c;
235 CFMutableDictionaryRef changes;
236 CFStringRef name;
237 CFStringRef circleName;
238 };
239 static CFStringRef SOSTransportCircleCopyDescription(SOSTransportCircleTestRef transport) {
240
241 return CFStringCreateWithFormat(NULL, NULL, CFSTR("<SOSTransportCircle@%p\n>"), transport);
242 }
243
244 static CFStringRef copyDescription(SOSTransportCircleRef transport){
245 return SOSTransportCircleCopyDescription((SOSTransportCircleTestRef)transport);
246 }
247
248 CFStringRef SOSTransportCircleTestGetName(SOSTransportCircleTestRef transport){
249 return transport->name;
250 }
251 void SOSTransportCircleTestSetName(SOSTransportCircleTestRef transport, CFStringRef accountName){
252 CFReleaseNull(transport->name);
253 transport->name = CFRetain(accountName);
254 }
255
256 CFMutableDictionaryRef SOSTransportCircleTestGetChanges(SOSTransportCircleTestRef transport){
257 return transport->changes;
258 }
259
260 void SOSTransportCircleTestClearChanges(SOSTransportCircleTestRef transport){
261 CFReleaseNull(transport->changes);
262 transport->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
263 }
264
265 SOSTransportCircleTestRef SOSTransportTestCreateCircle(SOSAccountRef account, CFStringRef name, CFStringRef circleName){
266 SOSTransportCircleTestRef tpt = (SOSTransportCircleTestRef) SOSTransportCircleCreateForSubclass(sizeof(struct SOSTransportCircleTest) - sizeof(CFRuntimeBase), account, NULL);
267
268 if(tpt){
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);
288
289 SOSRegisterTransportCircle((SOSTransportCircleRef)tpt);
290 }
291
292 return tpt;
293 }
294
295 static void destroy(SOSTransportCircleRef transport){
296 SOSTransportCircleTestRef tkvs = (SOSTransportCircleTestRef)transport;
297 CFArrayRemoveAllValue(circle_transports, tkvs);
298
299 SOSUnregisterTransportCircle(transport);
300
301 CFReleaseNull(tkvs->changes);
302 CFReleaseNull(tkvs->name);
303 CFReleaseNull(tkvs->circleName);
304 }
305
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);
310 return true;
311 }
312 static bool flushRingChanges(SOSTransportCircleRef transport, CFErrorRef* error){
313 return true;
314 }
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);
321 return true;
322 }
323
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);
328 return true;
329 }
330
331 static inline bool postRetirement(SOSTransportCircleRef transport, CFStringRef circleName, CFStringRef peer_id, CFDataRef retirement_data, CFErrorRef *error)
332 {
333 CFStringRef retirement_key = SOSRetirementKeyCreateWithCircleNameAndPeer(circleName, peer_id);
334 if (retirement_key)
335 SOSTransportCircleTestAddToChanges((SOSTransportCircleTestRef)transport, retirement_key, retirement_data);
336
337 CFReleaseNull(retirement_key);
338 return true;
339 }
340
341 static inline bool flushChanges(SOSTransportCircleRef transport, CFErrorRef *error)
342 {
343 return true;
344 }
345
346 static void SOSTransportCircleTestAddToChanges(SOSTransportCircleTestRef transport, CFStringRef message_key, CFDataRef message_data){
347
348 if (transport->changes == NULL) {
349 transport->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
350 }
351 if (message_data == NULL) {
352 CFDictionarySetValue(transport->changes, message_key, kCFNull);
353 } else {
354 CFDictionarySetValue(transport->changes, message_key, message_data);
355 }
356 secnotice("circle-changes", "Adding circle change %@ %@->%@", transport->name, message_key, message_data);
357 }
358
359 static void SOSTransportCircleTestAddBulkToChanges(SOSTransportCircleTestRef transport, CFDictionaryRef updates){
360
361 if (transport->changes == NULL) {
362 transport->changes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(updates), updates);
363
364 }
365 else{
366 CFDictionaryForEach(updates, ^(const void *key, const void *value) {
367 CFDictionarySetValue(transport->changes, key, value);
368 });
369 }
370 }
371
372
373 static bool expireRetirementRecords(SOSTransportCircleRef transport, CFDictionaryRef retirements, CFErrorRef *error) {
374
375 bool success = true;
376 SOSTransportCircleTestRef tpt = (SOSTransportCircleTestRef)transport;
377 CFMutableDictionaryRef keysToWrite = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
378
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;
383
384 CFArrayForEach(retirees, ^(const void *value) {
385 if (isString(value)) {
386 CFStringRef retiree_id = (CFStringRef) value;
387
388 CFStringRef kvsKey = SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name, retiree_id);
389
390 CFDictionaryAddValue(keysToWrite, kvsKey, kCFNull);
391
392 CFReleaseSafe(kvsKey);
393 }
394 });
395 }
396 });
397
398 if(CFDictionaryGetCount(keysToWrite)) {
399 SOSTransportCircleTestAddBulkToChanges(tpt, keysToWrite);
400 }
401 CFReleaseNull(keysToWrite);
402
403 return success;
404 }
405
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)){
410 success = true;
411 } else {
412 SOSCreateErrorWithFormat(kSOSErrorSendFailure, updateError, error, NULL,
413 CFSTR("update parameters key failed [%@]"), updates);
414 }
415 return success;
416 }
417
418 bool SOSTransportCircleTestRemovePendingChange(SOSTransportCircleRef transport, CFStringRef circleName, CFErrorRef *error){
419 SOSTransportCircleTestRef tkvs = (SOSTransportCircleTestRef)transport;
420 CFStringRef circle_key = SOSCircleKeyCreateWithName(circleName, error);
421 if (circle_key)
422 CFDictionaryRemoveValue(tkvs->changes, circle_key);
423 CFReleaseNull(circle_key);
424 return true;
425 }
426
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);
430 if (circle_key)
431 SOSTransportCircleTestAddToChanges(tkvs, circle_key, circle_data);
432 CFReleaseNull(circle_key);
433
434 return true;
435 }
436
437 static CF_RETURNS_RETAINED CFDictionaryRef handleRetirementMessages(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_retirement_messages_table, CFErrorRef *error){
438 SOSAccountRef account = transport->account;
439
440 return SOSAccountHandleRetirementMessages(account, circle_retirement_messages_table, error);
441 }
442
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);
449 }
450 else{
451 CFStringRef circle_id = (CFStringRef) key;
452 CFArrayAppendValue(handledKeys, circle_id);
453 }
454 CFReleaseNull(circleMessageError);
455 });
456
457 return handledKeys;
458 }
459
460 static bool SOSTransportCircleTestSendChanges(SOSTransportCircleTestRef transport, CFDictionaryRef changes, CFErrorRef *error){
461 if(!transport->changes)
462 transport->changes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(changes), changes);
463 else{
464 CFDictionaryForEach(changes, ^(const void *key, const void *value) {
465 CFDictionarySetValue(transport->changes, key, value);
466 });
467 }
468 return true;
469 }
470
471 SOSAccountRef SOSTransportCircleTestGetAccount(SOSTransportCircleTestRef transport) {
472 return ((SOSTransportCircleRef)transport)->account;
473 }
474
475 ///
476 //MARK Message Test Transport
477 ///
478
479 struct SOSTransportMessageTest{
480 struct __OpaqueSOSTransportMessage m;
481 CFMutableDictionaryRef changes;
482 CFStringRef name;
483 CFStringRef circleName;
484 };
485
486 SOSTransportMessageTestRef SOSTransportTestCreateMessage(SOSAccountRef account, CFStringRef name, CFStringRef circleName){
487 SOSTransportMessageTestRef tpt = (SOSTransportMessageTestRef) SOSTransportMessageCreateForSubclass(sizeof(struct SOSTransportMessageTest) - sizeof(CFRuntimeBase), account, circleName, NULL);
488
489 SOSEngineRef engine = SOSDataSourceFactoryGetEngineForDataSourceName(account->factory, circleName, NULL);
490
491 tpt->m.engine = CFRetainSafe(engine);
492 if(tpt){
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);
508 }
509
510 return tpt;
511 }
512 CFStringRef SOSTransportMessageTestGetName(SOSTransportMessageTestRef transport){
513 return transport->name;
514 }
515
516 void SOSTransportMessageTestSetName(SOSTransportMessageTestRef transport, CFStringRef accountName){
517 CFReleaseNull(transport->name);
518 transport->name = CFRetain(accountName);
519 }
520
521 CFMutableDictionaryRef SOSTransportMessageTestGetChanges(SOSTransportMessageTestRef transport){
522 return transport->changes;
523 }
524
525 void SOSTransportMessageTestClearChanges(SOSTransportMessageTestRef transport){
526 CFReleaseNull(transport->changes);
527 transport->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
528
529 }
530
531 static void destroyMessageTransport(SOSTransportMessageRef transport){
532 SOSTransportMessageTestRef tkvs = (SOSTransportMessageTestRef)transport;
533
534 SOSUnregisterTransportMessage(transport);
535
536 CFArrayRemoveAllValue(message_transports, tkvs);
537
538 CFReleaseNull(tkvs->circleName);
539 CFReleaseNull(tkvs->changes);
540 CFReleaseNull(tkvs->name);
541
542 }
543
544 static void SOSTransportMessageTestAddBulkToChanges(SOSTransportMessageTestRef transport, CFDictionaryRef updates){
545
546 if (transport->changes == NULL) {
547 transport->changes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(updates), updates);
548
549 }
550 else{
551 CFDictionaryForEach(updates, ^(const void *key, const void *value) {
552 CFDictionarySetValue(transport->changes, key, value);
553 });
554 }
555 }
556
557 static void SOSTransportMessageTestAddToChanges(SOSTransportMessageTestRef transport, CFStringRef message_key, CFDataRef message_data){
558 if (transport->changes == NULL) {
559 transport->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
560 }
561 if (message_data == NULL) {
562 CFDictionarySetValue(transport->changes, message_key, kCFNull);
563 } else {
564 CFDictionarySetValue(transport->changes, message_key, message_data);
565 }
566 }
567
568 static bool SOSTransportMessageTestCleanupAfterPeerMessages(SOSTransportMessageTestRef transport, CFDictionaryRef circle_to_peer_ids, CFErrorRef *error)
569 {
570 SOSEngineRef engine = SOSTransportMessageGetEngine((SOSTransportMessageRef)transport);
571 require_quiet(engine, fail);
572
573 CFArrayRef enginePeers = SOSEngineGetPeerIDs(engine);
574
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;
579
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;
587
588 CFStringRef kvsKey = SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name, cleanup_id, in_circle_id);
589 SOSTransportMessageTestAddToChanges(transport, kvsKey, NULL);
590 CFReleaseSafe(kvsKey);
591
592 kvsKey = SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name, in_circle_id, cleanup_id);
593 SOSTransportMessageTestAddToChanges(transport, kvsKey, NULL);
594 CFReleaseSafe(kvsKey);
595 }
596 });
597
598 }
599 });
600 }
601 });
602
603 return SOSTransportMessageFlushChanges((SOSTransportMessageRef)transport, error);
604 fail:
605 return true;
606 }
607
608 static bool sendToPeer(SOSTransportMessageRef transport, CFStringRef circleName, CFStringRef peerID, CFDataRef message, CFErrorRef *error) {
609 SOSTransportMessageTestRef testTransport = (SOSTransportMessageTestRef) transport;
610 bool result = true;
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);
613
614 SOSTransportMessageTestAddBulkToChanges((SOSTransportMessageTestRef)testTransport, a_message_to_a_peer);
615 CFReleaseNull(a_message_to_a_peer);
616 CFReleaseNull(message_to_peer_key);
617
618 return result;
619 }
620
621 static bool syncWithPeers(SOSTransportMessageRef transport, CFDictionaryRef circleToPeerIDs, CFErrorRef *error){
622 // Each entry is keyed by circle name and contains a list of peerIDs
623
624 __block bool result = true;
625
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);
642 }
643 Block_release(sent);
644 CFReleaseSafe(message_to_send);
645 });
646 }
647 });
648 }
649 });
650
651 return result;
652 }
653
654 static bool sendMessages(SOSTransportMessageRef transport, CFDictionaryRef circleToPeersToMessage, CFErrorRef *error) {
655 __block bool result = true;
656
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);
665 result &= rx;
666 }
667 });
668 }
669 });
670
671 return true;
672 }
673
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);
681
682 if(peerToMessage){
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;
687
688 if (SOSTransportMessageHandlePeerMessage((SOSTransportMessageRef) transport, peer_id, peer_message, &localError)) {
689 CFArrayAppendValue(handled_peers, key);
690 } else {
691 secdebug("transport", "%@ KVSTransport handle message failed: %@", peer_id, localError);
692 }
693 CFReleaseNull(localError);
694 });
695 }
696 CFReleaseNull(handled_peers);
697
698 return handled;
699 }
700
701 static bool flushMessageChanges(SOSTransportMessageRef transport, CFErrorRef *error)
702 {
703 return true;
704 }
705
706 static bool cleanupAfterPeer(SOSTransportMessageRef transport, CFDictionaryRef circle_to_peer_ids, CFErrorRef *error)
707 {
708 return SOSTransportMessageTestCleanupAfterPeerMessages((SOSTransportMessageTestRef) transport, circle_to_peer_ids, error);
709 }
710
711 SOSAccountRef SOSTransportMessageTestGetAccount(SOSTransportMessageTestRef transport) {
712 return ((SOSTransportMessageRef)transport)->account;
713 }
714
715
716 ///
717 //MARK Message Test Transport
718 ///
719
720 struct SOSTransportMessageIDSTest {
721 struct __OpaqueSOSTransportMessage m;
722 CFMutableDictionaryRef changes;
723 CFStringRef name;
724 CFStringRef circleName;
725 };
726
727
728 //
729 // V-table implementation forward declarations
730 //
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);
738
739 SOSTransportMessageIDSTestRef SOSTransportMessageIDSTestCreate(SOSAccountRef account, CFStringRef circleName, CFErrorRef *error)
740 {
741 SOSTransportMessageIDSTestRef ids = calloc(1, sizeof(struct SOSTransportMessageIDSTest));
742
743 if (ids) {
744 // Fill in vtable:
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
752
753 SOSRegisterTransportMessage((SOSTransportMessageRef)ids);
754 }
755 return ids;
756 }
757 static void destroyIDSTest(SOSTransportMessageRef transport){
758 SOSUnregisterTransportMessage(transport);
759 }
760
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);
765
766 if(message){
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;
771
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);
778
779 if (SOSTransportMessageHandlePeerMessage(transport, peerID, peer_message, &localError)) {
780 CFArrayAppendValue(handled_peers, key);
781 } else {
782 secdebug("transport", "%@ IDSTransport handle message failed: %@", peer_id, localError);
783 }
784 }
785 CFReleaseNull(deviceID);
786 });
787 CFReleaseNull(localError);
788 });
789 }
790 CFDictionaryAddValue(handled, transport->circleName, handled_peers);
791 CFReleaseNull(handled_peers);
792
793 return handled;
794 }
795
796 static void SOSTransportMessageIDSTestAddBulkToChanges(SOSTransportMessageIDSTestRef transport, CFDictionaryRef updates){
797
798 if (transport->changes == NULL) {
799 transport->changes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(updates), updates);
800
801 }
802 else{
803 CFDictionaryForEach(updates, ^(const void *key, const void *value) {
804 CFDictionarySetValue(transport->changes, key, value);
805 });
806 }
807 }
808 static bool sendToPeerIDSTest(SOSTransportMessageRef transport, CFStringRef circleName, CFStringRef deviceID, CFStringRef peerID, CFDataRef message, CFErrorRef *error)
809 {
810 SOSTransportMessageIDSTestRef testTransport = (SOSTransportMessageIDSTestRef)transport;
811 SOSEngineRef engine = SOSTransportMessageGetEngine(transport);
812 CFStringRef my_id = SOSEngineGetMyID(engine);
813
814 CFStringRef circle_to_transport_key = SOSMessageKeyCreateWithCircleNameAndTransportType(circleName, SOSTransportMessageTypeIDS);
815 CFDictionaryRef a_message_to_a_peer = CFDictionaryCreateForCFTypes(NULL, my_id, message, NULL);
816
817 CFDictionaryRef transport_to_messages = CFDictionaryCreateForCFTypes(NULL, circle_to_transport_key, a_message_to_a_peer, NULL);
818
819 SOSTransportMessageIDSTestAddBulkToChanges(testTransport, transport_to_messages);
820
821 CFReleaseNull(a_message_to_a_peer);
822 CFReleaseNull(transport_to_messages);
823 CFReleaseNull(circle_to_transport_key);
824 return true;
825
826 }
827
828
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;
832
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);
841 }
842 });
843 }
844 });
845
846 return result;
847 }
848
849 static bool sendMessagesIDSTest(SOSTransportMessageRef transport, CFDictionaryRef circleToPeersToMessage, CFErrorRef *error) {
850 __block bool result = true;
851 SOSCircleRef circle = SOSAccountGetCircle(transport->account, error);
852
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);
864 result &= rx;
865 CFReleaseNull(deviceID);
866 }
867 CFReleaseNull(deviceID);
868 });
869 }
870 });
871 }
872 });
873
874 return true;
875 }
876
877 static bool flushChangesIDSTest(SOSTransportMessageRef transport, CFErrorRef *error)
878 {
879 return true;
880 }
881
882 static bool cleanupAfterPeerIDSTest(SOSTransportMessageRef transport, CFDictionaryRef circle_to_peer_ids, CFErrorRef *error)
883 {
884 return true;
885 }
886