[prev in list] [next in list] [prev in thread] [next in thread] 

List:       cups-bugs
Subject:    [cups.bugs] [MOD] STR #4187: _cupsConnect() can return cached http connection which is already unusa
From:       Petr Cvachoucek <petr.cvachoucek () oracle ! com>
Date:       2012-09-12 8:01:49
Message-ID: 20120912080149.8202D3C6848F () dns ! easysw ! com
[Download RAW message or body]

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
["cupsconnect.patch" (text/plain)]

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...
   */


_______________________________________________
cups-bugs mailing list
cups-bugs@easysw.com
http://lists.easysw.com/mailman/listinfo/cups-bugs


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic