1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.commons.net.tftp;
17
18 import java.io.IOException;
19 import java.io.InterruptedIOException;
20 import java.net.DatagramPacket;
21 import java.net.SocketException;
22 import org.apache.commons.net.DatagramSocketClient;
23
24 /***
25 * The TFTP class exposes a set of methods to allow you to deal with the TFTP
26 * protocol directly, in case you want to write your own TFTP client or
27 * server. However, almost every user should only be concerend with
28 * the {@link org.apache.commons.net.DatagramSocketClient#open open() },
29 * and {@link org.apache.commons.net.DatagramSocketClient#close close() },
30 * methods. Additionally,the a
31 * {@link org.apache.commons.net.DatagramSocketClient#setDefaultTimeout setDefaultTimeout() }
32 * method may be of importance for performance tuning.
33 * <p>
34 * Details regarding the TFTP protocol and the format of TFTP packets can
35 * be found in RFC 783. But the point of these classes is to keep you
36 * from having to worry about the internals.
37 * <p>
38 * <p>
39 * @author Daniel F. Savarese
40 * @see org.apache.commons.net.DatagramSocketClient
41 * @see TFTPPacket
42 * @see TFTPPacketException
43 * @see TFTPClient
44 ***/
45
46 public class TFTP extends DatagramSocketClient
47 {
48 /***
49 * The ascii transfer mode. Its value is 0 and equivalent to NETASCII_MODE
50 ***/
51 public static final int ASCII_MODE = 0;
52
53 /***
54 * The netascii transfer mode. Its value is 0.
55 ***/
56 public static final int NETASCII_MODE = 0;
57
58 /***
59 * The binary transfer mode. Its value is 1 and equivalent to OCTET_MODE.
60 ***/
61 public static final int BINARY_MODE = 1;
62
63 /***
64 * The image transfer mode. Its value is 1 and equivalent to OCTET_MODE.
65 ***/
66 public static final int IMAGE_MODE = 1;
67
68 /***
69 * The octet transfer mode. Its value is 1.
70 ***/
71 public static final int OCTET_MODE = 1;
72
73 /***
74 * The default number of milliseconds to wait to receive a datagram
75 * before timing out. The default is 5000 milliseconds (5 seconds).
76 ***/
77 public static final int DEFAULT_TIMEOUT = 5000;
78
79 /***
80 * The default TFTP port according to RFC 783 is 69.
81 ***/
82 public static final int DEFAULT_PORT = 69;
83
84 /***
85 * The size to use for TFTP packet buffers. Its 4 plus the
86 * TFTPPacket.SEGMENT_SIZE, i.e. 516.
87 ***/
88 static final int PACKET_SIZE = TFTPPacket.SEGMENT_SIZE + 4;
89
90 /*** A buffer used to accelerate receives in bufferedReceive() ***/
91 private byte[] __receiveBuffer;
92
93 /*** A datagram used to minimize memory allocation in bufferedReceive() ***/
94 private DatagramPacket __receiveDatagram;
95
96 /*** A datagram used to minimize memory allocation in bufferedSend() ***/
97 private DatagramPacket __sendDatagram;
98
99 /***
100 * A buffer used to accelerate sends in bufferedSend().
101 * It is left package visible so that TFTPClient may be slightly more
102 * efficient during file sends. It saves the creation of an
103 * additional buffer and prevents a buffer copy in _newDataPcket().
104 ***/
105 byte[] _sendBuffer;
106
107
108 /***
109 * Returns the TFTP string representation of a TFTP transfer mode.
110 * Will throw an ArrayIndexOutOfBoundsException if an invalid transfer
111 * mode is specified.
112 * <p>
113 * @param mode The TFTP transfer mode. One of the MODE constants.
114 * @return The TFTP string representation of the TFTP transfer mode.
115 ***/
116 public static final String getModeName(int mode)
117 {
118 return TFTPRequestPacket._modeStrings[mode];
119 }
120
121 /***
122 * Creates a TFTP instance with a default timeout of DEFAULT_TIMEOUT,
123 * a null socket, and buffered operations disabled.
124 ***/
125 public TFTP()
126 {
127 setDefaultTimeout(DEFAULT_TIMEOUT);
128 __receiveBuffer = null;
129 __receiveDatagram = null;
130 }
131
132 /***
133 * This method synchronizes a connection by discarding all packets that
134 * may be in the local socket buffer. This method need only be called
135 * when you implement your own TFTP client or server.
136 * <p>
137 * @exception IOException if an I/O error occurs.
138 ***/
139 public final void discardPackets() throws IOException
140 {
141 int to;
142 DatagramPacket datagram;
143
144 datagram = new DatagramPacket(new byte[PACKET_SIZE], PACKET_SIZE);
145
146 to = getSoTimeout();
147 setSoTimeout(1);
148
149 try
150 {
151 while (true)
152 _socket_.receive(datagram);
153 }
154 catch (SocketException e)
155 {
156
157 }
158 catch (InterruptedIOException e)
159 {
160
161 }
162
163 setSoTimeout(to);
164 }
165
166
167 /***
168 * This is a special method to perform a more efficient packet receive.
169 * It should only be used after calling
170 * {@link #beginBufferedOps beginBufferedOps() }. beginBufferedOps()
171 * initializes a set of buffers used internally that prevent the new
172 * allocation of a DatagramPacket and byte array for each send and receive.
173 * To use these buffers you must call the bufferedReceive() and
174 * bufferedSend() methods instead of send() and receive(). You must
175 * also be certain that you don't manipulate the resulting packet in
176 * such a way that it interferes with future buffered operations.
177 * For example, a TFTPDataPacket received with bufferedReceive() will
178 * have a reference to the internal byte buffer. You must finish using
179 * this data before calling bufferedReceive() again, or else the data
180 * will be overwritten by the the call.
181 * <p>
182 * @return The TFTPPacket received.
183 * @exception InterruptedIOException If a socket timeout occurs. The
184 * Java documentation claims an InterruptedIOException is thrown
185 * on a DatagramSocket timeout, but in practice we find a
186 * SocketException is thrown. You should catch both to be safe.
187 * @exception SocketException If a socket timeout occurs. The
188 * Java documentation claims an InterruptedIOException is thrown
189 * on a DatagramSocket timeout, but in practice we find a
190 * SocketException is thrown. You should catch both to be safe.
191 * @exception IOException If some other I/O error occurs.
192 * @exception TFTPPacketException If an invalid TFTP packet is received.
193 ***/
194 public final TFTPPacket bufferedReceive() throws IOException,
195 InterruptedIOException, SocketException, TFTPPacketException
196 {
197 __receiveDatagram.setData(__receiveBuffer);
198 __receiveDatagram.setLength(__receiveBuffer.length);
199 _socket_.receive(__receiveDatagram);
200
201 return TFTPPacket.newTFTPPacket(__receiveDatagram);
202 }
203
204 /***
205 * This is a special method to perform a more efficient packet send.
206 * It should only be used after calling
207 * {@link #beginBufferedOps beginBufferedOps() }. beginBufferedOps()
208 * initializes a set of buffers used internally that prevent the new
209 * allocation of a DatagramPacket and byte array for each send and receive.
210 * To use these buffers you must call the bufferedReceive() and
211 * bufferedSend() methods instead of send() and receive(). You must
212 * also be certain that you don't manipulate the resulting packet in
213 * such a way that it interferes with future buffered operations.
214 * For example, a TFTPDataPacket received with bufferedReceive() will
215 * have a reference to the internal byte buffer. You must finish using
216 * this data before calling bufferedReceive() again, or else the data
217 * will be overwritten by the the call.
218 * <p>
219 * @param packet The TFTP packet to send.
220 * @exception IOException If some I/O error occurs.
221 ***/
222 public final void bufferedSend(TFTPPacket packet) throws IOException
223 {
224 _socket_.send(packet._newDatagram(__sendDatagram, _sendBuffer));
225 }
226
227
228 /***
229 * Initializes the internal buffers. Buffers are used by
230 * {@link #bufferedSend bufferedSend() } and
231 * {@link #bufferedReceive bufferedReceive() }. This
232 * method must be called before calling either one of those two
233 * methods. When you finish using buffered operations, you must
234 * call {@link #endBufferedOps endBufferedOps() }.
235 ***/
236 public final void beginBufferedOps()
237 {
238 __receiveBuffer = new byte[PACKET_SIZE];
239 __receiveDatagram =
240 new DatagramPacket(__receiveBuffer, __receiveBuffer.length);
241 _sendBuffer = new byte[PACKET_SIZE];
242 __sendDatagram =
243 new DatagramPacket(_sendBuffer, _sendBuffer.length);
244 }
245
246 /***
247 * Releases the resources used to perform buffered sends and receives.
248 ***/
249 public final void endBufferedOps()
250 {
251 __receiveBuffer = null;
252 __receiveDatagram = null;
253 _sendBuffer = null;
254 __sendDatagram = null;
255 }
256
257
258 /***
259 * Sends a TFTP packet to its destination.
260 * <p>
261 * @param packet The TFTP packet to send.
262 * @exception IOException If some I/O error occurs.
263 ***/
264 public final void send(TFTPPacket packet) throws IOException
265 {
266 _socket_.send(packet.newDatagram());
267 }
268
269
270 /***
271 * Receives a TFTPPacket.
272 * <p>
273 * @return The TFTPPacket received.
274 * @exception InterruptedIOException If a socket timeout occurs. The
275 * Java documentation claims an InterruptedIOException is thrown
276 * on a DatagramSocket timeout, but in practice we find a
277 * SocketException is thrown. You should catch both to be safe.
278 * @exception SocketException If a socket timeout occurs. The
279 * Java documentation claims an InterruptedIOException is thrown
280 * on a DatagramSocket timeout, but in practice we find a
281 * SocketException is thrown. You should catch both to be safe.
282 * @exception IOException If some other I/O error occurs.
283 * @exception TFTPPacketException If an invalid TFTP packet is received.
284 ***/
285 public final TFTPPacket receive() throws IOException, InterruptedIOException,
286 SocketException, TFTPPacketException
287 {
288 DatagramPacket packet;
289
290 packet = new DatagramPacket(new byte[PACKET_SIZE], PACKET_SIZE);
291
292 _socket_.receive(packet);
293
294 return TFTPPacket.newTFTPPacket(packet);
295 }
296
297
298 }