java.lang.UnsupportedOperationException: The method shutdownOutput() is not supported in SSLSocket

1,123 views
Skip to first unread message

Will Currie

unread,
Aug 6, 2012, 9:17:16 PM8/6/12
to jpos-...@googlegroups.com
Has anybody else run into a stack trace like the following when trying to call XMLChannel.disconnect() ?

java.lang.UnsupportedOperationException: The method shutdownOutput() is not supported in SSLSocket
    at sun.security.ssl.BaseSSLSocketImpl.shutdownOutput(BaseSSLSocketImpl.java:211)
    at org.jpos.iso.BaseChannel.closeSocket(BaseChannel.java:1032)
    at org.jpos.iso.BaseChannel.disconnect(BaseChannel.java:742)
    at org.jpos.iso.channel.XMLChannel.disconnect(XMLChannel.java:116)

This is using jpos 1.8.2 but the closeSocket() method is unchanged. We are trying to upgrade from version 1.6.6. I understand the reason for change to closeSocket() but I can't see how this change works when using SSL. The reason for this method not being supported is discussed here.

Why am I the first person to encounter this issue? I presume I am missing something simple. Or nobody else uses SSL with jpos. Or nobody closes connections...

We are using SunJSSESocketFactory.


Victor Salaman

unread,
Aug 6, 2012, 9:23:41 PM8/6/12
to jpos-...@googlegroups.com
Please put together a standalone piece of code that reproduces the exception so we can review.

Thanks


Sent from my iPhone.
--
--
jPOS is licensed under AGPL - free for community usage for your open-source project. Licenses are also available for commercial usage.
Please support jPOS, contact: sa...@jpos.org
 
You received this message because you are subscribed to the "jPOS Users" group.
Please see http://jpos.org/wiki/JPOS_Mailing_List_Readme_first
To post to this group, send email to jpos-...@googlegroups.com
To unsubscribe, send email to jpos-users+...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/jpos-users
 
 
 

Alejandro Revilla

unread,
Aug 6, 2012, 9:44:33 PM8/6/12
to jpos-...@googlegroups.com
Thanks for the link. I guess we'll have to delegate channel closing to the SSL socket factory implementation, so we can take special action in SSL connections. Will follow up shortly. i don't think we need test code, just setting an SSL channel and redeploying it should reproduce the problem. 

@apr

Alejandro Revilla

unread,
Aug 7, 2012, 10:29:06 AM8/7/12
to jpos-...@googlegroups.com
FYI, just created jPOS-85. Hope you can join the discussion there Will (I tried to add you as a watcher, but not sure you have created an account on the jPOS issuer tracker).

--
@apr



Will Currie

unread,
Aug 7, 2012, 9:52:05 PM8/7/12
to jpos-...@googlegroups.com
Thanks. I tried out the change in jPOS-85. Unfortunately it does not solve the problem if the server calls disconnect() on the channel. I created the attached test to highlight the problem (SslChannelIntegrationTest). Since the test uses SSL you need a keystore. If you put the attached one in jpos/src/test/resources and make sure the working directory is <checkout-root>/jpos when you run the test you should get similar results to the attached output. The test is probably flaky but highlights the issue.

If you change the if statement added in jPOS-85 to 'if (!(s instanceof SSLSocket))' the test passes.

I created an account in the issuer tracker but couldn't comment there (for good reasons I imagine).

Will.
ssl-unsupported-operation-exception.patch
keystore.jks
failing-test-output.txt

Will Currie

unread,
Aug 7, 2012, 10:03:23 PM8/7/12
to jpos-...@googlegroups.com
Out of interest, can I get an answer to my earlier question of "Why am I the first person to encounter this issue?" I see the following possibilities:
  • SSL is not widely used with JPOS. Do other folks handle encryption at another layer?
  • Other folks are not running a recent release.
  • Other folks don't encounter or trigger disconnects often and so don't notice or just ignore the error. Perhaps it's swallowed by calling code.
Thanks.

On Wednesday, 8 August 2012 00:29:06 UTC+10, Alejandro Revilla wrote:

Will Currie

unread,
Aug 8, 2012, 12:24:54 AM8/8/12
to jpos-...@googlegroups.com
Sorry to keep replying to myself. I can also make the SslChannelIntegrationTest pass by setting a socketFactory on the ISOServer's channel. Eg add 'clientSide.setSocketFactory(new SunJSSESocketFactory());' at line 78. Perhaps Q2 sets the socketFactory here by default (even though it is not used). We don't (at least currently) use Q2 as our deployment infrastructure is built around Jetty. Using 'if (!(s instanceof SSLSocket))' to avoid the exception seems a little more direct to me. If you'd like to sick with socketFactory != null we can change our code.

On another tack, what problem does calling setSoLinger() at all solve? Why not just call Socket.close()? Please excuse my naivety. I'm sure there are good reasons for the code in BaseChannel.closeSocket() but isn't the default behaviour of Socket.close() to handle the work of closing the socket in an orderly fashion (and timing out if this doesn't happen) off to the operating system after close() returns (reference).

Will Currie

unread,
Aug 8, 2012, 6:06:55 AM8/8/12
to jpos-...@googlegroups.com
Here's a little more context to my question about the call to setSoLinger(true, 5) in BaseChannel. I can appreciate it might be useful to somebody else (and maybe to me too in some circumstances). My employer has a switch with 1000s of terminals connected to an ISOServer over net links of varying quality. Ideally each terminal maintains one channel to the switch. Often enough a terminal will open a new channel without the switch seeing a close on the old channel (say the GPRS connection dropped or local router was rebooted). 

To prevent sessions being leaked the switch closes the old channel on receipt of a message on the new channel (using a map from terminal id to channel). It does this by calling disconnect() on the channel. Hence why we see the original UnsupportedOperationException from a server side disconnect() call. And why I'm a little nervous about each of these disconnect() calls blocking for 5 seconds whilst the Socket.close() call waits for the orderly TCP close to time out (because there's no longer a device on the other side).

