    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    }