/ src / CFNetServices.c
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  }