]> git.saurik.com Git - apple/security.git/blob - keychain/ot/OctagonStateMachineHelpers.m
Security-59754.41.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 #pragma mark -- OctagonStateTransitionOperation
36
37 @implementation OctagonStateTransitionOperation
38 - (instancetype)initIntending:(OctagonState*)intendedState
39 errorState:(OctagonState*)errorState
40 {
41 if((self = [super init])) {
42 _nextState = errorState;
43 _intendedState = intendedState;
44 }
45 return self;
46 }
47
48 - (NSString*)description
49 {
50 return [NSString stringWithFormat:@"<OctagonStateTransitionOperation(%@): intended:%@ actual:%@>", self.name, self.intendedState, self.nextState];
51 }
52
53 + (instancetype)named:(NSString*)name
54 intending:(OctagonState*)intendedState
55 errorState:(OctagonState*)errorState
56 withBlockTakingSelf:(void(^)(OctagonStateTransitionOperation* op))block
57 {
58 OctagonStateTransitionOperation* op = [[self alloc] initIntending:intendedState
59 errorState:errorState];
60 WEAKIFY(op);
61 [op addExecutionBlock:^{
62 STRONGIFY(op);
63 block(op);
64 }];
65 op.name = name;
66 return op;
67 }
68
69 + (instancetype)named:(NSString*)name
70 entering:(OctagonState*)intendedState
71 {
72 OctagonStateTransitionOperation* op = [[self alloc] initIntending:intendedState
73 errorState:intendedState];
74 op.name = name;
75 return op;
76 }
77
78 @end
79
80 #pragma mark -- OctagonStateTransitionGroupOperation
81
82 @implementation OctagonStateTransitionGroupOperation
83 - (instancetype)initIntending:(OctagonState*)intendedState
84 errorState:(OctagonState*)errorState
85 {
86 if((self = [super init])) {
87 _nextState = errorState;
88 _intendedState = intendedState;
89 }
90 return self;
91 }
92
93 - (NSString*)description
94 {
95 return [NSString stringWithFormat:@"<OctagonStateTransitionGroupOperation(%@): intended:%@ actual:%@>", self.name, self.intendedState, self.nextState];
96 }
97
98 + (instancetype)named:(NSString*)name
99 intending:(OctagonState*)intendedState
100 errorState:(OctagonState*)errorState
101 withBlockTakingSelf:(void(^)(OctagonStateTransitionGroupOperation* op))block
102 {
103 OctagonStateTransitionGroupOperation* op = [[self alloc] initIntending:intendedState
104 errorState:errorState];
105 WEAKIFY(op);
106 [op runBeforeGroupFinished:[NSBlockOperation blockOperationWithBlock:^{
107 STRONGIFY(op);
108 block(op);
109 }]];
110 op.name = name;
111 return op;
112 }
113 @end
114
115 #pragma mark -- OctagonStateTransitionRequest
116
117 @interface OctagonStateTransitionRequest ()
118 @property dispatch_queue_t queue;
119 @property bool timeoutCanOccur;
120 @end
121
122 @implementation OctagonStateTransitionRequest
123
124 - (instancetype)init:(NSString*)name
125 sourceStates:(NSSet<OctagonState*>*)sourceStates
126 serialQueue:(dispatch_queue_t)queue
127 timeout:(dispatch_time_t)timeout
128 transitionOp:(CKKSResultOperation<OctagonStateTransitionOperationProtocol>*)transitionOp
129 {
130 if((self = [super init])) {
131 _name = name;
132 _sourceStates = sourceStates;
133 _queue = queue;
134
135 _timeoutCanOccur = true;
136 _transitionOperation = transitionOp;
137 }
138
139 [self timeout:timeout];
140
141 return self;
142 }
143
144 - (NSString*)description
145 {
146 return [NSString stringWithFormat:@"<OctagonStateTransitionRequest: %@ %@ sources:%d>", self.name, self.transitionOperation, (unsigned int)[self.sourceStates count]];
147 }
148
149 - (CKKSResultOperation<OctagonStateTransitionOperationProtocol>* _Nullable)_onqueueStart
150 {
151 dispatch_assert_queue(self.queue);
152
153 if(self.timeoutCanOccur) {
154 self.timeoutCanOccur = false;
155 return self.transitionOperation;
156 } else {
157 return nil;
158 }
159 }
160
161 - (instancetype)timeout:(dispatch_time_t)timeout
162 {
163 WEAKIFY(self);
164 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timeout), self.queue, ^{
165 STRONGIFY(self);
166 if(self.timeoutCanOccur) {
167 self.timeoutCanOccur = false;
168
169 // The operation will only realize it's finished once added to any operation queue. Fake one up.
170 [self.transitionOperation timeout:0*NSEC_PER_SEC];
171 [[[NSOperationQueue alloc] init] addOperation:self.transitionOperation];
172 }
173 });
174
175 return self;
176 }
177
178 @end
179
180 #endif // OCTAGON