]> git.saurik.com Git - apple/security.git/blob - Security/sec/SOSCircle/SecureObjectSync/SOSPeer.c
Security-57031.40.6.tar.gz
[apple/security.git] / Security / sec / SOSCircle / SecureObjectSync / SOSPeer.c
1 /*
2 * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 /*
26 * SOSPeer.c - Implementation of a secure object syncing peer
27 */
28 #include <SecureObjectSync/SOSPeer.h>
29
30 #include <SecureObjectSync/SOSCoder.h>
31 #include <SecureObjectSync/SOSDigestVector.h>
32 #include <SecureObjectSync/SOSEngine.h>
33 #include <SecureObjectSync/SOSFullPeerInfo.h>
34 #include <SecureObjectSync/SOSInternal.h>
35 #include <SecureObjectSync/SOSPeerInfo.h>
36 #include <SecureObjectSync/SOSTransport.h>
37 #include <CommonCrypto/CommonDigest.h>
38 #include <CommonCrypto/CommonDigestSPI.h>
39 #include <utilities/SecCFError.h>
40 #include <utilities/SecCFRelease.h>
41 #include <utilities/SecCFWrappers.h>
42 #include <utilities/SecDb.h>
43 #include <utilities/SecFileLocations.h>
44 #include <utilities/SecIOFormat.h>
45 #include <utilities/array_size.h>
46 #include <utilities/debugging.h>
47 #include <utilities/der_plist.h>
48 #include <utilities/der_plist_internal.h>
49
50 #include <securityd/SOSCloudCircleServer.h>
51
52 #include <CoreFoundation/CoreFoundation.h>
53
54 #include <stdlib.h>
55
56 #include <AssertMacros.h>
57
58 //
59 // MARK: - SOSPeerPersistence code
60 //
61 static CFStringRef kSOSPeerSequenceNumberKey = CFSTR("sequence-number");
62 static CFStringRef kSOSPeerGetObjectsKey = CFSTR("get-objects");
63 static CFStringRef kSOSPeerReceivedUnknownConfirmedDigestKey = CFSTR("received-unknown");
64 static CFStringRef kSOSPeerJoinRequestedKey = CFSTR("join-requested");
65 static CFStringRef kSOSPeerSkipHelloKey = CFSTR("skip-hello");
66
67 CFStringRef kSOSPeerDataLabel = CFSTR("iCloud Peer Data Meta-data");
68
69 //
70 // MARK: SOSPeerState (dictionary keys)
71 //
72
73 // PeerState dictionary keys
74 static CFStringRef kSOSPeerSendObjectsKey = CFSTR("send-objects"); // bool
75 static CFStringRef kSOSPeerMustSendMessageKey = CFSTR("must-send"); // bool
76 static CFStringRef kSOSPeerPendingObjectsKey = CFSTR("pending-objects"); // digest
77 static CFStringRef kSOSPeerPendingDeletesKey = CFSTR("pending-deletes"); // digest
78 static CFStringRef kSOSPeerConfirmedManifestKey = CFSTR("confirmed-manifest"); //digest
79 static CFStringRef kSOSPeerProposedManifestKey = CFSTR("pending-manifest"); // array of digests
80 static CFStringRef kSOSPeerLocalManifestKey = CFSTR("local-manifest"); // array of digests
81 static CFStringRef kSOSPeerVersionKey = CFSTR("version"); // int
82
83 enum {
84 kSOSPeerMaxManifestWindowDepth = 4
85 };
86
87 //
88 // MARK: - SOSPeer
89 //
90
91 struct __OpaqueSOSPeer {
92 CFRuntimeBase _base;
93 SOSEngineRef engine;
94
95 SOSCoderRef coder;
96 CFStringRef peer_id;
97 CFIndex version;
98 uint64_t sequenceNumber;
99 bool mustSendMessage;
100 };
101
102 CFGiblisWithCompareFor(SOSPeer)
103
104 static CFStringRef SOSManifestCreateOptionalDescriptionWithLabel(SOSManifestRef manifest, CFStringRef label) {
105 if (!manifest) return CFSTR(" - ");
106 //return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@[%zu]"), label, SOSManifestGetCount(manifest));
107 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR(" %@%@"), label, manifest);
108 }
109
110 static CFMutableDictionaryRef SOSPeerGetState(SOSPeerRef peer) {
111 return SOSEngineGetPeerState(peer->engine, peer->peer_id);
112 }
113
114 static CFStringRef SOSPeerCreateManifestArrayDescriptionWithKey(SOSPeerRef peer, CFStringRef key, CFStringRef label) {
115 CFMutableArrayRef digests = (CFMutableArrayRef)CFDictionaryGetValue(SOSPeerGetState(peer), key);
116 CFIndex count = digests ? CFArrayGetCount(digests) : 0;
117 if (count == 0) return CFSTR(" - ");
118 CFDataRef digest = CFArrayGetValueAtIndex(digests, 0);
119 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR(" %@[%" PRIdCFIndex "]%@"), label, count, SOSEngineGetManifestForDigest(peer->engine, digest));
120 }
121
122 static CFStringRef SOSPeerCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
123 SOSPeerRef peer = (SOSPeerRef)cf;
124 if(peer){
125 CFStringRef po = SOSManifestCreateOptionalDescriptionWithLabel(SOSPeerGetPendingObjects(peer), CFSTR("O"));
126 CFStringRef de = SOSManifestCreateOptionalDescriptionWithLabel(SOSPeerGetPendingDeletes(peer), CFSTR("D"));
127 CFStringRef co = SOSManifestCreateOptionalDescriptionWithLabel(SOSPeerGetConfirmedManifest(peer), CFSTR("C"));
128 CFStringRef pe = SOSPeerCreateManifestArrayDescriptionWithKey(peer, kSOSPeerProposedManifestKey, CFSTR("P"));
129 CFStringRef lo = SOSPeerCreateManifestArrayDescriptionWithKey(peer, kSOSPeerLocalManifestKey, CFSTR("L"));
130 CFStringRef desc = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<%@ %s%s%@%@%@%@%@>"),
131 SOSPeerGetID(peer),
132 SOSPeerMustSendMessage(peer) ? "F" : "f",
133 SOSPeerSendObjects(peer) ? "S" : "s",
134 po, de, co, pe, lo);
135 CFReleaseSafe(lo);
136 CFReleaseSafe(pe);
137 CFReleaseSafe(co);
138 CFReleaseSafe(de);
139 CFReleaseSafe(po);
140
141 return desc;
142 }
143 else
144 return CFSTR("NULL");
145 }
146
147 static Boolean SOSPeerCompare(CFTypeRef cfA, CFTypeRef cfB)
148 {
149 SOSPeerRef peerA = (SOSPeerRef)cfA, peerB = (SOSPeerRef)cfB;
150 // Use mainly to see if peerB is actually this device (peerA)
151 return CFStringCompare(SOSPeerGetID(peerA), SOSPeerGetID(peerB), 0) == kCFCompareEqualTo;
152 }
153
154 static CFMutableArrayRef SOSPeerGetDigestsWithKey(SOSPeerRef peer, CFStringRef key) {
155 CFMutableDictionaryRef peerState = SOSPeerGetState(peer);
156 CFMutableArrayRef digests = (CFMutableArrayRef)CFDictionaryGetValue(peerState, key);
157 if (!digests) {
158 digests = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
159 CFDictionarySetValue(peerState, key, digests);
160 CFReleaseSafe(digests);
161 }
162 return digests;
163 }
164
165 static void SOSPeerStateSetDigestForKey(CFMutableDictionaryRef peerState, CFStringRef key, CFDataRef digest) {
166 if (digest)
167 CFDictionarySetValue(peerState, key, digest);
168 else
169 CFDictionaryRemoveValue(peerState, key);
170 }
171
172 static void SOSPeerAddManifestWithKey(SOSPeerRef peer, CFStringRef key, SOSManifestRef manifest) {
173 CFMutableArrayRef digests = SOSPeerGetDigestsWithKey(peer, key);
174 CFDataRef digest = SOSManifestGetDigest(manifest, NULL);
175 if (digest) {
176 CFIndex count = CFArrayGetCount(digests);
177 SOSEngineAddManifest(peer->engine, manifest);
178 CFIndex ixOfDigest = CFArrayGetFirstIndexOfValue(digests, CFRangeMake(0, count), digest);
179 if (ixOfDigest != 0) {
180 if (ixOfDigest != kCFNotFound) {
181 CFArrayRemoveValueAtIndex(digests, ixOfDigest);
182 } else {
183 while (count >= kSOSPeerMaxManifestWindowDepth)
184 CFArrayRemoveValueAtIndex(digests, --count);
185 }
186
187 CFArrayInsertValueAtIndex(digests, 0, digest);
188 }
189 } else {
190 // pending == NULL => nothing clear history
191 CFArrayRemoveAllValues(digests);
192 }
193 }
194
195 static SOSPeerRef SOSPeerCreate_Internal(SOSEngineRef engine, CFDictionaryRef persisted, CFStringRef theirPeerID, CFIndex version, CFErrorRef *error) {
196 SOSPeerRef p = CFTypeAllocate(SOSPeer, struct __OpaqueSOSPeer, kCFAllocatorDefault);
197 p->engine = engine;
198 p->peer_id = CFRetainSafe(theirPeerID);
199 p->version = version;
200
201 if (persisted) {
202 CFDictionaryRef peer_dict = (CFDictionaryRef) persisted;
203
204 int64_t sequenceNumber;
205 CFNumberRef seqNo = CFDictionaryGetValue(peer_dict, kSOSPeerSequenceNumberKey);
206 if (seqNo) {
207 CFNumberGetValue(seqNo, kCFNumberSInt64Type, &sequenceNumber);
208 p->sequenceNumber = sequenceNumber;
209 }
210 CFNumberRef version = CFDictionaryGetValue(peer_dict, kSOSPeerVersionKey);
211 if (version)
212 CFNumberGetValue(version, kCFNumberCFIndexType, &p->version);
213 }
214
215 return p;
216 }
217
218 SOSPeerRef SOSPeerCreateWithEngine(SOSEngineRef engine, CFStringRef peer_id) {
219 CFMutableDictionaryRef state = SOSEngineGetPeerState(engine, peer_id);
220 return SOSPeerCreate_Internal(engine, state, peer_id, 0, NULL);
221 }
222
223 static bool SOSPeerPersistData(SOSPeerRef peer, CFErrorRef *error)
224 {
225 CFMutableDictionaryRef data_dict = SOSPeerGetState(peer);
226
227 int64_t sequenceNumber = peer->sequenceNumber;
228 CFNumberRef seqNo = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &sequenceNumber);
229 CFDictionarySetValue(data_dict, kSOSPeerSequenceNumberKey, seqNo);
230 CFReleaseNull(seqNo);
231 CFDictionarySetValue(data_dict, kSOSPeerMustSendMessageKey, peer->mustSendMessage ? kCFBooleanTrue : kCFBooleanFalse);
232 if (peer->version) {
233 CFNumberRef version = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &peer->version);
234 CFDictionarySetValue(data_dict, kSOSPeerVersionKey, version);
235 CFReleaseSafe(version);
236 }
237 return true;
238 }
239
240 SOSPeerRef SOSPeerCreate(SOSEngineRef engine, SOSPeerInfoRef peerInfo,
241 CFErrorRef *error) {
242 if (peerInfo == NULL) {
243 SOSCreateError(kSOSErrorUnsupported, CFSTR("Can't create peer without their peer info!"), NULL, error);
244 return NULL;
245 }
246
247 CFStringRef peer_id = SOSPeerInfoGetPeerID(peerInfo);
248 CFDictionaryRef persisted = SOSEngineGetPeerState(engine, peer_id);
249 SOSPeerRef peer = SOSPeerCreate_Internal(engine,
250 persisted,
251 peer_id,
252 SOSPeerInfoGetVersion(peerInfo),
253 error);
254 if (peer)
255 SOSPeerPersistData(peer, error);
256 return peer;
257 }
258
259 SOSPeerRef SOSPeerCreateSimple(SOSEngineRef engine, CFStringRef peer_id, CFIndex version, CFErrorRef *error) {
260
261 CFDictionaryRef persisted = SOSEngineGetPeerState(engine, peer_id);
262 SOSPeerRef peer = SOSPeerCreate_Internal(engine, persisted, peer_id, version, error);
263 if (peer)
264 SOSPeerPersistData(peer, error);
265 return peer;
266 }
267
268 static void SOSPeerDestroy(CFTypeRef cf) {
269 SOSPeerRef peer = (SOSPeerRef)cf;
270 SOSPeerPersistData(peer, NULL);
271 CFReleaseSafe(peer->peer_id);
272 }
273
274 void SOSPeerDidConnect(SOSPeerRef peer) {
275 SOSPeerSetMustSendMessage(peer, true);
276 SOSPeerSetProposedManifest(peer, SOSPeerGetConfirmedManifest(peer));
277 }
278
279 CFIndex SOSPeerGetVersion(SOSPeerRef peer) {
280 return peer->version;
281 }
282
283 CFStringRef SOSPeerGetID(SOSPeerRef peer) {
284 return peer->peer_id;
285 }
286
287 SOSEngineRef SOSPeerGetEngine(SOSPeerRef peer){
288 return peer->engine;
289 }
290 SOSCoderRef SOSPeerGetCoder(SOSPeerRef peer){
291 return peer->coder;
292 }
293 void SOSPeerSetCoder(SOSPeerRef peer, SOSCoderRef coder){
294 peer->coder = coder;
295 }
296
297 uint64_t SOSPeerNextSequenceNumber(SOSPeerRef peer) {
298 return ++peer->sequenceNumber;
299 }
300
301 uint64_t SOSPeerGetMessageVersion(SOSPeerRef peer) {
302 return SOSPeerGetVersion(peer);
303
304 }
305
306 bool SOSPeerMustSendMessage(SOSPeerRef peer) {
307 CFBooleanRef must = CFDictionaryGetValue(SOSPeerGetState(peer), kSOSPeerMustSendMessageKey);
308 return must && CFBooleanGetValue(must);
309 }
310
311 void SOSPeerSetMustSendMessage(SOSPeerRef peer, bool sendMessage) {
312 CFDictionarySetValue(SOSPeerGetState(peer), kSOSPeerMustSendMessageKey, sendMessage ? kCFBooleanTrue : kCFBooleanFalse);
313 }
314
315 bool SOSPeerSendObjects(SOSPeerRef peer) {
316 CFBooleanRef send = CFDictionaryGetValue(SOSPeerGetState(peer), kSOSPeerSendObjectsKey);
317 return send && CFBooleanGetValue(send);
318 }
319
320 void SOSPeerSetSendObjects(SOSPeerRef peer, bool sendObjects) {
321 CFDictionarySetValue(SOSPeerGetState(peer), kSOSPeerSendObjectsKey, sendObjects ? kCFBooleanTrue : kCFBooleanFalse);
322 }
323
324 SOSManifestRef SOSPeerGetProposedManifest(SOSPeerRef peer) {
325 CFDataRef digest = NULL;
326 CFMutableArrayRef proposedDigests = (CFMutableArrayRef)CFDictionaryGetValue(SOSPeerGetState(peer), kSOSPeerProposedManifestKey);
327 if (proposedDigests && CFArrayGetCount(proposedDigests) > 0)
328 digest = CFArrayGetValueAtIndex(proposedDigests, 0);
329 return SOSEngineGetManifestForDigest(peer->engine, digest);
330 }
331
332 #if 0
333 static SOSManifestRef SOSPeerGetLocalManifest(SOSPeerRef peer) {
334 CFDataRef digest = NULL;
335 CFMutableArrayRef localDigests = (CFMutableArrayRef)CFDictionaryGetValue(SOSPeerGetState(peer), kSOSPeerLocalManifestKey);
336 if (localDigests && CFArrayGetCount(localDigests) > 0)
337 digest = CFArrayGetValueAtIndex(localDigests, 0);
338 return SOSEngineGetManifestForDigest(peer->engine, digest);
339 }
340 #endif
341
342 SOSManifestRef SOSPeerGetConfirmedManifest(SOSPeerRef peer) {
343 return SOSEngineGetManifestForDigest(peer->engine, CFDictionaryGetValue(SOSPeerGetState(peer), kSOSPeerConfirmedManifestKey));
344 }
345
346 void SOSPeerSetConfirmedManifest(SOSPeerRef peer, SOSManifestRef confirmed) {
347 SOSEngineAddManifest(peer->engine, confirmed);
348 SOSPeerStateSetDigestForKey(SOSPeerGetState(peer), kSOSPeerConfirmedManifestKey, SOSManifestGetDigest(confirmed, NULL));
349
350 // TODO: Clear only expired pending and local manifests from the array - this clears them all
351 // To do so we'd have to track the messageIds we sent to our peer and when we proposed a particular manifest.
352 // Then we simply remove the entires from messages older that the one we are confirming now
353 //CFArrayRemoveAllValues(SOSPeerGetDigestsWithKey(peer, kSOSPeerProposedManifestKey));
354 //CFArrayRemoveAllValues(SOSPeerGetDigestsWithKey(peer, kSOSPeerLocalManifestKey));
355 }
356
357 void SOSPeerAddProposedManifest(SOSPeerRef peer, SOSManifestRef pending) {
358 SOSPeerAddManifestWithKey(peer, kSOSPeerProposedManifestKey, pending);
359 }
360
361 void SOSPeerSetProposedManifest(SOSPeerRef peer, SOSManifestRef pending) {
362 SOSEngineAddManifest(peer->engine, pending);
363 CFMutableArrayRef proposedDigests = SOSPeerGetDigestsWithKey(peer, kSOSPeerProposedManifestKey);
364 CFArrayRemoveAllValues(proposedDigests);
365 if (pending)
366 CFArrayAppendValue(proposedDigests, SOSManifestGetDigest(pending, NULL));
367 }
368
369 void SOSPeerAddLocalManifest(SOSPeerRef peer, SOSManifestRef local) {
370 SOSPeerAddManifestWithKey(peer, kSOSPeerLocalManifestKey, local);
371 }
372
373 SOSManifestRef SOSPeerGetPendingObjects(SOSPeerRef peer) {
374 return SOSEngineGetManifestForDigest(peer->engine, CFDictionaryGetValue(SOSPeerGetState(peer), kSOSPeerPendingObjectsKey));
375 }
376
377 void SOSPeerSetPendingObjects(SOSPeerRef peer, SOSManifestRef pendingObjects) {
378 SOSEngineAddManifest(peer->engine, pendingObjects);
379 SOSPeerStateSetDigestForKey(SOSPeerGetState(peer), kSOSPeerPendingObjectsKey, SOSManifestGetDigest(pendingObjects, NULL));
380 }
381
382 SOSManifestRef SOSPeerGetPendingDeletes(SOSPeerRef peer) {
383 return SOSEngineGetManifestForDigest(peer->engine, CFDictionaryGetValue(SOSPeerGetState(peer), kSOSPeerPendingDeletesKey));
384 }
385
386 void SOSPeerSetPendingDeletes(SOSPeerRef peer, SOSManifestRef pendingDeletes) {
387 SOSEngineAddManifest(peer->engine, pendingDeletes);
388 SOSPeerStateSetDigestForKey(SOSPeerGetState(peer), kSOSPeerPendingDeletesKey, SOSManifestGetDigest(pendingDeletes, NULL));
389 }
390
391 static void SOSMarkDigestInUse(struct SOSDigestVector *mdInUse, CFDataRef digest) {
392 if (!isData(digest)) return;
393 SOSDigestVectorAppend(mdInUse, CFDataGetBytePtr(digest));
394 }
395
396 static void SOSMarkDigestsInUse(struct SOSDigestVector *mdInUse, CFArrayRef digests) {
397 if (!isArray(digests)) return;
398 CFDataRef digest = NULL;
399 CFArrayForEachC(digests, digest) {
400 SOSMarkDigestInUse(mdInUse, digest);
401 }
402 }
403
404 // Add all digests we are using to mdInUse
405 void SOSPeerMarkDigestsInUse(SOSPeerRef peer, struct SOSDigestVector *mdInUse) {
406 CFMutableDictionaryRef peerState = SOSPeerGetState(peer);
407 SOSMarkDigestInUse(mdInUse, CFDictionaryGetValue(peerState, kSOSPeerPendingObjectsKey));
408 SOSMarkDigestInUse(mdInUse, CFDictionaryGetValue(peerState, kSOSPeerPendingDeletesKey));
409 SOSMarkDigestInUse(mdInUse, CFDictionaryGetValue(peerState, kSOSPeerConfirmedManifestKey));
410 SOSMarkDigestsInUse(mdInUse, CFDictionaryGetValue(peerState, kSOSPeerLocalManifestKey));
411 SOSMarkDigestsInUse(mdInUse, CFDictionaryGetValue(peerState, kSOSPeerProposedManifestKey));
412 }
413
414
415 // absentFromRemote
416 // AbsentLocally
417 // additionsFromRemote
418 // original intent was that digests only got added to pendingObjects. We only know for sure if it is something added locally via api call
419
420
421 bool SOSPeerDidReceiveRemovalsAndAdditions(SOSPeerRef peer, SOSManifestRef absentFromRemote, SOSManifestRef additionsFromRemote,
422 SOSManifestRef local, CFErrorRef *error) {
423 // We assume that incoming manifests are all sorted, and absentFromRemote is disjoint from additionsFromRemote
424 bool ok = true;
425 SOSManifestRef remoteRemovals = NULL, sharedRemovals = NULL, sharedAdditions = NULL, remoteAdditions = NULL;
426 CFDataRef pendingObjectsDigest, pendingDeletesDigest;
427
428 // TODO: Simplyfy -- a lot.
429 ok = ok && (remoteRemovals = SOSManifestCreateIntersection(absentFromRemote, local, error)); // remoteRemovals = absentFromRemote <Intersected> local
430 ok = ok && (sharedRemovals = SOSManifestCreateComplement(remoteRemovals, absentFromRemote, error)); // sharedRemovals = absentFromRemote - remoteRemovals
431 ok = ok && (sharedAdditions = SOSManifestCreateIntersection(additionsFromRemote, local, error)); // sharedAdditions = additionsFromRemote <Intersected> local
432 ok = ok && (remoteAdditions = SOSManifestCreateComplement(sharedAdditions, additionsFromRemote, error)); // remoteAdditions = additionsFromRemote - sharedAdditions
433
434 secnotice("peer", "%@ R:%@ A:%@ C:%@ D:%@ O:%@", peer, absentFromRemote, additionsFromRemote, SOSPeerGetConfirmedManifest(peer), SOSPeerGetPendingDeletes(peer), SOSPeerGetPendingObjects(peer));
435
436 // TODO: Does the value of SOSPeerSendObjects() matter here?
437 pendingObjectsDigest = SOSEnginePatchRecordAndCopyDigest(peer->engine, SOSPeerGetPendingObjects(peer), sharedAdditions, NULL, error); // PO = PO - sharedAdditions
438 pendingDeletesDigest = SOSEnginePatchRecordAndCopyDigest(peer->engine, SOSPeerGetPendingDeletes(peer), sharedRemovals, NULL, error); // D = D - sharedRemovals
439
440 CFMutableDictionaryRef peerState = SOSPeerGetState(peer);
441 SOSPeerStateSetDigestForKey(peerState, kSOSPeerPendingObjectsKey, pendingObjectsDigest);
442 SOSPeerStateSetDigestForKey(peerState, kSOSPeerPendingDeletesKey, pendingDeletesDigest);
443
444 CFReleaseSafe(pendingDeletesDigest);
445 CFReleaseSafe(pendingObjectsDigest);
446 CFReleaseSafe(remoteRemovals);
447 CFReleaseSafe(sharedRemovals);
448 CFReleaseSafe(sharedAdditions);
449 CFReleaseSafe(remoteAdditions);
450
451 secnotice("peer", "%@ C:%@ D:%@ O:%@", peer, SOSPeerGetConfirmedManifest(peer), SOSPeerGetPendingDeletes(peer), SOSPeerGetPendingObjects(peer));
452
453 return ok;
454 }
455
456 bool SOSPeerDidReceiveConfirmedManifest(SOSPeerRef peer, SOSManifestRef confirmed, SOSManifestRef local, CFErrorRef *error) {
457 bool ok = true;
458 if (!confirmed) return ok;
459 SOSManifestRef confirmedRemovals = NULL, confirmedAdditions = NULL;
460
461 // confirmedAdditions = confirmed - previous_confirmed, confirmedRemovals = previous_confirmed - confirmed
462 ok &= SOSManifestDiff(SOSPeerGetConfirmedManifest(peer), confirmed, &confirmedRemovals, &confirmedAdditions, error);
463 ok &= SOSPeerDidReceiveRemovalsAndAdditions(peer, confirmedRemovals, confirmedAdditions, local, error);
464
465 CFReleaseSafe(confirmedRemovals);
466 CFReleaseSafe(confirmedAdditions);
467 return ok;
468 }
469
470 bool SOSPeerDataSourceWillCommit(SOSPeerRef peer, SOSDataSourceTransactionSource source, SOSManifestRef removals, SOSManifestRef additions, CFErrorRef *error) {
471 SOSManifestRef unconfirmedAdditions = NULL;
472 CFDataRef pendingObjectsDigest, pendingDeletesDigest = NULL;
473
474 secnotice("peer", "%@ R:%@ A:%@ C:%@ D:%@ O:%@", peer, removals, additions, SOSPeerGetConfirmedManifest(peer), SOSPeerGetPendingDeletes(peer), SOSPeerGetPendingObjects(peer));
475
476 // Remove confirmed from additions
477 // TODO: Add require and check for error
478 unconfirmedAdditions = SOSManifestCreateComplement(SOSPeerGetConfirmedManifest(peer), additions, error);
479 secnotice("peer", "%@ UA: %@ source: %s", peer, unconfirmedAdditions, source == kSOSDataSourceSOSTransaction ? "sos" : "api");
480
481 pendingObjectsDigest = SOSEnginePatchRecordAndCopyDigest(peer->engine, SOSPeerGetPendingObjects(peer), removals, source == kSOSDataSourceAPITransaction ? unconfirmedAdditions : NULL, error);
482 // TODO: Figure out how to update pendingDeletes...
483 //pendingDeletesDigest = SOSEnginePatchRecordAndCopyDigest(peer->engine, SOSPeerGetPendingDeletes(peer), removals, NULL, error);
484
485 CFMutableDictionaryRef peerState = SOSPeerGetState(peer);
486
487 SOSPeerStateSetDigestForKey(peerState, kSOSPeerPendingObjectsKey, pendingObjectsDigest);
488 SOSPeerStateSetDigestForKey(peerState, kSOSPeerPendingDeletesKey, pendingDeletesDigest);
489
490 CFReleaseSafe(pendingDeletesDigest);
491 CFReleaseSafe(pendingObjectsDigest);
492 CFReleaseSafe(unconfirmedAdditions);
493
494 secnotice("peer", "%@ C:%@ D:%@ P:%@", peer, SOSPeerGetConfirmedManifest(peer), SOSPeerGetPendingDeletes(peer), SOSPeerGetPendingObjects(peer));
495
496 return true;
497 }
498