    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.net.DatagramPacket;
    021    import java.net.InetAddress;
    022
    023    /***
    024     * TFTPPacket is an abstract class encapsulating the functionality common
    025     * to the 5 types of TFTP packets.  It also provides a static factory
    026     * method that will create the correct TFTP packet instance from a
    027     * datagram.  This relieves the programmer from having to figure out what
    028     * kind of TFTP packet is contained in a datagram and create it himself.
    029     * <p>
    030     * Details regarding the TFTP protocol and the format of TFTP packets can
    031     * be found in RFC 783.  But the point of these classes is to keep you
    032     * from having to worry about the internals.  Additionally, only very
    033     * few people should have to care about any of the TFTPPacket classes
    034     * or derived classes.  Almost all users should only be concerned with the
    035     * {@link org.apache.commons.net.tftp.TFTPClient} class
    036     * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()}
    037     * and
    038     * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()}
    039     * methods.
    040     * <p>
    041     * <p>
    042     * @see TFTPPacketException
    043     * @see TFTP
    044     ***/
    045
    046    public abstract class TFTPPacket
    047    {
    048        /***
    049         * The minimum size of a packet.  This is 4 bytes.  It is enough
    050         * to store the opcode and blocknumber or other required data
    051         * depending on the packet type.
    052         ***/
    053        static final int MIN_PACKET_SIZE = 4;
    054
    055        /***
    056         * This is the actual TFTP spec
    057         * identifier and is equal to 1.
    058         * Identifier returned by {@link #getType getType()}
    059         * indicating a read request packet.
    060         ***/
    061        public static final int READ_REQUEST = 1;
    062
    063        /***
    064         * This is the actual TFTP spec
    065         * identifier and is equal to 2.
    066         * Identifier returned by {@link #getType getType()}
    067         * indicating a write request packet.
    068         ***/
    069        public static final int WRITE_REQUEST = 2;
    070
    071        /***
    072         * This is the actual TFTP spec
    073         * identifier and is equal to 3.
    074         * Identifier returned by {@link #getType getType()}
    075         * indicating a data packet.
    076         ***/
    077        public static final int DATA = 3;
    078
    079        /***
    080         * This is the actual TFTP spec
    081         * identifier and is equal to 4.
    082         * Identifier returned by {@link #getType getType()}
    083         * indicating an acknowledgement packet.
    084         ***/
    085        public static final int ACKNOWLEDGEMENT = 4;
    086
    087        /***
    088         * This is the actual TFTP spec
    089         * identifier and is equal to 5.
    090         * Identifier returned by {@link #getType getType()}
    091         * indicating an error packet.
    092         ***/
    093        public static final int ERROR = 5;
    094
    095        /***
    096         * The TFTP data packet maximum segment size in bytes.  This is 512
    097         * and is useful for those familiar with the TFTP protocol who want
    098         * to use the {@link org.apache.commons.net.tftp.TFTP}
    099         * class methods to implement their own TFTP servers or clients.
    100         ***/
    101        public static final int SEGMENT_SIZE = 512;
    102
    103        /*** The type of packet. ***/
    104        int _type;
    105
    106        /*** The port the packet came from or is going to. ***/
    107        int _port;
    108
    109        /*** The host the packet is going to be sent or where it came from. ***/
    110        InetAddress _address;
    111
    112        /***
    113         * When you receive a datagram that you expect to be a TFTP packet, you use
    114         * this factory method to create the proper TFTPPacket object
    115         * encapsulating the data contained in that datagram.  This method is the
    116         * only way you can instantiate a TFTPPacket derived class from a
    117         * datagram.
    118         * <p>
    119         * @param datagram  The datagram containing a TFTP packet.
    120         * @return The TFTPPacket object corresponding to the datagram.
    121         * @exception TFTPPacketException  If the datagram does not contain a valid
    122         *             TFTP packet.
    123         ***/
    124        public final static TFTPPacket newTFTPPacket(DatagramPacket datagram)
    125        throws TFTPPacketException
    126        {
    127            byte[] data;
    128            TFTPPacket packet = null;
    129
    130            if (datagram.getLength() < MIN_PACKET_SIZE) {
    131                throw new TFTPPacketException(
    132                    "Bad packet. Datagram data length is too short.");
    133            }
    134
    135            data = datagram.getData();
    136
    137            switch (data[1])
    138            {
    139            case READ_REQUEST:
    140                packet = new TFTPReadRequestPacket(datagram);
    141                break;
    142            case WRITE_REQUEST:
    143                packet = new TFTPWriteRequestPacket(datagram);
    144                break;
    145            case DATA:
    146                packet = new TFTPDataPacket(datagram);
    147                break;
    148            case ACKNOWLEDGEMENT:
    149                packet = new TFTPAckPacket(datagram);
    150                break;
    151            case ERROR:
    152                packet = new TFTPErrorPacket(datagram);
    153                break;
    154            default:
    155                throw new TFTPPacketException(
    156                    "Bad packet.  Invalid TFTP operator code.");
    157            }
    158
    159            return packet;
    160        }
    161
    162        /***
    163         * This constructor is not visible outside of the package.  It is used
    164         * by subclasses within the package to initialize base data.
    165         * <p>
    166         * @param type The type of the packet.
    167         * @param address The host the packet came from or is going to be sent.
    168         * @param port The port the packet came from or is going to be sent.
    169         **/
    170        TFTPPacket(int type, InetAddress address, int port)
    171        {
    172            _type = type;
    173            _address = address;
    174            _port = port;
    175        }
    176
    177        /***
    178         * This is an abstract method only available within the package for
    179         * implementing efficient datagram transport by elminating buffering.
    180         * It takes a datagram as an argument, and a byte buffer in which
    181         * to store the raw datagram data.  Inside the method, the data
    182         * should be set as the datagram's data and the datagram returned.
    183         * <p>
    184         * @param datagram  The datagram to create.
    185         * @param data The buffer to store the packet and to use in the datagram.
    186         * @return The datagram argument.
    187         ***/
    188        abstract DatagramPacket _newDatagram(DatagramPacket datagram, byte[] data);
    189
    190        /***
    191         * Creates a UDP datagram containing all the TFTP packet
    192         * data in the proper format.
    193         * This is an abstract method, exposed to the programmer in case he
    194         * wants to implement his own TFTP client instead of using
    195         * the {@link org.apache.commons.net.tftp.TFTPClient}
    196         * class.
    197         * Under normal circumstances, you should not have a need to call this
    198         * method.
    199         * <p>
    200         * @return A UDP datagram containing the TFTP packet.
    201         ***/
    202        public abstract DatagramPacket newDatagram();
    203
    204        /***
    205         * Returns the type of the packet.
    206         * <p>
    207         * @return The type of the packet.
    208         ***/
    209        public final int getType()
    210        {
    211            return _type;
    212        }
    213
    214        /***
    215         * Returns the address of the host where the packet is going to be sent
    216         * or where it came from.
    217         * <p>
    218         * @return The type of the packet.
    219         ***/
    220        public final InetAddress getAddress()
    221        {
    222            return _address;
    223        }
    224
    225        /***
    226         * Returns the port where the packet is going to be sent
    227         * or where it came from.
    228         * <p>
    229         * @return The port where the packet came from or where it is going.
    230         ***/
    231        public final int getPort()
    232        {
    233            return _port;
    234        }
    235
    236        /*** Sets the port where the packet is going to be sent. ***/
    237        public final void setPort(int port)
    238        {
    239            _port = port;
    240        }
    241
    242        /*** Sets the host address where the packet is going to be sent. ***/
    243        public final void setAddress(InetAddress address)
    244        {
    245            _address = address;
    246        }
    247    }