]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/Regressions/SOSTransportTestTransports.c
Security-57336.1.9.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 return circle_key;
424 }
425
426 static bool postCircle(SOSTransportCircleRef transport, CFStringRef circleName, CFDataRef circle_data, CFErrorRef *error){
427 SOSTransportCircleTestRef tkvs = (SOSTransportCircleTestRef)transport;
428 CFStringRef circle_key = SOSCircleKeyCreateWithName(circleName, error);
429 if (circle_key)
430 SOSTransportCircleTestAddToChanges(tkvs, circle_key, circle_data);
431 CFReleaseNull(circle_key);
432
433 return true;
434 }
435
436 static CF_RETURNS_RETAINED CFDictionaryRef handleRetirementMessages(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_retirement_messages_table, CFErrorRef *error){
437 SOSAccountRef account = transport->account;
438
439 return SOSAccountHandleRetirementMessages(account, circle_retirement_messages_table, error);
440 }
441
442 static CFArrayRef handleCircleMessages(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_circle_messages_table, CFErrorRef *error){
443 CFMutableArrayRef handledKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
444 CFDictionaryForEach(circle_circle_messages_table, ^(const void *key, const void *value) {
445 CFErrorRef circleMessageError = NULL;
446 if (!SOSAccountHandleCircleMessage(transport->account, key, value, &circleMessageError)) {
447 secerror("Error handling circle message %@ (%@): %@", key, value, circleMessageError);
448 }
449 else{
450 CFStringRef circle_id = (CFStringRef) key;
451 CFArrayAppendValue(handledKeys, circle_id);
452 }
453 CFReleaseNull(circleMessageError);
454 });
455
456 return handledKeys;
457 }
458
459 static bool SOSTransportCircleTestSendChanges(SOSTransportCircleTestRef transport, CFDictionaryRef changes, CFErrorRef *error){
460 if(!transport->changes)
461 transport->changes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(changes), changes);
462 else{
463 CFDictionaryForEach(changes, ^(const void *key, const void *value) {
464 CFDictionarySetValue(transport->changes, key, value);
465 });
466 }
467 return true;
468 }
469
470 SOSAccountRef SOSTransportCircleTestGetAccount(SOSTransportCircleTestRef transport) {
471 return ((SOSTransportCircleRef)transport)->account;
472 }
473
474 ///
475 //MARK Message Test Transport
476 ///
477
478 struct SOSTransportMessageTest{
479 struct __OpaqueSOSTransportMessage m;
480 CFMutableDictionaryRef changes;
481 CFStringRef name;
482 CFStringRef circleName;
483 };
484
485 SOSTransportMessageTestRef SOSTransportTestCreateMessage(SOSAccountRef account, CFStringRef name, CFStringRef circleName){
486 SOSTransportMessageTestRef tpt = (SOSTransportMessageTestRef) SOSTransportMessageCreateForSubclass(sizeof(struct SOSTransportMessageTest) - sizeof(CFRuntimeBase), account, circleName, NULL);
487
488 SOSEngineRef engine = SOSDataSourceFactoryGetEngineForDataSourceName(account->factory, circleName, NULL);
489
490 tpt->m.engine = CFRetainSafe(engine);
491 if(tpt){
492 tpt->m.sendMessages = sendMessages;
493 tpt->m.syncWithPeers = syncWithPeers;
494 tpt->m.flushChanges = flushMessageChanges;
495 tpt->m.cleanupAfterPeerMessages = cleanupAfterPeer;
496 tpt->m.destroy = destroyMessageTransport;
497 tpt->m.handleMessages = handleMessages;
498 // Initialize ourselves
499 tpt->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
500 tpt->m.account = CFRetainSafe(account);
501 tpt->name = CFRetainSafe(name);
502 tpt->circleName = CFRetainSafe(circleName);
503 if(!message_transports)
504 message_transports = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
505 CFArrayAppendValue(message_transports, (SOSTransportMessageRef)tpt);
506 SOSRegisterTransportMessage((SOSTransportMessageRef)tpt);
507 }
508
509 return tpt;
510 }
511 CFStringRef SOSTransportMessageTestGetName(SOSTransportMessageTestRef transport){
512 return transport->name;
513 }
514
515 void SOSTransportMessageTestSetName(SOSTransportMessageTestRef transport, CFStringRef accountName){
516 CFReleaseNull(transport->name);
517 transport->name = CFRetain(accountName);
518 }
519
520 CFMutableDictionaryRef SOSTransportMessageTestGetChanges(SOSTransportMessageTestRef transport){
521 return transport->changes;
522 }
523
524 void SOSTransportMessageTestClearChanges(SOSTransportMessageTestRef transport){
525 CFReleaseNull(transport->changes);
526 transport->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
527
528 }
529
530 static void destroyMessageTransport(SOSTransportMessageRef transport){
531 SOSTransportMessageTestRef tkvs = (SOSTransportMessageTestRef)transport;
532
533 SOSUnregisterTransportMessage(transport);
534
535 CFArrayRemoveAllValue(message_transports, tkvs);
536
537 CFReleaseNull(tkvs->circleName);
538 CFReleaseNull(tkvs->changes);
539 CFReleaseNull(tkvs->name);
540
541 }
542
543 static void SOSTransportMessageTestAddBulkToChanges(SOSTransportMessageTestRef transport, CFDictionaryRef updates){
544
545 if (transport->changes == NULL) {
546 transport->changes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(updates), updates);
547
548 }
549 else{
550 CFDictionaryForEach(updates, ^(const void *key, const void *value) {
551 CFDictionarySetValue(transport->changes, key, value);
552 });
553 }
554 }
555
556 static void SOSTransportMessageTestAddToChanges(SOSTransportMessageTestRef transport, CFStringRef message_key, CFDataRef message_data){
557 if (transport->changes == NULL) {
558 transport->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
559 }
560 if (message_data == NULL) {
561 CFDictionarySetValue(transport->changes, message_key, kCFNull);
562 } else {
563 CFDictionarySetValue(transport->changes, message_key, message_data);
564 }
565 }
566
567 static bool SOSTransportMessageTestCleanupAfterPeerMessages(SOSTransportMessageTestRef transport, CFDictionaryRef circle_to_peer_ids, CFErrorRef *error)
568 {
569 SOSEngineRef engine = SOSTransportMessageGetEngine((SOSTransportMessageRef)transport);
570 require_quiet(engine, fail);
571
572 CFArrayRef enginePeers = SOSEngineGetPeerIDs(engine);
573
574 CFDictionaryForEach(circle_to_peer_ids, ^(const void *key, const void *value) {
575 if (isString(key) && isArray(value)) {
576 CFStringRef circle_name = (CFStringRef) key;
577 CFArrayRef peers_to_cleanup_after = (CFArrayRef) value;
578
579 CFArrayForEach(peers_to_cleanup_after, ^(const void *value) {
580 if (isString(value)) {
581 CFStringRef cleanup_id = (CFStringRef) value;
582 // TODO: Since the enginePeers list is not authorative (the Account is) this could inadvertently clean up active peers or leave behind stale peers
583 if (enginePeers) CFArrayForEach(enginePeers, ^(const void *value) {
584 if (isString(value)) {
585 CFStringRef in_circle_id = (CFStringRef) value;
586
587 CFStringRef kvsKey = SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name, cleanup_id, in_circle_id);
588 SOSTransportMessageTestAddToChanges(transport, kvsKey, NULL);
589 CFReleaseSafe(kvsKey);
590
591 kvsKey = SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name, in_circle_id, cleanup_id);
592 SOSTransportMessageTestAddToChanges(transport, kvsKey, NULL);
593 CFReleaseSafe(kvsKey);
594 }
595 });
596
597 }
598 });
599 }
600 });
601
602 return SOSTransportMessageFlushChanges((SOSTransportMessageRef)transport, error);
603 fail:
604 return true;
605 }
606
607 static bool sendToPeer(SOSTransportMessageRef transport, CFStringRef circleName, CFStringRef peerID, CFDataRef message, CFErrorRef *error) {
608 SOSTransportMessageTestRef testTransport = (SOSTransportMessageTestRef) transport;
609 bool result = true;
610 CFStringRef message_to_peer_key = SOSMessageKeyCreateFromTransportToPeer((SOSTransportMessageKVSRef)transport, peerID);
611 CFDictionaryRef a_message_to_a_peer = CFDictionaryCreateForCFTypes(NULL, message_to_peer_key, message, NULL);
612
613 SOSTransportMessageTestAddBulkToChanges((SOSTransportMessageTestRef)testTransport, a_message_to_a_peer);
614 CFReleaseNull(a_message_to_a_peer);
615 CFReleaseNull(message_to_peer_key);
616
617 return result;
618 }
619
620 static bool syncWithPeers(SOSTransportMessageRef transport, CFDictionaryRef circleToPeerIDs, CFErrorRef *error){
621 // Each entry is keyed by circle name and contains a list of peerIDs
622
623 __block bool result = true;
624
625 CFDictionaryForEach(circleToPeerIDs, ^(const void *key, const void *value) {
626 if (isString(key) && isArray(value)) {
627 CFStringRef circleName = (CFStringRef) key;
628 CFArrayForEach(value, ^(const void *value) {
629 if (isString(value)) {
630 CFStringRef peerID = (CFStringRef) value;
631 SOSEngineRef engine = SOSTransportMessageGetEngine(transport);
632 SOSEngineWithPeerID(engine, peerID, error, ^(SOSPeerRef peer, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) {
633 SOSEnginePeerMessageSentBlock sent = NULL;
634 CFDataRef message_to_send = NULL;
635 bool ok = SOSPeerCoderSendMessageIfNeeded(engine, peer, &message_to_send, circleName, peerID, &sent, error);
636 if (message_to_send) {
637 CFDictionaryRef peer_dict = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, peerID, message_to_send, NULL);
638 CFDictionarySetValue(SOSTransportMessageTestGetChanges((SOSTransportMessageTestRef)transport), circleName, peer_dict);
639 SOSPeerCoderConsume(&sent, ok);
640 CFReleaseSafe(peer_dict);
641 }
642 Block_release(sent);
643 CFReleaseSafe(message_to_send);
644 });
645 }
646 });
647 }
648 });
649
650 return result;
651 }
652
653 static bool sendMessages(SOSTransportMessageRef transport, CFDictionaryRef circleToPeersToMessage, CFErrorRef *error) {
654 __block bool result = true;
655
656 CFDictionaryForEach(circleToPeersToMessage, ^(const void *key, const void *value) {
657 if (isString(key) && isDictionary(value)) {
658 CFStringRef circleName = (CFStringRef) key;
659 CFDictionaryForEach(value, ^(const void *key, const void *value) {
660 if (isString(key) && isData(value)) {
661 CFStringRef peerID = (CFStringRef) key;
662 CFDataRef message = (CFDataRef) value;
663 bool rx = sendToPeer(transport, circleName, peerID, message, error);
664 result &= rx;
665 }
666 });
667 }
668 });
669
670 return true;
671 }
672
673 static CF_RETURNS_RETAINED
674 CFDictionaryRef handleMessages(SOSTransportMessageRef transport, CFMutableDictionaryRef circle_peer_messages_table, CFErrorRef *error) {
675 SOSTransportMessageTestRef tpt = (SOSTransportMessageTestRef)transport;
676 CFMutableDictionaryRef handled = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
677 CFDictionaryRef peerToMessage = CFDictionaryGetValue(circle_peer_messages_table, tpt->circleName);
678 CFMutableArrayRef handled_peers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
679 CFDictionaryAddValue(handled, tpt->circleName, handled_peers);
680
681 if(peerToMessage){
682 CFDictionaryForEach(peerToMessage, ^(const void *key, const void *value) {
683 CFStringRef peer_id = (CFStringRef) key;
684 CFDataRef peer_message = (CFDataRef) value;
685 CFErrorRef localError = NULL;
686
687 if (SOSTransportMessageHandlePeerMessage((SOSTransportMessageRef) transport, peer_id, peer_message, &localError)) {
688 CFArrayAppendValue(handled_peers, key);
689 } else {
690 secdebug("transport", "%@ KVSTransport handle message failed: %@", peer_id, localError);
691 }
692 CFReleaseNull(localError);
693 });
694 }
695 CFReleaseNull(handled_peers);
696
697 return handled;
698 }
699
700 static bool flushMessageChanges(SOSTransportMessageRef transport, CFErrorRef *error)
701 {
702 return true;
703 }
704
705 static bool cleanupAfterPeer(SOSTransportMessageRef transport, CFDictionaryRef circle_to_peer_ids, CFErrorRef *error)
706 {
707 return SOSTransportMessageTestCleanupAfterPeerMessages((SOSTransportMessageTestRef) transport, circle_to_peer_ids, error);
708 }
709
710 SOSAccountRef SOSTransportMessageTestGetAccount(SOSTransportMessageTestRef transport) {
711 return ((SOSTransportMessageRef)transport)->account;
712 }
713
714
715 ///
716 //MARK Message Test Transport
717 ///
718
719 struct SOSTransportMessageIDSTest {
720 struct __OpaqueSOSTransportMessage m;
721 CFMutableDictionaryRef changes;
722 CFStringRef name;
723 CFStringRef circleName;
724 };
725
726
727 //
728 // V-table implementation forward declarations
729 //
730 static bool sendToPeerIDSTest(SOSTransportMessageRef transport, CFStringRef circleName, CFStringRef deviceID, CFStringRef peerID, CFDataRef message, CFErrorRef *error);
731 static bool syncWithPeersIDSTest(SOSTransportMessageRef transport, CFDictionaryRef circleToPeerIDs, CFErrorRef *error);
732 static bool sendMessagesIDSTest(SOSTransportMessageRef transport, CFDictionaryRef circleToPeersToMessage, CFErrorRef *error);
733 static void destroyIDSTest(SOSTransportMessageRef transport);
734 static bool cleanupAfterPeerIDSTest(SOSTransportMessageRef transport, CFDictionaryRef circle_to_peer_ids, CFErrorRef *error);
735 static bool flushChangesIDSTest(SOSTransportMessageRef transport, CFErrorRef *error);
736 static CF_RETURNS_RETAINED CFDictionaryRef handleMessagesIDSTest(SOSTransportMessageRef transport, CFMutableDictionaryRef circle_peer_messages_table, CFErrorRef *error);
737
738 SOSTransportMessageIDSTestRef SOSTransportMessageIDSTestCreate(SOSAccountRef account, CFStringRef circleName, CFErrorRef *error)
739 {
740 SOSTransportMessageIDSTestRef ids = calloc(1, sizeof(struct SOSTransportMessageIDSTest));
741
742 if (ids) {
743 // Fill in vtable:
744 ids->m.sendMessages = sendMessagesIDSTest;
745 ids->m.syncWithPeers = syncWithPeersIDSTest;
746 ids->m.flushChanges = flushChangesIDSTest;
747 ids->m.cleanupAfterPeerMessages = cleanupAfterPeerIDSTest;
748 ids->m.destroy = destroyIDSTest;
749 ids->m.handleMessages = handleMessagesIDSTest;
750 // Initialize ourselves
751
752 SOSRegisterTransportMessage((SOSTransportMessageRef)ids);
753 }
754 return ids;
755 }
756 static void destroyIDSTest(SOSTransportMessageRef transport){
757 SOSUnregisterTransportMessage(transport);
758 }
759
760 static CF_RETURNS_RETAINED
761 CFDictionaryRef handleMessagesIDSTest(SOSTransportMessageRef transport, CFMutableDictionaryRef message, CFErrorRef *error) {
762 CFMutableDictionaryRef handled = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
763 CFMutableArrayRef handled_peers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
764
765 if(message){
766 CFDictionaryForEach(message, ^(const void *key, const void *value) {
767 CFStringRef peer_id = (CFStringRef) key;
768 CFDataRef peer_message = (CFDataRef) value;
769 __block CFErrorRef localError = NULL;
770
771 //find the Peer ID if we are given a Device ID
772 SOSCircleRef circle = SOSAccountGetCircle(transport->account, error);
773 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
774 CFStringRef deviceID = SOSPeerInfoCopyDeviceID(peer);
775 if(CFEqualSafe(deviceID, peer_id) || CFEqualSafe(SOSPeerInfoGetPeerID(peer), peer_id)){
776 CFStringRef peerID = SOSPeerInfoGetPeerID(peer);
777
778 if (SOSTransportMessageHandlePeerMessage(transport, peerID, peer_message, &localError)) {
779 CFArrayAppendValue(handled_peers, key);
780 } else {
781 secdebug("transport", "%@ IDSTransport handle message failed: %@", peer_id, localError);
782 }
783 }
784 CFReleaseNull(deviceID);
785 });
786 CFReleaseNull(localError);
787 });
788 }
789 CFDictionaryAddValue(handled, transport->circleName, handled_peers);
790 CFReleaseNull(handled_peers);
791
792 return handled;
793 }
794
795 static void SOSTransportMessageIDSTestAddBulkToChanges(SOSTransportMessageIDSTestRef transport, CFDictionaryRef updates){
796
797 if (transport->changes == NULL) {
798 transport->changes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(updates), updates);
799
800 }
801 else{
802 CFDictionaryForEach(updates, ^(const void *key, const void *value) {
803 CFDictionarySetValue(transport->changes, key, value);
804 });
805 }
806 }
807 static bool sendToPeerIDSTest(SOSTransportMessageRef transport, CFStringRef circleName, CFStringRef deviceID, CFStringRef peerID, CFDataRef message, CFErrorRef *error)
808 {
809 SOSTransportMessageIDSTestRef testTransport = (SOSTransportMessageIDSTestRef)transport;
810 SOSEngineRef engine = SOSTransportMessageGetEngine(transport);
811 CFStringRef my_id = SOSEngineGetMyID(engine);
812
813 CFStringRef circle_to_transport_key = SOSMessageKeyCreateWithCircleNameAndTransportType(circleName, SOSTransportMessageTypeIDS);
814 CFDictionaryRef a_message_to_a_peer = CFDictionaryCreateForCFTypes(NULL, my_id, message, NULL);
815
816 CFDictionaryRef transport_to_messages = CFDictionaryCreateForCFTypes(NULL, circle_to_transport_key, a_message_to_a_peer, NULL);
817
818 SOSTransportMessageIDSTestAddBulkToChanges(testTransport, transport_to_messages);
819
820 CFReleaseNull(a_message_to_a_peer);
821 CFReleaseNull(transport_to_messages);
822 CFReleaseNull(circle_to_transport_key);
823 return true;
824
825 }
826
827
828 static bool syncWithPeersIDSTest(SOSTransportMessageRef transport, CFDictionaryRef circleToPeerIDs, CFErrorRef *error){
829 // Each entry is keyed by circle name and contains a list of peerIDs
830 __block bool result = true;
831
832 CFDictionaryForEach(circleToPeerIDs, ^(const void *key, const void *value) {
833 if (isString(key) && isArray(value)) {
834 CFStringRef circleName = (CFStringRef) key;
835 CFArrayForEach(value, ^(const void *value) {
836 if (isString(value)) {
837 CFStringRef peerID = (CFStringRef) value;
838 secnotice("transport", "IDS sync with peerIDs %@", peerID);
839 result &= SOSTransportMessageSendMessageIfNeeded(transport, circleName, peerID, error);
840 }
841 });
842 }
843 });
844
845 return result;
846 }
847
848 static bool sendMessagesIDSTest(SOSTransportMessageRef transport, CFDictionaryRef circleToPeersToMessage, CFErrorRef *error) {
849 __block bool result = true;
850 SOSCircleRef circle = SOSAccountGetCircle(transport->account, error);
851
852 CFDictionaryForEach(circleToPeersToMessage, ^(const void *key, const void *value) {
853 if (isString(key) && isDictionary(value)) {
854 CFStringRef circleName = (CFStringRef) key;
855 CFDictionaryForEach(value, ^(const void *key, const void *value) {
856 if (isString(key) && isData(value)) {
857 CFStringRef peerID = (CFStringRef) key;
858 CFDataRef message = (CFDataRef) value;
859 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
860 CFStringRef deviceID = SOSPeerInfoCopyDeviceID(peer);
861 if(CFEqualSafe(SOSPeerInfoGetPeerID(peer), peerID) || CFEqualSafe(deviceID, peerID)){
862 bool rx = sendToPeerIDSTest(transport, circleName, deviceID, peerID, message, error);
863 result &= rx;
864 CFReleaseNull(deviceID);
865 }
866 CFReleaseNull(deviceID);
867 });
868 }
869 });
870 }
871 });
872
873 return true;
874 }
875
876 static bool flushChangesIDSTest(SOSTransportMessageRef transport, CFErrorRef *error)
877 {
878 return true;
879 }
880
881 static bool cleanupAfterPeerIDSTest(SOSTransportMessageRef transport, CFDictionaryRef circle_to_peer_ids, CFErrorRef *error)
882 {
883 return true;
884 }
885