]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/Regressions/SOSTransportTestTransports.c
Security-57740.51.3.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, 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);
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 CFMutableArrayRef key_transports = NULL;
52 CFMutableArrayRef circle_transports = NULL;
53 CFMutableArrayRef message_transports = NULL;
54
55 void SOSAccountUpdateTestTransports(SOSAccountRef account, CFDictionaryRef gestalt){
56 CFStringRef new_name = (CFStringRef)CFDictionaryGetValue(gestalt, kPIUserDefinedDeviceNameKey);
57
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);
61
62 }
63
64 static SOSCircleRef SOSAccountEnsureCircleTest(SOSAccountRef a, CFStringRef name, CFStringRef accountName, CFErrorRef *error)
65 {
66 CFErrorRef localError = NULL;
67
68 SOSCircleRef circle = SOSAccountGetCircle(a, &localError);
69
70 require_action_quiet(circle || !isSOSErrorCoded(localError, kSOSErrorIncompatibleCircle), fail,
71 if (error) { *error = localError; localError = NULL; });
72
73 if(NULL == circle){
74 circle = SOSCircleCreate(NULL, name, NULL);
75 if (circle){
76 CFRetainAssign(a->trusted_circle, circle);
77 CFRelease(circle);
78 circle = SOSAccountGetCircle(a, &localError);
79 }
80 }
81 require_quiet(SOSAccountInflateTestTransportsForCircle(a, name, accountName, &localError), fail);
82 require_quiet(SOSAccountHasFullPeerInfo(a, &localError), fail);
83
84 fail:
85 CFReleaseNull(localError);
86 return circle;
87 }
88
89 bool SOSAccountEnsureFactoryCirclesTest(SOSAccountRef a, CFStringRef accountName)
90 {
91 bool result = false;
92 if (a)
93 {
94 require(a->factory, xit);
95 CFStringRef circle_name = SOSDataSourceFactoryCopyName(a->factory);
96 require(circle_name, xit);
97
98 SOSAccountEnsureCircleTest(a, (CFStringRef)circle_name, accountName, NULL);
99
100 CFReleaseNull(circle_name);
101 result = true;
102 }
103 xit:
104 return result;
105 }
106
107 bool SOSAccountInflateTestTransportsForCircle(SOSAccountRef account, CFStringRef circleName, CFStringRef accountName, CFErrorRef *error){
108 bool success = false;
109 SOSTransportCircleTestRef tCircle = NULL;
110 SOSTransportMessageTestRef tMessage = NULL;
111
112 if(account->key_transport == NULL){
113 account->key_transport = (SOSTransportKeyParameterRef)SOSTransportTestCreateKeyParameter(account, accountName, circleName);
114 require_quiet(account->key_transport, fail);
115 }
116 if(account->circle_transport == NULL){
117 tCircle = SOSTransportTestCreateCircle(account, accountName, circleName);
118 require_quiet(tCircle, fail);
119 CFRetainAssign(account->circle_transport, (SOSTransportCircleRef)tCircle);
120 }
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);
125 }
126
127 success = true;
128 fail:
129 CFReleaseNull(tCircle);
130 CFReleaseNull(tMessage);
131 return success;
132 }
133
134 ///
135 //Mark Test Key Parameter Transport
136 ///
137
138 struct SOSTransportKeyParameterTest{
139 struct __OpaqueSOSTransportKeyParameter k;
140 CFMutableDictionaryRef changes;
141 CFStringRef name;
142 CFStringRef circleName;
143 };
144
145 SOSTransportKeyParameterTestRef SOSTransportTestCreateKeyParameter(SOSAccountRef account, CFStringRef name, CFStringRef circleName){
146
147 SOSTransportKeyParameterTestRef tpt = (SOSTransportKeyParameterTestRef) SOSTransportKeyParameterCreateForSubclass(sizeof(struct SOSTransportKeyParameterTest) - sizeof(CFRuntimeBase), account, NULL);
148
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;
157 if(!key_transports)
158 key_transports = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
159 CFArrayAppendValue(key_transports, (SOSTransportKeyParameterRef)tpt);
160
161 SOSRegisterTransportKeyParameter((SOSTransportKeyParameterRef)tpt);
162 return tpt;
163 }
164
165 static bool handleKeyParameterChanges(SOSTransportKeyParameterRef transport, CFDataRef data, CFErrorRef error){
166 SOSAccountRef account = transport->account;
167 return SOSAccountHandleParametersChange(account, data, &error);
168 }
169
170 static void destroyKeyParameters(SOSTransportKeyParameterRef transport){
171 SOSTransportKeyParameterTestRef tpt = (SOSTransportKeyParameterTestRef)transport;
172
173 CFArrayRemoveAllValue(key_transports, tpt);
174 SOSUnregisterTransportKeyParameter(transport);
175
176 CFReleaseNull(tpt->changes);
177 CFReleaseNull(tpt->name);
178 CFReleaseNull(tpt->circleName);
179 }
180
181
182 static bool setToNewAccount(SOSTransportKeyParameterRef transport, SOSAccountRef a){
183 SOSTransportKeyParameterTestRef tpt = (SOSTransportKeyParameterTestRef)transport;
184 CFStringRef accountName = SOSTransportKeyParameterTestGetName(tpt);
185
186 SOSAccountSetToNew(a);
187
188 CFReleaseNull(a->key_transport);
189 CFReleaseNull(a->circle_transport);
190 CFReleaseNull(a->kvs_message_transport);
191 CFReleaseNull(a->ids_message_transport);
192
193 SOSAccountEnsureFactoryCirclesTest(a, accountName);
194
195 return true;
196 }
197 CFStringRef SOSTransportKeyParameterTestGetName(SOSTransportKeyParameterTestRef transport){
198 return transport->name;
199 }
200
201 void SOSTransportKeyParameterTestSetName(SOSTransportKeyParameterTestRef transport, CFStringRef accountName){
202 CFReleaseNull(transport->name);
203 transport->name = CFRetain(accountName);
204 }
205
206 SOSAccountRef SOSTransportKeyParameterTestGetAccount(SOSTransportKeyParameterTestRef transport){
207 return ((SOSTransportKeyParameterRef)transport)->account;
208 }
209
210 CFMutableDictionaryRef SOSTransportKeyParameterTestGetChanges(SOSTransportKeyParameterTestRef transport){
211 return transport->changes;
212 }
213
214 void SOSTransportKeyParameterTestClearChanges(SOSTransportKeyParameterTestRef transport){
215 CFReleaseNull(transport->changes);
216 transport->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
217 }
218
219 static bool publishCloudParameters(SOSTransportKeyParameterRef transport, CFDataRef data, CFErrorRef* error)
220 {
221 return SOSTransportKeyParameterTestPublishCloudParameters((SOSTransportKeyParameterTestRef)transport, data, error);
222 }
223
224 static bool SOSTransportKeyParameterTestPublishCloudParameters(SOSTransportKeyParameterTestRef transport, CFDataRef newParameters, CFErrorRef *error)
225 {
226 if(!transport->changes)
227 transport->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
228
229 CFDictionarySetValue(transport->changes, kSOSKVSKeyParametersKey, newParameters);
230
231 return true;
232 }
233
234 ///
235 //MARK: Test Circle Transport
236 ///
237 struct SOSTransportCircleTest{
238 struct __OpaqueSOSTransportCircle c;
239 CFMutableDictionaryRef changes;
240 CFStringRef name;
241 CFStringRef circleName;
242 };
243 static CFStringRef SOSTransportCircleCopyDescription(SOSTransportCircleTestRef transport) {
244
245 return CFStringCreateWithFormat(NULL, NULL, CFSTR("<SOSTransportCircle@%p\n>"), transport);
246 }
247
248 static CFStringRef copyDescription(SOSTransportCircleRef transport){
249 return SOSTransportCircleCopyDescription((SOSTransportCircleTestRef)transport);
250 }
251
252 CFStringRef SOSTransportCircleTestGetName(SOSTransportCircleTestRef transport){
253 return transport->name;
254 }
255 void SOSTransportCircleTestSetName(SOSTransportCircleTestRef transport, CFStringRef accountName){
256 CFReleaseNull(transport->name);
257 transport->name = CFRetain(accountName);
258 }
259
260 CFMutableDictionaryRef SOSTransportCircleTestGetChanges(SOSTransportCircleTestRef transport){
261 return transport->changes;
262 }
263
264 void SOSTransportCircleTestClearChanges(SOSTransportCircleTestRef transport){
265 CFReleaseNull(transport->changes);
266 transport->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
267 }
268
269 SOSTransportCircleTestRef SOSTransportTestCreateCircle(SOSAccountRef account, CFStringRef name, CFStringRef circleName){
270 SOSTransportCircleTestRef tpt = (SOSTransportCircleTestRef) SOSTransportCircleCreateForSubclass(sizeof(struct SOSTransportCircleTest) - sizeof(CFRuntimeBase), account, NULL);
271
272 if(tpt){
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);
292
293 SOSRegisterTransportCircle((SOSTransportCircleRef)tpt);
294 }
295
296 return tpt;
297 }
298
299 static void destroy(SOSTransportCircleRef transport){
300 SOSTransportCircleTestRef tkvs = (SOSTransportCircleTestRef)transport;
301 CFArrayRemoveAllValue(circle_transports, tkvs);
302
303 SOSUnregisterTransportCircle(transport);
304
305 CFReleaseNull(tkvs->changes);
306 CFReleaseNull(tkvs->name);
307 CFReleaseNull(tkvs->circleName);
308 }
309
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);
314 return true;
315 }
316 static bool flushRingChanges(SOSTransportCircleRef transport, CFErrorRef* error){
317 return true;
318 }
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);
325 return true;
326 }
327
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);
332 return true;
333 }
334
335 static inline bool postRetirement(SOSTransportCircleRef transport, CFStringRef circleName, CFStringRef peer_id, CFDataRef retirement_data, CFErrorRef *error)
336 {
337 CFStringRef retirement_key = SOSRetirementKeyCreateWithCircleNameAndPeer(circleName, peer_id);
338 if (retirement_key)
339 SOSTransportCircleTestAddToChanges((SOSTransportCircleTestRef)transport, retirement_key, retirement_data);
340
341 CFReleaseNull(retirement_key);
342 return true;
343 }
344
345 static inline bool flushChanges(SOSTransportCircleRef transport, CFErrorRef *error)
346 {
347 return true;
348 }
349
350 static void SOSTransportCircleTestAddToChanges(SOSTransportCircleTestRef transport, CFStringRef message_key, CFDataRef message_data){
351
352 if (transport->changes == NULL) {
353 transport->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
354 }
355 if (message_data == NULL) {
356 CFDictionarySetValue(transport->changes, message_key, kCFNull);
357 } else {
358 CFDictionarySetValue(transport->changes, message_key, message_data);
359 }
360 secnotice("circle-changes", "Adding circle change %@ %@->%@", transport->name, message_key, message_data);
361 }
362
363 static void SOSTransportCircleTestAddBulkToChanges(SOSTransportCircleTestRef transport, CFDictionaryRef updates){
364
365 if (transport->changes == NULL) {
366 transport->changes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(updates), updates);
367
368 }
369 else{
370 CFDictionaryForEach(updates, ^(const void *key, const void *value) {
371 CFDictionarySetValue(transport->changes, key, value);
372 });
373 }
374 }
375
376
377 static bool expireRetirementRecords(SOSTransportCircleRef transport, CFDictionaryRef retirements, CFErrorRef *error) {
378
379 bool success = true;
380 SOSTransportCircleTestRef tpt = (SOSTransportCircleTestRef)transport;
381 CFMutableDictionaryRef keysToWrite = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
382
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;
387
388 CFArrayForEach(retirees, ^(const void *value) {
389 if (isString(value)) {
390 CFStringRef retiree_id = (CFStringRef) value;
391
392 CFStringRef kvsKey = SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name, retiree_id);
393
394 CFDictionaryAddValue(keysToWrite, kvsKey, kCFNull);
395
396 CFReleaseSafe(kvsKey);
397 }
398 });
399 }
400 });
401
402 if(CFDictionaryGetCount(keysToWrite)) {
403 SOSTransportCircleTestAddBulkToChanges(tpt, keysToWrite);
404 }
405 CFReleaseNull(keysToWrite);
406
407 return success;
408 }
409
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)){
414 success = true;
415 } else {
416 SOSCreateErrorWithFormat(kSOSErrorSendFailure, updateError, error, NULL,
417 CFSTR("update parameters key failed [%@]"), updates);
418 }
419 return success;
420 }
421
422 bool SOSTransportCircleTestRemovePendingChange(SOSTransportCircleRef transport, CFStringRef circleName, CFErrorRef *error){
423 SOSTransportCircleTestRef tkvs = (SOSTransportCircleTestRef)transport;
424 CFStringRef circle_key = SOSCircleKeyCreateWithName(circleName, error);
425 if (circle_key)
426 CFDictionaryRemoveValue(tkvs->changes, circle_key);
427 CFReleaseNull(circle_key);
428 return true;
429 }
430
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);
434 if (circle_key)
435 SOSTransportCircleTestAddToChanges(tkvs, circle_key, circle_data);
436 CFReleaseNull(circle_key);
437
438 return true;
439 }
440
441 static CF_RETURNS_RETAINED CFDictionaryRef handleRetirementMessages(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_retirement_messages_table, CFErrorRef *error){
442 SOSAccountRef account = transport->account;
443
444 return SOSAccountHandleRetirementMessages(account, circle_retirement_messages_table, error);
445 }
446
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);
453 }
454 else{
455 CFStringRef circle_id = (CFStringRef) key;
456 CFArrayAppendValue(handledKeys, circle_id);
457 }
458 CFReleaseNull(circleMessageError);
459 });
460
461 return handledKeys;
462 }
463
464 static bool SOSTransportCircleTestSendChanges(SOSTransportCircleTestRef transport, CFDictionaryRef changes, CFErrorRef *error){
465 if(!transport->changes)
466 transport->changes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(changes), changes);
467 else{
468 CFDictionaryForEach(changes, ^(const void *key, const void *value) {
469 CFDictionarySetValue(transport->changes, key, value);
470 });
471 }
472 return true;
473 }
474
475 SOSAccountRef SOSTransportCircleTestGetAccount(SOSTransportCircleTestRef transport) {
476 return ((SOSTransportCircleRef)transport)->account;
477 }
478
479 ///
480 //MARK Message Test Transport
481 ///
482
483 static CFIndex getKVSTestTransportType(SOSTransportMessageRef transport, CFErrorRef *error);
484
485
486 struct SOSTransportMessageTest{
487 struct __OpaqueSOSTransportMessage m;
488 CFMutableDictionaryRef changes;
489 CFStringRef name;
490 CFStringRef circleName;
491 };
492
493 SOSTransportMessageTestRef SOSTransportTestCreateMessage(SOSAccountRef account, CFStringRef name, CFStringRef circleName){
494 SOSTransportMessageTestRef tpt = (SOSTransportMessageTestRef) SOSTransportMessageCreateForSubclass(sizeof(struct SOSTransportMessageTest) - sizeof(CFRuntimeBase), account, circleName, NULL);
495
496 SOSEngineRef engine = SOSDataSourceFactoryGetEngineForDataSourceName(account->factory, circleName, NULL);
497
498 tpt->m.engine = CFRetainSafe(engine);
499 if(tpt){
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;
512
513
514 if(!message_transports)
515 message_transports = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
516 CFArrayAppendValue(message_transports, (SOSTransportMessageRef)tpt);
517 SOSRegisterTransportMessage((SOSTransportMessageRef)tpt);
518 }
519
520 return tpt;
521 }
522
523 static CFIndex getKVSTestTransportType(SOSTransportMessageRef transport, CFErrorRef *error){
524 return kKVSTest;
525 }
526 CFStringRef SOSTransportMessageTestGetName(SOSTransportMessageTestRef transport){
527 return transport->name;
528 }
529
530 void SOSTransportMessageTestSetName(SOSTransportMessageTestRef transport, CFStringRef accountName){
531 CFReleaseNull(transport->name);
532 transport->name = CFRetain(accountName);
533 }
534
535 CFMutableDictionaryRef SOSTransportMessageTestGetChanges(SOSTransportMessageTestRef transport){
536 return transport->changes;
537 }
538
539 void SOSTransportMessageTestClearChanges(SOSTransportMessageTestRef transport){
540 CFReleaseNull(transport->changes);
541 transport->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
542
543 }
544
545 static void destroyMessageTransport(SOSTransportMessageRef transport){
546 SOSTransportMessageTestRef tkvs = (SOSTransportMessageTestRef)transport;
547
548 SOSUnregisterTransportMessage(transport);
549
550 CFArrayRemoveAllValue(message_transports, tkvs);
551
552 CFReleaseNull(tkvs->circleName);
553 CFReleaseNull(tkvs->changes);
554 CFReleaseNull(tkvs->name);
555
556 }
557
558 static void SOSTransportMessageTestAddBulkToChanges(SOSTransportMessageTestRef transport, CFDictionaryRef updates){
559
560 if (transport->changes == NULL) {
561 transport->changes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(updates), updates);
562
563 }
564 else{
565 CFDictionaryForEach(updates, ^(const void *key, const void *value) {
566 CFDictionarySetValue(transport->changes, key, value);
567 });
568 }
569 }
570
571 static void SOSTransportMessageTestAddToChanges(SOSTransportMessageTestRef transport, CFStringRef message_key, CFDataRef message_data){
572 if (transport->changes == NULL) {
573 transport->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
574 }
575 if (message_data == NULL) {
576 CFDictionarySetValue(transport->changes, message_key, kCFNull);
577 } else {
578 CFDictionarySetValue(transport->changes, message_key, message_data);
579 }
580 }
581
582 static bool SOSTransportMessageTestCleanupAfterPeerMessages(SOSTransportMessageTestRef transport, CFDictionaryRef circle_to_peer_ids, CFErrorRef *error)
583 {
584 SOSEngineRef engine = SOSTransportMessageGetEngine((SOSTransportMessageRef)transport);
585 require_quiet(engine, fail);
586
587 CFArrayRef enginePeers = SOSEngineGetPeerIDs(engine);
588
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;
593
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;
601
602 CFStringRef kvsKey = SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name, cleanup_id, in_circle_id);
603 SOSTransportMessageTestAddToChanges(transport, kvsKey, NULL);
604 CFReleaseSafe(kvsKey);
605
606 kvsKey = SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name, in_circle_id, cleanup_id);
607 SOSTransportMessageTestAddToChanges(transport, kvsKey, NULL);
608 CFReleaseSafe(kvsKey);
609 }
610 });
611
612 }
613 });
614 }
615 });
616
617 return SOSTransportMessageFlushChanges((SOSTransportMessageRef)transport, error);
618 fail:
619 return true;
620 }
621
622 static bool sendToPeer(SOSTransportMessageRef transport, CFStringRef circleName, CFStringRef peerID, CFDataRef message, CFErrorRef *error) {
623 SOSTransportMessageTestRef testTransport = (SOSTransportMessageTestRef) transport;
624 bool result = true;
625 CFStringRef message_to_peer_key = SOSMessageKeyCreateFromTransportToPeer(transport, peerID);
626 CFDictionaryRef a_message_to_a_peer = CFDictionaryCreateForCFTypes(NULL, message_to_peer_key, message, NULL);
627
628 SOSTransportMessageTestAddBulkToChanges((SOSTransportMessageTestRef)testTransport, a_message_to_a_peer);
629 CFReleaseNull(a_message_to_a_peer);
630 CFReleaseNull(message_to_peer_key);
631
632 return result;
633 }
634
635 static bool syncWithPeers(SOSTransportMessageRef transport, CFSetRef peers, CFErrorRef *error){
636 // Each entry is keyed by circle name and contains a list of peerIDs
637
638 __block bool result = true;
639
640 CFStringRef circleName = transport->circleName;
641 CFSetForEach(peers, ^(const void *value) {
642 CFStringRef peerID = asString(value, NULL);
643
644 if (peerID) {
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);
655 }
656 Block_release(sent);
657 CFReleaseSafe(message_to_send);
658 });
659 }
660 });
661
662 return result;
663 }
664
665 static bool sendMessages(SOSTransportMessageRef transport, CFDictionaryRef peersToMessage, CFErrorRef *error) {
666 __block bool result = true;
667
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);
674 result &= rx;
675 }
676 });
677
678 return result;
679 }
680
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);
688
689 if(peerToMessage){
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;
694
695 if (SOSTransportMessageHandlePeerMessage((SOSTransportMessageRef) transport, peer_id, peer_message, &localError)) {
696 CFArrayAppendValue(handled_peers, key);
697 } else {
698 secdebug("transport", "%@ KVSTransport handle message failed: %@", peer_id, localError);
699 }
700 CFReleaseNull(localError);
701 });
702 }
703 CFReleaseNull(handled_peers);
704
705 return handled;
706 }
707
708 static bool flushMessageChanges(SOSTransportMessageRef transport, CFErrorRef *error)
709 {
710 return true;
711 }
712
713 static bool cleanupAfterPeer(SOSTransportMessageRef transport, CFDictionaryRef circle_to_peer_ids, CFErrorRef *error)
714 {
715 return SOSTransportMessageTestCleanupAfterPeerMessages((SOSTransportMessageTestRef) transport, circle_to_peer_ids, error);
716 }
717
718 SOSAccountRef SOSTransportMessageTestGetAccount(SOSTransportMessageRef transport) {
719 return ((SOSTransportMessageRef)transport)->account;
720 }
721
722
723 ///
724 //MARK Message Test Transport
725 ///
726
727 struct SOSTransportMessageIDSTest {
728 struct __OpaqueSOSTransportMessage m;
729 CFBooleanRef useFragmentation;
730 CFMutableDictionaryRef changes;
731 CFStringRef name;
732 CFStringRef circleName;
733 };
734
735 //
736 // V-table implementation forward declarations
737 //
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);
740
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);
749
750
751
752 SOSTransportMessageIDSTestRef SOSTransportMessageIDSTestCreate(SOSAccountRef account, CFStringRef accountName, CFStringRef circleName, CFErrorRef *error)
753 {
754
755 SOSTransportMessageIDSTestRef ids = (SOSTransportMessageIDSTestRef) SOSTransportMessageCreateForSubclass(sizeof(struct SOSTransportMessageIDSTest) - sizeof(CFRuntimeBase), account, circleName, NULL);
756
757
758 if (ids) {
759 // Fill in vtable:
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;
770
771 // Initialize ourselves
772 ids->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
773 ids->circleName = CFRetainSafe(circleName);
774 ids->name = CFRetainSafe(accountName);
775
776 if(!message_transports)
777 message_transports = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
778 CFArrayAppendValue(message_transports, (SOSTransportMessageRef)ids);
779 SOSRegisterTransportMessage((SOSTransportMessageRef)ids);
780 }
781
782 return ids;
783 }
784 CFMutableDictionaryRef SOSTransportMessageIDSTestGetChanges(SOSTransportMessageRef transport){
785 return ((SOSTransportMessageIDSTestRef)transport)->changes;
786 }
787
788 static CFStringRef copyIDSTestDescription(SOSTransportMessageRef transport){
789 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@,%@,%@,%ld"),transport->circleName, transport->account, transport->getName(transport), transport->getTransportType(transport, NULL));
790 }
791
792 CFStringRef SOSTransportMessageIDSTestGetName(SOSTransportMessageRef transport){
793 return ((SOSTransportMessageIDSTestRef)transport)->name;
794 }
795
796 static CFIndex getIDSTestTransportType(SOSTransportMessageRef transport, CFErrorRef *error){
797 return kIDSTest;
798 }
799
800 static void destroyIDSTest(SOSTransportMessageRef transport){
801 SOSUnregisterTransportMessage(transport);
802 }
803
804 void SOSTransportMessageIDSTestSetName(SOSTransportMessageRef transport, CFStringRef accountName){
805 SOSTransportMessageIDSTestRef t = (SOSTransportMessageIDSTestRef)transport;
806 t->name = accountName;
807 }
808
809 static CF_RETURNS_RETAINED
810 CFDictionaryRef handleMessagesIDSTest(SOSTransportMessageRef transport, CFMutableDictionaryRef message, CFErrorRef *error) {
811
812 CFMutableDictionaryRef handled = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
813 CFDictionaryRef peerToMessage = CFDictionaryGetValue(message, transport->circleName);
814 CFMutableArrayRef handled_peers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
815
816 secerror("Received IDS message!");
817 if(peerToMessage){
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;
822
823 if (peer_id && peer_message && SOSTransportMessageHandlePeerMessage(transport, peer_id, peer_message, &localError)) {
824 CFArrayAppendValue(handled_peers, key);
825 } else {
826 secnotice("transport", "%@ KVSTransport handle message failed: %@", peer_id, localError);
827 }
828 CFReleaseNull(localError);
829 });
830 }
831 CFDictionaryAddValue(handled, transport->circleName, handled_peers);
832 CFReleaseNull(handled_peers);
833
834 return handled;
835 }
836
837 static void SOSTransportMessageIDSTestAddBulkToChanges(SOSTransportMessageIDSTestRef transport, CFDictionaryRef updates){
838
839 if (transport->changes == NULL) {
840 transport->changes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(updates), updates);
841
842 }
843 else{
844 CFDictionaryForEach(updates, ^(const void *key, const void *value) {
845 CFDictionaryAddValue(transport->changes, key, value);
846 });
847 }
848 }
849 static bool sendDataToPeerIDSTest(SOSTransportMessageRef transport, CFStringRef circleName, CFStringRef deviceID, CFStringRef peerID, CFDataRef message, CFErrorRef *error)
850 {
851 SOSTransportMessageIDSTestRef testTransport = (SOSTransportMessageIDSTestRef)transport;
852
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);
856
857 SOSTransportMessageIDSTestAddBulkToChanges(testTransport, a_message_to_a_peer);
858
859 CFReleaseNull(message_to_peer_key);
860 CFReleaseNull(a_message_to_a_peer);
861 return true;
862
863 }
864 static bool sendDictionaryToPeerIDSTest(SOSTransportMessageRef transport, CFStringRef circleName, CFStringRef deviceID, CFStringRef peerID, CFDictionaryRef message, CFErrorRef *error)
865 {
866 SOSTransportMessageIDSTestRef testTransport = (SOSTransportMessageIDSTestRef)transport;
867
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);
871
872 SOSTransportMessageIDSTestAddBulkToChanges(testTransport, a_message_to_a_peer);
873
874 CFReleaseNull(message_to_peer_key);
875 CFReleaseNull(a_message_to_a_peer);
876 return true;
877
878 }
879
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;
883
884 CFSetForEach(peerIDs, ^(const void *value) {
885 CFStringRef peerID = asString(value, NULL);
886 if (peerID) {
887 secnotice("transport", "IDS sync with peerIDs %@", peerID);
888 result &= SOSTransportMessageSendMessageIfNeeded(transport, transport->circleName, peerID, error);
889 }
890 });
891
892 return result;
893 }
894
895 static bool sendMessagesIDSTest(SOSTransportMessageRef transport, CFDictionaryRef peersToMessage, CFErrorRef *error) {
896
897 __block bool result = true;
898 SOSAccountRef account = transport->account;
899
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);
906
907 pi = SOSAccountCopyPeerWithID(account, peerID, NULL);
908 require(pi, done);
909
910 idsDeviceID = SOSPeerInfoCopyDeviceID(pi);
911 require(idsDeviceID, done);
912
913 CFDictionaryRef messageDictionary = asDictionary(value, NULL);
914 if (messageDictionary) {
915 result &= sendDictionaryToPeerIDSTest(transport, transport->circleName, idsDeviceID, peerID, messageDictionary, error);
916 } else {
917 CFDataRef messageData = asData(value, NULL);
918 if (messageData) {
919 result &= sendDataToPeerIDSTest(transport, transport->circleName, idsDeviceID, peerID, messageData, error);
920 }
921 }
922 done:
923 CFReleaseNull(idsDeviceID);
924 CFReleaseNull(pi);
925
926 });
927
928 return result;
929 }
930
931 static bool flushChangesIDSTest(SOSTransportMessageRef transport, CFErrorRef *error)
932 {
933 return true;
934 }
935
936 static bool cleanupAfterPeerIDSTest(SOSTransportMessageRef transport, CFDictionaryRef circle_to_peer_ids, CFErrorRef *error)
937 {
938 return true;
939 }
940
941 void SOSTransportMessageIDSTestClearChanges(SOSTransportMessageRef transport){
942 SOSTransportMessageIDSTestRef ids = (SOSTransportMessageIDSTestRef)transport;
943 CFReleaseNull(ids->changes);
944
945 ids->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
946
947 }
948
949