io.netty.incubator.codec.quic.QuicCodecBuilder Maven / Gradle / Ivy
/*
* Copyright 2020 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.incubator.codec.quic;
import io.netty.channel.ChannelHandler;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import static io.netty.util.internal.ObjectUtil.checkInRange;
import static io.netty.util.internal.ObjectUtil.checkPositive;
import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
/**
* Abstract base class for {@code QUIC} codec builders.
*
* @param the type of the {@link QuicCodecBuilder}.
*/
public abstract class QuicCodecBuilder> {
private final boolean server;
private Boolean grease;
private Long maxIdleTimeout;
private Long maxRecvUdpPayloadSize;
private Long maxSendUdpPayloadSize;
private Long initialMaxData;
private Long initialMaxStreamDataBidiLocal;
private Long initialMaxStreamDataBidiRemote;
private Long initialMaxStreamDataUni;
private Long initialMaxStreamsBidi;
private Long initialMaxStreamsUni;
private Long ackDelayExponent;
private Long maxAckDelay;
private Boolean disableActiveMigration;
private Boolean enableHystart;
private QuicCongestionControlAlgorithm congestionControlAlgorithm;
private int localConnIdLength;
private Function sslEngineProvider;
private FlushStrategy flushStrategy = FlushStrategy.DEFAULT;
private Integer recvQueueLen;
private Integer sendQueueLen;
private Long activeConnectionIdLimit;
private byte[] statelessResetToken;
private Executor sslTaskExecutor;
// package-private for testing only
int version;
QuicCodecBuilder(boolean server) {
Quic.ensureAvailability();
this.version = Quiche.QUICHE_PROTOCOL_VERSION;
this.localConnIdLength = Quiche.QUICHE_MAX_CONN_ID_LEN;
this.server = server;
}
QuicCodecBuilder(QuicCodecBuilder builder) {
Quic.ensureAvailability();
this.server = builder.server;
this.grease = builder.grease;
this.maxIdleTimeout = builder.maxIdleTimeout;
this.maxRecvUdpPayloadSize = builder.maxRecvUdpPayloadSize;
this.maxSendUdpPayloadSize = builder.maxSendUdpPayloadSize;
this.initialMaxData = builder.initialMaxData;
this.initialMaxStreamDataBidiLocal = builder.initialMaxStreamDataBidiLocal;
this.initialMaxStreamDataBidiRemote = builder.initialMaxStreamDataBidiRemote;
this.initialMaxStreamDataUni = builder.initialMaxStreamDataUni;
this.initialMaxStreamsBidi = builder.initialMaxStreamsBidi;
this.initialMaxStreamsUni = builder.initialMaxStreamsUni;
this.ackDelayExponent = builder.ackDelayExponent;
this.maxAckDelay = builder.maxAckDelay;
this.disableActiveMigration = builder.disableActiveMigration;
this.enableHystart = builder.enableHystart;
this.congestionControlAlgorithm = builder.congestionControlAlgorithm;
this.localConnIdLength = builder.localConnIdLength;
this.sslEngineProvider = builder.sslEngineProvider;
this.flushStrategy = builder.flushStrategy;
this.recvQueueLen = builder.recvQueueLen;
this.sendQueueLen = builder.sendQueueLen;
this.activeConnectionIdLimit = builder.activeConnectionIdLimit;
this.statelessResetToken = builder.statelessResetToken;
this.sslTaskExecutor = builder.sslTaskExecutor;
this.version = builder.version;
}
/**
* Returns itself.
*
* @return itself.
*/
@SuppressWarnings("unchecked")
protected final B self() {
return (B) this;
}
/**
* Sets the {@link FlushStrategy} that will be used to detect when an automatic flush
* should happen.
*
* @param flushStrategy the strategy to use.
* @return the instance itself.
*/
public final B flushStrategy(FlushStrategy flushStrategy) {
this.flushStrategy = Objects.requireNonNull(flushStrategy, "flushStrategy");
return self();
}
/**
* Sets the congestion control algorithm to use.
*
* The default is {@link QuicCongestionControlAlgorithm#CUBIC}.
*
* @param congestionControlAlgorithm the {@link QuicCongestionControlAlgorithm} to use.
* @return the instance itself.
*/
public final B congestionControlAlgorithm(QuicCongestionControlAlgorithm congestionControlAlgorithm) {
this.congestionControlAlgorithm = congestionControlAlgorithm;
return self();
}
/**
* Set if greasing should be enabled
* or not.
*
* The default value is {@code true}.
*
* @param enable {@code true} if enabled, {@code false} otherwise.
* @return the instance itself.
*/
public final B grease(boolean enable) {
grease = enable;
return self();
}
/**
* See
* set_max_idle_timeout.
*
* The default value is infinite, that is, no timeout is used.
*
* @param amount the maximum idle timeout.
* @param unit the {@link TimeUnit}.
* @return the instance itself.
*/
public final B maxIdleTimeout(long amount, TimeUnit unit) {
this.maxIdleTimeout = unit.toMillis(checkPositiveOrZero(amount, "amount"));
return self();
}
/**
* See
* set_max_send_udp_payload_size.
*
* The default and minimum value is 1200.
*
* @param size the maximum payload size that is advertised to the remote peer.
* @return the instance itself.
*/
public final B maxSendUdpPayloadSize(long size) {
this.maxSendUdpPayloadSize = checkPositiveOrZero(size, "value");
return self();
}
/**
* See
* set_max_recv_udp_payload_size.
*
* The default value is 65527.
*
* @param size the maximum payload size that is advertised to the remote peer.
* @return the instance itself.
*/
public final B maxRecvUdpPayloadSize(long size) {
this.maxRecvUdpPayloadSize = checkPositiveOrZero(size, "value");
return self();
}
/**
* See
* set_initial_max_data.
*
* The default value is 0.
*
* @param value the initial maximum data limit.
* @return the instance itself.
*/
public final B initialMaxData(long value) {
this.initialMaxData = checkPositiveOrZero(value, "value");
return self();
}
/**
* See
*
* set_initial_max_stream_data_bidi_local.
*
* The default value is 0.
*
* @param value the initial maximum data limit for local bidirectional streams.
* @return the instance itself.
*/
public final B initialMaxStreamDataBidirectionalLocal(long value) {
this.initialMaxStreamDataBidiLocal = checkPositiveOrZero(value, "value");
return self();
}
/**
* See
*
* set_initial_max_stream_data_bidi_remote.
*
* The default value is 0.
*
* @param value the initial maximum data limit for remote bidirectional streams.
* @return the instance itself.
*/
public final B initialMaxStreamDataBidirectionalRemote(long value) {
this.initialMaxStreamDataBidiRemote = checkPositiveOrZero(value, "value");
return self();
}
/**
* See
*
* set_initial_max_stream_data_uni.
*
* The default value is 0.
*
* @param value the initial maximum data limit for unidirectional streams.
* @return the instance itself.
*/
public final B initialMaxStreamDataUnidirectional(long value) {
this.initialMaxStreamDataUni = checkPositiveOrZero(value, "value");
return self();
}
/**
* See
*
* set_initial_max_streams_bidi.
*
* The default value is 0.
*
* @param value the initial maximum stream limit for bidirectional streams.
* @return the instance itself.
*/
public final B initialMaxStreamsBidirectional(long value) {
this.initialMaxStreamsBidi = checkPositiveOrZero(value, "value");
return self();
}
/**
* See
*
* set_initial_max_streams_uni.
*
* The default value is 0.
*
* @param value the initial maximum stream limit for unidirectional streams.
* @return the instance itself.
*/
public final B initialMaxStreamsUnidirectional(long value) {
this.initialMaxStreamsUni = checkPositiveOrZero(value, "value");
return self();
}
/**
* See
*
* set_ack_delay_exponent.
*
* The default value is 3.
*
* @param value the delay exponent used for ACKs.
* @return the instance itself.
*/
public final B ackDelayExponent(long value) {
this.ackDelayExponent = checkPositiveOrZero(value, "value");
return self();
}
/**
* See
*
* set_max_ack_delay.
*
* The default value is 25 milliseconds.
*
* @param amount the max ack delay.
* @param unit the {@link TimeUnit}.
* @return the instance itself.
*/
public final B maxAckDelay(long amount, TimeUnit unit) {
this.maxAckDelay = unit.toMillis(checkPositiveOrZero(amount, "amount"));
return self();
}
/**
* See
*
* set_disable_active_migration.
*
* The default value is {@code true}.
*
* @param enable {@code true} if migration should be enabled, {@code false} otherwise.
* @return the instance itself.
*/
public final B activeMigration(boolean enable) {
this.disableActiveMigration = !enable;
return self();
}
/**
* See
*
* enable_hystart.
*
* The default value is {@code true}.
*
* @param enable {@code true} if Hystart should be enabled.
* @return the instance itself.
*/
public final B hystart(boolean enable) {
this.enableHystart = enable;
return self();
}
/**
* Sets the local connection id length that is used.
*
* The default is 20, which is also the maximum that is supported.
*
* @param value the length of local generated connections ids.
* @return the instance itself.
*/
public final B localConnectionIdLength(int value) {
this.localConnIdLength = checkInRange(value, 0, Quiche.QUICHE_MAX_CONN_ID_LEN, "value");
return self();
}
/**
* Allows to configure the {@code QUIC version} that should be used.
*
* The default value is the latest supported version by the underlying library.
*
* @param version the {@code QUIC version} to use.
* @return the instance itself.
*/
public final B version(int version) {
this.version = version;
return self();
}
/**
* If configured this will enable
* Datagram support.
* @param recvQueueLen the RECV queue length.
* @param sendQueueLen the SEND queue length.
* @return the instance itself.
*/
public final B datagram(int recvQueueLen, int sendQueueLen) {
checkPositive(recvQueueLen, "recvQueueLen");
checkPositive(sendQueueLen, "sendQueueLen");
this.recvQueueLen = recvQueueLen;
this.sendQueueLen = sendQueueLen;
return self();
}
/**
* The {@link QuicSslContext} that will be used to create {@link QuicSslEngine}s for {@link QuicChannel}s.
*
* If you need a more flexible way to provide {@link QuicSslEngine}s use {@link #sslEngineProvider(Function)}.
*
* @param sslContext the context.
* @return the instance itself.
*/
public final B sslContext(QuicSslContext sslContext) {
if (server != sslContext.isServer()) {
throw new IllegalArgumentException("QuicSslContext.isServer() " + sslContext.isServer()
+ " isn't supported by this builder");
}
return sslEngineProvider(q -> sslContext.newEngine(q.alloc()));
}
/**
* The {@link Function} that will return the {@link QuicSslEngine} that should be used for the
* {@link QuicChannel}.
*
* @param sslEngineProvider the provider.
* @return the instance itself.
*/
public final B sslEngineProvider(Function sslEngineProvider) {
this.sslEngineProvider = sslEngineProvider;
return self();
}
/**
* Allow to configure a {@link Executor} that will be used to run expensive SSL operations.
*
* @param sslTaskExecutor the {@link Executor} that will be used to offload expensive SSL operations.
* @return the instance itself.
*/
public final B sslTaskExecutor(Executor sslTaskExecutor) {
this.sslTaskExecutor = sslTaskExecutor;
return self();
}
/**
* Allows to configure the {@code active connect id limit} that should be used.
*
* @param limit the limit to use.
* @return the instance itself.
*/
public final B activeConnectionIdLimit(long limit) {
checkPositive(limit, "limit");
this.activeConnectionIdLimit = limit;
return self();
}
/**
* Allows to configure the {@code active connect id limit} that should be used.
*
* @param token the token to use.
* @return the instance itself.
*/
public final B statelessResetToken(byte[] token) {
if (token.length != 16) {
throw new IllegalArgumentException("token must be 16 bytes but was " + token.length);
}
this.statelessResetToken = token.clone();
return self();
}
private QuicheConfig createConfig() {
return new QuicheConfig(version, grease,
maxIdleTimeout, maxSendUdpPayloadSize, maxRecvUdpPayloadSize, initialMaxData,
initialMaxStreamDataBidiLocal, initialMaxStreamDataBidiRemote,
initialMaxStreamDataUni, initialMaxStreamsBidi, initialMaxStreamsUni,
ackDelayExponent, maxAckDelay, disableActiveMigration, enableHystart,
congestionControlAlgorithm, recvQueueLen, sendQueueLen, activeConnectionIdLimit, statelessResetToken);
}
/**
* Validate the configuration before building the codec.
*/
protected void validate() {
if (sslEngineProvider == null) {
throw new IllegalStateException("sslEngineProvider can't be null");
}
}
/**
* Builds the QUIC codec that should be added to the {@link io.netty.channel.ChannelPipeline} of the underlying
* {@link io.netty.channel.Channel} which is used as transport for QUIC.
*
* @return the {@link ChannelHandler} which acts as QUIC codec.
*/
public final ChannelHandler build() {
validate();
QuicheConfig config = createConfig();
try {
return build(config, sslEngineProvider, sslTaskExecutor, localConnIdLength, flushStrategy);
} catch (Throwable cause) {
config.free();
throw cause;
}
}
/**
* Clone the builder
*
* @return the new instance that is a clone if this instance.
*/
public abstract B clone();
/**
* Builds the QUIC codec.
*
* @param config the {@link QuicheConfig} that should be used.
* @param sslContextProvider the context provider
* @param sslTaskExecutor the {@link Executor} to use.
* @param localConnIdLength the local connection id length.
* @param flushStrategy the {@link FlushStrategy} that should be used.
* @return the {@link ChannelHandler} which acts as codec.
*/
abstract ChannelHandler build(QuicheConfig config,
Function sslContextProvider,
Executor sslTaskExecutor,
int localConnIdLength, FlushStrategy flushStrategy);
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy