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    *      http://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.tftp;
19  
20  import java.io.IOException;
21  import java.io.InterruptedIOException;
22  import java.net.DatagramPacket;
23  import java.net.SocketException;
24  
25  import org.apache.commons.net.DatagramSocketClient;
26  
27  /**
28   * The TFTP class exposes a set of methods to allow you to deal with the TFTP
29   * protocol directly, in case you want to write your own TFTP client or
30   * server.  However, almost every user should only be concerend with
31   * the {@link org.apache.commons.net.DatagramSocketClient#open  open() },
32   * and {@link org.apache.commons.net.DatagramSocketClient#close  close() },
33   * methods. Additionally,the a
34   * {@link org.apache.commons.net.DatagramSocketClient#setDefaultTimeout setDefaultTimeout() }
35   *  method may be of importance for performance tuning.
36   * <p>
37   * Details regarding the TFTP protocol and the format of TFTP packets can
38   * be found in RFC 783.  But the point of these classes is to keep you
39   * from having to worry about the internals.
40   *
41   *
42   * @see org.apache.commons.net.DatagramSocketClient
43   * @see TFTPPacket
44   * @see TFTPPacketException
45   * @see TFTPClient
46   */
47  
48  public class TFTP extends DatagramSocketClient
49  {
50      /**
51       * The ascii transfer mode.  Its value is 0 and equivalent to NETASCII_MODE
52       */
53      public static final int ASCII_MODE = 0;
54  
55      /**
56       * The netascii transfer mode.  Its value is 0.
57       */
58      public static final int NETASCII_MODE = 0;
59  
60      /**
61       * The binary transfer mode.  Its value is 1 and equivalent to OCTET_MODE.
62       */
63      public static final int BINARY_MODE = 1;
64  
65      /**
66       * The image transfer mode.  Its value is 1 and equivalent to OCTET_MODE.
67       */
68      public static final int IMAGE_MODE = 1;
69  
70      /**
71       * The octet transfer mode.  Its value is 1.
72       */
73      public static final int OCTET_MODE = 1;
74  
75      /**
76       * The default number of milliseconds to wait to receive a datagram
77       * before timing out.  The default is 5000 milliseconds (5 seconds).
78       */
79      public static final int DEFAULT_TIMEOUT = 5000;
80  
81      /**
82       * The default TFTP port according to RFC 783 is 69.
83       */
84      public static final int DEFAULT_PORT = 69;
85  
86      /**
87       * The size to use for TFTP packet buffers.  Its 4 plus the
88       * TFTPPacket.SEGMENT_SIZE, i.e. 516.
89       */
90      static final int PACKET_SIZE = TFTPPacket.SEGMENT_SIZE + 4;
91  
92      /** A buffer used to accelerate receives in bufferedReceive() */
93      private byte[] receiveBuffer;
94  
95      /** A datagram used to minimize memory allocation in bufferedReceive() */
96      private DatagramPacket receiveDatagram;
97  
98      /** A datagram used to minimize memory allocation in bufferedSend() */
99      private DatagramPacket sendDatagram;
100 
101     /**
102      * A buffer used to accelerate sends in bufferedSend().
103      * It is left package visible so that TFTPClient may be slightly more
104      * efficient during file sends.  It saves the creation of an
105      * additional buffer and prevents a buffer copy in _newDataPcket().
106      */
107     byte[] sendBuffer;
108 
109 
110     /**
111      * Returns the TFTP string representation of a TFTP transfer mode.
112      * Will throw an ArrayIndexOutOfBoundsException if an invalid transfer
113      * mode is specified.
114      *
115      * @param mode  The TFTP transfer mode.  One of the MODE constants.
116      * @return  The TFTP string representation of the TFTP transfer mode.
117      */
118     public static final String getModeName(final int mode)
119     {
120         return TFTPRequestPacket.modeStrings[mode];
121     }
122 
123     /**
124      * Creates a TFTP instance with a default timeout of DEFAULT_TIMEOUT,
125      * a null socket, and buffered operations disabled.
126      */
127     public TFTP()
128     {
129         setDefaultTimeout(DEFAULT_TIMEOUT);
130         receiveBuffer = null;
131         receiveDatagram = null;
132     }
133 
134     /**
135      * This method synchronizes a connection by discarding all packets that
136      * may be in the local socket buffer.  This method need only be called
137      * when you implement your own TFTP client or server.
138      *
139      * @throws IOException if an I/O error occurs.
140      */
141     public final void discardPackets() throws IOException
142     {
143         final int to;
144         final DatagramPacket datagram;
145 
146         datagram = new DatagramPacket(new byte[PACKET_SIZE], PACKET_SIZE);
147 
148         to = getSoTimeout();
149         setSoTimeout(1);
150 
151         try
152         {
153             while (true) {
154                 _socket_.receive(datagram);
155             }
156         }
157         catch (final SocketException | InterruptedIOException e)
158         {
159             // Do nothing.  We timed out so we hope we're caught up.
160         }
161 
162         setSoTimeout(to);
163     }
164 
165 
166     /**
167      * This is a special method to perform a more efficient packet receive.
168      * It should only be used after calling
169      * {@link #beginBufferedOps  beginBufferedOps() }.  beginBufferedOps()
170      * initializes a set of buffers used internally that prevent the new
171      * allocation of a DatagramPacket and byte array for each send and receive.
172      * To use these buffers you must call the bufferedReceive() and
173      * bufferedSend() methods instead of send() and receive().  You must
174      * also be certain that you don't manipulate the resulting packet in
175      * such a way that it interferes with future buffered operations.
176      * For example, a TFTPDataPacket received with bufferedReceive() will
177      * have a reference to the internal byte buffer.  You must finish using
178      * this data before calling bufferedReceive() again, or else the data
179      * will be overwritten by the the call.
180      *
181      * @return The TFTPPacket received.
182      * @throws InterruptedIOException  If a socket timeout occurs.  The
183      *       Java documentation claims an InterruptedIOException is thrown
184      *       on a DatagramSocket timeout, but in practice we find a
185      *       SocketException is thrown.  You should catch both to be safe.
186      * @throws SocketException  If a socket timeout occurs.  The
187      *       Java documentation claims an InterruptedIOException is thrown
188      *       on a DatagramSocket timeout, but in practice we find a
189      *       SocketException is thrown.  You should catch both to be safe.
190      * @throws IOException  If some other I/O error occurs.
191      * @throws TFTPPacketException If an invalid TFTP packet is received.
192      */
193     public final TFTPPacket bufferedReceive() throws IOException,
194                 InterruptedIOException, SocketException, TFTPPacketException
195     {
196         receiveDatagram.setData(receiveBuffer);
197         receiveDatagram.setLength(receiveBuffer.length);
198         _socket_.receive(receiveDatagram);
199 
200         final TFTPPacket newTFTPPacket = TFTPPacket.newTFTPPacket(receiveDatagram);
201         trace("<", newTFTPPacket);
202         return newTFTPPacket;
203     }
204 
205     /**
206      * This is a special method to perform a more efficient packet send.
207      * It should only be used after calling
208      * {@link #beginBufferedOps  beginBufferedOps() }.  beginBufferedOps()
209      * initializes a set of buffers used internally that prevent the new
210      * allocation of a DatagramPacket and byte array for each send and receive.
211      * To use these buffers you must call the bufferedReceive() and
212      * bufferedSend() methods instead of send() and receive().  You must
213      * also be certain that you don't manipulate the resulting packet in
214      * such a way that it interferes with future buffered operations.
215      * For example, a TFTPDataPacket received with bufferedReceive() will
216      * have a reference to the internal byte buffer.  You must finish using
217      * this data before calling bufferedReceive() again, or else the data
218      * will be overwritten by the the call.
219      *
220      * @param packet  The TFTP packet to send.
221      * @throws IOException  If some  I/O error occurs.
222      */
223     public final void bufferedSend(final TFTPPacket packet) throws IOException
224     {
225         trace(">", packet);
226         _socket_.send(packet.newDatagram(sendDatagram, sendBuffer));
227     }
228 
229 
230     /**
231      * Initializes the internal buffers. Buffers are used by
232      * {@link #bufferedSend  bufferedSend() } and
233      * {@link #bufferedReceive  bufferedReceive() }.  This
234      * method must be called before calling either one of those two
235      * methods.  When you finish using buffered operations, you must
236      * call {@link #endBufferedOps  endBufferedOps() }.
237      */
238     public final void beginBufferedOps()
239     {
240         receiveBuffer = new byte[PACKET_SIZE];
241         receiveDatagram =
242             new DatagramPacket(receiveBuffer, receiveBuffer.length);
243         sendBuffer = new byte[PACKET_SIZE];
244         sendDatagram =
245             new DatagramPacket(sendBuffer, sendBuffer.length);
246     }
247 
248     /**
249      * Releases the resources used to perform buffered sends and receives.
250      */
251     public final void endBufferedOps()
252     {
253         receiveBuffer = null;
254         receiveDatagram = null;
255         sendBuffer = null;
256         sendDatagram = null;
257     }
258 
259 
260     /**
261      * Sends a TFTP packet to its destination.
262      *
263      * @param packet  The TFTP packet to send.
264      * @throws IOException  If some  I/O error occurs.
265      */
266     public final void send(final TFTPPacket packet) throws IOException
267     {
268         trace(">", packet);
269         _socket_.send(packet.newDatagram());
270     }
271 
272 
273     /**
274      * Receives a TFTPPacket.
275      *
276      * @return The TFTPPacket received.
277      * @throws InterruptedIOException  If a socket timeout occurs.  The
278      *       Java documentation claims an InterruptedIOException is thrown
279      *       on a DatagramSocket timeout, but in practice we find a
280      *       SocketException is thrown.  You should catch both to be safe.
281      * @throws SocketException  If a socket timeout occurs.  The
282      *       Java documentation claims an InterruptedIOException is thrown
283      *       on a DatagramSocket timeout, but in practice we find a
284      *       SocketException is thrown.  You should catch both to be safe.
285      * @throws IOException  If some other I/O error occurs.
286      * @throws TFTPPacketException If an invalid TFTP packet is received.
287      */
288     public final TFTPPacket receive() throws IOException, InterruptedIOException,
289                 SocketException, TFTPPacketException
290     {
291         final DatagramPacket packet;
292 
293         packet = new DatagramPacket(new byte[PACKET_SIZE], PACKET_SIZE);
294 
295         _socket_.receive(packet);
296 
297         final TFTPPacket newTFTPPacket = TFTPPacket.newTFTPPacket(packet);
298         trace("<", newTFTPPacket);
299         return newTFTPPacket;
300     }
301 
302     /**
303      * Trace facility; this implementation does nothing.
304      * <p>
305      * Override it to trace the data, for example:<br>
306      * {@code System.out.println(direction + " " + packet.toString());}
307      * @param direction {@code >} or  {@code <}
308      * @param packet the packet to be sent or that has been received respectively
309      * @since 3.6
310      */
311     protected void trace(final String direction, final TFTPPacket packet) {
312     }
313 
314 }