]> git.saurik.com Git - apple/security.git/blob - KVSKeychainSyncingProxy/XPCNotificationDispatcher.m
Security-59754.41.1.tar.gz
[apple/security.git] / KVSKeychainSyncingProxy / XPCNotificationDispatcher.m
1 //
2 // XPCNotificationDispatcher.m
3 // Security
4 //
5 // Created by Mitch Adler on 11/1/16.
6 //
7 //
8
9 #import "XPCNotificationDispatcher.h"
10 #include <dispatch/dispatch.h>
11
12 #include <utilities/debugging.h>
13
14 #include <xpc/xpc.h>
15
16 //
17 // PointerArray helpers
18
19 @interface NSPointerArray (Removal)
20 - (void) removePointer: (nullable void *)pointer;
21 @end
22
23 @implementation NSPointerArray (Removal)
24 - (void) removePointer: (nullable void *)pointer {
25 NSUInteger pos = 0;
26 while(pos < [self count]) {
27 if (pointer == [self pointerAtIndex:pos]) {
28 [self removePointerAtIndex:pos];
29 } else {
30 pos += 1;
31 }
32 }
33 }
34 @end
35
36 //
37 //
38
39 static const char *kXPCNotificationStreamName = "com.apple.notifyd.matching";
40 static const char *kXPCNotificationNameKey = "Notification";
41
42 @interface XPCNotificationDispatcher ()
43 @property dispatch_queue_t queue;
44 @property NSPointerArray* listeners;
45
46 - (void) notification: (const char *) value;
47
48 @end
49
50
51 @implementation XPCNotificationDispatcher
52
53 + (instancetype) dispatcher {
54 static dispatch_once_t onceToken;
55 static XPCNotificationDispatcher* sDispactcher;
56 dispatch_once(&onceToken, ^{
57 sDispactcher = [[XPCNotificationDispatcher alloc] init];
58 });
59
60 return sDispactcher;
61 }
62
63 - (instancetype) init {
64 if ((self = [super init])) {
65 self.queue = dispatch_queue_create("XPC Notification Dispatch", DISPATCH_QUEUE_SERIAL);
66 self.listeners = [NSPointerArray weakObjectsPointerArray];
67 __weak typeof(self) weakSelf = self;
68
69 xpc_set_event_stream_handler(kXPCNotificationStreamName, self.queue, ^(xpc_object_t event){
70 const char *notificationName = xpc_dictionary_get_string(event, kXPCNotificationNameKey);
71 if (notificationName) {
72 [weakSelf notification:notificationName];
73 }
74 });
75 }
76
77 return self;
78 }
79
80 - (void) notification:(const char *)name {
81 [self.listeners compact];
82 [[self.listeners allObjects] enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
83 [obj handleNotification: name];
84 }];
85
86 }
87
88 - (void) addListener: (NSObject<XPCNotificationListener>*) newHandler {
89 dispatch_sync(self.queue, ^{
90 [self.listeners compact];
91 [self.listeners addPointer:(__bridge void * _Nullable)(newHandler)];
92 });
93 }
94
95 - (void) removeListener: (NSObject<XPCNotificationListener>*) existingHandler {
96 dispatch_sync(self.queue, ^{
97 [self.listeners removePointer:(__bridge void * _Nullable)existingHandler];
98 });
99 }
100
101 @end