Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions src/main/kotlin/com/open592/fileserver/buffer/XorExtensions.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.open592.fileserver.buffer

import io.netty.buffer.ByteBuf

internal fun ByteBuf.xor(key: Int): ByteBuf {
if (key == 0) {
return retain()
}

val buf =
if (refCnt() == 1) {
retain()
} else {
copy()
}

if (buf.hasArray()) {
val array = buf.array()

val off = buf.arrayOffset() + buf.readerIndex()
val len = buf.readableBytes()

for (i in off until off + len) {
array[i] = (array[i].toInt() xor key).toByte()
}
} else {
val off = buf.readerIndex()
val len = buf.readableBytes()

for (i in off until off + len) {
buf.setByte(i, buf.getByte(i).toInt() xor key)
}
}

return buf
}
3 changes: 2 additions & 1 deletion src/main/kotlin/com/open592/fileserver/cache/CacheModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ package com.open592.fileserver.cache

import com.displee.cache.CacheLibrary
import com.google.inject.AbstractModule
import com.google.inject.Scopes
import com.open592.fileserver.configuration.ServerConfigurationModule

object CacheModule : AbstractModule() {
override fun configure() {
install(ServerConfigurationModule)

bind(CacheLibrary::class.java).toProvider(CacheProvider::class.java)
bind(CacheLibrary::class.java).toProvider(CacheProvider::class.java).`in`(Scopes.SINGLETON)
}
}
16 changes: 16 additions & 0 deletions src/main/kotlin/com/open592/fileserver/net/ExceptionHandler.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.open592.fileserver.net

import com.github.michaelbull.logging.InlineLogger
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.ChannelInboundHandlerAdapter

class ExceptionHandler : ChannelInboundHandlerAdapter() {

override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
logger.error { "Caught exception: ${cause.message}" }
}

private companion object {
private val logger = InlineLogger()
}
}
Original file line number Diff line number Diff line change
@@ -1,43 +1,41 @@
package com.open592.fileserver.net

import com.github.michaelbull.logging.InlineLogger
import com.open592.fileserver.protocol.inbound.Js5InboundChannelHandler
import com.open592.fileserver.protocol.inbound.Js5InboundMessageDecoder
import com.open592.fileserver.protocol.outbound.Js5OutboundGroupMessageEncoder
import com.open592.fileserver.protocol.outbound.Js5OutboundStatusMessageEncoder
import io.netty.channel.Channel
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.ChannelInitializer
import io.netty.handler.timeout.IdleStateHandler
import jakarta.inject.Inject
import jakarta.inject.Provider
import jakarta.inject.Singleton
import java.util.concurrent.TimeUnit

@Singleton
class NetworkChannelInitializer
@Inject
constructor(private val js5InboundChannelHandler: Provider<Js5InboundChannelHandler>) :
ChannelInitializer<Channel>() {
override fun initChannel(channel: Channel) {
channel
.pipeline()
.addLast(
IdleStateHandler(
true, TIMEOUT_SECONDS, TIMEOUT_SECONDS, TIMEOUT_SECONDS, TimeUnit.SECONDS),
Js5InboundMessageDecoder(),
Js5OutboundStatusMessageEncoder(),
Js5OutboundGroupMessageEncoder(),
js5InboundChannelHandler.get(),
)
}

override fun exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) {
logger.error { "Caught exception: ${cause.message}" }
}

private companion object {
private const val TIMEOUT_SECONDS: Long = 30
private val logger = InlineLogger()
}
}
package com.open592.fileserver.net

import com.github.michaelbull.logging.InlineLogger
import com.open592.fileserver.protocol.inbound.Js5InboundChannelHandler
import com.open592.fileserver.protocol.inbound.Js5InboundMessageDecoder
import com.open592.fileserver.protocol.outbound.Js5OutboundGroupMessageEncoder
import com.open592.fileserver.protocol.outbound.Js5OutboundStatusMessageEncoder
import com.open592.fileserver.protocol.outbound.XorEncoder
import io.netty.channel.Channel
import io.netty.channel.ChannelInitializer
import io.netty.handler.timeout.IdleStateHandler
import jakarta.inject.Inject
import jakarta.inject.Provider
import jakarta.inject.Singleton
import java.util.concurrent.TimeUnit

