]> git.saurik.com Git - apple/security.git/blob - MultiDeviceSimulator/MultiDeviceSimulatorTests/MultiDeviceNetworking.m
Security-58286.251.4.tar.gz
[apple/security.git] / MultiDeviceSimulator / MultiDeviceSimulatorTests / MultiDeviceNetworking.m
1 //
2 // MultiDeviceNetworking.m
3 // Security
4 //
5
6 #import "MultiDeviceNetworking.h"
7 #import "MultiDeviceNetworkingProtocol.h"
8
9 @interface MDNCounters ()
10 @property (assign) unsigned long kvsSyncAndWait;
11 @property (assign) unsigned long kvsFlush;
12 @property (assign) unsigned long kvsSend;
13 @property (assign) unsigned long kvsRecv;
14 @property (assign) unsigned long kvsRecvAll;
15 @property (strong) NSMutableDictionary<NSString *,NSNumber *> *kvsKeys;
16
17 - (void)addCountToKey:(NSString *)key;
18 @end
19
20
21 @interface MDNConnection : NSObject <MultiDeviceNetworkingProtocol>
22 @property (weak) MultiDeviceNetworking *network;
23 @property NSXPCConnection *inConnection;
24 @property NSXPCConnection *outConnection;
25 @property MDNCounters *counters;
26 @end
27
28 @interface MultiDeviceNetworking () <NSXPCListenerDelegate>
29 @property NSXPCListener *networkListener;
30 @property NSMutableDictionary *kvs;
31 @property NSMutableArray<MDNConnection *> *connections;
32 @property dispatch_queue_t serialQueue;
33 @property NSMutableDictionary<NSString *, XCTestExpectation *> *expectations;
34 @end
35
36 @implementation MDNCounters
37
38 - (instancetype)init {
39 if ((self = [super init]) == NULL) {
40 return nil;
41 }
42 self.kvsKeys = [NSMutableDictionary dictionary];
43 return self;
44 }
45
46 - (NSDictionary *)summary{
47 NSDictionary *kvsKeys = @{};
48 @synchronized(self.kvsKeys) {
49 kvsKeys = [self.kvsKeys copy];
50 }
51 return @{
52 @"kvsSyncAndWait" : @(self.kvsSyncAndWait),
53 @"kvsFlush" : @(self.kvsFlush),
54 @"kvsSend" : @(self.kvsSend),
55 @"kvsRecv" : @(self.kvsRecv),
56 @"kvsRecvAll" : @(self.kvsRecvAll),
57 @"kvsKeys" : kvsKeys,
58 };
59 }
60 - (NSString *)description
61 {
62 return [NSString stringWithFormat:@"<MDNCounters: %@>", [self summary]];
63 }
64 - (void)addCountToKey:(NSString *)key
65 {
66 @synchronized(self.kvsKeys) {
67 NSNumber *number = self.kvsKeys[key];
68 self.kvsKeys[key] = @([number longValue] + 1);
69 }
70 }
71
72 @end
73
74 @implementation MultiDeviceNetworking
75
76 - (instancetype)init
77 {
78 self = [super init];
79 if (self) {
80 self.networkListener = [NSXPCListener anonymousListener];
81 self.networkListener.delegate = self;
82 [self.networkListener resume];
83 self.kvs = [[NSMutableDictionary alloc] init];
84 self.connections = [NSMutableArray array];
85 self.serialQueue = dispatch_queue_create("MultiDeviceNetworking.flushQueue", NULL);
86 self.expectations = [NSMutableDictionary dictionary];
87 }
88 return self;
89 }
90
91 - (NSXPCListenerEndpoint *)endpoint
92 {
93 return [self.networkListener endpoint];
94 }
95
96 - (void)dumpKVSState
97 {
98 @synchronized(self.kvs) {
99 puts("KVS STATE");
100 [self.kvs enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull __unused stop) {
101 puts([[NSString stringWithFormat:@"%@ - %@", key, obj] UTF8String]);
102 }];
103 }
104 }
105
106 - (void)dumpCounters
107 {
108 @synchronized(self.connections) {
109 puts("Network counters:");
110 for (MDNConnection *conn in self.connections) {
111 puts([[NSString stringWithFormat:@"%@", conn.counters] UTF8String]);
112 }
113 }
114 }
115
116
117 - (void)disconnectAll
118 {
119 @synchronized(self.connections) {
120 for (MDNConnection *conn in self.connections) {
121 [conn.inConnection invalidate];
122 [conn.outConnection invalidate];
123 }
124 self.connections = [NSMutableArray array];
125 }
126 }
127
128 - (void)setTestExpectation:(XCTestExpectation *)expectation forKey:(NSString *)key
129 {
130 self.expectations[key] = expectation;
131 }
132
133 - (void)clearTestExpectations
134 {
135 self.expectations = [NSMutableDictionary dictionary];
136 }
137
138 - (void)fulfill:(NSString *)key
139 {
140 [self.expectations[key] fulfill];
141 }
142
143
144
145 //MARK: - setup listener
146
147 - (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection
148 {
149 newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MultiDeviceNetworkingProtocol)];
150
151 MDNConnection *conn = [[MDNConnection alloc] init];
152 conn.network = self;
153 conn.inConnection = newConnection;
154 newConnection.exportedObject = conn;
155
156 [self.connections addObject:conn];
157 [newConnection resume];
158
159 return YES;
160 }
161
162 @end
163
164
165 //MARK: - KVS fun
166
167 @implementation MDNConnection
168
169 - (instancetype)init
170 {
171 if ((self = [super init]) == nil)
172 return nil;
173 _counters = [[MDNCounters alloc] init];
174 return self;
175 }
176
177 - (void)MDNRegisterCallback:(NSXPCListenerEndpoint *)callback complete:(MDNComplete)complete
178 {
179 self.outConnection = [[NSXPCConnection alloc] initWithListenerEndpoint:callback];
180 self.outConnection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(MultiDeviceNetworkingCallbackProtocol)];
181
182 __typeof(self) weakSelf = self;
183 self.outConnection.invalidationHandler = ^{
184 __typeof(self) strongSelf = weakSelf;
185 strongSelf.outConnection = nil;
186 };
187
188
189 [self.outConnection resume];
190 complete(NULL, NULL);
191 }
192
193 - (void)MDNCloudPut:(NSDictionary *)values complete:(MDNComplete)complete {
194 MultiDeviceNetworking *network = self.network;
195 @synchronized(network.kvs) {
196 [network.kvs setValuesForKeysWithDictionary:values];
197 }
198 /* interact with test expections so that tests can check that something happned in KVS */
199 [network fulfill:@"Network"];
200 for (NSString *key in values.allKeys) {
201 NSString *dataSummary = @"";
202 id value = values[key];
203 if ([value isKindOfClass:[NSString class]]) {
204 dataSummary = [NSString stringWithFormat:@" = string[%ld]", [(NSString *)value length]];
205 } else if ([value isKindOfClass:[NSData class]]) {
206 NSUInteger length = [(NSData *)value length];
207 NSData *subdata = [(NSData *)value subdataWithRange:NSMakeRange(0, MIN(length, 4))];
208 dataSummary = [NSString stringWithFormat:@" = data[%lu][%@]", (unsigned long)length, subdata];
209 } else {
210 dataSummary = [NSString stringWithFormat:@" = other(%@)", [value description]];
211 }
212 NSLog(@"KVS key update: %@%@", key, dataSummary);
213 [network fulfill:key];
214 [self.counters addCountToKey:key];
215 }
216
217
218 self.counters.kvsSend++;
219 for (MDNConnection *conn in network.connections) {
220 if (conn == self || conn.outConnection == NULL) {
221 continue;
222 }
223 conn.counters.kvsRecv++;
224 [[conn.outConnection remoteObjectProxy] MDNCItemsChanged:values complete:^(NSDictionary *returnedValues, NSError *error) {
225 ;
226 }];
227 }
228 complete(@{}, NULL);
229 }
230
231 - (void)MDNCloudsynchronizeAndWait:(NSDictionary *)values complete:(MDNComplete)complete {
232 MultiDeviceNetworking *network = self.network;
233 NSDictionary *kvsCopy = NULL;
234 @synchronized(network.kvs) {
235 kvsCopy = [network.kvs copy];
236 }
237 self.counters.kvsSyncAndWait++;
238 [[self.outConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {
239 NSLog(@"foo: %@", error);
240 //abort();
241 }] MDNCItemsChanged:kvsCopy complete:^(NSDictionary *returnedValues, NSError *error) {
242 }];
243 dispatch_async(network.serialQueue, ^{
244 complete(@{}, NULL);
245 });
246 }
247
248 - (void)MDNCloudGet:(NSArray *)keys complete:(MDNComplete)complete{
249 MultiDeviceNetworking *network = self.network;
250 NSLog(@"asking for: %@", keys);
251 self.counters.kvsRecv++;
252 NSMutableDictionary *reply = [NSMutableDictionary dictionary];
253 @synchronized(network.kvs) {
254 for (id key in keys) {
255 reply[key] = network.kvs[key];
256 }
257 }
258 complete(reply, NULL);
259 }
260
261 - (void)MDNCloudGetAll:(MDNComplete)complete
262 {
263 MultiDeviceNetworking *network = self.network;
264 NSDictionary *kvsCopy = NULL;
265 self.counters.kvsRecvAll++;
266 @synchronized(network.kvs) {
267 kvsCopy = [network.kvs copy];
268 }
269 complete(kvsCopy, NULL);
270 }
271
272 - (void)MDNCloudRemoveKeys:(NSArray<NSString *> *)keys complete:(MDNComplete)complete
273 {
274 MultiDeviceNetworking *network = self.network;
275 @synchronized(network.kvs) {
276 if (keys) {
277 for (NSString *key in keys) {
278 network.kvs[key] = NULL;
279 }
280 } else {
281 network.kvs = [NSMutableDictionary dictionary];
282 }
283 }
284 complete(NULL, NULL);
285 }
286
287 - (void)MDNCloudFlush:(MDNComplete)complete
288 {
289 self.counters.kvsFlush++;
290 dispatch_async(self.network.serialQueue, ^{
291 complete(@{}, NULL);
292 });
293 }
294
295 @end