mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2025-10-25 12:27:18 +02:00
Update libraries and make it build on windows.
Still gets some warnings because compilers have changed. But should work.
This commit is contained in:
406
vendor/POCO/DNSSD/doc/00200-DNSSDTutorialAndUserGuide.page
vendored
Normal file
406
vendor/POCO/DNSSD/doc/00200-DNSSDTutorialAndUserGuide.page
vendored
Normal file
@@ -0,0 +1,406 @@
|
||||
DNS-SD Tuturial And User Guide
|
||||
DNS-SD
|
||||
|
||||
!!!Introduction
|
||||
|
||||
The POCO DNS-SD POCO library provides an easy-to-use and
|
||||
unified programming interface for integrating Zeroconf features
|
||||
(service discovery and host name resolution) into a C++ application.
|
||||
The Applied Informatics DNS-SD library does not
|
||||
implement its own mDNS and DNS-SD protocol stacks, but rather uses
|
||||
an existing Zeroconf implementation for that purpose. Apple's Bonjour
|
||||
and Avahi can be used as backend for the DNS-SD library.
|
||||
|
||||
A great advantage of the library is that it provides a unified
|
||||
programming interface. For the programmer, it's completely
|
||||
transparent whether Avahi or Bonjour is used as backend.
|
||||
|
||||
|
||||
!!!Programming Basics
|
||||
|
||||
The DNS-SD library provides an asynchronous programming interface.
|
||||
This means that the application starts a browse or resolve operation
|
||||
by calling a member function of the Poco::DNSSD::DNSSDBrowser class,
|
||||
and this function returns immediately. The actual browse or resolve
|
||||
operation (which involves sending queries over the network and
|
||||
receiving responses from other hosts) is carried out in a separate
|
||||
thread, and as soon as results become available, these are reported
|
||||
to the application via events.
|
||||
|
||||
|
||||
!!Event Handlers
|
||||
|
||||
The event handlers registered by the application should
|
||||
complete their work and return as quick as possible, otherwise they may
|
||||
interfere with DNS-SD processing. Event handlers should never
|
||||
wait for other events to happen. Specifically, they must never
|
||||
wait for an other DNSSDBrowser event to happen, as this will
|
||||
result in a deadlock.
|
||||
|
||||
|
||||
!!Service Types
|
||||
|
||||
Service types (or registration types) are the most important concept when
|
||||
handling with DNS Service Discovery. A service type consists of a
|
||||
short name (maximum of 15 characters) specifying the protocol implemented
|
||||
by the service (prepended by an underscore), followed by a dot, followed
|
||||
by a name identifying the primary transport protocol, which is either
|
||||
"_tcp" or "_udp". Service types should be registered at <[dns-sd.org]>.
|
||||
A list of currently registered service types, as well as information on how
|
||||
to register a new service type can be found at the
|
||||
[[http://www.dns-sd.org/ServiceTypes.html DNS-SD website]].
|
||||
|
||||
Examples for service types are "_daap._tcp" (Digital Audio Access Protocol,
|
||||
the protocol used by iTunes music sharing), "_http._tcp" (web server)
|
||||
or "_printer._tcp" for a printing service.
|
||||
|
||||
Service names are not case sensitive.
|
||||
|
||||
|
||||
!!!Programming Tasks
|
||||
|
||||
In the following sections, the basic programming Tasks
|
||||
that need to be performed when working with the DNS-SD library
|
||||
are described.
|
||||
|
||||
|
||||
!!Initializing the DNS-SD Library
|
||||
|
||||
The DNS-SD core library only defines the classes that are part
|
||||
of the programming interfaces, it does not provide an actual
|
||||
implementation of these interfaces. So, in addition to the DNS-SD
|
||||
core library, a backend library must be linked with the application
|
||||
as well. Depending on which backend library is used, either Apple's
|
||||
Bonjour or Avahi will be used.
|
||||
|
||||
Before the DNS-SD library can be used it must be initialized.
|
||||
This is done by calling the Poco::DNSSD::initializeDNSSD() function.
|
||||
This function is actually defined implemented in a backend library,
|
||||
so the backend libraries's header file must be included.
|
||||
|
||||
It is good practice to control which backend header is being
|
||||
included via the preprocessor. For a cross-platform application,
|
||||
one would use Avahi on Linux platforms and Bonjour on Mac OS X and
|
||||
Windows platforms.
|
||||
|
||||
Typically, the <[#include]> statements for the DNS-SD library
|
||||
would be as follows:
|
||||
|
||||
#include "Poco/DNSSD/DNSSDResponder.h"
|
||||
#include "Poco/DNSSD/DNSSDBrowser.h"
|
||||
#if POCO_OS == POCO_OS_LINUX && !defined(POCO_DNSSD_USE_BONJOUR)
|
||||
#include "Poco/DNSSD/Avahi/Avahi.h"
|
||||
#else
|
||||
#include "Poco/DNSSD/Bonjour/Bonjour.h"
|
||||
#endif
|
||||
----
|
||||
|
||||
These statements will include the header files for the Poco::DNSSD::DNSSDResponder
|
||||
and Poco::DNSSD::DNSSDBrowser classes, as well as the core header
|
||||
file for a backend. Note that an application that only registers a service,
|
||||
but does not browse for services, does not need to include the
|
||||
<*Poco/DNSSD/DNSSDBrowser.h*> header file.
|
||||
|
||||
The Poco::DNSSD::initializeDNSSD() function must be called before an
|
||||
instance of the Poco::DNSSD::DNSSDResponder class is created. If the
|
||||
application uses the Poco::Util::Application class (or its server
|
||||
counterpart), this can happen in the constructor of the application
|
||||
subclass. It is also good practice to uninitialize the DNS-SD library
|
||||
when the application exits by calling Poco::DNSSD::uninitializeDNSSD(),
|
||||
which can be done in the application class destructor.
|
||||
|
||||
After initializing the DNS-SD library, the application should
|
||||
create an instance of the Poco::DNSSD::DNSSDResponder class.
|
||||
This class provides the main entry point into the DNS-SD library.
|
||||
Although it is possible to create more than one instance of
|
||||
the Poco::DNSSD::DNSSDResponder class, application programmers
|
||||
should refrain from doing so. The Poco::DNSSD::DNSSDResponder
|
||||
object should be kept alive during the entire lifetime of
|
||||
the application, or at least as long as DNS-SD services
|
||||
are required.
|
||||
|
||||
After the responder object has been created, its <[start()]> method
|
||||
must be called. This will start a thread that handles all
|
||||
DNS-SD related network activity for the application.
|
||||
|
||||
Similarly, when the application terminates, or when DNS-SD
|
||||
services are no longer required, the <[stop()]> method should
|
||||
be called to orderly shut-down the background thread.
|
||||
|
||||
|
||||
!!Registering A Service
|
||||
|
||||
Registering a service, and thus making it discoverable to other
|
||||
DNS-SD capable applications, is a two step process.
|
||||
First, an instance of Poco::DNSSD::Service must be created
|
||||
and properly initialized. At least the following information
|
||||
must be specified:
|
||||
|
||||
- the service type (e.g., "_http._tcp"), and
|
||||
- the port number of the service.
|
||||
|
||||
Other information can be specified, but defaults will be
|
||||
used if not. This includes:
|
||||
|
||||
- The service name, which defaults to the local hosts's machine name.
|
||||
- The network interface (by its interface index), on which the
|
||||
service shall be announced. The default is to announce the
|
||||
service on all interfaces (interface index is zero).
|
||||
- The domain, on which the service will be announced.
|
||||
- The domain name of the host providing the service.
|
||||
- Service properties, which will be announced in the TXT
|
||||
record of the service.
|
||||
|
||||
The service properties (basically, a list of key-value pairs)
|
||||
can be used to provide additional information
|
||||
necessary for invoking the service. These will be announced along
|
||||
with the basic service information (host name, port number, etc.).
|
||||
The content of the service properties is specific to the application
|
||||
or network protocol the application uses.
|
||||
When specifying service properties, a few restrictions must be
|
||||
considered:
|
||||
|
||||
- The total length of a key-value pair must not exceed 254 bytes.
|
||||
- The total length of all key-value pairs, including two additional
|
||||
bytes for each pair, must not exceed 65535 bytes.
|
||||
- The length of the key should not exceed nine bytes.
|
||||
- Values can contain text strings or arbitrary binary values, and
|
||||
can also be empty.
|
||||
|
||||
|
||||
The following code shows how to register and publish a HTTP server
|
||||
(running on port 8080) on a Zeroconf network:
|
||||
|
||||
Poco::DNSSD::DNSSDResponder dnssdResponder;
|
||||
dnssdResponder.start();
|
||||
|
||||
Poco::DNSSD::Service service("_http._tcp", 8080);
|
||||
Poco::DNSSD::ServiceHandle serviceHandle = dnssdResponder.registerService(service);
|
||||
----
|
||||
|
||||
Another example, the following code shows how to register
|
||||
and publish a network postscript-capable printer on a Zeroconf network.
|
||||
|
||||
Poco::DNSSD::DNSSDResponder dnssdResponder;
|
||||
dnssdResponder.start();
|
||||
|
||||
Poco::DNSSD::Service::Properties props;
|
||||
props.add("txtvers", "1");
|
||||
props.add("pdl", "application/postscript");
|
||||
props.add("qtotal", "1");
|
||||
props.add("rp", "ThePrinter");
|
||||
props.add("ty", "A Postscript Printer");
|
||||
Poco::DNSSD::Service service(0, "The Printer", "", "_printer._tcp", "", "", 515, props);
|
||||
Poco::DNSSD::ServiceHandle serviceHandle = dnssdResponder.registerService(service);
|
||||
----
|
||||
|
||||
!Unregistering A Service
|
||||
|
||||
The <[registerService()]> method returns a Poco::DNSSD::ServiceHandle object.
|
||||
This object is used to unregister the service when it's no longer available,
|
||||
by passing it as argument to the <[unregisterService()]> method.
|
||||
|
||||
dnssdResponder.unregisterService(serviceHandle);
|
||||
----
|
||||
|
||||
|
||||
!Handling Registration Errors
|
||||
|
||||
The above code examples don't do a very good job of error handling.
|
||||
Registration on the network may fail for various reasons.
|
||||
The Poco::DNSSD::DNSSDResponder class provides two events that can be
|
||||
used to check the status of a service registration.
|
||||
If the registration was successful, the <[serviceRegistered]> event
|
||||
will be fired. If registration failed, the <[serviceRegistrationFailed]>
|
||||
event will be fired. Please see the class documentation for a
|
||||
description of the available event arguments.
|
||||
|
||||
Usually, there's not much an application can do when service registration
|
||||
fails. This is especially true for embedded devices, which often don't
|
||||
even have a way to communicate this error to the user. However, an application
|
||||
should at least log a registration error in a log file, to help with
|
||||
error diagnostics.
|
||||
|
||||
Handling the <[serviceRegistered]> event is only necessary if the application
|
||||
needs to know the actual service name used to announce the service.
|
||||
In case of a name conflict (duplicate service names on the network), the
|
||||
name specified when registering the service may have been changed by
|
||||
the Bonjour or Avahi backend.
|
||||
|
||||
The following example shows an event handler (delegate) function for handling
|
||||
registration errors.
|
||||
|
||||
void onError(const void* sender, const Poco::DNSSD::DNSSDResponder::ErrorEventArgs& args)
|
||||
{
|
||||
std::cerr
|
||||
<< "Service registration failed: "
|
||||
<< args.error.message()
|
||||
<< " (" << args.error.code() << ")"
|
||||
<< std::endl;
|
||||
}
|
||||
----
|
||||
|
||||
To register this function as delegate for the <[serviceRegistrationFailed]> event:
|
||||
|
||||
dnssdResponder.serviceRegistrationFailed += Poco::delegate(onError);
|
||||
----
|
||||
|
||||
|
||||
!!Browsing For Services
|
||||
|
||||
To discover available services of a specific type on the network, a browse operation
|
||||
for a specific service type must be initiated. For this purpose, the
|
||||
Poco::DNSSD::DNSSDBrowser class is used. An instance of this class can be obtained
|
||||
from the Poco::DNSSD::DNSSDResponder object, by calling the <[browswer()]> method.
|
||||
|
||||
After a browse operation for a service type has been started, services becoming
|
||||
available or unavailable will be reported via events. A service that has been
|
||||
discovered will be reported via the <[serviceFound]> event.
|
||||
If a service is no longer available, it will be reported via the <[serviceRemoved]>
|
||||
event. The name, type and domain of the discovered service can be obtained from the
|
||||
Poco::DNSSD::Service object passed as event argument.
|
||||
|
||||
The following sample shows how to write a delegate function for
|
||||
the <[serviceFound]> event.
|
||||
|
||||
void onServiceFound(const void* sender, const Poco::DNSSD::DNSSDBrowser::ServiceEventArgs& args)
|
||||
{
|
||||
std::cout << "Service Found: \n"
|
||||
<< " Name: " << args.service.name() << "\n"
|
||||
<< " Domain: " << args.service.domain() << "\n"
|
||||
<< " Type: " << args.service.type() << "\n"
|
||||
<< " Interface: " << args.service.networkInterface() << "\n" << std::endl;
|
||||
}
|
||||
----
|
||||
|
||||
The next sample shows how to start a browse operation:
|
||||
|
||||
Poco::DNSSD::DNSSDResponder dnssdResponder;
|
||||
dnssdResponder.start();
|
||||
|
||||
dnssdResponder.browser().serviceFound += Poco::delegate(onServiceFound);
|
||||
Poco::DNSSD::BrowseHandle bh = dnssdResponder.browser().browse("_printer._tcp", "");
|
||||
----
|
||||
|
||||
Poco::DNSSD::DNSSDBrowser::browse() returns a Poco::DNSSD::BrowseHandle object, which can
|
||||
later be used to cancel a browse operation, by passing it to the <[cancel()]> method, as
|
||||
shown in the following example:
|
||||
|
||||
dnssdResponder.browser().cancel(bh);
|
||||
----
|
||||
|
||||
After a service has been discovered, the next step is resolving the service, to obtain
|
||||
its host name, port number and properties, so that the service can be invoked.
|
||||
|
||||
|
||||
!!Resolving A Service
|
||||
|
||||
Like browsing for services, resolving a service is an asynchronous operation.
|
||||
A resolve operation is started with a call to <[resolve()]>, passing the
|
||||
Poco::DNSSD::Service object obtained from the <[serviceFound]> event as
|
||||
argument. Once the service has been resolved, the result is reported via
|
||||
the <[serviceResolved]> event. The resolve operation can be started
|
||||
directly from the <[serviceFound]> event handler, as shown in the
|
||||
following sample:
|
||||
|
||||
void onServiceFound(const void* sender, const Poco::DNSSD::DNSSDBrowser::ServiceEventArgs& args)
|
||||
{
|
||||
std::cout << "Service Found: \n"
|
||||
<< " Name: " << args.service.name() << "\n"
|
||||
<< " Domain: " << args.service.domain() << "\n"
|
||||
<< " Type: " << args.service.type() << "\n"
|
||||
<< " Interface: " << args.service.networkInterface() << "\n" << std::endl;
|
||||
|
||||
reinterpret_cast<Poco::DNSSD::DNSSDBrowser*>(const_cast<void*>(sender))->resolve(args.service);
|
||||
}
|
||||
----
|
||||
|
||||
After a successful resolve, the service host name, port number and properties
|
||||
are available through the Poco::DNSSD::Service object passed to the event handler,
|
||||
as shown in the sample below:
|
||||
|
||||
void onServiceResolved(const void* sender, const Poco::DNSSD::DNSSDBrowser::ServiceEventArgs& args)
|
||||
{
|
||||
std::cout << "Service Resolved: \n"
|
||||
<< " Name: " << args.service.name() << "\n"
|
||||
<< " Full Name: " << args.service.fullName() << "\n"
|
||||
<< " Domain: " << args.service.domain() << "\n"
|
||||
<< " Type: " << args.service.type() << "\n"
|
||||
<< " Interface: " << args.service.networkInterface() << "\n"
|
||||
<< " Host: " << args.service.host() << "\n"
|
||||
<< " Port: " << args.service.port() << "\n"
|
||||
<< " Properties: \n";
|
||||
|
||||
for (Poco::DNSSD::Service::Properties::ConstIterator it = args.service.properties().begin(); it != args.service.properties().end(); ++it)
|
||||
{
|
||||
std::cout << " " << it->first << ": " << it->second << "\n";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
----
|
||||
|
||||
Of course, the event delegate for the <[serviceResolved]> event must be registered:
|
||||
|
||||
dnssdResponder.browser().serviceResolved += Poco::delegate(onServiceResolved);
|
||||
----
|
||||
|
||||
|
||||
!!Resolving A Service's Host Name
|
||||
|
||||
The last step necessary before invoking a service is to resolve the service's host name
|
||||
into an IP address. On systems where mDNS is integrated into the DNS resolver (e.g.,
|
||||
Mac OS X, Windows with Bonjour or most Linux distributions with Avahi), this
|
||||
can simply be done by creating a Poco::Net::SocketAddress instance from the service's
|
||||
host name and port number. However if the systems's DNS resolver cannot handle
|
||||
Multicast DNS queries, the host name must be resolved through the
|
||||
Poco::DNSSD::DNSSDBrowser::resolveHost() method. Like resolving a service, resolving
|
||||
a host name is an asynchronous operation, and the result will be reported via
|
||||
an event -- the <[hostResolved]> event.
|
||||
|
||||
The following sample shows how to implement the delegate function for the
|
||||
<[hostResolved]> event:
|
||||
|
||||
void onHostResolved(const void* sender, const Poco::DNSSD::DNSSDBrowser::ResolveHostEventArgs& args)
|
||||
{
|
||||
std::cout << "Host Resolved: \n"
|
||||
<< " Host: " << args.host << "\n"
|
||||
<< " Interface: " << args.networkInterface << "\n"
|
||||
<< " Address: " << args.address.toString() << "\n"
|
||||
<< " TTL: " << args.ttl << "\n" << std::endl;
|
||||
}
|
||||
----
|
||||
|
||||
Like with resolving a service, it is possible to initiate resolving a host name directly
|
||||
from within the event delegate for the <[serviceResolved]> event.
|
||||
|
||||
|
||||
!!!Advanced Programming Tasks
|
||||
|
||||
!!Enumerating Domains
|
||||
|
||||
Available domains for browsing and registration can be enumerated by calling the
|
||||
Poco::DNSSD::DNSSDBrowser::enumerateBrowseDomains() and
|
||||
Poco::DNSSD::DNSSDBrowser::enumerateRegistrationDomains() methods. As usual,
|
||||
results are reported via events.
|
||||
|
||||
|
||||
!!Registering And Browsing For Records
|
||||
|
||||
Additional DNS records for a specific service can be published on a Zeroconf network
|
||||
by invoking the Poco::DNSSD::DNSSDResponder::addRecord() method. It is also possible
|
||||
to alter a published record, or remove it. Records can be queried by invoking
|
||||
Poco::DNSSD::DNSSDBrowser::queryRecord(). Results are reported via
|
||||
events.
|
||||
|
||||
|
||||
!!Enumerating Available Service Types
|
||||
|
||||
It is possible to enumerate all available services types on a domain by
|
||||
browsing for the special service type "_services._dns-sd._udp".
|
||||
|
||||
Results will be reported via the <[serviceDiscovered]> event.
|
||||
The service type (without the primary transport protocol part,
|
||||
as in "_http") can be obtained from the service name stored
|
||||
in the Poco::DNSSD::Service object passed as event argument.
|
||||
The primary transport protocol and the domain can be obtained
|
||||
from the service type.
|
||||
Reference in New Issue
Block a user