View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.net.tftp;
19  
20  import java.net.DatagramPacket;
21  import java.net.InetAddress;
22  
23  /**
24   * TFTPPacket is an abstract class encapsulating the functionality common to the 5 types of TFTP packets. It also provides a static factory method that will
25   * create the correct TFTP packet instance from a datagram. This relieves the programmer from having to figure out what kind of TFTP packet is contained in a
26   * datagram and create it himself.
27   * <p>
28   * Details regarding the TFTP protocol and the format of TFTP packets can be found in RFC 783. But the point of these classes is to keep you from having to
29   * worry about the internals. Additionally, only very few people should have to care about any of the TFTPPacket classes or derived classes. Almost all users
30   * should only be concerned with the {@link org.apache.commons.net.tftp.TFTPClient} class {@link org.apache.commons.net.tftp.TFTPClient#receiveFile
31   * receiveFile()} and {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()} methods.
32   * </p>
33   *
34   * @see TFTPPacketException
35   * @see TFTP
36   */
37  
38  public abstract class TFTPPacket {
39  
40      /**
41       * The minimum size of a packet. This is 4 bytes. It is enough to store the opcode and blocknumber or other required data depending on the packet type.
42       */
43      static final int MIN_PACKET_SIZE = 4;
44  
45      /**
46       * This is the actual TFTP spec identifier and is equal to 1. Identifier returned by {@link #getType getType()} indicating a read request packet.
47       */
48      public static final int READ_REQUEST = 1;
49  
50      /**
51       * This is the actual TFTP spec identifier and is equal to 2. Identifier returned by {@link #getType getType()} indicating a write request packet.
52       */
53      public static final int WRITE_REQUEST = 2;
54  
55      /**
56       * This is the actual TFTP spec identifier and is equal to 3. Identifier returned by {@link #getType getType()} indicating a data packet.
57       */
58      public static final int DATA = 3;
59  
60      /**
61       * This is the actual TFTP spec identifier and is equal to 4. Identifier returned by {@link #getType getType()} indicating an acknowledgement packet.
62       */
63      public static final int ACKNOWLEDGEMENT = 4;
64  
65      /**
66       * This is the actual TFTP spec identifier and is equal to 5. Identifier returned by {@link #getType getType()} indicating an error packet.
67       */
68      public static final int ERROR = 5;
69  
70      /**
71       * TFTP spec identifier {@value}. Identifier returned by {@link #getType getType()} indicating an options acknowledgement packet.
72       *
73       * @since 3.12.0
74       */
75      public static final int OACK = 6;
76  
77      /**
78       * The TFTP data packet maximum segment size in bytes. This is 512 and is useful for those familiar with the TFTP protocol who want to use the
79       * {@link org.apache.commons.net.tftp.TFTP} class methods to implement their own TFTP servers or clients.
80       */
81      public static final int SEGMENT_SIZE = 512;
82  
83      /**
84       * When you receive a datagram that you expect to be a TFTP packet, you use this factory method to create the proper TFTPPacket object encapsulating the
85       * data contained in that datagram. This method is the only way you can instantiate a TFTPPacket derived class from a datagram.
86       *
87       * @param datagram The datagram containing a TFTP packet.
88       * @return The TFTPPacket object corresponding to the datagram.
89       * @throws TFTPPacketException If the datagram does not contain a valid TFTP packet.
90       */
91      public static final TFTPPacket newTFTPPacket(final DatagramPacket datagram) throws TFTPPacketException {
92          if (datagram.getLength() < MIN_PACKET_SIZE) {
93              throw new TFTPPacketException("Bad packet. Datagram data length is too short.");
94          }
95          final byte[] data = datagram.getData();
96          final TFTPPacket packet;
97          switch (data[1]) {
98          case READ_REQUEST:
99              packet = new TFTPReadRequestPacket(datagram);
100             break;
101         case WRITE_REQUEST:
102             packet = new TFTPWriteRequestPacket(datagram);
103             break;
104         case DATA:
105             packet = new TFTPDataPacket(datagram);
106             break;
107         case ACKNOWLEDGEMENT:
108             packet = new TFTPAckPacket(datagram);
109             break;
110         case ERROR:
111             packet = new TFTPErrorPacket(datagram);
112             break;
113         default:
114             throw new TFTPPacketException("Bad packet.  Invalid TFTP operator code.");
115         }
116         return packet;
117     }
118 
119     /** The type of packet. */
120     int type;
121 
122     /** The port the packet came from or is going to. */
123     int port;
124 
125     /** The host the packet is going to be sent or where it came from. */
126     InetAddress address;
127 
128     /**
129      * This constructor is not visible outside the package. It is used by subclasses within the package to initialize base data.
130      *
131      * @param type    The type of the packet.
132      * @param address The host the packet came from or is going to be sent.
133      * @param port    The port the packet came from or is going to be sent.
134      **/
135     TFTPPacket(final int type, final InetAddress address, final int port) {
136         this.type = type;
137         this.address = address;
138         this.port = port;
139     }
140 
141     /**
142      * Gets the address of the host where the packet is going to be sent or where it came from.
143      *
144      * @return The type of the packet.
145      */
146     public final InetAddress getAddress() {
147         return address;
148     }
149 
150     /**
151      * Gets the port where the packet is going to be sent or where it came from.
152      *
153      * @return The port where the packet came from or where it is going.
154      */
155     public final int getPort() {
156         return port;
157     }
158 
159     /**
160      * Gets the type of the packet.
161      *
162      * @return The type of the packet.
163      */
164     public final int getType() {
165         return type;
166     }
167 
168     /**
169      * Creates a UDP datagram containing all the TFTP packet data in the proper format. This is an abstract method, exposed to the programmer in case he wants
170      * to implement his own TFTP client instead of using the {@link org.apache.commons.net.tftp.TFTPClient} class. Under normal circumstances, you should not
171      * have a need to call this method.
172      *
173      * @return A UDP datagram containing the TFTP packet.
174      */
175     public abstract DatagramPacket newDatagram();
176 
177     /**
178      * This is an abstract method only available within the package for implementing efficient datagram transport by eliminating buffering. It takes a datagram
179      * as an argument, and a byte buffer in which to store the raw datagram data. Inside the method, the data should be set as the datagram's data and the
180      * datagram returned.
181      *
182      * @param datagram The datagram to create.
183      * @param data     The buffer to store the packet and to use in the datagram.
184      * @return The datagram argument.
185      */
186     abstract DatagramPacket newDatagram(DatagramPacket datagram, byte[] data);
187 
188     /**
189      * Sets the host address where the packet is going to be sent.
190      *
191      * @param address the address to set
192      */
193     public final void setAddress(final InetAddress address) {
194         this.address = address;
195     }
196 
197     /**
198      * Sets the port where the packet is going to be sent.
199      *
200      * @param port the port to set
201      */
202     public final void setPort(final int port) {
203         this.port = port;
204     }
205 
206     /**
207      * For debugging
208      *
209      * @since 3.6
210      */
211     @Override
212     public String toString() {
213         return address + " " + port + " " + type;
214     }
215 }