Reputation: 5057
I am trying to use the SystemConfiguration on mac OS to get a notification when a new network interface appears on the mac and a new IP address is assigned for it.
I set it up to watch for the system configuration key State:/Network/Interface
and it works that I get a notification whenever a new network interface appears or disappears.
However I would like to get a notification whenever the IPv4 address is assigned on the new network interface (e.g. by DHCP). I know that the key State:/Network/Interface/en0/IPv4
is holding the IPv4 address for the en0 interface. But using regular expressions as depicted in the man page for all IPv4 addresses State:/Network/Interface/.*/IPv4
does not work for the new interface.
I have put together a small minimal code example on github, however one can also use the scutil
command line tool.
main.c
#import <Foundation/Foundation.h>
#import <SystemConfiguration/SystemConfiguration.h>
/* Callback used if a configuration change on monitored keys was detected.
*/
void dynamicStoreCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void* __nullable info) {
CFIndex count = CFArrayGetCount(changedKeys);
for (CFIndex i=0; i<count; i++) {
NSLog(@"Key \"%@\" was changed", CFArrayGetValueAtIndex(changedKeys, i));
}
}
int main(int argc, const char * argv[]) {
NSArray *SCMonitoringInterfaceKeys = @[@"State:/Network/Interface.*"];
@autoreleasepool {
SCDynamicStoreRef dsr = SCDynamicStoreCreate(NULL, CFSTR("network_interface_detector"), &dynamicStoreCallback, NULL);
SCDynamicStoreSetNotificationKeys(dsr, CFBridgingRetain(SCMonitoringInterfaceKeys), NULL);
CFRunLoopAddSource(CFRunLoopGetCurrent(), SCDynamicStoreCreateRunLoopSource(NULL, dsr, 0), kCFRunLoopDefaultMode);
NSLog(@"Starting RunLoop...");
while([[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
}
return 0;
}
Upvotes: 1
Views: 638
Reputation: 5057
With the help of some developer colleagues I found out what went wrong. The signature for the SCDynamicStoreSetNotificationKeys
function is as follows:
Boolean SCDynamicStoreSetNotificationKeys (SCDynamicStoreRef store,
CFArrayRef __nullable keys,
CFArrayRef __nullable patterns
)
Meaning that I have to set the pattern separately from the keys which act as the root of the tree under which the pattern matching will occur. Here is the modified version of my main.m:
int main(int argc, const char * argv[]) {
NSArray *SCMonitoringInterfaceKeys = @[@"State:/Network/Interface"];
NSArray *patterns = @[@"en\\d*/IPv4"];
@autoreleasepool {
SCDynamicStoreRef dsr = SCDynamicStoreCreate(NULL, CFSTR("network_interface_detector"), &dynamicStoreCallback, NULL);
SCDynamicStoreSetNotificationKeys(dsr, CFBridgingRetain(SCMonitoringInterfaceKeys), CFBridgingRetain(patterns));
CFRunLoopAddSource(CFRunLoopGetCurrent(), SCDynamicStoreCreateRunLoopSource(NULL, dsr, 0), kCFRunLoopDefaultMode);
NSLog(@"Starting RunLoop...");
while([[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
}
return 0;
}
I have included the solution into the solved branch of the repo.
Upvotes: 2