From 68e3377d2efa1af25017e07ca1d94f403017befd Mon Sep 17 00:00:00 2001 From: FateJH Date: Mon, 12 Mar 2018 23:16:49 -0400 Subject: [PATCH] RelatedA0 and RelatedB0 have been superceded by RelatedA and RelatedB, respectively, with slots 0-3 for each; SlottedMetaAck has been removed and tests have been changed --- .../packet/ControlPacketOpcode.scala | 18 +++--- .../psforever/packet/control/RelatedA.scala | 38 +++++++++++ .../psforever/packet/control/RelatedA0.scala | 22 ------- .../psforever/packet/control/RelatedB.scala | 39 +++++++++++ .../psforever/packet/control/RelatedB0.scala | 23 ------- .../packet/control/SlottedMetaAck.scala | 35 ---------- .../src/test/scala/control/RelatedATest.scala | 64 +++++++++++++++++-- .../src/test/scala/control/RelatedBTest.scala | 64 +++++++++++++++++-- .../scala/control/SlottedMetaAckTest.scala | 29 --------- .../src/main/scala/PacketCodingActor.scala | 10 +-- 10 files changed, 211 insertions(+), 131 deletions(-) create mode 100644 common/src/main/scala/net/psforever/packet/control/RelatedA.scala delete mode 100644 common/src/main/scala/net/psforever/packet/control/RelatedA0.scala create mode 100644 common/src/main/scala/net/psforever/packet/control/RelatedB.scala delete mode 100644 common/src/main/scala/net/psforever/packet/control/RelatedB0.scala delete mode 100644 common/src/main/scala/net/psforever/packet/control/SlottedMetaAck.scala delete mode 100644 common/src/test/scala/control/SlottedMetaAckTest.scala diff --git a/common/src/main/scala/net/psforever/packet/ControlPacketOpcode.scala b/common/src/main/scala/net/psforever/packet/ControlPacketOpcode.scala index 7c63e573..69bc25ed 100644 --- a/common/src/main/scala/net/psforever/packet/ControlPacketOpcode.scala +++ b/common/src/main/scala/net/psforever/packet/ControlPacketOpcode.scala @@ -1,7 +1,7 @@ // Copyright (c) 2017 PSForever package net.psforever.packet -import net.psforever.packet.control.SlottedMetaPacket +import net.psforever.packet.control.{RelatedA, RelatedB, SlottedMetaPacket} import scodec.bits.BitVector import scodec.{Attempt, Codec, DecodeResult, Err} import scodec.codecs._ @@ -74,15 +74,15 @@ object ControlPacketOpcode extends Enumeration { // OPCODES 0x10-1e case 0x10 => SlottedMetaPacket.decodeWithOpcode(SlottedMetaPacket7) - case 0x11 => control.RelatedA0.decode - case 0x12 => noDecoder(RelatedA1) - case 0x13 => noDecoder(RelatedA2) - case 0x14 => noDecoder(RelatedA3) - case 0x15 => control.RelatedB0.decode - case 0x16 => noDecoder(RelatedB1) - case 0x17 => noDecoder(RelatedB2) + case 0x11 => RelatedA.decodeWithOpcode(RelatedA0) + case 0x12 => RelatedA.decodeWithOpcode(RelatedA1) + case 0x13 => RelatedA.decodeWithOpcode(RelatedA2) + case 0x14 => RelatedA.decodeWithOpcode(RelatedA3) + case 0x15 => RelatedB.decodeWithOpcode(RelatedB0) + case 0x16 => RelatedB.decodeWithOpcode(RelatedB1) + case 0x17 => RelatedB.decodeWithOpcode(RelatedB2) // 0x18 - case 0x18 => noDecoder(RelatedB3) + case 0x18 => RelatedB.decodeWithOpcode(RelatedB3) case 0x19 => control.MultiPacketEx.decode case 0x1a => noDecoder(Unknown26) case 0x1b => noDecoder(Unknown27) diff --git a/common/src/main/scala/net/psforever/packet/control/RelatedA.scala b/common/src/main/scala/net/psforever/packet/control/RelatedA.scala new file mode 100644 index 00000000..08b33501 --- /dev/null +++ b/common/src/main/scala/net/psforever/packet/control/RelatedA.scala @@ -0,0 +1,38 @@ +// Copyright (c) 2017 PSForever +package net.psforever.packet.control + +import net.psforever.packet.{ControlPacketOpcode, Marshallable, PlanetSideControlPacket} +import scodec.Codec +import scodec.bits.BitVector +import scodec.codecs._ + +/** + * Dispatched from the client in regards to errors trying to process prior `ControlPackets`. + * Explains which packet was in error by sending back its `subslot` number. + * @param slot the type of `ResultA` packet; + * valid types are integers 0-3 + * @param subslot identification of a control packet + */ +final case class RelatedA(slot : Int, subslot : Int) extends PlanetSideControlPacket { + type Packet = RelatedA + if(slot < 0 || slot > 3) { + throw new IllegalArgumentException(s"slot number is out of range - $slot") + } + + def opcode = { + val base = ControlPacketOpcode.RelatedA0.id + ControlPacketOpcode(base + slot) + } + def encode = RelatedA.encode(this).map(vect => vect.drop(8)) +} + +object RelatedA extends Marshallable[RelatedA] { + implicit val codec : Codec[RelatedA] = ( + ("slot" | uint8L.xmap[Int](a => a - ControlPacketOpcode.RelatedA0.id, a=>a) ) :: + ("subslot" | uint16) // the slot is big endian. see 0x00A42F76 + ).as[RelatedA] + + def decodeWithOpcode(slot : ControlPacketOpcode.Value)(bits : BitVector) = { + decode(ControlPacketOpcode.codec.encode(slot).require ++ bits) + } +} diff --git a/common/src/main/scala/net/psforever/packet/control/RelatedA0.scala b/common/src/main/scala/net/psforever/packet/control/RelatedA0.scala deleted file mode 100644 index 0bd34517..00000000 --- a/common/src/main/scala/net/psforever/packet/control/RelatedA0.scala +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2017 PSForever -package net.psforever.packet.control - -import net.psforever.packet.{ControlPacketOpcode, Marshallable, PlanetSideControlPacket} -import scodec.Codec -import scodec.codecs._ - -/** - * Dispatched from the client in regards to errors trying to process prior `ControlPackets`. - * Explains which packet was in error by sending back its `subslot` number. - * @param subslot identification of a control packet - */ -final case class RelatedA0(subslot : Int) - extends PlanetSideControlPacket { - type Packet = RelatedA0 - def opcode = ControlPacketOpcode.RelatedA0 - def encode = RelatedA0.encode(this) -} - -object RelatedA0 extends Marshallable[RelatedA0] { - implicit val codec : Codec[RelatedA0] = ("subslot" | uint16).as[RelatedA0] -} diff --git a/common/src/main/scala/net/psforever/packet/control/RelatedB.scala b/common/src/main/scala/net/psforever/packet/control/RelatedB.scala new file mode 100644 index 00000000..2b71c9a2 --- /dev/null +++ b/common/src/main/scala/net/psforever/packet/control/RelatedB.scala @@ -0,0 +1,39 @@ +// Copyright (c) 2017 PSForever +package net.psforever.packet.control + +import net.psforever.packet.{ControlPacketOpcode, Marshallable, PlanetSideControlPacket} +import scodec.Codec +import scodec.bits.BitVector +import scodec.codecs._ + +/** + * Dispatched to coordinate information regarding `ControlPacket` packets between the client and server. + * When dispatched by the client, it relates the current (or last received) `SlottedMetaPacket` `subslot` number back to the server. + * When dispatched by the server, it relates ??? + * @param slot the type of `ResultB` packet; + * valid types are integers 0-3 + * @param subslot identification of a control packet + */ +final case class RelatedB(slot : Int, subslot : Int) extends PlanetSideControlPacket { + type Packet = RelatedB + if(slot < 0 || slot > 3) { + throw new IllegalArgumentException(s"slot number is out of range - $slot") + } + + def opcode = { + val base = ControlPacketOpcode.RelatedB0.id + ControlPacketOpcode(base + slot) + } + def encode = RelatedB.encode(this).map(vect => vect.drop(8)) +} + +object RelatedB extends Marshallable[RelatedB] { + implicit val codec : Codec[RelatedB] = ( + ("slot" | uint8L.xmap[Int](a => a - ControlPacketOpcode.RelatedB0.id, a=>a) ) :: + ("subslot" | uint16) // the slot is big endian. see 0x00A42F76 + ).as[RelatedB] + + def decodeWithOpcode(slot : ControlPacketOpcode.Value)(bits : BitVector) = { + decode(ControlPacketOpcode.codec.encode(slot).require ++ bits) + } +} diff --git a/common/src/main/scala/net/psforever/packet/control/RelatedB0.scala b/common/src/main/scala/net/psforever/packet/control/RelatedB0.scala deleted file mode 100644 index 98372963..00000000 --- a/common/src/main/scala/net/psforever/packet/control/RelatedB0.scala +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2017 PSForever -package net.psforever.packet.control - -import net.psforever.packet.{ControlPacketOpcode, Marshallable, PlanetSideControlPacket} -import scodec.Codec -import scodec.codecs._ - -/** - * Dispatched to coordinate information regarding `ControlPacket` packets between the client and server. - * When dispatched by the client, it relates the current (or last received) `SlottedMetaPacket` `subslot` number back to the server. - * When dispatched by the server, it relates ??? - * @param subslot identification of a control packet - */ -final case class RelatedB0(subslot : Int) - extends PlanetSideControlPacket { - type Packet = RelatedB0 - def opcode = ControlPacketOpcode.RelatedB0 - def encode = RelatedB0.encode(this) -} - -object RelatedB0 extends Marshallable[RelatedB0] { - implicit val codec : Codec[RelatedB0] = ("subslot" | uint16).as[RelatedB0] -} diff --git a/common/src/main/scala/net/psforever/packet/control/SlottedMetaAck.scala b/common/src/main/scala/net/psforever/packet/control/SlottedMetaAck.scala deleted file mode 100644 index 31c940e9..00000000 --- a/common/src/main/scala/net/psforever/packet/control/SlottedMetaAck.scala +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) 2017 PSForever -package net.psforever.packet.control - -import net.psforever.packet.{ControlPacketOpcode, Marshallable, PlanetSideControlPacket} -import scodec.Codec -import scodec.bits.BitVector -import scodec.codecs._ - -final case class SlottedMetaAck(slot : Int, subslot : Int) - extends PlanetSideControlPacket { - type Packet = SlottedMetaAck - - assert(slot >= 0 && slot <= 7, s"Slot number ($slot) is out of range") //TODO 7 types of SlottedMeta, 4 types of ResultB? - - def opcode = { - val base = ControlPacketOpcode.RelatedB0.id - ControlPacketOpcode(base + slot % 4) - } - - // 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 = SlottedMetaAck.encode(this).map(vect => vect.drop(8)) -} - -object SlottedMetaAck extends Marshallable[SlottedMetaAck] { - implicit val codec : Codec[SlottedMetaAck] = ( - ("slot" | uint8L.xmap[Int](a => a - ControlPacketOpcode.RelatedB0.id, a=>a) ) :: - ("subslot" | uint16) - ).as[SlottedMetaAck] - - def decodeWithOpcode(slot : ControlPacketOpcode.Value)(bits : BitVector) = { - decode(ControlPacketOpcode.codec.encode(slot).require ++ bits) - } -} \ No newline at end of file diff --git a/common/src/test/scala/control/RelatedATest.scala b/common/src/test/scala/control/RelatedATest.scala index 6e28c955..b62b2210 100644 --- a/common/src/test/scala/control/RelatedATest.scala +++ b/common/src/test/scala/control/RelatedATest.scala @@ -3,24 +3,80 @@ package control import org.specs2.mutable._ import net.psforever.packet._ -import net.psforever.packet.control._ +import net.psforever.packet.control.RelatedA import scodec.bits._ class RelatedATest extends Specification { val string0 = hex"00 11 01 04" + val string1 = hex"00 12 01 04" + val string2 = hex"00 13 01 04" + val string3 = hex"00 14 01 04" "decode (0)" in { PacketCoding.DecodePacket(string0).require match { - case RelatedA0(slot) => - slot mustEqual 260 + case RelatedA(slot, subslot) => + slot mustEqual 0 + subslot mustEqual 260 + case _ => + ko + } + } + + "decode (1)" in { + PacketCoding.DecodePacket(string1).require match { + case RelatedA(slot, subslot) => + slot mustEqual 1 + subslot mustEqual 260 + case _ => + ko + } + } + + "decode (2)" in { + PacketCoding.DecodePacket(string2).require match { + case RelatedA(slot, subslot) => + slot mustEqual 2 + subslot mustEqual 260 + case _ => + ko + } + } + + "decode (3)" in { + PacketCoding.DecodePacket(string3).require match { + case RelatedA(slot, subslot) => + slot mustEqual 3 + subslot mustEqual 260 case _ => ko } } "encode (0)" in { - val pkt = RelatedA0(260) + val pkt = RelatedA(0, 260) val msg = PacketCoding.EncodePacket(pkt).require.toByteVector msg mustEqual string0 } + + "encode (1)" in { + val pkt = RelatedA(1, 260) + val msg = PacketCoding.EncodePacket(pkt).require.toByteVector + msg mustEqual string1 + } + + "encode (2)" in { + val pkt = RelatedA(2, 260) + val msg = PacketCoding.EncodePacket(pkt).require.toByteVector + msg mustEqual string2 + } + + "encode (3)" in { + val pkt = RelatedA(3, 260) + val msg = PacketCoding.EncodePacket(pkt).require.toByteVector + msg mustEqual string3 + } + + "encode (n)" in { + RelatedA(4, 260) must throwA[IllegalArgumentException] + } } diff --git a/common/src/test/scala/control/RelatedBTest.scala b/common/src/test/scala/control/RelatedBTest.scala index f9dbe56e..3b29cf91 100644 --- a/common/src/test/scala/control/RelatedBTest.scala +++ b/common/src/test/scala/control/RelatedBTest.scala @@ -3,24 +3,80 @@ package control import org.specs2.mutable._ import net.psforever.packet._ -import net.psforever.packet.control._ +import net.psforever.packet.control.RelatedB import scodec.bits._ class RelatedBTest extends Specification { val string0 = hex"00 15 01 04" + val string1 = hex"00 16 01 04" + val string2 = hex"00 17 01 04" + val string3 = hex"00 18 01 04" "decode (0)" in { PacketCoding.DecodePacket(string0).require match { - case RelatedB0(slot) => - slot mustEqual 260 + case RelatedB(slot, subslot) => + slot mustEqual 0 + subslot mustEqual 260 + case _ => + ko + } + } + + "decode (1)" in { + PacketCoding.DecodePacket(string1).require match { + case RelatedB(slot, subslot) => + slot mustEqual 1 + subslot mustEqual 260 + case _ => + ko + } + } + + "decode (2)" in { + PacketCoding.DecodePacket(string2).require match { + case RelatedB(slot, subslot) => + slot mustEqual 2 + subslot mustEqual 260 + case _ => + ko + } + } + + "decode (3)" in { + PacketCoding.DecodePacket(string3).require match { + case RelatedB(slot, subslot) => + slot mustEqual 3 + subslot mustEqual 260 case _ => ko } } "encode (0)" in { - val pkt = RelatedB0(260) + val pkt = RelatedB(0, 260) val msg = PacketCoding.EncodePacket(pkt).require.toByteVector msg mustEqual string0 } + + "encode (1)" in { + val pkt = RelatedB(1, 260) + val msg = PacketCoding.EncodePacket(pkt).require.toByteVector + msg mustEqual string1 + } + + "encode (2)" in { + val pkt = RelatedB(2, 260) + val msg = PacketCoding.EncodePacket(pkt).require.toByteVector + msg mustEqual string2 + } + + "encode (3)" in { + val pkt = RelatedB(3, 260) + val msg = PacketCoding.EncodePacket(pkt).require.toByteVector + msg mustEqual string3 + } + + "encode (n)" in { + RelatedB(4, 260) must throwA[IllegalArgumentException] + } } diff --git a/common/src/test/scala/control/SlottedMetaAckTest.scala b/common/src/test/scala/control/SlottedMetaAckTest.scala deleted file mode 100644 index 161ba526..00000000 --- a/common/src/test/scala/control/SlottedMetaAckTest.scala +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2017 PSForever -package control - -import org.specs2.mutable._ -import net.psforever.packet._ -import net.psforever.packet.control._ -import scodec.bits._ - -class SlottedMetaAckTest extends Specification { - val string = hex"00150da4" - - "decode" in { - PacketCoding.DecodePacket(string).require match { - case SlottedMetaAck(_, _) => - ko - case RelatedB0(subslot) => //important! - subslot mustEqual 3492 - case _ => - ko - } - } - - "encode" in { - val pkt = SlottedMetaAck(0, 3492) - val msg = PacketCoding.EncodePacket(pkt).require.toByteVector - - msg mustEqual string - } -} diff --git a/pslogin/src/main/scala/PacketCodingActor.scala b/pslogin/src/main/scala/PacketCodingActor.scala index 59a8ab28..42d7671d 100644 --- a/pslogin/src/main/scala/PacketCodingActor.scala +++ b/pslogin/src/main/scala/PacketCodingActor.scala @@ -241,7 +241,7 @@ class PacketCodingActor extends Actor with MDCContextAware { packet match { case SlottedMetaPacket(slot, subslot, innerPacket) => subslotInbound = subslot - self.tell(PacketCoding.CreateControlPacket(SlottedMetaAck(slot, subslot)), rightRef) //will go towards network + self.tell(PacketCoding.CreateControlPacket(RelatedB(slot, subslot)), rightRef) //will go to the network UnmarshalInnerPacket(innerPacket, "the inner packet of a SlottedMetaPacket") case MultiPacket(packets) => @@ -250,11 +250,11 @@ class PacketCodingActor extends Actor with MDCContextAware { case MultiPacketEx(packets) => packets.foreach { UnmarshalInnerPacket(_, "the inner packet of a MultiPacketEx") } - case RelatedA0(subslot) => - log.error(s"bad subslot data - $subslot; potential disarray") + case RelatedA(slot, subslot) => + log.error(s"result $slot: subslot $subslot was in error") - case RelatedB0(subslot) => - log.trace(s"good control packet received - subslot data $subslot") + case RelatedB(slot, subslot) => + log.trace(s"result $slot: subslot $subslot accepted") case _ => sendResponseRight(container)