Dear all, Unfortunately this bug still happens in Debian Stretch. To fix it I had to backport the two fixes upstream that are mentioned in this thread. The patches are attached and apply on top of the debian/stretch branch. A suggested changelog figures below, extracted from upstream changes to the NEWS file.
* Backport bug-fixes from the 1.16 branch: - cups-browsed: Make timeouts for HTTP access to the local CUPS daemon and remote IPP printers configurable. Thanks to Cedric Dufour (cedric dot dufour at idiap dot ch) for the patch (Bug #1387, Debian bug #852436). * Backport bug-fixes from the 1.13 branch: - cups-browsed: Do not use deprecated names for IPP status constants - cups-browsed: Corrected determination whether an IPP status is an error, to avoid "Unable to create/modify CUPS queue (Success)" and infinite repetition of a succeeded operation (Debian bug #852436). Thanks, Louis
>From a424e78c1e21cebe6e7d2000f77ed54245a1ed51 Mon Sep 17 00:00:00 2001 From: Till Kamppeter <till.kamppe...@gmail.com> Date: Tue, 24 Jan 2017 21:57:23 -0200 Subject: [PATCH 1/2] cups-browsed: Corrected determination whether an IPP status is an error. This is a backport from 1.13.4 Backport-by: Louis Rilling <l.rill...@av7.net> --- utils/cups-browsed.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/utils/cups-browsed.c b/utils/cups-browsed.c index 991d6da..294e450 100644 --- a/utils/cups-browsed.c +++ b/utils/cups-browsed.c @@ -742,7 +742,7 @@ prepare_browse_data (void) debug_printf("preparing browse data\n"); response = cupsDoRequest (conn, request, "/"); - if (cupsLastError() > IPP_OK_CONFLICT) { + if (cupsLastError() > IPP_STATUS_OK_EVENTS_COMPLETE) { debug_printf("browse send failed for localhost: %s\n", cupsLastErrorString ()); goto fail; @@ -1753,7 +1753,7 @@ create_subscription () "notify-lease-duration", NOTIFY_LEASE_DURATION); resp = cupsDoRequest (conn, req, "/"); - if (!resp || cupsLastError() != IPP_OK) { + if (!resp || cupsLastError() != IPP_STATUS_OK) { debug_printf ("Error subscribing to CUPS notifications: %s\n", cupsLastErrorString ()); return 0; @@ -1792,7 +1792,7 @@ renew_subscription (int id) "notify-lease-duration", NOTIFY_LEASE_DURATION); resp = cupsDoRequest (conn, req, "/"); - if (!resp || cupsLastError() != IPP_OK) { + if (!resp || cupsLastError() != IPP_STATUS_OK) { debug_printf ("Error renewing CUPS subscription %d: %s\n", id, cupsLastErrorString ()); return FALSE; @@ -1834,7 +1834,7 @@ cancel_subscription (int id) "notify-subscription-id", id); resp = cupsDoRequest (conn, req, "/"); - if (!resp || cupsLastError() != IPP_OK) { + if (!resp || cupsLastError() != IPP_STATUS_OK) { debug_printf ("Error subscribing to CUPS notifications: %s\n", cupsLastErrorString ()); return; @@ -1979,7 +1979,7 @@ enable_printer (const char *printer) { ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); ippDelete(cupsDoRequest (conn, request, "/admin/")); - if (cupsLastError() > IPP_STATUS_OK_CONFLICTING) { + if (cupsLastError() > IPP_STATUS_OK_EVENTS_COMPLETE) { debug_printf("ERROR: Failed enabling printer '%s': %s\n", printer, cupsLastErrorString()); return -1; @@ -2006,7 +2006,7 @@ disable_printer (const char *printer, const char *reason) { ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_TEXT, "printer-state-message", NULL, reason); ippDelete(cupsDoRequest (conn, request, "/admin/")); - if (cupsLastError() > IPP_STATUS_OK_CONFLICTING) { + if (cupsLastError() > IPP_STATUS_OK_EVENTS_COMPLETE) { debug_printf("ERROR: Failed disabling printer '%s': %s\n", printer, cupsLastErrorString()); return -1; @@ -2033,7 +2033,7 @@ set_cups_default_printer(const char *printer) { ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); ippDelete(cupsDoRequest(conn, request, "/admin/")); - if (cupsLastError() > IPP_STATUS_OK_CONFLICTING) { + if (cupsLastError() > IPP_STATUS_OK_EVENTS_COMPLETE) { debug_printf("ERROR: Failed setting CUPS default printer to '%s': %s\n", printer, cupsLastErrorString()); return -1; @@ -2059,7 +2059,7 @@ get_cups_default_printer() { "requesting-user-name", NULL, cupsUser()); /* Do it */ response = cupsDoRequest(conn, request, "/"); - if (cupsLastError() > IPP_OK_CONFLICT || !response) { + if (cupsLastError() > IPP_STATUS_OK_EVENTS_COMPLETE || !response) { debug_printf("Could not determine system default printer!\n"); } else { for (attr = ippFirstAttribute(response); attr != NULL; @@ -2782,7 +2782,7 @@ on_printer_state_changed (CupsNotifier *object, cupsEncodeOptions2(request, num_options, options, IPP_TAG_PRINTER); ippDelete(cupsDoRequest(conn, request, "/admin/")); cupsFreeOptions(num_options, options); - if (cupsLastError() > IPP_OK_CONFLICT) { + if (cupsLastError() > IPP_STATUS_OK_EVENTS_COMPLETE) { debug_printf("ERROR: Unable to set \"" CUPS_BROWSED_DEST_PRINTER "-default\" option to communicate the destination server for this job (%s)!\n", cupsLastErrorString()); @@ -3492,7 +3492,7 @@ gboolean handle_cups_queues(gpointer unused) { "requesting-user-name", NULL, cupsUser()); /* Do it */ ippDelete(cupsDoRequest(http, request, "/admin/")); - if (cupsLastError() > IPP_OK_CONFLICT) { + if (cupsLastError() > IPP_STATUS_OK_EVENTS_COMPLETE) { debug_printf("Unable to remove CUPS queue!\n"); if (in_shutdown == 0) { p->timeout = current_time + TIMEOUT_RETRY; @@ -3864,7 +3864,7 @@ gboolean handle_cups_queues(gpointer unused) { ippDelete(cupsDoRequest(http, request, "/admin/")); } cupsFreeOptions(num_options, options); - if (cupsLastError() > IPP_OK_CONFLICT) { + if (cupsLastError() > IPP_STATUS_OK_EVENTS_COMPLETE) { debug_printf("Unable to create/modify CUPS queue (%s)!\n", cupsLastErrorString()); p->timeout = current_time + TIMEOUT_RETRY; @@ -3895,7 +3895,7 @@ gboolean handle_cups_queues(gpointer unused) { cupsEncodeOptions2(request, num_options, options, IPP_TAG_PRINTER); ippDelete(cupsDoRequest(http, request, "/admin/")); cupsFreeOptions(num_options, options); - if (cupsLastError() > IPP_OK_CONFLICT) + if (cupsLastError() > IPP_STATUS_OK_EVENTS_COMPLETE) debug_printf("Unable to set printer-is-shared bit to false (%s)!\n", cupsLastErrorString()); @@ -3920,7 +3920,7 @@ gboolean handle_cups_queues(gpointer unused) { cupsEncodeOptions2(request, num_options, options, IPP_TAG_PRINTER); ippDelete(cupsDoRequest(http, request, "/admin/")); cupsFreeOptions(num_options, options); - if (cupsLastError() > IPP_OK_CONFLICT) + if (cupsLastError() > IPP_STATUS_OK_EVENTS_COMPLETE) debug_printf("Unable to remove PPD file from the print queue (%s)!\n", cupsLastErrorString()); } @@ -5498,7 +5498,7 @@ browse_poll_get_printers (browsepoll_t *context, http_t *conn) "requesting-user-name", NULL, cupsUser ()); response = cupsDoRequest(conn, request, "/"); - if (cupsLastError() > IPP_OK_CONFLICT) { + if (cupsLastError() > IPP_STATUS_OK_EVENTS_COMPLETE) { debug_printf("cups-browsed [BrowsePoll %s:%d]: failed: %s\n", context->server, context->port, cupsLastErrorString ()); goto fail; @@ -5585,7 +5585,8 @@ browse_poll_create_subscription (browsepoll_t *context, http_t *conn) "notify-time-interval", BrowseInterval); response = cupsDoRequest (conn, request, "/"); - if (!response || ippGetStatusCode (response) > IPP_OK_CONFLICT) { + if (!response || + ippGetStatusCode (response) > IPP_STATUS_OK_EVENTS_COMPLETE) { debug_printf("cupsd-browsed [BrowsePoll %s:%d]: failed: %s\n", context->server, context->port, cupsLastErrorString ()); context->subscription_id = -1; @@ -5652,7 +5653,8 @@ browse_poll_cancel_subscription (browsepoll_t *context) "notify-subscription-id", context->subscription_id); response = cupsDoRequest (conn, request, "/"); - if (!response || ippGetStatusCode (response) > IPP_OK_CONFLICT) + if (!response || + ippGetStatusCode (response) > IPP_STATUS_OK_EVENTS_COMPLETE) debug_printf("cupsd-browsed [BrowsePoll %s:%d]: failed: %s\n", context->server, context->port, cupsLastErrorString ()); @@ -5695,13 +5697,13 @@ browse_poll_get_notifications (browsepoll_t *context, http_t *conn) else status = ippGetStatusCode (response); - if (status == IPP_NOT_FOUND) { + if (status == IPP_STATUS_ERROR_NOT_FOUND) { /* Subscription lease has expired. */ debug_printf ("cups-browsed [BrowsePoll %s:%d]: Lease expired\n", context->server, context->port); browse_poll_create_subscription (context, conn); get_printers = TRUE; - } else if (status > IPP_OK_CONFLICT) { + } else if (status > IPP_STATUS_OK_EVENTS_COMPLETE) { debug_printf("cups-browsed [BrowsePoll %s:%d]: failed: %s\n", context->server, context->port, cupsLastErrorString ()); context->can_subscribe = FALSE; -- 2.11.0
>From 93fef84f53776c8a14c4f90affdf755546557ac0 Mon Sep 17 00:00:00 2001 From: Till Kamppeter <till.kamppe...@gmail.com> Date: Wed, 9 Aug 2017 15:11:06 -0300 Subject: [PATCH 2/2] cups-browsed: Make timeouts for HTTP access to the local CUPS daemon and remote IPP printers configurable. This is a backport from 1.16.1 Backport-by: Louis Rilling <l.rill...@av7.net> --- utils/cups-browsed.c | 28 ++++++++++++++++++++++------ utils/cups-browsed.conf.5 | 13 +++++++++++++ utils/cups-browsed.conf.in | 10 ++++++++++ 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/utils/cups-browsed.c b/utils/cups-browsed.c index 294e450..6932591 100644 --- a/utils/cups-browsed.c +++ b/utils/cups-browsed.c @@ -339,6 +339,8 @@ static size_t NumBrowsePoll = 0; static guint update_netifs_sourceid = 0; static char local_server_str[1024]; static char *DomainSocket = NULL; +static unsigned int HttpLocalTimeout = 5; +static unsigned int HttpRemoteTimeout = 10; static ip_based_uris_t IPBasedDeviceURIs = IP_BASED_URIS_NO; static unsigned int CreateRemoteRawPrinterQueues = 0; static unsigned int CreateIPPPrinterQueues = 0; @@ -579,6 +581,7 @@ httpConnectEncryptShortTimeout(const char *host, int port, int http_timeout_cb(http_t *http, void *user_data) { + debug_printf("HTTP timeout! (consider increasing HttpLocalTimeout/HttpRemoteTimeout value)\n"); return 0; } @@ -591,7 +594,7 @@ http_connect_local (void) cupsEncryption()); } if (local_conn) - httpSetTimeout(local_conn, 3, http_timeout_cb, NULL); + httpSetTimeout(local_conn, HttpLocalTimeout, http_timeout_cb, NULL); else debug_printf("cups-browsed: Failed creating http connection to local CUPS daemon: %s:%d\n", cupsServer(), ippPort()); @@ -2617,7 +2620,7 @@ on_printer_state_changed (CupsNotifier *object, p->port); if (http) { /* Check whether the printer is idle, processing, or disabled */ - httpSetTimeout(http, 2, http_timeout_cb, NULL); + httpSetTimeout(http, HttpRemoteTimeout, http_timeout_cb, NULL); request = ippNewRequest(CUPS_GET_PRINTERS); ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", @@ -3576,7 +3579,7 @@ gboolean handle_cups_queues(gpointer unused) { p->timeout = current_time + TIMEOUT_RETRY; break; } - httpSetTimeout(http, 3, http_timeout_cb, NULL); + httpSetTimeout(http, HttpLocalTimeout, http_timeout_cb, NULL); /* Do not auto-save option settings due to the print queue creation process */ @@ -3629,7 +3632,7 @@ gboolean handle_cups_queues(gpointer unused) { p->no_autosave = 0; break; } - httpSetTimeout(remote_http, 3, http_timeout_cb, NULL); + httpSetTimeout(remote_http, HttpRemoteTimeout, http_timeout_cb, NULL); if ((loadedppd = cupsGetPPD2(remote_http, p->name)) == NULL && CreateRemoteRawPrinterQueues == 0) { debug_printf("Unable to load PPD file for %s from the server %s:%d!\n", @@ -5632,7 +5635,7 @@ browse_poll_cancel_subscription (browsepoll_t *context) return; } - httpSetTimeout(conn, 3, http_timeout_cb, NULL); + httpSetTimeout(conn, HttpRemoteTimeout, http_timeout_cb, NULL); debug_printf ("cups-browsed [BrowsePoll %s:%d]: IPP-Cancel-Subscription\n", context->server, context->port); @@ -5774,7 +5777,7 @@ browse_poll (gpointer data) goto fail; } - httpSetTimeout(conn, 3, http_timeout_cb, NULL); + httpSetTimeout(conn, HttpRemoteTimeout, http_timeout_cb, NULL); if (context->can_subscribe) { if (context->subscription_id == -1) { @@ -6290,6 +6293,19 @@ read_configuration (const char *filename) } else if (!strcasecmp(line, "DomainSocket") && value) { if (value[0] != '\0') DomainSocket = strdup(value); + } else if ((!strcasecmp(line, "HttpLocalTimeout") || !strcasecmp(line, "HttpRemoteTimeout")) && value) { + int t = atoi(value); + if (t >= 0) { + if (!strcasecmp(line, "HttpLocalTimeout")) + HttpLocalTimeout = t; + else if (!strcasecmp(line, "HttpRemoteTimeout")) + HttpRemoteTimeout = t; + + debug_printf("Set %s to %d sec.\n", + line, t); + } else + debug_printf("Invalid %s value: %d\n", + line, t); } else if (!strcasecmp(line, "IPBasedDeviceURIs") && value) { if (!strcasecmp(value, "IPv4") || !strcasecmp(value, "IPv4Only")) IPBasedDeviceURIs = IP_BASED_URIS_IPV4_ONLY; diff --git a/utils/cups-browsed.conf.5 b/utils/cups-browsed.conf.5 index 81da976..30bbb31 100644 --- a/utils/cups-browsed.conf.5 +++ b/utils/cups-browsed.conf.5 @@ -416,6 +416,19 @@ or "Off" lets cups-browsed not use CUPS' domain socket. .fam T .fi +Set HTTP timeout (in seconds) for requests sent to local/remote +resources Note that too short timeouts can make services getting +missed when they are present and operations be unneccesarily +repeated and too long timeouts can make operations take too long +when the server does not respond. +.PP +.nf +.fam C + HttpLocalTimeout 5 + HttpRemoteTimeout 10 + +.fam T +.fi The interval between browsing/broadcasting cycles, local and/or remote, can be adjusted with the BrowseInterval directive. .PP diff --git a/utils/cups-browsed.conf.in b/utils/cups-browsed.conf.in index fd197cf..9fbd274 100644 --- a/utils/cups-browsed.conf.in +++ b/utils/cups-browsed.conf.in @@ -301,6 +301,16 @@ BrowseRemoteProtocols @BROWSEREMOTEPROTOCOLS@ # DomainSocket Off +# Set HTTP timeout (in seconds) for requests sent to local/remote +# resources Note that too short timeouts can make services getting +# missed when they are present and operations be unneccesarily +# repeated and too long timeouts can make operations take too long +# when the server does not respond. + +# HttpLocalTimeout 5 +# HttpRemoteTimeout 10 + + # Set IPBasedDeviceURIs to "Yes" if cups-browsed should create its # local queues with device URIs with the IP addresses instead of the # host names of the remote servers. This mode is there for any -- 2.11.0