I went back to remind myself about bonjour.
The key resources are this book: https://learning.oreilly.com/library/view/zero-configuration-networking/0596101007/ (chapters 6 and 7 are the most useful if you want to jump straight in)
and this https://developer.apple.com/bonjour/ (the linked video is particularly helpful from what I remember)
This is a quick command line app I wrote with JUCE that runs for 10 seconds printing any services it finds. It checks every second if there are any results to process, if there are and a service has been added or removed the callback function serviceAddedOrRemoved
will be called.
Unfortunately I couldn’t find a way to use anything in JUCE to avoid using low level sockets. Ideally something like waitForReadiness
in juce_Socket.cpp
would be used but it isn’t exposed.
#include <JuceHeader.h>
#include <dns_sd.h>
//==============================================================================
class DNSServiceProcessor : private juce::Thread
{
public:
DNSServiceProcessor (DNSServiceRef serviceRef)
: juce::Thread {"DNSServiceProcessor"}
, service {serviceRef}
{
startThread();
}
~DNSServiceProcessor()
{
stopThread (1500);
}
private:
void run() override
{
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
const int dns_sd_fd {DNSServiceRefSockFD (service)};
fd_set readfds;
while ( ! threadShouldExit())
{
FD_ZERO (&readfds);
FD_SET (dns_sd_fd, &readfds);
if (select (dns_sd_fd + 1, &readfds, nullptr, nullptr, &tv) > 0)
{
if (FD_ISSET (dns_sd_fd, &readfds))
DNSServiceProcessResult (service);
}
}
}
DNSServiceRef service;
};
//==============================================================================
void serviceAddedOrRemoved (DNSServiceRef sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
DNSServiceErrorType errorCode,
const char* serviceName,
const char* regtype,
const char* replyDomain,
void* context)
{
DBG (((flags & kDNSServiceFlagsAdd) ? "Added: " : "Removed: ") << serviceName);
}
//==============================================================================
int main (int argc, char* argv[])
{
DNSServiceRef service;
if (DNSServiceBrowse (&service, 0, 0, "_osc._udp", nullptr, &serviceAddedOrRemoved, nullptr) == kDNSServiceErr_NoError)
{
DNSServiceProcessor serviceProcessor {service};
Thread::sleep (10000); // run the program for 10 seconds
}
return 0;
}
You can test this by running this the following in another terminal…
timeout 2s dns-sd -R "OSC Test" _osc._udp local 9904
This will create a service called "_osc._udp"
in the local
domain on port 9904
and then 2 seconds later it quits the process which removes the service.