SystemConfiguration.framework でネットワークの情報を得る
Mac アプリのプログラミングで、SystemConfiguration.framework の DynamicStore を利用すると、ネットワーク関連の現在状態や設定値を取得できます。ネットワーク以外にもいくつか取得できたりします。
SystemConfiguration.framework は C 言語の API が用意されており、Objective-C の API はありません。関数等の接頭詞は “SC” です。
キー。
DynamicStore は名前からも分かるとおり現在のダイナミック(動的)な設定情報・状態値を保持していて、URI 形式のキーで値を取得することができます。
State:/Network/Global/DNS
といった表記でキーが表されます。キーは多岐にわたりますし、特定の文法で記載されるので、簡単にキーを取得するためのユーティリティ関数が用意されています。
SCDynamicStoreKey.h
- SCDynamicStoreKeyCreateConsoleUser()
- SCDynamicStoreKeyCreateHostNames()
- SCDynamicStoreKeyCreateLocation()
- SCDynamicStoreKeyCreateNetworkGlobalEntity()
- SCDynamicStoreKeyCreateNetworkInterface()
- SCDynamicStoreKeyCreateNetworkInterfaceEntity()
- SCDynamicStoreKeyCreateNetworkServiceEntity()
- SCDynamicStoreKeyCreateProxies()
また、各関数にキーの可変部をパラメタとして渡す場合の定数が、SCSchemaDefinitions.h に多数記載されています。
ただ、上記の関数リファレンスやヘッダを見ても、実際にどのようなキーがあり、上記のユーティリティ関数に与えるパラメタも、結果として得られるキーも、いまひとつ具体的に分かりません。
そこで役に立つのが scutil
というコマンド。
$ scutil > > list subKey [0] = Plugin:IPConfiguration subKey [1] = Plugin:InterfaceNamer subKey [2] = Setup: subKey [3] = Setup:/ subKey [4] = Setup:/Network/BackToMyMac subKey [5] = Setup:/Network/Global/IPv4 subKey [6] = Setup:/Network/HostNames subKey [7] = Setup:/Network/Interface/en1/AirPort subKey [8] = Setup:/Network/Service/17252794-5272-4263-8436-93458EA29A41 subKey [9] = Setup:/Network/Service/17252794-5272-4263-8436-93458EA29A41/IPv4 subKey [10] = Setup:/Network/Service/17252794-5272-4263-8436-93458EA29A41/IPv6 subKey [11] = Setup:/Network/Service/17252794-5272-4263-8436-93458EA29A41/Interface subKey [12] = Setup:/Network/Service/17252794-5272-4263-8436-93458EA29A41/Modem subKey [13] = Setup:/Network/Service/17252794-5272-4263-8436-93458EA29A41/PPP subKey [14] = Setup:/Network/Service/17252794-5272-4263-8436-93458EA29A41/Proxies subKey [15] = Setup:/Network/Service/6C67FE3C-C7EC-4885-9250-307B8EBA5DEA subKey [16] = Setup:/Network/Service/6C67FE3C-C7EC-4885-9250-307B8EBA5DEA/IPv4 subKey [17] = Setup:/Network/Service/6C67FE3C-C7EC-4885-9250-307B8EBA5DEA/IPv6 subKey [18] = Setup:/Network/Service/6C67FE3C-C7EC-4885-9250-307B8EBA5DEA/Interface subKey [19] = Setup:/Network/Service/6C67FE3C-C7EC-4885-9250-307B8EBA5DEA/Proxies subKey [20] = Setup:/Network/Service/9EAEE8A7-60C3-44EF-98F6-FA7E0D2E3396 subKey [21] = Setup:/Network/Service/9EAEE8A7-60C3-44EF-98F6-FA7E0D2E3396/IPv4 subKey [22] = Setup:/Network/Service/9EAEE8A7-60C3-44EF-98F6-FA7E0D2E3396/IPv6 subKey [23] = Setup:/Network/Service/9EAEE8A7-60C3-44EF-98F6-FA7E0D2E3396/Interface subKey [24] = Setup:/Network/Service/9EAEE8A7-60C3-44EF-98F6-FA7E0D2E3396/Proxies subKey [25] = Setup:/System subKey [26] = State:/IOKit/LowBatteryWarning subKey [27] = State:/IOKit/Power/CPUPower subKey [28] = State:/IOKit/PowerAdapter subKey [29] = State:/IOKit/PowerManagement/Assertions subKey [30] = State:/IOKit/PowerManagement/CurrentSettings subKey [31] = State:/IOKit/PowerManagement/SystemLoad subKey [32] = State:/IOKit/PowerManagement/SystemLoad/Detailed subKey [33] = State:/IOKit/PowerSources/InternalBattery-0 subKey [34] = State:/IOKit/SystemPowerCapabilities subKey [35] = State:/Network/BackToMyMac subKey [36] = State:/Network/Global/DNS subKey [37] = State:/Network/Global/IPv4 subKey [38] = State:/Network/Global/Proxies subKey [39] = State:/Network/Interface subKey [40] = State:/Network/Interface/en0/Link subKey [41] = State:/Network/Interface/en1/AirPort subKey [42] = State:/Network/Interface/en1/IPv4 subKey [43] = State:/Network/Interface/en1/IPv6 subKey [44] = State:/Network/Interface/en1/Link subKey [45] = State:/Network/Interface/lo0/IPv4 subKey [46] = State:/Network/Interface/lo0/IPv6 subKey [47] = State:/Network/Interface/vmnet1/IPv4 subKey [48] = State:/Network/Interface/vmnet8/IPv4 subKey [49] = State:/Network/MulticastDNS subKey [50] = State:/Network/PrivateDNS subKey [51] = State:/Network/Service/6C67FE3C-C7EC-4885-9250-307B8EBA5DEA/DHCP subKey [52] = State:/Network/Service/6C67FE3C-C7EC-4885-9250-307B8EBA5DEA/DNS subKey [53] = State:/Network/Service/6C67FE3C-C7EC-4885-9250-307B8EBA5DEA/IPv4 subKey [54] = State:/Users/ConsoleUser subKey [55] = com.apple.DirectoryService.NotifyTypeStandard:DirectoryNodeAdded subKey [56] = com.apple.network.identification >
scutil
は起動するとプロンプトになりコマンドが入力できます。help
で利用出来るコマンドが表示されますので見てみてください。そこそこいろいろ出来ます。
今回は、list
と言うコマンドで、利用出来るキーの一覧を表示しています。なお、キーは常に一定ではなく、ネットワークの状況によって増減します。
値。
DynamicStore から取得できる値は NSDictionary ( CFDictionary ) で、実際の個別の設定値はさらにその中に規定のプロパティ名で格納されています。これは scutil
の show
コマンドで確認することができます。
> show State:/Network/Global/IPv4 <dictionary> { PrimaryInterface : en1 PrimaryService : 6C67FE3C-C7EC-4885-9250-307B8EBA5DEA Router : 192.168.1.1 } > show State:/Network/Interface/en1/Link <dictionary> { Active : TRUE } > show State:/Network/Interface/en1/IPv4 <dictionary> { Addresses : <array> { 0 : 192.168.1.102 } BroadcastAddresses : <array> { 0 : 192.168.1.255 } SubnetMasks : <array> { 0 : 255.255.255.0 } } >
コード例。
さて、これをプログラム上ではどう取得するかですが、結構簡単です。
- #import <Cocoa/Cocoa.h>
- #import <SystemConfiguration/SCDynamicStoreKey.h>
- #import <SystemConfiguration/SCSchemaDefinitions.h>
- - (void)test
- {
- SCDynamicStoreRef store;
- SCDynamicStoreContext context;
- CFStringRef key;
- CFDictionaryRef val;
- CFStringRef host;
- CFStringRef primIF;
- CFArrayRef addrs;
- CFStringRef addr;
- // DynaimcStore生成
- context.info = self;
- store = SCDynamicStoreCreate(NULL, (CFStringRef)[[NSBundle mainBundle] bundleIdentifier], NULL, &context);
- // コンピュータ名取得
- key = SCDynamicStoreKeyCreateHostNames(NULL);
- val = (CFDictionaryRef)SCDynamicStoreCopyValue(store, key);
- host = (CFStringRef)CFDictionaryGetValue(val, kSCPropNetLocalHostName);
- NSLog(@"HostName is %@.", host);
- CFRelease(val);
- CFRelease(key);
- // PrimaryInteaface取得
- key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
- val = (CFDictionaryRef)SCDynamicStoreCopyValue(store, key);
- primIF = (CFStringRef)CFDictionaryGetValue(val, kSCDynamicStorePropNetPrimaryInterface);
- NSLog(@"PrimaryInterface is %@.", primaryIF);
- CFRetain(primIF);
- CFRelease(val);
- CFRelease(key);
- // IPアドレス取得
- key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, primIF, kSCEntNetIPv4);
- val = (CFDictionaryRef)SCDynamicStoreCopyValue(store, key);
- addrs = (CFArrayRef)CFDictionaryGetValue(val, kSCPropNetIPv4Addresses);
- addr = (CFStringRef)CFArrayGetValueAtIndex(addrs, 0);
- NSLog(@"IP Address is %@", addr);
- CFRelease(val);
- CFRelease(key);
- CFRelease(primIF);
- }
上記サンプルはエラー処理をしていませんが、値を階層的に取得しているので、エラーチェックは処理の都度行う必要があります。
scutil
で欲しいキーを確認すれば、別のキーでも取得の方法は同じ要領です。ネットワークの設定や諸情報、ネットワーク以外にも電源(電池)の状態などもわかったり、結構面白いです。
実は、DynamicStore を使うと今回取得したような値の変化(ネットワーク状態の変化、システム環境設定での変更)を検出することもできますが、それは次回に。