Issue #6728 - QUIC and HTTP/3
- Fixed configuration of QuicConnection. Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
parent
cd161b491e
commit
16a91b04a8
|
@ -18,7 +18,6 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import org.eclipse.jetty.http3.api.Session;
|
||||
import org.eclipse.jetty.io.ClientConnectionFactory;
|
||||
|
@ -57,7 +56,7 @@ public class HTTP3Client extends ContainerLifeCycle
|
|||
|
||||
public HTTP3Client()
|
||||
{
|
||||
this.connector = new ClientConnector(new QuicClientConnectorConfigurator());
|
||||
this.connector = new ClientConnector(new QuicClientConnectorConfigurator(this::configureConnection));
|
||||
addBean(connector);
|
||||
}
|
||||
|
||||
|
@ -134,7 +133,6 @@ public class HTTP3Client extends ContainerLifeCycle
|
|||
context.put(ClientQuicConnection.APPLICATION_PROTOCOLS, getProtocols());
|
||||
context.put(ClientConnector.CLIENT_CONNECTION_FACTORY_CONTEXT_KEY, factory);
|
||||
context.put(ClientConnector.CONNECTION_PROMISE_CONTEXT_KEY, Promise.from(ioConnection -> {}, completable::failed));
|
||||
context.put(QuicClientConnectorConfigurator.CONNECTION_CONFIGURATOR_CONTEXT_KEY, (UnaryOperator<Connection>)this::configureConnection);
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("connecting to {}", address);
|
||||
|
|
|
@ -19,6 +19,7 @@ import java.nio.channels.DatagramChannel;
|
|||
import java.nio.channels.SelectableChannel;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import org.eclipse.jetty.io.ClientConnector;
|
||||
|
@ -31,6 +32,18 @@ public class QuicClientConnectorConfigurator extends ClientConnector.Configurato
|
|||
{
|
||||
public static final String CONNECTION_CONFIGURATOR_CONTEXT_KEY = QuicClientConnectorConfigurator.class.getSimpleName() + ".connectionConfigurator";
|
||||
|
||||
private final UnaryOperator<Connection> connectionConfigurator;
|
||||
|
||||
public QuicClientConnectorConfigurator()
|
||||
{
|
||||
this(UnaryOperator.identity());
|
||||
}
|
||||
|
||||
public QuicClientConnectorConfigurator(UnaryOperator<Connection> connectionConfigurator)
|
||||
{
|
||||
this.connectionConfigurator = Objects.requireNonNull(connectionConfigurator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIntrinsicallySecure(ClientConnector clientConnector, SocketAddress address)
|
||||
{
|
||||
|
@ -40,6 +53,7 @@ public class QuicClientConnectorConfigurator extends ClientConnector.Configurato
|
|||
@Override
|
||||
public ChannelWithAddress newChannelWithAddress(ClientConnector clientConnector, SocketAddress address, Map<String, Object> context) throws IOException
|
||||
{
|
||||
context.putIfAbsent(CONNECTION_CONFIGURATOR_CONTEXT_KEY, connectionConfigurator);
|
||||
DatagramChannel channel = DatagramChannel.open();
|
||||
return new ChannelWithAddress(channel, address);
|
||||
}
|
||||
|
|
|
@ -54,9 +54,9 @@ public abstract class QuicConnection extends AbstractConnection
|
|||
private final Scheduler scheduler;
|
||||
private final ByteBufferPool byteBufferPool;
|
||||
private final Flusher flusher = new Flusher();
|
||||
private int outputBufferSize;
|
||||
private boolean useInputDirectByteBuffers;
|
||||
private boolean useOutputDirectByteBuffers;
|
||||
private int outputBufferSize = 2048;
|
||||
private boolean useInputDirectByteBuffers = true;
|
||||
private boolean useOutputDirectByteBuffers = true;
|
||||
|
||||
protected QuicConnection(Executor executor, Scheduler scheduler, ByteBufferPool byteBufferPool, EndPoint endPoint)
|
||||
{
|
||||
|
|
|
@ -40,11 +40,15 @@ import org.eclipse.jetty.util.thread.Scheduler;
|
|||
|
||||
public class QuicServerConnector extends AbstractNetworkConnector
|
||||
{
|
||||
private final ServerDatagramSelectorManager _manager;
|
||||
private final SslContextFactory.Server _sslContextFactory;
|
||||
private final QuicheConfig _quicheConfig = new QuicheConfig();
|
||||
private volatile DatagramChannel _datagramChannel;
|
||||
private volatile int _localPort = -1;
|
||||
private final ServerDatagramSelectorManager selectorManager;
|
||||
private final SslContextFactory.Server sslContextFactory;
|
||||
private final QuicheConfig quicheConfig = new QuicheConfig();
|
||||
private volatile DatagramChannel datagramChannel;
|
||||
private volatile int localPort = -1;
|
||||
private int inputBufferSize = 2048;
|
||||
private int outputBufferSize = 2048;
|
||||
private boolean useInputDirectByteBuffers = true;
|
||||
private boolean useOutputDirectByteBuffers = true;
|
||||
|
||||
public QuicServerConnector(Server server, SslContextFactory.Server sslContextFactory, ConnectionFactory... factories)
|
||||
{
|
||||
|
@ -54,22 +58,62 @@ public class QuicServerConnector extends AbstractNetworkConnector
|
|||
public QuicServerConnector(Server server, Executor executor, Scheduler scheduler, ByteBufferPool bufferPool, SslContextFactory.Server sslContextFactory, ConnectionFactory... factories)
|
||||
{
|
||||
super(server, executor, scheduler, bufferPool, 0, factories);
|
||||
_manager = new ServerDatagramSelectorManager(getExecutor(), getScheduler(), 1);
|
||||
addBean(_manager);
|
||||
_sslContextFactory = sslContextFactory;
|
||||
addBean(_sslContextFactory);
|
||||
this.selectorManager = new ServerDatagramSelectorManager(getExecutor(), getScheduler(), 1);
|
||||
addBean(this.selectorManager);
|
||||
this.sslContextFactory = sslContextFactory;
|
||||
addBean(this.sslContextFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLocalPort()
|
||||
{
|
||||
return _localPort;
|
||||
return localPort;
|
||||
}
|
||||
|
||||
public int getInputBufferSize()
|
||||
{
|
||||
return inputBufferSize;
|
||||
}
|
||||
|
||||
public void setInputBufferSize(int inputBufferSize)
|
||||
{
|
||||
this.inputBufferSize = inputBufferSize;
|
||||
}
|
||||
|
||||
public int getOutputBufferSize()
|
||||
{
|
||||
return outputBufferSize;
|
||||
}
|
||||
|
||||
public void setOutputBufferSize(int outputBufferSize)
|
||||
{
|
||||
this.outputBufferSize = outputBufferSize;
|
||||
}
|
||||
|
||||
public boolean isUseInputDirectByteBuffers()
|
||||
{
|
||||
return useInputDirectByteBuffers;
|
||||
}
|
||||
|
||||
public void setUseInputDirectByteBuffers(boolean useInputDirectByteBuffers)
|
||||
{
|
||||
this.useInputDirectByteBuffers = useInputDirectByteBuffers;
|
||||
}
|
||||
|
||||
public boolean isUseOutputDirectByteBuffers()
|
||||
{
|
||||
return useOutputDirectByteBuffers;
|
||||
}
|
||||
|
||||
public void setUseOutputDirectByteBuffers(boolean useOutputDirectByteBuffers)
|
||||
{
|
||||
this.useOutputDirectByteBuffers = useOutputDirectByteBuffers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen()
|
||||
{
|
||||
DatagramChannel channel = _datagramChannel;
|
||||
DatagramChannel channel = datagramChannel;
|
||||
return channel != null && channel.isOpen();
|
||||
}
|
||||
|
||||
|
@ -77,16 +121,16 @@ public class QuicServerConnector extends AbstractNetworkConnector
|
|||
protected void doStart() throws Exception
|
||||
{
|
||||
for (EventListener l : getBeans(SelectorManager.SelectorManagerListener.class))
|
||||
_manager.addEventListener(l);
|
||||
selectorManager.addEventListener(l);
|
||||
super.doStart();
|
||||
_manager.accept(_datagramChannel);
|
||||
selectorManager.accept(datagramChannel);
|
||||
|
||||
String alias = _sslContextFactory.getCertAlias();
|
||||
char[] keyStorePassword = _sslContextFactory.getKeyStorePassword().toCharArray();
|
||||
String keyManagerPassword = _sslContextFactory.getKeyManagerPassword();
|
||||
String alias = sslContextFactory.getCertAlias();
|
||||
char[] keyStorePassword = sslContextFactory.getKeyStorePassword().toCharArray();
|
||||
String keyManagerPassword = sslContextFactory.getKeyManagerPassword();
|
||||
SSLKeyPair keyPair = new SSLKeyPair(
|
||||
_sslContextFactory.getKeyStoreResource().getFile(),
|
||||
_sslContextFactory.getKeyStoreType(),
|
||||
sslContextFactory.getKeyStoreResource().getFile(),
|
||||
sslContextFactory.getKeyStoreType(),
|
||||
keyStorePassword,
|
||||
alias == null ? "mykey" : alias,
|
||||
keyManagerPassword == null ? keyStorePassword : keyManagerPassword.toCharArray()
|
||||
|
@ -94,35 +138,35 @@ public class QuicServerConnector extends AbstractNetworkConnector
|
|||
File[] pemFiles = keyPair.export(new File(System.getProperty("java.io.tmpdir")));
|
||||
|
||||
// TODO: make the QuicheConfig configurable.
|
||||
_quicheConfig.setPrivKeyPemPath(pemFiles[0].getPath());
|
||||
_quicheConfig.setCertChainPemPath(pemFiles[1].getPath());
|
||||
_quicheConfig.setVerifyPeer(false);
|
||||
quicheConfig.setPrivKeyPemPath(pemFiles[0].getPath());
|
||||
quicheConfig.setCertChainPemPath(pemFiles[1].getPath());
|
||||
quicheConfig.setVerifyPeer(false);
|
||||
// Idle timeouts must not be managed by Quiche.
|
||||
_quicheConfig.setMaxIdleTimeout(0L);
|
||||
_quicheConfig.setInitialMaxData(10000000L);
|
||||
_quicheConfig.setInitialMaxStreamDataBidiLocal(10000000L);
|
||||
_quicheConfig.setInitialMaxStreamDataBidiRemote(10000000L);
|
||||
_quicheConfig.setInitialMaxStreamDataUni(10000000L);
|
||||
_quicheConfig.setInitialMaxStreamsUni(100L);
|
||||
_quicheConfig.setInitialMaxStreamsBidi(100L);
|
||||
_quicheConfig.setCongestionControl(QuicheConfig.CongestionControl.RENO);
|
||||
quicheConfig.setMaxIdleTimeout(0L);
|
||||
quicheConfig.setInitialMaxData(10000000L);
|
||||
quicheConfig.setInitialMaxStreamDataBidiLocal(10000000L);
|
||||
quicheConfig.setInitialMaxStreamDataBidiRemote(10000000L);
|
||||
quicheConfig.setInitialMaxStreamDataUni(10000000L);
|
||||
quicheConfig.setInitialMaxStreamsUni(100L);
|
||||
quicheConfig.setInitialMaxStreamsBidi(100L);
|
||||
quicheConfig.setCongestionControl(QuicheConfig.CongestionControl.RENO);
|
||||
List<String> protocols = getProtocols();
|
||||
// This is only needed for Quiche example clients.
|
||||
protocols.add(0, "http/0.9");
|
||||
_quicheConfig.setApplicationProtos(protocols.toArray(String[]::new));
|
||||
quicheConfig.setApplicationProtos(protocols.toArray(String[]::new));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() throws IOException
|
||||
{
|
||||
if (_datagramChannel == null)
|
||||
if (datagramChannel == null)
|
||||
{
|
||||
_datagramChannel = openDatagramChannel();
|
||||
_datagramChannel.configureBlocking(false);
|
||||
_localPort = _datagramChannel.socket().getLocalPort();
|
||||
if (_localPort <= 0)
|
||||
datagramChannel = openDatagramChannel();
|
||||
datagramChannel.configureBlocking(false);
|
||||
localPort = datagramChannel.socket().getLocalPort();
|
||||
if (localPort <= 0)
|
||||
throw new IOException("DatagramChannel not bound");
|
||||
addBean(_datagramChannel);
|
||||
addBean(datagramChannel);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,7 +190,7 @@ public class QuicServerConnector extends AbstractNetworkConnector
|
|||
public void setIdleTimeout(long idleTimeout)
|
||||
{
|
||||
super.setIdleTimeout(idleTimeout);
|
||||
_manager.setIdleTimeout(idleTimeout);
|
||||
selectorManager.setIdleTimeout(idleTimeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -154,27 +198,27 @@ public class QuicServerConnector extends AbstractNetworkConnector
|
|||
{
|
||||
super.doStop();
|
||||
for (EventListener l : getBeans(EventListener.class))
|
||||
_manager.removeEventListener(l);
|
||||
selectorManager.removeEventListener(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
super.close();
|
||||
DatagramChannel datagramChannel = _datagramChannel;
|
||||
_datagramChannel = null;
|
||||
DatagramChannel datagramChannel = this.datagramChannel;
|
||||
this.datagramChannel = null;
|
||||
if (datagramChannel != null)
|
||||
{
|
||||
removeBean(datagramChannel);
|
||||
IO.close(datagramChannel);
|
||||
}
|
||||
_localPort = -2;
|
||||
localPort = -2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getTransport()
|
||||
{
|
||||
return _datagramChannel;
|
||||
return datagramChannel;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -201,7 +245,12 @@ public class QuicServerConnector extends AbstractNetworkConnector
|
|||
@Override
|
||||
public Connection newConnection(SelectableChannel channel, EndPoint endpoint, Object attachment)
|
||||
{
|
||||
return new ServerQuicConnection(QuicServerConnector.this, endpoint, _quicheConfig);
|
||||
ServerQuicConnection connection = new ServerQuicConnection(QuicServerConnector.this, endpoint, quicheConfig);
|
||||
connection.setInputBufferSize(getInputBufferSize());
|
||||
connection.setOutputBufferSize(getOutputBufferSize());
|
||||
connection.setUseInputDirectByteBuffers(isUseInputDirectByteBuffers());
|
||||
connection.setUseOutputDirectByteBuffers(isUseOutputDirectByteBuffers());
|
||||
return connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in New Issue