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;
    17
    18  import java.io.IOException;
    19  import java.io.InputStream;
    20  import java.io.OutputStream;
    21  import java.net.InetAddress;
    22  import java.net.Socket;
    23  import java.net.SocketException;
    24
    25  /***
    26   * The SocketClient provides the basic operations that are required of
    27   * client objects accessing sockets.  It is meant to be
    28   * subclassed to avoid having to rewrite the same code over and over again
    29   * to open a socket, close a socket, set timeouts, etc.  Of special note
    30   * is the {@link #setSocketFactory  setSocketFactory }
    31   * method, which allows you to control the type of Socket the SocketClient
    32   * creates for initiating network connections.  This is especially useful
    33   * for adding SSL or proxy support as well as better support for applets.  For
    34   * example, you could create a
    35   * {@link org.apache.commons.net.SocketFactory} that
    36   * requests browser security capabilities before creating a socket.
    37   * All classes derived from SocketClient should use the
    38   * {@link #_socketFactory_  _socketFactory_ } member variable to
    39   * create Socket and ServerSocket instances rather than instanting
    40   * them by directly invoking a constructor.  By honoring this contract
    41   * you guarantee that a user will always be able to provide his own
    42   * Socket implementations by substituting his own SocketFactory.
    43   * @author Daniel F. Savarese
    44   * @see SocketFactory
    45   */
    46  public abstract class SocketClient
    47  {
    48      /***
    49       * The end of line character sequence used by most IETF protocols.  That
    50       * is a carriage return followed by a newline: "\r\n"
    51       */
    52      public static final String NETASCII_EOL = "\r\n";
    53
    54      /*** The default SocketFactory shared by all SocketClient instances. */
    55      private static final SocketFactory __DEFAULT_SOCKET_FACTORY =
    56          new DefaultSocketFactory();
    57
    58      /*** The timeout to use after opening a socket. */
    59      protected int _timeout_;
    60
    61      /*** The socket used for the connection. */
    62      protected Socket _socket_;
    63
    64      /***
    65       * A status variable indicating if the client's socket is currently open.
    66       */
    67      protected boolean _isConnected_;
    68
    69      /*** The default port the client should connect to. */
    70      protected int _defaultPort_;
    71
    72      /*** The socket's InputStream. */
    73      protected InputStream _input_;
    74
    75      /*** The socket's OutputStream. */
    76      protected OutputStream _output_;
    77
    78      /*** The socket's SocketFactory. */
    79      protected SocketFactory _socketFactory_;
    80
    81
    82      /***
    83       * Default constructor for SocketClient.  Initializes
    84       * _socket_ to null, _timeout_ to 0, _defaultPort to 0,
    85       * _isConnected_ to false, and _socketFactory_ to a shared instance of
    86       * {@link org.apache.commons.net.DefaultSocketFactory}.
    87       */
    88      public SocketClient()
    89      {
    90          _socket_ = null;
    91          _input_ = null;
    92          _output_ = null;
    93          _timeout_ = 0;
    94          _defaultPort_ = 0;
    95          _isConnected_ = false;
    96          _socketFactory_ = __DEFAULT_SOCKET_FACTORY;
    97      }
    98
    99
    100     /***
    101      * Because there are so many connect() methods, the _connectAction_()
    102      * method is provided as a means of performing some action immediately
    103      * after establishing a connection, rather than reimplementing all
    104      * of the connect() methods.  The last action performed by every
    105      * connect() method after opening a socket is to call this method.
    106      * <p>
    107      * This method sets the timeout on the just opened socket to the default
    108      * timeout set by {@link #setDefaultTimeout  setDefaultTimeout() },
    109      * sets _input_ and _output_ to the socket's InputStream and OutputStream
    110      * respectively, and sets _isConnected_ to true.
    111      * <p>
    112      * Subclasses overriding this method should start by calling
    113      * <code> super._connectAction_() </code> first to ensure the
    114      * initialization of the aforementioned protected variables.
    115      */
    116     protected void _connectAction_() throws IOException
    117     {
    118         _socket_.setSoTimeout(_timeout_);
    119         _input_ = _socket_.getInputStream();
    120         _output_ = _socket_.getOutputStream();
    121         _isConnected_ = true;
    122     }
    123
    124
    125     /***
    126      * Opens a Socket connected to a remote host at the specified port and
    127      * originating from the current host at a system assigned port.
    128      * Before returning, {@link #_connectAction_  _connectAction_() }
    129      * is called to perform connection initialization actions.
    130      * <p>
    131      * @param host  The remote host.
    132      * @param port  The port to connect to on the remote host.
    133      * @exception SocketException If the socket timeout could not be set.
    134      * @exception IOException If the socket could not be opened.  In most
    135      *  cases you will only want to catch IOException since SocketException is
    136      *  derived from it.
    137      */
    138     public void connect(InetAddress host, int port)
    139     throws SocketException, IOException
    140     {
    141         _socket_ = _socketFactory_.createSocket(host, port);
    142         _connectAction_();
    143     }
    144
    145     /***
    146      * Opens a Socket connected to a remote host at the specified port and
    147      * originating from the current host at a system assigned port.
    148      * Before returning, {@link #_connectAction_  _connectAction_() }
    149      * is called to perform connection initialization actions.
    150      * <p>
    151      * @param hostname  The name of the remote host.
    152      * @param port  The port to connect to on the remote host.
    153      * @exception SocketException If the socket timeout could not be set.
    154      * @exception IOException If the socket could not be opened.  In most
    155      *  cases you will only want to catch IOException since SocketException is
    156      *  derived from it.
    157      * @exception UnknownHostException If the hostname cannot be resolved.
    158      */
    159     public void connect(String hostname, int port)
    160     throws SocketException, IOException
    161     {
    162         _socket_ = _socketFactory_.createSocket(hostname, port);
    163         _connectAction_();
    164     }
    165
    166
    167     /***
    168      * Opens a Socket connected to a remote host at the specified port and
    169      * originating from the specified local address and port.
    170      * Before returning, {@link #_connectAction_  _connectAction_() }
    171      * is called to perform connection initialization actions.
    172      * <p>
    173      * @param host  The remote host.
    174      * @param port  The port to connect to on the remote host.
    175      * @param localAddr  The local address to use.
    176      * @param localPort  The local port to use.
    177      * @exception SocketException If the socket timeout could not be set.
    178      * @exception IOException If the socket could not be opened.  In most
    179      *  cases you will only want to catch IOException since SocketException is
    180      *  derived from it.
    181      */
    182     public void connect(InetAddress host, int port,
    183                         InetAddress localAddr, int localPort)
    184     throws SocketException, IOException
    185     {
    186         _socket_ = _socketFactory_.createSocket(host, port, localAddr, localPort);
    187         _connectAction_();
    188     }
    189
    190
    191     /***
    192      * Opens a Socket connected to a remote host at the specified port and
    193      * originating from the specified local address and port.
    194      * Before returning, {@link #_connectAction_  _connectAction_() }
    195      * is called to perform connection initialization actions.
    196      * <p>
    197      * @param hostname  The name of the remote host.
    198      * @param port  The port to connect to on the remote host.
    199      * @param localAddr  The local address to use.
    200      * @param localPort  The local port to use.
    201      * @exception SocketException If the socket timeout could not be set.
    202      * @exception IOException If the socket could not be opened.  In most
    203      *  cases you will only want to catch IOException since SocketException is
    204      *  derived from it.
    205      * @exception UnknownHostException If the hostname cannot be resolved.
    206      */
    207     public void connect(String hostname, int port,
    208                         InetAddress localAddr, int localPort)
    209     throws SocketException, IOException
    210     {
    211         _socket_ =
    212             _socketFactory_.createSocket(hostname, port, localAddr, localPort);
    213         _connectAction_();
    214     }
    215
    216
    217     /***
    218      * Opens a Socket connected to a remote host at the current default port
    219      * and originating from the current host at a system assigned port.
    220      * Before returning, {@link #_connectAction_  _connectAction_() }
    221      * is called to perform connection initialization actions.
    222      * <p>
    223      * @param host  The remote host.
    224      * @exception SocketException If the socket timeout could not be set.
    225      * @exception IOException If the socket could not be opened.  In most
    226      *  cases you will only want to catch IOException since SocketException is
    227      *  derived from it.
    228      */
    229     public void connect(InetAddress host) throws SocketException, IOException
    230     {
    231         connect(host, _defaultPort_);
    232     }
    233
    234
    235     /***
    236      * Opens a Socket connected to a remote host at the current default
    237      * port and originating from the current host at a system assigned port.
    238      * Before returning, {@link #_connectAction_  _connectAction_() }
    239      * is called to perform connection initialization actions.
    240      * <p>
    241      * @param hostname  The name of the remote host.
    242      * @exception SocketException If the socket timeout could not be set.
    243      * @exception IOException If the socket could not be opened.  In most
    244      *  cases you will only want to catch IOException since SocketException is
    245      *  derived from it.
    246      * @exception UnknownHostException If the hostname cannot be resolved.
    247      */
    248     public void connect(String hostname) throws SocketException, IOException
    249     {
    250         connect(hostname, _defaultPort_);
    251     }
    252
    253
    254     /***
    255      * Disconnects the socket connection.
    256      * You should call this method after you've finished using the class
    257      * instance and also before you call
    258      * {@link #connect connect() }
    259      * again.  _isConnected_ is set to false, _socket_ is set to null,
    260      * _input_ is set to null, and _output_ is set to null.
    261      * <p>
    262      * @exception IOException  If there is an error closing the socket.
    263      */
    264     public void disconnect() throws IOException
    265     {
    266         _socket_.close();
    267         _input_.close();
    268         _output_.close();
    269         _socket_ = null;
    270         _input_ = null;
    271         _output_ = null;
    272         _isConnected_ = false;
    273     }
    274
    275
    276     /***
    277      * Returns true if the client is currently connected to a server.
    278      * <p>
    279      * @return True if the client is currently connected to a server,
    280      *         false otherwise.
    281      */
    282     public boolean isConnected()
    283     {
    284         return _isConnected_;
    285     }
    286
    287
    288     /***
    289      * Sets the default port the SocketClient should connect to when a port
    290      * is not specified.  The {@link #_defaultPort_  _defaultPort_ }
    291      * variable stores this value.  If never set, the default port is equal
    292      * to zero.
    293      * <p>
    294      * @param port  The default port to set.
    295      */
    296     public void setDefaultPort(int port)
    297     {
    298         _defaultPort_ = port;
    299     }
    300
    301     /***
    302      * Returns the current value of the default port (stored in
    303      * {@link #_defaultPort_  _defaultPort_ }).
    304      * <p>
    305      * @return The current value of the default port.
    306      */
    307     public int getDefaultPort()
    308     {
    309         return _defaultPort_;
    310     }
    311
    312
    313     /***
    314      * Set the default timeout in milliseconds to use when opening a socket.
    315      * This value is only used previous to a call to
    316      * {@link #connect connect()}
    317      * and should not be confused with {@link #setSoTimeout setSoTimeout()}
    318      * which operates on an the currently opened socket.  _timeout_ contains
    319      * the new timeout value.
    320      * <p>
    321      * @param timeout  The timeout in milliseconds to use for the socket
    322      *                 connection.
    323      */
    324     public void setDefaultTimeout(int timeout)
    325     {
    326         _timeout_ = timeout;
    327     }
    328
    329
    330     /***
    331      * Returns the default timeout in milliseconds that is used when
    332      * opening a socket.
    333      * <p>
    334      * @return The default timeout in milliseconds that is used when
    335      *         opening a socket.
    336      */
    337     public int getDefaultTimeout()
    338     {
    339         return _timeout_;
    340     }
    341
    342
    343     /***
    344      * Set the timeout in milliseconds of a currently open connection.
    345      * Only call this method after a connection has been opened
    346      * by {@link #connect connect()}.
    347      * <p>
    348      * @param timeout  The timeout in milliseconds to use for the currently
    349      *                 open socket connection.
    350      * @exception SocketException If the operation fails.
    351      */
    352     public void setSoTimeout(int timeout) throws SocketException
    353     {
    354         _socket_.setSoTimeout(timeout);
    355     }
    356
    357
    358     /***
    359      * Returns the timeout in milliseconds of the currently opened socket.
    360      * <p>
    361      * @return The timeout in milliseconds of the currently opened socket.
    362      * @exception SocketException If the operation fails.
    363      */
    364     public int getSoTimeout() throws SocketException
    365     {
    366         return _socket_.getSoTimeout();
    367     }
    368
    369     /***
    370      * Enables or disables the Nagle's algorithm (TCP_NODELAY) on the
    371      * currently opened socket.
    372      * <p>
    373      * @param on  True if Nagle's algorithm is to be enabled, false if not.
    374      * @exception SocketException If the operation fails.
    375      */
    376     public void setTcpNoDelay(boolean on) throws SocketException
    377     {
    378         _socket_.setTcpNoDelay(on);
    379     }
    380
    381
    382     /***
    383      * Returns true if Nagle's algorithm is enabled on the currently opened
    384      * socket.
    385      * <p>
    386      * @return True if Nagle's algorithm is enabled on the currently opened
    387      *        socket, false otherwise.
    388      * @exception SocketException If the operation fails.
    389      */
    390     public boolean getTcpNoDelay() throws SocketException
    391     {
    392         return _socket_.getTcpNoDelay();
    393     }
    394
    395
    396     /***
    397      * Sets the SO_LINGER timeout on the currently opened socket.
    398      * <p>
    399      * @param on  True if linger is to be enabled, false if not.
    400      * @param val The linger timeout (in hundredths of a second?)
    401      * @exception SocketException If the operation fails.
    402      */
    403     public void setSoLinger(boolean on, int val) throws SocketException
    404     {
    405         _socket_.setSoLinger(on, val);
    406     }
    407
    408
    409     /***
    410      * Returns the current SO_LINGER timeout of the currently opened socket.
    411      * <p>
    412      * @return The current SO_LINGER timeout.  If SO_LINGER is disabled returns
    413      *         -1.
    414      * @exception SocketException If the operation fails.
    415      */
    416     public int getSoLinger() throws SocketException
    417     {
    418         return _socket_.getSoLinger();
    419     }
    420
    421
    422     /***
    423      * Returns the port number of the open socket on the local host used
    424      * for the connection.
    425      * <p>
    426      * @return The port number of the open socket on the local host used
    427      *         for the connection.
    428      */
    429     public int getLocalPort()
    430     {
    431         return _socket_.getLocalPort();
    432     }
    433
    434
    435     /***
    436      * Returns the local address to which the client's socket is bound.
    437      * <p>
    438      * @return The local address to which the client's socket is bound.
    439      */
    440     public InetAddress getLocalAddress()
    441     {
    442         return _socket_.getLocalAddress();
    443     }
    444
    445     /***
    446      * Returns the port number of the remote host to which the client is
    447      * connected.
    448      * <p>
    449      * @return The port number of the remote host to which the client is
    450      *         connected.
    451      */
    452     public int getRemotePort()
    453     {
    454         return _socket_.getPort();
    455     }
    456
    457
    458     /***
    459      * @return The remote address to which the client is connected.
    460      */
    461     public InetAddress getRemoteAddress()
    462     {
    463         return _socket_.getInetAddress();
    464     }
    465
    466
    467     /***
    468      * Verifies that the remote end of the given socket is connected to the
    469      * the same host that the SocketClient is currently connected to.  This
    470      * is useful for doing a quick security check when a client needs to
    471      * accept a connection from a server, such as an FTP data connection or
    472      * a BSD R command standard error stream.
    473      * <p>
    474      * @return True if the remote hosts are the same, false if not.
    475      */
    476     public boolean verifyRemote(Socket socket)
    477     {
    478         InetAddress host1, host2;
    479
    480         host1 = socket.getInetAddress();
    481         host2 = getRemoteAddress();
    482
    483         return host1.equals(host2);
    484     }
    485
    486
    487     /***
    488      * Sets the SocketFactory used by the SocketClient to open socket
    489      * connections.  If the factory value is null, then a default
    490      * factory is used (only do this to reset the factory after having
    491      * previously altered it).
    492      * <p>
    493      * @param factory  The new SocketFactory the SocketClient should use.
    494      */
    495     public void setSocketFactory(SocketFactory factory)
    496     {
    497         if (factory == null)
    498             _socketFactory_ = __DEFAULT_SOCKET_FACTORY;
    499         else
    500             _socketFactory_ = factory;
    501     }
    502 }
    503
    504