-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathClient.java
More file actions
220 lines (182 loc) · 6.12 KB
/
Copy pathClient.java
File metadata and controls
220 lines (182 loc) · 6.12 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
import java.io.File;
import java.net.InetAddress;
/**
* Basic TFTP Client, adhering to RFC1350.
*
* @author James Li
*/
public class Client {
public static void main(String[] args) {
// Arguments parser
ArgumentsParser argsParser = new ArgumentsParser()
.register("port", ArgumentsParser.type.INT, Integer.toString(Constants.defaultServerTID)) // Port
.register("timeout", ArgumentsParser.type.INT, Integer.toString(Constants.defaultOperationTimeout)) // Timeout
.register("attempts", ArgumentsParser.type.INT, Integer.toString(Constants.defaultMaxOperationAttempts)) // Max
// attempts
.register("mode", ArgumentsParser.type.STRING, Constants.defaultEncoding) // Encoding
.registerBoolean("enable-error-message-delivery") // Error msg
// delivery
.registerBoolean("disable-block-messages"); // Disables standard
// block ack
// messages
// Parse what we can
args = argsParser.munch(args);
// There should be exactly 4 unmunched arguments
// <host> {get|put} <source> <dest>
if (args.length != 4) {
System.err.println(Constants.strings.INSUFFICIENT_ARGS);
return;
}
// The remaining 4 are fixed in order
String inputAddress = args[0];
String inputType = args[1].toLowerCase();
String file1 = args[2];
String file2 = args[3];
String localFile;
String remoteFile;
try {
// Attempt to convert inputs into what we need
InetAddress address = InetAddress.getByName(inputAddress);
short outgoingRequestType = Packet.opcode.ERROR;
File file;
switch (inputType) {
case "get":
// Read file from remote A -> local B
outgoingRequestType = Packet.opcode.RRQ;
remoteFile = file1;
localFile = file2;
// Check if file exists
file = new File(localFile);
if (file.exists()) {
throw new Exception(Packet.errstr[Packet.errcode.FILE_EXISTS]);
}
break;
case "put":
// Write file from local A -> remote B
outgoingRequestType = Packet.opcode.WRQ;
localFile = file1;
remoteFile = file2;
// Check if file does not exist
file = new File(localFile);
if (!file.exists()) {
throw new Exception(Packet.errstr[Packet.errcode.FILE_NOT_FOUND]);
}
break;
default:
System.err.println(Constants.strings.INVALID_REQUEST_TYPE_ARG);
return;
}
// Start here
System.out.println("TFTP Client starting");
new ClientSession(argsParser, address, outgoingRequestType, localFile, remoteFile).run();
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
}
/**
* Client-relevant implementation of `Session`.
*
* @see Session.
*/
class ClientSession extends Session {
private short outgoingRequestType;
private String localFile;
private String remoteFile;
private boolean switchedRemotePort;
/**
* Sends client-side initial request packet to the server.
*
* @return `OutgoingPacket` instance
* @throws Exception
*/
private OutgoingPacket sendInitialRequestPacket() throws Exception {
// In the format of a RRQ/WRQ packet
return this.createOutPacket() //
.addOpcode(this.outgoingRequestType) // RRQ/WRQ opcode
.addString(this.remoteFile) // Filename
.addNullByte() //
.addString(this.getMode()) // Encoding
.addNullByte() //
.send();
}
/*
* (non-Javadoc)
*
* @see Session#startSession()
*/
@Override
Session begin() throws Exception {
// Interpret the outgoing request type, set up session, and send the
// initial request packet
switch (this.outgoingRequestType) {
case Packet.opcode.RRQ:
this.setupSessionForWritingToLocal(false, this.outgoingRequestType, this.localFile);
this.sendInitialRequestPacket();
this.print(String.format(Constants.strings.REQUEST_REMOTE_FILE_X_READ_VIA_MODE_X, this.remoteFile,
this.getMode()));
break;
case Packet.opcode.WRQ:
this.setupSessionForReadingFromLocal(false, this.outgoingRequestType, this.localFile);
this.sendInitialRequestPacket();
this.print(String.format(Constants.strings.REQUEST_REMOTE_FILE_X_WRITE_VIA_MODE_X, this.remoteFile,
this.getMode()));
break;
default:
throw new Exception(Constants.strings.INVALID_REQUEST);
}
return this;
}
/*
* (non-Javadoc)
*
* @see Session#processPacket()
*/
@Override
Session processInPacket() throws Exception {
if (!switchedRemotePort) {
// This is the session's port
this.setDeliveryPort(this.getInPacket().getDatagramPacket().getPort()).print(String.format(
Constants.strings.CLIENT_SWITCH_REMOTE_PORT_X, this.getInPacket().getDatagramPacket().getPort()));
this.switchedRemotePort = true;
}
return this.commonProcessInPacket(Packet.opcode.WRQ, Packet.opcode.RRQ);
}
/**
* @param argsParser
* Arguments passed to the program
* @param address
* Destination server address
* @param outgoingRequestType
* Outgoing request type
* @param localFile
* Local filename
* @param remoteFile
* Remote filename
* @throws Exception
*/
ClientSession(ArgumentsParser argsParser, InetAddress address, short outgoingRequestType, String localFile,
String remoteFile) throws Exception {
this.outgoingRequestType = outgoingRequestType;
this.localFile = localFile;
this.remoteFile = remoteFile;
this.switchedRemotePort = false;
this.setDeliveryAddress(address) // Address
.setDeliveryPort(argsParser.readInt("port")) // Port
.setTimeout(argsParser.readInt("timeout")) // Timeout
.setMaxAttempts(argsParser.readInt("attempts")) // Max
// attempts
// Encoding is set prior to connection pull up
.setMode(argsParser.readString("mode"))
.print(String.format(Constants.strings.COMM_WITH_SERVER_OVER_IP_X_PORT_X_VIA_MODE_X,
this.getDeliveryAddress().getHostAddress(), this.getDeliveryPort(), this.getMode()));
// If error message delivery is enabled
if (argsParser.readBool("enable-error-message-delivery")) {
this.enableExceptionMessageDelivery();
}
// If std block ack messages are enabled
if (argsParser.readBool("disable-block-messages")) {
this.disableBlockAckMessagePrinting();
}
}
}