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