%line | %branch | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
org.apache.commons.net.tftp.TFTPClient |
|
|
1 | /* |
|
2 | * Copyright 2001-2005 The Apache Software Foundation |
|
3 | * |
|
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
|
5 | * you may not use this file except in compliance with the License. |
|
6 | * You may obtain a copy of the License at |
|
7 | * |
|
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
|
9 | * |
|
10 | * Unless required by applicable law or agreed to in writing, software |
|
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
|
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
13 | * See the License for the specific language governing permissions and |
|
14 | * limitations under the License. |
|
15 | */ |
|
16 | package org.apache.commons.net.tftp; |
|
17 | ||
18 | import java.io.IOException; |
|
19 | import java.io.InputStream; |
|
20 | import java.io.InterruptedIOException; |
|
21 | import java.io.OutputStream; |
|
22 | import java.net.InetAddress; |
|
23 | import java.net.SocketException; |
|
24 | import java.net.UnknownHostException; |
|
25 | import org.apache.commons.net.io.FromNetASCIIOutputStream; |
|
26 | import org.apache.commons.net.io.ToNetASCIIInputStream; |
|
27 | ||
28 | /*** |
|
29 | * The TFTPClient class encapsulates all the aspects of the TFTP protocol |
|
30 | * necessary to receive and send files through TFTP. It is derived from |
|
31 | * the {@link org.apache.commons.net.tftp.TFTP} because |
|
32 | * it is more convenient than using aggregation, and as a result exposes |
|
33 | * the same set of methods to allow you to deal with the TFTP protocol |
|
34 | * directly. However, almost every user should only be concerend with the |
|
35 | * the {@link org.apache.commons.net.DatagramSocketClient#open open() }, |
|
36 | * {@link org.apache.commons.net.DatagramSocketClient#close close() }, |
|
37 | * {@link #sendFile sendFile() }, and |
|
38 | * {@link #receiveFile receiveFile() } methods. Additionally, the |
|
39 | * {@link #setMaxTimeouts setMaxTimeouts() } and |
|
40 | * {@link org.apache.commons.net.DatagramSocketClient#setDefaultTimeout setDefaultTimeout() } |
|
41 | * methods may be of importance for performance |
|
42 | * tuning. |
|
43 | * <p> |
|
44 | * Details regarding the TFTP protocol and the format of TFTP packets can |
|
45 | * be found in RFC 783. But the point of these classes is to keep you |
|
46 | * from having to worry about the internals. |
|
47 | * <p> |
|
48 | * <p> |
|
49 | * @author Daniel F. Savarese |
|
50 | * @see TFTP |
|
51 | * @see TFTPPacket |
|
52 | * @see TFTPPacketException |
|
53 | ***/ |
|
54 | ||
55 | public class TFTPClient extends TFTP |
|
56 | { |
|
57 | /*** |
|
58 | * The default number of times a receive attempt is allowed to timeout |
|
59 | * before ending attempts to retry the receive and failing. The default |
|
60 | * is 5 timeouts. |
|
61 | ***/ |
|
62 | public static final int DEFAULT_MAX_TIMEOUTS = 5; |
|
63 | ||
64 | /*** The maximum number of timeouts allowed before failing. ***/ |
|
65 | private int __maxTimeouts; |
|
66 | ||
67 | /*** |
|
68 | * Creates a TFTPClient instance with a default timeout of DEFAULT_TIMEOUT, |
|
69 | * maximum timeouts value of DEFAULT_MAX_TIMEOUTS, a null socket, |
|
70 | * and buffered operations disabled. |
|
71 | ***/ |
|
72 | public TFTPClient() |
|
73 | 0 | { |
74 | 0 | __maxTimeouts = DEFAULT_MAX_TIMEOUTS; |
75 | 0 | } |
76 | ||
77 | /*** |
|
78 | * Sets the maximum number of times a receive attempt is allowed to |
|
79 | * timeout during a receiveFile() or sendFile() operation before ending |
|
80 | * attempts to retry the receive and failing. |
|
81 | * The default is DEFAULT_MAX_TIMEOUTS. |
|
82 | * <p> |
|
83 | * @param numTimeouts The maximum number of timeouts to allow. Values |
|
84 | * less than 1 should not be used, but if they are, they are |
|
85 | * treated as 1. |
|
86 | ***/ |
|
87 | public void setMaxTimeouts(int numTimeouts) |
|
88 | { |
|
89 | 0 | if (numTimeouts < 1) |
90 | 0 | __maxTimeouts = 1; |
91 | else |
|
92 | 0 | __maxTimeouts = numTimeouts; |
93 | 0 | } |
94 | ||
95 | /*** |
|
96 | * Returns the maximum number of times a receive attempt is allowed to |
|
97 | * timeout before ending attempts to retry the receive and failing. |
|
98 | * <p> |
|
99 | * @return The maximum number of timeouts allowed. |
|
100 | ***/ |
|
101 | public int getMaxTimeouts() |
|
102 | { |
|
103 | 0 | return __maxTimeouts; |
104 | } |
|
105 | ||
106 | ||
107 | /*** |
|
108 | * Requests a named file from a remote host, writes the |
|
109 | * file to an OutputStream, closes the connection, and returns the number |
|
110 | * of bytes read. A local UDP socket must first be created by |
|
111 | * {@link org.apache.commons.net.DatagramSocketClient#open open()} before |
|
112 | * invoking this method. This method will not close the OutputStream |
|
113 | * containing the file; you must close it after the method invocation. |
|
114 | * <p> |
|
115 | * @param filename The name of the file to receive. |
|
116 | * @param mode The TFTP mode of the transfer (one of the MODE constants). |
|
117 | * @param output The OutputStream to which the file should be written. |
|
118 | * @param host The remote host serving the file. |
|
119 | * @param port The port number of the remote TFTP server. |
|
120 | * @exception IOException If an I/O error occurs. The nature of the |
|
121 | * error will be reported in the message. |
|
122 | ***/ |
|
123 | public int receiveFile(String filename, class="keyword">int mode, OutputStream output, |
|
124 | InetAddress host, int port) throws IOException |
|
125 | { |
|
126 | int bytesRead, timeouts, lastBlock, block, hostPort, dataLength; |
|
127 | 0 | TFTPPacket sent, received = null; |
128 | TFTPErrorPacket error; |
|
129 | TFTPDataPacket data; |
|
130 | 0 | TFTPAckPacket ack = new TFTPAckPacket(host, port, 0); |
131 | ||
132 | 0 | beginBufferedOps(); |
133 | ||
134 | 0 | dataLength = lastBlock = hostPort = bytesRead = 0; |
135 | 0 | block = 1; |
136 | ||
137 | 0 | if (mode == TFTP.ASCII_MODE) |
138 | 0 | output = new FromNetASCIIOutputStream(output); |
139 | ||
140 | 0 | sent = |
141 | new TFTPReadRequestPacket(host, port, filename, mode); |
|
142 | ||
143 | _sendPacket: |
|
144 | do |
|
145 | { |
|
146 | 0 | bufferedSend(sent); |
147 | ||
148 | _receivePacket: |
|
149 | while (true) |
|
150 | { |
|
151 | 0 | timeouts = 0; |
152 | 0 | while (timeouts < __maxTimeouts) |
153 | { |
|
154 | try |
|
155 | { |
|
156 | 0 | received = bufferedReceive(); |
157 | 0 | break; |
158 | } |
|
159 | 0 | catch (SocketException e) |
160 | { |
|
161 | 0 | if (++timeouts >= __maxTimeouts) |
162 | { |
|
163 | 0 | endBufferedOps(); |
164 | 0 | throw new IOException("Connection timed out."); |
165 | } |
|
166 | 0 | continue; |
167 | } |
|
168 | 0 | catch (InterruptedIOException e) |
169 | { |
|
170 | 0 | if (++timeouts >= __maxTimeouts) |
171 | { |
|
172 | 0 | endBufferedOps(); |
173 | 0 | throw new IOException("Connection timed out."); |
174 | } |
|
175 | 0 | continue; |
176 | } |
|
177 | 0 | catch (TFTPPacketException e) |
178 | { |
|
179 | 0 | endBufferedOps(); |
180 | 0 | throw new IOException("Bad packet: " + e.getMessage()); |
181 | } |
|
182 | } |
|
183 | ||
184 | // The first time we receive we get the port number and |
|
185 | // answering host address (for hosts with multiple IPs) |
|
186 | 0 | if (lastBlock == 0) |
187 | { |
|
188 | 0 | hostPort = received.getPort(); |
189 | 0 | ack.setPort(hostPort); |
190 | 0 | if(!host.equals(received.getAddress())) |
191 | { |
|
192 | 0 | host = received.getAddress(); |
193 | 0 | ack.setAddress(host); |
194 | 0 | sent.setAddress(host); |
195 | } |
|
196 | } |
|
197 | ||
198 | // Comply with RFC 783 indication that an error acknowledgement |
|
199 | // should be sent to originator if unexpected TID or host. |
|
200 | 0 | if (host.equals(received.getAddress()) && |
201 | received.getPort() == hostPort) |
|
202 | { |
|
203 | ||
204 | 0 | switch (received.getType()) |
205 | { |
|
206 | case TFTPPacket.ERROR: |
|
207 | 0 | error = (TFTPErrorPacket)received; |
208 | 0 | endBufferedOps(); |
209 | 0 | throw new IOException("Error code " + error.getError() + |
210 | " received: " + error.getMessage()); |
|
211 | case TFTPPacket.DATA: |
|
212 | 0 | data = (TFTPDataPacket)received; |
213 | 0 | dataLength = data.getDataLength(); |
214 | ||
215 | 0 | lastBlock = data.getBlockNumber(); |
216 | ||
217 | 0 | if (lastBlock == block) |
218 | { |
|
219 | try |
|
220 | { |
|
221 | 0 | output.write(data.getData(), data.getDataOffset(), |
222 | dataLength); |
|
223 | } |
|
224 | 0 | catch (IOException e) |
225 | { |
|
226 | 0 | error = new TFTPErrorPacket(host, hostPort, |
227 | TFTPErrorPacket.OUT_OF_SPACE, |
|
228 | "File write failed."); |
|
229 | 0 | bufferedSend(error); |
230 | 0 | endBufferedOps(); |
231 | 0 | throw e; |
232 | 0 | } |
233 | 0 | ++block; |
234 | 0 | break _receivePacket; |
235 | } |
|
236 | else |
|
237 | { |
|
238 | 0 | discardPackets(); |
239 | ||
240 | 0 | if (lastBlock == (block - 1)) |
241 | 0 | continue _sendPacket; // Resend last acknowledgement. |
242 | ||
243 | continue _receivePacket; // Start fetching packets again. |
|
244 | } |
|
245 | //break; |
|
246 | ||
247 | default: |
|
248 | 0 | endBufferedOps(); |
249 | 0 | throw new IOException("Received unexpected packet type."); |
250 | } |
|
251 | } |
|
252 | else |
|
253 | { |
|
254 | 0 | error = new TFTPErrorPacket(received.getAddress(), |
255 | received.getPort(), |
|
256 | TFTPErrorPacket.UNKNOWN_TID, |
|
257 | "Unexpected host or port."); |
|
258 | 0 | bufferedSend(error); |
259 | 0 | continue _sendPacket; |
260 | } |
|
261 | ||
262 | // We should never get here, but this is a safety to avoid |
|
263 | // infinite loop. If only Java had the goto statement. |
|
264 | //break; |
|
265 | } |
|
266 | ||
267 | 0 | ack.setBlockNumber(lastBlock); |
268 | 0 | sent = ack; |
269 | 0 | bytesRead += dataLength; |
270 | } // First data packet less than 512 bytes signals end of stream. |
|
271 | ||
272 | 0 | while (dataLength == TFTPPacket.SEGMENT_SIZE); |
273 | ||
274 | 0 | bufferedSend(sent); |
275 | 0 | endBufferedOps(); |
276 | ||
277 | 0 | return bytesRead; |
278 | } |
|
279 | ||
280 | ||
281 | /*** |
|
282 | * Requests a named file from a remote host, writes the |
|
283 | * file to an OutputStream, closes the connection, and returns the number |
|
284 | * of bytes read. A local UDP socket must first be created by |
|
285 | * {@link org.apache.commons.net.DatagramSocketClient#open open()} before |
|
286 | * invoking this method. This method will not close the OutputStream |
|
287 | * containing the file; you must close it after the method invocation. |
|
288 | * <p> |
|
289 | * @param filename The name of the file to receive. |
|
290 | * @param mode The TFTP mode of the transfer (one of the MODE constants). |
|
291 | * @param output The OutputStream to which the file should be written. |
|
292 | * @param hostname The name of the remote host serving the file. |
|
293 | * @param port The port number of the remote TFTP server. |
|
294 | * @exception IOException If an I/O error occurs. The nature of the |
|
295 | * error will be reported in the message. |
|
296 | * @exception UnknownHostException If the hostname cannot be resolved. |
|
297 | ***/ |
|
298 | public int receiveFile(String filename, class="keyword">int mode, OutputStream output, |
|
299 | String hostname, int port) |
|
300 | throws UnknownHostException, IOException |
|
301 | { |
|
302 | 0 | return receiveFile(filename, mode, output, InetAddress.getByName(hostname), |
303 | port); |
|
304 | } |
|
305 | ||
306 | ||
307 | /*** |
|
308 | * Same as calling receiveFile(filename, mode, output, host, TFTP.DEFAULT_PORT). |
|
309 | * |
|
310 | * @param filename The name of the file to receive. |
|
311 | * @param mode The TFTP mode of the transfer (one of the MODE constants). |
|
312 | * @param output The OutputStream to which the file should be written. |
|
313 | * @param host The remote host serving the file. |
|
314 | * @exception IOException If an I/O error occurs. The nature of the |
|
315 | * error will be reported in the message. |
|
316 | ***/ |
|
317 | public int receiveFile(String filename, class="keyword">int mode, OutputStream output, |
|
318 | InetAddress host) |
|
319 | throws IOException |
|
320 | { |
|
321 | 0 | return receiveFile(filename, mode, output, host, DEFAULT_PORT); |
322 | } |
|
323 | ||
324 | /*** |
|
325 | * Same as calling receiveFile(filename, mode, output, hostname, TFTP.DEFAULT_PORT). |
|
326 | * |
|
327 | * @param filename The name of the file to receive. |
|
328 | * @param mode The TFTP mode of the transfer (one of the MODE constants). |
|
329 | * @param output The OutputStream to which the file should be written. |
|
330 | * @param hostname The name of the remote host serving the file. |
|
331 | * @exception IOException If an I/O error occurs. The nature of the |
|
332 | * error will be reported in the message. |
|
333 | * @exception UnknownHostException If the hostname cannot be resolved. |
|
334 | ***/ |
|
335 | public int receiveFile(String filename, class="keyword">int mode, OutputStream output, |
|
336 | String hostname) |
|
337 | throws UnknownHostException, IOException |
|
338 | { |
|
339 | 0 | return receiveFile(filename, mode, output, InetAddress.getByName(hostname), |
340 | DEFAULT_PORT); |
|
341 | } |
|
342 | ||
343 | ||
344 | /*** |
|
345 | * Requests to send a file to a remote host, reads the file from an |
|
346 | * InputStream, sends the file to the remote host, and closes the |
|
347 | * connection. A local UDP socket must first be created by |
|
348 | * {@link org.apache.commons.net.DatagramSocketClient#open open()} before |
|
349 | * invoking this method. This method will not close the InputStream |
|
350 | * containing the file; you must close it after the method invocation. |
|
351 | * <p> |
|
352 | * @param filename The name the remote server should use when creating |
|
353 | * the file on its file system. |
|
354 | * @param mode The TFTP mode of the transfer (one of the MODE constants). |
|
355 | * @param host The remote host receiving the file. |
|
356 | * @param port The port number of the remote TFTP server. |
|
357 | * @exception IOException If an I/O error occurs. The nature of the |
|
358 | * error will be reported in the message. |
|
359 | ***/ |
|
360 | public void sendFile(String filename, int mode, InputStream input, |
|
361 | InetAddress host, int port) throws IOException |
|
362 | { |
|
363 | int bytesRead, timeouts, lastBlock, block, hostPort, dataLength, offset; |
|
364 | 0 | TFTPPacket sent, received = null; |
365 | TFTPErrorPacket error; |
|
366 | 0 | TFTPDataPacket data = |
367 | new TFTPDataPacket(host, port, 0, _sendBuffer, 4, 0); |
|
368 | ; |
|
369 | TFTPAckPacket ack; |
|
370 | ||
371 | 0 | beginBufferedOps(); |
372 | ||
373 | 0 | dataLength = lastBlock = hostPort = bytesRead = 0; |
374 | 0 | block = 0; |
375 | 0 | boolean lastAckWait = false; |
376 | ||
377 | 0 | if (mode == TFTP.ASCII_MODE) |
378 | 0 | input = new ToNetASCIIInputStream(input); |
379 | ||
380 | 0 | sent = |
381 | new TFTPWriteRequestPacket(host, port, filename, mode); |
|
382 | ||
383 | _sendPacket: |
|
384 | do |
|
385 | { |
|
386 | 0 | bufferedSend(sent); |
387 | ||
388 | _receivePacket: |
|
389 | while (true) |
|
390 | { |
|
391 | 0 | timeouts = 0; |
392 | 0 | while (timeouts < __maxTimeouts) |
393 | { |
|
394 | try |
|
395 | { |
|
396 | 0 | received = bufferedReceive(); |
397 | 0 | break; |
398 | } |
|
399 | 0 | catch (SocketException e) |
400 | { |
|
401 | 0 | if (++timeouts >= __maxTimeouts) |
402 | { |
|
403 | 0 | endBufferedOps(); |
404 | 0 | throw new IOException("Connection timed out."); |
405 | } |
|
406 | 0 | continue; |
407 | } |
|
408 | 0 | catch (InterruptedIOException e) |
409 | { |
|
410 | 0 | if (++timeouts >= __maxTimeouts) |
411 | { |
|
412 | 0 | endBufferedOps(); |
413 | 0 | throw new IOException("Connection timed out."); |
414 | } |
|
415 | 0 | continue; |
416 | } |
|
417 | 0 | catch (TFTPPacketException e) |
418 | { |
|
419 | 0 | endBufferedOps(); |
420 | 0 | throw new IOException("Bad packet: " + e.getMessage()); |
421 | } |
|
422 | } |
|
423 | ||
424 | // The first time we receive we get the port number and |
|
425 | // answering host address (for hosts with multiple IPs) |
|
426 | 0 | if (lastBlock == 0) |
427 | { |
|
428 | 0 | hostPort = received.getPort(); |
429 | 0 | data.setPort(hostPort); |
430 | 0 | if(!host.equals(received.getAddress())) |
431 | { |
|
432 | 0 | host = received.getAddress(); |
433 | 0 | data.setAddress(host); |
434 | 0 | sent.setAddress(host); |
435 | } |
|
436 | } |
|
437 | ||
438 | // Comply with RFC 783 indication that an error acknowledgement |
|
439 | // should be sent to originator if unexpected TID or host. |
|
440 | 0 | if (host.equals(received.getAddress()) && |
441 | received.getPort() == hostPort) |
|
442 | { |
|
443 | ||
444 | 0 | switch (received.getType()) |
445 | { |
|
446 | case TFTPPacket.ERROR: |
|
447 | 0 | error = (TFTPErrorPacket)received; |
448 | 0 | endBufferedOps(); |
449 | 0 | throw new IOException("Error code " + error.getError() + |
450 | " received: " + error.getMessage()); |
|
451 | case TFTPPacket.ACKNOWLEDGEMENT: |
|
452 | 0 | ack = (TFTPAckPacket)received; |
453 | ||
454 | 0 | lastBlock = ack.getBlockNumber(); |
455 | ||
456 | 0 | if (lastBlock == block) |
457 | { |
|
458 | 0 | ++block; |
459 | 0 | if (lastAckWait) |
460 | 0 | break _sendPacket; |
461 | else |
|
462 | break _receivePacket; |
|
463 | } |
|
464 | else |
|
465 | { |
|
466 | 0 | discardPackets(); |
467 | ||
468 | 0 | if (lastBlock == (block - 1)) |
469 | 0 | continue _sendPacket; // Resend last acknowledgement. |
470 | ||
471 | continue _receivePacket; // Start fetching packets again. |
|
472 | } |
|
473 | //break; |
|
474 | ||
475 | default: |
|
476 | 0 | endBufferedOps(); |
477 | 0 | throw new IOException("Received unexpected packet type."); |
478 | } |
|
479 | } |
|
480 | else |
|
481 | { |
|
482 | 0 | error = new TFTPErrorPacket(received.getAddress(), |
483 | received.getPort(), |
|
484 | TFTPErrorPacket.UNKNOWN_TID, |
|
485 | "Unexpected host or port."); |
|
486 | 0 | bufferedSend(error); |
487 | 0 | continue _sendPacket; |
488 | } |
|
489 | ||
490 | // We should never get here, but this is a safety to avoid |
|
491 | // infinite loop. If only Java had the goto statement. |
|
492 | //break; |
|
493 | } |
|
494 | ||
495 | 0 | dataLength = TFTPPacket.SEGMENT_SIZE; |
496 | 0 | offset = 4; |
497 | while (dataLength > 0 && |
|
498 | 0 | (bytesRead = input.read(_sendBuffer, offset, dataLength)) > 0) |
499 | { |
|
500 | 0 | offset += bytesRead; |
501 | 0 | dataLength -= bytesRead; |
502 | } |
|
503 | ||
504 | 0 | data.setBlockNumber(block); |
505 | 0 | data.setData(_sendBuffer, 4, offset - 4); |
506 | 0 | sent = data; |
507 | } |
|
508 | 0 | while (dataLength == 0 || lastAckWait); |
509 | ||
510 | 0 | endBufferedOps(); |
511 | 0 | } |
512 | ||
513 | ||
514 | /*** |
|
515 | * Requests to send a file to a remote host, reads the file from an |
|
516 | * InputStream, sends the file to the remote host, and closes the |
|
517 | * connection. A local UDP socket must first be created by |
|
518 | * {@link org.apache.commons.net.DatagramSocketClient#open open()} before |
|
519 | * invoking this method. This method will not close the InputStream |
|
520 | * containing the file; you must close it after the method invocation. |
|
521 | * <p> |
|
522 | * @param filename The name the remote server should use when creating |
|
523 | * the file on its file system. |
|
524 | * @param mode The TFTP mode of the transfer (one of the MODE constants). |
|
525 | * @param hostname The name of the remote host receiving the file. |
|
526 | * @param port The port number of the remote TFTP server. |
|
527 | * @exception IOException If an I/O error occurs. The nature of the |
|
528 | * error will be reported in the message. |
|
529 | * @exception UnknownHostException If the hostname cannot be resolved. |
|
530 | ***/ |
|
531 | public void sendFile(String filename, int mode, InputStream input, |
|
532 | String hostname, int port) |
|
533 | throws UnknownHostException, IOException |
|
534 | { |
|
535 | 0 | sendFile(filename, mode, input, InetAddress.getByName(hostname), port); |
536 | 0 | } |
537 | ||
538 | ||
539 | /*** |
|
540 | * Same as calling sendFile(filename, mode, input, host, TFTP.DEFAULT_PORT). |
|
541 | * |
|
542 | * @param filename The name the remote server should use when creating |
|
543 | * the file on its file system. |
|
544 | * @param mode The TFTP mode of the transfer (one of the MODE constants). |
|
545 | * @param host The name of the remote host receiving the file. |
|
546 | * @exception IOException If an I/O error occurs. The nature of the |
|
547 | * error will be reported in the message. |
|
548 | * @exception UnknownHostException If the hostname cannot be resolved. |
|
549 | ***/ |
|
550 | public void sendFile(String filename, int mode, InputStream input, |
|
551 | InetAddress host) |
|
552 | throws IOException |
|
553 | { |
|
554 | 0 | sendFile(filename, mode, input, host, DEFAULT_PORT); |
555 | 0 | } |
556 | ||
557 | /*** |
|
558 | * Same as calling sendFile(filename, mode, input, hostname, TFTP.DEFAULT_PORT). |
|
559 | * |
|
560 | * @param filename The name the remote server should use when creating |
|
561 | * the file on its file system. |
|
562 | * @param mode The TFTP mode of the transfer (one of the MODE constants). |
|
563 | * @param hostname The name of the remote host receiving the file. |
|
564 | * @exception IOException If an I/O error occurs. The nature of the |
|
565 | * error will be reported in the message. |
|
566 | * @exception UnknownHostException If the hostname cannot be resolved. |
|
567 | ***/ |
|
568 | public void sendFile(String filename, int mode, InputStream input, |
|
569 | String hostname) |
|
570 | throws UnknownHostException, IOException |
|
571 | { |
|
572 | 0 | sendFile(filename, mode, input, InetAddress.getByName(hostname), |
573 | DEFAULT_PORT); |
|
574 | 0 | } |
575 | } |
This report is generated by jcoverage, Maven and Maven JCoverage Plugin. |