001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.net.tftp; 019 020import java.net.DatagramPacket; 021import java.net.InetAddress; 022 023/** 024 * A final class derived from TFTPPacket definiing the TFTP Data 025 * packet type. 026 * <p> 027 * Details regarding the TFTP protocol and the format of TFTP packets can 028 * be found in RFC 783. But the point of these classes is to keep you 029 * from having to worry about the internals. Additionally, only very 030 * few people should have to care about any of the TFTPPacket classes 031 * or derived classes. Almost all users should only be concerned with the 032 * {@link org.apache.commons.net.tftp.TFTPClient} class 033 * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()} 034 * and 035 * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()} 036 * methods. 037 * 038 * 039 * @see TFTPPacket 040 * @see TFTPPacketException 041 * @see TFTP 042 */ 043 044public final class TFTPDataPacket extends TFTPPacket 045{ 046 /** The maximum number of bytes in a TFTP data packet (512) */ 047 public static final int MAX_DATA_LENGTH = 512; 048 049 /** The minimum number of bytes in a TFTP data packet (0) */ 050 public static final int MIN_DATA_LENGTH = 0; 051 052 /** The block number of the packet. */ 053 int blockNumber; 054 055 /** The length of the data. */ 056 private int length; 057 058 /** The offset into the _data array at which the data begins. */ 059 private int offset; 060 061 /** The data stored in the packet. */ 062 private byte[] data; 063 064 /** 065 * Creates a data packet to be sent to a host at a given port 066 * with a given block number. The actual data to be sent is passed as 067 * an array, an offset, and a length. The offset is the offset into 068 * the byte array where the data starts. The length is the length of 069 * the data. If the length is greater than MAX_DATA_LENGTH, it is 070 * truncated. 071 * 072 * @param destination The host to which the packet is going to be sent. 073 * @param port The port to which the packet is going to be sent. 074 * @param blockNumber The block number of the data. 075 * @param data The byte array containing the data. 076 * @param offset The offset into the array where the data starts. 077 * @param length The length of the data. 078 */ 079 public TFTPDataPacket(final InetAddress destination, final int port, final int blockNumber, 080 final byte[] data, final int offset, final int length) 081 { 082 super(TFTPPacket.DATA, destination, port); 083 084 this.blockNumber = blockNumber; 085 this.data = data; 086 this.offset = offset; 087 088 if (length > MAX_DATA_LENGTH) { 089 this.length = MAX_DATA_LENGTH; 090 } else { 091 this.length = length; 092 } 093 } 094 095 public TFTPDataPacket(final InetAddress destination, final int port, final int blockNumber, 096 final byte[] data) 097 { 098 this(destination, port, blockNumber, data, 0, data.length); 099 } 100 101 102 /** 103 * Creates a data packet based from a received 104 * datagram. Assumes the datagram is at least length 4, else an 105 * ArrayIndexOutOfBoundsException may be thrown. 106 * 107 * @param datagram The datagram containing the received data. 108 * @throws TFTPPacketException If the datagram isn't a valid TFTP 109 * data packet. 110 */ 111 TFTPDataPacket(final DatagramPacket datagram) throws TFTPPacketException 112 { 113 super(TFTPPacket.DATA, datagram.getAddress(), datagram.getPort()); 114 115 this.data = datagram.getData(); 116 this.offset = 4; 117 118 if (getType() != this.data[1]) { 119 throw new TFTPPacketException("TFTP operator code does not match type."); 120 } 121 122 this.blockNumber = (((this.data[2] & 0xff) << 8) | (this.data[3] & 0xff)); 123 124 this.length = datagram.getLength() - 4; 125 126 if (this.length > MAX_DATA_LENGTH) { 127 this.length = MAX_DATA_LENGTH; 128 } 129 } 130 131 /** 132 * This is a method only available within the package for 133 * implementing efficient datagram transport by elminating buffering. 134 * It takes a datagram as an argument, and a byte buffer in which 135 * to store the raw datagram data. Inside the method, the data 136 * is set as the datagram's data and the datagram returned. 137 * 138 * @param datagram The datagram to create. 139 * @param data The buffer to store the packet and to use in the datagram. 140 * @return The datagram argument. 141 */ 142 @Override 143 DatagramPacket newDatagram(final DatagramPacket datagram, final byte[] data) 144 { 145 data[0] = 0; 146 data[1] = (byte)type; 147 data[2] = (byte)((blockNumber & 0xffff) >> 8); 148 data[3] = (byte)(blockNumber & 0xff); 149 150 // Doublecheck we're not the same 151 if (data != this.data) { 152 System.arraycopy(this.data, offset, data, 4, length); 153 } 154 155 datagram.setAddress(address); 156 datagram.setPort(port); 157 datagram.setData(data); 158 datagram.setLength(length + 4); 159 160 return datagram; 161 } 162 163 /** 164 * Creates a UDP datagram containing all the TFTP 165 * data packet data in the proper format. 166 * This is a method exposed to the programmer in case he 167 * wants to implement his own TFTP client instead of using 168 * the {@link org.apache.commons.net.tftp.TFTPClient} 169 * class. 170 * Under normal circumstances, you should not have a need to call this 171 * method. 172 * 173 * @return A UDP datagram containing the TFTP data packet. 174 */ 175 @Override 176 public DatagramPacket newDatagram() 177 { 178 final byte[] data; 179 180 data = new byte[length + 4]; 181 data[0] = 0; 182 data[1] = (byte)type; 183 data[2] = (byte)((blockNumber & 0xffff) >> 8); 184 data[3] = (byte)(blockNumber & 0xff); 185 186 System.arraycopy(this.data, offset, data, 4, length); 187 188 return new DatagramPacket(data, length + 4, address, port); 189 } 190 191 /** 192 * Returns the block number of the data packet. 193 * 194 * @return The block number of the data packet. 195 */ 196 public int getBlockNumber() 197 { 198 return blockNumber; 199 } 200 201 /** Sets the block number of the data packet. 202 * @param blockNumber the number to set 203 */ 204 public void setBlockNumber(final int blockNumber) 205 { 206 this.blockNumber = blockNumber; 207 } 208 209 /** 210 * Sets the data for the data packet. 211 * 212 * @param data The byte array containing the data. 213 * @param offset The offset into the array where the data starts. 214 * @param length The length of the data. 215 */ 216 public void setData(final byte[] data, final int offset, final int length) 217 { 218 this.data = data; 219 this.offset = offset; 220 this.length = length; 221 222 if (length > MAX_DATA_LENGTH) { 223 this.length = MAX_DATA_LENGTH; 224 } else { 225 this.length = length; 226 } 227 } 228 229 /** 230 * Returns the length of the data part of the data packet. 231 * 232 * @return The length of the data part of the data packet. 233 */ 234 public int getDataLength() 235 { 236 return length; 237 } 238 239 /** 240 * Returns the offset into the byte array where the packet data actually 241 * starts. 242 * 243 * @return The offset into the byte array where the packet data actually 244 * starts. 245 */ 246 public int getDataOffset() 247 { 248 return offset; 249 } 250 251 /** 252 * Returns the byte array containing the packet data. 253 * 254 * @return The byte array containing the packet data. 255 */ 256 public byte[] getData() 257 { 258 return data; 259 } 260 261 /** 262 * For debugging 263 * @since 3.6 264 */ 265 @Override 266 public String toString() { 267 return super.toString() + " DATA " + blockNumber + " " + length; 268 } 269}