* cups_block_cb() - Enumeration callback for block API.
* cups_compare_dests() - Compare two destinations.
* cups_dnssd_browse_cb() - Browse for printers.
+ * cups_dnssd_browse_cb() - Browse for printers.
+ * cups_dnssd_client_cb() - Avahi client callback function.
* cups_dnssd_compare_device() - Compare two devices.
* cups_dnssd_free_device() - Free the memory used by a device.
* cups_dnssd_get_device() - Lookup a device and create it as needed.
* cups_dnssd_local_cb() - Browse for local printers.
+ * cups_dnssd_poll_cb() - Wait for input on the specified file
+ * descriptors.
* cups_dnssd_query_cb() - Process query data.
- * cups_dnssd_resolve() - Resolve a Bonjour printer URI.
- * cups_dnssd_resolve_cb() - See if we should continue resolving.
+ * cups_dnssd_resolve() - Resolve a Bonjour printer URI.
+ * cups_dnssd_resolve_cb() - See if we should continue resolving.
* cups_dnssd_unquote() - Unquote a name string.
* cups_find_dest() - Find a destination using a binary search.
* cups_get_default() - Get the default destination from an
# include <dns_sd.h>
#endif /* HAVE_DNSSD */
+#ifdef HAVE_AVAHI
+# include <avahi-client/client.h>
+# include <avahi-client/lookup.h>
+# include <avahi-common/simple-watch.h>
+# include <avahi-common/domain.h>
+# include <avahi-common/error.h>
+# include <avahi-common/malloc.h>
+#define kDNSServiceMaxDomainName AVAHI_DOMAIN_NAME_MAX
+#endif /* HAVE_AVAHI */
+
/*
* Constants...
* Types...
*/
-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
typedef enum _cups_dnssd_state_e /* Enumerated device state */
{
_CUPS_DNSSD_NEW,
typedef struct _cups_dnssd_data_s /* Enumeration data */
{
+# ifdef HAVE_DNSSD
DNSServiceRef main_ref; /* Main service reference */
+# else /* HAVE_AVAHI */
+ AvahiSimplePoll *simple_poll; /* Polling interface */
+ AvahiClient *client; /* Client information */
+ int got_data; /* Did we get data? */
+# endif /* HAVE_DNSSD */
cups_dest_cb_t cb; /* Callback */
void *user_data; /* User data pointer */
cups_ptype_t type, /* Printer type filter */
typedef struct _cups_dnssd_device_s /* Enumerated device */
{
_cups_dnssd_state_t state; /* State of device listing */
+# ifdef HAVE_DNSSD
DNSServiceRef ref; /* Service reference for query */
+# else /* HAVE_AVAHI */
+ AvahiRecordBrowser *ref; /* Browser for query */
+# endif /* HAVE_DNSSD */
char *domain, /* Domain name */
*fullName, /* Full name */
*regtype; /* Registration type */
static CFArrayRef appleCopyLocations(void);
static CFStringRef appleCopyNetwork(void);
static char *appleGetPaperSize(char *name, int namesize);
-static CFStringRef appleGetPrinter(CFArrayRef locations, CFStringRef network,
- CFIndex *locindex);
+static CFStringRef appleGetPrinter(CFArrayRef locations,
+ CFStringRef network, CFIndex *locindex);
#endif /* __APPLE__ */
static cups_dest_t *cups_add_dest(const char *name, const char *instance,
int *num_dests, cups_dest_t **dests);
cups_dest_t *dest);
#endif /* __BLOCKS__ */
static int cups_compare_dests(cups_dest_t *a, cups_dest_t *b);
-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
+# ifdef HAVE_DNSSD
static void cups_dnssd_browse_cb(DNSServiceRef sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
const char *regtype,
const char *replyDomain,
void *context);
+# else /* HAVE_AVAHI */
+static void cups_dnssd_browse_cb(AvahiServiceBrowser *browser,
+ AvahiIfIndex interface,
+ AvahiProtocol protocol,
+ AvahiBrowserEvent event,
+ const char *serviceName,
+ const char *regtype,
+ const char *replyDomain,
+ AvahiLookupResultFlags flags,
+ void *context);
+static void cups_dnssd_client_cb(AvahiClient *client,
+ AvahiClientState state,
+ void *context);
+# endif /* HAVE_DNSSD */
static int cups_dnssd_compare_devices(_cups_dnssd_device_t *a,
_cups_dnssd_device_t *b);
static void cups_dnssd_free_device(_cups_dnssd_device_t *device,
const char *serviceName,
const char *regtype,
const char *replyDomain);
+# ifdef HAVE_DNSSD
static void cups_dnssd_local_cb(DNSServiceRef sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
uint16_t rrtype, uint16_t rrclass,
uint16_t rdlen, const void *rdata,
uint32_t ttl, void *context);
+# else /* HAVE_AVAHI */
+static int cups_dnssd_poll_cb(struct pollfd *pollfds,
+ unsigned int num_pollfds,
+ int timeout, void *context);
+static void cups_dnssd_query_cb(AvahiRecordBrowser *browser,
+ AvahiIfIndex interface,
+ AvahiProtocol protocol,
+ AvahiBrowserEvent event,
+ const char *name, uint16_t rrclass,
+ uint16_t rrtype, const void *rdata,
+ size_t rdlen,
+ AvahiLookupResultFlags flags,
+ void *context);
+# endif /* HAVE_DNSSD */
static const char *cups_dnssd_resolve(cups_dest_t *dest, const char *uri,
int msec, int *cancel,
cups_dest_cb_t cb, void *user_data);
static int cups_dnssd_resolve_cb(void *context);
static void cups_dnssd_unquote(char *dst, const char *src,
size_t dstsize);
-#endif /* HAVE_DNSSD */
+#endif /* HAVE_DNSSD || HAVE_AVAHI */
static int cups_find_dest(const char *name, const char *instance,
int num_dests, cups_dest_t *dests, int prev,
int *rdiff);
num_dests; /* Number of destinations */
cups_dest_t *dests = NULL, /* Destinations */
*dest; /* Current destination */
-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
int nfds, /* Number of files responded */
count, /* Number of queries started */
remaining; /* Remainder of timeout */
_cups_dnssd_data_t data; /* Data for callback */
_cups_dnssd_device_t *device; /* Current device */
+# ifdef HAVE_DNSSD
int main_fd; /* File descriptor for lookups */
DNSServiceRef ipp_ref, /* IPP browser */
local_ipp_ref; /* Local IPP browser */
-# ifdef HAVE_SSL
+# ifdef HAVE_SSL
DNSServiceRef ipps_ref, /* IPPS browser */
local_ipps_ref; /* Local IPPS browser */
-# endif /* HAVE_SSL */
-# ifdef HAVE_POLL
+# endif /* HAVE_SSL */
+# ifdef HAVE_POLL
struct pollfd pfd; /* Polling data */
-# else
+# else
fd_set input; /* Input set for select() */
struct timeval timeout; /* Timeout for select() */
-# endif /* HAVE_POLL */
-#endif /* HAVE_DNSSD */
-
+# endif /* HAVE_POLL */
+# else /* HAVE_AVAHI */
+ int error; /* Error value */
+ AvahiServiceBrowser *ipp_ref; /* IPP browser */
+# ifdef HAVE_SSL
+ AvahiServiceBrowser *ipps_ref; /* IPPS browser */
+# endif /* HAVE_SSL */
+# endif /* HAVE_DNSSD */
+#endif /* HAVE_DNSSD || HAVE_AVAHI */
/*
* Range check input...
if (i > 0 || msec == 0)
return (1);
-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
/*
* Get Bonjour-shared printers...
*/
NULL, NULL, 0, NULL,
(cups_afree_func_t)cups_dnssd_free_device);
+# ifdef HAVE_DNSSD
if (DNSServiceCreateConnection(&data.main_ref) != kDNSServiceErr_NoError)
return (0);
"_ipp._tcp,_cups", NULL,
(DNSServiceBrowseReply)cups_dnssd_local_cb, &data);
-# ifdef HAVE_SSL
+# ifdef HAVE_SSL
ipps_ref = data.main_ref;
DNSServiceBrowse(&ipps_ref, kDNSServiceFlagsShareConnection, 0,
"_ipps._tcp,_cups", NULL,
kDNSServiceInterfaceIndexLocalOnly,
"_ipps._tcp,_cups", NULL,
(DNSServiceBrowseReply)cups_dnssd_local_cb, &data);
-# endif /* HAVE_SSL */
+# endif /* HAVE_SSL */
+
+# else /* HAVE_AVAHI */
+ if ((data.simple_poll = avahi_simple_poll_new()) == NULL)
+ {
+ DEBUG_puts("cupsEnumDests: Unable to create Avahi simple poll object.");
+ return (1);
+ }
+
+ avahi_simple_poll_set_func(data.simple_poll, cups_dnssd_poll_cb, &data);
+
+ data.client = avahi_client_new(avahi_simple_poll_get(data.simple_poll),
+ 0, cups_dnssd_client_cb, &data,
+ &error);
+ if (!data.client)
+ {
+ DEBUG_puts("cupsEnumDests: Unable to create Avahi client.");
+ avahi_simple_poll_free(data.simple_poll);
+ return (1);
+ }
+
+ ipp_ref = avahi_service_browser_new(data.client, AVAHI_IF_UNSPEC,
+ AVAHI_PROTO_UNSPEC, "_ipp._tcp", NULL,
+ 0, cups_dnssd_browse_cb, &data);
+# ifdef HAVE_SSL
+ ipps_ref = avahi_service_browser_new(data.client, AVAHI_IF_UNSPEC,
+ AVAHI_PROTO_UNSPEC, "_ipps._tcp", NULL,
+ 0, cups_dnssd_browse_cb, &data);
+# endif /* HAVE_SSL */
+# endif /* HAVE_DNSSD */
if (msec < 0)
remaining = INT_MAX;
* Check for input...
*/
-# ifdef HAVE_POLL
+# ifdef HAVE_DNSSD
+# ifdef HAVE_POLL
pfd.fd = main_fd;
pfd.events = POLLIN;
nfds = poll(&pfd, 1, remaining > 250 ? 250 : remaining);
-# else
+# else
FD_ZERO(&input);
FD_SET(main_fd, &input);
timeout.tv_usec = remaining > 250 ? 250000 : remaining * 1000;
nfds = select(main_fd + 1, &input, NULL, NULL, &timeout);
-# endif /* HAVE_POLL */
+# endif /* HAVE_POLL */
if (nfds > 0)
DNSServiceProcessResult(data.main_ref);
else if (nfds == 0)
remaining -= 250;
+# else /* HAVE_AVAHI */
+ data.got_data = 0;
+
+ if ((error = avahi_simple_poll_iterate(data.simple_poll, 500)) > 0)
+ {
+ /*
+ * We've been told to exit the loop. Perhaps the connection to
+ * Avahi failed.
+ */
+
+ break;
+ }
+# endif /* HAVE_DNSSD */
+
for (device = (_cups_dnssd_device_t *)cupsArrayFirst(data.devices),
count = 0;
device;
if (!device->ref && device->state == _CUPS_DNSSD_NEW)
{
- device->ref = data.main_ref;
-
DEBUG_printf(("1cupsEnumDests: Querying '%s'.", device->fullName));
+# ifdef HAVE_DNSSD
+ device->ref = data.main_ref;
+
if (DNSServiceQueryRecord(&(device->ref),
kDNSServiceFlagsShareConnection,
0, device->fullName,
DEBUG_puts("1cupsEnumDests: Query failed.");
}
+
+# else /* HAVE_AVAHI */
+ if ((device->ref = avahi_record_browser_new(data.client,
+ AVAHI_IF_UNSPEC,
+ AVAHI_PROTO_UNSPEC,
+ device->fullName,
+ AVAHI_DNS_CLASS_IN,
+ AVAHI_DNS_TYPE_TXT,
+ 0,
+ cups_dnssd_query_cb,
+ &data)) != NULL)
+ {
+ count ++;
+ }
+ else
+ {
+ device->state = _CUPS_DNSSD_ERROR;
+
+ DEBUG_printf(("1cupsEnumDests: Query failed: %s",
+ avahi_strerror(avahi_client_errno(data.client))));
+ }
+# endif /* HAVE_DNSSD */
}
else if (device->ref && device->state == _CUPS_DNSSD_PENDING)
{
cupsArrayDelete(data.devices);
+# ifdef HAVE_DNSSD
DNSServiceRefDeallocate(ipp_ref);
DNSServiceRefDeallocate(local_ipp_ref);
-# ifdef HAVE_SSL
+# ifdef HAVE_SSL
DNSServiceRefDeallocate(ipp_ref);
DNSServiceRefDeallocate(local_ipp_ref);
-# endif /* HAVE_SSL */
+# endif /* HAVE_SSL */
DNSServiceRefDeallocate(data.main_ref);
-#endif /* HAVE_DNSSD */
+
+# else /* HAVE_AVAHI */
+ avahi_service_browser_free(ipp_ref);
+# ifdef HAVE_SSL
+ avahi_service_browser_free(ipps_ref);
+# endif /* HAVE_SSL */
+
+ avahi_client_free(data.client);
+ avahi_simple_poll_free(data.simple_poll);
+# endif /* HAVE_DNSSD */
+#endif /* HAVE_DNSSD || HAVE_DNSSD */
return (1);
}
}
-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
+# ifdef HAVE_DNSSD
/*
* 'cups_dnssd_browse_cb()' - Browse for printers.
*/
}
+# else /* HAVE_AVAHI */
+/*
+ * 'cups_dnssd_browse_cb()' - Browse for printers.
+ */
+
+static void
+cups_dnssd_browse_cb(
+ AvahiServiceBrowser *browser, /* I - Browser */
+ AvahiIfIndex interface, /* I - Interface index (unused) */
+ AvahiProtocol protocol, /* I - Network protocol (unused) */
+ AvahiBrowserEvent event, /* I - What happened */
+ const char *name, /* I - Service name */
+ const char *type, /* I - Registration type */
+ const char *domain, /* I - Domain */
+ AvahiLookupResultFlags flags, /* I - Flags */
+ void *context) /* I - Devices array */
+{
+ AvahiClient *client = avahi_service_browser_get_client(browser);
+ /* Client information */
+ _cups_dnssd_data_t *data = (_cups_dnssd_data_t *)context;
+ /* Enumeration data */
+
+
+ (void)interface;
+ (void)protocol;
+ (void)context;
+
+ switch (event)
+ {
+ case AVAHI_BROWSER_FAILURE:
+ DEBUG_printf(("cups_dnssd_browse_cb: %s",
+ avahi_strerror(avahi_client_errno(client))));
+ avahi_simple_poll_quit(data->simple_poll);
+ break;
+
+ case AVAHI_BROWSER_NEW:
+ /*
+ * This object is new on the network.
+ */
+
+ if (flags & AVAHI_LOOKUP_RESULT_LOCAL)
+ {
+ /*
+ * This comes from the local machine so ignore it.
+ */
+
+ DEBUG_printf(("cups_dnssd_browse_cb: Ignoring local service \"%s\".",
+ name));
+ }
+ else
+ {
+ /*
+ * Create a device entry for it if it doesn't yet exist.
+ */
+
+ cups_dnssd_get_device(data, name, type, domain);
+ }
+ break;
+
+ case AVAHI_BROWSER_REMOVE:
+ case AVAHI_BROWSER_ALL_FOR_NOW:
+ case AVAHI_BROWSER_CACHE_EXHAUSTED:
+ break;
+ }
+}
+
+
+/*
+ * 'cups_dnssd_client_cb()' - Avahi client callback function.
+ */
+
+static void
+cups_dnssd_client_cb(
+ AvahiClient *client, /* I - Client information (unused) */
+ AvahiClientState state, /* I - Current state */
+ void *context) /* I - User data (unused) */
+{
+ _cups_dnssd_data_t *data = (_cups_dnssd_data_t *)context;
+ /* Enumeration data */
+
+
+ (void)client;
+
+ /*
+ * If the connection drops, quit.
+ */
+
+ if (state == AVAHI_CLIENT_FAILURE)
+ {
+ DEBUG_puts("cups_dnssd_client_cb: Avahi connection failed.");
+ avahi_simple_poll_quit(data->simple_poll);
+ }
+}
+# endif /* HAVE_DNSSD */
+
+
/*
* 'cups_dnssd_compare_device()' - Compare two devices.
*/
DEBUG_printf(("5cups_dnssd_free_device(device=%p(%s), data=%p)", device,
device->dest.name, data));
+# ifdef HAVE_DNSSD
if (device->ref)
DNSServiceRefDeallocate(device->ref);
+# else /* HAVE_AVAHI */
+ if (device->ref)
+ avahi_record_browser_free(device->ref);
+# endif /* HAVE_DNSSD */
_cupsStrFree(device->domain);
_cupsStrFree(device->fullName);
* Set the "full name" of this service, which is used for queries...
*/
+# ifdef HAVE_DNSSD
DNSServiceConstructFullName(fullName, device->dest.name, device->regtype,
device->domain);
+# else /* HAVE_AVAHI */
+ avahi_service_name_join(fullName, kDNSServiceMaxDomainName, serviceName,
+ regtype, replyDomain);
+# endif /* HAVE_DNSSD */
+
_cupsStrFree(device->fullName);
device->fullName = _cupsStrAlloc(fullName);
if (device->ref)
{
+# ifdef HAVE_DNSSD
DNSServiceRefDeallocate(device->ref);
+# else /* HAVE_AVAHI */
+ avahi_record_browser_free(device->ref);
+# endif /* HAVE_DNSSD */
+
device->ref = 0;
}
}
+# ifdef HAVE_DNSSD
/*
* 'cups_dnssd_local_cb()' - Browse for local printers.
*/
device->state = _CUPS_DNSSD_LOCAL;
}
+# endif /* HAVE_DNSSD */
+
+
+# ifdef HAVE_AVAHI
+/*
+ * 'cups_dnssd_poll_cb()' - Wait for input on the specified file descriptors.
+ *
+ * Note: This function is needed because avahi_simple_poll_iterate is broken
+ * and always uses a timeout of 0 (!) milliseconds.
+ * (Avahi Ticket #364)
+ */
+
+static int /* O - Number of file descriptors matching */
+poll_callback(
+ struct pollfd *pollfds, /* I - File descriptors */
+ unsigned int num_pollfds, /* I - Number of file descriptors */
+ int timeout, /* I - Timeout in milliseconds (unused) */
+ void *context) /* I - User data (unused) */
+{
+ _cups_dnssd_data_t *data = (_cups_dnssd_data_t *)context;
+ /* Enumeration data */
+ int val; /* Return value */
+
+
+ (void)timeout;
+
+ val = poll(pollfds, num_pollfds, 500);
+
+ if (val < 0)
+ {
+ DEBUG_printf(("cups_dnssd_poll_cb: %s", strerror(errno)));
+ }
+ else if (val > 0)
+ data->got_data = 1;
+
+ return (val);
+}
+# endif /* HAVE_AVAHI */
/*
* 'cups_dnssd_query_cb()' - Process query data.
*/
+# ifdef HAVE_DNSSD
static void
cups_dnssd_query_cb(
DNSServiceRef sdRef, /* I - Service reference */
uint32_t ttl, /* I - Time-to-live */
void *context) /* I - Enumeration data */
{
+# else /* HAVE_AVAHI */
+static void
+cups_dnssd_query_cb(
+ AvahiRecordBrowser *browser, /* I - Record browser */
+ AvahiIfIndex interfaceIndex,
+ /* I - Interface index (unused) */
+ AvahiProtocol protocol, /* I - Network protocol (unused) */
+ AvahiBrowserEvent event, /* I - What happened? */
+ const char *fullName, /* I - Service name */
+ uint16_t rrclass, /* I - Record class */
+ uint16_t rrtype, /* I - Record type */
+ const void *rdata, /* I - TXT record */
+ size_t rdlen, /* I - Length of TXT record */
+ AvahiLookupResultFlags flags, /* I - Flags */
+ void *context) /* I - Enumeration data */
+{
+ AvahiClient *client = avahi_record_browser_get_client(browser);
+ /* Client information */
+# endif /* HAVE_DNSSD */
_cups_dnssd_data_t *data = (_cups_dnssd_data_t *)context;
/* Enumeration data */
char name[1024], /* Service name */
*device; /* Device */
+# ifdef HAVE_DNSSD
DEBUG_printf(("5cups_dnssd_query_cb(sdRef=%p, flags=%x, "
"interfaceIndex=%d, errorCode=%d, fullName=\"%s\", "
"rrtype=%u, rrclass=%u, rdlen=%u, rdata=%p, ttl=%u, "
if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd))
return;
+# else /* HAVE_AVAHI */
+ DEBUG_printf(("5cups_dnssd_query_cb(browser=%p, interfaceIndex=%d, "
+ "protocol=%d, event=%d, fullName=\"%s\", rrclass=%u, "
+ "rrtype=%u, rdata=%p, rdlen=%u, flags=%x, context=%p)",
+ browser, interfaceIndex, protocol, event, fullName, rrclass,
+ rrtype, rdata, (unsigned)rdlen, flags, context));
+
+ /*
+ * Only process "add" data...
+ */
+
+ if (event != AVAHI_BROWSER_NEW)
+ {
+ if (event == AVAHI_BROWSER_FAILURE)
+ DEBUG_printf(("cups_dnssd_query_cb: %s",
+ avahi_strerror(avahi_client_errno(client))));
+
+ return;
+ }
+# endif /* HAVE_DNSSD */
+
/*
* Lookup the service in the devices array.
*/
if ((device = cupsArrayFind(data->devices, &dkey)) != NULL)
{
/*
- * Found it, pull out the priority and make and model from the TXT
- * record and save it...
+ * Found it, pull out the make and model from the TXT record and save it...
*/
const uint8_t *txt, /* Pointer into data */