    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017
    018package org.apache.commons.net.tftp;
    019
    020import java.net.DatagramPacket;
    021import java.net.InetAddress;
    022
    023/**
    024 * A final class derived from TFTPPacket defining the TFTP Error packet type.
    025 * <p>
    026 * 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
    027 * 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
    028 * should only be concerned with the {@link org.apache.commons.net.tftp.TFTPClient} class {@link org.apache.commons.net.tftp.TFTPClient#receiveFile
    029 * receiveFile()} and {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()} methods.
    030 *
    031 *
    032 * @see TFTPPacket
    033 * @see TFTPPacketException
    034 * @see TFTP
    035 */
    036
    037public final class TFTPErrorPacket extends TFTPPacket {
    038    /** The undefined error code according to RFC 783, value 0. */
    039    public static final int UNDEFINED = 0;
    040
    041    /** The file not found error code according to RFC 783, value 1. */
    042    public static final int FILE_NOT_FOUND = 1;
    043
    044    /** The access violation error code according to RFC 783, value 2. */
    045    public static final int ACCESS_VIOLATION = 2;
    046
    047    /** The disk full error code according to RFC 783, value 3. */
    048    public static final int OUT_OF_SPACE = 3;
    049
    050    /**
    051     * The illegal TFTP operation error code according to RFC 783, value 4.
    052     */
    053    public static final int ILLEGAL_OPERATION = 4;
    054
    055    /** The unknown transfer id error code according to RFC 783, value 5. */
    056    public static final int UNKNOWN_TID = 5;
    057
    058    /** The file already exists error code according to RFC 783, value 6. */
    059    public static final int FILE_EXISTS = 6;
    060
    061    /** The no such user error code according to RFC 783, value 7. */
    062    public static final int NO_SUCH_USER = 7;
    063
    064    /** The error code of this packet. */
    065    private final int error;
    066
    067    /** The error message of this packet. */
    068    private final String message;
    069
    070    /**
    071     * Creates an error packet based from a received datagram. Assumes the datagram is at least length 4, else an ArrayIndexOutOfBoundsException may be thrown.
    072     *
    073     * @param datagram The datagram containing the received error.
    074     * @throws TFTPPacketException If the datagram isn't a valid TFTP error packet.
    075     */
    076    TFTPErrorPacket(final DatagramPacket datagram) throws TFTPPacketException {
    077        super(TFTPPacket.ERROR, datagram.getAddress(), datagram.getPort());
    078        int index;
    079        final int length;
    080        final byte[] data;
    081        final StringBuilder buffer;
    082
    083        data = datagram.getData();
    084        length = datagram.getLength();
    085
    086        if (getType() != data[1]) {
    087            throw new TFTPPacketException("TFTP operator code does not match type.");
    088        }
    089
    090        error = (data[2] & 0xff) << 8 | data[3] & 0xff;
    091
    092        if (length < 5) {
    093            throw new TFTPPacketException("Bad error packet. No message.");
    094        }
    095
    096        index = 4;
    097        buffer = new StringBuilder();
    098
    099        while (index < length && data[index] != 0) {
    100            buffer.append((char) data[index]);
    101            ++index;
    102        }
    103
    104        message = buffer.toString();
    105    }
    106
    107    /**
    108     * Creates an error packet to be sent to a host at a given port with an error code and error message.
    109     *
    110     * @param destination The host to which the packet is going to be sent.
    111     * @param port        The port to which the packet is going to be sent.
    112     * @param error       The error code of the packet.
    113     * @param message     The error message of the packet.
    114     */
    115    public TFTPErrorPacket(final InetAddress destination, final int port, final int error, final String message) {
    116        super(TFTPPacket.ERROR, destination, port);
    117
    118        this.error = error;
    119        this.message = message;
    120    }
    121
    122    /**
    123     * Returns the error code of the packet.
    124     *
    125     * @return The error code of the packet.
    126     */
    127    public int getError() {
    128        return error;
    129    }
    130
    131    /**
    132     * Returns the error message of the packet.
    133     *
    134     * @return The error message of the packet.
    135     */
    136    public String getMessage() {
    137        return message;
    138    }
    139
    140    /**
    141     * 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
    142     * implement his own TFTP client instead of using the {@link org.apache.commons.net.tftp.TFTPClient} class. Under normal circumstances, you should not have
    143     * a need to call this method.
    144     *
    145     * @return A UDP datagram containing the TFTP error packet.
    146     */
    147    @Override
    148    public DatagramPacket newDatagram() {
    149        final byte[] data;
    150        final int length;
    151
    152        length = message.length();
    153
    154        data = new byte[length + 5];
    155        data[0] = 0;
    156        data[1] = (byte) type;
    157        data[2] = (byte) ((error & 0xffff) >> 8);
    158        data[3] = (byte) (error & 0xff);
    159
    160        System.arraycopy(message.getBytes(), 0, data, 4, length);
    161
    162        data[length + 4] = 0;
    163
    164        return new DatagramPacket(data, data.length, address, port);
    165    }
    166
    167    /**
    168     * This is a method only available within the package for implementing efficient datagram transport by eliminating buffering. It takes a datagram as an
    169     * 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.
    170     *
    171     * @param datagram The datagram to create.
    172     * @param data     The buffer to store the packet and to use in the datagram.
    173     * @return The datagram argument.
    174     */
    175    @Override
    176    DatagramPacket newDatagram(final DatagramPacket datagram, final byte[] data) {
    177        final int length;
    178
    179        length = message.length();
    180
    181        data[0] = 0;
    182        data[1] = (byte) type;
    183        data[2] = (byte) ((error & 0xffff) >> 8);
    184        data[3] = (byte) (error & 0xff);
    185
    186        System.arraycopy(message.getBytes(), 0, data, 4, length);
    187
    188        data[length + 4] = 0;
    189
    190        datagram.setAddress(address);
    191        datagram.setPort(port);
    192        datagram.setData(data);
    193        datagram.setLength(length + 4);
    194
    195        return datagram;
    196    }
    197
    198    /**
    199     * For debugging
    200     *
    201     * @since 3.6
    202     */
    203    @Override
    204    public String toString() {
    205        return super.toString() + " ERR " + error + " " + message;
    206    }
    207}