TFTPClientpublic class TFTPClient extends TFTP The TFTPClient class encapsulates all the aspects of the TFTP protocol
necessary to receive and send files through TFTP. It is derived from
the {@link org.apache.commons.net.tftp.TFTP} because
it is more convenient than using aggregation, and as a result exposes
the same set of methods to allow you to deal with the TFTP protocol
directly. However, almost every user should only be concerend with the
the {@link org.apache.commons.net.DatagramSocketClient#open open() },
{@link org.apache.commons.net.DatagramSocketClient#close close() },
{@link #sendFile sendFile() }, and
{@link #receiveFile receiveFile() } methods. Additionally, the
{@link #setMaxTimeouts setMaxTimeouts() } and
{@link org.apache.commons.net.DatagramSocketClient#setDefaultTimeout setDefaultTimeout() }
methods 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.
|
Fields Summary |
---|
public static final int | DEFAULT_MAX_TIMEOUTSThe default number of times a receive attempt is allowed to timeout
before ending attempts to retry the receive and failing. The default
is 5 timeouts. | private int | __maxTimeoutsThe maximum number of timeouts allowed before failing. |
Constructors Summary |
---|
public TFTPClient()Creates a TFTPClient instance with a default timeout of DEFAULT_TIMEOUT,
maximum timeouts value of DEFAULT_MAX_TIMEOUTS, a null socket,
and buffered operations disabled.
__maxTimeouts = DEFAULT_MAX_TIMEOUTS;
|
Methods Summary |
---|
public int | getMaxTimeouts()Returns the maximum number of times a receive attempt is allowed to
timeout before ending attempts to retry the receive and failing.
return __maxTimeouts;
| public int | receiveFile(java.lang.String filename, int mode, java.io.OutputStream output, java.net.InetAddress host, int port)Requests a named file from a remote host, writes the
file to an OutputStream, closes the connection, and returns the number
of bytes read. A local UDP socket must first be created by
{@link org.apache.commons.net.DatagramSocketClient#open open()} before
invoking this method. This method will not close the OutputStream
containing the file; you must close it after the method invocation.
int bytesRead, timeouts, lastBlock, block, hostPort, dataLength;
TFTPPacket sent, received = null;
TFTPErrorPacket error;
TFTPDataPacket data;
TFTPAckPacket ack = new TFTPAckPacket(host, port, 0);
beginBufferedOps();
dataLength = lastBlock = hostPort = bytesRead = 0;
block = 1;
if (mode == TFTP.ASCII_MODE)
output = new FromNetASCIIOutputStream(output);
sent =
new TFTPReadRequestPacket(host, port, filename, mode);
_sendPacket:
do
{
bufferedSend(sent);
_receivePacket:
while (true)
{
timeouts = 0;
while (timeouts < __maxTimeouts)
{
try
{
received = bufferedReceive();
break;
}
catch (SocketException e)
{
if (++timeouts >= __maxTimeouts)
{
endBufferedOps();
throw new IOException("Connection timed out.");
}
continue;
}
catch (InterruptedIOException e)
{
if (++timeouts >= __maxTimeouts)
{
endBufferedOps();
throw new IOException("Connection timed out.");
}
continue;
}
catch (TFTPPacketException e)
{
endBufferedOps();
throw new IOException("Bad packet: " + e.getMessage());
}
}
// The first time we receive we get the port number and
// answering host address (for hosts with multiple IPs)
if (lastBlock == 0)
{
hostPort = received.getPort();
ack.setPort(hostPort);
if(!host.equals(received.getAddress()))
{
host = received.getAddress();
ack.setAddress(host);
sent.setAddress(host);
}
}
// Comply with RFC 783 indication that an error acknowledgement
// should be sent to originator if unexpected TID or host.
if (host.equals(received.getAddress()) &&
received.getPort() == hostPort)
{
switch (received.getType())
{
case TFTPPacket.ERROR:
error = (TFTPErrorPacket)received;
endBufferedOps();
throw new IOException("Error code " + error.getError() +
" received: " + error.getMessage());
case TFTPPacket.DATA:
data = (TFTPDataPacket)received;
dataLength = data.getDataLength();
lastBlock = data.getBlockNumber();
if (lastBlock == block)
{
try
{
output.write(data.getData(), data.getDataOffset(),
dataLength);
}
catch (IOException e)
{
error = new TFTPErrorPacket(host, hostPort,
TFTPErrorPacket.OUT_OF_SPACE,
"File write failed.");
bufferedSend(error);
endBufferedOps();
throw e;
}
++block;
break _receivePacket;
}
else
{
discardPackets();
if (lastBlock == (block - 1))
continue _sendPacket; // Resend last acknowledgement.
continue _receivePacket; // Start fetching packets again.
}
//break;
default:
endBufferedOps();
throw new IOException("Received unexpected packet type.");
}
}
else
{
error = new TFTPErrorPacket(received.getAddress(),
received.getPort(),
TFTPErrorPacket.UNKNOWN_TID,
"Unexpected host or port.");
bufferedSend(error);
continue _sendPacket;
}
// We should never get here, but this is a safety to avoid
// infinite loop. If only Java had the goto statement.
//break;
}
ack.setBlockNumber(lastBlock);
sent = ack;
bytesRead += dataLength;
} // First data packet less than 512 bytes signals end of stream.
while (dataLength == TFTPPacket.SEGMENT_SIZE);
bufferedSend(sent);
endBufferedOps();
return bytesRead;
| public int | receiveFile(java.lang.String filename, int mode, java.io.OutputStream output, java.lang.String hostname, int port)Requests a named file from a remote host, writes the
file to an OutputStream, closes the connection, and returns the number
of bytes read. A local UDP socket must first be created by
{@link org.apache.commons.net.DatagramSocketClient#open open()} before
invoking this method. This method will not close the OutputStream
containing the file; you must close it after the method invocation.
return receiveFile(filename, mode, output, InetAddress.getByName(hostname),
port);
| public int | receiveFile(java.lang.String filename, int mode, java.io.OutputStream output, java.net.InetAddress host)Same as calling receiveFile(filename, mode, output, host, TFTP.DEFAULT_PORT).
return receiveFile(filename, mode, output, host, DEFAULT_PORT);
| public int | receiveFile(java.lang.String filename, int mode, java.io.OutputStream output, java.lang.String hostname)Same as calling receiveFile(filename, mode, output, hostname, TFTP.DEFAULT_PORT).
return receiveFile(filename, mode, output, InetAddress.getByName(hostname),
DEFAULT_PORT);
| public void | sendFile(java.lang.String filename, int mode, java.io.InputStream input, java.net.InetAddress host)Same as calling sendFile(filename, mode, input, host, TFTP.DEFAULT_PORT).
sendFile(filename, mode, input, host, DEFAULT_PORT);
| public void | sendFile(java.lang.String filename, int mode, java.io.InputStream input, java.lang.String hostname)Same as calling sendFile(filename, mode, input, hostname, TFTP.DEFAULT_PORT).
sendFile(filename, mode, input, InetAddress.getByName(hostname),
DEFAULT_PORT);
| public void | sendFile(java.lang.String filename, int mode, java.io.InputStream input, java.net.InetAddress host, int port)Requests to send a file to a remote host, reads the file from an
InputStream, sends the file to the remote host, and closes the
connection. A local UDP socket must first be created by
{@link org.apache.commons.net.DatagramSocketClient#open open()} before
invoking this method. This method will not close the InputStream
containing the file; you must close it after the method invocation.
int bytesRead, timeouts, lastBlock, block, hostPort, dataLength, offset;
TFTPPacket sent, received = null;
TFTPErrorPacket error;
TFTPDataPacket data =
new TFTPDataPacket(host, port, 0, _sendBuffer, 4, 0);
;
TFTPAckPacket ack;
beginBufferedOps();
dataLength = lastBlock = hostPort = bytesRead = 0;
block = 0;
boolean lastAckWait = false;
if (mode == TFTP.ASCII_MODE)
input = new ToNetASCIIInputStream(input);
sent =
new TFTPWriteRequestPacket(host, port, filename, mode);
_sendPacket:
do
{
bufferedSend(sent);
_receivePacket:
while (true)
{
timeouts = 0;
while (timeouts < __maxTimeouts)
{
try
{
received = bufferedReceive();
break;
}
catch (SocketException e)
{
if (++timeouts >= __maxTimeouts)
{
endBufferedOps();
throw new IOException("Connection timed out.");
}
continue;
}
catch (InterruptedIOException e)
{
if (++timeouts >= __maxTimeouts)
{
endBufferedOps();
throw new IOException("Connection timed out.");
}
continue;
}
catch (TFTPPacketException e)
{
endBufferedOps();
throw new IOException("Bad packet: " + e.getMessage());
}
}
// The first time we receive we get the port number and
// answering host address (for hosts with multiple IPs)
if (lastBlock == 0)
{
hostPort = received.getPort();
data.setPort(hostPort);
if(!host.equals(received.getAddress()))
{
host = received.getAddress();
data.setAddress(host);
sent.setAddress(host);
}
}
// Comply with RFC 783 indication that an error acknowledgement
// should be sent to originator if unexpected TID or host.
if (host.equals(received.getAddress()) &&
received.getPort() == hostPort)
{
switch (received.getType())
{
case TFTPPacket.ERROR:
error = (TFTPErrorPacket)received;
endBufferedOps();
throw new IOException("Error code " + error.getError() +
" received: " + error.getMessage());
case TFTPPacket.ACKNOWLEDGEMENT:
ack = (TFTPAckPacket)received;
lastBlock = ack.getBlockNumber();
if (lastBlock == block)
{
++block;
if (lastAckWait)
break _sendPacket;
else
break _receivePacket;
}
else
{
discardPackets();
if (lastBlock == (block - 1))
continue _sendPacket; // Resend last acknowledgement.
continue _receivePacket; // Start fetching packets again.
}
//break;
default:
endBufferedOps();
throw new IOException("Received unexpected packet type.");
}
}
else
{
error = new TFTPErrorPacket(received.getAddress(),
received.getPort(),
TFTPErrorPacket.UNKNOWN_TID,
"Unexpected host or port.");
bufferedSend(error);
continue _sendPacket;
}
// We should never get here, but this is a safety to avoid
// infinite loop. If only Java had the goto statement.
//break;
}
dataLength = TFTPPacket.SEGMENT_SIZE;
offset = 4;
while (dataLength > 0 &&
(bytesRead = input.read(_sendBuffer, offset, dataLength)) > 0)
{
offset += bytesRead;
dataLength -= bytesRead;
}
data.setBlockNumber(block);
data.setData(_sendBuffer, 4, offset - 4);
sent = data;
}
while (dataLength == 0 || lastAckWait);
endBufferedOps();
| public void | sendFile(java.lang.String filename, int mode, java.io.InputStream input, java.lang.String hostname, int port)Requests to send a file to a remote host, reads the file from an
InputStream, sends the file to the remote host, and closes the
connection. A local UDP socket must first be created by
{@link org.apache.commons.net.DatagramSocketClient#open open()} before
invoking this method. This method will not close the InputStream
containing the file; you must close it after the method invocation.
sendFile(filename, mode, input, InetAddress.getByName(hostname), port);
| public void | setMaxTimeouts(int numTimeouts)Sets the maximum number of times a receive attempt is allowed to
timeout during a receiveFile() or sendFile() operation before ending
attempts to retry the receive and failing.
The default is DEFAULT_MAX_TIMEOUTS.
if (numTimeouts < 1)
__maxTimeouts = 1;
else
__maxTimeouts = numTimeouts;
|
|