Fix thread safety issues

* Synchronize RC5 cipher access
* Replace avatar using message to self in AvatarActor
This commit is contained in:
Jakob Gillich 2020-12-31 04:20:49 +01:00
parent 2f0c6d98fd
commit 4c1b9a64d3
No known key found for this signature in database
GPG key ID: FD8BF52DB8452C91
6 changed files with 25 additions and 25 deletions

1
.gitignore vendored
View file

@ -13,6 +13,7 @@ out/
project/metals.sbt
/docs
.vscode
.bsp
# User configs
config/psforever.conf

View file

@ -1 +1 @@
sbt.version = 1.3.13
sbt.version = 1.4.5

View file

@ -166,6 +166,7 @@ class MiddlewareActor(
val queueProcessor: Cancellable = {
context.system.scheduler.scheduleWithFixedDelay(10.milliseconds, 10.milliseconds)(() => {
try {
if (outQueue.nonEmpty && outQueueBundled.isEmpty) {
var length = 0L
val bundle = outQueue

View file

@ -407,6 +407,10 @@ class AvatarActor(
case ReplaceAvatar(newAvatar) =>
avatar = newAvatar
avatar.deployables.UpdateMaxCounts(avatar.certifications)
updateDeployableUIElements(
avatar.deployables.UpdateUI()
)
Behaviors.same
case AddFirstTimeEvent(event) =>
@ -461,15 +465,12 @@ class AvatarActor(
sessionActor ! SessionActor.SendResponse(
PlanetsideAttributeMessage(session.get.player.GUID, 24, certification.value)
)
avatar = avatar.copy(certifications = avatar.certifications.diff(replace) + certification)
context.self ! ReplaceAvatar(
avatar.copy(certifications = avatar.certifications.diff(replace) + certification)
)
sessionActor ! SessionActor.SendResponse(
ItemTransactionResultMessage(terminalGuid, TransactionType.Sell, success = true)
)
avatar.deployables.UpdateMaxCounts(avatar.certifications)
updateDeployableUIElements(
avatar.deployables.UpdateUI()
)
}
}
@ -510,19 +511,15 @@ class AvatarActor(
ItemTransactionResultMessage(terminalGuid, TransactionType.Sell, success = false)
)
case Success(certs) =>
context.self ! ReplaceAvatar(avatar.copy(certifications = avatar.certifications.diff(remove)))
certs.foreach { cert =>
sessionActor ! SessionActor.SendResponse(
PlanetsideAttributeMessage(session.get.player.GUID, 25, cert.value)
)
}
avatar = avatar.copy(certifications = avatar.certifications.diff(remove))
sessionActor ! SessionActor.SendResponse(
ItemTransactionResultMessage(terminalGuid, TransactionType.Sell, success = true)
)
avatar.deployables.UpdateMaxCounts(avatar.certifications)
updateDeployableUIElements(
avatar.deployables.UpdateUI()
)
}
}
Behaviors.same
@ -560,11 +557,7 @@ class AvatarActor(
)
.onComplete {
case Success(_) =>
avatar = avatar.copy(certifications = certifications)
avatar.deployables.UpdateMaxCounts(avatar.certifications)
updateDeployableUIElements(
avatar.deployables.UpdateUI()
)
context.self ! ReplaceAvatar(avatar.copy(certifications = certifications))
case Failure(exception) =>
log.error(exception)("db failure")
}
@ -600,7 +593,9 @@ class AvatarActor(
.run(query[persistence.Implant].insert(_.name -> lift(definition.Name), _.avatarId -> lift(avatar.id)))
.onComplete {
case Success(_) =>
avatar = avatar.copy(implants = avatar.implants.updated(index, Some(Implant(definition))))
context.self ! ReplaceAvatar(
avatar.copy(implants = avatar.implants.updated(index, Some(Implant(definition))))
)
sessionActor ! SessionActor.SendResponse(
AvatarImplantMessage(
session.get.player.GUID,
@ -641,7 +636,7 @@ class AvatarActor(
)
.onComplete {
case Success(_) =>
avatar = avatar.copy(implants = avatar.implants.updated(index, None))
context.self ! ReplaceAvatar(avatar.copy(implants = avatar.implants.updated(index, None)))
sessionActor ! SessionActor.SendResponse(
AvatarImplantMessage(session.get.player.GUID, ImplantAction.Remove, index, 0)
)
@ -668,7 +663,7 @@ class AvatarActor(
case Success(_) =>
loadLoadouts().onComplete {
case Success(loadouts) =>
avatar = avatar.copy(loadouts = loadouts)
context.self ! ReplaceAvatar(avatar.copy(loadouts = loadouts))
context.self ! RefreshLoadouts()
case Failure(exception) => log.error(exception)("db failure")
}
@ -694,7 +689,7 @@ class AvatarActor(
)
.onComplete {
case Success(_) =>
avatar = avatar.copy(loadouts = avatar.loadouts.updated(number, None))
context.self ! ReplaceAvatar(avatar.copy(loadouts = avatar.loadouts.updated(number, None)))
sessionActor ! SessionActor.SendResponse(FavoritesMessage(loadoutType, player.GUID, number, ""))
case Failure(exception) =>
log.error(exception)("db failure")

View file

@ -249,7 +249,6 @@ object PacketCoding {
macEncryptionKey: ByteVector,
macDecryptionKey: ByteVector
) {
private val iv = BigInt(64, random)
private val rc5Spec = new RC5ParameterSpec(0, 16, 32)
private val rc5Encrypt = Cipher.getInstance("RC5/ECB/NoPadding")
private val rc5Decrypt = Cipher.getInstance("RC5/ECB/NoPadding")
@ -276,7 +275,9 @@ object PacketCoding {
val packetWithPadding = packetNoPadding ++ ByteVector.fill(paddingNeeded)(0x00) ++ paddingEncoded.toByteVector
// raw packets plus MAC, padded to the nearest 8 byte boundary
try {
Successful(ByteVector.view(rc5Encrypt.doFinal(packetWithPadding.toArray)))
rc5Encrypt.synchronized {
Successful(ByteVector.view(rc5Encrypt.doFinal(packetWithPadding.toArray)))
}
} catch {
case e: Throwable => Failure(Err(s"encrypt error: '${e.getMessage}' data: ${packetWithPadding.toHex}"))
}
@ -285,7 +286,9 @@ object PacketCoding {
def decrypt(data: ByteVector): Attempt[ByteVector] = {
val payloadDecrypted =
try {
ByteVector.view(rc5Decrypt.doFinal(data.toArray))
rc5Decrypt.synchronized {
ByteVector.view(rc5Decrypt.doFinal(data.toArray))
}
} catch {
case e: Throwable => return Failure(Err(e.getMessage))
}

View file

@ -57,7 +57,7 @@ class Md5Mac(val key: ByteVector) {
assert(key.length == KEYLENGTH, s"key length must be ${KEYLENGTH}, not ${key.length}")
doKey()
private def doKey() = {
private def doKey(): Unit = {
val ek: ListBuffer[Byte] = ListBuffer.fill(48)(0)
val data: ListBuffer[Byte] = ListBuffer.fill(128)(0)
(0 until 16).foreach(j => {