-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPacketHandler.java
More file actions
244 lines (218 loc) · 6.78 KB
/
PacketHandler.java
File metadata and controls
244 lines (218 loc) · 6.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
import java.nio.ByteBuffer;
import java.util.zip.CRC32;
import java.util.zip.Checksum;
/**
* This class handles packets management
* @author Diga W
*
*/
class PacketHandler {
public final static int MAX_PACKET_SIZE = 1000;
public final static int MAX_PAYLOAD_LENGTH = 981;
// private final static int HEADER_LENGTH = 11;
private final static int OFFSET_SEQ_NO = 0;
private final static int OFFSET_ACK_NO = 4;
private final static int OFFSET_FLAGS = 8;
private final static int OFFSET_DATA_LENGTH = 9;
private final static int OFFSET_DATA = 11;
private final static int OFFSET_CHECKSUM = 992;
/**
* Create a general outgoing packet
* @param data
* @param argDataLength
* @param seqNo
* @return
*/
public byte[] createOutgoingPacket(
byte[] data, int argDataLength, int seqNo) {
return createPacket(data, argDataLength, seqNo, 0, false, false, false);
}
/**
* Create a SYN-flagged packet
* @param data
* @param argDataLength
* @param seqNo
* @return
*/
public byte[] createSynPacket(byte[] data, int argDataLength, int seqNo) {
return createPacket(data, argDataLength, seqNo, 0, true, false, false);
}
/**
* Create a ACK-flagged packet
* @param ackNo
* @return
*/
public byte[] createAckPacket(int ackNo) {
return createPacket(new byte[0], 0, 0, ackNo, false, true, false);
}
/**
* Create a FIN-flagged packet
* @param data
* @param argDataLength
* @param seqNo
* @return
*/
public byte[] createFinPacket(int seqNo) {
return createPacket(new byte[0], 0, seqNo, 0, false, false, true);
}
public byte[] createAckFinPacket(int ackNo) {
return createPacket(new byte[0], 0, 0, ackNo, false, true, true);
}
/**
* The generic method to create an outgoing packet with the arguments given
* @param data
* @param argDataLength
* @param seqNo
* @param ackNo
* @param isSyn
* @param isAck
* @param isFin
* @return
*/
private byte[] createPacket(byte[] data, int argDataLength,
int seqNo, int ackNo,
boolean isSyn, boolean isAck, boolean isFin) {
if (data.length > MAX_PAYLOAD_LENGTH ||
argDataLength > MAX_PAYLOAD_LENGTH) {
throw new IllegalArgumentException(
"Data length cannot exceed MAX_PAYLOAD_LENGTH");
}
byte flags = 0;
flags = (byte) (isSyn ? flags | 1 : flags | 0);
flags = (byte) (isAck ? flags | 2 : flags | 0);
flags = (byte) (isFin ? flags | 4 : flags | 0);
short dataLength = (short)argDataLength;
byte[] buffer = ByteBuffer.allocate(OFFSET_CHECKSUM)
.putInt(seqNo)
.putInt(ackNo)
.put(flags)
.putShort(dataLength)
.put(data)
.array();
Checksum crc32 = new CRC32();
crc32.update(buffer, 0, OFFSET_CHECKSUM);
long rawChecksum = crc32.getValue();
byte[] checksum = ByteBuffer.allocate(8).putLong(rawChecksum).array();
byte[] packet = new byte[MAX_PACKET_SIZE];
System.arraycopy(buffer, 0, packet, 0, OFFSET_CHECKSUM);
System.arraycopy(checksum, 0, packet, OFFSET_CHECKSUM, 8);
return packet;
}
/**
* Get the payload of the packet
* @param packet
* @return
*/
public byte[] getPayload(byte[] packet) {
short dataLength =
ByteBuffer.wrap(packet, OFFSET_DATA_LENGTH, 2).getShort();
byte[] data = new byte[dataLength];
ByteBuffer.wrap(packet, OFFSET_DATA, dataLength).get(data);
return data;
}
/**
* Checks if the packet's checksum matches the content and if
* the acknowledgement number is correct
* @param packet
* @param ackNo
* @return
*/
public boolean isCorruptedReply(byte[] packet, int ackNo) {
return !(isGood(packet) && isCorrectAck(packet, ackNo));
}
/**
* Checks if the packet's checksum matches the content and if
* the sequence number is not duplicate of previously received packet
* @param packet
* @param seqNo
* @return
*/
public boolean isCorruptedOrDuplicate(byte[] packet, int seqNo) {
return !(isGood(packet) && isCorrectSeq(packet, seqNo));
}
/**
* Checks whether the packet is corrupted or not by checking the checksum
* @param packet
* @return false if packet is corrupted, true otherwise
*/
public boolean isGood(byte[] packet) {
Checksum crc32 = new CRC32();
crc32.update(packet, 0, OFFSET_CHECKSUM);
long rawChecksum = crc32.getValue();
long checksum = ByteBuffer.wrap(packet, OFFSET_CHECKSUM, 8).getLong();
return rawChecksum == checksum;
}
/**
* Checks if the sequence number on the packet is the same as supplied
* @param packet
* @param seqNo
* @return
*/
private boolean isCorrectSeq(byte[] packet, int seqNo) {
int rawSeqNo = getSeqNo(packet);
return rawSeqNo == seqNo;
}
/**
* Checks if the ACK number on the packet is the same as supplied
* @param packet
* @param ackNo
* @return
*/
private boolean isCorrectAck(byte[] packet, int ackNo) {
int rawAckNo = getAckNo(packet);
return rawAckNo == ackNo;
}
/**
* Get the sequence number from the header of the packet
* @param packet
* @return
*/
public int getSeqNo(byte[] packet) {
int seqNo = ByteBuffer.wrap(packet, OFFSET_SEQ_NO, 4).getInt();
return seqNo;
}
/**
* Get the ACK number from the header of the packet
* @param packet
* @return
*/
public int getAckNo(byte[] packet) {
int ackNo = ByteBuffer.wrap(packet, OFFSET_ACK_NO, 4).getInt();
return ackNo;
}
/**
* Check if the SYN flag is set
* @param packet
* @return
*/
public boolean isSyn(byte[] packet) {
return getFlag(packet, 1);
}
/**
* Check if the ACK flag is set
* @param packet
* @return
*/
public boolean isAck(byte[] packet) {
return getFlag(packet, 2);
}
/**
* Check if the FIN flag is set
* @param packet
* @return
*/
public boolean isFin(byte[] packet) {
return getFlag(packet, 4);
}
/**
* Check if the flag is true by masking the flag of the packet with
* the supplied mask
* @param packet
* @param mask
* @return
*/
private boolean getFlag(byte[] packet, int mask) {
byte rawTypes = ByteBuffer.wrap(packet, OFFSET_FLAGS, 1).get();
return (rawTypes & mask) == mask;
}
}