CFNetServices.c
1 // 2 // CFNetServices.c 3 // CFNetwork 4 // 5 // Copyright (c) 2014 Apportable. All rights reserved. 6 // 7 8 #include "CFBase.h" 9 #include "CFRuntime.h" 10 #include "CFNetServices.h" 11 #include "dns_sd.h" 12 #include <libkern/OSAtomic.h> 13 14 /* extern */ const SInt32 kCFStreamErrorDomainNetServices = 10; 15 /* extern */ const SInt32 kCFStreamErrorDomainMach = 11; 16 17 struct __CFNetService { 18 CFRuntimeBase _base; 19 CFStringRef domain; 20 CFStringRef serviceType; 21 CFStringRef name; 22 UInt32 port; 23 CFDataRef txtData; 24 DNSServiceRef service; 25 DNSServiceRef resolver; 26 }; 27 28 struct __CFNetServiceMonitor { 29 CFRuntimeBase _base; 30 }; 31 32 struct __CFNetServiceBrowser { 33 CFRuntimeBase _base; 34 }; 35 36 static void __CFNetServiceDeallocate(CFTypeRef cf) { 37 struct __CFNetService *service = (struct __CFNetService *)cf; 38 if (service->domain != NULL) { 39 CFRelease(service->domain); 40 } 41 if (service->serviceType != NULL) { 42 CFRelease(service->serviceType); 43 } 44 if (service->name != NULL) { 45 CFRelease(service->name); 46 } 47 } 48 49 static void __CFNetServiceMonitorDeallocate(CFTypeRef cf) { 50 struct __CFNetServiceMonitor *monitor = (struct __CFNetServiceMonitor *)cf; 51 } 52 53 static void __CFNetServiceBrowserDeallocate(CFTypeRef cf) { 54 struct __CFNetServiceBrowser *browser = (struct __CFNetServiceBrowser *)cf; 55 } 56 57 static CFTypeID __kCFNetServiceTypeID = _kCFRuntimeNotATypeID; 58 static CFTypeID __kCFNetServiceMonitorTypeID = _kCFRuntimeNotATypeID; 59 static CFTypeID __kCFNetServiceBrowserTypeID = _kCFRuntimeNotATypeID; 60 61 static const CFRuntimeClass __CFNetServiceClass = { 62 _kCFRuntimeScannedObject, 63 "CFNetService", 64 NULL, 65 NULL, 66 __CFNetServiceDeallocate, 67 NULL, 68 NULL, 69 NULL, 70 NULL 71 }; 72 73 static const CFRuntimeClass __CFNetServiceMonitorClass = { 74 _kCFRuntimeScannedObject, 75 "CFNetServiceMonitor", 76 NULL, 77 NULL, 78 __CFNetServiceMonitorDeallocate, 79 NULL, 80 NULL, 81 NULL, 82 NULL 83 }; 84 85 static const CFRuntimeClass __CFNetServiceBrowserClass = { 86 _kCFRuntimeScannedObject, 87 "CFNetServiceBrowser", 88 NULL, 89 NULL, 90 __CFNetServiceBrowserDeallocate, 91 NULL, 92 NULL, 93 NULL, 94 NULL 95 }; 96 97 98 static void __CFNetServiceInitialize(void) { 99 __kCFNetServiceTypeID = _CFRuntimeRegisterClass(&__CFNetServiceClass); 100 } 101 102 static void __CFNetServiceMonitorInitialize(void) { 103 __kCFNetServiceMonitorTypeID = _CFRuntimeRegisterClass(&__CFNetServiceMonitorClass); 104 } 105 106 static void __CFNetServiceBrowserInitialize(void) { 107 __kCFNetServiceBrowserTypeID = _CFRuntimeRegisterClass(&__CFNetServiceBrowserClass); 108 } 109 110 CFTypeID CFNetServiceGetTypeID(void) { 111 if (__kCFNetServiceTypeID == _kCFRuntimeNotATypeID) { 112 __CFNetServiceInitialize(); 113 } 114 return __kCFNetServiceTypeID; 115 } 116 117 CFTypeID CFNetServiceMonitorGetTypeID(void) { 118 if (__kCFNetServiceMonitorTypeID == _kCFRuntimeNotATypeID) { 119 __CFNetServiceMonitorInitialize(); 120 } 121 return __kCFNetServiceMonitorTypeID; 122 } 123 124 CFTypeID CFNetServiceBrowserGetTypeID(void) { 125 if (__kCFNetServiceBrowserTypeID == _kCFRuntimeNotATypeID) { 126 __CFNetServiceBrowserInitialize(); 127 } 128 return __kCFNetServiceBrowserTypeID; 129 } 130 131 static struct __CFNetService *_CFNetServiceCreate(CFAllocatorRef allocator) { 132 CFIndex size = sizeof(struct __CFNetService) - sizeof(CFRuntimeBase); 133 return (struct __CFNetService *)_CFRuntimeCreateInstance(allocator, CFNetServiceGetTypeID(), size, NULL); 134 } 135 136 static struct __CFNetServiceMonitor *_CFNetServiceMonitorCreate(CFAllocatorRef allocator) { 137 CFIndex size = sizeof(struct __CFNetServiceMonitor) - sizeof(CFRuntimeBase); 138 return (struct __CFNetServiceMonitor *)_CFRuntimeCreateInstance(allocator, CFNetServiceMonitorGetTypeID(), size, NULL); 139 } 140 141 static struct __CFNetServiceBrowser *_CFNetServiceBrowserCreate(CFAllocatorRef allocator) { 142 CFIndex size = sizeof(struct __CFNetServiceBrowser) - sizeof(CFRuntimeBase); 143 return (struct __CFNetServiceBrowser *)_CFRuntimeCreateInstance(allocator, CFNetServiceBrowserGetTypeID(), size, NULL); 144 } 145 146 static void (*multicastLock)() = NULL; 147 static void (*multicastUnlock)() = NULL; 148 static int32_t lockState = 0; 149 150 static void _CFNetServiceMulticastAquire() { 151 if (OSAtomicIncrement32(&lockState) == 1) { 152 if (multicastLock != NULL) { 153 multicastLock(); 154 } 155 } 156 } 157 158 static void _CFNetServiceMulticastRelinquish() { 159 if (OSAtomicDecrement32(&lockState) == 0) { 160 if (multicastUnlock != NULL) { 161 multicastUnlock(); 162 } 163 } 164 } 165 166 void _CFNetServiceRegisterMulticastLock(void (*lock)(), void (*unlock)()) { 167 multicastLock = lock; 168 multicastUnlock = unlock; 169 } 170 171 CFNetServiceRef CFNetServiceCreate(CFAllocatorRef alloc, CFStringRef domain, CFStringRef serviceType, CFStringRef name, UInt32 port) { 172 struct __CFNetService *service = _CFNetServiceCreate(alloc); 173 if (domain != NULL) { 174 service->domain = CFStringCreateCopy(alloc, domain); 175 } 176 if (serviceType != NULL) { 177 service->serviceType = CFStringCreateCopy(alloc, serviceType); 178 } 179 if (name != NULL) { 180 service->name = CFStringCreateCopy(alloc, name); 181 } 182 service->port = port; 183 return service; 184 } 185 186 CFNetServiceRef CFNetServiceCreateCopy(CFAllocatorRef alloc, CFNetServiceRef service) { 187 return CFNetServiceCreate(alloc, service->domain, service->serviceType, service->name, service->port); 188 } 189 190 CFStringRef CFNetServiceGetDomain(CFNetServiceRef theService) { 191 return theService->domain; 192 } 193 194 CFStringRef CFNetServiceGetType(CFNetServiceRef theService) { 195 return theService->serviceType; 196 } 197 198 CFStringRef CFNetServiceGetName(CFNetServiceRef theService) { 199 return theService->name; 200 } 201 202 static inline Boolean _CFUTF8String(const char **str, char *buffer, size_t sz, CFStringRef string) { 203 if (string == NULL) { 204 *str = NULL; 205 return true; 206 } 207 *str = CFStringGetCStringPtr(string, kCFStringEncodingUTF8); 208 if (*str == NULL) { 209 if (CFStringGetCString(string, buffer, sz, kCFStringEncodingUTF8)) { 210 *str = buffer; 211 } 212 if (*str == NULL) { 213 214 return false; 215 } 216 } 217 return true; 218 } 219 220 #define BUFSIZE 256 221 222 static void _CFNetServiceRegistered(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain, void *context) { 223 CFNetServiceRef theService = (CFNetServiceRef)context; 224 225 CFRelease(theService); // balance registration 226 } 227 228 Boolean CFNetServiceRegisterWithOptions(CFNetServiceRef theService, CFOptionFlags options, CFStreamError *error) { 229 char nameBuffer[BUFSIZE]; 230 char typeBuffer[BUFSIZE]; 231 char domainBuffer[BUFSIZE]; 232 233 const char *name = NULL; 234 const char *type = NULL; 235 const char *domain = NULL; 236 237 if (!_CFUTF8String(&name, (char *)nameBuffer, BUFSIZE, theService->name)) { 238 // TODO: populate error here 239 return false; 240 } 241 if (!_CFUTF8String(&type, (char *)typeBuffer, BUFSIZE, theService->serviceType)) { 242 // TODO: populate error here 243 return false; 244 } 245 if (!_CFUTF8String(&domain, (char *)domainBuffer, BUFSIZE, theService->domain)) { 246 // TODO: populate error here 247 return false; 248 } 249 250 uint16_t txtLen = 0; 251 const void *txtRecord = NULL; 252 if (theService->txtData != NULL) { 253 txtRecord = CFDataGetBytePtr(theService->txtData); 254 txtLen = CFDataGetLength(theService->txtData); 255 } 256 CFRetain(theService); // retain across registration 257 _CFNetServiceMulticastAquire(); 258 DNSServiceErrorType err = DNSServiceRegister(&theService->service, 0, kDNSServiceInterfaceIndexAny, name, type, domain, NULL, 259 htons(theService->port), txtLen, txtRecord, &_CFNetServiceRegistered, theService); 260 261 return err == kDNSServiceErr_NoError; 262 } 263 264 static void _CFNetServiceResolved(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, 265 const char *fullname, const char *hosttarget, uint16_t port, uint16_t txtLen, 266 const unsigned char *txtRecord, void *context) { 267 CFNetServiceRef theService = (CFNetServiceRef)context; 268 CFRelease(theService); // balance resolve 269 } 270 271 Boolean CFNetServiceResolveWithTimeout(CFNetServiceRef theService, CFTimeInterval timeout, CFStreamError *error) { 272 char nameBuffer[BUFSIZE]; 273 char typeBuffer[BUFSIZE]; 274 char domainBuffer[BUFSIZE]; 275 276 const char *name = NULL; 277 const char *type = NULL; 278 const char *domain = NULL; 279 280 if (!_CFUTF8String(&name, (char *)nameBuffer, BUFSIZE, theService->name)) { 281 // TODO: populate error here 282 return false; 283 } 284 if (!_CFUTF8String(&type, (char *)typeBuffer, BUFSIZE, theService->serviceType)) { 285 // TODO: populate error here 286 return false; 287 } 288 if (!_CFUTF8String(&domain, (char *)domainBuffer, BUFSIZE, theService->domain)) { 289 // TODO: populate error here 290 return false; 291 } 292 293 CFRetain(theService); // retain across resolution 294 _CFNetServiceMulticastAquire(); 295 DNSServiceErrorType err = DNSServiceResolve(&theService->resolver, 0, kDNSServiceInterfaceIndexAny, 296 name, type, domain, &_CFNetServiceResolved, theService); 297 return err == kDNSServiceErr_NoError; 298 } 299 300 void CFNetServiceCancel(CFNetServiceRef theService) { 301 _CFNetServiceMulticastRelinquish(); 302 } 303 304 CFStringRef CFNetServiceGetTargetHost(CFNetServiceRef theService) { 305 return NULL; 306 } 307 308 SInt32 CFNetServiceGetPortNumber(CFNetServiceRef theService) { 309 return -1; 310 } 311 312 CFArrayRef CFNetServiceGetAddressing(CFNetServiceRef theService) { 313 return NULL; 314 } 315 316 CFDataRef CFNetServiceGetTXTData(CFNetServiceRef theService) { 317 return theService->txtData; 318 } 319 320 Boolean CFNetServiceSetTXTData(CFNetServiceRef theService, CFDataRef txtRecord) { 321 return false; 322 } 323 324 CFDictionaryRef CFNetServiceCreateDictionaryWithTXTData(CFAllocatorRef alloc, CFDataRef txtRecord) { 325 return NULL; 326 } 327 328 CFDataRef CFNetServiceCreateTXTDataWithDictionary(CFAllocatorRef alloc, CFDictionaryRef keyValuePairs) { 329 return NULL; 330 } 331 332 Boolean CFNetServiceSetClient(CFNetServiceRef theService, CFNetServiceClientCallBack clientCB, CFNetServiceClientContext *clientContext) { 333 return false; 334 } 335 336 void CFNetServiceScheduleWithRunLoop(CFNetServiceRef theService, CFRunLoopRef runLoop, CFStringRef runLoopMode) { 337 _CFNetServiceMulticastAquire(); 338 } 339 340 void CFNetServiceUnscheduleFromRunLoop(CFNetServiceRef theService, CFRunLoopRef runLoop, CFStringRef runLoopMode) { 341 _CFNetServiceMulticastRelinquish(); 342 } 343 344 CFNetServiceMonitorRef CFNetServiceMonitorCreate(CFAllocatorRef alloc, CFNetServiceRef theService, CFNetServiceMonitorClientCallBack clientCB, CFNetServiceClientContext *clientContext) { 345 return NULL; 346 } 347 348 void CFNetServiceMonitorInvalidate(CFNetServiceMonitorRef monitor) { 349 350 } 351 352 Boolean CFNetServiceMonitorStart(CFNetServiceMonitorRef monitor, CFNetServiceMonitorType recordType, CFStreamError *error) { 353 _CFNetServiceMulticastAquire(); 354 return false; 355 } 356 357 void CFNetServiceMonitorStop(CFNetServiceMonitorRef monitor, CFStreamError *error) { 358 _CFNetServiceMulticastRelinquish(); 359 } 360 361 void CFNetServiceMonitorScheduleWithRunLoop(CFNetServiceMonitorRef monitor, CFRunLoopRef runLoop, CFStringRef runLoopMode) { 362 _CFNetServiceMulticastAquire(); 363 } 364 365 void CFNetServiceMonitorUnscheduleFromRunLoop(CFNetServiceMonitorRef monitor, CFRunLoopRef runLoop, CFStringRef runLoopMode) { 366 _CFNetServiceMulticastRelinquish(); 367 } 368 369 CFNetServiceBrowserRef CFNetServiceBrowserCreate(CFAllocatorRef alloc, CFNetServiceBrowserClientCallBack clientCB, CFNetServiceClientContext *clientContext) { 370 return NULL; 371 } 372 373 void CFNetServiceBrowserInvalidate(CFNetServiceBrowserRef browser) { 374 375 } 376 377 Boolean CFNetServiceBrowserSearchForDomains(CFNetServiceBrowserRef browser, Boolean registrationDomains, CFStreamError *error) { 378 _CFNetServiceMulticastAquire(); 379 return false; 380 } 381 382 Boolean CFNetServiceBrowserSearchForServices(CFNetServiceBrowserRef browser, CFStringRef domain, CFStringRef serviceType, CFStreamError *error) { 383 _CFNetServiceMulticastAquire(); 384 return false; 385 } 386 387 void CFNetServiceBrowserStopSearch(CFNetServiceBrowserRef browser, CFStreamError *error) { 388 _CFNetServiceMulticastRelinquish(); 389 } 390 391 void CFNetServiceBrowserScheduleWithRunLoop(CFNetServiceBrowserRef browser, CFRunLoopRef runLoop, CFStringRef runLoopMode) { 392 _CFNetServiceMulticastAquire(); 393 } 394 395 void CFNetServiceBrowserUnscheduleFromRunLoop(CFNetServiceBrowserRef browser, CFRunLoopRef runLoop, CFStringRef runLoopMode) { 396 _CFNetServiceMulticastRelinquish(); 397 } 398 399 Boolean CFNetServiceRegister(CFNetServiceRef theService, CFStreamError *error) { 400 return false; 401 } 402 403 Boolean CFNetServiceResolve(CFNetServiceRef theService, CFStreamError *error) { 404 return false; 405 } 406 407 CFStringRef CFNetServiceGetProtocolSpecificInformation(CFNetServiceRef theService) { 408 return NULL; 409 } 410 411 void CFNetServiceSetProtocolSpecificInformation(CFNetServiceRef theService, CFStringRef theInfo) { 412 413 }