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.io.IOException;
    19  import java.io.InterruptedIOException;
    20  import java.net.DatagramPacket;
    21  import java.net.SocketException;
    22  import org.apache.commons.net.DatagramSocketClient;
    23
    24  /****
    25   * The TFTP class exposes a set of methods to allow you to deal with the TFTP
    26   * protocol directly, in case you want to write your own TFTP client or
    27   * server.  However, almost every user should only be concerend with
    28   * the {@link org.apache.commons.net.DatagramSocketClient#open  open() },
    29   * and {@link org.apache.commons.net.DatagramSocketClient#close  close() },
    30   * methods. Additionally,the a
    31   * {@link org.apache.commons.net.DatagramSocketClient#setDefaultTimeout setDefaultTimeout() }
    32   *  method may be of importance for performance tuning.
    33   * <p>
    34   * Details regarding the TFTP protocol and the format of TFTP packets can
    35   * be found in RFC 783.  But the point of these classes is to keep you
    36   * from having to worry about the internals.
    37   * <p>
    38   * <p>
    39   * @author Daniel F. Savarese
    40   * @see org.apache.commons.net.DatagramSocketClient
    41   * @see TFTPPacket
    42   * @see TFTPPacketException
    43   * @see TFTPClient
    44   ***/
    45
    46  public class TFTP extends DatagramSocketClient
    47  {
    48      /****
    49       * The ascii transfer mode.  Its value is 0 and equivalent to NETASCII_MODE
    50       ***/
    51      public static final int ASCII_MODE = 0;
    52
    53      /****
    54       * The netascii transfer mode.  Its value is 0.
    55       ***/
    56      public static final int NETASCII_MODE = 0;
    57
    58      /****
    59       * The binary transfer mode.  Its value is 1 and equivalent to OCTET_MODE.
    60       ***/
    61      public static final int BINARY_MODE = 1;
    62
    63      /****
    64       * The image transfer mode.  Its value is 1 and equivalent to OCTET_MODE.
    65       ***/
    66      public static final int IMAGE_MODE = 1;
    67
    68      /****
    69       * The octet transfer mode.  Its value is 1.
    70       ***/
    71      public static final int OCTET_MODE = 1;
    72
    73      /****
    74       * The default number of milliseconds to wait to receive a datagram
    75       * before timing out.  The default is 5000 milliseconds (5 seconds).
    76       ***/
    77      public static final int DEFAULT_TIMEOUT = 5000;
    78
    79      /****
    80       * The default TFTP port according to RFC 783 is 69.
    81       ***/
    82      public static final int DEFAULT_PORT = 69;
    83
    84      /****
    85       * The size to use for TFTP packet buffers.  Its 4 plus the
    86       * TFTPPacket.SEGMENT_SIZE, i.e. 516.
    87       ***/
    88      static final int PACKET_SIZE = TFTPPacket.SEGMENT_SIZE + 4;
    89
    90      /**** A buffer used to accelerate receives in bufferedReceive() ***/
    91      private byte[] __receiveBuffer;
    92
    93      /**** A datagram used to minimize memory allocation in bufferedReceive() ***/
    94      private DatagramPacket __receiveDatagram;
    95
    96      /**** A datagram used to minimize memory allocation in bufferedSend() ***/
    97      private DatagramPacket __sendDatagram;
    98
    99      /****
    100      * A buffer used to accelerate sends in bufferedSend().
    101      * It is left package visible so that TFTPClient may be slightly more
    102      * efficient during file sends.  It saves the creation of an
    103      * additional buffer and prevents a buffer copy in _newDataPcket().
    104      ***/
    105     byte[] _sendBuffer;
    106
    107
    108     /****
    109      * Returns the TFTP string representation of a TFTP transfer mode.
    110      * Will throw an ArrayIndexOutOfBoundsException if an invalid transfer
    111      * mode is specified.
    112      * <p>
    113      * @param mode  The TFTP transfer mode.  One of the MODE constants.
    114      * @return  The TFTP string representation of the TFTP transfer mode.
    115      ***/
    116     public static final String getModeName(int mode)
    117     {
    118         return TFTPRequestPacket._modeStrings[mode];
    119     }
    120
    121     /****
    122      * Creates a TFTP instance with a default timeout of DEFAULT_TIMEOUT,
    123      * a null socket, and buffered operations disabled.
    124      ***/
    125     public TFTP()
    126     {
    127         setDefaultTimeout(DEFAULT_TIMEOUT);
    128         __receiveBuffer = null;
    129         __receiveDatagram = null;
    130     }
    131
    132     /****
    133      * This method synchronizes a connection by discarding all packets that
    134      * may be in the local socket buffer.  This method need only be called
    135      * when you implement your own TFTP client or server.
    136      * <p>
    137      * @exception IOException if an I/O error occurs.
    138      ***/
    139     public final void discardPackets() throws IOException
    140     {
    141         int to;
    142         DatagramPacket datagram;
    143
    144         datagram = new DatagramPacket(new byte[PACKET_SIZE], PACKET_SIZE);
    145
    146         to = getSoTimeout();
    147         setSoTimeout(1);
    148
    149         try
    150         {
    151             while (true)
    152                 _socket_.receive(datagram);
    153         }
    154         catch (SocketException e)
    155         {
    156             // Do nothing.  We timed out so we hope we're caught up.
    157         }
    158         catch (InterruptedIOException e)
    159         {
    160             // Do nothing.  We timed out so we hope we're caught up.
    161         }
    162
    163         setSoTimeout(to);
    164     }
    165
    166
    167     /****
    168      * This is a special method to perform a more efficient packet receive.
    169      * It should only be used after calling
    170      * {@link #beginBufferedOps  beginBufferedOps() }.  beginBufferedOps()
    171      * initializes a set of buffers used internally that prevent the new
    172      * allocation of a DatagramPacket and byte array for each send and receive.
    173      * To use these buffers you must call the bufferedReceive() and
    174      * bufferedSend() methods instead of send() and receive().  You must
    175      * also be certain that you don't manipulate the resulting packet in
    176      * such a way that it interferes with future buffered operations.
    177      * For example, a TFTPDataPacket received with bufferedReceive() will
    178      * have a reference to the internal byte buffer.  You must finish using
    179      * this data before calling bufferedReceive() again, or else the data
    180      * will be overwritten by the the call.
    181      * <p>
    182      * @return The TFTPPacket received.
    183      * @exception InterruptedIOException  If a socket timeout occurs.  The
    184      *       Java documentation claims an InterruptedIOException is thrown
    185      *       on a DatagramSocket timeout, but in practice we find a
    186      *       SocketException is thrown.  You should catch both to be safe.
    187      * @exception SocketException  If a socket timeout occurs.  The
    188      *       Java documentation claims an InterruptedIOException is thrown
    189      *       on a DatagramSocket timeout, but in practice we find a
    190      *       SocketException is thrown.  You should catch both to be safe.
    191      * @exception IOException  If some other I/O error occurs.
    192      * @exception TFTPPacketException If an invalid TFTP packet is received.
    193      ***/
    194     public final TFTPPacket bufferedReceive() throws IOException,
    195                 InterruptedIOException, SocketException, TFTPPacketException
    196     {
    197         __receiveDatagram.setData(__receiveBuffer);
    198         __receiveDatagram.setLength(__receiveBuffer.length);
    199         _socket_.receive(__receiveDatagram);
    200
    201         return TFTPPacket.newTFTPPacket(__receiveDatagram);
    202     }
    203
    204     /****
    205      * This is a special method to perform a more efficient packet send.
    206      * It should only be used after calling
    207      * {@link #beginBufferedOps  beginBufferedOps() }.  beginBufferedOps()
    208      * initializes a set of buffers used internally that prevent the new
    209      * allocation of a DatagramPacket and byte array for each send and receive.
    210      * To use these buffers you must call the bufferedReceive() and
    211      * bufferedSend() methods instead of send() and receive().  You must
    212      * also be certain that you don't manipulate the resulting packet in
    213      * such a way that it interferes with future buffered operations.
    214      * For example, a TFTPDataPacket received with bufferedReceive() will
    215      * have a reference to the internal byte buffer.  You must finish using
    216      * this data before calling bufferedReceive() again, or else the data
    217      * will be overwritten by the the call.
    218      * <p>
    219      * @param packet  The TFTP packet to send.
    220      * @exception IOException  If some  I/O error occurs.
    221      ***/
    222     public final void bufferedSend(TFTPPacket packet) throws IOException
    223     {
    224         _socket_.send(packet._newDatagram(__sendDatagram, _sendBuffer));
    225     }
    226
    227
    228     /****
    229      * Initializes the internal buffers. Buffers are used by
    230      * {@link #bufferedSend  bufferedSend() } and
    231      * {@link #bufferedReceive  bufferedReceive() }.  This
    232      * method must be called before calling either one of those two
    233      * methods.  When you finish using buffered operations, you must
    234      * call {@link #endBufferedOps  endBufferedOps() }.
    235      ***/
    236     public final void beginBufferedOps()
    237     {
    238         __receiveBuffer = new byte[PACKET_SIZE];
    239         __receiveDatagram =
    240             new DatagramPacket(__receiveBuffer, __receiveBuffer.length);
    241         _sendBuffer = new byte[PACKET_SIZE];
    242         __sendDatagram =
    243             new DatagramPacket(_sendBuffer, _sendBuffer.length);
    244     }
    245
    246     /****
    247      * Releases the resources used to perform buffered sends and receives.
    248      ***/
    249     public final void endBufferedOps()
    250     {
    251         __receiveBuffer = null;
    252         __receiveDatagram = null;
    253         _sendBuffer = null;
    254         __sendDatagram = null;
    255     }
    256
    257
    258     /****
    259      * Sends a TFTP packet to its destination.
    260      * <p>
    261      * @param packet  The TFTP packet to send.
    262      * @exception IOException  If some  I/O error occurs.
    263      ***/
    264     public final void send(TFTPPacket packet) throws IOException
    265     {
    266         _socket_.send(packet.newDatagram());
    267     }
    268
    269
    270     /****
    271      * Receives a TFTPPacket.
    272      * <p>
    273      * @return The TFTPPacket received.
    274      * @exception InterruptedIOException  If a socket timeout occurs.  The
    275      *       Java documentation claims an InterruptedIOException is thrown
    276      *       on a DatagramSocket timeout, but in practice we find a
    277      *       SocketException is thrown.  You should catch both to be safe.
    278      * @exception SocketException  If a socket timeout occurs.  The
    279      *       Java documentation claims an InterruptedIOException is thrown
    280      *       on a DatagramSocket timeout, but in practice we find a
    281      *       SocketException is thrown.  You should catch both to be safe.
    282      * @exception IOException  If some other I/O error occurs.
    283      * @exception TFTPPacketException If an invalid TFTP packet is received.
    284      ***/
    285     public final TFTPPacket receive() throws IOException, InterruptedIOException,
    286                 SocketException, TFTPPacketException
    287     {
    288         DatagramPacket packet;
    289
    290         packet = new DatagramPacket(new byte[PACKET_SIZE], PACKET_SIZE);
    291
    292         _socket_.receive(packet);
    293
    294         return TFTPPacket.newTFTPPacket(packet);
    295     }
    296
    297
    298 }