mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-07-16 08:55:16 +00:00
Merge pull request #770 from jgillich/unknown30
add Unknown30 decoder, allow non-advanced packets
This commit is contained in:
commit
6fbe35b15f
5 changed files with 146 additions and 92 deletions
|
|
@ -182,7 +182,8 @@ class MiddlewareActor(
|
|||
val outQueueBundled: mutable.Queue[PlanetSidePacket] = mutable.Queue()
|
||||
|
||||
/** Latest outbound sequence number;
|
||||
* the current sequence is one less than this number */
|
||||
* the current sequence is one less than this number
|
||||
*/
|
||||
var outSequence = 0
|
||||
|
||||
/**
|
||||
|
|
@ -202,7 +203,8 @@ class MiddlewareActor(
|
|||
}
|
||||
|
||||
/** Latest outbound subslot number;
|
||||
* the current subslot is one less than this number */
|
||||
* the current subslot is one less than this number
|
||||
*/
|
||||
var outSubslot = 0
|
||||
|
||||
/**
|
||||
|
|
@ -230,6 +232,7 @@ class MiddlewareActor(
|
|||
)
|
||||
|
||||
val smpHistoryLength: Int = 100
|
||||
|
||||
/** History of created `SlottedMetaPacket`s.
|
||||
* In case the client does not register receiving a packet by checking against packet subslot index numbers,
|
||||
* it will dispatch a `RelatedA` packet,
|
||||
|
|
@ -244,19 +247,27 @@ class MiddlewareActor(
|
|||
|
||||
/** end of life stat */
|
||||
var timesInReorderQueue: Int = 0
|
||||
|
||||
/** end of life stat */
|
||||
var timesSubslotMissing: Int = 0
|
||||
|
||||
/** Delay between runs of the packet bundler/resolver timer (ms);
|
||||
* 250ms per network update (client upstream), so 10 runs of this bundling code every update */
|
||||
* 250ms per network update (client upstream), so 10 runs of this bundling code every update
|
||||
*/
|
||||
val packetProcessorDelay = Config.app.network.middleware.packetBundlingDelay
|
||||
|
||||
/** Timer that handles the bundling and throttling of outgoing packets and resolves disorganized inbound packets */
|
||||
var packetProcessor: Cancellable = Default.Cancellable
|
||||
|
||||
/** how long packets that are out of sequential order wait for the missing sequence before being expedited (ms) */
|
||||
val inReorderTimeout = Config.app.network.middleware.inReorderTimeout
|
||||
|
||||
/** Timer that handles the bundling and throttling of outgoing packets requesting packets with known subslot numbers */
|
||||
var subslotMissingProcessor: Cancellable = Default.Cancellable
|
||||
|
||||
/** how long to wait between repeated requests for packets with known missing subslot numbers (ms) */
|
||||
val inSubslotMissingDelay = Config.app.network.middleware.inSubslotMissingDelay
|
||||
|
||||
/** how many time to repeat the request for a packet with a known missing subslot number */
|
||||
val inSubslotMissingNumberOfAttempts = Config.app.network.middleware.inSubslotMissingAttempts
|
||||
|
||||
|
|
@ -274,6 +285,13 @@ class MiddlewareActor(
|
|||
send(ServerStart(nonce, serverNonce), None, None)
|
||||
cryptoSetup()
|
||||
|
||||
/** Unknown30 is used to reuse an existing crypto session when switching from login to world
|
||||
* When not handling it, it appears that the client will fall back to using ClientStart
|
||||
* TODO implement this
|
||||
*/
|
||||
case (Unknown30(nonce), _) =>
|
||||
connectionClose()
|
||||
|
||||
// TODO ResetSequence
|
||||
case _ =>
|
||||
log.warn(s"Unexpected packet type $packet in start (before crypto)")
|
||||
|
|
@ -381,8 +399,7 @@ class MiddlewareActor(
|
|||
)
|
||||
send(ServerFinished(serverChallengeResult))
|
||||
//start the queue processor loop
|
||||
packetProcessor =
|
||||
context.system.scheduler.scheduleWithFixedDelay(
|
||||
packetProcessor = context.system.scheduler.scheduleWithFixedDelay(
|
||||
packetProcessorDelay,
|
||||
packetProcessorDelay
|
||||
)(() => {
|
||||
|
|
@ -575,8 +592,7 @@ class MiddlewareActor(
|
|||
} else if (outQueue.nonEmpty) {
|
||||
val bundle = {
|
||||
var length = 0L
|
||||
val (_, bundle) = outQueue
|
||||
.dequeueWhile {
|
||||
val (_, bundle) = outQueue.dequeueWhile {
|
||||
case (packet, payload) =>
|
||||
// packet length + MultiPacketEx header length
|
||||
val packetLength = payload.length + (
|
||||
|
|
@ -598,8 +614,7 @@ class MiddlewareActor(
|
|||
// We deduct some bytes to leave room for SlottedMetaPacket (4 bytes) and MultiPacketEx (2 bytes + prefix per packet)
|
||||
length == packetLength || length <= (MTU - 6) * 8
|
||||
}
|
||||
}
|
||||
.unzip
|
||||
}.unzip
|
||||
bundle
|
||||
}
|
||||
|
||||
|
|
@ -870,14 +885,14 @@ class MiddlewareActor(
|
|||
*/
|
||||
def askForMissingSubslots(): Unit = {
|
||||
if (subslotMissingProcessor.isCancelled) {
|
||||
subslotMissingProcessor =
|
||||
context.system.scheduler.scheduleWithFixedDelay(
|
||||
subslotMissingProcessor = context.system.scheduler.scheduleWithFixedDelay(
|
||||
initialDelay = 0.milliseconds,
|
||||
inSubslotMissingDelay
|
||||
)(() => {
|
||||
inSubslotsMissing.synchronized {
|
||||
timesSubslotMissing += inSubslotsMissing.size
|
||||
inSubslotsMissing.foreach { case (subslot, attempt) =>
|
||||
inSubslotsMissing.foreach {
|
||||
case (subslot, attempt) =>
|
||||
val value = attempt - 1
|
||||
if (value > 0) {
|
||||
inSubslotsMissing(subslot) = value
|
||||
|
|
|
|||
|
|
@ -16,16 +16,37 @@ object ControlPacketOpcode extends Enumeration {
|
|||
ClientStart, // first packet ever sent during client connection
|
||||
ServerStart, // second packet sent in response to ClientStart
|
||||
MultiPacket, // used to send multiple packets with one UDP message (subpackets limited to <= 255)
|
||||
Unknown4, TeardownConnection, Unknown6, ControlSync, // sent to the server from the client
|
||||
Unknown4, //
|
||||
TeardownConnection, //
|
||||
Unknown6, //
|
||||
ControlSync, // sent to the server from the client
|
||||
// 0x08
|
||||
ControlSyncResp, // the response generated by the server
|
||||
SlottedMetaPacket0, SlottedMetaPacket1, SlottedMetaPacket2, SlottedMetaPacket3, SlottedMetaPacket4,
|
||||
SlottedMetaPacket5, SlottedMetaPacket6,
|
||||
SlottedMetaPacket0, //
|
||||
SlottedMetaPacket1, //
|
||||
SlottedMetaPacket2, //
|
||||
SlottedMetaPacket3, //
|
||||
SlottedMetaPacket4, //
|
||||
SlottedMetaPacket5, //
|
||||
SlottedMetaPacket6, //
|
||||
// OPCODES 0x10-1f
|
||||
SlottedMetaPacket7, RelatedA0, RelatedA1, RelatedA2, RelatedA3, RelatedB0, RelatedB1, RelatedB2,
|
||||
SlottedMetaPacket7, //
|
||||
RelatedA0, //
|
||||
RelatedA1, //
|
||||
RelatedA2, //
|
||||
RelatedA3, //
|
||||
RelatedB0, //
|
||||
RelatedB1, //
|
||||
RelatedB2, //
|
||||
// 0x18
|
||||
RelatedB3, MultiPacketEx, // same as MultiPacket, but with the ability to send extended length packets
|
||||
Unknown26, Unknown27, Unknown28, ConnectionClose, Unknown30 = Value
|
||||
RelatedB3, //
|
||||
MultiPacketEx, // same as MultiPacket, but with the ability to send extended length packets
|
||||
Unknown26, //
|
||||
Unknown27, //
|
||||
Unknown28, //
|
||||
ConnectionClose, //
|
||||
Unknown30 // Probably a more lightweight variant of ClientStart, containing only the client nonce
|
||||
= Value
|
||||
|
||||
private def noDecoder(opcode: ControlPacketOpcode.Type) =
|
||||
(bits: BitVector) => Attempt.failure(Err(s"Could not find a marshaller for control packet $opcode (${bits.toHex})"))
|
||||
|
|
@ -69,7 +90,7 @@ object ControlPacketOpcode extends Enumeration {
|
|||
case 0x1b => noDecoder(Unknown27)
|
||||
case 0x1c => noDecoder(Unknown28)
|
||||
case 0x1d => control.ConnectionClose.decode
|
||||
case 0x1e => noDecoder(Unknown30)
|
||||
case 0x1e => control.Unknown30.decode
|
||||
case _ => noDecoder(opcode)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ object PacketType extends Enumeration(1) {
|
|||
}
|
||||
|
||||
/** PlanetSide packet flags (beginning of most packets) */
|
||||
final case class PlanetSidePacketFlags(packetType: PacketType.Value, secured: Boolean)
|
||||
final case class PlanetSidePacketFlags(packetType: PacketType.Value, secured: Boolean, advanced: Boolean = true)
|
||||
|
||||
/** Codec for [[PlanetSidePacketFlags]] */
|
||||
object PlanetSidePacketFlags extends Marshallable[PlanetSidePacketFlags] {
|
||||
|
|
@ -71,7 +71,8 @@ object PlanetSidePacketFlags extends Marshallable[PlanetSidePacketFlags] {
|
|||
("packet_type" | PacketType.codec) :: // first 4-bits
|
||||
("unused" | constant(bin"0")) ::
|
||||
("secured" | bool) ::
|
||||
("advanced" | constant(bin"1")) :: // we only support "advanced packets"
|
||||
//("advanced" | constant(bin"1")) :: // we only support "advanced packets"
|
||||
("advanced" | bool) ::
|
||||
("length_specified" | constant(bin"0")) // we DO NOT support this field
|
||||
).as[PlanetSidePacketFlags]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -238,8 +238,7 @@ object PacketCoding {
|
|||
def decodePacket(msg: ByteVector): Attempt[PlanetSidePacket] = {
|
||||
if (msg.length < PLANETSIDE_MIN_PACKET_SIZE)
|
||||
return Failure(Err(s"Packet does not meet the minimum length of $PLANETSIDE_MIN_PACKET_SIZE bytes"))
|
||||
val firstByte = msg { 0 }
|
||||
firstByte match {
|
||||
msg(0) match {
|
||||
case 0x00 =>
|
||||
// control packets don't need the first byte
|
||||
ControlPacketOpcode.codec.decode(msg.drop(1).bits) match {
|
||||
|
|
|
|||
18
src/main/scala/net/psforever/packet/control/Unknown30.scala
Normal file
18
src/main/scala/net/psforever/packet/control/Unknown30.scala
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
package net.psforever.packet.control
|
||||
|
||||
import net.psforever.packet.{ControlPacketOpcode, Marshallable, PlanetSideControlPacket}
|
||||
import scodec.Codec
|
||||
import scodec.bits._
|
||||
import scodec.codecs._
|
||||
|
||||
final case class Unknown30(clientNonce: Long) extends PlanetSideControlPacket {
|
||||
type Packet = Unknown30
|
||||
def opcode = ControlPacketOpcode.Unknown30
|
||||
def encode = Unknown30.encode(this)
|
||||
}
|
||||
|
||||
object Unknown30 extends Marshallable[Unknown30] {
|
||||
implicit val codec: Codec[Unknown30] = (
|
||||
("client_nonce" | uint32L)
|
||||
).as[Unknown30]
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue