users@grizzly.java.net

Re: Getting a handle to the initial connection + other questions

From: Jeanfrancois Arcand <Jeanfrancois.Arcand_at_Sun.COM>
Date: Mon, 26 Nov 2007 20:32:38 -0500

Hi,

Alan Williamson wrote:
> Good day to you all,
>
> I am kinda new to Grizzly and on the face of it, it looks very
> interesting and definitely something that may help us. We currently
> have our own HTTP frontend server performing load balancing infront of a
> farm of JETTY servers.
>
>
> ___ Question #1 ___
>
> One of the things we need to do, is to determine whether or not an IP
> address is allowed to connect. We basically want to nuke this
> connection as soon as the "accept()" method has been called and the
> Socket created.
>
> This stops a lot of spammers from consuming resources they shouldn't be
> anywhere near. Our current frontend server sandboxes the IP for a small
> period of time and we've noticed that this has reduced a load.
>
> So in terms of the Grizzly how could one get a handle to the incoming
> connection as soon as possible and determine whether or not they are
> permitted to continue?

The easiest way is to write a com.sun.grizzly.ProtocolFilter (or extends
the com.sun.grizzly.filter.ReadFilter). The way connection are handled
is the SelectorHandler execute the accept()/OP_ACCEPT, and then delegate
the read operations to a ProtocolChain (a chain is a collection of
filters). As an example, let's say you extends the ReadFilter (let's
call it MyReadFilter) with:

> public boolean execute(Context ctx) throws IOException {
> SelectionKey key = ctx.getSelectionKey();
> SocketChannel channel = (SocketChannel)key.channel();
> if (allow(channel.socket().getRemoteSocketAddress())){
> return super.execute(ctx);
> } else {
> ctx.setKeyRegistrationState(
> Context.KeyRegistrationState.CANCEL);
> // Do not invoke the next Filter
> return false;
>
> }

Just implement the allow() method to return true/false.

>
> One the adapter code has triggered the "service()" method, then the
> header is already in. It's a bit late at that point. Out of interest,
> what is the cleanest way to nuke a connection at this stage

Agree this is way to late in the process. So what you need to do is to
inject your ProtocolFilter like the following:

When you embed Grizzly, create the com.sun.grizzly.http.SelectorThread
using the following (assuming t

SelectorThread mySelectorThread = new SelectorThread(){

     /**
      * Adds and configures <code>ProtocolChain</code>'s filters
      * @param <code>ProtocolChain</code> to configure
      */
     protected void configureFilters(ProtocolChain protocolChain) {
         if (portUnificationFilter != null) {
             protocolChain.addFilter(portUnificationFilter);
         } else {
// =========== Inject your Filter here =======================//
             ReadFilter readFilter = new MyReadFilter();
             readFilter.setContinuousExecution(true);
             protocolChain.addFilter(readFilter);
         }

         if (rcmSupport){
             protocolChain.addFilter(createRaFilter());
         }

         protocolChain.addFilter(createHttpParserFilter());
     }
};

This way your filter will be the first invoked without all the overhead
of the http protocol being executed.


>
> ___ Question #2 ___
>
> Running a large blog site you see a whole manner of nasty clients trying
> to really mess with you. One of things we see a lot of, is clients that
> will attempt a subtle DoS attack. They basically drip feed bytes to the
> server in such a speed as not to trip up any of the SO_TIMEOUT alarms.
> So one character a second for example, could tie up a connection for
> minutes. It doesn't take a lot of effort to really consume a server
> connections waiting.
>
> We've taken the approach, that if the complete HTTP header is not
> received within X seconds (5 we have found to be acceptable) then we
> deny this client from going on any further.
>
> Again, how would one manage this with Grizzly?

This is simple. Just set (this is a static method):

com.sun.grizzly.util.ByteBufferInputStream.setDefaultReadTimeout(//Timeout).
By default it is set to 30 seconds. This method tell Grizzly to wait
//timeout// seconds before considering it is a DoS when reading bytes.
This apply to both headers and body.

>
>
>
> Thanks again, and i look forward to hearing back and getting my sleeves
> rolled up with this one.

Thanks!

-- Jeanfrancois


>
> alan
>