import java.io.IOException import java.math.BigInteger /** * This class represents a 9P connection. It provides a practical implementation with networking to the 9P methods * described in [NinePTranslator]. Details about methods related to 9P can be found in [NinePTranslator]. Remember to * disconnect using [disconnect] after use. * * Details about network-related topics can be found in [NetworkPacketTransporter] and the implementation of choice. * * Details about 9P messages and methods can be found in [NinePTranslator]. * * @param netPackTrans The networking API backend of choice. * * @throws UnresolvableHostException if the host resolution made by [netPackTrans] failed. */ class NinePConnection(netPackTrans: NetworkPacketTransporter) : NinePTranslator { /** * Networking API. */ val npt: NetworkPacketTransporter = netPackTrans /** * Disconnect from the remote host, * * @throws IOException if an I/O error occurred while closing the socket. */ fun disconnect() { this.npt.close() } /** * Read an [nBytes]-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. */ private fun readInteger(nBytes: Int): BigInteger { require(nBytes > 0) val bytes = this.npt.receiveFixed(nBytes.toULong()) var number: BigInteger = BigInteger.valueOf(0) for (i in 0.. { return Triple( readInteger(4).toInt().toUInt(), NinePMessageType.fromByte(readInteger(1).toByte()), readInteger(2).toInt().toUInt() ) } // TODO: implement methods from NinePTranslator /** * Wait for a 9P message with the same tag from the server. * * All messages prior to the returned one are discarded. * * @param tag The tag to wait for. * @return A pair of (1) the size and (2) the type of the message that matches the given tag. */ private fun waitForTag(tag: UInt): Pair { var s = 0u var ty: NinePMessageType? = null var ta = 0u var found = false while (!found) { val stt = readSizeTypeTag() s = stt.first ty = stt.second ta = stt.third if (ta == tag) { found = true } } return Pair(s, ty ?: NinePMessageType.RERROR) } /** * 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 */ private fun readError(): Pair { val tag = readInteger(2) val error = readString() return Pair(SizedMessageField(2, tag), error) } }