diff options
author | Edoardo La Greca | 2025-08-01 16:53:52 +0200 |
---|---|---|
committer | Edoardo La Greca | 2025-08-01 16:53:52 +0200 |
commit | 391de1ffbd961f7ae6bc4e489975ed0a645e0089 (patch) | |
tree | 84a28da2f75a689c807aa056b7cb73118b97ce45 /src/main/kotlin | |
parent | 4050df8178def9df2107bab3d49ae97282f79e53 (diff) |
fix types
Diffstat (limited to 'src/main/kotlin')
-rw-r--r-- | src/main/kotlin/IPAddress.kt | 10 | ||||
-rw-r--r-- | src/main/kotlin/NetworkPacketTransporter.kt | 10 | ||||
-rw-r--r-- | src/main/kotlin/NetworkPacketTransporterJavaNet.kt | 23 | ||||
-rw-r--r-- | src/main/kotlin/NinePConnection.kt | 47 | ||||
-rw-r--r-- | src/main/kotlin/NinePMessage.kt | 27 | ||||
-rw-r--r-- | src/main/kotlin/NinePMessageType.kt | 58 | ||||
-rw-r--r-- | src/main/kotlin/NinePTranslator.kt | 2 |
7 files changed, 97 insertions, 80 deletions
diff --git a/src/main/kotlin/IPAddress.kt b/src/main/kotlin/IPAddress.kt index 58d0aae..8eb7414 100644 --- a/src/main/kotlin/IPAddress.kt +++ b/src/main/kotlin/IPAddress.kt @@ -2,7 +2,7 @@ * An IP address (v4 or v6). */ class IPAddress { - private var address: Array<Byte> + private var address: Array<UByte> private var is4: Boolean /** @@ -19,15 +19,15 @@ class IPAddress { val split4 = address.split('.') val split6 = address.split(':') - val bytes: List<Byte> + val bytes: List<UByte> if (this.is4) { - bytes = split4.map { it.toByte(10) } + bytes = split4.map { it.toUByte(10) } } else { val shorts = split6.map { it.toShort(16) } bytes = shorts.flatMap { listOf( - it.toInt().shr(8).toByte(), - it.toInt().and(0x00FF).toByte() + it.toInt().and(0xFF00).shr(0x08).toUByte(), + it.toInt().and(0x00FF).toUByte() ) } } diff --git a/src/main/kotlin/NetworkPacketTransporter.kt b/src/main/kotlin/NetworkPacketTransporter.kt index 4b11967..e12a6ac 100644 --- a/src/main/kotlin/NetworkPacketTransporter.kt +++ b/src/main/kotlin/NetworkPacketTransporter.kt @@ -10,7 +10,7 @@ import java.io.Closeable * if the remote address is a domain name, but it cannot be resolved. * * Depending on the specific given implementation, the constructor of this class might throw other exceptions (e.g. the - * [Socket] constructor from [java.net] in [NetworkPacketTransporterJavaNet]). + * [java.net.Socket] constructor in [NetworkPacketTransporterJavaNet]). */ abstract class NetworkPacketTransporter : Closeable { val address: String @@ -48,8 +48,8 @@ abstract class NetworkPacketTransporter : Closeable { * * @throws java.io.IOException if the message could not be correctly transmitted. */ - abstract fun transmit(payload: List<Byte>) + abstract fun transmit(payload: Array<UByte>) /** * Receive a payload until a byte occurs, which marks the end of the message. The byte is discarded after being read * and is not returned. @@ -64,11 +64,11 @@ abstract class NetworkPacketTransporter : Closeable { abstract fun receiveUntil(untilByte: Byte): List<Byte> /** - * Receive a payload with fixed length. + * Receive a payload with fixed length. If zero, nothing is read. * * @param length The length of the message in bytes. - * + * @return the received payload. * @throws java.io.IOException if the message could not be correctly received. */ - abstract fun receiveFixed(length: ULong): List<Byte> + abstract fun receive(length: ULong): Array<UByte> }
\ No newline at end of file diff --git a/src/main/kotlin/NetworkPacketTransporterJavaNet.kt b/src/main/kotlin/NetworkPacketTransporterJavaNet.kt index 6badc3d..6855604 100644 --- a/src/main/kotlin/NetworkPacketTransporterJavaNet.kt +++ b/src/main/kotlin/NetworkPacketTransporterJavaNet.kt @@ -1,6 +1,7 @@ import java.io.InputStream import java.io.OutputStream import java.net.Socket +import kotlin.math.min /* TODO: @@ -36,8 +37,9 @@ class NetworkPacketTransporterJavaNet : NetworkPacketTransporter { this.socket.close() } - override fun transmit(payload: List<Byte>) { - this.outStream.write(payload.toByteArray()) + override fun transmit(payload: Array<UByte>) { + val bytes = ByteArray(payload.size) { i -> payload[i].toByte() } + this.outStream.write(bytes) } override fun receiveUntil(untilByte: Byte): List<Byte> { @@ -55,7 +57,20 @@ class NetworkPacketTransporterJavaNet : NetworkPacketTransporter { return payload } - override fun receiveFixed(length: ULong): List<Byte> { - return this.inStream.readNBytes(length.toInt()).toList() + 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() } } }
\ No newline at end of file diff --git a/src/main/kotlin/NinePConnection.kt b/src/main/kotlin/NinePConnection.kt index 5adb35b..13e2ecf 100644 --- a/src/main/kotlin/NinePConnection.kt +++ b/src/main/kotlin/NinePConnection.kt @@ -42,24 +42,21 @@ class NinePConnection(netPackTrans: NetworkPacketTransporter) : NinePTranslator } /** - * Read an [nBytes]-long unsigned integer number from the connection. + * Read an [len] bytes long unsigned integer number from the connection. * * In 9P, binary numbers (non-textual) are specified in little-endian order (least significant byte first). * - * @param nBytes The length of the integer number in bytes. It only works with unsigned numbers strictly greater - * than zero (zero is excluded). - * @return The number's value. - * @throws IllegalArgumentException if [nBytes] is zero or negative. + * @param len The length of the integer number in bytes. If zero, nothing is read. + * @return the number's value. + * @throws java.io.IOException if the message could not be correctly received. */ - private fun readInteger(nBytes: Int): BigInteger { - require(nBytes > 0) - val bytes = this.npt.receiveFixed(nBytes.toULong()) - var number: BigInteger = BigInteger.valueOf(0) + private fun readInteger(len: ULong): BigInteger { + val bytes = this.npt.receive(len) + var value = 0.toBigInteger() for (i in 0..<bytes.size) { - number += bytes[i].toInt().toBigInteger().shl(i) + value += bytes[i].toInt().toBigInteger().shl(i*8) } - - return number + return value } /** @@ -80,12 +77,13 @@ class NinePConnection(netPackTrans: NetworkPacketTransporter) : NinePTranslator * * @return A triple in which the first element is the message size in bytes, the second is the message type as a * [NinePMessageType] constant, and the third element is the message tag. + * @throws java.io.IOException if the message could not be correctly received. */ private fun readSizeTypeTag(): Triple<UInt, NinePMessageType, UShort> { return Triple( - readInteger(4).toInt().toUInt(), - NinePMessageType.fromByte(readInteger(1).toByte()), - readInteger(2).toInt().toUShort() + readInteger(4u).toInt().toUInt(), + NinePMessageType.fromByte(readInteger(1u).toByte().toUByte()), + readInteger(2u).toShort().toUShort() ) } @@ -118,16 +116,17 @@ class NinePConnection(netPackTrans: NetworkPacketTransporter) : NinePTranslator /** * Read a 9P message of type Rerror, after the message size and type have already been read. * - * @return A pair of: (1) the message tag and (2) the error message + * @return A pair of: (1) the message tag and (2) the error message. + * @throws java.io.IOException if the message could not be correctly received. */ - private fun readError(): Pair<SizedMessageField, String> { - val tag = readInteger(2) + private fun readError(): Pair<UShort, String> { + val tag = readInteger(2u).toInt().toUShort() val error = readString() - return Pair(SizedMessageField(2, tag), error) + return Pair(tag, error) } /** - * Send 9P request and check for exceptions or a Rerror response. + * Send 9P request and check for exceptions or an Rerror response. */ private fun responseError(msg: NinePMessage): String? { try { @@ -143,10 +142,10 @@ class NinePConnection(netPackTrans: NetworkPacketTransporter) : NinePTranslator return null } - override fun version(msize: SizedMessageField, version: String): String? { + override fun version(msize: UInt, version: String): String? { val msg = NinePMessage(NinePMessageType.TVERSION, this.NOTAG, listOf("msize", "version"), mapOf( - "msize" to msize + "msize" to BigInteger(msize.toString()) ), mapOf( "version" to version @@ -157,10 +156,10 @@ class NinePConnection(netPackTrans: NetworkPacketTransporter) : NinePTranslator if (error != null) { return error } - val rmsize = readInteger(4) + val rmsize = readInteger(4u).toInt().toUInt() val rversion = readString() // this check should not be necessary, but you never know - this.maxSize = ( if (rmsize < msize.value) msize.value else rmsize ).toInt().toUInt() + this.maxSize = ( if (rmsize < msize) msize else rmsize ) if (rversion == "unknown") { return "Unknown version." } diff --git a/src/main/kotlin/NinePMessage.kt b/src/main/kotlin/NinePMessage.kt index 87d59a5..225ec45 100644 --- a/src/main/kotlin/NinePMessage.kt +++ b/src/main/kotlin/NinePMessage.kt @@ -1,3 +1,4 @@ +import java.math.BigInteger import kotlin.math.pow /** @@ -13,7 +14,7 @@ import kotlin.math.pow * @param fieldValuesInt A map of each field name into its value. This map only stores integer values. * @param fieldValuesStr A map of each field name into its value. This map only stores string values. */ -class NinePMessage(val type: NinePMessageType, val tag: UShort, val fieldNames: List<String>, val fieldValuesInt: Map<String, SizedMessageField>, val fieldValuesStr: Map<String, String>, val maxSize: UInt) { +class NinePMessage(val type: NinePMessageType, val tag: UShort, val fieldNames: List<String>, val fieldValuesInt: Map<String, BigInteger>, val fieldValuesStr: Map<String, String>, val maxSize: UInt) { /** * Intersection between [fieldNames] and [fieldValuesInt]. In other words: the amount of integer fields that are * going to be used when writing the message. @@ -37,11 +38,11 @@ class NinePMessage(val type: NinePMessageType, val tag: UShort, val fieldNames: require(insecInts.size == fieldNames.size - insecStrs.size) val totalSize = size() - if (totalSize > this.maxSize.toLong()) { + if (totalSize > this.maxSize) { throw IllegalArgumentException("Message size exceeded.") } writeMessageSizeType(npt, totalSize, type) - writeInteger(npt, SizedMessageField(2, tag.toInt().toBigInteger())) + writeInteger(npt, tag.toInt().toBigInteger()) for (field in fieldNames) { if (field in insecInts) { writeInteger(npt, fieldValuesInt[field]!!) @@ -59,8 +60,9 @@ class NinePMessage(val type: NinePMessageType, val tag: UShort, val fieldNames: * @param npt The networking API. * @param value The number's value. [SizedMessageField] defines both its actual value and its size. */ - private fun writeInteger(npt: NetworkPacketTransporter, value: SizedMessageField) { - npt.transmit(value.value.toByteArray().toList()) + private fun writeInteger(npt: NetworkPacketTransporter, value: BigInteger) { + val bytes = value.toByteArray() + npt.transmit(Array(bytes.size) { i -> bytes[i].toUByte() }) } /** @@ -75,8 +77,9 @@ class NinePMessage(val type: NinePMessageType, val tag: UShort, val fieldNames: */ private fun writeString(npt: NetworkPacketTransporter, value: String) { require(value.length <= 2.0.pow(16.0) - 1) - writeInteger(npt, SizedMessageField(2, value.length.toBigInteger())) - npt.transmit(value.toByteArray().toList()) + writeInteger(npt, value.length.toBigInteger()) + val bytes = value.toByteArray() + npt.transmit(Array(bytes.size) { i -> bytes[i].toUByte() }) } /** @@ -86,15 +89,15 @@ class NinePMessage(val type: NinePMessageType, val tag: UShort, val fieldNames: * @param size The total message size, including the 4 bytes of this parameter and the type's byte. * @param type The 9P message type as a [NinePMessageType] constant. */ - private fun writeMessageSizeType(npt: NetworkPacketTransporter, size: Int, type: NinePMessageType) { - writeInteger(npt, SizedMessageField(4, size.toBigInteger())) - writeInteger(npt, SizedMessageField(1, type.value.toInt().toBigInteger())) + private fun writeMessageSizeType(npt: NetworkPacketTransporter, size: UInt, type: NinePMessageType) { + writeInteger(npt, size.toInt().toBigInteger()) + writeInteger(npt, type.value.toInt().toBigInteger()) } /** * Calculate the expected size of the message. */ - fun size(): Int { - return 4 + 1 + 2 + this.insecInts.sumOf { this.fieldValuesInt[it]!!.size } + this.insecStrs.sumOf { 2 + this.fieldValuesStr[it]!!.length } + fun size(): UInt { + return 4u + 1u + 2u + this.insecInts.sumOf { this.fieldValuesInt[it]!!.bitLength().toUInt() } + this.insecStrs.sumOf { 2u + this.fieldValuesStr[it]!!.length.toUInt() } } }
\ No newline at end of file diff --git a/src/main/kotlin/NinePMessageType.kt b/src/main/kotlin/NinePMessageType.kt index c18e7e9..fadd0fe 100644 --- a/src/main/kotlin/NinePMessageType.kt +++ b/src/main/kotlin/NinePMessageType.kt @@ -1,34 +1,34 @@ -enum class NinePMessageType(val value: Byte) { - TVERSION(100), - RVERSION(101), - TAUTH(102), - RAUTH(103), - TATTACH(104), - RATTACH(105), +enum class NinePMessageType(val value: UByte) { + TVERSION(100u), + RVERSION(101u), + TAUTH(102u), + RAUTH(103u), + TATTACH(104u), + RATTACH(105u), //TERROR(106), <--- illegal - RERROR(107), - TFLUSH(108), - RFLUSH(109), - TWALK(110), - RWALK(111), - TOPEN(112), - ROPEN(113), - TCREATE(114), - RCREATE(115), - TREAD(116), - RREAD(117), - TWRITE(118), - RWRITE(119), - TCLUNK(120), - RCLUNK(121), - TREMOVE(122), - RREMOVE(123), - TSTAT(124), - RSTAT(125), - TWSTAT(126), - RWSTAT(127); + RERROR(107u), + TFLUSH(108u), + RFLUSH(109u), + TWALK(110u), + RWALK(111u), + TOPEN(112u), + ROPEN(113u), + TCREATE(114u), + RCREATE(115u), + TREAD(116u), + RREAD(117u), + TWRITE(118u), + RWRITE(119u), + TCLUNK(120u), + RCLUNK(121u), + TREMOVE(122u), + RREMOVE(123u), + TSTAT(124u), + RSTAT(125u), + TWSTAT(126u), + RWSTAT(127u); companion object { - fun fromByte(value: Byte) = NinePMessageType.entries.first { it.value == value } + fun fromByte(value: UByte) = NinePMessageType.entries.first { it.value == value } } }
\ No newline at end of file diff --git a/src/main/kotlin/NinePTranslator.kt b/src/main/kotlin/NinePTranslator.kt index a42ea3c..02c8ef4 100644 --- a/src/main/kotlin/NinePTranslator.kt +++ b/src/main/kotlin/NinePTranslator.kt @@ -24,7 +24,7 @@ interface NinePTranslator { * @param version Should be "9P2000", which is the only defined value. * @return a possible error. */ - fun version(msize: SizedMessageField, version: String): String? + fun version(msize: UInt, version: String): String? /** * Perform authentication. |