encode and decode of only known packet of the ResetSequence type (#752)

This commit is contained in:
Fate-JH 2021-04-07 14:20:51 -04:00 committed by GitHub
parent 41b3eb5f66
commit b548260257
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 92 additions and 9 deletions

View file

@ -1,7 +1,7 @@
package net.psforever.actors.net
import akka.actor.Cancellable
import akka.actor.typed.{ActorRef, ActorTags, Behavior, PostStop, Signal}
import akka.actor.typed._
import akka.actor.typed.scaladsl.{ActorContext, Behaviors}
import akka.io.Udp
import java.net.InetSocketAddress
@ -19,8 +19,8 @@ import scodec.Attempt.{Failure, Successful}
import scodec.bits.{BitVector, ByteVector, HexStringSyntax}
import scodec.interop.akka.EnrichedByteVector
import net.psforever.objects.Default
import net.psforever.packet.{CryptoPacketOpcode, PacketCoding, PlanetSideControlPacket, PlanetSideCryptoPacket, PlanetSideGamePacket, PlanetSidePacket}
import net.psforever.packet.control.{ClientStart, ConnectionClose, ControlSync, ControlSyncResp, HandleGamePacket, MultiPacket, MultiPacketEx, RelatedA, RelatedB, ServerStart, SlottedMetaPacket, TeardownConnection}
import net.psforever.packet._
import net.psforever.packet.control._
import net.psforever.packet.crypto.{ClientChallengeXchg, ClientFinished, ServerChallengeXchg, ServerFinished}
import net.psforever.packet.game.{ChangeFireModeMessage, CharacterInfoMessage, KeepAliveMessage, PingMsg}
import net.psforever.packet.PacketCoding.CryptoCoding
@ -522,8 +522,9 @@ class MiddlewareActor(
log.error(s"Unexpected crypto packet '$packet'")
Behaviors.same
case packet =>
log.error(s"Unexpected type of packet '$packet'")
case _: PlanetSideResetSequencePacket =>
log.debug("Received sequence reset request from client; complying")
outSequence = 0
Behaviors.same
}
}

View file

@ -40,7 +40,9 @@ trait PlanetSideCryptoPacket extends PlanetSidePacket {
}
/** PlanetSide ResetSequence packets: self-contained? */
trait PlanetSideResetSequencePacket extends PlanetSidePacket { }
trait PlanetSideResetSequencePacket extends PlanetSidePacket {
def opcode: ResetSequenceOpcode.Type
}
/** PlanetSide packet type. Used in more complicated packet headers
*

View file

@ -5,6 +5,7 @@ import java.security.{Key, Security}
import javax.crypto.Cipher
import javax.crypto.spec.RC5ParameterSpec
import net.psforever.packet.reset.ResetSequence
import scodec.Attempt.{Failure, Successful}
import scodec.bits._
import scodec.{Attempt, Codec, DecodeResult, Err}
@ -118,6 +119,13 @@ object PacketCoding {
case Successful(opcode) => Successful(opcode ++ payload)
case f @ Failure(_) => f
}
case packet: PlanetSideResetSequencePacket =>
ResetSequenceOpcode.codec.encode(packet.opcode) match {
case Successful(opcode) => Successful(opcode)
case f @ Failure(_) => f
}
case _ =>
Failure(Err("packet not supported"))
}
@ -208,8 +216,11 @@ object PacketCoding {
case (PacketType.Normal, None) =>
Failure(Err("Cannot unmarshal encrypted packet without a cipher"))
case (PacketType.ResetSequence, Some(_crypto)) =>
val test = _crypto.decrypt(payload.drop(1))
Failure(Err(s"ResetSequence not completely supported, but: $flags, $sequence, and $payload; decrypt: $test"))
_crypto.decrypt(payload.drop(1)) match {
case Successful(p) if p == hex"01" => Successful((ResetSequence(), sequence))
case Successful(p) => Failure(Err(s"ResetSequence decrypted to unsupported value - $p"))
case _ => Failure(Err(s"ResetSequence did not decrypt properly"))
}
case (ptype, _) =>
Failure(Err(s"Cannot unmarshal $ptype packet at all"))
}
@ -243,9 +254,12 @@ object PacketCoding {
GamePacketOpcode.codec.decode(msg.bits) match {
case Successful(opcode) =>
GamePacketOpcode.getPacketDecoder(opcode.value)(opcode.remainder) match {
case Failure(_) if opcode.value.id == 1 =>
Successful(ResetSequence())
case Failure(e) =>
Failure(Err(f"Failed to parse game packet 0x${opcode.value.id}%02x: " + e.messageWithContext))
case Successful(p) => Successful(p.value)
case Successful(p) =>
Successful(p.value)
}
case Failure(e) => Failure(Err("Failed to decode game packet's opcode: " + e.message))
}

View file

@ -0,0 +1,24 @@
// Copyright (c) 2020 PSForever
package net.psforever.packet
import scodec.bits.BitVector
import scodec.{Attempt, Codec, DecodeResult, Err}
import scodec.codecs.uint8L
object ResetSequenceOpcode extends Enumeration(1) {
type Type = Value
val ResetSequence = Value
def getPacketDecoder(opcode: ResetSequenceOpcode.Type): BitVector => Attempt[DecodeResult[PlanetSideResetSequencePacket]] =
opcode match {
case ResetSequence => reset.ResetSequence.decode
case _ =>
(_: BitVector) =>
Attempt.failure(
Err(s"Could not find a marshaller for reset sequence packet $opcode")
.pushContext("get_marshaller")
)
}
implicit val codec: Codec[this.Value] = PacketHelpers.createEnumerationCodec(this, uint8L)
}

View file

@ -0,0 +1,17 @@
// Copyright (c) 2020 PSForever
package net.psforever.packet.reset
import net.psforever.packet.{Marshallable, PacketHelpers, PlanetSideResetSequencePacket, ResetSequenceOpcode}
import scodec.{Attempt, Codec}
import scodec.bits.BitVector
final case class ResetSequence()
extends PlanetSideResetSequencePacket {
type Packet = ResetSequence
def opcode: ResetSequenceOpcode.Type = ResetSequenceOpcode.ResetSequence
def encode: Attempt[BitVector] = ResetSequence.encode(this)
}
object ResetSequence extends Marshallable[ResetSequence] {
implicit val codec: Codec[ResetSequence] = PacketHelpers.emptyCodec[ResetSequence](ResetSequence())
}

View file

@ -0,0 +1,25 @@
// Copyright (c) 2021 PSForever
package reset
import net.psforever.packet._
import net.psforever.packet.reset.ResetSequence
import org.specs2.mutable._
import scodec.bits._
class ResetSequenceTest extends Specification {
val string = hex"01"
"decode" in {
PacketCoding.decodePacket(string).require match {
case ResetSequence() => ok
case _ => ko
}
}
"encode" in {
val msg = ResetSequence()
val pkt = PacketCoding.encodePacket(msg).require.toByteVector
pkt mustEqual string
}
}