Renamed login server to auth and data to account.

This commit is contained in:
Daan Vanden Bosch 2021-08-01 16:03:20 +02:00
parent a2285a5a03
commit 73e53177a8
9 changed files with 103 additions and 86 deletions

View File

@ -8,8 +8,8 @@ the `--config=/path/to/config.json` parameter to specify a configuration file.
## Proxy ## Proxy
Phantasmal PSO server can proxy any other PSO server. Below is a sample configuration for proxying a Phantasmal PSO server can proxy any other PSO server. Below is a sample configuration for proxying a
locally running Tethealla server using a Tethealla client. Be sure to modify tethealla.ini and set locally running Tethealla patch and login server using the standard Tethealla client. Be sure to
server port to 22000. modify tethealla.ini and set server port to 22000.
```json ```json
{ {
@ -36,7 +36,7 @@ server port to 22000.
"remotePort": 22000 "remotePort": 22000
}, },
{ {
"name": "login_2_proxy", "name": "character_proxy",
"version": "BB", "version": "BB",
"bindPort": 12001, "bindPort": 12001,
"remotePort": 22001 "remotePort": 22001

View File

@ -6,8 +6,8 @@ import kotlinx.serialization.Serializable
class Config( class Config(
val address: String? = null, val address: String? = null,
val patch: PatchServerConfig? = null, val patch: PatchServerConfig? = null,
val login: ServerConfig? = null, val auth: ServerConfig? = null,
val data: ServerConfig? = null, val account: ServerConfig? = null,
val proxy: ProxyConfig? = null, val proxy: ProxyConfig? = null,
) )

View File

@ -11,8 +11,8 @@ import world.phantasmal.psoserv.messages.Message
import world.phantasmal.psoserv.messages.MessageDescriptor import world.phantasmal.psoserv.messages.MessageDescriptor
import world.phantasmal.psoserv.messages.PcMessageDescriptor import world.phantasmal.psoserv.messages.PcMessageDescriptor
import world.phantasmal.psoserv.servers.* import world.phantasmal.psoserv.servers.*
import world.phantasmal.psoserv.servers.character.DataServer import world.phantasmal.psoserv.servers.account.AccountServer
import world.phantasmal.psoserv.servers.login.LoginServer import world.phantasmal.psoserv.servers.auth.AuthServer
import world.phantasmal.psoserv.servers.patch.PatchServer import world.phantasmal.psoserv.servers.patch.PatchServer
import java.io.File import java.io.File
import java.net.Inet4Address import java.net.Inet4Address
@ -87,8 +87,8 @@ private class PhantasmalServer(
private fun initialize(config: Config): PhantasmalServer { private fun initialize(config: Config): PhantasmalServer {
val defaultAddress = config.address?.let(::inet4Address) ?: DEFAULT_ADDRESS val defaultAddress = config.address?.let(::inet4Address) ?: DEFAULT_ADDRESS
val dataAddress = config.data?.address?.let(::inet4Address) ?: defaultAddress val dataAddress = config.account?.address?.let(::inet4Address) ?: defaultAddress
val dataPort = config.data?.port ?: DEFAULT_DATA_PORT val dataPort = config.account?.port ?: DEFAULT_DATA_PORT
val servers = mutableListOf<Server>() val servers = mutableListOf<Server>()
@ -112,17 +112,17 @@ private fun initialize(config: Config): PhantasmalServer {
) )
} }
if (config.login == null && run || config.login?.run == true) { if (config.auth == null && run || config.auth?.run == true) {
val bindPair = Inet4Pair( val bindPair = Inet4Pair(
config.login?.address?.let(::inet4Address) ?: defaultAddress, config.auth?.address?.let(::inet4Address) ?: defaultAddress,
config.login?.port ?: DEFAULT_LOGIN_PORT, config.auth?.port ?: DEFAULT_LOGIN_PORT,
) )
LOGGER.info { "Configuring login server to bind to $bindPair." } LOGGER.info { "Configuring auth server to bind to $bindPair." }
servers.add( servers.add(
LoginServer( AuthServer(
name = "login", name = "auth",
bindPair, bindPair,
dataServerAddress = dataAddress, dataServerAddress = dataAddress,
dataServerPort = dataPort, dataServerPort = dataPort,
@ -130,17 +130,17 @@ private fun initialize(config: Config): PhantasmalServer {
) )
} }
if (config.data == null && run || config.data?.run == true) { if (config.account == null && run || config.account?.run == true) {
val bindPair = Inet4Pair( val bindPair = Inet4Pair(
config.data?.address?.let(::inet4Address) ?: defaultAddress, config.account?.address?.let(::inet4Address) ?: defaultAddress,
config.data?.port ?: DEFAULT_DATA_PORT, config.account?.port ?: DEFAULT_DATA_PORT,
) )
LOGGER.info { "Configuring data server to bind to $bindPair." } LOGGER.info { "Configuring account server to bind to $bindPair." }
servers.add( servers.add(
DataServer( AccountServer(
name = "data", name = "account",
bindPair, bindPair,
) )
) )

View File

@ -223,8 +223,8 @@ sealed class BbMessage(override val buffer: Buffer) : AbstractMessage(BB_HEADER_
// 2092 Bytes of team data. // 2092 Bytes of team data.
repeat(523) { writeInt(0) } repeat(523) { writeInt(0) }
// Enable all team rewards. // Enable all team rewards.
writeUInt(UInt.MAX_VALUE) writeUInt(0xFFFFFFFFu)
writeUInt(UInt.MAX_VALUE) writeUInt(0xFFFFFFFFu)
} }
) )
} }

View File

@ -6,7 +6,6 @@ import java.net.InetSocketAddress
class Inet4Pair(addr: Inet4Address, port: Int) : InetSocketAddress(addr, port) { class Inet4Pair(addr: Inet4Address, port: Int) : InetSocketAddress(addr, port) {
constructor(addr: ByteArray, port: Int) : this(inet4Address(addr), port) constructor(addr: ByteArray, port: Int) : this(inet4Address(addr), port)
constructor(addr: String, port: Int) : this(inet4Address(addr), port)
val address: Inet4Address get() = super.getAddress() as Inet4Address val address: Inet4Address get() = super.getAddress() as Inet4Address
} }

View File

@ -1,4 +1,4 @@
package world.phantasmal.psoserv.servers.character package world.phantasmal.psoserv.servers.account
import world.phantasmal.psoserv.encryption.Cipher import world.phantasmal.psoserv.encryption.Cipher
import world.phantasmal.psoserv.messages.BbMessage import world.phantasmal.psoserv.messages.BbMessage
@ -6,17 +6,17 @@ import world.phantasmal.psoserv.servers.BbServer
import world.phantasmal.psoserv.servers.Inet4Pair import world.phantasmal.psoserv.servers.Inet4Pair
import world.phantasmal.psoserv.servers.SocketSender import world.phantasmal.psoserv.servers.SocketSender
class DataServer( class AccountServer(
name: String, name: String,
bindPair: Inet4Pair, bindPair: Inet4Pair,
) : BbServer<DataState>(name, bindPair) { ) : BbServer<AccountState>(name, bindPair) {
override fun initializeState( override fun initializeState(
sender: SocketSender<BbMessage>, sender: SocketSender<BbMessage>,
serverCipher: Cipher, serverCipher: Cipher,
clientCipher: Cipher, clientCipher: Cipher,
): DataState { ): AccountState {
val ctx = DataContext(logger, sender) val ctx = AccountContext(logger, sender)
ctx.send( ctx.send(
BbMessage.InitEncryption( BbMessage.InitEncryption(
@ -27,6 +27,6 @@ class DataServer(
encrypt = false, encrypt = false,
) )
return DataState.Authentication(ctx) return AccountState.Authentication(ctx)
} }
} }

View File

@ -1,4 +1,4 @@
package world.phantasmal.psoserv.servers.character package world.phantasmal.psoserv.servers.account
import mu.KLogger import mu.KLogger
import world.phantasmal.core.math.clamp import world.phantasmal.core.math.clamp
@ -13,14 +13,16 @@ import world.phantasmal.psoserv.servers.ServerStateContext
import world.phantasmal.psoserv.servers.SocketSender import world.phantasmal.psoserv.servers.SocketSender
import kotlin.math.min import kotlin.math.min
class DataContext( class AccountContext(
logger: KLogger, logger: KLogger,
socketSender: SocketSender<BbMessage>, socketSender: SocketSender<BbMessage>,
) : ServerStateContext<BbMessage>(logger, socketSender) ) : ServerStateContext<BbMessage>(logger, socketSender)
sealed class DataState(ctx: DataContext) : ServerState<BbMessage, DataContext, DataState>(ctx) { sealed class AccountState(ctx: AccountContext) :
class Authentication(ctx: DataContext) : DataState(ctx) { ServerState<BbMessage, AccountContext, AccountState>(ctx) {
override fun process(message: BbMessage): DataState =
class Authentication(ctx: AccountContext) : AccountState(ctx) {
override fun process(message: BbMessage): AccountState =
if (message is BbMessage.Authenticate) { if (message is BbMessage.Authenticate) {
// TODO: Actual authentication. // TODO: Actual authentication.
ctx.send( ctx.send(
@ -31,26 +33,26 @@ sealed class DataState(ctx: DataContext) : ServerState<BbMessage, DataContext, D
) )
) )
Account(ctx) GetAccount(ctx)
} else { } else {
unexpectedMessage(message) unexpectedMessage(message)
} }
} }
class Account(ctx: DataContext) : DataState(ctx) { class GetAccount(ctx: AccountContext) : AccountState(ctx) {
override fun process(message: BbMessage): DataState = override fun process(message: BbMessage): AccountState =
if (message is BbMessage.GetAccount) { if (message is BbMessage.GetAccount) {
// TODO: Send correct guild card number and team ID. // TODO: Send correct guild card number and team ID.
ctx.send(BbMessage.Account(0, 0)) ctx.send(BbMessage.Account(0, 0))
CharacterSelect(ctx) GetCharacters(ctx)
} else { } else {
unexpectedMessage(message) unexpectedMessage(message)
} }
} }
class CharacterSelect(ctx: DataContext) : DataState(ctx) { class GetCharacters(ctx: AccountContext) : AccountState(ctx) {
override fun process(message: BbMessage): DataState = override fun process(message: BbMessage): AccountState =
when (message) { when (message) {
is BbMessage.CharacterSelect -> { is BbMessage.CharacterSelect -> {
// TODO: Look up character data. // TODO: Look up character data.
@ -89,19 +91,17 @@ sealed class DataState(ctx: DataContext) : ServerState<BbMessage, DataContext, D
// TODO: Checksum checking. // TODO: Checksum checking.
ctx.send(BbMessage.ChecksumResponse(true)) ctx.send(BbMessage.ChecksumResponse(true))
DataDownload(ctx) GetGuildCardData(ctx)
} }
else -> unexpectedMessage(message) else -> unexpectedMessage(message)
} }
} }
class DataDownload(ctx: DataContext) : DataState(ctx) { class GetGuildCardData(ctx: AccountContext) : AccountState(ctx) {
private val guildCardBuffer = Buffer.withSize(54672) private val guildCardBuffer = Buffer.withSize(54672)
private val fileBuffer = Buffer.withSize(0)
private var fileChunkNo = 0
override fun process(message: BbMessage): DataState = override fun process(message: BbMessage): AccountState =
when (message) { when (message) {
is BbMessage.GetGuildCardHeader -> { is BbMessage.GetGuildCardHeader -> {
ctx.send( ctx.send(
@ -126,28 +126,11 @@ sealed class DataState(ctx: DataContext) : ServerState<BbMessage, DataContext, D
guildCardBuffer.cursor(offset, size), guildCardBuffer.cursor(offset, size),
) )
) )
}
this this
} else {
GetFiles(ctx)
} }
is BbMessage.GetFileList -> {
ctx.send(BbMessage.FileList())
this
}
is BbMessage.GetFileChunk -> {
val offset = min(fileChunkNo * MAX_CHUNK_SIZE, fileBuffer.size)
val size = min(fileBuffer.size - offset, MAX_CHUNK_SIZE)
ctx.send(BbMessage.FileChunk(fileChunkNo, fileBuffer.cursor(offset, size)))
if (offset + size < fileBuffer.size) {
fileChunkNo++
}
this
} }
else -> unexpectedMessage(message) else -> unexpectedMessage(message)
@ -177,8 +160,41 @@ sealed class DataState(ctx: DataContext) : ServerState<BbMessage, DataContext, D
} }
} }
class Final(ctx: DataContext) : DataState(ctx), FinalServerState { class GetFiles(ctx: AccountContext) : AccountState(ctx) {
override fun process(message: BbMessage): DataState = private val fileBuffer = Buffer.withSize(0)
private var fileChunkNo = 0
override fun process(message: BbMessage): AccountState =
when (message) {
is BbMessage.GetFileList -> {
ctx.send(BbMessage.FileList())
this
}
is BbMessage.GetFileChunk -> {
val offset = min(fileChunkNo * MAX_CHUNK_SIZE, fileBuffer.size)
val size = min(fileBuffer.size - offset, MAX_CHUNK_SIZE)
ctx.send(BbMessage.FileChunk(fileChunkNo, fileBuffer.cursor(offset, size)))
if (offset + size < fileBuffer.size) {
fileChunkNo++
}
this
}
else -> unexpectedMessage(message)
}
companion object {
private const val MAX_CHUNK_SIZE: Int = 0x6800
}
}
class Final(ctx: AccountContext) : AccountState(ctx), FinalServerState {
override fun process(message: BbMessage): AccountState =
unexpectedMessage(message) unexpectedMessage(message)
} }
} }

