You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@mina.apache.org by Alexander <mi...@gmail.com> on 2008/08/25 11:26:25 UTC

General architectural overview

Hi all,

I've spent some time trying to familiarize myself with MINA, reading
tutorials, PowerPoint presentations, source code and examples.

What I lack is a quick architectural overview and a summary of the
type of guarantees MINA gives you as a developer. Questions which I
found hard to get answers to are:

*What are the semantics of the messageReceived method (without
filters)?  Will you receive one message per TCP package? Will the same
ByteBuffer always be reused for the whole message? How are the
positions you set interpreted, and will they be reset? This has been
hinted on this list and in the tutorial for ProtocolDecoder, but more
thorough documentation would be handy.
 Basically I'm worried about not getting the header in one buffer
(HTTP header), so it would be fragmented between two ByteBuffers. Is
this possible? Is there a size limit or so? What if you get a huge
header?

*Why is the cross-request-buffering techniques used in
CumulativeProtocolDecoder and DemuxingProtocolCodecFactory not using
the same interface? Are they different? I can see thet cumulative adds
all messages to an internal buffer, in demuxing I can't really find
any such code, but I might be overlooking something.

*How are you supposed to handle mixed high/low level protocols? For
instance, if you write a HTTP proxy based on header contents, you need
to parse the header into an object at first (maybe using
MessageDecoder)? When the subsequent packages arrive, you will want to
stream them directly. This means that the lower-level filters (the
messageDecoder perhaps), needs to know the result of the higher-level
parsing. Right now I'm doing this by sharing session variables between
layers (low-level checks if higher layer has set a flag in session).
Is this the recommended way?

Finally, thanks a lot for providing nio with a usable interface and
adding all these nice features!

Best Regards

Alexander T

Re: General architectural overview

Posted by Alexander <mi...@gmail.com>.
Hi Emmanuel,

>
> It's really depending on the protocol you are handling :
> - If you have fixed size PDUs, then you can build a filter which gather all
> the incoming packets until the PDU is complete.
> - If your PDU contains a size in the first few bytes (let's say that the 4
> first bytes are describing the PDU size), when you have received those 4
> first bytes (which may perfectly arrive in 4 packets), you fall back in the
> same scenario as the first one.
> - If your protocol does not gives you a size for a PDU, but you have a
> terminaison token like CR/LF or a keyword, then you have to read the bytes
> until you get this terminal token.
>
> In any case, as you can see, it's impossible for MINA to provide a generic
> solution to this kind of problem, as it's protocol dependant. However, for
> commonly used protocols, what would be good is to offer implementations.
>
> We discussed a while back about writing something like Ethereal (now
> WireShark) on top of MINA (a good name could be MINAreal ;) where we
> implement a lot of common protocol, that could help users to analyse the way
> MINA can be used to implement a protocol.
>
> Hope it helps.

It helps, it is a bit confusing to come into MINA when there's both
chained-based filters and inheritance-based decoders, which seem very
similar yet different :). Regarding WireShark, that is one idea, but
IMHO it would be better to have some sort of traffic injection
robustness tests. You would specify your data to send, and it got
injected into MINA in various ways, varying package sizes, offsets,
simulating resends etc. This way you could test that your handler can
cope with the corner cases. Of course not everything can be tested,
but if you design the robustness tests to be evil it should be enough
:)

Re: General architectural overview

Posted by Emmanuel Lecharny <el...@gmail.com>.
Alexander wrote:
> Hi Tuure, Thanks for you reply. Answers inline.
>
> 2008/8/25 Tuure Laurinolli <tu...@indagon.com>:
>   
>> Alexander wrote:
>>
>>     
>>> *What are the semantics of the messageReceived method (without
>>> filters)?  Will you receive one message per TCP package? Will the same
>>> ByteBuffer always be reused for the whole message?
>>>       
>> The message handed to messageReceived consists of whatever the network stack
>> of your operating system was fit. It has no necessary relation to IP
>> packets. There are certainly no guarantees that each IP-packetful of the TCP
>> stream will be received as a separate ByteBuffer.
>>
>> In fact, the operating system is free to give you one byte at a time if it
>> wants to. Or give you as much data as fits into your read buffer. Or
>> alternate between these modes. A sane operating system would likely give you
>> whatever is in its buffers, provided it fits into the buffer you gave the
>> syscall. However, the only guarantees you can have of this are
>> implementation-specific, and the onyl control you have is the read buffer
>> size.
>>     
>
> Ok. This makes sense. I just wanted to know if MINA provided anything
> above this. Now it is clear that the framework doesn't.
>   
It's really depending on the protocol you are handling :
- If you have fixed size PDUs, then you can build a filter which gather 
all the incoming packets until the PDU is complete.
- If your PDU contains a size in the first few bytes (let's say that the 
4 first bytes are describing the PDU size), when you have received those 
4 first bytes (which may perfectly arrive in 4 packets), you fall back 
in the same scenario as the first one.
- If your protocol does not gives you a size for a PDU, but you have a 
terminaison token like CR/LF or a keyword, then you have to read the 
bytes until you get this terminal token.

