diff --git a/src/main/java/org/fnet/mcrconapi/MalformedPacketException.java b/src/main/java/org/fnet/mcrconapi/MalformedPacketException.java new file mode 100644 index 0000000..58ff007 --- /dev/null +++ b/src/main/java/org/fnet/mcrconapi/MalformedPacketException.java @@ -0,0 +1,13 @@ +package org.fnet.mcrconapi; + +import java.io.IOException; + +public class MalformedPacketException extends IOException { + + private static final long serialVersionUID = -6409356862198025733L; + + public MalformedPacketException(String message) { + super(message); + } + +} diff --git a/src/main/java/org/fnet/mcrconapi/Packet.java b/src/main/java/org/fnet/mcrconapi/Packet.java index 9fda8c9..5b666eb 100644 --- a/src/main/java/org/fnet/mcrconapi/Packet.java +++ b/src/main/java/org/fnet/mcrconapi/Packet.java @@ -21,8 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. *******************************************************************************/ -package org.fnet.rcon; +package org.fnet.mcrconapi; +import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.nio.charset.Charset; @@ -46,6 +47,31 @@ public class Packet { private int type; private byte[] payload; + private Packet() { + } + + public static Packet readFrom(DataInputStream dataStream) throws IOException { + Packet packet = new Packet(); + packet.length = dataStream.readInt(); + if (packet.length < 10) + throw new MalformedPacketException("Packet length lower than ten (minimum package size)"); + packet.requestID = dataStream.readInt(); + packet.type = dataStream.readInt(); + if (packet.type != TYPE_LOGIN && packet.type != TYPE_AUTH_RESPONSE && packet.type != TYPE_COMMAND + && packet.type != TYPE_COMMAND_RESPONSE) + throw new MalformedPacketException("Packet type is none of allowed packet types"); + int payloadLength = packet.length - (Integer.BYTES * 2 + Byte.BYTES * 2); + packet.payload = new byte[payloadLength]; + for (int i = 0; i < payloadLength; i++) { + packet.payload[i] = dataStream.readByte(); + } + if (dataStream.readByte() != 0) + throw new MalformedPacketException("Payload terminator byte not zero"); + if (dataStream.readByte() != 0) + throw new MalformedPacketException("Packet terminator byte not zero"); + return packet; + } + /** * Generates a new packet with a type and a payload given. The length and * requestID are automatically generated where the requestID is a value that diff --git a/src/test/java/org/fnet/mcrconapi/PacketTest.java b/src/test/java/org/fnet/mcrconapi/PacketTest.java index 1a3cee3..e5b0eeb 100644 --- a/src/test/java/org/fnet/mcrconapi/PacketTest.java +++ b/src/test/java/org/fnet/mcrconapi/PacketTest.java @@ -21,15 +21,17 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. *******************************************************************************/ -package mcrconapi; +package org.fnet.mcrconapi; import static org.junit.Assert.*; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -import org.fnet.rcon.Packet; +import org.fnet.mcrconapi.Packet; import org.junit.Test; public class PacketTest { @@ -42,14 +44,14 @@ public class PacketTest { @Test public void testGetLength() { Packet packet = new Packet(0, "Test"); - assertTrue(packet.getLength() == 14); + assertEquals(14, packet.getLength()); } @Test public void testGetLengthAfterPayloadChange() { Packet packet = new Packet(0, "Test"); packet.setPayload("Teststring"); - assertTrue(packet.getLength() == 20); + assertEquals(20, packet.getLength()); } @Test @@ -71,7 +73,21 @@ public void testWriteTo() throws IOException { arrayStream.toByteArray()); } } - + + @Test + public void testWriteToNoPayload() throws IOException { + Packet packet = new Packet(3, ""); + // Set the request id so we don't have to get the current requestId + // counter value with reflections + packet.setRequestID(1); + try (ByteArrayOutputStream arrayStream = new ByteArrayOutputStream(packet.getLength()); + DataOutputStream dataStream = new DataOutputStream(arrayStream)) { + packet.writeTo(dataStream); + assertArrayEquals(new byte[] { 0, 0, 0, 10, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0 }, + arrayStream.toByteArray()); + } + } + @Test public void testAsciiEncoding() { Packet packet = new Packet(0, "�a"); @@ -79,4 +95,53 @@ public void testAsciiEncoding() { assertEquals('a', packet.getPayloadAsString().charAt(1)); } + @Test + public void testReadFrom() throws IOException { + byte[] packetData = new byte[] { 0, 0, 0, 14, 0, 0, 0, 1, 0, 0, 0, 3, 84, 101, 115, 116, 0, 0 }; + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(packetData); + DataInputStream dataStream = new DataInputStream(inputStream)) { + Packet packet = Packet.readFrom(dataStream); + assertEquals(14, packet.getLength()); + assertEquals(1, packet.getRequestID()); + assertEquals(3, packet.getType()); + assertEquals("Test", packet.getPayloadAsString()); + } + } + + @Test(expected = MalformedPacketException.class) + public void testReadFromThrowsExceptionOnWrongType() throws IOException { + byte[] packetData = new byte[] { 0, 0, 0, 14, 0, 0, 0, 1, 0, 0, 0, 4, 84, 101, 115, 116, 0, 0 }; + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(packetData); + DataInputStream dataStream = new DataInputStream(inputStream)) { + Packet.readFrom(dataStream); + } + } + + @Test(expected = MalformedPacketException.class) + public void testReadFromThrowsExceptionIfLengthTooShort() throws IOException { + byte[] packetData = new byte[] { 0, 0, 0, 13, 0, 0, 0, 1, 0, 0, 0, 3, 84, 101, 115, 116, 0, 0 }; + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(packetData); + DataInputStream dataStream = new DataInputStream(inputStream)) { + Packet.readFrom(dataStream); + } + } + + @Test(expected = MalformedPacketException.class) + public void testReadFromThrowsExceptionIfLengthTooShort2() throws IOException { + byte[] packetData = new byte[] { 0, 0, 0, 9, 0, 0, 0, 1, 0, 0, 0, 3, 84, 101, 115, 116, 0, 0 }; + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(packetData); + DataInputStream dataStream = new DataInputStream(inputStream)) { + Packet.readFrom(dataStream); + } + } + + @Test(expected = IOException.class) + public void testReadFromThrowsExceptionIfLengthTooLong() throws IOException { + byte[] packetData = new byte[] { 0, 0, 0, 15, 0, 0, 0, 1, 0, 0, 0, 3, 84, 101, 115, 116, 0, 0 }; + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(packetData); + DataInputStream dataStream = new DataInputStream(inputStream)) { + Packet.readFrom(dataStream); + } + } + }