001 /*
002 * Copyright 2001-2005 The Apache Software Foundation
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.apache.commons.net.tftp;
017
018 import java.net.DatagramPacket;
019 import java.net.InetAddress;
020
021 /***
022 * An abstract class derived from TFTPPacket definiing a TFTP Request
023 * packet type. It is subclassed by the
024 * {@link org.apache.commons.net.tftp.TFTPReadRequestPacket}
025 * and
026 * {@link org.apache.commons.net.tftp.TFTPWriteRequestPacket}
027 * classes.
028 * <p>
029 * Details regarding the TFTP protocol and the format of TFTP packets can
030 * be found in RFC 783. But the point of these classes is to keep you
031 * from having to worry about the internals. Additionally, only very
032 * few people should have to care about any of the TFTPPacket classes
033 * or derived classes. Almost all users should only be concerned with the
034 * {@link org.apache.commons.net.tftp.TFTPClient} class
035 * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()}
036 * and
037 * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()}
038 * methods.
039 * <p>
040 * <p>
041 * @author Daniel F. Savarese
042 * @see TFTPPacket
043 * @see TFTPReadRequestPacket
044 * @see TFTPWriteRequestPacket
045 * @see TFTPPacketException
046 * @see TFTP
047 ***/
048
049 public abstract class TFTPRequestPacket extends TFTPPacket
050 {
051 /***
052 * An array containing the string names of the transfer modes and indexed
053 * by the transfer mode constants.
054 ***/
055 static final String[] _modeStrings = { "netascii", "octet" };
056
057 /***
058 * A null terminated byte array representation of the ascii names of the
059 * transfer mode constants. This is convenient for creating the TFTP
060 * request packets.
061 ***/
062 static final byte[] _modeBytes[] = {
063 { (byte)'n', (byte)'e', (byte)'t', (byte)'a', (byte)'s', (byte)'c',
064 (byte)'i', (byte)'i', 0 },
065 { (byte)'o', (byte)'c', (byte)'t', (byte)'e', (byte)'t', 0 }
066 };
067
068 /*** The transfer mode of the request. ***/
069 int _mode;
070
071 /*** The filename of the request. ***/
072 String _filename;
073
074 /***
075 * Creates a request packet of a given type to be sent to a host at a
076 * given port with a filename and transfer mode request.
077 * <p>
078 * @param destination The host to which the packet is going to be sent.
079 * @param port The port to which the packet is going to be sent.
080 * @param type The type of the request (either TFTPPacket.READ_REQUEST or
081 * TFTPPacket.WRITE_REQUEST).
082 * @param filename The requested filename.
083 * @param mode The requested transfer mode. This should be on of the TFTP
084 * class MODE constants (e.g., TFTP.NETASCII_MODE).
085 ***/
086 TFTPRequestPacket(InetAddress destination, int port,
087 int type, String filename, int mode)
088 {
089 super(type, destination, port);
090
091 _filename = filename;
092 _mode = mode;
093 }
094
095 /***
096 * Creates a request packet of a given type based on a received
097 * datagram. Assumes the datagram is at least length 4, else an
098 * ArrayIndexOutOfBoundsException may be thrown.
099 * <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; // need to advance beyond the end of string marker
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 // May just want to default to binary mode instead of throwing
161 // exception.
162 //_mode = TFTP.OCTET_MODE;
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 }