    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     * @author Daniel F. Savarese
    043     * @see org.apache.commons.net.DatagramSocketClient
    044     * @see TFTPPacket
    045     * @see TFTPPacketException
    046     * @see TFTPClient
    047     ***/
    048
    049    public class TFTP extends DatagramSocketClient
    050    {
    051        /***
    052         * The ascii transfer mode.  Its value is 0 and equivalent to NETASCII_MODE
    053         ***/
    054        public static final int ASCII_MODE = 0;
    055
    056        /***
    057         * The netascii transfer mode.  Its value is 0.
    058         ***/
    059        public static final int NETASCII_MODE = 0;
    060
    061        /***
    062         * The binary transfer mode.  Its value is 1 and equivalent to OCTET_MODE.
    063         ***/
    064        public static final int BINARY_MODE = 1;
    065
    066        /***
    067         * The image transfer mode.  Its value is 1 and equivalent to OCTET_MODE.
    068         ***/
    069        public static final int IMAGE_MODE = 1;
    070
    071        /***
    072         * The octet transfer mode.  Its value is 1.
    073         ***/
    074        public static final int OCTET_MODE = 1;
    075
    076        /***
    077         * The default number of milliseconds to wait to receive a datagram
    078         * before timing out.  The default is 5000 milliseconds (5 seconds).
    079         ***/
    080        public static final int DEFAULT_TIMEOUT = 5000;
    081
    082        /***
    083         * The default TFTP port according to RFC 783 is 69.
    084         ***/
    085        public static final int DEFAULT_PORT = 69;
    086
    087        /***
    088         * The size to use for TFTP packet buffers.  Its 4 plus the
    089         * TFTPPacket.SEGMENT_SIZE, i.e. 516.
    090         ***/
    091        static final int PACKET_SIZE = TFTPPacket.SEGMENT_SIZE + 4;
    092
    093        /*** A buffer used to accelerate receives in bufferedReceive() ***/
    094        private byte[] __receiveBuffer;
    095
    096        /*** A datagram used to minimize memory allocation in bufferedReceive() ***/
    097        private DatagramPacket __receiveDatagram;
    098
    099        /*** A datagram used to minimize memory allocation in bufferedSend() ***/
    100        private DatagramPacket __sendDatagram;
    101
    102        /***
    103         * A buffer used to accelerate sends in bufferedSend().
    104         * It is left package visible so that TFTPClient may be slightly more
    105         * efficient during file sends.  It saves the creation of an
    106         * additional buffer and prevents a buffer copy in _newDataPcket().
    107         ***/
    108        byte[] _sendBuffer;
    109
    110
    111        /***
    112         * Returns the TFTP string representation of a TFTP transfer mode.
    113         * Will throw an ArrayIndexOutOfBoundsException if an invalid transfer
    114         * mode is specified.
    115         * <p>
    116         * @param mode  The TFTP transfer mode.  One of the MODE constants.
    117         * @return  The TFTP string representation of the TFTP transfer mode.
    118         ***/
    119        public static final String getModeName(int mode)
    120        {
    121            return TFTPRequestPacket._modeStrings[mode];
    122        }
    123
    124        /***
    125         * Creates a TFTP instance with a default timeout of DEFAULT_TIMEOUT,
    126         * a null socket, and buffered operations disabled.
    127         ***/
    128        public TFTP()
    129        {
    130            setDefaultTimeout(DEFAULT_TIMEOUT);
    131            __receiveBuffer = null;
    132            __receiveDatagram = null;
    133        }
    134
    135        /***
    136         * This method synchronizes a connection by discarding all packets that
    137         * may be in the local socket buffer.  This method need only be called
    138         * when you implement your own TFTP client or server.
    139         * <p>
    140         * @exception IOException if an I/O error occurs.
    141         ***/
    142        public final void discardPackets() throws IOException
    143        {
    144            int to;
    145            DatagramPacket datagram;
    146
    147            datagram = new DatagramPacket(new byte[PACKET_SIZE], PACKET_SIZE);
    148
    149            to = getSoTimeout();
    150            setSoTimeout(1);
    151
    152            try
    153            {
    154                while (true)
    155                    _socket_.receive(datagram);
    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    }