Finish coding for SlottedMetaPacket and wrote test

This commit is contained in:
Chord 2016-05-04 02:36:47 -04:00
parent ff4ea792ce
commit c7f70e3543
7 changed files with 147 additions and 38 deletions

View file

@ -51,19 +51,23 @@ object ControlPacketOpcode extends Enumeration {
Unknown30
= Value
def getPacketDecoder(opcode : ControlPacketOpcode.Type) : (BitVector) => Attempt[DecodeResult[PlanetSideControlPacket]] = {
import net.psforever
opcode match {
def getPacketDecoder(opcode : ControlPacketOpcode.Type) : (BitVector) => Attempt[DecodeResult[PlanetSideControlPacket]] = opcode match {
case HandleGamePacket => control.HandleGamePacket.decode
case ServerStart => control.ServerStart.decode
case ClientStart => control.ClientStart.decode
case MultiPacket => control.MultiPacket.decode
case SlottedMetaPacket0 => SlottedMetaPacket.decode
// IT'S GETTING "WET" IN HERE
case SlottedMetaPacket0 => SlottedMetaPacket.decodeWithOpcode(SlottedMetaPacket0)
case SlottedMetaPacket1 => SlottedMetaPacket.decodeWithOpcode(SlottedMetaPacket1)
case SlottedMetaPacket2 => SlottedMetaPacket.decodeWithOpcode(SlottedMetaPacket2)
case SlottedMetaPacket3 => SlottedMetaPacket.decodeWithOpcode(SlottedMetaPacket3)
case SlottedMetaPacket4 => SlottedMetaPacket.decodeWithOpcode(SlottedMetaPacket4)
case SlottedMetaPacket5 => SlottedMetaPacket.decodeWithOpcode(SlottedMetaPacket5)
case SlottedMetaPacket6 => SlottedMetaPacket.decodeWithOpcode(SlottedMetaPacket6)
case SlottedMetaPacket7 => SlottedMetaPacket.decodeWithOpcode(SlottedMetaPacket7)
case ConnectionClose => control.ConnectionClose.decode
case default => (a : BitVector) => Attempt.failure(Err(s"Could not find a marshaller for control packet ${opcode}"))
}
}
implicit val codec: Codec[this.Value] = PacketHelpers.createEnumerationCodec(this, uint8L)
}

View file

@ -10,10 +10,7 @@ object CryptoPacketOpcode extends Enumeration {
val Ignore, ClientChallengeXchg, ServerChallengeXchg,
ClientFinished, ServerFinished = Value
def getPacketDecoder(opcode : CryptoPacketOpcode.Type) : (BitVector) => Attempt[DecodeResult[PlanetSideCryptoPacket]] = {
import net.psforever
opcode match {
def getPacketDecoder(opcode : CryptoPacketOpcode.Type) : (BitVector) => Attempt[DecodeResult[PlanetSideCryptoPacket]] = opcode match {
case ClientChallengeXchg => crypto.ClientChallengeXchg.decode
case ServerChallengeXchg => crypto.ServerChallengeXchg.decode
case ServerFinished => crypto.ServerFinished.decode
@ -21,5 +18,4 @@ object CryptoPacketOpcode extends Enumeration {
case default => (a : BitVector) => Attempt.failure(Err(s"Could not find a marshaller for crypto packet ${opcode}")
.pushContext("get_marshaller"))
}
}
}

View file

@ -31,16 +31,12 @@ object GamePacketOpcode extends Enumeration {
DismountVehicleMsg
= Value
def getPacketDecoder(opcode : GamePacketOpcode.Type) : (BitVector) => Attempt[DecodeResult[PlanetSideGamePacket]] = {
import net.psforever
opcode match {
def getPacketDecoder(opcode : GamePacketOpcode.Type) : (BitVector) => Attempt[DecodeResult[PlanetSideGamePacket]] = opcode match {
case LoginMessage => game.LoginMessage.decode
case LoginRespMessage => game.LoginRespMessage.decode
case VNLWorldStatusMessage => game.VNLWorldStatusMessage.decode
case default => (a : BitVector) => Attempt.failure(Err(s"Could not find a marshaller for game packet ${opcode}"))
}
}
implicit val codec: Codec[this.Value] = PacketHelpers.createEnumerationCodec(this, uint8L)
}

View file

@ -3,27 +3,34 @@ package net.psforever.packet.control
import net.psforever.packet.{ControlPacketOpcode, Marshallable, PlanetSideControlPacket}
import scodec.Codec
import scodec.bits.ByteVector
import scodec.bits.{BitVector, ByteOrdering, ByteVector}
import scodec.codecs._
final case class SlottedMetaPacket(/*slot : Int,*/ packet : ByteVector)
final case class SlottedMetaPacket(slot : Int, subslot : Int, packet : ByteVector)
extends PlanetSideControlPacket {
type Packet = SlottedMetaPacket
//assert(slot >= 0 && slot <= 7, "Slot number is out of range")
assert(slot >= 0 && slot <= 7, s"Slot number ($slot) is out of range")
def opcode = {
val base = ControlPacketOpcode.SlottedMetaPacket0.id
ControlPacketOpcode(base/* + slot*/)
ControlPacketOpcode(base + slot)
}
def encode = SlottedMetaPacket.encode(this)
// XXX: a nasty hack to ignore the "slot" field
// There is so much wrong with this it's not even funny. Why scodec, whyyyy...
// I've never had a library make me feel so stupid and smart at the same time
def encode = SlottedMetaPacket.encode(this).map(vect => vect.drop(8))
}
object SlottedMetaPacket extends Marshallable[SlottedMetaPacket] {
implicit val codec : Codec[SlottedMetaPacket] = (
("unknown" | constant(0)) ::
("unknown" | constant(0)) ::
("slot" | uint8L.xmap[Int](a => a - ControlPacketOpcode.SlottedMetaPacket0.id, a=>a) ) ::
("subslot" | uint16) :: // the slot is big endian. see 0x00A42F76
("rest" | bytes)
).as[SlottedMetaPacket]
def decodeWithOpcode(slot : ControlPacketOpcode.Value)(bits : BitVector) = {
decode(ControlPacketOpcode.codec.encode(slot).require ++ bits)
}
}

View file

@ -0,0 +1,82 @@
// Copyright (c) 2016 PSForever.net to present
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.control._
import scodec.Attempt.Successful
import scodec.bits._
import scodec.codecs.uint16
class ControlPacketTest extends Specification {
"PlanetSide control packet" in {
val cNonce = 656287232
"SlottedMetaPacket" should {
val string = hex"00 09 00 00 00194302484C36563130433F" ++
hex"4C6835316369774A0000000018FABE0C" ++
hex"00000000000000000000000001000000" ++
hex"020000006B7BD8288C6469666671756F" ++
hex"7469656E740000000000440597570065" ++
hex"006C0063006F006D006500200074006F" ++
hex"00200050006C0061006E006500740053" ++
hex"0069006400650021002000018667656D" ++
hex"696E690100040001459E2540377540"
def createMetaPacket(slot : Int, subslot : Int, rest : ByteVector) = hex"00" ++
ControlPacketOpcode.codec.encode(
ControlPacketOpcode(ControlPacketOpcode.SlottedMetaPacket0.id + slot)
).require.toByteVector ++ uint16.encode(subslot).require.toByteVector ++ rest
"decode as the base slot and subslot" in {
PacketCoding.DecodePacket(string).require match {
case SlottedMetaPacket(slot, subslot, rest) =>
slot mustEqual 0
subslot mustEqual 0
rest mustEqual string.drop(4)
case default =>
true mustEqual false
}
}
"decode as an arbitrary slot and subslot" in {
val maxSlots = ControlPacketOpcode.SlottedMetaPacket7.id - ControlPacketOpcode.SlottedMetaPacket0.id
// create all possible SlottedMetaPackets
for(i <- 0 until maxSlots) {
val subslot = 12323
val pkt = createMetaPacket(i, subslot, ByteVector.empty)
PacketCoding.DecodePacket(pkt).require match {
case SlottedMetaPacket(slot, subslotDecoded, rest) =>
// XXX: there isn't a simple solution to Slot0 and Slot4 be aliases of each other structurally
// This is probably best left to higher layers
//slot mustEqual i % 4 // this is seen at 0x00A3FBFA
slot mustEqual i
subslotDecoded mustEqual subslot
rest mustEqual ByteVector.empty // empty in this case
case default =>
true mustEqual false
}
}
true
}
"encode" in {
val encoded = PacketCoding.EncodePacket(SlottedMetaPacket(0, 0x1000, ByteVector.empty)).require
val encoded2 = PacketCoding.EncodePacket(SlottedMetaPacket(3, 0xffff, hex"414243")).require
val encoded3 = PacketCoding.EncodePacket(SlottedMetaPacket(7, 0, hex"00")).require
encoded.toByteVector mustEqual createMetaPacket(0, 0x1000, ByteVector.empty)
encoded2.toByteVector mustEqual createMetaPacket(3, 0xffff, hex"414243")
encoded3.toByteVector mustEqual createMetaPacket(7, 0, hex"00")
PacketCoding.EncodePacket(SlottedMetaPacket(8, 0, hex"00")).require must throwA[AssertionError]
PacketCoding.EncodePacket(SlottedMetaPacket(-1, 0, hex"00")).require must throwA[AssertionError]
PacketCoding.EncodePacket(SlottedMetaPacket(0, 0x10000, hex"00")).require must throwA[IllegalArgumentException]
}
}
}
}