]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/IDSKeychainSyncingProxy/IDSProxy.m
Security-57337.50.23.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 NSError *localError = nil;
414 NSDictionary *options = @{IDSSendMessageOptionForceEncryptionOffKey : [NSNumber numberWithBool:encryptionOff] };
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
431 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);
432
433 result = [_service sendMessage:data toDestinations:destinations priority:priority options:options identifier:&identifier error:&localError ] ;
434
435 require_action_quiet(localError == nil, fail, errorMessage = @"Had an error sending IDS message"; code = kSecIDSErrorFailedToSend);
436
437 secdebug("IDS Transport", "IDSKeychainSyncingProxy sent this message over IDS: %@", data);
438
439 return result;
440
441 fail:
442 userInfo = [ NSDictionary dictionaryWithObjectsAndKeys:errorMessage, NSLocalizedDescriptionKey, nil ];
443 if(error != nil){
444 *error = [NSError errorWithDomain:@"com.apple.security.ids.error" code:code userInfo:userInfo];
445 secerror("%@", *error);
446 }
447 if(localError != nil)
448 secerror("%@", localError);
449
450 return false;
451 }
452
453
454 - (void) sendKeysCallout: (NSMutableDictionary*(^)(NSMutableDictionary* pending, NSError** error)) handleMessages {
455 [self calloutWith: ^(NSMutableDictionary *pending, bool handlePendingMesssages, bool doSetDeviceID, dispatch_queue_t queue, void(^done)(NSMutableDictionary *, bool, bool)) {
456 NSError* error = NULL;
457
458 NSMutableDictionary* handled = handleMessages(pending, &error);
459
460 dispatch_async(queue, ^{
461 if (!handled && error) {
462 secerror("%@ did not handle message: %@", self, error);
463 }
464
465 done(handled, NO, NO);
466 });
467 }];
468 }
469
470 - (void) handleAllPendingMessage
471 {
472 if([_unhandledMessageBuffer count] > 0){
473 secinfo("IDS Transport", "handling Message: %@", _unhandledMessageBuffer);
474 [_unhandledMessageBuffer enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop)
475 {
476 NSDictionary *messageAndFromID = (NSDictionary*)obj;
477 NSString *fromID = (NSString*)key;
478
479 if(_inCallout){
480 _shadowHandleAllPendingMessages = YES;
481 }
482 else{
483 __block CFErrorRef cf_error = NULL;
484 __block HandleIDSMessageReason success = kHandleIDSMessageSuccess;
485 _handleAllPendingMessages = YES;
486
487 [self sendKeysCallout:^NSMutableDictionary *(NSMutableDictionary *pending, NSError** error) {
488 success = SOSCCHandleIDSMessage(((__bridge CFDictionaryRef)messageAndFromID), &cf_error);
489
490 if(success == kHandleIDSMessageLocked){
491 secdebug("IDS Transport", "cannot handle messages when locked, error:%@", cf_error);
492 [_unhandledMessageBuffer setObject: messageAndFromID forKey: fromID];
493
494 _lastSyncTime = dispatch_time(DISPATCH_TIME_NOW, 0);
495 _deadline = dispatch_time(DISPATCH_TIME_NOW, kAttemptFlushBufferInterval);
496 //set timer
497 [self scheduleSyncRequestTimer];
498 return NULL;
499 }
500 else if(success == kHandleIDSMessageNotReady){
501 secdebug("IDS Transport", "not ready to handle message, error:%@", cf_error);
502 [_unhandledMessageBuffer setObject: messageAndFromID forKey: fromID];
503 _lastSyncTime = dispatch_time(DISPATCH_TIME_NOW, 0);
504 _deadline = dispatch_time(DISPATCH_TIME_NOW, kAttemptFlushBufferInterval);
505 //set timer
506 [self scheduleSyncRequestTimer];
507 return NULL;
508 }
509 else if(success == kHandleIDSMessageOtherFail){
510 secdebug("IDS Transport", "not ready to handle message, error:%@", cf_error);
511 [_unhandledMessageBuffer setObject: messageAndFromID forKey: fromID];
512 _lastSyncTime = dispatch_time(DISPATCH_TIME_NOW, 0);
513 _deadline = dispatch_time(DISPATCH_TIME_NOW, kAttemptFlushBufferInterval);
514 //set timer
515 [self scheduleSyncRequestTimer];
516 return NULL;
517 }
518 else{
519 secdebug("IDS Transport", "IDSProxy handled this message! %@", messageAndFromID);
520 _syncTimerScheduled = NO;
521 return (NSMutableDictionary*)messageAndFromID;
522 }
523 }];
524 }
525 }];
526 }
527 }
528
529 - (void)service:(IDSService *)service account:(IDSAccount *)account incomingMessage:(NSDictionary *)message fromID:(NSString *)fromID context:(IDSMessageContext *)context;
530 {
531 secdebug("IDS Transport", "IDSKeychainSyncingProxy handling this message sent over IDS%@", message);
532 NSString *dataKey = [ NSString stringWithUTF8String: kMessageKeyIDSDataMessage ];
533 NSString *deviceIDKey = [ NSString stringWithUTF8String: kMessageKeyDeviceID ];
534 NSString *peerIDKey = [ NSString stringWithUTF8String: kMessageKeyPeerID ];
535 NSString *ID = nil;
536 uint32_t operationType;
537 bool hadError = false;
538 CFStringRef errorMessage = NULL;
539 __block NSString* operation = nil;
540 __block NSString* myPeerID = @"";
541 NSString *messageString = nil;
542 __block NSData *messageData = nil;
543 __block NSString *messageAsString = nil;
544 __block BOOL operationIsString = false;
545 __block BOOL messageStringIsString = false;
546 __block BOOL messageDataIsData = false;
547
548 NSArray *devices = [_service devices];
549 for(NSUInteger i = 0; i < [ devices count ]; i++){
550 IDSDevice *device = devices[i];
551 if( [(IDSCopyIDForDevice(device)) containsString: fromID] == YES){
552 ID = device.uniqueID;
553 break;
554 }
555 }
556
557 require_action_quiet(ID, fail, hadError = true; errorMessage = CFSTR("require the sender's device ID"));
558 require_action_quiet([message count] == 1, fail, hadError = true; errorMessage = CFSTR("message contained too many objects"));
559
560 [message enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop){
561 operation = (NSString*)key;
562 operationIsString = (CFGetTypeID((__bridge CFTypeRef)(operation)) == CFStringGetTypeID());
563
564 if(CFGetTypeID((__bridge CFTypeRef)(obj)) == CFDataGetTypeID()){
565 messageDataIsData = true;
566 messageData = (NSData*)obj;
567 }
568 else if(CFGetTypeID((__bridge CFTypeRef)(obj)) == CFStringGetTypeID()){
569 messageStringIsString = true;
570 messageAsString = (NSString*)obj;
571 }
572 }];
573
574 require_action_quiet(operationIsString, fail, hadError = true; errorMessage = CFSTR("unexpected opeartion type"););
575
576 if(messageData)
577 require_action_quiet(messageDataIsData, fail, hadError = true; errorMessage = CFSTR("unexpected message type"););
578 else if(messageAsString)
579 require_action_quiet(messageStringIsString, fail, hadError = true; errorMessage = CFSTR("unexpected message type"););
580
581 operationType = [operation intValue];
582 if(operationType == 0)
583 myPeerID = operation;
584
585 switch(operationType){
586 case kIDSPeerAvailabilityDone:
587 {
588 secdebug("ids transport", "received availability done!");
589 notify_post(kSOSCCPeerAvailable);
590 break;
591 }
592 case kIDSEndPingTestMessage:
593 secdebug("ids transport", "received pong message from other device: %@, ping test PASSED", ID);
594 break;
595 case kIDSSendOneMessage:
596 secdebug("ids transport","received ping test message, dropping on the floor now");
597 break;
598
599 case kIDSPeerAvailability:
600 case kIDSStartPingTestMessage:
601 {
602 char* messageCharS;
603 if(operationType == kIDSPeerAvailability){
604 secdebug("ids transport", "Received Availability Message!");
605 asprintf(&messageCharS, "%d",kIDSPeerAvailabilityDone);
606 }
607 else{
608 secdebug("ids transport", "Received PingTest Message!");
609 asprintf(&messageCharS, "%d", kIDSEndPingTestMessage);
610 }
611
612 NSString *operationString = [[NSString alloc] initWithUTF8String:messageCharS];
613 messageString = @"peer availability check finished";
614 NSDictionary* messsageDictionary = @{operationString : messageString};
615
616 NSError *localError = NULL;
617 [self sendIDSMessage:messsageDictionary name:ID peer:@"me" error:&localError];
618 free(messageCharS);
619
620 break;
621
622 }
623 default:
624 {
625 NSDictionary *messageAndFromID = @{dataKey : messageData, deviceIDKey: ID, peerIDKey: myPeerID};
626 if(_isLocked){
627 //hang on to the message and set the retry deadline
628 [_unhandledMessageBuffer setObject: messageAndFromID forKey: fromID];
629 _deadline = dispatch_time(DISPATCH_TIME_NOW, kMaxMessageRetryDelay);
630 }
631 else{
632 __block CFErrorRef cf_error = NULL;
633 __block HandleIDSMessageReason success = kHandleIDSMessageSuccess;
634 _handleAllPendingMessages = YES;
635
636 [self sendKeysCallout:^NSMutableDictionary *(NSMutableDictionary *pending, NSError** error) {
637
638 success = SOSCCHandleIDSMessage(((__bridge CFDictionaryRef)messageAndFromID), &cf_error);
639
640 if(success == kHandleIDSMessageLocked){
641 secdebug("IDS Transport", "cannot handle messages when locked, error:%@", cf_error);
642 [_unhandledMessageBuffer setObject: messageAndFromID forKey: fromID];
643
644 _lastSyncTime = dispatch_time(DISPATCH_TIME_NOW, 0);
645 _deadline = dispatch_time(DISPATCH_TIME_NOW, kAttemptFlushBufferInterval);
646 //set timer
647 [self scheduleSyncRequestTimer];
648 return NULL;
649 }
650 else if(success == kHandleIDSMessageNotReady){
651 secdebug("IDS Transport", "not ready to handle message, error:%@", cf_error);
652 [_unhandledMessageBuffer setObject: messageAndFromID forKey: fromID];
653 _lastSyncTime = dispatch_time(DISPATCH_TIME_NOW, 0);
654 _deadline = dispatch_time(DISPATCH_TIME_NOW, kAttemptFlushBufferInterval);
655 //set timer
656 [self scheduleSyncRequestTimer];
657 return NULL;
658 }
659 else if(success == kHandleIDSMessageOtherFail){
660 secdebug("IDS Transport", "not ready to handle message, error:%@", cf_error);
661 [_unhandledMessageBuffer setObject: messageAndFromID forKey: fromID];
662 _lastSyncTime = dispatch_time(DISPATCH_TIME_NOW, 0);
663 _deadline = dispatch_time(DISPATCH_TIME_NOW, kAttemptFlushBufferInterval);
664 //set timer
665 [self scheduleSyncRequestTimer];
666 return NULL;
667 }
668 else{
669 secdebug("IDS Transport", "IDSProxy handled this message! %@", messageAndFromID);
670 return (NSMutableDictionary*)messageAndFromID;
671 }
672 }];
673 CFReleaseSafe(cf_error);
674 }
675 break;
676 }
677 }
678 fail:
679 if(hadError)
680 secerror("error:%@", errorMessage);
681 }
682
683 @end
684
685