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 }