IPConfigurationService.c [plain text]
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <CoreFoundation/CFRuntime.h>
#include <SystemConfiguration/SystemConfiguration.h>
#include <SystemConfiguration/SCValidation.h>
#include <pthread.h>
#include <mach/mach_error.h>
#include <mach/mach_port.h>
#include "ipconfig_types.h"
#include "ipconfig_ext.h"
#include "symbol_scope.h"
#include "cfutil.h"
#include "ipconfig.h"
#include "IPConfigurationServiceInternal.h"
#include "IPConfigurationService.h"
struct __IPConfigurationService {
CFRuntimeBase cf_base;
mach_port_t server;
CFStringRef ifname;
CFDataRef serviceID_data;
CFStringRef store_key;
};
STATIC CFStringRef __IPConfigurationServiceCopyDebugDesc(CFTypeRef cf);
STATIC void __IPConfigurationServiceDeallocate(CFTypeRef cf);
STATIC CFTypeID __kIPConfigurationServiceTypeID = _kCFRuntimeNotATypeID;
STATIC const CFRuntimeClass __IPConfigurationServiceClass = {
0,
"IPConfigurationService",
NULL,
NULL,
__IPConfigurationServiceDeallocate,
NULL,
NULL,
NULL,
__IPConfigurationServiceCopyDebugDesc
};
STATIC CFStringRef
__IPConfigurationServiceCopyDebugDesc(CFTypeRef cf)
{
CFAllocatorRef allocator = CFGetAllocator(cf);
CFMutableStringRef result;
IPConfigurationServiceRef service = (IPConfigurationServiceRef)cf;
result = CFStringCreateMutable(allocator, 0);
CFStringAppendFormat(result, NULL,
CFSTR("<IPConfigurationService %p [%p]> {"),
cf, allocator);
CFStringAppendFormat(result, NULL, CFSTR("ifname = %@, serviceID = %.*s"),
service->ifname,
CFDataGetLength(service->serviceID_data),
CFDataGetBytePtr(service->serviceID_data));
CFStringAppend(result, CFSTR("}"));
return (result);
}
STATIC void
__IPConfigurationServiceDeallocate(CFTypeRef cf)
{
kern_return_t kret;
IPConfigurationServiceRef service = (IPConfigurationServiceRef)cf;
inline_data_t service_id;
int service_id_len;
ipconfig_status_t status;
service_id_len = CFDataGetLength(service->serviceID_data);
bcopy(CFDataGetBytePtr(service->serviceID_data), &service_id,
service_id_len);
kret = ipconfig_remove_service_with_id(service->server,
service_id, service_id_len,
&status);
if (kret != KERN_SUCCESS) {
fprintf(stderr, "__IPConfigurationServiceDeallocate: "
"ipconfig_remove_service_with_id(%.*s) failed, %s\n",
service_id_len, service_id, mach_error_string(kret));
}
else if (status != ipconfig_status_success_e) {
fprintf(stderr, "IPConfigurationServiceCreate: "
"ipconfig_add_service(%.*s) failed: %s\n",
service_id_len, service_id,
ipconfig_status_string(status));
}
mach_port_deallocate(mach_task_self(), service->server);
service->server = MACH_PORT_NULL;
my_CFRelease(&service->ifname);
my_CFRelease(&service->serviceID_data);
my_CFRelease(&service->store_key);
return;
}
STATIC void
__IPConfigurationServiceInitialize(void)
{
__kIPConfigurationServiceTypeID
= _CFRuntimeRegisterClass(&__IPConfigurationServiceClass);
return;
}
STATIC void
__IPConfigurationServiceRegisterClass(void)
{
STATIC pthread_once_t initialized = PTHREAD_ONCE_INIT;
pthread_once(&initialized, __IPConfigurationServiceInitialize);
return;
}
STATIC IPConfigurationServiceRef
__IPConfigurationServiceAllocate(CFAllocatorRef allocator)
{
IPConfigurationServiceRef service;
int size;
__IPConfigurationServiceRegisterClass();
size = sizeof(*service) - sizeof(CFRuntimeBase);
service = (IPConfigurationServiceRef)
_CFRuntimeCreateInstance(allocator,
__kIPConfigurationServiceTypeID, size, NULL);
bzero(((void *)service) + sizeof(CFRuntimeBase), size);
return (service);
}
STATIC CFDictionaryRef
config_dict_create(pid_t pid)
{
CFDictionaryRef config_dict;
const void * keys[2];
CFDictionaryRef ipv6_dict;
CFDictionaryRef options;
const void * values[2];
keys[0] = kIPConfigurationServiceOptionMonitorPID;
values[0] = kCFBooleanTrue;
keys[1] = kIPConfigurationServiceOptionNoPublish;
values[1] = kCFBooleanTrue;
options
= CFDictionaryCreate(NULL, keys, values, 2,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
ipv6_dict
= CFDictionaryCreate(NULL,
(const void * *)&kSCPropNetIPv6ConfigMethod,
(const void * *)&kSCValNetIPv6ConfigMethodAutomatic,
1,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
keys[0] = kIPConfigurationServiceOptions;
values[0] = options;
keys[1] = kSCEntNetIPv6;
values[1] = ipv6_dict;
config_dict
= CFDictionaryCreate(NULL, keys, values, 2,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFRelease(options);
CFRelease(ipv6_dict);
return (config_dict);
}
PRIVATE_EXTERN CFTypeID
IPConfigurationServiceGetTypeID(void)
{
__IPConfigurationServiceRegisterClass();
return (__kIPConfigurationServiceTypeID);
}
IPConfigurationServiceRef
IPConfigurationServiceCreate(CFStringRef interface_name,
CFDictionaryRef options)
{
CFDictionaryRef config_dict;
CFDataRef data = NULL;
if_name_t if_name;
kern_return_t kret;
mach_port_t server = MACH_PORT_NULL;
IPConfigurationServiceRef service = NULL;
CFStringRef serviceID;
inline_data_t service_id;
unsigned int service_id_len;
ipconfig_status_t status = ipconfig_status_success_e;
boolean_t tried_to_delete = FALSE;
void * xml_data_ptr = NULL;
int xml_data_len = 0;
if (options != NULL) {
return (NULL);
}
kret = ipconfig_server_port(&server);
if (kret != BOOTSTRAP_SUCCESS) {
fprintf(stderr,
"IPConfigurationServiceCreate: ipconfig_server_port, %s\n",
mach_error_string(kret));
return (NULL);
}
config_dict = config_dict_create(getpid());
data = CFPropertyListCreateXMLData(NULL, config_dict);
CFRelease(config_dict);
xml_data_ptr = (void *)CFDataGetBytePtr(data);
xml_data_len = CFDataGetLength(data);
my_CFStringToCStringAndLength(interface_name, if_name,
sizeof(if_name));
while (1) {
kret = ipconfig_add_service(server, if_name,
xml_data_ptr, xml_data_len,
service_id, &service_id_len,
&status);
if (kret != KERN_SUCCESS) {
fprintf(stderr, "IPConfigurationServiceCreate: "
"ipconfig_add_service(%s) failed, %s\n",
if_name, mach_error_string(kret));
goto done;
}
if (status != ipconfig_status_duplicate_service_e) {
break;
}
if (tried_to_delete) {
break;
}
tried_to_delete = TRUE;
(void)ipconfig_remove_service(server, if_name,
xml_data_ptr, xml_data_len,
&status);
}
if (status != ipconfig_status_success_e) {
fprintf(stderr, "IPConfigurationServiceCreate: "
"ipconfig_add_service(%s) failed: %s\n",
if_name, ipconfig_status_string(status));
goto done;
}
service = __IPConfigurationServiceAllocate(NULL);
if (service == NULL) {
goto done;
}
service->ifname = CFStringCreateCopy(NULL, interface_name);
service->serviceID_data = CFDataCreate(NULL, (const UInt8 *)service_id,
service_id_len);
service->server = server;
serviceID
= CFStringCreateWithBytes(NULL,
CFDataGetBytePtr(service->serviceID_data),
CFDataGetLength(service->serviceID_data),
kCFStringEncodingASCII, FALSE);
service->store_key = IPConfigurationServiceKey(serviceID);
CFRelease(serviceID);
server = MACH_PORT_NULL;
done:
if (server != MACH_PORT_NULL) {
mach_port_deallocate(mach_task_self(), server);
}
my_CFRelease(&data);
return (service);
}
CFStringRef
IPConfigurationServiceGetNotificationKey(IPConfigurationServiceRef service)
{
return (service->store_key);
}
CFDictionaryRef
IPConfigurationServiceCopyInformation(IPConfigurationServiceRef service)
{
CFDictionaryRef info;
SCDynamicStoreRef store;
store = SCDynamicStoreCreate(NULL, CFSTR("IPConfigurationService"),
NULL, NULL);
if (store == NULL) {
return (NULL);
}
info = SCDynamicStoreCopyValue(store, service->store_key);
if (info != NULL
&& isA_CFDictionary(info) == NULL) {
my_CFRelease(&info);
}
CFRelease(store);
return (info);
}