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// 61static CFStringRef kSOSPeerSequenceNumberKey = CFSTR("sequence-number"); 62static CFStringRef kSOSPeerGetObjectsKey = CFSTR("get-objects"); 63static CFStringRef kSOSPeerReceivedUnknownConfirmedDigestKey = CFSTR("received-unknown"); 64static CFStringRef kSOSPeerJoinRequestedKey = CFSTR("join-requested"); 65static CFStringRef kSOSPeerSkipHelloKey = CFSTR("skip-hello"); 66 67CFStringRef kSOSPeerDataLabel = CFSTR("iCloud Peer Data Meta-data"); 68 69// 70// MARK: SOSPeerState (dictionary keys) 71// 72 73// PeerState dictionary keys 74static CFStringRef kSOSPeerSendObjectsKey = CFSTR("send-objects"); // bool 75static CFStringRef kSOSPeerMustSendMessageKey = CFSTR("must-send"); // bool 76static CFStringRef kSOSPeerPendingObjectsKey = CFSTR("pending-objects"); // digest 77static CFStringRef kSOSPeerPendingDeletesKey = CFSTR("pending-deletes"); // digest 78static CFStringRef kSOSPeerConfirmedManifestKey = CFSTR("confirmed-manifest"); //digest 79static CFStringRef kSOSPeerProposedManifestKey = CFSTR("pending-manifest"); // array of digests 80static CFStringRef kSOSPeerLocalManifestKey = CFSTR("local-manifest"); // array of digests 81static CFStringRef kSOSPeerVersionKey = CFSTR("version"); // int 82 83enum { 84 kSOSPeerMaxManifestWindowDepth = 4 85}; 86 87// 88// MARK: - SOSPeer 89// 90 91struct __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 102CFGiblisWithCompareFor(SOSPeer) 103 104static 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 110static CFMutableDictionaryRef SOSPeerGetState(SOSPeerRef peer) { 111 return SOSEngineGetPeerState(peer->engine, peer->peer_id); 112} 113 114static 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 122static CFStringRef SOSPeerCopyDescription(CFTypeRef cf) { 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 147static 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 154static 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 165static void SOSPeerStateSetDigestForKey(CFMutableDictionaryRef peerState, CFStringRef key, CFDataRef digest) { 166 if (digest) 167 CFDictionarySetValue(peerState, key, digest); 168 else 169 CFDictionaryRemoveValue(peerState, key); 170} 171 172static 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 195static 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 218SOSPeerRef 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 223static 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 240SOSPeerRef 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 259SOSPeerRef 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 268static void SOSPeerDestroy(CFTypeRef cf) { 269 SOSPeerRef peer = (SOSPeerRef)cf; 270 SOSPeerPersistData(peer, NULL); 271 CFReleaseSafe(peer->peer_id); 272} 273 274void SOSPeerDidConnect(SOSPeerRef peer) { 275 SOSPeerSetMustSendMessage(peer, true); 276 SOSPeerSetProposedManifest(peer, SOSPeerGetConfirmedManifest(peer)); 277} 278 279CFIndex SOSPeerGetVersion(SOSPeerRef peer) { 280 return peer->version; 281} 282 283CFStringRef SOSPeerGetID(SOSPeerRef peer) { 284 return peer->peer_id; 285} 286 287SOSEngineRef SOSPeerGetEngine(SOSPeerRef peer){ 288 return peer->engine; 289} 290SOSCoderRef SOSPeerGetCoder(SOSPeerRef peer){ 291 return peer->coder; 292} 293void SOSPeerSetCoder(SOSPeerRef peer, SOSCoderRef coder){ 294 peer->coder = coder; 295} 296 297uint64_t SOSPeerNextSequenceNumber(SOSPeerRef peer) { 298 return ++peer->sequenceNumber; 299} 300 301uint64_t SOSPeerGetMessageVersion(SOSPeerRef peer) { 302 return SOSPeerGetVersion(peer); 303 304} 305 306bool SOSPeerMustSendMessage(SOSPeerRef peer) { 307 CFBooleanRef must = CFDictionaryGetValue(SOSPeerGetState(peer), kSOSPeerMustSendMessageKey); 308 return must && CFBooleanGetValue(must); 309} 310 311void SOSPeerSetMustSendMessage(SOSPeerRef peer, bool sendMessage) { 312 CFDictionarySetValue(SOSPeerGetState(peer), kSOSPeerMustSendMessageKey, sendMessage ? kCFBooleanTrue : kCFBooleanFalse); 313} 314 315bool SOSPeerSendObjects(SOSPeerRef peer) { 316 CFBooleanRef send = CFDictionaryGetValue(SOSPeerGetState(peer), kSOSPeerSendObjectsKey); 317 return send && CFBooleanGetValue(send); 318} 319 320void SOSPeerSetSendObjects(SOSPeerRef peer, bool sendObjects) { 321 CFDictionarySetValue(SOSPeerGetState(peer), kSOSPeerSendObjectsKey, sendObjects ? kCFBooleanTrue : kCFBooleanFalse); 322} 323 324SOSManifestRef 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 333static 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 342SOSManifestRef SOSPeerGetConfirmedManifest(SOSPeerRef peer) { 343 return SOSEngineGetManifestForDigest(peer->engine, CFDictionaryGetValue(SOSPeerGetState(peer), kSOSPeerConfirmedManifestKey)); 344} 345 346void 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 357void SOSPeerAddProposedManifest(SOSPeerRef peer, SOSManifestRef pending) { 358 SOSPeerAddManifestWithKey(peer, kSOSPeerProposedManifestKey, pending); 359} 360 361void 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 369void SOSPeerAddLocalManifest(SOSPeerRef peer, SOSManifestRef local) { 370 SOSPeerAddManifestWithKey(peer, kSOSPeerLocalManifestKey, local); 371} 372 373SOSManifestRef SOSPeerGetPendingObjects(SOSPeerRef peer) { 374 return SOSEngineGetManifestForDigest(peer->engine, CFDictionaryGetValue(SOSPeerGetState(peer), kSOSPeerPendingObjectsKey)); 375} 376 377void SOSPeerSetPendingObjects(SOSPeerRef peer, SOSManifestRef pendingObjects) { 378 SOSEngineAddManifest(peer->engine, pendingObjects); 379 SOSPeerStateSetDigestForKey(SOSPeerGetState(peer), kSOSPeerPendingObjectsKey, SOSManifestGetDigest(pendingObjects, NULL)); 380} 381 382SOSManifestRef SOSPeerGetPendingDeletes(SOSPeerRef peer) { 383 return SOSEngineGetManifestForDigest(peer->engine, CFDictionaryGetValue(SOSPeerGetState(peer), kSOSPeerPendingDeletesKey)); 384} 385 386void SOSPeerSetPendingDeletes(SOSPeerRef peer, SOSManifestRef pendingDeletes) { 387 SOSEngineAddManifest(peer->engine, pendingDeletes); 388 SOSPeerStateSetDigestForKey(SOSPeerGetState(peer), kSOSPeerPendingDeletesKey, SOSManifestGetDigest(pendingDeletes, NULL)); 389} 390 391static void SOSMarkDigestInUse(struct SOSDigestVector *mdInUse, CFDataRef digest) { 392 if (!isData(digest)) return; 393 SOSDigestVectorAppend(mdInUse, CFDataGetBytePtr(digest)); 394} 395 396static 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 405void 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 421bool 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 456bool 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 470bool 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 499