View Javadoc

1   /*
2    * Copyright 2001-2005 The Apache Software Foundation
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.apache.commons.net.tftp;
17  
18  import java.net.DatagramPacket;
19  import java.net.InetAddress;
20  
21  /***
22   * An abstract class derived from TFTPPacket definiing a TFTP Request
23   * packet type.  It is subclassed by the
24   * {@link org.apache.commons.net.tftp.TFTPReadRequestPacket}
25   *   and
26   * {@link org.apache.commons.net.tftp.TFTPWriteRequestPacket}
27   *  classes.
28   * <p>
29   * Details regarding the TFTP protocol and the format of TFTP packets can
30   * be found in RFC 783.  But the point of these classes is to keep you
31   * from having to worry about the internals.  Additionally, only very
32   * few people should have to care about any of the TFTPPacket classes
33   * or derived classes.  Almost all users should only be concerned with the
34   * {@link org.apache.commons.net.tftp.TFTPClient} class
35   * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()}
36   * and
37   * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()}
38   * methods.
39   * <p>
40   * <p>
41   * @author Daniel F. Savarese
42   * @see TFTPPacket
43   * @see TFTPReadRequestPacket
44   * @see TFTPWriteRequestPacket
45   * @see TFTPPacketException
46   * @see TFTP
47   ***/
48  
49  public abstract class TFTPRequestPacket extends TFTPPacket
50  {
51      /***
52       * An array containing the string names of the transfer modes and indexed
53       * by the transfer mode constants.
54       ***/
55      static final String[] _modeStrings = { "netascii", "octet" };
56  
57      /***
58       * A null terminated byte array representation of the ascii names of the
59       * transfer mode constants.  This is convenient for creating the TFTP
60       * request packets.
61       ***/
62      static final byte[] _modeBytes[] = {
63                                             { (byte)'n', (byte)'e', (byte)'t', (byte)'a', (byte)'s', (byte)'c',
64                                               (byte)'i', (byte)'i', 0 },
65                                             { (byte)'o', (byte)'c', (byte)'t', (byte)'e', (byte)'t', 0 }
66                                         };
67  
68      /*** The transfer mode of the request. ***/
69      int _mode;
70  
71      /*** The filename of the request. ***/
72      String _filename;
73  
74      /***
75       * Creates a request packet of a given type to be sent to a host at a
76       * given port with a filename and transfer mode request.
77       * <p>
78       * @param destination  The host to which the packet is going to be sent.
79       * @param port  The port to which the packet is going to be sent.
80       * @param type The type of the request (either TFTPPacket.READ_REQUEST or
81       *             TFTPPacket.WRITE_REQUEST).
82       * @param filename The requested filename.
83       * @param mode The requested transfer mode.  This should be on of the TFTP
84       *        class MODE constants (e.g., TFTP.NETASCII_MODE).
85       ***/
86      TFTPRequestPacket(InetAddress destination, int port,
87                        int type, String filename, int mode)
88      {
89          super(type, destination, port);
90  
91          _filename = filename;
92          _mode = mode;
93      }
94  
95      /***
96       * Creates a request packet of a given type based on a received
97       * datagram.  Assumes the datagram is at least length 4, else an
98       * ArrayIndexOutOfBoundsException may be thrown.
99       * <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 }