-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathClientTFTP.java
More file actions
234 lines (197 loc) · 8.52 KB
/
Copy pathClientTFTP.java
File metadata and controls
234 lines (197 loc) · 8.52 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
/*
Names: Lee Page, Edward Banner
Class: CIS 410 - Networks
Assignment: 5
Due date: April 18 2012
*/
import java.net.*;
import java.io.*;
import java.util.*;
public class ClientTFTP {
public static void main(String [] args) {
// error checking
String usage = "Usage: java TFTPClinet <server> <READ | WRITE> <file>";
if (args.length < 3) {
System.err.println(usage);
System.exit(1);
} else if (!args[1].equals("read") && !args[1].equals("write")){
System.err.println(usage);
System.exit(1);
} else if (args[2].contains("/")){
System.err.println("Filename cannot contain '/'!");
System.exit(1);
} else if (args[2].charAt(0) == '.'){
System.err.println("Filename cannot start with '.'!");
System.exit(1);
}
if (args[1].equals("read") || args[1].equals("write")){
// initialize some variables
int block = 0;
DataOutputStream fileOut = null;
DataInputStream fileData = null;
byte[] bay = new byte[516];
String server = args[0];
String request = args[1];
String fileName = args[2];
try {
if (request.equals("read")) { // make sure file doesn't already exist
// open up stream on file
if (new File(fileName).exists()) {
System.out.println("ERROR: FILE ALREADY EXISTS");
System.exit(1);
}
// open up a stream for writing
fileOut = new DataOutputStream(new FileOutputStream(fileName));
// prepare the RRQ data to send to server
// populates bay with [01][fileName][0][octet][0]
ClientTFTP.prepareDataRRQ(bay, fileName, "octet");
// first block receiver plans to receive is 1
block = 1;
} else if (request.equals("write")) { // open up a stream for reading
// open up stream on file
fileData = new DataInputStream(new FileInputStream(fileName));
// prepare WRQ packet data
// populates bay with [02[fileName][0][octet][0]
ClientTFTP.prepareDataWRQ(bay, fileName, "octet");
// first block receiver plans to see is 0
block = 0;
}
// create generic socket
DatagramSocket cli = new DatagramSocket(); // no specific port
// get information for packet
int port = 6969;
InetAddress address = InetAddress.getByName(server);
DatagramPacket pkt = new DatagramPacket(bay, bay.length, address, port);
// send the packet
ClientTFTP.sendWithTimeout(cli, pkt, request, block);
// port for server has changed -- get the new port
port = pkt.getPort();
address = pkt.getAddress();
if (request.equals("write")) {
// TFTPClient now takes on the role of sender
SenderTFTP sender = new SenderTFTP(address, port, fileData, cli);
sender.send();
}
else if (request.equals("read")) {
// only write to the file if file was non-empty
if (pkt.getLength()-4 > 0) {
fileOut.write(bay, 4, pkt.getLength()-4);
}
// create first ACK with block #1 to send to server
byte[] ack = {0, 4, 0, 1};
DatagramPacket ackPkt = new DatagramPacket(ack, ack.length, address, port);
// send the first ACK
cli.send(ackPkt);
// TFTPClient now takes on the role of receiver
// only start receiving if data received was 512 bytes
if (pkt.getLength()-4 == 512) {
ReceiverTFTP receiver = new ReceiverTFTP(address, port, fileOut, cli, 2);
receiver.receive();
}
}
} catch(Exception e) {
System.out.println(e);
}
}
}
public static void printErrorMessage(byte[] bay) {
// prints the error message contained within an error packet
int length = 0;
int slot = 4;
while (bay[slot++] != 0)
length++;
// create a new string the will contain the mode
String error = new String(bay, 4, length);
System.out.println("ERROR MESSAGE: " + error);
}
public static byte[] makeErrorData(int errorCode, String errorMessage) {
// returns a byte array of error packet data
int position;
byte[] errorBytes = new byte[516];
errorBytes[0] = 0;
errorBytes[1] = 5;
errorBytes[2] = 0;
errorBytes[3] = (byte)errorCode;
for (position = 0; position < errorMessage.length(); position++) {
errorBytes[4+position] = (byte)errorMessage.charAt(position);
}
errorBytes[position+4] = 0;
return errorBytes;
}
public static void prepareDataRRQ(byte[] bay, String fileName, String mode) {
int index;
// set first two bytes of outgoing packet to 01 to indicicate RRQ
bay[0] = 0;
bay[1] = 1;
/* populate next free bytes in bay with the ``fileName" followed
by null character */
for (index = 0; index < fileName.length(); index++) {
bay[index+2] = (byte)fileName.charAt(index);
}
index += 2;
bay[index++] = 0; // bay is now [02][filename][0]
/* populate next free bytes in bay with ``octet" followed
by null character */
for (int i = 0; i < mode.length(); i++) {
bay[index++] = (byte)mode.charAt(i);
}
bay[index] = 0; // bay is now [02][filename][0][octet][0]
}
public static void prepareDataWRQ(byte[] bay, String fileName, String mode) {
int index;
// set first two bytes of outgoing packet to 02 to indicicate WRQ
bay[0] = 0;
bay[1] = 2;
/* populate next free bytes in bay with the ``fileName" followed
by null character */
for (index = 0; index < fileName.length(); index++) {
bay[index+2] = (byte)fileName.charAt(index);
}
index += 2;
bay[index++] = 0; // bay is now [02][filename][0]
/* populate next free bytes in bay with ``octet" followed
by null character */
for (int i = 0; i < mode.length(); i++) {
bay[index++] = (byte)mode.charAt(i);
}
bay[index] = 0; // bay is now [02][filename][0][octet][0]
}
public static boolean incorrectBlockRRQ(byte[] bay, int block) {
return bay[0] != 0 || bay[1] != 3 || bay[2] != 0 || (int)bay[3] != block;
}
public static boolean incorrectBlockWRQ(byte[] bay, int block) {
return bay[0] != 0 || bay[1] != 4 || bay[2] != 0 || (int)bay[3] != block;
}
public static void sendWithTimeout(DatagramSocket cli, DatagramPacket pkt, String request, int block) throws Exception {
int retry = 0;
byte[] bay = new byte[516];
while(retry < 3) {
try {
cli.send(pkt);
//pkt = new DatagramPacket(bay, bay.length);
cli.receive(pkt);
bay = pkt.getData();
// check for error opcode
if (bay[0] == 0 && bay[1] == 5) {
ClientTFTP.printErrorMessage(bay);
System.exit(1);
}
if (request.equals("write") && ClientTFTP.incorrectBlockWRQ(bay, block)) {
// ACK number is not zero
System.out.println("INCORRECT BLOCK NUMBER SENT -- EXITING");
System.exit(1);
} else if (request.equals("read") && ClientTFTP.incorrectBlockRRQ(bay, block)) {
// intial header of data has block other than 1
System.out.println("INCORRECT BLOCK NUMBER SENT -- EXITING");
System.exit(1);
}
// header looks good, break out
break;
} catch (SocketTimeoutException e) {
System.out.println("TIMEOUT");
retry++;
continue;
}
}
}
}