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
018 package org.apache.commons.net.tftp;
019
020 import java.io.IOException;
021 import java.io.InterruptedIOException;
022 import java.net.DatagramPacket;
023 import java.net.SocketException;
024
025 import org.apache.commons.net.DatagramSocketClient;
026
027 /***
028 * The TFTP class exposes a set of methods to allow you to deal with the TFTP
029 * protocol directly, in case you want to write your own TFTP client or
030 * server. However, almost every user should only be concerend with
031 * the {@link org.apache.commons.net.DatagramSocketClient#open open() },
032 * and {@link org.apache.commons.net.DatagramSocketClient#close close() },
033 * methods. Additionally,the a
034 * {@link org.apache.commons.net.DatagramSocketClient#setDefaultTimeout setDefaultTimeout() }
035 * method may be of importance for performance tuning.
036 * <p>
037 * Details regarding the TFTP protocol and the format of TFTP packets can
038 * be found in RFC 783. But the point of these classes is to keep you
039 * from having to worry about the internals.
040 * <p>
041 * <p>
042 * @see org.apache.commons.net.DatagramSocketClient
043 * @see TFTPPacket
044 * @see TFTPPacketException
045 * @see TFTPClient
046 ***/
047
048 public class TFTP extends DatagramSocketClient
049 {
050 /***
051 * The ascii transfer mode. Its value is 0 and equivalent to NETASCII_MODE
052 ***/
053 public static final int ASCII_MODE = 0;
054
055 /***
056 * The netascii transfer mode. Its value is 0.
057 ***/
058 public static final int NETASCII_MODE = 0;
059
060 /***
061 * The binary transfer mode. Its value is 1 and equivalent to OCTET_MODE.
062 ***/
063 public static final int BINARY_MODE = 1;
064
065 /***
066 * The image transfer mode. Its value is 1 and equivalent to OCTET_MODE.
067 ***/
068 public static final int IMAGE_MODE = 1;
069
070 /***
071 * The octet transfer mode. Its value is 1.
072 ***/
073 public static final int OCTET_MODE = 1;
074
075 /***
076 * The default number of milliseconds to wait to receive a datagram
077 * before timing out. The default is 5000 milliseconds (5 seconds).
078 ***/
079 public static final int DEFAULT_TIMEOUT = 5000;
080
081 /***
082 * The default TFTP port according to RFC 783 is 69.
083 ***/
084 public static final int DEFAULT_PORT = 69;
085
086 /***
087 * The size to use for TFTP packet buffers. Its 4 plus the
088 * TFTPPacket.SEGMENT_SIZE, i.e. 516.
089 ***/
090 static final int PACKET_SIZE = TFTPPacket.SEGMENT_SIZE + 4;
091
092 /*** A buffer used to accelerate receives in bufferedReceive() ***/
093 private byte[] __receiveBuffer;
094
095 /*** A datagram used to minimize memory allocation in bufferedReceive() ***/
096 private DatagramPacket __receiveDatagram;
097
098 /*** A datagram used to minimize memory allocation in bufferedSend() ***/
099 private DatagramPacket __sendDatagram;
100
101 /***
102 * A buffer used to accelerate sends in bufferedSend().
103 * It is left package visible so that TFTPClient may be slightly more
104 * efficient during file sends. It saves the creation of an
105 * additional buffer and prevents a buffer copy in _newDataPcket().
106 ***/
107 byte[] _sendBuffer;
108
109
110 /***
111 * Returns the TFTP string representation of a TFTP transfer mode.
112 * Will throw an ArrayIndexOutOfBoundsException if an invalid transfer
113 * mode is specified.
114 * <p>
115 * @param mode The TFTP transfer mode. One of the MODE constants.
116 * @return The TFTP string representation of the TFTP transfer mode.
117 ***/
118 public static final String getModeName(int mode)
119 {
120 return TFTPRequestPacket._modeStrings[mode];
121 }
122
123 /***
124 * Creates a TFTP instance with a default timeout of DEFAULT_TIMEOUT,
125 * a null socket, and buffered operations disabled.
126 ***/
127 public TFTP()
128 {
129 setDefaultTimeout(DEFAULT_TIMEOUT);
130 __receiveBuffer = null;
131 __receiveDatagram = null;
132 }
133
134 /***
135 * This method synchronizes a connection by discarding all packets that
136 * may be in the local socket buffer. This method need only be called
137 * when you implement your own TFTP client or server.
138 * <p>
139 * @exception IOException if an I/O error occurs.
140 ***/
141 public final void discardPackets() throws IOException
142 {
143 int to;
144 DatagramPacket datagram;
145
146 datagram = new DatagramPacket(new byte[PACKET_SIZE], PACKET_SIZE);
147
148 to = getSoTimeout();
149 setSoTimeout(1);
150
151 try
152 {
153 while (true)
154 _socket_.receive(datagram);
155 }
156 catch (SocketException e)
157 {
158 // Do nothing. We timed out so we hope we're caught up.
159 }
160 catch (InterruptedIOException e)
161 {
162 // Do nothing. We timed out so we hope we're caught up.
163 }
164
165 setSoTimeout(to);
166 }
167
168
169 /***
170 * This is a special method to perform a more efficient packet receive.
171 * It should only be used after calling
172 * {@link #beginBufferedOps beginBufferedOps() }. beginBufferedOps()
173 * initializes a set of buffers used internally that prevent the new
174 * allocation of a DatagramPacket and byte array for each send and receive.
175 * To use these buffers you must call the bufferedReceive() and
176 * bufferedSend() methods instead of send() and receive(). You must
177 * also be certain that you don't manipulate the resulting packet in
178 * such a way that it interferes with future buffered operations.
179 * For example, a TFTPDataPacket received with bufferedReceive() will
180 * have a reference to the internal byte buffer. You must finish using
181 * this data before calling bufferedReceive() again, or else the data
182 * will be overwritten by the the call.
183 * <p>
184 * @return The TFTPPacket received.
185 * @exception InterruptedIOException If a socket timeout occurs. The
186 * Java documentation claims an InterruptedIOException is thrown
187 * on a DatagramSocket timeout, but in practice we find a
188 * SocketException is thrown. You should catch both to be safe.
189 * @exception SocketException If a socket timeout occurs. The
190 * Java documentation claims an InterruptedIOException is thrown
191 * on a DatagramSocket timeout, but in practice we find a
192 * SocketException is thrown. You should catch both to be safe.
193 * @exception IOException If some other I/O error occurs.
194 * @exception TFTPPacketException If an invalid TFTP packet is received.
195 ***/
196 public final TFTPPacket bufferedReceive() throws IOException,
197 InterruptedIOException, SocketException, TFTPPacketException
198 {
199 __receiveDatagram.setData(__receiveBuffer);
200 __receiveDatagram.setLength(__receiveBuffer.length);
201 _socket_.receive(__receiveDatagram);
202
203 return TFTPPacket.newTFTPPacket(__receiveDatagram);
204 }
205
206 /***
207 * This is a special method to perform a more efficient packet send.
208 * It should only be used after calling
209 * {@link #beginBufferedOps beginBufferedOps() }. beginBufferedOps()
210 * initializes a set of buffers used internally that prevent the new
211 * allocation of a DatagramPacket and byte array for each send and receive.
212 * To use these buffers you must call the bufferedReceive() and
213 * bufferedSend() methods instead of send() and receive(). You must
214 * also be certain that you don't manipulate the resulting packet in
215 * such a way that it interferes with future buffered operations.
216 * For example, a TFTPDataPacket received with bufferedReceive() will
217 * have a reference to the internal byte buffer. You must finish using
218 * this data before calling bufferedReceive() again, or else the data
219 * will be overwritten by the the call.
220 * <p>
221 * @param packet The TFTP packet to send.
222 * @exception IOException If some I/O error occurs.
223 ***/
224 public final void bufferedSend(TFTPPacket packet) throws IOException
225 {
226 _socket_.send(packet._newDatagram(__sendDatagram, _sendBuffer));
227 }
228
229
230 /***
231 * Initializes the internal buffers. Buffers are used by
232 * {@link #bufferedSend bufferedSend() } and
233 * {@link #bufferedReceive bufferedReceive() }. This
234 * method must be called before calling either one of those two
235 * methods. When you finish using buffered operations, you must
236 * call {@link #endBufferedOps endBufferedOps() }.
237 ***/
238 public final void beginBufferedOps()
239 {
240 __receiveBuffer = new byte[PACKET_SIZE];
241 __receiveDatagram =
242 new DatagramPacket(__receiveBuffer, __receiveBuffer.length);
243 _sendBuffer = new byte[PACKET_SIZE];
244 __sendDatagram =
245 new DatagramPacket(_sendBuffer, _sendBuffer.length);
246 }
247
248 /***
249 * Releases the resources used to perform buffered sends and receives.
250 ***/
251 public final void endBufferedOps()
252 {
253 __receiveBuffer = null;
254 __receiveDatagram = null;
255 _sendBuffer = null;
256 __sendDatagram = null;
257 }
258
259
260 /***
261 * Sends a TFTP packet to its destination.
262 * <p>
263 * @param packet The TFTP packet to send.
264 * @exception IOException If some I/O error occurs.
265 ***/
266 public final void send(TFTPPacket packet) throws IOException
267 {
268 _socket_.send(packet.newDatagram());
269 }
270
271
272 /***
273 * Receives a TFTPPacket.
274 * <p>
275 * @return The TFTPPacket received.
276 * @exception InterruptedIOException If a socket timeout occurs. The
277 * Java documentation claims an InterruptedIOException is thrown
278 * on a DatagramSocket timeout, but in practice we find a
279 * SocketException is thrown. You should catch both to be safe.
280 * @exception SocketException If a socket timeout occurs. The
281 * Java documentation claims an InterruptedIOException is thrown
282 * on a DatagramSocket timeout, but in practice we find a
283 * SocketException is thrown. You should catch both to be safe.
284 * @exception IOException If some other I/O error occurs.
285 * @exception TFTPPacketException If an invalid TFTP packet is received.
286 ***/
287 public final TFTPPacket receive() throws IOException, InterruptedIOException,
288 SocketException, TFTPPacketException
289 {
290 DatagramPacket packet;
291
292 packet = new DatagramPacket(new byte[PACKET_SIZE], PACKET_SIZE);
293
294 _socket_.receive(packet);
295
296 return TFTPPacket.newTFTPPacket(packet);
297 }
298
299
300 }