Created
November 24, 2020 13:51
-
-
Save Mr00Anderson/2a44fc7ef5c06573704bd4f991cc111a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package app.virtualhex.network; | |
import app.virtualhex.network.internal.api.SessionLookup; | |
import com.virtual_hex.networking.datatypes.VLQDecoder; | |
import com.virtual_hex.types.BitSlotInt; | |
import io.netty.buffer.ByteBuf; | |
import io.netty.channel.ChannelHandlerContext; | |
import io.netty.channel.SimpleChannelInboundHandler; | |
import io.netty.channel.socket.DatagramPacket; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
import java.net.InetSocketAddress; | |
import java.nio.ByteBuffer; | |
import java.util.zip.Adler32; | |
/** | |
* The client only sends and receives from this pipeline, while the servers has many received on | |
* its pipe line and will have to have special handling | |
*/ | |
public class StdDatagramPacketDecoder extends SimpleChannelInboundHandler<DatagramPacket> { | |
/** | |
* Simply a logger reference | |
*/ | |
private static final Logger L = LoggerFactory.getLogger(StdDatagramPacketDecoder.class); | |
private SessionLookup<Session> sessionLookup; | |
// private SessionLookup<> pendingSessionLookup; | |
private ConnectionData connectionData; | |
public StdDatagramPacketDecoder() { | |
super(false); | |
} | |
@Override | |
public void channelRegistered(ChannelHandlerContext ctx) throws Exception { | |
this.sessionLookup = ctx.channel().attr(AttributeKeys.SESSION_LOOKUP).get(); | |
// this.connectionData = ctx.channel().attr(AttributeKeys.CONNECTION_NAME).get().connectionNameConnectionData; | |
super.channelRegistered(ctx); | |
} | |
@Override | |
protected void channelRead0(final ChannelHandlerContext ctx, final DatagramPacket msg) throws Exception { | |
// Check Addresses TODO Needs to be super fast for fast fail | |
InetSocketAddress sender = msg.sender(); | |
String hostString = sender.getHostString(); | |
int port = sender.getPort(); | |
L.debug("{} packet received by {} on {} port", this, hostString, port); | |
// Get the data | |
ByteBuf in = msg.content(); | |
int readableBytes = in.readableBytes(); | |
// Read CRC32 | |
long crc32Packet = in.readLong(); | |
// Lets check and reply for reliability ASAP | |
int reliabilityOffset = in.readByte(); | |
boolean reliable = BitSlotInt.isBitSet(reliabilityOffset, BitSlotInt._8); | |
ByteBuffer payloadBuffer = in.nioBuffer(8, in.readableBytes()); | |
// Lets get the session number and look our session up | |
int sessionNumber = VLQDecoder.decodeInteger(in); | |
Session session = sessionLookup.get(sessionNumber); | |
if(session == null){ | |
L.debug("{} received a packet for a session with number {} but no session was found.", this, sessionNumber); | |
msg.release(); | |
return; | |
} | |
SessionToken sessionToken = session.sessionToken; | |
// checksum time | |
Adler32 crc32 = new Adler32();// Todo object creation potential | |
boolean saltFirst = sessionToken.dataIntegrity.isSaltFirst(); | |
if(saltFirst){ | |
crc32.update(sessionToken.dataIntegrity.salt, 0 , sessionToken.dataIntegrity.salt.length); | |
crc32.update(payloadBuffer); | |
} else { | |
crc32.update(payloadBuffer); | |
crc32.update(sessionToken.dataIntegrity.salt,0 , sessionToken.dataIntegrity.salt.length); | |
} | |
long crc32Value = crc32.getValue(); | |
boolean dataIntactUnmodified = crc32Value == crc32Packet; | |
// Lets check in the sequence number so we can track packet loss | |
int sequenceNumber = in.readUnsignedByte(); | |
// Lets check and reply for reliability ASAP | |
if(!dataIntactUnmodified){ | |
session.recordBadChecksum(sequenceNumber); | |
msg.release(); | |
return; | |
} | |
boolean alreadyExistedRecently = session.receivedSequenceNumber(sequenceNumber); | |
if(alreadyExistedRecently){ | |
session.recordDuplicatePacket(sequenceNumber); | |
msg.release(); | |
return; | |
} | |
if(reliable){ | |
session.writeAcknowledgement(sequenceNumber); | |
} | |
int bytesLeft = in.readableBytes(); | |
while (in.isReadable() && bytesLeft < in.readableBytes()){// Stop loop in case packet does not read | |
// We will always assume UDP is a multi-packet | |
byte packetId = in.readByte(); | |
Packet packet = session.packetManager.getPacketById(packetId); | |
packet.read(msg, in); | |
} | |
// Record Stats | |
session.updateUdpReadBytes(readableBytes); | |
msg.release(); | |
} | |
@Override | |
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { | |
//TODO Resource clean up | |
L.warn("{} - Channel exception", "todo parent", cause); | |
cause.printStackTrace(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment