]> git.saurik.com Git - apple/security.git/blob - KVSKeychainSyncingProxy/XPCNotificationDispatcher.m
1eccd2f6598f1f5b4187e0091854d6c546bf2470
[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 self = [super init];
65
66 if (self) {
67 self.queue = dispatch_queue_create("XPC Notification Dispatch", DISPATCH_QUEUE_SERIAL);
68 self.listeners = [NSPointerArray weakObjectsPointerArray];
69
70 xpc_set_event_stream_handler(kXPCNotificationStreamName, self.queue, ^(xpc_object_t event){
71 const char *notificationName = xpc_dictionary_get_string(event, kXPCNotificationNameKey);
72 if (notificationName) {
73 [self notification:notificationName];
74 }
75 });
76 }
77
78 return self;
79 }
80
81 - (void) notification:(const char *)name {
82 [self.listeners compact];
83 [[self.listeners allObjects] enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
84 [obj handleNotification: name];
85 }];
86
87 }
88
89 - (void) addListener: (NSObject<XPCNotificationListener>*) newHandler {
90 dispatch_sync(self.queue, ^{
91 [self.listeners compact];
92 [self.listeners addPointer:(__bridge void * _Nullable)(newHandler)];
93 });
94 }
95
96 - (void) removeListener: (NSObject<XPCNotificationListener>*) existingHandler {
97 dispatch_sync(self.queue, ^{
98 [self.listeners removePointer:(__bridge void * _Nullable)existingHandler];
99 });
100 }
101
102 @end