users@grizzly.java.net

Re: Implementing a NIO tunnel with Grizzly

From: Sam Crawford <samcrawford_at_gmail.com>
Date: Tue, 1 Sep 2009 17:10:19 +0100

Adding the following to handleAccept in the filter does what I want,
but it doesn't seem very modern! I'm going to explore using the
ScheduledExecutorService, but would still be interested to know if
there's a proper grizzly way of doing this.

Thanks,

Sam


Thread r = new Thread() {
        public void run() {
                try {
                        Thread.sleep(5000);
                        // ctx.getConnection() is still null in handleAccept...
                        Connection conn = ctx.getProcessorRunnable().getConnection();
                        TunnelHandshake handshake = handshakeAttribute.get(conn);
                        if (handshake == null || !handshake.isComplete()) {
                                System.out.println("Closing connection");
                                conn.close();
                        }
                } catch (Exception e) {
                        e.printStackTrace();
                }
        }
};
r.start();




2009/9/1 Sam Crawford <samcrawford_at_gmail.com>:
> Hi Alexey,
>
> Thanks, but I recognise already that we don't need to block for
> operations. I've had great success with getting the non-blocking
> aspect working well!
>
> My question was around creating time limits for logical steps of
> execution (not physical timeouts when reading from a blocking
> socket!). So my handshaking process completes in a non-blocking
> manner, but I want to enforce an absolute time limit of 5 seconds that
> the handshake can take.
>
> To be specific:
>
> 1. If the client connects but does not transfer any bytes then the
> connection should be dropped after 5 seconds
> 2. If the client connects and starts the handshake, but does not
> complete it within 5 seconds, then the connection should be dropped
> 3. If the client connects, completes the handshake within 5 seconds,
> and establishes the tunnel then there should not be an enforced
> timeout
>
> Thanks,
>
> Sam
>
>
> 2009/9/1 Oleksiy Stashok <Oleksiy.Stashok_at_sun.com>:
>> Hi Sam,
>>
>>> Apologies for the slow reply. There was no issues with the tunneling
>>> when the exception was thrown, so I'm not concerned about it.
>>>
>>> I'm now actively working on porting our project to use Grizzly (and I
>>> will certainly write an article afterwards to cover my experiences!),
>>> and have another query...
>>>
>>> Our tunneling mechanism uses a handshaking mechanism (not unlike a
>>> SOCKS proxy with the CONNECT header). We don't want to wait
>>> indefinitely for the handshake to complete (e.g. 5 seconds is probably
>>> a sensible maximum). That said, once the tunnel is running, we would
>>> not want to have any timeouts (i.e. the tunnel should be able to sit
>>> idle for hours if need be).
>>>
>>> In the old Java sockets API I'd set a read timeout on the socket
>>> before doing the handshaking, and remove it afterwards.
>>>
>>> I can't see how to achieve the same (or similar) in Grizzly 2.0. Is
>>> there a recommended way of doing this?
>>
>> By default all the I/O operations on Grizzly 2.0 TCP NIO connections are
>> non-blocking.
>> You have Grizzly Connection object, which represents your network connection
>> [1]. You can get StreamReader, StreamWriter out of this Connection.
>>
>> Using StreamReader [2] you can check number of bytes available for reading:
>> StreamReader.availableDataSize() or retrieve/register some notifier, which
>> will notify you, when StreamReader state will be changed: new bytes become
>> available, connection was closed etc:
>> Future f = StreamReader.notifyAvailable(numberOfBytes, [completionHandler]);
>>
>> Using StreamWriter [3] you can perform write operations in non-blocking
>> mode, using StreamWriter.writeXXX(...). By calling
>> Future f = StreamReader.flush([completionHandler]);
>> you can register/retrieve notifier, using which you can asynchronously check
>> write operation completion state.
>>
>> So, really, you don't to block for anything :)
>>
>> Please let me know, if you'll have any questions.
>>
>> WBR,
>> Alexey.
>>
>>
>> [1]
>> https://grizzly.dev.java.net/source/browse/grizzly/branches/2dot0/code/modules/grizzly/src/main/java/com/sun/grizzly/Connection.java?rev=3266&view=markup
>> [2]
>> https://grizzly.dev.java.net/source/browse/grizzly/branches/2dot0/code/modules/grizzly/src/main/java/com/sun/grizzly/streams/StreamReader.java?rev=3292&view=markup
>> [3]
>> https://grizzly.dev.java.net/source/browse/grizzly/branches/2dot0/code/modules/grizzly/src/main/java/com/sun/grizzly/streams/StreamWriter.java?rev=3496&view=markup
>>
>>>
>>> Thanks again,
>>>
>>> Sam
>>>
>>>
>>>
>>> 2009/8/18 Oleksiy Stashok <Oleksiy.Stashok_at_sun.com>:
>>>>
>>>> Hi Sam,
>>>>
>>>>> I've fired up the example you provided and it seems pretty
>>>>> straightforward and works well.
>>>>>
>>>>> However, when doing some quick tests via it I noted the following
>>>>> exception was printed every so often... Is this something to be
>>>>> concerned about? I was running this with the latest 2.0 SNAPSHOT.
>>>>
>>>> Hmm, I think you can say me, if it's something you have concerns about
>>>> :))))
>>>> For me it looks like issue occurs, when Filter decides to close one
>>>> connection, it also closes a peer connection. And closing of peer
>>>> connection
>>>> may cause this exception.
>>>>
>>>> Do you see any problem with tunneling functionality, when the exception
>>>> occurs?
>>>>
>>>> I will probably reduce the logging level for the exception.
>>>>
>>>> Thank you.
>>>>
>>>> WBR,
>>>> Alexey.
>>>>
>>>>>
>>>>> Thanks
>>>>>
>>>>> Sam
>>>>>
>>>>> # java -cp "grizzly-framework-2.0.0-SNAPSHOT.jar:."
>>>>> com.sun.grizzly.samples.tunnel.TunnelServer
>>>>> Aug 16, 2009 9:33:31 PM com.sun.grizzly.samples.tunnel.TunnelServer main
>>>>> INFO: Press any key to stop the server...
>>>>> Aug 16, 2009 9:33:36 PM com.sun.grizzly.nio.transport.TCPNIOTransport
>>>>> fireIOEvent
>>>>> WARNING: Unexpected exception occurred
>>>>>
>>>>>
>>>>> fireIOEvent().connection=com.sun.grizzly.nio.transport.TCPNIOConnection_at_785f8172
>>>>> event=READ
>>>>> java.nio.channels.CancelledKeyException
>>>>>      at
>>>>> sun.nio.ch.SelectionKeyImpl.ensureValid(SelectionKeyImpl.java:55)
>>>>>      at
>>>>> sun.nio.ch.SelectionKeyImpl.interestOps(SelectionKeyImpl.java:64)
>>>>>      at
>>>>>
>>>>> com.sun.grizzly.nio.DefaultSelectorHandler.unregisterKey0(DefaultSelectorHandler.java:216)
>>>>>      at
>>>>>
>>>>> com.sun.grizzly.nio.DefaultSelectorHandler.unregisterKey(DefaultSelectorHandler.java:104)
>>>>>      at
>>>>>
>>>>> com.sun.grizzly.nio.AbstractNIOConnection.disableIOEvent(AbstractNIOConnection.java:271)
>>>>>      at
>>>>>
>>>>> com.sun.grizzly.nio.transport.TCPNIOTransport.executeDefaultProcessor(TCPNIOTransport.java:730)
>>>>>      at
>>>>>
>>>>> com.sun.grizzly.nio.transport.TCPNIOTransport.processReadIoEvent(TCPNIOTransport.java:703)
>>>>>      at
>>>>>
>>>>> com.sun.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:648)
>>>>>      at com.sun.grizzly.nio.SelectorRunner.fire(SelectorRunner.java:385)
>>>>>      at
>>>>>
>>>>> com.sun.grizzly.nio.SelectorRunner.iterateKeyEvents(SelectorRunner.java:317)
>>>>>      at
>>>>> com.sun.grizzly.nio.SelectorRunner.iterateKeys(SelectorRunner.java:287)
>>>>>      at
>>>>> com.sun.grizzly.nio.SelectorRunner.doSelect(SelectorRunner.java:259)
>>>>>      at com.sun.grizzly.nio.SelectorRunner.run(SelectorRunner.java:190)
>>>>>      at
>>>>>
>>>>> java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
>>>>>      at
>>>>>
>>>>> java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
>>>>>      at java.lang.Thread.run(Thread.java:619)
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> 2009/8/12 Sam Crawford <samcrawford_at_gmail.com>:
>>>>>>
>>>>>> Brilliant, thank you very much! Hopefully I'll get started on this
>>>>>> next month and you'll no doubt see me posting lots of questions here.
>>>>>>
>>>>>> Thanks,
>>>>>>
>>>>>> Sam
>>>>>>
>>>>>>
>>>>>> 2009/8/11 Oleksiy Stashok <Oleksiy.Stashok_at_sun.com>:
>>>>>>>
>>>>>>> Hi Sam,
>>>>>>>
>>>>>>>> I'm currently looking to rewrite our (blocking) tunneling software
>>>>>>>> using NIO (in an effort to increase scalability), and Grizzly seems
>>>>>>>> like it could save me a considerable amount of time. To be clear,
>>>>>>>> this
>>>>>>>> is for tunneling arbitrary TCP traffic (not just HTTP!), over both
>>>>>>>> SSL
>>>>>>>> and non-SSL.
>>>>>>>>
>>>>>>>> Having searched the archives, I see that someone else two years was
>>>>>>>> interested in something similar
>>>>>>>>
>>>>>>>>
>>>>>>>> (https://grizzly.dev.java.net/servlets/ReadMsg?listName=users&msgNo=52).
>>>>>>>> Are the concepts largely the same nowadays? I know the Grizzly
>>>>>>>> libraries have progressed a great deal since then, so I didn't want
>>>>>>>> to
>>>>>>>> dive too deeply into that if there were more appropriate ways of
>>>>>>>> achieving this these days.
>>>>>>>>
>>>>>>>> Any other pointers would be most welcome!
>>>>>>>
>>>>>>> IMHO it should be pretty easy to write simple tunneling application.
>>>>>>> All you'll need on server side - is to build filter chain and keep
>>>>>>> client<->server connection map to redirect data among them.
>>>>>>>
>>>>>>> I've just created simple tunnel example for Grizzly 2.0, hope it will
>>>>>>> help.
>>>>>>> To build them - please use the latest Grizzly 2.0 snapshot [2]
>>>>>>>
>>>>>>> WBR,
>>>>>>> Alexey.
>>>>>>>
>>>>>>> [1]
>>>>>>>
>>>>>>>
>>>>>>> https://grizzly.dev.java.net/source/browse/grizzly/branches/2dot0/code/samples/framework-samples/src/main/java/com/sun/grizzly/samples/tunnel/
>>>>>>> [2]
>>>>>>>  <groupId>com.sun.grizzly</groupId>
>>>>>>>  <artifactId>grizzly-framework</artifactId>
>>>>>>>  <version>2.0.0-SNAPSHOT</version>
>>>>>>>
>>>>>>>>
>>>>>>>> Many thanks,
>>>>>>>>
>>>>>>>> Sam
>>>>>>>>
>>>>>>>> ---------------------------------------------------------------------
>>>>>>>> To unsubscribe, e-mail: users-unsubscribe_at_grizzly.dev.java.net
>>>>>>>> For additional commands, e-mail: users-help_at_grizzly.dev.java.net
>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> ---------------------------------------------------------------------
>>>>>>> To unsubscribe, e-mail: users-unsubscribe_at_grizzly.dev.java.net
>>>>>>> For additional commands, e-mail: users-help_at_grizzly.dev.java.net
>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>> ---------------------------------------------------------------------
>>>>> To unsubscribe, e-mail: users-unsubscribe_at_grizzly.dev.java.net
>>>>> For additional commands, e-mail: users-help_at_grizzly.dev.java.net
>>>>>
>>>>
>>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: users-unsubscribe_at_grizzly.dev.java.net
>>>> For additional commands, e-mail: users-help_at_grizzly.dev.java.net
>>>>
>>>>
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: users-unsubscribe_at_grizzly.dev.java.net
>>> For additional commands, e-mail: users-help_at_grizzly.dev.java.net
>>>
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe_at_grizzly.dev.java.net
>> For additional commands, e-mail: users-help_at_grizzly.dev.java.net
>>
>>
>