diff options
Diffstat (limited to 'src/main/kotlin/net/TransportLayerJavaNet.kt')
-rw-r--r-- | src/main/kotlin/net/TransportLayerJavaNet.kt | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/src/main/kotlin/net/TransportLayerJavaNet.kt b/src/main/kotlin/net/TransportLayerJavaNet.kt new file mode 100644 index 0000000..3d2867a --- /dev/null +++ b/src/main/kotlin/net/TransportLayerJavaNet.kt @@ -0,0 +1,95 @@ +package net + +import nineAddressToValues +import java.io.InputStream +import java.io.OutputStream +import java.net.Socket +import kotlin.math.min + +/* +TODO: + - add TLS support +*/ + +/** + * An implementation of [TransportLayer] written using the [java.net] package. + */ +class TransportLayerJavaNet(val address: String, val port: UShort) : TransportLayer { + /** + * The connection's socket. + */ + private val socket: Socket = Socket(this.address, this.port.toInt()) + + /** + * The connection's input stream. + */ + private val inStream: InputStream = this.socket.inputStream + + /** + * The connection's output stream. + */ + private val outStream: OutputStream = this.socket.outputStream + + constructor(fullAddress: String) : this(nineAddressToValues(fullAddress).first, nineAddressToValues(fullAddress).second) + + private class InStreamIterator(val inStream: InputStream) : Iterator<UByte> { + override fun next(): UByte { + return this.inStream.readNBytes(1).first().toUByte() + } + + override fun hasNext(): Boolean { + return this.inStream.available() > 0 + } + } + + override fun close() { + if (this.socket.isClosed) { + return + } + this.socket.close() + } + + override fun transmit(payload: Iterable<UByte>) { + val payload = payload.toList() + val bytes = ByteArray(payload.size, { i -> payload[i].toByte() }) + this.outStream.write(bytes) + } + +/* + override fun receiveUntil(untilByte: UByte): Array<UByte> { + var stop = false + val payload: Array<UByte> = MutableList(0, { 0 }) + while (!stop) { + val b = this.inStream.readNBytes(1)[0] + if (b == untilByte) { + stop = true + continue + } else { + payload.add(b) + } + } + return payload + } +*/ + + override fun receive(length: ULong): Array<UByte> { + var length = length + val intMax = Int.MAX_VALUE.toULong() + val bytes: MutableList<Byte> = MutableList(0) { 0 } + // readNBytes only takes Int values, so it must be called multiple times if the length is greater than Int's + // maximum value + while (length > 0u) { + // the min function ensures that the value passed to readNBytes never exceeds Int's maximum value while also + // switching to the length variable when its value eventually becomes less than Int's maximum value, which + // avoids writing duplicated readNBytes calls in the code + val lenMin = min(length, intMax) + bytes += this.inStream.readNBytes(lenMin.toInt()).toMutableList() + length -= intMax + } + return Array(bytes.size) { i -> bytes[i].toUByte() } + } + + override fun receiver(): Iterable<UByte> { + return Iterable { InStreamIterator(this.inStream) } + } +}
\ No newline at end of file |