1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.commons.net.tftp;
17
18 import java.net.DatagramPacket;
19 import java.net.InetAddress;
20
21 /***
22 * An abstract class derived from TFTPPacket definiing a TFTP Request
23 * packet type. It is subclassed by the
24 * {@link org.apache.commons.net.tftp.TFTPReadRequestPacket}
25 * and
26 * {@link org.apache.commons.net.tftp.TFTPWriteRequestPacket}
27 * classes.
28 * <p>
29 * Details regarding the TFTP protocol and the format of TFTP packets can
30 * be found in RFC 783. But the point of these classes is to keep you
31 * from having to worry about the internals. Additionally, only very
32 * few people should have to care about any of the TFTPPacket classes
33 * or derived classes. Almost all users should only be concerned with the
34 * {@link org.apache.commons.net.tftp.TFTPClient} class
35 * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()}
36 * and
37 * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()}
38 * methods.
39 * <p>
40 * <p>
41 * @author Daniel F. Savarese
42 * @see TFTPPacket
43 * @see TFTPReadRequestPacket
44 * @see TFTPWriteRequestPacket
45 * @see TFTPPacketException
46 * @see TFTP
47 ***/
48
49 public abstract class TFTPRequestPacket extends TFTPPacket
50 {
51 /***
52 * An array containing the string names of the transfer modes and indexed
53 * by the transfer mode constants.
54 ***/
55 static final String[] _modeStrings = { "netascii", "octet" };
56
57 /***
58 * A null terminated byte array representation of the ascii names of the
59 * transfer mode constants. This is convenient for creating the TFTP
60 * request packets.
61 ***/
62 static final byte[] _modeBytes[] = {
63 { (byte)'n', (byte)'e', (byte)'t', (byte)'a', (byte)'s', (byte)'c',
64 (byte)'i', (byte)'i', 0 },
65 { (byte)'o', (byte)'c', (byte)'t', (byte)'e', (byte)'t', 0 }
66 };
67
68 /*** The transfer mode of the request. ***/
69 int _mode;
70
71 /*** The filename of the request. ***/
72 String _filename;
73
74 /***
75 * Creates a request packet of a given type to be sent to a host at a
76 * given port with a filename and transfer mode request.
77 * <p>
78 * @param destination The host to which the packet is going to be sent.
79 * @param port The port to which the packet is going to be sent.
80 * @param type The type of the request (either TFTPPacket.READ_REQUEST or
81 * TFTPPacket.WRITE_REQUEST).
82 * @param filename The requested filename.
83 * @param mode The requested transfer mode. This should be on of the TFTP
84 * class MODE constants (e.g., TFTP.NETASCII_MODE).
85 ***/
86 TFTPRequestPacket(InetAddress destination, int port,
87 int type, String filename, int mode)
88 {
89 super(type, destination, port);
90
91 _filename = filename;
92 _mode = mode;
93 }
94
95 /***
96 * Creates a request packet of a given type based on a received
97 * datagram. Assumes the datagram is at least length 4, else an
98 * ArrayIndexOutOfBoundsException may be thrown.
99 * <p>
100 * @param type The type of the request (either TFTPPacket.READ_REQUEST or
101 * TFTPPacket.WRITE_REQUEST).
102 * @param datagram The datagram containing the received request.
103 * @throws TFTPPacketException If the datagram isn't a valid TFTP
104 * request packet of the appropriate type.
105 ***/
106 TFTPRequestPacket(int type, DatagramPacket datagram)
107 throws TFTPPacketException
108 {
109 super(type, datagram.getAddress(), datagram.getPort());
110
111 byte[] data;
112 int index, length;
113 String mode;
114 StringBuffer buffer;
115
116 data = datagram.getData();
117
118 if (getType() != data[1])
119 throw new TFTPPacketException("TFTP operator code does not match type.");
120
121 buffer = new StringBuffer();
122
123 index = 2;
124 length = datagram.getLength();
125
126 while (index < length && data[index] != 0)
127 {
128 buffer.append((char)data[index]);
129 ++index;
130 }
131
132 _filename = buffer.toString();
133
134 if (index >= length)
135 throw new TFTPPacketException("Bad filename and mode format.");
136
137 buffer.setLength(0);
138 ++index;
139 while (index < length && data[index] != 0)
140 {
141 buffer.append((char)data[index]);
142 ++index;
143 }
144
145 mode = buffer.toString().toLowerCase();
146 length = _modeStrings.length;
147
148 for (index = 0; index < length; index++)
149 {
150 if (mode.equals(_modeStrings[index]))
151 {
152 _mode = index;
153 break;
154 }
155 }
156
157 if (index >= length)
158 {
159 throw new TFTPPacketException("Unrecognized TFTP transfer mode: " + mode);
160
161
162
163 }
164 }
165
166
167 /***
168 * This is a method only available within the package for
169 * implementing efficient datagram transport by elminating buffering.
170 * It takes a datagram as an argument, and a byte buffer in which
171 * to store the raw datagram data. Inside the method, the data
172 * is set as the datagram's data and the datagram returned.
173 * <p>
174 * @param datagram The datagram to create.
175 * @param data The buffer to store the packet and to use in the datagram.
176 * @return The datagram argument.
177 ***/
178 final DatagramPacket _newDatagram(DatagramPacket datagram, byte[] data)
179 {
180 int fileLength, modeLength;
181
182 fileLength = _filename.length();
183 modeLength = _modeBytes[_mode].length;
184
185 data[0] = 0;
186 data[1] = (byte)_type;
187 System.arraycopy(_filename.getBytes(), 0, data, 2, fileLength);
188 data[fileLength + 2] = 0;
189 System.arraycopy(_modeBytes[_mode], 0, data, fileLength + 3,
190 modeLength);
191
192 datagram.setAddress(_address);
193 datagram.setPort(_port);
194 datagram.setData(data);
195 datagram.setLength(fileLength + modeLength + 3);
196
197 return datagram;
198 }
199
200 /***
201 * Creates a UDP datagram containing all the TFTP
202 * request packet data in the proper format.
203 * This is a method exposed to the programmer in case he
204 * wants to implement his own TFTP client instead of using
205 * the {@link org.apache.commons.net.tftp.TFTPClient}
206 * class. Under normal circumstances, you should not have a need to call
207 * this method.
208 * <p>
209 * @return A UDP datagram containing the TFTP request packet.
210 ***/
211 public final DatagramPacket newDatagram()
212 {
213 int fileLength, modeLength;
214 byte[] data;
215
216 fileLength = _filename.length();
217 modeLength = _modeBytes[_mode].length;
218
219 data = new byte[fileLength + modeLength + 4];
220 data[0] = 0;
221 data[1] = (byte)_type;
222 System.arraycopy(_filename.getBytes(), 0, data, 2, fileLength);
223 data[fileLength + 2] = 0;
224 System.arraycopy(_modeBytes[_mode], 0, data, fileLength + 3,
225 modeLength);
226
227 return new DatagramPacket(data, data.length, _address, _port);
228 }
229
230 /***
231 * Returns the transfer mode of the request.
232 * <p>
233 * @return The transfer mode of the request.
234 ***/
235 public final int getMode()
236 {
237 return _mode;
238 }
239
240 /***
241 * Returns the requested filename.
242 * <p>
243 * @return The requested filename.
244 ***/
245 public final String getFilename()
246 {
247 return _filename;
248 }
249 }