View File

@ -1,4 +1,4 @@
package world.phantasmal.psoserv.servers.login package world.phantasmal.psoserv.servers.auth
import world.phantasmal.psoserv.encryption.Cipher import world.phantasmal.psoserv.encryption.Cipher
import world.phantasmal.psoserv.messages.BbMessage import world.phantasmal.psoserv.messages.BbMessage
@ -7,19 +7,19 @@ import world.phantasmal.psoserv.servers.Inet4Pair
import world.phantasmal.psoserv.servers.SocketSender import world.phantasmal.psoserv.servers.SocketSender
import java.net.Inet4Address import java.net.Inet4Address
class LoginServer( class AuthServer(
name: String, name: String,
bindPair: Inet4Pair, bindPair: Inet4Pair,
private val dataServerAddress: Inet4Address, private val dataServerAddress: Inet4Address,
private val dataServerPort: Int, private val dataServerPort: Int,
) : BbServer<LoginState>(name, bindPair) { ) : BbServer<AuthState>(name, bindPair) {
override fun initializeState( override fun initializeState(
sender: SocketSender<BbMessage>, sender: SocketSender<BbMessage>,
serverCipher: Cipher, serverCipher: Cipher,
clientCipher: Cipher, clientCipher: Cipher,
): LoginState { ): AuthState {
val ctx = LoginContext(logger, sender, dataServerAddress.address, dataServerPort) val ctx = AuthContext(logger, sender, dataServerAddress.address, dataServerPort)
ctx.send( ctx.send(
BbMessage.InitEncryption( BbMessage.InitEncryption(
@ -30,6 +30,6 @@ class LoginServer(
encrypt = false, encrypt = false,
) )
return LoginState.Authentication(ctx) return AuthState.Authentication(ctx)
} }
} }

View File

@ -1,4 +1,4 @@
package world.phantasmal.psoserv.servers.login package world.phantasmal.psoserv.servers.auth
import mu.KLogger import mu.KLogger
import world.phantasmal.psoserv.messages.BbAuthenticationStatus import world.phantasmal.psoserv.messages.BbAuthenticationStatus
@ -8,16 +8,18 @@ import world.phantasmal.psoserv.servers.ServerState
import world.phantasmal.psoserv.servers.ServerStateContext import world.phantasmal.psoserv.servers.ServerStateContext
import world.phantasmal.psoserv.servers.SocketSender import world.phantasmal.psoserv.servers.SocketSender
class LoginContext( class AuthContext(
logger: KLogger, logger: KLogger,
socketSender: SocketSender<BbMessage>, socketSender: SocketSender<BbMessage>,
val characterServerAddress: ByteArray, val accountServerAddress: ByteArray,
val characterServerPort: Int, val accountServerPort: Int,
) : ServerStateContext<BbMessage>(logger, socketSender) ) : ServerStateContext<BbMessage>(logger, socketSender)
sealed class LoginState(ctx: LoginContext) : ServerState<BbMessage, LoginContext, LoginState>(ctx) { sealed class AuthState(ctx: AuthContext) :
class Authentication(ctx: LoginContext) : LoginState(ctx) { ServerState<BbMessage, AuthContext, AuthState>(ctx) {
override fun process(message: BbMessage): LoginState =
class Authentication(ctx: AuthContext) : AuthState(ctx) {
override fun process(message: BbMessage): AuthState =
if (message is BbMessage.Authenticate) { if (message is BbMessage.Authenticate) {
// TODO: Actual authentication. // TODO: Actual authentication.
ctx.send( ctx.send(
@ -29,8 +31,8 @@ sealed class LoginState(ctx: LoginContext) : ServerState<BbMessage, LoginContext
) )
ctx.send( ctx.send(
BbMessage.Redirect( BbMessage.Redirect(
ctx.characterServerAddress, ctx.accountServerAddress,
ctx.characterServerPort, ctx.accountServerPort,
) )
) )
@ -40,8 +42,8 @@ sealed class LoginState(ctx: LoginContext) : ServerState<BbMessage, LoginContext
} }
} }
class Final(ctx: LoginContext) : LoginState(ctx), FinalServerState { class Final(ctx: AuthContext) : AuthState(ctx), FinalServerState {
override fun process(message: BbMessage): LoginState = override fun process(message: BbMessage): AuthState =
unexpectedMessage(message) unexpectedMessage(message)
} }
} }