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
018package org.apache.commons.net.tftp;
019
020import java.io.IOException;
021import java.io.InterruptedIOException;
022import java.net.DatagramPacket;
023import java.net.SocketException;
024
025import 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 *
041 *
042 * @see org.apache.commons.net.DatagramSocketClient
043 * @see TFTPPacket
044 * @see TFTPPacketException
045 * @see TFTPClient
046 ***/
047
048public 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     *
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     *
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     *
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     *
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     *
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     *
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}