[MOD] STR #4187: _cupsConnect() can return cached http connection which is already unusable
Petr Cvachoucek <[email protected]> Wed, 12 Sep 2012 01:01:49 -0700 (PDT)
| Newsgroups | gmane.comp.printing.cups.bugs |
|---|---|
| Message-ID | <[email protected]> |
DO NOT REPLY TO THIS MESSAGE. INSTEAD, POST ANY RESPONSES TO THE LINK BELOW. [STR New] Hi all, we have CUPS clients configured to print directly to remote CUPS server - ie. we have /etc/cups/client.conf with ServerName pointing to our CUPS server. And we see such unpleasant behavior: 1) first time the app does some request to libcups.so, the HTTP connection is created and used - all works ok. The HTTP connection is not closed but cached in _cupsGlobals. 2) The CUPS server has its timeout - if the connection is idle for some time (the default is 5 minutes), it closes it. This can be verified for example by netstat output on clients - the TCP connection state changes from ESTABLISHED to CLOSE_WAIT. 3) Next time the app does some request to libcups.so, the cached HTTP connection is directly used - returned by _cupsConnect(). Request is sent (no error produced) and when reading response, the recv() call gets ECONNRESET and the request fails. This is easy to reproduce. Start OpenOffice or LibreOffice, open "File -> Printer Settings" dialog, close it and wait 5 minutes. Then try to open it again - and the list of printers is empty. The idea for fix is to check the TCP connection state in _cupsConnect() and verify the connection is still in ESTABLISHED state. If its not then close it - the _cupsConnect() will then re-create it. I'm attaching the patch with the fix for Solaris - checking the TCP connection state is system-specific, so the real fix for upstream would have to add the code for other supported platforms as well. I understand the fix is not perfect - there's still chance for request to fail if the server closes the connection just after the client checks it. But it is not very invasive and improves the users experience a lot in this scenario, because otherwise this bug is hit always and is very annoying for users. Link: http://www.cups.org/str.php?L4187 Version: 1.6-current _______________________________________________ cups-bugs mailing list [email protected] http://lists.easysw.com/mailman/listinfo/cups-bugs
cupsconnect.patch
(text/plain, 1.3 KB)
diff -Naur cups-1.6svn-r10486.orig/cups/request.c cups-1.6svn-r10486/cups/request.c
--- cups-1.6svn-r10486.orig/cups/request.c 2012-05-12 02:07:16.000000000 +0200
+++ cups-1.6svn-r10486/cups/request.c 2012-09-12 09:16:21.888777664 +0200
@@ -46,7 +46,9 @@
#ifndef O_BINARY
# define O_BINARY 0
#endif /* O_BINARY */
-
+#if defined(__sun)
+#include <inet/tcp.h> /* need this for TCPS_ESTABLISHED ... */
+#endif
/*
* 'cupsDoFileRequest()' - Do an IPP request with a file.
@@ -1000,6 +1002,38 @@
}
}
+#if defined(__sun)
+ /*
+ * Check the connection state.
+ * If the connection wasn't used for some time, the server could close it.
+ * The socket state would change to CLOSE_WAIT in such case.
+ */
+ if (cg->http)
+ {
+ struct tcp_info tcpi;
+ socklen_t len = sizeof(tcpi);
+ memset(&tcpi, 0, sizeof(tcpi));
+
+ /*
+ * Get TCP connection info.
+ */
+ if (getsockopt(cg->http->fd, IPPROTO_TCP, TCP_INFO, &tcpi, &len) == 0)
+ {
+ /*
+ * Successfully got TCP connection state. Check it.
+ */
+ if (tcpi.tcpi_state != TCPS_ESTABLISHED)
+ {
+ /*
+ * Need to close the current connection.
+ */
+ httpClose(cg->http);
+ cg->http = NULL;
+ }
+ }
+ }
+#endif
+
/*
* (Re)connect as needed...
*/