In any case, as you can see, it's impossible for MINA to provide a 
generic solution to this kind of problem, as it's protocol dependant. 
However, for commonly used protocols, what would be good is to offer 
implementations.

We discussed a while back about writing something like Ethereal (now 
WireShark) on top of MINA (a good name could be MINAreal ;) where we 
implement a lot of common protocol, that could help users to analyse the 
way MINA can be used to implement a protocol.

Hope it helps.
>   
>>> How are the
>>> positions you set interpreted, and will they be reset? This has been
>>> hinted on this list and in the tutorial for ProtocolDecoder, but more
>>> thorough documentation would be handy.
>>>       
>> My impression is that each message (ie. ByteBuffer) delivered to
>> IoHandler/IoFilter via messageReceived is independent - whatever the
>> handler/filter does with them is its business. I.e. MINA shouldn't touch a
>> buffer it has given you a reference to.
>>     
>
> Sounds good.
>
>   
>>>  Basically I'm worried about not getting the header in one buffer
>>> (HTTP header), so it would be fragmented between two ByteBuffers. Is
>>> this possible? Is there a size limit or so? What if you get a huge
>>> header?
>>>       
>> Certainly it can be fragmented and delivered over multiple ByteBuffers.
>>     
>
> Ok, so this means that I need to use some type of local buffering
> until the header is present, which I could use
> CumulativeProtocolDecoder for, right? I need this right on the lowest
> level, to figure out if there is a CRLFCRLF present in the stream
> or not, before I can start decoding. I also wondered if
> DemuxingProtocolDecoder does this type of buffering, since it seems to
> wait until it can find a decoder. But I'm not sure if it selects a
> decoder per-session or per-package (message), and if there is any
> buffering involved.
>
>   
>>> *How are you supposed to handle mixed high/low level protocols? For
>>> instance, if you write a HTTP proxy based on header contents, you need
>>> to parse the header into an object at first (maybe using
>>> MessageDecoder)? When the subsequent packages arrive, you will want to
>>> stream them directly.
>>>       
>> I'm not sure what you mean by high/low level protocols here. To me it seems
>> that you only mentioned HTTP. What is the higher/lower level here?
>>     
>
> Well, since I'm writing a proxy, there is the "byte stream" level, and
> then there is a "http header" interpreted level. Basically, what I
> want to do is to buffer the stream until I hit CRLFCRLF, then decode
> the header, read the header properties and then proxy if certain
> headers are set. If so, I would put a flag in the session, and the
> next time my protocol decoder gets a message, it can see that the
> header interpreter put a flag in the session to stream the rest of the
> contents. For all subsequent packages, they should simply be written
> to the proxy connection (as set up by the header interpreter). Is that
> the recommended way of achieving "dynamic proxying"?
>
> Regards,
>
> Alexander
>
>   


-- 
--
cordialement, regards,
Emmanuel Lécharny
www.iktek.com
directory.apache.org



Re: General architectural overview

Posted by Alexander <mi...@gmail.com>.
Hi Tuure, Thanks for you reply. Answers inline.

2008/8/25 Tuure Laurinolli <tu...@indagon.com>:
> Alexander wrote:
>
>> *What are the semantics of the messageReceived method (without
>> filters)?  Will you receive one message per TCP package? Will the same
>> ByteBuffer always be reused for the whole message?
>
> The message handed to messageReceived consists of whatever the network stack
> of your operating system was fit. It has no necessary relation to IP
> packets. There are certainly no guarantees that each IP-packetful of the TCP
> stream will be received as a separate ByteBuffer.
>
> In fact, the operating system is free to give you one byte at a time if it
> wants to. Or give you as much data as fits into your read buffer. Or
> alternate between these modes. A sane operating system would likely give you
> whatever is in its buffers, provided it fits into the buffer you gave the
> syscall. However, the only guarantees you can have of this are
> implementation-specific, and the onyl control you have is the read buffer
> size.