We can work around this in our switch (calling close in another thread perhaps) but in this use case the original TCP RST behaviour was actually perfect. We have another use case where an orderly TCP disconnect is preferable (switch upgrades) but only to be good TCP citizens (and avoid a memory leak in our terminal manufacturers code caused by receipt of TCP RST packets).

Perhaps adding a disconnect(boolean orderly) method leaving disconnect() calling disconnect(true) would help. Hopefully it wouldn't hinder. I can try it out in a fork, see if it works for us and create a pull request. We also have some hacks to work around not using Q2 which break upgrading from 1.6.6. I will float the idea with my employer (if you guys are open to the idea) of creating some pull requests for these too. They would be small changes to QMUX and ChannelAdaptor I think. Switching to Q2 is not viable in the short term for us I think. Yet we'd like to stay up to date.

For anybody confused by talk about setSoLinger() this seems a quite good reference (in addition to the references commit comments). I haven't yet delved into what complications SSL might add to Socket.close().

Will

Alejandro Revilla

unread,
Aug 8, 2012, 8:27:16 AM8/8/12
to jpos-...@googlegroups.com
Thank you for the patches, I've reopened jPOS-85 and will test with it (BTW, I liked the avoidNeedingToMoveTheMouseToMakeTheTestRunRepeatablyOnLinux :)

I will answer your questions here, and then perhaps we can continue the dialogue in jPOS-85 (you should be able to post comments, but let me know otherwise).


Out of interest, can I get an answer to my earlier question of "Why am I the first person to encounter this issue?" I see the following possibilities:
  • SSL is not widely used with JPOS. Do other folks handle encryption at another layer?
That is correct, most of the links with major networks I've seen don't use SSL encryption, they use VPN or even more archaic dedicated networks. That said, we have many applications that do use SSL encryption, specially when we have more than one distributed jPOS system, we use it a lot.
 
  • Other folks are not running a recent release.
That could be true too, there are many production instances running older versions out there. We (I speak for jPOS Consulting) run many very new ones in production, but probably without SSL.
  
  • Other folks don't encounter or trigger disconnects often and so don't notice or just ignore the error. Perhaps it's swallowed by calling code.
Honestly, I think I've seen that UnsupportedOperationException in some logs and it was in my to-research thing, it's just a warning after all.

Hope that answers your question. Thank you for the detailed report, comment and tests.

Will Currie

unread,
Aug 8, 2012, 10:55:05 AM8/8/12
to jpos-...@googlegroups.com

Thanks. That does answer my question. I forgot to say 'please' when re-asking it. My mother would be very disappointed.

Alejandro Revilla

unread,
Aug 8, 2012, 1:23:17 PM8/8/12
to jpos-...@googlegroups.com
Just fixed jPOS-85, now checking for "s instanceof SSLSocket". I didn't use that check in first place because I though we could get away by checking the socket factory, but problem is on channels created by an ISOServer, the socket factory is assigned to the ISOServer object, not the individual channels.

As for the SO_LINGER, we just try to expedite closing on flaky networks (mostly GPRS), so the system tries to handle the handshake, but in 5 seconds it just forgets about it. I believe the default is way larger. Using this trick, we recover faster and avoid 'pool exhausted' errors in the ISOServers.

Answering individual questions from your previous post:

>
To prevent sessions being leaked the switch closes the old channel on receipt of a message on the new channel (using a map from terminal id to channel)
>
You could just set a timeout on the socket, that's what we do for long lived connections. We know that there has to be traffic (either due to 0800s or high activity) say every minute, so we set a 5 minutes timeout, if we don't get a message in 5 minutes, the system gets an EOFException and the resource is freed.

>
We can work around this in our switch (calling close in another thread perhaps) but in this use case the original TCP RST behaviour was actually perfect.
> We have another use case where an orderly TCP disconnect is preferable (switch upgrades) but only to be good TCP citizens (and avoid a memory leak 
> in our terminal manufacturers code caused by receipt of TCP RST packets).
>
That was exactly our use case, poorly written TCP stacks in the terminal was causing problems (perhaps yours?)

>
Perhaps adding a disconnect(boolean orderly) method leaving disconnect() calling disconnect(true) would help. 
> Hopefully it wouldn't hinder. I can try it out in a fork, see if it works for us and create a pull request
>
That wouldn't hurt, and we can also make it configurable via Q2, with a default backward compatibility.

>
We also have some hacks to work around not using Q2 which break upgrading from 1.6.6.
I will float the idea with my employer (if you guys are open to the idea) of creating some pull requests for these too. 
> They would be small changes to QMUX and ChannelAdaptor I think. 
>
Sure!

>
> Switching to Q2 is not viable in the short term for us I think. Yet we'd like to stay up to date.
>
You'll find out that it is not that hard to make the move, you can run Jetty from Q2, or Q2 from Jetty, it's as easy as instantiating a Q2 object and let it run.

--
Reply all
Reply to author
Forward
0 new messages