diff options
author | Jonathan McCrohan <jmccrohan@gmail.com> | 2012-05-09 00:47:30 +0100 |
---|---|---|
committer | Jonathan McCrohan <jmccrohan@gmail.com> | 2012-05-09 00:47:30 +0100 |
commit | 260123716172d33f44bdc0e4e5422554d139215c (patch) | |
tree | 840e8e6387b96bd6f9afe3ffebc19c781a112f1b /zeroconf.c | |
parent | 0b624384cd52be20e61284551d832b499d7b7707 (diff) | |
download | libphidget21-260123716172d33f44bdc0e4e5422554d139215c.tar.gz |
Imported Upstream version 2.1.8.20120507upstream/2.1.8.20120507
Diffstat (limited to 'zeroconf.c')
-rw-r--r-- | zeroconf.c | 2463 |
1 files changed, 1232 insertions, 1231 deletions
@@ -1,1231 +1,1232 @@ -#include "stdafx.h" -#include "csocket.h" -#include "csocketevents.h" -#include "cphidgetlist.h" -#include "cphidgetmanager.h" -#include "cphidgetdictionary.h" -#include "cphidgetsbc.h" -#include "zeroconf.h" -#include "dns_sd.h" - -#ifdef ZEROCONF_RUNTIME_LINKING -//function prototypes for run-time loaded library -typedef DNSServiceErrorType (DNSSD_API * DNSServiceRegisterType) -(DNSServiceRef *,DNSServiceFlags,uint32_t,const char *, - const char *,const char *,const char *,uint16_t,uint16_t, - const void *,DNSServiceRegisterReply,void *); -typedef DNSServiceErrorType (DNSSD_API * DNSServiceProcessResultType) (DNSServiceRef); -typedef void (DNSSD_API * DNSServiceRefDeallocateType) (DNSServiceRef); -typedef DNSServiceErrorType (DNSSD_API * DNSServiceAddRecordType) -(DNSServiceRef, DNSRecordRef *, DNSServiceFlags, - uint16_t, uint16_t, const void *, uint32_t); -typedef DNSServiceErrorType (DNSSD_API * DNSServiceUpdateRecordType) -(DNSServiceRef, DNSRecordRef, DNSServiceFlags, - uint16_t, const void *, uint32_t); -typedef DNSServiceErrorType (DNSSD_API * DNSServiceRemoveRecordType) -(DNSServiceRef, DNSRecordRef, DNSServiceFlags); -typedef DNSServiceErrorType (DNSSD_API * DNSServiceBrowseType) -(DNSServiceRef *, DNSServiceFlags, uint32_t, const char *, - const char *, DNSServiceBrowseReply, void *); -typedef DNSServiceErrorType (DNSSD_API * DNSServiceResolveType) -(DNSServiceRef *, DNSServiceFlags, uint32_t, const char *, - const char *, const char *, DNSServiceResolveReply, - void *context); -typedef DNSServiceErrorType (DNSSD_API * DNSServiceQueryRecordType) -(DNSServiceRef *, DNSServiceFlags, uint32_t, const char *, - uint16_t, uint16_t, DNSServiceQueryRecordReply, void *context); -typedef int (DNSSD_API * DNSServiceConstructFullNameType) -(char *, const char *, const char *, const char *); -typedef int (DNSSD_API * DNSServiceRefSockFDType) (DNSServiceRef sdRef); -#else -#define DNSServiceRegisterPtr DNSServiceRegister -#define DNSServiceProcessResultPtr DNSServiceProcessResult -#define DNSServiceRefDeallocatePtr DNSServiceRefDeallocate -#define DNSServiceAddRecordPtr DNSServiceAddRecord -#define DNSServiceUpdateRecordPtr DNSServiceUpdateRecord -#define DNSServiceRemoveRecordPtr DNSServiceRemoveRecord -#define DNSServiceBrowsePtr DNSServiceBrowse -#define DNSServiceResolvePtr DNSServiceResolve -#define DNSServiceQueryRecordPtr DNSServiceQueryRecord -#define DNSServiceConstructFullNamePtr DNSServiceConstructFullName -#define DNSServiceRefSockFDPtr DNSServiceRefSockFD -#endif - -int Dns_sdInitialized = FALSE; -int Dns_sdBrowsing = FALSE; -int stopBrowsing = FALSE; -DNSServiceRef zeroconf_browse_ws_ref = NULL; -DNSServiceRef zeroconf_browse_sbc_ref = NULL; -DNSServiceRef zeroconf_browse_phidget_ref = NULL; - -pthread_t dns_thread = NULL; - -#ifdef ZEROCONF_RUNTIME_LINKING - -//DNS_SD functions -DNSServiceRegisterType DNSServiceRegisterPtr = NULL; -DNSServiceProcessResultType DNSServiceProcessResultPtr = NULL; -DNSServiceRefDeallocateType DNSServiceRefDeallocatePtr = NULL; -DNSServiceAddRecordType DNSServiceAddRecordPtr = NULL; -DNSServiceUpdateRecordType DNSServiceUpdateRecordPtr = NULL; -DNSServiceRemoveRecordType DNSServiceRemoveRecordPtr = NULL; -DNSServiceBrowseType DNSServiceBrowsePtr = NULL; -DNSServiceResolveType DNSServiceResolvePtr = NULL; -DNSServiceQueryRecordType DNSServiceQueryRecordPtr = NULL; -DNSServiceConstructFullNameType DNSServiceConstructFullNamePtr = NULL; -DNSServiceRefSockFDType DNSServiceRefSockFDPtr = NULL; - -#ifdef _WINDOWS -HMODULE dllHandle = NULL; -#elif _LINUX -void *libHandle = NULL; -#endif -#endif - - -static uint8_t *InternalTXTRecordSearch -( - uint16_t txtLen, - const void *txtRecord, - const char *key, - unsigned long *keylen - ) -{ - uint8_t *p = (uint8_t*)txtRecord; - uint8_t *e = p + txtLen; - *keylen = (unsigned long) strlen(key); - while (p<e) - { - uint8_t *x = p; - p += 1 + p[0]; - if (p <= e && *keylen <= x[0] && !strncmp(key, (char*)x+1, *keylen)) - if (*keylen == x[0] || x[1+*keylen] == '=') return(x); - } - return(NULL); -} - -const void * TXTRecordGetValuePtrPtr -( - uint16_t txtLen, - const void *txtRecord, - const char *key, - uint8_t *valueLen - ) -{ - unsigned long keylen; - uint8_t *item = InternalTXTRecordSearch(txtLen, txtRecord, key, &keylen); - if (!item || item[0] <= keylen) return(NULL); // If key not found, or found with no value, return NULL - *valueLen = (uint8_t)(item[0] - (keylen + 1)); - return (item + 1 + keylen + 1); -} - -int dns_callback_thread(void *ptr) -{ - int nfds; - fd_set readfds; - struct timeval tv; - int result; - - int ws_fd = DNSServiceRefSockFDPtr(zeroconf_browse_ws_ref); - int sbc_fd = DNSServiceRefSockFDPtr(zeroconf_browse_sbc_ref); - int phidget_fd = DNSServiceRefSockFDPtr(zeroconf_browse_phidget_ref); - - nfds = ws_fd; - if(sbc_fd>nfds) - nfds = sbc_fd; - if(phidget_fd > nfds) - nfds = phidget_fd; - nfds++; - - while (!stopBrowsing) - { - FD_ZERO(&readfds); - FD_SET(ws_fd, &readfds); - FD_SET(sbc_fd, &readfds); - FD_SET(phidget_fd, &readfds); - - //100ms - tv.tv_sec = 0; - tv.tv_usec = 100000; - - result = select(nfds, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv); - if (result > 0) - { - DNSServiceErrorType err = kDNSServiceErr_NoError; - if (FD_ISSET(ws_fd, &readfds)) - { - if ((err = DNSServiceProcessResultPtr(zeroconf_browse_ws_ref)) != kDNSServiceErr_NoError) - stopBrowsing = 1; - } - if (FD_ISSET(sbc_fd, &readfds)) - { - if ((err = DNSServiceProcessResultPtr(zeroconf_browse_sbc_ref)) != kDNSServiceErr_NoError) - stopBrowsing = 1; - } - if (FD_ISSET(phidget_fd, &readfds)) - { - if ((err = DNSServiceProcessResultPtr(zeroconf_browse_phidget_ref)) != kDNSServiceErr_NoError) - stopBrowsing = 1; - } - } - else if(result == SOCKET_ERROR) - { - LOG(PHIDGET_LOG_DEBUG, "select( ) returned %d errno %d %s\n", result, errno, strerror(errno)); - if (errno != EINTR) - stopBrowsing = 1; - } - //result==0 means timeout, loop around again - } - return EPHIDGET_OK; -} - -void PhidFromTXT(CPhidgetHandle phid, uint16_t txtLen, const char *txtRecord) -{ - int i = 0; - short txtver; - //char *label = NULL; - char temp[128]; - //unsigned int labelLen = 0; - - uint8_t valLen = 0; - const char *valPtr = NULL; - - //txt version - if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "txtvers", &valLen))) return; - memcpy(temp, valPtr, valLen); - temp[valLen] = '\0'; - txtver = (short)strtol(temp, NULL, 10); - - //Serial Number - if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "serial", &valLen))) return; - memcpy(temp, valPtr, valLen); - temp[valLen] = '\0'; - phid->serialNumber = strtol(temp, NULL, 10); - phid->specificDevice = PHIDGETOPEN_SERIAL; - - //version - if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "version", &valLen))) return; - memcpy(temp, valPtr, valLen); - temp[valLen] = '\0'; - phid->deviceVersion = strtol(temp, NULL, 10); - - //label - if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "label", &valLen))) return; - if(valLen >= MAX_LABEL_STORAGE) valLen = MAX_LABEL_STORAGE-1; - memcpy(phid->label, valPtr, valLen); - phid->label[valLen] = '\0'; - /* memcpy(temp, valPtr, valLen); - temp[valLen] = '\0'; - unescape(temp, &label, &labelLen); - if(labelLen > MAX_LABEL_STORAGE-1) labelLen = MAX_LABEL_STORAGE-1; - memcpy(phid->label, label, labelLen); - phid->label[labelLen] = '\0'; - free(label);*/ - - //server_id - if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "server_id", &valLen))) return; - free(phid->networkInfo->zeroconf_server_id); - if(!(phid->networkInfo->zeroconf_server_id = malloc(valLen+1))) return; - ZEROMEM(phid->networkInfo->zeroconf_server_id, valLen+1); - memcpy(phid->networkInfo->zeroconf_server_id, valPtr, valLen); - - // things added in version 2 of the txt - if(txtver >= 2) - { - //Device ID - if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "id", &valLen))) return; - memcpy(temp, valPtr, valLen); - temp[valLen] = '\0'; - phid->deviceIDSpec = strtol(temp, NULL, 10); - - for(i = 1;i<PHIDGET_DEVICE_COUNT;i++) - if(phid->deviceIDSpec == Phid_Device_Def[i].pdd_sdid) break; - phid->deviceDef = &Phid_Device_Def[i]; - phid->attr = Phid_Device_Def[i].pdd_attr; - - //Device Class - if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "class", &valLen))) return; - memcpy(temp, valPtr, valLen); - temp[valLen] = '\0'; - phid->deviceID = strtol(temp, NULL, 10); - phid->deviceType = Phid_DeviceName[phid->deviceID]; - } - //Old version uses string searching, but some devices have the same name with different IDs - else - { - char *name = NULL; - char *type = NULL; - - //name - if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "name", &valLen))) return; - if(!(name = malloc(valLen+1))) return; - ZEROMEM(name, valLen+1); - memcpy(name, valPtr, valLen); - for(i = 0;i<PHIDGET_DEVICE_COUNT;i++) - { - if(!strcmp(name, Phid_Device_Def[i].pdd_name)) - { - phid->deviceIDSpec = Phid_Device_Def[i].pdd_sdid; - phid->deviceDef = &Phid_Device_Def[i]; - phid->attr = Phid_Device_Def[i].pdd_attr; - break; - } - } - free(name); - - //type - if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "type", &valLen))) return; - if(!(type = malloc(valLen+1))) return; - ZEROMEM(type, valLen+1); - memcpy(type, valPtr, valLen); - phid->deviceID = phidget_type_to_id(type); - phid->deviceType = Phid_DeviceName[phid->deviceID]; - free(type); - } - - phid->networkInfo->mdns = PTRUE; - -} - -void DNSServiceQueryRecord_Phidget_CallBack -( - DNSServiceRef DNSServiceRef, - DNSServiceFlags flags, - uint32_t interfaceIndex, - DNSServiceErrorType errorCode, - const char *fullname, - uint16_t rrtype, - uint16_t rrclass, - uint16_t rdlen, - const void *rdata, - uint32_t ttl, - void *context - ) -{ - if (errorCode != kDNSServiceErr_NoError) - LOG(PHIDGET_LOG_ERROR, "DNSServiceQueryRecord_Phidget_CallBack returned error: %d\n", errorCode); - else - { - CPhidgetHandle phid = (CPhidgetHandle)context; - LOG(PHIDGET_LOG_INFO, "DNSServiceQueryRecord_Phidget_CallBack: %s (%d)",fullname,interfaceIndex); - - PhidFromTXT(phid, rdlen, rdata); - } -} - -void SBCFromTXT(CPhidgetSBCHandle sbc, uint16_t txtLen, const char *txtRecord) -{ - char *hversion = NULL, *txtver = NULL; - - uint8_t valLen = 0; - const char *valPtr = NULL; - - //txt version - if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "txtvers", &valLen))) return; - if(!(txtver = malloc(valLen+1))) return; - ZEROMEM(txtver, valLen+1); - memcpy(txtver, valPtr, valLen); - sbc->txtver = (short)strtol(txtver, NULL, 10); - free(txtver); - - //Firmware version - if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "fversion", &valLen))) return; - if(valLen > 12) valLen = 12; - memcpy(sbc->fversion, valPtr, valLen); - sbc->fversion[valLen] = '\0'; - - //Hardware version - if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "hversion", &valLen))) return; - if(!(hversion = malloc(valLen+1))) return; - ZEROMEM(hversion, valLen+1); - memcpy(hversion, valPtr, valLen); - sbc->hversion = (short)strtol(hversion, NULL, 10); - free(hversion); - - // things added in version 2 of the txt - if(sbc->txtver >= 2) - { - //Hostname - if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "hostname", &valLen))) return; - if(valLen > 128) valLen = 128; - memcpy(sbc->hostname, valPtr, valLen); - sbc->hostname[valLen] = '\0'; - } - // things added in version 3 of the txt - if(sbc->txtver >= 3) - { - //Device Name - if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "name", &valLen))) return; - if(valLen > 128) valLen = 128; - memcpy(sbc->deviceName, valPtr, valLen); - sbc->deviceName[valLen] = '\0'; - } - else - { - sprintf(sbc->deviceName, "PhidgetSBC"); - } -} - -void DNSServiceQueryRecord_SBC_CallBack -( - DNSServiceRef DNSServiceRef, - DNSServiceFlags flags, - uint32_t interfaceIndex, - DNSServiceErrorType errorCode, - const char *fullname, - uint16_t rrtype, - uint16_t rrclass, - uint16_t rdlen, - const void *rdata, - uint32_t ttl, - void *context - ) -{ - if (errorCode != kDNSServiceErr_NoError) - LOG(PHIDGET_LOG_ERROR, "DNSServiceQueryRecord_sbc_CallBack returned error: %d\n", errorCode); - else - { - CPhidgetSBCHandle sbc = (CPhidgetSBCHandle)context; - LOG(PHIDGET_LOG_INFO, "DNSServiceQueryRecord_sbc_CallBack: %s (%d)",fullname,interfaceIndex); - - SBCFromTXT(sbc, rdlen, rdata); - } -} - -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 (%s, %s, %d)",name,type,domain,interfaceIndex); - - 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); - phid->networkInfo->zeroconf_interface = interfaceIndex; - - 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)) - { - //prefer local. domain - if((strcmp(domain, found_phid->networkInfo->zeroconf_domain) != 0) && !(strcmp(domain, "local."))) - { - free(found_phid->networkInfo->zeroconf_domain); - found_phid->networkInfo->zeroconf_domain = phid->networkInfo->zeroconf_domain; - phid->networkInfo->zeroconf_domain = NULL; - } - 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_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->zeroconf_interface = interfaceIndex; - 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 - { - //prefer local. domain - if((strcmp(domain, found_sbc->networkInfo->zeroconf_domain) != 0) && !(strcmp(domain, "local."))) - { - free(found_sbc->networkInfo->zeroconf_domain); - found_sbc->networkInfo->zeroconf_domain = sbc->networkInfo->zeroconf_domain; - sbc->networkInfo->zeroconf_domain = NULL; - } - 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); - } - } -} - -void DNSServiceBrowse_ws_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, "DNSServiceBrowse_ws_CallBack returned error: %d\n", errorCode); - else - { - char fullname[kDNSServiceMaxDomainName]; - - 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); - networkInfo->zeroconf_interface = interfaceIndex; - - DNSServiceConstructFullNamePtr(fullname, name, type, domain); - - LOG(PHIDGET_LOG_INFO, "DNSServiceBrowse_ws_CallBack: %s (%s, %s, %d)",name,type,domain,interfaceIndex); - - CThread_mutex_lock(&zeroconfServersLock); - if(flags & kDNSServiceFlagsAdd) - { - if(CList_addToList((CListHandle *)&zeroconfServers, networkInfo, CPhidgetRemote_areEqual) != EPHIDGET_OK) - CPhidgetRemote_free(networkInfo); - } - else - { - CList_removeFromList((CListHandle *)&zeroconfServers, networkInfo, CPhidgetRemote_areEqual, TRUE, CPhidgetRemote_free); - } - CThread_mutex_unlock(&zeroconfServersLock); - } -} - -int cancelPendingZeroconfLookups(CPhidgetRemoteHandle networkInfo) -{ - if(networkInfo->zeroconf_ref != NULL) - { - DNSServiceRefDeallocatePtr((DNSServiceRef)networkInfo->zeroconf_ref); - networkInfo->zeroconf_ref = NULL; - } - return EPHIDGET_OK; -} - - -void DNSServiceQueryRecord_CallBack -( - DNSServiceRef DNSServiceRef, - DNSServiceFlags flags, - uint32_t interfaceIndex, - DNSServiceErrorType errorCode, - const char *fullname, - uint16_t rrtype, - uint16_t rrclass, - uint16_t rdlen, - const void *rdata, - uint32_t ttl, - void *context - ) -{ - - CPhidgetRemoteHandle networkInfo = (CPhidgetRemoteHandle)context; - - if (errorCode != kDNSServiceErr_NoError) - { - LOG(PHIDGET_LOG_ERROR, "DNSServiceQueryRecord_CallBack returned error: %d\n", errorCode); - networkInfo->zeroconf_ipaddr = NULL; - } - else if(networkInfo->zeroconf_ipaddr == NULL) - { - if(rrtype == kDNSServiceType_A && rdlen == 4) - { - struct in_addr ip; - memcpy(&ip, rdata, 4); - - networkInfo->zeroconf_ipaddr = strdup(inet_ntoa(ip)); - } - //NOTE: Windows doesn't have inet_ntop - /* - else if(rrtype == kDNSServiceType_AAAA && rdlen == 16) - { - struct in6_addr ip; - memcpy(&ip, rdata, 16); - - if((networkInfo->zeroconf_ipaddr = malloc(200)) != NULL) - { - networkInfo->zeroconf_ipaddr = strdup(inet_ntop(AF_INET6, &ip, networkInfo->zeroconf_ipaddr, 200)); - } - } - */ - - LOG(PHIDGET_LOG_INFO, "DNSServiceQueryRecord_CallBack: %s (%s %d)",fullname, networkInfo->zeroconf_ipaddr, interfaceIndex); - } - else - LOG(PHIDGET_LOG_INFO, "DNSServiceQueryRecord_CallBack (extra, not used): %s (%d)",fullname, interfaceIndex); -} - -int getZeroconfIPAddr(CPhidgetRemoteHandle networkInfo) -{ - DNSServiceErrorType error; - - LOG(PHIDGET_LOG_VERBOSE, "Resolving IP Address for: %s, %s, %s, %s, %d", - networkInfo->zeroconf_name, //name - networkInfo->zeroconf_type, // service type - networkInfo->zeroconf_domain, //domain - networkInfo->zeroconf_host, - networkInfo->zeroconf_interface); - - //already a lookup pending? cancel it and start a new one... - CThread_mutex_lock(&networkInfo->zeroconf_ref_lock); - if(networkInfo->zeroconf_ref != NULL) - { - DNSServiceRefDeallocatePtr((DNSServiceRef)networkInfo->zeroconf_ref); - networkInfo->zeroconf_ref = NULL; - } - - free(networkInfo->zeroconf_ipaddr); - networkInfo->zeroconf_ipaddr = NULL; - - error = DNSServiceQueryRecordPtr((DNSServiceRef *)&networkInfo->zeroconf_ref, - 0, // no flags - networkInfo->zeroconf_interface, - networkInfo->zeroconf_host, //hostname - kDNSServiceType_A, // IPv4 address for now.. - kDNSServiceClass_IN, // service class - DNSServiceQueryRecord_CallBack, - networkInfo); - if (error != kDNSServiceErr_NoError) - { - LOG(PHIDGET_LOG_ERROR, "DNSServiceQueryRecordPtr returned error: %d\n", error); - networkInfo->zeroconf_ref = NULL; - CThread_mutex_unlock(&networkInfo->zeroconf_ref_lock); - return EPHIDGET_NETWORK; - } - else - { - DNSServiceProcessResultPtr((DNSServiceRef)networkInfo->zeroconf_ref); - DNSServiceRefDeallocatePtr((DNSServiceRef)networkInfo->zeroconf_ref); - networkInfo->zeroconf_ref = NULL; - CThread_mutex_unlock(&networkInfo->zeroconf_ref_lock); - LOG(PHIDGET_LOG_VERBOSE, "Successfull lookup: %s",networkInfo->zeroconf_host); - return EPHIDGET_OK; - } - -} - -void DNSServiceResolve_CallBack( - DNSServiceRef sdRef, - DNSServiceFlags flags, - uint32_t interfaceIndex, - DNSServiceErrorType errorCode, - const char *fullname, - const char *hosttarget, - uint16_t port, - uint16_t txtLen, - const unsigned char *txtRecord, - void *context) -{ - CPhidgetRemoteHandle networkInfo = (CPhidgetRemoteHandle)context; - - - if (errorCode != kDNSServiceErr_NoError) - { - LOG(PHIDGET_LOG_ERROR, "DNSServiceResolve_CallBack returned error: %d\n", errorCode); - networkInfo->zeroconf_host = NULL; - networkInfo->zeroconf_port = NULL; - } - else if(!networkInfo->zeroconf_host && !networkInfo->zeroconf_port) - { - - LOG(PHIDGET_LOG_INFO, "DNSServiceResolve_CallBack: %s (%s:%d %d)",fullname, hosttarget, ntohs(port), interfaceIndex); - - networkInfo->zeroconf_host = strdup(hosttarget); - networkInfo->zeroconf_port = malloc(10); - snprintf(networkInfo->zeroconf_port, 10, "%d", ntohs(port)); - } - else - LOG(PHIDGET_LOG_INFO, "DNSServiceResolve_CallBack (extra, not used): %s (%s:%d %d)",fullname, hosttarget, ntohs(port), interfaceIndex); -} - -int getZeroconfHostPort(CPhidgetRemoteHandle networkInfo) -{ - DNSServiceErrorType error; - - LOG(PHIDGET_LOG_VERBOSE, "Resolving host:port for: %s, %s, %s", - networkInfo->zeroconf_name, //name - networkInfo->zeroconf_type, // service type - networkInfo->zeroconf_domain //domain - ); - - //already a lookup pending? cancel it and start a new one... - CThread_mutex_lock(&networkInfo->zeroconf_ref_lock); - if(networkInfo->zeroconf_ref != NULL) - { - DNSServiceRefDeallocatePtr((DNSServiceRef)networkInfo->zeroconf_ref); - networkInfo->zeroconf_ref = NULL; - } - - free(networkInfo->zeroconf_host); - networkInfo->zeroconf_host = NULL; - free(networkInfo->zeroconf_port); - networkInfo->zeroconf_port = NULL; - - error = DNSServiceResolvePtr((DNSServiceRef *)&networkInfo->zeroconf_ref, - 0, // no flags - 0, // all interfaces - //networkInfo->zeroconf_interface, // interface this service was discovered on - networkInfo->zeroconf_name, //name - networkInfo->zeroconf_type, // service type - networkInfo->zeroconf_domain, //domain - DNSServiceResolve_CallBack, - networkInfo); // no context - if (error != kDNSServiceErr_NoError) - { - LOG(PHIDGET_LOG_ERROR, "getZeroconfHostPort returned error: %d\n", error); - networkInfo->zeroconf_ref = NULL; - CThread_mutex_unlock(&networkInfo->zeroconf_ref_lock); - return EPHIDGET_NETWORK; - } - else - { - DNSServiceProcessResultPtr((DNSServiceRef)networkInfo->zeroconf_ref); - DNSServiceRefDeallocatePtr((DNSServiceRef)networkInfo->zeroconf_ref); - networkInfo->zeroconf_ref = NULL; - LOG(PHIDGET_LOG_VERBOSE, "Successfull host:port lookup: %s:%s",networkInfo->zeroconf_host,networkInfo->zeroconf_port); - CThread_mutex_unlock(&networkInfo->zeroconf_ref_lock); - //Don't bother - we aren't going to use it anyways - //This is just another way to lookup the IP address - from the DNS record - //getZeroconfIPAddr(networkInfo); - return EPHIDGET_OK; - } -} - -int refreshZeroconf(CPhidgetRemoteHandle networkInfo, DNSServiceQueryRecordReply callBack, void *userPtr) -{ - DNSServiceErrorType error; - char fullname[kDNSServiceMaxDomainName]; - - LOG(PHIDGET_LOG_VERBOSE, "Refreshing zeroconf on: 0x%x",networkInfo); - - //already a lookup pending? cancel it and start a new one... - CThread_mutex_lock(&networkInfo->zeroconf_ref_lock); - - DNSServiceConstructFullNamePtr(fullname, networkInfo->zeroconf_name, networkInfo->zeroconf_type, networkInfo->zeroconf_domain); - - if(networkInfo->zeroconf_ref != NULL) - { - DNSServiceRefDeallocatePtr((DNSServiceRef)networkInfo->zeroconf_ref); - networkInfo->zeroconf_ref = NULL; - } - error = DNSServiceQueryRecordPtr((DNSServiceRef *)&networkInfo->zeroconf_ref, - 0, // no flags - networkInfo->zeroconf_interface, - fullname, //name - kDNSServiceType_TXT, // service type - kDNSServiceClass_IN, // service class - callBack, - userPtr); - if (error != kDNSServiceErr_NoError) - { - LOG(PHIDGET_LOG_ERROR, "DNSServiceQueryRecordPtr returned error: %d\n", error); - networkInfo->zeroconf_ref = NULL; - CThread_mutex_unlock(&networkInfo->zeroconf_ref_lock); - return EPHIDGET_NETWORK; - } - else - { - DNSServiceProcessResultPtr((DNSServiceRef)networkInfo->zeroconf_ref); - DNSServiceRefDeallocatePtr((DNSServiceRef)networkInfo->zeroconf_ref); - networkInfo->zeroconf_ref = NULL; - CThread_mutex_unlock(&networkInfo->zeroconf_ref_lock); - LOG(PHIDGET_LOG_VERBOSE, "Successfull refresh."); - return EPHIDGET_OK; - } -} - -int refreshZeroconfSBC(CPhidgetSBCHandle sbc) -{ - return refreshZeroconf(sbc->networkInfo, DNSServiceQueryRecord_SBC_CallBack, sbc); -} - -int refreshZeroconfPhidget(CPhidgetHandle phid) -{ - return refreshZeroconf(phid->networkInfo, DNSServiceQueryRecord_Phidget_CallBack, phid); -} - -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; -} - -int UninitializeZeroconf() -{ - void *status; - CThread_mutex_lock(&zeroconfInitLock); - if(Dns_sdBrowsing) - { - stopBrowsing = TRUE; - if(dns_thread) - { - pthread_join(dns_thread, &status); - dns_thread = NULL; - } - - if(zeroconf_browse_ws_ref) - { - DNSServiceRefDeallocatePtr(zeroconf_browse_ws_ref); - zeroconf_browse_ws_ref = NULL; - } - if(zeroconf_browse_sbc_ref) - { - DNSServiceRefDeallocatePtr(zeroconf_browse_sbc_ref); - zeroconf_browse_sbc_ref = NULL; - } - if(zeroconf_browse_phidget_ref) - { - DNSServiceRefDeallocatePtr(zeroconf_browse_phidget_ref); - zeroconf_browse_phidget_ref = NULL; - } - - CThread_mutex_lock(&zeroconfPhidgetsLock); - CList_emptyList((CListHandle *)&zeroconfPhidgets, FALSE, NULL); - CThread_mutex_unlock(&zeroconfPhidgetsLock); - - CThread_mutex_lock(&zeroconfSBCsLock); - CList_emptyList((CListHandle *)&zeroconfSBCs, FALSE, NULL); - CThread_mutex_unlock(&zeroconfSBCsLock); - - CThread_mutex_lock(&zeroconfServersLock); - CList_emptyList((CListHandle *)&zeroconfServers, FALSE, NULL); - CThread_mutex_unlock(&zeroconfServersLock); - - Dns_sdBrowsing = FALSE; - } - CThread_mutex_unlock(&zeroconfInitLock); - return EPHIDGET_OK; -} - - +#include "stdafx.h"
+#include "csocket.h"
+#include "csocketevents.h"
+#include "cphidgetlist.h"
+#include "cphidgetmanager.h"
+#include "cphidgetdictionary.h"
+#include "cphidgetsbc.h"
+#include "zeroconf.h"
+#include "dns_sd.h"
+
+#ifdef ZEROCONF_RUNTIME_LINKING
+//function prototypes for run-time loaded library
+typedef DNSServiceErrorType (DNSSD_API * DNSServiceRegisterType)
+(DNSServiceRef *,DNSServiceFlags,uint32_t,const char *,
+ const char *,const char *,const char *,uint16_t,uint16_t,
+ const void *,DNSServiceRegisterReply,void *);
+typedef DNSServiceErrorType (DNSSD_API * DNSServiceProcessResultType) (DNSServiceRef);
+typedef void (DNSSD_API * DNSServiceRefDeallocateType) (DNSServiceRef);
+typedef DNSServiceErrorType (DNSSD_API * DNSServiceAddRecordType)
+(DNSServiceRef, DNSRecordRef *, DNSServiceFlags,
+ uint16_t, uint16_t, const void *, uint32_t);
+typedef DNSServiceErrorType (DNSSD_API * DNSServiceUpdateRecordType)
+(DNSServiceRef, DNSRecordRef, DNSServiceFlags,
+ uint16_t, const void *, uint32_t);
+typedef DNSServiceErrorType (DNSSD_API * DNSServiceRemoveRecordType)
+(DNSServiceRef, DNSRecordRef, DNSServiceFlags);
+typedef DNSServiceErrorType (DNSSD_API * DNSServiceBrowseType)
+(DNSServiceRef *, DNSServiceFlags, uint32_t, const char *,
+ const char *, DNSServiceBrowseReply, void *);
+typedef DNSServiceErrorType (DNSSD_API * DNSServiceResolveType)
+(DNSServiceRef *, DNSServiceFlags, uint32_t, const char *,
+ const char *, const char *, DNSServiceResolveReply,
+ void *context);
+typedef DNSServiceErrorType (DNSSD_API * DNSServiceQueryRecordType)
+(DNSServiceRef *, DNSServiceFlags, uint32_t, const char *,
+ uint16_t, uint16_t, DNSServiceQueryRecordReply, void *context);
+typedef int (DNSSD_API * DNSServiceConstructFullNameType)
+(char *, const char *, const char *, const char *);
+typedef int (DNSSD_API * DNSServiceRefSockFDType) (DNSServiceRef sdRef);
+#else
+#define DNSServiceRegisterPtr DNSServiceRegister
+#define DNSServiceProcessResultPtr DNSServiceProcessResult
+#define DNSServiceRefDeallocatePtr DNSServiceRefDeallocate
+#define DNSServiceAddRecordPtr DNSServiceAddRecord
+#define DNSServiceUpdateRecordPtr DNSServiceUpdateRecord
+#define DNSServiceRemoveRecordPtr DNSServiceRemoveRecord
+#define DNSServiceBrowsePtr DNSServiceBrowse
+#define DNSServiceResolvePtr DNSServiceResolve
+#define DNSServiceQueryRecordPtr DNSServiceQueryRecord
+#define DNSServiceConstructFullNamePtr DNSServiceConstructFullName
+#define DNSServiceRefSockFDPtr DNSServiceRefSockFD
+#endif
+
+int Dns_sdInitialized = FALSE;
+int Dns_sdBrowsing = FALSE;
+int stopBrowsing = FALSE;
+DNSServiceRef zeroconf_browse_ws_ref = NULL;
+DNSServiceRef zeroconf_browse_sbc_ref = NULL;
+DNSServiceRef zeroconf_browse_phidget_ref = NULL;
+
+pthread_t dns_thread = NULL;
+
+#ifdef ZEROCONF_RUNTIME_LINKING
+
+//DNS_SD functions
+DNSServiceRegisterType DNSServiceRegisterPtr = NULL;
+DNSServiceProcessResultType DNSServiceProcessResultPtr = NULL;
+DNSServiceRefDeallocateType DNSServiceRefDeallocatePtr = NULL;
+DNSServiceAddRecordType DNSServiceAddRecordPtr = NULL;
+DNSServiceUpdateRecordType DNSServiceUpdateRecordPtr = NULL;
+DNSServiceRemoveRecordType DNSServiceRemoveRecordPtr = NULL;
+DNSServiceBrowseType DNSServiceBrowsePtr = NULL;
+DNSServiceResolveType DNSServiceResolvePtr = NULL;
+DNSServiceQueryRecordType DNSServiceQueryRecordPtr = NULL;
+DNSServiceConstructFullNameType DNSServiceConstructFullNamePtr = NULL;
+DNSServiceRefSockFDType DNSServiceRefSockFDPtr = NULL;
+
+#ifdef _WINDOWS
+HMODULE dllHandle = NULL;
+#elif _LINUX
+void *libHandle = NULL;
+#endif
+#endif
+
+
+static uint8_t *InternalTXTRecordSearch
+(
+ uint16_t txtLen,
+ const void *txtRecord,
+ const char *key,
+ unsigned long *keylen
+ )
+{
+ uint8_t *p = (uint8_t*)txtRecord;
+ uint8_t *e = p + txtLen;
+ *keylen = (unsigned long) strlen(key);
+ while (p<e)
+ {
+ uint8_t *x = p;
+ p += 1 + p[0];
+ if (p <= e && *keylen <= x[0] && !strncmp(key, (char*)x+1, *keylen))
+ if (*keylen == x[0] || x[1+*keylen] == '=') return(x);
+ }
+ return(NULL);
+}
+
+const void * TXTRecordGetValuePtrPtr
+(
+ uint16_t txtLen,
+ const void *txtRecord,
+ const char *key,
+ uint8_t *valueLen
+ )
+{
+ unsigned long keylen;
+ uint8_t *item = InternalTXTRecordSearch(txtLen, txtRecord, key, &keylen);
+ if (!item || item[0] <= keylen) return(NULL); // If key not found, or found with no value, return NULL
+ *valueLen = (uint8_t)(item[0] - (keylen + 1));
+ return (item + 1 + keylen + 1);
+}
+
+int dns_callback_thread(void *ptr)
+{
+ int nfds;
+ fd_set readfds;
+ struct timeval tv;
+ int result;
+
+ int ws_fd = DNSServiceRefSockFDPtr(zeroconf_browse_ws_ref);
+ int sbc_fd = DNSServiceRefSockFDPtr(zeroconf_browse_sbc_ref);
+ int phidget_fd = DNSServiceRefSockFDPtr(zeroconf_browse_phidget_ref);
+
+ nfds = ws_fd;
+ if(sbc_fd>nfds)
+ nfds = sbc_fd;
+ if(phidget_fd > nfds)
+ nfds = phidget_fd;
+ nfds++;
+
+ while (!stopBrowsing)
+ {
+ FD_ZERO(&readfds);
+ FD_SET(ws_fd, &readfds);
+ FD_SET(sbc_fd, &readfds);
+ FD_SET(phidget_fd, &readfds);
+
+ //100ms
+ tv.tv_sec = 0;
+ tv.tv_usec = 100000;
+
+ result = select(nfds, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv);
+ if (result > 0)
+ {
+ DNSServiceErrorType err = kDNSServiceErr_NoError;
+ if (FD_ISSET(ws_fd, &readfds))
+ {
+ if ((err = DNSServiceProcessResultPtr(zeroconf_browse_ws_ref)) != kDNSServiceErr_NoError)
+ stopBrowsing = 1;
+ }
+ if (FD_ISSET(sbc_fd, &readfds))
+ {
+ if ((err = DNSServiceProcessResultPtr(zeroconf_browse_sbc_ref)) != kDNSServiceErr_NoError)
+ stopBrowsing = 1;
+ }
+ if (FD_ISSET(phidget_fd, &readfds))
+ {
+ if ((err = DNSServiceProcessResultPtr(zeroconf_browse_phidget_ref)) != kDNSServiceErr_NoError)
+ stopBrowsing = 1;
+ }
+ }
+ else if(result == SOCKET_ERROR)
+ {
+ LOG(PHIDGET_LOG_DEBUG, "select( ) returned %d errno %d %s\n", result, errno, strerror(errno));
+ if (errno != EINTR)
+ stopBrowsing = 1;
+ }
+ //result==0 means timeout, loop around again
+ }
+ return EPHIDGET_OK;
+}
+
+void PhidFromTXT(CPhidgetHandle phid, uint16_t txtLen, const char *txtRecord)
+{
+ int i = 0;
+ short txtver;
+ //char *label = NULL;
+ char temp[128];
+ //unsigned int labelLen = 0;
+
+ uint8_t valLen = 0;
+ const char *valPtr = NULL;
+
+ //txt version
+ if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "txtvers", &valLen))) return;
+ memcpy(temp, valPtr, valLen);
+ temp[valLen] = '\0';
+ txtver = (short)strtol(temp, NULL, 10);
+
+ //Serial Number
+ if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "serial", &valLen))) return;
+ memcpy(temp, valPtr, valLen);
+ temp[valLen] = '\0';
+ phid->serialNumber = strtol(temp, NULL, 10);
+ phid->specificDevice = PHIDGETOPEN_SERIAL;
+
+ //version
+ if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "version", &valLen))) return;
+ memcpy(temp, valPtr, valLen);
+ temp[valLen] = '\0';
+ phid->deviceVersion = strtol(temp, NULL, 10);
+
+ //label
+ if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "label", &valLen))) return;
+ if(valLen >= MAX_LABEL_STORAGE) valLen = MAX_LABEL_STORAGE-1;
+ memcpy(phid->label, valPtr, valLen);
+ phid->label[valLen] = '\0';
+ /* memcpy(temp, valPtr, valLen);
+ temp[valLen] = '\0';
+ unescape(temp, &label, &labelLen);
+ if(labelLen > MAX_LABEL_STORAGE-1) labelLen = MAX_LABEL_STORAGE-1;
+ memcpy(phid->label, label, labelLen);
+ phid->label[labelLen] = '\0';
+ free(label);*/
+
+ //server_id
+ if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "server_id", &valLen))) return;
+ free(phid->networkInfo->zeroconf_server_id);
+ if(!(phid->networkInfo->zeroconf_server_id = malloc(valLen+1))) return;
+ ZEROMEM(phid->networkInfo->zeroconf_server_id, valLen+1);
+ memcpy(phid->networkInfo->zeroconf_server_id, valPtr, valLen);
+
+ // things added in version 2 of the txt
+ if(txtver >= 2)
+ {
+ //Device ID
+ if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "id", &valLen))) return;
+ memcpy(temp, valPtr, valLen);
+ temp[valLen] = '\0';
+ phid->deviceIDSpec = strtol(temp, NULL, 10);
+
+ for(i = 1;i<PHIDGET_DEVICE_COUNT;i++)
+ if(phid->deviceIDSpec == Phid_Device_Def[i].pdd_sdid) break;
+ phid->deviceDef = &Phid_Device_Def[i];
+ phid->attr = Phid_Device_Def[i].pdd_attr;
+
+ //Device Class
+ if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "class", &valLen))) return;
+ memcpy(temp, valPtr, valLen);
+ temp[valLen] = '\0';
+ phid->deviceID = strtol(temp, NULL, 10);
+ phid->deviceType = Phid_DeviceName[phid->deviceID];
+ }
+ //Old version uses string searching, but some devices have the same name with different IDs
+ else
+ {
+ char *name = NULL;
+ char *type = NULL;
+
+ //name
+ if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "name", &valLen))) return;
+ if(!(name = malloc(valLen+1))) return;
+ ZEROMEM(name, valLen+1);
+ memcpy(name, valPtr, valLen);
+ for(i = 0;i<PHIDGET_DEVICE_COUNT;i++)
+ {
+ if(!strcmp(name, Phid_Device_Def[i].pdd_name))
+ {
+ phid->deviceIDSpec = Phid_Device_Def[i].pdd_sdid;
+ phid->deviceDef = &Phid_Device_Def[i];
+ phid->attr = Phid_Device_Def[i].pdd_attr;
+ break;
+ }
+ }
+ free(name);
+
+ //type
+ if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "type", &valLen))) return;
+ if(!(type = malloc(valLen+1))) return;
+ ZEROMEM(type, valLen+1);
+ memcpy(type, valPtr, valLen);
+ phid->deviceID = phidget_type_to_id(type);
+ phid->deviceType = Phid_DeviceName[phid->deviceID];
+ free(type);
+ }
+
+ phid->deviceUID = CPhidget_getUID(phid->deviceIDSpec, phid->deviceVersion);
+ phid->networkInfo->mdns = PTRUE;
+
+}
+
+void DNSServiceQueryRecord_Phidget_CallBack
+(
+ DNSServiceRef DNSServiceRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ const char *fullname,
+ uint16_t rrtype,
+ uint16_t rrclass,
+ uint16_t rdlen,
+ const void *rdata,
+ uint32_t ttl,
+ void *context
+ )
+{
+ if (errorCode != kDNSServiceErr_NoError)
+ LOG(PHIDGET_LOG_ERROR, "DNSServiceQueryRecord_Phidget_CallBack returned error: %d\n", errorCode);
+ else
+ {
+ CPhidgetHandle phid = (CPhidgetHandle)context;
+ LOG(PHIDGET_LOG_INFO, "DNSServiceQueryRecord_Phidget_CallBack: %s (%d)",fullname,interfaceIndex);
+
+ PhidFromTXT(phid, rdlen, rdata);
+ }
+}
+
+void SBCFromTXT(CPhidgetSBCHandle sbc, uint16_t txtLen, const char *txtRecord)
+{
+ char *hversion = NULL, *txtver = NULL;
+
+ uint8_t valLen = 0;
+ const char *valPtr = NULL;
+
+ //txt version
+ if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "txtvers", &valLen))) return;
+ if(!(txtver = malloc(valLen+1))) return;
+ ZEROMEM(txtver, valLen+1);
+ memcpy(txtver, valPtr, valLen);
+ sbc->txtver = (short)strtol(txtver, NULL, 10);
+ free(txtver);
+
+ //Firmware version
+ if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "fversion", &valLen))) return;
+ if(valLen > 12) valLen = 12;
+ memcpy(sbc->fversion, valPtr, valLen);
+ sbc->fversion[valLen] = '\0';
+
+ //Hardware version
+ if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "hversion", &valLen))) return;
+ if(!(hversion = malloc(valLen+1))) return;
+ ZEROMEM(hversion, valLen+1);
+ memcpy(hversion, valPtr, valLen);
+ sbc->hversion = (short)strtol(hversion, NULL, 10);
+ free(hversion);
+
+ // things added in version 2 of the txt
+ if(sbc->txtver >= 2)
+ {
+ //Hostname
+ if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "hostname", &valLen))) return;
+ if(valLen > 128) valLen = 128;
+ memcpy(sbc->hostname, valPtr, valLen);
+ sbc->hostname[valLen] = '\0';
+ }
+ // things added in version 3 of the txt
+ if(sbc->txtver >= 3)
+ {
+ //Device Name
+ if(!(valPtr = TXTRecordGetValuePtrPtr(txtLen, txtRecord, "name", &valLen))) return;
+ if(valLen > 128) valLen = 128;
+ memcpy(sbc->deviceName, valPtr, valLen);
+ sbc->deviceName[valLen] = '\0';
+ }
+ else
+ {
+ sprintf(sbc->deviceName, "PhidgetSBC");
+ }
+}
+
+void DNSServiceQueryRecord_SBC_CallBack
+(
+ DNSServiceRef DNSServiceRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ const char *fullname,
+ uint16_t rrtype,
+ uint16_t rrclass,
+ uint16_t rdlen,
+ const void *rdata,
+ uint32_t ttl,
+ void *context
+ )
+{
+ if (errorCode != kDNSServiceErr_NoError)
+ LOG(PHIDGET_LOG_ERROR, "DNSServiceQueryRecord_sbc_CallBack returned error: %d\n", errorCode);
+ else
+ {
+ CPhidgetSBCHandle sbc = (CPhidgetSBCHandle)context;
+ LOG(PHIDGET_LOG_INFO, "DNSServiceQueryRecord_sbc_CallBack: %s (%d)",fullname,interfaceIndex);
+
+ SBCFromTXT(sbc, rdlen, rdata);
+ }
+}
+
+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 (%s, %s, %d)",name,type,domain,interfaceIndex);
+
+ 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);
+ phid->networkInfo->zeroconf_interface = interfaceIndex;
+
+ 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))
+ {
+ //prefer local. domain
+ if((strcmp(domain, found_phid->networkInfo->zeroconf_domain) != 0) && !(strcmp(domain, "local.")))
+ {
+ free(found_phid->networkInfo->zeroconf_domain);
+ found_phid->networkInfo->zeroconf_domain = phid->networkInfo->zeroconf_domain;
+ phid->networkInfo->zeroconf_domain = NULL;
+ }
+ 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_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->zeroconf_interface = interfaceIndex;
+ 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
+ {
+ //prefer local. domain
+ if((strcmp(domain, found_sbc->networkInfo->zeroconf_domain) != 0) && !(strcmp(domain, "local.")))
+ {
+ free(found_sbc->networkInfo->zeroconf_domain);
+ found_sbc->networkInfo->zeroconf_domain = sbc->networkInfo->zeroconf_domain;
+ sbc->networkInfo->zeroconf_domain = NULL;
+ }
+ 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);
+ }
+ }
+}
+
+void DNSServiceBrowse_ws_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, "DNSServiceBrowse_ws_CallBack returned error: %d\n", errorCode);
+ else
+ {
+ char fullname[kDNSServiceMaxDomainName];
+
+ 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);
+ networkInfo->zeroconf_interface = interfaceIndex;
+
+ DNSServiceConstructFullNamePtr(fullname, name, type, domain);
+
+ LOG(PHIDGET_LOG_INFO, "DNSServiceBrowse_ws_CallBack: %s (%s, %s, %d)",name,type,domain,interfaceIndex);
+
+ CThread_mutex_lock(&zeroconfServersLock);
+ if(flags & kDNSServiceFlagsAdd)
+ {
+ if(CList_addToList((CListHandle *)&zeroconfServers, networkInfo, CPhidgetRemote_areEqual) != EPHIDGET_OK)
+ CPhidgetRemote_free(networkInfo);
+ }
+ else
+ {
+ CList_removeFromList((CListHandle *)&zeroconfServers, networkInfo, CPhidgetRemote_areEqual, TRUE, CPhidgetRemote_free);
+ }
+ CThread_mutex_unlock(&zeroconfServersLock);
+ }
+}
+
+int cancelPendingZeroconfLookups(CPhidgetRemoteHandle networkInfo)
+{
+ if(networkInfo->zeroconf_ref != NULL)
+ {
+ DNSServiceRefDeallocatePtr((DNSServiceRef)networkInfo->zeroconf_ref);
+ networkInfo->zeroconf_ref = NULL;
+ }
+ return EPHIDGET_OK;
+}
+
+
+void DNSServiceQueryRecord_CallBack
+(
+ DNSServiceRef DNSServiceRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ const char *fullname,
+ uint16_t rrtype,
+ uint16_t rrclass,
+ uint16_t rdlen,
+ const void *rdata,
+ uint32_t ttl,
+ void *context
+ )
+{
+
+ CPhidgetRemoteHandle networkInfo = (CPhidgetRemoteHandle)context;
+
+ if (errorCode != kDNSServiceErr_NoError)
+ {
+ LOG(PHIDGET_LOG_ERROR, "DNSServiceQueryRecord_CallBack returned error: %d\n", errorCode);
+ networkInfo->zeroconf_ipaddr = NULL;
+ }
+ else if(networkInfo->zeroconf_ipaddr == NULL)
+ {
+ if(rrtype == kDNSServiceType_A && rdlen == 4)
+ {
+ struct in_addr ip;
+ memcpy(&ip, rdata, 4);
+
+ networkInfo->zeroconf_ipaddr = strdup(inet_ntoa(ip));
+ }
+ //NOTE: Windows doesn't have inet_ntop
+ /*
+ else if(rrtype == kDNSServiceType_AAAA && rdlen == 16)
+ {
+ struct in6_addr ip;
+ memcpy(&ip, rdata, 16);
+
+ if((networkInfo->zeroconf_ipaddr = malloc(200)) != NULL)
+ {
+ networkInfo->zeroconf_ipaddr = strdup(inet_ntop(AF_INET6, &ip, networkInfo->zeroconf_ipaddr, 200));
+ }
+ }
+ */
+
+ LOG(PHIDGET_LOG_INFO, "DNSServiceQueryRecord_CallBack: %s (%s %d)",fullname, networkInfo->zeroconf_ipaddr, interfaceIndex);
+ }
+ else
+ LOG(PHIDGET_LOG_INFO, "DNSServiceQueryRecord_CallBack (extra, not used): %s (%d)",fullname, interfaceIndex);
+}
+
+int getZeroconfIPAddr(CPhidgetRemoteHandle networkInfo)
+{
+ DNSServiceErrorType error;
+
+ LOG(PHIDGET_LOG_VERBOSE, "Resolving IP Address for: %s, %s, %s, %s, %d",
+ networkInfo->zeroconf_name, //name
+ networkInfo->zeroconf_type, // service type
+ networkInfo->zeroconf_domain, //domain
+ networkInfo->zeroconf_host,
+ networkInfo->zeroconf_interface);
+
+ //already a lookup pending? cancel it and start a new one...
+ CThread_mutex_lock(&networkInfo->zeroconf_ref_lock);
+ if(networkInfo->zeroconf_ref != NULL)
+ {
+ DNSServiceRefDeallocatePtr((DNSServiceRef)networkInfo->zeroconf_ref);
+ networkInfo->zeroconf_ref = NULL;
+ }
+
+ free(networkInfo->zeroconf_ipaddr);
+ networkInfo->zeroconf_ipaddr = NULL;
+
+ error = DNSServiceQueryRecordPtr((DNSServiceRef *)&networkInfo->zeroconf_ref,
+ 0, // no flags
+ networkInfo->zeroconf_interface,
+ networkInfo->zeroconf_host, //hostname
+ kDNSServiceType_A, // IPv4 address for now..
+ kDNSServiceClass_IN, // service class
+ DNSServiceQueryRecord_CallBack,
+ networkInfo);
+ if (error != kDNSServiceErr_NoError)
+ {
+ LOG(PHIDGET_LOG_ERROR, "DNSServiceQueryRecordPtr returned error: %d\n", error);
+ networkInfo->zeroconf_ref = NULL;
+ CThread_mutex_unlock(&networkInfo->zeroconf_ref_lock);
+ return EPHIDGET_NETWORK;
+ }
+ else
+ {
+ DNSServiceProcessResultPtr((DNSServiceRef)networkInfo->zeroconf_ref);
+ DNSServiceRefDeallocatePtr((DNSServiceRef)networkInfo->zeroconf_ref);
+ networkInfo->zeroconf_ref = NULL;
+ CThread_mutex_unlock(&networkInfo->zeroconf_ref_lock);
+ LOG(PHIDGET_LOG_VERBOSE, "Successfull lookup: %s",networkInfo->zeroconf_host);
+ return EPHIDGET_OK;
+ }
+
+}
+
+void DNSServiceResolve_CallBack(
+ DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ const char *fullname,
+ const char *hosttarget,
+ uint16_t port,
+ uint16_t txtLen,
+ const unsigned char *txtRecord,
+ void *context)
+{
+ CPhidgetRemoteHandle networkInfo = (CPhidgetRemoteHandle)context;
+
+
+ if (errorCode != kDNSServiceErr_NoError)
+ {
+ LOG(PHIDGET_LOG_ERROR, "DNSServiceResolve_CallBack returned error: %d\n", errorCode);
+ networkInfo->zeroconf_host = NULL;
+ networkInfo->zeroconf_port = NULL;
+ }
+ else if(!networkInfo->zeroconf_host && !networkInfo->zeroconf_port)
+ {
+
+ LOG(PHIDGET_LOG_INFO, "DNSServiceResolve_CallBack: %s (%s:%d %d)",fullname, hosttarget, ntohs(port), interfaceIndex);
+
+ networkInfo->zeroconf_host = strdup(hosttarget);
+ networkInfo->zeroconf_port = malloc(10);
+ snprintf(networkInfo->zeroconf_port, 10, "%d", ntohs(port));
+ }
+ else
+ LOG(PHIDGET_LOG_INFO, "DNSServiceResolve_CallBack (extra, not used): %s (%s:%d %d)",fullname, hosttarget, ntohs(port), interfaceIndex);
+}
+
+int getZeroconfHostPort(CPhidgetRemoteHandle networkInfo)
+{
+ DNSServiceErrorType error;
+
+ LOG(PHIDGET_LOG_VERBOSE, "Resolving host:port for: %s, %s, %s",
+ networkInfo->zeroconf_name, //name
+ networkInfo->zeroconf_type, // service type
+ networkInfo->zeroconf_domain //domain
+ );
+
+ //already a lookup pending? cancel it and start a new one...
+ CThread_mutex_lock(&networkInfo->zeroconf_ref_lock);
+ if(networkInfo->zeroconf_ref != NULL)
+ {
+ DNSServiceRefDeallocatePtr((DNSServiceRef)networkInfo->zeroconf_ref);
+ networkInfo->zeroconf_ref = NULL;
+ }
+
+ free(networkInfo->zeroconf_host);
+ networkInfo->zeroconf_host = NULL;
+ free(networkInfo->zeroconf_port);
+ networkInfo->zeroconf_port = NULL;
+
+ error = DNSServiceResolvePtr((DNSServiceRef *)&networkInfo->zeroconf_ref,
+ 0, // no flags
+ 0, // all interfaces
+ //networkInfo->zeroconf_interface, // interface this service was discovered on
+ networkInfo->zeroconf_name, //name
+ networkInfo->zeroconf_type, // service type
+ networkInfo->zeroconf_domain, //domain
+ DNSServiceResolve_CallBack,
+ networkInfo); // no context
+ if (error != kDNSServiceErr_NoError)
+ {
+ LOG(PHIDGET_LOG_ERROR, "getZeroconfHostPort returned error: %d\n", error);
+ networkInfo->zeroconf_ref = NULL;
+ CThread_mutex_unlock(&networkInfo->zeroconf_ref_lock);
+ return EPHIDGET_NETWORK;
+ }
+ else
+ {
+ DNSServiceProcessResultPtr((DNSServiceRef)networkInfo->zeroconf_ref);
+ DNSServiceRefDeallocatePtr((DNSServiceRef)networkInfo->zeroconf_ref);
+ networkInfo->zeroconf_ref = NULL;
+ LOG(PHIDGET_LOG_VERBOSE, "Successfull host:port lookup: %s:%s",networkInfo->zeroconf_host,networkInfo->zeroconf_port);
+ CThread_mutex_unlock(&networkInfo->zeroconf_ref_lock);
+ //Don't bother - we aren't going to use it anyways
+ //This is just another way to lookup the IP address - from the DNS record
+ //getZeroconfIPAddr(networkInfo);
+ return EPHIDGET_OK;
+ }
+}
+
+int refreshZeroconf(CPhidgetRemoteHandle networkInfo, DNSServiceQueryRecordReply callBack, void *userPtr)
+{
+ DNSServiceErrorType error;
+ char fullname[kDNSServiceMaxDomainName];
+
+ LOG(PHIDGET_LOG_VERBOSE, "Refreshing zeroconf on: 0x%x",networkInfo);
+
+ //already a lookup pending? cancel it and start a new one...
+ CThread_mutex_lock(&networkInfo->zeroconf_ref_lock);
+
+ DNSServiceConstructFullNamePtr(fullname, networkInfo->zeroconf_name, networkInfo->zeroconf_type, networkInfo->zeroconf_domain);
+
+ if(networkInfo->zeroconf_ref != NULL)
+ {
+ DNSServiceRefDeallocatePtr((DNSServiceRef)networkInfo->zeroconf_ref);
+ networkInfo->zeroconf_ref = NULL;
+ }
+ error = DNSServiceQueryRecordPtr((DNSServiceRef *)&networkInfo->zeroconf_ref,
+ 0, // no flags
+ networkInfo->zeroconf_interface,
+ fullname, //name
+ kDNSServiceType_TXT, // service type
+ kDNSServiceClass_IN, // service class
+ callBack,
+ userPtr);
+ if (error != kDNSServiceErr_NoError)
+ {
+ LOG(PHIDGET_LOG_ERROR, "DNSServiceQueryRecordPtr returned error: %d\n", error);
+ networkInfo->zeroconf_ref = NULL;
+ CThread_mutex_unlock(&networkInfo->zeroconf_ref_lock);
+ return EPHIDGET_NETWORK;
+ }
+ else
+ {
+ DNSServiceProcessResultPtr((DNSServiceRef)networkInfo->zeroconf_ref);
+ DNSServiceRefDeallocatePtr((DNSServiceRef)networkInfo->zeroconf_ref);
+ networkInfo->zeroconf_ref = NULL;
+ CThread_mutex_unlock(&networkInfo->zeroconf_ref_lock);
+ LOG(PHIDGET_LOG_VERBOSE, "Successfull refresh.");
+ return EPHIDGET_OK;
+ }
+}
+
+int refreshZeroconfSBC(CPhidgetSBCHandle sbc)
+{
+ return refreshZeroconf(sbc->networkInfo, DNSServiceQueryRecord_SBC_CallBack, sbc);
+}
+
+int refreshZeroconfPhidget(CPhidgetHandle phid)
+{
+ return refreshZeroconf(phid->networkInfo, DNSServiceQueryRecord_Phidget_CallBack, phid);
+}
+
+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;
+}
+
+int UninitializeZeroconf()
+{
+ void *status;
+ CThread_mutex_lock(&zeroconfInitLock);
+ if(Dns_sdBrowsing)
+ {
+ stopBrowsing = TRUE;
+ if(dns_thread)
+ {
+ pthread_join(dns_thread, &status);
+ dns_thread = NULL;
+ }
+
+ if(zeroconf_browse_ws_ref)
+ {
+ DNSServiceRefDeallocatePtr(zeroconf_browse_ws_ref);
+ zeroconf_browse_ws_ref = NULL;
+ }
+ if(zeroconf_browse_sbc_ref)
+ {
+ DNSServiceRefDeallocatePtr(zeroconf_browse_sbc_ref);
+ zeroconf_browse_sbc_ref = NULL;
+ }
+ if(zeroconf_browse_phidget_ref)
+ {
+ DNSServiceRefDeallocatePtr(zeroconf_browse_phidget_ref);
+ zeroconf_browse_phidget_ref = NULL;
+ }
+
+ CThread_mutex_lock(&zeroconfPhidgetsLock);
+ CList_emptyList((CListHandle *)&zeroconfPhidgets, FALSE, NULL);
+ CThread_mutex_unlock(&zeroconfPhidgetsLock);
+
+ CThread_mutex_lock(&zeroconfSBCsLock);
+ CList_emptyList((CListHandle *)&zeroconfSBCs, FALSE, NULL);
+ CThread_mutex_unlock(&zeroconfSBCsLock);
+
+ CThread_mutex_lock(&zeroconfServersLock);
+ CList_emptyList((CListHandle *)&zeroconfServers, FALSE, NULL);
+ CThread_mutex_unlock(&zeroconfServersLock);
+
+ Dns_sdBrowsing = FALSE;
+ }
+ CThread_mutex_unlock(&zeroconfInitLock);
+ return EPHIDGET_OK;
+}
+
+
|