View Javadoc

    1   /*
    2    * Copyright 2001-2005 The Apache Software Foundation
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *     http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  package org.apache.commons.net.tftp;
    17
    18  import java.net.DatagramPacket;
    19  import java.net.InetAddress;
    20
    21  /****
    22   * An abstract class derived from TFTPPacket definiing a TFTP Request
    23   * packet type.  It is subclassed by the
    24   * {@link org.apache.commons.net.tftp.TFTPReadRequestPacket}
    25   *   and
    26   * {@link org.apache.commons.net.tftp.TFTPWriteRequestPacket}
    27   *  classes.
    28   * <p>
    29   * Details regarding the TFTP protocol and the format of TFTP packets can
    30   * be found in RFC 783.  But the point of these classes is to keep you
    31   * from having to worry about the internals.  Additionally, only very
    32   * few people should have to care about any of the TFTPPacket classes
    33   * or derived classes.  Almost all users should only be concerned with the
    34   * {@link org.apache.commons.net.tftp.TFTPClient} class
    35   * {@link org.apache.commons.net.tftp.TFTPClient#receiveFile receiveFile()}
    36   * and
    37   * {@link org.apache.commons.net.tftp.TFTPClient#sendFile sendFile()}
    38   * methods.
    39   * <p>
    40   * <p>
    41   * @author Daniel F. Savarese
    42   * @see TFTPPacket
    43   * @see TFTPReadRequestPacket
    44   * @see TFTPWriteRequestPacket
    45   * @see TFTPPacketException
    46   * @see TFTP
    47   ***/
    48
    49  public abstract class TFTPRequestPacket extends TFTPPacket
    50  {
    51      /****
    52       * An array containing the string names of the transfer modes and indexed
    53       * by the transfer mode constants.
    54       ***/
    55      static final String[] _modeStrings = { "netascii", "octet" };
    56
    57      /****
    58       * A null terminated byte array representation of the ascii names of the
    59       * transfer mode constants.  This is convenient for creating the TFTP
    60       * request packets.
    61       ***/
    62      static final byte[] _modeBytes[] = {
    63                                             { (byte)'n', (byte)'e', (byte)'t', (byte)'a', (byte)'s', (byte)'c',
    64                                               (byte)'i', (byte)'i', 0 },
    65                                             { (byte)'o', (byte)'c', (byte)'t', (byte)'e', (byte)'t', 0 }
    66                                         };
    67
    68      /**** The transfer mode of the request. ***/
    69      int _mode;
    70
    71      /**** The filename of the request. ***/
    72      String _filename;
    73
    74      /****
    75       * Creates a request packet of a given type to be sent to a host at a
    76       * given port with a filename and transfer mode request.
    77       * <p>
    78       * @param destination  The host to which the packet is going to be sent.
    79       * @param port  The port to which the packet is going to be sent.
    80       * @param type The type of the request (either TFTPPacket.READ_REQUEST or
    81       *             TFTPPacket.WRITE_REQUEST).
    82       * @param filename The requested filename.
    83       * @param mode The requested transfer mode.  This should be on of the TFTP
    84       *        class MODE constants (e.g., TFTP.NETASCII_MODE).
    85       ***/
    86      TFTPRequestPacket(InetAddress destination, int port,
    87                        int type, String filename, int mode)
    88      {
    89          super(type, destination, port);
    90
    91          _filename = filename;
    92          _mode = mode;
    93      }
    94
    95      /****
    96       * Creates a request packet of a given type based on a received
    97       * datagram.  Assumes the datagram is at least length 4, else an
    98       * ArrayIndexOutOfBoundsException may be thrown.
    99       * <p>
    100      * @param type The type of the request (either TFTPPacket.READ_REQUEST or
    101      *             TFTPPacket.WRITE_REQUEST).
    102      * @param datagram  The datagram containing the received request.
    103      * @throws TFTPPacketException  If the datagram isn't a valid TFTP
    104      *         request packet of the appropriate type.
    105      ***/
    106     TFTPRequestPacket(int type, DatagramPacket datagram)
    107     throws TFTPPacketException
    108     {
    109         super(type, datagram.getAddress(), datagram.getPort());
    110
    111         byte[] data;
    112         int index, length;
    113         String mode;
    114         StringBuffer buffer;
    115
    116         data = datagram.getData();
    117
    118         if (getType() != data[1])
    119             throw new TFTPPacketException("TFTP operator code does not match type.");
    120
    121         buffer = new StringBuffer();
    122
    123         index = 2;
    124         length = datagram.getLength();
    125
    126         while (index < length && data[index] != 0)
    127         {
    128             buffer.append((char)data[index]);
    129             ++index;
    130         }
    131
    132         _filename = buffer.toString();
    133
    134         if (index >= length)
    135             throw new TFTPPacketException("Bad filename and mode format.");
    136
    137         buffer.setLength(0);
    138         ++index; // need to advance beyond the end of string marker
    139         while (index < length && data[index] != 0)
    140         {
    141             buffer.append((char)data[index]);
    142             ++index;
    143         }
    144
    145         mode = buffer.toString().toLowerCase();
    146         length = _modeStrings.length;
    147
    148         for (index = 0; index < length; index++)
    149         {
    150             if (mode.equals(_modeStrings[index]))
    151             {
    152                 _mode = index;
    153                 break;
    154             }
    155         }
    156
    157         if (index >= length)
    158         {
    159             throw new TFTPPacketException("Unrecognized TFTP transfer mode: " + mode);
    160             // May just want to default to binary mode instead of throwing
    161             // exception.
    162             //_mode = TFTP.OCTET_MODE;
    163         }
    164     }
    165
    166
    167     /****
    168      * This is a method only available within the package for
    169      * implementing efficient datagram transport by elminating buffering.
    170      * It takes a datagram as an argument, and a byte buffer in which
    171      * to store the raw datagram data.  Inside the method, the data
    172      * is set as the datagram's data and the datagram returned.
    173      * <p>
    174      * @param datagram  The datagram to create.
    175      * @param data The buffer to store the packet and to use in the datagram.
    176      * @return The datagram argument.
    177      ***/
    178     final DatagramPacket _newDatagram(DatagramPacket datagram, byte[] data)
    179     {
    180         int fileLength, modeLength;
    181
    182         fileLength = _filename.length();
    183         modeLength = _modeBytes[_mode].length;
    184
    185         data[0] = 0;
    186         data[1] = (byte)_type;
    187         System.arraycopy(_filename.getBytes(), 0, data, 2, fileLength);
    188         data[fileLength + 2] = 0;
    189         System.arraycopy(_modeBytes[_mode], 0, data, fileLength + 3,
    190                          modeLength);
    191
    192         datagram.setAddress(_address);
    193         datagram.setPort(_port);
    194         datagram.setData(data);
    195         datagram.setLength(fileLength + modeLength + 3);
    196
    197         return datagram;
    198     }
    199
    200     /****
    201      * Creates a UDP datagram containing all the TFTP
    202      * request packet data in the proper format.
    203      * This is a method exposed to the programmer in case he
    204      * wants to implement his own TFTP client instead of using
    205      * the {@link org.apache.commons.net.tftp.TFTPClient}
    206      * class.  Under normal circumstances, you should not have a need to call
    207      * this method.
    208      * <p>
    209      * @return A UDP datagram containing the TFTP request packet.
    210      ***/
    211     public final DatagramPacket newDatagram()
    212     {
    213         int fileLength, modeLength;
    214         byte[] data;
    215
    216         fileLength = _filename.length();
    217         modeLength = _modeBytes[_mode].length;
    218
    219         data = new byte[fileLength + modeLength + 4];
    220         data[0] = 0;
    221         data[1] = (byte)_type;
    222         System.arraycopy(_filename.getBytes(), 0, data, 2, fileLength);
    223         data[fileLength + 2] = 0;
    224         System.arraycopy(_modeBytes[_mode], 0, data, fileLength + 3,
    225                          modeLength);
    226
    227         return new DatagramPacket(data, data.length, _address, _port);
    228     }
    229
    230     /****
    231      * Returns the transfer mode of the request.
    232      * <p>
    233      * @return The transfer mode of the request.
    234      ***/
    235     public final int getMode()
    236     {
    237         return _mode;
    238     }
    239
    240     /****
    241      * Returns the requested filename.
    242      * <p>
    243      * @return The requested filename.
    244      ***/
    245     public final String getFilename()
    246     {
    247         return _filename;
    248     }
    249 }