bool SOSAccountSendIKSPSyncList(SOSAccountRef account, CFErrorRef *error){ bool result = true; __block CFErrorRef localError = NULL; __block CFMutableArrayRef ids = NULL; SOSCircleRef circle = NULL; require_action_quiet(SOSAccountIsInCircle(account, NULL), xit, SOSCreateError(kSOSErrorNoCircle, CFSTR("This device is not in circle"), NULL, &localError)); circle = SOSAccountGetCircle(account, error); ids = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault); SOSCircleForEachValidPeer(circle, account->user_public, ^(SOSPeerInfoRef peer) { if (!SOSAccountIsThisPeerIDMe(account, SOSPeerInfoGetPeerID(peer))) { if(SOSPeerInfoShouldUseIDSTransport(SOSFullPeerInfoGetPeerInfo(account->my_identity), peer) && SOSPeerInfoShouldUseIDSMessageFragmentation(SOSFullPeerInfoGetPeerInfo(account->my_identity), peer) && !SOSPeerInfoShouldUseACKModel(SOSFullPeerInfoGetPeerInfo(account->my_identity), peer)){ SOSTransportMessageIDSSetFragmentationPreference(account->ids_message_transport, kCFBooleanTrue); CFStringRef deviceID = SOSPeerInfoCopyDeviceID(peer); if(deviceID != NULL){ CFArrayAppendValue(ids, deviceID); } CFReleaseNull(deviceID); } } });
bool SOSAccountIsMyPeerActiveInCircleNamed(SOSAccountRef account, CFStringRef circle_name, CFErrorRef* error) { SOSFullPeerInfoRef myfpi = SOSAccountGetMyFullPeerInCircleNamedIfPresent(account, circle_name, NULL); if(!myfpi) return false; SOSPeerInfoRef mypi = SOSFullPeerInfoGetPeerInfo(myfpi); if(!mypi) return false; CFStringRef peerid = SOSPeerInfoGetPeerID(mypi); if (!peerid) return false; return SOSAccountIsActivePeerInCircleNamed(account, circle_name, peerid, error); }
bool SOSAccountVerifyAndAcceptHSAApplicants(SOSAccountRef account, SOSCircleRef newCircle, CFErrorRef *error) { SOSFullPeerInfoRef fpi = account->my_identity; __block bool circleChanged = false; CFMutableSetRef approvals = SOSAccountCopyPreApprovedHSA2Info(account); if(approvals && CFSetGetCount(approvals) > 0) { SOSCircleForEachApplicant(newCircle, ^(SOSPeerInfoRef peer) { CFStringRef peerID = SOSPeerInfoGetPeerID(peer); if(CFSetContainsValue(approvals, peerID)) { SOSPeerInfoRef copypi = SOSPeerInfoCreateCopy(NULL, peer, NULL); circleChanged = SOSCircleAcceptRequest(newCircle, SOSAccountGetPrivateCredential(account, NULL), fpi, copypi, error); CFSetRemoveValue(approvals, peerID); } });
static bool SOSAccountIsThisPeerIDMe(SOSAccountRef account, CFStringRef peerID) { SOSPeerInfoRef mypi = SOSFullPeerInfoGetPeerInfo(account->my_identity); CFStringRef myPeerID = SOSPeerInfoGetPeerID(mypi); return myPeerID && CFEqualSafe(myPeerID, peerID); }
static void tests(void) { __block CFErrorRef testError = NULL; CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); CFStringRef circleName = CFSTR("Woot Circle"); /* DataSource */ SOSDataSourceRef aliceDs = SOSTestDataSourceCreate(); SOSDataSourceRef bobDs = SOSTestDataSourceCreate(); SOSDataSourceFactoryRef aliceDsf = SOSTestDataSourceFactoryCreate(); SOSTestDataSourceFactoryAddDataSource(aliceDsf, circleName, aliceDs); SOSDataSourceFactoryRef bobDsf = SOSTestDataSourceFactoryCreate(); SOSTestDataSourceFactoryAddDataSource(bobDsf, circleName, bobDs); CFDictionaryRef alice_gestalt = SOSCreatePeerGestaltFromName(CFSTR("Alice Device")); CFDictionaryRef bob_gestalt = SOSCreatePeerGestaltFromName(CFSTR("Bob Device")); SOSAccountRef alice_account = SOSAccountCreate(kCFAllocatorDefault, alice_gestalt, aliceDsf); SOSAccountRef bob_account = SOSAccountCreate(kCFAllocatorDefault, bob_gestalt, bobDsf); SOSAccountAssertUserCredentials(alice_account, CFSTR("alice"), cfpassword, &testError); SOSAccountAssertUserCredentials(bob_account, CFSTR("bob"), cfpassword, &testError); CFReleaseNull(cfpassword); SOSAccountJoinCircles(alice_account, &testError); SOSAccountJoinCircles(bob_account, &testError); CFDataRef alice_account_data = SOSAccountCopyEncodedData(alice_account, kCFAllocatorDefault, &testError); CFDataRef bob_account_data = SOSAccountCopyEncodedData(bob_account, kCFAllocatorDefault, &testError); CFArrayRef alice_peers = SOSAccountCopyPeers(alice_account, &testError); CFArrayRef bob_peers = SOSAccountCopyPeers(bob_account, &testError); SOSPeerInfoRef alice_peer_info = (SOSPeerInfoRef)CFArrayGetValueAtIndex(alice_peers, 0); SOSPeerInfoRef bob_peer_info = (SOSPeerInfoRef)CFArrayGetValueAtIndex(bob_peers, 0); CFStringRef alice_peer_id = SOSPeerInfoGetPeerID(alice_peer_info); CFStringRef bob_peer_id = SOSPeerInfoGetPeerID(bob_peer_info); CFDataRef alice_peer_external_form = CFStringCreateExternalRepresentation(kCFAllocatorDefault, alice_peer_id, kCFStringEncodingUTF8, '?'); CFDataRef bob_peer_external_form = CFStringCreateExternalRepresentation(kCFAllocatorDefault, bob_peer_id, kCFStringEncodingUTF8, '?'); bool aliceReady = false; bool bobReady = false; CFDataRef aliceSideSession = SecOTRSessionCreateRemote_internal(bob_account_data, bob_peer_external_form, alice_account_data, &testError); RegressionsLogError(testError); CFReleaseNull(testError); ok(aliceSideSession != NULL, "Make Alice side remote session"); CFDataRef bobSideSession = SecOTRSessionCreateRemote_internal(alice_account_data, alice_peer_external_form, bob_account_data, &testError); RegressionsLogError(testError); CFReleaseNull(testError); ok(bobSideSession != NULL, "Make Bob side remote session"); CFDataRef aliceSideSessionResult = NULL; CFDataRef bobSideSessionResult = NULL; CFDataRef aliceToBob = NULL; CFDataRef bobToAlice = NULL; do { bool aliceStatus = SecOTRSessionProcessPacketRemote(aliceSideSession, bobToAlice, &aliceSideSessionResult, &aliceToBob, &aliceReady, &testError); ok (aliceStatus, "Alice sent packet OK"); RegressionsLogError(testError); CFReleaseNull(testError); CFReleaseSafe(aliceSideSession); aliceSideSession = aliceSideSessionResult; if (aliceReady) { break; } bool bobStatus = SecOTRSessionProcessPacketRemote(bobSideSession, aliceToBob, &bobSideSessionResult, &bobToAlice, &bobReady, &testError); ok (bobStatus, "Bob sent packet OK"); RegressionsLogError(testError); CFReleaseNull(testError); CFReleaseSafe(bobSideSession); bobSideSession = bobSideSessionResult; } while (1); ok(bobReady, "Bob finished negotiating at the same time as Alice."); CFReleaseNull(aliceSideSession); CFReleaseNull(bobSideSession); SecOTRFIPurgeAllFromKeychain(&testError); RegressionsLogError(testError); CFReleaseNull(bob_peer_external_form); CFReleaseNull(alice_peer_external_form); CFReleaseNull(alice_account_data); CFReleaseNull(bob_account_data); CFReleaseNull(alice_peers); CFReleaseNull(bob_peers); CFReleaseNull(aliceSideSession); CFReleaseNull(bobSideSession); CFReleaseNull(testError); }
static void tests(void) { CFErrorRef error = NULL; CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); CFStringRef cfaccount = CFSTR("*****@*****.**"); CFStringRef circle_name = CFSTR("TestSource"); CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); SOSAccountRef alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), circle_name); SOSAccountRef bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), circle_name); SOSAccountRef carole_account = CreateAccountForLocalChanges(CFSTR("Carole"), circle_name); ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); // Bob wins writing at this point, feed the changes back to alice. is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); CFReleaseNull(error); ok(SOSAccountAssertUserCredentialsAndUpdate(carole_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); CFReleaseNull(error); ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error); CFReleaseNull(error); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); ok(SOSAccountJoinCircles_wTxn(bob_account, &error), "Bob Applies (%@)", error); CFReleaseNull(error); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); { CFArrayRef applicants = SOSAccountCopyApplicants(alice_account, &error); ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); ok(SOSAccountAcceptApplicants(alice_account, applicants, &error), "Alice accepts (%@)", error); CFReleaseNull(error); CFReleaseNull(applicants); } is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 3, "updates"); accounts_agree("bob&alice pair", bob_account, alice_account); CFArrayRef peers = SOSAccountCopyPeers(alice_account, &error); ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error); CFReleaseNull(peers); SOSFullPeerInfoRef fpiAlice = SOSAccountGetMyFullPeerInfo(alice_account); CFStringRef alice_id = CFStringCreateCopy(NULL, SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(fpiAlice))); ok(SOSAccountLeaveCircle(alice_account, &error), "Alice Leaves (%@)", error); CFReleaseNull(error); CFReleaseNull(cfpassword); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); accounts_agree("Alice bails", bob_account, alice_account); accounts_agree("Alice bails", bob_account, carole_account); SOSAccountCleanupRetirementTickets(bob_account, 0, &error); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); //is(CFDictionaryGetCountOfValue(BobChanges, kCFNull),0, "0 Keys Nulled Out"); ok(SOSAccountJoinCircles_wTxn(carole_account, &error), "Carole Applies (%@)", error); CFReleaseNull(error); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); { CFArrayRef applicants = SOSAccountCopyApplicants(bob_account, &error); ok(applicants && CFArrayGetCount(applicants) == 1, "See one applicant %@ (%@)", applicants, error); ok(SOSAccountAcceptApplicants(bob_account, applicants, &error), "Bob accepts Carole (%@)", error); CFReleaseNull(error); CFReleaseNull(applicants); } // Bob should not yet cleanup Alice's retirment here on his own since it hasn't been long enough // by default. //is(CFDictionaryGetCountOfValue(BobChanges, kCFNull),0, "0 Keys Nulled Out"); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 3, "updates"); accounts_agree("Carole joins", bob_account, carole_account); SOSAccountCleanupRetirementTickets(bob_account, 0, &error); is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); is(countPeers(bob_account), 2, "Active peers after forced cleanup"); is(countActivePeers(bob_account), 3, "Inactive peers after forced cleanup"); //is(CFDictionaryGetCountOfValue(BobChanges, kCFNull), 1, "1 Keys Nulled Out"); // CFDictionaryForEach(BobChanges, ^(const void *key, const void *value) { // if(isNull(value)) { // CFStringRef circle_name = NULL, retiree = NULL; // SOSKVSKeyType keytype = SOSKVSKeyGetKeyTypeAndParse(key, &circle_name, &retiree, NULL); // is(keytype, kRetirementKey, "Expect only a retirement key"); // ok(CFEqualSafe(alice_id, retiree), "Alice (%@) is retiree (%@)", alice_id, retiree); // CFReleaseNull(circle_name); // CFReleaseNull(retiree); // } // }); CFReleaseNull(alice_id); CFReleaseNull(carole_account); CFReleaseNull(bob_account); CFReleaseNull(alice_account); SOSTestCleanup(); }
static void tests(void) { SecKeyRef publicKey = NULL; CFErrorRef error = NULL; SOSCircleRef circle = SOSCircleCreate(NULL, CFSTR("Test Circle"), &error); CFStringRef circle_key = SOSCircleKeyCreateWithCircle(circle, NULL); CFStringRef circle_name = NULL; ok(circle_key, "Circle key created"); is(SOSKVSKeyGetKeyType(circle_key), kCircleKey, "Is circle key"); is(SOSKVSKeyGetKeyTypeAndParse(circle_key, &circle_name, NULL, NULL, NULL, NULL, NULL), kCircleKey, "Is circle key, extract name"); ok(circle_name, "Circle name extracted"); ok(CFEqualSafe(circle_name, SOSCircleGetName(circle)), "Circle name matches '%@' '%@'", circle_name, SOSCircleGetName(circle)); CFReleaseNull(circle_name); CFReleaseNull(circle_key); SOSPeerInfoRef pi = SOSCreatePeerInfoFromName(CFSTR("Test Peer"), &publicKey, &error); CFStringRef other_peer_id = CFSTR("OTHER PEER"); CFStringRef messageKey = SOSMessageKeyCreateWithCircleAndPeerNames(circle, SOSPeerInfoGetPeerID(pi), other_peer_id); ok(messageKey, "Getting message key '%@'", messageKey); CFStringRef message_circle_name = NULL; CFStringRef message_from_peer_id = NULL; CFStringRef message_to_peer_id = NULL; CFStringRef message_ring = NULL; CFStringRef message_peer_info = NULL; CFStringRef message_backup = NULL; is(SOSKVSKeyGetKeyType(messageKey), kMessageKey, "Is message key"); is(SOSKVSKeyGetKeyTypeAndParse(messageKey, &message_circle_name, &message_peer_info, &message_ring, &message_backup, &message_from_peer_id, &message_to_peer_id), kMessageKey, "Is message key, extract parts"); ok(CFEqualSafe(SOSCircleGetName(circle), message_circle_name), "circle key matches in message (%@ v %@)",SOSCircleGetName(circle), message_circle_name); ok(CFEqualSafe(SOSPeerInfoGetPeerID(pi), message_from_peer_id), "from peer set correctly (%@ v %@)", SOSPeerInfoGetPeerID(pi), message_from_peer_id); ok(CFEqualSafe(other_peer_id, message_to_peer_id), "to peer set correctly (%@ v %@)", other_peer_id, message_to_peer_id); CFStringRef retirementKey = SOSRetirementKeyCreateWithCircleAndPeer(circle, SOSPeerInfoGetPeerID(pi)); CFStringRef retirement_circle_name = NULL; CFStringRef retirement_peer_id = NULL; is(SOSKVSKeyGetKeyType(retirementKey), kRetirementKey, "Is retirement key"); is(SOSKVSKeyGetKeyTypeAndParse(retirementKey, &retirement_circle_name, NULL, NULL, NULL, &retirement_peer_id, NULL), kRetirementKey, "Is retirement key, extract parts"); CFReleaseSafe(retirementKey); ok(CFEqualSafe(SOSCircleGetName(circle), retirement_circle_name), "circle key matches in retirement (%@ v %@)", SOSCircleGetName(circle), retirement_circle_name); ok(CFEqualSafe(SOSPeerInfoGetPeerID(pi), retirement_peer_id), "retirement peer set correctly (%@ v %@)", SOSPeerInfoGetPeerID(pi), retirement_peer_id); CFReleaseNull(publicKey); CFReleaseNull(circle); CFReleaseNull(error); CFReleaseNull(pi); CFReleaseNull(messageKey); CFReleaseNull(message_circle_name); CFReleaseNull(message_from_peer_id); CFReleaseNull(message_to_peer_id); CFReleaseNull(retirement_circle_name); CFReleaseNull(retirement_peer_id); }
static void tests() { CFErrorRef error = NULL; CFStringRef aliceID = CFSTR("Alice"); CFStringRef bobID = CFSTR("Bob"); // not really remote, just another client on same machine SecKeyRef alice_key = NULL; SecKeyRef bob_key = NULL; CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10); CFDataRef parameters = SOSUserKeyCreateGenerateParameters(&error); ok(parameters, "No parameters!"); ok(error == NULL, "Error: (%@)", error); CFReleaseNull(error); SecKeyRef user_privkey = SOSUserKeygen(cfpassword, parameters, &error); CFReleaseNull(parameters); CFReleaseSafe(cfpassword); CFStringRef circleName = CFSTR("Woot Circle"); SOSFullPeerInfoRef alice_full_peer_info = SOSCreateFullPeerInfoFromName(aliceID, &alice_key, &error); SOSPeerInfoRef alice_peer_info = SOSFullPeerInfoGetPeerInfo(alice_full_peer_info); SOSFullPeerInfoRef bob_full_peer_info = SOSCreateFullPeerInfoFromName(bobID, &bob_key, &error); SOSPeerInfoRef bob_peer_info = SOSFullPeerInfoGetPeerInfo(bob_full_peer_info); SOSCircleRef aliceCircle = SOSCircleCreate(kCFAllocatorDefault, circleName, &error); ok(SOSCircleRequestAdmission(aliceCircle, user_privkey, alice_full_peer_info, &error)); ok(SOSCircleAcceptRequests(aliceCircle, user_privkey, alice_full_peer_info, NULL)); ok(SOSCircleRequestAdmission(aliceCircle, user_privkey, bob_full_peer_info, &error), "requested admission"); ok(SOSCircleAcceptRequests(aliceCircle, user_privkey, bob_full_peer_info, &error), "accepted them all!"); alice_peer_info = SOSFullPeerInfoGetPeerInfo(alice_full_peer_info); bob_peer_info = SOSFullPeerInfoGetPeerInfo(bob_full_peer_info); CFDataRef aliceCircleEncoded; ok(aliceCircleEncoded = SOSCircleCopyEncodedData(aliceCircle, kCFAllocatorDefault, &error), "encode alice circle: %@", error); CFReleaseNull(error); SOSCircleRef bobCircle; ok(bobCircle = SOSCircleCreateFromData(0, aliceCircleEncoded, &error), "decode bobCircle: %@", error); CFReleaseNull(aliceCircleEncoded); CFReleaseNull(error); /* Transport. */ __block CFDataRef queued_message = NULL; SOSPeerSendBlock enqueueMessage = ^bool (CFDataRef message, CFErrorRef *error) { if (queued_message) fail("We already had an unproccessed message"); queued_message = (CFDataRef) CFRetain(message); return true; }; CFDataRef (^dequeueMessage)() = ^CFDataRef () { CFDataRef result = queued_message; queued_message = NULL; return result; }; /* DataSource */ SOSDataSourceRef aliceDs = SOSTestDataSourceCreate(); SOSDataSourceRef bobDs = SOSTestDataSourceCreate(); SOSDataSourceFactoryRef aliceDsf = SOSTestDataSourceFactoryCreate(); SOSTestDataSourceFactoryAddDataSource(aliceDsf, circleName, aliceDs); SOSDataSourceFactoryRef bobDsf = SOSTestDataSourceFactoryCreate(); SOSTestDataSourceFactoryAddDataSource(bobDsf, circleName, bobDs); /* Test passing peer messages to the engine. */ CFDataRef message; CFStringRef bob_peer_id = SOSPeerInfoGetPeerID(bob_peer_info); /* Hand an empty message to the engine for handeling. */ message = CFDataCreate(NULL, NULL, 0); is(SOSCircleHandlePeerMessage(aliceCircle, alice_full_peer_info, aliceDsf, enqueueMessage, bob_peer_id, message, &error), false, "empty message rejected, %@", error); CFReleaseNull(error); CFReleaseNull(message); ok(SOSCircleSyncWithPeer(alice_full_peer_info, aliceCircle, aliceDsf, enqueueMessage, bob_peer_id, &error), "Start sync [error %@]", error); CFReleaseNull(error); ok(message = dequeueMessage(), "Alice sent message"); CFStringRef alice_peer_id = SOSPeerInfoGetPeerID(alice_peer_info); is(SOSCircleHandlePeerMessage(bobCircle, bob_full_peer_info, bobDsf, enqueueMessage, alice_peer_id, message, &error), true, "Bob accepted message: %@", error); CFReleaseNull(message); #if 1 CFStringRef desc = NULL; ok(message = dequeueMessage(), "we got a message from Bob %@", desc = SOSMessageCopyDescription(message)); ok(SOSCircleHandlePeerMessage(aliceCircle, alice_full_peer_info, aliceDsf, enqueueMessage, bob_peer_id, message, &error), "Alice accepted message: %@", error); CFReleaseNull(message); CFReleaseNull(desc); ok(message = dequeueMessage(), "we got a reply from Alice %@", desc = SOSMessageCopyDescription(message)); ok(SOSCircleHandlePeerMessage(bobCircle, bob_full_peer_info, bobDsf, enqueueMessage, alice_peer_id, message, &error), "Bob accepted message: %@", error); CFReleaseNull(message); CFReleaseNull(desc); #endif #if 0 message = dequeueMessage(); ok(NULL == message, "we got no message from Bob %@", desc = SOSMessageCopyDescription(message)); SOSObjectRef object = SOSDataSourceCreateGenericItem(aliceDs, CFSTR("75_circle_engine_account"), CFSTR("test service")); ok(SOSTestDataSourceAddObject(aliceDs, object, &error), "add empty object to datasource: %@", error); CFReleaseNull(error); CFReleaseNull(object); ok(SOSCircleSyncWithPeer(alice_full_peer_info, aliceCircle, aliceDsf, enqueueMessage, bob_peer_id, &error), "Restart sync [error %@]", error); CFReleaseNull(error); ok(message = dequeueMessage(), "Alice started again %@", desc = SOSMessageCopyDescription(message)); is(SOSCircleHandlePeerMessage(bobCircle, bob_full_peer_info, bobDsf, enqueueMessage, alice_peer_id, message, &error), true, "bob accepted %@: %@", SOSMessageCopyDescription(message), error); CFReleaseNull(error); CFReleaseNull(message); #endif #if 1 bool alice = true; int max_loops = 50; while (max_loops-- && NULL != (message = dequeueMessage())) { if (alice) { ok(SOSCircleHandlePeerMessage(aliceCircle, alice_full_peer_info, aliceDsf, enqueueMessage, bob_peer_id, message, &error), "alice accepted %@: %@", desc = SOSMessageCopyDescription(message), error); } else { ok(SOSCircleHandlePeerMessage(bobCircle, bob_full_peer_info, bobDsf, enqueueMessage, alice_peer_id, message, &error), "bob accepted %@: %@", desc = SOSMessageCopyDescription(message), error); } alice = !alice; CFRelease(message); CFReleaseNull(desc); } #endif CFReleaseNull(aliceCircle); CFReleaseNull(bobCircle); CFReleaseNull(alice_peer_info); CFReleaseNull(bob_peer_info); CFReleaseNull(alice_key); CFReleaseNull(bob_key); aliceDsf->release(aliceDsf); bobDsf->release(bobDsf); }