Add NOTE on the SSL trouble
authorEugene Crosser <Eugene.Crosser@ru.ibm.com>
Thu, 9 Feb 2012 15:52:13 +0000 (19:52 +0400)
committerEugene Crosser <Eugene.Crosser@ru.ibm.com>
Thu, 9 Feb 2012 15:52:13 +0000 (19:52 +0400)
NOTES.ssl-trouble [new file with mode: 0644]

diff --git a/NOTES.ssl-trouble b/NOTES.ssl-trouble
new file mode 100644 (file)
index 0000000..779eff6
--- /dev/null
@@ -0,0 +1,59 @@
+https://groups.google.com/d/topic/google-api-java-client/iSL2bzoy9jw/discussion
+
+When an API call is performed over Apache HTTP client after long period of inactivity, this exception happens:
+
+W/System.err(  350): java.io.IOException: SSL shutdown failed: I/O error during system call, Broken pipe
+W/System.err(  350):   at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.nativeclose(Native Method)
+W/System.err(  350):   at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.close(OpenSSLSocketImpl.java:958)
+W/System.err(  350):   at org.apache.http.impl.SocketHttpClientConnection.close(SocketHttpClientConnection.java:205)
+W/System.err(  350):   at org.apache.http.impl.conn.DefaultClientConnection.close(DefaultClientConnection.java:161)
+W/System.err(  350):   at org.apache.http.impl.conn.AbstractPooledConnAdapter.close(AbstractPooledConnAdapter.java:158)
+W/System.err(  350):   at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125)
+W/System.err(  350):   at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:410)
+W/System.err(  350):   at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
+W/System.err(  350):   at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
+W/System.err(  350):   at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
+W/System.err(  350):   at com.google.api.client.http.apache.ApacheHttpRequest.execute(ApacheHttpRequest.java:58)
+W/System.err(  350):   at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:639)
+W/System.err(  350):   at com.google.api.client.http.json.JsonHttpClient.execute(JsonHttpClient.java:257)
+W/System.err(  350):   at com.google.api.client.googleapis.services.GoogleClient.execute(GoogleClient.java:121)
+W/System.err(  350):   at com.google.api.client.http.json.JsonHttpRequest.executeUnparsed(JsonHttpRequest.java:67)
+W/System.err(  350):   at com.google.api.services.calendar.Calendar$Events$List.execute(Calendar.java:2643)
+
+Presumably the Apache HttpClient connection manager notices that connection(s) are stale and tries to close them before re-opening to execute the current request.
+
+SocketHttpClientConnection.close looks like this:
+
+   public void close() throws IOException {
+       if (!this.open) {
+           return;
+       }
+       this.open = false;
+       Socket sock = this.socket;
+       try {
+           doFlush();
+           try {
+               try {
+                   sock.shutdownOutput();
+               } catch (IOException ignore) {
+               }
+               try {
+                   sock.shutdownInput();
+               } catch (IOException ignore) {
+               }
+           } catch (UnsupportedOperationException ignore) {
+               // if one isn't supported, the other one isn't either
+           }
+       } finally {
+           sock.close();
+       }
+   }
+
+It does catch and ignore IOException from shutdown() calls. Having done shutdown for both read and write, the assumption is that sock.close() will never throw a spurious exception.
+
+But in our case the socket is not a TCP socket, but an SSL one. Presumably, socket close() is executed by
+
+org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.close(OpenSSLSocketImpl.java:958)
+
+I cannot find the source code of this module anywhere (there is no such file in the Apache Harmony tree). Anyway, my hypothesis is that while regular TCP socket close() succeeds when the peer is already gone, the implementation of close() in this class tries to close the SSL session prior to closing the TCP socket, and that involves sending a message over the underlying TCP connection. Possibly the IOException that happens if the peer has already closed the TCP connection should have been ignored in this case. And prossibly it is not. Therefore it is propagated upstream, and nobody upstream expects that close would throw an exception in such a trivial case.
+