users@grizzly.java.net

Re: [Q] How-to client Protocol

From: Jeanfrancois Arcand <Jeanfrancois.Arcand_at_Sun.COM>
Date: Tue, 04 Mar 2008 11:13:38 -0500

Simon Trudeau wrote:
> Of course it sounds french, I'm from Montreal! :.)

And I'm on the 15 North :-)

>
> Your tutorial on SIP
>
> http://weblogs.java.net/blog/jfarcand/archive/2008/02/writing_a_tcpud_1.
> html
>
> and the one from Erick
>
> http://www.nabble.com/Grizzly-on-the-client-side%2C-a-modest-tutorial-td
> 15643977.html
>
> were real breakthrough for me, they gave me the starting point I needed
> to understand Grizzly better. By the way, I am still anxiously waiting
> to the follow up to your Sip tutorial ;.P

:-) Working on it, but have all kind of firedrill this week :-)

>
> Now moving onward to my not so obvious stuff...
>
> Thanks for the quick reply. I so much wish I could make use of something
> standard such as SSL but unfortunately I can't. I am using Grizzly to
> communicate to a legacy device (actually thousands of them...) which
> implements its own custom password negotiation protocol. That is why I
> need to implement my own protocol. Unfortunately, I only have control of
> the code on my client application side, the server side being the legacy
> device.
>
> So, what would you recommend?
>
> I think I cannot avoid it, I need to implement my own protocolFilter on
> the client side.
>
> My idea is the following...
>
> ***** Client Snippet ****
>
> Controller controller = new Controller();
> TCPSelectorHandler mySelectorHandler = new TCPSelectorHandler() ;
>
> mySelectorHandler.setProtocolChainInstanceHandler(new
> DefaultProtocolChainInstanceHandler(){
> public ProtocolChain poll()
> {
> ProtocolChain protocolChain = protocolChains.poll();
> if (protocolChain == null)
> {
> protocolChain = new DefaultProtocolChain();
> protocolChain.addFilter(new ReadFilter());
> protocolChain.addFilter(new MyProtocolFilter());
> }
> return protocolChain;
> }
> });
>
> controller.addSelectorHandler(mySelectorHandler);
>
> ...
>
> TCPConnectorHandler myConnectorHandler = (TCPConnectorHandler)
> controller.acquireConnectorHandler(Controller.Protocol.TCP);
> myConnectorHandler.connect(new InetSocketAddress(host, port));
>
> ...
>
> Public class MyProtocolFilter() implements ProtocolFilter
> {
> public boolean execute(Context ctx) throws IOException
> {
> - Set custom state information in ctx object according
> to my protocol
> - Given a certain custom state stored in the ctx object,
> process the message according to the given state.

So far so good.


> }
> }
>
> ************
>
> Does my pseudo code make sense or am I totally wrong?

Make a lot of senses!

>
> How should I go about managing state for my protocol?

You have two solutions:

(1) Use a statefull ProtocolChain/ProtocolChainInstanceHandler. That
means that each Thread will execute their own instance of ProtocolFilter
(your myProtocolFilter). Some like:


> ProtocolChainInstanceHandler pciHandler =
> new ProtocolChainInstanceHandler() {
>
> final private ConcurrentLinkedQueue<ProtocolChain> protocolChains = ...
> public ProtocolChain poll() {
> return protocolChains.poll();
> }
>
> public boolean offer(ProtocolChain instance) {
> return protocolChains.offer(instance);
> }
> };
> controller.setProtocolChainInstanceHandler(pciHandler);

And then you can store the information inside the Context. Or you can

(2) Store the information inside the SelectorHandler's attributes list

ctx.getSelectorHandler().setAttribute(...);

The information will be available to all ProtocolFlter via the ctx
interface.

