001    /*
002     * Copyright 2001-2005 The Apache Software Foundation
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *     http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.apache.commons.net.tftp;
017    
018    import java.io.IOException;
019    import java.io.InterruptedIOException;
020    import java.net.DatagramPacket;
021    import java.net.SocketException;
022    import org.apache.commons.net.DatagramSocketClient;
023    
024    /***
025     * The TFTP class exposes a set of methods to allow you to deal with the TFTP
026     * protocol directly, in case you want to write your own TFTP client or
027     * server.  However, almost every user should only be concerend with
028     * the {@link org.apache.commons.net.DatagramSocketClient#open  open() },
029     * and {@link org.apache.commons.net.DatagramSocketClient#close  close() },
030     * methods. Additionally,the a
031     * {@link org.apache.commons.net.DatagramSocketClient#setDefaultTimeout setDefaultTimeout() }
032     *  method may be of importance for performance tuning.
033     * <p>
034     * Details regarding the TFTP protocol and the format of TFTP packets can
035     * be found in RFC 783.  But the point of these classes is to keep you
036     * from having to worry about the internals.
037     * <p>
038     * <p>
039     * @author Daniel F. Savarese
040     * @see org.apache.commons.net.DatagramSocketClient
041     * @see TFTPPacket
042     * @see TFTPPacketException
043     * @see TFTPClient
044     ***/
045    
046    public class TFTP extends DatagramSocketClient
047    {
048        /***
049         * The ascii transfer mode.  Its value is 0 and equivalent to NETASCII_MODE
050         ***/
051        public static final int ASCII_MODE = 0;
052    
053        /***
054         * The netascii transfer mode.  Its value is 0.
055         ***/
056        public static final int NETASCII_MODE = 0;
057    
058        /***
059         * The binary transfer mode.  Its value is 1 and equivalent to OCTET_MODE.
060         ***/
061        public static final int BINARY_MODE = 1;
062    
063        /***
064         * The image transfer mode.  Its value is 1 and equivalent to OCTET_MODE.
065         ***/
066        public static final int IMAGE_MODE = 1;
067    
068        /***
069         * The octet transfer mode.  Its value is 1.
070         ***/
071        public static final int OCTET_MODE = 1;
072    
073        /***
074         * The default number of milliseconds to wait to receive a datagram
075         * before timing out.  The default is 5000 milliseconds (5 seconds).
076         ***/
077        public static final int DEFAULT_TIMEOUT = 5000;
078    
079        /***
080         * The default TFTP port according to RFC 783 is 69.
081         ***/
082        public static final int DEFAULT_PORT = 69;
083    
084        /***
085         * The size to use for TFTP packet buffers.  Its 4 plus the
086         * TFTPPacket.SEGMENT_SIZE, i.e. 516.
087         ***/
088        static final int PACKET_SIZE = TFTPPacket.SEGMENT_SIZE + 4;
089    
090        /*** A buffer used to accelerate receives in bufferedReceive() ***/
091        private byte[] __receiveBuffer;
092    
093        /*** A datagram used to minimize memory allocation in bufferedReceive() ***/
094        private DatagramPacket __receiveDatagram;
095    
096        /*** A datagram used to minimize memory allocation in bufferedSend() ***/
097        private DatagramPacket __sendDatagram;
098    
099        /***
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    }