View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.net.examples.ftp;
19  
20  import java.io.Closeable;
21  import java.io.File;
22  import java.io.FileInputStream;
23  import java.io.FileOutputStream;
24  import java.io.IOException;
25  import java.net.SocketException;
26  import java.net.UnknownHostException;
27  import java.time.Duration;
28  
29  import org.apache.commons.io.IOUtils;
30  import org.apache.commons.net.tftp.TFTP;
31  import org.apache.commons.net.tftp.TFTPClient;
32  import org.apache.commons.net.tftp.TFTPPacket;
33  
34  /**
35   * This is an example of a simple Java TFTP client. Notice how all the code is really just argument processing and error handling.
36   * <p>
37   * Usage: TFTPExample [options] hostname localfile remotefile hostname - The name of the remote host, with optional :port localfile - The name of the local file
38   * to send or the name to use for the received file remotefile - The name of the remote file to receive or the name for the remote server to use to name the
39   * local file being sent. options: (The default is to assume -r -b) -s Send a local file -r Receive a remote file -a Use ASCII transfer mode -b Use binary
40   * transfer mode.
41   * </p>
42   */
43  public final class TFTPExample {
44      // @formatter:off
45      static final String USAGE = "Usage: TFTPExample [options] hostname localfile remotefile\n\n"
46              + "hostname   - The name of the remote host [:port]\n"
47              + "localfile  - The name of the local file to send or the name to use for\n"
48              + "\tthe received file\n"
49              + "remotefile - The name of the remote file to receive or the name for\n"
50              + "\tthe remote server to use to name the local file being sent.\n\n"
51              + "options: (The default is to assume -r -b)\n"
52              + "\t-t timeout in seconds (default 60s)\n"
53              + "\t-s Send a local file\n"
54              + "\t-r Receive a remote file\n"
55              + "\t-a Use ASCII transfer mode\n"
56              + "\t-b Use binary transfer mode\n"
57              + "\t-v Verbose (trace packets)\n";
58      // @formatter:on
59  
60      private static boolean close(final TFTPClient tftp, final Closeable output) {
61          boolean closed;
62          tftp.close();
63          try {
64              IOUtils.close(output);
65              closed = true;
66          } catch (final IOException e) {
67              closed = false;
68              System.err.println("Error: error closing file.");
69              System.err.println(e.getMessage());
70          }
71          return closed;
72      }
73  
74      /**
75       * Runs this application.
76       *
77       * @param args command line arguments.
78       * @throws IOException if a network or I/O error occurs.
79       */
80      public static void main(final String[] args) throws IOException {
81          boolean receiveFile = true;
82          boolean closed;
83          int transferMode = TFTP.BINARY_MODE;
84          int argc;
85          String arg;
86          final String hostname;
87          final String localFilename;
88          final String remoteFilename;
89          final TFTPClient tftp;
90          int timeout = 60_000;
91          boolean verbose = false;
92  
93          // Parse options
94          for (argc = 0; argc < args.length; argc++) {
95              arg = args[argc];
96              if (!arg.startsWith("-")) {
97                  break;
98              }
99              switch (arg) {
100             case "-r":
101                 receiveFile = true;
102                 break;
103             case "-s":
104                 receiveFile = false;
105                 break;
106             case "-a":
107                 transferMode = TFTP.ASCII_MODE;
108                 break;
109             case "-b":
110                 transferMode = TFTP.BINARY_MODE;
111                 break;
112             case "-t":
113                 timeout = 1000 * Integer.parseInt(args[++argc]);
114                 break;
115             case "-v":
116                 verbose = true;
117                 break;
118             default:
119                 System.err.println("Error: unrecognized option.");
120                 System.err.print(USAGE);
121                 System.exit(1);
122                 break;
123             }
124         }
125 
126         // Make sure there are enough arguments
127         if (args.length - argc != 3) {
128             System.err.println("Error: invalid number of arguments.");
129             System.err.print(USAGE);
130             System.exit(1);
131         }
132 
133         // Get host and file arguments
134         hostname = args[argc];
135         localFilename = args[argc + 1];
136         remoteFilename = args[argc + 2];
137 
138         // Create our TFTP instance to handle the file transfer.
139         if (verbose) {
140             tftp = new TFTPClient() {
141                 @Override
142                 protected void trace(final String direction, final TFTPPacket packet) {
143                     System.out.println(direction + " " + packet);
144                 }
145             };
146         } else {
147             tftp = new TFTPClient();
148         }
149 
150         // We want to timeout if a response takes longer than 60 seconds
151         tftp.setDefaultTimeout(Duration.ofSeconds(timeout));
152 
153         // We haven't closed the local file yet.
154         closed = false;
155 
156         // If we're receiving a file, receive, otherwise send.
157         if (receiveFile) {
158             closed = receive(transferMode, hostname, localFilename, remoteFilename, tftp);
159         } else {
160             // We're sending a file
161             closed = send(transferMode, hostname, localFilename, remoteFilename, tftp);
162         }
163 
164         System.out.println("Recd: " + tftp.getTotalBytesReceived() + " Sent: " + tftp.getTotalBytesSent());
165 
166         if (!closed) {
167             System.out.println("Failed");
168             System.exit(1);
169         }
170 
171         System.out.println("OK");
172     }
173 
174     private static void open(final TFTPClient tftp) throws IOException {
175         try {
176             tftp.open();
177         } catch (final SocketException e) {
178             throw new IOException("Error: could not open local UDP socket.", e);
179         }
180     }
181 
182     private static boolean receive(final int transferMode, final String hostname, final String localFilename, final String remoteFilename,
183             final TFTPClient tftp) throws IOException {
184         final File file = new File(localFilename);
185         // If file exists, don't overwrite it.
186         if (file.exists()) {
187             System.err.println("Error: " + localFilename + " already exists.");
188             return false;
189         }
190         final FileOutputStream output;
191         // Try to open local file for writing
192         try {
193             output = new FileOutputStream(file);
194         } catch (final IOException e) {
195             tftp.close();
196             throw new IOException("Error: could not open local file for writing.", e);
197         }
198         open(tftp);
199         final boolean closed;
200         // Try to receive remote file via TFTP
201         try {
202             final String[] parts = hostname.split(":");
203             if (parts.length == 2) {
204                 tftp.receiveFile(remoteFilename, transferMode, output, parts[0], Integer.parseInt(parts[1]));
205             } else {
206                 tftp.receiveFile(remoteFilename, transferMode, output, hostname);
207             }
208         } catch (final UnknownHostException e) {
209             System.err.println("Error: could not resolve hostname.");
210             System.err.println(e.getMessage());
211             System.exit(1);
212         } catch (final IOException e) {
213             System.err.println("Error: I/O exception occurred while receiving file.");
214             System.err.println(e.getMessage());
215             System.exit(1);
216         } finally {
217             // Close local socket and output file
218             closed = close(tftp, output);
219         }
220         return closed;
221     }
222 
223     private static boolean send(final int transferMode, final String hostname, final String localFilename, final String remoteFilename, final TFTPClient tftp)
224             throws IOException {
225         final FileInputStream input;
226         // Try to open local file for reading
227         try {
228             input = new FileInputStream(localFilename);
229         } catch (final IOException e) {
230             tftp.close();
231             throw new IOException("Error: could not open local file for reading.", e);
232         }
233         open(tftp);
234         final boolean closed;
235         // Try to send local file via TFTP
236         try {
237             final String[] parts = hostname.split(":");
238             if (parts.length == 2) {
239                 tftp.sendFile(remoteFilename, transferMode, input, parts[0], Integer.parseInt(parts[1]));
240             } else {
241                 tftp.sendFile(remoteFilename, transferMode, input, hostname);
242             }
243         } catch (final UnknownHostException e) {
244             System.err.println("Error: could not resolve hostname.");
245             System.err.println(e.getMessage());
246             System.exit(1);
247         } catch (final IOException e) {
248             System.err.println("Error: I/O exception occurred while sending file.");
249             System.err.println(e.getMessage());
250             System.exit(1);
251         } finally {
252             // Close local socket and input file
253             closed = close(tftp, input);
254         }
255         return closed;
256     }
257 
258 }