panda.net.tftp.TFTP Maven / Gradle / Ivy
Show all versions of panda-nets Show documentation
package panda.net.tftp;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.DatagramPacket;
import java.net.SocketException;
import panda.net.DatagramSocketClient;
/***
* The TFTP class exposes a set of methods to allow you to deal with the TFTP protocol directly, in
* case you want to write your own TFTP client or server. However, almost every user should only be
* concerend with the {@link panda.net.DatagramSocketClient#open open() }, and
* {@link panda.net.DatagramSocketClient#close close() }, methods. Additionally,the a
* {@link panda.net.DatagramSocketClient#setDefaultTimeout setDefaultTimeout() } method may be of
* importance for performance tuning.
*
* Details regarding the TFTP protocol and the format of TFTP packets can be found in RFC 783. But
* the point of these classes is to keep you from having to worry about the internals.
*
* @see panda.net.DatagramSocketClient
* @see TFTPPacket
* @see TFTPPacketException
* @see TFTPClient
***/
public class TFTP extends DatagramSocketClient {
/***
* The ascii transfer mode. Its value is 0 and equivalent to NETASCII_MODE
***/
public static final int ASCII_MODE = 0;
/***
* The netascii transfer mode. Its value is 0.
***/
public static final int NETASCII_MODE = 0;
/***
* The binary transfer mode. Its value is 1 and equivalent to OCTET_MODE.
***/
public static final int BINARY_MODE = 1;
/***
* The image transfer mode. Its value is 1 and equivalent to OCTET_MODE.
***/
public static final int IMAGE_MODE = 1;
/***
* The octet transfer mode. Its value is 1.
***/
public static final int OCTET_MODE = 1;
/***
* The default number of milliseconds to wait to receive a datagram before timing out. The
* default is 5000 milliseconds (5 seconds).
***/
public static final int DEFAULT_TIMEOUT = 5000;
/***
* The default TFTP port according to RFC 783 is 69.
***/
public static final int DEFAULT_PORT = 69;
/***
* The size to use for TFTP packet buffers. Its 4 plus the TFTPPacket.SEGMENT_SIZE, i.e. 516.
***/
static final int PACKET_SIZE = TFTPPacket.SEGMENT_SIZE + 4;
/*** A buffer used to accelerate receives in bufferedReceive() ***/
private byte[] __receiveBuffer;
/*** A datagram used to minimize memory allocation in bufferedReceive() ***/
private DatagramPacket __receiveDatagram;
/*** A datagram used to minimize memory allocation in bufferedSend() ***/
private DatagramPacket __sendDatagram;
/***
* A buffer used to accelerate sends in bufferedSend(). It is left package visible so that
* TFTPClient may be slightly more efficient during file sends. It saves the creation of an
* additional buffer and prevents a buffer copy in _newDataPcket().
***/
byte[] _sendBuffer;
/***
* Returns the TFTP string representation of a TFTP transfer mode. Will throw an
* ArrayIndexOutOfBoundsException if an invalid transfer mode is specified.
*
* @param mode The TFTP transfer mode. One of the MODE constants.
* @return The TFTP string representation of the TFTP transfer mode.
***/
public static final String getModeName(int mode) {
return TFTPRequestPacket._modeStrings[mode];
}
/***
* Creates a TFTP instance with a default timeout of DEFAULT_TIMEOUT, a null socket, and
* buffered operations disabled.
***/
public TFTP() {
setDefaultTimeout(DEFAULT_TIMEOUT);
__receiveBuffer = null;
__receiveDatagram = null;
}
/***
* This method synchronizes a connection by discarding all packets that may be in the local
* socket buffer. This method need only be called when you implement your own TFTP client or
* server.
*
* @exception IOException if an I/O error occurs.
***/
public final void discardPackets() throws IOException {
int to;
DatagramPacket datagram;
datagram = new DatagramPacket(new byte[PACKET_SIZE], PACKET_SIZE);
to = getSoTimeout();
setSoTimeout(1);
try {
while (true) {
_socket_.receive(datagram);
}
}
catch (SocketException e) {
// Do nothing. We timed out so we hope we're caught up.
}
catch (InterruptedIOException e) {
// Do nothing. We timed out so we hope we're caught up.
}
setSoTimeout(to);
}
/***
* This is a special method to perform a more efficient packet receive. It should only be used
* after calling {@link #beginBufferedOps beginBufferedOps() }. beginBufferedOps() initializes a
* set of buffers used internally that prevent the new allocation of a DatagramPacket and byte
* array for each send and receive. To use these buffers you must call the bufferedReceive() and
* bufferedSend() methods instead of send() and receive(). You must also be certain that you
* don't manipulate the resulting packet in such a way that it interferes with future buffered
* operations. For example, a TFTPDataPacket received with bufferedReceive() will have a
* reference to the internal byte buffer. You must finish using this data before calling
* bufferedReceive() again, or else the data will be overwritten by the the call.
*
* @return The TFTPPacket received.
* @exception InterruptedIOException If a socket timeout occurs. The Java documentation claims
* an InterruptedIOException is thrown on a DatagramSocket timeout, but in
* practice we find a SocketException is thrown. You should catch both to be
* safe.
* @exception SocketException If a socket timeout occurs. The Java documentation claims an
* InterruptedIOException is thrown on a DatagramSocket timeout, but in practice
* we find a SocketException is thrown. You should catch both to be safe.
* @exception IOException If some other I/O error occurs.
* @exception TFTPPacketException If an invalid TFTP packet is received.
***/
public final TFTPPacket bufferedReceive() throws IOException, InterruptedIOException, SocketException,
TFTPPacketException {
__receiveDatagram.setData(__receiveBuffer);
__receiveDatagram.setLength(__receiveBuffer.length);
_socket_.receive(__receiveDatagram);
return TFTPPacket.newTFTPPacket(__receiveDatagram);
}
/***
* This is a special method to perform a more efficient packet send. It should only be used
* after calling {@link #beginBufferedOps beginBufferedOps() }. beginBufferedOps() initializes a
* set of buffers used internally that prevent the new allocation of a DatagramPacket and byte
* array for each send and receive. To use these buffers you must call the bufferedReceive() and
* bufferedSend() methods instead of send() and receive(). You must also be certain that you
* don't manipulate the resulting packet in such a way that it interferes with future buffered
* operations. For example, a TFTPDataPacket received with bufferedReceive() will have a
* reference to the internal byte buffer. You must finish using this data before calling
* bufferedReceive() again, or else the data will be overwritten by the the call.
*
* @param packet The TFTP packet to send.
* @exception IOException If some I/O error occurs.
***/
public final void bufferedSend(TFTPPacket packet) throws IOException {
_socket_.send(packet._newDatagram(__sendDatagram, _sendBuffer));
}
/***
* Initializes the internal buffers. Buffers are used by {@link #bufferedSend bufferedSend() }
* and {@link #bufferedReceive bufferedReceive() }. This method must be called before calling
* either one of those two methods. When you finish using buffered operations, you must call
* {@link #endBufferedOps endBufferedOps() }.
***/
public final void beginBufferedOps() {
__receiveBuffer = new byte[PACKET_SIZE];
__receiveDatagram = new DatagramPacket(__receiveBuffer, __receiveBuffer.length);
_sendBuffer = new byte[PACKET_SIZE];
__sendDatagram = new DatagramPacket(_sendBuffer, _sendBuffer.length);
}
/***
* Releases the resources used to perform buffered sends and receives.
***/
public final void endBufferedOps() {
__receiveBuffer = null;
__receiveDatagram = null;
_sendBuffer = null;
__sendDatagram = null;
}
/***
* Sends a TFTP packet to its destination.
*
* @param packet The TFTP packet to send.
* @exception IOException If some I/O error occurs.
***/
public final void send(TFTPPacket packet) throws IOException {
_socket_.send(packet.newDatagram());
}
/***
* Receives a TFTPPacket.
*
* @return The TFTPPacket received.
* @exception InterruptedIOException If a socket timeout occurs. The Java documentation claims
* an InterruptedIOException is thrown on a DatagramSocket timeout, but in
* practice we find a SocketException is thrown. You should catch both to be
* safe.
* @exception SocketException If a socket timeout occurs. The Java documentation claims an
* InterruptedIOException is thrown on a DatagramSocket timeout, but in practice
* we find a SocketException is thrown. You should catch both to be safe.
* @exception IOException If some other I/O error occurs.
* @exception TFTPPacketException If an invalid TFTP packet is received.
***/
public final TFTPPacket receive() throws IOException, InterruptedIOException, SocketException, TFTPPacketException {
DatagramPacket packet;
packet = new DatagramPacket(new byte[PACKET_SIZE], PACKET_SIZE);
_socket_.receive(packet);
return TFTPPacket.newTFTPPacket(packet);
}
}