int CPhidgetDetachEvent(CPhidgetHandle phid) { int result = 0; CPhidgetList *trav = 0; CPhidgetManagerList *trav2 = 0; CPhidgetHandle travPhid = 0; TESTPTR(phid) CPhidget_clearStatusFlag(&phid->status, PHIDGET_ATTACHED_FLAG, NULL); CPhidget_setStatusFlag(&phid->status, PHIDGET_DETACHING_FLAG, NULL); CList_removeFromList((CListHandle *)&AttachedDevices, phid, CPhidget_areExtraEqual, FALSE, NULL); for(trav2 = localPhidgetManagers; trav2; trav2 = trav2->next) { if (trav2->phidm->fptrDetachChange && trav2->phidm->state == PHIDGETMANAGER_ACTIVE) { //So we can access AttachedDevices from within the manager atach event CThread_mutex_unlock(&attachedDevicesLock); trav2->phidm->fptrDetachChange((CPhidgetHandle)phid, trav2->phidm->fptrDetachChangeptr); CThread_mutex_lock(&attachedDevicesLock); } } CPhidget_clearStatusFlag(&phid->status, PHIDGET_DETACHING_FLAG, NULL); CThread_mutex_lock(&activeDevicesLock); for (trav=ActiveDevices; trav; trav = trav->next) { if((CPhidget_areExtraEqual(phid, trav->phid) && CPhidget_statusFlagIsSet(trav->phid->status, PHIDGET_ATTACHED_FLAG)) || CPhidgetHandle_areEqual(phid, trav->phid)) { CPhidget_setStatusFlag(&trav->phid->status, PHIDGET_DETACHING_FLAG, &trav->phid->lock); if(trav->phid->specificDevice == PHIDGETOPEN_ANY_ATTACHED) trav->phid->specificDevice = PHIDGETOPEN_ANY; trav->phid->writeStopFlag = PTRUE; CThread_set_event(&trav->phid->writeAvailableEvent); //if it's waiting on this event - signal NOW result = CUSBCloseHandle(trav->phid); CThread_join(&trav->phid->writeThread); CThread_join(&trav->phid->readThread); //because trav can be freed during the detach call, don't use it in or after the call travPhid = trav->phid; CThread_mutex_unlock(&activeDevicesLock); if (travPhid->fptrDetach) travPhid->fptrDetach((CPhidgetHandle)travPhid, travPhid->fptrDetachptr); travPhid->deviceIDSpec = 0; travPhid->deviceUID = 0; #if !defined(_MACOSX) && !defined(WINCE) CPhidgetFHandle_free(travPhid->CPhidgetFHandle); travPhid->CPhidgetFHandle = NULL; #endif CPhidget_clearStatusFlag(&travPhid->status, PHIDGET_DETACHING_FLAG, &travPhid->lock); CPhidget_clearStatusFlag(&travPhid->status, PHIDGET_USB_ERROR_FLAG, &travPhid->lock); goto found_to_detach; } } CThread_mutex_unlock(&activeDevicesLock); found_to_detach: CPhidget_free(phid); return result; }
int CPhidgetManager_poll() { CPhidgetList *curList = 0, *detachList = 0; CPhidgetList *trav = 0, *trav2 = 0; CPhidgetHandle foundPhidget; if(!managerLockInitialized) { CThread_mutex_init(&managerLock); managerLockInitialized = PTRUE; } CThread_mutex_lock(&managerLock); CThread_mutex_lock(&attachedDevicesLock); sendInitialEvents(); CUSBBuildList(&curList); for (trav=AttachedDevices; trav; trav = trav->next) { if(CList_findInList((CListHandle)curList, trav->phid, CPhidget_areExtraEqual, NULL) == EPHIDGET_NOTFOUND) { CList_addToList((CListHandle *)&detachList, trav->phid, CPhidget_areEqual); } } for (trav=curList; trav; trav = trav->next) { if(CList_findInList((CListHandle)AttachedDevices, trav->phid, CPhidget_areExtraEqual, NULL) == EPHIDGET_NOTFOUND) { CPhidgetAttachEvent(trav->phid); } //if PHIDGET_USB_ERROR_FLAG is set, cycle device through a detach //if it's ok, it will re-attach CThread_mutex_lock(&activeDevicesLock); if(CList_findInList((CListHandle)ActiveDevices, trav->phid, CPhidget_areEqual, (void **)&foundPhidget) == EPHIDGET_OK) { if(CPhidget_statusFlagIsSet(foundPhidget->status, PHIDGET_ATTACHED_FLAG) && CPhidget_statusFlagIsSet(foundPhidget->status, PHIDGET_USB_ERROR_FLAG)) { LOG(PHIDGET_LOG_WARNING,"PHIDGET_USB_ERROR_FLAG is set - cycling device through a detach"); CList_addToList((CListHandle *)&detachList, trav->phid, CPhidget_areEqual); //if this is a composite device, we must find it's pair and detach that as well. //same serial, but different interface num for (trav2=curList; trav2; trav2 = trav2->next) { if(trav->phid->serialNumber == trav2->phid->serialNumber && trav->phid->deviceDef->pdd_iid != trav2->phid->deviceDef->pdd_iid) { LOG(PHIDGET_LOG_WARNING,"PHIDGET_USB_ERROR_FLAG is set - cycling composite device 2nd interface through a detach"); CList_addToList((CListHandle *)&detachList, trav2->phid, CPhidget_areEqual); } } } } CThread_mutex_unlock(&activeDevicesLock); } for (trav=detachList; trav; trav = trav->next) { CPhidgetDetachEvent(trav->phid); } CList_emptyList((CListHandle *)&detachList, FALSE, NULL); CList_emptyList((CListHandle *)&curList, FALSE, NULL); CThread_mutex_unlock(&attachedDevicesLock); CThread_mutex_unlock(&managerLock); return EPHIDGET_OK; }
int CCONV CPhidgetManager_getAttachedDevices(CPhidgetManagerHandle phidm, CPhidgetHandle *phidArray[], int *count) { CPhidgetList *trav = 0; int i = 0; TESTPTRS(phidArray, count) TESTPTR(phidm) *count = 0; if(CPhidget_statusFlagIsSet(phidm->status, PHIDGET_REMOTE_FLAG)) { for (trav=phidm->AttachedPhidgets; trav; trav = trav->next) { if (CPhidget_statusFlagIsSet(trav->phid->status, PHIDGET_ATTACHED_FLAG)) (*count)++; } if(*count==0) { *phidArray = NULL; } else { *phidArray = (CPhidgetHandle *)malloc(sizeof(**phidArray) * *count); if (!*phidArray) return EPHIDGET_NOMEMORY; ZEROMEM(*phidArray, sizeof(**phidArray) * *count); for (trav=phidm->AttachedPhidgets, i=0; trav; trav = trav->next) { if (CPhidget_statusFlagIsSet(trav->phid->status, PHIDGET_ATTACHED_FLAG)) { (*phidArray)[i] = trav->phid; i++; } } } } else { CThread_mutex_lock(&attachedDevicesLock); for (trav=AttachedDevices; trav; trav = trav->next) { if (CPhidget_statusFlagIsSet(trav->phid->status, PHIDGET_ATTACHED_FLAG)) (*count)++; } if(*count==0) { *phidArray = NULL; } else { *phidArray = (CPhidgetHandle *)malloc(sizeof(**phidArray) * *count); if (!*phidArray) { CThread_mutex_unlock(&attachedDevicesLock); return EPHIDGET_NOMEMORY; } ZEROMEM(*phidArray, sizeof(**phidArray) * *count); for (trav=AttachedDevices, i=0; trav; trav = trav->next) { if (CPhidget_statusFlagIsSet(trav->phid->status, PHIDGET_ATTACHED_FLAG)) { (*phidArray)[i] = trav->phid; i++; } } } CThread_mutex_unlock(&attachedDevicesLock); } return EPHIDGET_OK; }
void DNSServiceBrowse_sbc_CallBack(DNSServiceRef service, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char * name, const char * type, const char * domain, void * context) { if (errorCode != kDNSServiceErr_NoError) LOG(PHIDGET_LOG_ERROR, "Dns_sbc_BrowseCallBack returned error: %d\n", errorCode); else { DNSServiceErrorType error; DNSServiceRef serviceRef; char fullname[kDNSServiceMaxDomainName]; CPhidgetSBCHandle sbc; CPhidgetSBCHandle found_sbc; CPhidgetSBCManagerList *trav; DNSServiceConstructFullNamePtr(fullname, name, type, domain); if((CPhidgetSBC_create(&sbc))) return; if((CPhidgetRemote_create(&sbc->networkInfo))) return; sbc->networkInfo->zeroconf_name = strdup(name); sbc->networkInfo->zeroconf_type = strdup(type); sbc->networkInfo->zeroconf_domain = strdup(domain); sbc->networkInfo->mdns = PTRUE; strncpy(sbc->mac, name+12, 18); //name == 'PhidgetSBC (??:??:??:??:??:??)' sbc->mac[17] = '\0'; if(flags & kDNSServiceFlagsAdd) { LOG(PHIDGET_LOG_INFO, "DNSServiceBrowse_sbc_CallBack (Add): %s",name); error = DNSServiceQueryRecordPtr(&serviceRef, 0, interfaceIndex, fullname, kDNSServiceType_TXT, kDNSServiceClass_IN, DNSServiceQueryRecord_SBC_CallBack, sbc); if (error == kDNSServiceErr_NoError) { DNSServiceProcessResultPtr(serviceRef); DNSServiceRefDeallocatePtr(serviceRef); CThread_mutex_lock(&zeroconfSBCsLock); CThread_mutex_lock(&activeSBCManagersLock); //Check if it's in the list and if it's different, remove it to make way for the new one // (Sometimes, we don't get a proper detach notification) if(CList_findInList((CListHandle)zeroconfSBCs, sbc, CPhidgetSBC_areEqual, (void **)&found_sbc) == EPHIDGET_OK) { if(CPhidgetSBC_areExtraEqual(found_sbc, sbc) != PTRUE) //A version number has changed { //make sure zeroconf_ref is not pending if(found_sbc->networkInfo) { CThread_mutex_lock(&found_sbc->networkInfo->zeroconf_ref_lock); if(found_sbc->networkInfo->zeroconf_ref) { DNSServiceRefDeallocatePtr((DNSServiceRef)found_sbc->networkInfo->zeroconf_ref); found_sbc->networkInfo->zeroconf_ref = NULL; } CThread_mutex_unlock(&found_sbc->networkInfo->zeroconf_ref_lock); } //Remove from list - don't free until after detach event CList_removeFromList((CListHandle *)&zeroconfSBCs, found_sbc, CPhidgetSBC_areEqual, PFALSE, NULL); for (trav=activeSBCManagers; trav; trav = trav->next) { if (trav->sbcm->fptrDetachChange && trav->sbcm->state == PHIDGETMANAGER_ACTIVE) trav->sbcm->fptrDetachChange((CPhidgetSBCHandle)found_sbc, trav->sbcm->fptrDetachChangeptr); } CPhidgetSBC_free(found_sbc); //now we fall through and add back to new one } else //Nothing has changed, we didn't remove, don't add { CPhidgetSBC_free(sbc); goto dontadd; } } //now add it CList_addToList((CListHandle *)&zeroconfSBCs, sbc, CPhidgetSBC_areEqual); //send out events for (trav=activeSBCManagers; trav; trav = trav->next) { if (trav->sbcm->fptrAttachChange && trav->sbcm->state == PHIDGETMANAGER_ACTIVE) trav->sbcm->fptrAttachChange((CPhidgetSBCHandle)sbc, trav->sbcm->fptrAttachChangeptr); } dontadd: CThread_mutex_unlock(&activeSBCManagersLock); CThread_mutex_unlock(&zeroconfSBCsLock); } else LOG(PHIDGET_LOG_ERROR, "DNSServiceQueryRecordPtr returned error: %d\n", error); } else { LOG(PHIDGET_LOG_INFO, "DNSServiceBrowse_sbc_CallBack (Remove): %s",name); CThread_mutex_lock(&zeroconfSBCsLock); CThread_mutex_lock(&activeSBCManagersLock); //make sure zeroconf_ref is not pending if(sbc->networkInfo) { CThread_mutex_lock(&sbc->networkInfo->zeroconf_ref_lock); if(sbc->networkInfo->zeroconf_ref) { DNSServiceRefDeallocatePtr((DNSServiceRef)sbc->networkInfo->zeroconf_ref); sbc->networkInfo->zeroconf_ref = NULL; } CThread_mutex_unlock(&sbc->networkInfo->zeroconf_ref_lock); } if(CList_findInList((CListHandle)zeroconfSBCs, sbc, CPhidgetSBC_areEqual, (void **)&found_sbc) == EPHIDGET_OK) { CList_removeFromList((CListHandle *)&zeroconfSBCs, found_sbc, CPhidgetSBC_areEqual, PFALSE, NULL); //managers for (trav=activeSBCManagers; trav; trav = trav->next) { if (trav->sbcm->fptrDetachChange && trav->sbcm->state == PHIDGETMANAGER_ACTIVE) trav->sbcm->fptrDetachChange((CPhidgetSBCHandle)found_sbc, trav->sbcm->fptrDetachChangeptr); } CPhidgetSBC_free(found_sbc); } CThread_mutex_unlock(&activeSBCManagersLock); CThread_mutex_unlock(&zeroconfSBCsLock); CPhidgetSBC_free(sbc); } } }
int InitializeZeroconf() { DNSServiceErrorType error; CThread_mutex_lock(&zeroconfInitLock); if(!Dns_sdInitialized) { #ifdef ZEROCONF_RUNTIME_LINKING #ifdef _WINDOWS if(!(dllHandle = LoadLibrary(L"dnssd.dll"))) { DWORD error = GetLastError(); switch(error) { case ERROR_MOD_NOT_FOUND: LOG(PHIDGET_LOG_DEBUG,"LoadLibrary failed - module could not be found"); break; default: LOG(PHIDGET_LOG_DEBUG,"LoadLibrary failed with error code: %d", error); } CThread_mutex_unlock(&zeroconfInitLock); return EPHIDGET_UNEXPECTED; } // If the handle is valid, try to get the function address. if (NULL != dllHandle) { //Get pointers to our functions using GetProcAddress: #ifdef WINCE DNSServiceRegisterPtr = (DNSServiceRegisterType)GetProcAddress(dllHandle, L"DNSServiceRegister"); DNSServiceProcessResultPtr = (DNSServiceProcessResultType)GetProcAddress(dllHandle, L"DNSServiceProcessResult"); DNSServiceRefDeallocatePtr = (DNSServiceRefDeallocateType)GetProcAddress(dllHandle, L"DNSServiceRefDeallocate"); DNSServiceAddRecordPtr = (DNSServiceAddRecordType)GetProcAddress(dllHandle, L"DNSServiceAddRecord"); DNSServiceUpdateRecordPtr = (DNSServiceUpdateRecordType)GetProcAddress(dllHandle, L"DNSServiceUpdateRecord"); DNSServiceRemoveRecordPtr = (DNSServiceRemoveRecordType)GetProcAddress(dllHandle, L"DNSServiceRemoveRecord"); DNSServiceBrowsePtr = (DNSServiceBrowseType)GetProcAddress(dllHandle, L"DNSServiceBrowse"); DNSServiceResolvePtr = (DNSServiceResolveType)GetProcAddress(dllHandle, L"DNSServiceResolve"); DNSServiceQueryRecordPtr = (DNSServiceQueryRecordType)GetProcAddress(dllHandle, L"DNSServiceQueryRecord"); DNSServiceConstructFullNamePtr = (DNSServiceConstructFullNameType)GetProcAddress(dllHandle, L"DNSServiceConstructFullName"); DNSServiceRefSockFDPtr = (DNSServiceRefSockFDType)GetProcAddress(dllHandle, L"DNSServiceRefSockFD"); #else DNSServiceRegisterPtr = (DNSServiceRegisterType)GetProcAddress(dllHandle, "DNSServiceRegister"); DNSServiceProcessResultPtr = (DNSServiceProcessResultType)GetProcAddress(dllHandle, "DNSServiceProcessResult"); DNSServiceRefDeallocatePtr = (DNSServiceRefDeallocateType)GetProcAddress(dllHandle, "DNSServiceRefDeallocate"); DNSServiceAddRecordPtr = (DNSServiceAddRecordType)GetProcAddress(dllHandle, "DNSServiceAddRecord"); DNSServiceUpdateRecordPtr = (DNSServiceUpdateRecordType)GetProcAddress(dllHandle, "DNSServiceUpdateRecord"); DNSServiceRemoveRecordPtr = (DNSServiceRemoveRecordType)GetProcAddress(dllHandle, "DNSServiceRemoveRecord"); DNSServiceBrowsePtr = (DNSServiceBrowseType)GetProcAddress(dllHandle, "DNSServiceBrowse"); DNSServiceResolvePtr = (DNSServiceResolveType)GetProcAddress(dllHandle, "DNSServiceResolve"); DNSServiceQueryRecordPtr = (DNSServiceQueryRecordType)GetProcAddress(dllHandle, "DNSServiceQueryRecord"); DNSServiceConstructFullNamePtr = (DNSServiceConstructFullNameType)GetProcAddress(dllHandle, "DNSServiceConstructFullName"); DNSServiceRefSockFDPtr = (DNSServiceRefSockFDType)GetProcAddress(dllHandle, "DNSServiceRefSockFD"); #endif Dns_sdInitialized = ( NULL != DNSServiceRegisterPtr && NULL != DNSServiceProcessResultPtr && NULL != DNSServiceRefDeallocatePtr && NULL != DNSServiceAddRecordPtr && NULL != DNSServiceUpdateRecordPtr && NULL != DNSServiceRemoveRecordPtr && NULL != DNSServiceQueryRecordPtr && NULL != DNSServiceConstructFullNamePtr && NULL != DNSServiceRefSockFDPtr); } if(!Dns_sdInitialized) { LOG(PHIDGET_LOG_DEBUG,"InitializeZeroconf failed somehow..."); CThread_mutex_unlock(&zeroconfInitLock); return EPHIDGET_UNSUPPORTED; } #elif _LINUX libHandle = dlopen("libdns_sd.so",RTLD_LAZY); if(!libHandle) { LOG(PHIDGET_LOG_WARNING, "dlopen failed with error: %s", dlerror()); LOG(PHIDGET_LOG_WARNING, "Assuming that zeroconf is not supported on this machine."); CThread_mutex_unlock(&zeroconfInitLock); return EPHIDGET_UNSUPPORTED; } //Get pointers to our functions using dlsym: if(!(DNSServiceRegisterPtr = (DNSServiceRegisterType)dlsym(libHandle, "DNSServiceRegister"))) goto dlsym_err; if(!(DNSServiceProcessResultPtr = (DNSServiceProcessResultType)dlsym(libHandle, "DNSServiceProcessResult"))) goto dlsym_err; if(!(DNSServiceRefDeallocatePtr = (DNSServiceRefDeallocateType)dlsym(libHandle, "DNSServiceRefDeallocate"))) goto dlsym_err; if(!(DNSServiceAddRecordPtr = (DNSServiceAddRecordType)dlsym(libHandle, "DNSServiceAddRecord"))) goto dlsym_err; if(!(DNSServiceUpdateRecordPtr = (DNSServiceUpdateRecordType)dlsym(libHandle, "DNSServiceUpdateRecord"))) goto dlsym_err; if(!(DNSServiceRemoveRecordPtr = (DNSServiceRemoveRecordType)dlsym(libHandle, "DNSServiceRemoveRecord"))) goto dlsym_err; if(!(DNSServiceBrowsePtr = (DNSServiceBrowseType)dlsym(libHandle, "DNSServiceBrowse"))) goto dlsym_err; if(!(DNSServiceResolvePtr = (DNSServiceResolveType)dlsym(libHandle, "DNSServiceResolve"))) goto dlsym_err; if(!(DNSServiceQueryRecordPtr = (DNSServiceQueryRecordType)dlsym(libHandle, "DNSServiceQueryRecord"))) goto dlsym_err; if(!(DNSServiceConstructFullNamePtr = (DNSServiceConstructFullNameType)dlsym(libHandle, "DNSServiceConstructFullName"))) goto dlsym_err; if(!(DNSServiceRefSockFDPtr = (DNSServiceRefSockFDType)dlsym(libHandle, "DNSServiceRefSockFD"))) goto dlsym_err; goto dlsym_good; dlsym_err: LOG(PHIDGET_LOG_WARNING, "dlsym failed with error: %s", dlerror()); LOG(PHIDGET_LOG_WARNING, "Assuming that zeroconf is not supported on this machine."); CThread_mutex_unlock(&zeroconfInitLock); return EPHIDGET_UNSUPPORTED; dlsym_good: Dns_sdInitialized = TRUE; #endif #else Dns_sdInitialized = TRUE; #endif LOG(PHIDGET_LOG_DEBUG,"InitializeZeroconf - System supports zeroconf."); } if(!Dns_sdBrowsing) { error = DNSServiceBrowsePtr(&zeroconf_browse_ws_ref, 0, // no flags 0, // all network interfaces "_phidget_ws._tcp", // service type "", // default domains DNSServiceBrowse_ws_CallBack, // call back function NULL); // no context if (error != kDNSServiceErr_NoError) { LOG(PHIDGET_LOG_ERROR,"DNSServiceBrowse on _phidget_ws._tcp failed: %d", error); CThread_mutex_unlock(&zeroconfInitLock); return EPHIDGET_TRYAGAIN; } error = DNSServiceBrowsePtr(&zeroconf_browse_sbc_ref, 0, // no flags 0, // all network interfaces "_phidget_sbc._tcp", // service type "", // default domains DNSServiceBrowse_sbc_CallBack, // call back function NULL); // no context if (error != kDNSServiceErr_NoError) { LOG(PHIDGET_LOG_ERROR,"DNSServiceBrowse on _phidget_sbc._tcp failed: %d", error); CThread_mutex_unlock(&zeroconfInitLock); return EPHIDGET_TRYAGAIN; } error = DNSServiceBrowsePtr(&zeroconf_browse_phidget_ref, 0, // no flags 0, // all network interfaces "_phidget._tcp", // service type "", // default domains DNSServiceBrowse_Phidget_CallBack, // call back function NULL); // no context if (error != kDNSServiceErr_NoError) { LOG(PHIDGET_LOG_ERROR,"DNSServiceBrowse on _phidget._tcp failed: %d", error); CThread_mutex_unlock(&zeroconfInitLock); return EPHIDGET_TRYAGAIN; } stopBrowsing = FALSE; pthread_create(&dns_thread, NULL, (void *(*)(void *))dns_callback_thread,NULL); Dns_sdBrowsing = PTRUE; LOG(PHIDGET_LOG_DEBUG,"InitializeZeroconf - Zeroconf browsing active."); } CThread_mutex_unlock(&zeroconfInitLock); return EPHIDGET_OK; }
void DNSServiceBrowse_ws_CallBack( AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, void* userdata) { switch (event) { case AVAHI_BROWSER_FAILURE: LOG(PHIDGET_LOG_ERROR, "(Browser) %s", avahi_strerror_ptr(avahi_client_errno_ptr(client))); //avahi_threaded_poll_quit_ptr(threaded_poll); return; case AVAHI_BROWSER_NEW: { CPhidgetRemoteHandle networkInfo; if((CPhidgetRemote_create(&networkInfo))) return; networkInfo->zeroconf_name = strdup(name); networkInfo->zeroconf_server_id = strdup(name); networkInfo->zeroconf_type = strdup(type); networkInfo->zeroconf_domain = strdup(domain); LOG(PHIDGET_LOG_INFO, "(Browser) NEW: service '%s' of type '%s' in domain '%s'", name, type, domain); CThread_mutex_lock(&zeroconfServersLock); CList_addToList((CListHandle *)&zeroconfServers, networkInfo, CPhidgetRemote_areEqual); CThread_mutex_unlock(&zeroconfServersLock); } break; case AVAHI_BROWSER_REMOVE: { CPhidgetRemoteHandle networkInfo; if((CPhidgetRemote_create(&networkInfo))) return; networkInfo->zeroconf_name = strdup(name); networkInfo->zeroconf_server_id = strdup(name); networkInfo->zeroconf_type = strdup(type); networkInfo->zeroconf_domain = strdup(domain); LOG(PHIDGET_LOG_INFO, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'", name, type, domain); CThread_mutex_lock(&zeroconfServersLock); CList_removeFromList((CListHandle *)&zeroconfServers, networkInfo, CPhidgetRemote_areEqual, TRUE, CPhidgetRemote_free); CThread_mutex_unlock(&zeroconfServersLock); } break; case AVAHI_BROWSER_ALL_FOR_NOW: case AVAHI_BROWSER_CACHE_EXHAUSTED: LOG(PHIDGET_LOG_INFO, "(Browser) %s", event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW"); break; } }
void DNSServiceBrowse_Phidget_CallBack(DNSServiceRef service, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char * name, const char * type, const char * domain, void * context) { if (errorCode != kDNSServiceErr_NoError) LOG(PHIDGET_LOG_ERROR, "Dns_sd_BrowseCallBack returned error: %d\n", errorCode); else { DNSServiceErrorType error; DNSServiceRef serviceRef; char fullname[kDNSServiceMaxDomainName]; CPhidgetHandle phid; CPhidgetHandle found_phid; CPhidgetManagerList *trav; DNSServiceConstructFullNamePtr(fullname, name, type, domain); LOG(PHIDGET_LOG_INFO, "DNSServiceBrowse_Phidget_CallBack: %s",name); if((CPhidget_create(&phid))) return; if((CPhidgetRemote_create(&phid->networkInfo))) return; phid->networkInfo->zeroconf_name = strdup(name); phid->networkInfo->zeroconf_type = strdup(type); phid->networkInfo->zeroconf_domain = strdup(domain); if(flags & kDNSServiceFlagsAdd) { error = DNSServiceQueryRecordPtr(&serviceRef, 0, interfaceIndex, fullname, kDNSServiceType_TXT, kDNSServiceClass_IN, DNSServiceQueryRecord_Phidget_CallBack, phid); if (error == kDNSServiceErr_NoError) { DNSServiceProcessResultPtr(serviceRef); DNSServiceRefDeallocatePtr(serviceRef); CThread_mutex_lock(&zeroconfPhidgetsLock); CThread_mutex_lock(&activeRemoteManagersLock); CPhidget_setStatusFlag(&phid->status, PHIDGET_ATTACHED_FLAG, &phid->lock); CPhidget_setStatusFlag(&phid->status, PHIDGET_REMOTE_FLAG, &phid->lock); if(CList_findInList((CListHandle)zeroconfPhidgets, phid, CPhidget_areExtraEqual, (void **)&found_phid) == EPHIDGET_OK) { //Only do a detach/attach cycle if something's different if(found_phid->serialNumber == phid->serialNumber && found_phid->deviceVersion == phid->deviceVersion && !strcmp(found_phid->label, phid->label) && !strcmp(found_phid->networkInfo->zeroconf_server_id, phid->networkInfo->zeroconf_server_id)) { CPhidgetRemote_free(phid->networkInfo); CPhidget_free(phid); CThread_mutex_unlock(&activeRemoteManagersLock); CThread_mutex_unlock(&zeroconfPhidgetsLock); return; } //set detaching status CPhidget_clearStatusFlag(&found_phid->status, PHIDGET_ATTACHED_FLAG, &found_phid->lock); CPhidget_setStatusFlag(&found_phid->status, PHIDGET_DETACHING_FLAG, &found_phid->lock); //Remove from list - don't free until after detach event CList_removeFromList((CListHandle *)&zeroconfPhidgets, found_phid, CPhidget_areExtraEqual, FALSE, NULL); for (trav=activeRemoteManagers; trav; trav = trav->next) { if(trav->phidm->networkInfo->requested_address==NULL && (trav->phidm->networkInfo->requested_serverID == NULL || !strcmp(trav->phidm->networkInfo->requested_serverID,found_phid->networkInfo->zeroconf_server_id))) { CList_removeFromList((CListHandle *)&trav->phidm->AttachedPhidgets, found_phid, CPhidget_areExtraEqual, PFALSE, NULL); if (trav->phidm->fptrDetachChange && trav->phidm->state == PHIDGETMANAGER_ACTIVE) trav->phidm->fptrDetachChange((CPhidgetHandle)found_phid, trav->phidm->fptrDetachChangeptr); } } CPhidgetRemote_free(found_phid->networkInfo); CPhidget_free(found_phid); } CPhidget_setStatusFlag(&phid->status, PHIDGET_SERVER_CONNECTED_FLAG, &phid->lock); //now add it CList_addToList((CListHandle *)&zeroconfPhidgets, phid, CPhidget_areExtraEqual); //managers for (trav=activeRemoteManagers; trav; trav = trav->next) { if(trav->phidm->networkInfo->requested_address==NULL && (trav->phidm->networkInfo->requested_serverID == NULL || !strcmp(trav->phidm->networkInfo->requested_serverID,phid->networkInfo->zeroconf_server_id))) { CList_addToList((CListHandle *)&trav->phidm->AttachedPhidgets, phid, CPhidget_areExtraEqual); if (trav->phidm->fptrAttachChange && trav->phidm->state == PHIDGETMANAGER_ACTIVE) trav->phidm->fptrAttachChange((CPhidgetHandle)phid, trav->phidm->fptrAttachChangeptr); } } CThread_mutex_unlock(&activeRemoteManagersLock); CThread_mutex_unlock(&zeroconfPhidgetsLock); } else LOG(PHIDGET_LOG_ERROR, "DNSServiceQueryRecordPtr returned error: %d\n", error); } else { //have to fill in phid manually from just the name int i; char *name_copy = strdup(name); for(i=0;i<(int)strlen(name_copy);i++) if(name_copy[i] == '(') break; if(i<=1) return; name_copy[strlen(name_copy)-1]='\0'; name_copy[i-1] = '\0'; phid->serialNumber = strtol(name_copy+i+1, NULL, 10); //we need to set this so it checks the serial numbers for a match phid->specificDevice = PHIDGETOPEN_SERIAL; for(i = 0;i<PHIDGET_DEVICE_COUNT;i++) if(!strcmp(name_copy, Phid_Device_Def[i].pdd_name)) break; phid->deviceDef = &Phid_Device_Def[i]; //phid->deviceIDSpec = Phid_Device_Def[i].pdd_sdid; phid->deviceIDSpec = 0; //Needs to be 0 because the name can be ambiguous (ie 1018/1200) - we will still match on serial/device class, which is enough for uniqueness phid->attr = Phid_Device_Def[i].pdd_attr; phid->deviceID = Phid_Device_Def[i].pdd_did; phid->deviceType = Phid_DeviceName[phid->deviceID]; phid->networkInfo->mdns = PTRUE; CThread_mutex_lock(&zeroconfPhidgetsLock); CThread_mutex_lock(&activeRemoteManagersLock); CPhidget_clearStatusFlag(&phid->status, PHIDGET_ATTACHED_FLAG, &phid->lock); CPhidget_setStatusFlag(&phid->status, PHIDGET_DETACHING_FLAG, &phid->lock); if(!CList_findInList((CListHandle)zeroconfPhidgets, phid, CPhidget_areEqual, (void **)&found_phid)) { CPhidget_clearStatusFlag(&found_phid->status, PHIDGET_ATTACHED_FLAG, &found_phid->lock); CPhidget_setStatusFlag(&found_phid->status, PHIDGET_DETACHING_FLAG, &found_phid->lock); CPhidget_setStatusFlag(&found_phid->status, PHIDGET_REMOTE_FLAG, &found_phid->lock); CPhidget_clearStatusFlag(&found_phid->status, PHIDGET_SERVER_CONNECTED_FLAG, &found_phid->lock); CList_removeFromList((CListHandle *)&zeroconfPhidgets, found_phid, CPhidget_areExtraEqual, FALSE, NULL); //managers for (trav=activeRemoteManagers; trav; trav = trav->next) { if(trav->phidm->networkInfo->requested_address==NULL && (trav->phidm->networkInfo->requested_serverID == NULL || !strcmp(trav->phidm->networkInfo->requested_serverID,found_phid->networkInfo->zeroconf_server_id))) { CList_removeFromList((CListHandle *)&trav->phidm->AttachedPhidgets, found_phid, CPhidget_areExtraEqual, PFALSE, NULL); if (trav->phidm->fptrDetachChange && trav->phidm->state == PHIDGETMANAGER_ACTIVE) trav->phidm->fptrDetachChange((CPhidgetHandle)found_phid, trav->phidm->fptrDetachChangeptr); } } CPhidget_clearStatusFlag(&found_phid->status, PHIDGET_DETACHING_FLAG, &found_phid->lock); CPhidgetRemote_free(found_phid->networkInfo); CPhidget_free(found_phid); } CPhidgetRemote_free(phid->networkInfo); CPhidget_free(phid); CThread_mutex_unlock(&activeRemoteManagersLock); CThread_mutex_unlock(&zeroconfPhidgetsLock); free(name_copy); } } }
void DNSServiceBrowse_Phidget_CallBack( AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, void* userdata) { CPhidgetHandle phid; CPhidgetManagerList *trav; switch (event) { case AVAHI_BROWSER_FAILURE: LOG(PHIDGET_LOG_WARNING, "(Browser) %s", avahi_strerror_ptr(avahi_client_errno_ptr(client))); avahi_threaded_poll_quit_ptr(threaded_poll); return; case AVAHI_BROWSER_NEW: { char fullname[AVAHI_DOMAIN_NAME_MAX]; if((CPhidget_create(&phid))) return; if((CPhidgetRemote_create(&phid->networkInfo))) return; phid->networkInfo->zeroconf_name = strdup(name); phid->networkInfo->zeroconf_type = strdup(type); phid->networkInfo->zeroconf_domain = strdup(domain); LOG(PHIDGET_LOG_INFO, "(Browser) NEW: service '%s' of type '%s' in domain '%s'", name, type, domain); if(!(avahi_service_name_join_ptr(fullname, AVAHI_DOMAIN_NAME_MAX, name, type, domain))) LOG(PHIDGET_LOG_ERROR, "Failed avahi_service_name_join_ptr '%s': %s", name, avahi_strerror_ptr(avahi_client_errno_ptr(client))); if(!(avahi_record_browser_new_ptr(client, interface, protocol, fullname, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_TXT, 0, DNSServiceQueryRecord_Phidget_CallBack, phid))) LOG(PHIDGET_LOG_ERROR, "Failed to resolve service '%s': %s", name, avahi_strerror_ptr(avahi_client_errno_ptr(client))); //gets added to list in callback } break; case AVAHI_BROWSER_REMOVE: { if((CPhidget_create(&phid))) return; if((CPhidgetRemote_create(&phid->networkInfo))) return; phid->networkInfo->zeroconf_name = strdup(name); phid->networkInfo->zeroconf_type = strdup(type); phid->networkInfo->zeroconf_domain = strdup(domain); LOG(PHIDGET_LOG_INFO, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'", name, type, domain); //have to fill in phid manually from just the name int i; char *name_copy = strdup(name); for(i=0;i<strlen(name_copy);i++) if(name_copy[i] == '(') break; if(i<=1) return; name_copy[strlen(name_copy)-1]='\0'; name_copy[i-1] = '\0'; phid->serialNumber = strtol(name_copy+i+1, NULL, 10); phid->specificDevice = PTRUE; for(i = 0;i<PHIDGET_DEVICE_COUNT;i++) if(!strcmp(name_copy, Phid_DeviceSpecificName[i])) break; phid->deviceIDSpec = i; phid->attr = Phid_Device_Def[i].pdd_attr; phid->deviceID = Phid_Device_Def[i].pdd_did; phid->deviceType = Phid_DeviceName[phid->deviceID]; phid->networkInfo->mdns = PTRUE; CThread_mutex_lock(&zeroconfPhidgetsLock); CThread_mutex_lock(&activeRemoteManagersLock); CPhidget_clearStatusFlag(phid, PHIDGET_ATTACHED_FLAG); CPhidget_setStatusFlag(phid, PHIDGET_DETACHING_FLAG); if(!CList_findInList((CListHandle)zeroconfPhidgets, phid, CPhidget_areEqual, NULL)) { CList_removeFromList((CListHandle *)&zeroconfPhidgets, phid, CPhidget_areExtraEqual, TRUE, CPhidget_free); //managers for (trav=activeRemoteManagers; trav; trav = trav->next) { if(trav->phidm->networkInfo->requested_address==NULL && (trav->phidm->networkInfo->requested_serverID == NULL || !strcmp(trav->phidm->networkInfo->requested_serverID,phid->networkInfo->zeroconf_server_id))) { if (trav->phidm->fptrDetachChange && trav->phidm->state == PHIDGETMANAGER_ACTIVE) trav->phidm->fptrDetachChange((CPhidgetHandle)phid, trav->phidm->fptrDetachChangeptr); } } CPhidget_clearStatusFlag(phid, PHIDGET_DETACHING_FLAG); CPhidget_free(phid); } CThread_mutex_unlock(&activeRemoteManagersLock); CThread_mutex_unlock(&zeroconfPhidgetsLock); free(name_copy); } break; case AVAHI_BROWSER_ALL_FOR_NOW: case AVAHI_BROWSER_CACHE_EXHAUSTED: LOG(PHIDGET_LOG_INFO, "(Browser) %s", event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW"); break; } }
/* The internal event handlers for PhidgetManager - these should be called directly from the usb functions... * these run in the context of the central thread * if AddDevice returns EPHIDGET_DUPLICATE, the user callback is not run (good) */ int CPhidgetAttachEvent(CPhidgetHandle phid) { int result = 0; CPhidgetList *trav = 0; CPhidgetManagerList *trav2 = 0; CPhidgetHandle travPhid = 0; TESTPTR(phid) result = CList_addToList((CListHandle *)&AttachedDevices, phid, CPhidget_areEqual); if(result == EPHIDGET_DUPLICATE) { return EPHIDGET_OK; } else if(result) { return result; } for(trav2 = localPhidgetManagers; trav2; trav2 = trav2->next) { if (trav2->phidm->fptrAttachChange && trav2->phidm->state == PHIDGETMANAGER_ACTIVE) { //So we can access AttachedDevices from within the manager atach event CThread_mutex_unlock(&attachedDevicesLock); trav2->phidm->fptrAttachChange((CPhidgetHandle)phid, trav2->phidm->fptrAttachChangeptr); CThread_mutex_lock(&attachedDevicesLock); } } result = EPHIDGET_OK; CThread_mutex_lock(&activeDevicesLock); //first look for this specific device for (trav=ActiveDevices; trav; trav = trav->next) { if((trav->phid->serialNumber == phid->serialNumber) && (trav->phid->deviceID == phid->deviceID) && !CPhidget_statusFlagIsSet(trav->phid->status, PHIDGET_ATTACHED_FLAG)) { travPhid = trav->phid; CThread_mutex_unlock(&activeDevicesLock); //Prevent close from being called during attachActiveDevice CThread_mutex_lock(&travPhid->openCloseLock); result = attachActiveDevice(travPhid, phid); CThread_mutex_unlock(&travPhid->openCloseLock); return result; } } //second look for a general device for (trav=ActiveDevices; trav; trav = trav->next) { if(CPhidget_areEqual(trav->phid, phid) && !CPhidget_statusFlagIsSet(trav->phid->status, PHIDGET_ATTACHED_FLAG)) { travPhid = trav->phid; CThread_mutex_unlock(&activeDevicesLock); //Prevent close from being called during attachActiveDevice CThread_mutex_lock(&travPhid->openCloseLock); result = attachActiveDevice(travPhid, phid); CThread_mutex_unlock(&travPhid->openCloseLock); //If one doesn't work, try the next one - this would happen if the first one in opened elsewhere if(result != EPHIDGET_OK) { CThread_mutex_lock(&activeDevicesLock); continue; } return result; } } CThread_mutex_unlock(&activeDevicesLock); return result; }
int CPhidgetManager_poll() { CPhidgetList *curList = 0, *detachList = 0; CPhidgetList *trav = 0; CPhidgetHandle foundPhidget; if(!managerLockInitialized) { CThread_mutex_init(&managerLock); managerLockInitialized = PTRUE; } CThread_mutex_lock(&managerLock); CThread_mutex_lock(&attachedDevicesLock); sendInitialEvents(); CUSBBuildList(&curList); for (trav=AttachedDevices; trav; trav = trav->next) { if(CList_findInList((CListHandle)curList, trav->phid, CPhidget_areExtraEqual, NULL) == EPHIDGET_NOTFOUND) { CList_addToList((CListHandle *)&detachList, trav->phid, CPhidget_areEqual); } } for (trav=curList; trav; trav = trav->next) { if(CList_findInList((CListHandle)AttachedDevices, trav->phid, CPhidget_areExtraEqual, NULL) == EPHIDGET_NOTFOUND) { CPhidgetAttachEvent(trav->phid); } //if PHIDGET_USB_ERROR_FLAG is set, cycle device through a detach //if it's ok, it will re-attach //this can't yet handle unexpected timeouts (because we don't have a definitive list of expected timeouts) if(CList_findInList((CListHandle)ActiveDevices, trav->phid, CPhidget_areEqual, (void **)&foundPhidget) == EPHIDGET_OK) { if(CPhidget_statusFlagIsSet(foundPhidget->status, PHIDGET_ATTACHED_FLAG)) { if(CPhidget_statusFlagIsSet(foundPhidget->status, PHIDGET_USB_ERROR_FLAG)) { LOG(PHIDGET_LOG_WARNING,"PHIDGET_USB_ERROR_FLAG is set - cycling device through a detach"); CList_addToList((CListHandle *)&detachList, trav->phid, CPhidget_areEqual); } } } } for (trav=detachList; trav; trav = trav->next) { CPhidgetDetachEvent(trav->phid); } CList_emptyList((CListHandle *)&detachList, FALSE, NULL); CList_emptyList((CListHandle *)&curList, FALSE, NULL); CThread_mutex_unlock(&attachedDevicesLock); CThread_mutex_unlock(&managerLock); return EPHIDGET_OK; }
//if outputting to a file, it is designed to be CSV compliant //only print out debug logs in debug library PHIDGET21_API int CCONV CPhidget_log(CPhidgetLog_level level, const char *msg, const char *fmt, ...) { int threadID = 0; int logToStderr = (int)level & LOG_TO_STDERR; va_list va; level = level & 0xFF; #ifdef DEBUG if(level <= logging_level || level == PHIDGET_LOG_DEBUG || logToStderr) #else if((level <= logging_level && level != PHIDGET_LOG_DEBUG) || logToStderr) #endif { if(!logLockInitialized) { CThread_mutex_init(&logLock); logLockInitialized = PTRUE; } CThread_mutex_lock(&logLock); if (!logFile) logFile = stdout; #ifdef WINCE if(logToStderr) fprintf(stderr, "%s: ",logLevelToStr(level)); else if(logFile==stdout) fprintf(logFile, "%s: ",logLevelToStr(level)); else fprintf(logFile, "%d,\"%s\",%s,\"", threadID, msg, logLevelToStr(level)); va_start(va, fmt); if(logToStderr) { vfprintf(stderr, fmt, va); va_end(va); fprintf(stderr, "\n"); fflush(stderr); } else { vfprintf(logFile, fmt, va); va_end(va); if(logFile==stdout) fprintf(logFile, "\n"); else fprintf(logFile, "\"\n"); fflush(logFile); } #else //!WINCE { char date[50]; struct tm *tmp; time_t t; time(&t); #ifndef _WINDOWS struct tm tm; localtime_r(&t, &tm); tmp = &tm; threadID = (int)pthread_self(); #else tmp = localtime(&t); threadID = (int)GetCurrentThreadId(); #endif if (!strftime(date, sizeof (date), "%c", tmp)) strncpy(date, "?", sizeof (date)); if(logToStderr) fprintf(stderr, "%s: ",logLevelToStr(level)); else if(logFile==stdout) fprintf(logFile, "%s: ",logLevelToStr(level)); else fprintf(logFile, "%s,%d,\"%s\",%s,\"", date, threadID, msg, logLevelToStr(level)); va_start(va, fmt); if(logToStderr) { vfprintf(stderr, fmt, va); va_end(va); fprintf(stderr, "\n"); fflush(stderr); } else { vfprintf(logFile, fmt, va); va_end(va); if(logFile==stdout) fprintf(logFile, "\n"); else fprintf(logFile, "\"\n"); fflush(logFile); } } #endif CThread_mutex_unlock(&logLock); } return EPHIDGET_OK; }
void DNSServiceBrowse_Phidget_CallBack(DNSServiceRef service, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char * name, const char * type, const char * domain, void * context) { if (errorCode != kDNSServiceErr_NoError) LOG(PHIDGET_LOG_ERROR, "Dns_sd_BrowseCallBack returned error: %d\n", errorCode); else { DNSServiceErrorType error; DNSServiceRef serviceRef; char fullname[kDNSServiceMaxDomainName]; CPhidgetHandle phid; CPhidgetManagerList *trav; DNSServiceConstructFullNamePtr(fullname, name, type, domain); LOG(PHIDGET_LOG_INFO, "DNSServiceBrowse_Phidget_CallBack: %s",name); if((CPhidget_create(&phid))) return; if((CPhidgetRemote_create(&phid->networkInfo))) return; phid->networkInfo->zeroconf_name = strdup(name); phid->networkInfo->zeroconf_type = strdup(type); phid->networkInfo->zeroconf_domain = strdup(domain); if(flags & kDNSServiceFlagsAdd) { error = DNSServiceQueryRecordPtr(&serviceRef, 0, interfaceIndex, fullname, kDNSServiceType_TXT, kDNSServiceClass_IN, DNSServiceQueryRecord_Phidget_CallBack, phid); if (error == kDNSServiceErr_NoError) { DNSServiceProcessResultPtr(serviceRef); DNSServiceRefDeallocatePtr(serviceRef); CThread_mutex_lock(&zeroconfPhidgetsLock); CThread_mutex_lock(&activeRemoteManagersLock); CPhidget_setStatusFlag(phid, PHIDGET_ATTACHED_FLAG); if(CList_findInList((CListHandle)zeroconfPhidgets, phid, CPhidget_areEqual, NULL)) { CList_addToList((CListHandle *)&zeroconfPhidgets, phid, CPhidget_areEqual); //managers for (trav=activeRemoteManagers; trav; trav = trav->next) { if(trav->phidm->networkInfo->requested_address==NULL && (trav->phidm->networkInfo->requested_serverID == NULL || !strcmp(trav->phidm->networkInfo->requested_serverID,phid->networkInfo->zeroconf_server_id))) { if (trav->phidm->fptrAttachChange && trav->phidm->state == PHIDGETMANAGER_ACTIVE) trav->phidm->fptrAttachChange((CPhidgetHandle)phid, trav->phidm->fptrAttachChangeptr); } } } CThread_mutex_unlock(&activeRemoteManagersLock); CThread_mutex_unlock(&zeroconfPhidgetsLock); } else LOG(PHIDGET_LOG_ERROR, "DNSServiceQueryRecordPtr returned error: %d\n", error); } else { //have to fill in phid manually from just the name int i; char *name_copy = strdup(name); for(i=0;i<strlen(name_copy);i++) if(name_copy[i] == '(') break; if(i<=1) return; name_copy[strlen(name_copy)-1]='\0'; name_copy[i-1] = '\0'; phid->serialNumber = strtol(name_copy+i+1, NULL, 10); phid->specificDevice = PTRUE; for(i = 0;i<PHIDGET_DEVICE_COUNT;i++) if(!strcmp(name_copy, Phid_DeviceSpecificName[i])) break; phid->deviceIDSpec = i; phid->attr = Phid_Device_Def[i].pdd_attr; phid->deviceID = Phid_Device_Def[i].pdd_did; phid->deviceType = Phid_DeviceName[phid->deviceID]; phid->networkInfo->mdns = PTRUE; CThread_mutex_lock(&zeroconfPhidgetsLock); CThread_mutex_lock(&activeRemoteManagersLock); CPhidget_clearStatusFlag(phid, PHIDGET_ATTACHED_FLAG); CPhidget_setStatusFlag(phid, PHIDGET_DETACHING_FLAG); if(!CList_findInList((CListHandle)zeroconfPhidgets, phid, CPhidget_areEqual, NULL)) { CList_removeFromList((CListHandle *)&zeroconfPhidgets, phid, CPhidget_areExtraEqual, TRUE, CPhidget_free); //managers for (trav=activeRemoteManagers; trav; trav = trav->next) { if(trav->phidm->networkInfo->requested_address==NULL && (trav->phidm->networkInfo->requested_serverID == NULL || !strcmp(trav->phidm->networkInfo->requested_serverID,phid->networkInfo->zeroconf_server_id))) { if (trav->phidm->fptrDetachChange && trav->phidm->state == PHIDGETMANAGER_ACTIVE) trav->phidm->fptrDetachChange((CPhidgetHandle)phid, trav->phidm->fptrDetachChangeptr); } } CPhidget_clearStatusFlag(phid, PHIDGET_DETACHING_FLAG); CPhidget_free(phid); } CThread_mutex_unlock(&activeRemoteManagersLock); CThread_mutex_unlock(&zeroconfPhidgetsLock); free(name_copy); } } }