Ok. This makes sense. I just wanted to know if MINA provided anything
above this. Now it is clear that the framework doesn't.

>
>> How are the
>> positions you set interpreted, and will they be reset? This has been
>> hinted on this list and in the tutorial for ProtocolDecoder, but more
>> thorough documentation would be handy.
>
> My impression is that each message (ie. ByteBuffer) delivered to
> IoHandler/IoFilter via messageReceived is independent - whatever the
> handler/filter does with them is its business. I.e. MINA shouldn't touch a
> buffer it has given you a reference to.

Sounds good.

>
>>  Basically I'm worried about not getting the header in one buffer
>> (HTTP header), so it would be fragmented between two ByteBuffers. Is
>> this possible? Is there a size limit or so? What if you get a huge
>> header?
>
> Certainly it can be fragmented and delivered over multiple ByteBuffers.

Ok, so this means that I need to use some type of local buffering
until the header is present, which I could use
CumulativeProtocolDecoder for, right? I need this right on the lowest
level, to figure out if there is a CRLFCRLF present in the stream
or not, before I can start decoding. I also wondered if
DemuxingProtocolDecoder does this type of buffering, since it seems to
wait until it can find a decoder. But I'm not sure if it selects a
decoder per-session or per-package (message), and if there is any
buffering involved.

>
>> *How are you supposed to handle mixed high/low level protocols? For
>> instance, if you write a HTTP proxy based on header contents, you need
>> to parse the header into an object at first (maybe using
>> MessageDecoder)? When the subsequent packages arrive, you will want to
>> stream them directly.
>
> I'm not sure what you mean by high/low level protocols here. To me it seems
> that you only mentioned HTTP. What is the higher/lower level here?

Well, since I'm writing a proxy, there is the "byte stream" level, and
then there is a "http header" interpreted level. Basically, what I
want to do is to buffer the stream until I hit CRLFCRLF, then decode
the header, read the header properties and then proxy if certain
headers are set. If so, I would put a flag in the session, and the
next time my protocol decoder gets a message, it can see that the
header interpreter put a flag in the session to stream the rest of the
contents. For all subsequent packages, they should simply be written
to the proxy connection (as set up by the header interpreter). Is that
the recommended way of achieving "dynamic proxying"?

Regards,

Alexander

Re: General architectural overview

Posted by Tuure Laurinolli <tu...@indagon.com>.
Alexander wrote:

> *What are the semantics of the messageReceived method (without
> filters)?  Will you receive one message per TCP package? Will the same
> ByteBuffer always be reused for the whole message?

The message handed to messageReceived consists of whatever the network 
stack of your operating system was fit. It has no necessary relation to 
IP packets. There are certainly no guarantees that each IP-packetful of 
the TCP stream will be received as a separate ByteBuffer.

In fact, the operating system is free to give you one byte at a time if 
it wants to. Or give you as much data as fits into your read buffer. Or 
alternate between these modes. A sane operating system would likely give 
you whatever is in its buffers, provided it fits into the buffer you 
gave the syscall. However, the only guarantees you can have of this are 
implementation-specific, and the onyl control you have is the read 
buffer size.

> How are the
> positions you set interpreted, and will they be reset? This has been
> hinted on this list and in the tutorial for ProtocolDecoder, but more
> thorough documentation would be handy.

My impression is that each message (ie. ByteBuffer) delivered to 
IoHandler/IoFilter via messageReceived is independent - whatever the 
handler/filter does with them is its business. I.e. MINA shouldn't touch 
a buffer it has given you a reference to.

>  Basically I'm worried about not getting the header in one buffer
> (HTTP header), so it would be fragmented between two ByteBuffers. Is
> this possible? Is there a size limit or so? What if you get a huge
> header?

Certainly it can be fragmented and delivered over multiple ByteBuffers.

> *How are you supposed to handle mixed high/low level protocols? For
> instance, if you write a HTTP proxy based on header contents, you need
> to parse the header into an object at first (maybe using
> MessageDecoder)? When the subsequent packages arrive, you will want to
> stream them directly. 

I'm not sure what you mean by high/low level protocols here. To me it 
seems that you only mentioned HTTP. What is the higher/lower level here?