1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.net.tftp;
19
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.InterruptedIOException;
23 import java.io.OutputStream;
24 import java.net.InetAddress;
25 import java.net.SocketException;
26 import java.net.UnknownHostException;
27
28 import org.apache.commons.net.io.FromNetASCIIOutputStream;
29 import org.apache.commons.net.io.ToNetASCIIInputStream;
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 public class TFTPClient extends TFTP
58 {
59
60
61
62
63
64 public static final int DEFAULT_MAX_TIMEOUTS = 5;
65
66
67 private int maxTimeouts;
68
69
70 private long totalBytesReceived;
71
72
73 private long totalBytesSent;
74
75
76
77
78
79
80 public TFTPClient()
81 {
82 maxTimeouts = DEFAULT_MAX_TIMEOUTS;
83 }
84
85
86
87
88
89
90
91
92
93
94
95 public void setMaxTimeouts(final int numTimeouts)
96 {
97 if (numTimeouts < 1) {
98 maxTimeouts = 1;
99 } else {
100 maxTimeouts = numTimeouts;
101 }
102 }
103
104
105
106
107
108
109
110 public int getMaxTimeouts()
111 {
112 return maxTimeouts;
113 }
114
115
116
117
118
119 public long getTotalBytesReceived() {
120 return totalBytesReceived;
121 }
122
123
124
125
126 public long getTotalBytesSent() {
127 return totalBytesSent;
128 }
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147 public int receiveFile(final String fileName, final int mode, OutputStream output,
148 InetAddress host, final int port) throws IOException
149 {
150 int bytesRead = 0;
151 int lastBlock = 0;
152 int block = 1;
153 int hostPort = 0;
154 int dataLength = 0;
155
156 totalBytesReceived = 0;
157
158 if (mode == TFTP.ASCII_MODE) {
159 output = new FromNetASCIIOutputStream(output);
160 }
161
162 TFTPPacket sent = new TFTPReadRequestPacket(host, port, fileName, mode);
163 final TFTPAckPacketFTPAckPacket.html#TFTPAckPacket">TFTPAckPacket ack = new TFTPAckPacket(host, port, 0);
164
165 beginBufferedOps();
166
167 boolean justStarted = true;
168 try {
169 do {
170 bufferedSend(sent);
171 boolean wantReply = true;
172 int timeouts = 0;
173 do {
174 try {
175 final TFTPPacket received = bufferedReceive();
176
177
178 final int recdPort = received.getPort();
179 final InetAddress recdAddress = received.getAddress();
180 if (justStarted) {
181 justStarted = false;
182 if (recdPort == port) {
183 final TFTPErrorPacketrrorPacket.html#TFTPErrorPacket">TFTPErrorPacket error = new TFTPErrorPacket(recdAddress,
184 recdPort, TFTPErrorPacket.UNKNOWN_TID,
185 "INCORRECT SOURCE PORT");
186 bufferedSend(error);
187 throw new IOException("Incorrect source port ("+recdPort+") in request reply.");
188 }
189 hostPort = recdPort;
190 ack.setPort(hostPort);
191 if(!host.equals(recdAddress))
192 {
193 host = recdAddress;
194 ack.setAddress(host);
195 sent.setAddress(host);
196 }
197 }
198
199
200 if (host.equals(recdAddress) && recdPort == hostPort) {
201 switch (received.getType()) {
202
203 case TFTPPacket.ERROR:
204 TFTPErrorPacket/../../org/apache/commons/net/tftp/TFTPErrorPacket.html#TFTPErrorPacket">TFTPErrorPacket error = (TFTPErrorPacket)received;
205 throw new IOException("Error code " + error.getError() +
206 " received: " + error.getMessage());
207 case TFTPPacket.DATA:
208 final TFTPDataPacket../../../org/apache/commons/net/tftp/TFTPDataPacket.html#TFTPDataPacket">TFTPDataPacket data = (TFTPDataPacket)received;
209 dataLength = data.getDataLength();
210 lastBlock = data.getBlockNumber();
211
212 if (lastBlock == block) {
213 try {
214 output.write(data.getData(), data.getDataOffset(), dataLength);
215 } catch (final IOException e) {
216 error = new TFTPErrorPacket(host, hostPort,
217 TFTPErrorPacket.OUT_OF_SPACE,
218 "File write failed.");
219 bufferedSend(error);
220 throw e;
221 }
222 ++block;
223 if (block > 65535) {
224
225 block = 0;
226 }
227 wantReply = false;
228 } else {
229 discardPackets();
230 if (lastBlock == (block == 0 ? 65535 : block - 1)) {
231 wantReply = false;
232 }
233 }
234 break;
235
236 default:
237 throw new IOException("Received unexpected packet type (" + received.getType() + ")");
238 }
239 } else {
240 final TFTPErrorPacketrrorPacket.html#TFTPErrorPacket">TFTPErrorPacket error = new TFTPErrorPacket(recdAddress, recdPort,
241 TFTPErrorPacket.UNKNOWN_TID,
242 "Unexpected host or port.");
243 bufferedSend(error);
244 }
245 } catch (final SocketException | InterruptedIOException e) {
246 if (++timeouts >= maxTimeouts) {
247 throw new IOException("Connection timed out.");
248 }
249 } catch (final TFTPPacketException e) {
250 throw new IOException("Bad packet: " + e.getMessage());
251 }
252 } while(wantReply);
253
254 ack.setBlockNumber(lastBlock);
255 sent = ack;
256 bytesRead += dataLength;
257 totalBytesReceived += dataLength;
258 } while (dataLength == TFTPPacket.SEGMENT_SIZE);
259 bufferedSend(sent);
260 } finally {
261 endBufferedOps();
262 }
263 return bytesRead;
264 }
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285 public int receiveFile(final String fileName, final int mode, final OutputStream output,
286 final String hostname, final int port)
287 throws UnknownHostException, IOException
288 {
289 return receiveFile(fileName, mode, output, InetAddress.getByName(hostname),
290 port);
291 }
292
293
294
295
296
297
298
299
300
301
302
303
304
305 public int receiveFile(final String fileName, final int mode, final OutputStream output,
306 final InetAddress host)
307 throws IOException
308 {
309 return receiveFile(fileName, mode, output, host, DEFAULT_PORT);
310 }
311
312
313
314
315
316
317
318
319
320
321
322
323
324 public int receiveFile(final String fileName, final int mode, final OutputStream output,
325 final String hostname)
326 throws UnknownHostException, IOException
327 {
328 return receiveFile(fileName, mode, output, InetAddress.getByName(hostname),
329 DEFAULT_PORT);
330 }
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350 public void sendFile(final String fileName, final int mode, InputStream input,
351 InetAddress host, final int port) throws IOException
352 {
353 int block = 0;
354 int hostPort = 0;
355 boolean justStarted = true;
356 boolean lastAckWait = false;
357
358 totalBytesSent = 0L;
359
360 if (mode == TFTP.ASCII_MODE) {
361 input = new ToNetASCIIInputStream(input);
362 }
363
364 TFTPPacket sent = new TFTPWriteRequestPacket(host, port, fileName, mode);
365 final TFTPDataPacketPDataPacket.html#TFTPDataPacket">TFTPDataPacket data = new TFTPDataPacket(host, port, 0, sendBuffer, 4, 0);
366
367 beginBufferedOps();
368
369 try {
370 do {
371
372
373 bufferedSend(sent);
374 boolean wantReply = true;
375 int timeouts = 0;
376 do {
377 try {
378 final TFTPPacket received = bufferedReceive();
379 final InetAddress recdAddress = received.getAddress();
380 final int recdPort = received.getPort();
381
382
383 if (justStarted) {
384 justStarted = false;
385 if (recdPort == port) {
386 final TFTPErrorPacketrrorPacket.html#TFTPErrorPacket">TFTPErrorPacket error = new TFTPErrorPacket(recdAddress,
387 recdPort, TFTPErrorPacket.UNKNOWN_TID,
388 "INCORRECT SOURCE PORT");
389 bufferedSend(error);
390 throw new IOException("Incorrect source port ("+recdPort+") in request reply.");
391 }
392 hostPort = recdPort;
393 data.setPort(hostPort);
394 if (!host.equals(recdAddress)) {
395 host = recdAddress;
396 data.setAddress(host);
397 sent.setAddress(host);
398 }
399 }
400
401
402 if (host.equals(recdAddress) && recdPort == hostPort) {
403
404 switch (received.getType()) {
405 case TFTPPacket.ERROR:
406 final TFTPErrorPacket/../../org/apache/commons/net/tftp/TFTPErrorPacket.html#TFTPErrorPacket">TFTPErrorPacket error = (TFTPErrorPacket)received;
407 throw new IOException("Error code " + error.getError() +
408 " received: " + error.getMessage());
409 case TFTPPacket.ACKNOWLEDGEMENT:
410
411 final int lastBlock = ((TFTPAckPacket)received).getBlockNumber();
412
413 if (lastBlock == block) {
414 ++block;
415 if (block > 65535) {
416
417 block = 0;
418 }
419 wantReply = false;
420 } else {
421 discardPackets();
422 }
423 break;
424 default:
425 throw new IOException("Received unexpected packet type.");
426 }
427 } else {
428 final TFTPErrorPacketrrorPacket.html#TFTPErrorPacket">TFTPErrorPacket error = new TFTPErrorPacket(recdAddress,
429 recdPort,
430 TFTPErrorPacket.UNKNOWN_TID,
431 "Unexpected host or port.");
432 bufferedSend(error);
433 }
434 } catch (final SocketException | InterruptedIOException e) {
435 if (++timeouts >= maxTimeouts) {
436 throw new IOException("Connection timed out.");
437 }
438 } catch (final TFTPPacketException e) {
439 throw new IOException("Bad packet: " + e.getMessage());
440 }
441
442 } while(wantReply);
443
444 if (lastAckWait) {
445 break;
446 }
447
448 int dataLength = TFTPPacket.SEGMENT_SIZE;
449 int offset = 4;
450 int totalThisPacket = 0;
451 int bytesRead = 0;
452 while (dataLength > 0 &&
453 (bytesRead = input.read(sendBuffer, offset, dataLength)) > 0) {
454 offset += bytesRead;
455 dataLength -= bytesRead;
456 totalThisPacket += bytesRead;
457 }
458 if( totalThisPacket < TFTPPacket.SEGMENT_SIZE ) {
459
460 lastAckWait = true;
461 }
462 data.setBlockNumber(block);
463 data.setData(sendBuffer, 4, totalThisPacket);
464 sent = data;
465 totalBytesSent += totalThisPacket;
466 } while (true);
467 } finally {
468 endBufferedOps();
469 }
470 }
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491 public void sendFile(final String fileName, final int mode, final InputStream input,
492 final String hostname, final int port)
493 throws UnknownHostException, IOException
494 {
495 sendFile(fileName, mode, input, InetAddress.getByName(hostname), port);
496 }
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511 public void sendFile(final String fileName, final int mode, final InputStream input,
512 final InetAddress host)
513 throws IOException
514 {
515 sendFile(fileName, mode, input, host, DEFAULT_PORT);
516 }
517
518
519
520
521
522
523
524
525
526
527
528
529
530 public void sendFile(final String fileName, final int mode, final InputStream input,
531 final String hostname)
532 throws UnknownHostException, IOException
533 {
534 sendFile(fileName, mode, input, InetAddress.getByName(hostname),
535 DEFAULT_PORT);
536 }
537 }