/***************************************************************************** * CreateBrowser * - * This method returns a NetBrowserInfo that is looking for a type of * service in a domain. If no browser exists, it will create one and return it. *****************************************************************************/ NetBrowserInfo* CreateBrowser(BonjourUserEventsPlugin* plugin, CFStringRef type, CFStringRef domain) { CFIndex i; CFIndex count = CFDictionaryGetCount(plugin->_browsers); NetBrowserInfo* browser = NULL; CFDictionaryRef* dicts = malloc(count * sizeof(CFDictionaryRef)); NetBrowserInfo** browsers = malloc(count * sizeof(NetBrowserInfo*)); // Fetch the values of the browser dictionary CFDictionaryGetKeysAndValues(plugin->_browsers, (const void**)browsers, (const void**)dicts); // Loop thru the browsers list and see if we can find a matching one. for (i = 0; i < count; ++i) { CFDictionaryRef browserDict = dicts[i]; CFStringRef browserType = CFDictionaryGetValue(browserDict, sServiceTypeKey); CFStringRef browserDomain = CFDictionaryGetValue(browserDict, sServiceDomainKey); // If we have a matching browser, break if ((CFStringCompare(browserType, type, kCFCompareCaseInsensitive) == kCFCompareEqualTo) && (CFStringCompare(browserDomain, domain, kCFCompareCaseInsensitive) == kCFCompareEqualTo)) { asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: found a duplicate browser\n", sPluginIdentifier, __FUNCTION__); browser = browsers[i]; NetBrowserInfoRetain(NULL, browser); break; } } // No match found, lets create one! if (!browser) { browser = NetBrowserInfoCreate(type, domain, plugin); if (!browser) { fprintf(stderr, "%s:%s failed to search for %s.%s", sPluginIdentifier, __FUNCTION__, CStringFromCFString(type), CStringFromCFString(domain)); free(dicts); free(browsers); return NULL; } // Service browser created, lets add this to ourselves to the dictionary. CFMutableDictionaryRef browserDict = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(browserDict, sServiceTypeKey, type); CFDictionarySetValue(browserDict, sServiceDomainKey, domain); // Add the dictionary to the browsers dictionary. CFDictionarySetValue(plugin->_browsers, browser, browserDict); NetBrowserInfoRelease(NULL, browser); // Release Memory CFRelease(browserDict); } free(dicts); free(browsers); return browser; }
/***************************************************************************** * AddEventToPlugin * - * This method is invoked when launchd wishes the plugin to setup a launch * event matching the parameters in the dictionary. *****************************************************************************/ void AddEventToPlugin(BonjourUserEventsPlugin* plugin, CFNumberRef launchdToken, CFDictionaryRef eventParameters) { CFStringRef domain = CFDictionaryGetValue(eventParameters, sServiceDomainKey); CFStringRef type = CFDictionaryGetValue(eventParameters, sServiceTypeKey); CFStringRef name = CFDictionaryGetValue(eventParameters, sServiceNameKey); CFBooleanRef cfOnAdd = CFDictionaryGetValue(eventParameters, sOnServiceAddKey); CFBooleanRef cfOnRemove = CFDictionaryGetValue(eventParameters, sOnServiceRemoveKey); CFBooleanRef cfWhileSericeExists = CFDictionaryGetValue(eventParameters, sWhileServiceExistsKey); Boolean onAdd = false; Boolean onRemove = false; Boolean whileExists = false; if (cfOnAdd && CFGetTypeID(cfOnRemove) == CFBooleanGetTypeID() && CFBooleanGetValue(cfOnAdd)) onAdd = true; if (cfOnRemove && CFGetTypeID(cfOnRemove) == CFBooleanGetTypeID() && CFBooleanGetValue(cfOnRemove)) onRemove = true; if (cfWhileSericeExists && CFGetTypeID(cfWhileSericeExists) == CFBooleanGetTypeID() && CFBooleanGetValue(cfWhileSericeExists)) whileExists = true; // A type is required. If none is specified, BAIL if (!type || CFGetTypeID(type) != CFStringGetTypeID()) { fprintf(stderr, "%s, a LaunchEvent is missing a service type.\n", sPluginIdentifier); return; } // If we aren't suppose to launch on services appearing or disappearing, this service does nothing. Ignore. if ((!onAdd && !onRemove && !whileExists) || (onAdd && onRemove && whileExists)) { fprintf(stderr, "%s, a LaunchEvent is missing both onAdd/onRemove/existance or has both.\n", sPluginIdentifier); return; } // If no domain is specified, assume local. if (!domain) { domain = CFSTR("local"); } else if (CFGetTypeID(domain) != CFStringGetTypeID() ) // If the domain is not a string, fai; { fprintf(stderr, "%s, a LaunchEvent has a domain that is not a string.\n", sPluginIdentifier); return; } // If we have a name filter, but it's not a string. This event it broken, bail. if (name && CFGetTypeID(name) != CFStringGetTypeID()) { fprintf(stderr, "%s, a LaunchEvent has a domain that is not a string.\n", sPluginIdentifier); return; } // Get us a browser NetBrowserInfo* browser = CreateBrowserForTypeAndDomain(plugin, type, domain); if (!browser) { fprintf(stderr, "%s, a LaunchEvent has a domain that is not a string.\n", sPluginIdentifier); return; } // Create Event Dictionary CFMutableDictionaryRef eventDictionary = CFDictionaryCreateMutable(NULL, 4, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(eventDictionary, sLaunchdTokenKey, launchdToken); if (name) CFDictionarySetValue(eventDictionary, sServiceNameKey, name); // Add to the correct dictionary. if (onAdd) AddEventDictionary(eventDictionary, plugin->_onAddEvents, browser); if (onRemove) AddEventDictionary(eventDictionary, plugin->_onRemoveEvents, browser); if (whileExists) AddEventDictionary(eventDictionary, plugin->_whileServiceExist, browser); // Add Token Mapping CFDictionarySetValue(plugin->_tokenToBrowserMap, launchdToken, browser); // Release Memory CFRelease(eventDictionary); NetBrowserInfoRelease(NULL, browser); }
/***************************************************************************** * RemoveEventFromPlugin * - * This method is invoked when launchd wishes the plugin to setup a launch * event matching the parameters in the dictionary. *****************************************************************************/ void RemoveEventFromPlugin(BonjourUserEventsPlugin* plugin, CFNumberRef launchdToken) { NetBrowserInfo* browser = (NetBrowserInfo*)CFDictionaryGetValue(plugin->_tokenToBrowserMap, launchdToken); Boolean othersUsingBrowser = false; if (!browser) { long long value = 0; CFNumberGetValue(launchdToken, kCFNumberLongLongType, &value); fprintf(stderr, "%s:%s Launchd asked us to remove a token we did not register! ==Token:%lld== \n", sPluginIdentifier, __FUNCTION__, value); return; } CFMutableArrayRef onAddEvents = (CFMutableArrayRef)CFDictionaryGetValue(plugin->_onAddEvents, browser); CFMutableArrayRef onRemoveEvents = (CFMutableArrayRef)CFDictionaryGetValue(plugin->_onRemoveEvents, browser); if (onAddEvents) { asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: Calling RemoveEventFromArray for OnAddEvents", sPluginIdentifier, __FUNCTION__); RemoveEventFromArray(onAddEvents, launchdToken); // Is the array now empty, clean up if (CFArrayGetCount(onAddEvents) == 0) { asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: Removing the browser from AddEvents", sPluginIdentifier, __FUNCTION__); CFDictionaryRemoveValue(plugin->_onAddEvents, browser); } } if (onRemoveEvents) { asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: Calling RemoveEventFromArray for OnRemoveEvents", sPluginIdentifier, __FUNCTION__); RemoveEventFromArray(onRemoveEvents, launchdToken); // Is the array now empty, clean up if (CFArrayGetCount(onRemoveEvents) == 0) { asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: Removing the browser from RemoveEvents", sPluginIdentifier, __FUNCTION__); CFDictionaryRemoveValue(plugin->_onRemoveEvents, browser); } } // Remove ourselves from the token dictionary. CFDictionaryRemoveValue(plugin->_tokenToBrowserMap, launchdToken); // Check to see if anyone else is using this browser. CFIndex i; CFIndex count = CFDictionaryGetCount(plugin->_tokenToBrowserMap); NetBrowserInfo** browsers = malloc(count * sizeof(NetBrowserInfo*)); // Fetch the values of the token dictionary CFDictionaryGetKeysAndValues(plugin->_tokenToBrowserMap, NULL, (const void**)browsers); for (i = 0; i < count; ++i) { if (NetBrowserInfoEqual(browsers[i], browser)) { othersUsingBrowser = true; break; } } // If no one else is useing our browser, clean up! if (!othersUsingBrowser) { asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: Removing browser %p from _browsers", sPluginIdentifier, __FUNCTION__, browser); CFDictionaryRemoveValue(plugin->_browsers, browser); // This triggers release and dealloc of the browser } else { asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: Decrementing browsers %p count", sPluginIdentifier, __FUNCTION__, browser); // Decrement my reference count (it was incremented when it was added to _browsers in CreateBrowser) NetBrowserInfoRelease(NULL, browser); } free(browsers); }