    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
    018    package org.apache.commons.net;
    019
    020    import java.io.Closeable;
    021    import java.io.IOException;
    022    import java.io.InputStream;
    023    import java.io.OutputStream;
    024    import java.net.InetAddress;
    025    import java.net.InetSocketAddress;
    026    import java.net.Socket;
    027    import java.net.SocketException;
    028    import java.net.UnknownHostException;
    029
    030    import javax.net.ServerSocketFactory;
    031    import javax.net.SocketFactory;
    032
    033
    034    /**
    035     * The SocketClient provides the basic operations that are required of
    036     * client objects accessing sockets.  It is meant to be
    037     * subclassed to avoid having to rewrite the same code over and over again
    038     * to open a socket, close a socket, set timeouts, etc.  Of special note
    039     * is the {@link #setSocketFactory  setSocketFactory }
    040     * method, which allows you to control the type of Socket the SocketClient
    041     * creates for initiating network connections.  This is especially useful
    042     * for adding SSL or proxy support as well as better support for applets.  For
    043     * example, you could create a
    044     * {@link javax.net.SocketFactory} that
    045     * requests browser security capabilities before creating a socket.
    046     * All classes derived from SocketClient should use the
    047     * {@link #_socketFactory_  _socketFactory_ } member variable to
    048     * create Socket and ServerSocket instances rather than instanting
    049     * them by directly invoking a constructor.  By honoring this contract
    050     * you guarantee that a user will always be able to provide his own
    051     * Socket implementations by substituting his own SocketFactory.
    052     * @author Daniel F. Savarese
    053     * @see SocketFactory
    054     */
    055    public abstract class SocketClient
    056    {
    057        /**
    058         * The end of line character sequence used by most IETF protocols.  That
    059         * is a carriage return followed by a newline: "\r\n"
    060         */
    061        public static final String NETASCII_EOL = "\r\n";
    062
    063        /** The default SocketFactory shared by all SocketClient instances. */
    064        private static final SocketFactory __DEFAULT_SOCKET_FACTORY =
    065                SocketFactory.getDefault();
    066
    067        /** The default {@link ServerSocketFactory} */
    068        private static final ServerSocketFactory __DEFAULT_SERVER_SOCKET_FACTORY =
    069                ServerSocketFactory.getDefault();
    070
    071        /** The timeout to use after opening a socket. */
    072        protected int _timeout_;
    073
    074        /** The socket used for the connection. */
    075        protected Socket _socket_;
    076
    077        /** The default port the client should connect to. */
    078        protected int _defaultPort_;
    079
    080        /** The socket's InputStream. */
    081        protected InputStream _input_;
    082
    083        /** The socket's OutputStream. */
    084        protected OutputStream _output_;
    085
    086        /** The socket's SocketFactory. */
    087        protected SocketFactory _socketFactory_;
    088
    089        /** The socket's ServerSocket Factory. */
    090        protected ServerSocketFactory _serverSocketFactory_;
    091
    092        /** The socket's connect timeout (0 = infinite timeout) */
    093        private static final int DEFAULT_CONNECT_TIMEOUT = 0;
    094        protected int connectTimeout = DEFAULT_CONNECT_TIMEOUT;
    095
    096        /** Hint for SO_RCVBUF size */
    097        int receiveBufferSize = -1;
    098
    099        /** Hint for SO_SNDBUF size */
    100        int sendBufferSize = -1;
    101
    102        /**
    103         * Default constructor for SocketClient.  Initializes
    104         * _socket_ to null, _timeout_ to 0, _defaultPort to 0,
    105         * _isConnected_ to false, and _socketFactory_ to a shared instance of
    106         * {@link org.apache.commons.net.DefaultSocketFactory}.
    107         */
    108        public SocketClient()
    109        {
    110            _socket_ = null;
    111            _input_ = null;
    112            _output_ = null;
    113            _timeout_ = 0;
    114            _defaultPort_ = 0;
    115            _socketFactory_ = __DEFAULT_SOCKET_FACTORY;
    116            _serverSocketFactory_ = __DEFAULT_SERVER_SOCKET_FACTORY;
    117        }
    118
    119
    120        /**
    121         * Because there are so many connect() methods, the _connectAction_()
    122         * method is provided as a means of performing some action immediately
    123         * after establishing a connection, rather than reimplementing all
    124         * of the connect() methods.  The last action performed by every
    125         * connect() method after opening a socket is to call this method.
    126         * <p>
    127         * This method sets the timeout on the just opened socket to the default
    128         * timeout set by {@link #setDefaultTimeout  setDefaultTimeout() },
    129         * sets _input_ and _output_ to the socket's InputStream and OutputStream
    130         * respectively, and sets _isConnected_ to true.
    131         * <p>
    132         * Subclasses overriding this method should start by calling
    133         * <code> super._connectAction_() </code> first to ensure the
    134         * initialization of the aforementioned protected variables.
    135         */
    136        protected void _connectAction_() throws IOException
    137        {
    138            _socket_.setSoTimeout(_timeout_);
    139            _input_ = _socket_.getInputStream();
    140            _output_ = _socket_.getOutputStream();
    141        }
    142
    143
    144        /**
    145         * Opens a Socket connected to a remote host at the specified port and
    146         * originating from the current host at a system assigned port.
    147         * Before returning, {@link #_connectAction_  _connectAction_() }
    148         * is called to perform connection initialization actions.
    149         * <p>
    150         * @param host  The remote host.
    151         * @param port  The port to connect to on the remote host.
    152         * @exception SocketException If the socket timeout could not be set.
    153         * @exception IOException If the socket could not be opened.  In most
    154         *  cases you will only want to catch IOException since SocketException is
    155         *  derived from it.
    156         */
    157        public void connect(InetAddress host, int port)
    158        throws SocketException, IOException
    159        {
    160            _socket_ = _socketFactory_.createSocket();
    161            if (receiveBufferSize != -1) _socket_.setReceiveBufferSize(receiveBufferSize);
    162            if (sendBufferSize != -1) _socket_.setSendBufferSize(sendBufferSize);
    163            _socket_.connect(new InetSocketAddress(host, port), connectTimeout);
    164            _connectAction_();
    165        }
    166
    167        /**
    168         * Opens a Socket connected to a remote host at the specified port and
    169         * originating from the current host at a system assigned port.
    170         * Before returning, {@link #_connectAction_  _connectAction_() }
    171         * is called to perform connection initialization actions.
    172         * <p>
    173         * @param hostname  The name of the remote host.
    174         * @param port  The port to connect to on the remote host.
    175         * @exception SocketException If the socket timeout could not be set.
    176         * @exception IOException If the socket could not be opened.  In most
    177         *  cases you will only want to catch IOException since SocketException is
    178         *  derived from it.
    179         * @exception UnknownHostException If the hostname cannot be resolved.
    180         */
    181        public void connect(String hostname, int port)
    182        throws SocketException, IOException
    183        {
    184            connect(InetAddress.getByName(hostname), port);
    185        }
    186
    187
    188        /**
    189         * Opens a Socket connected to a remote host at the specified port and
    190         * originating from the specified local address and port.
    191         * Before returning, {@link #_connectAction_  _connectAction_() }
    192         * is called to perform connection initialization actions.
    193         * <p>
    194         * @param host  The remote host.
    195         * @param port  The port to connect to on the remote host.
    196         * @param localAddr  The local address to use.
    197         * @param localPort  The local port to use.
    198         * @exception SocketException If the socket timeout could not be set.
    199         * @exception IOException If the socket could not be opened.  In most
    200         *  cases you will only want to catch IOException since SocketException is
    201         *  derived from it.
    202         */
    203        public void connect(InetAddress host, int port,
    204                            InetAddress localAddr, int localPort)
    205        throws SocketException, IOException
    206        {
    207            _socket_ = _socketFactory_.createSocket();
    208            if (receiveBufferSize != -1) _socket_.setReceiveBufferSize(receiveBufferSize);
    209            if (sendBufferSize != -1) _socket_.setSendBufferSize(sendBufferSize);
    210            _socket_.bind(new InetSocketAddress(localAddr, localPort));
    211            _socket_.connect(new InetSocketAddress(host, port), connectTimeout);
    212            _connectAction_();
    213        }
    214
    215
    216        /**
    217         * Opens a Socket connected to a remote host at the specified port and
    218         * originating from the specified local address and port.
    219         * Before returning, {@link #_connectAction_  _connectAction_() }
    220         * is called to perform connection initialization actions.
    221         * <p>
    222         * @param hostname  The name of the remote host.
    223         * @param port  The port to connect to on the remote host.
    224         * @param localAddr  The local address to use.
    225         * @param localPort  The local port to use.
    226         * @exception SocketException If the socket timeout could not be set.
    227         * @exception IOException If the socket could not be opened.  In most
    228         *  cases you will only want to catch IOException since SocketException is
    229         *  derived from it.
    230         * @exception UnknownHostException If the hostname cannot be resolved.
    231         */
    232        public void connect(String hostname, int port,
    233                            InetAddress localAddr, int localPort)
    234        throws SocketException, IOException
    235        {
    236           connect(InetAddress.getByName(hostname), port, localAddr, localPort);
    237        }
    238
    239
    240        /**
    241         * Opens a Socket connected to a remote host at the current default port
    242         * and originating from the current host at a system assigned port.
    243         * Before returning, {@link #_connectAction_  _connectAction_() }
    244         * is called to perform connection initialization actions.
    245         * <p>
    246         * @param host  The remote host.
    247         * @exception SocketException If the socket timeout could not be set.
    248         * @exception IOException If the socket could not be opened.  In most
    249         *  cases you will only want to catch IOException since SocketException is
    250         *  derived from it.
    251         */
    252        public void connect(InetAddress host) throws SocketException, IOException
    253        {
    254            connect(host, _defaultPort_);
    255        }
    256
    257
    258        /**
    259         * Opens a Socket connected to a remote host at the current default
    260         * port and originating from the current host at a system assigned port.
    261         * Before returning, {@link #_connectAction_  _connectAction_() }
    262         * is called to perform connection initialization actions.
    263         * <p>
    264         * @param hostname  The name of the remote host.
    265         * @exception SocketException If the socket timeout could not be set.
    266         * @exception IOException If the socket could not be opened.  In most
    267         *  cases you will only want to catch IOException since SocketException is
    268         *  derived from it.
    269         * @exception UnknownHostException If the hostname cannot be resolved.
    270         */
    271        public void connect(String hostname) throws SocketException, IOException
    272        {
    273            connect(hostname, _defaultPort_);
    274        }
    275
    276
    277        /**
    278         * Disconnects the socket connection.
    279         * You should call this method after you've finished using the class
    280         * instance and also before you call
    281         * {@link #connect connect() }
    282         * again.  _isConnected_ is set to false, _socket_ is set to null,
    283         * _input_ is set to null, and _output_ is set to null.
    284         * <p>
    285         * @exception IOException  If there is an error closing the socket.
    286         */
    287        public void disconnect() throws IOException
    288        {
    289            closeQuietly(_socket_);
    290            closeQuietly(_input_);
    291            closeQuietly(_output_);
    292            _socket_ = null;
    293            _input_ = null;
    294            _output_ = null;
    295        }
    296
    297        private void closeQuietly(Socket socket) {
    298            if (socket != null){
    299                try {
    300                    socket.close();
    301                } catch (IOException e) {
    302                }
    303            }
    304        }
    305
    306        private void closeQuietly(Closeable close){
    307            if (close != null){
    308                try {
    309                    close.close();
    310                } catch (IOException e) {
    311                }
    312            }
    313        }
    314        /**
    315         * Returns true if the client is currently connected to a server.
    316         * <p>
    317         * @return True if the client is currently connected to a server,
    318         *         false otherwise.
    319         */
    320        public boolean isConnected()
    321        {
    322            if (_socket_ == null)
    323                return false;
    324
    325            return _socket_.isConnected();
    326        }
    327
    328
    329        /**
    330         * Sets the default port the SocketClient should connect to when a port
    331         * is not specified.  The {@link #_defaultPort_  _defaultPort_ }
    332         * variable stores this value.  If never set, the default port is equal
    333         * to zero.
    334         * <p>
    335         * @param port  The default port to set.
    336         */
    337        public void setDefaultPort(int port)
    338        {
    339            _defaultPort_ = port;
    340        }
    341
    342        /**
    343         * Returns the current value of the default port (stored in
    344         * {@link #_defaultPort_  _defaultPort_ }).
    345         * <p>
    346         * @return The current value of the default port.
    347         */
    348        public int getDefaultPort()
    349        {
    350            return _defaultPort_;
    351        }
    352
    353
    354        /**
    355         * Set the default timeout in milliseconds to use when opening a socket.
    356         * This value is only used previous to a call to
    357         * {@link #connect connect()}
    358         * and should not be confused with {@link #setSoTimeout setSoTimeout()}
    359         * which operates on an the currently opened socket.  _timeout_ contains
    360         * the new timeout value.
    361         * <p>
    362         * @param timeout  The timeout in milliseconds to use for the socket
    363         *                 connection.
    364         */
    365        public void setDefaultTimeout(int timeout)
    366        {
    367            _timeout_ = timeout;
    368        }
    369
    370
    371        /**
    372         * Returns the default timeout in milliseconds that is used when
    373         * opening a socket.
    374         * <p>
    375         * @return The default timeout in milliseconds that is used when
    376         *         opening a socket.
    377         */
    378        public int getDefaultTimeout()
    379        {
    380            return _timeout_;
    381        }
    382
    383
    384        /**
    385         * Set the timeout in milliseconds of a currently open connection.
    386         * Only call this method after a connection has been opened
    387         * by {@link #connect connect()}.
    388         * <p>
    389         * @param timeout  The timeout in milliseconds to use for the currently
    390         *                 open socket connection.
    391         * @exception SocketException If the operation fails.
    392         */
    393        public void setSoTimeout(int timeout) throws SocketException
    394        {
    395            _socket_.setSoTimeout(timeout);
    396        }
    397
    398
    399        /**
    400         * Set the underlying socket send buffer size.
    401         * <p>
    402         * @param size The size of the buffer in bytes.
    403         * @throws SocketException
    404         * @since 2.0
    405         */
    406        public void setSendBufferSize(int size) throws SocketException {
    407            sendBufferSize = size;
    408        }
    409
    410
    411        /**
    412         * Sets the underlying socket receive buffer size.
    413         * <p>
    414         * @param size The size of the buffer in bytes.
    415         * @throws SocketException
    416         * @since 2.0
    417         */
    418        public void setReceiveBufferSize(int size) throws SocketException  {
    419            receiveBufferSize = size;
    420        }
    421
    422
    423        /**
    424         * Returns the timeout in milliseconds of the currently opened socket.
    425         * <p>
    426         * @return The timeout in milliseconds of the currently opened socket.
    427         * @exception SocketException If the operation fails.
    428         */
    429        public int getSoTimeout() throws SocketException
    430        {
    431            return _socket_.getSoTimeout();
    432        }
    433
    434        /**
    435         * Enables or disables the Nagle's algorithm (TCP_NODELAY) on the
    436         * currently opened socket.
    437         * <p>
    438         * @param on  True if Nagle's algorithm is to be enabled, false if not.
    439         * @exception SocketException If the operation fails.
    440         */
    441        public void setTcpNoDelay(boolean on) throws SocketException
    442        {
    443            _socket_.setTcpNoDelay(on);
    444        }
    445
    446
    447        /**
    448         * Returns true if Nagle's algorithm is enabled on the currently opened
    449         * socket.
    450         * <p>
    451         * @return True if Nagle's algorithm is enabled on the currently opened
    452         *        socket, false otherwise.
    453         * @exception SocketException If the operation fails.
    454         */
    455        public boolean getTcpNoDelay() throws SocketException
    456        {
    457            return _socket_.getTcpNoDelay();
    458        }
    459
    460        /**
    461         * Sets the SO_KEEPALIVE flag on the currently opened socket.
    462         *
    463         * From the Javadocs, the default keepalive time is 2 hours (although this is
    464         * implementation  dependent). It looks as though the Windows WSA sockets implementation
    465         * allows a specific keepalive value to be set, although this seems not to be the case on
    466         * other systems.
    467         * @param  keepAlive If true, keepAlive is turned on
    468         * @throws SocketException
    469         * @since 2.2
    470         */
    471        public void setKeepAlive(boolean keepAlive) throws SocketException {
    472            _socket_.setKeepAlive(keepAlive);
    473        }
    474
    475        /**
    476         * Returns the current value of the SO_KEEPALIVE flag on the currently opened socket.
    477         *
    478         * @return True if SO_KEEPALIVE is enabled.
    479         * @throws SocketException
    480         * @since 2.2
    481         */
    482        public boolean getKeepAlive() throws SocketException {
    483            return _socket_.getKeepAlive();
    484        }
    485
    486        /**
    487         * Sets the SO_LINGER timeout on the currently opened socket.
    488         * <p>
    489         * @param on  True if linger is to be enabled, false if not.
    490         * @param val The linger timeout (in hundredths of a second?)
    491         * @exception SocketException If the operation fails.
    492         */
    493        public void setSoLinger(boolean on, int val) throws SocketException
    494        {
    495            _socket_.setSoLinger(on, val);
    496        }
    497
    498
    499        /**
    500         * Returns the current SO_LINGER timeout of the currently opened socket.
    501         * <p>
    502         * @return The current SO_LINGER timeout.  If SO_LINGER is disabled returns
    503         *         -1.
    504         * @exception SocketException If the operation fails.
    505         */
    506        public int getSoLinger() throws SocketException
    507        {
    508            return _socket_.getSoLinger();
    509        }
    510
    511
    512        /**
    513         * Returns the port number of the open socket on the local host used
    514         * for the connection.
    515         * <p>
    516         * @return The port number of the open socket on the local host used
    517         *         for the connection.
    518         */
    519        public int getLocalPort()
    520        {
    521            return _socket_.getLocalPort();
    522        }
    523
    524
    525        /**
    526         * Returns the local address to which the client's socket is bound.
    527         * <p>
    528         * @return The local address to which the client's socket is bound.
    529         */
    530        public InetAddress getLocalAddress()
    531        {
    532            return _socket_.getLocalAddress();
    533        }
    534
    535        /**
    536         * Returns the port number of the remote host to which the client is
    537         * connected.
    538         * <p>
    539         * @return The port number of the remote host to which the client is
    540         *         connected.
    541         */
    542        public int getRemotePort()
    543        {
    544            return _socket_.getPort();
    545        }
    546
    547
    548        /**
    549         * @return The remote address to which the client is connected.
    550         */
    551        public InetAddress getRemoteAddress()
    552        {
    553            return _socket_.getInetAddress();
    554        }
    555
    556
    557        /**
    558         * Verifies that the remote end of the given socket is connected to the
    559         * the same host that the SocketClient is currently connected to.  This
    560         * is useful for doing a quick security check when a client needs to
    561         * accept a connection from a server, such as an FTP data connection or
    562         * a BSD R command standard error stream.
    563         * <p>
    564         * @return True if the remote hosts are the same, false if not.
    565         */
    566        public boolean verifyRemote(Socket socket)
    567        {
    568            InetAddress host1, host2;
    569
    570            host1 = socket.getInetAddress();
    571            host2 = getRemoteAddress();
    572
    573            return host1.equals(host2);
    574        }
    575
    576
    577        /**
    578         * Sets the SocketFactory used by the SocketClient to open socket
    579         * connections.  If the factory value is null, then a default
    580         * factory is used (only do this to reset the factory after having
    581         * previously altered it).
    582         * <p>
    583         * @param factory  The new SocketFactory the SocketClient should use.
    584         */
    585        public void setSocketFactory(SocketFactory factory)
    586        {
    587            if (factory == null)
    588                _socketFactory_ = __DEFAULT_SOCKET_FACTORY;
    589            else
    590                _socketFactory_ = factory;
    591        }
    592
    593        /**
    594         * Sets the ServerSocketFactory used by the SocketClient to open ServerSocket
    595         * connections.  If the factory value is null, then a default
    596         * factory is used (only do this to reset the factory after having
    597         * previously altered it).
    598         * <p>
    599         * @param factory  The new ServerSocketFactory the SocketClient should use.
    600         * @since 2.0
    601         */
    602        public void setServerSocketFactory(ServerSocketFactory factory) {
    603            if (factory == null)
    604                _serverSocketFactory_ = __DEFAULT_SERVER_SOCKET_FACTORY;
    605            else
    606                _serverSocketFactory_ = factory;
    607        }
    608
    609        /**
    610         * Sets the connection timeout in milliseconds, which will be passed to the {@link Socket} object's
    611         * connect() method.
    612         * @param connectTimeout The connection timeout to use (in ms)
    613         * @since 2.0
    614         */
    615        public void setConnectTimeout(int connectTimeout) {
    616            this.connectTimeout = connectTimeout;
    617        }
    618
    619        /**
    620         * Get the underlying socket connection timeout.
    621         * @return timeout (in ms)
    622         * @since 2.0
    623         */
    624        public int getConnectTimeout() {
    625            return connectTimeout;
    626        }
    627
    628        /**
    629         * Get the underlying {@link ServerSocketFactory}
    630         * @return The server socket factory
    631         * @since 2.2
    632         */
    633        public ServerSocketFactory getServerSocketFactory() {
    634            return _serverSocketFactory_;
    635        }
    636
    637    }
    638
    639