]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/IDSKeychainSyncingProxy/IDSProxy.m
Security-57336.10.29.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / IDSKeychainSyncingProxy / IDSProxy.m
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 // IDSProxy.m
26 // ids-xpc
27 //
28
29
30 #import <Foundation/NSArray.h>
31 #import <Foundation/Foundation.h>
32
33 #import <Security/SecBasePriv.h>
34 #import <Security/SecItemPriv.h>
35 #import <utilities/debugging.h>
36 #import <notify.h>
37
38 #include <Security/CKBridge/SOSCloudKeychainConstants.h>
39 #include <Security/SecureObjectSync/SOSARCDefines.h>
40 #include <Security/SecureObjectSync/SOSCloudCircle.h>
41 #include <Security/SecureObjectSync/SOSCloudCircleInternal.h>
42
43 #import <IDS/IDS.h>
44 #import <os/activity.h>
45
46 #include <utilities/SecAKSWrappers.h>
47 #include <utilities/SecCFRelease.h>
48 #include <AssertMacros.h>
49
50 #import "IDSProxy.h"
51 #import "IDSPersistentState.h"
52
53 static const char *kStreamName = "com.apple.notifyd.matching";
54 NSString *const IDSSendMessageOptionForceEncryptionOffKey = @"IDSSendMessageOptionForceEncryptionOff";
55
56 static const int64_t kAttemptFlushBufferInterval = (NSEC_PER_SEC * 15);
57 static const int64_t kSyncTimerLeeway = (NSEC_PER_MSEC * 250); // 250ms leeway for handling unhandled messages.
58 static const int64_t kMaxMessageRetryDelay = (NSEC_PER_SEC * 5); // 5s maximun delay for a given request
59 static const int64_t kMinMessageRetryDelay = (NSEC_PER_MSEC * 500); // 500ms minimum delay before attempting to retry handling messages.
60
61 #define SECD_RUN_AS_ROOT_ERROR 550
62
63
64 @implementation IDSKeychainSyncingProxy
65
66 + (IDSKeychainSyncingProxy *) idsProxy
67 {
68 static IDSKeychainSyncingProxy *idsProxy;
69 if (!idsProxy) {
70 static dispatch_once_t onceToken;
71 dispatch_once(&onceToken, ^{
72 idsProxy = [[self alloc] init];
73 });
74 }
75 return idsProxy;
76 }
77
78 - (void)persistState
79 {
80 if([_unhandledMessageBuffer count] > 0){
81 [IDSKeychainSyncingProxyPersistentState setUnhandledMessages:_unhandledMessageBuffer];
82 }
83 }
84
85 - (void) importKeyInterests: (NSMutableDictionary*) unhandledMessages
86 {
87 _unhandledMessageBuffer = unhandledMessages;
88 }
89
90 - (id)init
91 {
92 if (self = [super init])
93 {
94 secnotice("event", "%@ start", self);
95
96 _isIDSInitDone = false;
97 _service = nil;
98 _calloutQueue = dispatch_queue_create("IDSCallout", DISPATCH_QUEUE_SERIAL);
99 _unhandledMessageBuffer = [ [NSMutableDictionary alloc] initWithCapacity: 0];
100 _isSecDRunningAsRoot = false;
101 secdebug(IDSPROXYSCOPE, "%@ done", self);
102
103 [self doIDSInitialization];
104 if(_isIDSInitDone)
105 [self doSetIDSDeviceID:nil];
106
107 _syncTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
108 dispatch_source_set_timer(_syncTimer, DISPATCH_TIME_FOREVER, DISPATCH_TIME_FOREVER, kSyncTimerLeeway);
109 dispatch_source_set_event_handler(_syncTimer, ^{
110 [self timerFired];
111 });
112 dispatch_resume(_syncTimer);
113
114 [self importKeyInterests: [IDSKeychainSyncingProxyPersistentState unhandledMessages]];
115
116 xpc_set_event_stream_handler(kStreamName, dispatch_get_main_queue(),
117 ^(xpc_object_t notification){
118 [self streamEvent:notification];
119 });
120
121 [self updateUnlockedSinceBoot];
122 [self updateIsLocked];
123 if (!_isLocked)
124 [self keybagDidUnlock];
125
126 }
127 return self;
128 }
129
130 - (void) keybagDidLock
131 {
132 secnotice("event", "%@", self);
133 }
134
135 - (void) keybagDidUnlock
136 {
137 secnotice("event", "%@", self);
138 [self handleAllPendingMessage];
139 }
140
141 - (BOOL) updateUnlockedSinceBoot
142 {
143 CFErrorRef aksError = NULL;
144 if (!SecAKSGetHasBeenUnlocked(&_unlockedSinceBoot, &aksError)) {
145 secerror("%@ Got error from SecAKSGetHasBeenUnlocked: %@", self, aksError);
146 CFReleaseSafe(aksError);
147 return NO;
148 }
149 return YES;
150 }
151
152 - (BOOL) updateIsLocked
153 {
154 CFErrorRef aksError = NULL;
155 if (!SecAKSGetIsLocked(&_isLocked, &aksError)) {
156 secerror("%@ Got error querying lock state: %@", self, aksError);
157 CFReleaseSafe(aksError);
158 return NO;
159 }
160 if (!_isLocked)
161 _unlockedSinceBoot = YES;
162 return YES;
163 }
164
165 - (void) keybagStateChange
166 {
167 os_activity_initiate("keybagStateChanged", OS_ACTIVITY_FLAG_DEFAULT, ^{
168 BOOL wasLocked = _isLocked;
169 if ([self updateIsLocked]) {
170 if (wasLocked == _isLocked)
171 secdebug("event", "%@ still %s ignoring", self, _isLocked ? "locked" : "unlocked");
172 else if (_isLocked)
173 [self keybagDidLock];
174 else
175 [self keybagDidUnlock];
176 }
177 });
178 }
179
180 - (void)streamEvent:(xpc_object_t)notification
181 {
182 #if (!TARGET_IPHONE_SIMULATOR)
183 const char *notificationName = xpc_dictionary_get_string(notification, "Notification");
184 if (!notificationName) {
185 } else if (strcmp(notificationName, kUserKeybagStateChangeNotification)==0) {
186 return [self keybagStateChange];
187 }
188 const char *eventName = xpc_dictionary_get_string(notification, "XPCEventName");
189 char *desc = xpc_copy_description(notification);
190 secnotice("event", "%@ event: %s name: %s desc: %s", self, eventName, notificationName, desc);
191 if (desc)
192 free((void *)desc);
193 #endif
194 }
195
196 - (void)timerFired
197 {
198 secdebug("IDS Transport", "%@ attempting to hand unhandled messages to securityd, here is our message queue: %@", self, _unhandledMessageBuffer);
199 if([_unhandledMessageBuffer count] == 0)
200 _syncTimerScheduled = NO;
201 else if (_syncTimerScheduled && !_isLocked){
202 [self handleAllPendingMessage];
203 }
204 }
205
206 - (dispatch_time_t) nextSyncTime
207 {
208 secdebug("IDS Transport", "nextSyncTime");
209
210 dispatch_time_t nextSync = dispatch_time(DISPATCH_TIME_NOW, kMinMessageRetryDelay);
211
212 // Don't sync again unless we waited at least kAttemptFlushBufferInterval
213 if (_lastSyncTime) {
214 dispatch_time_t soonest = dispatch_time(_lastSyncTime, kAttemptFlushBufferInterval);
215 if (nextSync < soonest || _deadline < soonest) {
216 secdebug("timer", "%@ backing off", self);
217 return soonest;
218 }
219 }
220
221 // Don't delay more than kMaxMessageRetryDelay after the first request.
222 if (nextSync > _deadline) {
223 secdebug("timer", "%@ hit deadline", self);
224 return _deadline;
225 }
226
227 // Bump the timer by kMinMessageRetryDelay
228 if (_syncTimerScheduled)
229 secdebug("timer", "%@ bumped timer", self);
230 else
231 secdebug("timer", "%@ scheduled timer", self);
232
233 return nextSync;
234 }
235
236 - (void)scheduleSyncRequestTimer
237 {
238 secdebug("IDS Transport", "scheduling sync request timer");
239 dispatch_source_set_timer(_syncTimer, [self nextSyncTime], DISPATCH_TIME_FOREVER, kSyncTimerLeeway);
240 _syncTimerScheduled = YES;
241 }
242
243
244 - (void)setItemsChangedBlock:(CloudItemsChangedBlock)itemsChangedBlock
245 {
246 self->itemsChangedCallback = itemsChangedBlock;
247 }
248
249 - (void)doIDSInitialization{
250
251 secnotice("IDS Transport", "doIDSInitialization!");
252
253 _service = [[IDSService alloc] initWithService: @IDSServiceNameKeychainSync];
254
255 if( _service == nil ){
256 _isIDSInitDone = false;
257 secerror("Could not create ids service");
258 }
259 else{
260 secnotice("IDS Transport", "IDS Transport Successfully set up IDS!");
261 [_service addDelegate:self queue: dispatch_get_main_queue()];
262
263 _isIDSInitDone = true;
264 if(_isSecDRunningAsRoot == false)
265 [self doSetIDSDeviceID:nil];
266 }
267 }
268
269 - (void) calloutWith: (void(^)(NSMutableDictionary *pending, bool handlePendingMesssages, bool doSetDeviceID, dispatch_queue_t queue, void(^done)(NSMutableDictionary *handledMessages, bool handledPendingMessage, bool handledSettingDeviceID))) callout
270 {
271 // In IDSKeychainSyncingProxy serial queue
272 dispatch_queue_t idsproxy_queue = dispatch_get_main_queue();
273
274 _oldInCallout = YES;
275
276 // dispatch_get_global_queue - well-known global concurrent queue
277 // dispatch_get_main_queue - default queue that is bound to the main thread
278 xpc_transaction_begin();
279 dispatch_async(_calloutQueue, ^{
280 __block NSMutableDictionary *myPending;
281 __block bool myHandlePendingMessage;
282 __block bool myDoSetDeviceID;
283 __block bool wasLocked;
284 dispatch_sync(idsproxy_queue, ^{
285 myPending = [_unhandledMessageBuffer copy];
286 myHandlePendingMessage = _handleAllPendingMessages;
287 myDoSetDeviceID = _setIDSDeviceID;
288 wasLocked = _isLocked;
289
290 _inCallout = YES;
291 if (!_oldInCallout)
292 secnotice("deaf", ">>>>>>>>>>> _oldInCallout is NO and we're heading in to the callout!");
293
294 _shadowHandleAllPendingMessages = NO;
295 });
296
297 callout(myPending, myHandlePendingMessage, myDoSetDeviceID, idsproxy_queue, ^(NSMutableDictionary *handledMessages, bool handledPendingMessage, bool handledSetDeviceID) {
298 secdebug("event", "%@ %s%s before callout handled: %s%s", self, myHandlePendingMessage ? "P" : "p", myDoSetDeviceID ? "D" : "d", handledPendingMessage ? "H" : "h", handledSetDeviceID ? "I" : "i");
299
300 // In IDSKeychainSyncingProxy's serial queue
301 _inCallout = NO;
302 _oldInCallout = NO;
303
304 NSError *error;
305
306 // Update setting device id
307 _setIDSDeviceID = ((myDoSetDeviceID && !handledSetDeviceID) || _shadowHandleAllPendingMessages);
308
309 _shadowDoSetIDSDeviceID = NO;
310
311 if(_setIDSDeviceID && !_isLocked && _isSecDRunningAsRoot == false)
312 [self doSetIDSDeviceID:&error];
313
314 // Update handling pending messages
315 _handleAllPendingMessages = ((myHandlePendingMessage && (!handledPendingMessage)) || _shadowHandleAllPendingMessages);
316
317 _shadowHandleAllPendingMessages = NO;
318
319 if (handledPendingMessage)
320 _lastSyncTime = dispatch_time(DISPATCH_TIME_NOW, 0);
321
322 // Update pending messages and handle them
323 [handledMessages enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop){
324 NSString* fromID = (NSString*)key;
325 [_unhandledMessageBuffer removeObjectForKey:fromID];
326 }];
327
328 // Write state to disk
329 [self persistState];
330
331 if ([_unhandledMessageBuffer count] > 0 || (!_isLocked && wasLocked))
332 [self handleAllPendingMessage];
333
334 xpc_transaction_end();
335 });
336 });
337 }
338
339 - (BOOL) doSetIDSDeviceID: (NSError**)error
340 {
341 BOOL result = false;
342 NSDictionary *userInfo;
343 NSInteger code = 0;
344 NSString *errorMessage;
345 __block NSString* deviceID;
346 __block CFErrorRef localError = NULL;
347 __block bool handledSettingID = false;
348
349 if(!_isIDSInitDone){
350 [self doIDSInitialization];
351 }
352 if(_isSecDRunningAsRoot == true)
353 {
354 secerror("cannot set IDS device ID, secd is running as root");
355 return false;
356 }
357 require_action_quiet(_isIDSInitDone, fail, errorMessage = @"IDSKeychainSyncingProxy can't set up the IDS service"; code = kSecIDSErrorNotRegistered);
358 require_action_quiet(!_isLocked, fail, errorMessage = @"IDSKeychainSyncingProxy can't set device ID, device is locked"; code = kSecIDSErrorDeviceIsLocked);
359
360 deviceID = IDSCopyLocalDeviceUniqueID();
361 secdebug("IDS Transport", "This is our IDS device ID: %@", deviceID);
362
363 require_action_quiet(deviceID != nil, fail, errorMessage = @"IDSKeychainSyncingProxy could not retrieve device ID from keychain"; code = kSecIDSErrorNoDeviceID);
364
365 if(_inCallout && _isSecDRunningAsRoot == false){
366 _shadowDoSetIDSDeviceID = YES;
367 result = true;
368 }
369 else{
370 _setIDSDeviceID = YES;
371 [self calloutWith:^(NSMutableDictionary *pending, bool handlePendingMesssages, bool doSetDeviceID, dispatch_queue_t queue, void(^done)(NSMutableDictionary *, bool, bool)) {
372 handledSettingID = SOSCCSetDeviceID((__bridge CFStringRef) deviceID, &localError);
373
374 dispatch_async(queue, ^{
375 if(localError){
376 if(CFErrorGetCode(localError) == SECD_RUN_AS_ROOT_ERROR){
377 secerror("SETTING RUN AS ROOT ERROR");
378 _isSecDRunningAsRoot = true;
379 }
380 if(error)
381 *error = (__bridge NSError *)(localError);
382 }
383 handledSettingID = YES;
384 done(nil, NO, handledSettingID);
385 });
386 }];
387 result = handledSettingID;
388 }
389 return result;
390
391 fail:
392 userInfo = [ NSDictionary dictionaryWithObjectsAndKeys:errorMessage, NSLocalizedDescriptionKey, nil ];
393 if(error != nil){
394 *error = [NSError errorWithDomain:@"com.apple.security.ids.error" code:code userInfo:userInfo];
395 secerror("%@", *error);
396 }
397 return false;
398 }
399
400 -(BOOL) sendIDSMessage:(NSDictionary*)data name:(NSString*) deviceName peer:(NSString*) peerID error:(NSError**) error
401 {
402 BOOL result = true;
403 NSDictionary *userInfo;
404 NSInteger code = 0;
405
406 NSString *errorMessage;
407 NSString* identifier = [NSString string];
408 NSMutableSet *destinations = [NSMutableSet set];
409 NSArray *ListOfIDSDevices = nil;
410 IDSMessagePriority priority = IDSMessagePriorityHigh;
411 IDSDevice *device = nil;
412 BOOL encryptionOff = YES;
413
414 NSDictionary *options = [ NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:encryptionOff], IDSSendMessageOptionForceEncryptionOffKey, nil ];
415
416 require_action_quiet(_service, fail, errorMessage = @"Could not send message: IDS delegate uninitialized, can't use IDS to send this message"; code = kSecIDSErrorNotRegistered);
417
418 secdebug("IDS Transport", "[_service devices]: %@, we have their deviceName: %@", [_service devices], deviceName);
419 ListOfIDSDevices = [_service devices];
420
421 require_action_quiet([ListOfIDSDevices count]> 0, fail, errorMessage=@"Could not send message: IDS devices are not registered yet"; code = kSecIDSErrorNotRegistered);
422 secinfo("IDS Transport", "This is our list of devices: %@", ListOfIDSDevices);
423
424 for(NSUInteger i = 0; i < [ ListOfIDSDevices count ]; i++){
425 device = ListOfIDSDevices[i];
426 if( [ deviceName compare:device.uniqueID ] == 0){
427 [destinations addObject: IDSCopyIDForDevice(device)];
428 }
429 }
430 require_action_quiet([destinations count] != 0, fail, errorMessage = @"Could not send message: IDS device ID for peer does not match any devices within an IDS Account"; code = kSecIDSErrorCouldNotFindMatchingAuthToken);
431
432 result = [_service sendMessage:data toDestinations:destinations priority:priority options:options identifier:&identifier error:error ] ;
433
434 require_action_quiet(*error == nil, fail, errorMessage = @"Had an error sending IDS message"; code = kSecIDSErrorFailedToSend);
435
436 secdebug("IDS Transport", "IDSKeychainSyncingProxy sent this message over IDS: %@", data);
437
438 return result;
439
440 fail:
441 userInfo = [ NSDictionary dictionaryWithObjectsAndKeys:errorMessage, NSLocalizedDescriptionKey, nil ];
442 if(error != nil){
443 *error = [NSError errorWithDomain:@"com.apple.security.ids.error" code:code userInfo:userInfo];
444 secerror("%@", *error);
445 }
446
447 return false;
448 }
449
450
451 - (void) sendKeysCallout: (NSMutableDictionary*(^)(NSMutableDictionary* pending, NSError** error)) handleMessages {
452 [self calloutWith: ^(NSMutableDictionary *pending, bool handlePendingMesssages, bool doSetDeviceID, dispatch_queue_t queue, void(^done)(NSMutableDictionary *, bool, bool)) {
453 NSError* error = NULL;
454
455 NSMutableDictionary* handled = handleMessages(pending, &error);
456
457 dispatch_async(queue, ^{
458 if (!handled && error) {
459 secerror("%@ did not handle message: %@", self, error);
460 }
461
462 done(handled, NO, NO);
463 });
464 }];
465 }
466
467 - (void) handleAllPendingMessage
468 {
469 if([_unhandledMessageBuffer count] > 0){
470 secinfo("IDS Transport", "handling Message: %@", _unhandledMessageBuffer);
471 [_unhandledMessageBuffer enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop)
472 {
473 NSDictionary *messageAndFromID = (NSDictionary*)obj;
474 NSString *fromID = (NSString*)key;
475
476 if(_inCallout){
477 _shadowHandleAllPendingMessages = YES;
478 }
479 else{
480 __block CFErrorRef cf_error = NULL;
481 __block HandleIDSMessageReason success = kHandleIDSMessageSuccess;
482 _handleAllPendingMessages = YES;
483
484 [self sendKeysCallout:^NSMutableDictionary *(NSMutableDictionary *pending, NSError** error) {
485 success = SOSCCHandleIDSMessage(((__bridge CFDictionaryRef)messageAndFromID), &cf_error);
486
487 if(success == kHandleIDSMessageLocked){
488 secdebug("IDS Transport", "cannot handle messages when locked, error:%@", cf_error);
489 [_unhandledMessageBuffer setObject: messageAndFromID forKey: fromID];
490
491 _lastSyncTime = dispatch_time(DISPATCH_TIME_NOW, 0);
492 _deadline = dispatch_time(DISPATCH_TIME_NOW, kAttemptFlushBufferInterval);
493 //set timer
494 [self scheduleSyncRequestTimer];
495 return NULL;
496 }
497 else if(success == kHandleIDSMessageNotReady){
498 secdebug("IDS Transport", "not ready to handle message, error:%@", cf_error);
499 [_unhandledMessageBuffer setObject: messageAndFromID forKey: fromID];
500 _lastSyncTime = dispatch_time(DISPATCH_TIME_NOW, 0);
501 _deadline = dispatch_time(DISPATCH_TIME_NOW, kAttemptFlushBufferInterval);
502 //set timer
503 [self scheduleSyncRequestTimer];
504 return NULL;
505 }
506 else if(success == kHandleIDSMessageOtherFail){
507 secdebug("IDS Transport", "not ready to handle message, error:%@", cf_error);
508 [_unhandledMessageBuffer setObject: messageAndFromID forKey: fromID];
509 _lastSyncTime = dispatch_time(DISPATCH_TIME_NOW, 0);
510 _deadline = dispatch_time(DISPATCH_TIME_NOW, kAttemptFlushBufferInterval);
511 //set timer
512 [self scheduleSyncRequestTimer];
513 return NULL;
514 }
515 else{
516 secdebug("IDS Transport", "IDSProxy handled this message! %@", messageAndFromID);
517 _syncTimerScheduled = NO;
518 return (NSMutableDictionary*)messageAndFromID;
519 }
520 }];
521 }
522 }];
523 }
524 }
525
526 - (void)service:(IDSService *)service account:(IDSAccount *)account incomingMessage:(NSDictionary *)message fromID:(NSString *)fromID context:(IDSMessageContext *)context;
527 {
528 secdebug("IDS Transport", "IDSKeychainSyncingProxy handling this message sent over IDS%@", message);
529 NSString *dataKey = [ NSString stringWithUTF8String: kMessageKeyIDSDataMessage ];
530 NSString *deviceIDKey = [ NSString stringWithUTF8String: kMessageKeyDeviceID ];
531 NSString *ID = nil;
532 uint32_t operationType;
533 bool hadError = false;
534 CFStringRef errorMessage = NULL;
535 __block NSString* operation = nil;
536 NSString *messageString = nil;
537 __block NSData *messageData = nil;
538
539 NSArray *devices = [_service devices];
540 for(NSUInteger i = 0; i < [ devices count ]; i++){
541 IDSDevice *device = devices[i];
542 if( [(IDSCopyIDForDevice(device)) containsString: fromID] == YES){
543 ID = device.uniqueID;
544 break;
545 }
546 }
547 require_action_quiet(ID, fail, hadError = true; errorMessage = CFSTR("require the sender's device ID"));
548 require_action_quiet([message count] == 1, fail, hadError = true; errorMessage = CFSTR("message contained too many objects"););
549
550 [message enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop){
551 operation = (NSString*)key;
552 messageData = (NSData*)obj;
553 }];
554
555 operationType = [operation intValue];
556
557 switch(operationType){
558 case kIDSPeerAvailabilityDone:
559 {
560 secdebug("ids transport", "received availability done!");
561 notify_post(kSOSCCPeerAvailable);
562 break;
563 }
564 case kIDSEndPingTestMessage:
565 secdebug("ids transport", "received pong message from other device: %@, ping test PASSED", ID);
566 break;
567 case kIDSSendOneMessage:
568 secdebug("ids transport","received ping test message, dropping on the floor now");
569 break;
570
571 case kIDSPeerAvailability:
572 case kIDSStartPingTestMessage:
573 {
574 char* messageCharS;
575 if(operationType == kIDSPeerAvailability){
576 secdebug("ids transport", "Received Availability Message!");
577 asprintf(&messageCharS, "%d",kIDSPeerAvailabilityDone);
578 }
579 else{
580 secdebug("ids transport", "Received PingTest Message!");
581 asprintf(&messageCharS, "%d", kIDSEndPingTestMessage);
582 }
583
584 NSString *operationString = [[NSString alloc] initWithUTF8String:messageCharS];
585 messageString = @"peer availability check finished";
586 NSDictionary* messsageDictionary = @{operationString : messageString};
587
588 NSError *localError = NULL;
589 [self sendIDSMessage:messsageDictionary name:ID peer:@"me" error:&localError];
590 free(messageCharS);
591
592 break;
593
594 }
595 default:
596 {
597 NSDictionary *messageAndFromID = @{dataKey : messageData, deviceIDKey: ID};
598 if(_isLocked){
599 //hang on to the message and set the retry deadline
600 [_unhandledMessageBuffer setObject: messageAndFromID forKey: fromID];
601 _deadline = dispatch_time(DISPATCH_TIME_NOW, kMaxMessageRetryDelay);
602 }
603 else{
604 __block CFErrorRef cf_error = NULL;
605 __block HandleIDSMessageReason success = kHandleIDSMessageSuccess;
606 _handleAllPendingMessages = YES;
607
608 [self sendKeysCallout:^NSMutableDictionary *(NSMutableDictionary *pending, NSError** error) {
609
610 success = SOSCCHandleIDSMessage(((__bridge CFDictionaryRef)messageAndFromID), &cf_error);
611
612 if(success == kHandleIDSMessageLocked){
613 secdebug("IDS Transport", "cannot handle messages when locked, error:%@", cf_error);
614 [_unhandledMessageBuffer setObject: messageAndFromID forKey: fromID];
615
616 _lastSyncTime = dispatch_time(DISPATCH_TIME_NOW, 0);
617 _deadline = dispatch_time(DISPATCH_TIME_NOW, kAttemptFlushBufferInterval);
618 //set timer
619 [self scheduleSyncRequestTimer];
620 return NULL;
621 }
622 else if(success == kHandleIDSMessageNotReady){
623 secdebug("IDS Transport", "not ready to handle message, error:%@", cf_error);
624 [_unhandledMessageBuffer setObject: messageAndFromID forKey: fromID];
625 _lastSyncTime = dispatch_time(DISPATCH_TIME_NOW, 0);
626 _deadline = dispatch_time(DISPATCH_TIME_NOW, kAttemptFlushBufferInterval);
627 //set timer
628 [self scheduleSyncRequestTimer];
629 return NULL;
630 }
631 else if(success == kHandleIDSMessageOtherFail){
632 secdebug("IDS Transport", "not ready to handle message, error:%@", cf_error);
633 [_unhandledMessageBuffer setObject: messageAndFromID forKey: fromID];
634 _lastSyncTime = dispatch_time(DISPATCH_TIME_NOW, 0);
635 _deadline = dispatch_time(DISPATCH_TIME_NOW, kAttemptFlushBufferInterval);
636 //set timer
637 [self scheduleSyncRequestTimer];
638 return NULL;
639 }
640 else{
641 secdebug("IDS Transport", "IDSProxy handled this message! %@", messageAndFromID);
642 return (NSMutableDictionary*)messageAndFromID;
643 }
644 }];
645 CFReleaseSafe(cf_error);
646 }
647 break;
648 }
649 }
650 fail:
651 if(hadError)
652 secerror("error:%@", errorMessage);
653 }
654
655 @end
656