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: * An array containing the string names of the transfer modes and indexed
052: * by the transfer mode constants.
053: ***/
054: static final String[] _modeStrings = { "netascii", "octet" };
055:
056: /***
057: * A null terminated byte array representation of the ascii names of the
058: * transfer mode constants. This is convenient for creating the TFTP
059: * request packets.
060: ***/
061: static final byte[] _modeBytes[] = {
062: { (byte) 'n', (byte) 'e', (byte) 't', (byte) 'a',
063: (byte) 's', (byte) 'c', (byte) 'i', (byte) 'i', 0 },
064: { (byte) 'o', (byte) 'c', (byte) 't', (byte) 'e',
065: (byte) 't', 0 } };
066:
067: /*** The transfer mode of the request. ***/
068: int _mode;
069:
070: /*** The filename of the request. ***/
071: String _filename;
072:
073: /***
074: * Creates a request packet of a given type to be sent to a host at a
075: * given port with a filename and transfer mode request.
076: * <p>
077: * @param destination The host to which the packet is going to be sent.
078: * @param port The port to which the packet is going to be sent.
079: * @param type The type of the request (either TFTPPacket.READ_REQUEST or
080: * TFTPPacket.WRITE_REQUEST).
081: * @param filename The requested filename.
082: * @param mode The requested transfer mode. This should be on of the TFTP
083: * class MODE constants (e.g., TFTP.NETASCII_MODE).
084: ***/
085: TFTPRequestPacket(InetAddress destination, int port, int type,
086: String filename, int mode) {
087: super (type, destination, port);
088:
089: _filename = filename;
090: _mode = mode;
091: }
092:
093: /***
094: * Creates a request packet of a given type based on a received
095: * datagram. Assumes the datagram is at least length 4, else an
096: * ArrayIndexOutOfBoundsException may be thrown.
097: * <p>
098: * @param type The type of the request (either TFTPPacket.READ_REQUEST or
099: * TFTPPacket.WRITE_REQUEST).
100: * @param datagram The datagram containing the received request.
101: * @throws TFTPPacketException If the datagram isn't a valid TFTP
102: * request packet of the appropriate type.
103: ***/
104: TFTPRequestPacket(int type, DatagramPacket datagram)
105: throws TFTPPacketException {
106: super (type, datagram.getAddress(), datagram.getPort());
107:
108: byte[] data;
109: int index, length;
110: String mode;
111: StringBuffer buffer;
112:
113: data = datagram.getData();
114:
115: if (getType() != data[1])
116: throw new TFTPPacketException(
117: "TFTP operator code does not match type.");
118:
119: buffer = new StringBuffer();
120:
121: index = 2;
122: length = datagram.getLength();
123:
124: while (index < length && data[index] != 0) {
125: buffer.append((char) data[index]);
126: ++index;
127: }
128:
129: _filename = buffer.toString();
130:
131: if (index >= length)
132: throw new TFTPPacketException(
133: "Bad filename and mode format.");
134:
135: buffer.setLength(0);
136: ++index; // need to advance beyond the end of string marker
137: while (index < length && data[index] != 0) {
138: buffer.append((char) data[index]);
139: ++index;
140: }
141:
142: mode = buffer.toString().toLowerCase();
143: length = _modeStrings.length;
144:
145: for (index = 0; index < length; index++) {
146: if (mode.equals(_modeStrings[index])) {
147: _mode = index;
148: break;
149: }
150: }
151:
152: if (index >= length) {
153: throw new TFTPPacketException(
154: "Unrecognized TFTP transfer mode: " + mode);
155: // May just want to default to binary mode instead of throwing
156: // exception.
157: //_mode = TFTP.OCTET_MODE;
158: }
159: }
160:
161: /***
162: * This is a method only available within the package for
163: * implementing efficient datagram transport by elminating buffering.
164: * It takes a datagram as an argument, and a byte buffer in which
165: * to store the raw datagram data. Inside the method, the data
166: * is set as the datagram's data and the datagram returned.
167: * <p>
168: * @param datagram The datagram to create.
169: * @param data The buffer to store the packet and to use in the datagram.
170: * @return The datagram argument.
171: ***/
172: final DatagramPacket _newDatagram(DatagramPacket datagram,
173: byte[] data) {
174: int fileLength, modeLength;
175:
176: fileLength = _filename.length();
177: modeLength = _modeBytes[_mode].length;
178:
179: data[0] = 0;
180: data[1] = (byte) _type;
181: System.arraycopy(_filename.getBytes(), 0, data, 2, fileLength);
182: data[fileLength + 2] = 0;
183: System.arraycopy(_modeBytes[_mode], 0, data, fileLength + 3,
184: modeLength);
185:
186: datagram.setAddress(_address);
187: datagram.setPort(_port);
188: datagram.setData(data);
189: datagram.setLength(fileLength + modeLength + 3);
190:
191: return datagram;
192: }
193:
194: /***
195: * Creates a UDP datagram containing all the TFTP
196: * request packet data in the proper format.
197: * This is a method exposed to the programmer in case he
198: * wants to implement his own TFTP client instead of using
199: * the {@link org.apache.commons.net.tftp.TFTPClient}
200: * class. Under normal circumstances, you should not have a need to call
201: * this method.
202: * <p>
203: * @return A UDP datagram containing the TFTP request packet.
204: ***/
205: public final DatagramPacket newDatagram() {
206: int fileLength, modeLength;
207: byte[] data;
208:
209: fileLength = _filename.length();
210: modeLength = _modeBytes[_mode].length;
211:
212: data = new byte[fileLength + modeLength + 4];
213: data[0] = 0;
214: data[1] = (byte) _type;
215: System.arraycopy(_filename.getBytes(), 0, data, 2, fileLength);
216: data[fileLength + 2] = 0;
217: System.arraycopy(_modeBytes[_mode], 0, data, fileLength + 3,
218: modeLength);
219:
220: return new DatagramPacket(data, data.length, _address, _port);
221: }
222:
223: /***
224: * Returns the transfer mode of the request.
225: * <p>
226: * @return The transfer mode of the request.
227: ***/
228: public final int getMode() {
229: return _mode;
230: }
231:
232: /***
233: * Returns the requested filename.
234: * <p>
235: * @return The requested filename.
236: ***/
237: public final String getFilename() {
238: return _filename;
239: }
240: }
|