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(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(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     *
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(int port)
241    {
242        _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(InetAddress address)
249    {
250        _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}