forked from johndbritton/teleport
-
Notifications
You must be signed in to change notification settings - Fork 0
/
TPNetworkConfigurationWatcher.m
117 lines (93 loc) · 3.51 KB
/
TPNetworkConfigurationWatcher.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
//
// TPNetworkConfigurationWatcher.m
// teleport
//
// Created by Julien Robert on 13/04/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "TPNetworkConfigurationWatcher.h"
static void _networkChangeCallBack(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info);
@implementation TPNetworkConfigurationWatcher
- (void)setDelegate:(id)delegate
{
_delegate = delegate;
}
- (void)startWatching
{
SCDynamicStoreContext context = {
0, // version
(__bridge void *)(self), // info
NULL, // retain
NULL, // release
NULL, // copyDescription
};
_storeRef = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("com.abyssoft.teleport"), &_networkChangeCallBack, &context);
if(_storeRef == NULL) {
NSLog(@"Error creating the dynamic store");
}
else {
CFMutableArrayRef keys = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
CFMutableArrayRef patterns = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
CFStringRef key;
/* watch for IPv4 configuration changes (e.g. new default route) */
key = SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCEntNetIPv4);
CFArrayAppendValue(keys, key);
CFRelease(key);
/* as above, but for IPv6 */
key = SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCEntNetIPv6);
CFArrayAppendValue(keys, key);
CFRelease(key);
/* watch for IPv4 interface configuration changes */
key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
CFArrayAppendValue(patterns, key);
CFRelease(key);
/* as above, but for IPv6 */
key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
CFArrayAppendValue(patterns, key);
CFRelease(key);
/* watch for DNS interface configuration changes */
key = SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCEntNetDNS);
CFArrayAppendValue(keys, key);
CFRelease(key);
_sourceRef = SCDynamicStoreCreateRunLoopSource(NULL, _storeRef, 0);
if(_sourceRef == NULL) {
NSLog(@"Error creating the dynamic store runloop source");
}
else {
CFRunLoopAddSource(CFRunLoopGetCurrent(), _sourceRef, kCFRunLoopDefaultMode);
if(!SCDynamicStoreSetNotificationKeys(_storeRef, (CFArrayRef)keys, (CFArrayRef)patterns)) {
NSLog(@"Error setting the dynamic store notification keys");
}
CFRelease(_sourceRef);
}
CFRelease(keys);
CFRelease(patterns);
}
}
- (void)stopWatching
{
if (_sourceRef) {
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), _sourceRef, kCFRunLoopDefaultMode);
CFRelease(_sourceRef);
_sourceRef = NULL;
}
}
- (void)_networkChanged
{
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(_notifyNetworkChanged) object:nil];
[self performSelector:@selector(_notifyNetworkChanged) withObject:nil afterDelay:1.0];
}
- (void)_notifyNetworkChanged
{
if([_delegate respondsToSelector:@selector(networkConfigurationDidChange:)]) {
[_delegate networkConfigurationDidChange:self];
}
}
@end
static void _networkChangeCallBack(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info)
{
@autoreleasepool {
TPNetworkConfigurationWatcher * self = (__bridge TPNetworkConfigurationWatcher*)info;
[self _networkChanged];
}
}