Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [jetty-dev] Jetty + SO_REUSEPORT

Hi Simone,

Thanks for the reply.  I've got some experimental code that seems to work
(tested on Mac OS X Yosemite & Oracle Java 8).  It simply extends the system
default SelectorProvider and overrides the inheritedChannel() method to
create and return a socket to Jetty.  Internally Jetty seems to check for
inheritedChannel() and defer to it which is great

Advantages:
1. No changes to Jetty required :-)

Disadvantages: (not sure where to start...)
1. Uses reflection. Of a JDK method. Of a JDK method which is marked
private. Developers get fired for a lot less ;-)
2. Assumes SO_REUSEPORT constant and doesn't really check against the native
socket option whether the constant is right.
3. Obviously replacing inheritedChannel means if you use my approach then
you can't use inheritedChannels.


Anywhere, below is the code - if anyone wants it - to play, experiment, etc. 
On its own its not that useful but combined with some other abuses of code
the results can be quite fun to say the least.  More on SO_REUSEPORT here:
https://domsch.com/linux/lpc2010/Scaling_techniques_for_servers_with_high_connection%20rates.pdf
and 
http://www.ebaytechblog.com/2013/11/21/zero-downtime-instant-deployment-and-rollback/
(obviously ignore the bit about it not being available in Java :D).

To use it set the system property to change the SelectorProvider before
firing up a Jetty server connector:
System.setProperty("java.nio.channels.spi.SelectorProvider",
"com.badjava.MySelectorProvider");


// Package & class name changed.

package com.badjava.nio;

import sun.nio.ch.DefaultSelectorProvider;
import sun.nio.ch.Net;

import java.io.FileDescriptor;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.ProtocolFamily;
import java.net.ServerSocket;
import java.nio.channels.*;
import java.nio.channels.spi.AbstractSelector;
import java.nio.channels.spi.SelectorProvider;

public class MySelectorProvider extends SelectorProvider {

    private final static int SO_REUSEPORT = 0x0200;

    public static String getHost() {
        return "127.0.0.1";
    }

    public static int getPort() {
        return 8080;
    }

    private final SelectorProvider provider;
    private volatile SocketChannel channel = null;

    public MySelectorProvider() {
        provider = DefaultSelectorProvider.create();
    }

    public DatagramChannel openDatagramChannel() throws IOException {
        return provider.openDatagramChannel();
    }

    public DatagramChannel openDatagramChannel(ProtocolFamily family)
        throws IOException
    {
        return provider.openDatagramChannel(family);
    }

    public Pipe openPipe() throws IOException {
        return provider.openPipe();
    }

    public AbstractSelector openSelector() throws IOException {
        return provider.openSelector();
    }

    public ServerSocketChannel openServerSocketChannel()
        throws IOException
    {
        return provider.openServerSocketChannel();
    }

    public SocketChannel openSocketChannel() throws IOException {
        return provider.openSocketChannel();
    }

    @Override
    public Channel inheritedChannel() throws IOException {
        ServerSocketChannel serverChannel = ServerSocketChannel.open();

        InetSocketAddress bindAddress = getHost() == null ? new
InetSocketAddress(getPort()) : new InetSocketAddress(getHost(), getPort());
        ServerSocket socket = serverChannel.socket();

        try {
            Field fieldFd = serverChannel.getClass().getDeclaredField("fd");
//NoSuchFieldException
            fieldFd.setAccessible(true);
            FileDescriptor fd = (FileDescriptor) fieldFd.get(serverChannel);
//IllegalAccessException


            Method methodSetIntOption0 =
Net.class.getDeclaredMethod("setIntOption0", FileDescriptor.class,
Boolean.TYPE, Integer.TYPE, Integer.TYPE, Integer.TYPE);
            methodSetIntOption0.setAccessible(true);
            methodSetIntOption0.invoke(null, fd, false, '\uffff',
SO_REUSEPORT, 1 );

        }
        catch (Exception e) {

            System.out.println(e.toString());
        }


        socket.bind(bindAddress, 0);
        socket.setReuseAddress(true);
        return serverChannel;
    }
}




--
View this message in context: http://jetty.4.x6.nabble.com/Jetty-SO-REUSEPORT-tp4963137p4963189.html
Sent from the Jetty Dev mailing list archive at Nabble.com.


Back to the top