Example #1
0
// netservice browser callback - calls whenever service is discovered
void ofxBonjourIp::NetServiceBrowserCallBack(CFNetServiceBrowserRef browser,CFOptionFlags flags,CFTypeRef domainOrService,CFStreamError* error,void* info) {
    ofLog() << "----------------------";
    
    if(error->error != 0) {
        ofLog() << "Error: " << error->error;
        return;
    }
    
    // unresovled still... but can get type and domain (pointless)
    CFNetServiceRef netServiceRef = (CFNetServiceRef) domainOrService; // casting to this thing
    
    
    //service removed/closed
    if (flags & kCFNetServiceFlagRemove) {
        ofLog() << "Service was removed.";
        if(info != NULL) {
            
            // notify service has been removed
            ofxBonjourIp* bonjour = (ofxBonjourIp*)info;
            ofNotifyEvent(bonjour->removedServiceEvent,bonjour->serverIp,bonjour); 
            
            // reset
            bonjour->serverHostName = "";
            bonjour->serverIp = "";
            bonjour->connectedToService = false;
            
            // dont know if i need this? maybe causing a crash after long period of time. I don't think it's been added to the run loop yet either
            //CFNetServiceUnscheduleFromRunLoop(netServiceRef, CFRunLoopGetCurrent(),kCFRunLoopCommonModes);
            //CFNetServiceSetClient(netServiceRef, NULL, NULL);
        }
        return;
    }
    
    // the 'flags' property = 8 when it closes, and 0 when it opens. let's use that for now?
    /*if(flags != 0) {
     ofLog() << "Flag error/ service closed elsewhere (8): " << flags;
     return;
     }*/
    
    
    
    // resolve the service
    CFNetServiceClientContext clientContext = { 0, info, NULL, NULL, NULL };
    CFNetServiceSetClient(netServiceRef, ofxBonjourIp::NetServiceResolvedCallBack, &clientContext);
    CFNetServiceScheduleWithRunLoop(netServiceRef, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
    
    if(!CFNetServiceResolveWithTimeout(netServiceRef, 0, NULL)) {
        ofLog() << "Error resolving service";

        CFNetServiceUnscheduleFromRunLoop(netServiceRef, CFRunLoopGetCurrent(),kCFRunLoopCommonModes);
        CFNetServiceSetClient(netServiceRef, NULL, NULL);
    }
}
Example #2
0
void ofxBonjourIp::startService( string type, string name, int port, string domain ){
    
    // format parameters
    CFStringRef serviceType = CFStringCreateWithCString(kCFAllocatorDefault, type.c_str(), kCFStringEncodingUTF8);
    CFStringRef serviceName =  CFStringCreateWithCString(kCFAllocatorDefault, name.c_str(), kCFStringEncodingUTF8); // if empty becomes device name
    SInt32 chosenPort = (SInt32) port;
    CFStringRef serviceDomain = CFStringCreateWithCString(kCFAllocatorDefault, domain.c_str(), kCFStringEncodingUTF8);
    
    // start service- async
    netService = CFNetServiceCreate(kCFAllocatorDefault, serviceDomain, serviceType, serviceName, chosenPort);
    CFNetServiceScheduleWithRunLoop(netService, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
    
    // creat a client context for a callback function when service successfully publishes
    CFNetServiceClientContext clientContext = { 0, this, NULL, NULL, NULL };
    CFNetServiceSetClient(netService, ofxBonjourIp::NetServicePublishedCallBack, &clientContext); //CFNetServiceSetClient(netService, registerCallback, &clientContext);
    
    
    if (!CFNetServiceRegisterWithOptions(netService, kCFNetServiceFlagNoAutoRename, NULL)) {
        stopService();
        ofLog() << "Could not register Bonjour service";
    }
    
    // do i need to do this?
    CFRelease(serviceType);
    CFRelease(serviceName);
    CFRelease(serviceDomain);
}
Example #3
0
void CZeroconfOSX::cancelRegistration(CFNetServiceRef theService)
{
  assert(theService != NULL);
  CFNetServiceUnscheduleFromRunLoop(theService, m_runloop, kCFRunLoopCommonModes);
  CFNetServiceSetClient(theService, NULL, NULL);
  CFNetServiceCancel(theService);
  CFRelease(theService);
}
Example #4
0
static void
bonjour_stop_service(CFNetServiceRef *svc)
{
  CFNetServiceUnscheduleFromRunLoop(*svc, CFRunLoopGetCurrent(), 
                                    kCFRunLoopCommonModes);
  CFNetServiceSetClient(*svc, NULL, NULL);  
  CFRelease(*svc);
}
Example #5
0
//methods to implement for concrete implementations
bool CZeroconfOSX::doPublishService(const std::string& fcr_identifier,
                                    const std::string& fcr_type,
                                    const std::string& fcr_name,
                                    unsigned int f_port)
{
    CLog::Log(LOGDEBUG, "CZeroconfOSX::doPublishService identifier: %s type: %s name:%s port:%i", fcr_identifier.c_str(),
              fcr_type.c_str(), fcr_name.c_str(), f_port);

    CFStringRef name = CFStringCreateWithCString (NULL,
                       assemblePublishedName(fcr_name).c_str(),
                       kCFStringEncodingUTF8
                                                 );
    CFStringRef type = CFStringCreateWithCString (NULL,
                       fcr_type.c_str(),
                       kCFStringEncodingUTF8
                                                 );
    CFNetServiceRef netService = CFNetServiceCreate(NULL, CFSTR(""), type, name, f_port);
    CFRelease(name);
    CFRelease(type);

    //now register it
    CFNetServiceClientContext clientContext = { 0, this, NULL, NULL, NULL };

    CFStreamError error;
    CFNetServiceSetClient(netService, registerCallback, &clientContext);
    CFNetServiceScheduleWithRunLoop(netService, m_runloop, kCFRunLoopCommonModes);

    Boolean result = CFNetServiceRegisterWithOptions (netService, 0, &error);
    if (result == false)
    {
        // Something went wrong so lets clean up.
        CFNetServiceUnscheduleFromRunLoop(netService, m_runloop, kCFRunLoopCommonModes);
        CFNetServiceSetClient(netService, NULL, NULL);
        CFRelease(netService);
        netService = NULL;
        CLog::Log(LOGERROR, "CZeroconfOSX::doPublishService CFNetServiceRegister returned (domain = %d, error = %ld)\n", (int)error.domain, error.error);
    } else
    {
        CSingleLock lock(m_data_guard);
        m_services.insert(make_pair(fcr_identifier, netService));
    }

    return result;
}
Example #6
0
void ofxBonjourIp::stopService(){
    
    if(netService) {
        CFNetServiceCancel(netService);
        CFNetServiceUnscheduleFromRunLoop(netService, CFRunLoopGetCurrent(),kCFRunLoopCommonModes);
        CFNetServiceSetClient(netService, NULL, NULL);
        CFRelease(netService);
        netService = NULL;
    }
}
Example #7
0
/* extern */ void
_CFTypeInvalidate(CFTypeRef obj) {

	CFTypeID t = CFGetTypeID(obj);

	/* Invalidate according to type of object. */
	if (t == CFRunLoopSourceGetTypeID()) {
		CFRunLoopSourceInvalidate((CFRunLoopSourceRef)obj);
	}

	else if (t == CFMachPortGetTypeID()) {
		CFMachPortInvalidate((CFMachPortRef)obj);
	}

	else if (t == CFSocketGetTypeID()) {
		CFSocketInvalidate((CFSocketRef)obj);
	}

	/* For scheduled types of objects, it is invalidated by setting the client to NULL. */
	else if (t == CFReadStreamGetTypeID()) {
		CFReadStreamSetClient((CFReadStreamRef)obj, kCFStreamEventNone, NULL, NULL);
	}

	else if (t == CFWriteStreamGetTypeID()) {
		CFWriteStreamSetClient((CFWriteStreamRef)obj, kCFStreamEventNone, NULL, NULL);
	}

	else if (t == CFHostGetTypeID()) {
		CFHostSetClient((CFHostRef)obj, NULL, NULL);
	}

	else if (t == SCNetworkReachabilityGetTypeID()) {
		SCNetworkReachabilitySetCallback((SCNetworkReachabilityRef)obj, NULL, NULL);
	}

	else if (t == CFRunLoopTimerGetTypeID()) {
		CFRunLoopTimerInvalidate((CFRunLoopTimerRef)obj);
	}

	else if (t == CFNetServiceGetTypeID()) {
		CFNetServiceSetClient((CFNetServiceRef)obj, NULL, NULL);
	}

	else if (t == CFNetServiceBrowserGetTypeID()) {
		CFNetServiceBrowserInvalidate((CFNetServiceBrowserRef)obj);
	}

	else if (t == CFNetServiceMonitorGetTypeID()) {
		CFNetServiceMonitorInvalidate((CFNetServiceMonitorRef)obj);
	}

	else if (t == SCNetworkReachabilityGetTypeID()) {
		SCNetworkConnectionStop((SCNetworkConnectionRef)obj, FALSE);
	}
}
Example #8
0
/* static */ void
_ServerReleaseNetService(Server* server) {
	
	// Unschedule, cancel, and release the net service if there is one.
	if (server->_service != NULL) {
		CFNetServiceUnscheduleFromRunLoop(server->_service, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
		CFNetServiceSetClient(server->_service, NULL, NULL);
		CFNetServiceCancel(server->_service);
		CFRelease(server->_service);
		server->_service = NULL;
	}
}
Example #9
0
static void
bonjour_start_service(CFNetServiceRef *svc, char *service_type,
                      uint32_t port, txt_rec_t *txt)
{
  CFStringRef str;
  CFStreamError error = {0};
  CFNetServiceClientContext context = {0, NULL, NULL, NULL, NULL};
  
  str = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, service_type,
                                        kCFStringEncodingASCII,
                                        kCFAllocatorNull);

  *svc = CFNetServiceCreate(NULL, CFSTR(""), str, CFSTR("Tvheadend"), port);
  if (!*svc) {
    tvhlog(LOG_ERR, "bonjour", "service creation failed"); 
    return;
  }

  CFNetServiceSetClient(*svc, bonjour_callback, &context);
  CFNetServiceScheduleWithRunLoop(*svc, CFRunLoopGetCurrent(),
                                  kCFRunLoopCommonModes);

  if (txt) {
    CFDataRef data = NULL;
    CFMutableDictionaryRef dict;
    dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
                                     &kCFTypeDictionaryValueCallBacks);
    
    while(txt->key) {
      str = CFStringCreateWithCString (NULL, txt->key, kCFStringEncodingASCII);
      data = CFDataCreate (NULL, (uint8_t *) txt->value, strlen(txt->value));
      CFDictionaryAddValue(dict, str, data);
      txt++;
    }
    
    data = CFNetServiceCreateTXTDataWithDictionary(NULL, dict);
    CFNetServiceSetTXTData(*svc, data);
    CFRelease(data);
    CFRelease(dict);
  }

  if (!CFNetServiceRegisterWithOptions(*svc, 0, &error))
    tvhlog(LOG_ERR, "bonjour", "registration failed (service type = %s, "
           "domain = %ld, error =%d)", service_type, error.domain, error.error); 
  else
    tvhlog(LOG_INFO, "bonjour", "service '%s' successfully established",
           service_type);
}
Example #10
0
//methods to implement for concrete implementations
bool CZeroconfOSX::doPublishService(const std::string& fcr_identifier,
                      const std::string& fcr_type,
                      const std::string& fcr_name,
                      unsigned int f_port,
                      std::map<std::string, std::string> txt)
{
  CLog::Log(LOGDEBUG, "CZeroconfOSX::doPublishService identifier: %s type: %s name:%s port:%i", fcr_identifier.c_str(),
            fcr_type.c_str(), fcr_name.c_str(), f_port);

  CFStringRef name = CFStringCreateWithCString (NULL,
                                                fcr_name.c_str(),
                                                kCFStringEncodingUTF8
                                                );
  CFStringRef type = CFStringCreateWithCString (NULL,
                                                fcr_type.c_str(),
                                                kCFStringEncodingUTF8
                                                );
  CFNetServiceRef netService = CFNetServiceCreate(NULL, CFSTR(""), type, name, f_port);
  CFRelease(name);
  CFRelease(type);

  //now register it
  CFNetServiceClientContext clientContext = { 0, this, NULL, NULL, NULL };

  CFStreamError error;
  CFNetServiceSetClient(netService, registerCallback, &clientContext);
  CFNetServiceScheduleWithRunLoop(netService, m_runloop, kCFRunLoopCommonModes);

  //add txt records
  if(!txt.empty())
  {
    //txt map to dictionary
    CFDataRef txtData = NULL;
    CFMutableDictionaryRef txtDict = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);    
    for(std::map<std::string, std::string>::const_iterator it = txt.begin(); it != txt.end(); ++it)
    {
      CFStringRef key = CFStringCreateWithCString (NULL,
                                                   it->first.c_str(),
                                                   kCFStringEncodingUTF8
                                                  );
      CFDataRef value = CFDataCreate              ( NULL,
                                                    (UInt8 *)it->second.c_str(),
                                                    strlen(it->second.c_str())
                                                  );
                                                  
      CFDictionaryAddValue(txtDict,key, value);
    }    
    
    //add txt records to service
    txtData = CFNetServiceCreateTXTDataWithDictionary(NULL, txtDict);
    CFNetServiceSetTXTData(netService, txtData);
    CFRelease(txtData);
    CFRelease(txtDict);
  }

  Boolean result = CFNetServiceRegisterWithOptions (netService, 0, &error);
  if (result == false)
  {
    // Something went wrong so lets clean up.
    CFNetServiceUnscheduleFromRunLoop(netService, m_runloop, kCFRunLoopCommonModes);
    CFNetServiceSetClient(netService, NULL, NULL);
    CFRelease(netService);
    netService = NULL;
    CLog::Log(LOGERROR, "CZeroconfOSX::doPublishService CFNetServiceRegister returned "
      "(domain = %d, error = %"PRId64")", (int)error.domain, (int64_t)error.error);
  } else
  {
    CSingleLock lock(m_data_guard);
    m_services.insert(make_pair(fcr_identifier, netService));
  }

  return result;
}
Example #11
0
void ofxBonjourIp::NetServiceResolvedCallBack(CFNetServiceRef theService, CFStreamError* error, void* info) {
    
    //ofLog() << "netService resolved";
    bool serviceResolved = false;
    if(error->error != 0) ofLog() << "Error: " << error->error;
    
    CFArrayRef addresses = CFNetServiceGetAddressing(theService);
    struct sockaddr * socketAddress = NULL;
    
    for(int i=0; i < CFArrayGetCount(addresses); i++) {
        
        // error stopped here once!
        socketAddress = (struct sockaddr *) CFDataGetBytePtr((CFDataRef)CFArrayGetValueAtIndex(addresses, i));
        
        /* Only continue if this is an IPv4 address. */
        //|| socketAddress->sa_family == AF_INET6 ) == 0.0.0.0
        if (socketAddress && socketAddress->sa_family == AF_INET && info != NULL) {
            string addr = inet_ntoa(((struct sockaddr_in *)socketAddress)->sin_addr); // pdp_ip0
            int port = ntohs(((struct sockaddr_in *)socketAddress)->sin_port);
            
            // don't connect to self or 127.0.0.1 or 0.0.0.0
            ofxBonjourIp* bonjour = (ofxBonjourIp*)info;
            if(addr != "0.0.0.0" && addr != "127.0.0.1" && addr != bonjour->deviceIp) {
                
                serviceResolved = true;
                ofLog() << "* Successful connection: " << addr << ", " << port;
                // info has a reference to the class object
                
                // set the server ip
                bonjour->serverIp = addr;
                bonjour->serverHostName = CFStringGetCStringPtr(CFNetServiceGetTargetHost(theService), kCFStringEncodingMacRoman);
                bonjour->connectedToService = true;
                
                ofNotifyEvent(bonjour->discoveredServiceEvent,bonjour->serverIp,bonjour);
                
            } else {
                ofLog() << "Not connecting to self: " << addr << ", " << port;
            }
            
            
        }
    }
    
    // all the service details
    /*const char *host = CFStringGetCStringPtr(CFNetServiceGetTargetHost(theService), kCFStringEncodingMacRoman); //trents-MacBook-Pro.local
     ofLog() << "host: " << host;
     const char *type = CFStringGetCStringPtr(CFNetServiceGetType(theService), kCFStringEncodingMacRoman); //_ofxBonjourIp._tcp.
     ofLog() << "type: " << type;
     const char *domain = CFStringGetCStringPtr(CFNetServiceGetDomain(theService), kCFStringEncodingMacRoman); //local.
     ofLog() << "domain: " << domain;
     int port = CFNetServiceGetPortNumber(theService); //7777
     ofLog() << "port: " << port;
     const char *name = CFStringGetCStringPtr(CFNetServiceGetName(theService), kCFStringEncodingMacRoman);
     ofLog() << "name: " << name; // name is "" if not defined. should become device name once resolved?*/
    
    
    // release stuff (loop and callback)
    if(!serviceResolved) {
        CFNetServiceUnscheduleFromRunLoop(theService, CFRunLoopGetCurrent(),kCFRunLoopCommonModes);
        CFNetServiceSetClient(theService, NULL, NULL);
    }
    //CFNetServiceUnscheduleFromRunLoop(theService, CFRunLoopGetCurrent(),kCFRunLoopCommonModes);
    //CFNetServiceSetClient(theService, NULL, NULL);
    //CFRelease(theService); breaks stuff
    //CFRelease(addresses);
}
Example #12
0
/* static */ Boolean
_ServerCreateAndRegisterNetService(Server* server) {

	do {
        UInt32 port = server->_port;
		Boolean didSet, didRegister;
		CFNetServiceClientContext netSvcCtxt = {0,
												server,
												(CFAllocatorRetainCallBack)&CFRetain,
												(CFAllocatorReleaseCallBack)&CFRelease,
												(CFAllocatorCopyDescriptionCallBack)&CFCopyDescription};
        
        // If the port was unspecified, get the port from the socket.
        if (port == 0) {
            
            // Get the local address
            CFDataRef addr = CFSocketCopyAddress(server->_sockets[0]);
            struct sockaddr_in* nativeAddr = (struct sockaddr_in*)CFDataGetBytePtr(addr);
            
            CFRelease(addr);
            
            port = ntohs(nativeAddr->sin_port);
        }
        
        // Create the service for registration.
        server->_service = CFNetServiceCreate(CFGetAllocator((_CFServerRef)server),
                                              _kCFServerEmptyString,
                                              server->_type,
                                              server->_name,
                                              port);
        
		// Require the service for the socket.
		if (server->_service == NULL)
			break;
					
		// Try setting the client on the service.
		didSet = CFNetServiceSetClient(server->_service,
									   (CFNetServiceClientCallBack)&_NetServiceCallBack,
									   &netSvcCtxt);
	
		// Check to make sure it set before registering.
		if (!didSet)
			break;
	
		// Schedule the service on the run loop.
		CFNetServiceScheduleWithRunLoop(server->_service, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
			
		// Start the registration.
		didRegister = CFNetServiceRegisterWithOptions(server->_service, 0, NULL);
		
		// If registration failed, die.
		if (!didRegister)
			break;
			
		return TRUE;
	
    } while (0);
    
	// Failed to set up the service, so clean up anything that succeeded.
	_ServerReleaseNetService(server);
	
    return FALSE;
}