implement PING Netop
This commit is contained in:
parent
2c064fe15c
commit
d907ff138a
|
@ -0,0 +1,65 @@
|
||||||
|
package org.hso.texturesyncclient.controller.net
|
||||||
|
|
||||||
|
import com.google.gson.*
|
||||||
|
import java.io.*
|
||||||
|
import java.lang.Exception
|
||||||
|
import java.net.*
|
||||||
|
|
||||||
|
@Suppress("MemberVisibilityCanBePrivate")
|
||||||
|
class Connection(val addr: InetAddress, val port: Int = 10796) : Closeable {
|
||||||
|
|
||||||
|
var socket: Socket? = null
|
||||||
|
var output: DataOutputStream? = null
|
||||||
|
var input: DataInputStream? = null
|
||||||
|
|
||||||
|
@Throws(IOException::class)
|
||||||
|
private fun getStreams(): Pair<DataInputStream, DataOutputStream> {
|
||||||
|
val i: DataInputStream
|
||||||
|
val o: DataOutputStream
|
||||||
|
|
||||||
|
if (socket == null || !socket!!.isConnected) {
|
||||||
|
val sock = Socket(addr, port)
|
||||||
|
i = DataInputStream(BufferedInputStream(sock.getInputStream()))
|
||||||
|
o = DataOutputStream(BufferedOutputStream(sock.getOutputStream()))
|
||||||
|
|
||||||
|
input = i
|
||||||
|
output = o
|
||||||
|
socket = sock
|
||||||
|
} else {
|
||||||
|
i = input!!
|
||||||
|
o = output!!
|
||||||
|
}
|
||||||
|
|
||||||
|
return Pair(i, o)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(IOException::class)
|
||||||
|
fun ping() {
|
||||||
|
val io = getStreams()
|
||||||
|
|
||||||
|
val obj = JsonObject()
|
||||||
|
obj.add("ping", JsonObject())
|
||||||
|
|
||||||
|
JsonPacket(obj).write(io.second)
|
||||||
|
|
||||||
|
when (Packet.read(io.first)) {
|
||||||
|
is JsonPacket -> return
|
||||||
|
is ErrorPacket -> throw Exception("TODO")
|
||||||
|
is BinaryPacket -> throw Exception("TODO")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(IOException::class)
|
||||||
|
override fun close() {
|
||||||
|
if (output != null) {
|
||||||
|
output!!.close()
|
||||||
|
}
|
||||||
|
if (input != null) {
|
||||||
|
input!!.close()
|
||||||
|
}
|
||||||
|
if (socket != null) {
|
||||||
|
socket!!.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,167 @@
|
||||||
|
package org.hso.texturesyncclient.controller.net
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import com.google.gson.JsonParseException
|
||||||
|
import com.google.gson.JsonParser
|
||||||
|
import java.io.DataInputStream
|
||||||
|
import java.io.DataOutputStream
|
||||||
|
import java.io.IOException
|
||||||
|
import java.lang.Exception
|
||||||
|
|
||||||
|
open class PacketException(msg: String) : Exception(msg)
|
||||||
|
class PacketTooLongException : PacketException("The Package is too long.")
|
||||||
|
class PacketInvalidType : PacketException("The Package has an Invalid Type.")
|
||||||
|
class PacketInvalidData : PacketException("The Package has an Invalid Data. (e.g. Invalid Json.)")
|
||||||
|
|
||||||
|
abstract class Packet {
|
||||||
|
|
||||||
|
@Throws(IOException::class)
|
||||||
|
abstract fun write(out: DataOutputStream)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
const val TYPE_ERROR: Byte = 0
|
||||||
|
protected const val TYPE_ERROR_MAX_PAYLOAD: Int = 1024
|
||||||
|
|
||||||
|
const val TYPE_JSON: Byte = 1
|
||||||
|
protected const val TYPE_JSON_MAX_PAYLOAD: Int = 16 * 1024 * 1024
|
||||||
|
|
||||||
|
const val TYPE_BINARY: Byte = 2
|
||||||
|
protected const val TYPE_BINARY_MAX_PAYLOAD: Int = 512 * 1024 * 1024
|
||||||
|
|
||||||
|
@Throws(PacketException::class, IOException::class)
|
||||||
|
fun read(input: DataInputStream): Packet {
|
||||||
|
// Type Byte
|
||||||
|
val type = input.readByte()
|
||||||
|
|
||||||
|
// 3 Reserved Bytes
|
||||||
|
input.readByte()
|
||||||
|
input.readByte()
|
||||||
|
input.readByte()
|
||||||
|
|
||||||
|
// 4 Len Bytes
|
||||||
|
val length = input.readInt()
|
||||||
|
|
||||||
|
when (type) {
|
||||||
|
TYPE_ERROR -> if (length > TYPE_ERROR_MAX_PAYLOAD) {
|
||||||
|
throw PacketTooLongException()
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPE_JSON -> if (length > TYPE_JSON_MAX_PAYLOAD) {
|
||||||
|
throw PacketTooLongException()
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPE_BINARY -> if (length > TYPE_BINARY_MAX_PAYLOAD) {
|
||||||
|
throw PacketTooLongException()
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> throw PacketInvalidType()
|
||||||
|
}
|
||||||
|
|
||||||
|
val payload = ByteArray(length)
|
||||||
|
input.readFully(payload)
|
||||||
|
|
||||||
|
when (type) {
|
||||||
|
TYPE_ERROR -> {
|
||||||
|
val msg = String(payload)
|
||||||
|
val results = msg.split(' ', ignoreCase = false, limit = 2)
|
||||||
|
|
||||||
|
return if (results.size == 2) {
|
||||||
|
val code = results[0].toIntOrNull()
|
||||||
|
|
||||||
|
if (code == null) {
|
||||||
|
ErrorPacket(0, msg)
|
||||||
|
} else {
|
||||||
|
ErrorPacket(code, results[1])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ErrorPacket(0, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPE_JSON -> {
|
||||||
|
try {
|
||||||
|
val obj = JsonParser().parse(String(payload)).asJsonObject
|
||||||
|
|
||||||
|
return JsonPacket(obj)
|
||||||
|
} catch (e: JsonParseException) {
|
||||||
|
throw PacketInvalidData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPE_BINARY -> {
|
||||||
|
return BinaryPacket(payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
// Unreachable
|
||||||
|
throw PacketInvalidType()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
data class JsonPacket(val content: JsonObject) : Packet() {
|
||||||
|
override fun write(out: DataOutputStream) {
|
||||||
|
val payload = content.toString().toByteArray()
|
||||||
|
// Tag Byte
|
||||||
|
out.writeByte(TYPE_JSON.toInt())
|
||||||
|
|
||||||
|
// 3 Reserved Bytes
|
||||||
|
out.writeByte(0x42)
|
||||||
|
out.writeByte(0x42)
|
||||||
|
out.writeByte(0x42)
|
||||||
|
|
||||||
|
// Length of Payload
|
||||||
|
out.writeInt(payload.size)
|
||||||
|
|
||||||
|
// Payload
|
||||||
|
out.write(payload)
|
||||||
|
|
||||||
|
out.flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("MemberVisibilityCanBePrivate")
|
||||||
|
class BinaryPacket(val content: ByteArray) : Packet() {
|
||||||
|
override fun write(out: DataOutputStream) {
|
||||||
|
// Tag Byte
|
||||||
|
out.writeByte(TYPE_BINARY.toInt())
|
||||||
|
|
||||||
|
// 3 Reserved Bytes
|
||||||
|
out.writeByte(0x42)
|
||||||
|
out.writeByte(0x42)
|
||||||
|
out.writeByte(0x42)
|
||||||
|
|
||||||
|
// Length of Payload
|
||||||
|
out.writeInt(content.size)
|
||||||
|
|
||||||
|
// Payload
|
||||||
|
out.write(content)
|
||||||
|
|
||||||
|
out.flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class ErrorPacket(val code: Int, val message: String) : Packet() {
|
||||||
|
override fun write(out: DataOutputStream) {
|
||||||
|
val payload = "$code $message".toByteArray()
|
||||||
|
// Tag Byte
|
||||||
|
out.writeByte(TYPE_ERROR.toInt())
|
||||||
|
|
||||||
|
// 3 Reserved Bytes
|
||||||
|
out.writeByte(0x42)
|
||||||
|
out.writeByte(0x42)
|
||||||
|
out.writeByte(0x42)
|
||||||
|
|
||||||
|
// Length of Payload
|
||||||
|
out.writeInt(payload.size)
|
||||||
|
|
||||||
|
// Payload
|
||||||
|
out.write(payload)
|
||||||
|
|
||||||
|
out.flush()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package org.hso.texturesyncclient.controller.net
|
||||||
|
|
||||||
|
import java.net.*
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
// Just some test code.
|
||||||
|
|
||||||
|
val con = Connection(InetAddress.getByName("::1"))
|
||||||
|
|
||||||
|
con.ping()
|
||||||
|
|
||||||
|
con.close()
|
||||||
|
}
|
Loading…
Reference in New Issue