diff --git a/0001-Update-cupsEnumDests-implementation-to-return-early-if-all.patch b/0001-Update-cupsEnumDests-implementation-to-return-early-if-all.patch new file mode 100644 index 0000000..d2e8441 --- /dev/null +++ b/0001-Update-cupsEnumDests-implementation-to-return-early-if-all.patch @@ -0,0 +1,366 @@ +From a2187a63425a3d6c05de1e1cbf8c26fd39a1aced Mon Sep 17 00:00:00 2001 +From: Michael R Sweet +Date: Wed, 19 Apr 2017 15:29:42 -0400 +Subject: [PATCH] Update cupsEnumDests implementation to return early if all + printers have been discovered (Issue #4989) + +Also update the code to generate the same queue names as cupsd does for IPP +Everywhere printers. +--- + CHANGES.txt | 4 +- + cups/dest.c | 169 +++++++++++++++++++++++++++++++++++++++++++------------- + cups/testdest.c | 4 +- + 3 files changed, 136 insertions(+), 41 deletions(-) + +diff --git a/cups/dest.c b/cups/dest.c +index b06a9ee..54f2a7f 100644 +--- a/cups/dest.c ++++ b/cups/dest.c +@@ -101,9 +101,10 @@ typedef struct _cups_dnssd_device_s /* Enumerated device */ + # else /* HAVE_AVAHI */ + AvahiRecordBrowser *ref; /* Browser for query */ + # endif /* HAVE_DNSSD */ +- char *domain, /* Domain name */ +- *fullName, /* Full name */ +- *regtype; /* Registration type */ ++ char *fullName, /* Full name */ ++// *serviceName, /* Service name */ ++ *regtype, /* Registration type */ ++ *domain; /* Domain name */ + cups_ptype_t type; /* Device registration type */ + cups_dest_t dest; /* Destination record */ + } _cups_dnssd_device_t; +@@ -202,6 +203,7 @@ static void cups_dnssd_query_cb(AvahiRecordBrowser *browser, + AvahiLookupResultFlags flags, + void *context); + # endif /* HAVE_DNSSD */ ++static void cups_dnssd_queue_name(char *name, const char *serviceName, size_t namesize); + 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); +@@ -920,14 +922,13 @@ _cupsCreateDest(const char *name, /* I - Printer name */ + + int /* O - 1 on success, 0 on failure */ + cupsEnumDests( +- unsigned flags, /* I - Enumeration flags */ +- int msec, /* I - Timeout in milliseconds, +- * -1 for indefinite */ +- int *cancel, /* I - Pointer to "cancel" variable */ +- cups_ptype_t type, /* I - Printer type bits */ +- cups_ptype_t mask, /* I - Mask for printer type bits */ +- cups_dest_cb_t cb, /* I - Callback function */ +- void *user_data) /* I - User data */ ++ unsigned flags, /* I - Enumeration flags */ ++ int msec, /* I - Timeout in milliseconds, -1 for indefinite */ ++ int *cancel, /* I - Pointer to "cancel" variable */ ++ cups_ptype_t type, /* I - Printer type bits */ ++ cups_ptype_t mask, /* I - Mask for printer type bits */ ++ cups_dest_cb_t cb, /* I - Callback function */ ++ void *user_data) /* I - User data */ + { + int i, /* Looping var */ + num_dests; /* Number of destinations */ +@@ -939,6 +940,7 @@ cupsEnumDests( + *user_default; /* User default printer */ + #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) + int count, /* Number of queries started */ ++ completed, /* Number of completed queries */ + remaining; /* Remainder of timeout */ + _cups_dnssd_data_t data; /* Data for callback */ + _cups_dnssd_device_t *device; /* Current device */ +@@ -1007,29 +1009,70 @@ cupsEnumDests( + dest->is_default = 1; + } + ++#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) ++ data.type = type; ++ data.mask = mask; ++ data.cb = cb; ++ data.user_data = user_data; ++ data.devices = cupsArrayNew3((cups_array_func_t)cups_dnssd_compare_devices, NULL, NULL, 0, NULL, (cups_afree_func_t)cups_dnssd_free_device); ++#endif /* HAVE_DNSSD || HAVE_AVAHI */ ++ + for (i = num_dests, dest = dests; + i > 0 && (!cancel || !*cancel); + i --, dest ++) ++ { ++ const char *device_uri; /* Device URI */ ++ + if (!(*cb)(user_data, i > 1 ? CUPS_DEST_FLAGS_MORE : CUPS_DEST_FLAGS_NONE, + dest)) + break; + ++ if (!dest->instance && (device_uri = cupsGetOption("device-uri", dest->num_options, dest->options)) != NULL && !strncmp(device_uri, "dnssd://", 8)) ++ { ++ /* ++ * Add existing queue using service name, etc. so we don't list it again... ++ */ ++ ++ char scheme[32], /* URI scheme */ ++ userpass[32], /* Username:password */ ++ serviceName[256], /* Service name (host field) */ ++ resource[256], /* Resource (options) */ ++ *regtype, /* Registration type */ ++ *replyDomain; /* Registration domain */ ++ int port; /* Port number (not used) */ ++ ++ if (httpSeparateURI(HTTP_URI_CODING_ALL, device_uri, scheme, sizeof(scheme), userpass, sizeof(userpass), serviceName, sizeof(serviceName), &port, resource, sizeof(resource)) >= HTTP_URI_STATUS_OK) ++ { ++ if ((regtype = strstr(serviceName, "._ipp")) != NULL) ++ { ++ *regtype++ = '\0'; ++ ++ if ((replyDomain = strstr(regtype, "._tcp.")) != NULL) ++ { ++ replyDomain[5] = '\0'; ++ replyDomain += 6; ++ ++ if ((device = cups_dnssd_get_device(&data, serviceName, regtype, replyDomain)) != NULL) ++ device->state = _CUPS_DNSSD_ACTIVE; ++ } ++ } ++ } ++ } ++ } ++ + cupsFreeDests(num_dests, dests); + + if (i > 0 || msec == 0) ++ { ++ cupsArrayDelete(data.devices); + return (1); ++ } + + #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) + /* + * Get Bonjour-shared printers... + */ + +- data.type = type; +- data.mask = mask; +- data.cb = cb; +- data.user_data = user_data; +- data.devices = cupsArrayNew3((cups_array_func_t)cups_dnssd_compare_devices, NULL, NULL, 0, NULL, (cups_afree_func_t)cups_dnssd_free_device); +- + # ifdef HAVE_DNSSD + if (DNSServiceCreateConnection(&data.main_ref) != kDNSServiceErr_NoError) + return (0); +@@ -1105,27 +1148,25 @@ cupsEnumDests( + pfd.fd = main_fd; + pfd.events = POLLIN; + +- nfds = poll(&pfd, 1, remaining > 250 ? 250 : remaining); ++ nfds = poll(&pfd, 1, remaining > 500 ? 500 : remaining); + + # else + FD_ZERO(&input); + FD_SET(main_fd, &input); + + timeout.tv_sec = 0; +- timeout.tv_usec = remaining > 250 ? 250000 : remaining * 1000; ++ timeout.tv_usec = remaining > 500 ? 500000 : remaining * 1000; + + nfds = select(main_fd + 1, &input, NULL, NULL, &timeout); + # 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, 250)) > 0) ++ if ((error = avahi_simple_poll_iterate(data.simple_poll, 500)) > 0) + { + /* + * We've been told to exit the loop. Perhaps the connection to +@@ -1135,18 +1176,21 @@ cupsEnumDests( + break; + } + +- if (!data.got_data) +- remaining -= 250; + # endif /* HAVE_DNSSD */ + ++ remaining -= 500; ++ + for (device = (_cups_dnssd_device_t *)cupsArrayFirst(data.devices), +- count = 0; ++ count = 0, completed = 0; + device; + device = (_cups_dnssd_device_t *)cupsArrayNext(data.devices)) + { + if (device->ref) + count ++; + ++ if (device->state == _CUPS_DNSSD_ACTIVE) ++ completed ++; ++ + if (!device->ref && device->state == _CUPS_DNSSD_NEW) + { + DEBUG_printf(("1cupsEnumDests: Querying '%s'.", device->fullName)); +@@ -1196,8 +1240,11 @@ cupsEnumDests( + } + else if (device->ref && device->state == _CUPS_DNSSD_PENDING) + { ++ completed ++; ++ + if ((device->type & mask) == type) + { ++ DEBUG_printf(("1cupsEnumDests: Add callback for \"%s\".", device->dest.name)); + if (!(*cb)(user_data, CUPS_DEST_FLAGS_NONE, &device->dest)) + { + remaining = -1; +@@ -1208,6 +1255,9 @@ cupsEnumDests( + device->state = _CUPS_DNSSD_ACTIVE; + } + } ++ ++ if (completed == cupsArrayCount(data.devices)) ++ break; + } + + cupsArrayDelete(data.devices); +@@ -2964,8 +3014,9 @@ cups_dnssd_get_device( + { + _cups_dnssd_device_t key, /* Search key */ + *device; /* Device */ +- char fullName[kDNSServiceMaxDomainName]; ++ char fullName[kDNSServiceMaxDomainName], + /* Full name for query */ ++ name[128]; /* Queue name */ + + + DEBUG_printf(("5cups_dnssd_get_device(data=%p, serviceName=\"%s\", " +@@ -2974,7 +3025,9 @@ cups_dnssd_get_device( + * See if this is an existing device... + */ + +- key.dest.name = (char *)serviceName; ++ cups_dnssd_queue_name(name, serviceName, sizeof(name)); ++ ++ key.dest.name = name; + + if ((device = cupsArrayFind(data->devices, &key)) != NULL) + { +@@ -3035,10 +3088,12 @@ cups_dnssd_get_device( + replyDomain)); + + device = calloc(sizeof(_cups_dnssd_device_t), 1); +- device->dest.name = _cupsStrAlloc(serviceName); ++ device->dest.name = _cupsStrAlloc(name); + device->domain = _cupsStrAlloc(replyDomain); + device->regtype = _cupsStrAlloc(regtype); + ++ device->dest.num_options = cupsAddOption("printer-info", serviceName, 0, &device->dest.options); ++ + cupsArrayAdd(data->devices, device); + } + +@@ -3047,11 +3102,9 @@ cups_dnssd_get_device( + */ + + # ifdef HAVE_DNSSD +- DNSServiceConstructFullName(fullName, device->dest.name, device->regtype, +- device->domain); ++ DNSServiceConstructFullName(fullName, serviceName, regtype, replyDomain); + # else /* HAVE_AVAHI */ +- avahi_service_name_join(fullName, kDNSServiceMaxDomainName, serviceName, +- regtype, replyDomain); ++ avahi_service_name_join(fullName, kDNSServiceMaxDomainName, serviceName, regtype, replyDomain); + # endif /* HAVE_DNSSD */ + + _cupsStrFree(device->fullName); +@@ -3070,6 +3123,8 @@ cups_dnssd_get_device( + + if (device->state == _CUPS_DNSSD_ACTIVE) + { ++ DEBUG_printf(("6cups_dnssd_get_device: Remove callback for \"%s\".", device->dest.name)); ++ + (*data->cb)(data->user_data, CUPS_DEST_FLAGS_REMOVED, &device->dest); + device->state = _CUPS_DNSSD_NEW; + } +@@ -3128,7 +3183,10 @@ cups_dnssd_local_cb( + } + + if (device->state == _CUPS_DNSSD_ACTIVE) ++ { ++ DEBUG_printf(("6cups_dnssd_local_cb: Remove callback for \"%s\".", device->dest.name)); + (*data->cb)(data->user_data, CUPS_DEST_FLAGS_REMOVED, &device->dest); ++ } + + device->state = _CUPS_DNSSD_LOCAL; + } +@@ -3214,7 +3272,8 @@ cups_dnssd_query_cb( + # endif /* HAVE_DNSSD */ + _cups_dnssd_data_t *data = (_cups_dnssd_data_t *)context; + /* Enumeration data */ +- char name[1024], /* Service name */ ++ char serviceName[256],/* Service name */ ++ name[128], /* Queue name */ + *ptr; /* Pointer into string */ + _cups_dnssd_device_t dkey, /* Search key */ + *device; /* Device */ +@@ -3255,14 +3314,16 @@ cups_dnssd_query_cb( + * Lookup the service in the devices array. + */ + +- dkey.dest.name = name; +- +- cups_dnssd_unquote(name, fullName, sizeof(name)); ++ cups_dnssd_unquote(serviceName, fullName, sizeof(serviceName)); + +- if ((ptr = strstr(name, "._")) != NULL) ++ if ((ptr = strstr(serviceName, "._")) != NULL) + *ptr = '\0'; + +- if ((device = cupsArrayFind(data->devices, &dkey)) != NULL) ++ cups_dnssd_queue_name(name, serviceName, sizeof(name)); ++ ++ dkey.dest.name = name; ++ ++ if ((device = cupsArrayFind(data->devices, &dkey)) != NULL && device->state == _CUPS_DNSSD_NEW) + { + /* + * Found it, pull out the make and model from the TXT record and save it... +@@ -3620,6 +3681,38 @@ cups_dnssd_unquote(char *dst, /* I - Destination buffer */ + #endif /* HAVE_DNSSD */ + + ++#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) ++/* ++ * 'cups_dnssd_queue_name()' - Create a local queue name based on the service name. ++ */ ++ ++static void ++cups_dnssd_queue_name( ++ char *name, /* I - Name buffer */ ++ const char *serviceName, /* I - Service name */ ++ size_t namesize) /* I - Size of name buffer */ ++{ ++ const char *ptr; /* Pointer into serviceName */ ++ char *nameptr; /* Pointer into name */ ++ ++ ++ for (nameptr = name, ptr = serviceName; *ptr && nameptr < (name + namesize - 1); ptr ++) ++ { ++ /* ++ * Sanitize the printer name... ++ */ ++ ++ if (_cups_isalnum(*ptr)) ++ *nameptr++ = *ptr; ++ else if (nameptr == name || nameptr[-1] != '_') ++ *nameptr++ = '_'; ++ } ++ ++ *nameptr = '\0'; ++} ++#endif /* HAVE_DNSSD || HAVE_AVAHI */ ++ ++ + /* + * 'cups_find_dest()' - Find a destination using a binary search. + */ diff --git a/0002-Save-work-on-Avahi-code.patch b/0002-Save-work-on-Avahi-code.patch new file mode 100644 index 0000000..14a20cb --- /dev/null +++ b/0002-Save-work-on-Avahi-code.patch @@ -0,0 +1,226 @@ +From 657c5b5f91e6d5120c4ad7b118cf9098dd27f03d Mon Sep 17 00:00:00 2001 +From: Michael R Sweet +Date: Thu, 20 Apr 2017 09:11:45 -0400 +Subject: [PATCH] Save work on Avahi code + +--- + cups/dest.c | 64 +++++++++++++++++++++++++++++++++++++++++++------------------ + 1 file changed, 45 insertions(+), 19 deletions(-) + +diff --git a/cups/dest.c b/cups/dest.c +index 54f2a7f..c1a0913 100644 +--- a/cups/dest.c ++++ b/cups/dest.c +@@ -85,6 +85,7 @@ typedef struct _cups_dnssd_data_s /* Enumeration data */ + AvahiSimplePoll *simple_poll; /* Polling interface */ + AvahiClient *client; /* Client information */ + int got_data; /* Did we get data? */ ++ int browsers; /* How many browsers are running? */ + # endif /* HAVE_DNSSD */ + cups_dest_cb_t cb; /* Callback */ + void *user_data; /* User data pointer */ +@@ -102,7 +103,6 @@ typedef struct _cups_dnssd_device_s /* Enumerated device */ + AvahiRecordBrowser *ref; /* Browser for query */ + # endif /* HAVE_DNSSD */ + char *fullName, /* Full name */ +-// *serviceName, /* Service name */ + *regtype, /* Registration type */ + *domain; /* Domain name */ + cups_ptype_t type; /* Device registration type */ +@@ -1021,12 +1021,15 @@ cupsEnumDests( + i > 0 && (!cancel || !*cancel); + i --, dest ++) + { ++#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) + const char *device_uri; /* Device URI */ ++#endif /* HAVE_DNSSD || HAVE_AVAHI */ + + if (!(*cb)(user_data, i > 1 ? CUPS_DEST_FLAGS_MORE : CUPS_DEST_FLAGS_NONE, + dest)) + break; + ++#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) + if (!dest->instance && (device_uri = cupsGetOption("device-uri", dest->num_options, dest->options)) != NULL && !strncmp(device_uri, "dnssd://", 8)) + { + /* +@@ -1058,13 +1061,17 @@ cupsEnumDests( + } + } + } ++#endif /* HAVE_DNSSD || HAVE_AVAHI */ + } + + cupsFreeDests(num_dests, dests); + + if (i > 0 || msec == 0) + { ++#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) + cupsArrayDelete(data.devices); ++#endif /* HAVE_DNSSD || HAVE_AVAHI */ ++ + return (1); + } + +@@ -1122,10 +1129,12 @@ cupsEnumDests( + return (1); + } + ++ data.browsers ++; + 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 ++ data.browsers ++; + ipps_ref = avahi_service_browser_new(data.client, AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, "_ipps._tcp", NULL, + 0, cups_dnssd_browse_cb, &data); +@@ -1166,7 +1175,7 @@ cupsEnumDests( + # else /* HAVE_AVAHI */ + data.got_data = 0; + +- if ((error = avahi_simple_poll_iterate(data.simple_poll, 500)) > 0) ++ if ((error = avahi_simple_poll_iterate(data.simple_poll, 1000)) > 0) + { + /* + * We've been told to exit the loop. Perhaps the connection to +@@ -1176,6 +1185,7 @@ cupsEnumDests( + break; + } + ++ DEBUG_printf(("1cupsEnumDests: got_data=%d", data.got_data)); + # endif /* HAVE_DNSSD */ + + remaining -= 500; +@@ -1227,14 +1237,14 @@ cupsEnumDests( + cups_dnssd_query_cb, + &data)) != NULL) + { ++ DEBUG_printf(("1cupsEnumDests: browser ref=%p", device->ref)); + count ++; + } + else + { + device->state = _CUPS_DNSSD_ERROR; + +- DEBUG_printf(("1cupsEnumDests: Query failed: %s", +- avahi_strerror(avahi_client_errno(data.client)))); ++ DEBUG_printf(("1cupsEnumDests: Query failed: %s", avahi_strerror(avahi_client_errno(data.client)))); + } + # endif /* HAVE_DNSSD */ + } +@@ -1256,8 +1266,17 @@ cupsEnumDests( + } + } + ++# ifdef HAVE_AVAHI ++ DEBUG_printf(("1cupsEnumDests: browsers=%d, completed=%d, count=%d, devices count=%d", data.browsers, completed, count, cupsArrayCount(data.devices))); ++ ++ if (data.browsers == 0 && completed == cupsArrayCount(data.devices)) ++ break; ++# else ++ DEBUG_printf(("1cupsEnumDests: completed=%d, count=%d, devices count=%d", completed, count, cupsArrayCount(data.devices))); ++ + if (completed == cupsArrayCount(data.devices)) + break; ++# endif /* HAVE_AVAHI */ + } + + cupsArrayDelete(data.devices); +@@ -2889,11 +2908,12 @@ cups_dnssd_browse_cb( + (void)protocol; + (void)context; + ++ DEBUG_printf(("cups_dnssd_browse_cb(..., name=\"%s\", type=\"%s\", domain=\"%s\", ...);", name, type, domain)); ++ + switch (event) + { + case AVAHI_BROWSER_FAILURE: +- DEBUG_printf(("cups_dnssd_browse_cb: %s", +- avahi_strerror(avahi_client_errno(client)))); ++ DEBUG_printf(("cups_dnssd_browse_cb: %s", avahi_strerror(avahi_client_errno(client)))); + avahi_simple_poll_quit(data->simple_poll); + break; + +@@ -2908,8 +2928,7 @@ cups_dnssd_browse_cb( + * This comes from the local machine so ignore it. + */ + +- DEBUG_printf(("cups_dnssd_browse_cb: Ignoring local service \"%s\".", +- name)); ++ DEBUG_printf(("cups_dnssd_browse_cb: Ignoring local service \"%s\".", name)); + } + else + { +@@ -2921,9 +2940,13 @@ cups_dnssd_browse_cb( + } + break; + +- case AVAHI_BROWSER_REMOVE: +- case AVAHI_BROWSER_ALL_FOR_NOW: +- case AVAHI_BROWSER_CACHE_EXHAUSTED: ++ case AVAHI_BROWSER_REMOVE : ++ case AVAHI_BROWSER_CACHE_EXHAUSTED : ++ break; ++ ++ case AVAHI_BROWSER_ALL_FOR_NOW : ++ DEBUG_puts("cups_dnssd_browse_cb: ALL_FOR_NOW"); ++ data->browsers --; + break; + } + } +@@ -2945,6 +2968,8 @@ cups_dnssd_client_cb( + + (void)client; + ++ DEBUG_printf(("cups_dnssd_client_cb(client=%p, state=%d, context=%p)", client, state, context)); ++ + /* + * If the connection drops, quit. + */ +@@ -3214,16 +3239,22 @@ cups_dnssd_poll_cb( + int val; /* Return value */ + + ++ DEBUG_printf(("cups_dnssd_poll_cb(pollfds=%p, num_pollfds=%d, timeout=%d, context=%p)", pollfds, num_pollfds, timeout, context)); ++ + (void)timeout; + +- val = poll(pollfds, num_pollfds, 250); ++ val = poll(pollfds, num_pollfds, 500); ++ ++ DEBUG_printf(("cups_dnssd_poll_cb: poll() returned %d", val)); + + if (val < 0) + { + DEBUG_printf(("cups_dnssd_poll_cb: %s", strerror(errno))); + } + else if (val > 0) ++ { + data->got_data = 1; ++ } + + return (val); + } +@@ -3290,11 +3321,7 @@ cups_dnssd_query_cb( + 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)); ++ DEBUG_printf(("cups_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... +@@ -3303,8 +3330,7 @@ cups_dnssd_query_cb( + if (event != AVAHI_BROWSER_NEW) + { + if (event == AVAHI_BROWSER_FAILURE) +- DEBUG_printf(("cups_dnssd_query_cb: %s", +- avahi_strerror(avahi_client_errno(client)))); ++ DEBUG_printf(("cups_dnssd_query_cb: %s", avahi_strerror(avahi_client_errno(client)))); + + return; + } diff --git a/0003-Avahi-fixes-for-cupsEnumDests.patch b/0003-Avahi-fixes-for-cupsEnumDests.patch new file mode 100644 index 0000000..08f8b7e --- /dev/null +++ b/0003-Avahi-fixes-for-cupsEnumDests.patch @@ -0,0 +1,186 @@ +From 3fae3b337df0be1a766857be741173d8a9915da7 Mon Sep 17 00:00:00 2001 +From: Michael R Sweet +Date: Thu, 20 Apr 2017 10:12:40 -0400 +Subject: [PATCH] Avahi fixes for cupsEnumDests (Issue #4989) + +Also fix timeouts to track elapsed time so the timeout is more accurate. +--- + cups/dest.c | 70 ++++++++++++++++++++++++++++++++++++++++--------------------- + 1 file changed, 46 insertions(+), 24 deletions(-) + +diff --git a/cups/dest.c b/cups/dest.c +index c1a0913..48758bf 100644 +--- a/cups/dest.c ++++ b/cups/dest.c +@@ -60,6 +60,10 @@ + # define kUseLastPrinter CFSTR("UseLastPrinter") + #endif /* __APPLE__ */ + ++#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) ++# define _CUPS_DNSSD_MAXTIME 500 /* Milliseconds for maximum quantum of time */ ++#endif /* HAVE_DNSSD || HAVE_AVAHI */ ++ + + /* + * Types... +@@ -211,6 +215,7 @@ static int cups_dnssd_resolve_cb(void *context); + static void cups_dnssd_unquote(char *dst, const char *src, + size_t dstsize); + #endif /* HAVE_DNSSD || HAVE_AVAHI */ ++static int cups_elapsed(struct timeval *t); + static int cups_find_dest(const char *name, const char *instance, + int num_dests, cups_dest_t *dests, int prev, + int *rdiff); +@@ -942,6 +947,7 @@ cupsEnumDests( + int count, /* Number of queries started */ + completed, /* Number of completed queries */ + remaining; /* Remainder of timeout */ ++ struct timeval curtime; /* Current time */ + _cups_dnssd_data_t data; /* Data for callback */ + _cups_dnssd_device_t *device; /* Current device */ + # ifdef HAVE_DNSSD +@@ -1129,15 +1135,12 @@ cupsEnumDests( + return (1); + } + +- data.browsers ++; +- ipp_ref = avahi_service_browser_new(data.client, AVAHI_IF_UNSPEC, +- AVAHI_PROTO_UNSPEC, "_ipp._tcp", NULL, +- 0, cups_dnssd_browse_cb, &data); ++ data.browsers = 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 + data.browsers ++; +- ipps_ref = avahi_service_browser_new(data.client, AVAHI_IF_UNSPEC, +- AVAHI_PROTO_UNSPEC, "_ipps._tcp", NULL, +- 0, cups_dnssd_browse_cb, &data); ++ 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 */ + +@@ -1152,19 +1155,23 @@ cupsEnumDests( + * Check for input... + */ + ++ DEBUG_printf(("1cupsEnumDests: remaining=%d", remaining)); ++ ++ cups_elapsed(&curtime); ++ + # ifdef HAVE_DNSSD + # ifdef HAVE_POLL + pfd.fd = main_fd; + pfd.events = POLLIN; + +- nfds = poll(&pfd, 1, remaining > 500 ? 500 : remaining); ++ nfds = poll(&pfd, 1, remaining > _CUPS_DNSSD_MAXTIME ? _CUPS_DNSSD_MAXTIME : remaining); + + # else + FD_ZERO(&input); + FD_SET(main_fd, &input); + + timeout.tv_sec = 0; +- timeout.tv_usec = remaining > 500 ? 500000 : remaining * 1000; ++ timeout.tv_usec = 1000 * (remaining > _CUPS_DNSSD_MAXTIME ? _CUPS_DNSSD_MAXTIME : remaining); + + nfds = select(main_fd + 1, &input, NULL, NULL, &timeout); + # endif /* HAVE_POLL */ +@@ -1175,7 +1182,7 @@ cupsEnumDests( + # else /* HAVE_AVAHI */ + data.got_data = 0; + +- if ((error = avahi_simple_poll_iterate(data.simple_poll, 1000)) > 0) ++ if ((error = avahi_simple_poll_iterate(data.simple_poll, _CUPS_DNSSD_MAXTIME)) > 0) + { + /* + * We've been told to exit the loop. Perhaps the connection to +@@ -1188,7 +1195,7 @@ cupsEnumDests( + DEBUG_printf(("1cupsEnumDests: got_data=%d", data.got_data)); + # endif /* HAVE_DNSSD */ + +- remaining -= 500; ++ remaining -= cups_elapsed(&curtime); + + for (device = (_cups_dnssd_device_t *)cupsArrayFirst(data.devices), + count = 0, completed = 0; +@@ -1227,17 +1234,9 @@ cupsEnumDests( + } + + # 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) ++ 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) + { +- DEBUG_printf(("1cupsEnumDests: browser ref=%p", device->ref)); ++ DEBUG_printf(("1cupsEnumDests: Query ref=%p", device->ref)); + count ++; + } + else +@@ -1252,6 +1251,8 @@ cupsEnumDests( + { + completed ++; + ++ DEBUG_printf(("1cupsEnumDests: Query for \"%s\" is complete.", device->fullName)); ++ + if ((device->type & mask) == type) + { + DEBUG_printf(("1cupsEnumDests: Add callback for \"%s\".", device->dest.name)); +@@ -1267,12 +1268,12 @@ cupsEnumDests( + } + + # ifdef HAVE_AVAHI +- DEBUG_printf(("1cupsEnumDests: browsers=%d, completed=%d, count=%d, devices count=%d", data.browsers, completed, count, cupsArrayCount(data.devices))); ++ DEBUG_printf(("1cupsEnumDests: remaining=%d, browsers=%d, completed=%d, count=%d, devices count=%d", remaining, data.browsers, completed, count, cupsArrayCount(data.devices))); + + if (data.browsers == 0 && completed == cupsArrayCount(data.devices)) + break; + # else +- DEBUG_printf(("1cupsEnumDests: completed=%d, count=%d, devices count=%d", completed, count, cupsArrayCount(data.devices))); ++ DEBUG_printf(("1cupsEnumDests: remaining=%d, completed=%d, count=%d, devices count=%d", remaining, completed, count, cupsArrayCount(data.devices))); + + if (completed == cupsArrayCount(data.devices)) + break; +@@ -3243,7 +3244,7 @@ cups_dnssd_poll_cb( + + (void)timeout; + +- val = poll(pollfds, num_pollfds, 500); ++ val = poll(pollfds, num_pollfds, _CUPS_DNSSD_MAXTIME); + + DEBUG_printf(("cups_dnssd_poll_cb: poll() returned %d", val)); + +@@ -3740,6 +3741,27 @@ cups_dnssd_queue_name( + + + /* ++ * 'cups_elapsed()' - Return the elapsed time in milliseconds. ++ */ ++ ++static int /* O - Elapsed time in milliseconds */ ++cups_elapsed(struct timeval *t) /* IO - Previous time */ ++{ ++ int msecs; /* Milliseconds */ ++ struct timeval nt; /* New time */ ++ ++ ++ gettimeofday(&nt, NULL); ++ ++ msecs = 1000 * (nt.tv_sec - t->tv_sec) + (nt.tv_usec - t->tv_usec) / 1000; ++ ++ *t = nt; ++ ++ return (msecs); ++} ++ ++ ++/* + * 'cups_find_dest()' - Find a destination using a binary search. + */ + diff --git a/cups.changes b/cups.changes index e4fec56..14ff878 100644 --- a/cups.changes +++ b/cups.changes @@ -1,3 +1,25 @@ +------------------------------------------------------------------- +Thu Apr 20 16:26:52 UTC 2017 - alarrosa@suse.com + +- Drop cups-1.7.5-cupsEnumDests-react-to-all-for-now.diff and add + 0001-Update-cupsEnumDests-implementation-to-return-early-if-all.patch, + 0002-Save-work-on-Avahi-code.patch and + 0003-Avahi-fixes-for-cupsEnumDests.patch which is what upstream + finally commited to cups 2.2 sources in response to + https://github.com/apple/cups/pull/4989 in order to fix cupsEnumDests + to react to the ALL_FOR_NOW avahi event (and also include a similar + fix for the dnssd case). Related to bsc#955432. + +------------------------------------------------------------------- +Mon Apr 10 17:37:16 UTC 2017 - alarrosa@suse.com + +- Add cups-2.1.3-cupsEnumDests-react-to-all-for-now.diff . + Avahi sends an ALL_FOR_NOW event when it finishes sending + its cache contents. This patch makes cupsEnumDests finish + when the signal is received so it doesn't block the caller + doing nothing until the timeout finishes (related to bsc#955432, + submitted upstream at https://github.com/apple/cups/pull/4989) + ------------------------------------------------------------------- Wed Mar 29 13:41:15 UTC 2017 - kukuk@suse.com diff --git a/cups.spec b/cups.spec index 89b5759..059677b 100644 --- a/cups.spec +++ b/cups.spec @@ -45,6 +45,12 @@ Patch10: cups-2.1.0-choose-uri-template.patch Patch11: cups-2.1.0-default-webcontent-path.patch # Patch12 cups-2.1.0-cups-systemd-socket.patch Use systemd socket activation properly: Patch12: cups-2.1.0-cups-systemd-socket.patch +# Patch13 0001-Update-cupsEnumDests-implementation-to-return-early-if-all.patch bsc#955432 -- React properly to avahi's ALL_FOR_NOW signal to reduce unneeded delay +Patch13: 0001-Update-cupsEnumDests-implementation-to-return-early-if-all.patch +# Patch14 0002-Save-work-on-Avahi-code.patch bsc#955432 -- React properly to avahi's ALL_FOR_NOW signal to reduce unneeded delay +Patch14: 0002-Save-work-on-Avahi-code.patch +# Patch15 0003-Avahi-fixes-for-cupsEnumDests.patch bsc#955432 -- React properly to avahi's ALL_FOR_NOW signal to reduce unneeded delay +Patch15: 0003-Avahi-fixes-for-cupsEnumDests.patch # Patch100...Patch999 is for private patches from SUSE which are not intended for upstream: # Patch100 cups-pam.diff adds conf/pam.suse regarding support for PAM for SUSE: Patch100: cups-pam.diff @@ -133,9 +139,9 @@ browsing". This is now handled by cups-browsed service. %package libs Summary: Libraries for CUPS -# Prerequire /sbin/ldconfig which is used in the traditional bash scriptlets for post/postun: License: GPL-2.0 and LGPL-2.1 Group: Hardware/Printing +# Prerequire /sbin/ldconfig which is used in the traditional bash scriptlets for post/postun: Requires(pre): /sbin/ldconfig %if 0%{?suse_version} >= 1330 Requires(pre): group(lp) @@ -157,6 +163,8 @@ browsing". This is now handled by cups-browsed service. %package client Summary: CUPS Client Programs +License: GPL-2.0 +Group: Hardware/Printing # Require the exact matching version-release of the cups-libs sub-package because # non-matching CUPS libraries may let CUPS software crash (e.g. segfault) # because all CUPS software is built from the one same CUPS source tar ball @@ -166,8 +174,6 @@ Summary: CUPS Client Programs # on the same package repository where the cups package is because # all are built simulaneously from the same cups source package # and all required packages are provided on the same repository: -License: GPL-2.0 -Group: Hardware/Printing Requires: cups-libs = %{version}-%{release} # Conflicts with other print spoolers which provide same binaries like /usr/bin/lp and so on: Conflicts: lprng @@ -190,13 +196,13 @@ browsing". This is now handled by cups-browsed service. %package devel Summary: Development Environment for CUPS +License: GPL-2.0 +Group: Development/Libraries/C and C++ # Do not require the exact matching version-release of cups-libs # but only a cups-libs package with matching version because # for building third-party software which uses only the CUPS public API # there are no CUPS-internal dependencies via CUPS private API calls # (the latter would require the exact matching cups-libs version-release): -License: GPL-2.0 -Group: Development/Libraries/C and C++ Requires: cups-libs = %{version} Requires: glibc-devel @@ -258,6 +264,12 @@ browsing". This is now handled by cups-browsed service. %patch11 -b default-webcontent-path.prig # Patch12 cups-2.1.0-cups-systemd-socket.patch Use systemd socket activation properly: %patch12 -b cups-systemd-socket.orig +# Patch13 0001-Update-cupsEnumDests-implementation-to-return-early-if-all.patch React properly to avahi's ALL_FOR_NOW signal to reduce unneeded delay +%patch13 -p1 +# Patch14 0002-Save-work-on-Avahi-code.patch React properly to avahi's ALL_FOR_NOW signal to reduce unneeded delay +%patch14 -p1 +# Patch15 0003-Avahi-fixes-for-cupsEnumDests.patch React properly to avahi's ALL_FOR_NOW signal to reduce unneeded delay +%patch15 -p1 # Patch100...Patch999 is for private patches from SUSE which are not intended for upstream: # Patch100 cups-pam.diff adds conf/pam.suse regarding support for PAM for SUSE: %patch100