Should I store
> them in the Context object or declare them as private variable in the
> MyProtocolFilter() object? The SSLReadFilter seems to hold a private
> SSLContext...
>
> I am not sure I understand the life cycle of the MyProtocolFilter? Is my
> instance alive as long as I have a connection? It is important for me to
> know that since I need to make the appropriate cleanup if the connection
> drops or an exception is raised.

Depending on how you create your ProtocolChain, you may have several
ProtocolChain (hence ProtocolFilter) inside your
ProtocolChainInstanceHandler. That may impact performance if you need to
serve 20 000 connections. The alternative is to use a stateless
ProtocolChainInstanceHandler:


> ProtocolChainInstanceHandler pciHandler =
> new ProtocolChainInstanceHandler() {
>
> final private ProtocolChain protocolChain = new DefaultProtocolChain();
>
> public ProtocolChain poll() {
> return protocolChain;
> }
>
> public boolean offer(ProtocolChain instance) {
> return true;
> }
> };
> controller.setProtocolChainInstanceHandler(pciHandler);

That means only 1 ProtocolChain will be created (and only one
myProtocolChain).

If the connection drop, your ProtocolFilter will never get deleted
unless you implement the behavior (but I would not recommend that).

>
>
> Thanks for your help,
>
>
> Simon
>
> By the way, a tutorial on exception handling using Grizzly could be
> great!

Merci!

-- Jeanfrancois

