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