@Singleton
class NetworkChannelInitializer
@Inject
constructor(private val js5InboundChannelHandler: Provider<Js5InboundChannelHandler>) :
ChannelInitializer<Channel>() {
override fun initChannel(channel: Channel) {
channel
.pipeline()
.addLast(
IdleStateHandler(
true, TIMEOUT_SECONDS, TIMEOUT_SECONDS, TIMEOUT_SECONDS, TimeUnit.SECONDS),
XorEncoder(),
Js5InboundMessageDecoder(),
Js5OutboundStatusMessageEncoder(),
Js5OutboundGroupMessageEncoder(),
js5InboundChannelHandler.get(),
ExceptionHandler(),
)
}

private companion object {
private const val TIMEOUT_SECONDS: Long = 30
private val logger = InlineLogger()
}
}
6 changes: 3 additions & 3 deletions src/main/kotlin/com/open592/fileserver/net/js5/Js5Service.kt
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@ constructor(
} else {
allocator.buffer().use { buffer ->
val archiveSector =
if (request.group == 255) {
cacheLibrary.index255?.readArchiveSector(request.archive)
if (request.archive == ARCHIVE_SET) {
cacheLibrary.index255?.readArchiveSector(request.group)
} else {
cacheLibrary.index(request.group).readArchiveSector(request.archive)
cacheLibrary.index(request.archive).readArchiveSector(request.group)
} ?: return

buffer.writeBytes(archiveSector.data)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,71 +1,79 @@
package com.open592.fileserver.protocol.inbound

import com.github.michaelbull.logging.InlineLogger
import com.open592.fileserver.configuration.ServerConfiguration
import com.open592.fileserver.net.js5.Js5Client
import com.open592.fileserver.net.js5.Js5Service
import com.open592.fileserver.protocol.outbound.Js5OutboundStatusMessage
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.SimpleChannelInboundHandler
import io.netty.handler.timeout.IdleStateEvent
import jakarta.inject.Inject

class Js5InboundChannelHandler
@Inject
constructor(
private val service: Js5Service,
private val serverConfiguration: ServerConfiguration,
) : SimpleChannelInboundHandler<Js5InboundMessage>(Js5InboundMessage::class.java) {
private lateinit var client: Js5Client

override fun handlerAdded(ctx: ChannelHandlerContext) {
client = Js5Client(ctx.read())
}

override fun channelRead0(ctx: ChannelHandlerContext, message: Js5InboundMessage) {
when (message) {
is Js5InboundMessage.InitializeJs5RemoteConnection ->
handleInitializeJs5RemoteConnection(ctx, message)
is Js5InboundMessage.RequestGroup -> service.push(client, message)
is Js5InboundMessage.ExchangeObfuscationKey -> handleExchangeObfuscationKey(message)
is Js5InboundMessage.RequestConnectionDisconnect -> ctx.close()
else -> Unit
}
}

private fun handleInitializeJs5RemoteConnection(
ctx: ChannelHandlerContext,
message: Js5InboundMessage.InitializeJs5RemoteConnection
) {
if (message.build != serverConfiguration.getBuildNumber()) {
ctx.write(Js5OutboundStatusMessage.ClientIsOutOfDate)
} else {
ctx.write(Js5OutboundStatusMessage.Ok)
}
}

private fun handleExchangeObfuscationKey(message: Js5InboundMessage.ExchangeObfuscationKey) {
logger.info { "Handle Exchange Obfuscation Key with value = ${message.key}" }
}

override fun channelReadComplete(ctx: ChannelHandlerContext) {
service.readIfNotFull(client)
ctx.flush()
}

override fun channelWritabilityChanged(ctx: ChannelHandlerContext) {
if (ctx.channel().isWritable) {
service.notifyIfNotEmpty(client)
}
}

override fun userEventTriggered(ctx: ChannelHandlerContext, event: Any) {
if (event is IdleStateEvent) {
ctx.close()
}
}

private companion object {
private val logger = InlineLogger()
}
}
package com.open592.fileserver.protocol.inbound

import com.github.michaelbull.logging.InlineLogger
import com.open592.fileserver.configuration.ServerConfiguration
import com.open592.fileserver.net.js5.Js5Client
import com.open592.fileserver.net.js5.Js5Service
import com.open592.fileserver.protocol.outbound.Js5OutboundStatusMessage
import com.open592.fileserver.protocol.outbound.XorEncoder
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.SimpleChannelInboundHandler
import io.netty.handler.timeout.IdleStateEvent
import jakarta.inject.Inject

class Js5InboundChannelHandler
@Inject
constructor(
private val service: Js5Service,
private val serverConfiguration: ServerConfiguration,
) : SimpleChannelInboundHandler<Js5InboundMessage>(Js5InboundMessage::class.java) {
private lateinit var client: Js5Client

override fun handlerAdded(ctx: ChannelHandlerContext) {
client = Js5Client(ctx.read())
}

override fun channelRead0(ctx: ChannelHandlerContext, message: Js5InboundMessage) {
when (message) {
is Js5InboundMessage.InitializeJs5RemoteConnection ->
handleInitializeJs5RemoteConnection(ctx, message)
is Js5InboundMessage.RequestGroup -> service.push(client, message)
is Js5InboundMessage.ExchangeObfuscationKey -> handleExchangeObfuscationKey(ctx, message)
is Js5InboundMessage.RequestConnectionDisconnect -> ctx.close()
else -> Unit
}
}

private fun handleInitializeJs5RemoteConnection(
ctx: ChannelHandlerContext,
message: Js5InboundMessage.InitializeJs5RemoteConnection
) {
if (message.build != serverConfiguration.getBuildNumber()) {
ctx.write(Js5OutboundStatusMessage.ClientIsOutOfDate)
} else {
ctx.write(Js5OutboundStatusMessage.Ok)
}
}

private fun handleExchangeObfuscationKey(
ctx: ChannelHandlerContext,
message: Js5InboundMessage.ExchangeObfuscationKey
) {
val encoder = ctx.pipeline().get(XorEncoder::class.java)

encoder.key = message.key

logger.info { "Setting key ${message.key}" }
}

override fun channelReadComplete(ctx: ChannelHandlerContext) {
service.readIfNotFull(client)
ctx.flush()
}

override fun channelWritabilityChanged(ctx: ChannelHandlerContext) {
if (ctx.channel().isWritable) {
service.notifyIfNotEmpty(client)
}
}

override fun userEventTriggered(ctx: ChannelHandlerContext, event: Any) {
if (event is IdleStateEvent) {
ctx.close()
}
}

private companion object {
private val logger = InlineLogger()
}
}
Loading