diff options
| author | Joe Robinson <joe@lc8n.com> | 2010-10-27 14:21:09 +0100 | 
|---|---|---|
| committer | Joe Robinson <joe@lc8n.com> | 2010-10-27 14:21:09 +0100 | 
| commit | 063284837c8c366e5502b1b0264b8eb807b61732 (patch) | |
| tree | fff3a1e1e5afaa671485b9d990704658276627ac /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.java | 301 | ||||
| -rw-r--r-- | org/apache/commons/net/tftp/TFTPAckPacket.java | 158 | ||||
| -rw-r--r-- | org/apache/commons/net/tftp/TFTPClient.java | 610 | ||||
| -rw-r--r-- | org/apache/commons/net/tftp/TFTPDataPacket.java | 254 | ||||
| -rw-r--r-- | org/apache/commons/net/tftp/TFTPErrorPacket.java | 226 | ||||
| -rw-r--r-- | org/apache/commons/net/tftp/TFTPPacket.java | 247 | ||||
| -rw-r--r-- | org/apache/commons/net/tftp/TFTPPacketException.java | 57 | ||||
| -rw-r--r-- | org/apache/commons/net/tftp/TFTPReadRequestPacket.java | 80 | ||||
| -rw-r--r-- | org/apache/commons/net/tftp/TFTPRequestPacket.java | 253 | ||||
| -rw-r--r-- | org/apache/commons/net/tftp/TFTPWriteRequestPacket.java | 79 | 
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);
 +    }
 +}
  | 
