]> git.saurik.com Git - apple/security.git/blob - Security/sec/securityd/Regressions/SOSTransportTestTransports.c
Security-57031.1.35.tar.gz
[apple/security.git] / Security / sec / securityd / Regressions / SOSTransportTestTransports.c
1 #include <CoreFoundation/CoreFoundation.h>
2 #include <CoreFoundation/CFRuntime.h>
3
4 #include <SecureObjectSync/SOSAccount.h>
5 #include <SecureObjectSync/SOSAccountPriv.h>
6 #include <SecureObjectSync/SOSTransport.h>
7 #include <SecureObjectSync/SOSTransportKeyParameter.h>
8 #include <SecureObjectSync/SOSKVSKeys.h>
9 #include <SecureObjectSync/SOSPeerCoder.h>
10 #include <utilities/SecCFWrappers.h>
11
12 #include "SOSTransportTestTransports.h"
13
14 static bool sendToPeer(SOSTransportMessageRef transport, CFStringRef circleName, CFStringRef peerID, CFDataRef message, CFErrorRef *error);
15 static bool syncWithPeers(SOSTransportMessageRef transport, CFDictionaryRef circleToPeerIDs, CFErrorRef *error);
16 static bool sendMessages(SOSTransportMessageRef transport, CFDictionaryRef circleToPeersToMessage, CFErrorRef *error);
17 static bool cleanupAfterPeer(SOSTransportMessageRef transport, CFDictionaryRef circle_to_peer_ids, CFErrorRef *error);
18 static CF_RETURNS_RETAINED
19 CFDictionaryRef handleMessages(SOSTransportMessageRef transport, CFMutableDictionaryRef circle_peer_messages_table, CFErrorRef *error);
20 static void destroyMessageTransport(SOSTransportMessageRef transport);
21 static void SOSTransportMessageTestAddBulkToChanges(SOSTransportMessageTestRef transport, CFDictionaryRef updates);
22
23 static bool flushMessageChanges(SOSTransportMessageRef transport, CFErrorRef *error);
24 static bool publishCloudParameters(SOSTransportKeyParameterRef transport, CFDataRef data, CFErrorRef* error);
25 static bool SOSTransportKeyParameterTestPublishCloudParameters(SOSTransportKeyParameterTestRef transport, CFDataRef newParameters, CFErrorRef *error);
26
27 static bool expireRetirementRecords(SOSTransportCircleRef transport, CFDictionaryRef retirements, CFErrorRef *error);
28 static void destroy(SOSTransportCircleRef transport);
29 static inline bool flushChanges(SOSTransportCircleRef transport, CFErrorRef *error);
30 static bool postCircle(SOSTransportCircleRef transport, CFStringRef circleName, CFDataRef circle_data, CFErrorRef *error);
31 static inline bool postRetirement(SOSTransportCircleRef transport, CFStringRef circleName, CFStringRef peer_id, CFDataRef retirement_data, CFErrorRef *error);
32 static bool handleKeyParameterChanges(SOSTransportKeyParameterRef transport, CFDataRef data, CFErrorRef error);
33
34 static CFArrayRef handleCircleMessages(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_circle_messages_table, CFErrorRef *error);
35 static CFDictionaryRef handleRetirementMessages(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_retirement_messages_table, CFErrorRef *error);
36 static bool setToNewAccount(SOSTransportKeyParameterRef transport);
37
38 static void SOSTransportCircleTestAddBulkToChanges(SOSTransportCircleTestRef transport, CFDictionaryRef updates);
39 static void SOSTransportCircleTestAddToChanges(SOSTransportCircleTestRef transport, CFStringRef message_key, CFDataRef message_data);
40 static bool SOSTransportCircleTestSendChanges(SOSTransportCircleTestRef transport, CFDictionaryRef changes, CFErrorRef *error);
41
42
43 void SOSAccountUpdateTestTransports(SOSAccountRef account, CFDictionaryRef gestalt){
44 CFStringRef new_name = (CFStringRef)CFDictionaryGetValue(gestalt, kPIUserDefinedDeviceName);
45 SOSTransportKeyParameterTestRef key = (SOSTransportKeyParameterTestRef)account->key_transport;
46 CFDictionaryRef circles = account->circle_transports;
47 CFDictionaryRef messages = account->message_transports;
48
49 SOSTransportKeyParameterTestSetName(key, new_name);
50 CFDictionaryForEach(circles, ^(const void *key, const void *value) {
51 SOSTransportCircleTestSetName((SOSTransportCircleTestRef)value, new_name);
52 });
53 CFDictionaryForEach(messages, ^(const void *key, const void *value) {
54 SOSTransportMessageTestSetName((SOSTransportMessageTestRef)value, new_name);
55 });
56
57 }
58
59 static SOSCircleRef SOSAccountEnsureCircleTest(SOSAccountRef a, CFStringRef name, CFStringRef accountName, CFErrorRef *error)
60 {
61 CFErrorRef localError = NULL;
62
63 SOSCircleRef circle = SOSAccountFindCircle(a, name, &localError);
64
65 require_action_quiet(circle || !isSOSErrorCoded(localError, kSOSErrorIncompatibleCircle), fail,
66 if (error) { *error = localError; localError = NULL; });
67
68 if(NULL == circle){
69 circle = SOSCircleCreate(NULL, name, NULL);
70 if (circle){
71 CFDictionaryAddValue(a->circles, name, circle);
72 CFRelease(circle);
73 circle = SOSAccountFindCircle(a, name, &localError);
74 }
75 }
76 require_quiet(SOSAccountInflateTestTransportsForCircle(a, name, accountName, &localError), fail);
77
78 fail:
79 CFReleaseNull(localError);
80 return circle;
81 }
82
83 bool SOSAccountEnsureFactoryCirclesTest(SOSAccountRef a, CFStringRef accountName)
84 {
85 bool result = false;
86 if (a)
87 {
88 require(a->factory, xit);
89 CFArrayRef circle_names = a->factory->copy_names(a->factory);
90 require(circle_names, xit);
91 CFArrayForEach(circle_names, ^(const void*name) {
92 if (isString(name))
93 SOSAccountEnsureCircleTest(a, (CFStringRef)name, accountName, NULL);
94 });
95
96 CFReleaseNull(circle_names);
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_transports == NULL){
113 account->circle_transports = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
114 tCircle = SOSTransportTestCreateCircle(account, accountName, circleName);
115 require_quiet(tCircle, fail);
116 CFDictionarySetValue(account->circle_transports, circleName, tCircle);
117 }
118 else if(CFDictionaryGetCount(account->circle_transports) == 0){
119 tCircle = SOSTransportTestCreateCircle(account, accountName, circleName);
120 require_quiet(tCircle, fail);
121 CFDictionarySetValue(account->circle_transports, circleName, tCircle);
122 }
123 if(account->message_transports == NULL){
124 account->message_transports = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
125 tMessage = SOSTransportTestCreateMessage(account, accountName, circleName);
126 require_quiet(tMessage, fail);
127 CFDictionarySetValue(account->message_transports, circleName, tMessage);
128 }
129 else if(CFDictionaryGetCount(account->message_transports) == 0){
130 tMessage = SOSTransportTestCreateMessage(account, accountName, circleName);
131 require_quiet(tMessage, fail);
132 CFDictionarySetValue(account->message_transports, circleName, tMessage);
133 }
134
135 success = true;
136 fail:
137 CFReleaseNull(tCircle);
138 CFReleaseNull(tMessage);
139 return success;
140 }
141
142 ///
143 //Mark Test Key Parameter Transport
144 ///
145
146 struct SOSTransportKeyParameterTest{
147 struct __OpaqueSOSTransportKeyParameter k;
148 CFMutableDictionaryRef changes;
149 CFStringRef name;
150 CFStringRef circleName;
151 };
152
153 SOSTransportKeyParameterTestRef SOSTransportTestCreateKeyParameter(SOSAccountRef account, CFStringRef name, CFStringRef circleName){
154
155 SOSTransportKeyParameterTestRef tpt = calloc(1, sizeof(struct SOSTransportKeyParameterTest));
156
157 tpt->name = CFRetainSafe(name);
158 tpt->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
159 tpt->k.account = CFRetainSafe(account);
160 tpt->circleName = CFRetainSafe(circleName);
161 tpt->k.publishCloudParameters = publishCloudParameters;
162 tpt->k.handleKeyParameterChanges = handleKeyParameterChanges;
163 tpt->k.setToNewAccount = setToNewAccount;
164 if(!key_transports)
165 key_transports = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
166 CFArrayAppendValue(key_transports, (SOSTransportKeyParameterRef)tpt);
167 SOSRegisterTransportKeyParameter((SOSTransportKeyParameterRef)tpt);
168 return tpt;
169 }
170
171 static bool handleKeyParameterChanges(SOSTransportKeyParameterRef transport, CFDataRef data, CFErrorRef error){
172 SOSAccountRef account = transport->account;
173 return SOSAccountHandleParametersChange(account, data, &error);
174 }
175
176 static bool setToNewAccount(SOSTransportKeyParameterRef transport){
177 SOSTransportKeyParameterTestRef tpt = (SOSTransportKeyParameterTestRef)transport;
178 SOSAccountRef a = SOSTransportKeyParameterTestGetAccount(tpt);
179 CFStringRef accountName = SOSTransportKeyParameterTestGetName(tpt);
180 CFAllocatorRef allocator = CFGetAllocator(a);
181 CFReleaseNull(a->circle_identities);
182 CFReleaseNull(a->circles);
183 CFReleaseNull(a->retired_peers);
184
185 CFReleaseNull(a->user_key_parameters);
186 CFReleaseNull(a->user_public);
187 CFReleaseNull(a->previous_public);
188 CFReleaseNull(a->_user_private);
189
190 a->user_public_trusted = false;
191 a->departure_code = kSOSNeverAppliedToCircle;
192 a->user_private_timer = 0;
193 a->lock_notification_token = 0;
194
195 // keeping gestalt;
196 // keeping factory;
197 // Live Notification
198 // change_blocks;
199 // update_interest_block;
200 // update_block;
201
202 a->circles = CFDictionaryCreateMutableForCFTypes(allocator);
203 a->circle_identities = CFDictionaryCreateMutableForCFTypes(allocator);
204 a->retired_peers = CFDictionaryCreateMutableForCFTypes(allocator);
205
206 //unregister all the transports from the global transport queue
207 SOSUnregisterTransportKeyParameter(a->key_transport);
208 CFArrayForEach(circle_transports, ^(const void *value) {
209 SOSTransportCircleTestRef tpt = (SOSTransportCircleTestRef) value;
210 if(CFStringCompare(SOSTransportCircleTestGetName(tpt), accountName, 0) == 0){
211 SOSUnregisterTransportCircle((SOSTransportCircleRef)tpt);
212 }
213 });
214 CFArrayForEach(message_transports, ^(const void *value) {
215 SOSTransportMessageTestRef tpt = (SOSTransportMessageTestRef) value;
216 if(CFStringCompare(SOSTransportMessageTestGetName(tpt), accountName, 0) == 0){
217 SOSUnregisterTransportMessage((SOSTransportMessageRef)tpt);
218 }
219 });
220
221
222 CFReleaseNull(a->key_transport);
223 CFReleaseNull(a->circle_transports);
224 CFReleaseNull(a->message_transports);
225
226 SOSAccountEnsureFactoryCirclesTest(a, accountName);
227
228 return true;
229 }
230 CFStringRef SOSTransportKeyParameterTestGetName(SOSTransportKeyParameterTestRef transport){
231 return transport->name;
232 }
233
234 void SOSTransportKeyParameterTestSetName(SOSTransportKeyParameterTestRef transport, CFStringRef accountName){
235 CFReleaseNull(transport->name);
236 transport->name = CFRetain(accountName);
237 }
238
239 SOSAccountRef SOSTransportKeyParameterTestGetAccount(SOSTransportKeyParameterTestRef transport){
240 return ((SOSTransportKeyParameterRef)transport)->account;
241 }
242
243 CFMutableDictionaryRef SOSTransportKeyParameterTestGetChanges(SOSTransportKeyParameterTestRef transport){
244 return transport->changes;
245 }
246 static bool publishCloudParameters(SOSTransportKeyParameterRef transport, CFDataRef data, CFErrorRef* error)
247 {
248 return SOSTransportKeyParameterTestPublishCloudParameters((SOSTransportKeyParameterTestRef)transport, data, error);
249 }
250
251 static bool SOSTransportKeyParameterTestPublishCloudParameters(SOSTransportKeyParameterTestRef transport, CFDataRef newParameters, CFErrorRef *error)
252 {
253 if(!transport->changes)
254 transport->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
255
256 CFDictionarySetValue(transport->changes, kSOSKVSKeyParametersKey, newParameters);
257
258 return true;
259 }
260
261 ///
262 //MARK: Test Circle Transport
263 ///
264 struct SOSTransportCircleTest{
265 struct __OpaqueSOSTransportCircle c;
266 CFMutableDictionaryRef changes;
267 CFStringRef name;
268 CFStringRef circleName;
269 };
270 static CFStringRef SOSTransportCircleCopyDescription(SOSTransportCircleTestRef transport) {
271
272 return CFStringCreateWithFormat(NULL, NULL, CFSTR("<SOSTransportCircle@%p\n>"), transport);
273 }
274
275 static CFStringRef copyDescription(SOSTransportCircleRef transport){
276 return SOSTransportCircleCopyDescription((SOSTransportCircleTestRef)transport);
277 }
278
279 CFStringRef SOSTransportCircleTestGetName(SOSTransportCircleTestRef transport){
280 return transport->name;
281 }
282 void SOSTransportCircleTestSetName(SOSTransportCircleTestRef transport, CFStringRef accountName){
283 CFReleaseNull(transport->name);
284 transport->name = CFRetain(accountName);
285 }
286
287 CFMutableDictionaryRef SOSTransportCircleTestGetChanges(SOSTransportCircleTestRef transport){
288 return transport->changes;
289 }
290 SOSTransportCircleTestRef SOSTransportTestCreateCircle(SOSAccountRef account, CFStringRef name, CFStringRef circleName){
291 SOSTransportCircleTestRef tpt = calloc(1, sizeof(struct SOSTransportCircleTest));
292 if(tpt){
293 tpt->c.account = CFRetainSafe(account);
294 tpt->c.copyDescription = copyDescription;
295 tpt->c.expireRetirementRecords = expireRetirementRecords;
296 tpt->c.postCircle = postCircle;
297 tpt->c.postRetirement = postRetirement;
298 tpt->c.flushChanges = flushChanges;
299 tpt->c.handleRetirementMessages = handleRetirementMessages;
300 tpt->c.handleCircleMessages = handleCircleMessages;
301 tpt->c.destroy = destroy;
302 tpt->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
303 tpt->name = CFRetainSafe(name);
304 tpt->circleName = CFRetainSafe(circleName);
305 if(!circle_transports)
306 circle_transports = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
307 CFArrayAppendValue(circle_transports, (SOSTransportCircleRef)tpt);
308 SOSRegisterTransportCircle((SOSTransportCircleRef)tpt);
309 }
310
311 return tpt;
312 }
313
314 static void destroy(SOSTransportCircleRef transport){
315 SOSTransportCircleTestRef tkvs = (SOSTransportCircleTestRef)transport;
316 CFArrayRemoveAllValue(circle_transports, tkvs);
317 CFReleaseNull(tkvs->changes);
318 CFReleaseNull(tkvs->name);
319 CFReleaseNull(tkvs->circleName);
320 }
321
322 static inline bool postRetirement(SOSTransportCircleRef transport, CFStringRef circleName, CFStringRef peer_id, CFDataRef retirement_data, CFErrorRef *error)
323 {
324 CFStringRef retirement_key = SOSRetirementKeyCreateWithCircleNameAndPeer(circleName, peer_id);
325 if (retirement_key)
326 SOSTransportCircleTestAddToChanges((SOSTransportCircleTestRef)transport, retirement_key, retirement_data);
327
328 CFReleaseNull(retirement_key);
329 return true;
330 }
331
332 static inline bool flushChanges(SOSTransportCircleRef transport, CFErrorRef *error)
333 {
334 return true;
335 }
336
337 static void SOSTransportCircleTestAddToChanges(SOSTransportCircleTestRef transport, CFStringRef message_key, CFDataRef message_data){
338
339 if (transport->changes == NULL) {
340 transport->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
341 }
342 if (message_data == NULL) {
343 CFDictionarySetValue(transport->changes, message_key, kCFNull);
344 } else {
345 CFDictionarySetValue(transport->changes, message_key, message_data);
346 }
347 }
348
349 static void SOSTransportCircleTestAddBulkToChanges(SOSTransportCircleTestRef transport, CFDictionaryRef updates){
350
351 if (transport->changes == NULL) {
352 transport->changes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(updates), updates);
353
354 }
355 else{
356 CFDictionaryForEach(updates, ^(const void *key, const void *value) {
357 CFDictionarySetValue(transport->changes, key, value);
358 });
359 }
360 }
361
362
363 static bool expireRetirementRecords(SOSTransportCircleRef transport, CFDictionaryRef retirements, CFErrorRef *error) {
364
365 bool success = true;
366 SOSTransportCircleTestRef tpt = (SOSTransportCircleTestRef)transport;
367 CFMutableDictionaryRef keysToWrite = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
368
369 CFDictionaryForEach(retirements, ^(const void *key, const void *value) {
370 if (isString(key) && isArray(value)) {
371 CFStringRef circle_name = (CFStringRef) key;
372 CFArrayRef retirees = (CFArrayRef) value;
373
374 CFArrayForEach(retirees, ^(const void *value) {
375 if (isString(value)) {
376 CFStringRef retiree_id = (CFStringRef) value;
377
378 CFStringRef kvsKey = SOSRetirementKeyCreateWithCircleNameAndPeer(circle_name, retiree_id);
379
380 CFDictionaryAddValue(keysToWrite, kvsKey, kCFNull);
381
382 CFReleaseSafe(kvsKey);
383 }
384 });
385 }
386 });
387
388 if(CFDictionaryGetCount(keysToWrite)) {
389 SOSTransportCircleTestAddBulkToChanges(tpt, keysToWrite);
390 }
391 CFReleaseNull(keysToWrite);
392
393 return success;
394 }
395
396 __unused static bool SOSTransportCircleTestUpdateRetirementRecords(SOSTransportCircleTestRef transport, CFDictionaryRef updates, CFErrorRef* error){
397 CFErrorRef updateError = NULL;
398 bool success = false;
399 if (SOSTransportCircleTestSendChanges((SOSTransportCircleTestRef)transport, updates, &updateError)){
400 success = true;
401 } else {
402 SOSCreateErrorWithFormat(kSOSErrorSendFailure, updateError, error, NULL,
403 CFSTR("update parameters key failed [%@]"), updates);
404 }
405 return success;
406 }
407
408 static bool postCircle(SOSTransportCircleRef transport, CFStringRef circleName, CFDataRef circle_data, CFErrorRef *error){
409 SOSTransportCircleTestRef tkvs = (SOSTransportCircleTestRef)transport;
410 CFStringRef circle_key = SOSCircleKeyCreateWithName(circleName, error);
411 if (circle_key)
412 SOSTransportCircleTestAddToChanges(tkvs, circle_key, circle_data);
413 CFReleaseNull(circle_key);
414
415 return true;
416 }
417
418 static CFDictionaryRef handleRetirementMessages(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_retirement_messages_table, CFErrorRef *error){
419 SOSAccountRef account = transport->account;
420 CFMutableDictionaryRef handledRetirementMessages = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
421 CFDictionaryForEach(circle_retirement_messages_table, ^(const void *key, const void *value) {
422 if (isString(key) && isDictionary(value)) {
423 CFStringRef circle_name = (CFStringRef) key;
424
425 CFDictionaryRef retirment_dictionary = (CFDictionaryRef) value;
426 CFDictionaryForEach(retirment_dictionary, ^(const void *key, const void *value) {
427 if(isData(value)) {
428 SOSPeerInfoRef pi = SOSPeerInfoCreateFromData(NULL, error, (CFDataRef) value);
429 if(pi && CFEqual(key, SOSPeerInfoGetPeerID(pi)) && SOSPeerInfoInspectRetirementTicket(pi, error)) {
430 CFMutableDictionaryRef circle_retirements = CFDictionaryEnsureCFDictionaryAndGetCurrentValue(account->retired_peers, circle_name);
431 CFDictionarySetValue(circle_retirements, key, value);
432
433 SOSAccountRecordRetiredPeerInCircleNamed(account, circle_name, pi);
434
435 CFMutableArrayRef handledRetirementIDs = CFDictionaryEnsureCFArrayAndGetCurrentValue(handledRetirementMessages, circle_name);
436 CFArrayAppendValue(handledRetirementIDs, SOSPeerInfoGetPeerID(pi));
437 }
438 CFReleaseSafe(pi);
439 }
440 });
441 }
442 });
443 return handledRetirementMessages;
444 }
445
446 static CFArrayRef handleCircleMessages(SOSTransportCircleRef transport, CFMutableDictionaryRef circle_circle_messages_table, CFErrorRef *error){
447 CFMutableArrayRef handledKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
448 CFDictionaryForEach(circle_circle_messages_table, ^(const void *key, const void *value) {
449 CFErrorRef circleMessageError = NULL;
450 if (!SOSAccountHandleCircleMessage(transport->account, key, value, &circleMessageError)) {
451 secerror("Error handling circle message %@ (%@): %@", key, value, circleMessageError);
452 }
453 else{
454 CFStringRef circle_id = (CFStringRef) key;
455 CFArrayAppendValue(handledKeys, circle_id);
456 }
457 CFReleaseNull(circleMessageError);
458 });
459
460 return handledKeys;
461 }
462
463 static bool SOSTransportCircleTestSendChanges(SOSTransportCircleTestRef transport, CFDictionaryRef changes, CFErrorRef *error){
464 if(!transport->changes)
465 transport->changes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(changes), changes);
466 else{
467 CFDictionaryForEach(changes, ^(const void *key, const void *value) {
468 CFDictionarySetValue(transport->changes, key, value);
469 });
470 }
471 return true;
472 }
473
474 SOSAccountRef SOSTransportCircleTestGetAccount(SOSTransportCircleTestRef transport) {
475 return ((SOSTransportCircleRef)transport)->account;
476 }
477
478 ///
479 //MARK Message Test Transport
480 ///
481
482 struct SOSTransportMessageTest{
483 struct __OpaqueSOSTransportMessage m;
484 CFMutableDictionaryRef changes;
485 CFStringRef name;
486 CFStringRef circleName;
487 };
488
489 SOSTransportMessageTestRef SOSTransportTestCreateMessage(SOSAccountRef account, CFStringRef name, CFStringRef circleName){
490 SOSTransportMessageTestRef tpt = calloc(1, sizeof(struct SOSTransportMessageTest));
491
492 SOSEngineRef engine = SOSDataSourceFactoryGetEngineForDataSourceName(account->factory, circleName, NULL);
493
494 tpt->m.engine = CFRetainSafe(engine);
495 if(tpt){
496 tpt->m.sendMessages = sendMessages;
497 tpt->m.syncWithPeers = syncWithPeers;
498 tpt->m.flushChanges = flushMessageChanges;
499 tpt->m.cleanupAfterPeerMessages = cleanupAfterPeer;
500 tpt->m.destroy = destroyMessageTransport;
501 tpt->m.handleMessages = handleMessages;
502 // Initialize ourselves
503 tpt->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
504 tpt->name = CFRetainSafe(name);
505 tpt->circleName = CFRetainSafe(circleName);
506 if(!message_transports)
507 message_transports = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
508 CFArrayAppendValue(message_transports, (SOSTransportMessageRef)tpt);
509 SOSRegisterTransportMessage((SOSTransportMessageRef)tpt);
510 }
511
512 return tpt;
513 }
514 CFStringRef SOSTransportMessageTestGetName(SOSTransportMessageTestRef transport){
515 return transport->name;
516 }
517
518 void SOSTransportMessageTestSetName(SOSTransportMessageTestRef transport, CFStringRef accountName){
519 CFReleaseNull(transport->name);
520 transport->name = CFRetain(accountName);
521 }
522
523 CFMutableDictionaryRef SOSTransportMessageTestGetChanges(SOSTransportMessageTestRef transport){
524 return transport->changes;
525 }
526
527 static void destroyMessageTransport(SOSTransportMessageRef transport){
528 SOSTransportMessageTestRef tkvs = (SOSTransportMessageTestRef)transport;
529 CFArrayRemoveAllValue(message_transports, tkvs);
530 CFReleaseNull(tkvs->circleName);
531 CFReleaseNull(tkvs->changes);
532 CFReleaseNull(tkvs->name);
533
534 }
535
536 static void SOSTransportMessageTestAddBulkToChanges(SOSTransportMessageTestRef transport, CFDictionaryRef updates){
537
538 if (transport->changes == NULL) {
539 transport->changes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(updates), updates);
540
541 }
542 else{
543 CFDictionaryForEach(updates, ^(const void *key, const void *value) {
544 CFDictionarySetValue(transport->changes, key, value);
545 });
546 }
547 }
548
549 static void SOSTransportMessageTestAddToChanges(SOSTransportMessageTestRef transport, CFStringRef message_key, CFDataRef message_data){
550 if (transport->changes == NULL) {
551 transport->changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
552 }
553 if (message_data == NULL) {
554 CFDictionarySetValue(transport->changes, message_key, kCFNull);
555 } else {
556 CFDictionarySetValue(transport->changes, message_key, message_data);
557 }
558 }
559
560 static bool SOSTransportMessageTestCleanupAfterPeerMessages(SOSTransportMessageTestRef transport, CFDictionaryRef circle_to_peer_ids, CFErrorRef *error)
561 {
562 SOSEngineRef engine = SOSTransportMessageGetEngine((SOSTransportMessageRef)transport);
563 require_quiet(engine, fail);
564
565 CFArrayRef enginePeers = SOSEngineGetPeerIDs(engine);
566
567 CFDictionaryForEach(circle_to_peer_ids, ^(const void *key, const void *value) {
568 if (isString(key) && isArray(value)) {
569 CFStringRef circle_name = (CFStringRef) key;
570 CFArrayRef peers_to_cleanup_after = (CFArrayRef) value;
571
572 CFArrayForEach(peers_to_cleanup_after, ^(const void *value) {
573 if (isString(value)) {
574 CFStringRef cleanup_id = (CFStringRef) value;
575 // TODO: Since the enginePeers list is not authorative (the Account is) this could inadvertently clean up active peers or leave behind stale peers
576 if (enginePeers) CFArrayForEach(enginePeers, ^(const void *value) {
577 if (isString(value)) {
578 CFStringRef in_circle_id = (CFStringRef) value;
579
580 CFStringRef kvsKey = SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name, cleanup_id, in_circle_id);
581 SOSTransportMessageTestAddToChanges(transport, kvsKey, NULL);
582 CFReleaseSafe(kvsKey);
583
584 kvsKey = SOSMessageKeyCreateWithCircleNameAndPeerNames(circle_name, in_circle_id, cleanup_id);
585 SOSTransportMessageTestAddToChanges(transport, kvsKey, NULL);
586 CFReleaseSafe(kvsKey);
587 }
588 });
589
590 }
591 });
592 }
593 });
594
595 return SOSTransportMessageFlushChanges((SOSTransportMessageRef)transport, error);
596 fail:
597 return true;
598 }
599
600 static bool sendToPeer(SOSTransportMessageRef transport, CFStringRef circleName, CFStringRef peerID, CFDataRef message, CFErrorRef *error) {
601 SOSTransportMessageTestRef testTransport = (SOSTransportMessageTestRef) transport;
602 bool result = true;
603 CFStringRef message_to_peer_key = SOSMessageKeyCreateFromTransportToPeer((SOSTransportMessageKVSRef)transport, peerID);
604 CFDictionaryRef a_message_to_a_peer = CFDictionaryCreateForCFTypes(NULL, message_to_peer_key, message, NULL);
605
606 SOSTransportMessageTestAddBulkToChanges((SOSTransportMessageTestRef)testTransport, a_message_to_a_peer);
607 CFReleaseNull(a_message_to_a_peer);
608 CFReleaseNull(message_to_peer_key);
609
610 return result;
611 }
612
613 static bool syncWithPeers(SOSTransportMessageRef transport, CFDictionaryRef circleToPeerIDs, CFErrorRef *error){
614 // Each entry is keyed by circle name and contains a list of peerIDs
615
616 __block bool result = true;
617
618 CFDictionaryForEach(circleToPeerIDs, ^(const void *key, const void *value) {
619 if (isString(key) && isArray(value)) {
620 CFStringRef circleName = (CFStringRef) key;
621 CFArrayForEach(value, ^(const void *value) {
622 if (isString(value)) {
623 CFStringRef peerID = (CFStringRef) value;
624
625 SOSEnginePeerMessageSentBlock sent = NULL;
626 CFDataRef message_to_send = NULL;
627 bool ok = false;
628 SOSPeerRef peer = SOSPeerCreateWithEngine(SOSTransportMessageGetEngine(transport), peerID);
629 CFDataRef coderData = SOSEngineGetCoderData(SOSTransportMessageGetEngine(transport), peerID);
630
631 SOSCoderRef coder = SOSCoderCreateFromData(coderData, error);
632 SOSPeerSetCoder(peer, coder);
633
634 ok = SOSPeerCoderSendMessageIfNeeded(peer, &message_to_send, circleName, peerID, &sent, error);
635 coder = SOSPeerGetCoder(peer);
636
637 if (message_to_send) {
638 CFDictionaryRef peer_dict = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
639 peerID, message_to_send,
640 NULL);
641
642 CFDictionarySetValue(SOSTransportMessageTestGetChanges((SOSTransportMessageTestRef)transport), circleName, peer_dict);
643 SOSPeerCoderConsume(&sent, ok);
644
645 CFReleaseSafe(peer_dict);
646 }
647
648
649 Block_release(sent);
650
651
652 CFReleaseSafe(message_to_send);
653
654 coderData = SOSCoderCopyDER(coder, error);
655
656 if(!SOSEngineSetCoderData(SOSTransportMessageGetEngine(transport), peerID, coderData, error)){
657 secerror("SOSTransportMessageSendMessageIfNeeded, Could not save peer state");
658 }
659 CFReleaseNull(coderData);
660
661 if (coder)
662 SOSCoderDispose(coder);
663
664 CFReleaseNull(peer);
665 }
666 });
667 }
668 });
669
670 return result;
671 }
672
673 static bool sendMessages(SOSTransportMessageRef transport, CFDictionaryRef circleToPeersToMessage, CFErrorRef *error) {
674 __block bool result = true;
675
676 CFDictionaryForEach(circleToPeersToMessage, ^(const void *key, const void *value) {
677 if (isString(key) && isDictionary(value)) {
678 CFStringRef circleName = (CFStringRef) key;
679 CFDictionaryForEach(value, ^(const void *key, const void *value) {
680 if (isString(key) && isData(value)) {
681 CFStringRef peerID = (CFStringRef) key;
682 CFDataRef message = (CFDataRef) value;
683 bool rx = sendToPeer(transport, circleName, peerID, message, error);
684 result &= rx;
685 }
686 });
687 }
688 });
689
690 return true;
691 }
692
693 static CF_RETURNS_RETAINED
694 CFDictionaryRef handleMessages(SOSTransportMessageRef transport, CFMutableDictionaryRef circle_peer_messages_table, CFErrorRef *error) {
695 SOSTransportMessageTestRef tpt = (SOSTransportMessageTestRef)transport;
696 CFMutableDictionaryRef handled = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
697 CFDictionaryRef peerToMessage = CFDictionaryGetValue(circle_peer_messages_table, tpt->circleName);
698 CFMutableArrayRef handled_peers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
699 CFDictionaryAddValue(handled, tpt->circleName, handled_peers);
700
701 if(peerToMessage){
702 CFDictionaryForEach(peerToMessage, ^(const void *key, const void *value) {
703 CFStringRef peer_id = (CFStringRef) key;
704 CFDataRef peer_message = (CFDataRef) value;
705 CFErrorRef localError = NULL;
706
707 if (SOSTransportMessageHandlePeerMessage((SOSTransportMessageRef) transport, peer_id, peer_message, &localError)) {
708 CFArrayAppendValue(handled_peers, key);
709 } else {
710 secdebug("transport", "%@ KVSTransport handle message failed: %@", peer_id, localError);
711 }
712 CFReleaseNull(localError);
713 });
714 }
715 CFReleaseNull(handled_peers);
716
717 return handled;
718 }
719
720 static bool flushMessageChanges(SOSTransportMessageRef transport, CFErrorRef *error)
721 {
722 return true;
723 }
724
725 static bool cleanupAfterPeer(SOSTransportMessageRef transport, CFDictionaryRef circle_to_peer_ids, CFErrorRef *error)
726 {
727 return SOSTransportMessageTestCleanupAfterPeerMessages((SOSTransportMessageTestRef) transport, circle_to_peer_ids, error);
728 }
729
730 SOSAccountRef SOSTransportMessageTestGetAccount(SOSTransportMessageTestRef transport) {
731 return ((SOSTransportMessageRef)transport)->account;
732 }
733