jnetperf/src/main/java/biz/nellemann/jnetperf/Payload.java

139 lines
3.5 KiB
Java

/*
Copyright 2023 mark.nellemann@gmail.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package biz.nellemann.jnetperf;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
/**
*
* Datagram consists of the following
* <p>
* <------------------------- HEADER 32 bytes --------------> <---------- DATA bytes min 32, max 65475 -------->
* _long _int _int _long _long
* 8_bytes 4_bytes 4_bytes 8_bytes 8_bytes
* MAGIC-ID TYPE LENGTH CUR_PKT MAX_PKT
*
*/
public class Payload {
public final static int MIN_LENGTH = 64;
public final static int MAX_UDP_LENGTH = 64000;
public final static int DEFAULT_LENGTH = 1432;
public final static int HEADER_LENGTH = 32;
private final byte[] MAGIC_ID = "jPerfTok".getBytes(StandardCharsets.UTF_8); // Must be 8-bytes
private final int type;
private final int length;
private final long curPkt;
private final long maxPkt;
private final byte[] data;
/**
* Create new empty datagram
* @param type
* @param length
* @param currentPkt
*/
public Payload(int type, int length, long currentPkt, long maxPkt) {
this.type = type;
this.curPkt = currentPkt;
this.maxPkt = maxPkt;
this.length = length;
if (type == PayloadType.HANDSHAKE.getValue()) {
data = new byte[DEFAULT_LENGTH - HEADER_LENGTH];
} else {
data = new byte[length - HEADER_LENGTH];
}
}
/**
* Assemble datagram from byte[] payload
* @param payload
*/
public Payload(byte[] payload) {
this(ByteBuffer.wrap(payload));
}
/**
* Assemble datagram from ByteBuffer payload
* @param payload
*/
public Payload(ByteBuffer payload) {
byte[] id = new byte[8];
payload.get(id);
if(!Arrays.equals(id, MAGIC_ID)) {
System.out.println(Arrays.toString(id));
System.out.println(Arrays.toString(MAGIC_ID));
throw new RuntimeException("Datagram magic ID does not match: " + MAGIC_ID);
}
// Order is importent when assembling header fields like this
type = payload.getInt();
length = payload.getInt();
curPkt = payload.getLong();
maxPkt = payload.getLong();
data = new byte[payload.limit() - payload.position()];
payload.get(data);
}
public int getLength() {
return length;
}
public byte[] getPayload() {
ByteBuffer buffer = ByteBuffer.allocate(data.length + HEADER_LENGTH);
// Order is important
buffer.put(MAGIC_ID);
buffer.putInt(type);
buffer.putInt(length);
buffer.putLong(curPkt);
buffer.putLong(maxPkt);
buffer.put(data);
return buffer.array();
}
public int getType() {
return type;
}
public long getCurPkt() {
return curPkt;
}
public long getMaxPkt() {
return maxPkt;
}
}