2 * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 * SOSPeer.c - Implementation of a secure object syncing peer
28 #include <SecureObjectSync/SOSPeer.h>
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>
50 #include <securityd/SOSCloudCircleServer.h>
52 #include <CoreFoundation/CoreFoundation.h>
56 #include <AssertMacros.h>
59 // MARK: - SOSPeerPersistence code
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");
67 CFStringRef kSOSPeerDataLabel
= CFSTR("iCloud Peer Data Meta-data");
70 // MARK: SOSPeerState (dictionary keys)
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
84 kSOSPeerMaxManifestWindowDepth
= 4
91 struct __OpaqueSOSPeer
{
98 uint64_t sequenceNumber
;
102 CFGiblisWithCompareFor(SOSPeer
)
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
);
110 static CFMutableDictionaryRef
SOSPeerGetState(SOSPeerRef peer
) {
111 return SOSEngineGetPeerState(peer
->engine
, peer
->peer_id
);
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
));
122 static CFStringRef
SOSPeerCopyFormatDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
123 SOSPeerRef peer
= (SOSPeerRef
)cf
;
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%@%@%@%@%@>"),
132 SOSPeerMustSendMessage(peer
) ? "F" : "f",
133 SOSPeerSendObjects(peer
) ? "S" : "s",
144 return CFSTR("NULL");
147 static Boolean
SOSPeerCompare(CFTypeRef cfA
, CFTypeRef cfB
)
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
;
154 static CFMutableArrayRef
SOSPeerGetDigestsWithKey(SOSPeerRef peer
, CFStringRef key
) {
155 CFMutableDictionaryRef peerState
= SOSPeerGetState(peer
);
156 CFMutableArrayRef digests
= (CFMutableArrayRef
)CFDictionaryGetValue(peerState
, key
);
158 digests
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
159 CFDictionarySetValue(peerState
, key
, digests
);
160 CFReleaseSafe(digests
);
165 static void SOSPeerStateSetDigestForKey(CFMutableDictionaryRef peerState
, CFStringRef key
, CFDataRef digest
) {
167 CFDictionarySetValue(peerState
, key
, digest
);
169 CFDictionaryRemoveValue(peerState
, key
);
172 static void SOSPeerAddManifestWithKey(SOSPeerRef peer
, CFStringRef key
, SOSManifestRef manifest
) {
173 CFMutableArrayRef digests
= SOSPeerGetDigestsWithKey(peer
, key
);
174 CFDataRef digest
= SOSManifestGetDigest(manifest
, NULL
);
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
);
183 while (count
>= kSOSPeerMaxManifestWindowDepth
)
184 CFArrayRemoveValueAtIndex(digests
, --count
);
187 CFArrayInsertValueAtIndex(digests
, 0, digest
);
190 // pending == NULL => nothing clear history
191 CFArrayRemoveAllValues(digests
);
195 static SOSPeerRef
SOSPeerCreate_Internal(SOSEngineRef engine
, CFDictionaryRef persisted
, CFStringRef theirPeerID
, CFIndex version
, CFErrorRef
*error
) {
196 SOSPeerRef p
= CFTypeAllocate(SOSPeer
, struct __OpaqueSOSPeer
, kCFAllocatorDefault
);
198 p
->peer_id
= CFRetainSafe(theirPeerID
);
199 p
->version
= version
;
202 CFDictionaryRef peer_dict
= (CFDictionaryRef
) persisted
;
204 int64_t sequenceNumber
;
205 CFNumberRef seqNo
= CFDictionaryGetValue(peer_dict
, kSOSPeerSequenceNumberKey
);
207 CFNumberGetValue(seqNo
, kCFNumberSInt64Type
, &sequenceNumber
);
208 p
->sequenceNumber
= sequenceNumber
;
210 CFNumberRef version
= CFDictionaryGetValue(peer_dict
, kSOSPeerVersionKey
);
212 CFNumberGetValue(version
, kCFNumberCFIndexType
, &p
->version
);
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
);
223 static bool SOSPeerPersistData(SOSPeerRef peer
, CFErrorRef
*error
)
225 CFMutableDictionaryRef data_dict
= SOSPeerGetState(peer
);
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
);
233 CFNumberRef version
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberCFIndexType
, &peer
->version
);
234 CFDictionarySetValue(data_dict
, kSOSPeerVersionKey
, version
);
235 CFReleaseSafe(version
);
240 SOSPeerRef
SOSPeerCreate(SOSEngineRef engine
, SOSPeerInfoRef peerInfo
,
242 if (peerInfo
== NULL
) {
243 SOSCreateError(kSOSErrorUnsupported
, CFSTR("Can't create peer without their peer info!"), NULL
, error
);
247 CFStringRef peer_id
= SOSPeerInfoGetPeerID(peerInfo
);
248 CFDictionaryRef persisted
= SOSEngineGetPeerState(engine
, peer_id
);
249 SOSPeerRef peer
= SOSPeerCreate_Internal(engine
,
252 SOSPeerInfoGetVersion(peerInfo
),
255 SOSPeerPersistData(peer
, error
);
259 SOSPeerRef
SOSPeerCreateSimple(SOSEngineRef engine
, CFStringRef peer_id
, CFIndex version
, CFErrorRef
*error
) {
261 CFDictionaryRef persisted
= SOSEngineGetPeerState(engine
, peer_id
);
262 SOSPeerRef peer
= SOSPeerCreate_Internal(engine
, persisted
, peer_id
, version
, error
);
264 SOSPeerPersistData(peer
, error
);
268 static void SOSPeerDestroy(CFTypeRef cf
) {
269 SOSPeerRef peer
= (SOSPeerRef
)cf
;
270 SOSPeerPersistData(peer
, NULL
);
271 CFReleaseSafe(peer
->peer_id
);
274 void SOSPeerDidConnect(SOSPeerRef peer
) {
275 SOSPeerSetMustSendMessage(peer
, true);
276 SOSPeerSetProposedManifest(peer
, SOSPeerGetConfirmedManifest(peer
));
279 CFIndex
SOSPeerGetVersion(SOSPeerRef peer
) {
280 return peer
->version
;
283 CFStringRef
SOSPeerGetID(SOSPeerRef peer
) {
284 return peer
->peer_id
;
287 SOSEngineRef
SOSPeerGetEngine(SOSPeerRef peer
){
290 SOSCoderRef
SOSPeerGetCoder(SOSPeerRef peer
){
293 void SOSPeerSetCoder(SOSPeerRef peer
, SOSCoderRef coder
){
297 uint64_t SOSPeerNextSequenceNumber(SOSPeerRef peer
) {
298 return ++peer
->sequenceNumber
;
301 uint64_t SOSPeerGetMessageVersion(SOSPeerRef peer
) {
302 return SOSPeerGetVersion(peer
);
306 bool SOSPeerMustSendMessage(SOSPeerRef peer
) {
307 CFBooleanRef must
= CFDictionaryGetValue(SOSPeerGetState(peer
), kSOSPeerMustSendMessageKey
);
308 return must
&& CFBooleanGetValue(must
);
311 void SOSPeerSetMustSendMessage(SOSPeerRef peer
, bool sendMessage
) {
312 CFDictionarySetValue(SOSPeerGetState(peer
), kSOSPeerMustSendMessageKey
, sendMessage
? kCFBooleanTrue
: kCFBooleanFalse
);
315 bool SOSPeerSendObjects(SOSPeerRef peer
) {
316 CFBooleanRef send
= CFDictionaryGetValue(SOSPeerGetState(peer
), kSOSPeerSendObjectsKey
);
317 return send
&& CFBooleanGetValue(send
);
320 void SOSPeerSetSendObjects(SOSPeerRef peer
, bool sendObjects
) {
321 CFDictionarySetValue(SOSPeerGetState(peer
), kSOSPeerSendObjectsKey
, sendObjects
? kCFBooleanTrue
: kCFBooleanFalse
);
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
);
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
);
342 SOSManifestRef
SOSPeerGetConfirmedManifest(SOSPeerRef peer
) {
343 return SOSEngineGetManifestForDigest(peer
->engine
, CFDictionaryGetValue(SOSPeerGetState(peer
), kSOSPeerConfirmedManifestKey
));
346 void SOSPeerSetConfirmedManifest(SOSPeerRef peer
, SOSManifestRef confirmed
) {
347 SOSEngineAddManifest(peer
->engine
, confirmed
);
348 SOSPeerStateSetDigestForKey(SOSPeerGetState(peer
), kSOSPeerConfirmedManifestKey
, SOSManifestGetDigest(confirmed
, NULL
));
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));
357 void SOSPeerAddProposedManifest(SOSPeerRef peer
, SOSManifestRef pending
) {
358 SOSPeerAddManifestWithKey(peer
, kSOSPeerProposedManifestKey
, pending
);
361 void SOSPeerSetProposedManifest(SOSPeerRef peer
, SOSManifestRef pending
) {
362 SOSEngineAddManifest(peer
->engine
, pending
);
363 CFMutableArrayRef proposedDigests
= SOSPeerGetDigestsWithKey(peer
, kSOSPeerProposedManifestKey
);
364 CFArrayRemoveAllValues(proposedDigests
);
366 CFArrayAppendValue(proposedDigests
, SOSManifestGetDigest(pending
, NULL
));
369 void SOSPeerAddLocalManifest(SOSPeerRef peer
, SOSManifestRef local
) {
370 SOSPeerAddManifestWithKey(peer
, kSOSPeerLocalManifestKey
, local
);
373 SOSManifestRef
SOSPeerGetPendingObjects(SOSPeerRef peer
) {
374 return SOSEngineGetManifestForDigest(peer
->engine
, CFDictionaryGetValue(SOSPeerGetState(peer
), kSOSPeerPendingObjectsKey
));
377 void SOSPeerSetPendingObjects(SOSPeerRef peer
, SOSManifestRef pendingObjects
) {
378 SOSEngineAddManifest(peer
->engine
, pendingObjects
);
379 SOSPeerStateSetDigestForKey(SOSPeerGetState(peer
), kSOSPeerPendingObjectsKey
, SOSManifestGetDigest(pendingObjects
, NULL
));
382 SOSManifestRef
SOSPeerGetPendingDeletes(SOSPeerRef peer
) {
383 return SOSEngineGetManifestForDigest(peer
->engine
, CFDictionaryGetValue(SOSPeerGetState(peer
), kSOSPeerPendingDeletesKey
));
386 void SOSPeerSetPendingDeletes(SOSPeerRef peer
, SOSManifestRef pendingDeletes
) {
387 SOSEngineAddManifest(peer
->engine
, pendingDeletes
);
388 SOSPeerStateSetDigestForKey(SOSPeerGetState(peer
), kSOSPeerPendingDeletesKey
, SOSManifestGetDigest(pendingDeletes
, NULL
));
391 static void SOSMarkDigestInUse(struct SOSDigestVector
*mdInUse
, CFDataRef digest
) {
392 if (!isData(digest
)) return;
393 SOSDigestVectorAppend(mdInUse
, CFDataGetBytePtr(digest
));
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
);
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
));
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
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
425 SOSManifestRef remoteRemovals
= NULL
, sharedRemovals
= NULL
, sharedAdditions
= NULL
, remoteAdditions
= NULL
;
426 CFDataRef pendingObjectsDigest
, pendingDeletesDigest
;
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
434 secnotice("peer", "%@ R:%@ A:%@ C:%@ D:%@ O:%@", peer
, absentFromRemote
, additionsFromRemote
, SOSPeerGetConfirmedManifest(peer
), SOSPeerGetPendingDeletes(peer
), SOSPeerGetPendingObjects(peer
));
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
440 CFMutableDictionaryRef peerState
= SOSPeerGetState(peer
);
441 SOSPeerStateSetDigestForKey(peerState
, kSOSPeerPendingObjectsKey
, pendingObjectsDigest
);
442 SOSPeerStateSetDigestForKey(peerState
, kSOSPeerPendingDeletesKey
, pendingDeletesDigest
);
444 CFReleaseSafe(pendingDeletesDigest
);
445 CFReleaseSafe(pendingObjectsDigest
);
446 CFReleaseSafe(remoteRemovals
);
447 CFReleaseSafe(sharedRemovals
);
448 CFReleaseSafe(sharedAdditions
);
449 CFReleaseSafe(remoteAdditions
);
451 secnotice("peer", "%@ C:%@ D:%@ O:%@", peer
, SOSPeerGetConfirmedManifest(peer
), SOSPeerGetPendingDeletes(peer
), SOSPeerGetPendingObjects(peer
));
456 bool SOSPeerDidReceiveConfirmedManifest(SOSPeerRef peer
, SOSManifestRef confirmed
, SOSManifestRef local
, CFErrorRef
*error
) {
458 if (!confirmed
) return ok
;
459 SOSManifestRef confirmedRemovals
= NULL
, confirmedAdditions
= NULL
;
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
);
465 CFReleaseSafe(confirmedRemovals
);
466 CFReleaseSafe(confirmedAdditions
);
470 bool SOSPeerDataSourceWillCommit(SOSPeerRef peer
, SOSDataSourceTransactionSource source
, SOSManifestRef removals
, SOSManifestRef additions
, CFErrorRef
*error
) {
471 SOSManifestRef unconfirmedAdditions
= NULL
;
472 CFDataRef pendingObjectsDigest
, pendingDeletesDigest
= NULL
;
474 secnotice("peer", "%@ R:%@ A:%@ C:%@ D:%@ O:%@", peer
, removals
, additions
, SOSPeerGetConfirmedManifest(peer
), SOSPeerGetPendingDeletes(peer
), SOSPeerGetPendingObjects(peer
));
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");
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);
485 CFMutableDictionaryRef peerState
= SOSPeerGetState(peer
);
487 SOSPeerStateSetDigestForKey(peerState
, kSOSPeerPendingObjectsKey
, pendingObjectsDigest
);
488 SOSPeerStateSetDigestForKey(peerState
, kSOSPeerPendingDeletesKey
, pendingDeletesDigest
);
490 CFReleaseSafe(pendingDeletesDigest
);
491 CFReleaseSafe(pendingObjectsDigest
);
492 CFReleaseSafe(unconfirmedAdditions
);
494 secnotice("peer", "%@ C:%@ D:%@ P:%@", peer
, SOSPeerGetConfirmedManifest(peer
), SOSPeerGetPendingDeletes(peer
), SOSPeerGetPendingObjects(peer
));