QuicheConnection class
Пакет: com.hypixel.hytale.lib.quiche
Файл: com/hypixel/hytale/lib/quiche/QuicheConnection.java
Поля (111)
| Модификаторы | Тип | Имя |
|---|---|---|
final |
HytaleLogger |
LOGGER |
|
|
break |
|
|
break |
|
|
break |
|
|
break |
|
|
break |
|
|
break |
|
|
continue |
|
|
continue |
|
|
continue |
|
|
continue |
|
|
continue |
|
Long2ObjectFunction |
var1 |
|
QuicheListener.DatagramBuffer |
var1 |
|
int |
var10 |
|
|
var10 |
|
MemorySegment |
var105 |
|
QuicheChannel |
var106 |
|
QuicheListener.DatagramBuffer |
var109 |
|
MemorySegment |
var11 |
|
String |
var11 |
|
|
var11 |
|
QuicheChannel |
var110 |
|
QuicheChannel |
var111 |
|
int |
var112 |
|
long |
var113 |
|
long |
var115 |
|
MemorySegment |
var116 |
|
MemorySegment |
var117 |
|
MemorySegment |
var118 |
|
long |
var119 |
|
|
var119 |
|
MemorySegment |
var12 |
|
MemorySegment |
var12 |
|
MemorySegment |
var120 |
|
int |
var121 |
|
|
var121 |
|
long |
var122 |
|
ObjectIterator |
var123 |
|
long |
var124 |
|
QuicheChannel |
var125 |
|
long |
var126 |
|
long |
var127 |
|
long |
var128 |
|
MemorySegment |
var129 |
|
MemorySegment |
var13 |
|
MemorySegment |
var13 |
|
boolean |
var14 |
|
|
var14 |
|
long |
var14 |
|
boolean |
var15 |
|
|
var15 |
|
|
var15 |
|
|
var15 |
|
|
var15 |
|
boolean |
var15 |
|
Runnable |
var16 |
|
long |
var17 |
|
QuicheChannel |
var19 |
|
long |
var2 |
|
MemorySegment |
var2 |
|
MemorySegment |
var2 |
|
FormattedMessage |
var2 |
|
MemorySegment |
var2 |
|
int |
var2 |
|
long |
var20 |
|
long |
var21 |
|
long |
var22 |
|
int |
var23 |
|
ObjectIterator |
var24 |
|
QuicheChannel |
var25 |
|
CertificateFactory |
var26 |
|
MemorySegment |
var27 |
|
MemorySegment |
var28 |
|
long |
var29 |
|
QuicheChannel |
var3 |
|
MemorySegment |
var3 |
|
MemorySegment |
var3 |
|
ByteBuffer |
var3 |
|
long |
var3 |
|
QuicheChannel |
var3 |
|
long |
var30 |
|
MemorySegment |
var31 |
|
MemorySegment |
var32 |
|
MemorySegment |
var33 |
|
ObjectIterator |
var36 |
|
QuicheChannel |
var37 |
|
QuicheConfig.RateLimit |
var4 |
|
MemorySegment |
var4 |
|
BiFunction |
var4 |
|
long |
var4 |
|
MemorySegment |
var4 |
|
MemorySegment |
var4 |
|
MemorySegment |
var5 |
|
QuicheChannel |
var5 |
|
MemorySegment |
var5 |
|
MemorySegment |
var6 |
|
ConnectionHandler |
var6 |
|
MemorySegment |
var6 |
|
long |
var6 |
|
long |
var6 |
|
ByteBuffer |
var7 |
|
int |
var7 |
|
String |
var7 |
|
InetSocketAddress |
var8 |
|
|
var8 |
|
FormattedMessage |
var8 |
|
boolean |
var8 |
|
InetSocketAddress |
var8 |
|
MemorySegment |
var9 |
|
long |
var9 |
Методы (48)
| Модификаторы | Возврат | Сигнатура |
|---|---|---|
abstract |
throw new |
IllegalArgumentExceptionthrow new IllegalArgumentException("Cannot create server-initiated uni stream for " + var1) |
abstract |
throw new |
IllegalStateExceptionthrow new IllegalStateException("Failed to send all bytes") |
|
QuicheChannel |
createChannelQuicheChannel createChannel(NetworkChannel var1) |
private |
void |
drainSendQueuevoid drainSendQueue() |
public |
void |
executevoid execute(Runnable var1) |
|
|
for for(int var5 = 0; var5 < 100; var5++) |
private |
int |
getNegotiatedAlpnVersionint getNegotiatedAlpnVersion() |
private |
void |
gracefulClosevoid gracefulClose(QuicheChannel var1) |
|
|
if if(var19.isNew) |
|
|
if if(var20 < 0L) |
|
|
if if(var20 != -1L) |
|
|
if if(var110 != null) |
|
|
if if(var111 == null) |
|
|
if if(var21 < 0L) |
|
|
if if(var113 < 0L) |
|
|
if if(var113 != -1L) |
|
|
if if(var113 == 0L) |
|
|
if if(var121 != var113) |
|
|
if if(this.certificate != null) |
|
|
if if(var29 > 0L) |
|
|
if if(this.address == null) |
|
|
if if(var126 < var119) |
|
|
if if(var30 == 0L) |
|
|
if if(var106 != null) |
|
|
if if(var3 != null) |
|
|
if if(var37.handler != null) |
|
|
if if(var2 == 0L) |
|
|
if if(var7 < 3) |
|
|
if if(var4 == null) |
|
|
if if(var5 != null && var5.handler != null) |
|
|
if if(var6 == null) |
|
|
if if(var4 == 0L) |
|
|
if if(var9 > 0L) |
|
|
if if(var6 <= 0L) |
|
|
if if(var3 - this.lastDropLogNanos >= DROP_LOG_INTERVAL_NANOS) |
|
|
if if(var1 != NetworkChannel.Default && var1 != NetworkChannel.Voice) |
private |
void |
initChannelvoid initChannel(QuicheChannel var1) |
public |
boolean |
isActiveboolean isActive() |
static |
boolean |
isOverMtuSendboolean isOverMtuSend(SocketException var0, long var1) |
private |
void |
logCloseReasonvoid logCloseReason(Arena var1) |
public |
void |
processvoid process() |
private |
void |
returnQueuedBuffersvoid returnQueuedBuffers() |
|
void |
stopvoid stop() |
public |
void |
submitvoid submit(InetSocketAddress var1, QuicheListener.DatagramBuffer var2) |
public |
void |
wakevoid wake() |
|
|
while while(!this.stopRequested) |
|
|
while while(true) |
|
|
while while(true) |
Исходный код
Показать/скрыть
class="kw">package com.hypixel.hytale.lib.quiche;
class="kw">import com.hypixel.hytale.logger.HytaleLogger;
class="kw">import com.hypixel.hytale.protocol.FormattedMessage;
class="kw">import com.hypixel.hytale.protocol.NetworkChannel;
class="kw">import com.hypixel.hytale.protocol.io.ChannelConnection;
class="kw">import com.hypixel.hytale.protocol.io.ConnectionHandler;
class="kw">import com.hypixel.hytale.protocol.io.ZstdNative;
class="kw">import com.hypixel.hytale.protocol.packets.connection.DisconnectType;
class="kw">import com.hypixel.hytale.protocol.packets.connection.QuicApplicationErrorCode;
class="kw">import com.hypixel.hytale.protocol.packets.connection.ServerDisconnect;
class="kw">import it.unimi.dsi.fastutil.longs.Long2ObjectFunction;
class="kw">import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
class="kw">import it.unimi.dsi.fastutil.longs.LongArrayList;
class="kw">import it.unimi.dsi.fastutil.objects.ObjectIterator;
class="kw">import java.io.ByteArrayInputStream;
class="kw">import java.io.IOException;
class="kw">import java.lang.foreign.Arena;
class="kw">import java.lang.foreign.MemorySegment;
class="kw">import java.lang.foreign.ValueLayout;
class="kw">import java.net.InetSocketAddress;
class="kw">import java.net.SocketAddress;
class="kw">import java.net.SocketException;
class="kw">import java.nio.ByteBuffer;
class="kw">import java.nio.channels.ClosedChannelException;
class="kw">import java.nio.charset.StandardCharsets;
class="kw">import java.security.cert.CertificateException;
class="kw">import java.security.cert.CertificateFactory;
class="kw">import java.security.cert.X509Certificate;
class="kw">import java.time.Duration;
class="kw">import java.util.concurrent.ArrayBlockingQueue;
class="kw">import java.util.concurrent.atomic.AtomicBoolean;
class="kw">import java.util.concurrent.locks.LockSupport;
class="kw">import java.util.function.BiFunction;
class="kw">import java.util.logging.Level;
class="kw">import javax.annotation.Nullable;
class QuicheConnection {
class="kw">private class="kw">static class="kw">final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass();
class="kw">private class="kw">static class="kw">final int EVENT_QUEUE_SIZE = 1024;
class="kw">private class="kw">static class="kw">final int INCOMING_QUEUE_SIZE = 64;
class="kw">private class="kw">static class="kw">final long DROP_LOG_INTERVAL_NANOS = Duration.ofSeconds(1L).toNanos();
class="kw">private class="kw">static class="kw">final int DATA_BUFFER_SIZE = 65535;
class="kw">private class="kw">static class="kw">final int QUIC_MIN_DATAGRAM_SIZE = 1200;
class="kw">public class="kw">static class="kw">final int ASSUMED_CLIENT_MAX_PACKET_SIZE_BYTES = 102400;
class="kw">public class="kw">final QuicheListener listener;
class="kw">public class="kw">final byte[] dcid;
class="kw">private class="kw">final String dcidLabel;
class="kw">public class="kw">final MemorySegment connHandle;
class="kw">private class="kw">final ArrayBlockingQueue<QuicheListener.DatagramBuffer> incomingDatagrams = new ArrayBlockingQueue<>(64);
class="kw">private class="kw">final ArrayBlockingQueue<Runnable> eventTasks = new ArrayBlockingQueue<>(1024);
class="kw">private int droppedDatagrams;
class="kw">private long lastDropLogNanos;
class="kw">private class="kw">final AtomicBoolean active = new AtomicBoolean(true);
class="kw">private class="kw">volatile boolean stopRequested;
class="kw">final MemorySegment decompressionContext = ZstdNative.createDCtx();
class="kw">final MemorySegment compressionContext = ZstdNative.createCCtx();
class="kw">final Thread processingThread;
@Nullable
class="kw">public X509Certificate certificate;
class="kw">public SocketAddress address;
class="kw">public String serverName;
class="kw">private class="kw">final Long2ObjectOpenHashMap<QuicheChannel> streams = new Long2ObjectOpenHashMap();
class="kw">private class="kw">final LongArrayList writableStreams = new LongArrayList();
@Nullable
class="kw">final TokenBucket rateLimitBucket;
class="kw">public QuicheConnection(QuicheListener var1, byte[] var2, MemorySegment var3) {
this.listener = var1;
this.dcid = var2;
this.dcidLabel = QuicheChannel.formatDcid(var2);
this.connHandle = var3;
QuicheConfig.RateLimit var4 = var1.quicheConfig.rateLimit();
this.rateLimitBucket = var4.isEnabled() ? new TokenBucket(var4.burstCapacity(), var4.packetsPerSecond(), System.nanoTime()) : null;
this.processingThread = Thread.ofVirtual().name("quiche-conn-" + this.dcidLabel).unstarted(this::process);
}
class="kw">public void process() {
Long2ObjectFunction var1 = var1x -> new QuicheChannel(this, var1x, var1x == 0L ? NetworkChannel.Default : NetworkChannel.Voice);
try (Arena var2 = Arena.ofConfined()) {
MemorySegment var105 = var2.allocate(QuicheNative.RECV_INFO_LAYOUT);
MemorySegment var4 = var2.allocate(QuicheNative.SEND_INFO_LAYOUT);
MemorySegment var5 = var2.allocate(QuicheNative.SOCKADDR_STORAGE_LAYOUT);
QuicheNative.setRecvInfoTo(var105, this.listener.localAddr);
QuicheNative.setRecvInfoToLen(var105, this.listener.localAddrLen);
MemorySegment var6 = var2.allocate(65535L);
ByteBuffer var7 = var6.asByteBuffer();
InetSocketAddress var8 = null;
MemorySegment var9 = var2.allocate(QuicheNative.SOCKADDR_STORAGE_LAYOUT);
int var10 = 0;
MemorySegment var11 = var2.allocate(65535L);
MemorySegment var12 = var2.allocate(QuicheNative.C_BOOL);
MemorySegment var13 = var2.allocate(QuicheNative.C_LONG);
boolean var14 = false;
while (!this.stopRequested) {
boolean var15 = false;
if (QuicheNative.connIsClosed(this.connHandle)) {
this.logCloseReason(var2);
break;
}
Runnable var16;
while ((var16 = this.eventTasks.poll()) != null) {
var15 = true;
var16.run();
}
long var17;
label1058:
while ((var17 = QuicheNative.connStreamReadableNext(this.connHandle)) != -1L) {
QuicheChannel var19 = (QuicheChannel)this.streams.computeIfAbsent(var17, var1);
if (var19.isNew) {
((HytaleLogger.Api)LOGGER.atInfo()).log("Stream %d created", var17);
this.initChannel(var19);
var19.isNew = false;
}
while (QuicheNative.connStreamReadable(this.connHandle, var17)) {
while (true) {
long var20 = QuicheNative.connStreamRecv(this.connHandle, var17, var11, var11.byteSize(), var12, var13);
if (var20 < 0L) {
if (var20 != -1L) {
((HytaleLogger.Api)LOGGER.atSevere())
.log("Error reading stream %d: %s (%d)", var17, QuicheNative.QuicheError.fromCode((int)var20), var20);
}
break;
}
var15 = true;
try {
var19.consumePacketData(var11, (int)var20);
} catch (Exception var100) {
((HytaleLogger.Api)LOGGER.at(Level.SEVERE).withCause(var100)).log("Exception processing packet on stream %d", var17);
this.gracefulClose(var19);
break;
}
long var22 = System.nanoTime();
ObjectIterator var24 = this.streams.values().iterator();
while (var24.hasNext()) {
QuicheChannel var25 = (QuicheChannel)var24.next();
var25.checkTimersAndGetDeadline(var22);
}
if (QuicheNative.connIsClosed(this.connHandle)) {
break label1058;
}
}
}
if (QuicheNative.connStreamFinished(this.connHandle, var17)) {
((HytaleLogger.Api)LOGGER.atInfo()).log("Stream %d finished", var17);
QuicheChannel var110 = (QuicheChannel)this.streams.remove(var17);
if (var110 != null) {
var110.close();
}
}
}
if (!QuicheNative.connIsClosed(this.connHandle)) {
while ((var17 = QuicheNative.connStreamWritableNext(this.connHandle)) != -1L) {
this.writableStreams.add(var17);
}
for (int var108 = this.writableStreams.size() - 1; var108 >= 0; var108--) {
QuicheChannel var111 = (QuicheChannel)this.streams.get(this.writableStreams.getLong(var108));
if (var111 == null) {
this.writableStreams.removeLong(var108);
} else {
var15 |= var111.tryWrite();
if (!var111.isWritable()) {
this.writableStreams.removeLong(var108);
}
}
}
QuicheListener.DatagramBuffer var109;
while ((var109 = this.incomingDatagrams.poll()) != null) {
var15 = true;
try {
int var112 = QuicheUtil.toSocketAddrStorage(var5, var109.source);
QuicheNative.setRecvInfoFrom(var105, var5);
QuicheNative.setRecvInfoFromLen(var105, var112);
long var21 = QuicheNative.connRecv(this.connHandle, var109.memory, var109.buffer.limit(), var105);
if (var21 < 0L) {
((HytaleLogger.Api)LOGGER.atWarning()).log("Failed to recv: %s (%d)", QuicheNative.QuicheError.fromCode((int)var21), var21);
}
} class="kw">finally {
this.listener.returnBuffer(var109);
}
}
while (true) {
long var113 = QuicheNative.connSend(this.connHandle, var6, var6.byteSize(), var4);
if (var113 < 0L) {
if (var113 != -1L) {
((HytaleLogger.Api)LOGGER.atWarning()).log("Failed to send: %s (%d)", QuicheNative.QuicheError.fromCode((int)var113), var113);
}
break;
}
if (var113 == 0L) {
break;
}
var15 = true;
var7.position(0);
var7.limit((int)var113);
MemorySegment var117 = QuicheNative.getSendInfoTo(var4);
int var23 = QuicheNative.getSendInfoToLen(var4);
if (var8 == null || var10 != var23 || MemorySegment.mismatch(var9, 0L, var10, var117, 0L, var23) != -1L) {
var9.copyFrom(var117);
var10 = var23;
var8 = QuicheUtil.fromSocketAddr(var117, var23);
}
int var121;
try {
var121 = this.listener.channel.send(var7, var8);
} catch (SocketException var99) {
if (isOverMtuSend(var99, var113)) {
LOGGER.at(Level.FINE).log("Dropping %d-byte datagram the OS refused: %s", var113, var99.getMessage());
class="kw">continue;
}
throw var99;
}
this.listener.wireBytesSent.addAndGet(var121);
if (var121 != var113) {
throw new IllegalStateException("Failed to send all bytes");
}
}
if (QuicheNative.connIsEstablished(this.connHandle) && !var14) {
var14 = true;
try (Arena var114 = Arena.ofConfined()) {
label1099: {
MemorySegment var116 = var114.allocate(QuicheNative.C_POINTER);
MemorySegment var118 = var114.allocate(QuicheNative.C_SIZE_T);
QuicheNative.connPeerCert(this.connHandle, var116, var118);
MemorySegment var120 = var116.get(QuicheNative.C_POINTER, 0L);
long var122 = QuicheNative.getSizeT(var118, 0L);
if (var122 != 0L && !var120.equals(MemorySegment.NULL)) {
CertificateFactory var26 = CertificateFactory.getInstance("X.509");
this.certificate = (X509Certificate)var26.generateCertificate(
new ByteArrayInputStream(var120.reinterpret(var122).toArray(ValueLayout.JAVA_BYTE))
);
if (this.certificate != null) {
((HytaleLogger.Api)LOGGER.atInfo()).log("Peer certificate retrieved: %s", this.certificate);
MemorySegment var27 = var114.allocate(QuicheNative.C_POINTER);
MemorySegment var28 = var114.allocate(QuicheNative.C_SIZE_T);
QuicheNative.connServerName(this.connHandle, var27, var28);
long var29 = QuicheNative.getSizeT(var28, 0L);
if (var29 > 0L) {
MemorySegment var31 = var27.get(QuicheNative.C_POINTER, 0L).reinterpret(var29);
this.serverName = new String(var31.toArray(ValueLayout.JAVA_BYTE), StandardCharsets.UTF_8);
((HytaleLogger.Api)LOGGER.atInfo()).log("SNI hostname: %s", this.serverName);
}
MemorySegment var129 = var2.allocate(QuicheNative.SOCKADDR_STORAGE_LAYOUT);
MemorySegment var32 = var2.allocate(QuicheNative.C_SIZE_T);
MemorySegment var33 = QuicheNative.connPathsIter(this.connHandle, this.listener.localAddr, this.listener.localAddrLen);
try {
if (QuicheNative.socketAddrIterNext(var33, var129, var32)) {
this.address = QuicheUtil.fromSocketAddr(var129, (int)QuicheNative.getSizeT(var32, 0L));
}
break label1099;
} class="kw">finally {
QuicheNative.socketAddrIterFree(var33);
}
}
((HytaleLogger.Api)LOGGER.atSevere()).log("Missing client cert for %s", this.dcidLabel);
QuicheNative.connClose(this.connHandle, true, QuicApplicationErrorCode.AuthFailed.getValue(), MemorySegment.NULL, 0L);
class="kw">continue;
}
((HytaleLogger.Api)LOGGER.atSevere()).log("Failed to retrieve peer certificate for %s", this.dcidLabel);
QuicheNative.connClose(this.connHandle, true, QuicApplicationErrorCode.AuthFailed.getValue(), MemorySegment.NULL, 0L);
class="kw">continue;
}
} catch (CertificateException var98) {
((HytaleLogger.Api)LOGGER.at(Level.SEVERE).withCause(var98)).log("Certificate error for %s", this.dcidLabel);
if (!QuicheNative.connIsClosed(this.connHandle)) {
QuicheNative.connClose(this.connHandle, true, QuicApplicationErrorCode.AuthFailed.getValue(), MemorySegment.NULL, 0L);
}
class="kw">continue;
}
if (this.address == null) {
((HytaleLogger.Api)LOGGER.atSevere()).log("Failed to find connection path for %s", this.dcidLabel);
QuicheNative.connClose(this.connHandle, true, QuicApplicationErrorCode.NoError.getValue(), MemorySegment.NULL, 0L);
class="kw">continue;
}
((HytaleLogger.Api)LOGGER.atInfo()).log("Connection established");
}
this.active.set(!QuicheNative.connIsClosed(this.connHandle));
long var115 = System.nanoTime();
long var119 = Long.MAX_VALUE;
ObjectIterator var123 = this.streams.values().iterator();
while (var123.hasNext()) {
QuicheChannel var125 = (QuicheChannel)var123.next();
long var126 = var125.checkTimersAndGetDeadline(var115);
if (var126 < var119) {
var119 = var126;
}
}
long var124 = QuicheNative.connTimeoutAsNanos(this.connHandle);
long var127 = var124 < 0L ? Long.MAX_VALUE : var124;
long var128 = var119 == Long.MAX_VALUE ? Long.MAX_VALUE : Math.max(0L, var119 - var115);
long var30 = Math.min(var127, var128);
if (var30 == 0L) {
QuicheNative.connOnTimeout(this.connHandle);
} else if (!var15 && var30 == Long.MAX_VALUE) {
LockSupport.park();
} else if (!var15) {
LockSupport.parkNanos(var30);
QuicheNative.connOnTimeout(this.connHandle);
}
}
}
if (!QuicheNative.connIsClosed(this.connHandle)) {
QuicheChannel var106 = (QuicheChannel)this.streams.get(0L);
if (var106 != null) {
this.gracefulClose(var106);
} else {
QuicheNative.connClose(this.connHandle, true, QuicApplicationErrorCode.NoError.getValue(), MemorySegment.NULL, 0L);
}
this.drainSendQueue();
}
} catch (ClosedChannelException var102) {
((HytaleLogger.Api)LOGGER.atInfo()).log("Connection %s shutting down", this.dcidLabel);
} catch (Exception var103) {
((HytaleLogger.Api)LOGGER.at(Level.SEVERE).withCause(var103)).log("Unhandled exception in connection %s processing", this.dcidLabel);
try {
QuicheChannel var3 = (QuicheChannel)this.streams.get(0L);
if (var3 != null) {
this.gracefulClose(var3);
} else if (!QuicheNative.connIsClosed(this.connHandle)) {
QuicheNative.connClose(this.connHandle, false, 1L, MemorySegment.NULL, 0L);
}
this.drainSendQueue();
} catch (Exception var92) {
((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(var92)).log("Error during connection close cleanup for %s", this.dcidLabel);
}
} class="kw">finally {
ObjectIterator var36 = this.streams.values().iterator();
while (var36.hasNext()) {
QuicheChannel var37 = (QuicheChannel)var36.next();
try {
if (var37.handler != null) {
var37.handler.logCloseMessage();
}
} catch (Exception var91) {
((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(var91)).log("Error logging close message for stream %d", var37.getStreamId());
}
try {
var37.close();
} catch (Exception var90) {
((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(var90)).log("Error closing stream %d", var37.getStreamId());
}
}
this.active.set(false);
this.returnQueuedBuffers();
QuicheNative.connFree(this.connHandle);
ZstdNative.freeDCtx(this.decompressionContext);
ZstdNative.freeCCtx(this.compressionContext);
this.listener.liveConnections.remove(this);
}
}
class="kw">private void initChannel(QuicheChannel var1) {
long var2 = var1.getStreamId();
if (var2 == 0L) {
((HytaleLogger.Api)LOGGER.atInfo()).log("Primary stream %d created", var2);
int var7 = this.getNegotiatedAlpnVersion();
if (var7 < 3) {
((HytaleLogger.Api)LOGGER.atInfo()).log("Rejecting connection %s: ALPN version %d < required %d", this.dcidLabel, var7, 3);
FormattedMessage var8 = new FormattedMessage();
var8.messageId = "client.general.disconnect.clientOutdated";
var1.handler = this.listener.handler.apply(var1);
var1.handler.registered(null);
var1.writeForClose(new ServerDisconnect(var8, DisconnectType.Disconnect));
QuicheChannel.closeWithReason(this.connHandle, QuicApplicationErrorCode.ClientOutdated, var8);
} else {
QuicheNative.connStreamPriority(this.connHandle, var2, (byte)0, false);
var1.setPacketTimeout(this.listener.quicheConfig.initialPacketTimeout());
var1.handler = this.listener.handler.apply(var1);
var1.handler.registered(null);
}
} else if ((var2 & 3L) == 0L) {
BiFunction var4 = this.listener.auxStreamHandler;
if (var4 == null) {
((HytaleLogger.Api)LOGGER.atWarning()).log("No aux stream handler configured, closing stream %d", var2);
QuicheNative.connStreamShutdown(this.connHandle, var2, 0, 0L);
QuicheNative.connStreamShutdown(this.connHandle, var2, 1, 0L);
} else {
QuicheChannel var5 = (QuicheChannel)this.streams.get(0L);
if (var5 != null && var5.handler != null) {
ConnectionHandler var6 = var4.apply(var5.handler, var1);
if (var6 == null) {
((HytaleLogger.Api)LOGGER.atWarning()).log("Aux stream %d rejected by handler", var2);
QuicheNative.connStreamShutdown(this.connHandle, var2, 0, 0L);
QuicheNative.connStreamShutdown(this.connHandle, var2, 1, 0L);
} else {
var1.setPacketTimeout(this.listener.quicheConfig.auxStreamPendingTimeout());
var1.handler = var6;
var6.registered(null);
}
} else {
((HytaleLogger.Api)LOGGER.atWarning()).log("Primary stream not ready, closing aux stream %d", var2);
QuicheNative.connStreamShutdown(this.connHandle, var2, 0, 0L);
QuicheNative.connStreamShutdown(this.connHandle, var2, 1, 0L);
}
}
} else {
((HytaleLogger.Api)LOGGER.atWarning()).log("Unexpected stream type for stream %d (low bits: %d), ignoring", var2, var2 & 3L);
}
}
class="kw">public boolean isActive() {
class="kw">return this.active.get();
}
class="kw">private int getNegotiatedAlpnVersion() {
try (Arena var1 = Arena.ofConfined()) {
MemorySegment var2 = var1.allocate(QuicheNative.C_POINTER);
MemorySegment var3 = var1.allocate(QuicheNative.C_SIZE_T);
QuicheNative.connApplicationProto(this.connHandle, var2, var3);
long var4 = QuicheNative.getSizeT(var3, 0L);
if (var4 == 0L) {
class="kw">return 0;
}
MemorySegment var6 = var2.get(QuicheNative.C_POINTER, 0L).reinterpret(var4);
String var7 = new String(var6.toArray(ValueLayout.JAVA_BYTE), StandardCharsets.UTF_8);
if (var7.startsWith("hytale/")) {
try {
class="kw">return Integer.parseInt(var7.substring(7));
} catch (NumberFormatException var11) {
class="kw">return 0;
}
} else {
class="kw">return 0;
}
}
}
class="kw">public void execute(Runnable var1) {
if (!this.eventTasks.offer(var1)) {
((HytaleLogger.Api)LOGGER.atSevere()).log("Event task queue full for %s, terminating connection", this.dcidLabel);
this.stop();
} else {
LockSupport.unpark(this.processingThread);
}
}
void stop() {
this.stopRequested = true;
this.wake();
}
class="kw">public void wake() {
LockSupport.unpark(this.processingThread);
}
class="kw">private void logCloseReason(Arena var1) {
if (QuicheNative.connIsTimedOut(this.connHandle)) {
((HytaleLogger.Api)LOGGER.atInfo()).log("Connection %s closed: timed out", this.dcidLabel);
} else {
MemorySegment var2 = var1.allocate(QuicheNative.C_BOOL);
MemorySegment var3 = var1.allocate(QuicheNative.C_LONG);
MemorySegment var4 = var1.allocate(QuicheNative.C_POINTER);
MemorySegment var5 = var1.allocate(QuicheNative.C_SIZE_T);
if (QuicheNative.connPeerError(this.connHandle, var2, var3, var4, var5)) {
long var14 = var3.get(ValueLayout.JAVA_LONG, 0L);
boolean var15 = var2.get(ValueLayout.JAVA_BOOLEAN, 0L);
long var9 = QuicheNative.getSizeT(var5, 0L);
String var11 = "";
if (var9 > 0L) {
MemorySegment var12 = var4.get(QuicheNative.C_POINTER, 0L);
if (var12.address() != 0L) {
MemorySegment var13 = var12.reinterpret(var9);
var11 = " reason=\"" + new String(var13.toArray(ValueLayout.JAVA_BYTE), StandardCharsets.UTF_8) + "\"";
}
}
((HytaleLogger.Api)LOGGER.atInfo())
.log("Connection %s closed by peer: %s error code %d%s", this.dcidLabel, var15 ? "application" : "transport", var14, var11);
} else if (QuicheNative.connLocalError(this.connHandle, var2, var3, var4, var5)) {
long var6 = var3.get(ValueLayout.JAVA_LONG, 0L);
boolean var8 = var2.get(ValueLayout.JAVA_BOOLEAN, 0L);
((HytaleLogger.Api)LOGGER.atInfo()).log("Connection %s closed locally: %s error code %d", this.dcidLabel, var8 ? "application" : "transport", var6);
} else {
((HytaleLogger.Api)LOGGER.atInfo()).log("Connection %s closed (reason unknown)", this.dcidLabel);
}
}
}
class="kw">private void gracefulClose(QuicheChannel var1) {
if (!QuicheNative.connIsClosed(this.connHandle)) {
FormattedMessage var2 = new FormattedMessage();
var2.messageId = "client.general.disconnect.internalServerError";
var1.writeForClose(new ServerDisconnect(var2, DisconnectType.Crash));
QuicheChannel.closeWithReason(this.connHandle, QuicApplicationErrorCode.Crash, var2);
}
}
class="kw">private class="kw">static boolean isOverMtuSend(SocketException var0, long var1) {
class="kw">return var0.getClass() != SocketException.class ? false : var1 > 1200L;
}
class="kw">private void drainSendQueue() {
try (Arena var1 = Arena.ofConfined()) {
MemorySegment var2 = var1.allocate(65535L);
ByteBuffer var3 = var2.asByteBuffer();
MemorySegment var4 = var1.allocate(QuicheNative.SEND_INFO_LAYOUT);
for (int var5 = 0; var5 < 100; var5++) {
long var6 = QuicheNative.connSend(this.connHandle, var2, var2.byteSize(), var4);
if (var6 <= 0L) {
break;
}
var3.position(0);
var3.limit((int)var6);
InetSocketAddress var8 = QuicheUtil.fromSocketAddr(QuicheNative.getSendInfoTo(var4), QuicheNative.getSendInfoToLen(var4));
try {
this.listener.channel.send(var3, var8);
} catch (SocketException var11) {
if (!isOverMtuSend(var11, var6)) {
throw var11;
}
}
}
} catch (IOException var13) {
((HytaleLogger.Api)LOGGER.atWarning()).log("Failed to drain send queue for %s: %s", this.dcidLabel, var13.getMessage());
}
}
class="kw">public void submit(InetSocketAddress var1, QuicheListener.DatagramBuffer var2) {
var2.source = var1;
if (!this.incomingDatagrams.offer(var2)) {
this.listener.returnBuffer(var2);
this.droppedDatagrams++;
long var3 = System.nanoTime();
if (var3 - this.lastDropLogNanos >= DROP_LOG_INTERVAL_NANOS) {
this.lastDropLogNanos = var3;
((HytaleLogger.Api)LOGGER.atInfo()).log("%s: isn't processing packets fast enough, discarded %d datagrams", this.dcidLabel, this.droppedDatagrams);
}
} else if (!this.active.get()) {
this.returnQueuedBuffers();
} else {
LockSupport.unpark(this.processingThread);
}
}
class="kw">private void returnQueuedBuffers() {
QuicheListener.DatagramBuffer var1;
while ((var1 = this.incomingDatagrams.poll()) != null) {
this.listener.returnBuffer(var1);
}
}
QuicheChannel createChannel(NetworkChannel var1) {
if (var1 != NetworkChannel.Default && var1 != NetworkChannel.Voice) {
int var2 = var1.ordinal() - 1 << 2 | 3;
QuicheChannel var3 = (QuicheChannel)this.streams.computeIfAbsent(var2, var2x -> new QuicheChannel(this, var2x, var1));
this.writableStreams.add(var2);
class="kw">return var3;
} else {
throw new IllegalArgumentException("Cannot create server-initiated uni stream for " + var1);
}
}
}