View Javadoc

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