    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.net.DatagramPacket;
    021import 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 *
    041 *
    042 * @see TFTPPacketException
    043 * @see TFTP
    044 ***/
    045
    046public 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     *
    119     * @param datagram  The datagram containing a TFTP packet.
    120     * @return The TFTPPacket object corresponding to the datagram.
    121     * @throws TFTPPacketException  If the datagram does not contain a valid
    122     *             TFTP packet.
    123     ***/
    124    public static final TFTPPacket newTFTPPacket(final 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     *
    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(final int type, final InetAddress address, final int port)
    171    {
    172        this.type = type;
    173        this.address = address;
    174        this.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     *
    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     *
    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     *
    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     *
    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     *
    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    /***
    237     * Sets the port where the packet is going to be sent.
    238     * @param port the port to set
    239     ***/
    240    public final void setPort(final int port)
    241    {
    242        this.port = port;
    243    }
    244
    245    /*** Sets the host address where the packet is going to be sent.
    246     * @param address the address to set
    247     ***/
    248    public final void setAddress(final InetAddress address)
    249    {
    250        this.address = address;
    251    }
    252
    253    /**
    254     * For debugging
    255     * @since 3.6
    256     */
    257    @Override
    258    public String toString() {
    259        return address + " " + port + " " + type;
    260    }
    261}