コード例 #1
0
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);
            }
        }
    });
コード例 #2
0
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);
}
コード例 #3
0
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);
            }
        });
コード例 #4
0
static bool SOSAccountIsThisPeerIDMe(SOSAccountRef account, CFStringRef peerID) {
    SOSPeerInfoRef mypi = SOSFullPeerInfoGetPeerInfo(account->my_identity);
    CFStringRef myPeerID = SOSPeerInfoGetPeerID(mypi);
    
    return myPeerID && CFEqualSafe(myPeerID, peerID);
}
コード例 #5
0
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);
}
コード例 #6
0
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();
}
コード例 #7
0
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);

}
コード例 #8
0
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);
}