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     * A final class derived from TFTPPacket definiing the TFTP Data
023     * packet type.
024     * <p>
025     * Details regarding the TFTP protocol and the format of TFTP packets can
026     * be found in RFC 783.  But the point of these classes is to keep you
027     * from having to worry about the internals.  Additionally, only very
028     * few people should have to care about any of the TFTPPacket classes
029     * or derived classes.  Almost all users should only be concerned with the
030     * {@link org.apache.commons.net.tftp.TFTPClient} class
031     * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()}
032     * and
033     * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()}
034     * methods.
035     * <p>
036     * <p>
037     * @author Daniel F. Savarese
038     * @see TFTPPacket
039     * @see TFTPPacketException
040     * @see TFTP
041     ***/
042    
043    public final class TFTPDataPacket extends TFTPPacket
044    {
045        /*** The maximum number of bytes in a TFTP data packet (512) ***/
046        public static final int MAX_DATA_LENGTH = 512;
047    
048        /*** The minimum number of bytes in a TFTP data packet (0) ***/
049        public static final int MIN_DATA_LENGTH = 0;
050    
051        /*** The block number of the packet. ***/
052        int _blockNumber;
053    
054        /*** The length of the data. ***/
055        int _length;
056    
057        /*** The offset into the _data array at which the data begins. ***/
058        int _offset;
059    
060        /*** The data stored in the packet. ***/
061        byte[] _data;
062    
063        /***
064         * Creates a data packet to be sent to a host at a given port
065         * with a given block number.  The actual data to be sent is passed as
066         * an array, an offset, and a length.  The offset is the offset into
067         * the byte array where the data starts.  The length is the length of
068         * the data.  If the length is greater than MAX_DATA_LENGTH, it is
069         * truncated.
070         * <p>
071         * @param destination  The host to which the packet is going to be sent.
072         * @param port  The port to which the packet is going to be sent.
073         * @param blockNumber The block number of the data.
074         * @param data The byte array containing the data.
075         * @param offset The offset into the array where the data starts.
076         * @param length The length of the data.
077         ***/
078        public TFTPDataPacket(InetAddress destination, int port, int blockNumber,
079                              byte[] data, int offset, int length)
080        {
081            super(TFTPPacket.DATA, destination, port);
082    
083            _blockNumber = blockNumber;
084            _data = data;
085            _offset = offset;
086    
087            if (length > MAX_DATA_LENGTH)
088                _length = MAX_DATA_LENGTH;
089            else
090                _length = length;
091        }
092    
093        public TFTPDataPacket(InetAddress destination, int port, int blockNumber,
094                              byte[] data)
095        {
096            this(destination, port, blockNumber, data, 0, data.length);
097        }
098    
099    
100        /***
101         * Creates a data packet based from a received
102         * datagram.  Assumes the datagram is at least length 4, else an
103         * ArrayIndexOutOfBoundsException may be thrown.
104         * <p>
105         * @param datagram  The datagram containing the received data.
106         * @throws TFTPPacketException  If the datagram isn't a valid TFTP
107         *         data packet.
108         ***/
109        TFTPDataPacket(DatagramPacket datagram) throws TFTPPacketException
110        {
111            super(TFTPPacket.DATA, datagram.getAddress(), datagram.getPort());
112    
113            _data = datagram.getData();
114            _offset = 4;
115    
116            if (getType() != _data[1])
117                throw new TFTPPacketException("TFTP operator code does not match type.");
118    
119            _blockNumber = (((_data[2] & 0xff) << 8) | (_data[3] & 0xff));
120    
121            _length = datagram.getLength() - 4;
122    
123            if (_length > MAX_DATA_LENGTH)
124                _length = MAX_DATA_LENGTH;
125        }
126    
127        /***
128         * This is a method only available within the package for
129         * implementing efficient datagram transport by elminating buffering.
130         * It takes a datagram as an argument, and a byte buffer in which
131         * to store the raw datagram data.  Inside the method, the data
132         * is set as the datagram's data and the datagram returned.
133         * <p>
134         * @param datagram  The datagram to create.
135         * @param data The buffer to store the packet and to use in the datagram.
136         * @return The datagram argument.
137         ***/
138        DatagramPacket _newDatagram(DatagramPacket datagram, byte[] data)
139        {
140            data[0] = 0;
141            data[1] = (byte)_type;
142            data[2] = (byte)((_blockNumber & 0xffff) >> 8);
143            data[3] = (byte)(_blockNumber & 0xff);
144    
145            // Doublecheck we're not the same
146            if (data != _data)
147                System.arraycopy(_data, _offset, data, 4, _length);
148    
149            datagram.setAddress(_address);
150            datagram.setPort(_port);
151            datagram.setData(data);
152            datagram.setLength(_length + 4);
153    
154            return datagram;
155        }
156    
157        /***
158         * Creates a UDP datagram containing all the TFTP
159         * data packet data in the proper format.
160         * This is a method exposed to the programmer in case he
161         * wants to implement his own TFTP client instead of using
162         * the {@link org.apache.commons.net.tftp.TFTPClient}
163         * class.
164         * Under normal circumstances, you should not have a need to call this
165         * method.
166         * <p>
167         * @return A UDP datagram containing the TFTP data packet.
168         ***/
169        public DatagramPacket newDatagram()
170        {
171            byte[] data;
172    
173            data = new byte[_length + 4];
174            data[0] = 0;
175            data[1] = (byte)_type;
176            data[2] = (byte)((_blockNumber & 0xffff) >> 8);
177            data[3] = (byte)(_blockNumber & 0xff);
178    
179            System.arraycopy(_data, _offset, data, 4, _length);
180    
181            return new DatagramPacket(data, _length + 4, _address, _port);
182        }
183    
184        /***
185         * Returns the block number of the data packet.
186         * <p>
187         * @return The block number of the data packet.
188         ***/
189        public int getBlockNumber()
190        {
191            return _blockNumber;
192        }
193    
194        /*** Sets the block number of the data packet.  ***/
195        public void setBlockNumber(int blockNumber)
196        {
197            _blockNumber = blockNumber;
198        }
199    
200        /***
201         * Sets the data for the data packet.
202         * <p>
203         * @param data The byte array containing the data.
204         * @param offset The offset into the array where the data starts.
205         * @param length The length of the data.
206         ***/
207        public void setData(byte[] data, int offset, int length)
208        {
209            _data = data;
210            _offset = offset;
211            _length = length;
212    
213            if (length > MAX_DATA_LENGTH)
214                _length = MAX_DATA_LENGTH;
215            else
216                _length = length;
217        }
218    
219        /***
220         * Returns the length of the data part of the data packet.
221         * <p>
222         * @return The length of the data part of the data packet.
223         ***/
224        public int getDataLength()
225        {
226            return _length;
227        }
228    
229        /***
230         * Returns the offset into the byte array where the packet data actually
231         * starts.
232         * <p>
233         * @return The offset into the byte array where the packet data actually
234         *         starts.
235         ***/
236        public int getDataOffset()
237        {
238            return _offset;
239        }
240    
241        /***
242         * Returns the byte array containing the packet data.
243         * <p>
244         * @return The byte array containing the packet data.
245         ***/
246        public byte[] getData()
247        {
248            return _data;
249        }
250    }