mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-01-19 18:44:45 +00:00
Middleware (#662)
* removed suspicious shadowing and clarified failure message; customized skipped bundling * smp history is now a no-less-efficient circular array * adjustment to bundle dispatch timing; adjustment to inbound sequence reorder queue * adjustments to handling inbound packets with missing subslots * unused PacketCoding features * comments; delayed start of the queue processor task; turned sequence reorder task and subslot missing task into function literals * optimizations to the inbound re-order by sequence routines by controlling execution flow * the subslot request timer has been separated from the standard bundling processor; config values for bundling, sequence resolution, and subslot requests in the middleware actor have been included * replacing func-array with conditional logic
This commit is contained in:
parent
563afcdb19
commit
b5fc2ecf70
|
|
@ -99,6 +99,23 @@ anti-cheat {
|
|||
}
|
||||
|
||||
network {
|
||||
middleware {
|
||||
# How often between executions of the outbound bundling process
|
||||
packet-bundling-delay = 25 milliseconds
|
||||
|
||||
# Pause inbound packet transmission towards the network if the sequence number is out of order
|
||||
# Packets are put aside until the sequence is restored, or this timeout passes
|
||||
in-reorder-timeout = 50 milliseconds
|
||||
|
||||
# Wait on inbound packets if that packet is a SlottedMetaPacket and the next subslot number is greater than expected
|
||||
# Does not stop the transmission of packets to the server
|
||||
# but dictates how long between requests to the network (client) for missing packets with anticipated subslot numbers
|
||||
in-subslot-missing-delay = 50 milliseconds
|
||||
|
||||
# How many attempts at resolving missing packets with anticipated subslot numbers
|
||||
in-subslot-missing-attempts = 10
|
||||
}
|
||||
|
||||
session {
|
||||
# The maximum amount of time since the last inbound packet from a UDP session
|
||||
# before it is dropped.
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.packet
|
||||
|
||||
import java.security.{Key, SecureRandom, Security}
|
||||
import java.security.{Key, Security}
|
||||
|
||||
import javax.crypto.Cipher
|
||||
import javax.crypto.spec.RC5ParameterSpec
|
||||
|
|
@ -16,8 +16,6 @@ import net.psforever.util.Md5Mac
|
|||
object PacketCoding {
|
||||
Security.addProvider(new BouncyCastleProvider)
|
||||
|
||||
private val random = new SecureRandom()
|
||||
|
||||
val RC5_BLOCK_SIZE = 8
|
||||
|
||||
/** A lower bound on the packet size */
|
||||
|
|
@ -40,9 +38,9 @@ object PacketCoding {
|
|||
case _: PlanetSideControlPacket if crypto.isEmpty => BitVector.empty
|
||||
case _ =>
|
||||
sequence match {
|
||||
case Some(sequence) =>
|
||||
uint16L.encode(sequence) match {
|
||||
case Successful(seq) => seq
|
||||
case Some(_sequence) =>
|
||||
uint16L.encode(_sequence) match {
|
||||
case Successful(_seq) => _seq
|
||||
case f @ Failure(_) => return f
|
||||
}
|
||||
case None =>
|
||||
|
|
@ -53,8 +51,8 @@ object PacketCoding {
|
|||
val (flags, payload) = packet match {
|
||||
case _: PlanetSideGamePacket | _: PlanetSideControlPacket if crypto.isDefined =>
|
||||
encodePacket(packet) match {
|
||||
case Successful(payload) =>
|
||||
val encryptedPayload = crypto.get.encrypt(payload.bytes) match {
|
||||
case Successful(_payload) =>
|
||||
val encryptedPayload = crypto.get.encrypt(_payload.bytes) match {
|
||||
case Successful(p) => p
|
||||
case f: Failure => return f
|
||||
}
|
||||
|
|
@ -68,29 +66,29 @@ object PacketCoding {
|
|||
}
|
||||
case packet: PlanetSideGamePacket =>
|
||||
encodePacket(packet) match {
|
||||
case Successful(payload) =>
|
||||
case Successful(_payload) =>
|
||||
(
|
||||
PlanetSidePacketFlags.codec.encode(PlanetSidePacketFlags(PacketType.Normal, secured = false)).require,
|
||||
payload
|
||||
_payload
|
||||
)
|
||||
case f @ Failure(_) => return f
|
||||
}
|
||||
case packet: PlanetSideControlPacket =>
|
||||
encodePacket(packet) match {
|
||||
case Successful(payload) =>
|
||||
case Successful(_payload) =>
|
||||
(
|
||||
// control packets don't have flags
|
||||
BitVector.empty,
|
||||
payload
|
||||
_payload
|
||||
)
|
||||
case f @ Failure(_) => return f
|
||||
}
|
||||
case packet: PlanetSideCryptoPacket =>
|
||||
encodePacket(packet) match {
|
||||
case Successful(payload) =>
|
||||
case Successful(_payload) =>
|
||||
(
|
||||
PlanetSidePacketFlags.codec.encode(PlanetSidePacketFlags(PacketType.Crypto, secured = false)).require,
|
||||
payload
|
||||
_payload
|
||||
)
|
||||
case f @ Failure(_) => return f
|
||||
}
|
||||
|
|
@ -164,7 +162,7 @@ object PacketCoding {
|
|||
crypto: Option[CryptoCoding] = None
|
||||
): Attempt[(PlanetSidePacket, Int)] = {
|
||||
val (flags, remainder) = Codec.decode[PlanetSidePacketFlags](BitVector(msg)) match {
|
||||
case Successful(DecodeResult(value, remainder)) => (value, remainder)
|
||||
case Successful(DecodeResult(value, _remainder)) => (value, _remainder)
|
||||
case Failure(e) => return Failure(Err(s"Failed to parse packet flags: ${e.message}"))
|
||||
}
|
||||
|
||||
|
|
@ -184,8 +182,8 @@ object PacketCoding {
|
|||
|
||||
// all packets have a two byte sequence ID
|
||||
val (sequence, payload) = uint16L.decode(remainder) match {
|
||||
case Successful(DecodeResult(value, remainder)) =>
|
||||
(value, remainder.toByteVector)
|
||||
case Successful(DecodeResult(value, _remainder)) =>
|
||||
(value, _remainder.toByteVector)
|
||||
case Failure(e) =>
|
||||
return Failure(Err(s"Failed to parse packet sequence number: ${e.message}"))
|
||||
}
|
||||
|
|
@ -195,9 +193,9 @@ object PacketCoding {
|
|||
CryptoPacketOpcode
|
||||
.getPacketDecoder(cryptoState)(payload.bits)
|
||||
.map(p => (p.value.asInstanceOf[PlanetSidePacket], sequence))
|
||||
case (PacketType.Normal, Some(crypto)) if flags.secured =>
|
||||
case (PacketType.Normal, Some(_crypto)) if flags.secured =>
|
||||
// encrypted payload is 4-byte aligned: 1b flags, 2b sequence, 1b padding
|
||||
crypto.decrypt(payload.drop(1)).map(p => decodePacket(p)).flatten.map(p => (p, sequence))
|
||||
_crypto.decrypt(payload.drop(1)).map(p => decodePacket(p)).flatten.map(p => (p, sequence))
|
||||
case (PacketType.Normal, None) if !flags.secured =>
|
||||
decodePacket(payload).map(p => (p, sequence))
|
||||
case (PacketType.Normal, None) =>
|
||||
|
|
@ -279,7 +277,9 @@ object PacketCoding {
|
|||
Successful(ByteVector.view(rc5Encrypt.doFinal(packetWithPadding.toArray)))
|
||||
}
|
||||
} catch {
|
||||
case e: Throwable => Failure(Err(s"encrypt error: '${e.getMessage}' data: ${packetWithPadding.toHex}"))
|
||||
case e: Throwable =>
|
||||
val msg = if(e.getMessage == null) e.getClass.getSimpleName else e.getMessage
|
||||
Failure(Err(s"encrypt error: '$msg' data: ${packetWithPadding.toHex}"))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -295,7 +295,7 @@ object PacketCoding {
|
|||
|
||||
// last byte is the padding length
|
||||
val padding = uint8L.decode(payloadDecrypted.takeRight(1).bits) match {
|
||||
case Successful(padding) => padding.value
|
||||
case Successful(_padding) => _padding.value
|
||||
case Failure(e) => return Failure(Err(s"Failed to decode the encrypted padding length: ${e.message}"))
|
||||
}
|
||||
|
||||
|
|
@ -304,7 +304,7 @@ object PacketCoding {
|
|||
|
||||
val mac = bytes(Md5Mac.MACLENGTH).decode(payloadMac.bits) match {
|
||||
case Failure(e) => return Failure(Err("Failed to extract the encrypted MAC: " + e.message))
|
||||
case Successful(mac) => mac.value
|
||||
case Successful(_mac) => _mac.value
|
||||
}
|
||||
|
||||
val payloadNoMac = payloadNoPadding.dropRight(Md5Mac.MACLENGTH)
|
||||
|
|
|
|||
|
|
@ -114,7 +114,15 @@ case class AntiCheatConfig(
|
|||
)
|
||||
|
||||
case class NetworkConfig(
|
||||
session: SessionConfig
|
||||
session: SessionConfig,
|
||||
middleware: MiddlewareConfig
|
||||
)
|
||||
|
||||
case class MiddlewareConfig(
|
||||
packetBundlingDelay: FiniteDuration,
|
||||
inReorderTimeout: FiniteDuration,
|
||||
inSubslotMissingDelay: FiniteDuration,
|
||||
inSubslotMissingAttempts: Int
|
||||
)
|
||||
|
||||
case class SessionConfig(
|
||||
|
|
|
|||
Loading…
Reference in a new issue