>
>
> -----Original Message-----
> From: Jeanfrancois.Arcand_at_Sun.COM [mailto:Jeanfrancois.Arcand_at_Sun.COM]
> Sent: February-29-08 4:01 PM
> To: users_at_grizzly.dev.java.net
> Subject: Re: [Q] How-to client Protocol
>
> Hi Simon (sound french :-))
>
> Simon Trudeau wrote:
>> I'm looking for help building a TCP client with a specific protocol :
>>
>>
>>
>> If server is password protected:
>>
>>
>>
>> 1. Client connects to server
>> 2. Server sends password prompt to client
>> 3. Client sends server's password
>> 4. Server sends acknowledgement
>> 5. Client sends request
>> 6. Server sends reply
>> 7. Repeat step 5 and 6
>>
>>
>>
>> If server is not password protected:
>>
>>
>>
>> 1. Client connects to server
>> 2. Client sends request
>> 3. Server sends reply
>> 4. Repeat step 2 and 3
>>
>>
>>
>> How should I go about implementing this protocol? In once case, the
>> client, upon establishing a connection, can send a request right away
> in
>> the other case, it must wait for the server to negotiate the password.
>>
>>
>>
>> What's the right way to handle protocol specific data exchange on the
>> client side?
>
> With Grizzly, you don't have to implement such mechanism, as it already
> support it by default. I will first explain without too much details, so
>
> feel free to ask questions if I'm unclear. But first, are you planning
> to use a single port for both TLS (secure) and TCP (unsecure) or will
> you have two ports? We have a mechanism that support a single port:
>
> http://weblogs.java.net/blog/jfarcand/archive/2006/11/one_port_to_rul.ht
> ml
>
> Might want to use that (but for now, let's focus on not using it). For
> the server side, you need to add to SelectorHandler:
>
> Controller controller = new Controller();
> controller.addSelectorHandler(new SSLSelectorHandler());
> controller.addSelectorHandler(new TCPSelectorHandler());
>
> This is just a code snippet. Next the client.
>
>
>>
>>
>> My first guess would be to create a custom CallbackHandler to trigger
>> the password negociation upon connecting to the server like so...
>
> Right,
>
>
>
>>
>>
>> connector_handler.connect(new InetSocketAddress(host,port),
>>
>> new CallbackHandler<Context>()
>>
>> {
>>
>> public void onConnect(IOEvent<Context> e)
>>
>> {
>>
>> SelectionKey k = e.attachment().getSelectionKey();
>>
>> System.out.println("Callbackhandler: OnConnect...");
>>
>> try
>>
>> {
>>
>> connector_handler.finishConnect(k);
>>
>>
>>
>> //*Negociate password password exchange here*
>>
>> } catch(Exception ex)
>>
>> {
>>
>> System.out.println("exception in
> CallbackHandler:"+ex.getMessage());
>> }
>>
>> e.attachment().getSelectorHandler().register(k,SelectionKey.OP_READ);
>>
>> }
>>
>>
>>
>> public void onRead(IOEvent<Context> e){}
>>
>> public void onWrite(IOEvent<Context> e){}
>>
>> });
>>
>>
>>
>> It might work... but it definitely doesn't look very nice. Is there
> some sort of state machine facility to deal with this kind of situation?
> I guess there must be since Grizzly is implemented with protocols such
> as SIP.
>
> But how/where is your password (what kind of form does it take). Usually
>
> you add a certificate on the client and server side, and Grizzly will
> do the negociation for you. Is that what you have in mind?
>
>
>
>>
>>
>> There is also something called a ProtocolFilter, I guess it could be
> better suited than using the CallbackHandler...eventhough I need to
> define a behaviour OnConnection...
>
> ProtocolFilter are used on the server side usually (but can be used on
> the client side as well...SIP does use it). For your SSL stuff, you will
>
> use the SSLReadFilter, and for TCP/UDP, the ReadFilter. What you usually
>
> do is:
>
> 91 Controller sel = new Controller();
> 92 sel.setProtocolChainInstanceHandler(new
> DefaultProtocolChainInstanceHandler(){
> 93 public ProtocolChain poll() {
> 94 ProtocolChain protocolChain =
> protocolChains.poll();
> 95 if (protocolChain == null){
> 96 protocolChain = new DefaultProtocolChain();
> 97 protocolChain.addFilter(new ReadFilter());
> 98 protocolChain.addFilter(*** What you need to do
>
> with the bytes ****);
> 99 }
> 100 return protocolChain;
> 101 }
> 102 });
>
> This is the server side :-)
>
>>
>>
>> Using a ProtocolFilter, how would I go about making it stateful and
> maintaining state information between invocation of the ProtocolFilter?
> I guess it has something to do with the Context object... But how do you
> store user defined states in this object? Do I have to overload it?
>
> Context.setAttribute() or SelectorHandler.setAttribute or
> Controller.setAttribute. You can also makes your ProtocolFilter
> statefull:
>
>> ProtocolChainInstanceHandler pciHandler =
>> new ProtocolChainInstanceHandler() {
>>
>> final private ProtocolChain protocolChain = new
> DefaultProtocolChain();
>> public ProtocolChain poll() {
>> return protocolChain;
>> }
>>
>> public boolean offer(ProtocolChain instance) {
>> return true;
>> }
>> };
>> controller.setProtocolChainInstanceHandler(pciHandler);
>
> So you can store you state inside any ProtocolFilter. But
>
>
>>
>>
>>
>>
>> Well, I guess I have a lot of interrogations! :.)
>
> Keep them coming :-) Our documentation really really sucks :-)
>
>
> Are there any test cases in the Grizzly code base that could help me?
>
>
>
> Are there any tutorials, code samples, on the topic?
>
> There is a couple on grizzly.dev.java.net. A good starter is:
>
> http://weblogs.java.net/blog/jfarcand/archive/2008/02/writing_a_tcpud_1.
> html
>
> and the SIP example is here:
>
> http://weblogs.java.net/blog/jfarcand/archive/2007/11/supporting_the.htm
> l
>
> Erick also proposed a tutorial:
>
> http://www.nabble.com/Grizzly-on-the-client-side%2C-a-modest-tutorial-td
> 15643977.html
>
> But the best source of information is the mailing list. We are all happy
>
> to help so bombard us with questions :-)
>
> Thanks!
>
> -- Jeanfrancois
>
>
>
>>
>>
>>
>>
>> Thanks for your help,
>>
>>
>>
>>
>>
>> Simon
>>
>>
>>
>
> ---------------------------------------------------------------------
> 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
>