From 93fef84f53776c8a14c4f90affdf755546557ac0 Mon Sep 17 00:00:00 2001
From: Till Kamppeter <till.kamppeter@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.rilling@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

