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