From d27bd7988cebefcd40219ff9704bfb80be990e68 Mon Sep 17 00:00:00 2001 From: Chord Date: Tue, 17 May 2016 20:34:21 -0400 Subject: [PATCH] Made some hacks to get to 100% on the World login Literally sending raw bytes instead of actual packets. No fks given --- .../src/main/scala/CryptoSessionActor.scala | 35 +++--- .../src/main/scala/LoginSessionActor.scala | 7 +- pslogin/src/main/scala/PsLogin.scala | 10 +- pslogin/src/main/scala/SessionRouter.scala | 23 +++- .../src/main/scala/WorldSessionActor.scala | 117 ++++++++++++++++++ 5 files changed, 169 insertions(+), 23 deletions(-) create mode 100644 pslogin/src/main/scala/WorldSessionActor.scala diff --git a/pslogin/src/main/scala/CryptoSessionActor.scala b/pslogin/src/main/scala/CryptoSessionActor.scala index 6a8421b80..21bef0d90 100644 --- a/pslogin/src/main/scala/CryptoSessionActor.scala +++ b/pslogin/src/main/scala/CryptoSessionActor.scala @@ -214,23 +214,28 @@ class CryptoSessionActor extends Actor with MDCContextAware { def Established : Receive = { case RawPacket(msg) => - PacketCoding.UnmarshalPacket(msg) match { - case Successful(p) => - p match { - case encPacket @ EncryptedPacket(seq, _) => - //println("Decrypting packet..." + encPacket) - PacketCoding.decryptPacket(cryptoState.get, encPacket) match { - case Successful(packet) => - //println("RECV[E]: " + packet) + if(sender() == rightRef) { + val packet = PacketCoding.encryptPacket(cryptoState.get, 0, msg).require + sendResponse(packet) + } else { + PacketCoding.UnmarshalPacket(msg) match { + case Successful(p) => + p match { + case encPacket @ EncryptedPacket(seq, _) => + //println("Decrypting packet..." + encPacket) + PacketCoding.decryptPacket(cryptoState.get, encPacket) match { + case Successful(packet) => + //println("RECV[E]: " + packet) - self ! packet - case Failure(e) => - log.error("Failed to decode encrypted packet: " + e) - } - case default => failWithError(s"Unexpected packet type $default in state Established") + self ! packet + case Failure(e) => + log.error("Failed to decode encrypted packet: " + e) + } + case default => failWithError(s"Unexpected packet type $default in state Established") - } - case Failure(e) => log.error("Could not decode raw packet: " + e) + } + case Failure(e) => log.error("Could not decode raw packet: " + e) + } } case ctrl @ ControlPacket(_, _) => val from = sender() diff --git a/pslogin/src/main/scala/LoginSessionActor.scala b/pslogin/src/main/scala/LoginSessionActor.scala index 439b13a0b..a9c555030 100644 --- a/pslogin/src/main/scala/LoginSessionActor.scala +++ b/pslogin/src/main/scala/LoginSessionActor.scala @@ -88,7 +88,7 @@ class LoginSessionActor extends Actor with MDCContextAware { } val serverName = "PSForever" - val serverAddress = new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 51000) + val serverAddress = new InetSocketAddress(InetAddress.getLocalHost, 51001) def handleGamePkt(pkt : PlanetSideGamePacket) = pkt match { case LoginMessage(majorVersion, minorVersion, buildDate, username, @@ -134,4 +134,9 @@ class LoginSessionActor extends Actor with MDCContextAware { log.trace("LOGIN SEND: " + cont) rightRef ! cont } + + def sendRawResponse(pkt : ByteVector) = { + log.trace("LOGIN SEND RAW: " + pkt) + rightRef ! RawPacket(pkt) + } } diff --git a/pslogin/src/main/scala/PsLogin.scala b/pslogin/src/main/scala/PsLogin.scala index 0114cd220..2b1f3a1a4 100644 --- a/pslogin/src/main/scala/PsLogin.scala +++ b/pslogin/src/main/scala/PsLogin.scala @@ -64,7 +64,15 @@ object PsLogin { //val system = ActorSystem("PsLogin", Some(ConfigFactory.parseMap(config)), None, Some(MDCPropagatingExecutionContextWrapper(ExecutionContext.Implicits.global))) val system = ActorSystem("PsLogin", ConfigFactory.parseMap(config)) - val listener = system.actorOf(Props(new UdpListener(Props[SessionRouter], "session-router", + + val loginTemplate = List(SessionPipeline("crypto-session-", Props[CryptoSessionActor]), + SessionPipeline("login-session-", Props[LoginSessionActor])) + val worldTemplate = List(SessionPipeline("crypto-session-", Props[CryptoSessionActor]), + SessionPipeline("world-session-", Props[WorldSessionActor])) + + val listener = system.actorOf(Props(new UdpListener(Props(new SessionRouter(loginTemplate)), "login-session-router", InetAddress.getLocalHost, 51000)), "login-udp-endpoint") + val worldListener = system.actorOf(Props(new UdpListener(Props(new SessionRouter(worldTemplate)), "world-session-router", + InetAddress.getLocalHost, 51001)), "world-udp-endpoint") } } diff --git a/pslogin/src/main/scala/SessionRouter.scala b/pslogin/src/main/scala/SessionRouter.scala index 137996b5f..1e8fb7e6f 100644 --- a/pslogin/src/main/scala/SessionRouter.scala +++ b/pslogin/src/main/scala/SessionRouter.scala @@ -18,7 +18,9 @@ case class SessionState(id : Long, address : InetSocketAddress, pipeline : List[ def nextOfStart = pipeline.tail.head } -class SessionRouter extends Actor with MDCContextAware { +case class SessionPipeline(nameTemplate : String, props : Props) + +class SessionRouter(pipeline : List[SessionPipeline]) extends Actor with MDCContextAware { private[this] val log = org.log4s.getLogger val idBySocket = mutable.Map[InetSocketAddress, Long]() @@ -112,15 +114,24 @@ class SessionRouter extends Actor with MDCContextAware { def createNewSession(address : InetSocketAddress) = { val id = newSessionId - val cryptoSession = context.actorOf(Props[CryptoSessionActor], + + + // inflate the pipeline + val actors = pipeline.map { actor => + val a = context.actorOf(actor.props, actor.nameTemplate + id.toString) + context.watch(a) + a + } + + /*val cryptoSession = context.actorOf(Props[CryptoSessionActor], "crypto-session-" + id.toString) val loginSession = context.actorOf(Props[LoginSessionActor], - "login-session-" + id.toString) + "login-session-" + id.toString)*/ - context.watch(cryptoSession) - context.watch(loginSession) + //context.watch(cryptoSession) + //context.watch(loginSession) - SessionState(id, address, List(cryptoSession, loginSession)) + SessionState(id, address, actors) } def removeSessionById(id : Long, reason : String) : Unit = { diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala new file mode 100644 index 000000000..b6bc98a25 --- /dev/null +++ b/pslogin/src/main/scala/WorldSessionActor.scala @@ -0,0 +1,117 @@ +// Copyright (c) 2016 PSForever.net to present +import java.net.{InetAddress, InetSocketAddress} + +import akka.actor.{Actor, ActorRef, MDCContextAware} +import net.psforever.packet.{PlanetSideGamePacket, _} +import net.psforever.packet.control._ +import net.psforever.packet.game._ +import scodec.Attempt.{Failure, Successful} +import scodec.bits._ + +class WorldSessionActor extends Actor with MDCContextAware { + private[this] val log = org.log4s.getLogger + + private case class UpdateServerList() + + var leftRef : ActorRef = ActorRef.noSender + var rightRef : ActorRef = ActorRef.noSender + + def receive = Initializing + + def Initializing : Receive = { + case HelloFriend(right) => + leftRef = sender() + rightRef = right.asInstanceOf[ActorRef] + + context.become(Started) + case _ => + log.error("Unknown message") + context.stop(self) + } + + def Started : Receive = { + case ctrl @ ControlPacket(_, _) => + handlePktContainer(ctrl) + case game @ GamePacket(_, _, _) => + handlePktContainer(game) + case default => failWithError(s"Invalid packet class received: $default") + } + + def handlePkt(pkt : PlanetSidePacket) : Unit = pkt match { + case ctrl : PlanetSideControlPacket => + handleControlPkt(ctrl) + case game : PlanetSideGamePacket => + handleGamePkt(game) + case default => failWithError(s"Invalid packet class received: $default") + } + + def handlePktContainer(pkt : PlanetSidePacketContainer) : Unit = pkt match { + case ctrl @ ControlPacket(opcode, ctrlPkt) => + handleControlPkt(ctrlPkt) + case game @ GamePacket(opcode, seq, gamePkt) => + handleGamePkt(gamePkt) + case default => failWithError(s"Invalid packet container class received: $default") + } + + def handleControlPkt(pkt : PlanetSideControlPacket) = { + pkt match { + case SlottedMetaPacket(slot, subslot, innerPacket) => + sendResponse(PacketCoding.CreateControlPacket(SlottedMetaAck(slot, subslot))) + + PacketCoding.DecodePacket(innerPacket) match { + case Failure(e) => + log.error(s"Failed to decode inner packet of SlottedMetaPacket: $e") + case Successful(v) => + handlePkt(v) + } + case sync @ ControlSync(diff, unk, f1, f2, f3, f4, fa, fb) => + log.debug(s"SYNC: ${sync}") + val serverTick = Math.abs(System.nanoTime().toInt) // limit the size to prevent encoding error + sendResponse(PacketCoding.CreateControlPacket(ControlSyncResp(diff, serverTick, + fa, fb, fb, fa))) + case MultiPacket(packets) => + packets.foreach { pkt => + PacketCoding.DecodePacket(pkt) match { + case Failure(e) => + log.error(s"Failed to decode inner packet of MultiPacket: $e") + case Successful(v) => + handlePkt(v) + } + } + case default => + log.debug(s"Unhandled ControlPacket $default") + } + } + + def handleGamePkt(pkt : PlanetSideGamePacket) = pkt match { + case LoginMessage(majorVersion, minorVersion, buildDate, username, + password, token, revision) => + + val clientVersion = s"Client Version: ${majorVersion}.${minorVersion}.${revision}, ${buildDate}" + + if(token.isDefined) + log.info(s"New login UN:$username Token:${token.get}. ${clientVersion}") + else + log.info(s"New login UN:$username PW:$password. ${clientVersion}") + + // testing + //sendRawResponse(hex"00 09 00 00 00 19 08 2C 00 00 4B 00 00 00 00 02 1F 80 09 9B 05 00 00 00 0D 77 BC F1 05 12 2E 40 00 80 3F D7 04 00 00 00 61 C0 6C 6F 63 6B 2D 7A 33 61 C0 6C 6F 63 6B 2D 7A 34 61 C0 6C 6F 63 6B 2D 7A 39 64 00 6C 6F 63 6B 2D 69 31 2D 69 32 2D 69 33 2D 69 34 04 00 00 00 40 40 10 30 04 10 01 06 00 ") + //sendRawResponse(hex"00 09 00 01 00 19 08 2C 00 00 70 01 00 00 00 6A 95 01 00 00 00 00 79 94 FD BF 00 A1 AF BF F3 A5 D0 3E 26 39 76 3B 08 00 00 00 36 AE 11 3F 70 5D 9B 3E 2E 15 9A 9B 3A 3F CC 90 DB 3E 45 1C EC 0F 14 3D AF CF 36 3F 06 32 BA AF 13 3F 18 4C 12 3F 26 2F D2 2D 71 3F 94 AA FB 3E 4D 16 5D 1B 1A 3F 0C 25 D5 3C 55 6B 38 89 63 3F 5D F5 25 3F 3C AC 8E 5E E6 3E 79 25 62 3F 10 32 1F 12 E3 40 00 9A 40 43 4D 54 5F 43 55 4C 4C 57 41 54 45 52 4D 41 52 4B 5F 73 75 63 63 65 73 73 ") + case default => log.debug(s"Unhandled GamePacket ${pkt}") + } + + def failWithError(error : String) = { + log.error(error) + //sendResponse(PacketCoding.CreateControlPacket(ConnectionClose())) + } + + def sendResponse(cont : PlanetSidePacketContainer) = { + log.trace("WORLD SEND: " + cont) + rightRef ! cont + } + + def sendRawResponse(pkt : ByteVector) = { + log.trace("WORLD SEND RAW: " + pkt) + rightRef ! RawPacket(pkt) + } +}