001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    package org.apache.commons.net.tftp;
019    
020    import java.io.IOException;
021    import java.io.InterruptedIOException;
022    import java.net.DatagramPacket;
023    import java.net.SocketException;
024    
025    import org.apache.commons.net.DatagramSocketClient;
026    
027    /***
028     * The TFTP class exposes a set of methods to allow you to deal with the TFTP
029     * protocol directly, in case you want to write your own TFTP client or
030     * server.  However, almost every user should only be concerend with
031     * the {@link org.apache.commons.net.DatagramSocketClient#open  open() },
032     * and {@link org.apache.commons.net.DatagramSocketClient#close  close() },
033     * methods. Additionally,the a
034     * {@link org.apache.commons.net.DatagramSocketClient#setDefaultTimeout setDefaultTimeout() }
035     *  method may be of importance for performance tuning.
036     * <p>
037     * Details regarding the TFTP protocol and the format of TFTP packets can
038     * be found in RFC 783.  But the point of these classes is to keep you
039     * from having to worry about the internals.
040     * <p>
041     * <p>
042     * @see org.apache.commons.net.DatagramSocketClient
043     * @see TFTPPacket
044     * @see TFTPPacketException
045     * @see TFTPClient
046     ***/
047    
048    public class TFTP extends DatagramSocketClient
049    {
050        /***
051         * The ascii transfer mode.  Its value is 0 and equivalent to NETASCII_MODE
052         ***/
053        public static final int ASCII_MODE = 0;
054    
055        /***
056         * The netascii transfer mode.  Its value is 0.
057         ***/
058        public static final int NETASCII_MODE = 0;
059    
060        /***
061         * The binary transfer mode.  Its value is 1 and equivalent to OCTET_MODE.
062         ***/
063        public static final int BINARY_MODE = 1;
064    
065        /***
066         * The image transfer mode.  Its value is 1 and equivalent to OCTET_MODE.
067         ***/
068        public static final int IMAGE_MODE = 1;
069    
070        /***
071         * The octet transfer mode.  Its value is 1.
072         ***/
073        public static final int OCTET_MODE = 1;
074    
075        /***
076         * The default number of milliseconds to wait to receive a datagram
077         * before timing out.  The default is 5000 milliseconds (5 seconds).
078         ***/
079        public static final int DEFAULT_TIMEOUT = 5000;
080    
081        /***
082         * The default TFTP port according to RFC 783 is 69.
083         ***/
084        public static final int DEFAULT_PORT = 69;
085    
086        /***
087         * The size to use for TFTP packet buffers.  Its 4 plus the
088         * TFTPPacket.SEGMENT_SIZE, i.e. 516.
089         ***/
090        static final int PACKET_SIZE = TFTPPacket.SEGMENT_SIZE + 4;
091    
092        /*** A buffer used to accelerate receives in bufferedReceive() ***/
093        private byte[] __receiveBuffer;
094    
095        /*** A datagram used to minimize memory allocation in bufferedReceive() ***/
096        private DatagramPacket __receiveDatagram;
097    
098        /*** A datagram used to minimize memory allocation in bufferedSend() ***/
099        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         * <p>
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(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         * <p>
139         * @exception IOException if an I/O error occurs.
140         ***/
141        public final void discardPackets() throws IOException
142        {
143            int to;
144            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            catch (SocketException e)
157            {
158                // Do nothing.  We timed out so we hope we're caught up.
159            }
160            catch (InterruptedIOException e)
161            {
162                // Do nothing.  We timed out so we hope we're caught up.
163            }
164    
165            setSoTimeout(to);
166        }
167    
168    
169        /***
170         * This is a special method to perform a more efficient packet receive.
171         * It should only be used after calling
172         * {@link #beginBufferedOps  beginBufferedOps() }.  beginBufferedOps()
173         * initializes a set of buffers used internally that prevent the new
174         * allocation of a DatagramPacket and byte array for each send and receive.
175         * To use these buffers you must call the bufferedReceive() and
176         * bufferedSend() methods instead of send() and receive().  You must
177         * also be certain that you don't manipulate the resulting packet in
178         * such a way that it interferes with future buffered operations.
179         * For example, a TFTPDataPacket received with bufferedReceive() will
180         * have a reference to the internal byte buffer.  You must finish using
181         * this data before calling bufferedReceive() again, or else the data
182         * will be overwritten by the the call.
183         * <p>
184         * @return The TFTPPacket received.
185         * @exception InterruptedIOException  If a socket timeout occurs.  The
186         *       Java documentation claims an InterruptedIOException is thrown
187         *       on a DatagramSocket timeout, but in practice we find a
188         *       SocketException is thrown.  You should catch both to be safe.
189         * @exception SocketException  If a socket timeout occurs.  The
190         *       Java documentation claims an InterruptedIOException is thrown
191         *       on a DatagramSocket timeout, but in practice we find a
192         *       SocketException is thrown.  You should catch both to be safe.
193         * @exception IOException  If some other I/O error occurs.
194         * @exception TFTPPacketException If an invalid TFTP packet is received.
195         ***/
196        public final TFTPPacket bufferedReceive() throws IOException,
197                    InterruptedIOException, SocketException, TFTPPacketException
198        {
199            __receiveDatagram.setData(__receiveBuffer);
200            __receiveDatagram.setLength(__receiveBuffer.length);
201            _socket_.receive(__receiveDatagram);
202    
203            return TFTPPacket.newTFTPPacket(__receiveDatagram);
204        }
205    
206        /***
207         * This is a special method to perform a more efficient packet send.
208         * It should only be used after calling
209         * {@link #beginBufferedOps  beginBufferedOps() }.  beginBufferedOps()
210         * initializes a set of buffers used internally that prevent the new
211         * allocation of a DatagramPacket and byte array for each send and receive.
212         * To use these buffers you must call the bufferedReceive() and
213         * bufferedSend() methods instead of send() and receive().  You must
214         * also be certain that you don't manipulate the resulting packet in
215         * such a way that it interferes with future buffered operations.
216         * For example, a TFTPDataPacket received with bufferedReceive() will
217         * have a reference to the internal byte buffer.  You must finish using
218         * this data before calling bufferedReceive() again, or else the data
219         * will be overwritten by the the call.
220         * <p>
221         * @param packet  The TFTP packet to send.
222         * @exception IOException  If some  I/O error occurs.
223         ***/
224        public final void bufferedSend(TFTPPacket packet) throws IOException
225        {
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         * <p>
263         * @param packet  The TFTP packet to send.
264         * @exception IOException  If some  I/O error occurs.
265         ***/
266        public final void send(TFTPPacket packet) throws IOException
267        {
268            _socket_.send(packet.newDatagram());
269        }
270    
271    
272        /***
273         * Receives a TFTPPacket.
274         * <p>
275         * @return The TFTPPacket received.
276         * @exception InterruptedIOException  If a socket timeout occurs.  The
277         *       Java documentation claims an InterruptedIOException is thrown
278         *       on a DatagramSocket timeout, but in practice we find a
279         *       SocketException is thrown.  You should catch both to be safe.
280         * @exception SocketException  If a socket timeout occurs.  The
281         *       Java documentation claims an InterruptedIOException is thrown
282         *       on a DatagramSocket timeout, but in practice we find a
283         *       SocketException is thrown.  You should catch both to be safe.
284         * @exception IOException  If some other I/O error occurs.
285         * @exception TFTPPacketException If an invalid TFTP packet is received.
286         ***/
287        public final TFTPPacket receive() throws IOException, InterruptedIOException,
288                    SocketException, TFTPPacketException
289        {
290            DatagramPacket packet;
291    
292            packet = new DatagramPacket(new byte[PACKET_SIZE], PACKET_SIZE);
293    
294            _socket_.receive(packet);
295    
296            return TFTPPacket.newTFTPPacket(packet);
297        }
298    
299    
300    }