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            }
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    }