summaryrefslogtreecommitdiff
path: root/src/main/kotlin/net/TransportLayerJavaNet.kt
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/kotlin/net/TransportLayerJavaNet.kt')
-rw-r--r--src/main/kotlin/net/TransportLayerJavaNet.kt95
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