summaryrefslogtreecommitdiff
path: root/org/apache/commons/net/tftp
diff options
context:
space:
mode:
authorJoe Robinson <joe@lc8n.com>2010-10-27 14:21:09 +0100
committerJoe Robinson <joe@lc8n.com>2010-10-27 14:21:09 +0100
commit063284837c8c366e5502b1b0264b8eb807b61732 (patch)
treefff3a1e1e5afaa671485b9d990704658276627ac /org/apache/commons/net/tftp
Basic upload functionality to predifined location, with basic file browser
Diffstat (limited to 'org/apache/commons/net/tftp')
-rw-r--r--org/apache/commons/net/tftp/TFTP.java301
-rw-r--r--org/apache/commons/net/tftp/TFTPAckPacket.java158
-rw-r--r--org/apache/commons/net/tftp/TFTPClient.java610
-rw-r--r--org/apache/commons/net/tftp/TFTPDataPacket.java254
-rw-r--r--org/apache/commons/net/tftp/TFTPErrorPacket.java226
-rw-r--r--org/apache/commons/net/tftp/TFTPPacket.java247
-rw-r--r--org/apache/commons/net/tftp/TFTPPacketException.java57
-rw-r--r--org/apache/commons/net/tftp/TFTPReadRequestPacket.java80
-rw-r--r--org/apache/commons/net/tftp/TFTPRequestPacket.java253
-rw-r--r--org/apache/commons/net/tftp/TFTPWriteRequestPacket.java79
10 files changed, 2265 insertions, 0 deletions
diff --git a/org/apache/commons/net/tftp/TFTP.java b/org/apache/commons/net/tftp/TFTP.java
new file mode 100644
index 0000000..662da11
--- /dev/null
+++ b/org/apache/commons/net/tftp/TFTP.java
@@ -0,0 +1,301 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.net.tftp;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.DatagramPacket;
+import java.net.SocketException;
+
+import org.apache.commons.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 org.apache.commons.net.DatagramSocketClient#open open() },
+ * and {@link org.apache.commons.net.DatagramSocketClient#close close() },
+ * methods. Additionally,the a
+ * {@link org.apache.commons.net.DatagramSocketClient#setDefaultTimeout setDefaultTimeout() }
+ * method may be of importance for performance tuning.
+ * <p>
+ * 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.
+ * <p>
+ * <p>
+ * @author Daniel F. Savarese
+ * @see org.apache.commons.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.
+ * <p>
+ * @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.
+ * <p>
+ * @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.
+ * <p>
+ * @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.
+ * <p>
+ * @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.
+ * <p>
+ * @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.
+ * <p>
+ * @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);
+ }
+
+
+}
diff --git a/org/apache/commons/net/tftp/TFTPAckPacket.java b/org/apache/commons/net/tftp/TFTPAckPacket.java
new file mode 100644
index 0000000..a0fe7f9
--- /dev/null
+++ b/org/apache/commons/net/tftp/TFTPAckPacket.java
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.net.tftp;
+
+import java.net.DatagramPacket;
+import java.net.InetAddress;
+
+/***
+ * A final class derived from TFTPPacket definiing the TFTP Acknowledgement
+ * packet type.
+ * <p>
+ * 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. Additionally, only very
+ * few people should have to care about any of the TFTPPacket classes
+ * or derived classes. Almost all users should only be concerned with the
+ * {@link org.apache.commons.net.tftp.TFTPClient} class
+ * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()}
+ * and
+ * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()}
+ * methods.
+ * <p>
+ * <p>
+ * @author Daniel F. Savarese
+ * @see TFTPPacket
+ * @see TFTPPacketException
+ * @see TFTP
+ ***/
+
+public final class TFTPAckPacket extends TFTPPacket
+{
+ /*** The block number being acknowledged by the packet. ***/
+ int _blockNumber;
+
+ /***
+ * Creates an acknowledgment packet to be sent to a host at a given port
+ * acknowledging receipt of a block.
+ * <p>
+ * @param destination The host to which the packet is going to be sent.
+ * @param port The port to which the packet is going to be sent.
+ * @param blockNumber The block number being acknowledged.
+ ***/
+ public TFTPAckPacket(InetAddress destination, int port, int blockNumber)
+ {
+ super(TFTPPacket.ACKNOWLEDGEMENT, destination, port);
+ _blockNumber = blockNumber;
+ }
+
+ /***
+ * Creates an acknowledgement packet based from a received
+ * datagram. Assumes the datagram is at least length 4, else an
+ * ArrayIndexOutOfBoundsException may be thrown.
+ * <p>
+ * @param datagram The datagram containing the received acknowledgement.
+ * @throws TFTPPacketException If the datagram isn't a valid TFTP
+ * acknowledgement packet.
+ ***/
+ TFTPAckPacket(DatagramPacket datagram) throws TFTPPacketException
+ {
+ super(TFTPPacket.ACKNOWLEDGEMENT, datagram.getAddress(),
+ datagram.getPort());
+ byte[] data;
+
+ data = datagram.getData();
+
+ if (getType() != data[1])
+ throw new TFTPPacketException("TFTP operator code does not match type.");
+
+ _blockNumber = (((data[2] & 0xff) << 8) | (data[3] & 0xff));
+ }
+
+ /***
+ * This is a method only available within the package for
+ * implementing efficient datagram transport by elminating buffering.
+ * It takes a datagram as an argument, and a byte buffer in which
+ * to store the raw datagram data. Inside the method, the data
+ * is set as the datagram's data and the datagram returned.
+ * <p>
+ * @param datagram The datagram to create.
+ * @param data The buffer to store the packet and to use in the datagram.
+ * @return The datagram argument.
+ ***/
+ @Override
+ DatagramPacket _newDatagram(DatagramPacket datagram, byte[] data)
+ {
+ data[0] = 0;
+ data[1] = (byte)_type;
+ data[2] = (byte)((_blockNumber & 0xffff) >> 8);
+ data[3] = (byte)(_blockNumber & 0xff);
+
+ datagram.setAddress(_address);
+ datagram.setPort(_port);
+ datagram.setData(data);
+ datagram.setLength(4);
+
+ return datagram;
+ }
+
+
+ /***
+ * Creates a UDP datagram containing all the TFTP
+ * acknowledgement packet data in the proper format.
+ * This is a method exposed to the programmer in case he
+ * wants to implement his own TFTP client instead of using
+ * the {@link org.apache.commons.net.tftp.TFTPClient}
+ * class. Under normal circumstances, you should not have a need to call this
+ * method.
+ * <p>
+ * @return A UDP datagram containing the TFTP acknowledgement packet.
+ ***/
+ @Override
+ public DatagramPacket newDatagram()
+ {
+ byte[] data;
+
+ data = new byte[4];
+ data[0] = 0;
+ data[1] = (byte)_type;
+ data[2] = (byte)((_blockNumber & 0xffff) >> 8);
+ data[3] = (byte)(_blockNumber & 0xff);
+
+ return new DatagramPacket(data, data.length, _address, _port);
+ }
+
+
+ /***
+ * Returns the block number of the acknowledgement.
+ * <p>
+ * @return The block number of the acknowledgement.
+ ***/
+ public int getBlockNumber()
+ {
+ return _blockNumber;
+ }
+
+
+ /*** Sets the block number of the acknowledgement. ***/
+ public void setBlockNumber(int blockNumber)
+ {
+ _blockNumber = blockNumber;
+ }
+}
+
diff --git a/org/apache/commons/net/tftp/TFTPClient.java b/org/apache/commons/net/tftp/TFTPClient.java
new file mode 100644
index 0000000..71d4ec6
--- /dev/null
+++ b/org/apache/commons/net/tftp/TFTPClient.java
@@ -0,0 +1,610 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.net.tftp;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import org.apache.commons.net.io.FromNetASCIIOutputStream;
+import org.apache.commons.net.io.ToNetASCIIInputStream;
+
+/***
+ * 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.
+ * <p>
+ * 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.
+ * <p>
+ * <p>
+ * @author Daniel F. Savarese
+ * @see TFTP
+ * @see TFTPPacket
+ * @see TFTPPacketException
+ ***/
+
+public class TFTPClient extends TFTP
+{
+ /***
+ * The 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.
+ ***/
+ public static final int DEFAULT_MAX_TIMEOUTS = 5;
+
+ /*** The maximum number of timeouts allowed before failing. ***/
+ private int __maxTimeouts;
+
+ /***
+ * 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.
+ ***/
+ public TFTPClient()
+ {
+ __maxTimeouts = DEFAULT_MAX_TIMEOUTS;
+ }
+
+ /***
+ * 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.
+ * <p>
+ * @param numTimeouts The maximum number of timeouts to allow. Values
+ * less than 1 should not be used, but if they are, they are
+ * treated as 1.
+ ***/
+ public void setMaxTimeouts(int numTimeouts)
+ {
+ if (numTimeouts < 1)
+ __maxTimeouts = 1;
+ else
+ __maxTimeouts = numTimeouts;
+ }
+
+ /***
+ * Returns the maximum number of times a receive attempt is allowed to
+ * timeout before ending attempts to retry the receive and failing.
+ * <p>
+ * @return The maximum number of timeouts allowed.
+ ***/
+ public int getMaxTimeouts()
+ {
+ return __maxTimeouts;
+ }
+
+
+ /***
+ * 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.
+ * <p>
+ * @param filename The name of the file to receive.
+ * @param mode The TFTP mode of the transfer (one of the MODE constants).
+ * @param output The OutputStream to which the file should be written.
+ * @param host The remote host serving the file.
+ * @param port The port number of the remote TFTP server.
+ * @exception IOException If an I/O error occurs. The nature of the
+ * error will be reported in the message.
+ ***/
+ public int receiveFile(String filename, int mode, OutputStream output,
+ InetAddress host, int port) throws IOException
+ {
+ 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;
+ if (block > 65535)
+ {
+ // wrap the block number
+ block = 0;
+ }
+
+ break _receivePacket;
+ }
+ else
+ {
+ discardPackets();
+
+ if (lastBlock == (block == 0 ? 65535 : (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;
+ }
+
+
+ /***
+ * 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.
+ * <p>
+ * @param filename The name of the file to receive.
+ * @param mode The TFTP mode of the transfer (one of the MODE constants).
+ * @param output The OutputStream to which the file should be written.
+ * @param hostname The name of the remote host serving the file.
+ * @param port The port number of the remote TFTP server.
+ * @exception IOException If an I/O error occurs. The nature of the
+ * error will be reported in the message.
+ * @exception UnknownHostException If the hostname cannot be resolved.
+ ***/
+ public int receiveFile(String filename, int mode, OutputStream output,
+ String hostname, int port)
+ throws UnknownHostException, IOException
+ {
+ return receiveFile(filename, mode, output, InetAddress.getByName(hostname),
+ port);
+ }
+
+
+ /***
+ * Same as calling receiveFile(filename, mode, output, host, TFTP.DEFAULT_PORT).
+ *
+ * @param filename The name of the file to receive.
+ * @param mode The TFTP mode of the transfer (one of the MODE constants).
+ * @param output The OutputStream to which the file should be written.
+ * @param host The remote host serving the file.
+ * @exception IOException If an I/O error occurs. The nature of the
+ * error will be reported in the message.
+ ***/
+ public int receiveFile(String filename, int mode, OutputStream output,
+ InetAddress host)
+ throws IOException
+ {
+ return receiveFile(filename, mode, output, host, DEFAULT_PORT);
+ }
+
+ /***
+ * Same as calling receiveFile(filename, mode, output, hostname, TFTP.DEFAULT_PORT).
+ *
+ * @param filename The name of the file to receive.
+ * @param mode The TFTP mode of the transfer (one of the MODE constants).
+ * @param output The OutputStream to which the file should be written.
+ * @param hostname The name of the remote host serving the file.
+ * @exception IOException If an I/O error occurs. The nature of the
+ * error will be reported in the message.
+ * @exception UnknownHostException If the hostname cannot be resolved.
+ ***/
+ public int receiveFile(String filename, int mode, OutputStream output,
+ String hostname)
+ throws UnknownHostException, IOException
+ {
+ return receiveFile(filename, mode, output, InetAddress.getByName(hostname),
+ DEFAULT_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.
+ * <p>
+ * @param filename The name the remote server should use when creating
+ * the file on its file system.
+ * @param mode The TFTP mode of the transfer (one of the MODE constants).
+ * @param host The remote host receiving the file.
+ * @param port The port number of the remote TFTP server.
+ * @exception IOException If an I/O error occurs. The nature of the
+ * error will be reported in the message.
+ ***/
+ public void sendFile(String filename, int mode, InputStream input,
+ InetAddress host, int port) throws IOException
+ {
+ int bytesRead, timeouts, lastBlock, block, hostPort, dataLength, offset, totalThisPacket;
+ TFTPPacket sent, received = null;
+ TFTPErrorPacket error;
+ TFTPDataPacket data =
+ new TFTPDataPacket(host, port, 0, _sendBuffer, 4, 0);
+ TFTPAckPacket ack;
+
+ boolean justStarted = true;
+
+ beginBufferedOps();
+
+ dataLength = lastBlock = hostPort = bytesRead = totalThisPacket = 0;
+ block = 0;
+ boolean lastAckWait = false;
+
+ if (mode == TFTP.ASCII_MODE)
+ input = new ToNetASCIIInputStream(input);
+
+ sent =
+ new TFTPWriteRequestPacket(host, port, filename, mode);
+
+_sendPacket:
+ do
+ {
+ // first time: block is 0, lastBlock is 0, send a request packet.
+ // subsequent: block is integer starting at 1, send data packet.
+ bufferedSend(sent);
+
+ // this is trying to receive an ACK
+_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());
+ }
+ } // end of while loop over tries to receive
+
+ // The first time we receive we get the port number and
+ // answering host address (for hosts with multiple IPs)
+ if (justStarted)
+ {
+ justStarted = false;
+ 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 (block > 65535)
+ {
+ // wrap the block number
+ block = 0;
+ }
+ if (lastAckWait) {
+
+ break _sendPacket;
+ }
+ else {
+ break _receivePacket;
+ }
+ }
+ else
+ {
+ discardPackets();
+
+ if (lastBlock == (block == 0 ? 65535 : (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;
+ }
+
+ // OK, we have just gotten ACK about the last data we sent. Make another
+ // and send it
+
+ dataLength = TFTPPacket.SEGMENT_SIZE;
+ offset = 4;
+ totalThisPacket = 0;
+ while (dataLength > 0 &&
+ (bytesRead = input.read(_sendBuffer, offset, dataLength)) > 0)
+ {
+ offset += bytesRead;
+ dataLength -= bytesRead;
+ totalThisPacket += bytesRead;
+ }
+
+ if( totalThisPacket < TFTPPacket.SEGMENT_SIZE ) {
+ /* this will be our last packet -- send, wait for ack, stop */
+ lastAckWait = true;
+ }
+ data.setBlockNumber(block);
+ data.setData(_sendBuffer, 4, totalThisPacket);
+ sent = data;
+ }
+ while ( totalThisPacket > 0 || lastAckWait );
+ // Note: this was looping while dataLength == 0 || lastAckWait,
+ // which was discarding the last packet if it was not full size
+ // Should send the packet.
+
+ endBufferedOps();
+ }
+
+
+ /***
+ * 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.
+ * <p>
+ * @param filename The name the remote server should use when creating
+ * the file on its file system.
+ * @param mode The TFTP mode of the transfer (one of the MODE constants).
+ * @param hostname The name of the remote host receiving the file.
+ * @param port The port number of the remote TFTP server.
+ * @exception IOException If an I/O error occurs. The nature of the
+ * error will be reported in the message.
+ * @exception UnknownHostException If the hostname cannot be resolved.
+ ***/
+ public void sendFile(String filename, int mode, InputStream input,
+ String hostname, int port)
+ throws UnknownHostException, IOException
+ {
+ sendFile(filename, mode, input, InetAddress.getByName(hostname), port);
+ }
+
+
+ /***
+ * Same as calling sendFile(filename, mode, input, host, TFTP.DEFAULT_PORT).
+ *
+ * @param filename The name the remote server should use when creating
+ * the file on its file system.
+ * @param mode The TFTP mode of the transfer (one of the MODE constants).
+ * @param host The name of the remote host receiving the file.
+ * @exception IOException If an I/O error occurs. The nature of the
+ * error will be reported in the message.
+ * @exception UnknownHostException If the hostname cannot be resolved.
+ ***/
+ public void sendFile(String filename, int mode, InputStream input,
+ InetAddress host)
+ throws IOException
+ {
+ sendFile(filename, mode, input, host, DEFAULT_PORT);
+ }
+
+ /***
+ * Same as calling sendFile(filename, mode, input, hostname, TFTP.DEFAULT_PORT).
+ *
+ * @param filename The name the remote server should use when creating
+ * the file on its file system.
+ * @param mode The TFTP mode of the transfer (one of the MODE constants).
+ * @param hostname The name of the remote host receiving the file.
+ * @exception IOException If an I/O error occurs. The nature of the
+ * error will be reported in the message.
+ * @exception UnknownHostException If the hostname cannot be resolved.
+ ***/
+ public void sendFile(String filename, int mode, InputStream input,
+ String hostname)
+ throws UnknownHostException, IOException
+ {
+ sendFile(filename, mode, input, InetAddress.getByName(hostname),
+ DEFAULT_PORT);
+ }
+}
diff --git a/org/apache/commons/net/tftp/TFTPDataPacket.java b/org/apache/commons/net/tftp/TFTPDataPacket.java
new file mode 100644
index 0000000..24c0dd3
--- /dev/null
+++ b/org/apache/commons/net/tftp/TFTPDataPacket.java
@@ -0,0 +1,254 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.net.tftp;
+
+import java.net.DatagramPacket;
+import java.net.InetAddress;
+
+/***
+ * A final class derived from TFTPPacket definiing the TFTP Data
+ * packet type.
+ * <p>
+ * 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. Additionally, only very
+ * few people should have to care about any of the TFTPPacket classes
+ * or derived classes. Almost all users should only be concerned with the
+ * {@link org.apache.commons.net.tftp.TFTPClient} class
+ * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()}
+ * and
+ * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()}
+ * methods.
+ * <p>
+ * <p>
+ * @author Daniel F. Savarese
+ * @see TFTPPacket
+ * @see TFTPPacketException
+ * @see TFTP
+ ***/
+
+public final class TFTPDataPacket extends TFTPPacket
+{
+ /*** The maximum number of bytes in a TFTP data packet (512) ***/
+ public static final int MAX_DATA_LENGTH = 512;
+
+ /*** The minimum number of bytes in a TFTP data packet (0) ***/
+ public static final int MIN_DATA_LENGTH = 0;
+
+ /*** The block number of the packet. ***/
+ int _blockNumber;
+
+ /*** The length of the data. ***/
+ int _length;
+
+ /*** The offset into the _data array at which the data begins. ***/
+ int _offset;
+
+ /*** The data stored in the packet. ***/
+ byte[] _data;
+
+ /***
+ * Creates a data packet to be sent to a host at a given port
+ * with a given block number. The actual data to be sent is passed as
+ * an array, an offset, and a length. The offset is the offset into
+ * the byte array where the data starts. The length is the length of
+ * the data. If the length is greater than MAX_DATA_LENGTH, it is
+ * truncated.
+ * <p>
+ * @param destination The host to which the packet is going to be sent.
+ * @param port The port to which the packet is going to be sent.
+ * @param blockNumber The block number of the data.
+ * @param data The byte array containing the data.
+ * @param offset The offset into the array where the data starts.
+ * @param length The length of the data.
+ ***/
+ public TFTPDataPacket(InetAddress destination, int port, int blockNumber,
+ byte[] data, int offset, int length)
+ {
+ super(TFTPPacket.DATA, destination, port);
+
+ _blockNumber = blockNumber;
+ _data = data;
+ _offset = offset;
+
+ if (length > MAX_DATA_LENGTH)
+ _length = MAX_DATA_LENGTH;
+ else
+ _length = length;
+ }
+
+ public TFTPDataPacket(InetAddress destination, int port, int blockNumber,
+ byte[] data)
+ {
+ this(destination, port, blockNumber, data, 0, data.length);
+ }
+
+
+ /***
+ * Creates a data packet based from a received
+ * datagram. Assumes the datagram is at least length 4, else an
+ * ArrayIndexOutOfBoundsException may be thrown.
+ * <p>
+ * @param datagram The datagram containing the received data.
+ * @throws TFTPPacketException If the datagram isn't a valid TFTP
+ * data packet.
+ ***/
+ TFTPDataPacket(DatagramPacket datagram) throws TFTPPacketException
+ {
+ super(TFTPPacket.DATA, datagram.getAddress(), datagram.getPort());
+
+ _data = datagram.getData();
+ _offset = 4;
+
+ if (getType() != _data[1])
+ throw new TFTPPacketException("TFTP operator code does not match type.");
+
+ _blockNumber = (((_data[2] & 0xff) << 8) | (_data[3] & 0xff));
+
+ _length = datagram.getLength() - 4;
+
+ if (_length > MAX_DATA_LENGTH)
+ _length = MAX_DATA_LENGTH;
+ }
+
+ /***
+ * This is a method only available within the package for
+ * implementing efficient datagram transport by elminating buffering.
+ * It takes a datagram as an argument, and a byte buffer in which
+ * to store the raw datagram data. Inside the method, the data
+ * is set as the datagram's data and the datagram returned.
+ * <p>
+ * @param datagram The datagram to create.
+ * @param data The buffer to store the packet and to use in the datagram.
+ * @return The datagram argument.
+ ***/
+ @Override
+ DatagramPacket _newDatagram(DatagramPacket datagram, byte[] data)
+ {
+ data[0] = 0;
+ data[1] = (byte)_type;
+ data[2] = (byte)((_blockNumber & 0xffff) >> 8);
+ data[3] = (byte)(_blockNumber & 0xff);
+
+ // Doublecheck we're not the same
+ if (data != _data)
+ System.arraycopy(_data, _offset, data, 4, _length);
+
+ datagram.setAddress(_address);
+ datagram.setPort(_port);
+ datagram.setData(data);
+ datagram.setLength(_length + 4);
+
+ return datagram;
+ }
+
+ /***
+ * Creates a UDP datagram containing all the TFTP
+ * data packet data in the proper format.
+ * This is a method exposed to the programmer in case he
+ * wants to implement his own TFTP client instead of using
+ * the {@link org.apache.commons.net.tftp.TFTPClient}
+ * class.
+ * Under normal circumstances, you should not have a need to call this
+ * method.
+ * <p>
+ * @return A UDP datagram containing the TFTP data packet.
+ ***/
+ @Override
+ public DatagramPacket newDatagram()
+ {
+ byte[] data;
+
+ data = new byte[_length + 4];
+ data[0] = 0;
+ data[1] = (byte)_type;
+ data[2] = (byte)((_blockNumber & 0xffff) >> 8);
+ data[3] = (byte)(_blockNumber & 0xff);
+
+ System.arraycopy(_data, _offset, data, 4, _length);
+
+ return new DatagramPacket(data, _length + 4, _address, _port);
+ }
+
+ /***
+ * Returns the block number of the data packet.
+ * <p>
+ * @return The block number of the data packet.
+ ***/
+ public int getBlockNumber()
+ {
+ return _blockNumber;
+ }
+
+ /*** Sets the block number of the data packet. ***/
+ public void setBlockNumber(int blockNumber)
+ {
+ _blockNumber = blockNumber;
+ }
+
+ /***
+ * Sets the data for the data packet.
+ * <p>
+ * @param data The byte array containing the data.
+ * @param offset The offset into the array where the data starts.
+ * @param length The length of the data.
+ ***/
+ public void setData(byte[] data, int offset, int length)
+ {
+ _data = data;
+ _offset = offset;
+ _length = length;
+
+ if (length > MAX_DATA_LENGTH)
+ _length = MAX_DATA_LENGTH;
+ else
+ _length = length;
+ }
+
+ /***
+ * Returns the length of the data part of the data packet.
+ * <p>
+ * @return The length of the data part of the data packet.
+ ***/
+ public int getDataLength()
+ {
+ return _length;
+ }
+
+ /***
+ * Returns the offset into the byte array where the packet data actually
+ * starts.
+ * <p>
+ * @return The offset into the byte array where the packet data actually
+ * starts.
+ ***/
+ public int getDataOffset()
+ {
+ return _offset;
+ }
+
+ /***
+ * Returns the byte array containing the packet data.
+ * <p>
+ * @return The byte array containing the packet data.
+ ***/
+ public byte[] getData()
+ {
+ return _data;
+ }
+}
diff --git a/org/apache/commons/net/tftp/TFTPErrorPacket.java b/org/apache/commons/net/tftp/TFTPErrorPacket.java
new file mode 100644
index 0000000..2e7aec2
--- /dev/null
+++ b/org/apache/commons/net/tftp/TFTPErrorPacket.java
@@ -0,0 +1,226 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.net.tftp;
+
+import java.net.DatagramPacket;
+import java.net.InetAddress;
+
+/***
+ * A final class derived from TFTPPacket definiing the TFTP Error
+ * packet type.
+ * <p>
+ * 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. Additionally, only very
+ * few people should have to care about any of the TFTPPacket classes
+ * or derived classes. Almost all users should only be concerned with the
+ * {@link org.apache.commons.net.tftp.TFTPClient} class
+ * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()}
+ * and
+ * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()}
+ * methods.
+ * <p>
+ * <p>
+ * @author Daniel F. Savarese
+ * @see TFTPPacket
+ * @see TFTPPacketException
+ * @see TFTP
+ ***/
+
+public final class TFTPErrorPacket extends TFTPPacket
+{
+ /*** The undefined error code according to RFC 783, value 0. ***/
+ public static final int UNDEFINED = 0;
+
+ /*** The file not found error code according to RFC 783, value 1. ***/
+ public static final int FILE_NOT_FOUND = 1;
+
+ /*** The access violation error code according to RFC 783, value 2. ***/
+ public static final int ACCESS_VIOLATION = 2;
+
+ /*** The disk full error code according to RFC 783, value 3. ***/
+ public static final int OUT_OF_SPACE = 3;
+
+ /***
+ * The illegal TFTP operation error code according to RFC 783, value 4.
+ ***/
+ public static final int ILLEGAL_OPERATION = 4;
+
+ /*** The unknown transfer id error code according to RFC 783, value 5. ***/
+ public static final int UNKNOWN_TID = 5;
+
+ /*** The file already exists error code according to RFC 783, value 6. ***/
+ public static final int FILE_EXISTS = 6;
+
+ /*** The no such user error code according to RFC 783, value 7. ***/
+ public static final int NO_SUCH_USER = 7;
+
+ /*** The error code of this packet. ***/
+ int _error;
+
+ /*** The error message of this packet. ***/
+ String _message;
+
+ /***
+ * Creates an error packet to be sent to a host at a given port
+ * with an error code and error message.
+ * <p>
+ * @param destination The host to which the packet is going to be sent.
+ * @param port The port to which the packet is going to be sent.
+ * @param error The error code of the packet.
+ * @param message The error message of the packet.
+ ***/
+ public TFTPErrorPacket(InetAddress destination, int port,
+ int error, String message)
+ {
+ super(TFTPPacket.ERROR, destination, port);
+
+ _error = error;
+ _message = message;
+ }
+
+ /***
+ * Creates an error packet based from a received
+ * datagram. Assumes the datagram is at least length 4, else an
+ * ArrayIndexOutOfBoundsException may be thrown.
+ * <p>
+ * @param datagram The datagram containing the received error.
+ * @throws TFTPPacketException If the datagram isn't a valid TFTP
+ * error packet.
+ ***/
+ TFTPErrorPacket(DatagramPacket datagram) throws TFTPPacketException
+ {
+ super(TFTPPacket.ERROR, datagram.getAddress(), datagram.getPort());
+ int index, length;
+ byte[] data;
+ StringBuffer buffer;
+
+ data = datagram.getData();
+ length = datagram.getLength();
+
+ if (getType() != data[1])
+ throw new TFTPPacketException("TFTP operator code does not match type.");
+
+ _error = (((data[2] & 0xff) << 8) | (data[3] & 0xff));
+
+ if (length < 5)
+ throw new TFTPPacketException("Bad error packet. No message.");
+
+ index = 4;
+ buffer = new StringBuffer();
+
+ while (index < length && data[index] != 0)
+ {
+ buffer.append((char)data[index]);
+ ++index;
+ }
+
+ _message = buffer.toString();
+ }
+
+ /***
+ * This is a method only available within the package for
+ * implementing efficient datagram transport by elminating buffering.
+ * It takes a datagram as an argument, and a byte buffer in which
+ * to store the raw datagram data. Inside the method, the data
+ * is set as the datagram's data and the datagram returned.
+ * <p>
+ * @param datagram The datagram to create.
+ * @param data The buffer to store the packet and to use in the datagram.
+ * @return The datagram argument.
+ ***/
+ @Override
+ DatagramPacket _newDatagram(DatagramPacket datagram, byte[] data)
+ {
+ int length;
+
+ length = _message.length();
+
+ data[0] = 0;
+ data[1] = (byte)_type;
+ data[2] = (byte)((_error & 0xffff) >> 8);
+ data[3] = (byte)(_error & 0xff);
+
+ System.arraycopy(_message.getBytes(), 0, data, 4, length);
+
+ data[length + 4] = 0;
+
+ datagram.setAddress(_address);
+ datagram.setPort(_port);
+ datagram.setData(data);
+ datagram.setLength(length + 4);
+
+ return datagram;
+ }
+
+
+ /***
+ * Creates a UDP datagram containing all the TFTP
+ * error packet data in the proper format.
+ * This is a method exposed to the programmer in case he
+ * wants to implement his own TFTP client instead of using
+ * the {@link org.apache.commons.net.tftp.TFTPClient}
+ * class.
+ * Under normal circumstances, you should not have a need to call this
+ * method.
+ * <p>
+ * @return A UDP datagram containing the TFTP error packet.
+ ***/
+ @Override
+ public DatagramPacket newDatagram()
+ {
+ byte[] data;
+ int length;
+
+ length = _message.length();
+
+ data = new byte[length + 5];
+ data[0] = 0;
+ data[1] = (byte)_type;
+ data[2] = (byte)((_error & 0xffff) >> 8);
+ data[3] = (byte)(_error & 0xff);
+
+ System.arraycopy(_message.getBytes(), 0, data, 4, length);
+
+ data[length + 4] = 0;
+
+ return new DatagramPacket(data, data.length, _address, _port);
+ }
+
+
+ /***
+ * Returns the error code of the packet.
+ * <p>
+ * @return The error code of the packet.
+ ***/
+ public int getError()
+ {
+ return _error;
+ }
+
+
+ /***
+ * Returns the error message of the packet.
+ * <p>
+ * @return The error message of the packet.
+ ***/
+ public String getMessage()
+ {
+ return _message;
+ }
+}
diff --git a/org/apache/commons/net/tftp/TFTPPacket.java b/org/apache/commons/net/tftp/TFTPPacket.java
new file mode 100644
index 0000000..e1dc5f1
--- /dev/null
+++ b/org/apache/commons/net/tftp/TFTPPacket.java
@@ -0,0 +1,247 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.net.tftp;
+
+import java.net.DatagramPacket;
+import java.net.InetAddress;
+
+/***
+ * TFTPPacket is an abstract class encapsulating the functionality common
+ * to the 5 types of TFTP packets. It also provides a static factory
+ * method that will create the correct TFTP packet instance from a
+ * datagram. This relieves the programmer from having to figure out what
+ * kind of TFTP packet is contained in a datagram and create it himself.
+ * <p>
+ * 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. Additionally, only very
+ * few people should have to care about any of the TFTPPacket classes
+ * or derived classes. Almost all users should only be concerned with the
+ * {@link org.apache.commons.net.tftp.TFTPClient} class
+ * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()}
+ * and
+ * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()}
+ * methods.
+ * <p>
+ * <p>
+ * @author Daniel F. Savarese
+ * @see TFTPPacketException
+ * @see TFTP
+ ***/
+
+public abstract class TFTPPacket
+{
+ /***
+ * The minimum size of a packet. This is 4 bytes. It is enough
+ * to store the opcode and blocknumber or other required data
+ * depending on the packet type.
+ ***/
+ static final int MIN_PACKET_SIZE = 4;
+
+ /***
+ * This is the actual TFTP spec
+ * identifier and is equal to 1.
+ * Identifier returned by {@link #getType getType()}
+ * indicating a read request packet.
+ ***/
+ public static final int READ_REQUEST = 1;
+
+ /***
+ * This is the actual TFTP spec
+ * identifier and is equal to 2.
+ * Identifier returned by {@link #getType getType()}
+ * indicating a write request packet.
+ ***/
+ public static final int WRITE_REQUEST = 2;
+
+ /***
+ * This is the actual TFTP spec
+ * identifier and is equal to 3.
+ * Identifier returned by {@link #getType getType()}
+ * indicating a data packet.
+ ***/
+ public static final int DATA = 3;
+
+ /***
+ * This is the actual TFTP spec
+ * identifier and is equal to 4.
+ * Identifier returned by {@link #getType getType()}
+ * indicating an acknowledgement packet.
+ ***/
+ public static final int ACKNOWLEDGEMENT = 4;
+
+ /***
+ * This is the actual TFTP spec
+ * identifier and is equal to 5.
+ * Identifier returned by {@link #getType getType()}
+ * indicating an error packet.
+ ***/
+ public static final int ERROR = 5;
+
+ /***
+ * The TFTP data packet maximum segment size in bytes. This is 512
+ * and is useful for those familiar with the TFTP protocol who want
+ * to use the {@link org.apache.commons.net.tftp.TFTP}
+ * class methods to implement their own TFTP servers or clients.
+ ***/
+ public static final int SEGMENT_SIZE = 512;
+
+ /*** The type of packet. ***/
+ int _type;
+
+ /*** The port the packet came from or is going to. ***/
+ int _port;
+
+ /*** The host the packet is going to be sent or where it came from. ***/
+ InetAddress _address;
+
+ /***
+ * When you receive a datagram that you expect to be a TFTP packet, you use
+ * this factory method to create the proper TFTPPacket object
+ * encapsulating the data contained in that datagram. This method is the
+ * only way you can instantiate a TFTPPacket derived class from a
+ * datagram.
+ * <p>
+ * @param datagram The datagram containing a TFTP packet.
+ * @return The TFTPPacket object corresponding to the datagram.
+ * @exception TFTPPacketException If the datagram does not contain a valid
+ * TFTP packet.
+ ***/
+ public final static TFTPPacket newTFTPPacket(DatagramPacket datagram)
+ throws TFTPPacketException
+ {
+ byte[] data;
+ TFTPPacket packet = null;
+
+ if (datagram.getLength() < MIN_PACKET_SIZE)
+ throw new TFTPPacketException(
+ "Bad packet. Datagram data length is too short.");
+
+ data = datagram.getData();
+
+ switch (data[1])
+ {
+ case READ_REQUEST:
+ packet = new TFTPReadRequestPacket(datagram);
+ break;
+ case WRITE_REQUEST:
+ packet = new TFTPWriteRequestPacket(datagram);
+ break;
+ case DATA:
+ packet = new TFTPDataPacket(datagram);
+ break;
+ case ACKNOWLEDGEMENT:
+ packet = new TFTPAckPacket(datagram);
+ break;
+ case ERROR:
+ packet = new TFTPErrorPacket(datagram);
+ break;
+ default:
+ throw new TFTPPacketException(
+ "Bad packet. Invalid TFTP operator code.");
+ }
+
+ return packet;
+ }
+
+ /***
+ * This constructor is not visible outside of the package. It is used
+ * by subclasses within the package to initialize base data.
+ * <p>
+ * @param type The type of the packet.
+ * @param address The host the packet came from or is going to be sent.
+ * @param port The port the packet came from or is going to be sent.
+ **/
+ TFTPPacket(int type, InetAddress address, int port)
+ {
+ _type = type;
+ _address = address;
+ _port = port;
+ }
+
+ /***
+ * This is an abstract method only available within the package for
+ * implementing efficient datagram transport by elminating buffering.
+ * It takes a datagram as an argument, and a byte buffer in which
+ * to store the raw datagram data. Inside the method, the data
+ * should be set as the datagram's data and the datagram returned.
+ * <p>
+ * @param datagram The datagram to create.
+ * @param data The buffer to store the packet and to use in the datagram.
+ * @return The datagram argument.
+ ***/
+ abstract DatagramPacket _newDatagram(DatagramPacket datagram, byte[] data);
+
+ /***
+ * Creates a UDP datagram containing all the TFTP packet
+ * data in the proper format.
+ * This is an abstract method, exposed to the programmer in case he
+ * wants to implement his own TFTP client instead of using
+ * the {@link org.apache.commons.net.tftp.TFTPClient}
+ * class.
+ * Under normal circumstances, you should not have a need to call this
+ * method.
+ * <p>
+ * @return A UDP datagram containing the TFTP packet.
+ ***/
+ public abstract DatagramPacket newDatagram();
+
+ /***
+ * Returns the type of the packet.
+ * <p>
+ * @return The type of the packet.
+ ***/
+ public final int getType()
+ {
+ return _type;
+ }
+
+ /***
+ * Returns the address of the host where the packet is going to be sent
+ * or where it came from.
+ * <p>
+ * @return The type of the packet.
+ ***/
+ public final InetAddress getAddress()
+ {
+ return _address;
+ }
+
+ /***
+ * Returns the port where the packet is going to be sent
+ * or where it came from.
+ * <p>
+ * @return The port where the packet came from or where it is going.
+ ***/
+ public final int getPort()
+ {
+ return _port;
+ }
+
+ /*** Sets the port where the packet is going to be sent. ***/
+ public final void setPort(int port)
+ {
+ _port = port;
+ }
+
+ /*** Sets the host address where the packet is going to be sent. ***/
+ public final void setAddress(InetAddress address)
+ {
+ _address = address;
+ }
+}
diff --git a/org/apache/commons/net/tftp/TFTPPacketException.java b/org/apache/commons/net/tftp/TFTPPacketException.java
new file mode 100644
index 0000000..286fa3a
--- /dev/null
+++ b/org/apache/commons/net/tftp/TFTPPacketException.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.net.tftp;
+
+/***
+ * A class used to signify the occurrence of an error in the creation of
+ * a TFTP packet. It is not declared final so that it may be subclassed
+ * to identify more specific errors. You would only want to do this if
+ * you were building your own TFTP client or server on top of the
+ * {@link org.apache.commons.net.tftp.TFTP}
+ * class if you
+ * wanted more functionality than the
+ * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()}
+ * and
+ * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()}
+ * methods provide.
+ * <p>
+ * <p>
+ * @author Daniel F. Savarese
+ * @see TFTPPacket
+ * @see TFTP
+ ***/
+
+public class TFTPPacketException extends Exception
+{
+
+ /***
+ * Simply calls the corresponding constructor of its superclass.
+ ***/
+ public TFTPPacketException()
+ {
+ super();
+ }
+
+ /***
+ * Simply calls the corresponding constructor of its superclass.
+ ***/
+ public TFTPPacketException(String message)
+ {
+ super(message);
+ }
+}
diff --git a/org/apache/commons/net/tftp/TFTPReadRequestPacket.java b/org/apache/commons/net/tftp/TFTPReadRequestPacket.java
new file mode 100644
index 0000000..2669df6
--- /dev/null
+++ b/org/apache/commons/net/tftp/TFTPReadRequestPacket.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.net.tftp;
+
+import java.net.DatagramPacket;
+import java.net.InetAddress;
+
+/***
+ * A class derived from TFTPRequestPacket definiing a TFTP read request
+ * packet type.
+ * <p>
+ * 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. Additionally, only very
+ * few people should have to care about any of the TFTPPacket classes
+ * or derived classes. Almost all users should only be concerned with the
+ * {@link org.apache.commons.net.tftp.TFTPClient} class
+ * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()}
+ * and
+ * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()}
+ * methods.
+ * <p>
+ * <p>
+ * @author Daniel F. Savarese
+ * @see TFTPPacket
+ * @see TFTPRequestPacket
+ * @see TFTPPacketException
+ * @see TFTP
+ ***/
+
+public final class TFTPReadRequestPacket extends TFTPRequestPacket
+{
+
+ /***
+ * Creates a read request packet to be sent to a host at a
+ * given port with a filename and transfer mode request.
+ * <p>
+ * @param destination The host to which the packet is going to be sent.
+ * @param port The port to which the packet is going to be sent.
+ * @param filename The requested filename.
+ * @param mode The requested transfer mode. This should be on of the TFTP
+ * class MODE constants (e.g., TFTP.NETASCII_MODE).
+ ***/
+ public TFTPReadRequestPacket(InetAddress destination, int port,
+ String filename, int mode)
+ {
+ super(destination, port, TFTPPacket.READ_REQUEST, filename, mode);
+ }
+
+ /***
+ * Creates a read request packet of based on a received
+ * datagram and assumes the datagram has already been identified as a
+ * read request. Assumes the datagram is at least length 4, else an
+ * ArrayIndexOutOfBoundsException may be thrown.
+ * <p>
+ * @param datagram The datagram containing the received request.
+ * @throws TFTPPacketException If the datagram isn't a valid TFTP
+ * request packet.
+ ***/
+ TFTPReadRequestPacket(DatagramPacket datagram) throws TFTPPacketException
+ {
+ super(TFTPPacket.READ_REQUEST, datagram);
+ }
+
+}
diff --git a/org/apache/commons/net/tftp/TFTPRequestPacket.java b/org/apache/commons/net/tftp/TFTPRequestPacket.java
new file mode 100644
index 0000000..a0f4407
--- /dev/null
+++ b/org/apache/commons/net/tftp/TFTPRequestPacket.java
@@ -0,0 +1,253 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.net.tftp;
+
+import java.net.DatagramPacket;
+import java.net.InetAddress;
+
+/***
+ * An abstract class derived from TFTPPacket definiing a TFTP Request
+ * packet type. It is subclassed by the
+ * {@link org.apache.commons.net.tftp.TFTPReadRequestPacket}
+ * and
+ * {@link org.apache.commons.net.tftp.TFTPWriteRequestPacket}
+ * classes.
+ * <p>
+ * 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. Additionally, only very
+ * few people should have to care about any of the TFTPPacket classes
+ * or derived classes. Almost all users should only be concerned with the
+ * {@link org.apache.commons.net.tftp.TFTPClient} class
+ * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()}
+ * and
+ * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()}
+ * methods.
+ * <p>
+ * <p>
+ * @author Daniel F. Savarese
+ * @see TFTPPacket
+ * @see TFTPReadRequestPacket
+ * @see TFTPWriteRequestPacket
+ * @see TFTPPacketException
+ * @see TFTP
+ ***/
+
+public abstract class TFTPRequestPacket extends TFTPPacket
+{
+ /***
+ * An array containing the string names of the transfer modes and indexed
+ * by the transfer mode constants.
+ ***/
+ static final String[] _modeStrings = { "netascii", "octet" };
+
+ /***
+ * A null terminated byte array representation of the ascii names of the
+ * transfer mode constants. This is convenient for creating the TFTP
+ * request packets.
+ ***/
+ static final byte[] _modeBytes[] = {
+ { (byte)'n', (byte)'e', (byte)'t', (byte)'a', (byte)'s', (byte)'c',
+ (byte)'i', (byte)'i', 0 },
+ { (byte)'o', (byte)'c', (byte)'t', (byte)'e', (byte)'t', 0 }
+ };
+
+ /*** The transfer mode of the request. ***/
+ int _mode;
+
+ /*** The filename of the request. ***/
+ String _filename;
+
+ /***
+ * Creates a request packet of a given type to be sent to a host at a
+ * given port with a filename and transfer mode request.
+ * <p>
+ * @param destination The host to which the packet is going to be sent.
+ * @param port The port to which the packet is going to be sent.
+ * @param type The type of the request (either TFTPPacket.READ_REQUEST or
+ * TFTPPacket.WRITE_REQUEST).
+ * @param filename The requested filename.
+ * @param mode The requested transfer mode. This should be on of the TFTP
+ * class MODE constants (e.g., TFTP.NETASCII_MODE).
+ ***/
+ TFTPRequestPacket(InetAddress destination, int port,
+ int type, String filename, int mode)
+ {
+ super(type, destination, port);
+
+ _filename = filename;
+ _mode = mode;
+ }
+
+ /***
+ * Creates a request packet of a given type based on a received
+ * datagram. Assumes the datagram is at least length 4, else an
+ * ArrayIndexOutOfBoundsException may be thrown.
+ * <p>
+ * @param type The type of the request (either TFTPPacket.READ_REQUEST or
+ * TFTPPacket.WRITE_REQUEST).
+ * @param datagram The datagram containing the received request.
+ * @throws TFTPPacketException If the datagram isn't a valid TFTP
+ * request packet of the appropriate type.
+ ***/
+ TFTPRequestPacket(int type, DatagramPacket datagram)
+ throws TFTPPacketException
+ {
+ super(type, datagram.getAddress(), datagram.getPort());
+
+ byte[] data;
+ int index, length;
+ String mode;
+ StringBuffer buffer;
+
+ data = datagram.getData();
+
+ if (getType() != data[1])
+ throw new TFTPPacketException("TFTP operator code does not match type.");
+
+ buffer = new StringBuffer();
+
+ index = 2;
+ length = datagram.getLength();
+
+ while (index < length && data[index] != 0)
+ {
+ buffer.append((char)data[index]);
+ ++index;
+ }
+
+ _filename = buffer.toString();
+
+ if (index >= length)
+ throw new TFTPPacketException("Bad filename and mode format.");
+
+ buffer.setLength(0);
+ ++index; // need to advance beyond the end of string marker
+ while (index < length && data[index] != 0)
+ {
+ buffer.append((char)data[index]);
+ ++index;
+ }
+
+ mode = buffer.toString().toLowerCase(java.util.Locale.ENGLISH);
+ length = _modeStrings.length;
+
+ for (index = 0; index < length; index++)
+ {
+ if (mode.equals(_modeStrings[index]))
+ {
+ _mode = index;
+ break;
+ }
+ }
+
+ if (index >= length)
+ {
+ throw new TFTPPacketException("Unrecognized TFTP transfer mode: " + mode);
+ // May just want to default to binary mode instead of throwing
+ // exception.
+ //_mode = TFTP.OCTET_MODE;
+ }
+ }
+
+
+ /***
+ * This is a method only available within the package for
+ * implementing efficient datagram transport by elminating buffering.
+ * It takes a datagram as an argument, and a byte buffer in which
+ * to store the raw datagram data. Inside the method, the data
+ * is set as the datagram's data and the datagram returned.
+ * <p>
+ * @param datagram The datagram to create.
+ * @param data The buffer to store the packet and to use in the datagram.
+ * @return The datagram argument.
+ ***/
+ @Override
+ final DatagramPacket _newDatagram(DatagramPacket datagram, byte[] data)
+ {
+ int fileLength, modeLength;
+
+ fileLength = _filename.length();
+ modeLength = _modeBytes[_mode].length;
+
+ data[0] = 0;
+ data[1] = (byte)_type;
+ System.arraycopy(_filename.getBytes(), 0, data, 2, fileLength);
+ data[fileLength + 2] = 0;
+ System.arraycopy(_modeBytes[_mode], 0, data, fileLength + 3,
+ modeLength);
+
+ datagram.setAddress(_address);
+ datagram.setPort(_port);
+ datagram.setData(data);
+ datagram.setLength(fileLength + modeLength + 3);
+
+ return datagram;
+ }
+
+ /***
+ * Creates a UDP datagram containing all the TFTP
+ * request packet data in the proper format.
+ * This is a method exposed to the programmer in case he
+ * wants to implement his own TFTP client instead of using
+ * the {@link org.apache.commons.net.tftp.TFTPClient}
+ * class. Under normal circumstances, you should not have a need to call
+ * this method.
+ * <p>
+ * @return A UDP datagram containing the TFTP request packet.
+ ***/
+ @Override
+ public final DatagramPacket newDatagram()
+ {
+ int fileLength, modeLength;
+ byte[] data;
+
+ fileLength = _filename.length();
+ modeLength = _modeBytes[_mode].length;
+
+ data = new byte[fileLength + modeLength + 4];
+ data[0] = 0;
+ data[1] = (byte)_type;
+ System.arraycopy(_filename.getBytes(), 0, data, 2, fileLength);
+ data[fileLength + 2] = 0;
+ System.arraycopy(_modeBytes[_mode], 0, data, fileLength + 3,
+ modeLength);
+
+ return new DatagramPacket(data, data.length, _address, _port);
+ }
+
+ /***
+ * Returns the transfer mode of the request.
+ * <p>
+ * @return The transfer mode of the request.
+ ***/
+ public final int getMode()
+ {
+ return _mode;
+ }
+
+ /***
+ * Returns the requested filename.
+ * <p>
+ * @return The requested filename.
+ ***/
+ public final String getFilename()
+ {
+ return _filename;
+ }
+}
diff --git a/org/apache/commons/net/tftp/TFTPWriteRequestPacket.java b/org/apache/commons/net/tftp/TFTPWriteRequestPacket.java
new file mode 100644
index 0000000..b545b2d
--- /dev/null
+++ b/org/apache/commons/net/tftp/TFTPWriteRequestPacket.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.net.tftp;
+
+import java.net.DatagramPacket;
+import java.net.InetAddress;
+
+/***
+ * A class derived from TFTPRequestPacket definiing a TFTP write request
+ * packet type.
+ * <p>
+ * 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. Additionally, only very
+ * few people should have to care about any of the TFTPPacket classes
+ * or derived classes. Almost all users should only be concerned with the
+ * {@link org.apache.commons.net.tftp.TFTPClient} class
+ * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()}
+ * and
+ * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()}
+ * methods.
+ * <p>
+ * <p>
+ * @author Daniel F. Savarese
+ * @see TFTPPacket
+ * @see TFTPRequestPacket
+ * @see TFTPPacketException
+ * @see TFTP
+ ***/
+
+public final class TFTPWriteRequestPacket extends TFTPRequestPacket
+{
+
+ /***
+ * Creates a write request packet to be sent to a host at a
+ * given port with a filename and transfer mode request.
+ * <p>
+ * @param destination The host to which the packet is going to be sent.
+ * @param port The port to which the packet is going to be sent.
+ * @param filename The requested filename.
+ * @param mode The requested transfer mode. This should be on of the TFTP
+ * class MODE constants (e.g., TFTP.NETASCII_MODE).
+ ***/
+ public TFTPWriteRequestPacket(InetAddress destination, int port,
+ String filename, int mode)
+ {
+ super(destination, port, TFTPPacket.WRITE_REQUEST, filename, mode);
+ }
+
+ /***
+ * Creates a write request packet of based on a received
+ * datagram and assumes the datagram has already been identified as a
+ * write request. Assumes the datagram is at least length 4, else an
+ * ArrayIndexOutOfBoundsException may be thrown.
+ * <p>
+ * @param datagram The datagram containing the received request.
+ * @throws TFTPPacketException If the datagram isn't a valid TFTP
+ * request packet.
+ ***/
+ TFTPWriteRequestPacket(DatagramPacket datagram) throws TFTPPacketException
+ {
+ super(TFTPPacket.WRITE_REQUEST, datagram);
+ }
+}