]> git.saurik.com Git - apple/security.git/blob - keychain/ot/OctagonStateMachineHelpers.m
Security-59306.61.1.tar.gz
[apple/security.git] / keychain / ot / OctagonStateMachineHelpers.m
1 /*
2 * Copyright (c) 2018 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 #if OCTAGON
25
26 #import "keychain/ot/OTStates.h"
27 #import "keychain/ot/ObjCImprovements.h"
28 #import "keychain/ot/OTDefines.h"
29 #import "keychain/ot/OTConstants.h"
30 #import "keychain/categories/NSError+UsefulConstructors.h"
31
32 OctagonState* const OctagonStateMachineNotStarted = (OctagonState*) @"not_started";
33 OctagonState* const OctagonStateMachineHalted = (OctagonState*) @"halted";
34
35 @implementation OctagonStateTransitionOperation : CKKSResultOperation
36 - (instancetype)initIntending:(OctagonState*)intendedState
37 errorState:(OctagonState*)errorState
38 {
39 if((self = [super init])) {
40 _nextState = errorState;
41 _intendedState = intendedState;
42 }
43 return self;
44 }
45
46 - (NSString*)description
47 {
48 return [NSString stringWithFormat:@"<OctagonStateTransitionOperation(%@): intended:%@ actual:%@>", self.name, self.intendedState, self.nextState];
49 }
50
51 + (instancetype)named:(NSString*)name
52 intending:(OctagonState*)intendedState
53 errorState:(OctagonState*)errorState
54 withBlockTakingSelf:(void(^)(OctagonStateTransitionOperation* op))block
55 {
56 OctagonStateTransitionOperation* op = [[self alloc] initIntending:intendedState
57 errorState:errorState];
58 WEAKIFY(op);
59 [op addExecutionBlock:^{
60 STRONGIFY(op);
61 block(op);
62 }];
63 op.name = name;
64 return op;
65 }
66
67 + (instancetype)named:(NSString*)name
68 entering:(OctagonState*)intendedState
69 {
70 OctagonStateTransitionOperation* op = [[self alloc] initIntending:intendedState
71 errorState:intendedState];
72 op.name = name;
73 return op;
74 }
75
76 @end
77
78 @interface OctagonStateTransitionRequest ()
79 @property dispatch_queue_t queue;
80 @property bool timeoutCanOccur;
81 @end
82
83 @implementation OctagonStateTransitionRequest
84
85 - (instancetype)init:(NSString*)name
86 sourceStates:(NSSet<OctagonState*>*)sourceStates
87 serialQueue:(dispatch_queue_t)queue
88 timeout:(dispatch_time_t)timeout
89 transitionOp:(CKKSResultOperation<OctagonStateTransitionOperationProtocol>*)transitionOp
90 {
91 if((self = [super init])) {
92 _name = name;
93 _sourceStates = sourceStates;
94 _queue = queue;
95
96 _timeoutCanOccur = true;
97 _transitionOperation = transitionOp;
98 }
99
100 [self timeout:timeout];
101
102 return self;
103 }
104
105 - (NSString*)description
106 {
107 return [NSString stringWithFormat:@"<OctagonStateTransitionRequest: %@ %@ %@>", self.name, self.transitionOperation, self.sourceStates];
108 }
109
110 - (CKKSResultOperation<OctagonStateTransitionOperationProtocol>* _Nullable)_onqueueStart
111 {
112 dispatch_assert_queue(self.queue);
113
114 if(self.timeoutCanOccur) {
115 self.timeoutCanOccur = false;
116 return self.transitionOperation;
117 } else {
118 return nil;
119 }
120 }
121
122 - (instancetype)timeout:(dispatch_time_t)timeout
123 {
124 WEAKIFY(self);
125 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timeout), self.queue, ^{
126 STRONGIFY(self);
127 if(self.timeoutCanOccur) {
128 self.timeoutCanOccur = false;
129
130 // The operation will only realize it's finished once added to any operation queue. Fake one up.
131 [self.transitionOperation timeout:0*NSEC_PER_SEC];
132 [[[NSOperationQueue alloc] init] addOperation:self.transitionOperation];
133 }
134 });
135
136 return self;
137 }
138
139 @end
140
141 #endif // OCTAGON