diff -up cups-1.5.0/backend/dnssd.c.avahi-2-backend cups-1.5.0/backend/dnssd.c --- cups-1.5.0/backend/dnssd.c.avahi-2-backend 2011-08-05 15:04:46.182591844 +0100 +++ cups-1.5.0/backend/dnssd.c 2011-08-05 15:05:13.868710181 +0100 @@ -15,14 +15,21 @@ * * Contents: * + * next_txt_record() - Get next TXT record from a cups_txt_records_t. + * parse_txt_record_pair() - Read key/value pair in cups_txt_records_t. * main() - Browse for printers. * browse_callback() - Browse devices. * browse_local_callback() - Browse local devices. * compare_devices() - Compare two devices. * exec_backend() - Execute the backend that corresponds to the * resolved service name. + * device_type() - Get DNS-SD type enumeration from string. * get_device() - Create or update a device. * query_callback() - Process query data. + * avahi_client_callback() - Avahi client callback function. + * avahi_query_callback() - Avahi query callback function. + * avahi_browse_callback() - Avahi browse callback function. + * find_device() - Find a device from its name and domain. * sigterm_handler() - Handle termination signals... * unquote() - Unquote a name string. */ @@ -33,7 +40,18 @@ #include "backend-private.h" #include -#include +#ifdef HAVE_DNSSD +# include +#endif /* HAVE_DNSSD */ +#ifdef HAVE_AVAHI +# include +# include +# include +# include +# include +# include +#define kDNSServiceMaxDomainName AVAHI_DOMAIN_NAME_MAX +#endif /* HAVE_AVAHI */ /* @@ -53,7 +71,12 @@ typedef enum typedef struct { +#ifdef HAVE_DNSSD DNSServiceRef ref; /* Service reference for resolve */ +#endif /* HAVE_DNSSD */ +#ifdef HAVE_AVAHI + int resolved; /* Did we resolve the device? */ +#endif /* HAVE_AVAHI */ char *name, /* Service name */ *domain, /* Domain name */ *fullName, /* Full name */ @@ -65,6 +88,20 @@ typedef struct sent; /* Did we list the device? */ } cups_device_t; +typedef struct +{ + char key[256]; + char value[256]; + +#ifdef HAVE_DNSSD + const uint8_t *data; + const uint8_t *datanext; + const uint8_t *dataend; +#else /* HAVE_AVAHI */ + AvahiStringList *txt; +#endif /* HAVE_DNSSD */ +} cups_txt_records_t; + /* * Local globals... @@ -78,6 +115,7 @@ static int job_canceled = 0; * Local functions... */ +#ifdef HAVE_DNSSD static void browse_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, @@ -93,12 +131,6 @@ static void browse_local_callback(DNSSe const char *regtype, const char *replyDomain, void *context); -static int compare_devices(cups_device_t *a, cups_device_t *b); -static void exec_backend(char **argv); -static cups_device_t *get_device(cups_array_t *devices, - const char *serviceName, - const char *regtype, - const char *replyDomain); static void query_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, @@ -107,9 +139,118 @@ static void query_callback(DNSServiceRe uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, void *context); +#endif /* HAVE_DNSSD */ +#ifdef HAVE_AVAHI +static void avahi_client_callback (AvahiClient *client, + AvahiClientState state, + void *context); +static void avahi_browse_callback (AvahiServiceBrowser *browser, + AvahiIfIndex interface, + AvahiProtocol protocol, + AvahiBrowserEvent event, + const char *serviceName, + const char *regtype, + const char *replyDomain, + AvahiLookupResultFlags flags, + void *context); +#endif /* HAVE_AVAHI */ + +static cups_device_t * find_device (cups_array_t *devices, + cups_txt_records_t *txt, + cups_device_t *dkey); +static int compare_devices(cups_device_t *a, cups_device_t *b); +static void exec_backend(char **argv); +static cups_device_t *get_device(cups_array_t *devices, + const char *serviceName, + const char *regtype, + const char *replyDomain); static void sigterm_handler(int sig); static void unquote(char *dst, const char *src, size_t dstsize); +#ifdef HAVE_AVAHI +static AvahiSimplePoll *simple_poll = NULL; +static int avahi_got_callback; +#endif /* HAVE_AVAHI */ + + +/* + * 'next_txt_record()' - Get next TXT record from a cups_txt_records_t. + */ + +static cups_txt_records_t * +next_txt_record (cups_txt_records_t *txt) +{ +#ifdef HAVE_DNSSD + txt->data = txt->datanext; +#else /* HAVE_AVAHI */ + txt->txt = avahi_string_list_get_next (txt->txt); + if (txt->txt == NULL) + return NULL; +#endif /* HAVE_DNSSD */ + + return txt; +} + + +/* + * 'parse_txt_record_pair()' - Read key/value pair in cups_txt_records_t. + */ + +static int +parse_txt_record_pair (cups_txt_records_t *txt) +{ +#ifdef HAVE_DNSSD + uint8_t datalen; + uint8_t *data = txt->data; + char *ptr; + + /* + * Read a key/value pair starting with an 8-bit length. Since the + * length is 8 bits and the size of the key/value buffers is 256, we + * don't need to check for overflow... + */ + + datalen = *data++; + if (!datalen || (data + datalen) >= txt->dataend) + return NULL; + txt->datanext = data + datalen; + + for (ptr = txt->key; data < txt->datanext && *data != '='; data ++) + *ptr++ = *data; + *ptr = '\0'; + + if (data < txt->datanext && *data == '=') + { + data++; + + if (data < datanext) + memcpy (txt->value, data, txt->datanext - data); + value[txt->datanext - data] = '\0'; + } + else + return 1; +#else /* HAVE_AVAHI */ + char *key, *value; + size_t len; + avahi_string_list_get_pair (txt->txt, &key, &value, &len); + if (len > sizeof (txt->value) - 1) + len = sizeof (txt->value) - 1; + + memcpy (txt->value, value, len); + txt->value[len] = '\0'; + len = strlen (key); + if (len > sizeof (txt->key) - 1) + len = sizeof (txt->key) - 1; + + memcpy (txt->key, key, len); + txt->key[len] = '\0'; + avahi_free (key); + avahi_free (value); +#endif /* HAVE_AVAHI */ + + return 0; +} + /* * 'main()' - Browse for printers. @@ -120,6 +261,13 @@ main(int argc, /* I - Number of comm char *argv[]) /* I - Command-line arguments */ { const char *name; /* Backend name */ + cups_array_t *devices; /* Device array */ + cups_device_t *device; /* Current device */ + char uriName[1024]; /* Unquoted fullName for URI */ +#ifdef HAVE_DNSSD + int fd; /* Main file descriptor */ + fd_set input; /* Input set for select() */ + struct timeval timeout; /* Timeout for select() */ DNSServiceRef main_ref, /* Main service reference */ fax_ipp_ref, /* IPP fax service reference */ ipp_ref, /* IPP service reference */ @@ -133,12 +281,11 @@ main(int argc, /* I - Number of comm pdl_datastream_ref, /* AppSocket service reference */ printer_ref, /* LPD service reference */ riousbprint_ref; /* Remote IO service reference */ - int fd; /* Main file descriptor */ - fd_set input; /* Input set for select() */ - struct timeval timeout; /* Timeout for select() */ - cups_array_t *devices; /* Device array */ - cups_device_t *device; /* Current device */ - char uriName[1024]; /* Unquoted fullName for URI */ +#endif /* HAVE_DNSSD */ +#ifdef HAVE_AVAHI + AvahiClient *client; + int error; +#endif /* HAVE_AVAHI */ #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) struct sigaction action; /* Actions for POSIX signals */ #endif /* HAVE_SIGACTION && !HAVE_SIGSET */ @@ -198,6 +345,49 @@ main(int argc, /* I - Number of comm * Browse for different kinds of printers... */ +#ifdef HAVE_AVAHI + if ((simple_poll = avahi_simple_poll_new ()) == NULL) + { + perror ("ERROR: Unable to create avahi simple poll object"); + return (1); + } + + client = avahi_client_new (avahi_simple_poll_get (simple_poll), + 0, avahi_client_callback, NULL, &error); + if (!client) + { + perror ("DEBUG: Unable to create avahi client"); + return (0); + } + + avahi_service_browser_new (client, AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, + "_fax-ipp._tcp", NULL, 0, + avahi_browse_callback, devices); + avahi_service_browser_new (client, AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, + "_ipp._tcp", NULL, 0, + avahi_browse_callback, devices); + avahi_service_browser_new (client, AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, + "_ipp-tls._tcp", NULL, 0, + avahi_browse_callback, devices); + avahi_service_browser_new (client, AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, + "_pdl-datastream._tcp", + NULL, 0, + avahi_browse_callback, + devices); + avahi_service_browser_new (client, AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, + "_printer._tcp", NULL, 0, + avahi_browse_callback, devices); + avahi_service_browser_new (client, AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, + "_riousbprint._tcp", NULL, 0, + avahi_browse_callback, devices); +#endif /* HAVE_AVAHI */ +#ifdef HAVE_DNSSD if (DNSServiceCreateConnection(&main_ref) != kDNSServiceErr_NoError) { perror("ERROR: Unable to create service connection"); @@ -258,6 +448,7 @@ main(int argc, /* I - Number of comm riousbprint_ref = main_ref; DNSServiceBrowse(&riousbprint_ref, kDNSServiceFlagsShareConnection, 0, "_riousbprint._tcp", NULL, browse_callback, devices); +#endif /* HAVE_DNSSD */ /* * Loop until we are killed... @@ -265,6 +456,9 @@ main(int argc, /* I - Number of comm while (!job_canceled) { + int announce = 0; + +#ifdef HAVE_DNSSD FD_ZERO(&input); FD_SET(fd, &input); @@ -284,11 +478,35 @@ main(int argc, /* I - Number of comm } else { + announce = 1; + } +#else /* HAVE_AVAHI */ + int r; + avahi_got_callback = 0; + r = avahi_simple_poll_iterate (simple_poll, 1); + if (r != 0 && r != EINTR) + { + /* + * We've been told to exit the loop. Perhaps the connection to + * avahi failed. + */ + + break; + } + + if (avahi_got_callback) + announce = 1; +#endif /* HAVE_DNSSD */ + + if (announce) + { /* * Announce any devices we've found... */ +#ifdef HAVE_DNSSD DNSServiceErrorType status; /* DNS query status */ +#endif /* HAVE_DNSSD */ cups_device_t *best; /* Best matching device */ char device_uri[1024]; /* Device URI */ int count; /* Number of queries */ @@ -302,6 +520,7 @@ main(int argc, /* I - Number of comm if (device->sent) sent ++; +#ifdef HAVE_DNSSD if (device->ref) count ++; @@ -333,14 +552,23 @@ main(int argc, /* I - Number of comm count ++; } } - else if (!device->sent) + else +#endif /* HAVE_DNSSD */ +#ifdef HAVE_AVAHI + if (!device->resolved) + continue; + else +#endif /* HAVE_AVAHI */ + if (!device->sent) { +#ifdef HAVE_DNSSD /* * Got the TXT records, now report the device... */ DNSServiceRefDeallocate(device->ref); device->ref = 0; +#endif /* HAVE_DNSSD */ if (!best) best = device; @@ -401,6 +629,7 @@ main(int argc, /* I - Number of comm } +#ifdef HAVE_DNSSD /* * 'browse_callback()' - Browse devices. */ @@ -489,6 +718,7 @@ browse_local_callback( device->fullName); device->sent = 1; } +#endif /* HAVE_DNSSD */ /* @@ -569,6 +799,41 @@ exec_backend(char **argv) /* I - Comman /* + * 'device_type()' - Get DNS-SD type enumeration from string. + */ + +static int +device_type (const char *regtype) +{ +#ifdef HAVE_AVAHI + if (!strcmp(regtype, "_ipp._tcp")) + return (CUPS_DEVICE_IPP); + else if (!strcmp(regtype, "_ipps._tcp") || + !strcmp(regtype, "_ipp-tls._tcp")) + return (CUPS_DEVICE_IPPS); + else if (!strcmp(regtype, "_fax-ipp._tcp")) + return (CUPS_DEVICE_FAX_IPP); + else if (!strcmp(regtype, "_printer._tcp")) + return (CUPS_DEVICE_PDL_DATASTREAM); +#else + if (!strcmp(regtype, "_ipp._tcp.")) + return (CUPS_DEVICE_IPP); + else if (!strcmp(regtype, "_ipps._tcp.") || + !strcmp(regtype, "_ipp-tls._tcp.")) + return (CUPS_DEVICE_IPPS); + else if (!strcmp(regtype, "_fax-ipp._tcp.")) + return (CUPS_DEVICE_FAX_IPP); + else if (!strcmp(regtype, "_printer._tcp.")) + return (CUPS_DEVICE_PRINTER); + else if (!strcmp(regtype, "_pdl-datastream._tcp.")) + return (CUPS_DEVICE_PDL_DATASTREAM); +#endif /* HAVE_AVAHI */ + + return (CUPS_DEVICE_RIOUSBPRINT); +} + + +/* * 'get_device()' - Create or update a device. */ @@ -589,20 +854,7 @@ get_device(cups_array_t *devices, /* I - */ key.name = (char *)serviceName; - - if (!strcmp(regtype, "_ipp._tcp.")) - key.type = CUPS_DEVICE_IPP; - else if (!strcmp(regtype, "_ipps._tcp.") || - !strcmp(regtype, "_ipp-tls._tcp.")) - key.type = CUPS_DEVICE_IPPS; - else if (!strcmp(regtype, "_fax-ipp._tcp.")) - key.type = CUPS_DEVICE_FAX_IPP; - else if (!strcmp(regtype, "_printer._tcp.")) - key.type = CUPS_DEVICE_PRINTER; - else if (!strcmp(regtype, "_pdl-datastream._tcp.")) - key.type = CUPS_DEVICE_PDL_DATASTREAM; - else - key.type = CUPS_DEVICE_RIOUSBPRINT; + key.type = device_type (regtype); for (device = cupsArrayFind(devices, &key); device; @@ -622,8 +874,14 @@ get_device(cups_array_t *devices, /* I - free(device->domain); device->domain = strdup(replyDomain); +#ifdef HAVE_DNSSD DNSServiceConstructFullName(fullName, device->name, regtype, replyDomain); +#else /* HAVE_AVAHI */ + avahi_service_name_join (fullName, kDNSServiceMaxDomainName, + serviceName, regtype, replyDomain); +#endif /* HAVE_DNSSD */ + free(device->fullName); device->fullName = strdup(fullName); } @@ -643,6 +901,9 @@ get_device(cups_array_t *devices, /* I - device->domain = strdup(replyDomain); device->type = key.type; device->priority = 50; +#ifdef HAVE_AVAHI + device->resolved = 0; +#endif /* HAVE_AVAHI */ cupsArrayAdd(devices, device); @@ -650,13 +911,20 @@ get_device(cups_array_t *devices, /* I - * Set the "full name" of this service, which is used for queries... */ +#ifdef HAVE_DNSSD DNSServiceConstructFullName(fullName, serviceName, regtype, replyDomain); +#else /* HAVE_AVAHI */ + avahi_service_name_join (fullName, kDNSServiceMaxDomainName, + serviceName, regtype, replyDomain); +#endif /* HAVE_DNSSD */ + device->fullName = strdup(fullName); return (device); } +#ifdef HAVE_DNSSD /* * 'query_callback()' - Process query data. */ @@ -680,7 +948,7 @@ query_callback( *ptr; /* Pointer into string */ cups_device_t dkey, /* Search key */ *device; /* Device */ - + cups_txt_records_t txt; fprintf(stderr, "DEBUG2: query_callback(sdRef=%p, flags=%x, " "interfaceIndex=%d, errorCode=%d, fullName=\"%s\", " @@ -714,94 +982,233 @@ query_callback( if ((ptr = strstr(name, "._")) != NULL) *ptr = '\0'; - if (strstr(fullName, "_ipp._tcp.")) - dkey.type = CUPS_DEVICE_IPP; - else if (strstr(fullName, "_ipps._tcp.") || - strstr(fullName, "_ipp-tls._tcp.")) - dkey.type = CUPS_DEVICE_IPPS; - else if (strstr(fullName, "_fax-ipp._tcp.")) - dkey.type = CUPS_DEVICE_FAX_IPP; - else if (strstr(fullName, "_printer._tcp.")) - dkey.type = CUPS_DEVICE_PRINTER; - else if (strstr(fullName, "_pdl-datastream._tcp.")) - dkey.type = CUPS_DEVICE_PDL_DATASTREAM; + dkey.type = device_type (fullName); + + txt.data = rdata; + txt.dataend = rdata + rdlen; + device = find_device ((cups_array_t *) context, &txt, &dkey); + if (!device) + fprintf(stderr, "DEBUG: Ignoring TXT record for \"%s\"...\n", fullName); +} +#endif /* HAVE_DNSSD */ + + +#ifdef HAVE_AVAHI +/* + * 'avahi_client_callback()' - Avahi client callback function. + */ + +static void +avahi_client_callback(AvahiClient *client, + AvahiClientState state, + void *context) +{ + /* + * If the connection drops, quit. + */ + + if (state == AVAHI_CLIENT_FAILURE) + { + fprintf (stderr, "ERROR: Avahi connection failed\n"); + avahi_simple_poll_quit (simple_poll); + } +} + + +/* + * 'avahi_query_callback()' - Avahi query callback function. + */ + +static void +avahi_query_callback(AvahiServiceResolver *resolver, + AvahiIfIndex interface, + AvahiProtocol protocol, + AvahiResolverEvent event, + const char *name, + const char *type, + const char *domain, + const char *host_name, + const AvahiAddress *address, + uint16_t port, + AvahiStringList *txt, + AvahiLookupResultFlags flags, + void *context) +{ + AvahiClient *client; + cups_device_t key, + *device; + char uqname[1024], + *ptr; + cups_txt_records_t txtr; + + client = avahi_service_resolver_get_client (resolver); + if (event != AVAHI_RESOLVER_FOUND) + { + if (event == AVAHI_RESOLVER_FAILURE) + { + fprintf (stderr, "ERROR: %s\n", + avahi_strerror (avahi_client_errno (client))); + } + + avahi_service_resolver_free (resolver); + return; + } + + /* + * Set search key for device. + */ + + key.name = uqname; + unquote (uqname, name, sizeof (uqname)); + if ((ptr = strstr(name, "._")) != NULL) + *ptr = '\0'; + + key.domain = (char *) domain; + key.type = device_type (type); + + /* + * Find the device and the the TXT information. + */ + + txtr.txt = txt; + device = find_device ((cups_array_t *) context, &txtr, &key); + if (device) + { + /* + * Let the main loop know to announce the device. + */ + + device->resolved = 1; + avahi_got_callback = 1; + } else - dkey.type = CUPS_DEVICE_RIOUSBPRINT; + fprintf (stderr, "DEBUG: Ignoring TXT record for \"%s\"...\n", name); + + avahi_service_resolver_free (resolver); +} + + +/* + * 'avahi_browse_callback()' - Avahi browse callback function. + */ + +static void +avahi_browse_callback(AvahiServiceBrowser *browser, + AvahiIfIndex interface, + AvahiProtocol protocol, + AvahiBrowserEvent event, + const char *name, + const char *type, + const char *domain, + AvahiLookupResultFlags flags, + void *context) +{ + AvahiClient *client = avahi_service_browser_get_client (browser); + + switch (event) + { + case AVAHI_BROWSER_FAILURE: + fprintf (stderr, "ERROR: %s\n", + avahi_strerror (avahi_client_errno (client))); + avahi_simple_poll_quit (simple_poll); + return; + + 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. + */ + + fprintf (stderr, "DEBUG: ignoring local service %s\n", name); + } + else + { + /* + * Create a device entry for it if it doesn't yet exist. + */ + + get_device ((cups_array_t *)context, name, type, domain); + + /* + * Now look for a TXT entry. + */ + + if (avahi_service_resolver_new (client, interface, protocol, + name, type, domain, + AVAHI_PROTO_UNSPEC, 0, + avahi_query_callback, context) == NULL) + { + fprintf (stderr, "ERROR: failed to resolve service %s: %s\n", + name, avahi_strerror (avahi_client_errno (client))); + } + } + + break; + + case AVAHI_BROWSER_REMOVE: + case AVAHI_BROWSER_ALL_FOR_NOW: + case AVAHI_BROWSER_CACHE_EXHAUSTED: + break; + } +} +#endif /* HAVE_AVAHI */ + - for (device = cupsArrayFind(devices, &dkey); +/* + * 'find_device()' - Find a device from its name and domain. + */ + +static cups_device_t * +find_device (cups_array_t *devices, + cups_txt_records_t *txt, + cups_device_t *dkey) +{ + cups_device_t *device; + char *ptr; + + for (device = cupsArrayFind(devices, dkey); device; device = cupsArrayNext(devices)) { - if (_cups_strcasecmp(device->name, dkey.name) || - _cups_strcasecmp(device->domain, dkey.domain)) + if (_cups_strcasecmp(device->name, dkey->name) || + _cups_strcasecmp(device->domain, dkey->domain)) { device = NULL; break; } - else if (device->type == dkey.type) + else if (device->type == dkey->type) { /* * Found it, pull out the priority and make and model from the TXT * record and save it... */ - const uint8_t *data, /* Pointer into data */ - *datanext, /* Next key/value pair */ - *dataend; /* End of entire TXT record */ - uint8_t datalen; /* Length of current key/value pair */ - char key[256], /* Key string */ - value[256], /* Value string */ - make_and_model[512], + char make_and_model[512], /* Manufacturer and model */ model[256], /* Model */ - device_id[2048];/* 1284 device ID */ - + device_id[2048]; /* 1284 device ID */ device_id[0] = '\0'; make_and_model[0] = '\0'; strcpy(model, "Unknown"); - for (data = rdata, dataend = data + rdlen; - data < dataend; - data = datanext) + for (;;) { - /* - * Read a key/value pair starting with an 8-bit length. Since the - * length is 8 bits and the size of the key/value buffers is 256, we - * don't need to check for overflow... - */ - - datalen = *data++; - - if (!datalen || (data + datalen) >= dataend) - break; - - datanext = data + datalen; - - for (ptr = key; data < datanext && *data != '='; data ++) - *ptr++ = *data; - *ptr = '\0'; + char *key; + char *value; - if (data < datanext && *data == '=') - { - data ++; - - if (data < datanext) - memcpy(value, data, datanext - data); - value[datanext - data] = '\0'; + if (parse_txt_record_pair (txt)) + goto next; - fprintf(stderr, "DEBUG2: query_callback: \"%s=%s\".\n", - key, value); - } - else - { - fprintf(stderr, "DEBUG2: query_callback: \"%s\" with no value.\n", - key); - continue; - } - - if (!_cups_strncasecmp(key, "usb_", 4)) + key = txt->key; + value = txt->value; + if (!strncasecmp(key, "usb_", 4)) { /* * Add USB device ID information... @@ -856,6 +1263,10 @@ query_callback( if (device->type == CUPS_DEVICE_PRINTER) device->sent = 1; } + + next: + if (next_txt_record (txt) == NULL) + break; } if (device->device_id) @@ -912,11 +1323,9 @@ query_callback( } } - if (!device) - fprintf(stderr, "DEBUG: Ignoring TXT record for \"%s\"...\n", fullName); + return device; } - /* * 'sigterm_handler()' - Handle termination signals... */ diff -up cups-1.5.0/cups/http-support.c.avahi-2-backend cups-1.5.0/cups/http-support.c --- cups-1.5.0/cups/http-support.c.avahi-2-backend 2011-06-10 23:06:26.000000000 +0100 +++ cups-1.5.0/cups/http-support.c 2011-08-05 15:05:13.870710117 +0100 @@ -43,6 +43,10 @@ * http_copy_decode() - Copy and decode a URI. * http_copy_encode() - Copy and encode a URI. * http_resolve_cb() - Build a device URI for the given service name. + * avahi_resolve_uri_client_cb() + * - Avahi client callback for resolving URI. + * avahi_resolve_uri_resolver_cb() + * - Avahi resolver callback for resolving URI. */ /* @@ -60,6 +64,11 @@ # include # endif /* WIN32 */ #endif /* HAVE_DNSSD */ +#ifdef HAVE_AVAHI +# include +# include +# include +#endif /* HAVE_AVAHI */ /* @@ -127,6 +136,24 @@ static void DNSSD_API http_resolve_cb(DN void *context); #endif /* HAVE_DNSSD */ +#ifdef HAVE_AVAHI +static void avahi_resolve_uri_client_cb(AvahiClient *client, + AvahiClientState state, + void *simple_poll); +static void avahi_resolve_uri_resolver_cb(AvahiServiceResolver *resolver, + AvahiIfIndex interface, + AvahiProtocol protocol, + AvahiResolverEvent event, + const char *name, + const char *type, + const char *domain, + const char *host_name, + const AvahiAddress *address, + uint16_t port, + AvahiStringList *txt, + AvahiLookupResultFlags flags, + void *context); +#endif /* HAVE_AVAHI */ /* * 'httpAssembleURI()' - Assemble a uniform resource identifier from its @@ -1431,6 +1458,9 @@ _httpResolveURI( if (strstr(hostname, "._tcp")) { +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) + char *regtype, /* Pointer to type in hostname */ + *domain; /* Pointer to domain in hostname */ #ifdef HAVE_DNSSD # ifdef WIN32 # pragma comment(lib, "dnssd.lib") @@ -1449,6 +1479,17 @@ _httpResolveURI( fd_set input_set; /* Input set for select() */ struct timeval stimeout; /* Timeout value for select() */ #endif /* HAVE_POLL */ +#else /* HAVE_AVAHI */ + AvahiSimplePoll *simple_poll; + AvahiClient *client; + int error; + struct + { + AvahiSimplePoll *poll; + _http_uribuf_t uribuf; + } user_data; +#endif /* HAVE_DNSSD */ + if (options & _HTTP_RESOLVE_STDERR) fprintf(stderr, "DEBUG: Resolving \"%s\"...\n", hostname); @@ -1485,9 +1526,16 @@ _httpResolveURI( if (domain) *domain++ = '\0'; +#ifdef HAVE_DNSSD uribuf.buffer = resolved_uri; uribuf.bufsize = resolved_size; uribuf.options = options; +#else + user_data.uribuf.buffer = resolved_uri; + user_data.uribuf.bufsize = resolved_size; + user_data.uribuf.options = options; +#endif + resolved_uri[0] = '\0'; DEBUG_printf(("6_httpResolveURI: Resolving hostname=\"%s\", regtype=\"%s\", " @@ -1501,6 +1549,7 @@ _httpResolveURI( uri = NULL; +#ifdef HAVE_DNSSD if (DNSServiceCreateConnection(&ref) == kDNSServiceErr_NoError) { localref = ref; @@ -1608,6 +1657,36 @@ _httpResolveURI( DNSServiceRefDeallocate(ref); } +#else /* HAVE_AVAHI */ + if ((simple_poll = avahi_simple_poll_new ()) != NULL) + { + if ((client = avahi_client_new (avahi_simple_poll_get (simple_poll), + 0, avahi_resolve_uri_client_cb, + &simple_poll, &error)) != NULL) + { + user_data.poll = simple_poll; + if (avahi_service_resolver_new (client, AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, hostname, + regtype, domain, AVAHI_PROTO_UNSPEC, 0, + avahi_resolve_uri_resolver_cb, + &user_data) != NULL) + { + avahi_simple_poll_loop (simple_poll); + + /* + * Collect the result. + */ + + if (resolved_uri[0]) + uri = resolved_uri; + } + + avahi_client_free (client); + } + + avahi_simple_poll_free (simple_poll); + } +#endif /* HAVE_DNSSD */ if (options & _HTTP_RESOLVE_STDERR) { @@ -1619,13 +1698,13 @@ _httpResolveURI( fputs("STATE: -connecting-to-device,offline-report\n", stderr); } -#else +#else /* HAVE_DNSSD || HAVE_AVAHI */ /* * No DNS-SD support... */ uri = NULL; -#endif /* HAVE_DNSSD */ +#endif /* HAVE_DNSSD || HAVE_AVAHI */ if ((options & _HTTP_RESOLVE_STDERR) && !uri) _cupsLangPrintFilter(stderr, "ERROR", _("Unable to find printer.")); @@ -1895,6 +1974,116 @@ http_resolve_cb( #endif /* HAVE_DNSSD */ +#ifdef HAVE_AVAHI +/* + * 'avahi_resolve_uri_client_cb()' - Avahi client callback for resolving URI. + */ + +static void +avahi_resolve_uri_client_cb (AvahiClient *client, + AvahiClientState state, + void *simple_poll) +{ + DEBUG_printf(("avahi_resolve_uri_client_callback(client=%p, state=%d, " + "simple_poll=%p)\n", client, state, simple_poll)); + + /* + * If the connection drops, quit. + */ + + if (state == AVAHI_CLIENT_FAILURE) + avahi_simple_poll_quit (simple_poll); +} + + +/* + * 'avahi_resolve_uri_resolver_cb()' - Avahi resolver callback for resolving + * URI. + */ + +static void +avahi_resolve_uri_resolver_cb (AvahiServiceResolver *resolver, + AvahiIfIndex interface, + AvahiProtocol protocol, + AvahiResolverEvent event, + const char *name, + const char *type, + const char *domain, + const char *host_name, + const AvahiAddress *address, + uint16_t port, + AvahiStringList *txt, + AvahiLookupResultFlags flags, + void *context) +{ + const char *scheme; /* URI scheme */ + char rp[256]; /* Remote printer */ + AvahiStringList *pair; + char *value; + size_t valueLen = 0; + char addr[AVAHI_ADDRESS_STR_MAX]; + struct + { + AvahiSimplePoll *poll; + _http_uribuf_t uribuf; + } *poll_uribuf = context; + + DEBUG_printf(("avahi_resolve_uri_resolver_callback(resolver=%p, " + "interface=%d, protocol=%d, event=%d, name=\"%s\", " + "type=\"%s\", domain=\"%s\", host_name=\"%s\", address=%p, " + "port=%d, txt=%p, flags=%d, context=%p)\n", + resolver, interface, protocol, event, name, type, domain, + host_name, address, port, txt, flags, context)); + + if (event != AVAHI_RESOLVER_FOUND) + { + avahi_service_resolver_free (resolver); + avahi_simple_poll_quit (poll_uribuf->poll); + return; + } + + /* + * Figure out the scheme from the full name... + */ + + if (strstr(type, "_ipp.")) + scheme = "ipp"; + else if (strstr(type, "_printer.")) + scheme = "lpd"; + else if (strstr(type, "_pdl-datastream.")) + scheme = "socket"; + else + scheme = "riousbprint"; + + /* + * Extract the "remote printer key from the TXT record... + */ + + if ((pair = avahi_string_list_find (txt, "rp")) != NULL) + { + avahi_string_list_get_pair (pair, NULL, &value, &valueLen); + rp[0] = '/'; + memcpy (rp + 1, value, valueLen); + rp[valueLen + 1] = '\0'; + } + else + rp[0] = '\0'; + + /* + * Assemble the final device URI... + */ + + avahi_address_snprint (addr, AVAHI_ADDRESS_STR_MAX, address); + httpAssembleURI(HTTP_URI_CODING_ALL, poll_uribuf->uribuf.buffer, + poll_uribuf->uribuf.bufsize, scheme, NULL, + addr, port, rp); + DEBUG_printf(("avahi_resolve_uri_resolver_callback: Resolved URI is \"%s\"\n", + poll_uribuf->uribuf.buffer)); + avahi_simple_poll_quit (poll_uribuf->poll); +} +#endif /* HAVE_AVAHI */ + + /* * End of "$Id: http-support.c 9820 2011-06-10 22:06:26Z mike $". */